xref: /openbmc/linux/samples/bpf/lathist_kern.c (revision 3677d0a1)
10fb1170eSDaniel Wagner /* Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com
20fb1170eSDaniel Wagner  * Copyright (c) 2015 BMW Car IT GmbH
30fb1170eSDaniel Wagner  *
40fb1170eSDaniel Wagner  * This program is free software; you can redistribute it and/or
50fb1170eSDaniel Wagner  * modify it under the terms of version 2 of the GNU General Public
60fb1170eSDaniel Wagner  * License as published by the Free Software Foundation.
70fb1170eSDaniel Wagner  */
80fb1170eSDaniel Wagner #include <linux/version.h>
90fb1170eSDaniel Wagner #include <linux/ptrace.h>
100fb1170eSDaniel Wagner #include <uapi/linux/bpf.h>
117cf245a3SToke Høiland-Jørgensen #include <bpf/bpf_helpers.h>
120fb1170eSDaniel Wagner 
130fb1170eSDaniel Wagner #define MAX_ENTRIES	20
140fb1170eSDaniel Wagner #define MAX_CPU		4
150fb1170eSDaniel Wagner 
160fb1170eSDaniel Wagner /* We need to stick to static allocated memory (an array instead of
170fb1170eSDaniel Wagner  * hash table) because managing dynamic memory from the
180fb1170eSDaniel Wagner  * trace_preempt_[on|off] tracepoints hooks is not supported.
190fb1170eSDaniel Wagner  */
200fb1170eSDaniel Wagner 
213677d0a1SDaniel T. Lee struct {
223677d0a1SDaniel T. Lee 	__uint(type, BPF_MAP_TYPE_ARRAY);
233677d0a1SDaniel T. Lee 	__type(key, int);
243677d0a1SDaniel T. Lee 	__type(value, u64);
253677d0a1SDaniel T. Lee 	__uint(max_entries, MAX_CPU);
263677d0a1SDaniel T. Lee } my_map SEC(".maps");
270fb1170eSDaniel Wagner 
280fb1170eSDaniel Wagner SEC("kprobe/trace_preempt_off")
bpf_prog1(struct pt_regs * ctx)290fb1170eSDaniel Wagner int bpf_prog1(struct pt_regs *ctx)
300fb1170eSDaniel Wagner {
310fb1170eSDaniel Wagner 	int cpu = bpf_get_smp_processor_id();
320fb1170eSDaniel Wagner 	u64 *ts = bpf_map_lookup_elem(&my_map, &cpu);
330fb1170eSDaniel Wagner 
340fb1170eSDaniel Wagner 	if (ts)
350fb1170eSDaniel Wagner 		*ts = bpf_ktime_get_ns();
360fb1170eSDaniel Wagner 
370fb1170eSDaniel Wagner 	return 0;
380fb1170eSDaniel Wagner }
390fb1170eSDaniel Wagner 
log2(unsigned int v)400fb1170eSDaniel Wagner static unsigned int log2(unsigned int v)
410fb1170eSDaniel Wagner {
420fb1170eSDaniel Wagner 	unsigned int r;
430fb1170eSDaniel Wagner 	unsigned int shift;
440fb1170eSDaniel Wagner 
450fb1170eSDaniel Wagner 	r = (v > 0xFFFF) << 4; v >>= r;
460fb1170eSDaniel Wagner 	shift = (v > 0xFF) << 3; v >>= shift; r |= shift;
470fb1170eSDaniel Wagner 	shift = (v > 0xF) << 2; v >>= shift; r |= shift;
480fb1170eSDaniel Wagner 	shift = (v > 0x3) << 1; v >>= shift; r |= shift;
490fb1170eSDaniel Wagner 	r |= (v >> 1);
500fb1170eSDaniel Wagner 
510fb1170eSDaniel Wagner 	return r;
520fb1170eSDaniel Wagner }
530fb1170eSDaniel Wagner 
log2l(unsigned long v)540fb1170eSDaniel Wagner static unsigned int log2l(unsigned long v)
550fb1170eSDaniel Wagner {
560fb1170eSDaniel Wagner 	unsigned int hi = v >> 32;
570fb1170eSDaniel Wagner 
580fb1170eSDaniel Wagner 	if (hi)
590fb1170eSDaniel Wagner 		return log2(hi) + 32;
600fb1170eSDaniel Wagner 	else
610fb1170eSDaniel Wagner 		return log2(v);
620fb1170eSDaniel Wagner }
630fb1170eSDaniel Wagner 
643677d0a1SDaniel T. Lee struct {
653677d0a1SDaniel T. Lee 	__uint(type, BPF_MAP_TYPE_ARRAY);
663677d0a1SDaniel T. Lee 	__type(key, int);
673677d0a1SDaniel T. Lee 	__type(value, long);
683677d0a1SDaniel T. Lee 	__uint(max_entries, MAX_CPU * MAX_ENTRIES);
693677d0a1SDaniel T. Lee } my_lat SEC(".maps");
700fb1170eSDaniel Wagner 
710fb1170eSDaniel Wagner SEC("kprobe/trace_preempt_on")
bpf_prog2(struct pt_regs * ctx)720fb1170eSDaniel Wagner int bpf_prog2(struct pt_regs *ctx)
730fb1170eSDaniel Wagner {
740fb1170eSDaniel Wagner 	u64 *ts, cur_ts, delta;
750fb1170eSDaniel Wagner 	int key, cpu;
760fb1170eSDaniel Wagner 	long *val;
770fb1170eSDaniel Wagner 
780fb1170eSDaniel Wagner 	cpu = bpf_get_smp_processor_id();
790fb1170eSDaniel Wagner 	ts = bpf_map_lookup_elem(&my_map, &cpu);
800fb1170eSDaniel Wagner 	if (!ts)
810fb1170eSDaniel Wagner 		return 0;
820fb1170eSDaniel Wagner 
830fb1170eSDaniel Wagner 	cur_ts = bpf_ktime_get_ns();
840fb1170eSDaniel Wagner 	delta = log2l(cur_ts - *ts);
850fb1170eSDaniel Wagner 
860fb1170eSDaniel Wagner 	if (delta > MAX_ENTRIES - 1)
870fb1170eSDaniel Wagner 		delta = MAX_ENTRIES - 1;
880fb1170eSDaniel Wagner 
890fb1170eSDaniel Wagner 	key = cpu * MAX_ENTRIES + delta;
900fb1170eSDaniel Wagner 	val = bpf_map_lookup_elem(&my_lat, &key);
910fb1170eSDaniel Wagner 	if (val)
920fb1170eSDaniel Wagner 		__sync_fetch_and_add((long *)val, 1);
930fb1170eSDaniel Wagner 
940fb1170eSDaniel Wagner 	return 0;
950fb1170eSDaniel Wagner 
960fb1170eSDaniel Wagner }
970fb1170eSDaniel Wagner 
980fb1170eSDaniel Wagner char _license[] SEC("license") = "GPL";
990fb1170eSDaniel Wagner u32 _version SEC("version") = LINUX_VERSION_CODE;
100