File indexing completed on 2025-01-18 10:17:18
0001
0002 import re
0003 import svgwrite
0004 from datetime import datetime, timedelta
0005 from collections import defaultdict
0006
0007
0008 def parse_logfile():
0009
0010
0011 thread_history = defaultdict(list)
0012 barrier_history = []
0013
0014 start_times = {}
0015
0016
0017 source_start_pattern = re.compile(r"^(\d{2}):(\d{2}):(\d{2})\.(\d{3}) \[debug\] (\d+) Executing arrow (\w+)$")
0018 source_finish_noemit_pattern = re.compile(r"^(\d{2}):(\d{2}):(\d{2})\.(\d{3}) \[debug\] (\d+) Executed arrow (\w+) with result (\w+)$")
0019 source_finish_emit_pattern = re.compile(r"^(\d{2}):(\d{2}):(\d{2})\.(\d{3}) \[debug\] (\d+) Executed arrow (\w+) with result (\w+), emitting event# (\d+)$")
0020 source_finish_pending_pattern = re.compile(r"^(\d{2}):(\d{2}):(\d{2})\.(\d{3}) \[debug\] (\d+) Executed arrow (\w+) with result (\w+), holding back barrier event# (\d+)$")
0021 processor_start_pattern = re.compile(r"^(\d{2}):(\d{2}):(\d{2})\.(\d{3}) \[debug\] (\d+) Executing arrow (\w+) for event# (\d+)$")
0022 processor_finish_pattern = re.compile(r"^(\d{2}):(\d{2}):(\d{2})\.(\d{3}) \[debug\] (\d+) Executed arrow (\w+) for event# (\d+)$")
0023 barrier_inflight_pattern = re.compile(r"^(\d{2}):(\d{2}):(\d{2})\.(\d{3}) \[debug\] (\d+) JEventSourceArrow: Barrier event is in-flight$")
0024 barrier_finished_pattern = re.compile(r"^(\d{2}):(\d{2}):(\d{2})\.(\d{3}) \[debug\] (\d+) JEventSourceArrow: Barrier event finished, returning to normal operation$")
0025
0026 with open("log.txt", "r") as log_file:
0027 for line in log_file:
0028
0029 match = re.match(source_start_pattern, line.strip())
0030 if match:
0031 hours_str, mins_str, secs_str, millis_str, thread_id, processor_name = match.groups()
0032 millis = (((int(hours_str) * 60) + int(mins_str) * 60) + int(secs_str)) * 1000 + int(millis_str)
0033 start_times[(thread_id, processor_name)] = millis
0034 continue
0035
0036 match = re.match(source_finish_noemit_pattern, line.strip())
0037 if match:
0038 hours_str, mins_str, secs_str, millis_str, thread_id, processor_name, result = match.groups()
0039 millis = (((int(hours_str) * 60) + int(mins_str) * 60) + int(secs_str)) * 1000 + int(millis_str)
0040 start_time = start_times.pop((thread_id, processor_name), None)
0041 if start_time:
0042 thread_history[thread_id].append((start_time, millis, processor_name, None, result))
0043 continue
0044
0045 match = re.match(source_finish_emit_pattern, line.strip())
0046 if match:
0047 hours_str, mins_str, secs_str, millis_str, thread_id, processor_name, result, event_nr = match.groups()
0048 millis = (((int(hours_str) * 60) + int(mins_str) * 60) + int(secs_str)) * 1000 + int(millis_str)
0049 start_time = start_times.pop((thread_id, processor_name), None)
0050 if start_time:
0051 thread_history[thread_id].append((start_time, millis, processor_name, event_nr, result))
0052 continue
0053
0054 match = re.match(source_finish_pending_pattern, line.strip())
0055 if match:
0056 hours_str, mins_str, secs_str, millis_str, thread_id, processor_name, result, event_nr = match.groups()
0057 millis = (((int(hours_str) * 60) + int(mins_str) * 60) + int(secs_str)) * 1000 + int(millis_str)
0058 start_time = start_times.pop((thread_id, processor_name), None)
0059 if start_time:
0060 thread_history[thread_id].append((start_time, millis, processor_name, event_nr, result))
0061 continue
0062
0063 match = re.match(processor_start_pattern, line.strip())
0064 if match:
0065 hours_str, mins_str, secs_str, millis_str, thread_id, processor_name, event_nr = match.groups()
0066 millis = (((int(hours_str) * 60) + int(mins_str) * 60) + int(secs_str)) * 1000 + int(millis_str)
0067 start_times[(thread_id, processor_name)] = millis
0068 continue
0069
0070 match = re.match(processor_finish_pattern, line.strip())
0071 if match:
0072 hours_str, mins_str, secs_str, millis_str, thread_id, processor_name, event_nr = match.groups()
0073 millis = (((int(hours_str) * 60) + int(mins_str) * 60) + int(secs_str)) * 1000 + int(millis_str)
0074 start_time = start_times.pop((thread_id, processor_name), None)
0075 if start_time:
0076 thread_history[thread_id].append((start_time, millis, processor_name, event_nr, result))
0077 continue
0078
0079 match = re.match(barrier_inflight_pattern, line.strip())
0080 if match:
0081 hours_str, mins_str, secs_str, millis_str, thread_id = match.groups()
0082 millis = (((int(hours_str) * 60) + int(mins_str) * 60) + int(secs_str)) * 1000 + int(millis_str)
0083 start_times[()] = millis
0084 continue
0085
0086 match = re.match(barrier_finished_pattern, line.strip())
0087 if match:
0088 hours_str, mins_str, secs_str, millis_str, thread_id = match.groups()
0089 millis = (((int(hours_str) * 60) + int(mins_str) * 60) + int(secs_str)) * 1000 + int(millis_str)
0090 start_time = start_times.pop((), None)
0091 if start_time:
0092 barrier_history.append((start_time, millis))
0093 continue
0094
0095 return (thread_history, barrier_history)
0096
0097
0098
0099 def create_svg(all_thread_history, barrier_history):
0100
0101 processor_colors = {}
0102 color_palette = ['#004E64', '#00A5CF', '#9FFFCB', '#25A18E', '#7AE582', '#FF69B4']
0103 color_index = 0
0104
0105
0106 overall_start_time = min(start for history in all_thread_history.values() for (start,_,_,_,_) in history)
0107 overall_end_time = max(end for history in all_thread_history.values() for (_,end,_,_,_) in history)
0108 thread_count = len(all_thread_history)
0109 width=1000
0110 x_scale = width/(overall_end_time-overall_start_time)
0111 thread_height=40
0112 thread_y_padding=20
0113 height=thread_count * thread_height + (thread_count+1) * thread_y_padding
0114
0115
0116
0117 dwg = svgwrite.Drawing("timeline.svg", profile='tiny', size=(width, height))
0118
0119
0120
0121 y_position = thread_y_padding
0122
0123 for barrier_start,barrier_end in barrier_history:
0124 rect_start = (barrier_start-overall_start_time)*x_scale
0125 if (barrier_end == barrier_start):
0126 rect_width=1
0127 else:
0128 rect_width = (barrier_end-barrier_start)*x_scale
0129
0130 rect = dwg.rect(insert=(rect_start, 0),
0131 size=(rect_width, height),
0132 fill="red",
0133 stroke="none",
0134 stroke_width=1)
0135 dwg.add(rect)
0136
0137 for thread_id, intervals in all_thread_history.items():
0138 dwg.add(dwg.rect(insert=(0,y_position),size=(1000,thread_height),stroke="lightgray",fill="lightgray"))
0139 for start_time, end_time, processor_name, event_nr, result in intervals:
0140
0141
0142 if processor_name not in processor_colors:
0143 processor_colors[processor_name] = color_palette[color_index % len(color_palette)]
0144 color_index += 1
0145
0146
0147 rect_start = (start_time-overall_start_time)*x_scale
0148 if (end_time == start_time):
0149 rect_width=1
0150 else:
0151 rect_width = (end_time-start_time)*x_scale
0152
0153 rect_stroke_color = "black"
0154 if (result == "ComeBackLater" and event_nr is None):
0155 rect_stroke_color = "gray"
0156
0157
0158 rect = dwg.rect(insert=(rect_start, y_position),
0159 size=(rect_width, thread_height),
0160 fill=processor_colors[processor_name],
0161 stroke=rect_stroke_color,
0162 stroke_width=1)
0163 mouseover = "Arrow: " + processor_name + "\nEvent nr: " + str(event_nr) + "\nResult: " + result + "\nTime: "+ str(end_time-start_time) + "ms"
0164 rect.add(svgwrite.base.Title(mouseover))
0165 dwg.add(rect)
0166 if (event_nr is not None):
0167 text = dwg.text(str(event_nr), insert=(rect_start+1, y_position+thread_height-1), fill="white", font_size=8)
0168 dwg.add(text)
0169
0170
0171 y_position += (thread_y_padding + thread_height)
0172
0173
0174
0175 dwg.save()
0176
0177
0178
0179 if __name__ == "__main__":
0180 thread_history,barrier_history = parse_logfile()
0181
0182
0183
0184
0185
0186 create_svg(thread_history, barrier_history)
0187
0188