Commit 739100c8 authored by Stefan Roesch's avatar Stefan Roesch Committed by Andrew Morton
Browse files

mm: add tracepoints to ksm

This adds the following tracepoints to ksm:
- start / stop scan
- ksm enter / exit
- merge a page
- merge a page with ksm
- remove a page
- remove a rmap item

This patch has been split off from the RFC patch series "mm:
process/cgroup ksm support".

Link: https://lkml.kernel.org/r/20230210214645.2720847-1-shr@devkernel.io


Signed-off-by: default avatarStefan Roesch <shr@devkernel.io>
Reviewed-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 77f68ebe
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -13409,6 +13409,7 @@ F: include/linux/memory_hotplug.h
F:	include/linux/mm.h
F:	include/linux/mmzone.h
F:	include/linux/pagewalk.h
F:	include/trace/events/ksm.h
F:	mm/
F:	tools/mm/
F:	tools/testing/selftests/mm/
+251 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM ksm

#if !defined(_TRACE_KSM_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_KSM_H

#include <linux/tracepoint.h>

/**
 * ksm_scan_template - called for start / stop scan
 *
 * @seq:		sequence number of scan
 * @rmap_entries:	actual number of rmap entries
 *
 * Allows to trace the start / stop of a ksm scan.
 */
DECLARE_EVENT_CLASS(ksm_scan_template,

	TP_PROTO(int seq, u32 rmap_entries),

	TP_ARGS(seq, rmap_entries),

	TP_STRUCT__entry(
		__field(int,	seq)
		__field(u32,	rmap_entries)
	),

	TP_fast_assign(
		__entry->seq		= seq;
		__entry->rmap_entries	= rmap_entries;
	),

	TP_printk("seq %d rmap size %d",
			__entry->seq, __entry->rmap_entries)
);

/**
 * ksm_start_scan - called after a new ksm scan is started
 *
 * @seq:		sequence number of scan
 * @rmap_entries:	actual number of rmap entries
 *
 * Allows to trace the start of a ksm scan.
 */
DEFINE_EVENT(ksm_scan_template, ksm_start_scan,

	TP_PROTO(int seq, u32 rmap_entries),

	TP_ARGS(seq, rmap_entries)
);

/**
 * ksm_stop_scan - called after a new ksm scan has completed
 *
 * @seq:		sequence number of scan
 * @rmap_entries:	actual number of rmap entries
 *
 * Allows to trace the completion of a ksm scan.
 */
DEFINE_EVENT(ksm_scan_template, ksm_stop_scan,

	TP_PROTO(int seq, u32 rmap_entries),

	TP_ARGS(seq, rmap_entries)
);

/**
 * ksm_enter - called after a new process has been added / removed from ksm
 *
 * @mm:			address of the mm object of the process
 *
 * Allows to trace the when a process has been added or removed from ksm.
 */
DECLARE_EVENT_CLASS(ksm_enter_exit_template,

	TP_PROTO(void *mm),

	TP_ARGS(mm),

	TP_STRUCT__entry(
		__field(void *,		mm)
	),

	TP_fast_assign(
		__entry->mm	= mm;
	),

	TP_printk("mm %p", __entry->mm)
);

/**
 * ksm_enter - called after a new process has been added to ksm
 *
 * @mm:			address of the mm object of the process
 *
 * Allows to trace the when a process has been added to ksm.
 */
DEFINE_EVENT(ksm_enter_exit_template, ksm_enter,

	TP_PROTO(void *mm),

	TP_ARGS(mm)
);

/**
 * ksm_exit - called after a new process has been removed from ksm
 *
 * @mm:			address of the mm object of the process
 *
 * Allows to trace the when a process has been removed from ksm.
 */
DEFINE_EVENT(ksm_enter_exit_template, ksm_exit,

	TP_PROTO(void *mm),

	TP_ARGS(mm)
);

/**
 * ksm_merge_one_page - called after a page has been merged
 *
 * @pfn:		page frame number of ksm page
 * @rmap_item:		address of rmap_item  object
 * @mm:			address of the process mm struct
 * @err:		success
 *
 * Allows to trace the ksm merging of individual pages.
 */
TRACE_EVENT(ksm_merge_one_page,

	TP_PROTO(unsigned long pfn, void *rmap_item, void *mm, int err),

	TP_ARGS(pfn, rmap_item, mm, err),

	TP_STRUCT__entry(
		__field(unsigned long,	pfn)
		__field(void *,		rmap_item)
		__field(void *,		mm)
		__field(int,		err)
	),

	TP_fast_assign(
		__entry->pfn		= pfn;
		__entry->rmap_item	= rmap_item;
		__entry->mm		= mm;
		__entry->err		= err;
	),

	TP_printk("ksm pfn %lu rmap_item %p mm %p error %d",
			__entry->pfn, __entry->rmap_item, __entry->mm, __entry->err)
);

/**
 * ksm_merge_with_ksm_page - called after a page has been merged with a ksm page
 *
 * @ksm_page:		address ksm page
 * @pfn:		page frame number of ksm page
 * @rmap_item:		address of rmap_item  object
 * @mm:			address of the mm object of the process
 * @err:		success
 *
 * Allows to trace the merging of a page with a ksm page.
 */
TRACE_EVENT(ksm_merge_with_ksm_page,

	TP_PROTO(void *ksm_page, unsigned long pfn, void *rmap_item, void *mm, int err),

	TP_ARGS(ksm_page, pfn, rmap_item, mm, err),

	TP_STRUCT__entry(
		__field(void *,		ksm_page)
		__field(unsigned long,	pfn)
		__field(void *,		rmap_item)
		__field(void *,		mm)
		__field(int,		err)
	),

	TP_fast_assign(
		__entry->ksm_page	= ksm_page;
		__entry->pfn		= pfn;
		__entry->rmap_item	= rmap_item;
		__entry->mm		= mm;
		__entry->err		= err;
	),

	TP_printk("%spfn %lu rmap_item %p mm %p error %d",
		  (__entry->ksm_page ? "ksm " : ""),
		  __entry->pfn, __entry->rmap_item, __entry->mm, __entry->err)
);

