2019-05-19 15:51:55 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2006-07-14 00:24:36 -07:00
/* delayacct.c - per-task delay accounting
*
* Copyright ( C ) Shailabh Nagar , IBM Corp . 2006
*/
# include <linux/sched.h>
2017-02-04 01:20:53 +01:00
# include <linux/sched/task.h>
2017-02-05 11:48:36 +01:00
# include <linux/sched/cputime.h>
2021-05-04 22:43:48 +02:00
# include <linux/sched/clock.h>
2006-07-14 00:24:36 -07:00
# include <linux/slab.h>
2009-09-18 23:55:55 +04:00
# include <linux/taskstats.h>
2006-07-14 00:24:36 -07:00
# include <linux/sysctl.h>
# include <linux/delayacct.h>
2011-07-11 15:28:14 -04:00
# include <linux/module.h>
2006-07-14 00:24:36 -07:00
2021-05-04 22:43:32 +02:00
DEFINE_STATIC_KEY_FALSE ( delayacct_key ) ;
int delayacct_on __read_mostly ; /* Delay accounting turned on/off */
2006-12-06 20:33:20 -08:00
struct kmem_cache * delayacct_cache ;
2006-07-14 00:24:36 -07:00
2021-05-10 14:01:00 +02:00
static void set_delayacct ( bool enabled )
{
if ( enabled ) {
static_branch_enable ( & delayacct_key ) ;
delayacct_on = 1 ;
} else {
delayacct_on = 0 ;
static_branch_disable ( & delayacct_key ) ;
}
}
2021-05-04 22:43:32 +02:00
static int __init delayacct_setup_enable ( char * str )
2006-07-14 00:24:36 -07:00
{
2021-05-04 22:43:32 +02:00
delayacct_on = 1 ;
2006-07-14 00:24:36 -07:00
return 1 ;
}
2021-05-04 22:43:32 +02:00
__setup ( " delayacct " , delayacct_setup_enable ) ;
2006-07-14 00:24:36 -07:00
void delayacct_init ( void )
{
2016-01-14 15:18:21 -08:00
delayacct_cache = KMEM_CACHE ( task_delay_info , SLAB_PANIC | SLAB_ACCOUNT ) ;
2006-07-14 00:24:36 -07:00
delayacct_tsk_init ( & init_task ) ;
2021-05-10 14:01:00 +02:00
set_delayacct ( delayacct_on ) ;
}
# ifdef CONFIG_PROC_SYSCTL
2022-02-18 18:59:36 +08:00
static int sysctl_delayacct ( struct ctl_table * table , int write , void * buffer ,
2021-05-10 14:01:00 +02:00
size_t * lenp , loff_t * ppos )
{
int state = delayacct_on ;
struct ctl_table t ;
int err ;
if ( write & & ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
t = * table ;
t . data = & state ;
err = proc_dointvec_minmax ( & t , write , buffer , lenp , ppos ) ;
if ( err < 0 )
return err ;
if ( write )
set_delayacct ( state ) ;
return err ;
2006-07-14 00:24:36 -07:00
}
2022-02-18 18:59:36 +08:00
static struct ctl_table kern_delayacct_table [ ] = {
{
. procname = " task_delayacct " ,
. data = NULL ,
. maxlen = sizeof ( unsigned int ) ,
. mode = 0644 ,
. proc_handler = sysctl_delayacct ,
. extra1 = SYSCTL_ZERO ,
. extra2 = SYSCTL_ONE ,
} ,
{ }
} ;
static __init int kernel_delayacct_sysctls_init ( void )
{
register_sysctl_init ( " kernel " , kern_delayacct_table ) ;
return 0 ;
}
late_initcall ( kernel_delayacct_sysctls_init ) ;
2021-05-10 14:01:00 +02:00
# endif
2006-07-14 00:24:36 -07:00
void __delayacct_tsk_init ( struct task_struct * tsk )
{
2006-12-06 20:33:17 -08:00
tsk - > delays = kmem_cache_zalloc ( delayacct_cache , GFP_KERNEL ) ;
2006-07-14 00:24:36 -07:00
if ( tsk - > delays )
2018-04-23 18:10:23 +02:00
raw_spin_lock_init ( & tsk - > delays - > lock ) ;
2006-07-14 00:24:36 -07:00
}
/*
2014-07-16 21:04:35 +00:00
* Finish delay accounting for a statistic using its timestamps ( @ start ) ,
* accumalator ( @ total ) and @ count
2006-07-14 00:24:36 -07:00
*/
2021-05-04 22:43:48 +02:00
static void delayacct_end ( raw_spinlock_t * lock , u64 * start , u64 * total , u32 * count )
2006-07-14 00:24:36 -07:00
{
2021-05-04 22:43:48 +02:00
s64 ns = local_clock ( ) - * start ;
2006-11-05 23:52:10 -08:00
unsigned long flags ;
2006-07-14 00:24:36 -07:00
2014-07-16 21:04:35 +00:00
if ( ns > 0 ) {
2018-04-23 18:10:23 +02:00
raw_spin_lock_irqsave ( lock , flags ) ;
2014-07-16 21:04:35 +00:00
* total + = ns ;
( * count ) + + ;
2018-04-23 18:10:23 +02:00
raw_spin_unlock_irqrestore ( lock , flags ) ;
2014-07-16 21:04:35 +00:00
}
2006-07-14 00:24:36 -07:00
}
2006-07-14 00:24:37 -07:00
void __delayacct_blkio_start ( void )
{
2021-05-04 22:43:48 +02:00
current - > delays - > blkio_start = local_clock ( ) ;
2006-07-14 00:24:37 -07:00
}
2017-12-18 16:15:10 +00:00
/*
* We cannot rely on the ` current ` macro , as we haven ' t yet switched back to
* the process being woken .
*/
void __delayacct_blkio_end ( struct task_struct * p )
2006-07-14 00:24:37 -07:00
{
2022-01-19 18:10:02 -08:00
delayacct_end ( & p - > delays - > lock ,
& p - > delays - > blkio_start ,
& p - > delays - > blkio_delay ,
& p - > delays - > blkio_count ) ;
2006-07-14 00:24:37 -07:00
}
2006-07-14 00:24:41 -07:00
2021-05-04 22:43:32 +02:00
int delayacct_add_tsk ( struct taskstats * d , struct task_struct * tsk )
2006-07-14 00:24:41 -07:00
{
2017-01-31 04:09:29 +01:00
u64 utime , stime , stimescaled , utimescaled ;
2014-07-16 21:04:37 +00:00
unsigned long long t2 , t3 ;
unsigned long flags , t1 ;
s64 tmp ;
2006-07-14 00:24:41 -07:00
2017-01-31 04:09:29 +01:00
task_cputime ( tsk , & utime , & stime ) ;
2014-07-16 21:04:37 +00:00
tmp = ( s64 ) d - > cpu_run_real_total ;
2017-01-31 04:09:29 +01:00
tmp + = utime + stime ;
2006-07-14 00:24:41 -07:00
d - > cpu_run_real_total = ( tmp < ( s64 ) d - > cpu_run_real_total ) ? 0 : tmp ;
2017-01-31 04:09:29 +01:00
task_cputime_scaled ( tsk , & utimescaled , & stimescaled ) ;
2014-07-16 21:04:37 +00:00
tmp = ( s64 ) d - > cpu_scaled_run_real_total ;
2017-01-31 04:09:29 +01:00
tmp + = utimescaled + stimescaled ;
2007-10-18 03:06:34 -07:00
d - > cpu_scaled_run_real_total =
( tmp < ( s64 ) d - > cpu_scaled_run_real_total ) ? 0 : tmp ;
2006-07-14 00:24:41 -07:00
/*
* No locking available for sched_info ( and too expensive to add one )
* Mitigate by taking snapshot of values
*/
2007-10-15 17:00:12 +02:00
t1 = tsk - > sched_info . pcount ;
2006-07-14 00:24:41 -07:00
t2 = tsk - > sched_info . run_delay ;
2008-12-16 23:41:22 -08:00
t3 = tsk - > se . sum_exec_runtime ;
2006-07-14 00:24:41 -07:00
d - > cpu_count + = t1 ;
2007-07-09 18:52:00 +02:00
tmp = ( s64 ) d - > cpu_delay_total + t2 ;
2006-07-14 00:24:41 -07:00
d - > cpu_delay_total = ( tmp < ( s64 ) d - > cpu_delay_total ) ? 0 : tmp ;
2007-07-09 18:52:00 +02:00
tmp = ( s64 ) d - > cpu_run_virtual_total + t3 ;
2006-07-14 00:24:41 -07:00
d - > cpu_run_virtual_total =
( tmp < ( s64 ) d - > cpu_run_virtual_total ) ? 0 : tmp ;
2021-05-04 22:43:32 +02:00
if ( ! tsk - > delays )
return 0 ;
2006-07-14 00:24:41 -07:00
/* zero XXX_total, non-zero XXX_count implies XXX stat overflowed */
2018-04-23 18:10:23 +02:00
raw_spin_lock_irqsave ( & tsk - > delays - > lock , flags ) ;
2006-07-14 00:24:41 -07:00
tmp = d - > blkio_delay_total + tsk - > delays - > blkio_delay ;
d - > blkio_delay_total = ( tmp < d - > blkio_delay_total ) ? 0 : tmp ;
tmp = d - > swapin_delay_total + tsk - > delays - > swapin_delay ;
d - > swapin_delay_total = ( tmp < d - > swapin_delay_total ) ? 0 : tmp ;
2008-07-25 01:48:53 -07:00
tmp = d - > freepages_delay_total + tsk - > delays - > freepages_delay ;
d - > freepages_delay_total = ( tmp < d - > freepages_delay_total ) ? 0 : tmp ;
2018-10-26 15:06:08 -07:00
tmp = d - > thrashing_delay_total + tsk - > delays - > thrashing_delay ;
d - > thrashing_delay_total = ( tmp < d - > thrashing_delay_total ) ? 0 : tmp ;
2022-01-19 18:10:15 -08:00
tmp = d - > compact_delay_total + tsk - > delays - > compact_delay ;
d - > compact_delay_total = ( tmp < d - > compact_delay_total ) ? 0 : tmp ;
2022-06-01 15:55:25 -07:00
tmp = d - > wpcopy_delay_total + tsk - > delays - > wpcopy_delay ;
d - > wpcopy_delay_total = ( tmp < d - > wpcopy_delay_total ) ? 0 : tmp ;
2006-07-14 00:24:41 -07:00
d - > blkio_count + = tsk - > delays - > blkio_count ;
d - > swapin_count + = tsk - > delays - > swapin_count ;
2008-07-25 01:48:53 -07:00
d - > freepages_count + = tsk - > delays - > freepages_count ;
2018-10-26 15:06:08 -07:00
d - > thrashing_count + = tsk - > delays - > thrashing_count ;
2022-01-19 18:10:15 -08:00
d - > compact_count + = tsk - > delays - > compact_count ;
2022-06-01 15:55:25 -07:00
d - > wpcopy_count + = tsk - > delays - > wpcopy_count ;
2018-04-23 18:10:23 +02:00
raw_spin_unlock_irqrestore ( & tsk - > delays - > lock , flags ) ;
2006-07-14 00:24:41 -07:00
return 0 ;
}
2006-07-14 00:24:43 -07:00
__u64 __delayacct_blkio_ticks ( struct task_struct * tsk )
{
__u64 ret ;
2006-11-05 23:52:10 -08:00
unsigned long flags ;
2006-07-14 00:24:43 -07:00
2018-04-23 18:10:23 +02:00
raw_spin_lock_irqsave ( & tsk - > delays - > lock , flags ) ;
2022-01-19 18:10:02 -08:00
ret = nsec_to_clock_t ( tsk - > delays - > blkio_delay ) ;
2018-04-23 18:10:23 +02:00
raw_spin_unlock_irqrestore ( & tsk - > delays - > lock , flags ) ;
2006-07-14 00:24:43 -07:00
return ret ;
}
2008-07-25 01:48:52 -07:00
void __delayacct_freepages_start ( void )
{
2021-05-04 22:43:48 +02:00
current - > delays - > freepages_start = local_clock ( ) ;
2008-07-25 01:48:52 -07:00
}
void __delayacct_freepages_end ( void )
{
2021-05-04 22:43:48 +02:00
delayacct_end ( & current - > delays - > lock ,
& current - > delays - > freepages_start ,
& current - > delays - > freepages_delay ,
& current - > delays - > freepages_count ) ;
2008-07-25 01:48:52 -07:00
}
2022-08-15 07:11:35 +00:00
void __delayacct_thrashing_start ( bool * in_thrashing )
2018-10-26 15:06:08 -07:00
{
2022-08-15 07:11:35 +00:00
* in_thrashing = ! ! current - > in_thrashing ;
if ( * in_thrashing )
return ;
current - > in_thrashing = 1 ;
2021-05-04 22:43:48 +02:00
current - > delays - > thrashing_start = local_clock ( ) ;
2018-10-26 15:06:08 -07:00
}
2022-08-15 07:11:35 +00:00
void __delayacct_thrashing_end ( bool * in_thrashing )
2018-10-26 15:06:08 -07:00
{
2022-08-15 07:11:35 +00:00
if ( * in_thrashing )
return ;
current - > in_thrashing = 0 ;
2018-10-26 15:06:08 -07:00
delayacct_end ( & current - > delays - > lock ,
& current - > delays - > thrashing_start ,
& current - > delays - > thrashing_delay ,
& current - > delays - > thrashing_count ) ;
}
2022-01-19 18:10:02 -08:00
void __delayacct_swapin_start ( void )
{
current - > delays - > swapin_start = local_clock ( ) ;
}
void __delayacct_swapin_end ( void )
{
delayacct_end ( & current - > delays - > lock ,
& current - > delays - > swapin_start ,
& current - > delays - > swapin_delay ,
& current - > delays - > swapin_count ) ;
}
2022-01-19 18:10:15 -08:00
void __delayacct_compact_start ( void )
{
current - > delays - > compact_start = local_clock ( ) ;
}
void __delayacct_compact_end ( void )
{
delayacct_end ( & current - > delays - > lock ,
& current - > delays - > compact_start ,
& current - > delays - > compact_delay ,
& current - > delays - > compact_count ) ;
}
2022-06-01 15:55:25 -07:00
void __delayacct_wpcopy_start ( void )
{
current - > delays - > wpcopy_start = local_clock ( ) ;
}
void __delayacct_wpcopy_end ( void )
{
delayacct_end ( & current - > delays - > lock ,
& current - > delays - > wpcopy_start ,
& current - > delays - > wpcopy_delay ,
& current - > delays - > wpcopy_count ) ;
}