mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-19 12:00:00 +00:00
cgroup/cpuset: move memory_pressure to cpuset-v1.c
Collection of memory_pressure can be enabled by writing 1 to the cpuset file 'memory_pressure_enabled', which is only for cpuset-v1. Therefore, move the corresponding code to cpuset-v1.c. Currently, the 'fmeter_init' and 'fmeter_getrate' functions are called at cpuset.c, so expose them to cpuset.c. Signed-off-by: Chen Ridong <chenridong@huawei.com> Acked-by: Waiman Long <longman@redhat.com> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
parent
619a33efa0
commit
49434094ef
@ -238,4 +238,11 @@ static inline int is_spread_slab(const struct cpuset *cs)
|
||||
return test_bit(CS_SPREAD_SLAB, &cs->flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* cpuset-v1.c
|
||||
*/
|
||||
|
||||
void fmeter_init(struct fmeter *fmp);
|
||||
int fmeter_getrate(struct fmeter *fmp);
|
||||
|
||||
#endif /* __CPUSET_INTERNAL_H */
|
||||
|
@ -1,3 +1,137 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "cpuset-internal.h"
|
||||
|
||||
/*
|
||||
* Frequency meter - How fast is some event occurring?
|
||||
*
|
||||
* These routines manage a digitally filtered, constant time based,
|
||||
* event frequency meter. There are four routines:
|
||||
* fmeter_init() - initialize a frequency meter.
|
||||
* fmeter_markevent() - called each time the event happens.
|
||||
* fmeter_getrate() - returns the recent rate of such events.
|
||||
* fmeter_update() - internal routine used to update fmeter.
|
||||
*
|
||||
* A common data structure is passed to each of these routines,
|
||||
* which is used to keep track of the state required to manage the
|
||||
* frequency meter and its digital filter.
|
||||
*
|
||||
* The filter works on the number of events marked per unit time.
|
||||
* The filter is single-pole low-pass recursive (IIR). The time unit
|
||||
* is 1 second. Arithmetic is done using 32-bit integers scaled to
|
||||
* simulate 3 decimal digits of precision (multiplied by 1000).
|
||||
*
|
||||
* With an FM_COEF of 933, and a time base of 1 second, the filter
|
||||
* has a half-life of 10 seconds, meaning that if the events quit
|
||||
* happening, then the rate returned from the fmeter_getrate()
|
||||
* will be cut in half each 10 seconds, until it converges to zero.
|
||||
*
|
||||
* It is not worth doing a real infinitely recursive filter. If more
|
||||
* than FM_MAXTICKS ticks have elapsed since the last filter event,
|
||||
* just compute FM_MAXTICKS ticks worth, by which point the level
|
||||
* will be stable.
|
||||
*
|
||||
* Limit the count of unprocessed events to FM_MAXCNT, so as to avoid
|
||||
* arithmetic overflow in the fmeter_update() routine.
|
||||
*
|
||||
* Given the simple 32 bit integer arithmetic used, this meter works
|
||||
* best for reporting rates between one per millisecond (msec) and
|
||||
* one per 32 (approx) seconds. At constant rates faster than one
|
||||
* per msec it maxes out at values just under 1,000,000. At constant
|
||||
* rates between one per msec, and one per second it will stabilize
|
||||
* to a value N*1000, where N is the rate of events per second.
|
||||
* At constant rates between one per second and one per 32 seconds,
|
||||
* it will be choppy, moving up on the seconds that have an event,
|
||||
* and then decaying until the next event. At rates slower than
|
||||
* about one in 32 seconds, it decays all the way back to zero between
|
||||
* each event.
|
||||
*/
|
||||
|
||||
#define FM_COEF 933 /* coefficient for half-life of 10 secs */
|
||||
#define FM_MAXTICKS ((u32)99) /* useless computing more ticks than this */
|
||||
#define FM_MAXCNT 1000000 /* limit cnt to avoid overflow */
|
||||
#define FM_SCALE 1000 /* faux fixed point scale */
|
||||
|
||||
/* Initialize a frequency meter */
|
||||
void fmeter_init(struct fmeter *fmp)
|
||||
{
|
||||
fmp->cnt = 0;
|
||||
fmp->val = 0;
|
||||
fmp->time = 0;
|
||||
spin_lock_init(&fmp->lock);
|
||||
}
|
||||
|
||||
/* Internal meter update - process cnt events and update value */
|
||||
static void fmeter_update(struct fmeter *fmp)
|
||||
{
|
||||
time64_t now;
|
||||
u32 ticks;
|
||||
|
||||
now = ktime_get_seconds();
|
||||
ticks = now - fmp->time;
|
||||
|
||||
if (ticks == 0)
|
||||
return;
|
||||
|
||||
ticks = min(FM_MAXTICKS, ticks);
|
||||
while (ticks-- > 0)
|
||||
fmp->val = (FM_COEF * fmp->val) / FM_SCALE;
|
||||
fmp->time = now;
|
||||
|
||||
fmp->val += ((FM_SCALE - FM_COEF) * fmp->cnt) / FM_SCALE;
|
||||
fmp->cnt = 0;
|
||||
}
|
||||
|
||||
/* Process any previous ticks, then bump cnt by one (times scale). */
|
||||
static void fmeter_markevent(struct fmeter *fmp)
|
||||
{
|
||||
spin_lock(&fmp->lock);
|
||||
fmeter_update(fmp);
|
||||
fmp->cnt = min(FM_MAXCNT, fmp->cnt + FM_SCALE);
|
||||
spin_unlock(&fmp->lock);
|
||||
}
|
||||
|
||||
/* Process any previous ticks, then return current value. */
|
||||
int fmeter_getrate(struct fmeter *fmp)
|
||||
{
|
||||
int val;
|
||||
|
||||
spin_lock(&fmp->lock);
|
||||
fmeter_update(fmp);
|
||||
val = fmp->val;
|
||||
spin_unlock(&fmp->lock);
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Collection of memory_pressure is suppressed unless
|
||||
* this flag is enabled by writing "1" to the special
|
||||
* cpuset file 'memory_pressure_enabled' in the root cpuset.
|
||||
*/
|
||||
|
||||
int cpuset_memory_pressure_enabled __read_mostly;
|
||||
|
||||
/*
|
||||
* __cpuset_memory_pressure_bump - keep stats of per-cpuset reclaims.
|
||||
*
|
||||
* Keep a running average of the rate of synchronous (direct)
|
||||
* page reclaim efforts initiated by tasks in each cpuset.
|
||||
*
|
||||
* This represents the rate at which some task in the cpuset
|
||||
* ran low on memory on all nodes it was allowed to use, and
|
||||
* had to enter the kernels page reclaim code in an effort to
|
||||
* create more free memory by tossing clean pages or swapping
|
||||
* or writing dirty pages.
|
||||
*
|
||||
* Display to user space in the per-cpuset read-only file
|
||||
* "memory_pressure". Value displayed is an integer
|
||||
* representing the recent rate of entry into the synchronous
|
||||
* (direct) page reclaim by any task attached to the cpuset.
|
||||
*/
|
||||
|
||||
void __cpuset_memory_pressure_bump(void)
|
||||
{
|
||||
rcu_read_lock();
|
||||
fmeter_markevent(&task_cs(current)->fmeter);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
@ -2996,107 +2996,6 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Frequency meter - How fast is some event occurring?
|
||||
*
|
||||
* These routines manage a digitally filtered, constant time based,
|
||||
* event frequency meter. There are four routines:
|
||||
* fmeter_init() - initialize a frequency meter.
|
||||
* fmeter_markevent() - called each time the event happens.
|
||||
* fmeter_getrate() - returns the recent rate of such events.
|
||||
* fmeter_update() - internal routine used to update fmeter.
|
||||
*
|
||||
* A common data structure is passed to each of these routines,
|
||||
* which is used to keep track of the state required to manage the
|
||||
* frequency meter and its digital filter.
|
||||
*
|
||||
* The filter works on the number of events marked per unit time.
|
||||
* The filter is single-pole low-pass recursive (IIR). The time unit
|
||||
* is 1 second. Arithmetic is done using 32-bit integers scaled to
|
||||
* simulate 3 decimal digits of precision (multiplied by 1000).
|
||||
*
|
||||
* With an FM_COEF of 933, and a time base of 1 second, the filter
|
||||
* has a half-life of 10 seconds, meaning that if the events quit
|
||||
* happening, then the rate returned from the fmeter_getrate()
|
||||
* will be cut in half each 10 seconds, until it converges to zero.
|
||||
*
|
||||
* It is not worth doing a real infinitely recursive filter. If more
|
||||
* than FM_MAXTICKS ticks have elapsed since the last filter event,
|
||||
* just compute FM_MAXTICKS ticks worth, by which point the level
|
||||
* will be stable.
|
||||
*
|
||||
* Limit the count of unprocessed events to FM_MAXCNT, so as to avoid
|
||||
* arithmetic overflow in the fmeter_update() routine.
|
||||
*
|
||||
* Given the simple 32 bit integer arithmetic used, this meter works
|
||||
* best for reporting rates between one per millisecond (msec) and
|
||||
* one per 32 (approx) seconds. At constant rates faster than one
|
||||
* per msec it maxes out at values just under 1,000,000. At constant
|
||||
* rates between one per msec, and one per second it will stabilize
|
||||
* to a value N*1000, where N is the rate of events per second.
|
||||
* At constant rates between one per second and one per 32 seconds,
|
||||
* it will be choppy, moving up on the seconds that have an event,
|
||||
* and then decaying until the next event. At rates slower than
|
||||
* about one in 32 seconds, it decays all the way back to zero between
|
||||
* each event.
|
||||
*/
|
||||
|
||||
#define FM_COEF 933 /* coefficient for half-life of 10 secs */
|
||||
#define FM_MAXTICKS ((u32)99) /* useless computing more ticks than this */
|
||||
#define FM_MAXCNT 1000000 /* limit cnt to avoid overflow */
|
||||
#define FM_SCALE 1000 /* faux fixed point scale */
|
||||
|
||||
/* Initialize a frequency meter */
|
||||
static void fmeter_init(struct fmeter *fmp)
|
||||
{
|
||||
fmp->cnt = 0;
|
||||
fmp->val = 0;
|
||||
fmp->time = 0;
|
||||
spin_lock_init(&fmp->lock);
|
||||
}
|
||||
|
||||
/* Internal meter update - process cnt events and update value */
|
||||
static void fmeter_update(struct fmeter *fmp)
|
||||
{
|
||||
time64_t now;
|
||||
u32 ticks;
|
||||
|
||||
now = ktime_get_seconds();
|
||||
ticks = now - fmp->time;
|
||||
|
||||
if (ticks == 0)
|
||||
return;
|
||||
|
||||
ticks = min(FM_MAXTICKS, ticks);
|
||||
while (ticks-- > 0)
|
||||
fmp->val = (FM_COEF * fmp->val) / FM_SCALE;
|
||||
fmp->time = now;
|
||||
|
||||
fmp->val += ((FM_SCALE - FM_COEF) * fmp->cnt) / FM_SCALE;
|
||||
fmp->cnt = 0;
|
||||
}
|
||||
|
||||
/* Process any previous ticks, then bump cnt by one (times scale). */
|
||||
static void fmeter_markevent(struct fmeter *fmp)
|
||||
{
|
||||
spin_lock(&fmp->lock);
|
||||
fmeter_update(fmp);
|
||||
fmp->cnt = min(FM_MAXCNT, fmp->cnt + FM_SCALE);
|
||||
spin_unlock(&fmp->lock);
|
||||
}
|
||||
|
||||
/* Process any previous ticks, then return current value. */
|
||||
static int fmeter_getrate(struct fmeter *fmp)
|
||||
{
|
||||
int val;
|
||||
|
||||
spin_lock(&fmp->lock);
|
||||
fmeter_update(fmp);
|
||||
val = fmp->val;
|
||||
spin_unlock(&fmp->lock);
|
||||
return val;
|
||||
}
|
||||
|
||||
static struct cpuset *cpuset_attach_old_cs;
|
||||
|
||||
/*
|
||||
@ -4793,39 +4692,6 @@ void cpuset_print_current_mems_allowed(void)
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* Collection of memory_pressure is suppressed unless
|
||||
* this flag is enabled by writing "1" to the special
|
||||
* cpuset file 'memory_pressure_enabled' in the root cpuset.
|
||||
*/
|
||||
|
||||
int cpuset_memory_pressure_enabled __read_mostly;
|
||||
|
||||
/*
|
||||
* __cpuset_memory_pressure_bump - keep stats of per-cpuset reclaims.
|
||||
*
|
||||
* Keep a running average of the rate of synchronous (direct)
|
||||
* page reclaim efforts initiated by tasks in each cpuset.
|
||||
*
|
||||
* This represents the rate at which some task in the cpuset
|
||||
* ran low on memory on all nodes it was allowed to use, and
|
||||
* had to enter the kernels page reclaim code in an effort to
|
||||
* create more free memory by tossing clean pages or swapping
|
||||
* or writing dirty pages.
|
||||
*
|
||||
* Display to user space in the per-cpuset read-only file
|
||||
* "memory_pressure". Value displayed is an integer
|
||||
* representing the recent rate of entry into the synchronous
|
||||
* (direct) page reclaim by any task attached to the cpuset.
|
||||
*/
|
||||
|
||||
void __cpuset_memory_pressure_bump(void)
|
||||
{
|
||||
rcu_read_lock();
|
||||
fmeter_markevent(&task_cs(current)->fmeter);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_PID_CPUSET
|
||||
/*
|
||||
* proc_cpuset_show()
|
||||
|
Loading…
x
Reference in New Issue
Block a user