linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/7] DAMON: Support Physical Memory Address Space Monitoring
@ 2021-10-12 20:57 SeongJae Park
  2021-10-12 20:57 ` [PATCH 1/7] mm/damon/dbgfs: Allow users to set initial monitoring target regions SeongJae Park
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: SeongJae Park @ 2021-10-12 20:57 UTC (permalink / raw)
  To: akpm
  Cc: SeongJae Park, Jonathan.Cameron, amit, benh, corbet, david, dwmw,
	elver, foersleo, gthelen, markubo, rientjes, shakeelb, shuah,
	linux-damon, linux-mm, linux-doc, linux-kernel

Changes from Previous Version (RFC[1])
======================================

- Rebase on latest -mm tree
- Remove page granularity idleness monitoring part

[1] https://lore.kernel.org/linux-mm/20201216094221.11898-1-sjpark@amazon.com/

Introduction
============

DAMON is currently supporting only virtual address spaces monitoring.  It can
be easily extended for various use cases and address spaces by configuring its
monitoring primitives layer to use appropriate primitives implementations,
though.  This patchset implements monitoring primitives for the physical
address space monitoring using the structure.

Baseline and Complete Git Trees
===============================

The patches are based on the latest -mm tree
(v5.15-rc4-mmots-2021-10-10-18-34)[1].  You can also clone the complete git
tree:

    $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/sj/linux.git -b damon-paddr/patches/v1

The web is also available:
https://git.kernel.org/pub/scm/linux/kernel/git/sj/linux.git/tag/?h=damon-paddr/patches/v1

[1] https://github.com/hnaz/linux-mm/tree/v5.15-rc4-mmots-2021-10-10-18-34

Sequence of Patches
===================

The first 3 patches allow the user space users manually set the monitoring
regions.  The 1st patch implements the feature in the 'damon-dbgfs'.  Then,
patches for adding a unit tests (the 2nd patch) and updating the documentation
(the 3rd patch) follow.

Following 4 patches implement the physical address space monitoring primitives.
The 4th patch makes some primitive functions for the virtual address spaces
primitives reusable.  The 5th patch implements the physical address space
monitoring primitives.  The 6th patch links the primitives to the
'damon-dbgfs'.  Finally, 7th patch documents this new features.

Patch History
=============

Changes from RFC v10
(https://lore.kernel.org/linux-mm/20201216094221.11898-1-sjpark@amazon.com/)
- Rebase on latest -mm tree
- Remove page granularity idleness monitoring part

Please refer to RFC v10 for previous history.

SeongJae Park (7):
  mm/damon/dbgfs: Allow users to set initial monitoring target regions
  mm/damon/dbgfs-test: Add a unit test case for 'init_regions'
  Docs/admin-guide/mm/damon: Document 'init_regions' feature
  mm/damon/vaddr: Separate commonly usable functions
  mm/damon: Implement primitives for physical address space monitoring
  mm/damon/dbgfs: Support physical memory monitoring
  Docs/DAMON: Document physical memory monitoring support

 Documentation/admin-guide/mm/damon/usage.rst |  62 ++++-
 Documentation/vm/damon/design.rst            |  29 ++-
 Documentation/vm/damon/faq.rst               |   5 +-
 include/linux/damon.h                        |  10 +
 mm/damon/Kconfig                             |  10 +-
 mm/damon/Makefile                            |   3 +-
 mm/damon/dbgfs-test.h                        |  54 +++++
 mm/damon/dbgfs.c                             | 177 ++++++++++++++-
 mm/damon/paddr.c                             | 224 +++++++++++++++++++
 mm/damon/prmtv-common.c                      |  88 ++++++++
 mm/damon/prmtv-common.h                      |  17 ++
 mm/damon/vaddr.c                             |  87 +------
 12 files changed, 655 insertions(+), 111 deletions(-)
 create mode 100644 mm/damon/paddr.c
 create mode 100644 mm/damon/prmtv-common.c
 create mode 100644 mm/damon/prmtv-common.h

-- 
2.17.1



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/7] mm/damon/dbgfs: Allow users to set initial monitoring target regions
  2021-10-12 20:57 [PATCH 0/7] DAMON: Support Physical Memory Address Space Monitoring SeongJae Park
@ 2021-10-12 20:57 ` SeongJae Park
  2021-10-13 22:45   ` Andrew Morton
  2021-10-12 20:57 ` [PATCH 2/7] mm/damon/dbgfs-test: Add a unit test case for 'init_regions' SeongJae Park
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 10+ messages in thread
From: SeongJae Park @ 2021-10-12 20:57 UTC (permalink / raw)
  To: akpm
  Cc: SeongJae Park, Jonathan.Cameron, amit, benh, corbet, david, dwmw,
	elver, foersleo, gthelen, markubo, rientjes, shakeelb, shuah,
	linux-damon, linux-mm, linux-doc, linux-kernel

Some 'damon-dbgfs' users would want to monitor only a part of the entire
virtual memory address space.  The program interface users in the kernel
space could use '->before_start()' callback or set the regions inside
the context struct as they want, but 'damon-dbgfs' users cannot.

For the reason, this commit introduces a new debugfs file called
'init_region'.  'damon-dbgfs' users can specify which initial monitoring
target address regions they want by writing special input to the file.
The input should describe each region in each line in the below form:

    <pid> <start address> <end address>

Note that the regions will be updated to cover entire memory mapped
regions after a 'regions update interval' is passed.  If you want the
regions to not be updated after the initial setting, you could set the
interval as a very long time, say, a few decades.

Signed-off-by: SeongJae Park <sj@kernel.org>
---
 mm/damon/dbgfs.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 154 insertions(+), 2 deletions(-)

diff --git a/mm/damon/dbgfs.c b/mm/damon/dbgfs.c
index 28d6abf27763..1cce53cd241d 100644
--- a/mm/damon/dbgfs.c
+++ b/mm/damon/dbgfs.c
@@ -394,6 +394,152 @@ static ssize_t dbgfs_target_ids_write(struct file *file,
 	return ret;
 }
 
