Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: tools/cygprofile/mergetraces.py

Issue 281093002: Make cygprofile order functions by process and thread ID. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove unnecessary blank line Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/cygprofile/PRESUBMIT.py ('k') | tools/cygprofile/mergetraces_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright 2013 The Chromium Authors. All rights reserved. 2 # Copyright 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 # Use: ../mergetraces.py `ls cyglog.* -Sr` > merged_cyglog 6 # Use: ../mergetraces.py `ls cyglog.* -Sr` > merged_cyglog
7 7
8 """"Merge multiple logs files from different processes into a single log. 8 """"Merge multiple logs files from different processes into a single log.
9 9
10 Given two log files of execution traces, merge the traces into a single trace. 10 Given two log files of execution traces, merge the traces into a single trace.
11 Merging will use timestamps (i.e. the first two columns of logged calls) to 11 Merging will use timestamps (i.e. the first two columns of logged calls) to
12 create a single log that is an ordered trace of calls by both processes. 12 create a single log that is an ordered trace of calls by both processes.
13 """ 13 """
14 14
15 import optparse 15 import optparse
16 import os
17 import string 16 import string
18 import subprocess
19 import sys 17 import sys
20 18
21 def ParseLogLines(lines): 19 def ParseLogLines(lines):
22 """Parse log file lines. 20 """Parse log file lines.
23 21
24 Args: 22 Args:
25 lines: lines from log file produced by profiled run 23 lines: lines from log file produced by profiled run
26 24
27 Below is an example of a small log file: 25 Below is an example of a small log file:
28 5086e000-52e92000 r-xp 00000000 b3:02 51276 libchromeview.so 26 5086e000-52e92000 r-xp 00000000 b3:02 51276 libchromeview.so
(...skipping 19 matching lines...) Expand all
48 vm_end = int (lines[0][dash_index+1:space_index], 16) 46 vm_end = int (lines[0][dash_index+1:space_index], 16)
49 for line in lines[2:]: 47 for line in lines[2:]:
50 line = line.strip() 48 line = line.strip()
51 # print hex (vm_start) 49 # print hex (vm_start)
52 fields = line.split() 50 fields = line.split()
53 call_lines.append (fields) 51 call_lines.append (fields)
54 52
55 return (call_lines, vm_start, vm_end) 53 return (call_lines, vm_start, vm_end)
56 54
57 def HasDuplicates(calls): 55 def HasDuplicates(calls):
58 """Funcition is a sanity check to make sure that calls are only logged once. 56 """Makes sure that calls are only logged once.
59 57
60 Args: 58 Args:
61 calls: list of calls logged 59 calls: list of calls logged
62 60
63 Returns: 61 Returns:
64 boolean indicating if calls has duplicate calls 62 boolean indicating if calls has duplicate calls
65 """ 63 """
66 seen = [] 64 seen = set([])
67 for call in calls: 65 for call in calls:
68 if call[3] in seen: 66 if call[3] in seen:
69 return true 67 return True
70 else: 68 seen.add(call[3])
71 seen.append(call[3]) 69 return False
72 70
73 def CheckTimestamps(calls): 71 def CheckTimestamps(calls):
74 """Prints warning to stderr if the call timestamps are not in order. 72 """Prints warning to stderr if the call timestamps are not in order.
75 73
76 Args: 74 Args:
77 calls: list of calls logged 75 calls: list of calls logged
78 """ 76 """
79 index = 0 77 index = 0
80 last_timestamp_secs = -1 78 last_timestamp_secs = -1
81 last_timestamp_us = -1 79 last_timestamp_us = -1
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 tracemap: the tracemap 128 tracemap: the tracemap
131 trace: the trace 129 trace: the trace
132 130
133 """ 131 """
134 for trace_entry in trace: 132 for trace_entry in trace:
135 call = trace_entry[3] 133 call = trace_entry[3]
136 if (not call in tracemap) or ( 134 if (not call in tracemap) or (
137 Timestamp(tracemap[call]) > Timestamp(trace_entry)): 135 Timestamp(tracemap[call]) > Timestamp(trace_entry)):
138 tracemap[call] = trace_entry 136 tracemap[call] = trace_entry
139 137
138 def GroupByProcessAndThreadId(input_trace):
139 """Returns an array of traces grouped by pid and tid.
140
141 This is used to make the order of functions not depend on thread scheduling
142 which can be greatly impacted when profiling is done with cygprofile. As a
143 result each thread has its own contiguous segment of code (ordered by
144 timestamp) and processes also have their code isolated (i.e. not interleaved).
145 """
146 def MakeTimestamp(usec, sec):
147 return usec * 1000000 + sec
148
149 def PidAndTidFromString(pid_and_tid):
150 strings = pid_and_tid.split(':')
151 return (int(strings[0]), int(strings[1]))
152
153 pid_first_seen = {}
154 tid_first_seen = {}
155 for (sec, usec, pid_and_tid, _) in input_trace:
156 (pid, tid) = PidAndTidFromString(pid_and_tid)
157 if not pid in pid_first_seen:
158 pid_first_seen[pid] = MakeTimestamp(usec, sec)
159 if not tid in tid_first_seen:
160 tid_first_seen[tid] = MakeTimestamp(usec, sec)
161
162 def CompareEvents(event1, event2):
163 (sec1, usec1, pid_and_tid, _) = event1
164 (pid1, tid1) = PidAndTidFromString(pid_and_tid)
165 (sec2, usec2, pid_and_tid, _) = event2
166 (pid2, tid2) = PidAndTidFromString(pid_and_tid)
167
168 pid_cmp = cmp(pid_first_seen[pid1], pid_first_seen[pid2])
169 if pid_cmp != 0:
170 return pid_cmp
171 tid_cmp = cmp(tid_first_seen[tid1], tid_first_seen[tid2])
172 if tid_cmp != 0:
173 return tid_cmp
174 return cmp(MakeTimestamp(usec1, sec1), MakeTimestamp(usec2, sec2))
175
176 return sorted(input_trace, cmp=CompareEvents)
177
140 def main(): 178 def main():
141 """Merge two traces for code in specified library and write to stdout. 179 """Merge two traces for code in specified library and write to stdout.
142 180
143 Merges the two traces and coverts the virtual addresses to the offsets in the 181 Merges the two traces and coverts the virtual addresses to the offsets in the
144 library. First line of merged trace has dummy virtual address of 0-ffffffff 182 library. First line of merged trace has dummy virtual address of 0-ffffffff
145 so that symbolizing the addresses uses the addresses in the log, since the 183 so that symbolizing the addresses uses the addresses in the log, since the
146 addresses have already been converted to static offsets. 184 addresses have already been converted to static offsets.
147 """ 185 """
148 parser = optparse.OptionParser('usage: %prog trace1 ... traceN') 186 parser = optparse.OptionParser('usage: %prog trace1 ... traceN')
149 (_, args) = parser.parse_args() 187 (_, args) = parser.parse_args()
150 if len(args) <= 1: 188 if len(args) <= 1:
151 parser.error('expected at least the following args: trace1 trace2') 189 parser.error('expected at least the following args: trace1 trace2')
152 190
153 step = 0 191 step = 0
192
193 # Maps function addresses to their corresponding trace entry.
154 tracemap = dict() 194 tracemap = dict()
195
155 for trace_file in args: 196 for trace_file in args:
156 step += 1 197 step += 1
157 sys.stderr.write(" " + str(step) + "/" + str(len(args)) + 198 sys.stderr.write(" " + str(step) + "/" + str(len(args)) +
158 ": " + trace_file + ":\n") 199 ": " + trace_file + ":\n")
159 200
160 trace_lines = map(string.rstrip, open(trace_file).readlines()) 201 trace_lines = map(string.rstrip, open(trace_file).readlines())
161 (trace_calls, trace_start, trace_end) = ParseLogLines(trace_lines) 202 (trace_calls, trace_start, trace_end) = ParseLogLines(trace_lines)
162 CheckTimestamps(trace_calls) 203 CheckTimestamps(trace_calls)
163 sys.stderr.write("Len: " + str(len(trace_calls)) + 204 sys.stderr.write("Len: " + str(len(trace_calls)) +
164 ". Start: " + hex(trace_start) + 205 ". Start: " + hex(trace_start) +
165 ", end: " + hex(trace_end) + '\n') 206 ", end: " + hex(trace_end) + '\n')
166 207
167 trace_calls = Convert(trace_calls, trace_start, trace_end) 208 trace_calls = Convert(trace_calls, trace_start, trace_end)
168 sys.stderr.write("Converted len: " + str(len(trace_calls)) + "\n") 209 sys.stderr.write("Converted len: " + str(len(trace_calls)) + "\n")
169 210
170 AddTrace(tracemap, trace_calls) 211 AddTrace(tracemap, trace_calls)
171 sys.stderr.write("Merged len: " + str(len(tracemap)) + "\n") 212 sys.stderr.write("Merged len: " + str(len(tracemap)) + "\n")
172 213
173 # Extract the resulting trace from the tracemap 214 # Extract the resulting trace from the tracemap
174 merged_trace = [] 215 merged_trace = []
175 for call in tracemap: 216 for call in tracemap:
176 merged_trace.append(tracemap[call]) 217 merged_trace.append(tracemap[call])
177 merged_trace.sort(key=Timestamp) 218 merged_trace.sort(key=Timestamp)
178 219
220 grouped_trace = GroupByProcessAndThreadId(merged_trace)
221 merged_trace = None
pasko 2014/06/05 12:50:10 nit: seems not necessary
Philippe 2014/06/05 13:00:45 Done.
222
179 print "0-ffffffff r-xp 00000000 xx:00 00000 ./" 223 print "0-ffffffff r-xp 00000000 xx:00 00000 ./"
180 print "secs\tusecs\tpid:threadid\tfunc" 224 print "secs\tusecs\tpid:threadid\tfunc"
181 for call in merged_trace: 225 for call in grouped_trace:
182 print (str(call[0]) + "\t" + str(call[1]) + "\t" + call[2] + "\t" + 226 print (str(call[0]) + "\t" + str(call[1]) + "\t" + call[2] + "\t" +
183 hex(call[3])) 227 hex(call[3]))
184 228
185 if __name__ == '__main__': 229 if __name__ == '__main__':
186 main() 230 main()
OLDNEW
« no previous file with comments | « tools/cygprofile/PRESUBMIT.py ('k') | tools/cygprofile/mergetraces_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698