184e5d89aSTony Jones# report time spent in compaction 284e5d89aSTony Jones# Licensed under the terms of the GNU GPL License version 2 384e5d89aSTony Jones 484e5d89aSTony Jones# testing: 584e5d89aSTony Jones# 'echo 1 > /proc/sys/vm/compact_memory' to force compaction of all zones 684e5d89aSTony Jones 784e5d89aSTony Jonesimport os 884e5d89aSTony Jonesimport sys 984e5d89aSTony Jonesimport re 1084e5d89aSTony Jones 1184e5d89aSTony Jonesimport signal 1284e5d89aSTony Jonessignal.signal(signal.SIGPIPE, signal.SIG_DFL) 1384e5d89aSTony Jones 1484e5d89aSTony Jonesusage = "usage: perf script report compaction-times.py -- [-h] [-u] [-p|-pv] [-t | [-m] [-fs] [-ms]] [pid|pid-range|comm-regex]\n" 1584e5d89aSTony Jones 1684e5d89aSTony Jonesclass popt: 1784e5d89aSTony Jones DISP_DFL = 0 1884e5d89aSTony Jones DISP_PROC = 1 1984e5d89aSTony Jones DISP_PROC_VERBOSE=2 2084e5d89aSTony Jones 2184e5d89aSTony Jonesclass topt: 2284e5d89aSTony Jones DISP_TIME = 0 2384e5d89aSTony Jones DISP_MIG = 1 2484e5d89aSTony Jones DISP_ISOLFREE = 2 2584e5d89aSTony Jones DISP_ISOLMIG = 4 2684e5d89aSTony Jones DISP_ALL = 7 2784e5d89aSTony Jones 2884e5d89aSTony Jonesclass comm_filter: 2984e5d89aSTony Jones def __init__(self, re): 3084e5d89aSTony Jones self.re = re 3184e5d89aSTony Jones 3284e5d89aSTony Jones def filter(self, pid, comm): 3384e5d89aSTony Jones m = self.re.search(comm) 3484e5d89aSTony Jones return m == None or m.group() == "" 3584e5d89aSTony Jones 3684e5d89aSTony Jonesclass pid_filter: 3784e5d89aSTony Jones def __init__(self, low, high): 3884e5d89aSTony Jones self.low = (0 if low == "" else int(low)) 3984e5d89aSTony Jones self.high = (0 if high == "" else int(high)) 4084e5d89aSTony Jones 4184e5d89aSTony Jones def filter(self, pid, comm): 4284e5d89aSTony Jones return not (pid >= self.low and (self.high == 0 or pid <= self.high)) 4384e5d89aSTony Jones 4484e5d89aSTony Jonesdef set_type(t): 4584e5d89aSTony Jones global opt_disp 4684e5d89aSTony Jones opt_disp = (t if opt_disp == topt.DISP_ALL else opt_disp|t) 4784e5d89aSTony Jones 4884e5d89aSTony Jonesdef ns(sec, nsec): 4984e5d89aSTony Jones return (sec * 1000000000) + nsec 5084e5d89aSTony Jones 5184e5d89aSTony Jonesdef time(ns): 5284e5d89aSTony Jones return "%dns" % ns if opt_ns else "%dus" % (round(ns, -3) / 1000) 5384e5d89aSTony Jones 5484e5d89aSTony Jonesclass pair: 5584e5d89aSTony Jones def __init__(self, aval, bval, alabel = None, blabel = None): 5684e5d89aSTony Jones self.alabel = alabel 5784e5d89aSTony Jones self.blabel = blabel 5884e5d89aSTony Jones self.aval = aval 5984e5d89aSTony Jones self.bval = bval 6084e5d89aSTony Jones 6184e5d89aSTony Jones def __add__(self, rhs): 6284e5d89aSTony Jones self.aval += rhs.aval 6384e5d89aSTony Jones self.bval += rhs.bval 6484e5d89aSTony Jones return self 6584e5d89aSTony Jones 6684e5d89aSTony Jones def __str__(self): 6784e5d89aSTony Jones return "%s=%d %s=%d" % (self.alabel, self.aval, self.blabel, self.bval) 6884e5d89aSTony Jones 6984e5d89aSTony Jonesclass cnode: 7084e5d89aSTony Jones def __init__(self, ns): 7184e5d89aSTony Jones self.ns = ns 7284e5d89aSTony Jones self.migrated = pair(0, 0, "moved", "failed") 7384e5d89aSTony Jones self.fscan = pair(0,0, "scanned", "isolated") 7484e5d89aSTony Jones self.mscan = pair(0,0, "scanned", "isolated") 7584e5d89aSTony Jones 7684e5d89aSTony Jones def __add__(self, rhs): 7784e5d89aSTony Jones self.ns += rhs.ns 7884e5d89aSTony Jones self.migrated += rhs.migrated 7984e5d89aSTony Jones self.fscan += rhs.fscan 8084e5d89aSTony Jones self.mscan += rhs.mscan 8184e5d89aSTony Jones return self 8284e5d89aSTony Jones 8384e5d89aSTony Jones def __str__(self): 8484e5d89aSTony Jones prev = 0 8584e5d89aSTony Jones s = "%s " % time(self.ns) 8684e5d89aSTony Jones if (opt_disp & topt.DISP_MIG): 8784e5d89aSTony Jones s += "migration: %s" % self.migrated 8884e5d89aSTony Jones prev = 1 8984e5d89aSTony Jones if (opt_disp & topt.DISP_ISOLFREE): 9084e5d89aSTony Jones s += "%sfree_scanner: %s" % (" " if prev else "", self.fscan) 9184e5d89aSTony Jones prev = 1 9284e5d89aSTony Jones if (opt_disp & topt.DISP_ISOLMIG): 9384e5d89aSTony Jones s += "%smigration_scanner: %s" % (" " if prev else "", self.mscan) 9484e5d89aSTony Jones return s 9584e5d89aSTony Jones 9684e5d89aSTony Jones def complete(self, secs, nsecs): 9784e5d89aSTony Jones self.ns = ns(secs, nsecs) - self.ns 9884e5d89aSTony Jones 9984e5d89aSTony Jones def increment(self, migrated, fscan, mscan): 10084e5d89aSTony Jones if (migrated != None): 10184e5d89aSTony Jones self.migrated += migrated 10284e5d89aSTony Jones if (fscan != None): 10384e5d89aSTony Jones self.fscan += fscan 10484e5d89aSTony Jones if (mscan != None): 10584e5d89aSTony Jones self.mscan += mscan 10684e5d89aSTony Jones 10784e5d89aSTony Jones 10884e5d89aSTony Jonesclass chead: 10984e5d89aSTony Jones heads = {} 11084e5d89aSTony Jones val = cnode(0); 11184e5d89aSTony Jones fobj = None 11284e5d89aSTony Jones 11384e5d89aSTony Jones @classmethod 11484e5d89aSTony Jones def add_filter(cls, filter): 11584e5d89aSTony Jones cls.fobj = filter 11684e5d89aSTony Jones 11784e5d89aSTony Jones @classmethod 11884e5d89aSTony Jones def create_pending(cls, pid, comm, start_secs, start_nsecs): 11984e5d89aSTony Jones filtered = 0 12084e5d89aSTony Jones try: 12184e5d89aSTony Jones head = cls.heads[pid] 12284e5d89aSTony Jones filtered = head.is_filtered() 12384e5d89aSTony Jones except KeyError: 12484e5d89aSTony Jones if cls.fobj != None: 12584e5d89aSTony Jones filtered = cls.fobj.filter(pid, comm) 12684e5d89aSTony Jones head = cls.heads[pid] = chead(comm, pid, filtered) 12784e5d89aSTony Jones 12884e5d89aSTony Jones if not filtered: 12984e5d89aSTony Jones head.mark_pending(start_secs, start_nsecs) 13084e5d89aSTony Jones 13184e5d89aSTony Jones @classmethod 13284e5d89aSTony Jones def increment_pending(cls, pid, migrated, fscan, mscan): 13384e5d89aSTony Jones head = cls.heads[pid] 13484e5d89aSTony Jones if not head.is_filtered(): 13584e5d89aSTony Jones if head.is_pending(): 13684e5d89aSTony Jones head.do_increment(migrated, fscan, mscan) 13784e5d89aSTony Jones else: 13884e5d89aSTony Jones sys.stderr.write("missing start compaction event for pid %d\n" % pid) 13984e5d89aSTony Jones 14084e5d89aSTony Jones @classmethod 14184e5d89aSTony Jones def complete_pending(cls, pid, secs, nsecs): 14284e5d89aSTony Jones head = cls.heads[pid] 14384e5d89aSTony Jones if not head.is_filtered(): 14484e5d89aSTony Jones if head.is_pending(): 14584e5d89aSTony Jones head.make_complete(secs, nsecs) 14684e5d89aSTony Jones else: 14784e5d89aSTony Jones sys.stderr.write("missing start compaction event for pid %d\n" % pid) 14884e5d89aSTony Jones 14984e5d89aSTony Jones @classmethod 15084e5d89aSTony Jones def gen(cls): 15184e5d89aSTony Jones if opt_proc != popt.DISP_DFL: 15284e5d89aSTony Jones for i in cls.heads: 15384e5d89aSTony Jones yield cls.heads[i] 15484e5d89aSTony Jones 15584e5d89aSTony Jones @classmethod 15684e5d89aSTony Jones def str(cls): 15784e5d89aSTony Jones return cls.val 15884e5d89aSTony Jones 15984e5d89aSTony Jones def __init__(self, comm, pid, filtered): 16084e5d89aSTony Jones self.comm = comm 16184e5d89aSTony Jones self.pid = pid 16284e5d89aSTony Jones self.val = cnode(0) 16384e5d89aSTony Jones self.pending = None 16484e5d89aSTony Jones self.filtered = filtered 16584e5d89aSTony Jones self.list = [] 16684e5d89aSTony Jones 16784e5d89aSTony Jones def __add__(self, rhs): 16884e5d89aSTony Jones self.ns += rhs.ns 16984e5d89aSTony Jones self.val += rhs.val 17084e5d89aSTony Jones return self 17184e5d89aSTony Jones 17284e5d89aSTony Jones def mark_pending(self, secs, nsecs): 17384e5d89aSTony Jones self.pending = cnode(ns(secs, nsecs)) 17484e5d89aSTony Jones 17584e5d89aSTony Jones def do_increment(self, migrated, fscan, mscan): 17684e5d89aSTony Jones self.pending.increment(migrated, fscan, mscan) 17784e5d89aSTony Jones 17884e5d89aSTony Jones def make_complete(self, secs, nsecs): 17984e5d89aSTony Jones self.pending.complete(secs, nsecs) 18084e5d89aSTony Jones chead.val += self.pending 18184e5d89aSTony Jones 18284e5d89aSTony Jones if opt_proc != popt.DISP_DFL: 18384e5d89aSTony Jones self.val += self.pending 18484e5d89aSTony Jones 18584e5d89aSTony Jones if opt_proc == popt.DISP_PROC_VERBOSE: 18684e5d89aSTony Jones self.list.append(self.pending) 18784e5d89aSTony Jones self.pending = None 18884e5d89aSTony Jones 18984e5d89aSTony Jones def enumerate(self): 19084e5d89aSTony Jones if opt_proc == popt.DISP_PROC_VERBOSE and not self.is_filtered(): 19184e5d89aSTony Jones for i, pelem in enumerate(self.list): 19284e5d89aSTony Jones sys.stdout.write("%d[%s].%d: %s\n" % (self.pid, self.comm, i+1, pelem)) 19384e5d89aSTony Jones 19484e5d89aSTony Jones def is_pending(self): 19584e5d89aSTony Jones return self.pending != None 19684e5d89aSTony Jones 19784e5d89aSTony Jones def is_filtered(self): 19884e5d89aSTony Jones return self.filtered 19984e5d89aSTony Jones 20084e5d89aSTony Jones def display(self): 20184e5d89aSTony Jones if not self.is_filtered(): 20284e5d89aSTony Jones sys.stdout.write("%d[%s]: %s\n" % (self.pid, self.comm, self.val)) 20384e5d89aSTony Jones 20484e5d89aSTony Jones 20584e5d89aSTony Jonesdef trace_end(): 20684e5d89aSTony Jones sys.stdout.write("total: %s\n" % chead.str()) 20784e5d89aSTony Jones for i in chead.gen(): 20884e5d89aSTony Jones i.display(), 20984e5d89aSTony Jones i.enumerate() 21084e5d89aSTony Jones 21184e5d89aSTony Jonesdef compaction__mm_compaction_migratepages(event_name, context, common_cpu, 21284e5d89aSTony Jones common_secs, common_nsecs, common_pid, common_comm, 21384e5d89aSTony Jones common_callchain, nr_migrated, nr_failed): 21484e5d89aSTony Jones 21584e5d89aSTony Jones chead.increment_pending(common_pid, 21684e5d89aSTony Jones pair(nr_migrated, nr_failed), None, None) 21784e5d89aSTony Jones 21884e5d89aSTony Jonesdef compaction__mm_compaction_isolate_freepages(event_name, context, common_cpu, 21984e5d89aSTony Jones common_secs, common_nsecs, common_pid, common_comm, 22084e5d89aSTony Jones common_callchain, start_pfn, end_pfn, nr_scanned, nr_taken): 22184e5d89aSTony Jones 22284e5d89aSTony Jones chead.increment_pending(common_pid, 22384e5d89aSTony Jones None, pair(nr_scanned, nr_taken), None) 22484e5d89aSTony Jones 22584e5d89aSTony Jonesdef compaction__mm_compaction_isolate_migratepages(event_name, context, common_cpu, 22684e5d89aSTony Jones common_secs, common_nsecs, common_pid, common_comm, 22784e5d89aSTony Jones common_callchain, start_pfn, end_pfn, nr_scanned, nr_taken): 22884e5d89aSTony Jones 22984e5d89aSTony Jones chead.increment_pending(common_pid, 23084e5d89aSTony Jones None, None, pair(nr_scanned, nr_taken)) 23184e5d89aSTony Jones 23284e5d89aSTony Jonesdef compaction__mm_compaction_end(event_name, context, common_cpu, 23384e5d89aSTony Jones common_secs, common_nsecs, common_pid, common_comm, 23484e5d89aSTony Jones common_callchain, zone_start, migrate_start, free_start, zone_end, 23584e5d89aSTony Jones sync, status): 23684e5d89aSTony Jones 23784e5d89aSTony Jones chead.complete_pending(common_pid, common_secs, common_nsecs) 23884e5d89aSTony Jones 23984e5d89aSTony Jonesdef compaction__mm_compaction_begin(event_name, context, common_cpu, 24084e5d89aSTony Jones common_secs, common_nsecs, common_pid, common_comm, 24184e5d89aSTony Jones common_callchain, zone_start, migrate_start, free_start, zone_end, 24284e5d89aSTony Jones sync): 24384e5d89aSTony Jones 24484e5d89aSTony Jones chead.create_pending(common_pid, common_comm, common_secs, common_nsecs) 24584e5d89aSTony Jones 24684e5d89aSTony Jonesdef pr_help(): 24784e5d89aSTony Jones global usage 24884e5d89aSTony Jones 24984e5d89aSTony Jones sys.stdout.write(usage) 25084e5d89aSTony Jones sys.stdout.write("\n") 25184e5d89aSTony Jones sys.stdout.write("-h display this help\n") 25284e5d89aSTony Jones sys.stdout.write("-p display by process\n") 25384e5d89aSTony Jones sys.stdout.write("-pv display by process (verbose)\n") 25484e5d89aSTony Jones sys.stdout.write("-t display stall times only\n") 25584e5d89aSTony Jones sys.stdout.write("-m display stats for migration\n") 25684e5d89aSTony Jones sys.stdout.write("-fs display stats for free scanner\n") 25784e5d89aSTony Jones sys.stdout.write("-ms display stats for migration scanner\n") 25884e5d89aSTony Jones sys.stdout.write("-u display results in microseconds (default nanoseconds)\n") 25984e5d89aSTony Jones 26084e5d89aSTony Jones 26184e5d89aSTony Jonescomm_re = None 26284e5d89aSTony Jonespid_re = None 263*280b4e4aSBenjamin Graypid_regex = r"^(\d*)-(\d*)$|^(\d*)$" 26484e5d89aSTony Jones 26584e5d89aSTony Jonesopt_proc = popt.DISP_DFL 26684e5d89aSTony Jonesopt_disp = topt.DISP_ALL 26784e5d89aSTony Jones 26884e5d89aSTony Jonesopt_ns = True 26984e5d89aSTony Jones 27084e5d89aSTony Jonesargc = len(sys.argv) - 1 27184e5d89aSTony Jonesif argc >= 1: 27284e5d89aSTony Jones pid_re = re.compile(pid_regex) 27384e5d89aSTony Jones 27484e5d89aSTony Jones for i, opt in enumerate(sys.argv[1:]): 27584e5d89aSTony Jones if opt[0] == "-": 27684e5d89aSTony Jones if opt == "-h": 27784e5d89aSTony Jones pr_help() 27884e5d89aSTony Jones exit(0); 27984e5d89aSTony Jones elif opt == "-p": 28084e5d89aSTony Jones opt_proc = popt.DISP_PROC 28184e5d89aSTony Jones elif opt == "-pv": 28284e5d89aSTony Jones opt_proc = popt.DISP_PROC_VERBOSE 28384e5d89aSTony Jones elif opt == '-u': 28484e5d89aSTony Jones opt_ns = False 28584e5d89aSTony Jones elif opt == "-t": 28684e5d89aSTony Jones set_type(topt.DISP_TIME) 28784e5d89aSTony Jones elif opt == "-m": 28884e5d89aSTony Jones set_type(topt.DISP_MIG) 28984e5d89aSTony Jones elif opt == "-fs": 29084e5d89aSTony Jones set_type(topt.DISP_ISOLFREE) 29184e5d89aSTony Jones elif opt == "-ms": 29284e5d89aSTony Jones set_type(topt.DISP_ISOLMIG) 29384e5d89aSTony Jones else: 29484e5d89aSTony Jones sys.exit(usage) 29584e5d89aSTony Jones 29684e5d89aSTony Jones elif i == argc - 1: 29784e5d89aSTony Jones m = pid_re.search(opt) 29884e5d89aSTony Jones if m != None and m.group() != "": 29984e5d89aSTony Jones if m.group(3) != None: 30084e5d89aSTony Jones f = pid_filter(m.group(3), m.group(3)) 30184e5d89aSTony Jones else: 30284e5d89aSTony Jones f = pid_filter(m.group(1), m.group(2)) 30384e5d89aSTony Jones else: 30484e5d89aSTony Jones try: 30584e5d89aSTony Jones comm_re=re.compile(opt) 30684e5d89aSTony Jones except: 30784e5d89aSTony Jones sys.stderr.write("invalid regex '%s'" % opt) 30884e5d89aSTony Jones sys.exit(usage) 30984e5d89aSTony Jones f = comm_filter(comm_re) 31084e5d89aSTony Jones 31184e5d89aSTony Jones chead.add_filter(f) 312