xref: /xnu-10002.61.3/tools/trace/parse_ipc_trace.py (revision 0f4c859e951fba394238ab619495c4e1d54d0f34)
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