OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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() |
OLD | NEW |