1*0f4c859eSApple OSS Distributions#!/usr/bin/env python 2*0f4c859eSApple OSS Distributions# machtrace_parse.py 3*0f4c859eSApple OSS Distributions# Parse Mach IPC kmsg data trace from XNU 4*0f4c859eSApple OSS Distributions# 5*0f4c859eSApple OSS Distributions# Jeremy C. Andrus <[email protected]> 6*0f4c859eSApple OSS Distributions# 7*0f4c859eSApple OSS Distributionsfrom __future__ import division 8*0f4c859eSApple OSS Distributions 9*0f4c859eSApple OSS Distributionsimport argparse 10*0f4c859eSApple OSS Distributionsimport subprocess 11*0f4c859eSApple OSS Distributionsimport sys 12*0f4c859eSApple OSS Distributionsimport re 13*0f4c859eSApple OSS Distributionsfrom collections import deque 14*0f4c859eSApple OSS Distributions 15*0f4c859eSApple OSS Distributionsimport os.path 16*0f4c859eSApple OSS Distributions 17*0f4c859eSApple OSS Distributionsfrom collections import defaultdict 18*0f4c859eSApple OSS Distributions 19*0f4c859eSApple OSS Distributionsg_verbose = 0 20*0f4c859eSApple OSS Distributionsg_min_messages = 10 21*0f4c859eSApple OSS Distributionsg_rolling_window = 200 22*0f4c859eSApple OSS Distributions 23*0f4c859eSApple OSS Distributionsdef RunCommand(cmd_string): 24*0f4c859eSApple OSS Distributions """ 25*0f4c859eSApple OSS Distributions returns: (int,str) : exit_code and output_str 26*0f4c859eSApple OSS Distributions """ 27*0f4c859eSApple OSS Distributions global g_verbose 28*0f4c859eSApple OSS Distributions if g_verbose > 1: 29*0f4c859eSApple OSS Distributions sys.stderr.write("\tCMD:{}\n".format(cmd_string)) 30*0f4c859eSApple OSS Distributions output_str = "" 31*0f4c859eSApple OSS Distributions exit_code = 0 32*0f4c859eSApple OSS Distributions try: 33*0f4c859eSApple OSS Distributions output_str = subprocess.check_output(cmd_string, shell=True) 34*0f4c859eSApple OSS Distributions except subprocess.CalledProcessError, e: 35*0f4c859eSApple OSS Distributions exit_code = e.returncode 36*0f4c859eSApple OSS Distributions finally: 37*0f4c859eSApple OSS Distributions return (exit_code, output_str.strip()) 38*0f4c859eSApple OSS Distributions 39*0f4c859eSApple OSS Distributions 40*0f4c859eSApple OSS Distributionsclass IPCNode: 41*0f4c859eSApple OSS Distributions """ Class interface to a graph node representing a logical service name. 42*0f4c859eSApple OSS Distributions In general, this should correspond to a unique binary on the system 43*0f4c859eSApple OSS Distributions which could be started / stopped as different PIDs throughout the life 44*0f4c859eSApple OSS Distributions of the system. 45*0f4c859eSApple OSS Distributions """ 46*0f4c859eSApple OSS Distributions def __init__(self, name = ''): 47*0f4c859eSApple OSS Distributions global g_verbose 48*0f4c859eSApple OSS Distributions self.nname = "L_" + name.replace(".", "_").replace("-", "_") 49*0f4c859eSApple OSS Distributions self.nicename = name 50*0f4c859eSApple OSS Distributions self.outgoing = {} 51*0f4c859eSApple OSS Distributions self.incoming = {} 52*0f4c859eSApple OSS Distributions self.msg_stat = {'o.num':0, 'o.first':0.0, 'o.last':0.0, 'o.window':deque(), 'o.avg':0, 'o.peak':0, \ 53*0f4c859eSApple OSS Distributions 'i.num':0, 'i.first':0.0, 'i.last':0.0, 'i.window':deque(), 'i.avg':0, 'i.peak':0} 54*0f4c859eSApple OSS Distributions self.pidset = {} 55*0f4c859eSApple OSS Distributions self.scalefactor = 100.0 56*0f4c859eSApple OSS Distributions if g_verbose > 0: 57*0f4c859eSApple OSS Distributions sys.stderr.write(' New node: "{}"{}\n'.format(self.nname, ' '*50)) 58*0f4c859eSApple OSS Distributions 59*0f4c859eSApple OSS Distributions def add_outgoing_edge(self, edge, time): 60*0f4c859eSApple OSS Distributions self.outgoing[edge.ename()] = [edge, time] 61*0f4c859eSApple OSS Distributions 62*0f4c859eSApple OSS Distributions def add_incoming_edge(self, edge, time): 63*0f4c859eSApple OSS Distributions self.incoming[edge.ename()] = [edge, time] 64*0f4c859eSApple OSS Distributions 65*0f4c859eSApple OSS Distributions def addpid(self, pid, time): 66*0f4c859eSApple OSS Distributions if not pid in self.pidset: 67*0f4c859eSApple OSS Distributions self.pidset[pid] = [time, 0] 68*0f4c859eSApple OSS Distributions self.pidset[pid][1] = time 69*0f4c859eSApple OSS Distributions 70*0f4c859eSApple OSS Distributions def incoming_msg(self, size, time_us): 71*0f4c859eSApple OSS Distributions global g_min_messages 72*0f4c859eSApple OSS Distributions global g_rolling_window 73*0f4c859eSApple OSS Distributions num = self.msg_stat['i.num'] + 1 74*0f4c859eSApple OSS Distributions self.msg_stat['i.num'] = num 75*0f4c859eSApple OSS Distributions time_us = float(time_us) 76*0f4c859eSApple OSS Distributions if self.msg_stat['i.first'] == 0.0: 77*0f4c859eSApple OSS Distributions self.msg_stat['i.first'] = time_us 78*0f4c859eSApple OSS Distributions self.msg_stat['i.last'] = time_us 79*0f4c859eSApple OSS Distributions else: 80*0f4c859eSApple OSS Distributions self.msg_stat['i.last'] = time_us 81*0f4c859eSApple OSS Distributions if num > g_min_messages: 82*0f4c859eSApple OSS Distributions avg = (num * self.scalefactor) / (time_us - self.msg_stat['i.first']) 83*0f4c859eSApple OSS Distributions self.msg_stat['i.avg'] = avg 84*0f4c859eSApple OSS Distributions 85*0f4c859eSApple OSS Distributions self.msg_stat['i.window'].append(time_us) 86*0f4c859eSApple OSS Distributions if len(self.msg_stat['i.window']) > g_rolling_window: 87*0f4c859eSApple OSS Distributions self.msg_stat['i.window'].popleft() 88*0f4c859eSApple OSS Distributions n = len(self.msg_stat['i.window']) 89*0f4c859eSApple OSS Distributions ravg = float(len(self.msg_stat['i.window']) * self.scalefactor) / \ 90*0f4c859eSApple OSS Distributions (self.msg_stat['i.window'][-1] - self.msg_stat['i.window'][0]) 91*0f4c859eSApple OSS Distributions if ravg > self.msg_stat['i.peak']: 92*0f4c859eSApple OSS Distributions self.msg_stat['i.peak'] = ravg 93*0f4c859eSApple OSS Distributions 94*0f4c859eSApple OSS Distributions def outgoing_msg(self, size, time_us): 95*0f4c859eSApple OSS Distributions global g_min_messages 96*0f4c859eSApple OSS Distributions global g_rolling_window 97*0f4c859eSApple OSS Distributions num = self.msg_stat['o.num'] + 1 98*0f4c859eSApple OSS Distributions self.msg_stat['o.num'] = num 99*0f4c859eSApple OSS Distributions time_us = float(time_us) 100*0f4c859eSApple OSS Distributions if self.msg_stat['o.first'] == 0.0: 101*0f4c859eSApple OSS Distributions self.msg_stat['o.first'] = time_us 102*0f4c859eSApple OSS Distributions self.msg_stat['o.last'] = time_us 103*0f4c859eSApple OSS Distributions else: 104*0f4c859eSApple OSS Distributions self.msg_stat['o.last'] = time_us 105*0f4c859eSApple OSS Distributions if num > g_min_messages: 106*0f4c859eSApple OSS Distributions avg = (num * self.scalefactor) / (time_us - self.msg_stat['o.first']) 107*0f4c859eSApple OSS Distributions self.msg_stat['o.avg'] = avg 108*0f4c859eSApple OSS Distributions 109*0f4c859eSApple OSS Distributions self.msg_stat['o.window'].append(time_us) 110*0f4c859eSApple OSS Distributions if len(self.msg_stat['o.window']) > g_rolling_window: 111*0f4c859eSApple OSS Distributions self.msg_stat['o.window'].popleft() 112*0f4c859eSApple OSS Distributions n = len(self.msg_stat['o.window']) 113*0f4c859eSApple OSS Distributions ravg = float(len(self.msg_stat['o.window']) * self.scalefactor) / \ 114*0f4c859eSApple OSS Distributions (self.msg_stat['o.window'][-1] - self.msg_stat['o.window'][0]) 115*0f4c859eSApple OSS Distributions if ravg > self.msg_stat['o.peak']: 116*0f4c859eSApple OSS Distributions self.msg_stat['o.peak'] = ravg 117*0f4c859eSApple OSS Distributions 118*0f4c859eSApple OSS Distributions def nmsgs(self): 119*0f4c859eSApple OSS Distributions return self.msg_stat['o.num'], self.msg_stat['i.num'] 120*0f4c859eSApple OSS Distributions 121*0f4c859eSApple OSS Distributions def recycled(self): 122*0f4c859eSApple OSS Distributions return len(self.pidset) 123*0f4c859eSApple OSS Distributions 124*0f4c859eSApple OSS Distributions def label(self, timebase = 1000000.0): 125*0f4c859eSApple OSS Distributions oavg = float(self.msg_stat['o.avg']) / self.scalefactor 126*0f4c859eSApple OSS Distributions opeak = float(self.msg_stat['o.peak']) / self.scalefactor 127*0f4c859eSApple OSS Distributions oactive = self.msg_stat['o.last'] - self.msg_stat['o.first'] 128*0f4c859eSApple OSS Distributions iavg = float(self.msg_stat['i.avg']) / self.scalefactor 129*0f4c859eSApple OSS Distributions ipeak = float(self.msg_stat['i.peak']) / self.scalefactor 130*0f4c859eSApple OSS Distributions iactive = self.msg_stat['i.last'] - self.msg_stat['i.first'] 131*0f4c859eSApple OSS Distributions if timebase > 0.0: 132*0f4c859eSApple OSS Distributions oavg = oavg * timebase 133*0f4c859eSApple OSS Distributions opeak = opeak * timebase 134*0f4c859eSApple OSS Distributions oactive = oactive / timebase 135*0f4c859eSApple OSS Distributions iavg = iavg * timebase 136*0f4c859eSApple OSS Distributions ipeak = ipeak * timebase 137*0f4c859eSApple OSS Distributions iactive = iactive / timebase 138*0f4c859eSApple OSS Distributions return "{:s}\\no:{:d}/({:d}:{:.1f}s)/{:.1f}:{:.1f})\\ni:{:d}({:d}:{:.1f}s)/{:.1f}:{:.1f})\\nR:{:d}"\ 139*0f4c859eSApple OSS Distributions .format(self.nicename, \ 140*0f4c859eSApple OSS Distributions len(self.outgoing), self.msg_stat['o.num'], oactive, oavg, opeak, \ 141*0f4c859eSApple OSS Distributions len(self.incoming), self.msg_stat['i.num'], iactive, iavg, ipeak, \ 142*0f4c859eSApple OSS Distributions len(self.pidset)) 143*0f4c859eSApple OSS Distributions 144*0f4c859eSApple OSS Distributionsclass IPCEdge: 145*0f4c859eSApple OSS Distributions """ Class interface to an graph edge representing two services / programs 146*0f4c859eSApple OSS Distributions communicating via Mach IPC. Note that this communication could 147*0f4c859eSApple OSS Distributions use many different PIDs. The connected graph nodes (see IPCNode) 148*0f4c859eSApple OSS Distributions represent logical services on the system which could be instantiated 149*0f4c859eSApple OSS Distributions as many different PIDs depending on the lifecycle of the process 150*0f4c859eSApple OSS Distributions (dictated in part by launchd). 151*0f4c859eSApple OSS Distributions """ 152*0f4c859eSApple OSS Distributions 153*0f4c859eSApple OSS Distributions F_TRACED = 0x00000100 154*0f4c859eSApple OSS Distributions F_COMPLEX = 0x00000200 155*0f4c859eSApple OSS Distributions F_OOLMEM = 0x00000400 156*0f4c859eSApple OSS Distributions F_VCPY = 0x00000800 157*0f4c859eSApple OSS Distributions F_PCPY = 0x00001000 158*0f4c859eSApple OSS Distributions F_SND64 = 0x00002000 159*0f4c859eSApple OSS Distributions F_RAISEIMP = 0x00004000 160*0f4c859eSApple OSS Distributions F_APP_SRC = 0x00008000 161*0f4c859eSApple OSS Distributions F_APP_DST = 0x00010000 162*0f4c859eSApple OSS Distributions F_DAEMON_SRC = 0x00020000 163*0f4c859eSApple OSS Distributions F_DAEMON_DST = 0x00040000 164*0f4c859eSApple OSS Distributions F_DST_NDFLTQ = 0x00080000 165*0f4c859eSApple OSS Distributions F_SRC_NDFLTQ = 0x00100000 166*0f4c859eSApple OSS Distributions F_DST_SONCE = 0x00200000 167*0f4c859eSApple OSS Distributions F_SRC_SONCE = 0x00400000 168*0f4c859eSApple OSS Distributions F_CHECKIN = 0x00800000 169*0f4c859eSApple OSS Distributions F_ONEWAY = 0x01000000 170*0f4c859eSApple OSS Distributions F_IOKIT = 0x02000000 171*0f4c859eSApple OSS Distributions F_SNDRCV = 0x04000000 172*0f4c859eSApple OSS Distributions F_DSTQFULL = 0x08000000 173*0f4c859eSApple OSS Distributions F_VOUCHER = 0x10000000 174*0f4c859eSApple OSS Distributions F_TIMER = 0x20000000 175*0f4c859eSApple OSS Distributions F_SEMA = 0x40000000 176*0f4c859eSApple OSS Distributions F_PORTS_MASK = 0x000000FF 177*0f4c859eSApple OSS Distributions 178*0f4c859eSApple OSS Distributions DTYPES = [ 'std', 'xpc', 'iokit', 'std.reply', 'xpc.reply', 'iokit.reply' ] 179*0f4c859eSApple OSS Distributions DFLAVORS = [ 'std', 'ool', 'vcpy', 'iokit' ] 180*0f4c859eSApple OSS Distributions 181*0f4c859eSApple OSS Distributions def __init__(self, src = IPCNode(), dst = IPCNode(), data = '0', flags = '0', time = 0.0): 182*0f4c859eSApple OSS Distributions self.src = src 183*0f4c859eSApple OSS Distributions self.dst = dst 184*0f4c859eSApple OSS Distributions self.flags = 0 185*0f4c859eSApple OSS Distributions self.dweight = 0 186*0f4c859eSApple OSS Distributions self.pweight = 0 187*0f4c859eSApple OSS Distributions self.weight = 0 188*0f4c859eSApple OSS Distributions self._data = { 'std':0, 'ool':0, 'vcpy':0, 'iokit':0 } 189*0f4c859eSApple OSS Distributions self._dtype = { 'std':0, 'xpc':0, 'iokit':0, 'std.reply':0, 'xpc.reply':0, 'iokit.reply':0 } 190*0f4c859eSApple OSS Distributions self._msgs = { 'std':0, 'ool':0, 'vcpy':0, 'iokit':0 } 191*0f4c859eSApple OSS Distributions self._mtype = { 'std':0, 'xpc':0, 'iokit':0, 'std.reply':0, 'xpc.reply':0, 'iokit.reply':0 } 192*0f4c859eSApple OSS Distributions self.ports = 0 193*0f4c859eSApple OSS Distributions self.task64 = False 194*0f4c859eSApple OSS Distributions self.task32 = False 195*0f4c859eSApple OSS Distributions self.src.add_outgoing_edge(self, time) 196*0f4c859eSApple OSS Distributions self.dst.add_incoming_edge(self, time) 197*0f4c859eSApple OSS Distributions self.addmsg(data, flags, time) 198*0f4c859eSApple OSS Distributions 199*0f4c859eSApple OSS Distributions def ename(self): 200*0f4c859eSApple OSS Distributions return self.src.nname + " -> " + self.dst.nname 201*0f4c859eSApple OSS Distributions 202*0f4c859eSApple OSS Distributions def msgdata(self): 203*0f4c859eSApple OSS Distributions return self._data, self._dtype 204*0f4c859eSApple OSS Distributions 205*0f4c859eSApple OSS Distributions def data(self, flavor = None): 206*0f4c859eSApple OSS Distributions if not flavor: 207*0f4c859eSApple OSS Distributions return sum(self._data.itervalues()) 208*0f4c859eSApple OSS Distributions elif flavor in self._data: 209*0f4c859eSApple OSS Distributions return self._data[flavor] 210*0f4c859eSApple OSS Distributions else: 211*0f4c859eSApple OSS Distributions return 0 212*0f4c859eSApple OSS Distributions 213*0f4c859eSApple OSS Distributions def dtype(self, type): 214*0f4c859eSApple OSS Distributions if not type: 215*0f4c859eSApple OSS Distributions return sum(self._dtype.itervalues()) 216*0f4c859eSApple OSS Distributions elif type in self._dtype: 217*0f4c859eSApple OSS Distributions return self._dtype[type] 218*0f4c859eSApple OSS Distributions else: 219*0f4c859eSApple OSS Distributions return 0 220*0f4c859eSApple OSS Distributions 221*0f4c859eSApple OSS Distributions def msgs(self, flavor = None): 222*0f4c859eSApple OSS Distributions if not flavor: 223*0f4c859eSApple OSS Distributions return sum(self._msgs.itervalues()) 224*0f4c859eSApple OSS Distributions elif flavor in self._msgs: 225*0f4c859eSApple OSS Distributions return self._msgs[flavor] 226*0f4c859eSApple OSS Distributions else: 227*0f4c859eSApple OSS Distributions return 0 228*0f4c859eSApple OSS Distributions 229*0f4c859eSApple OSS Distributions def mtype(self, type): 230*0f4c859eSApple OSS Distributions if not type: 231*0f4c859eSApple OSS Distributions return sum(self._mtype.itervalues()) 232*0f4c859eSApple OSS Distributions elif type in self._mtype: 233*0f4c859eSApple OSS Distributions return self._mtype[type] 234*0f4c859eSApple OSS Distributions else: 235*0f4c859eSApple OSS Distributions return 0 236*0f4c859eSApple OSS Distributions 237*0f4c859eSApple OSS Distributions def selfedge(self): 238*0f4c859eSApple OSS Distributions if self.src.nname == self.dst.nname: 239*0f4c859eSApple OSS Distributions return True 240*0f4c859eSApple OSS Distributions return False 241*0f4c859eSApple OSS Distributions 242*0f4c859eSApple OSS Distributions def addmsg(self, data_hex_str, flags_str, time): 243*0f4c859eSApple OSS Distributions global g_verbose 244*0f4c859eSApple OSS Distributions f = int(flags_str, 16) 245*0f4c859eSApple OSS Distributions self.flags |= f 246*0f4c859eSApple OSS Distributions df = {f:0 for f in self.DFLAVORS} 247*0f4c859eSApple OSS Distributions dt = {t:0 for t in self.DTYPES} 248*0f4c859eSApple OSS Distributions if not f & self.F_TRACED: 249*0f4c859eSApple OSS Distributions return df, dt 250*0f4c859eSApple OSS Distributions self.weight += 1 251*0f4c859eSApple OSS Distributions if f & self.F_SND64: 252*0f4c859eSApple OSS Distributions self.task64 = True 253*0f4c859eSApple OSS Distributions else: 254*0f4c859eSApple OSS Distributions self.task32 = True 255*0f4c859eSApple OSS Distributions if not f & self.F_COMPLEX: 256*0f4c859eSApple OSS Distributions self.dweight += 1 257*0f4c859eSApple OSS Distributions df['std'] = int(data_hex_str, 16) 258*0f4c859eSApple OSS Distributions if f & self.F_IOKIT: 259*0f4c859eSApple OSS Distributions df['iokit'] = df['std'] 260*0f4c859eSApple OSS Distributions df['std'] = 0 261*0f4c859eSApple OSS Distributions self._data['iokit'] += df['iokit'] 262*0f4c859eSApple OSS Distributions self._msgs['iokit'] += 1 263*0f4c859eSApple OSS Distributions else: 264*0f4c859eSApple OSS Distributions self._data['std'] += df['std'] 265*0f4c859eSApple OSS Distributions self._msgs['std'] += 1 266*0f4c859eSApple OSS Distributions elif f & self.F_OOLMEM: 267*0f4c859eSApple OSS Distributions self.dweight += 1 268*0f4c859eSApple OSS Distributions df['ool'] = int(data_hex_str, 16) 269*0f4c859eSApple OSS Distributions if f & self.F_IOKIT: 270*0f4c859eSApple OSS Distributions df['iokit'] = df['ool'] 271*0f4c859eSApple OSS Distributions df['ool'] = 0 272*0f4c859eSApple OSS Distributions self._data['iokit'] += df['iokit'] 273*0f4c859eSApple OSS Distributions self._msgs['iokit'] += 1 274*0f4c859eSApple OSS Distributions elif f & self.F_VCPY: 275*0f4c859eSApple OSS Distributions df['vcpy'] = df['ool'] 276*0f4c859eSApple OSS Distributions df['ool'] = 0 277*0f4c859eSApple OSS Distributions self._data['vcpy'] += df['vcpy'] 278*0f4c859eSApple OSS Distributions self._msgs['vcpy'] += 1 279*0f4c859eSApple OSS Distributions else: 280*0f4c859eSApple OSS Distributions self._data['ool'] += df['ool'] 281*0f4c859eSApple OSS Distributions self._msgs['ool'] += 1 282*0f4c859eSApple OSS Distributions # Complex messages can contain ports and data 283*0f4c859eSApple OSS Distributions if f & self.F_COMPLEX: 284*0f4c859eSApple OSS Distributions nports = f & self.F_PORTS_MASK 285*0f4c859eSApple OSS Distributions if nports > 0: 286*0f4c859eSApple OSS Distributions self.pweight += 1 287*0f4c859eSApple OSS Distributions self.ports += nports 288*0f4c859eSApple OSS Distributions dsize = sum(df.values()) 289*0f4c859eSApple OSS Distributions if f & self.F_DST_SONCE: 290*0f4c859eSApple OSS Distributions if f & self.F_IOKIT: 291*0f4c859eSApple OSS Distributions dt['iokit.reply'] = dsize 292*0f4c859eSApple OSS Distributions self._dtype['iokit.reply'] += dsize 293*0f4c859eSApple OSS Distributions self._mtype['iokit.reply'] += 1 294*0f4c859eSApple OSS Distributions elif f & (self.F_DST_NDFLTQ | self.F_SRC_NDFLTQ): 295*0f4c859eSApple OSS Distributions dt['xpc.reply'] = dsize 296*0f4c859eSApple OSS Distributions self._dtype['xpc.reply'] += dsize 297*0f4c859eSApple OSS Distributions self._mtype['xpc.reply'] += 1 298*0f4c859eSApple OSS Distributions else: 299*0f4c859eSApple OSS Distributions dt['std.reply'] = dsize 300*0f4c859eSApple OSS Distributions self._dtype['std.reply'] += dsize 301*0f4c859eSApple OSS Distributions self._mtype['std.reply'] += 1 302*0f4c859eSApple OSS Distributions elif f & self.F_IOKIT: 303*0f4c859eSApple OSS Distributions dt['iokit'] = dsize 304*0f4c859eSApple OSS Distributions self._dtype['iokit'] += dsize 305*0f4c859eSApple OSS Distributions self._mtype['iokit'] += 1 306*0f4c859eSApple OSS Distributions elif f & (self.F_DST_NDFLTQ | self.F_SRC_NDFLTQ): 307*0f4c859eSApple OSS Distributions dt['xpc'] = dsize 308*0f4c859eSApple OSS Distributions self._dtype['xpc'] += dsize 309*0f4c859eSApple OSS Distributions self._mtype['xpc'] += 1 310*0f4c859eSApple OSS Distributions else: 311*0f4c859eSApple OSS Distributions dt['std'] = dsize 312*0f4c859eSApple OSS Distributions self._dtype['std'] += dsize 313*0f4c859eSApple OSS Distributions self._mtype['std'] += 1 314*0f4c859eSApple OSS Distributions self.src.outgoing_msg(dsize, time) 315*0f4c859eSApple OSS Distributions self.dst.incoming_msg(dsize, time) 316*0f4c859eSApple OSS Distributions if g_verbose > 2: 317*0f4c859eSApple OSS Distributions sys.stderr.write(' {}->{} ({}/{}){}\r'.format(self.src.nname, self.dst.nname, df['ool'], df['std'], ' ' *50)) 318*0f4c859eSApple OSS Distributions return df, dt 319*0f4c859eSApple OSS Distributions 320*0f4c859eSApple OSS Distributions def avgmsg(self): 321*0f4c859eSApple OSS Distributions avgsz = self.data() / self.dweight 322*0f4c859eSApple OSS Distributions msgs_with_data = self.dweight / self.weight 323*0f4c859eSApple OSS Distributions avgports = self.ports / self.pweight 324*0f4c859eSApple OSS Distributions msgs_with_ports = self.pweight / self.weight 325*0f4c859eSApple OSS Distributions return (avgsz, msgs_with_data, avgports, msgs_with_ports) 326*0f4c859eSApple OSS Distributions 327*0f4c859eSApple OSS Distributions 328*0f4c859eSApple OSS Distributionsclass EdgeError(Exception): 329*0f4c859eSApple OSS Distributions """ IPCEdge exception class 330*0f4c859eSApple OSS Distributions """ 331*0f4c859eSApple OSS Distributions def __init__(self, edge, nm): 332*0f4c859eSApple OSS Distributions self.msg = "Edge {} (w:{}) didn't match incoming name {}!".format(edge.ename(), edge.weight, nm) 333*0f4c859eSApple OSS Distributions 334*0f4c859eSApple OSS Distributionsclass IPCGraph: 335*0f4c859eSApple OSS Distributions """ Class interface to a directed graph of IPC interconnectivity 336*0f4c859eSApple OSS Distributions """ 337*0f4c859eSApple OSS Distributions def __init__(self, name = '', timebase = 0.0): 338*0f4c859eSApple OSS Distributions global g_verbose 339*0f4c859eSApple OSS Distributions if len(name) == 0: 340*0f4c859eSApple OSS Distributions self.name = 'ipcgraph' 341*0f4c859eSApple OSS Distributions else: 342*0f4c859eSApple OSS Distributions self.name = name 343*0f4c859eSApple OSS Distributions if g_verbose > 0: 344*0f4c859eSApple OSS Distributions sys.stderr.write('Creating new IPCGraph named {}...\n'.format(self.name)) 345*0f4c859eSApple OSS Distributions self.nodes = {} 346*0f4c859eSApple OSS Distributions self.edges = {} 347*0f4c859eSApple OSS Distributions self.msgs = defaultdict(lambda: {f:0 for f in IPCEdge.DFLAVORS}) 348*0f4c859eSApple OSS Distributions self.msgtypes = defaultdict(lambda: {t:0 for t in IPCEdge.DTYPES}) 349*0f4c859eSApple OSS Distributions self.nmsgs = 0 350*0f4c859eSApple OSS Distributions self.totals = {} 351*0f4c859eSApple OSS Distributions self.maxdweight = 0 352*0f4c859eSApple OSS Distributions for f in IPCEdge.DFLAVORS: 353*0f4c859eSApple OSS Distributions self.totals['n'+f] = 0 354*0f4c859eSApple OSS Distributions self.totals['D'+f] = 0 355*0f4c859eSApple OSS Distributions if timebase and timebase > 0.0: 356*0f4c859eSApple OSS Distributions self.timebase = timebase 357*0f4c859eSApple OSS Distributions else: 358*0f4c859eSApple OSS Distributions self.timebase = 0.0 359*0f4c859eSApple OSS Distributions 360*0f4c859eSApple OSS Distributions def __iter__(self): 361*0f4c859eSApple OSS Distributions return edges 362*0f4c859eSApple OSS Distributions 363*0f4c859eSApple OSS Distributions def edgename(self, src, dst): 364*0f4c859eSApple OSS Distributions if src and dst: 365*0f4c859eSApple OSS Distributions return src.nname + ' -> ' + dst.nname 366*0f4c859eSApple OSS Distributions return '' 367*0f4c859eSApple OSS Distributions 368*0f4c859eSApple OSS Distributions def addmsg(self, src_str, src_pid, dst_str, dst_pid, data_hex_str, flags_str, time): 369*0f4c859eSApple OSS Distributions src = None 370*0f4c859eSApple OSS Distributions dst = None 371*0f4c859eSApple OSS Distributions for k, v in self.nodes.iteritems(): 372*0f4c859eSApple OSS Distributions if not src and k == src_str: 373*0f4c859eSApple OSS Distributions src = v 374*0f4c859eSApple OSS Distributions if not dst and k == dst_str: 375*0f4c859eSApple OSS Distributions dst = v 376*0f4c859eSApple OSS Distributions if src and dst: 377*0f4c859eSApple OSS Distributions break 378*0f4c859eSApple OSS Distributions if not src: 379*0f4c859eSApple OSS Distributions src = IPCNode(src_str) 380*0f4c859eSApple OSS Distributions self.nodes[src_str] = src; 381*0f4c859eSApple OSS Distributions if not dst: 382*0f4c859eSApple OSS Distributions dst = IPCNode(dst_str) 383*0f4c859eSApple OSS Distributions self.nodes[dst_str] = dst 384*0f4c859eSApple OSS Distributions src.addpid(src_pid, time) 385*0f4c859eSApple OSS Distributions dst.addpid(dst_pid, time) 386*0f4c859eSApple OSS Distributions 387*0f4c859eSApple OSS Distributions nm = self.edgename(src, dst) 388*0f4c859eSApple OSS Distributions msgdata = {} 389*0f4c859eSApple OSS Distributions msgDtype = {} 390*0f4c859eSApple OSS Distributions e = self.edges.get(nm) 391*0f4c859eSApple OSS Distributions if e != None: 392*0f4c859eSApple OSS Distributions if e.ename() != nm: 393*0f4c859eSApple OSS Distributions raise EdgeError(e,nm) 394*0f4c859eSApple OSS Distributions msgdata, msgDtype = e.addmsg(data_hex_str, flags_str, time) 395*0f4c859eSApple OSS Distributions else: 396*0f4c859eSApple OSS Distributions e = IPCEdge(src, dst, data_hex_str, flags_str, time) 397*0f4c859eSApple OSS Distributions msgdata, msgDtype = e.msgdata() 398*0f4c859eSApple OSS Distributions self.edges[nm] = e 399*0f4c859eSApple OSS Distributions 400*0f4c859eSApple OSS Distributions if self.maxdweight < e.dweight: 401*0f4c859eSApple OSS Distributions self.maxdweight = e.dweight 402*0f4c859eSApple OSS Distributions 403*0f4c859eSApple OSS Distributions if sum(msgdata.values()) == 0: 404*0f4c859eSApple OSS Distributions self.msgs[0]['std'] += 1 405*0f4c859eSApple OSS Distributions self.msgtypes[0]['std'] += 1 406*0f4c859eSApple OSS Distributions if not 'enames' in self.msgs[0]: 407*0f4c859eSApple OSS Distributions self.msgs[0]['enames'] = [ nm ] 408*0f4c859eSApple OSS Distributions elif not nm in self.msgs[0]['enames']: 409*0f4c859eSApple OSS Distributions self.msgs[0]['enames'].append(nm) 410*0f4c859eSApple OSS Distributions else: 411*0f4c859eSApple OSS Distributions for k,d in msgdata.iteritems(): 412*0f4c859eSApple OSS Distributions if d > 0: 413*0f4c859eSApple OSS Distributions self.msgs[d][k] += 1 414*0f4c859eSApple OSS Distributions self.totals['n'+k] += 1 415*0f4c859eSApple OSS Distributions self.totals['D'+k] += d 416*0f4c859eSApple OSS Distributions if not 'enames' in self.msgs[d]: 417*0f4c859eSApple OSS Distributions self.msgs[d]['enames'] = [ nm ] 418*0f4c859eSApple OSS Distributions elif not nm in self.msgs[d]['enames']: 419*0f4c859eSApple OSS Distributions self.msgs[d]['enames'].append(nm) 420*0f4c859eSApple OSS Distributions for k,d in msgDtype.iteritems(): 421*0f4c859eSApple OSS Distributions if d > 0: 422*0f4c859eSApple OSS Distributions self.msgtypes[d][k] += 1 423*0f4c859eSApple OSS Distributions self.nmsgs += 1 424*0f4c859eSApple OSS Distributions if self.nmsgs % 1024 == 0: 425*0f4c859eSApple OSS Distributions sys.stderr.write(" {:d}...\r".format(self.nmsgs)); 426*0f4c859eSApple OSS Distributions 427*0f4c859eSApple OSS Distributions def print_dot_node(self, ofile, node): 428*0f4c859eSApple OSS Distributions omsgs, imsgs = node.nmsgs() 429*0f4c859eSApple OSS Distributions recycled = node.recycled() * 5 430*0f4c859eSApple OSS Distributions tcolor = 'black' 431*0f4c859eSApple OSS Distributions if recycled >= 50: 432*0f4c859eSApple OSS Distributions tcolor = 'white' 433*0f4c859eSApple OSS Distributions if recycled == 5: 434*0f4c859eSApple OSS Distributions bgcolor = 'white' 435*0f4c859eSApple OSS Distributions elif recycled <= 100: 436*0f4c859eSApple OSS Distributions bgcolor = 'grey{:d}'.format(100 - recycled) 437*0f4c859eSApple OSS Distributions else: 438*0f4c859eSApple OSS Distributions bgcolor = 'red' 439*0f4c859eSApple OSS Distributions ofile.write("\t{:s} [style=filled,fontcolor={:s},fillcolor={:s},label=\"{:s}\"];\n"\ 440*0f4c859eSApple OSS Distributions .format(node.nname, tcolor, bgcolor, node.label())) 441*0f4c859eSApple OSS Distributions 442*0f4c859eSApple OSS Distributions def print_dot_edge(self, nm, edge, ofile): 443*0f4c859eSApple OSS Distributions #weight = 100 * edge.dweight / self.maxdweight 444*0f4c859eSApple OSS Distributions ##if weight < 1: 445*0f4c859eSApple OSS Distributions # weight = 1 446*0f4c859eSApple OSS Distributions weight = edge.dweight 447*0f4c859eSApple OSS Distributions penwidth = edge.weight / 512 448*0f4c859eSApple OSS Distributions if penwidth < 0.5: 449*0f4c859eSApple OSS Distributions penwidth = 0.5 450*0f4c859eSApple OSS Distributions if penwidth > 7.99: 451*0f4c859eSApple OSS Distributions penwidth = 8 452*0f4c859eSApple OSS Distributions attrs = "weight={},penwidth={}".format(round(weight,2), round(penwidth,2)) 453*0f4c859eSApple OSS Distributions 454*0f4c859eSApple OSS Distributions if edge.flags & edge.F_RAISEIMP: 455*0f4c859eSApple OSS Distributions attrs += ",arrowhead=dot" 456*0f4c859eSApple OSS Distributions 457*0f4c859eSApple OSS Distributions xpc = edge.dtype('xpc') + edge.dtype('xpc.reply') 458*0f4c859eSApple OSS Distributions iokit = edge.dtype('iokit') + edge.dtype('iokit.reply') 459*0f4c859eSApple OSS Distributions std = edge.dtype('std') + edge.dtype('std.reply') 460*0f4c859eSApple OSS Distributions if xpc > (iokit + std): 461*0f4c859eSApple OSS Distributions attrs += ',color=blue' 462*0f4c859eSApple OSS Distributions elif iokit > (std + xpc): 463*0f4c859eSApple OSS Distributions attrs += ',color=red' 464*0f4c859eSApple OSS Distributions 465*0f4c859eSApple OSS Distributions if edge.data('vcpy') > (edge.data('ool') + edge.data('std')): 466*0f4c859eSApple OSS Distributions attrs += ',style="dotted"' 467*0f4c859eSApple OSS Distributions """ # block comment 468*0f4c859eSApple OSS Distributions ltype = [] 469*0f4c859eSApple OSS Distributions if edge.flags & (edge.F_DST_NDFLTQ | edge.F_SRC_NDFLTQ): 470*0f4c859eSApple OSS Distributions ltype.append('dotted') 471*0f4c859eSApple OSS Distributions if edge.flags & edge.F_APP_SRC: 472*0f4c859eSApple OSS Distributions ltype.append('bold') 473*0f4c859eSApple OSS Distributions if len(ltype) > 0: 474*0f4c859eSApple OSS Distributions attrs += ',style="' + reduce(lambda a, v: a + ',' + v, ltype) + '"' 475*0f4c859eSApple OSS Distributions 476*0f4c859eSApple OSS Distributions if edge.data('ool') > (edge.data('std') + edge.data('vcpy')): 477*0f4c859eSApple OSS Distributions attrs += ",color=blue" 478*0f4c859eSApple OSS Distributions if edge.data('vcpy') > (edge.data('ool') + edge.data('std')): 479*0f4c859eSApple OSS Distributions attrs += ",color=green" 480*0f4c859eSApple OSS Distributions """ 481*0f4c859eSApple OSS Distributions 482*0f4c859eSApple OSS Distributions ofile.write("\t{:s} [{:s}];\n".format(nm, attrs)) 483*0f4c859eSApple OSS Distributions 484*0f4c859eSApple OSS Distributions def print_follow_graph(self, ofile, follow, visited = None): 485*0f4c859eSApple OSS Distributions ofile.write("digraph {:s} {{\n".format(self.name)) 486*0f4c859eSApple OSS Distributions ofile.write("\tsplines=ortho;\n") 487*0f4c859eSApple OSS Distributions if not visited: 488*0f4c859eSApple OSS Distributions visited = [] 489*0f4c859eSApple OSS Distributions for f in follow: 490*0f4c859eSApple OSS Distributions sys.stderr.write("following {}\n".format(f)) 491*0f4c859eSApple OSS Distributions lvl = 0 492*0f4c859eSApple OSS Distributions printedges = {} 493*0f4c859eSApple OSS Distributions while len(follow) > 0: 494*0f4c859eSApple OSS Distributions cnodes = [] 495*0f4c859eSApple OSS Distributions for nm, e in self.edges.iteritems(): 496*0f4c859eSApple OSS Distributions nicename = e.src.nicename 497*0f4c859eSApple OSS Distributions # Find all nodes to which 'follow' nodes communicate 498*0f4c859eSApple OSS Distributions if e.src.nicename in follow: 499*0f4c859eSApple OSS Distributions printedges[nm] = e 500*0f4c859eSApple OSS Distributions if not e.selfedge() and not e.dst in cnodes: 501*0f4c859eSApple OSS Distributions cnodes.append(e.dst) 502*0f4c859eSApple OSS Distributions visited.extend(follow) 503*0f4c859eSApple OSS Distributions follow = [] 504*0f4c859eSApple OSS Distributions for n in cnodes: 505*0f4c859eSApple OSS Distributions if not n.nicename in visited: 506*0f4c859eSApple OSS Distributions follow.append(n.nicename) 507*0f4c859eSApple OSS Distributions lvl += 1 508*0f4c859eSApple OSS Distributions for f in follow: 509*0f4c859eSApple OSS Distributions sys.stderr.write("{}following {}\n".format(' |--'*lvl, f)) 510*0f4c859eSApple OSS Distributions # END: while len(follow) 511*0f4c859eSApple OSS Distributions for k, v in self.nodes.iteritems(): 512*0f4c859eSApple OSS Distributions if v.nicename in visited: 513*0f4c859eSApple OSS Distributions self.print_dot_node(ofile, v) 514*0f4c859eSApple OSS Distributions for nm, edge in printedges.iteritems(): 515*0f4c859eSApple OSS Distributions self.print_dot_edge(nm, edge, ofile) 516*0f4c859eSApple OSS Distributions ofile.write("}\n\n") 517*0f4c859eSApple OSS Distributions 518*0f4c859eSApple OSS Distributions def print_graph(self, ofile, follow): 519*0f4c859eSApple OSS Distributions ofile.write("digraph {:s} {{\n".format(self.name)) 520*0f4c859eSApple OSS Distributions ofile.write("\tsplines=ortho;\n") 521*0f4c859eSApple OSS Distributions for k, v in self.nodes.iteritems(): 522*0f4c859eSApple OSS Distributions self.print_dot_node(ofile, v) 523*0f4c859eSApple OSS Distributions for nm, edge in self.edges.iteritems(): 524*0f4c859eSApple OSS Distributions self.print_dot_edge(nm, edge, ofile) 525*0f4c859eSApple OSS Distributions ofile.write("}\n\n") 526*0f4c859eSApple OSS Distributions 527*0f4c859eSApple OSS Distributions def print_nodegrid(self, ofile, type='msg', dfilter=None): 528*0f4c859eSApple OSS Distributions showdata = False 529*0f4c859eSApple OSS Distributions dfname = dfilter 530*0f4c859eSApple OSS Distributions if not dfname: 531*0f4c859eSApple OSS Distributions dfname = 'all' 532*0f4c859eSApple OSS Distributions if type == 'data': 533*0f4c859eSApple OSS Distributions showdata = True 534*0f4c859eSApple OSS Distributions ofile.write("{} Data sent between nodes.\nRow == SOURCE; Column == DESTINATION\n".format(dfname)) 535*0f4c859eSApple OSS Distributions else: 536*0f4c859eSApple OSS Distributions ofile.write("{} Messages sent between nodes.\nRow == SOURCE; Column == DESTINATION\n".format(dfname)) 537*0f4c859eSApple OSS Distributions 538*0f4c859eSApple OSS Distributions if not dfilter: 539*0f4c859eSApple OSS Distributions dfilter = IPCEdge.DTYPES 540*0f4c859eSApple OSS Distributions ofile.write(' ,' + ','.join(self.nodes.keys()) + '\n') 541*0f4c859eSApple OSS Distributions for snm, src in self.nodes.iteritems(): 542*0f4c859eSApple OSS Distributions odata = [] 543*0f4c859eSApple OSS Distributions for dnm, dst in self.nodes.iteritems(): 544*0f4c859eSApple OSS Distributions enm = self.edgename(src, dst) 545*0f4c859eSApple OSS Distributions e = self.edges.get(enm) 546*0f4c859eSApple OSS Distributions if e and enm in src.outgoing.keys(): 547*0f4c859eSApple OSS Distributions if showdata: 548*0f4c859eSApple OSS Distributions dsize = reduce(lambda accum, t: accum + e.dtype(t), dfilter, 0) 549*0f4c859eSApple OSS Distributions odata.append('{:d}'.format(dsize)) 550*0f4c859eSApple OSS Distributions else: 551*0f4c859eSApple OSS Distributions nmsg = reduce(lambda accum, t: accum + e.mtype(t), dfilter, 0) 552*0f4c859eSApple OSS Distributions odata.append('{:d}'.format(nmsg)) 553*0f4c859eSApple OSS Distributions else: 554*0f4c859eSApple OSS Distributions odata.append('0') 555*0f4c859eSApple OSS Distributions ofile.write(snm + ',' + ','.join(odata) + '\n') 556*0f4c859eSApple OSS Distributions 557*0f4c859eSApple OSS Distributions def print_datasummary(self, ofile): 558*0f4c859eSApple OSS Distributions m = {} 559*0f4c859eSApple OSS Distributions for type in IPCEdge.DTYPES: 560*0f4c859eSApple OSS Distributions m[type] = [0, 0] 561*0f4c859eSApple OSS Distributions for k, v in self.edges.iteritems(): 562*0f4c859eSApple OSS Distributions for t in IPCEdge.DTYPES: 563*0f4c859eSApple OSS Distributions m[t][0] += v.mtype(t) 564*0f4c859eSApple OSS Distributions m[t][1] += v.dtype(t) 565*0f4c859eSApple OSS Distributions tdata = 0 566*0f4c859eSApple OSS Distributions tmsgs = 0 567*0f4c859eSApple OSS Distributions for f in IPCEdge.DFLAVORS: 568*0f4c859eSApple OSS Distributions tdata += self.totals['D'+f] 569*0f4c859eSApple OSS Distributions tmsgs += self.totals['n'+f] 570*0f4c859eSApple OSS Distributions # we account for 0-sized messages differently 571*0f4c859eSApple OSS Distributions tmsgs += self.msgs[0]['std'] 572*0f4c859eSApple OSS Distributions ofile.write("Nodes:{:d}\nEdges:{:d}\n".format(len(self.nodes),len(self.edges))) 573*0f4c859eSApple OSS Distributions ofile.write("Total Messages,{}\nTotal Data,{}\n".format(tmsgs, tdata)) 574*0f4c859eSApple OSS Distributions ofile.write("Flavor,Messages,Data,\n") 575*0f4c859eSApple OSS Distributions for f in IPCEdge.DFLAVORS: 576*0f4c859eSApple OSS Distributions ofile.write("{:s},{:d},{:d}\n".format(f, self.totals['n'+f], self.totals['D'+f])) 577*0f4c859eSApple OSS Distributions ofile.write("Style,Messages,Data,\n") 578*0f4c859eSApple OSS Distributions for t in IPCEdge.DTYPES: 579*0f4c859eSApple OSS Distributions ofile.write("{:s},{:d},{:d}\n".format(t, m[t][0], m[t][1])) 580*0f4c859eSApple OSS Distributions 581*0f4c859eSApple OSS Distributions def print_freqdata(self, ofile, gnuplot = False): 582*0f4c859eSApple OSS Distributions flavoridx = {} 583*0f4c859eSApple OSS Distributions ostr = "Message Size" 584*0f4c859eSApple OSS Distributions idx = 1 585*0f4c859eSApple OSS Distributions for f in IPCEdge.DFLAVORS: 586*0f4c859eSApple OSS Distributions ostr += ',{fmt:s} Freq,{fmt:s} CDF,{fmt:s} Data CDF,{fmt:s} Cumulative Data'.format(fmt=f) 587*0f4c859eSApple OSS Distributions idx += 1 588*0f4c859eSApple OSS Distributions flavoridx[f] = idx 589*0f4c859eSApple OSS Distributions idx += 3 590*0f4c859eSApple OSS Distributions ostr += ',#Unique SVC pairs\n' 591*0f4c859eSApple OSS Distributions ofile.write(ostr) 592*0f4c859eSApple OSS Distributions 593*0f4c859eSApple OSS Distributions lastmsg = 0 594*0f4c859eSApple OSS Distributions maxmsgs = {} 595*0f4c859eSApple OSS Distributions totalmsgs = {} 596*0f4c859eSApple OSS Distributions Tdata = {} 597*0f4c859eSApple OSS Distributions for f in IPCEdge.DFLAVORS: 598*0f4c859eSApple OSS Distributions maxmsgs[f] = 0 599*0f4c859eSApple OSS Distributions totalmsgs[f] = 0 600*0f4c859eSApple OSS Distributions Tdata[f] = 0 601*0f4c859eSApple OSS Distributions 602*0f4c859eSApple OSS Distributions for k, v in sorted(self.msgs.iteritems()): 603*0f4c859eSApple OSS Distributions lastmsg = k 604*0f4c859eSApple OSS Distributions _nmsgs = {} 605*0f4c859eSApple OSS Distributions for f in IPCEdge.DFLAVORS: 606*0f4c859eSApple OSS Distributions _nmsgs[f] = v[f] 607*0f4c859eSApple OSS Distributions if v[f] > maxmsgs[f]: 608*0f4c859eSApple OSS Distributions maxmsgs[f] = v[f] 609*0f4c859eSApple OSS Distributions if k > 0: 610*0f4c859eSApple OSS Distributions Tdata[f] += v[f] * k 611*0f4c859eSApple OSS Distributions totalmsgs[f] += v[f] 612*0f4c859eSApple OSS Distributions 613*0f4c859eSApple OSS Distributions cdf = {f:0 for f in IPCEdge.DFLAVORS} 614*0f4c859eSApple OSS Distributions dcdf = {f:0 for f in IPCEdge.DFLAVORS} 615*0f4c859eSApple OSS Distributions if k > 0: # Only use messages with data size > 0 616*0f4c859eSApple OSS Distributions for f in IPCEdge.DFLAVORS: 617*0f4c859eSApple OSS Distributions if self.totals['n'+f] > 0: 618*0f4c859eSApple OSS Distributions cdf[f] = int(100 * totalmsgs[f] / self.totals['n'+f]) 619*0f4c859eSApple OSS Distributions if self.totals['D'+f] > 0: 620*0f4c859eSApple OSS Distributions dcdf[f] = int(100 * Tdata[f] / self.totals['D'+f]) 621*0f4c859eSApple OSS Distributions 622*0f4c859eSApple OSS Distributions ostr = "{:d}".format(k) 623*0f4c859eSApple OSS Distributions for f in IPCEdge.DFLAVORS: 624*0f4c859eSApple OSS Distributions ostr += ",{:d},{:d},{:d},{:d}".format(_nmsgs[f],cdf[f],dcdf[f],Tdata[f]) 625*0f4c859eSApple OSS Distributions ostr += ",{:d}\n".format(len(v['enames'])) 626*0f4c859eSApple OSS Distributions ofile.write(ostr) 627*0f4c859eSApple OSS Distributions 628*0f4c859eSApple OSS Distributions if not gnuplot: 629*0f4c859eSApple OSS Distributions return 630*0f4c859eSApple OSS Distributions 631*0f4c859eSApple OSS Distributions colors = [ 'blue', 'red', 'green', 'black', 'grey', 'yellow' ] 632*0f4c859eSApple OSS Distributions idx = 0 633*0f4c859eSApple OSS Distributions flavorcolor = {} 634*0f4c859eSApple OSS Distributions maxdata = 0 635*0f4c859eSApple OSS Distributions maxmsg = max(maxmsgs.values()) 636*0f4c859eSApple OSS Distributions for f in IPCEdge.DFLAVORS: 637*0f4c859eSApple OSS Distributions flavorcolor[f] = colors[idx] 638*0f4c859eSApple OSS Distributions if self.totals['D'+f] > maxdata: 639*0f4c859eSApple OSS Distributions maxdata = self.totals['D'+f] 640*0f4c859eSApple OSS Distributions idx += 1 641*0f4c859eSApple OSS Distributions 642*0f4c859eSApple OSS Distributions sys.stderr.write("Creating GNUPlot...\n") 643*0f4c859eSApple OSS Distributions 644*0f4c859eSApple OSS Distributions cdf_data_fmt = """\ 645*0f4c859eSApple OSS Distributions set terminal postscript eps enhanced color solid 'Courier' 12 646*0f4c859eSApple OSS Distributions set border 3 647*0f4c859eSApple OSS Distributions set size 1.5, 1.5 648*0f4c859eSApple OSS Distributions set xtics nomirror 649*0f4c859eSApple OSS Distributions set ytics nomirror 650*0f4c859eSApple OSS Distributions set xrange [1:2048] 651*0f4c859eSApple OSS Distributions set yrange [0:100] 652*0f4c859eSApple OSS Distributions set ylabel font 'Courier,14' "Total Message CDF\\n(% of total number of messages)" 653*0f4c859eSApple OSS Distributions set xlabel font 'Courier,14' "Message Size (bytes)" 654*0f4c859eSApple OSS Distributions set datafile separator "," 655*0f4c859eSApple OSS Distributions set ytics ( '0' 0, '10' 10, '20' 20, '30' 30, '40' 40, '50' 50, '60' 60, '70' 70, '80' 80, '90' 90, '100' 100) 656*0f4c859eSApple OSS Distributions plot """ 657*0f4c859eSApple OSS Distributions plots = [] 658*0f4c859eSApple OSS Distributions for f in IPCEdge.DFLAVORS: 659*0f4c859eSApple OSS Distributions plots.append("'{{csvfile:s}}' using 1:{:d} title '{:s} Messages' with lines lw 2 lt 1 lc rgb \"{:s}\"".format(flavoridx[f]+1, f, flavorcolor[f])) 660*0f4c859eSApple OSS Distributions cdf_data_fmt += ', \\\n'.join(plots) 661*0f4c859eSApple OSS Distributions 662*0f4c859eSApple OSS Distributions dcdf_data_fmt = """\ 663*0f4c859eSApple OSS Distributions set terminal postscript eps enhanced color solid 'Courier' 12 664*0f4c859eSApple OSS Distributions set border 3 665*0f4c859eSApple OSS Distributions set size 1.5, 1.5 666*0f4c859eSApple OSS Distributions set xtics nomirror 667*0f4c859eSApple OSS Distributions set ytics nomirror 668*0f4c859eSApple OSS Distributions set xrange [1:32768] 669*0f4c859eSApple OSS Distributions set yrange [0:100] 670*0f4c859eSApple OSS Distributions set ylabel font 'Courier,14' "Total Data CDF\\n(% of total data transmitted)" 671*0f4c859eSApple OSS Distributions set xlabel font 'Courier,14' "Message Size (bytes)" 672*0f4c859eSApple OSS Distributions set datafile separator "," 673*0f4c859eSApple OSS Distributions set ytics ( '0' 0, '10' 10, '20' 20, '30' 30, '40' 40, '50' 50, '60' 60, '70' 70, '80' 80, '90' 90, '100' 100) 674*0f4c859eSApple OSS Distributions plot """ 675*0f4c859eSApple OSS Distributions plots = [] 676*0f4c859eSApple OSS Distributions for f in IPCEdge.DFLAVORS: 677*0f4c859eSApple OSS Distributions plots.append("'{{csvfile:s}}' using 1:{:d} title '{:s} Message Data' with lines lw 2 lt 1 lc rgb \"{:s}\"".format(flavoridx[f]+2, f, flavorcolor[f])) 678*0f4c859eSApple OSS Distributions dcdf_data_fmt += ', \\\n'.join(plots) 679*0f4c859eSApple OSS Distributions 680*0f4c859eSApple OSS Distributions freq_data_fmt = """\ 681*0f4c859eSApple OSS Distributions set terminal postscript eps enhanced color solid 'Courier' 12 682*0f4c859eSApple OSS Distributions set size 1.5, 1.5 683*0f4c859eSApple OSS Distributions set xrange [1:32768] 684*0f4c859eSApple OSS Distributions set yrange [0:9000] 685*0f4c859eSApple OSS Distributions set x2range [1:32768] 686*0f4c859eSApple OSS Distributions set y2range [0:{maxdata:d}] 687*0f4c859eSApple OSS Distributions set xtics nomirror 688*0f4c859eSApple OSS Distributions set ytics nomirror 689*0f4c859eSApple OSS Distributions set y2tics 690*0f4c859eSApple OSS Distributions set autoscale y2 691*0f4c859eSApple OSS Distributions set grid x y2 692*0f4c859eSApple OSS Distributions set ylabel font 'Courier,14' "Number of Messages" 693*0f4c859eSApple OSS Distributions set y2label font 'Courier,14' "Data Transferred (bytes)" 694*0f4c859eSApple OSS Distributions set xlabel font 'Courier,14' "Message Size (bytes)" 695*0f4c859eSApple OSS Distributions set datafile separator "," 696*0f4c859eSApple OSS Distributions set tics out 697*0f4c859eSApple OSS Distributions set boxwidth 1 698*0f4c859eSApple OSS Distributions set style fill solid 699*0f4c859eSApple OSS Distributions plot """ 700*0f4c859eSApple OSS Distributions plots = [] 701*0f4c859eSApple OSS Distributions for f in IPCEdge.DFLAVORS: 702*0f4c859eSApple OSS Distributions plots.append("'{{csvfile:s}}' using 1:{:d} axes x1y1 title '{:s} Messages' with boxes lt 1 lc rgb \"{:s}\"".format(flavoridx[f], f, flavorcolor[f])) 703*0f4c859eSApple OSS Distributions plots.append("'{{csvfile:s}}' using 1:{:d} axes x2y2 title '{:s} Data' with line lt 1 lw 2 lc rgb \"{:s}\"".format(flavoridx[f]+3, f, flavorcolor[f])) 704*0f4c859eSApple OSS Distributions freq_data_fmt += ', \\\n'.join(plots) 705*0f4c859eSApple OSS Distributions try: 706*0f4c859eSApple OSS Distributions new_file = re.sub(r'(.*)\.\w+$', r'\1_cdf.plot', ofile.name) 707*0f4c859eSApple OSS Distributions sys.stderr.write("\t{:s}...\n".format(new_file)) 708*0f4c859eSApple OSS Distributions plotfile = open(new_file, 'w') 709*0f4c859eSApple OSS Distributions plotfile.write(cdf_data_fmt.format(lastmsg=lastmsg, maxdata=maxdata, maxmsg=maxmsg, csvfile=ofile.name)) 710*0f4c859eSApple OSS Distributions plotfile.flush() 711*0f4c859eSApple OSS Distributions plotfile.close() 712*0f4c859eSApple OSS Distributions 713*0f4c859eSApple OSS Distributions new_file = re.sub(r'(.*)\.\w+$', r'\1_dcdf.plot', ofile.name) 714*0f4c859eSApple OSS Distributions sys.stderr.write("\t{:s}...\n".format(new_file)) 715*0f4c859eSApple OSS Distributions plotfile = open(new_file, 'w') 716*0f4c859eSApple OSS Distributions plotfile.write(dcdf_data_fmt.format(lastmsg=lastmsg, maxdata=maxdata, maxmsg=maxmsg, csvfile=ofile.name)) 717*0f4c859eSApple OSS Distributions plotfile.flush() 718*0f4c859eSApple OSS Distributions plotfile.close() 719*0f4c859eSApple OSS Distributions 720*0f4c859eSApple OSS Distributions new_file = re.sub(r'(.*)\.\w+$', r'\1_hist.plot', ofile.name) 721*0f4c859eSApple OSS Distributions sys.stderr.write("\t{:s}...\n".format(new_file)) 722*0f4c859eSApple OSS Distributions plotfile = open(new_file, 'w') 723*0f4c859eSApple OSS Distributions plotfile.write(freq_data_fmt.format(lastmsg=lastmsg, maxdata=maxdata, maxmsg=maxmsg, csvfile=ofile.name)) 724*0f4c859eSApple OSS Distributions plotfile.flush() 725*0f4c859eSApple OSS Distributions plotfile.close() 726*0f4c859eSApple OSS Distributions except: 727*0f4c859eSApple OSS Distributions sys.stderr.write("\nFailed to write gnuplot script!\n"); 728*0f4c859eSApple OSS Distributions return 729*0f4c859eSApple OSS Distributions 730*0f4c859eSApple OSS Distributions 731*0f4c859eSApple OSS Distributionsdef convert_raw_tracefiles(args): 732*0f4c859eSApple OSS Distributions if not args.raw or len(args.raw) < 1: 733*0f4c859eSApple OSS Distributions return 734*0f4c859eSApple OSS Distributions 735*0f4c859eSApple OSS Distributions if not args.tracefile: 736*0f4c859eSApple OSS Distributions args.tracefile = [] 737*0f4c859eSApple OSS Distributions 738*0f4c859eSApple OSS Distributions for rawfile in args.raw: 739*0f4c859eSApple OSS Distributions sys.stderr.write("Converting RAW tracefile '{:s}'...\n".format(rawfile.name)) 740*0f4c859eSApple OSS Distributions if args.tbfreq and len(args.tbfreq) > 0: 741*0f4c859eSApple OSS Distributions args.tbfreq = " -F " + args.tbfreq 742*0f4c859eSApple OSS Distributions else: 743*0f4c859eSApple OSS Distributions args.tbfreq = "" 744*0f4c859eSApple OSS Distributions tfile = re.sub(r'(.*)(\.\w+)*$', r'\1.ascii', rawfile.name) 745*0f4c859eSApple OSS Distributions cmd = 'trace -R {:s}{:s} -o {:s}'.format(rawfile.name, args.tbfreq, tfile) 746*0f4c859eSApple OSS Distributions if args.tracecodes and len(args.tracecodes) > 0: 747*0f4c859eSApple OSS Distributions cmd += " -N {}".format(args.tracecodes[0]) 748*0f4c859eSApple OSS Distributions elif os.path.isfile('bsd/kern/trace.codes'): 749*0f4c859eSApple OSS Distributions cmd += " -N bsd/kern/trace.codes" 750*0f4c859eSApple OSS Distributions if args.traceargs and len(args.traceargs) > 0: 751*0f4c859eSApple OSS Distributions cmd += ' '.join(args.traceargs) 752*0f4c859eSApple OSS Distributions (ret, outstr) = RunCommand(cmd) 753*0f4c859eSApple OSS Distributions if ret != 0: 754*0f4c859eSApple OSS Distributions os.stderr.write("Couldn't convert raw trace file. ret=={:d}\nE: {:s}\n".format(ret, outstr)) 755*0f4c859eSApple OSS Distributions sys.exit(ret) 756*0f4c859eSApple OSS Distributions 757*0f4c859eSApple OSS Distributions if not os.path.isfile(tfile): 758*0f4c859eSApple OSS Distributions sys.stderr.write("Failure to convert raw trace file '{:s}'\ncmd: '{:s}'\n".format(args.raw[0].name, cmd)) 759*0f4c859eSApple OSS Distributions sys.exit(1) 760*0f4c859eSApple OSS Distributions args.tracefile.append(open(tfile, 'r')) 761*0f4c859eSApple OSS Distributions # END: for rawfile in args.raw 762*0f4c859eSApple OSS Distributions 763*0f4c859eSApple OSS Distributions 764*0f4c859eSApple OSS Distributionsdef parse_tracefile_line(line, exclude, include, exflags, incflags, active_proc, graph, base=16): 765*0f4c859eSApple OSS Distributions val = line.split() 766*0f4c859eSApple OSS Distributions if len(val) < 10: 767*0f4c859eSApple OSS Distributions return 768*0f4c859eSApple OSS Distributions if val[2] == "proc_exec" or val[2] == "TRACE_DATA_EXEC": 769*0f4c859eSApple OSS Distributions pid = int(val[3], base) 770*0f4c859eSApple OSS Distributions active_proc[pid] = val[9] 771*0f4c859eSApple OSS Distributions if val[2] == "MACH_IPC_kmsg_info": 772*0f4c859eSApple OSS Distributions sendpid = int(val[3], base) 773*0f4c859eSApple OSS Distributions destpid = int(val[4], base) 774*0f4c859eSApple OSS Distributions if sendpid == 0: 775*0f4c859eSApple OSS Distributions src = "kernel_task" 776*0f4c859eSApple OSS Distributions elif sendpid in active_proc: 777*0f4c859eSApple OSS Distributions src = active_proc[sendpid] 778*0f4c859eSApple OSS Distributions else: 779*0f4c859eSApple OSS Distributions src = "{:d}".format(sendpid) 780*0f4c859eSApple OSS Distributions if destpid == 0: 781*0f4c859eSApple OSS Distributions dst = "kernel_task" 782*0f4c859eSApple OSS Distributions elif destpid in active_proc: 783*0f4c859eSApple OSS Distributions dst = active_proc[destpid] 784*0f4c859eSApple OSS Distributions else: 785*0f4c859eSApple OSS Distributions dst = "{:d}".format(destpid) 786*0f4c859eSApple OSS Distributions if exclude and len(exclude) > 0 and (src in exclude or dst in exclude): 787*0f4c859eSApple OSS Distributions return 788*0f4c859eSApple OSS Distributions if include and len(include) > 0 and (not (src in include or dst in include)): 789*0f4c859eSApple OSS Distributions return 790*0f4c859eSApple OSS Distributions flags = int(val[6], 16) 791*0f4c859eSApple OSS Distributions if exflags or incflags: 792*0f4c859eSApple OSS Distributions if exflags and (flags & int(exflags[0], 0)): 793*0f4c859eSApple OSS Distributions return 794*0f4c859eSApple OSS Distributions if incflags and (flags & int(incflags[0], 0)) != int(incflags[0], 0): 795*0f4c859eSApple OSS Distributions return 796*0f4c859eSApple OSS Distributions # create a graph edge 797*0f4c859eSApple OSS Distributions if (flags & IPCEdge.F_TRACED): 798*0f4c859eSApple OSS Distributions graph.addmsg(src, sendpid, dst, destpid, val[5], val[6], float(val[0])) 799*0f4c859eSApple OSS Distributions # END: MACH_IPC_kmsg_info 800*0f4c859eSApple OSS Distributions 801*0f4c859eSApple OSS Distributions# 802*0f4c859eSApple OSS Distributions# Main 803*0f4c859eSApple OSS Distributions# 804*0f4c859eSApple OSS Distributionsdef main(argv=sys.argv): 805*0f4c859eSApple OSS Distributions """ Main program entry point. 806*0f4c859eSApple OSS Distributions 807*0f4c859eSApple OSS Distributions Trace file output lines look like this: 808*0f4c859eSApple OSS Distributions {abstime} {delta} MACH_IPC_kmsg_info {src_pid} {dst_pid} {msg_len} {flags} {threadid} {cpu} {proc_name} 809*0f4c859eSApple OSS Distributions e.g. 810*0f4c859eSApple OSS Distributions 4621921.2 33.8(0.0) MACH_IPC_kmsg_info ac 9d c 230002 b2e 1 MobileMail 811*0f4c859eSApple OSS Distributions 812*0f4c859eSApple OSS Distributions Or like this: 813*0f4c859eSApple OSS Distributions {abstime} {delta} proc_exec {pid} 0 0 0 {threadid} {cpu} {proc_name} 814*0f4c859eSApple OSS Distributions e.g. 815*0f4c859eSApple OSS Distributions 4292212.3 511.2 proc_exec c8 0 0 0 b44 0 voiced 816*0f4c859eSApple OSS Distributions """ 817*0f4c859eSApple OSS Distributions global g_verbose 818*0f4c859eSApple OSS Distributions 819*0f4c859eSApple OSS Distributions parser = argparse.ArgumentParser(description='Parse an XNU Mach IPC kmsg ktrace file') 820*0f4c859eSApple OSS Distributions 821*0f4c859eSApple OSS Distributions # output a DOT formatted graph file 822*0f4c859eSApple OSS Distributions parser.add_argument('--printgraph', '-g', dest='graph', default=None, type=argparse.FileType('w'), help='Output a DOT connectivity graph from the trace data') 823*0f4c859eSApple OSS Distributions parser.add_argument('--graphname', dest='name', default='ipcgraph', help='A name for the DOT graph output') 824*0f4c859eSApple OSS Distributions parser.add_argument('--graphfollow', dest='follow', nargs='+', metavar='NAME', help='Graph only the transitive closure of services / processes which communicate with the given service(s)') 825*0f4c859eSApple OSS Distributions 826*0f4c859eSApple OSS Distributions # output a CDF of message data 827*0f4c859eSApple OSS Distributions parser.add_argument('--printfreq', '-f', dest='freq', default=None, type=argparse.FileType('w'), help='Output a frequency distribution of message data (in CSV format)') 828*0f4c859eSApple OSS Distributions parser.add_argument('--gnuplot', dest='gnuplot', action='store_true', help='Write out a gnuplot file along with the frequency distribution data') 829*0f4c859eSApple OSS Distributions 830*0f4c859eSApple OSS Distributions # output a simple summary of message data 831*0f4c859eSApple OSS Distributions parser.add_argument('--printsummary', '-s', dest='summary', default=None, type=argparse.FileType('w'), help='Output a summary of all messages in the trace data') 832*0f4c859eSApple OSS Distributions 833*0f4c859eSApple OSS Distributions # Output a CSV grid of node data/messages 834*0f4c859eSApple OSS Distributions parser.add_argument('--printnodegrid', '-n', dest='nodegrid', default=None, type=argparse.FileType('w'), help='Output a CSV grid of all messages/data sent between nodes (defaults to # messages)') 835*0f4c859eSApple OSS Distributions parser.add_argument('--ngridtype', dest='ngridtype', default=None, choices=['msgs', 'data'], help='Used with the --printnodegrid argument, this option control whether the grid will be # of messages sent between nodes, or amount of data sent between nodes') 836*0f4c859eSApple OSS Distributions parser.add_argument('--ngridfilter', dest='ngridfilter', default=None, nargs='+', choices=IPCEdge.DTYPES, help='Used with the --printnodegrid argument, this option controls the type of messages or data counted') 837*0f4c859eSApple OSS Distributions 838*0f4c859eSApple OSS Distributions parser.add_argument('--raw', '-R', dest='raw', nargs='+', type=argparse.FileType('r'), metavar='tracefile', help='Process a raw tracefile using the "trace" utility on the host. This requires an ssh connection to the device, or a manual specification of the tbfrequency.') 839*0f4c859eSApple OSS Distributions parser.add_argument('--tbfreq', '-T', dest='tbfreq', default=None, help='The value of sysctl hw.tbfrequency run on the device') 840*0f4c859eSApple OSS Distributions parser.add_argument('--device', '-D', dest='device', nargs=1, metavar='DEV', help='The name of the iOS device reachable via "ssh DEV"') 841*0f4c859eSApple OSS Distributions parser.add_argument('--tracecodes', '-N', dest='tracecodes', nargs=1, metavar='TRACE.CODES', help='Path to a custom trace.codes file. By default, the script will look for bsd/kern/trace.codes from the current directory)') 842*0f4c859eSApple OSS Distributions parser.add_argument('--traceargs', dest='traceargs', nargs='+', metavar='TRACE_OPT', help='Extra options to the "trace" program run on the host') 843*0f4c859eSApple OSS Distributions 844*0f4c859eSApple OSS Distributions parser.add_argument('--psfile', dest='psfile', nargs='+', type=argparse.FileType('r'), help='Process list file output by ios_trace_ipc.sh') 845*0f4c859eSApple OSS Distributions 846*0f4c859eSApple OSS Distributions parser.add_argument('--exclude', dest='exclude', metavar='NAME', nargs='+', help='List of services to exclude from processing. Any messages sent to or originating from these services will be discarded.') 847*0f4c859eSApple OSS Distributions parser.add_argument('--include', dest='include', metavar='NAME', nargs='+', help='List of services to include in processing. Only messages sent to or originating from these services will be processed.') 848*0f4c859eSApple OSS Distributions parser.add_argument('--exflags', dest='exflags', metavar='0xFLAGS', nargs=1, help='Messages with any of these flags bits set will be discarded') 849*0f4c859eSApple OSS Distributions parser.add_argument('--incflags', dest='incflags', metavar='0xFLAGS', nargs=1, type=int, help='Only messages with all of these flags bits set will be processed') 850*0f4c859eSApple OSS Distributions 851*0f4c859eSApple OSS Distributions parser.add_argument('--verbose', '-v', dest='verbose', action='count', help='be verbose (can be used multiple times)') 852*0f4c859eSApple OSS Distributions parser.add_argument('tracefile', nargs='*', type=argparse.FileType('r'), help='Input trace file') 853*0f4c859eSApple OSS Distributions 854*0f4c859eSApple OSS Distributions args = parser.parse_args() 855*0f4c859eSApple OSS Distributions 856*0f4c859eSApple OSS Distributions g_verbose = args.verbose 857*0f4c859eSApple OSS Distributions 858*0f4c859eSApple OSS Distributions if not args.graph and not args.freq and not args.summary and not args.nodegrid: 859*0f4c859eSApple OSS Distributions sys.stderr.write("Please select at least one output format: [-gfsn] {file}\n") 860*0f4c859eSApple OSS Distributions sys.exit(1) 861*0f4c859eSApple OSS Distributions 862*0f4c859eSApple OSS Distributions convert_raw_tracefiles(args) 863*0f4c859eSApple OSS Distributions 864*0f4c859eSApple OSS Distributions graph = IPCGraph(args.name, args.tbfreq) 865*0f4c859eSApple OSS Distributions 866*0f4c859eSApple OSS Distributions nfiles = len(args.tracefile) 867*0f4c859eSApple OSS Distributions idx = 0 868*0f4c859eSApple OSS Distributions while idx < nfiles: 869*0f4c859eSApple OSS Distributions active_proc = {} 870*0f4c859eSApple OSS Distributions # Parse a ps output file (generated by ios_trace_ipc.sh) 871*0f4c859eSApple OSS Distributions # This pre-fills the active_proc list 872*0f4c859eSApple OSS Distributions if args.psfile and len(args.psfile) > idx: 873*0f4c859eSApple OSS Distributions sys.stderr.write("Parsing {:s}...\n".format(args.psfile[idx].name)) 874*0f4c859eSApple OSS Distributions for line in args.psfile[idx]: 875*0f4c859eSApple OSS Distributions if line.strip() == '': 876*0f4c859eSApple OSS Distributions continue 877*0f4c859eSApple OSS Distributions parse_tracefile_line(line.strip(), None, None, None, None, active_proc, graph, 10) 878*0f4c859eSApple OSS Distributions # END: for line in psfile 879*0f4c859eSApple OSS Distributions 880*0f4c859eSApple OSS Distributions sys.stderr.write("Parsing {:s}...\n".format(args.tracefile[idx].name)) 881*0f4c859eSApple OSS Distributions for line in args.tracefile[idx]: 882*0f4c859eSApple OSS Distributions if line.strip() == '': 883*0f4c859eSApple OSS Distributions continue 884*0f4c859eSApple OSS Distributions parse_tracefile_line(line.strip(), args.exclude, args.include, args.exflags, args.incflags, active_proc, graph) 885*0f4c859eSApple OSS Distributions # END: for line in tracefile 886*0f4c859eSApple OSS Distributions idx += 1 887*0f4c859eSApple OSS Distributions # END: foreach tracefile/psfile 888*0f4c859eSApple OSS Distributions 889*0f4c859eSApple OSS Distributions if args.graph: 890*0f4c859eSApple OSS Distributions if args.follow and len(args.follow) > 0: 891*0f4c859eSApple OSS Distributions sys.stderr.write("Writing follow-graph to {:s}...\n".format(args.graph.name)) 892*0f4c859eSApple OSS Distributions graph.print_follow_graph(args.graph, args.follow) 893*0f4c859eSApple OSS Distributions else: 894*0f4c859eSApple OSS Distributions sys.stderr.write("Writing graph output to {:s}...\n".format(args.graph.name)) 895*0f4c859eSApple OSS Distributions graph.print_graph(args.graph, args.follow) 896*0f4c859eSApple OSS Distributions if args.freq: 897*0f4c859eSApple OSS Distributions sys.stderr.write("Writing CDF data to {:s}...\n".format(args.freq.name)) 898*0f4c859eSApple OSS Distributions graph.print_freqdata(args.freq, args.gnuplot) 899*0f4c859eSApple OSS Distributions if args.summary: 900*0f4c859eSApple OSS Distributions sys.stderr.write("Writing summary data to {:s}...\n".format(args.summary.name)) 901*0f4c859eSApple OSS Distributions graph.print_datasummary(args.summary) 902*0f4c859eSApple OSS Distributions if args.nodegrid: 903*0f4c859eSApple OSS Distributions nm = args.ngridtype 904*0f4c859eSApple OSS Distributions sys.stderr.write("Writing node grid data to {:s}...]\n".format(args.nodegrid.name)) 905*0f4c859eSApple OSS Distributions graph.print_nodegrid(args.nodegrid, args.ngridtype, args.ngridfilter) 906*0f4c859eSApple OSS Distributions 907*0f4c859eSApple OSS Distributionsif __name__ == '__main__': 908*0f4c859eSApple OSS Distributions sys.exit(main()) 909