- Feb 2025
-
elixir.bootlin.com elixir.bootlin.com
-
pressure = scale - (reclaimed * scale / scanned); pressure = pressure * 100 / scale;
Calculates pressure via reclaim efficiency rather than actual memory pressure.
-
static const unsigned int vmpressure_level_med = 60; static const unsigned int vmpressure_level_critical = 95;
Encoded threshold values - could be machine dependent.
-
static const unsigned long vmpressure_win = SWAP_CLUSTER_MAX * 16;
changed based on machine but also application potentially. Goal is to minimize the number of false positives.
-
-
elixir.bootlin.com elixir.bootlin.com
-
static struct ksm_rmap_item *scan_get_next_rmap_item(struct page **page) {
This method chooses what section to process next by going in the order of the linked list - could be improved by going off historical success rates
-
static ssize_t general_profit_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
Can be used to evaluate most efficient use of ksm
-
if (ksm_run & KSM_RUN_UNMERGE) list_add_tail(&slot->mm_node, &ksm_mm_head.slot.mm_node); else list_add_tail(&slot->mm_node, &ksm_scan.mm_slot->slot.mm_node); spin_unlock(&ksm_mmlist_lock);
Determines where to insert the process in the list of processes.
-
switch (advice) { case MADV_MERGEABLE: if (vma->vm_flags & VM_MERGEABLE) return 0; if (!vma_ksm_compatible(vma)) return 0; if (!test_bit(MMF_VM_MERGEABLE, &mm->flags)) { err = __ksm_enter(mm); if (err) return err; } *vm_flags |= VM_MERGEABLE; break; case MADV_UNMERGEABLE: if (!(*vm_flags & VM_MERGEABLE)) return 0; /* just ignore the advice */ if (vma->anon_vma) { err = unmerge_ksm_pages(vma, start, end, true); if (err) return err; } *vm_flags &= ~VM_MERGEABLE; break; }
Sets whether pages should be merged or unmerged, relies on flags in order to do so.
-
sleep_ms = READ_ONCE(ksm_thread_sleep_millisecs); wait_event_interruptible_timeout(ksm_iter_wait, sleep_ms != READ_ONCE(ksm_thread_sleep_millisecs), msecs_to_jiffies(sleep_ms));
Sleep duration dynamically adjusted, if this value changes while sleeping then it will wake up immediately. But uses intial hardcoded values - potential to change this.
-
set_user_nice(current, 5);
Potentially delays function by setting priority low so that when CPU is too busy, it will get delayed until more space frees up
-
-
elixir.bootlin.com elixir.bootlin.com
-
static void ondemand_readahead(struct readahead_control *ractl, struct folio *folio, unsigned long req_size) {
Function uses heuristics to allocate readahead size when assumed/predicted to be sequential reads. However, mostly in trivial cases so may not be worth changing.
-
expected = round_down(ra->start + ra->size - ra->async_size, 1UL << order);
Assumes sequential access and increases readahead size in expectation.
-
if (new_order < MAX_PAGECACHE_ORDER) {
Adjusts new_order so that it's balanced with the readahead window size while increasing it as much as possible.
-
if (size >= index) size *= 2;
Assumes that there will be a long sequential read - potentially overestimating.
-
if (cur < max / 16) return 4 * cur; if (cur <= max / 2) return 2 * cur;
Set values for scaling readahead window. Might be too minor to need changes though.
-
unsigned long newsize = roundup_pow_of_two(size); if (newsize <= max / 32) newsize = newsize * 4; else if (newsize <= max / 4) newsize = newsize * 2; else newsize = max; return newsize;
These are all heuristics to determine intial readahead size. Trades potentially memory overuse for faster access. Could be changed to not use these hardcoded values.
-
if (unlikely(rac->_workingset))
Heuristic that says _workingset likely isn't set (pages being read aren't likely to be used soon and don't belong to physical memory). When true, stalls current task due to lack of memory (relieves memory pressure)
-