+static ssize_t sprint_init_regions(struct damon_ctx *c, char *buf, ssize_t len)
+{
+	struct damon_target *t;
+	struct damon_region *r;
+	int written = 0;
+	int rc;
+
+	damon_for_each_target(t, c) {
+		damon_for_each_region(r, t) {
+			rc = scnprintf(&buf[written], len - written,
+					"%lu %lu %lu\n",
+					t->id, r->ar.start, r->ar.end);
+			if (!rc)
+				return -ENOMEM;
+			written += rc;
+		}
+	}
+	return written;
+}
+
+static ssize_t dbgfs_init_regions_read(struct file *file, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct damon_ctx *ctx = file->private_data;
+	char *kbuf;
+	ssize_t len;
+
+	kbuf = kmalloc(count, GFP_KERNEL);
+	if (!kbuf)
+		return -ENOMEM;
+
+	mutex_lock(&ctx->kdamond_lock);
+	if (ctx->kdamond) {
+		mutex_unlock(&ctx->kdamond_lock);
+		len = -EBUSY;
+		goto out;
+	}
+
+	len = sprint_init_regions(ctx, kbuf, count);
+	mutex_unlock(&ctx->kdamond_lock);
+	if (len < 0)
+		goto out;
+	len = simple_read_from_buffer(buf, count, ppos, kbuf, len);
+
+out:
+	kfree(kbuf);
+	return len;
+}
+
+static int add_init_region(struct damon_ctx *c,
+			 unsigned long target_id, struct damon_addr_range *ar)
+{
+	struct damon_target *t;
+	struct damon_region *r, *prev;
+	unsigned long id;
+	int rc = -EINVAL;
+
+	if (ar->start >= ar->end)
+		return -EINVAL;
+
+	damon_for_each_target(t, c) {
+		id = t->id;
+		if (targetid_is_pid(c))
+			id = (unsigned long)pid_vnr((struct pid *)id);
+		if (id == target_id) {
+			r = damon_new_region(ar->start, ar->end);
+			if (!r)
+				return -ENOMEM;
+			damon_add_region(r, t);
+			if (damon_nr_regions(t) > 1) {
+				prev = damon_prev_region(r);
+				if (prev->ar.end > r->ar.start) {
+					damon_destroy_region(r, t);
+					return -EINVAL;
+				}
+			}
+			rc = 0;
+		}
+	}
+	return rc;
+}
+
+static int set_init_regions(struct damon_ctx *c, const char *str, ssize_t len)
+{
+	struct damon_target *t;
+	struct damon_region *r, *next;
+	int pos = 0, parsed, ret;
+	unsigned long target_id;
+	struct damon_addr_range ar;
+	int err;
+
+	damon_for_each_target(t, c) {
+		damon_for_each_region_safe(r, next, t)
+			damon_destroy_region(r, t);
+	}
+
+	while (pos < len) {
+		ret = sscanf(&str[pos], "%lu %lu %lu%n",
+				&target_id, &ar.start, &ar.end, &parsed);
+		if (ret != 3)
+			break;
+		err = add_init_region(c, target_id, &ar);
+		if (err)
+			goto fail;
+		pos += parsed;
+	}
+
+	return 0;
+
+fail:
+	damon_for_each_target(t, c) {
+		damon_for_each_region_safe(r, next, t)
+			damon_destroy_region(r, t);
+	}
+	return err;
+}
+
+static ssize_t dbgfs_init_regions_write(struct file *file,
+					  const char __user *buf, size_t count,
+					  loff_t *ppos)
+{
+	struct damon_ctx *ctx = file->private_data;
+	char *kbuf;
+	ssize_t ret = count;
+	int err;
+
+	kbuf = user_input_str(buf, count, ppos);
+	if (IS_ERR(kbuf))
+		return PTR_ERR(kbuf);
+
+	mutex_lock(&ctx->kdamond_lock);
+	if (ctx->kdamond) {
+		ret = -EBUSY;
+		goto unlock_out;
+	}
+
+	err = set_init_regions(ctx, kbuf, ret);
+	if (err)
+		ret = err;
+
+unlock_out:
+	mutex_unlock(&ctx->kdamond_lock);
+	kfree(kbuf);
+	return ret;
+}
+
 static ssize_t dbgfs_kdamond_pid_read(struct file *file,
 		char __user *buf, size_t count, loff_t *ppos)
 {
@@ -445,6 +591,12 @@ static const struct file_operations target_ids_fops = {
 	.write = dbgfs_target_ids_write,
 };
 
+static const struct file_operations init_regions_fops = {
+	.open = damon_dbgfs_open,
+	.read = dbgfs_init_regions_read,
+	.write = dbgfs_init_regions_write,
+};
+
 static const struct file_operations kdamond_pid_fops = {
 	.open = damon_dbgfs_open,
 	.read = dbgfs_kdamond_pid_read,
@@ -453,9 +605,9 @@ static const struct file_operations kdamond_pid_fops = {
 static void dbgfs_fill_ctx_dir(struct dentry *dir, struct damon_ctx *ctx)
 {
 	const char * const file_names[] = {"attrs", "schemes", "target_ids",
-		"kdamond_pid"};
+		"init_regions", "kdamond_pid"};
 	const struct file_operations *fops[] = {&attrs_fops, &schemes_fops,
-		&target_ids_fops, &kdamond_pid_fops};
+		&target_ids_fops, &init_regions_fops, &kdamond_pid_fops};
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(file_names); i++)
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/7] mm/damon/dbgfs-test: Add a unit test case for 'init_regions'
  2021-10-12 20:57 [PATCH 0/7] DAMON: Support Physical Memory Address Space Monitoring SeongJae Park
  2021-10-12 20:57 ` [PATCH 1/7] mm/damon/dbgfs: Allow users to set initial monitoring target regions SeongJae Park
@ 2021-10-12 20:57 ` SeongJae Park
  2021-10-12 20:57 ` [PATCH 3/7] Docs/admin-guide/mm/damon: Document 'init_regions' feature SeongJae Park
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: SeongJae Park @ 2021-10-12 20:57 UTC (permalink / raw)
  To: akpm
  Cc: SeongJae Park, Jonathan.Cameron, amit, benh, corbet, david, dwmw,
	elver, foersleo, gthelen, markubo, rientjes, shakeelb, shuah,
	linux-damon, linux-mm, linux-doc, linux-kernel

This commit adds another test case for the new feature, 'init_regions'.

Signed-off-by: SeongJae Park <sj@kernel.org>
Reviewed-by: Brendan Higgins <brendanhiggins@google.com>
---
 mm/damon/dbgfs-test.h | 54 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/mm/damon/dbgfs-test.h b/mm/damon/dbgfs-test.h
index 4eddcfa73996..104b22957616 100644
--- a/mm/damon/dbgfs-test.h
+++ b/mm/damon/dbgfs-test.h
@@ -109,9 +109,63 @@ static void damon_dbgfs_test_set_targets(struct kunit *test)
 	dbgfs_destroy_ctx(ctx);
 }
 
+static void damon_dbgfs_test_set_init_regions(struct kunit *test)
+{
+	struct damon_ctx *ctx = damon_new_ctx();
+	unsigned long ids[] = {1, 2, 3};
+	/* Each line represents one region in ``<target id> <start> <end>`` */
+	char * const valid_inputs[] = {"2 10 20\n 2   20 30\n2 35 45",
+		"2 10 20\n",
+		"2 10 20\n1 39 59\n1 70 134\n  2  20 25\n",
+		""};
+	/* Reading the file again will show sorted, clean output */
+	char * const valid_expects[] = {"2 10 20\n2 20 30\n2 35 45\n",
+		"2 10 20\n",
+		"1 39 59\n1 70 134\n2 10 20\n2 20 25\n",
+		""};
+	char * const invalid_inputs[] = {"4 10 20\n",	/* target not exists */
+		"2 10 20\n 2 14 26\n",		/* regions overlap */
+		"1 10 20\n2 30 40\n 1 5 8"};	/* not sorted by address */
+	char *input, *expect;
+	int i, rc;
+	char buf[256];
+
+	damon_set_targets(ctx, ids, 3);
+
+	/* Put valid inputs and check the results */
+	for (i = 0; i < ARRAY_SIZE(valid_inputs); i++) {
+		input = valid_inputs[i];
+		expect = valid_expects[i];
+
+		rc = set_init_regions(ctx, input, strnlen(input, 256));
+		KUNIT_EXPECT_EQ(test, rc, 0);
+
+		memset(buf, 0, 256);
+		sprint_init_regions(ctx, buf, 256);
+
+		KUNIT_EXPECT_STREQ(test, (char *)buf, expect);
+	}
+	/* Put invlid inputs and check the return error code */
+	for (i = 0; i < ARRAY_SIZE(invalid_inputs); i++) {
+		input = invalid_inputs[i];
+		pr_info("input: %s\n", input);
+		rc = set_init_regions(ctx, input, strnlen(input, 256));
+		KUNIT_EXPECT_EQ(test, rc, -EINVAL);
+
+		memset(buf, 0, 256);
+		sprint_init_regions(ctx, buf, 256);
+
+		KUNIT_EXPECT_STREQ(test, (char *)buf, "");
+	}
+
+	damon_set_targets(ctx, NULL, 0);
+	damon_destroy_ctx(ctx);
+}
+
 static struct kunit_case damon_test_cases[] = {
 	KUNIT_CASE(damon_dbgfs_test_str_to_target_ids),
 	KUNIT_CASE(damon_dbgfs_test_set_targets),
+	KUNIT_CASE(damon_dbgfs_test_set_init_regions),
 	{},
 };
 
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/7] Docs/admin-guide/mm/damon: Document 'init_regions' feature
  2021-10-12 20:57 [PATCH 0/7] DAMON: Support Physical Memory Address Space Monitoring SeongJae Park
  2021-10-12 20:57 ` [PATCH 1/7] mm/damon/dbgfs: Allow users to set initial monitoring target regions SeongJae Park
  2021-10-12 20:57 ` [PATCH 2/7] mm/damon/dbgfs-test: Add a unit test case for 'init_regions' SeongJae Park
@ 2021-10-12 20:57 ` SeongJae Park
  2021-10-12 20:57 ` [PATCH 4/7] mm/damon/vaddr: Separate commonly usable functions SeongJae Park
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: SeongJae Park @ 2021-10-12 20:57 UTC (permalink / raw)
  To: akpm
  Cc: SeongJae Park, Jonathan.Cameron, amit, benh, corbet, david, dwmw,
	elver, foersleo, gthelen, markubo, rientjes, shakeelb, shuah,
	linux-damon, linux-mm, linux-doc, linux-kernel

This commit adds description of the 'init_regions' feature in the DAMON
usage document.

Signed-off-by: SeongJae Park <sj@kernel.org>
---
 Documentation/admin-guide/mm/damon/usage.rst | 41 +++++++++++++++++++-
 1 file changed, 39 insertions(+), 2 deletions(-)

diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst
index c0296c14babf..f7d5cfbb50c2 100644
--- a/Documentation/admin-guide/mm/damon/usage.rst
+++ b/Documentation/admin-guide/mm/damon/usage.rst
@@ -34,8 +34,9 @@ the reason, this document describes only the debugfs interface
 debugfs Interface
 =================
 
-DAMON exports four files, ``attrs``, ``target_ids``, ``schemes`` and
-``monitor_on`` under its debugfs directory, ``<debugfs>/damon/``.
+DAMON exports five files, ``attrs``, ``target_ids``, ``init_regions``,
+``schemes`` and ``monitor_on`` under its debugfs directory,
+``<debugfs>/damon/``.
 
 
 Attributes
@@ -74,6 +75,42 @@ check it again::
 Note that setting the target ids doesn't start the monitoring.
 
 
+Initial Monitoring Target Regions
+---------------------------------
+
+In case of the debugfs based monitoring, DAMON automatically sets and updates
+the monitoring target regions so that entire memory mappings of target
+processes can be covered.  However, users can want to limit the monitoring
+region to specific address ranges, such as the heap, the stack, or specific
+file-mapped area.  Or, some users can know the initial access pattern of their
+workloads and therefore want to set optimal initial regions for the 'adaptive
+regions adjustment'.
+
+In such cases, users can explicitly set the initial monitoring target regions
+as they want, by writing proper values to the ``init_regions`` file.  Each line
+of the input should represent one region in below form.::
+
+    <target id> <start address> <end address>
+
+The ``target id`` should already in ``target_ids`` file, and the regions should
+be passed in address order.  For example, below commands will set a couple of
+address ranges, ``1-100`` and ``100-200`` as the initial monitoring target
+region of process 42, and another couple of address ranges, ``20-40`` and
+``50-100`` as that of process 4242.::
+
+    # cd <debugfs>/damon
+    # echo "42   1       100
+            42   100     200
+            4242 20      40
+            4242 50      100" > init_regions
+
+Note that this sets the initial monitoring target regions only.  In case of
+virtual memory monitoring, DAMON will automatically updates the boundary of the
+regions after one ``regions update interval``.  Therefore, users should set the
+``regions update interval`` large enough in this case, if they don't want the
+update.
+
+
 Schemes
 -------
 
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/7] mm/damon/vaddr: Separate commonly usable functions
  2021-10-12 20:57 [PATCH 0/7] DAMON: Support Physical Memory Address Space Monitoring SeongJae Park
                   ` (2 preceding siblings ...)
  2021-10-12 20:57 ` [PATCH 3/7] Docs/admin-guide/mm/damon: Document 'init_regions' feature SeongJae Park
@ 2021-10-12 20:57 ` SeongJae Park
  2021-10-12 20:57 ` [PATCH 5/7] mm/damon: Implement primitives for physical address space monitoring SeongJae Park
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: SeongJae Park @ 2021-10-12 20:57 UTC (permalink / raw)
  To: akpm
  Cc: SeongJae Park, Jonathan.Cameron, amit, benh, corbet, david, dwmw,
	elver, foersleo, gthelen, markubo, rientjes, shakeelb, shuah,
	linux-damon, linux-mm, linux-doc, linux-kernel

This commit moves functions in the default virtual address spaces
monitoring primitives that commonly usable from other address spaces
like physical address space into a header file.  Those will be reused by
the physical address space monitoring primitives which will be
implemented by the following commit.

Signed-off-by: SeongJae Park <sj@kernel.org>
---
 mm/damon/Makefile       |  2 +-
 mm/damon/prmtv-common.c | 88 +++++++++++++++++++++++++++++++++++++++++
 mm/damon/prmtv-common.h | 17 ++++++++
 mm/damon/vaddr.c        | 87 +---------------------------------------
 4 files changed, 108 insertions(+), 86 deletions(-)
 create mode 100644 mm/damon/prmtv-common.c
 create mode 100644 mm/damon/prmtv-common.h

diff --git a/mm/damon/Makefile b/mm/damon/Makefile
index fed4be3bace3..99b1bfe01ff5 100644
--- a/mm/damon/Makefile
+++ b/mm/damon/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 
 obj-$(CONFIG_DAMON)		:= core.o
-obj-$(CONFIG_DAMON_VADDR)	+= vaddr.o
+obj-$(CONFIG_DAMON_VADDR)	+= prmtv-common.o vaddr.o
 obj-$(CONFIG_DAMON_DBGFS)	+= dbgfs.o
diff --git a/mm/damon/prmtv-common.c b/mm/damon/prmtv-common.c
new file mode 100644
index 000000000000..1768cbe1b9ff
--- /dev/null
+++ b/mm/damon/prmtv-common.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Common Primitives for Data Access Monitoring
+ *
+ * Author: SeongJae Park <sj@kernel.org>
+ */
+
+#include <linux/highmem.h>
+#include <linux/mmu_notifier.h>
+#include <linux/page_idle.h>
+#include <linux/pagemap.h>
+#include <linux/rmap.h>
+
+#include "prmtv-common.h"
+
+/*
+ * Get an online page for a pfn if it's in the LRU list.  Otherwise, returns
+ * NULL.
+ *
+ * The body of this function is stolen from the 'page_idle_get_page()'.  We
+ * steal rather than reuse it because the code is quite simple.
+ */
+struct page *damon_get_page(unsigned long pfn)
+{
+	struct page *page = pfn_to_online_page(pfn);
+
+	if (!page || !PageLRU(page) || !get_page_unless_zero(page))
+		return NULL;
+
+	if (unlikely(!PageLRU(page))) {
+		put_page(page);
+		page = NULL;
+	}
+	return page;
+}
+
+void damon_ptep_mkold(pte_t *pte, struct mm_struct *mm, unsigned long addr)
+{
+	bool referenced = false;
+	struct page *page = damon_get_page(pte_pfn(*pte));
+
+	if (!page)
+		return;
+
+	if (pte_young(*pte)) {
+		referenced = true;
+		*pte = pte_mkold(*pte);
+	}
+
+#ifdef CONFIG_MMU_NOTIFIER
+	if (mmu_notifier_clear_young(mm, addr, addr + PAGE_SIZE))
+		referenced = true;
+#endif /* CONFIG_MMU_NOTIFIER */
+
+	if (referenced)
+		set_page_young(page);
+
+	set_page_idle(page);
+	put_page(page);
+}
+
+void damon_pmdp_mkold(pmd_t *pmd, struct mm_struct *mm, unsigned long addr)
+{
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+	bool referenced = false;
+	struct page *page = damon_get_page(pmd_pfn(*pmd));
+
+	if (!page)
+		return;
+
+	if (pmd_young(*pmd)) {
+		referenced = true;
+		*pmd = pmd_mkold(*pmd);
+	}
+
+#ifdef CONFIG_MMU_NOTIFIER
+	if (mmu_notifier_clear_young(mm, addr,
+				addr + ((1UL) << HPAGE_PMD_SHIFT)))
+		referenced = true;
+#endif /* CONFIG_MMU_NOTIFIER */
+
+	if (referenced)
+		set_page_young(page);
+
+	set_page_idle(page);
+	put_page(page);
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+}
diff --git a/mm/damon/prmtv-common.h b/mm/damon/prmtv-common.h
new file mode 100644
index 000000000000..7093d19e5d42
--- /dev/null
+++ b/mm/damon/prmtv-common.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Common Primitives for Data Access Monitoring
+ *
+ * Author: SeongJae Park <sj@kernel.org>
+ */
+
+#include <linux/damon.h>
+#include <linux/random.h>
+
+/* Get a random number in [l, r) */
+#define damon_rand(l, r) (l + prandom_u32_max(r - l))
+
+struct page *damon_get_page(unsigned long pfn);
+
+void damon_ptep_mkold(pte_t *pte, struct mm_struct *mm, unsigned long addr);
+void damon_pmdp_mkold(pmd_t *pmd, struct mm_struct *mm, unsigned long addr);
diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c
index 953c145b4f08..b8ba44f69db6 100644
--- a/mm/damon/vaddr.c
+++ b/mm/damon/vaddr.c
@@ -8,25 +8,18 @@
 #define pr_fmt(fmt) "damon-va: " fmt
 
 #include <asm-generic/mman-common.h>
-#include <linux/damon.h>
 #include <linux/hugetlb.h>
-#include <linux/mm.h>
 #include <linux/mmu_notifier.h>
-#include <linux/highmem.h>
 #include <linux/page_idle.h>
 #include <linux/pagewalk.h>
-#include <linux/random.h>
-#include <linux/sched/mm.h>
-#include <linux/slab.h>
+
+#include "prmtv-common.h"
 
 #ifdef CONFIG_DAMON_VADDR_KUNIT_TEST
 #undef DAMON_MIN_REGION
 #define DAMON_MIN_REGION 1
 #endif
 
-/* Get a random number in [l, r) */
-#define damon_rand(l, r) (l + prandom_u32_max(r - l))
-
 /*
  * 't->id' should be the pointer to the relevant 'struct pid' having reference
  * count.  Caller must put the returned task, unless it is NULL.
@@ -373,82 +366,6 @@ void damon_va_update(struct damon_ctx *ctx)
 	}
 }
 
-/*
- * Get an online page for a pfn if it's in the LRU list.  Otherwise, returns
- * NULL.
- *
- * The body of this function is stolen from the 'page_idle_get_page()'.  We
- * steal rather than reuse it because the code is quite simple.
- */
-static struct page *damon_get_page(unsigned long pfn)
-{
-	struct page *page = pfn_to_online_page(pfn);
-
-	if (!page || !PageLRU(page) || !get_page_unless_zero(page))
-		return NULL;
-
-	if (unlikely(!PageLRU(page))) {
-		put_page(page);
-		page = NULL;
-	}
-	return page;
-}
-
-static void damon_ptep_mkold(pte_t *pte, struct mm_struct *mm,
-			     unsigned long addr)
-{
-	bool referenced = false;
-	struct page *page = damon_get_page(pte_pfn(*pte));
-
-	if (!page)
-		return;
-
-	if (pte_young(*pte)) {
-		referenced = true;
-		*pte = pte_mkold(*pte);
-	}
-
-#ifdef CONFIG_MMU_NOTIFIER
-	if (mmu_notifier_clear_young(mm, addr, addr + PAGE_SIZE))
-		referenced = true;
-#endif /* CONFIG_MMU_NOTIFIER */
-
-	if (referenced)
-		set_page_young(page);
-
-	set_page_idle(page);
-	put_page(page);
-}
-
-static void damon_pmdp_mkold(pmd_t *pmd, struct mm_struct *mm,
-			     unsigned long addr)
-{
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-	bool referenced = false;
-	struct page *page = damon_get_page(pmd_pfn(*pmd));
-
-	if (!page)
-		return;
-
-	if (pmd_young(*pmd)) {
-		referenced = true;
-		*pmd = pmd_mkold(*pmd);
-	}
-
-#ifdef CONFIG_MMU_NOTIFIER
-	if (mmu_notifier_clear_young(mm, addr,
-				addr + ((1UL) << HPAGE_PMD_SHIFT)))
-		referenced = true;
-#endif /* CONFIG_MMU_NOTIFIER */
-
-	if (referenced)
-		set_page_young(page);
-
-	set_page_idle(page);
-	put_page(page);
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
-}
-
 static int damon_mkold_pmd_entry(pmd_t *pmd, unsigned long addr,
 		unsigned long next, struct mm_walk *walk)
 {
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/7] mm/damon: Implement primitives for physical address space monitoring
  2021-10-12 20:57 [PATCH 0/7] DAMON: Support Physical Memory Address Space Monitoring SeongJae Park
                   ` (3 preceding siblings ...)
  2021-10-12 20:57 ` [PATCH 4/7] mm/damon/vaddr: Separate commonly usable functions SeongJae Park
@ 2021-10-12 20:57 ` SeongJae Park
  2021-10-12 20:57 ` [PATCH 6/7] mm/damon/dbgfs: Support physical memory monitoring SeongJae Park
  2021-10-12 20:57 ` [PATCH 7/7] Docs/DAMON: Document physical memory monitoring support SeongJae Park
  6 siblings, 0 replies; 10+ messages in thread
