162306a36Sopenharmony_ci# report time spent in compaction 262306a36Sopenharmony_ci# Licensed under the terms of the GNU GPL License version 2 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci# testing: 562306a36Sopenharmony_ci# 'echo 1 > /proc/sys/vm/compact_memory' to force compaction of all zones 662306a36Sopenharmony_ci 762306a36Sopenharmony_ciimport os 862306a36Sopenharmony_ciimport sys 962306a36Sopenharmony_ciimport re 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ciimport signal 1262306a36Sopenharmony_cisignal.signal(signal.SIGPIPE, signal.SIG_DFL) 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ciusage = "usage: perf script report compaction-times.py -- [-h] [-u] [-p|-pv] [-t | [-m] [-fs] [-ms]] [pid|pid-range|comm-regex]\n" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciclass popt: 1762306a36Sopenharmony_ci DISP_DFL = 0 1862306a36Sopenharmony_ci DISP_PROC = 1 1962306a36Sopenharmony_ci DISP_PROC_VERBOSE=2 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ciclass topt: 2262306a36Sopenharmony_ci DISP_TIME = 0 2362306a36Sopenharmony_ci DISP_MIG = 1 2462306a36Sopenharmony_ci DISP_ISOLFREE = 2 2562306a36Sopenharmony_ci DISP_ISOLMIG = 4 2662306a36Sopenharmony_ci DISP_ALL = 7 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ciclass comm_filter: 2962306a36Sopenharmony_ci def __init__(self, re): 3062306a36Sopenharmony_ci self.re = re 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci def filter(self, pid, comm): 3362306a36Sopenharmony_ci m = self.re.search(comm) 3462306a36Sopenharmony_ci return m == None or m.group() == "" 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ciclass pid_filter: 3762306a36Sopenharmony_ci def __init__(self, low, high): 3862306a36Sopenharmony_ci self.low = (0 if low == "" else int(low)) 3962306a36Sopenharmony_ci self.high = (0 if high == "" else int(high)) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci def filter(self, pid, comm): 4262306a36Sopenharmony_ci return not (pid >= self.low and (self.high == 0 or pid <= self.high)) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cidef set_type(t): 4562306a36Sopenharmony_ci global opt_disp 4662306a36Sopenharmony_ci opt_disp = (t if opt_disp == topt.DISP_ALL else opt_disp|t) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cidef ns(sec, nsec): 4962306a36Sopenharmony_ci return (sec * 1000000000) + nsec 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cidef time(ns): 5262306a36Sopenharmony_ci return "%dns" % ns if opt_ns else "%dus" % (round(ns, -3) / 1000) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciclass pair: 5562306a36Sopenharmony_ci def __init__(self, aval, bval, alabel = None, blabel = None): 5662306a36Sopenharmony_ci self.alabel = alabel 5762306a36Sopenharmony_ci self.blabel = blabel 5862306a36Sopenharmony_ci self.aval = aval 5962306a36Sopenharmony_ci self.bval = bval 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci def __add__(self, rhs): 6262306a36Sopenharmony_ci self.aval += rhs.aval 6362306a36Sopenharmony_ci self.bval += rhs.bval 6462306a36Sopenharmony_ci return self 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci def __str__(self): 6762306a36Sopenharmony_ci return "%s=%d %s=%d" % (self.alabel, self.aval, self.blabel, self.bval) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ciclass cnode: 7062306a36Sopenharmony_ci def __init__(self, ns): 7162306a36Sopenharmony_ci self.ns = ns 7262306a36Sopenharmony_ci self.migrated = pair(0, 0, "moved", "failed") 7362306a36Sopenharmony_ci self.fscan = pair(0,0, "scanned", "isolated") 7462306a36Sopenharmony_ci self.mscan = pair(0,0, "scanned", "isolated") 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci def __add__(self, rhs): 7762306a36Sopenharmony_ci self.ns += rhs.ns 7862306a36Sopenharmony_ci self.migrated += rhs.migrated 7962306a36Sopenharmony_ci self.fscan += rhs.fscan 8062306a36Sopenharmony_ci self.mscan += rhs.mscan 8162306a36Sopenharmony_ci return self 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci def __str__(self): 8462306a36Sopenharmony_ci prev = 0 8562306a36Sopenharmony_ci s = "%s " % time(self.ns) 8662306a36Sopenharmony_ci if (opt_disp & topt.DISP_MIG): 8762306a36Sopenharmony_ci s += "migration: %s" % self.migrated 8862306a36Sopenharmony_ci prev = 1 8962306a36Sopenharmony_ci if (opt_disp & topt.DISP_ISOLFREE): 9062306a36Sopenharmony_ci s += "%sfree_scanner: %s" % (" " if prev else "", self.fscan) 9162306a36Sopenharmony_ci prev = 1 9262306a36Sopenharmony_ci if (opt_disp & topt.DISP_ISOLMIG): 9362306a36Sopenharmony_ci s += "%smigration_scanner: %s" % (" " if prev else "", self.mscan) 9462306a36Sopenharmony_ci return s 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci def complete(self, secs, nsecs): 9762306a36Sopenharmony_ci self.ns = ns(secs, nsecs) - self.ns 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci def increment(self, migrated, fscan, mscan): 10062306a36Sopenharmony_ci if (migrated != None): 10162306a36Sopenharmony_ci self.migrated += migrated 10262306a36Sopenharmony_ci if (fscan != None): 10362306a36Sopenharmony_ci self.fscan += fscan 10462306a36Sopenharmony_ci if (mscan != None): 10562306a36Sopenharmony_ci self.mscan += mscan 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ciclass chead: 10962306a36Sopenharmony_ci heads = {} 11062306a36Sopenharmony_ci val = cnode(0); 11162306a36Sopenharmony_ci fobj = None 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci @classmethod 11462306a36Sopenharmony_ci def add_filter(cls, filter): 11562306a36Sopenharmony_ci cls.fobj = filter 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci @classmethod 11862306a36Sopenharmony_ci def create_pending(cls, pid, comm, start_secs, start_nsecs): 11962306a36Sopenharmony_ci filtered = 0 12062306a36Sopenharmony_ci try: 12162306a36Sopenharmony_ci head = cls.heads[pid] 12262306a36Sopenharmony_ci filtered = head.is_filtered() 12362306a36Sopenharmony_ci except KeyError: 12462306a36Sopenharmony_ci if cls.fobj != None: 12562306a36Sopenharmony_ci filtered = cls.fobj.filter(pid, comm) 12662306a36Sopenharmony_ci head = cls.heads[pid] = chead(comm, pid, filtered) 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if not filtered: 12962306a36Sopenharmony_ci head.mark_pending(start_secs, start_nsecs) 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci @classmethod 13262306a36Sopenharmony_ci def increment_pending(cls, pid, migrated, fscan, mscan): 13362306a36Sopenharmony_ci head = cls.heads[pid] 13462306a36Sopenharmony_ci if not head.is_filtered(): 13562306a36Sopenharmony_ci if head.is_pending(): 13662306a36Sopenharmony_ci head.do_increment(migrated, fscan, mscan) 13762306a36Sopenharmony_ci else: 13862306a36Sopenharmony_ci sys.stderr.write("missing start compaction event for pid %d\n" % pid) 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci @classmethod 14162306a36Sopenharmony_ci def complete_pending(cls, pid, secs, nsecs): 14262306a36Sopenharmony_ci head = cls.heads[pid] 14362306a36Sopenharmony_ci if not head.is_filtered(): 14462306a36Sopenharmony_ci if head.is_pending(): 14562306a36Sopenharmony_ci head.make_complete(secs, nsecs) 14662306a36Sopenharmony_ci else: 14762306a36Sopenharmony_ci sys.stderr.write("missing start compaction event for pid %d\n" % pid) 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci @classmethod 15062306a36Sopenharmony_ci def gen(cls): 15162306a36Sopenharmony_ci if opt_proc != popt.DISP_DFL: 15262306a36Sopenharmony_ci for i in cls.heads: 15362306a36Sopenharmony_ci yield cls.heads[i] 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci @classmethod 15662306a36Sopenharmony_ci def str(cls): 15762306a36Sopenharmony_ci return cls.val 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci def __init__(self, comm, pid, filtered): 16062306a36Sopenharmony_ci self.comm = comm 16162306a36Sopenharmony_ci self.pid = pid 16262306a36Sopenharmony_ci self.val = cnode(0) 16362306a36Sopenharmony_ci self.pending = None 16462306a36Sopenharmony_ci self.filtered = filtered 16562306a36Sopenharmony_ci self.list = [] 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci def __add__(self, rhs): 16862306a36Sopenharmony_ci self.ns += rhs.ns 16962306a36Sopenharmony_ci self.val += rhs.val 17062306a36Sopenharmony_ci return self 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci def mark_pending(self, secs, nsecs): 17362306a36Sopenharmony_ci self.pending = cnode(ns(secs, nsecs)) 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci def do_increment(self, migrated, fscan, mscan): 17662306a36Sopenharmony_ci self.pending.increment(migrated, fscan, mscan) 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci def make_complete(self, secs, nsecs): 17962306a36Sopenharmony_ci self.pending.complete(secs, nsecs) 18062306a36Sopenharmony_ci chead.val += self.pending 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if opt_proc != popt.DISP_DFL: 18362306a36Sopenharmony_ci self.val += self.pending 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if opt_proc == popt.DISP_PROC_VERBOSE: 18662306a36Sopenharmony_ci self.list.append(self.pending) 18762306a36Sopenharmony_ci self.pending = None 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci def enumerate(self): 19062306a36Sopenharmony_ci if opt_proc == popt.DISP_PROC_VERBOSE and not self.is_filtered(): 19162306a36Sopenharmony_ci for i, pelem in enumerate(self.list): 19262306a36Sopenharmony_ci sys.stdout.write("%d[%s].%d: %s\n" % (self.pid, self.comm, i+1, pelem)) 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci def is_pending(self): 19562306a36Sopenharmony_ci return self.pending != None 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci def is_filtered(self): 19862306a36Sopenharmony_ci return self.filtered 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci def display(self): 20162306a36Sopenharmony_ci if not self.is_filtered(): 20262306a36Sopenharmony_ci sys.stdout.write("%d[%s]: %s\n" % (self.pid, self.comm, self.val)) 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cidef trace_end(): 20662306a36Sopenharmony_ci sys.stdout.write("total: %s\n" % chead.str()) 20762306a36Sopenharmony_ci for i in chead.gen(): 20862306a36Sopenharmony_ci i.display(), 20962306a36Sopenharmony_ci i.enumerate() 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cidef compaction__mm_compaction_migratepages(event_name, context, common_cpu, 21262306a36Sopenharmony_ci common_secs, common_nsecs, common_pid, common_comm, 21362306a36Sopenharmony_ci common_callchain, nr_migrated, nr_failed): 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci chead.increment_pending(common_pid, 21662306a36Sopenharmony_ci pair(nr_migrated, nr_failed), None, None) 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cidef compaction__mm_compaction_isolate_freepages(event_name, context, common_cpu, 21962306a36Sopenharmony_ci common_secs, common_nsecs, common_pid, common_comm, 22062306a36Sopenharmony_ci common_callchain, start_pfn, end_pfn, nr_scanned, nr_taken): 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci chead.increment_pending(common_pid, 22362306a36Sopenharmony_ci None, pair(nr_scanned, nr_taken), None) 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cidef compaction__mm_compaction_isolate_migratepages(event_name, context, common_cpu, 22662306a36Sopenharmony_ci common_secs, common_nsecs, common_pid, common_comm, 22762306a36Sopenharmony_ci common_callchain, start_pfn, end_pfn, nr_scanned, nr_taken): 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci chead.increment_pending(common_pid, 23062306a36Sopenharmony_ci None, None, pair(nr_scanned, nr_taken)) 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cidef compaction__mm_compaction_end(event_name, context, common_cpu, 23362306a36Sopenharmony_ci common_secs, common_nsecs, common_pid, common_comm, 23462306a36Sopenharmony_ci common_callchain, zone_start, migrate_start, free_start, zone_end, 23562306a36Sopenharmony_ci sync, status): 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci chead.complete_pending(common_pid, common_secs, common_nsecs) 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cidef compaction__mm_compaction_begin(event_name, context, common_cpu, 24062306a36Sopenharmony_ci common_secs, common_nsecs, common_pid, common_comm, 24162306a36Sopenharmony_ci common_callchain, zone_start, migrate_start, free_start, zone_end, 24262306a36Sopenharmony_ci sync): 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci chead.create_pending(common_pid, common_comm, common_secs, common_nsecs) 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cidef pr_help(): 24762306a36Sopenharmony_ci global usage 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci sys.stdout.write(usage) 25062306a36Sopenharmony_ci sys.stdout.write("\n") 25162306a36Sopenharmony_ci sys.stdout.write("-h display this help\n") 25262306a36Sopenharmony_ci sys.stdout.write("-p display by process\n") 25362306a36Sopenharmony_ci sys.stdout.write("-pv display by process (verbose)\n") 25462306a36Sopenharmony_ci sys.stdout.write("-t display stall times only\n") 25562306a36Sopenharmony_ci sys.stdout.write("-m display stats for migration\n") 25662306a36Sopenharmony_ci sys.stdout.write("-fs display stats for free scanner\n") 25762306a36Sopenharmony_ci sys.stdout.write("-ms display stats for migration scanner\n") 25862306a36Sopenharmony_ci sys.stdout.write("-u display results in microseconds (default nanoseconds)\n") 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cicomm_re = None 26262306a36Sopenharmony_cipid_re = None 26362306a36Sopenharmony_cipid_regex = "^(\d*)-(\d*)$|^(\d*)$" 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ciopt_proc = popt.DISP_DFL 26662306a36Sopenharmony_ciopt_disp = topt.DISP_ALL 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ciopt_ns = True 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ciargc = len(sys.argv) - 1 27162306a36Sopenharmony_ciif argc >= 1: 27262306a36Sopenharmony_ci pid_re = re.compile(pid_regex) 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci for i, opt in enumerate(sys.argv[1:]): 27562306a36Sopenharmony_ci if opt[0] == "-": 27662306a36Sopenharmony_ci if opt == "-h": 27762306a36Sopenharmony_ci pr_help() 27862306a36Sopenharmony_ci exit(0); 27962306a36Sopenharmony_ci elif opt == "-p": 28062306a36Sopenharmony_ci opt_proc = popt.DISP_PROC 28162306a36Sopenharmony_ci elif opt == "-pv": 28262306a36Sopenharmony_ci opt_proc = popt.DISP_PROC_VERBOSE 28362306a36Sopenharmony_ci elif opt == '-u': 28462306a36Sopenharmony_ci opt_ns = False 28562306a36Sopenharmony_ci elif opt == "-t": 28662306a36Sopenharmony_ci set_type(topt.DISP_TIME) 28762306a36Sopenharmony_ci elif opt == "-m": 28862306a36Sopenharmony_ci set_type(topt.DISP_MIG) 28962306a36Sopenharmony_ci elif opt == "-fs": 29062306a36Sopenharmony_ci set_type(topt.DISP_ISOLFREE) 29162306a36Sopenharmony_ci elif opt == "-ms": 29262306a36Sopenharmony_ci set_type(topt.DISP_ISOLMIG) 29362306a36Sopenharmony_ci else: 29462306a36Sopenharmony_ci sys.exit(usage) 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci elif i == argc - 1: 29762306a36Sopenharmony_ci m = pid_re.search(opt) 29862306a36Sopenharmony_ci if m != None and m.group() != "": 29962306a36Sopenharmony_ci if m.group(3) != None: 30062306a36Sopenharmony_ci f = pid_filter(m.group(3), m.group(3)) 30162306a36Sopenharmony_ci else: 30262306a36Sopenharmony_ci f = pid_filter(m.group(1), m.group(2)) 30362306a36Sopenharmony_ci else: 30462306a36Sopenharmony_ci try: 30562306a36Sopenharmony_ci comm_re=re.compile(opt) 30662306a36Sopenharmony_ci except: 30762306a36Sopenharmony_ci sys.stderr.write("invalid regex '%s'" % opt) 30862306a36Sopenharmony_ci sys.exit(usage) 30962306a36Sopenharmony_ci f = comm_filter(comm_re) 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci chead.add_filter(f) 312