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. |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
136 tracemap[call] = trace_entry | 136 tracemap[call] = trace_entry |
137 | 137 |
138 def GroupByProcessAndThreadId(input_trace): | 138 def GroupByProcessAndThreadId(input_trace): |
139 """Returns an array of traces grouped by pid and tid. | 139 """Returns an array of traces grouped by pid and tid. |
140 | 140 |
141 This is used to make the order of functions not depend on thread scheduling | 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 | 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 | 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). | 144 timestamp) and processes also have their code isolated (i.e. not interleaved). |
145 """ | 145 """ |
146 def MakeTimestamp(usec, sec): | 146 def MakeTimestamp(sec, usec): |
147 return usec * 1000000 + sec | 147 return sec * 1000000 + usec |
148 | 148 |
149 def PidAndTidFromString(pid_and_tid): | 149 def PidAndTidFromString(pid_and_tid): |
150 strings = pid_and_tid.split(':') | 150 strings = pid_and_tid.split(':') |
151 return (int(strings[0]), int(strings[1])) | 151 return (int(strings[0]), int(strings[1])) |
152 | 152 |
153 tid_to_pid_map = {} | |
153 pid_first_seen = {} | 154 pid_first_seen = {} |
154 tid_first_seen = {} | 155 tid_first_seen = {} |
156 | |
155 for (sec, usec, pid_and_tid, _) in input_trace: | 157 for (sec, usec, pid_and_tid, _) in input_trace: |
156 (pid, tid) = PidAndTidFromString(pid_and_tid) | 158 (pid, tid) = PidAndTidFromString(pid_and_tid) |
159 | |
160 # Make sure that thread IDs are unique since this is a property we rely on. | |
161 if tid_to_pid_map.setdefault(tid, pid) != pid: | |
pasko
2014/06/06 09:53:29
nice!
| |
162 raise Exception( | |
163 'Seen PIDs %d and %d for TID=%d. Thread-IDs should be unique' % ( | |
pasko
2014/06/06 09:53:29
nit:
s/should be unique/must be unique./
Philippe
2014/06/06 10:53:36
Done.
| |
164 tid_to_pid_map[tid], pid, tid)) | |
165 | |
157 if not pid in pid_first_seen: | 166 if not pid in pid_first_seen: |
158 pid_first_seen[pid] = MakeTimestamp(usec, sec) | 167 pid_first_seen[pid] = MakeTimestamp(sec, usec) |
159 if not tid in tid_first_seen: | 168 if not tid in tid_first_seen: |
160 tid_first_seen[tid] = MakeTimestamp(usec, sec) | 169 tid_first_seen[tid] = MakeTimestamp(sec, usec) |
161 | 170 |
162 def CompareEvents(event1, event2): | 171 def CompareEvents(event1, event2): |
163 (sec1, usec1, pid_and_tid, _) = event1 | 172 (sec1, usec1, pid_and_tid, _) = event1 |
164 (pid1, tid1) = PidAndTidFromString(pid_and_tid) | 173 (pid1, tid1) = PidAndTidFromString(pid_and_tid) |
165 (sec2, usec2, pid_and_tid, _) = event2 | 174 (sec2, usec2, pid_and_tid, _) = event2 |
166 (pid2, tid2) = PidAndTidFromString(pid_and_tid) | 175 (pid2, tid2) = PidAndTidFromString(pid_and_tid) |
167 | 176 |
168 pid_cmp = cmp(pid_first_seen[pid1], pid_first_seen[pid2]) | 177 pid_cmp = cmp(pid_first_seen[pid1], pid_first_seen[pid2]) |
169 if pid_cmp != 0: | 178 if pid_cmp != 0: |
170 return pid_cmp | 179 return pid_cmp |
171 tid_cmp = cmp(tid_first_seen[tid1], tid_first_seen[tid2]) | 180 tid_cmp = cmp(tid_first_seen[tid1], tid_first_seen[tid2]) |
172 if tid_cmp != 0: | 181 if tid_cmp != 0: |
173 return tid_cmp | 182 return tid_cmp |
174 return cmp(MakeTimestamp(usec1, sec1), MakeTimestamp(usec2, sec2)) | 183 return cmp(MakeTimestamp(sec1, usec1), MakeTimestamp(sec2, usec2)) |
175 | 184 |
176 return sorted(input_trace, cmp=CompareEvents) | 185 return sorted(input_trace, cmp=CompareEvents) |
177 | 186 |
178 def main(): | 187 def main(): |
179 """Merge two traces for code in specified library and write to stdout. | 188 """Merge two traces for code in specified library and write to stdout. |
180 | 189 |
181 Merges the two traces and coverts the virtual addresses to the offsets in the | 190 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 | 191 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 | 192 so that symbolizing the addresses uses the addresses in the log, since the |
184 addresses have already been converted to static offsets. | 193 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) | 229 grouped_trace = GroupByProcessAndThreadId(merged_trace) |
221 | 230 |
222 print "0-ffffffff r-xp 00000000 xx:00 00000 ./" | 231 print "0-ffffffff r-xp 00000000 xx:00 00000 ./" |
223 print "secs\tusecs\tpid:threadid\tfunc" | 232 print "secs\tusecs\tpid:threadid\tfunc" |
224 for call in grouped_trace: | 233 for call in grouped_trace: |
225 print (str(call[0]) + "\t" + str(call[1]) + "\t" + call[2] + "\t" + | 234 print (str(call[0]) + "\t" + str(call[1]) + "\t" + call[2] + "\t" + |
226 hex(call[3])) | 235 hex(call[3])) |
227 | 236 |
228 if __name__ == '__main__': | 237 if __name__ == '__main__': |
229 main() | 238 main() |
OLD | NEW |