From: SeongJae Park @ 2021-10-12 20:57 UTC (permalink / raw)
  To: akpm
  Cc: SeongJae Park, Jonathan.Cameron, amit, benh, corbet, david, dwmw,
	elver, foersleo, gthelen, markubo, rientjes, shakeelb, shuah,
	linux-damon, linux-mm, linux-doc, linux-kernel

This commit implements the monitoring primitives for the physical memory
address space.  Internally, it uses the PTE Accessed bit, similar to
that of the virtual address spaces monitoring primitives.  It supports
only user memory pages, as idle pages tracking does.  If the monitoring
target physical memory address range contains non-user memory pages,
access check of the pages will do nothing but simply treat the pages as
not accessed.

Signed-off-by: SeongJae Park <sj@kernel.org>
---
 include/linux/damon.h |  10 ++
 mm/damon/Kconfig      |   8 ++
 mm/damon/Makefile     |   1 +
 mm/damon/paddr.c      | 224 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 243 insertions(+)
 create mode 100644 mm/damon/paddr.c

diff --git a/include/linux/damon.h b/include/linux/damon.h
index f301bb53381c..715dadd21f7c 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -351,4 +351,14 @@ 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);
+void damon_pa_set_primitives(struct damon_ctx *ctx);
+
+#endif	/* CONFIG_DAMON_PADDR */
+
 #endif	/* _DAMON_H */
