2019-05-19 13:08:55 +01:00
// SPDX-License-Identifier: GPL-2.0-only
2017-09-25 08:12:05 -07:00
# include "cgroup-internal.h"
# include <linux/sched/cputime.h>
2018-04-26 14:29:05 -07:00
static DEFINE_SPINLOCK ( cgroup_rstat_lock ) ;
2018-04-26 14:29:04 -07:00
static DEFINE_PER_CPU ( raw_spinlock_t , cgroup_rstat_cpu_lock ) ;
2017-09-25 08:12:05 -07:00
2018-04-26 14:29:05 -07:00
static void cgroup_base_stat_flush ( struct cgroup * cgrp , int cpu ) ;
2018-04-26 14:29:04 -07:00
static struct cgroup_rstat_cpu * cgroup_rstat_cpu ( struct cgroup * cgrp , int cpu )
2017-09-25 08:12:05 -07:00
{
2018-04-26 14:29:04 -07:00
return per_cpu_ptr ( cgrp - > rstat_cpu , cpu ) ;
2017-09-25 08:12:05 -07:00
}
/**
2018-04-26 14:29:05 -07:00
* cgroup_rstat_updated - keep track of updated rstat_cpu
2017-09-25 08:12:05 -07:00
* @ cgrp : target cgroup
2018-04-26 14:29:04 -07:00
* @ cpu : cpu on which rstat_cpu was updated
2017-09-25 08:12:05 -07:00
*
2018-04-26 14:29:04 -07:00
* @ cgrp ' s rstat_cpu on @ cpu was updated . Put it on the parent ' s matching
* rstat_cpu - > updated_children list . See the comment on top of
* cgroup_rstat_cpu definition for details .
2017-09-25 08:12:05 -07:00
*/
2018-04-26 14:29:05 -07:00
void cgroup_rstat_updated ( struct cgroup * cgrp , int cpu )
2017-09-25 08:12:05 -07:00
{
2018-04-26 14:29:04 -07:00
raw_spinlock_t * cpu_lock = per_cpu_ptr ( & cgroup_rstat_cpu_lock , cpu ) ;
2017-09-25 08:12:05 -07:00
struct cgroup * parent ;
unsigned long flags ;
2018-04-26 14:29:06 -07:00
/* nothing to do for root */
if ( ! cgroup_parent ( cgrp ) )
return ;
2017-09-25 08:12:05 -07:00
/*
2020-04-09 14:55:35 -04:00
* Speculative already - on - list test . This may race leading to
* temporary inaccuracies , which is fine .
*
2017-09-25 08:12:05 -07:00
* Because @ parent ' s updated_children is terminated with @ parent
* instead of NULL , we can tell whether @ cgrp is on the list by
* testing the next pointer for NULL .
*/
2018-04-26 14:29:04 -07:00
if ( cgroup_rstat_cpu ( cgrp , cpu ) - > updated_next )
2017-09-25 08:12:05 -07:00
return ;
raw_spin_lock_irqsave ( cpu_lock , flags ) ;
/* put @cgrp and all ancestors on the corresponding updated lists */
for ( parent = cgroup_parent ( cgrp ) ; parent ;
cgrp = parent , parent = cgroup_parent ( cgrp ) ) {
2018-04-26 14:29:04 -07:00
struct cgroup_rstat_cpu * rstatc = cgroup_rstat_cpu ( cgrp , cpu ) ;
struct cgroup_rstat_cpu * prstatc = cgroup_rstat_cpu ( parent , cpu ) ;
2017-09-25 08:12:05 -07:00
/*
* Both additions and removals are bottom - up . If a cgroup
* is already in the tree , all ancestors are .
*/
2018-04-26 14:29:04 -07:00
if ( rstatc - > updated_next )
2017-09-25 08:12:05 -07:00
break ;
2018-04-26 14:29:04 -07:00
rstatc - > updated_next = prstatc - > updated_children ;
prstatc - > updated_children = cgrp ;
2017-09-25 08:12:05 -07:00
}
raw_spin_unlock_irqrestore ( cpu_lock , flags ) ;
}
2018-04-26 14:29:05 -07:00
EXPORT_SYMBOL_GPL ( cgroup_rstat_updated ) ;
2017-09-25 08:12:05 -07:00
/**
2018-04-26 14:29:04 -07:00
* cgroup_rstat_cpu_pop_updated - iterate and dismantle rstat_cpu updated tree
2017-09-25 08:12:05 -07:00
* @ pos : current position
* @ root : root of the tree to traversal
* @ cpu : target cpu
*
2018-04-26 14:29:04 -07:00
* Walks the udpated rstat_cpu tree on @ cpu from @ root . % NULL @ pos starts
2017-09-25 08:12:05 -07:00
* the traversal and % NULL return indicates the end . During traversal ,
* each returned cgroup is unlinked from the tree . Must be called with the
2018-04-26 14:29:04 -07:00
* matching cgroup_rstat_cpu_lock held .
2017-09-25 08:12:05 -07:00
*
* The only ordering guarantee is that , for a parent and a child pair
* covered by a given traversal , if a child is visited , its parent is
* guaranteed to be visited afterwards .
*/
2018-04-26 14:29:04 -07:00
static struct cgroup * cgroup_rstat_cpu_pop_updated ( struct cgroup * pos ,
struct cgroup * root , int cpu )
2017-09-25 08:12:05 -07:00
{
2018-04-26 14:29:04 -07:00
struct cgroup_rstat_cpu * rstatc ;
2017-09-25 08:12:05 -07:00
if ( pos = = root )
return NULL ;
/*
* We ' re gonna walk down to the first leaf and visit / remove it . We
* can pick whatever unvisited node as the starting point .
*/
if ( ! pos )
pos = root ;
else
pos = cgroup_parent ( pos ) ;
/* walk down to the first leaf */
while ( true ) {
2018-04-26 14:29:04 -07:00
rstatc = cgroup_rstat_cpu ( pos , cpu ) ;
if ( rstatc - > updated_children = = pos )
2017-09-25 08:12:05 -07:00
break ;
2018-04-26 14:29:04 -07:00
pos = rstatc - > updated_children ;
2017-09-25 08:12:05 -07:00
}
/*
* Unlink @ pos from the tree . As the updated_children list is
* singly linked , we have to walk it to find the removal point .
* However , due to the way we traverse , @ pos will be the first
* child in most cases . The only exception is @ root .
*/
2019-02-15 11:01:31 -08:00
if ( rstatc - > updated_next ) {
struct cgroup * parent = cgroup_parent ( pos ) ;
2018-04-26 14:29:04 -07:00
struct cgroup_rstat_cpu * prstatc = cgroup_rstat_cpu ( parent , cpu ) ;
struct cgroup_rstat_cpu * nrstatc ;
2017-09-25 08:12:05 -07:00
struct cgroup * * nextp ;
2018-04-26 14:29:04 -07:00
nextp = & prstatc - > updated_children ;
2017-09-25 08:12:05 -07:00
while ( true ) {
2018-04-26 14:29:04 -07:00
nrstatc = cgroup_rstat_cpu ( * nextp , cpu ) ;
2017-09-25 08:12:05 -07:00
if ( * nextp = = pos )
break ;
WARN_ON_ONCE ( * nextp = = parent ) ;
2018-04-26 14:29:04 -07:00
nextp = & nrstatc - > updated_next ;
2017-09-25 08:12:05 -07:00
}
2018-04-26 14:29:04 -07:00
* nextp = rstatc - > updated_next ;
rstatc - > updated_next = NULL ;
2018-04-26 14:29:05 -07:00
2019-02-15 11:01:31 -08:00
return pos ;
2017-09-25 08:12:05 -07:00
}
2019-02-15 11:01:31 -08:00
/* only happens for @root */
return NULL ;
2017-09-25 08:12:05 -07:00
}
2018-04-26 14:29:05 -07:00
/* see cgroup_rstat_flush() */
2018-04-26 14:29:05 -07:00
static void cgroup_rstat_flush_locked ( struct cgroup * cgrp , bool may_sleep )
__releases ( & cgroup_rstat_lock ) __acquires ( & cgroup_rstat_lock )
2018-04-26 14:29:05 -07:00
{
int cpu ;
2018-04-26 14:29:05 -07:00
lockdep_assert_held ( & cgroup_rstat_lock ) ;
2018-04-26 14:29:05 -07:00
for_each_possible_cpu ( cpu ) {
raw_spinlock_t * cpu_lock = per_cpu_ptr ( & cgroup_rstat_cpu_lock ,
cpu ) ;
struct cgroup * pos = NULL ;
2018-04-26 14:29:05 -07:00
raw_spin_lock ( cpu_lock ) ;
2018-04-26 14:29:05 -07:00
while ( ( pos = cgroup_rstat_cpu_pop_updated ( pos , cgrp , cpu ) ) ) {
struct cgroup_subsys_state * css ;
2018-04-26 14:29:05 -07:00
cgroup_base_stat_flush ( pos , cpu ) ;
2018-04-26 14:29:05 -07:00
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( css , & pos - > rstat_css_list ,
rstat_css_node )
css - > ss - > css_rstat_flush ( css , cpu ) ;
rcu_read_unlock ( ) ;
}
2018-04-26 14:29:05 -07:00
raw_spin_unlock ( cpu_lock ) ;
/* if @may_sleep, play nice and yield if necessary */
if ( may_sleep & & ( need_resched ( ) | |
spin_needbreak ( & cgroup_rstat_lock ) ) ) {
spin_unlock_irq ( & cgroup_rstat_lock ) ;
if ( ! cond_resched ( ) )
cpu_relax ( ) ;
spin_lock_irq ( & cgroup_rstat_lock ) ;
}
2018-04-26 14:29:05 -07:00
}
}
/**
* cgroup_rstat_flush - flush stats in @ cgrp ' s subtree
* @ cgrp : target cgroup
*
* Collect all per - cpu stats in @ cgrp ' s subtree into the global counters
* and propagate them upwards . After this function returns , all cgroups in
* the subtree have up - to - date - > stat .
*
* This also gets all cgroups in the subtree including @ cgrp off the
* - > updated_children lists .
2018-04-26 14:29:05 -07:00
*
* This function may block .
2018-04-26 14:29:05 -07:00
*/
void cgroup_rstat_flush ( struct cgroup * cgrp )
{
2018-04-26 14:29:05 -07:00
might_sleep ( ) ;
spin_lock_irq ( & cgroup_rstat_lock ) ;
cgroup_rstat_flush_locked ( cgrp , true ) ;
spin_unlock_irq ( & cgroup_rstat_lock ) ;
}
/**
* cgroup_rstat_flush_irqsafe - irqsafe version of cgroup_rstat_flush ( )
* @ cgrp : target cgroup
*
* This function can be called from any context .
*/
void cgroup_rstat_flush_irqsafe ( struct cgroup * cgrp )
{
unsigned long flags ;
spin_lock_irqsave ( & cgroup_rstat_lock , flags ) ;
cgroup_rstat_flush_locked ( cgrp , false ) ;
spin_unlock_irqrestore ( & cgroup_rstat_lock , flags ) ;
2018-04-26 14:29:05 -07:00
}
2018-04-26 14:29:05 -07:00
/**
* cgroup_rstat_flush_begin - flush stats in @ cgrp ' s subtree and hold
* @ cgrp : target cgroup
*
* Flush stats in @ cgrp ' s subtree and prevent further flushes . Must be
* paired with cgroup_rstat_flush_release ( ) .
2018-04-26 14:29:05 -07:00
*
* This function may block .
2018-04-26 14:29:05 -07:00
*/
void cgroup_rstat_flush_hold ( struct cgroup * cgrp )
2018-04-26 14:29:05 -07:00
__acquires ( & cgroup_rstat_lock )
2018-04-26 14:29:05 -07:00
{
2018-04-26 14:29:05 -07:00
might_sleep ( ) ;
spin_lock_irq ( & cgroup_rstat_lock ) ;
cgroup_rstat_flush_locked ( cgrp , true ) ;
2018-04-26 14:29:05 -07:00
}
/**
* cgroup_rstat_flush_release - release cgroup_rstat_flush_hold ( )
*/
void cgroup_rstat_flush_release ( void )
2018-04-26 14:29:05 -07:00
__releases ( & cgroup_rstat_lock )
2018-04-26 14:29:05 -07:00
{
2018-04-26 14:29:05 -07:00
spin_unlock_irq ( & cgroup_rstat_lock ) ;
2018-04-26 14:29:05 -07:00
}
2018-04-26 14:29:05 -07:00
int cgroup_rstat_init ( struct cgroup * cgrp )
{
int cpu ;
/* the root cgrp has rstat_cpu preallocated */
if ( ! cgrp - > rstat_cpu ) {
cgrp - > rstat_cpu = alloc_percpu ( struct cgroup_rstat_cpu ) ;
if ( ! cgrp - > rstat_cpu )
return - ENOMEM ;
}
/* ->updated_children list is self terminated */
for_each_possible_cpu ( cpu ) {
struct cgroup_rstat_cpu * rstatc = cgroup_rstat_cpu ( cgrp , cpu ) ;
rstatc - > updated_children = cgrp ;
u64_stats_init ( & rstatc - > bsync ) ;
}
return 0 ;
}
void cgroup_rstat_exit ( struct cgroup * cgrp )
{
int cpu ;
cgroup_rstat_flush ( cgrp ) ;
/* sanity check */
for_each_possible_cpu ( cpu ) {
struct cgroup_rstat_cpu * rstatc = cgroup_rstat_cpu ( cgrp , cpu ) ;
if ( WARN_ON_ONCE ( rstatc - > updated_children ! = cgrp ) | |
WARN_ON_ONCE ( rstatc - > updated_next ) )
return ;
}
free_percpu ( cgrp - > rstat_cpu ) ;
cgrp - > rstat_cpu = NULL ;
}
void __init cgroup_rstat_boot ( void )
{
int cpu ;
for_each_possible_cpu ( cpu )
raw_spin_lock_init ( per_cpu_ptr ( & cgroup_rstat_cpu_lock , cpu ) ) ;
BUG_ON ( cgroup_rstat_init ( & cgrp_dfl_root . cgrp ) ) ;
}
/*
* Functions for cgroup basic resource statistics implemented on top of
* rstat .
*/
2019-11-06 12:49:57 -08:00
static void cgroup_base_stat_add ( struct cgroup_base_stat * dst_bstat ,
struct cgroup_base_stat * src_bstat )
2017-09-25 08:12:05 -07:00
{
2018-04-26 14:29:04 -07:00
dst_bstat - > cputime . utime + = src_bstat - > cputime . utime ;
dst_bstat - > cputime . stime + = src_bstat - > cputime . stime ;
dst_bstat - > cputime . sum_exec_runtime + = src_bstat - > cputime . sum_exec_runtime ;
2017-09-25 08:12:05 -07:00
}
2019-11-06 12:49:57 -08:00
static void cgroup_base_stat_sub ( struct cgroup_base_stat * dst_bstat ,
struct cgroup_base_stat * src_bstat )
{
dst_bstat - > cputime . utime - = src_bstat - > cputime . utime ;
dst_bstat - > cputime . stime - = src_bstat - > cputime . stime ;
dst_bstat - > cputime . sum_exec_runtime - = src_bstat - > cputime . sum_exec_runtime ;
}
2018-04-26 14:29:04 -07:00
static void cgroup_base_stat_flush ( struct cgroup * cgrp , int cpu )
2017-09-25 08:12:05 -07:00
{
struct cgroup * parent = cgroup_parent ( cgrp ) ;
2018-04-26 14:29:04 -07:00
struct cgroup_rstat_cpu * rstatc = cgroup_rstat_cpu ( cgrp , cpu ) ;
2019-11-06 12:49:57 -08:00
struct cgroup_base_stat cur , delta ;
2017-09-25 08:12:05 -07:00
unsigned seq ;
/* fetch the current per-cpu values */
do {
2018-04-26 14:29:04 -07:00
seq = __u64_stats_fetch_begin ( & rstatc - > bsync ) ;
2019-11-06 12:49:57 -08:00
cur . cputime = rstatc - > bstat . cputime ;
2018-04-26 14:29:04 -07:00
} while ( __u64_stats_fetch_retry ( & rstatc - > bsync , seq ) ) ;
2017-09-25 08:12:05 -07:00
2019-11-06 12:49:57 -08:00
/* propagate percpu delta to global */
delta = cur ;
cgroup_base_stat_sub ( & delta , & rstatc - > last_bstat ) ;
cgroup_base_stat_add ( & cgrp - > bstat , & delta ) ;
cgroup_base_stat_add ( & rstatc - > last_bstat , & delta ) ;
/* propagate global delta to parent */
if ( parent ) {
delta = cgrp - > bstat ;
cgroup_base_stat_sub ( & delta , & cgrp - > last_bstat ) ;
cgroup_base_stat_add ( & parent - > bstat , & delta ) ;
cgroup_base_stat_add ( & cgrp - > last_bstat , & delta ) ;
}
2017-09-25 08:12:05 -07:00
}
2018-04-26 14:29:04 -07:00
static struct cgroup_rstat_cpu *
2018-04-26 14:29:04 -07:00
cgroup_base_stat_cputime_account_begin ( struct cgroup * cgrp )
2017-09-25 08:12:05 -07:00
{
2018-04-26 14:29:04 -07:00
struct cgroup_rstat_cpu * rstatc ;
2017-09-25 08:12:05 -07:00
2018-04-26 14:29:04 -07:00
rstatc = get_cpu_ptr ( cgrp - > rstat_cpu ) ;
2018-04-26 14:29:04 -07:00
u64_stats_update_begin ( & rstatc - > bsync ) ;
2018-04-26 14:29:04 -07:00
return rstatc ;
2017-09-25 08:12:05 -07:00
}
2018-04-26 14:29:04 -07:00
static void cgroup_base_stat_cputime_account_end ( struct cgroup * cgrp ,
struct cgroup_rstat_cpu * rstatc )
2017-09-25 08:12:05 -07:00
{
2018-04-26 14:29:04 -07:00
u64_stats_update_end ( & rstatc - > bsync ) ;
2018-04-26 14:29:05 -07:00
cgroup_rstat_updated ( cgrp , smp_processor_id ( ) ) ;
2018-04-26 14:29:04 -07:00
put_cpu_ptr ( rstatc ) ;
2017-09-25 08:12:05 -07:00
}
void __cgroup_account_cputime ( struct cgroup * cgrp , u64 delta_exec )
{
2018-04-26 14:29:04 -07:00
struct cgroup_rstat_cpu * rstatc ;
2017-09-25 08:12:05 -07:00
2018-04-26 14:29:04 -07:00
rstatc = cgroup_base_stat_cputime_account_begin ( cgrp ) ;
rstatc - > bstat . cputime . sum_exec_runtime + = delta_exec ;
cgroup_base_stat_cputime_account_end ( cgrp , rstatc ) ;
2017-09-25 08:12:05 -07:00
}
void __cgroup_account_cputime_field ( struct cgroup * cgrp ,
enum cpu_usage_stat index , u64 delta_exec )
{
2018-04-26 14:29:04 -07:00
struct cgroup_rstat_cpu * rstatc ;
2017-09-25 08:12:05 -07:00
2018-04-26 14:29:04 -07:00
rstatc = cgroup_base_stat_cputime_account_begin ( cgrp ) ;
2017-09-25 08:12:05 -07:00
switch ( index ) {
case CPUTIME_USER :
case CPUTIME_NICE :
2018-04-26 14:29:04 -07:00
rstatc - > bstat . cputime . utime + = delta_exec ;
2017-09-25 08:12:05 -07:00
break ;
case CPUTIME_SYSTEM :
case CPUTIME_IRQ :
case CPUTIME_SOFTIRQ :
2018-04-26 14:29:04 -07:00
rstatc - > bstat . cputime . stime + = delta_exec ;
2017-09-25 08:12:05 -07:00
break ;
default :
break ;
}
2018-04-26 14:29:04 -07:00
cgroup_base_stat_cputime_account_end ( cgrp , rstatc ) ;
2017-09-25 08:12:05 -07:00
}
2018-04-26 14:29:04 -07:00
void cgroup_base_stat_cputime_show ( struct seq_file * seq )
2017-09-25 08:12:05 -07:00
{
struct cgroup * cgrp = seq_css ( seq ) - > cgroup ;
u64 usage , utime , stime ;
if ( ! cgroup_parent ( cgrp ) )
return ;
2018-04-26 14:29:05 -07:00
cgroup_rstat_flush_hold ( cgrp ) ;
2018-04-26 14:29:04 -07:00
usage = cgrp - > bstat . cputime . sum_exec_runtime ;
cputime_adjust ( & cgrp - > bstat . cputime , & cgrp - > prev_cputime , & utime , & stime ) ;
2018-04-26 14:29:05 -07:00
cgroup_rstat_flush_release ( ) ;
2017-09-25 08:12:05 -07:00
do_div ( usage , NSEC_PER_USEC ) ;
do_div ( utime , NSEC_PER_USEC ) ;
do_div ( stime , NSEC_PER_USEC ) ;
2017-10-23 16:18:27 -07:00
seq_printf ( seq , " usage_usec %llu \n "
" user_usec %llu \n "
" system_usec %llu \n " ,
usage , utime , stime ) ;
2017-09-25 08:12:05 -07:00
}