| 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: |
| 162 raise Exception( |
| 163 'Seen PIDs %d and %d for TID=%d. Thread-IDs must be unique' % ( |
| 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 |