FROMLIST: mm: compaction: support triggering of proactive compaction by user

The proactive compaction[1] gets triggered for every 500msec and run
compaction on the node for COMPACTION_HPAGE_ORDER (usually order-9)
pages based on the value set to sysctl.compaction_proactiveness.
Triggering the compaction for every 500msec in search of
COMPACTION_HPAGE_ORDER pages is not needed for all applications,
especially on the embedded system usecases which may have few MB's of
RAM. Enabling the proactive compaction in its state will endup in
running almost always on such systems.

Other side, proactive compaction can still be very much useful for
getting a set of higher order pages in some controllable
manner(controlled by using the sysctl.compaction_proactiveness). Thus on
systems where enabling the proactive compaction always may proove not
required, can trigger the same from user space on write to its sysctl
interface. As an example, say app launcher decide to launch the memory
heavy application which can be launched fast if it gets more higher
order pages thus launcher can prepare the system in advance by
triggering the proactive compaction from userspace.

This triggering of proactive compaction is done on a write to
sysctl.compaction_proactiveness by user.

[1]https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=facdaa917c4d5a376d09d25865f5a863f906234a

Bug: 186387247
Link: https://lore.kernel.org/patchwork/patch/1438211/
Signed-off-by: Charan Teja Reddy <charante@codeaurora.org>
Change-Id: Ie5208e274b9d7e7354471bb98ff1f10becf93595
This commit is contained in:
Charan Teja Reddy
2021-05-31 16:24:51 +05:30
committed by Sandeep Patil
parent e6c0526092
commit 71fdbce075
5 changed files with 47 additions and 5 deletions

View File

@@ -127,7 +127,8 @@ compaction_proactiveness
This tunable takes a value in the range [0, 100] with a default value of
20. This tunable determines how aggressively compaction is done in the
background. Setting it to 0 disables proactive compaction.
background. On write of non zero value to this tunable will immediately
trigger the proactive compaction. Setting it to 0 disables proactive compaction.
Note that compaction has a non-trivial system-wide impact as pages
belonging to different processes are moved around, which could also lead

View File

@@ -85,6 +85,8 @@ extern int sysctl_compact_memory;
extern unsigned int sysctl_compaction_proactiveness;
extern int sysctl_compaction_handler(struct ctl_table *table, int write,
void *buffer, size_t *length, loff_t *ppos);
extern int compaction_proactiveness_sysctl_handler(struct ctl_table *table,
int write, void *buffer, size_t *length, loff_t *ppos);
extern int sysctl_extfrag_threshold;
extern int sysctl_compact_unevictable_allowed;

View File

@@ -783,6 +783,7 @@ typedef struct pglist_data {
enum zone_type kcompactd_highest_zoneidx;
wait_queue_head_t kcompactd_wait;
struct task_struct *kcompactd;
bool proactive_compact_trigger;
#endif
/*
* This is a per-node reserve of pages that are not available

View File

@@ -2858,7 +2858,7 @@ static struct ctl_table vm_table[] = {
.data = &sysctl_compaction_proactiveness,
.maxlen = sizeof(sysctl_compaction_proactiveness),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.proc_handler = compaction_proactiveness_sysctl_handler,
.extra1 = SYSCTL_ZERO,
.extra2 = &one_hundred,
},

View File

@@ -2650,6 +2650,30 @@ int sysctl_compact_memory;
*/
unsigned int __read_mostly sysctl_compaction_proactiveness = 20;
int compaction_proactiveness_sysctl_handler(struct ctl_table *table, int write,
void *buffer, size_t *length, loff_t *ppos)
{
int rc, nid;
rc = proc_dointvec_minmax(table, write, buffer, length, ppos);
if (rc)
return rc;
if (write && sysctl_compaction_proactiveness) {
for_each_online_node(nid) {
pg_data_t *pgdat = NODE_DATA(nid);
if (pgdat->proactive_compact_trigger)
continue;
pgdat->proactive_compact_trigger = true;
wake_up_interruptible(&pgdat->kcompactd_wait);
}
}
return 0;
}
/*
* This is the entry point for compacting all nodes via
* /proc/sys/vm/compact_memory
@@ -2694,7 +2718,8 @@ void compaction_unregister_node(struct node *node)
static inline bool kcompactd_work_requested(pg_data_t *pgdat)
{
return pgdat->kcompactd_max_order > 0 || kthread_should_stop();
return pgdat->kcompactd_max_order > 0 || kthread_should_stop() ||
pgdat->proactive_compact_trigger;
}
static bool kcompactd_node_suitable(pg_data_t *pgdat)
@@ -2847,7 +2872,8 @@ static int kcompactd(void *p)
trace_mm_compaction_kcompactd_sleep(pgdat->node_id);
if (wait_event_freezable_timeout(pgdat->kcompactd_wait,
kcompactd_work_requested(pgdat),
msecs_to_jiffies(HPAGE_FRAG_CHECK_INTERVAL_MSEC))) {
msecs_to_jiffies(HPAGE_FRAG_CHECK_INTERVAL_MSEC)) &&
!pgdat->proactive_compact_trigger) {
psi_memstall_enter(&pflags);
kcompactd_do_work(pgdat);
@@ -2859,10 +2885,20 @@ static int kcompactd(void *p)
if (should_proactive_compact_node(pgdat)) {
unsigned int prev_score, score;
if (proactive_defer) {
/*
* On wakeup of proactive compaction by sysctl
* write, ignore the accumulated defer score.
* Anyway, if the proactive compaction didn't
* make any progress for the new value, it will
* be further deferred by 2^COMPACT_MAX_DEFER_SHIFT
* times.
*/
if (proactive_defer &&
!pgdat->proactive_compact_trigger) {
proactive_defer--;
continue;
}
prev_score = fragmentation_score_node(pgdat);
proactive_compact_node(pgdat);
score = fragmentation_score_node(pgdat);
@@ -2873,6 +2909,8 @@ static int kcompactd(void *p)
proactive_defer = score < prev_score ?
0 : 1 << COMPACT_MAX_DEFER_SHIFT;
}
if (pgdat->proactive_compact_trigger)
pgdat->proactive_compact_trigger = false;
}
return 0;