162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 262306a36Sopenharmony_ci// Copyright (c) 2020 Facebook 362306a36Sopenharmony_ci#include <vmlinux.h> 462306a36Sopenharmony_ci#include <bpf/bpf_helpers.h> 562306a36Sopenharmony_ci#include <bpf/bpf_tracing.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_cistruct bpf_perf_event_value___local { 862306a36Sopenharmony_ci __u64 counter; 962306a36Sopenharmony_ci __u64 enabled; 1062306a36Sopenharmony_ci __u64 running; 1162306a36Sopenharmony_ci} __attribute__((preserve_access_index)); 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* map of perf event fds, num_cpu * num_metric entries */ 1462306a36Sopenharmony_cistruct { 1562306a36Sopenharmony_ci __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); 1662306a36Sopenharmony_ci __uint(key_size, sizeof(u32)); 1762306a36Sopenharmony_ci __uint(value_size, sizeof(int)); 1862306a36Sopenharmony_ci} events SEC(".maps"); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* readings at fentry */ 2162306a36Sopenharmony_cistruct { 2262306a36Sopenharmony_ci __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 2362306a36Sopenharmony_ci __uint(key_size, sizeof(u32)); 2462306a36Sopenharmony_ci __uint(value_size, sizeof(struct bpf_perf_event_value___local)); 2562306a36Sopenharmony_ci} fentry_readings SEC(".maps"); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* accumulated readings */ 2862306a36Sopenharmony_cistruct { 2962306a36Sopenharmony_ci __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 3062306a36Sopenharmony_ci __uint(key_size, sizeof(u32)); 3162306a36Sopenharmony_ci __uint(value_size, sizeof(struct bpf_perf_event_value___local)); 3262306a36Sopenharmony_ci} accum_readings SEC(".maps"); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* sample counts, one per cpu */ 3562306a36Sopenharmony_cistruct { 3662306a36Sopenharmony_ci __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 3762306a36Sopenharmony_ci __uint(key_size, sizeof(u32)); 3862306a36Sopenharmony_ci __uint(value_size, sizeof(u64)); 3962306a36Sopenharmony_ci} counts SEC(".maps"); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciconst volatile __u32 num_cpu = 1; 4262306a36Sopenharmony_ciconst volatile __u32 num_metric = 1; 4362306a36Sopenharmony_ci#define MAX_NUM_MATRICS 4 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ciSEC("fentry/XXX") 4662306a36Sopenharmony_ciint BPF_PROG(fentry_XXX) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct bpf_perf_event_value___local *ptrs[MAX_NUM_MATRICS]; 4962306a36Sopenharmony_ci u32 key = bpf_get_smp_processor_id(); 5062306a36Sopenharmony_ci u32 i; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci /* look up before reading, to reduce error */ 5362306a36Sopenharmony_ci for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++) { 5462306a36Sopenharmony_ci u32 flag = i; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci ptrs[i] = bpf_map_lookup_elem(&fentry_readings, &flag); 5762306a36Sopenharmony_ci if (!ptrs[i]) 5862306a36Sopenharmony_ci return 0; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++) { 6262306a36Sopenharmony_ci struct bpf_perf_event_value___local reading; 6362306a36Sopenharmony_ci int err; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci err = bpf_perf_event_read_value(&events, key, (void *)&reading, 6662306a36Sopenharmony_ci sizeof(reading)); 6762306a36Sopenharmony_ci if (err) 6862306a36Sopenharmony_ci return 0; 6962306a36Sopenharmony_ci *(ptrs[i]) = reading; 7062306a36Sopenharmony_ci key += num_cpu; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return 0; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic inline void 7762306a36Sopenharmony_cifexit_update_maps(u32 id, struct bpf_perf_event_value___local *after) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct bpf_perf_event_value___local *before, diff; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci before = bpf_map_lookup_elem(&fentry_readings, &id); 8262306a36Sopenharmony_ci /* only account samples with a valid fentry_reading */ 8362306a36Sopenharmony_ci if (before && before->counter) { 8462306a36Sopenharmony_ci struct bpf_perf_event_value___local *accum; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci diff.counter = after->counter - before->counter; 8762306a36Sopenharmony_ci diff.enabled = after->enabled - before->enabled; 8862306a36Sopenharmony_ci diff.running = after->running - before->running; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci accum = bpf_map_lookup_elem(&accum_readings, &id); 9162306a36Sopenharmony_ci if (accum) { 9262306a36Sopenharmony_ci accum->counter += diff.counter; 9362306a36Sopenharmony_ci accum->enabled += diff.enabled; 9462306a36Sopenharmony_ci accum->running += diff.running; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ciSEC("fexit/XXX") 10062306a36Sopenharmony_ciint BPF_PROG(fexit_XXX) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct bpf_perf_event_value___local readings[MAX_NUM_MATRICS]; 10362306a36Sopenharmony_ci u32 cpu = bpf_get_smp_processor_id(); 10462306a36Sopenharmony_ci u32 i, zero = 0; 10562306a36Sopenharmony_ci int err; 10662306a36Sopenharmony_ci u64 *count; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* read all events before updating the maps, to reduce error */ 10962306a36Sopenharmony_ci for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++) { 11062306a36Sopenharmony_ci err = bpf_perf_event_read_value(&events, cpu + i * num_cpu, 11162306a36Sopenharmony_ci (void *)(readings + i), 11262306a36Sopenharmony_ci sizeof(*readings)); 11362306a36Sopenharmony_ci if (err) 11462306a36Sopenharmony_ci return 0; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci count = bpf_map_lookup_elem(&counts, &zero); 11762306a36Sopenharmony_ci if (count) { 11862306a36Sopenharmony_ci *count += 1; 11962306a36Sopenharmony_ci for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++) 12062306a36Sopenharmony_ci fexit_update_maps(i, &readings[i]); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci return 0; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cichar LICENSE[] SEC("license") = "Dual BSD/GPL"; 126