18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 28c2ecf20Sopenharmony_ci// Copyright (c) 2020 Facebook 38c2ecf20Sopenharmony_ci#include <vmlinux.h> 48c2ecf20Sopenharmony_ci#include <bpf/bpf_helpers.h> 58c2ecf20Sopenharmony_ci#include <bpf/bpf_tracing.h> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_cistruct bpf_perf_event_value___local { 88c2ecf20Sopenharmony_ci __u64 counter; 98c2ecf20Sopenharmony_ci __u64 enabled; 108c2ecf20Sopenharmony_ci __u64 running; 118c2ecf20Sopenharmony_ci} __attribute__((preserve_access_index)); 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* map of perf event fds, num_cpu * num_metric entries */ 148c2ecf20Sopenharmony_cistruct { 158c2ecf20Sopenharmony_ci __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); 168c2ecf20Sopenharmony_ci __uint(key_size, sizeof(u32)); 178c2ecf20Sopenharmony_ci __uint(value_size, sizeof(int)); 188c2ecf20Sopenharmony_ci} events SEC(".maps"); 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* readings at fentry */ 218c2ecf20Sopenharmony_cistruct { 228c2ecf20Sopenharmony_ci __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 238c2ecf20Sopenharmony_ci __uint(key_size, sizeof(u32)); 248c2ecf20Sopenharmony_ci __uint(value_size, sizeof(struct bpf_perf_event_value___local)); 258c2ecf20Sopenharmony_ci} fentry_readings SEC(".maps"); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* accumulated readings */ 288c2ecf20Sopenharmony_cistruct { 298c2ecf20Sopenharmony_ci __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 308c2ecf20Sopenharmony_ci __uint(key_size, sizeof(u32)); 318c2ecf20Sopenharmony_ci __uint(value_size, sizeof(struct bpf_perf_event_value___local)); 328c2ecf20Sopenharmony_ci} accum_readings SEC(".maps"); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* sample counts, one per cpu */ 358c2ecf20Sopenharmony_cistruct { 368c2ecf20Sopenharmony_ci __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 378c2ecf20Sopenharmony_ci __uint(key_size, sizeof(u32)); 388c2ecf20Sopenharmony_ci __uint(value_size, sizeof(u64)); 398c2ecf20Sopenharmony_ci} counts SEC(".maps"); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciconst volatile __u32 num_cpu = 1; 428c2ecf20Sopenharmony_ciconst volatile __u32 num_metric = 1; 438c2ecf20Sopenharmony_ci#define MAX_NUM_MATRICS 4 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciSEC("fentry/XXX") 468c2ecf20Sopenharmony_ciint BPF_PROG(fentry_XXX) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct bpf_perf_event_value___local *ptrs[MAX_NUM_MATRICS]; 498c2ecf20Sopenharmony_ci u32 key = bpf_get_smp_processor_id(); 508c2ecf20Sopenharmony_ci u32 i; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* look up before reading, to reduce error */ 538c2ecf20Sopenharmony_ci for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++) { 548c2ecf20Sopenharmony_ci u32 flag = i; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci ptrs[i] = bpf_map_lookup_elem(&fentry_readings, &flag); 578c2ecf20Sopenharmony_ci if (!ptrs[i]) 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++) { 628c2ecf20Sopenharmony_ci struct bpf_perf_event_value___local reading; 638c2ecf20Sopenharmony_ci int err; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci err = bpf_perf_event_read_value(&events, key, (void *)&reading, 668c2ecf20Sopenharmony_ci sizeof(reading)); 678c2ecf20Sopenharmony_ci if (err) 688c2ecf20Sopenharmony_ci return 0; 698c2ecf20Sopenharmony_ci *(ptrs[i]) = reading; 708c2ecf20Sopenharmony_ci key += num_cpu; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic inline void 778c2ecf20Sopenharmony_cifexit_update_maps(u32 id, struct bpf_perf_event_value___local *after) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct bpf_perf_event_value___local *before, diff; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci before = bpf_map_lookup_elem(&fentry_readings, &id); 828c2ecf20Sopenharmony_ci /* only account samples with a valid fentry_reading */ 838c2ecf20Sopenharmony_ci if (before && before->counter) { 848c2ecf20Sopenharmony_ci struct bpf_perf_event_value___local *accum; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci diff.counter = after->counter - before->counter; 878c2ecf20Sopenharmony_ci diff.enabled = after->enabled - before->enabled; 888c2ecf20Sopenharmony_ci diff.running = after->running - before->running; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci accum = bpf_map_lookup_elem(&accum_readings, &id); 918c2ecf20Sopenharmony_ci if (accum) { 928c2ecf20Sopenharmony_ci accum->counter += diff.counter; 938c2ecf20Sopenharmony_ci accum->enabled += diff.enabled; 948c2ecf20Sopenharmony_ci accum->running += diff.running; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ciSEC("fexit/XXX") 1008c2ecf20Sopenharmony_ciint BPF_PROG(fexit_XXX) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct bpf_perf_event_value___local readings[MAX_NUM_MATRICS]; 1038c2ecf20Sopenharmony_ci u32 cpu = bpf_get_smp_processor_id(); 1048c2ecf20Sopenharmony_ci u32 i, zero = 0; 1058c2ecf20Sopenharmony_ci int err; 1068c2ecf20Sopenharmony_ci u64 *count; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* read all events before updating the maps, to reduce error */ 1098c2ecf20Sopenharmony_ci for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++) { 1108c2ecf20Sopenharmony_ci err = bpf_perf_event_read_value(&events, cpu + i * num_cpu, 1118c2ecf20Sopenharmony_ci (void *)(readings + i), 1128c2ecf20Sopenharmony_ci sizeof(*readings)); 1138c2ecf20Sopenharmony_ci if (err) 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci count = bpf_map_lookup_elem(&counts, &zero); 1178c2ecf20Sopenharmony_ci if (count) { 1188c2ecf20Sopenharmony_ci *count += 1; 1198c2ecf20Sopenharmony_ci for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++) 1208c2ecf20Sopenharmony_ci fexit_update_maps(i, &readings[i]); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cichar LICENSE[] SEC("license") = "Dual BSD/GPL"; 126