2 #include <linux/mm_event.h>
3 #include <linux/sched.h>
4 #include <linux/vmalloc.h>
5 #include <linux/seq_file.h>
6 #include <linux/debugfs.h>
8 #define CREATE_TRACE_POINTS
9 #include <trace/events/mm_event.h>
11 static unsigned long period_ms __read_mostly
= 500;
12 static unsigned long vmstat_period_ms __read_mostly
= 1000;
13 static unsigned long vmstat_next_period
;
15 static DEFINE_SPINLOCK(vmstat_lock
);
16 static DEFINE_RWLOCK(period_lock
);
18 void mm_event_task_init(struct task_struct
*tsk
)
20 memset(tsk
->mm_event
, 0, sizeof(tsk
->mm_event
));
24 static void record_vmstat(void)
27 struct mm_event_vmstat vmstat
;
29 if (time_is_after_jiffies(vmstat_next_period
))
32 /* Need double check under the lock */
33 spin_lock(&vmstat_lock
);
34 if (time_is_after_jiffies(vmstat_next_period
)) {
35 spin_unlock(&vmstat_lock
);
38 vmstat_next_period
= jiffies
+ msecs_to_jiffies(vmstat_period_ms
);
39 spin_unlock(&vmstat_lock
);
41 memset(&vmstat
, 0, sizeof(vmstat
));
42 vmstat
.free
= global_zone_page_state(NR_FREE_PAGES
);
43 vmstat
.slab
= global_node_page_state(NR_SLAB_RECLAIMABLE
) +
44 global_node_page_state(NR_SLAB_UNRECLAIMABLE
);
46 vmstat
.file
= global_node_page_state(NR_ACTIVE_FILE
) +
47 global_node_page_state(NR_INACTIVE_FILE
);
48 vmstat
.anon
= global_node_page_state(NR_ACTIVE_ANON
) +
49 global_node_page_state(NR_INACTIVE_ANON
);
51 vmstat
.ws_refault
= global_node_page_state(WORKINGSET_REFAULT
);
52 vmstat
.ws_activate
= global_node_page_state(WORKINGSET_ACTIVATE
);
53 vmstat
.mapped
= global_node_page_state(NR_FILE_MAPPED
);
55 /* No want to make lock dependency between vmstat_lock and hotplug */
57 for_each_online_cpu(cpu
) {
58 struct vm_event_state
*this = &per_cpu(vm_event_states
, cpu
);
60 /* sectors to kbytes for PGPGIN/PGPGOUT */
61 vmstat
.pgin
+= this->event
[PGPGIN
] / 2;
62 vmstat
.pgout
+= this->event
[PGPGOUT
] / 2;
63 vmstat
.swpin
+= this->event
[PSWPIN
];
64 vmstat
.swpout
+= this->event
[PSWPOUT
];
65 vmstat
.reclaim_steal
+= this->event
[PGSTEAL_DIRECT
] +
66 this->event
[PGSTEAL_KSWAPD
];
67 vmstat
.reclaim_scan
+= this->event
[PGSCAN_DIRECT
] +
68 this->event
[PGSCAN_KSWAPD
];
69 vmstat
.compact_scan
+= this->event
[COMPACTFREE_SCANNED
] +
70 this->event
[COMPACTFREE_SCANNED
];
73 trace_mm_event_vmstat_record(&vmstat
);
76 static void record_stat(void)
79 bool need_vmstat
= false;
81 if (time_is_after_jiffies(current
->next_period
))
84 read_lock(&period_lock
);
85 current
->next_period
= jiffies
+ msecs_to_jiffies(period_ms
);
86 read_unlock(&period_lock
);
88 for (i
= 0; i
< MM_TYPE_NUM
; i
++) {
89 if (current
->mm_event
[i
].count
== 0)
91 if (i
== MM_COMPACTION
|| i
== MM_RECLAIM
)
93 trace_mm_event_record(i
, ¤t
->mm_event
[i
]);
94 memset(¤t
->mm_event
[i
], 0,
95 sizeof(struct mm_event_task
));
102 void mm_event_start(ktime_t
*time
)
107 void mm_event_end(enum mm_event_type event
, ktime_t start
)
109 s64 elapsed
= ktime_us_delta(ktime_get(), start
);
111 current
->mm_event
[event
].count
++;
112 current
->mm_event
[event
].accm_lat
+= elapsed
;
113 if (elapsed
> current
->mm_event
[event
].max_lat
)
114 current
->mm_event
[event
].max_lat
= elapsed
;
118 void mm_event_count(enum mm_event_type event
, int count
)
120 current
->mm_event
[event
].count
+= count
;
124 static struct dentry
*mm_event_root
;
126 static int period_ms_set(void *data
, u64 val
)
128 if (val
< 1 || val
> ULONG_MAX
)
131 write_lock(&period_lock
);
132 period_ms
= (unsigned long)val
;
133 write_unlock(&period_lock
);
137 static int period_ms_get(void *data
, u64
*val
)
139 read_lock(&period_lock
);
141 read_unlock(&period_lock
);
146 static int vmstat_period_ms_set(void *data
, u64 val
)
148 if (val
< 1 || val
> ULONG_MAX
)
151 spin_lock(&vmstat_lock
);
152 vmstat_period_ms
= (unsigned long)val
;
153 spin_unlock(&vmstat_lock
);
157 static int vmstat_period_ms_get(void *data
, u64
*val
)
159 spin_lock(&vmstat_lock
);
160 *val
= vmstat_period_ms
;
161 spin_unlock(&vmstat_lock
);
165 DEFINE_SIMPLE_ATTRIBUTE(period_ms_operations
, period_ms_get
,
166 period_ms_set
, "%llu\n");
167 DEFINE_SIMPLE_ATTRIBUTE(vmstat_period_ms_operations
, vmstat_period_ms_get
,
168 vmstat_period_ms_set
, "%llu\n");
170 static int __init
mm_event_init(void)
172 struct dentry
*entry
;
174 mm_event_root
= debugfs_create_dir("mm_event", NULL
);
175 if (!mm_event_root
) {
176 pr_warn("debugfs dir <mm_event> creation failed\n");
177 return PTR_ERR(mm_event_root
);
180 entry
= debugfs_create_file("period_ms", 0644,
181 mm_event_root
, NULL
, &period_ms_operations
);
184 pr_warn("debugfs file mm_event_task creation failed\n");
185 debugfs_remove_recursive(mm_event_root
);
186 return PTR_ERR(entry
);
189 entry
= debugfs_create_file("vmstat_period_ms", 0644,
190 mm_event_root
, NULL
, &vmstat_period_ms_operations
);
192 pr_warn("debugfs file vmstat_mm_event_task creation failed\n");
193 debugfs_remove_recursive(mm_event_root
);
194 return PTR_ERR(entry
);
199 subsys_initcall(mm_event_init
);