diff --git a/mm/damon/Kconfig b/mm/damon/Kconfig
index ba8898c7eb8e..2a5923be631e 100644
--- a/mm/damon/Kconfig
+++ b/mm/damon/Kconfig
@@ -32,6 +32,14 @@ config DAMON_VADDR
 	  This builds the default data access monitoring primitives for DAMON
 	  that work for virtual address spaces.
 
+config DAMON_PADDR
+	bool "Data access monitoring primitives for the physical address space"
+	depends on DAMON && MMU
+	select PAGE_IDLE_FLAG
+	help
+	  This builds the default data access monitoring primitives for DAMON
+	  that works for the physical address space.
+
 config DAMON_VADDR_KUNIT_TEST
 	bool "Test for DAMON primitives" if !KUNIT_ALL_TESTS
 	depends on DAMON_VADDR && KUNIT=y
diff --git a/mm/damon/Makefile b/mm/damon/Makefile
index 99b1bfe01ff5..8d9b0df79702 100644
--- a/mm/damon/Makefile
+++ b/mm/damon/Makefile
@@ -2,4 +2,5 @@
 
 obj-$(CONFIG_DAMON)		:= core.o
 obj-$(CONFIG_DAMON_VADDR)	+= prmtv-common.o vaddr.o
+obj-$(CONFIG_DAMON_PADDR)	+= prmtv-common.o paddr.o
 obj-$(CONFIG_DAMON_DBGFS)	+= dbgfs.o
diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
new file mode 100644
index 000000000000..d7a2ecd09ed0
--- /dev/null
+++ b/mm/damon/paddr.c
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DAMON Primitives for The Physical Address Space
+ *
+ * Author: SeongJae Park <sj@kernel.org>
+ */
+
+#define pr_fmt(fmt) "damon-pa: " fmt
+
+#include <linux/mmu_notifier.h>
+#include <linux/page_idle.h>
+#include <linux/pagemap.h>
+#include <linux/rmap.h>
+
+#include "prmtv-common.h"
+
+static bool __damon_pa_mkold(struct page *page, struct vm_area_struct *vma,
+		unsigned long addr, void *arg)
+{
+	struct page_vma_mapped_walk pvmw = {
+		.page = page,
+		.vma = vma,
+		.address = addr,
+	};
+
+	while (page_vma_mapped_walk(&pvmw)) {
+		addr = pvmw.address;
+		if (pvmw.pte)
+			damon_ptep_mkold(pvmw.pte, vma->vm_mm, addr);
+		else
+			damon_pmdp_mkold(pvmw.pmd, vma->vm_mm, addr);
+	}
+	return true;
+}
+
+static void damon_pa_mkold(unsigned long paddr)
+{
+	struct page *page = damon_get_page(PHYS_PFN(paddr));
+	struct rmap_walk_control rwc = {
+		.rmap_one = __damon_pa_mkold,
+		.anon_lock = page_lock_anon_vma_read,
+	};
+	bool need_lock;
+
+	if (!page)
+		return;
+
+	if (!page_mapped(page) || !page_rmapping(page)) {
+		set_page_idle(page);
+		goto out;
+	}
+
+	need_lock = !PageAnon(page) || PageKsm(page);
+	if (need_lock && !trylock_page(page))
+		goto out;
+
+	rmap_walk(page, &rwc);
+
+	if (need_lock)
+		unlock_page(page);
+
+out:
+	put_page(page);
+}
+
+static void __damon_pa_prepare_access_check(struct damon_ctx *ctx,
+					    struct damon_region *r)
+{
+	r->sampling_addr = damon_rand(r->ar.start, r->ar.end);
+
+	damon_pa_mkold(r->sampling_addr);
+}
+
+void damon_pa_prepare_access_checks(struct damon_ctx *ctx)
+{
+	struct damon_target *t;
+	struct damon_region *r;
+
+	damon_for_each_target(t, ctx) {
+		damon_for_each_region(r, t)
+			__damon_pa_prepare_access_check(ctx, r);
+	}
+}
+
+struct damon_pa_access_chk_result {
+	unsigned long page_sz;
+	bool accessed;
+};
+
+static bool __damon_pa_young(struct page *page, struct vm_area_struct *vma,
+		unsigned long addr, void *arg)
+{
+	struct damon_pa_access_chk_result *result = arg;
+	struct page_vma_mapped_walk pvmw = {
+		.page = page,
+		.vma = vma,
+		.address = addr,
+	};
+
+	result->accessed = false;
+	result->page_sz = PAGE_SIZE;
+	while (page_vma_mapped_walk(&pvmw)) {
+		addr = pvmw.address;
+		if (pvmw.pte) {
+			result->accessed = pte_young(*pvmw.pte) ||
+				!page_is_idle(page) ||
+				mmu_notifier_test_young(vma->vm_mm, addr);
+		} else {
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+			result->accessed = pmd_young(*pvmw.pmd) ||
+				!page_is_idle(page) ||
+				mmu_notifier_test_young(vma->vm_mm, addr);
+			result->page_sz = ((1UL) << HPAGE_PMD_SHIFT);
+#else
+			WARN_ON_ONCE(1);
+#endif	/* CONFIG_TRANSPARENT_HUGEPAGE */
+		}
+		if (result->accessed) {
+			page_vma_mapped_walk_done(&pvmw);
+			break;
+		}
+	}
+
+	/* If accessed, stop walking */
+	return !result->accessed;
+}
+
+static bool damon_pa_young(unsigned long paddr, unsigned long *page_sz)
+{
+	struct page *page = damon_get_page(PHYS_PFN(paddr));
+	struct damon_pa_access_chk_result result = {
+		.page_sz = PAGE_SIZE,
+		.accessed = false,
+	};
+	struct rmap_walk_control rwc = {
+		.arg = &result,
+		.rmap_one = __damon_pa_young,
+		.anon_lock = page_lock_anon_vma_read,
+	};
+	bool need_lock;
+
+	if (!page)
+		return false;
+
+	if (!page_mapped(page) || !page_rmapping(page)) {
+		if (page_is_idle(page))
+			result.accessed = false;
+		else
+			result.accessed = true;
+		put_page(page);
+		goto out;
+	}
+
+	need_lock = !PageAnon(page) || PageKsm(page);
+	if (need_lock && !trylock_page(page)) {
+		put_page(page);
+		return NULL;
+	}
+
+	rmap_walk(page, &rwc);
+
+	if (need_lock)
+		unlock_page(page);
+	put_page(page);
+
+out:
+	*page_sz = result.page_sz;
+	return result.accessed;
+}
+
+static void __damon_pa_check_access(struct damon_ctx *ctx,
+				    struct damon_region *r)
+{
+	static unsigned long last_addr;
+	static unsigned long last_page_sz = PAGE_SIZE;
+	static bool last_accessed;
+
+	/* If the region is in the last checked page, reuse the result */
+	if (ALIGN_DOWN(last_addr, last_page_sz) ==
+				ALIGN_DOWN(r->sampling_addr, last_page_sz)) {
+		if (last_accessed)
+			r->nr_accesses++;
+		return;
+	}
+
+	last_accessed = damon_pa_young(r->sampling_addr, &last_page_sz);
+	if (last_accessed)
+		r->nr_accesses++;
+
+	last_addr = r->sampling_addr;
+}
+
+unsigned int damon_pa_check_accesses(struct damon_ctx *ctx)
+{
+	struct damon_target *t;
+	struct damon_region *r;
+	unsigned int max_nr_accesses = 0;
+
+	damon_for_each_target(t, ctx) {
+		damon_for_each_region(r, t) {
+			__damon_pa_check_access(ctx, r);
+			max_nr_accesses = max(r->nr_accesses, max_nr_accesses);
+		}
+	}
+
+	return max_nr_accesses;
+}
+
+bool damon_pa_target_valid(void *t)
+{
+	return true;
+}
+
+void damon_pa_set_primitives(struct damon_ctx *ctx)
+{
+	ctx->primitive.init = NULL;
+	ctx->primitive.update = NULL;
+	ctx->primitive.prepare_access_checks = damon_pa_prepare_access_checks;
+	ctx->primitive.check_accesses = damon_pa_check_accesses;
+	ctx->primitive.reset_aggregated = NULL;
+	ctx->primitive.target_valid = damon_pa_target_valid;
+	ctx->primitive.cleanup = NULL;
+	ctx->primitive.apply_scheme = NULL;
+}
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 6/7] mm/damon/dbgfs: Support physical memory monitoring
  2021-10-12 20:57 [PATCH 0/7] DAMON: Support Physical Memory Address Space Monitoring SeongJae Park
                   ` (4 preceding siblings ...)
  2021-10-12 20:57 ` [PATCH 5/7] mm/damon: Implement primitives for physical address space monitoring SeongJae Park
