This commit is contained in:
2026-04-23 10:36:51 +07:00
parent bdb432dc39
commit eacdc424bc
3 changed files with 90 additions and 39 deletions
+58 -7
View File
@@ -3,9 +3,11 @@ import argparse
import re
import sys
from dataclasses import dataclass
from decimal import Decimal
from typing import Dict, Iterable, List, Tuple
from openpyxl import Workbook
from openpyxl.chart import BarChart, Reference
from openpyxl.styles import Font
@@ -18,8 +20,10 @@ LINE_RE = re.compile(
class ProcessLog:
pid: int
ppid: int
start: float
finish: float | None = None
start: Decimal
start_text: str
finish: Decimal | None = None
finish_text: str | None = None
first_seen_order: int = 0
@@ -65,16 +69,23 @@ def parse_processes(lines: Iterable[str]) -> Dict[int, ProcessLog]:
event, pid_s, ppid_s, _depth_s, _l_s, _r_s, ts_s = m.groups()
pid = int(pid_s)
ppid = int(ppid_s)
ts = float(ts_s)
ts = Decimal(ts_s)
if event == "START":
processes[pid] = ProcessLog(
pid=pid, ppid=ppid, start=ts, finish=None, first_seen_order=order
pid=pid,
ppid=ppid,
start=ts,
start_text=ts_s,
finish=None,
finish_text=None,
first_seen_order=order,
)
order += 1
else:
if pid in processes:
processes[pid].finish = ts
processes[pid].finish_text = ts_s
return processes
@@ -113,29 +124,69 @@ def tree_rows(processes: Dict[int, ProcessLog]) -> List[Tuple[int, ProcessLog]]:
return ordered
def fmt6(value: Decimal) -> str:
return f"{value.quantize(Decimal('0.000001'))}"
def export_excel(rows: List[Tuple[int, ProcessLog]], output_path: str) -> None:
wb = Workbook()
ws = wb.active
ws.title = "process_logs"
ws.append(["PPID", "PID", "START", "FINISH", "DURATION"])
ws.append(["PPID", "PID", "START", "TIME_FROM_START", "FINISH", "DURATION"])
for cell in ws[1]:
cell.font = Font(bold=True)
base_start = min((node.start for _, node in rows), default=Decimal("0"))
for depth, node in rows:
if node.finish is None:
continue
if node.finish_text is None:
continue
time_from_start = node.start - base_start
duration = node.finish - node.start
pid_display = f"{' ' * depth}{node.pid}"
ws.append([node.ppid, pid_display, node.start, node.finish, duration])
ws.append(
[
node.ppid,
pid_display,
node.start_text,
fmt6(time_from_start),
node.finish_text,
fmt6(duration),
]
)
ws.column_dimensions["A"].width = 12
ws.column_dimensions["B"].width = 20
ws.column_dimensions["C"].width = 18
ws.column_dimensions["D"].width = 18
ws.column_dimensions["E"].width = 14
ws.column_dimensions["E"].width = 18
ws.column_dimensions["F"].width = 14
ws.freeze_panes = "A2"
last_row = ws.max_row
if last_row >= 2:
chart = BarChart()
chart.type = "bar"
chart.grouping = "stacked"
chart.overlap = 100
chart.gapWidth = 150
chart.legend.position = "b"
chart.width = 15
chart.height = 7.5
chart.x_axis.scaling.orientation = "maxMin"
data = Reference(ws, min_col=4, max_col=4, min_row=2, max_row=last_row)
duration = Reference(ws, min_col=6, max_col=6, min_row=2, max_row=last_row)
chart.add_data(data, titles_from_data=False)
chart.add_data(duration, titles_from_data=False)
chart.series[0].graphicalProperties.noFill = True
ws.add_chart(chart, "D21")
wb.save(output_path)