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

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

Issue 319053004: Fix bug in mergetraces.py. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address Egor's comments 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 | « no previous file | 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 string 16 import string
17 import sets
17 import sys 18 import sys
18 19
19 def ParseLogLines(lines): 20 def ParseLogLines(lines):
20 """Parse log file lines. 21 """Parse log file lines.
21 22
22 Args: 23 Args:
23 lines: lines from log file produced by profiled run 24 lines: lines from log file produced by profiled run
24 25
25 Below is an example of a small log file: 26 Below is an example of a small log file:
26 5086e000-52e92000 r-xp 00000000 b3:02 51276 libchromeview.so 27 5086e000-52e92000 r-xp 00000000 b3:02 51276 libchromeview.so
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 tracemap[call] = trace_entry 137 tracemap[call] = trace_entry
137 138
138 def GroupByProcessAndThreadId(input_trace): 139 def GroupByProcessAndThreadId(input_trace):
139 """Returns an array of traces grouped by pid and tid. 140 """Returns an array of traces grouped by pid and tid.
140 141
141 This is used to make the order of functions not depend on thread scheduling 142 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 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 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 timestamp) and processes also have their code isolated (i.e. not interleaved).
145 """ 146 """
146 def MakeTimestamp(usec, sec): 147 def MakeTimestamp(sec, usec):
147 return usec * 1000000 + sec 148 return sec * 1000000 + usec
148 149
149 def PidAndTidFromString(pid_and_tid): 150 def PidAndTidFromString(pid_and_tid):
150 strings = pid_and_tid.split(':') 151 strings = pid_and_tid.split(':')
151 return (int(strings[0]), int(strings[1])) 152 return (int(strings[0]), int(strings[1]))
152 153
154 tid_to_pids_map = {}
153 pid_first_seen = {} 155 pid_first_seen = {}
154 tid_first_seen = {} 156 tid_first_seen = {}
157
155 for (sec, usec, pid_and_tid, _) in input_trace: 158 for (sec, usec, pid_and_tid, _) in input_trace:
156 (pid, tid) = PidAndTidFromString(pid_and_tid) 159 (pid, tid) = PidAndTidFromString(pid_and_tid)
160
161 # Make sure that thread IDs are unique since this a property we rely on.
pasko 2014/06/06 09:41:44 s/this/this is/
Philippe 2014/06/06 09:50:23 Done.
Philippe 2014/06/06 09:50:23 Done.
162 pids_for_tid = tid_to_pids_map.setdefault(tid, sets.Set())
163 pids_for_tid.add(pid)
164 if len(pids_for_tid) > 1:
165 raise Exception('Thread IDs should be unique.')
pasko 2014/06/06 09:41:44 in this context we actually have the tid and two p
Philippe 2014/06/06 09:50:23 Yeah :) I haven't slept much last night :)
166
157 if not pid in pid_first_seen: 167 if not pid in pid_first_seen:
158 pid_first_seen[pid] = MakeTimestamp(usec, sec) 168 pid_first_seen[pid] = MakeTimestamp(sec, usec)
159 if not tid in tid_first_seen: 169 if not tid in tid_first_seen:
160 tid_first_seen[tid] = MakeTimestamp(usec, sec) 170 tid_first_seen[tid] = MakeTimestamp(sec, usec)
161 171
162 def CompareEvents(event1, event2): 172 def CompareEvents(event1, event2):
163 (sec1, usec1, pid_and_tid, _) = event1 173 (sec1, usec1, pid_and_tid, _) = event1
164 (pid1, tid1) = PidAndTidFromString(pid_and_tid) 174 (pid1, tid1) = PidAndTidFromString(pid_and_tid)
165 (sec2, usec2, pid_and_tid, _) = event2 175 (sec2, usec2, pid_and_tid, _) = event2
166 (pid2, tid2) = PidAndTidFromString(pid_and_tid) 176 (pid2, tid2) = PidAndTidFromString(pid_and_tid)
167 177
168 pid_cmp = cmp(pid_first_seen[pid1], pid_first_seen[pid2]) 178 pid_cmp = cmp(pid_first_seen[pid1], pid_first_seen[pid2])
169 if pid_cmp != 0: 179 if pid_cmp != 0:
170 return pid_cmp 180 return pid_cmp
171 tid_cmp = cmp(tid_first_seen[tid1], tid_first_seen[tid2]) 181 tid_cmp = cmp(tid_first_seen[tid1], tid_first_seen[tid2])
172 if tid_cmp != 0: 182 if tid_cmp != 0:
173 return tid_cmp 183 return tid_cmp
174 return cmp(MakeTimestamp(usec1, sec1), MakeTimestamp(usec2, sec2)) 184 return cmp(MakeTimestamp(sec1, usec1), MakeTimestamp(sec2, usec2))
175 185
176 return sorted(input_trace, cmp=CompareEvents) 186 return sorted(input_trace, cmp=CompareEvents)
177 187
178 def main(): 188 def main():
179 """Merge two traces for code in specified library and write to stdout. 189 """Merge two traces for code in specified library and write to stdout.
180 190
181 Merges the two traces and coverts the virtual addresses to the offsets in the 191 Merges the two traces and coverts the virtual addresses to the offsets in the
182 library. First line of merged trace has dummy virtual address of 0-ffffffff 192 library. First line of merged trace has dummy virtual address of 0-ffffffff
183 so that symbolizing the addresses uses the addresses in the log, since the 193 so that symbolizing the addresses uses the addresses in the log, since the
184 addresses have already been converted to static offsets. 194 addresses have already been converted to static offsets.
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 grouped_trace = GroupByProcessAndThreadId(merged_trace) 230 grouped_trace = GroupByProcessAndThreadId(merged_trace)
221 231
222 print "0-ffffffff r-xp 00000000 xx:00 00000 ./" 232 print "0-ffffffff r-xp 00000000 xx:00 00000 ./"
223 print "secs\tusecs\tpid:threadid\tfunc" 233 print "secs\tusecs\tpid:threadid\tfunc"
224 for call in grouped_trace: 234 for call in grouped_trace:
225 print (str(call[0]) + "\t" + str(call[1]) + "\t" + call[2] + "\t" + 235 print (str(call[0]) + "\t" + str(call[1]) + "\t" + call[2] + "\t" +
226 hex(call[3])) 236 hex(call[3]))
227 237
228 if __name__ == '__main__': 238 if __name__ == '__main__':
229 main() 239 main()
OLDNEW
« no previous file with comments | « no previous file | tools/cygprofile/mergetraces_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698