1*e34293ddSTomas Glozar // SPDX-License-Identifier: GPL-2.0 2*e34293ddSTomas Glozar #include <linux/bpf.h> 3*e34293ddSTomas Glozar #include <bpf/bpf_tracing.h> 4*e34293ddSTomas Glozar #include <stdbool.h> 5*e34293ddSTomas Glozar #include "timerlat_bpf.h" 6*e34293ddSTomas Glozar 7*e34293ddSTomas Glozar #define nosubprog __always_inline 8*e34293ddSTomas Glozar #define MAX_ENTRIES_DEFAULT 4096 9*e34293ddSTomas Glozar 10*e34293ddSTomas Glozar char LICENSE[] SEC("license") = "GPL"; 11*e34293ddSTomas Glozar 12*e34293ddSTomas Glozar struct trace_event_raw_timerlat_sample { 13*e34293ddSTomas Glozar unsigned long long timer_latency; 14*e34293ddSTomas Glozar int context; 15*e34293ddSTomas Glozar } __attribute__((preserve_access_index)); 16*e34293ddSTomas Glozar 17*e34293ddSTomas Glozar struct { 18*e34293ddSTomas Glozar __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 19*e34293ddSTomas Glozar __uint(max_entries, MAX_ENTRIES_DEFAULT); 20*e34293ddSTomas Glozar __type(key, unsigned int); 21*e34293ddSTomas Glozar __type(value, unsigned long long); 22*e34293ddSTomas Glozar } hist_irq SEC(".maps"), hist_thread SEC(".maps"), hist_user SEC(".maps"); 23*e34293ddSTomas Glozar 24*e34293ddSTomas Glozar struct { 25*e34293ddSTomas Glozar __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 26*e34293ddSTomas Glozar __uint(max_entries, SUMMARY_FIELD_N); 27*e34293ddSTomas Glozar __type(key, unsigned int); 28*e34293ddSTomas Glozar __type(value, unsigned long long); 29*e34293ddSTomas Glozar } summary_irq SEC(".maps"), summary_thread SEC(".maps"), summary_user SEC(".maps"); 30*e34293ddSTomas Glozar 31*e34293ddSTomas Glozar struct { 32*e34293ddSTomas Glozar __uint(type, BPF_MAP_TYPE_RINGBUF); 33*e34293ddSTomas Glozar __uint(max_entries, 1); 34*e34293ddSTomas Glozar } signal_stop_tracing SEC(".maps"); 35*e34293ddSTomas Glozar 36*e34293ddSTomas Glozar /* Params to be set by rtla */ 37*e34293ddSTomas Glozar const volatile int bucket_size = 1; 38*e34293ddSTomas Glozar const volatile int output_divisor = 1000; 39*e34293ddSTomas Glozar const volatile int entries = 256; 40*e34293ddSTomas Glozar const volatile int irq_threshold; 41*e34293ddSTomas Glozar const volatile int thread_threshold; 42*e34293ddSTomas Glozar const volatile bool aa_only; 43*e34293ddSTomas Glozar 44*e34293ddSTomas Glozar int stop_tracing; 45*e34293ddSTomas Glozar 46*e34293ddSTomas Glozar nosubprog unsigned long long map_get(void *map, 47*e34293ddSTomas Glozar unsigned int key) 48*e34293ddSTomas Glozar { 49*e34293ddSTomas Glozar unsigned long long *value_ptr; 50*e34293ddSTomas Glozar 51*e34293ddSTomas Glozar value_ptr = bpf_map_lookup_elem(map, &key); 52*e34293ddSTomas Glozar 53*e34293ddSTomas Glozar return !value_ptr ? 0 : *value_ptr; 54*e34293ddSTomas Glozar } 55*e34293ddSTomas Glozar 56*e34293ddSTomas Glozar nosubprog void map_set(void *map, 57*e34293ddSTomas Glozar unsigned int key, 58*e34293ddSTomas Glozar unsigned long long value) 59*e34293ddSTomas Glozar { 60*e34293ddSTomas Glozar bpf_map_update_elem(map, &key, &value, BPF_ANY); 61*e34293ddSTomas Glozar } 62*e34293ddSTomas Glozar 63*e34293ddSTomas Glozar nosubprog void map_increment(void *map, 64*e34293ddSTomas Glozar unsigned int key) 65*e34293ddSTomas Glozar { 66*e34293ddSTomas Glozar map_set(map, key, map_get(map, key) + 1); 67*e34293ddSTomas Glozar } 68*e34293ddSTomas Glozar 69*e34293ddSTomas Glozar nosubprog void update_main_hist(void *map, 70*e34293ddSTomas Glozar int bucket) 71*e34293ddSTomas Glozar { 72*e34293ddSTomas Glozar if (entries == 0) 73*e34293ddSTomas Glozar /* No histogram */ 74*e34293ddSTomas Glozar return; 75*e34293ddSTomas Glozar 76*e34293ddSTomas Glozar if (bucket >= entries) 77*e34293ddSTomas Glozar /* Overflow */ 78*e34293ddSTomas Glozar return; 79*e34293ddSTomas Glozar 80*e34293ddSTomas Glozar map_increment(map, bucket); 81*e34293ddSTomas Glozar } 82*e34293ddSTomas Glozar 83*e34293ddSTomas Glozar nosubprog void update_summary(void *map, 84*e34293ddSTomas Glozar unsigned long long latency, 85*e34293ddSTomas Glozar int bucket) 86*e34293ddSTomas Glozar { 87*e34293ddSTomas Glozar if (aa_only) 88*e34293ddSTomas Glozar /* Auto-analysis only, nothing to be done here */ 89*e34293ddSTomas Glozar return; 90*e34293ddSTomas Glozar 91*e34293ddSTomas Glozar map_set(map, SUMMARY_CURRENT, latency); 92*e34293ddSTomas Glozar 93*e34293ddSTomas Glozar if (bucket >= entries) 94*e34293ddSTomas Glozar /* Overflow */ 95*e34293ddSTomas Glozar map_increment(map, SUMMARY_OVERFLOW); 96*e34293ddSTomas Glozar 97*e34293ddSTomas Glozar if (latency > map_get(map, SUMMARY_MAX)) 98*e34293ddSTomas Glozar map_set(map, SUMMARY_MAX, latency); 99*e34293ddSTomas Glozar 100*e34293ddSTomas Glozar if (latency < map_get(map, SUMMARY_MIN) || map_get(map, SUMMARY_COUNT) == 0) 101*e34293ddSTomas Glozar map_set(map, SUMMARY_MIN, latency); 102*e34293ddSTomas Glozar 103*e34293ddSTomas Glozar map_increment(map, SUMMARY_COUNT); 104*e34293ddSTomas Glozar map_set(map, SUMMARY_SUM, map_get(map, SUMMARY_SUM) + latency); 105*e34293ddSTomas Glozar } 106*e34293ddSTomas Glozar 107*e34293ddSTomas Glozar nosubprog void set_stop_tracing(void) 108*e34293ddSTomas Glozar { 109*e34293ddSTomas Glozar int value = 0; 110*e34293ddSTomas Glozar 111*e34293ddSTomas Glozar /* Suppress further sample processing */ 112*e34293ddSTomas Glozar stop_tracing = 1; 113*e34293ddSTomas Glozar 114*e34293ddSTomas Glozar /* Signal to userspace */ 115*e34293ddSTomas Glozar bpf_ringbuf_output(&signal_stop_tracing, &value, sizeof(value), 0); 116*e34293ddSTomas Glozar } 117*e34293ddSTomas Glozar 118*e34293ddSTomas Glozar SEC("tp/osnoise/timerlat_sample") 119*e34293ddSTomas Glozar int handle_timerlat_sample(struct trace_event_raw_timerlat_sample *tp_args) 120*e34293ddSTomas Glozar { 121*e34293ddSTomas Glozar unsigned long long latency, latency_us; 122*e34293ddSTomas Glozar int bucket; 123*e34293ddSTomas Glozar 124*e34293ddSTomas Glozar if (stop_tracing) 125*e34293ddSTomas Glozar return 0; 126*e34293ddSTomas Glozar 127*e34293ddSTomas Glozar latency = tp_args->timer_latency / output_divisor; 128*e34293ddSTomas Glozar latency_us = tp_args->timer_latency / 1000; 129*e34293ddSTomas Glozar bucket = latency / bucket_size; 130*e34293ddSTomas Glozar 131*e34293ddSTomas Glozar if (tp_args->context == 0) { 132*e34293ddSTomas Glozar update_main_hist(&hist_irq, bucket); 133*e34293ddSTomas Glozar update_summary(&summary_irq, latency, bucket); 134*e34293ddSTomas Glozar 135*e34293ddSTomas Glozar if (irq_threshold != 0 && latency_us >= irq_threshold) 136*e34293ddSTomas Glozar set_stop_tracing(); 137*e34293ddSTomas Glozar } else if (tp_args->context == 1) { 138*e34293ddSTomas Glozar update_main_hist(&hist_thread, bucket); 139*e34293ddSTomas Glozar update_summary(&summary_thread, latency, bucket); 140*e34293ddSTomas Glozar 141*e34293ddSTomas Glozar if (thread_threshold != 0 && latency_us >= thread_threshold) 142*e34293ddSTomas Glozar set_stop_tracing(); 143*e34293ddSTomas Glozar } else { 144*e34293ddSTomas Glozar update_main_hist(&hist_user, bucket); 145*e34293ddSTomas Glozar update_summary(&summary_user, latency, bucket); 146*e34293ddSTomas Glozar } 147*e34293ddSTomas Glozar 148*e34293ddSTomas Glozar return 0; 149*e34293ddSTomas Glozar } 150