init gannt in 1

This commit is contained in:
2026-04-25 06:53:53 +07:00
parent d44a581cee
commit dfe87e9b31
8 changed files with 208 additions and 292 deletions
+33 -6
View File
@@ -7,29 +7,56 @@ LDFLAGS := -lrt
TARGET := lab1 TARGET := lab1
SRC := main.cpp SRC := main.cpp
LOG_FILE := log.txt LOG_FILE := log.txt
XLSX_FILE:= process_log.xlsx
.PHONY: all run log excel export report deps clean rebuild MD_FILE := processes.md
IMG_FILE := gantt.png
PY_EXPORT := exporter.py
.PHONY: all run log export report deps clean rebuild
# -------------------------
# BUILD
# -------------------------
all: $(TARGET) all: $(TARGET)
$(TARGET): $(SRC) $(TARGET): $(SRC)
$(CXX) $(CXXFLAGS) $(SRC) -o $(TARGET) $(LDFLAGS) $(CXX) $(CXXFLAGS) $(SRC) -o $(TARGET) $(LDFLAGS)
# -------------------------
# RUN ONLY
# -------------------------
run: $(TARGET) run: $(TARGET)
./$(TARGET) ./$(TARGET)
# -------------------------
# LOG ONLY (C++ output)
# -------------------------
log: $(TARGET) log: $(TARGET)
./$(TARGET) > $(LOG_FILE) ./$(TARGET) > $(LOG_FILE)
excel: log # -------------------------
$(PYTHON) export.py --input $(LOG_FILE) --output $(XLSX_FILE) # EXPORT (C++ + Python pipeline)
# -------------------------
export: $(TARGET)
./$(TARGET) > $(LOG_FILE)
$(PYTHON) $(PY_EXPORT) $(LOG_FILE)
# -------------------------
# DEPENDENCIES
# -------------------------
deps: deps:
$(PIP) install -r req.txt $(PIP) install matplotlib
# -------------------------
# CLEAN
# -------------------------
clean: clean:
rm -f $(TARGET) $(XLSX_FILE) rm -f $(TARGET) $(LOG_FILE) $(MD_FILE) $(IMG_FILE)
# -------------------------
# REBUILD
# -------------------------
rebuild: clean all rebuild: clean all
-203
View File
@@ -1,203 +0,0 @@
#!/usr/bin/env python3
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
LINE_RE = re.compile(
r"^(START|END)\s+PID=(\d+)\s+PPID=(\d+)\s+depth=(\d+)\s+range=\[(\d+),(\d+)\]\s+time=([0-9.]+)$"
)
@dataclass
class ProcessLog:
pid: int
ppid: int
start: Decimal
start_text: str
finish: Decimal | None = None
finish_text: str | None = None
first_seen_order: int = 0
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Convert process START/END log to a ptree-like Excel report."
)
parser.add_argument(
"-i",
"--input",
default="-",
help="Input log file path (default: stdin)",
)
parser.add_argument(
"-o",
"--output",
default="process_log.xlsx",
help="Output Excel file path (default: process_log.xlsx)",
)
return parser.parse_args()
def read_lines(input_path: str) -> Iterable[str]:
if input_path == "-":
for line in sys.stdin:
yield line.rstrip("\n")
return
with open(input_path, "r", encoding="utf-8") as f:
for line in f:
yield line.rstrip("\n")
def parse_processes(lines: Iterable[str]) -> Dict[int, ProcessLog]:
processes: Dict[int, ProcessLog] = {}
order = 0
for raw in lines:
m = LINE_RE.match(raw.strip())
if not m:
continue
event, pid_s, ppid_s, _depth_s, _l_s, _r_s, ts_s = m.groups()
pid = int(pid_s)
ppid = int(ppid_s)
ts = Decimal(ts_s)
if event == "START":
processes[pid] = ProcessLog(
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
def tree_rows(processes: Dict[int, ProcessLog]) -> List[Tuple[int, ProcessLog]]:
complete = {pid: p for pid, p in processes.items() if p.finish is not None}
children: Dict[int, List[int]] = {}
for pid in complete:
children[pid] = []
for pid, node in complete.items():
if node.ppid in complete:
children[node.ppid].append(pid)
for pid in children:
children[pid].sort(key=lambda cpid: complete[cpid].start)
roots = [pid for pid, node in complete.items() if node.ppid not in complete]
roots.sort(key=lambda pid: complete[pid].start)
ordered: List[Tuple[int, ProcessLog]] = []
def dfs(pid: int, depth: int) -> None:
ordered.append((depth, complete[pid]))
for ch in children[pid]:
dfs(ch, depth + 1)
for root_pid in roots:
dfs(root_pid, 0)
remaining = [pid for pid in complete if pid not in {p.pid for _, p in ordered}]
remaining.sort(key=lambda pid: complete[pid].start)
for pid in remaining:
dfs(pid, 0)
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", "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_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 = 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)
def main() -> int:
args = parse_args()
processes = parse_processes(read_lines(args.input))
rows = tree_rows(processes)
export_excel(rows, args.output)
print(f"Saved to {args.output}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+97
View File
@@ -0,0 +1,97 @@
import re
import sys
import matplotlib.pyplot as plt
LOG_RE = re.compile(
r"(PROC_START|PROC_END)\s+pid=(\d+)\s+ppid=(\d+)\s+depth=(\d+)\s+l=(\d+)\s+r=(\d+)\s+ts=([\d.]+)"
)
class Proc:
def __init__(self, pid, ppid):
self.pid = pid
self.ppid = ppid
self.start = None
self.end = None
self.children = []
@property
def duration(self):
return self.end - self.start
def parse_log(path):
procs = {}
for line in open(path):
m = LOG_RE.search(line)
if not m:
continue
typ, pid, ppid, depth, l, r, ts = m.groups()
pid, ppid, ts = int(pid), int(ppid), float(ts)
if pid not in procs:
procs[pid] = Proc(pid, ppid)
if typ == "PROC_START":
procs[pid].start = ts
else:
procs[pid].end = ts
return procs
def build_tree(procs):
root = None
for p in procs.values():
if p.ppid in procs:
procs[p.ppid].children.append(p)
else:
root = p
return root
def dfs_order(root):
order = []
def dfs(p):
order.append(p)
for c in sorted(p.children, key=lambda x: x.start):
dfs(c)
dfs(root)
return order
def write_md(procs, ordered):
first = min(p.start for p in procs.values())
with open("processes.md", "w") as f:
f.write("| PID | PPID | Start | End | Offset | Duration |\n")
f.write("|---|---|---|---|---|---|\n")
for p in ordered:
f.write(
f"| {p.pid} | {p.ppid} | {p.start:.6f} | {p.end:.6f} | {p.start - first:.6f} | {p.duration:.6f} |\n"
)
def draw_gantt(ordered):
first = min(p.start for p in ordered)
fig, ax = plt.subplots(figsize=(12, 6))
for i, p in enumerate(ordered):
ax.barh(i, p.duration, left=p.start - first, height=0.6)
ax.text(p.start - first, i, f" PID {p.pid}", va="center")
ax.set_yticks(range(len(ordered)))
ax.set_yticklabels([p.pid for p in ordered])
ax.set_xlabel("Seconds from first process start")
ax.set_title("Process Gantt")
plt.tight_layout()
plt.savefig("gantt.png")
def main():
procs = parse_log(sys.argv[1])
root = build_tree(procs)
ordered = dfs_order(root)
write_md(procs, ordered)
draw_gantt(ordered)
if __name__ == "__main__":
main()
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
View File
Binary file not shown.
+30 -36
View File
@@ -1,36 +1,30 @@
Before: PROC_START pid=41115 ppid=41113 depth=0 l=0 r=19999 ts=1777074730.331155
58004 89472 63849 21489 55079 3458 75571 99360 41392 19102 39020 191 15438 77248 35268 63821 27080 47931 57519 22445 PROC_START pid=41116 ppid=41115 depth=1 l=0 r=9999 ts=1777074730.332433
PROC_START pid=41117 ppid=41115 depth=1 l=10000 r=19999 ts=1777074730.332633
START PID=22020 PPID=22019 depth=0 range=[0,19999] time=1776915463.198584 PROC_START pid=41118 ppid=41116 depth=2 l=0 r=4999 ts=1777074730.333202
START PID=22021 PPID=22020 depth=1 range=[0,9999] time=1776915463.198737 PROC_START pid=41119 ppid=41117 depth=2 l=10000 r=14999 ts=1777074730.333253
START PID=22022 PPID=22020 depth=1 range=[10000,19999] time=1776915463.198837 PROC_START pid=41120 ppid=41116 depth=2 l=5000 r=9999 ts=1777074730.333499
START PID=22023 PPID=22021 depth=2 range=[0,4999] time=1776915463.198895 PROC_START pid=41121 ppid=41117 depth=2 l=15000 r=19999 ts=1777074730.333522
START PID=22024 PPID=22021 depth=2 range=[5000,9999] time=1776915463.198963 PROC_START pid=41122 ppid=41118 depth=3 l=0 r=2499 ts=1777074730.333905
START PID=22025 PPID=22022 depth=2 range=[10000,14999] time=1776915463.199044 PROC_START pid=41123 ppid=41119 depth=3 l=10000 r=12499 ts=1777074730.334001
START PID=22026 PPID=22022 depth=2 range=[15000,19999] time=1776915463.199059 PROC_START pid=41124 ppid=41121 depth=3 l=15000 r=17499 ts=1777074730.334220
START PID=22027 PPID=22023 depth=3 range=[0,2499] time=1776915463.199078 PROC_START pid=41125 ppid=41120 depth=3 l=5000 r=7499 ts=1777074730.334244
START PID=22028 PPID=22024 depth=3 range=[5000,7499] time=1776915463.199143 PROC_START pid=41127 ppid=41119 depth=3 l=12500 r=14999 ts=1777074730.334636
START PID=22029 PPID=22023 depth=3 range=[2500,4999] time=1776915463.199144 PROC_START pid=41126 ppid=41118 depth=3 l=2500 r=4999 ts=1777074730.334760
START PID=22030 PPID=22024 depth=3 range=[7500,9999] time=1776915463.199226 PROC_START pid=41128 ppid=41121 depth=3 l=17500 r=19999 ts=1777074730.334799
START PID=22033 PPID=22025 depth=3 range=[12500,14999] time=1776915463.199313 PROC_START pid=41129 ppid=41120 depth=3 l=7500 r=9999 ts=1777074730.334870
START PID=22031 PPID=22025 depth=3 range=[10000,12499] time=1776915463.199356 PROC_END pid=41123 ppid=41119 depth=3 l=10000 r=12499 ts=1777074730.336351
START PID=22032 PPID=22026 depth=3 range=[15000,17499] time=1776915463.199389 PROC_END pid=41127 ppid=41119 depth=3 l=12500 r=14999 ts=1777074730.336705
END PID=22027 PPID=22023 depth=3 range=[0,2499] time=1776915463.199444 PROC_END pid=41124 ppid=41121 depth=3 l=15000 r=17499 ts=1777074730.336857
END PID=22028 PPID=22024 depth=3 range=[5000,7499] time=1776915463.199544 PROC_END pid=41129 ppid=41120 depth=3 l=7500 r=9999 ts=1777074730.336864
END PID=22029 PPID=22023 depth=3 range=[2500,4999] time=1776915463.199582 PROC_END pid=41125 ppid=41120 depth=3 l=5000 r=7499 ts=1777074730.337630
END PID=22030 PPID=22024 depth=3 range=[7500,9999] time=1776915463.199608 PROC_END pid=41119 ppid=41117 depth=2 l=10000 r=14999 ts=1777074730.337559
END PID=22031 PPID=22025 depth=3 range=[10000,12499] time=1776915463.199723 PROC_END pid=41128 ppid=41121 depth=3 l=17500 r=19999 ts=1777074730.337974
END PID=22033 PPID=22025 depth=3 range=[12500,14999] time=1776915463.199746 PROC_END pid=41121 ppid=41117 depth=2 l=15000 r=19999 ts=1777074730.338710
END PID=22023 PPID=22021 depth=2 range=[0,4999] time=1776915463.199774 PROC_END pid=41120 ppid=41116 depth=2 l=5000 r=9999 ts=1777074730.338724
END PID=22024 PPID=22021 depth=2 range=[5000,9999] time=1776915463.199782 PROC_END pid=41117 ppid=41115 depth=1 l=10000 r=19999 ts=1777074730.339777
START PID=22034 PPID=22026 depth=3 range=[17500,19999] time=1776915463.199843 PROC_END pid=41122 ppid=41118 depth=3 l=0 r=2499 ts=1777074730.340717
END PID=22025 PPID=22022 depth=2 range=[10000,14999] time=1776915463.199932 PROC_END pid=41126 ppid=41118 depth=3 l=2500 r=4999 ts=1777074730.340948
END PID=22021 PPID=22020 depth=1 range=[0,9999] time=1776915463.199996 PROC_END pid=41118 ppid=41116 depth=2 l=0 r=4999 ts=1777074730.341717
END PID=22034 PPID=22026 depth=3 range=[17500,19999] time=1776915463.200103 PROC_END pid=41116 ppid=41115 depth=1 l=0 r=9999 ts=1777074730.342666
END PID=22032 PPID=22026 depth=3 range=[15000,17499] time=1776915463.200222 PROC_END pid=41115 ppid=41113 depth=0 l=0 r=19999 ts=1777074730.343971
END PID=22026 PPID=22022 depth=2 range=[15000,19999] time=1776915463.200412
END PID=22022 PPID=22020 depth=1 range=[10000,19999] time=1776915463.200655
END PID=22020 PPID=22019 depth=0 range=[0,19999] time=1776915463.200993
After:
10 11 20 40 40 43 51 56 58 72 74 80 96 96 98 103 108 113 119 137
+31 -47
View File
@@ -28,17 +28,33 @@ std::string now() {
return oss.str(); return oss.str();
} }
/* ========= ONLY MODIFIED PART ========= */
void log_start(int l, int r, int depth) { void log_start(int l, int r, int depth) {
std::cout << "START PID=" << getpid() << " PPID=" << getppid() << " depth=" << depth std::cout
<< " range=[" << l << "," << r << "] time=" << now() << '\n' << "PROC_START"
<< std::flush; << " pid=" << getpid()
<< " ppid=" << getppid()
<< " depth=" << depth
<< " l=" << l
<< " r=" << r
<< " ts=" << now()
<< '\n'
<< std::flush;
} }
void log_end(int l, int r, int depth) { void log_end(int l, int r, int depth) {
std::cout << "END PID=" << getpid() << " PPID=" << getppid() << " depth=" << depth std::cout
<< " range=[" << l << "," << r << "] time=" << now() << '\n' << "PROC_END"
<< std::flush; << " pid=" << getpid()
<< " ppid=" << getppid()
<< " depth=" << depth
<< " l=" << l
<< " r=" << r
<< " ts=" << now()
<< '\n'
<< std::flush;
} }
/* ====================================== */
void merge_range(int* arr, int l, int m, int r) { void merge_range(int* arr, int l, int m, int r) {
std::vector<int> temp; std::vector<int> temp;
@@ -55,20 +71,14 @@ void merge_range(int* arr, int l, int m, int r) {
} }
} }
while (i <= m) { while (i <= m) temp.push_back(arr[i++]);
temp.push_back(arr[i++]); while (j <= r) temp.push_back(arr[j++]);
}
while (j <= r) {
temp.push_back(arr[j++]);
}
std::copy(temp.begin(), temp.end(), arr + l); std::copy(temp.begin(), temp.end(), arr + l);
} }
void local_sort(int* arr, int l, int r) { void local_sort(int* arr, int l, int r) {
if (l >= r) { if (l >= r) return;
return;
}
const int m = l + (r - l) / 2; const int m = l + (r - l) / 2;
local_sort(arr, l, m); local_sort(arr, l, m);
@@ -137,19 +147,11 @@ bool parse_positive_int(const char* value, int& out) {
try { try {
size_t consumed = 0; size_t consumed = 0;
const int parsed = std::stoi(value, &consumed); const int parsed = std::stoi(value, &consumed);
if (value[consumed] != '\0') { if (value[consumed] != '\0') return false;
return false; if (parsed <= 0) return false;
}
if (parsed <= 0) {
return false;
}
out = parsed; out = parsed;
return true; return true;
} catch (const std::invalid_argument&) { } catch (...) { return false; }
return false;
} catch (const std::out_of_range&) {
return false;
}
} }
} // namespace } // namespace
@@ -183,30 +185,12 @@ int main(int argc, char* argv[]) {
std::mt19937 rng(std::random_device{}()); std::mt19937 rng(std::random_device{}());
std::uniform_int_distribution<int> dist(0, 99999); std::uniform_int_distribution<int> dist(0, 99999);
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) arr[i] = dist(rng);
arr[i] = dist(rng);
}
std::cout << "Before:\n";
for (int i = 0; i < std::min(n, kPreviewCount); ++i) {
std::cout << arr[i] << ' ';
}
std::cout << "\n\n";
parallel_sort(arr, 0, n - 1, 0, max_depth); parallel_sort(arr, 0, n - 1, 0, max_depth);
std::cout << "\nAfter:\n"; if (shmdt(arr) < 0) std::perror("shmdt");
for (int i = 0; i < std::min(n, kPreviewCount); ++i) { if (shmctl(shmid, IPC_RMID, nullptr) < 0) std::perror("shmctl IPC_RMID");
std::cout << arr[i] << ' ';
}
std::cout << '\n';
if (shmdt(arr) < 0) {
std::perror("shmdt");
}
if (shmctl(shmid, IPC_RMID, nullptr) < 0) {
std::perror("shmctl IPC_RMID");
}
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
+17
View File
@@ -0,0 +1,17 @@
| PID | PPID | Start | End | Offset | Duration |
|---|---|---|---|---|---|
| 41115 | 41113 | 1777074730.331155 | 1777074730.343971 | 0.000000 | 0.012816 |
| 41116 | 41115 | 1777074730.332433 | 1777074730.342666 | 0.001278 | 0.010233 |
| 41118 | 41116 | 1777074730.333202 | 1777074730.341717 | 0.002047 | 0.008515 |
| 41122 | 41118 | 1777074730.333905 | 1777074730.340717 | 0.002750 | 0.006812 |
| 41126 | 41118 | 1777074730.334760 | 1777074730.340948 | 0.003605 | 0.006188 |
| 41120 | 41116 | 1777074730.333499 | 1777074730.338724 | 0.002344 | 0.005225 |
| 41125 | 41120 | 1777074730.334244 | 1777074730.337630 | 0.003089 | 0.003386 |
| 41129 | 41120 | 1777074730.334870 | 1777074730.336864 | 0.003715 | 0.001994 |
| 41117 | 41115 | 1777074730.332633 | 1777074730.339777 | 0.001478 | 0.007144 |
| 41119 | 41117 | 1777074730.333253 | 1777074730.337559 | 0.002098 | 0.004306 |
| 41123 | 41119 | 1777074730.334001 | 1777074730.336351 | 0.002846 | 0.002350 |
| 41127 | 41119 | 1777074730.334636 | 1777074730.336705 | 0.003481 | 0.002069 |
| 41121 | 41117 | 1777074730.333522 | 1777074730.338710 | 0.002367 | 0.005188 |
| 41124 | 41121 | 1777074730.334220 | 1777074730.336857 | 0.003065 | 0.002637 |
| 41128 | 41121 | 1777074730.334799 | 1777074730.337974 | 0.003644 | 0.003175 |