@ 2021-10-12 20:57 ` SeongJae Park
  2021-10-12 20:57 ` [PATCH 7/7] Docs/DAMON: Document physical memory monitoring support SeongJae Park
  6 siblings, 0 replies; 10+ messages in thread
From: SeongJae Park @ 2021-10-12 20:57 UTC (permalink / raw)
  To: akpm
  Cc: SeongJae Park, Jonathan.Cameron, amit, benh, corbet, david, dwmw,
	elver, foersleo, gthelen, markubo, rientjes, shakeelb, shuah,
	linux-damon, linux-mm, linux-doc, linux-kernel

This commit makes the 'damon-dbgfs' to support the physical memory
monitoring, in addition to the virtual memory monitoring.

Users can do the physical memory monitoring by writing a special
keyword, 'paddr\n' to the 'target_ids' debugfs file.  Then, DAMON will
check the special keyword and configure the monitoring context to run
with the primitives for the physical address space.

Unlike the virtual memory monitoring, the monitoring target region will
not be automatically set.  Therefore, users should also set the
monitoring target address region using the 'init_regions' debugfs file.

Also, note that the physical memory monitoring will not automatically
terminated.  The user should explicitly turn off the monitoring by
writing 'off' to the 'monitor_on' debugfs file.

Signed-off-by: SeongJae Park <sj@kernel.org>
---
 mm/damon/Kconfig |  2 +-
 mm/damon/dbgfs.c | 21 ++++++++++++++++++---
 2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/mm/damon/Kconfig b/mm/damon/Kconfig
index 2a5923be631e..ca33b289ebbe 100644
--- a/mm/damon/Kconfig
+++ b/mm/damon/Kconfig
@@ -54,7 +54,7 @@ config DAMON_VADDR_KUNIT_TEST
 
 config DAMON_DBGFS
 	bool "DAMON debugfs interface"
-	depends on DAMON_VADDR && DEBUG_FS
+	depends on DAMON_VADDR && DAMON_PADDR && DEBUG_FS
 	help
 	  This builds the debugfs interface for DAMON.  The user space admins
 	  can use the interface for arbitrary data access monitoring.
