2020-01-13 10:31:42 +03:00
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
# include "vmlinux.h"
2020-01-20 16:06:44 +03:00
# include <bpf/bpf_helpers.h>
2020-01-13 10:31:42 +03:00
# include "runqslower.h"
# define TASK_RUNNING 0
2020-03-11 07:30:10 +03:00
# define BPF_F_CURRENT_CPU 0xffffffffULL
2020-01-13 10:31:42 +03:00
const volatile __u64 min_us = 0 ;
const volatile pid_t targ_pid = 0 ;
struct {
2021-02-26 02:43:19 +03:00
__uint ( type , BPF_MAP_TYPE_TASK_STORAGE ) ;
__uint ( map_flags , BPF_F_NO_PREALLOC ) ;
__type ( key , int ) ;
2020-01-13 10:31:42 +03:00
__type ( value , u64 ) ;
} start SEC ( " .maps " ) ;
struct {
__uint ( type , BPF_MAP_TYPE_PERF_EVENT_ARRAY ) ;
__uint ( key_size , sizeof ( u32 ) ) ;
__uint ( value_size , sizeof ( u32 ) ) ;
} events SEC ( " .maps " ) ;
/* record enqueue timestamp */
__always_inline
2021-02-26 02:43:19 +03:00
static int trace_enqueue ( struct task_struct * t )
2020-01-13 10:31:42 +03:00
{
2021-02-26 02:43:19 +03:00
u32 pid = t - > pid ;
u64 * ptr ;
2020-01-13 10:31:42 +03:00
if ( ! pid | | ( targ_pid & & targ_pid ! = pid ) )
return 0 ;
2021-02-26 02:43:19 +03:00
ptr = bpf_task_storage_get ( & start , t , 0 ,
BPF_LOCAL_STORAGE_GET_F_CREATE ) ;
if ( ! ptr )
return 0 ;
* ptr = bpf_ktime_get_ns ( ) ;
2020-01-13 10:31:42 +03:00
return 0 ;
}
SEC ( " tp_btf/sched_wakeup " )
int handle__sched_wakeup ( u64 * ctx )
{
/* TP_PROTO(struct task_struct *p) */
struct task_struct * p = ( void * ) ctx [ 0 ] ;
2021-02-26 02:43:19 +03:00
return trace_enqueue ( p ) ;
2020-01-13 10:31:42 +03:00
}
SEC ( " tp_btf/sched_wakeup_new " )
int handle__sched_wakeup_new ( u64 * ctx )
{
/* TP_PROTO(struct task_struct *p) */
struct task_struct * p = ( void * ) ctx [ 0 ] ;
2021-02-26 02:43:19 +03:00
return trace_enqueue ( p ) ;
2020-01-13 10:31:42 +03:00
}
SEC ( " tp_btf/sched_switch " )
int handle__sched_switch ( u64 * ctx )
{
/* TP_PROTO(bool preempt, struct task_struct *prev,
* struct task_struct * next )
*/
struct task_struct * prev = ( struct task_struct * ) ctx [ 1 ] ;
struct task_struct * next = ( struct task_struct * ) ctx [ 2 ] ;
struct event event = { } ;
u64 * tsp , delta_us ;
long state ;
u32 pid ;
/* ivcsw: treat like an enqueue event and store timestamp */
2021-07-07 08:29:14 +03:00
if ( prev - > __state = = TASK_RUNNING )
2021-02-26 02:43:19 +03:00
trace_enqueue ( prev ) ;
2020-01-13 10:31:42 +03:00
pid = next - > pid ;
2021-02-26 02:43:19 +03:00
/* For pid mismatch, save a bpf_task_storage_get */
if ( ! pid | | ( targ_pid & & targ_pid ! = pid ) )
return 0 ;
2020-01-13 10:31:42 +03:00
/* fetch timestamp and calculate delta */
2021-02-26 02:43:19 +03:00
tsp = bpf_task_storage_get ( & start , next , 0 , 0 ) ;
2020-01-13 10:31:42 +03:00
if ( ! tsp )
return 0 ; /* missed enqueue */
delta_us = ( bpf_ktime_get_ns ( ) - * tsp ) / 1000 ;
if ( min_us & & delta_us < = min_us )
return 0 ;
event . pid = pid ;
event . delta_us = delta_us ;
bpf_get_current_comm ( & event . task , sizeof ( event . task ) ) ;
/* output */
bpf_perf_event_output ( ctx , & events , BPF_F_CURRENT_CPU ,
& event , sizeof ( event ) ) ;
2021-02-26 02:43:19 +03:00
bpf_task_storage_delete ( & start , next ) ;
2020-01-13 10:31:42 +03:00
return 0 ;
}
char LICENSE [ ] SEC ( " license " ) = " GPL " ;