/**
 * ksm_remove_ksm_page - called after a ksm page has been removed
 *
 * @pfn:		page frame number of ksm page
 *
 * Allows to trace the removing of stable ksm pages.
 */
TRACE_EVENT(ksm_remove_ksm_page,

	TP_PROTO(unsigned long pfn),

	TP_ARGS(pfn),

	TP_STRUCT__entry(
		__field(unsigned long, pfn)
	),

	TP_fast_assign(
		__entry->pfn = pfn;
	),

	TP_printk("pfn %lu", __entry->pfn)
);

/**
 * ksm_remove_rmap_item - called after a rmap_item has been removed from the
 *                        stable tree
 *
 * @pfn:		page frame number of ksm page
 * @rmap_item:		address of rmap_item  object
 * @mm:			address of the process mm struct
 *
 * Allows to trace the removal of pages from the stable tree list.
 */
TRACE_EVENT(ksm_remove_rmap_item,

	TP_PROTO(unsigned long pfn, void *rmap_item, void *mm),

	TP_ARGS(pfn, rmap_item, mm),

	TP_STRUCT__entry(
		__field(unsigned long,	pfn)
		__field(void *,		rmap_item)
		__field(void *,		mm)
	),

	TP_fast_assign(
		__entry->pfn		= pfn;
		__entry->rmap_item	= rmap_item;
		__entry->mm		= mm;
	),

	TP_printk("pfn %lu rmap_item %p mm %p",
			__entry->pfn, __entry->rmap_item, __entry->mm)
);

#endif /* _TRACE_KSM_H */

/* This part must be outside protection */
#include <trace/define_trace.h>
+19 −2
Original line number Diff line number Diff line
@@ -45,6 +45,9 @@
#include "internal.h"
#include "mm_slot.h"

#define CREATE_TRACE_POINTS
#include <trace/events/ksm.h>

#ifdef CONFIG_NUMA
#define NUMA(x)		(x)
#define DO_NUMA(x)	do { (x); } while (0)
@@ -633,10 +636,12 @@ static void remove_node_from_stable_tree(struct ksm_stable_node *stable_node)
	BUG_ON(stable_node->rmap_hlist_len < 0);

	hlist_for_each_entry(rmap_item, &stable_node->hlist, hlist) {
		if (rmap_item->hlist.next)
		if (rmap_item->hlist.next) {
			ksm_pages_sharing--;
		else
			trace_ksm_remove_rmap_item(stable_node->kpfn, rmap_item, rmap_item->mm);
		} else {
			ksm_pages_shared--;
		}

		rmap_item->mm->ksm_merging_pages--;

@@ -657,6 +662,7 @@ static void remove_node_from_stable_tree(struct ksm_stable_node *stable_node)
	BUILD_BUG_ON(STABLE_NODE_DUP_HEAD <= &migrate_nodes);
	BUILD_BUG_ON(STABLE_NODE_DUP_HEAD >= &migrate_nodes + 1);

	trace_ksm_remove_ksm_page(stable_node->kpfn);
	if (stable_node->head == &migrate_nodes)
		list_del(&stable_node->list);
	else
@@ -1324,6 +1330,8 @@ static int try_to_merge_with_ksm_page(struct ksm_rmap_item *rmap_item,
	get_anon_vma(vma->anon_vma);
out:
	mmap_read_unlock(mm);
	trace_ksm_merge_with_ksm_page(kpage, page_to_pfn(kpage ? kpage : page),
				rmap_item, mm, err);
	return err;
}

@@ -2142,6 +2150,9 @@ static void cmp_and_merge_page(struct page *page, struct ksm_rmap_item *rmap_ite
		if (vma) {
			err = try_to_merge_one_page(vma, page,
					ZERO_PAGE(rmap_item->address));
			trace_ksm_merge_one_page(
				page_to_pfn(ZERO_PAGE(rmap_item->address)),
				rmap_item, mm, err);
		} else {
			/*
			 * If the vma is out of date, we do not need to
@@ -2264,6 +2275,8 @@ static struct ksm_rmap_item *scan_get_next_rmap_item(struct page **page)

	mm_slot = ksm_scan.mm_slot;
	if (mm_slot == &ksm_mm_head) {
		trace_ksm_start_scan(ksm_scan.seqnr, ksm_rmap_items);

		/*
		 * A number of pages can hang around indefinitely on per-cpu
		 * pagevecs, raised page count preventing write_protect_page
@@ -2414,6 +2427,7 @@ static struct ksm_rmap_item *scan_get_next_rmap_item(struct page **page)
	if (mm_slot != &ksm_mm_head)
		goto next_mm;

	trace_ksm_stop_scan(ksm_scan.seqnr, ksm_rmap_items);
	ksm_scan.seqnr++;
	return NULL;
}
@@ -2565,6 +2579,7 @@ int __ksm_enter(struct mm_struct *mm)
	if (needs_wakeup)
		wake_up_interruptible(&ksm_thread_wait);

	trace_ksm_enter(mm);
	return 0;
}

@@ -2606,6 +2621,8 @@ void __ksm_exit(struct mm_struct *mm)
		mmap_write_lock(mm);
		mmap_write_unlock(mm);
	}

	trace_ksm_exit(mm);
}

struct page *ksm_might_need_to_copy(struct page *page,