diff --git a/mm/damon/dbgfs.c b/mm/damon/dbgfs.c
index 1cce53cd241d..38188347d8ab 100644
--- a/mm/damon/dbgfs.c
+++ b/mm/damon/dbgfs.c
@@ -339,6 +339,7 @@ static ssize_t dbgfs_target_ids_write(struct file *file,
 		const char __user *buf, size_t count, loff_t *ppos)
 {
 	struct damon_ctx *ctx = file->private_data;
+	bool id_is_pid = true;
 	char *kbuf, *nrs;
 	unsigned long *targets;
 	ssize_t nr_targets;
@@ -351,6 +352,11 @@ static ssize_t dbgfs_target_ids_write(struct file *file,
 		return PTR_ERR(kbuf);
 
 	nrs = kbuf;
+	if (!strncmp(kbuf, "paddr\n", count)) {
+		id_is_pid = false;
+		/* target id is meaningless here, but we set it just for fun */
+		scnprintf(kbuf, count, "42    ");
+	}
 
 	targets = str_to_target_ids(nrs, ret, &nr_targets);
 	if (!targets) {
@@ -358,7 +364,7 @@ static ssize_t dbgfs_target_ids_write(struct file *file,
 		goto out;
 	}
 
-	if (targetid_is_pid(ctx)) {
+	if (id_is_pid) {
 		for (i = 0; i < nr_targets; i++) {
 			targets[i] = (unsigned long)find_get_pid(
 					(int)targets[i]);
@@ -372,15 +378,24 @@ static ssize_t dbgfs_target_ids_write(struct file *file,
 
 	mutex_lock(&ctx->kdamond_lock);
 	if (ctx->kdamond) {
-		if (targetid_is_pid(ctx))
+		if (id_is_pid)
 			dbgfs_put_pids(targets, nr_targets);
 		ret = -EBUSY;
 		goto unlock_out;
 	}
 
+	/* remove targets with previously-set primitive */
+	damon_set_targets(ctx, NULL, 0);
+
+	/* Configure the context for the address space type */
+	if (id_is_pid)
+		damon_va_set_primitives(ctx);
+	else
+		damon_pa_set_primitives(ctx);
+
 	err = damon_set_targets(ctx, targets, nr_targets);
 	if (err) {
-		if (targetid_is_pid(ctx))
+		if (id_is_pid)
 			dbgfs_put_pids(targets, nr_targets);
 		ret = err;
 	}
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 7/7] Docs/DAMON: Document physical memory monitoring support
  2021-10-12 20:57 [PATCH 0/7] DAMON: Support Physical Memory Address Space Monitoring SeongJae Park
                   ` (5 preceding siblings ...)
  2021-10-12 20:57 ` [PATCH 6/7] mm/damon/dbgfs: Support physical memory monitoring SeongJae Park
@ 2021-10-12 20:57 ` SeongJae Park
  6 siblings, 0 replies; 10+ messages in thread
From: SeongJae Park @ 2021-10-12 20:57 UTC (permalink / raw)
  To: akpm
  Cc: SeongJae Park, Jonathan.Cameron, amit, benh, corbet, david, dwmw,
	elver, foersleo, gthelen, markubo, rientjes, shakeelb, shuah,
	linux-damon, linux-mm, linux-doc, linux-kernel

This commit updates the DAMON documents for the physical memory address
space monitoring support.

Signed-off-by: SeongJae Park <sj@kernel.org>
---
 Documentation/admin-guide/mm/damon/usage.rst | 25 +++++++++++++----
 Documentation/vm/damon/design.rst            | 29 ++++++++++++--------
 Documentation/vm/damon/faq.rst               |  5 ++--
 3 files changed, 40 insertions(+), 19 deletions(-)

diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst
index f7d5cfbb50c2..ed96bbf0daff 100644
--- a/Documentation/admin-guide/mm/damon/usage.rst
+++ b/Documentation/admin-guide/mm/damon/usage.rst
@@ -10,15 +10,16 @@ DAMON provides below three interfaces for different users.
   This is for privileged people such as system administrators who want a
   just-working human-friendly interface.  Using this, users can use the DAMON’s
   major features in a human-friendly way.  It may not be highly tuned for
-  special cases, though.  It supports only virtual address spaces monitoring.
+  special cases, though.  It supports both virtual and physical address spaces
+  monitoring.
 - *debugfs interface.*
   This is for privileged user space programmers who want more optimized use of
   DAMON.  Using this, users can use DAMON’s major features by reading
   from and writing to special debugfs files.  Therefore, you can write and use
   your personalized DAMON debugfs wrapper programs that reads/writes the
   debugfs files instead of you.  The DAMON user space tool is also a reference
-  implementation of such programs.  It supports only virtual address spaces
-  monitoring.
+  implementation of such programs.  It supports both virtual and physical
+  address spaces monitoring.
 - *Kernel Space Programming Interface.*
   This is for kernel space programmers.  Using this, users can utilize every
   feature of DAMON most flexibly and efficiently by writing kernel space
@@ -72,20 +73,34 @@ check it again::
     # cat target_ids
     42 4242
 
+Users can also monitor the physical memory address space of the system by
+writing a special keyword, "``paddr\n``" to the file.  Because physical address
+space monitoring doesn't support multiple targets, reading the file will show a
+fake value, ``42``, as below::
+
+    # cd <debugfs>/damon
+    # echo paddr > target_ids
+    # cat target_ids
+    42
+
 Note that setting the target ids doesn't start the monitoring.
 
 
 Initial Monitoring Target Regions
 ---------------------------------
 
-In case of the debugfs based monitoring, DAMON automatically sets and updates
-the monitoring target regions so that entire memory mappings of target
+In case of the virtual address space monitoring, DAMON automatically sets and
+updates the monitoring target regions so that entire memory mappings of target
 processes can be covered.  However, users can want to limit the monitoring
 region to specific address ranges, such as the heap, the stack, or specific
 file-mapped area.  Or, some users can know the initial access pattern of their
 workloads and therefore want to set optimal initial regions for the 'adaptive
 regions adjustment'.
 
+In contrast, DAMON do not automatically sets and updates the monitoring target
+regions in case of physical memory monitoring.  Therefore, users should set the
+monitoring target regions by themselves.
+
 In such cases, users can explicitly set the initial monitoring target regions
 as they want, by writing proper values to the ``init_regions`` file.  Each line
 of the input should represent one region in below form.::
diff --git a/Documentation/vm/damon/design.rst b/Documentation/vm/damon/design.rst
index b05159c295f4..210f0f50efd8 100644
--- a/Documentation/vm/damon/design.rst
+++ b/Documentation/vm/damon/design.rst
@@ -35,13 +35,17 @@ two parts:
 1. Identification of the monitoring target address range for the address space.
 2. Access check of specific address range in the target space.
 
-DAMON currently provides the implementation of the primitives for only the
-virtual address spaces. Below two subsections describe how it works.
+DAMON currently provides the implementations of the primitives for the physical
+and virtual address spaces. Below two subsections describe how those work.
 
 
 VMA-based Target Address Range Construction
 -------------------------------------------
 
+This is only for the virtual address space primitives implementation.  That for
+the physical address space simply asks users to manually set the monitoring
+target address ranges.
+
 Only small parts in the super-huge virtual address space of the processes are
 mapped to the physical memory and accessed.  Thus, tracking the unmapped
 address regions is just wasteful.  However, because DAMON can deal with some
@@ -71,15 +75,18 @@ to make a reasonable trade-off.  Below shows this in detail::
 PTE Accessed-bit Based Access Check
 -----------------------------------
 
-The implementation for the virtual address space uses PTE Accessed-bit for
-basic access checks.  It finds the relevant PTE Accessed bit from the address
-by walking the page table for the target task of the address.  In this way, the
-implementation finds and clears the bit for next sampling target address and
-checks whether the bit set again after one sampling period.  This could disturb
-other kernel subsystems using the Accessed bits, namely Idle page tracking and
-the reclaim logic.  To avoid such disturbances, DAMON makes it mutually
-exclusive with Idle page tracking and uses ``PG_idle`` and ``PG_young`` page
-flags to solve the conflict with the reclaim logic, as Idle page tracking does.
+Both of the implementations for physical and virtual address spaces use PTE
+Accessed-bit for basic access checks.  Only one difference is the way of
+finding the relevant PTE Accessed bit(s) from the address.  While the
+implementation for the virtual address walks the page table for the target task
+of the address, the implementation for the physical address walks every page
+table having a mapping to the address.  In this way, the implementations find
+and clear the bit(s) for next sampling target address and checks whether the
+bit(s) set again after one sampling period.  This could disturb other kernel
+subsystems using the Accessed bits, namely Idle page tracking and the reclaim
+logic.  To avoid such disturbances, DAMON makes it mutually exclusive with Idle
+page tracking and uses ``PG_idle`` and ``PG_young`` page flags to solve the
+conflict with the reclaim logic, as Idle page tracking does.
 
 
 Address Space Independent Core Mechanisms
diff --git a/Documentation/vm/damon/faq.rst b/Documentation/vm/damon/faq.rst
index cb3d8b585a8b..11aea40eb328 100644
--- a/Documentation/vm/damon/faq.rst
+++ b/Documentation/vm/damon/faq.rst
@@ -36,10 +36,9 @@ constructions and actual access checks can be implemented and configured on the
 DAMON core by the users.  In this way, DAMON users can monitor any address
 space with any access check technique.
 
-Nonetheless, DAMON provides vma tracking and PTE Accessed bit check based
+Nonetheless, DAMON provides vma/rmap tracking and PTE Accessed bit check based
 implementations of the address space dependent functions for the virtual memory
-by default, for a reference and convenient use.  In near future, we will
-provide those for physical memory address space.
+and the physical memory by default, for a reference and convenient use.
 
 
 Can I simply monitor page granularity?
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/7] mm/damon/dbgfs: Allow users to set initial monitoring target regions
  2021-10-12 20:57 ` [PATCH 1/7] mm/damon/dbgfs: Allow users to set initial monitoring target regions SeongJae Park
@ 2021-10-13 22:45   ` Andrew Morton
  2021-10-14  6:45     ` SeongJae Park
  0 siblings, 1 reply; 10+ messages in thread
From: Andrew Morton @ 2021-10-13 22:45 UTC (permalink / raw)
  To: SeongJae Park
  Cc: Jonathan.Cameron, amit, benh, corbet, david, dwmw, elver,
	foersleo, gthelen, markubo, rientjes, shakeelb, shuah,
	linux-damon, linux-mm, linux-doc, linux-kernel

On Tue, 12 Oct 2021 20:57:05 +0000 SeongJae Park <sj@kernel.org> wrote:

> Some 'damon-dbgfs' users would want to monitor only a part of the entire
> virtual memory address space.  The program interface users in the kernel
> space could use '->before_start()' callback or set the regions inside
> the context struct as they want, but 'damon-dbgfs' users cannot.
> 
> For the reason, this commit introduces a new debugfs file called
> 'init_region'.  'damon-dbgfs' users can specify which initial monitoring
> target address regions they want by writing special input to the file.
> The input should describe each region in each line in the below form:
> 
>     <pid> <start address> <end address>
> 
> Note that the regions will be updated to cover entire memory mapped
> regions after a 'regions update interval' is passed.  If you want the
> regions to not be updated after the initial setting, you could set the
> interval as a very long time, say, a few decades.
> 
> ...
>
> +static int add_init_region(struct damon_ctx *c,
> +			 unsigned long target_id, struct damon_addr_range *ar)
> +{
> +	struct damon_target *t;
> +	struct damon_region *r, *prev;
> +	unsigned long id;
> +	int rc = -EINVAL;
> +
> +	if (ar->start >= ar->end)
> +		return -EINVAL;
> +
> +	damon_for_each_target(t, c) {
> +		id = t->id;
> +		if (targetid_is_pid(c))
> +			id = (unsigned long)pid_vnr((struct pid *)id);

This is a bit ugly.  Did you consider making damon_target.id a union of
all the possible types it can contain?  This will avoid typecasts, has
documentation value and reflacts what is actually going on.

> +		if (id == target_id) {
> +			r = damon_new_region(ar->start, ar->end);
> +			if (!r)
> +				return -ENOMEM;
> +			damon_add_region(r, t);
> +			if (damon_nr_regions(t) > 1) {
> +				prev = damon_prev_region(r);
> +				if (prev->ar.end > r->ar.start) {
> +					damon_destroy_region(r, t);
> +					return -EINVAL;
> +				}
> +			}
> +			rc = 0;
> +		}
> +	}
> +	return rc;
> +}
> +



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/7] mm/damon/dbgfs: Allow users to set initial monitoring target regions
  2021-10-13 22:45   ` Andrew Morton
@ 2021-10-14  6:45     ` SeongJae Park
  0 siblings, 0 replies; 10+ messages in thread
From: SeongJae Park @ 2021-10-14  6:45 UTC (permalink / raw)
  To: Andrew Morton
  Cc: SeongJae Park, Jonathan.Cameron, amit, benh, corbet, david, dwmw,
	elver, foersleo, gthelen, markubo, rientjes, shakeelb, shuah,
	linux-damon, linux-mm, linux-doc, linux-kernel

On Wed, 13 Oct 2021 15:45:35 -0700 Andrew Morton <akpm@linux-foundation.org> wrote:

> On Tue, 12 Oct 2021 20:57:05 +0000 SeongJae Park <sj@kernel.org> wrote:
> 
> > Some 'damon-dbgfs' users would want to monitor only a part of the entire
> > virtual memory address space.  The program interface users in the kernel
> > space could use '->before_start()' callback or set the regions inside
> > the context struct as they want, but 'damon-dbgfs' users cannot.
> > 
> > For the reason, this commit introduces a new debugfs file called
> > 'init_region'.  'damon-dbgfs' users can specify which initial monitoring
> > target address regions they want by writing special input to the file.
> > The input should describe each region in each line in the below form:
> > 
> >     <pid> <start address> <end address>
> > 
> > Note that the regions will be updated to cover entire memory mapped
> > regions after a 'regions update interval' is passed.  If you want the
> > regions to not be updated after the initial setting, you could set the
> > interval as a very long time, say, a few decades.
> > 
> > ...
> >
> > +static int add_init_region(struct damon_ctx *c,
> > +			 unsigned long target_id, struct damon_addr_range *ar)
> > +{
> > +	struct damon_target *t;
> > +	struct damon_region *r, *prev;
> > +	unsigned long id;
> > +	int rc = -EINVAL;
> > +
> > +	if (ar->start >= ar->end)
> > +		return -EINVAL;
> > +
> > +	damon_for_each_target(t, c) {
> > +		id = t->id;
> > +		if (targetid_is_pid(c))
> > +			id = (unsigned long)pid_vnr((struct pid *)id);
> 
> This is a bit ugly.  Did you consider making damon_target.id a union of
> all the possible types it can contain?  This will avoid typecasts, has
> documentation value and reflacts what is actually going on.

Agreed, thank you for this great comment!  I will make it at least before
adding another type of monitoring target.


Thanks,
SJ

> 
> > +		if (id == target_id) {
> > +			r = damon_new_region(ar->start, ar->end);
> > +			if (!r)
> > +				return -ENOMEM;
> > +			damon_add_region(r, t);
> > +			if (damon_nr_regions(t) > 1) {
> > +				prev = damon_prev_region(r);
> > +				if (prev->ar.end > r->ar.start) {
> > +					damon_destroy_region(r, t);
> > +					return -EINVAL;
> > +				}
> > +			}
> > +			rc = 0;
> > +		}
> > +	}
> > +	return rc;
> > +}
> > +
> 
> 


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2021-10-14  6:45 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-12 20:57 [PATCH 0/7] DAMON: Support Physical Memory Address Space Monitoring SeongJae Park
2021-10-12 20:57 ` [PATCH 1/7] mm/damon/dbgfs: Allow users to set initial monitoring target regions SeongJae Park
2021-10-13 22:45   ` Andrew Morton
2021-10-14  6:45     ` SeongJae Park
2021-10-12 20:57 ` [PATCH 2/7] mm/damon/dbgfs-test: Add a unit test case for 'init_regions' SeongJae Park
2021-10-12 20:57 ` [PATCH 3/7] Docs/admin-guide/mm/damon: Document 'init_regions' feature SeongJae Park
2021-10-12 20:57 ` [PATCH 4/7] mm/damon/vaddr: Separate commonly usable functions SeongJae Park
2021-10-12 20:57 ` [PATCH 5/7] mm/damon: Implement primitives for physical address space monitoring SeongJae Park
2021-10-12 20:57 ` [PATCH 6/7] mm/damon/dbgfs: Support physical memory monitoring SeongJae Park
2021-10-12 20:57 ` [PATCH 7/7] Docs/DAMON: Document physical memory monitoring support SeongJae Park

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).