Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312# report time spent in compaction# Licensed under the terms of the GNU GPL License version 2
# testing:# 'echo 1 > /proc/sys/vm/compact_memory' to force compaction of all zones
import osimport sysimport re
import signalsignal.signal(signal.SIGPIPE, signal.SIG_DFL)
usage = "usage: perf script report compaction-times.py -- [-h] [-u] [-p|-pv] [-t | [-m] [-fs] [-ms]] [pid|pid-range|comm-regex]\n"
class popt: DISP_DFL = 0 DISP_PROC = 1 DISP_PROC_VERBOSE=2
class topt: DISP_TIME = 0 DISP_MIG = 1 DISP_ISOLFREE = 2 DISP_ISOLMIG = 4 DISP_ALL = 7
class comm_filter: def __init__(self, re): self.re = re
def filter(self, pid, comm): m = self.re.search(comm) return m == None or m.group() == ""
class pid_filter: def __init__(self, low, high): self.low = (0 if low == "" else int(low)) self.high = (0 if high == "" else int(high))
def filter(self, pid, comm): return not (pid >= self.low and (self.high == 0 or pid <= self.high))
def set_type(t): global opt_disp opt_disp = (t if opt_disp == topt.DISP_ALL else opt_disp|t)
def ns(sec, nsec): return (sec * 1000000000) + nsec
def time(ns): return "%dns" % ns if opt_ns else "%dus" % (round(ns, -3) / 1000)
class pair: def __init__(self, aval, bval, alabel = None, blabel = None): self.alabel = alabel self.blabel = blabel self.aval = aval self.bval = bval
def __add__(self, rhs): self.aval += rhs.aval self.bval += rhs.bval return self
def __str__(self): return "%s=%d %s=%d" % (self.alabel, self.aval, self.blabel, self.bval)
class cnode: def __init__(self, ns): self.ns = ns self.migrated = pair(0, 0, "moved", "failed") self.fscan = pair(0,0, "scanned", "isolated") self.mscan = pair(0,0, "scanned", "isolated")
def __add__(self, rhs): self.ns += rhs.ns self.migrated += rhs.migrated self.fscan += rhs.fscan self.mscan += rhs.mscan return self
def __str__(self): prev = 0 s = "%s " % time(self.ns) if (opt_disp & topt.DISP_MIG): s += "migration: %s" % self.migrated prev = 1 if (opt_disp & topt.DISP_ISOLFREE): s += "%sfree_scanner: %s" % (" " if prev else "", self.fscan) prev = 1 if (opt_disp & topt.DISP_ISOLMIG): s += "%smigration_scanner: %s" % (" " if prev else "", self.mscan) return s
def complete(self, secs, nsecs): self.ns = ns(secs, nsecs) - self.ns
def increment(self, migrated, fscan, mscan): if (migrated != None): self.migrated += migrated if (fscan != None): self.fscan += fscan if (mscan != None): self.mscan += mscan
class chead: heads = {} val = cnode(0); fobj = None
@classmethod def add_filter(cls, filter): cls.fobj = filter
@classmethod def create_pending(cls, pid, comm, start_secs, start_nsecs): filtered = 0 try: head = cls.heads[pid] filtered = head.is_filtered() except KeyError: if cls.fobj != None: filtered = cls.fobj.filter(pid, comm) head = cls.heads[pid] = chead(comm, pid, filtered)
if not filtered: head.mark_pending(start_secs, start_nsecs)
@classmethod def increment_pending(cls, pid, migrated, fscan, mscan): head = cls.heads[pid] if not head.is_filtered(): if head.is_pending(): head.do_increment(migrated, fscan, mscan) else: sys.stderr.write("missing start compaction event for pid %d\n" % pid)
@classmethod def complete_pending(cls, pid, secs, nsecs): head = cls.heads[pid] if not head.is_filtered(): if head.is_pending(): head.make_complete(secs, nsecs) else: sys.stderr.write("missing start compaction event for pid %d\n" % pid)
@classmethod def gen(cls): if opt_proc != popt.DISP_DFL: for i in cls.heads: yield cls.heads[i]
@classmethod def str(cls): return cls.val
def __init__(self, comm, pid, filtered): self.comm = comm self.pid = pid self.val = cnode(0) self.pending = None self.filtered = filtered self.list = []
def __add__(self, rhs): self.ns += rhs.ns self.val += rhs.val return self
def mark_pending(self, secs, nsecs): self.pending = cnode(ns(secs, nsecs))
def do_increment(self, migrated, fscan, mscan): self.pending.increment(migrated, fscan, mscan)
def make_complete(self, secs, nsecs): self.pending.complete(secs, nsecs) chead.val += self.pending
if opt_proc != popt.DISP_DFL: self.val += self.pending
if opt_proc == popt.DISP_PROC_VERBOSE: self.list.append(self.pending) self.pending = None
def enumerate(self): if opt_proc == popt.DISP_PROC_VERBOSE and not self.is_filtered(): for i, pelem in enumerate(self.list): sys.stdout.write("%d[%s].%d: %s\n" % (self.pid, self.comm, i+1, pelem))
def is_pending(self): return self.pending != None
def is_filtered(self): return self.filtered
def display(self): if not self.is_filtered(): sys.stdout.write("%d[%s]: %s\n" % (self.pid, self.comm, self.val))
def trace_end(): sys.stdout.write("total: %s\n" % chead.str()) for i in chead.gen(): i.display(), i.enumerate()
def compaction__mm_compaction_migratepages(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, nr_migrated, nr_failed):
chead.increment_pending(common_pid, pair(nr_migrated, nr_failed), None, None)
def compaction__mm_compaction_isolate_freepages(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, start_pfn, end_pfn, nr_scanned, nr_taken):
chead.increment_pending(common_pid, None, pair(nr_scanned, nr_taken), None)
def compaction__mm_compaction_isolate_migratepages(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, start_pfn, end_pfn, nr_scanned, nr_taken):
chead.increment_pending(common_pid, None, None, pair(nr_scanned, nr_taken))
def compaction__mm_compaction_end(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, zone_start, migrate_start, free_start, zone_end, sync, status):
chead.complete_pending(common_pid, common_secs, common_nsecs)
def compaction__mm_compaction_begin(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, zone_start, migrate_start, free_start, zone_end, sync):
chead.create_pending(common_pid, common_comm, common_secs, common_nsecs)
def pr_help(): global usage
sys.stdout.write(usage) sys.stdout.write("\n") sys.stdout.write("-h display this help\n") sys.stdout.write("-p display by process\n") sys.stdout.write("-pv display by process (verbose)\n") sys.stdout.write("-t display stall times only\n") sys.stdout.write("-m display stats for migration\n") sys.stdout.write("-fs display stats for free scanner\n") sys.stdout.write("-ms display stats for migration scanner\n") sys.stdout.write("-u display results in microseconds (default nanoseconds)\n")
comm_re = Nonepid_re = Nonepid_regex = r"^(\d*)-(\d*)$|^(\d*)$"
opt_proc = popt.DISP_DFLopt_disp = topt.DISP_ALL
opt_ns = True
argc = len(sys.argv) - 1if argc >= 1: pid_re = re.compile(pid_regex)
for i, opt in enumerate(sys.argv[1:]): if opt[0] == "-": if opt == "-h": pr_help() exit(0); elif opt == "-p": opt_proc = popt.DISP_PROC elif opt == "-pv": opt_proc = popt.DISP_PROC_VERBOSE elif opt == '-u': opt_ns = False elif opt == "-t": set_type(topt.DISP_TIME) elif opt == "-m": set_type(topt.DISP_MIG) elif opt == "-fs": set_type(topt.DISP_ISOLFREE) elif opt == "-ms": set_type(topt.DISP_ISOLMIG) else: sys.exit(usage)
elif i == argc - 1: m = pid_re.search(opt) if m != None and m.group() != "": if m.group(3) != None: f = pid_filter(m.group(3), m.group(3)) else: f = pid_filter(m.group(1), m.group(2)) else: try: comm_re=re.compile(opt) except: sys.stderr.write("invalid regex '%s'" % opt) sys.exit(usage) f = comm_filter(comm_re)
chead.add_filter(f)