mirror of
https://git.proxmox.com/git/mirror_ubuntu-kernels.git
synced 2026-01-26 15:16:12 +00:00
Introduction ============ This patchset 1) makes the engine for general data access pattern-oriented memory management (DAMOS) be more useful for production environments, and 2) implements a static kernel module for lightweight proactive reclamation using the engine. Proactive Reclamation --------------------- On general memory over-committed systems, proactively reclaiming cold pages helps saving memory and reducing latency spikes that incurred by the direct reclaim or the CPU consumption of kswapd, while incurring only minimal performance degradation[2]. A Free Pages Reporting[8] based memory over-commit virtualization system would be one more specific use case. In the system, the guest VMs reports their free memory to host, and the host reallocates the reported memory to other guests. As a result, the system's memory utilization can be maximized. However, the guests could be not so memory-frugal, because some kernel subsystems and user-space applications are designed to use as much memory as available. Then, guests would report only small amount of free memory to host, results in poor memory utilization. Running the proactive reclamation in such guests could help mitigating this problem. Google has also implemented this idea and using it in their data center. They further proposed upstreaming it in LSFMM'19, and "the general consensus was that, while this sort of proactive reclaim would be useful for a number of users, the cost of this particular solution was too high to consider merging it upstream"[3]. The cost mainly comes from the coldness tracking. Roughly speaking, the implementation periodically scans the 'Accessed' bit of each page. For the reason, the overhead linearly increases as the size of the memory and the scanning frequency grows. As a result, Google is known to dedicating one CPU for the work. That's a reasonable option to someone like Google, but it wouldn't be so to some others. DAMON and DAMOS: An engine for data access pattern-oriented memory management ----------------------------------------------------------------------------- DAMON[4] is a framework for general data access monitoring. Its adaptive monitoring overhead control feature minimizes its monitoring overhead. It also let the upper-bound of the overhead be configurable by clients, regardless of the size of the monitoring target memory. While monitoring 70 GiB memory of a production system every 5 milliseconds, it consumes less than 1% single CPU time. For this, it could sacrify some of the quality of the monitoring results. Nevertheless, the lower-bound of the quality is configurable, and it uses a best-effort algorithm for better quality. Our test results[5] show the quality is practical enough. From the production system monitoring, we were able to find a 4 KiB region in the 70 GiB memory that shows highest access frequency. We normally don't monitor the data access pattern just for fun but to improve something like memory management. Proactive reclamation is one such usage. For such general cases, DAMON provides a feature called DAMon-based Operation Schemes (DAMOS)[6]. It makes DAMON an engine for general data access pattern oriented memory management. Using this, clients can ask DAMON to find memory regions of specific data access pattern and apply some memory management action (e.g., page out, move to head of the LRU list, use huge page, ...). We call the request 'scheme'. Proactive Reclamation on top of DAMON/DAMOS ------------------------------------------- Therefore, by using DAMON for the cold pages detection, the proactive reclamation's monitoring overhead issue can be solved. Actually, we previously implemented a version of proactive reclamation using DAMOS and achieved noticeable improvements with our evaluation setup[5]. Nevertheless, it more for a proof-of-concept, rather than production uses. It supports only virtual address spaces of processes, and require additional tuning efforts for given workloads and the hardware. For the tuning, we introduced a simple auto-tuning user space tool[8]. Google is also known to using a ML-based similar approach for their fleets[2]. But, making it just works with intuitive knobs in the kernel would be helpful for general users. To this end, this patchset improves DAMOS to be ready for such production usages, and implements another version of the proactive reclamation, namely DAMON_RECLAIM, on top of it. DAMOS Improvements: Aggressiveness Control, Prioritization, and Watermarks -------------------------------------------------------------------------- First of all, the current version of DAMOS supports only virtual address spaces. This patchset makes it supports the physical address space for the page out action. Next major problem of the current version of DAMOS is the lack of the aggressiveness control, which can results in arbitrary overhead. For example, if huge memory regions having the data access pattern of interest are found, applying the requested action to all of the regions could incur significant overhead. It can be controlled by tuning the target data access pattern with manual or automated approaches[2,7]. But, some people would prefer the kernel to just work with only intuitive tuning or default values. For such cases, this patchset implements a safeguard, namely time/size quota. Using this, the clients can specify up to how much time can be used for applying the action, and/or up to how much memory regions the action can be applied within a user-specified time duration. A followup question is, to which memory regions should the action applied within the limits? We implement a simple regions prioritization mechanism for each action and make DAMOS to apply the action to high priority regions first. It also allows clients tune the prioritization mechanism to use different weights for size, access frequency, and age of memory regions. This means we could use not only LRU but also LFU or some fancy algorithms like CAR[9] with lightweight overhead. Though DAMON is lightweight, someone would want to remove even the cold pages monitoring overhead when it is unnecessary. Currently, it should manually turned on and off by clients, but some clients would simply want to turn it on and off based on some metrics like free memory ratio or memory fragmentation. For such cases, this patchset implements a watermarks-based automatic activation feature. It allows the clients configure the metric of their interest, and three watermarks of the metric. If the metric is higher than the high watermark or lower than the low watermark, the scheme is deactivated. If the metric is lower than the mid watermark but higher than the low watermark, the scheme is activated. DAMON-based Reclaim ------------------- Using the improved version of DAMOS, this patchset implements a static kernel module called 'damon_reclaim'. It finds memory regions that didn't accessed for specific time duration and page out. Consuming too much CPU for the paging out operations, or doing pageout too frequently can be critical for systems configuring their swap devices with software-defined in-memory block devices like zram/zswap or total number of writes limited devices like SSDs, respectively. To avoid the problems, the time/size quotas can be configured. Under the quotas, it pages out memory regions that didn't accessed longer first. Also, to remove the monitoring overhead under peaceful situation, and to fall back to the LRU-list based page granularity reclamation when it doesn't make progress, the three watermarks based activation mechanism is used, with the free memory ratio as the watermark metric. For convenient configurations, it provides several module parameters. Using these, sysadmins can enable/disable it, and tune its parameters including the coldness identification time threshold, the time/size quotas and the three watermarks. Evaluation ========== In short, DAMON_RECLAIM with 50ms/s time quota and regions prioritization on v5.15-rc5 Linux kernel with ZRAM swap device achieves 38.58% memory saving with only 1.94% runtime overhead. For this, DAMON_RECLAIM consumes only 4.97% of single CPU time. Setup ----- We evaluate DAMON_RECLAIM to show how each of the DAMOS improvements make effect. For this, we measure DAMON_RECLAIM's CPU consumption, entire system memory footprint, total number of major page faults, and runtime of 24 realistic workloads in PARSEC3 and SPLASH-2X benchmark suites on my QEMU/KVM based virtual machine. The virtual machine runs on an i3.metal AWS instance, has 130GiB memory, and runs a linux kernel built on latest -mm tree[1] plus this patchset. It also utilizes a 4 GiB ZRAM swap device. We repeats the measurement 5 times and use averages. [1] https://github.com/hnaz/linux-mm/tree/v5.15-rc5-mmots-2021-10-13-19-55 Detailed Results ---------------- The results are summarized in the below table. With coldness identification threshold of 5 seconds, DAMON_RECLAIM without the time quota-based speed limit achieves 47.21% memory saving, but incur 4.59% runtime slowdown to the workloads on average. For this, DAMON_RECLAIM consumes about 11.28% single CPU time. Applying time quotas of 200ms/s, 50ms/s, and 10ms/s without the regions prioritization reduces the slowdown to 4.89%, 2.65%, and 1.5%, respectively. Time quota of 200ms/s (20%) makes no real change compared to the quota unapplied version, because the quota unapplied version consumes only 11.28% CPU time. DAMON_RECLAIM's CPU utilization also similarly reduced: 11.24%, 5.51%, and 2.01% of single CPU time. That is, the overhead is proportional to the speed limit. Nevertheless, it also reduces the memory saving because it becomes less aggressive. In detail, the three variants show 48.76%, 37.83%, and 7.85% memory saving, respectively. Applying the regions prioritization (page out regions that not accessed longer first within the time quota) further reduces the performance degradation. Runtime slowdowns and total number of major page faults increase has been 4.89%/218,690% -> 4.39%/166,136% (200ms/s), 2.65%/111,886% -> 1.94%/59,053% (50ms/s), and 1.5%/34,973.40% -> 2.08%/8,781.75% (10ms/s). The runtime under 10ms/s time quota has increased with prioritization, but apparently that's under the margin of error. time quota prioritization memory_saving cpu_util slowdown pgmajfaults overhead N N 47.21% 11.28% 4.59% 194,802% 200ms/s N 48.76% 11.24% 4.89% 218,690% 50ms/s N 37.83% 5.51% 2.65% 111,886% 10ms/s N 7.85% 2.01% 1.5% 34,793.40% 200ms/s Y 50.08% 10.38% 4.39% 166,136% 50ms/s Y 38.58% 4.97% 1.94% 59,053% 10ms/s Y 3.63% 1.73% 2.08% 8,781.75% Baseline and Complete Git Trees =============================== The patches are based on the latest -mm tree (v5.15-rc5-mmots-2021-10-13-19-55). You can also clone the complete git tree from: $ git clone git://github.com/sjp38/linux -b damon_reclaim/patches/v1 The web is also available: https://git.kernel.org/pub/scm/linux/kernel/git/sj/linux.git/tag/?h=damon_reclaim/patches/v1 Sequence Of Patches =================== The first patch makes DAMOS support the physical address space for the page out action. Following five patches (patches 2-6) implement the time/size quotas. Next four patches (patches 7-10) implement the memory regions prioritization within the limit. Then, three following patches (patches 11-13) implement the watermarks-based schemes activation. Finally, the last two patches (patches 14-15) implement and document the DAMON-based reclamation using the advanced DAMOS. [1] https://www.kernel.org/doc/html/v5.15-rc1/vm/damon/index.html [2] https://research.google/pubs/pub48551/ [3] https://lwn.net/Articles/787611/ [4] https://damonitor.github.io [5] https://damonitor.github.io/doc/html/latest/vm/damon/eval.html [6] https://lore.kernel.org/linux-mm/20211001125604.29660-1-sj@kernel.org/ [7] https://github.com/awslabs/damoos [8] https://www.kernel.org/doc/html/latest/vm/free_page_reporting.html [9] https://www.usenix.org/conference/fast-04/car-clock-adaptive-replacement This patch (of 15): This makes the DAMON primitives for physical address space support the pageout action for DAMON-based Operation Schemes. With this commit, hence, users can easily implement system-level data access-aware reclamations using DAMOS. [sj@kernel.org: fix missing-prototype build warning] Link: https://lkml.kernel.org/r/20211025064220.13904-1-sj@kernel.org Link: https://lkml.kernel.org/r/20211019150731.16699-1-sj@kernel.org Link: https://lkml.kernel.org/r/20211019150731.16699-2-sj@kernel.org Signed-off-by: SeongJae Park <sj@kernel.org> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com> Cc: Amit Shah <amit@kernel.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Jonathan Corbet <corbet@lwn.net> Cc: David Hildenbrand <david@redhat.com> Cc: David Woodhouse <dwmw@amazon.com> Cc: Marco Elver <elver@google.com> Cc: Leonard Foerster <foersleo@amazon.de> Cc: Greg Thelen <gthelen@google.com> Cc: Markus Boehme <markubo@amazon.de> Cc: David Rientjes <rientjes@google.com> Cc: Shakeel Butt <shakeelb@google.com> Cc: Shuah Khan <shuah@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
367 lines
14 KiB
C
367 lines
14 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* DAMON api
|
|
*
|
|
* Author: SeongJae Park <sjpark@amazon.de>
|
|
*/
|
|
|
|
#ifndef _DAMON_H_
|
|
#define _DAMON_H_
|
|
|
|
#include <linux/mutex.h>
|
|
#include <linux/time64.h>
|
|
#include <linux/types.h>
|
|
|
|
/* Minimal region size. Every damon_region is aligned by this. */
|
|
#define DAMON_MIN_REGION PAGE_SIZE
|
|
|
|
/**
|
|
* struct damon_addr_range - Represents an address region of [@start, @end).
|
|
* @start: Start address of the region (inclusive).
|
|
* @end: End address of the region (exclusive).
|
|
*/
|
|
struct damon_addr_range {
|
|
unsigned long start;
|
|
unsigned long end;
|
|
};
|
|
|
|
/**
|
|
* struct damon_region - Represents a monitoring target region.
|
|
* @ar: The address range of the region.
|
|
* @sampling_addr: Address of the sample for the next access check.
|
|
* @nr_accesses: Access frequency of this region.
|
|
* @list: List head for siblings.
|
|
* @age: Age of this region.
|
|
*
|
|
* @age is initially zero, increased for each aggregation interval, and reset
|
|
* to zero again if the access frequency is significantly changed. If two
|
|
* regions are merged into a new region, both @nr_accesses and @age of the new
|
|
* region are set as region size-weighted average of those of the two regions.
|
|
*/
|
|
struct damon_region {
|
|
struct damon_addr_range ar;
|
|
unsigned long sampling_addr;
|
|
unsigned int nr_accesses;
|
|
struct list_head list;
|
|
|
|
unsigned int age;
|
|
/* private: Internal value for age calculation. */
|
|
unsigned int last_nr_accesses;
|
|
};
|
|
|
|
/**
|
|
* struct damon_target - Represents a monitoring target.
|
|
* @id: Unique identifier for this target.
|
|
* @nr_regions: Number of monitoring target regions of this target.
|
|
* @regions_list: Head of the monitoring target regions of this target.
|
|
* @list: List head for siblings.
|
|
*
|
|
* Each monitoring context could have multiple targets. For example, a context
|
|
* for virtual memory address spaces could have multiple target processes. The
|
|
* @id of each target should be unique among the targets of the context. For
|
|
* example, in the virtual address monitoring context, it could be a pidfd or
|
|
* an address of an mm_struct.
|
|
*/
|
|
struct damon_target {
|
|
unsigned long id;
|
|
unsigned int nr_regions;
|
|
struct list_head regions_list;
|
|
struct list_head list;
|
|
};
|
|
|
|
/**
|
|
* enum damos_action - Represents an action of a Data Access Monitoring-based
|
|
* Operation Scheme.
|
|
*
|
|
* @DAMOS_WILLNEED: Call ``madvise()`` for the region with MADV_WILLNEED.
|
|
* @DAMOS_COLD: Call ``madvise()`` for the region with MADV_COLD.
|
|
* @DAMOS_PAGEOUT: Call ``madvise()`` for the region with MADV_PAGEOUT.
|
|
* @DAMOS_HUGEPAGE: Call ``madvise()`` for the region with MADV_HUGEPAGE.
|
|
* @DAMOS_NOHUGEPAGE: Call ``madvise()`` for the region with MADV_NOHUGEPAGE.
|
|
* @DAMOS_STAT: Do nothing but count the stat.
|
|
*/
|
|
enum damos_action {
|
|
DAMOS_WILLNEED,
|
|
DAMOS_COLD,
|
|
DAMOS_PAGEOUT,
|
|
DAMOS_HUGEPAGE,
|
|
DAMOS_NOHUGEPAGE,
|
|
DAMOS_STAT, /* Do nothing but only record the stat */
|
|
};
|
|
|
|
/**
|
|
* struct damos - Represents a Data Access Monitoring-based Operation Scheme.
|
|
* @min_sz_region: Minimum size of target regions.
|
|
* @max_sz_region: Maximum size of target regions.
|
|
* @min_nr_accesses: Minimum ``->nr_accesses`` of target regions.
|
|
* @max_nr_accesses: Maximum ``->nr_accesses`` of target regions.
|
|
* @min_age_region: Minimum age of target regions.
|
|
* @max_age_region: Maximum age of target regions.
|
|
* @action: &damo_action to be applied to the target regions.
|
|
* @stat_count: Total number of regions that this scheme is applied.
|
|
* @stat_sz: Total size of regions that this scheme is applied.
|
|
* @list: List head for siblings.
|
|
*
|
|
* For each aggregation interval, DAMON applies @action to monitoring target
|
|
* regions fit in the condition and updates the statistics. Note that both
|
|
* the minimums and the maximums are inclusive.
|
|
*/
|
|
struct damos {
|
|
unsigned long min_sz_region;
|
|
unsigned long max_sz_region;
|
|
unsigned int min_nr_accesses;
|
|
unsigned int max_nr_accesses;
|
|
unsigned int min_age_region;
|
|
unsigned int max_age_region;
|
|
enum damos_action action;
|
|
unsigned long stat_count;
|
|
unsigned long stat_sz;
|
|
struct list_head list;
|
|
};
|
|
|
|
struct damon_ctx;
|
|
|
|
/**
|
|
* struct damon_primitive - Monitoring primitives for given use cases.
|
|
*
|
|
* @init: Initialize primitive-internal data structures.
|
|
* @update: Update primitive-internal data structures.
|
|
* @prepare_access_checks: Prepare next access check of target regions.
|
|
* @check_accesses: Check the accesses to target regions.
|
|
* @reset_aggregated: Reset aggregated accesses monitoring results.
|
|
* @apply_scheme: Apply a DAMON-based operation scheme.
|
|
* @target_valid: Determine if the target is valid.
|
|
* @cleanup: Clean up the context.
|
|
*
|
|
* DAMON can be extended for various address spaces and usages. For this,
|
|
* users should register the low level primitives for their target address
|
|
* space and usecase via the &damon_ctx.primitive. Then, the monitoring thread
|
|
* (&damon_ctx.kdamond) calls @init and @prepare_access_checks before starting
|
|
* the monitoring, @update after each &damon_ctx.primitive_update_interval, and
|
|
* @check_accesses, @target_valid and @prepare_access_checks after each
|
|
* &damon_ctx.sample_interval. Finally, @reset_aggregated is called after each
|
|
* &damon_ctx.aggr_interval.
|
|
*
|
|
* @init should initialize primitive-internal data structures. For example,
|
|
* this could be used to construct proper monitoring target regions and link
|
|
* those to @damon_ctx.adaptive_targets.
|
|
* @update should update the primitive-internal data structures. For example,
|
|
* this could be used to update monitoring target regions for current status.
|
|
* @prepare_access_checks should manipulate the monitoring regions to be
|
|
* prepared for the next access check.
|
|
* @check_accesses should check the accesses to each region that made after the
|
|
* last preparation and update the number of observed accesses of each region.
|
|
* It should also return max number of observed accesses that made as a result
|
|
* of its update. The value will be used for regions adjustment threshold.
|
|
* @reset_aggregated should reset the access monitoring results that aggregated
|
|
* by @check_accesses.
|
|
* @apply_scheme is called from @kdamond when a region for user provided
|
|
* DAMON-based operation scheme is found. It should apply the scheme's action
|
|
* to the region. This is not used for &DAMON_ARBITRARY_TARGET case.
|
|
* @target_valid should check whether the target is still valid for the
|
|
* monitoring.
|
|
* @cleanup is called from @kdamond just before its termination.
|
|
*/
|
|
struct damon_primitive {
|
|
void (*init)(struct damon_ctx *context);
|
|
void (*update)(struct damon_ctx *context);
|
|
void (*prepare_access_checks)(struct damon_ctx *context);
|
|
unsigned int (*check_accesses)(struct damon_ctx *context);
|
|
void (*reset_aggregated)(struct damon_ctx *context);
|
|
int (*apply_scheme)(struct damon_ctx *context, struct damon_target *t,
|
|
struct damon_region *r, struct damos *scheme);
|
|
bool (*target_valid)(void *target);
|
|
void (*cleanup)(struct damon_ctx *context);
|
|
};
|
|
|
|
/**
|
|
* struct damon_callback - Monitoring events notification callbacks.
|
|
*
|
|
* @before_start: Called before starting the monitoring.
|
|
* @after_sampling: Called after each sampling.
|
|
* @after_aggregation: Called after each aggregation.
|
|
* @before_terminate: Called before terminating the monitoring.
|
|
* @private: User private data.
|
|
*
|
|
* The monitoring thread (&damon_ctx.kdamond) calls @before_start and
|
|
* @before_terminate just before starting and finishing the monitoring,
|
|
* respectively. Therefore, those are good places for installing and cleaning
|
|
* @private.
|
|
*
|
|
* The monitoring thread calls @after_sampling and @after_aggregation for each
|
|
* of the sampling intervals and aggregation intervals, respectively.
|
|
* Therefore, users can safely access the monitoring results without additional
|
|
* protection. For the reason, users are recommended to use these callback for
|
|
* the accesses to the results.
|
|
*
|
|
* If any callback returns non-zero, monitoring stops.
|
|
*/
|
|
struct damon_callback {
|
|
void *private;
|
|
|
|
int (*before_start)(struct damon_ctx *context);
|
|
int (*after_sampling)(struct damon_ctx *context);
|
|
int (*after_aggregation)(struct damon_ctx *context);
|
|
int (*before_terminate)(struct damon_ctx *context);
|
|
};
|
|
|
|
/**
|
|
* struct damon_ctx - Represents a context for each monitoring. This is the
|
|
* main interface that allows users to set the attributes and get the results
|
|
* of the monitoring.
|
|
*
|
|
* @sample_interval: The time between access samplings.
|
|
* @aggr_interval: The time between monitor results aggregations.
|
|
* @primitive_update_interval: The time between monitoring primitive updates.
|
|
*
|
|
* For each @sample_interval, DAMON checks whether each region is accessed or
|
|
* not. It aggregates and keeps the access information (number of accesses to
|
|
* each region) for @aggr_interval time. DAMON also checks whether the target
|
|
* memory regions need update (e.g., by ``mmap()`` calls from the application,
|
|
* in case of virtual memory monitoring) and applies the changes for each
|
|
* @primitive_update_interval. All time intervals are in micro-seconds.
|
|
* Please refer to &struct damon_primitive and &struct damon_callback for more
|
|
* detail.
|
|
*
|
|
* @kdamond: Kernel thread who does the monitoring.
|
|
* @kdamond_stop: Notifies whether kdamond should stop.
|
|
* @kdamond_lock: Mutex for the synchronizations with @kdamond.
|
|
*
|
|
* For each monitoring context, one kernel thread for the monitoring is
|
|
* created. The pointer to the thread is stored in @kdamond.
|
|
*
|
|
* Once started, the monitoring thread runs until explicitly required to be
|
|
* terminated or every monitoring target is invalid. The validity of the
|
|
* targets is checked via the &damon_primitive.target_valid of @primitive. The
|
|
* termination can also be explicitly requested by writing non-zero to
|
|
* @kdamond_stop. The thread sets @kdamond to NULL when it terminates.
|
|
* Therefore, users can know whether the monitoring is ongoing or terminated by
|
|
* reading @kdamond. Reads and writes to @kdamond and @kdamond_stop from
|
|
* outside of the monitoring thread must be protected by @kdamond_lock.
|
|
*
|
|
* Note that the monitoring thread protects only @kdamond and @kdamond_stop via
|
|
* @kdamond_lock. Accesses to other fields must be protected by themselves.
|
|
*
|
|
* @primitive: Set of monitoring primitives for given use cases.
|
|
* @callback: Set of callbacks for monitoring events notifications.
|
|
*
|
|
* @min_nr_regions: The minimum number of adaptive monitoring regions.
|
|
* @max_nr_regions: The maximum number of adaptive monitoring regions.
|
|
* @adaptive_targets: Head of monitoring targets (&damon_target) list.
|
|
* @schemes: Head of schemes (&damos) list.
|
|
*/
|
|
struct damon_ctx {
|
|
unsigned long sample_interval;
|
|
unsigned long aggr_interval;
|
|
unsigned long primitive_update_interval;
|
|
|
|
/* private: internal use only */
|
|
struct timespec64 last_aggregation;
|
|
struct timespec64 last_primitive_update;
|
|
|
|
/* public: */
|
|
struct task_struct *kdamond;
|
|
bool kdamond_stop;
|
|
struct mutex kdamond_lock;
|
|
|
|
struct damon_primitive primitive;
|
|
struct damon_callback callback;
|
|
|
|
unsigned long min_nr_regions;
|
|
unsigned long max_nr_regions;
|
|
struct list_head adaptive_targets;
|
|
struct list_head schemes;
|
|
};
|
|
|
|
#define damon_next_region(r) \
|
|
(container_of(r->list.next, struct damon_region, list))
|
|
|
|
#define damon_prev_region(r) \
|
|
(container_of(r->list.prev, struct damon_region, list))
|
|
|
|
#define damon_for_each_region(r, t) \
|
|
list_for_each_entry(r, &t->regions_list, list)
|
|
|
|
#define damon_for_each_region_safe(r, next, t) \
|
|
list_for_each_entry_safe(r, next, &t->regions_list, list)
|
|
|
|
#define damon_for_each_target(t, ctx) \
|
|
list_for_each_entry(t, &(ctx)->adaptive_targets, list)
|
|
|
|
#define damon_for_each_target_safe(t, next, ctx) \
|
|
list_for_each_entry_safe(t, next, &(ctx)->adaptive_targets, list)
|
|
|
|
#define damon_for_each_scheme(s, ctx) \
|
|
list_for_each_entry(s, &(ctx)->schemes, list)
|
|
|
|
#define damon_for_each_scheme_safe(s, next, ctx) \
|
|
list_for_each_entry_safe(s, next, &(ctx)->schemes, list)
|
|
|
|
#ifdef CONFIG_DAMON
|
|
|
|
struct damon_region *damon_new_region(unsigned long start, unsigned long end);
|
|
inline void damon_insert_region(struct damon_region *r,
|
|
struct damon_region *prev, struct damon_region *next,
|
|
struct damon_target *t);
|
|
void damon_add_region(struct damon_region *r, struct damon_target *t);
|
|
void damon_destroy_region(struct damon_region *r, struct damon_target *t);
|
|
|
|
struct damos *damon_new_scheme(
|
|
unsigned long min_sz_region, unsigned long max_sz_region,
|
|
unsigned int min_nr_accesses, unsigned int max_nr_accesses,
|
|
unsigned int min_age_region, unsigned int max_age_region,
|
|
enum damos_action action);
|
|
void damon_add_scheme(struct damon_ctx *ctx, struct damos *s);
|
|
void damon_destroy_scheme(struct damos *s);
|
|
|
|
struct damon_target *damon_new_target(unsigned long id);
|
|
void damon_add_target(struct damon_ctx *ctx, struct damon_target *t);
|
|
void damon_free_target(struct damon_target *t);
|
|
void damon_destroy_target(struct damon_target *t);
|
|
unsigned int damon_nr_regions(struct damon_target *t);
|
|
|
|
struct damon_ctx *damon_new_ctx(void);
|
|
void damon_destroy_ctx(struct damon_ctx *ctx);
|
|
int damon_set_targets(struct damon_ctx *ctx,
|
|
unsigned long *ids, ssize_t nr_ids);
|
|
int damon_set_attrs(struct damon_ctx *ctx, unsigned long sample_int,
|
|
unsigned long aggr_int, unsigned long primitive_upd_int,
|
|
unsigned long min_nr_reg, unsigned long max_nr_reg);
|
|
int damon_set_schemes(struct damon_ctx *ctx,
|
|
struct damos **schemes, ssize_t nr_schemes);
|
|
int damon_nr_running_ctxs(void);
|
|
|
|
int damon_start(struct damon_ctx **ctxs, int nr_ctxs);
|
|
int damon_stop(struct damon_ctx **ctxs, int nr_ctxs);
|
|
|
|
#endif /* CONFIG_DAMON */
|
|
|
|
#ifdef CONFIG_DAMON_VADDR
|
|
|
|
/* Monitoring primitives for virtual memory address spaces */
|
|
void damon_va_init(struct damon_ctx *ctx);
|
|
void damon_va_update(struct damon_ctx *ctx);
|
|
void damon_va_prepare_access_checks(struct damon_ctx *ctx);
|
|
unsigned int damon_va_check_accesses(struct damon_ctx *ctx);
|
|
bool damon_va_target_valid(void *t);
|
|
void damon_va_cleanup(struct damon_ctx *ctx);
|
|
int damon_va_apply_scheme(struct damon_ctx *context, struct damon_target *t,
|
|
struct damon_region *r, struct damos *scheme);
|
|
void damon_va_set_primitives(struct damon_ctx *ctx);
|
|
|
|
#endif /* CONFIG_DAMON_VADDR */
|
|
|
|
#ifdef CONFIG_DAMON_PADDR
|
|
|
|
/* Monitoring primitives for the physical memory address space */
|
|
void damon_pa_prepare_access_checks(struct damon_ctx *ctx);
|
|
unsigned int damon_pa_check_accesses(struct damon_ctx *ctx);
|
|
bool damon_pa_target_valid(void *t);
|
|
int damon_pa_apply_scheme(struct damon_ctx *context, struct damon_target *t,
|
|
struct damon_region *r, struct damos *scheme);
|
|
void damon_pa_set_primitives(struct damon_ctx *ctx);
|
|
|
|
#endif /* CONFIG_DAMON_PADDR */
|
|
|
|
#endif /* _DAMON_H */
|