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