1 # report time spent in compaction
2 # Licensed under the terms of the GNU GPL License version 2
5 # 'echo 1 > /proc/sys/vm/compact_memory' to force compaction of all zones
12 signal
.signal(signal
.SIGPIPE
, signal
.SIG_DFL
)
14 usage
= "usage: perf script report compaction-times.py -- [-h] [-u] [-p|-pv] [-t | [-m] [-fs] [-ms]] [pid|pid-range|comm-regex]\n"
29 def __init__(self
, re
):
32 def filter(self
, pid
, comm
):
33 m
= self
.re
.search(comm
)
34 return m
== None or m
.group() == ""
37 def __init__(self
, low
, high
):
38 self
.low
= (0 if low
== "" else int(low
))
39 self
.high
= (0 if high
== "" else int(high
))
41 def filter(self
, pid
, comm
):
42 return not (pid
>= self
.low
and (self
.high
== 0 or pid
<= self
.high
))
46 opt_disp
= (t
if opt_disp
== topt
.DISP_ALL
else opt_disp|t
)
49 return (sec
* 1000000000) + nsec
52 return "%dns" % ns
if opt_ns
else "%dus" % (round(ns
, -3) / 1000)
55 def __init__(self
, aval
, bval
, alabel
= None, blabel
= None):
61 def __add__(self
, rhs
):
67 return "%s=%d %s=%d" % (self
.alabel
, self
.aval
, self
.blabel
, self
.bval
)
70 def __init__(self
, ns
):
72 self
.migrated
= pair(0, 0, "moved", "failed")
73 self
.fscan
= pair(0,0, "scanned", "isolated")
74 self
.mscan
= pair(0,0, "scanned", "isolated")
76 def __add__(self
, rhs
):
78 self
.migrated
+= rhs
.migrated
79 self
.fscan
+= rhs
.fscan
80 self
.mscan
+= rhs
.mscan
85 s
= "%s " % time(self
.ns
)
86 if (opt_disp
& topt
.DISP_MIG
):
87 s
+= "migration: %s" % self
.migrated
89 if (opt_disp
& topt
.DISP_ISOLFREE
):
90 s
+= "%sfree_scanner: %s" % (" " if prev
else "", self
.fscan
)
92 if (opt_disp
& topt
.DISP_ISOLMIG
):
93 s
+= "%smigration_scanner: %s" % (" " if prev
else "", self
.mscan
)
96 def complete(self
, secs
, nsecs
):
97 self
.ns
= ns(secs
, nsecs
) - self
.ns
99 def increment(self
, migrated
, fscan
, mscan
):
100 if (migrated
!= None):
101 self
.migrated
+= migrated
114 def add_filter(cls
, filter):
118 def create_pending(cls
, pid
, comm
, start_secs
, start_nsecs
):
121 head
= cls
.heads
[pid
]
122 filtered
= head
.is_filtered()
125 filtered
= cls
.fobj
.filter(pid
, comm
)
126 head
= cls
.heads
[pid
] = chead(comm
, pid
, filtered
)
129 head
.mark_pending(start_secs
, start_nsecs
)
132 def increment_pending(cls
, pid
, migrated
, fscan
, mscan
):
133 head
= cls
.heads
[pid
]
134 if not head
.is_filtered():
135 if head
.is_pending():
136 head
.do_increment(migrated
, fscan
, mscan
)
138 sys
.stderr
.write("missing start compaction event for pid %d\n" % pid
)
141 def complete_pending(cls
, pid
, secs
, nsecs
):
142 head
= cls
.heads
[pid
]
143 if not head
.is_filtered():
144 if head
.is_pending():
145 head
.make_complete(secs
, nsecs
)
147 sys
.stderr
.write("missing start compaction event for pid %d\n" % pid
)
151 if opt_proc
!= popt
.DISP_DFL
:
159 def __init__(self
, comm
, pid
, filtered
):
164 self
.filtered
= filtered
167 def __add__(self
, rhs
):
172 def mark_pending(self
, secs
, nsecs
):
173 self
.pending
= cnode(ns(secs
, nsecs
))
175 def do_increment(self
, migrated
, fscan
, mscan
):
176 self
.pending
.increment(migrated
, fscan
, mscan
)
178 def make_complete(self
, secs
, nsecs
):
179 self
.pending
.complete(secs
, nsecs
)
180 chead
.val
+= self
.pending
182 if opt_proc
!= popt
.DISP_DFL
:
183 self
.val
+= self
.pending
185 if opt_proc
== popt
.DISP_PROC_VERBOSE
:
186 self
.list.append(self
.pending
)
190 if opt_proc
== popt
.DISP_PROC_VERBOSE
and not self
.is_filtered():
191 for i
, pelem
in enumerate(self
.list):
192 sys
.stdout
.write("%d[%s].%d: %s\n" % (self
.pid
, self
.comm
, i
+1, pelem
))
194 def is_pending(self
):
195 return self
.pending
!= None
197 def is_filtered(self
):
201 if not self
.is_filtered():
202 sys
.stdout
.write("%d[%s]: %s\n" % (self
.pid
, self
.comm
, self
.val
))
206 sys
.stdout
.write("total: %s\n" % chead
.str())
207 for i
in chead
.gen():
211 def compaction__mm_compaction_migratepages(event_name
, context
, common_cpu
,
212 common_secs
, common_nsecs
, common_pid
, common_comm
,
213 common_callchain
, nr_migrated
, nr_failed
):
215 chead
.increment_pending(common_pid
,
216 pair(nr_migrated
, nr_failed
), None, None)
218 def compaction__mm_compaction_isolate_freepages(event_name
, context
, common_cpu
,
219 common_secs
, common_nsecs
, common_pid
, common_comm
,
220 common_callchain
, start_pfn
, end_pfn
, nr_scanned
, nr_taken
):
222 chead
.increment_pending(common_pid
,
223 None, pair(nr_scanned
, nr_taken
), None)
225 def compaction__mm_compaction_isolate_migratepages(event_name
, context
, common_cpu
,
226 common_secs
, common_nsecs
, common_pid
, common_comm
,
227 common_callchain
, start_pfn
, end_pfn
, nr_scanned
, nr_taken
):
229 chead
.increment_pending(common_pid
,
230 None, None, pair(nr_scanned
, nr_taken
))
232 def compaction__mm_compaction_end(event_name
, context
, common_cpu
,
233 common_secs
, common_nsecs
, common_pid
, common_comm
,
234 common_callchain
, zone_start
, migrate_start
, free_start
, zone_end
,
237 chead
.complete_pending(common_pid
, common_secs
, common_nsecs
)
239 def compaction__mm_compaction_begin(event_name
, context
, common_cpu
,
240 common_secs
, common_nsecs
, common_pid
, common_comm
,
241 common_callchain
, zone_start
, migrate_start
, free_start
, zone_end
,
244 chead
.create_pending(common_pid
, common_comm
, common_secs
, common_nsecs
)
249 sys
.stdout
.write(usage
)
250 sys
.stdout
.write("\n")
251 sys
.stdout
.write("-h display this help\n")
252 sys
.stdout
.write("-p display by process\n")
253 sys
.stdout
.write("-pv display by process (verbose)\n")
254 sys
.stdout
.write("-t display stall times only\n")
255 sys
.stdout
.write("-m display stats for migration\n")
256 sys
.stdout
.write("-fs display stats for free scanner\n")
257 sys
.stdout
.write("-ms display stats for migration scanner\n")
258 sys
.stdout
.write("-u display results in microseconds (default nanoseconds)\n")
263 pid_regex
= "^(\d*)-(\d*)$|^(\d*)$"
265 opt_proc
= popt
.DISP_DFL
266 opt_disp
= topt
.DISP_ALL
270 argc
= len(sys
.argv
) - 1
272 pid_re
= re
.compile(pid_regex
)
274 for i
, opt
in enumerate(sys
.argv
[1:]):
280 opt_proc
= popt
.DISP_PROC
282 opt_proc
= popt
.DISP_PROC_VERBOSE
286 set_type(topt
.DISP_TIME
)
288 set_type(topt
.DISP_MIG
)
290 set_type(topt
.DISP_ISOLFREE
)
292 set_type(topt
.DISP_ISOLMIG
)
297 m
= pid_re
.search(opt
)
298 if m
!= None and m
.group() != "":
299 if m
.group(3) != None:
300 f
= pid_filter(m
.group(3), m
.group(3))
302 f
= pid_filter(m
.group(1), m
.group(2))
305 comm_re
=re
.compile(opt
)
307 sys
.stderr
.write("invalid regex '%s'" % opt
)
309 f
= comm_filter(comm_re
)