mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 13:55:32 +00:00
![Suren Baghdasaryan](/assets/img/avatar_default.png)
Patch series "psi: pressure stall monitors", v6. This is a respin of: https://lwn.net/ml/linux-kernel/20190308184311.144521-1-surenb%40google.com/ Android is adopting psi to detect and remedy memory pressure that results in stuttering and decreased responsiveness on mobile devices. Psi gives us the stall information, but because we're dealing with latencies in the millisecond range, periodically reading the pressure files to detect stalls in a timely fashion is not feasible. Psi also doesn't aggregate its averages at a high-enough frequency right now. This patch series extends the psi interface such that users can configure sensitive latency thresholds and use poll() and friends to be notified when these are breached. As high-frequency aggregation is costly, it implements an aggregation method that is optimized for fast, short-interval averaging, and makes the aggregation frequency adaptive, such that high-frequency updates only happen while monitored stall events are actively occurring. With these patches applied, Android can monitor for, and ward off, mounting memory shortages before they cause problems for the user. For example, using memory stall monitors in userspace low memory killer daemon (lmkd) we can detect mounting pressure and kill less important processes before device becomes visibly sluggish. In our memory stress testing psi memory monitors produce roughly 10x less false positives compared to vmpressure signals. Having ability to specify multiple triggers for the same psi metric allows other parts of Android framework to monitor memory state of the device and act accordingly. The new interface is straight-forward. The user opens one of the pressure files for writing and writes a trigger description into the file descriptor that defines the stall state - some or full, and the maximum stall time over a given window of time. E.g.: /* Signal when stall time exceeds 100ms of a 1s window */ char trigger[] = "full 100000 1000000" fd = open("/proc/pressure/memory") write(fd, trigger, sizeof(trigger)) while (poll() >= 0) { ... }; close(fd); When the monitored stall state is entered, psi adapts its aggregation frequency according to what the configured time window requires in order to emit event signals in a timely fashion. Once the stalling subsides, aggregation reverts back to normal. The trigger is associated with the open file descriptor. To stop monitoring, the user only needs to close the file descriptor and the trigger is discarded. Patches 1-6 prepare the psi code for polling support. Patch 7 implements the adaptive polling logic, the pressure growth detection optimized for short intervals, and hooks up write() and poll() on the pressure files. The patches were developed in collaboration with Johannes Weiner. This patch (of 7): The psi monitoring patches will need to determine the same states as record_times(). To avoid calculating them twice, maintain a state mask that can be consulted cheaply. Do this in a separate patch to keep the churn in the main feature patch at a minimum. This adds 4-byte state_mask member into psi_group_cpu struct which results in its first cacheline-aligned part becoming 52 bytes long. Add explicit values to enumeration element counters that affect psi_group_cpu struct size. Link: http://lkml.kernel.org/r/20190124211518.244221-4-surenb@google.com Signed-off-by: Suren Baghdasaryan <surenb@google.com> Acked-by: Johannes Weiner <hannes@cmpxchg.org> Cc: Dennis Zhou <dennis@kernel.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Jens Axboe <axboe@kernel.dk> Cc: Li Zefan <lizefan@huawei.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Tejun Heo <tj@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
95 lines
2 KiB
C
95 lines
2 KiB
C
#ifndef _LINUX_PSI_TYPES_H
|
|
#define _LINUX_PSI_TYPES_H
|
|
|
|
#include <linux/seqlock.h>
|
|
#include <linux/types.h>
|
|
|
|
#ifdef CONFIG_PSI
|
|
|
|
/* Tracked task states */
|
|
enum psi_task_count {
|
|
NR_IOWAIT,
|
|
NR_MEMSTALL,
|
|
NR_RUNNING,
|
|
NR_PSI_TASK_COUNTS = 3,
|
|
};
|
|
|
|
/* Task state bitmasks */
|
|
#define TSK_IOWAIT (1 << NR_IOWAIT)
|
|
#define TSK_MEMSTALL (1 << NR_MEMSTALL)
|
|
#define TSK_RUNNING (1 << NR_RUNNING)
|
|
|
|
/* Resources that workloads could be stalled on */
|
|
enum psi_res {
|
|
PSI_IO,
|
|
PSI_MEM,
|
|
PSI_CPU,
|
|
NR_PSI_RESOURCES = 3,
|
|
};
|
|
|
|
/*
|
|
* Pressure states for each resource:
|
|
*
|
|
* SOME: Stalled tasks & working tasks
|
|
* FULL: Stalled tasks & no working tasks
|
|
*/
|
|
enum psi_states {
|
|
PSI_IO_SOME,
|
|
PSI_IO_FULL,
|
|
PSI_MEM_SOME,
|
|
PSI_MEM_FULL,
|
|
PSI_CPU_SOME,
|
|
/* Only per-CPU, to weigh the CPU in the global average: */
|
|
PSI_NONIDLE,
|
|
NR_PSI_STATES = 6,
|
|
};
|
|
|
|
struct psi_group_cpu {
|
|
/* 1st cacheline updated by the scheduler */
|
|
|
|
/* Aggregator needs to know of concurrent changes */
|
|
seqcount_t seq ____cacheline_aligned_in_smp;
|
|
|
|
/* States of the tasks belonging to this group */
|
|
unsigned int tasks[NR_PSI_TASK_COUNTS];
|
|
|
|
/* Aggregate pressure state derived from the tasks */
|
|
u32 state_mask;
|
|
|
|
/* Period time sampling buckets for each state of interest (ns) */
|
|
u32 times[NR_PSI_STATES];
|
|
|
|
/* Time of last task change in this group (rq_clock) */
|
|
u64 state_start;
|
|
|
|
/* 2nd cacheline updated by the aggregator */
|
|
|
|
/* Delta detection against the sampling buckets */
|
|
u32 times_prev[NR_PSI_STATES] ____cacheline_aligned_in_smp;
|
|
};
|
|
|
|
struct psi_group {
|
|
/* Protects data updated during an aggregation */
|
|
struct mutex stat_lock;
|
|
|
|
/* Per-cpu task state & time tracking */
|
|
struct psi_group_cpu __percpu *pcpu;
|
|
|
|
/* Periodic aggregation state */
|
|
u64 total_prev[NR_PSI_STATES - 1];
|
|
u64 last_update;
|
|
u64 next_update;
|
|
struct delayed_work clock_work;
|
|
|
|
/* Total stall times and sampled pressure averages */
|
|
u64 total[NR_PSI_STATES - 1];
|
|
unsigned long avg[NR_PSI_STATES - 1][3];
|
|
};
|
|
|
|
#else /* CONFIG_PSI */
|
|
|
|
struct psi_group { };
|
|
|
|
#endif /* CONFIG_PSI */
|
|
|
|
#endif /* _LINUX_PSI_TYPES_H */
|