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 for_each_online_cpu(cpu
) {
56 struct vm_event_state
*this = &per_cpu(vm_event_states
, cpu
);
58 /* sectors to kbytes for PGPGIN/PGPGOUT */
59 vmstat
.pgin
+= this->event
[PGPGIN
] / 2;
60 vmstat
.pgout
+= this->event
[PGPGOUT
] / 2;
61 vmstat
.swpin
+= this->event
[PSWPIN
];
62 vmstat
.swpout
+= this->event
[PSWPOUT
];
63 vmstat
.reclaim_steal
+= this->event
[PGSTEAL_DIRECT
] +
64 this->event
[PGSTEAL_KSWAPD
];
65 vmstat
.reclaim_scan
+= this->event
[PGSCAN_DIRECT
] +
66 this->event
[PGSCAN_KSWAPD
];
67 vmstat
.compact_scan
+= this->event
[COMPACTFREE_SCANNED
] +
68 this->event
[COMPACTMIGRATE_SCANNED
];
70 trace_mm_event_vmstat_record(&vmstat
);
73 static void record_stat(void)
76 bool need_vmstat
= false;
78 if (time_is_after_jiffies(current
->next_period
))
81 read_lock(&period_lock
);
82 current
->next_period
= jiffies
+ msecs_to_jiffies(period_ms
);
83 read_unlock(&period_lock
);
85 for (i
= 0; i
< MM_TYPE_NUM
; i
++) {
86 if (current
->mm_event
[i
].count
== 0)
88 if (i
== MM_COMPACTION
|| i
== MM_RECLAIM
)
90 trace_mm_event_record(i
, ¤t
->mm_event
[i
]);
91 memset(¤t
->mm_event
[i
], 0,
92 sizeof(struct mm_event_task
));
99 void mm_event_start(ktime_t
*time
)
104 void mm_event_end(enum mm_event_type event
, ktime_t start
)
106 s64 elapsed
= ktime_us_delta(ktime_get(), start
);
108 current
->mm_event
[event
].count
++;
109 current
->mm_event
[event
].accm_lat
+= elapsed
;
110 if (elapsed
> current
->mm_event
[event
].max_lat
)
111 current
->mm_event
[event
].max_lat
= elapsed
;
115 void mm_event_count(enum mm_event_type event
, int count
)
117 current
->mm_event
[event
].count
+= count
;
121 static struct dentry
*mm_event_root
;
123 static int period_ms_set(void *data
, u64 val
)
125 if (val
< 1 || val
> ULONG_MAX
)
128 write_lock(&period_lock
);
129 period_ms
= (unsigned long)val
;
130 write_unlock(&period_lock
);
134 static int period_ms_get(void *data
, u64
*val
)
136 read_lock(&period_lock
);
138 read_unlock(&period_lock
);
143 static int vmstat_period_ms_set(void *data
, u64 val
)
145 if (val
< 1 || val
> ULONG_MAX
)
148 spin_lock(&vmstat_lock
);
149 vmstat_period_ms
= (unsigned long)val
;
150 spin_unlock(&vmstat_lock
);
154 static int vmstat_period_ms_get(void *data
, u64
*val
)
156 spin_lock(&vmstat_lock
);
157 *val
= vmstat_period_ms
;
158 spin_unlock(&vmstat_lock
);
162 DEFINE_SIMPLE_ATTRIBUTE(period_ms_operations
, period_ms_get
,
163 period_ms_set
, "%llu\n");
164 DEFINE_SIMPLE_ATTRIBUTE(vmstat_period_ms_operations
, vmstat_period_ms_get
,
165 vmstat_period_ms_set
, "%llu\n");
167 static int __init
mm_event_init(void)
169 struct dentry
*entry
;
171 mm_event_root
= debugfs_create_dir("mm_event", NULL
);
172 if (!mm_event_root
) {
173 pr_warn("debugfs dir <mm_event> creation failed\n");
174 return PTR_ERR(mm_event_root
);
177 entry
= debugfs_create_file("period_ms", 0644,
178 mm_event_root
, NULL
, &period_ms_operations
);
181 pr_warn("debugfs file mm_event_task creation failed\n");
182 debugfs_remove_recursive(mm_event_root
);
183 return PTR_ERR(entry
);
186 entry
= debugfs_create_file("vmstat_period_ms", 0644,
187 mm_event_root
, NULL
, &vmstat_period_ms_operations
);
189 pr_warn("debugfs file vmstat_mm_event_task creation failed\n");
190 debugfs_remove_recursive(mm_event_root
);
191 return PTR_ERR(entry
);
196 subsys_initcall(mm_event_init
);