xref: /openbmc/linux/tools/perf/util/bpf_skel/kwork_trace.bpf.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1daf07d22SYang Jihong // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2daf07d22SYang Jihong // Copyright (c) 2022, Huawei
3daf07d22SYang Jihong 
4daf07d22SYang Jihong #include "vmlinux.h"
5daf07d22SYang Jihong #include <bpf/bpf_helpers.h>
6daf07d22SYang Jihong #include <bpf/bpf_tracing.h>
7daf07d22SYang Jihong 
8daf07d22SYang Jihong #define KWORK_COUNT 100
9daf07d22SYang Jihong #define MAX_KWORKNAME 128
10daf07d22SYang Jihong 
11daf07d22SYang Jihong /*
12daf07d22SYang Jihong  * This should be in sync with "util/kwork.h"
13daf07d22SYang Jihong  */
14daf07d22SYang Jihong enum kwork_class_type {
15daf07d22SYang Jihong 	KWORK_CLASS_IRQ,
16daf07d22SYang Jihong 	KWORK_CLASS_SOFTIRQ,
17daf07d22SYang Jihong 	KWORK_CLASS_WORKQUEUE,
18daf07d22SYang Jihong 	KWORK_CLASS_MAX,
19daf07d22SYang Jihong };
20daf07d22SYang Jihong 
21daf07d22SYang Jihong struct work_key {
22daf07d22SYang Jihong 	__u32 type;
23daf07d22SYang Jihong 	__u32 cpu;
24daf07d22SYang Jihong 	__u64 id;
25daf07d22SYang Jihong };
26daf07d22SYang Jihong 
27daf07d22SYang Jihong struct report_data {
28daf07d22SYang Jihong 	__u64 nr;
29daf07d22SYang Jihong 	__u64 total_time;
30daf07d22SYang Jihong 	__u64 max_time;
31daf07d22SYang Jihong 	__u64 max_time_start;
32daf07d22SYang Jihong 	__u64 max_time_end;
33daf07d22SYang Jihong };
34daf07d22SYang Jihong 
35daf07d22SYang Jihong struct {
36daf07d22SYang Jihong 	__uint(type, BPF_MAP_TYPE_HASH);
37daf07d22SYang Jihong 	__uint(key_size, sizeof(struct work_key));
38daf07d22SYang Jihong 	__uint(value_size, MAX_KWORKNAME);
39daf07d22SYang Jihong 	__uint(max_entries, KWORK_COUNT);
40daf07d22SYang Jihong } perf_kwork_names SEC(".maps");
41daf07d22SYang Jihong 
42daf07d22SYang Jihong struct {
43daf07d22SYang Jihong 	__uint(type, BPF_MAP_TYPE_HASH);
44daf07d22SYang Jihong 	__uint(key_size, sizeof(struct work_key));
45daf07d22SYang Jihong 	__uint(value_size, sizeof(__u64));
46daf07d22SYang Jihong 	__uint(max_entries, KWORK_COUNT);
47daf07d22SYang Jihong } perf_kwork_time SEC(".maps");
48daf07d22SYang Jihong 
49daf07d22SYang Jihong struct {
50daf07d22SYang Jihong 	__uint(type, BPF_MAP_TYPE_HASH);
51daf07d22SYang Jihong 	__uint(key_size, sizeof(struct work_key));
52daf07d22SYang Jihong 	__uint(value_size, sizeof(struct report_data));
53daf07d22SYang Jihong 	__uint(max_entries, KWORK_COUNT);
54daf07d22SYang Jihong } perf_kwork_report SEC(".maps");
55daf07d22SYang Jihong 
56daf07d22SYang Jihong struct {
57daf07d22SYang Jihong 	__uint(type, BPF_MAP_TYPE_HASH);
58daf07d22SYang Jihong 	__uint(key_size, sizeof(__u32));
59daf07d22SYang Jihong 	__uint(value_size, sizeof(__u8));
60daf07d22SYang Jihong 	__uint(max_entries, 1);
61daf07d22SYang Jihong } perf_kwork_cpu_filter SEC(".maps");
62daf07d22SYang Jihong 
63daf07d22SYang Jihong struct {
64daf07d22SYang Jihong 	__uint(type, BPF_MAP_TYPE_ARRAY);
65daf07d22SYang Jihong 	__uint(key_size, sizeof(__u32));
66daf07d22SYang Jihong 	__uint(value_size, MAX_KWORKNAME);
67daf07d22SYang Jihong 	__uint(max_entries, 1);
68daf07d22SYang Jihong } perf_kwork_name_filter SEC(".maps");
69daf07d22SYang Jihong 
70daf07d22SYang Jihong int enabled = 0;
71daf07d22SYang Jihong int has_cpu_filter = 0;
72daf07d22SYang Jihong int has_name_filter = 0;
73daf07d22SYang Jihong 
local_strncmp(const char * s1,unsigned int sz,const char * s2)74420298aeSYang Jihong static __always_inline int local_strncmp(const char *s1,
75420298aeSYang Jihong 					 unsigned int sz, const char *s2)
76420298aeSYang Jihong {
77420298aeSYang Jihong 	int ret = 0;
78420298aeSYang Jihong 	unsigned int i;
79420298aeSYang Jihong 
80420298aeSYang Jihong 	for (i = 0; i < sz; i++) {
81420298aeSYang Jihong 		ret = (unsigned char)s1[i] - (unsigned char)s2[i];
82420298aeSYang Jihong 		if (ret || !s1[i] || !s2[i])
83420298aeSYang Jihong 			break;
84420298aeSYang Jihong 	}
85420298aeSYang Jihong 
86420298aeSYang Jihong 	return ret;
87420298aeSYang Jihong }
88420298aeSYang Jihong 
trace_event_match(struct work_key * key,char * name)89420298aeSYang Jihong static __always_inline int trace_event_match(struct work_key *key, char *name)
90420298aeSYang Jihong {
91420298aeSYang Jihong 	__u8 *cpu_val;
92420298aeSYang Jihong 	char *name_val;
93420298aeSYang Jihong 	__u32 zero = 0;
94420298aeSYang Jihong 	__u32 cpu = bpf_get_smp_processor_id();
95420298aeSYang Jihong 
96420298aeSYang Jihong 	if (!enabled)
97420298aeSYang Jihong 		return 0;
98420298aeSYang Jihong 
99420298aeSYang Jihong 	if (has_cpu_filter) {
100420298aeSYang Jihong 		cpu_val = bpf_map_lookup_elem(&perf_kwork_cpu_filter, &cpu);
101420298aeSYang Jihong 		if (!cpu_val)
102420298aeSYang Jihong 			return 0;
103420298aeSYang Jihong 	}
104420298aeSYang Jihong 
105420298aeSYang Jihong 	if (has_name_filter && (name != NULL)) {
106420298aeSYang Jihong 		name_val = bpf_map_lookup_elem(&perf_kwork_name_filter, &zero);
107420298aeSYang Jihong 		if (name_val &&
108420298aeSYang Jihong 		    (local_strncmp(name_val, MAX_KWORKNAME, name) != 0)) {
109420298aeSYang Jihong 			return 0;
110420298aeSYang Jihong 		}
111420298aeSYang Jihong 	}
112420298aeSYang Jihong 
113420298aeSYang Jihong 	return 1;
114420298aeSYang Jihong }
115420298aeSYang Jihong 
do_update_time(void * map,struct work_key * key,__u64 time_start,__u64 time_end)116420298aeSYang Jihong static __always_inline void do_update_time(void *map, struct work_key *key,
117420298aeSYang Jihong 					   __u64 time_start, __u64 time_end)
118420298aeSYang Jihong {
119420298aeSYang Jihong 	struct report_data zero, *data;
120420298aeSYang Jihong 	__s64 delta = time_end - time_start;
121420298aeSYang Jihong 
122420298aeSYang Jihong 	if (delta < 0)
123420298aeSYang Jihong 		return;
124420298aeSYang Jihong 
125420298aeSYang Jihong 	data = bpf_map_lookup_elem(map, key);
126420298aeSYang Jihong 	if (!data) {
127420298aeSYang Jihong 		__builtin_memset(&zero, 0, sizeof(zero));
128420298aeSYang Jihong 		bpf_map_update_elem(map, key, &zero, BPF_NOEXIST);
129420298aeSYang Jihong 		data = bpf_map_lookup_elem(map, key);
130420298aeSYang Jihong 		if (!data)
131420298aeSYang Jihong 			return;
132420298aeSYang Jihong 	}
133420298aeSYang Jihong 
134420298aeSYang Jihong 	if ((delta > data->max_time) ||
135420298aeSYang Jihong 	    (data->max_time == 0)) {
136420298aeSYang Jihong 		data->max_time       = delta;
137420298aeSYang Jihong 		data->max_time_start = time_start;
138420298aeSYang Jihong 		data->max_time_end   = time_end;
139420298aeSYang Jihong 	}
140420298aeSYang Jihong 
141420298aeSYang Jihong 	data->total_time += delta;
142420298aeSYang Jihong 	data->nr++;
143420298aeSYang Jihong }
144420298aeSYang Jihong 
do_update_timestart(void * map,struct work_key * key)145420298aeSYang Jihong static __always_inline void do_update_timestart(void *map, struct work_key *key)
146420298aeSYang Jihong {
147420298aeSYang Jihong 	__u64 ts = bpf_ktime_get_ns();
148420298aeSYang Jihong 
149420298aeSYang Jihong 	bpf_map_update_elem(map, key, &ts, BPF_ANY);
150420298aeSYang Jihong }
151420298aeSYang Jihong 
do_update_timeend(void * report_map,void * time_map,struct work_key * key)152420298aeSYang Jihong static __always_inline void do_update_timeend(void *report_map, void *time_map,
153420298aeSYang Jihong 					      struct work_key *key)
154420298aeSYang Jihong {
155420298aeSYang Jihong 	__u64 *time = bpf_map_lookup_elem(time_map, key);
156420298aeSYang Jihong 
157420298aeSYang Jihong 	if (time) {
158420298aeSYang Jihong 		bpf_map_delete_elem(time_map, key);
159420298aeSYang Jihong 		do_update_time(report_map, key, *time, bpf_ktime_get_ns());
160420298aeSYang Jihong 	}
161420298aeSYang Jihong }
162420298aeSYang Jihong 
do_update_name(void * map,struct work_key * key,char * name)163420298aeSYang Jihong static __always_inline void do_update_name(void *map,
164420298aeSYang Jihong 					   struct work_key *key, char *name)
165420298aeSYang Jihong {
166420298aeSYang Jihong 	if (!bpf_map_lookup_elem(map, key))
167420298aeSYang Jihong 		bpf_map_update_elem(map, key, name, BPF_ANY);
168420298aeSYang Jihong }
169420298aeSYang Jihong 
update_timestart(void * map,struct work_key * key)170*acfb65feSYang Jihong static __always_inline int update_timestart(void *map, struct work_key *key)
171*acfb65feSYang Jihong {
172*acfb65feSYang Jihong 	if (!trace_event_match(key, NULL))
173*acfb65feSYang Jihong 		return 0;
174*acfb65feSYang Jihong 
175*acfb65feSYang Jihong 	do_update_timestart(map, key);
176*acfb65feSYang Jihong 	return 0;
177*acfb65feSYang Jihong }
178*acfb65feSYang Jihong 
update_timestart_and_name(void * time_map,void * names_map,struct work_key * key,char * name)179420298aeSYang Jihong static __always_inline int update_timestart_and_name(void *time_map,
180420298aeSYang Jihong 						     void *names_map,
181420298aeSYang Jihong 						     struct work_key *key,
182420298aeSYang Jihong 						     char *name)
183420298aeSYang Jihong {
184420298aeSYang Jihong 	if (!trace_event_match(key, name))
185420298aeSYang Jihong 		return 0;
186420298aeSYang Jihong 
187420298aeSYang Jihong 	do_update_timestart(time_map, key);
188420298aeSYang Jihong 	do_update_name(names_map, key, name);
189420298aeSYang Jihong 
190420298aeSYang Jihong 	return 0;
191420298aeSYang Jihong }
192420298aeSYang Jihong 
update_timeend(void * report_map,void * time_map,struct work_key * key)193420298aeSYang Jihong static __always_inline int update_timeend(void *report_map,
194420298aeSYang Jihong 					  void *time_map, struct work_key *key)
195420298aeSYang Jihong {
196420298aeSYang Jihong 	if (!trace_event_match(key, NULL))
197420298aeSYang Jihong 		return 0;
198420298aeSYang Jihong 
199420298aeSYang Jihong 	do_update_timeend(report_map, time_map, key);
200420298aeSYang Jihong 
201420298aeSYang Jihong 	return 0;
202420298aeSYang Jihong }
203420298aeSYang Jihong 
update_timeend_and_name(void * report_map,void * time_map,void * names_map,struct work_key * key,char * name)204*acfb65feSYang Jihong static __always_inline int update_timeend_and_name(void *report_map,
205*acfb65feSYang Jihong 						   void *time_map,
206*acfb65feSYang Jihong 						   void *names_map,
207*acfb65feSYang Jihong 						   struct work_key *key,
208*acfb65feSYang Jihong 						   char *name)
209*acfb65feSYang Jihong {
210*acfb65feSYang Jihong 	if (!trace_event_match(key, name))
211*acfb65feSYang Jihong 		return 0;
212*acfb65feSYang Jihong 
213*acfb65feSYang Jihong 	do_update_timeend(report_map, time_map, key);
214*acfb65feSYang Jihong 	do_update_name(names_map, key, name);
215*acfb65feSYang Jihong 
216*acfb65feSYang Jihong 	return 0;
217*acfb65feSYang Jihong }
218*acfb65feSYang Jihong 
219420298aeSYang Jihong SEC("tracepoint/irq/irq_handler_entry")
report_irq_handler_entry(struct trace_event_raw_irq_handler_entry * ctx)220420298aeSYang Jihong int report_irq_handler_entry(struct trace_event_raw_irq_handler_entry *ctx)
221420298aeSYang Jihong {
222420298aeSYang Jihong 	char name[MAX_KWORKNAME];
223420298aeSYang Jihong 	struct work_key key = {
224420298aeSYang Jihong 		.type = KWORK_CLASS_IRQ,
225420298aeSYang Jihong 		.cpu  = bpf_get_smp_processor_id(),
226420298aeSYang Jihong 		.id   = (__u64)ctx->irq,
227420298aeSYang Jihong 	};
228420298aeSYang Jihong 	void *name_addr = (void *)ctx + (ctx->__data_loc_name & 0xffff);
229420298aeSYang Jihong 
230420298aeSYang Jihong 	bpf_probe_read_kernel_str(name, sizeof(name), name_addr);
231420298aeSYang Jihong 
232420298aeSYang Jihong 	return update_timestart_and_name(&perf_kwork_time,
233420298aeSYang Jihong 					 &perf_kwork_names, &key, name);
234420298aeSYang Jihong }
235420298aeSYang Jihong 
236420298aeSYang Jihong SEC("tracepoint/irq/irq_handler_exit")
report_irq_handler_exit(struct trace_event_raw_irq_handler_exit * ctx)237420298aeSYang Jihong int report_irq_handler_exit(struct trace_event_raw_irq_handler_exit *ctx)
238420298aeSYang Jihong {
239420298aeSYang Jihong 	struct work_key key = {
240420298aeSYang Jihong 		.type = KWORK_CLASS_IRQ,
241420298aeSYang Jihong 		.cpu  = bpf_get_smp_processor_id(),
242420298aeSYang Jihong 		.id   = (__u64)ctx->irq,
243420298aeSYang Jihong 	};
244420298aeSYang Jihong 
245420298aeSYang Jihong 	return update_timeend(&perf_kwork_report, &perf_kwork_time, &key);
246420298aeSYang Jihong }
247420298aeSYang Jihong 
2485a81927aSYang Jihong static char softirq_name_list[NR_SOFTIRQS][MAX_KWORKNAME] = {
2495a81927aSYang Jihong 	{ "HI"       },
2505a81927aSYang Jihong 	{ "TIMER"    },
2515a81927aSYang Jihong 	{ "NET_TX"   },
2525a81927aSYang Jihong 	{ "NET_RX"   },
2535a81927aSYang Jihong 	{ "BLOCK"    },
2545a81927aSYang Jihong 	{ "IRQ_POLL" },
2555a81927aSYang Jihong 	{ "TASKLET"  },
2565a81927aSYang Jihong 	{ "SCHED"    },
2575a81927aSYang Jihong 	{ "HRTIMER"  },
2585a81927aSYang Jihong 	{ "RCU"      },
2595a81927aSYang Jihong };
2605a81927aSYang Jihong 
2615a81927aSYang Jihong SEC("tracepoint/irq/softirq_entry")
report_softirq_entry(struct trace_event_raw_softirq * ctx)2625a81927aSYang Jihong int report_softirq_entry(struct trace_event_raw_softirq *ctx)
2635a81927aSYang Jihong {
2645a81927aSYang Jihong 	unsigned int vec = ctx->vec;
2655a81927aSYang Jihong 	struct work_key key = {
2665a81927aSYang Jihong 		.type = KWORK_CLASS_SOFTIRQ,
2675a81927aSYang Jihong 		.cpu  = bpf_get_smp_processor_id(),
2685a81927aSYang Jihong 		.id   = (__u64)vec,
2695a81927aSYang Jihong 	};
2705a81927aSYang Jihong 
2715a81927aSYang Jihong 	if (vec < NR_SOFTIRQS) {
2725a81927aSYang Jihong 		return update_timestart_and_name(&perf_kwork_time,
2735a81927aSYang Jihong 						 &perf_kwork_names, &key,
2745a81927aSYang Jihong 						 softirq_name_list[vec]);
2755a81927aSYang Jihong 	}
2765a81927aSYang Jihong 
2775a81927aSYang Jihong 	return 0;
2785a81927aSYang Jihong }
2795a81927aSYang Jihong 
2805a81927aSYang Jihong SEC("tracepoint/irq/softirq_exit")
report_softirq_exit(struct trace_event_raw_softirq * ctx)2815a81927aSYang Jihong int report_softirq_exit(struct trace_event_raw_softirq *ctx)
2825a81927aSYang Jihong {
2835a81927aSYang Jihong 	struct work_key key = {
2845a81927aSYang Jihong 		.type = KWORK_CLASS_SOFTIRQ,
2855a81927aSYang Jihong 		.cpu  = bpf_get_smp_processor_id(),
2865a81927aSYang Jihong 		.id   = (__u64)ctx->vec,
2875a81927aSYang Jihong 	};
2885a81927aSYang Jihong 
2895a81927aSYang Jihong 	return update_timeend(&perf_kwork_report, &perf_kwork_time, &key);
2905a81927aSYang Jihong }
2915a81927aSYang Jihong 
2925a81927aSYang Jihong SEC("tracepoint/irq/softirq_raise")
latency_softirq_raise(struct trace_event_raw_softirq * ctx)2935a81927aSYang Jihong int latency_softirq_raise(struct trace_event_raw_softirq *ctx)
2945a81927aSYang Jihong {
2955a81927aSYang Jihong 	unsigned int vec = ctx->vec;
2965a81927aSYang Jihong 	struct work_key key = {
2975a81927aSYang Jihong 		.type = KWORK_CLASS_SOFTIRQ,
2985a81927aSYang Jihong 		.cpu  = bpf_get_smp_processor_id(),
2995a81927aSYang Jihong 		.id   = (__u64)vec,
3005a81927aSYang Jihong 	};
3015a81927aSYang Jihong 
3025a81927aSYang Jihong 	if (vec < NR_SOFTIRQS) {
3035a81927aSYang Jihong 		return update_timestart_and_name(&perf_kwork_time,
3045a81927aSYang Jihong 						 &perf_kwork_names, &key,
3055a81927aSYang Jihong 						 softirq_name_list[vec]);
3065a81927aSYang Jihong 	}
3075a81927aSYang Jihong 
3085a81927aSYang Jihong 	return 0;
3095a81927aSYang Jihong }
3105a81927aSYang Jihong 
3115a81927aSYang Jihong SEC("tracepoint/irq/softirq_entry")
latency_softirq_entry(struct trace_event_raw_softirq * ctx)3125a81927aSYang Jihong int latency_softirq_entry(struct trace_event_raw_softirq *ctx)
3135a81927aSYang Jihong {
3145a81927aSYang Jihong 	struct work_key key = {
3155a81927aSYang Jihong 		.type = KWORK_CLASS_SOFTIRQ,
3165a81927aSYang Jihong 		.cpu  = bpf_get_smp_processor_id(),
3175a81927aSYang Jihong 		.id   = (__u64)ctx->vec,
3185a81927aSYang Jihong 	};
3195a81927aSYang Jihong 
3205a81927aSYang Jihong 	return update_timeend(&perf_kwork_report, &perf_kwork_time, &key);
3215a81927aSYang Jihong }
3225a81927aSYang Jihong 
323*acfb65feSYang Jihong SEC("tracepoint/workqueue/workqueue_execute_start")
report_workqueue_execute_start(struct trace_event_raw_workqueue_execute_start * ctx)324*acfb65feSYang Jihong int report_workqueue_execute_start(struct trace_event_raw_workqueue_execute_start *ctx)
325*acfb65feSYang Jihong {
326*acfb65feSYang Jihong 	struct work_key key = {
327*acfb65feSYang Jihong 		.type = KWORK_CLASS_WORKQUEUE,
328*acfb65feSYang Jihong 		.cpu  = bpf_get_smp_processor_id(),
329*acfb65feSYang Jihong 		.id   = (__u64)ctx->work,
330*acfb65feSYang Jihong 	};
331*acfb65feSYang Jihong 
332*acfb65feSYang Jihong 	return update_timestart(&perf_kwork_time, &key);
333*acfb65feSYang Jihong }
334*acfb65feSYang Jihong 
335*acfb65feSYang Jihong SEC("tracepoint/workqueue/workqueue_execute_end")
report_workqueue_execute_end(struct trace_event_raw_workqueue_execute_end * ctx)336*acfb65feSYang Jihong int report_workqueue_execute_end(struct trace_event_raw_workqueue_execute_end *ctx)
337*acfb65feSYang Jihong {
338*acfb65feSYang Jihong 	char name[MAX_KWORKNAME];
339*acfb65feSYang Jihong 	struct work_key key = {
340*acfb65feSYang Jihong 		.type = KWORK_CLASS_WORKQUEUE,
341*acfb65feSYang Jihong 		.cpu  = bpf_get_smp_processor_id(),
342*acfb65feSYang Jihong 		.id   = (__u64)ctx->work,
343*acfb65feSYang Jihong 	};
344*acfb65feSYang Jihong 	unsigned long long func_addr = (unsigned long long)ctx->function;
345*acfb65feSYang Jihong 
346*acfb65feSYang Jihong 	__builtin_memset(name, 0, sizeof(name));
347*acfb65feSYang Jihong 	bpf_snprintf(name, sizeof(name), "%ps", &func_addr, sizeof(func_addr));
348*acfb65feSYang Jihong 
349*acfb65feSYang Jihong 	return update_timeend_and_name(&perf_kwork_report, &perf_kwork_time,
350*acfb65feSYang Jihong 				       &perf_kwork_names, &key, name);
351*acfb65feSYang Jihong }
352*acfb65feSYang Jihong 
353*acfb65feSYang Jihong SEC("tracepoint/workqueue/workqueue_activate_work")
latency_workqueue_activate_work(struct trace_event_raw_workqueue_activate_work * ctx)354*acfb65feSYang Jihong int latency_workqueue_activate_work(struct trace_event_raw_workqueue_activate_work *ctx)
355*acfb65feSYang Jihong {
356*acfb65feSYang Jihong 	struct work_key key = {
357*acfb65feSYang Jihong 		.type = KWORK_CLASS_WORKQUEUE,
358*acfb65feSYang Jihong 		.cpu  = bpf_get_smp_processor_id(),
359*acfb65feSYang Jihong 		.id   = (__u64)ctx->work,
360*acfb65feSYang Jihong 	};
361*acfb65feSYang Jihong 
362*acfb65feSYang Jihong 	return update_timestart(&perf_kwork_time, &key);
363*acfb65feSYang Jihong }
364*acfb65feSYang Jihong 
365*acfb65feSYang Jihong SEC("tracepoint/workqueue/workqueue_execute_start")
latency_workqueue_execute_start(struct trace_event_raw_workqueue_execute_start * ctx)366*acfb65feSYang Jihong int latency_workqueue_execute_start(struct trace_event_raw_workqueue_execute_start *ctx)
367*acfb65feSYang Jihong {
368*acfb65feSYang Jihong 	char name[MAX_KWORKNAME];
369*acfb65feSYang Jihong 	struct work_key key = {
370*acfb65feSYang Jihong 		.type = KWORK_CLASS_WORKQUEUE,
371*acfb65feSYang Jihong 		.cpu  = bpf_get_smp_processor_id(),
372*acfb65feSYang Jihong 		.id   = (__u64)ctx->work,
373*acfb65feSYang Jihong 	};
374*acfb65feSYang Jihong 	unsigned long long func_addr = (unsigned long long)ctx->function;
375*acfb65feSYang Jihong 
376*acfb65feSYang Jihong 	__builtin_memset(name, 0, sizeof(name));
377*acfb65feSYang Jihong 	bpf_snprintf(name, sizeof(name), "%ps", &func_addr, sizeof(func_addr));
378*acfb65feSYang Jihong 
379*acfb65feSYang Jihong 	return update_timeend_and_name(&perf_kwork_report, &perf_kwork_time,
380*acfb65feSYang Jihong 				       &perf_kwork_names, &key, name);
381*acfb65feSYang Jihong }
382*acfb65feSYang Jihong 
383daf07d22SYang Jihong char LICENSE[] SEC("license") = "Dual BSD/GPL";
384