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
SRC := main.cpp
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)
$(TARGET): $(SRC)
$(CXX) $(CXXFLAGS) $(SRC) -o $(TARGET) $(LDFLAGS)
# -------------------------
# RUN ONLY
# -------------------------
run: $(TARGET)
./$(TARGET)
# -------------------------
# LOG ONLY (C++ output)
# -------------------------
log: $(TARGET)
./$(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:
$(PIP) install -r req.txt
$(PIP) install matplotlib
# -------------------------
# CLEAN
# -------------------------
clean:
rm -f $(TARGET) $(XLSX_FILE)
rm -f $(TARGET) $(LOG_FILE) $(MD_FILE) $(IMG_FILE)
# -------------------------
# REBUILD
# -------------------------
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:
58004 89472 63849 21489 55079 3458 75571 99360 41392 19102 39020 191 15438 77248 35268 63821 27080 47931 57519 22445
START PID=22020 PPID=22019 depth=0 range=[0,19999] time=1776915463.198584
START PID=22021 PPID=22020 depth=1 range=[0,9999] time=1776915463.198737
START PID=22022 PPID=22020 depth=1 range=[10000,19999] time=1776915463.198837
START PID=22023 PPID=22021 depth=2 range=[0,4999] time=1776915463.198895
START PID=22024 PPID=22021 depth=2 range=[5000,9999] time=1776915463.198963
START PID=22025 PPID=22022 depth=2 range=[10000,14999] time=1776915463.199044
START PID=22026 PPID=22022 depth=2 range=[15000,19999] time=1776915463.199059
START PID=22027 PPID=22023 depth=3 range=[0,2499] time=1776915463.199078
START PID=22028 PPID=22024 depth=3 range=[5000,7499] time=1776915463.199143
START PID=22029 PPID=22023 depth=3 range=[2500,4999] time=1776915463.199144
START PID=22030 PPID=22024 depth=3 range=[7500,9999] time=1776915463.199226
START PID=22033 PPID=22025 depth=3 range=[12500,14999] time=1776915463.199313
START PID=22031 PPID=22025 depth=3 range=[10000,12499] time=1776915463.199356
START PID=22032 PPID=22026 depth=3 range=[15000,17499] time=1776915463.199389
END PID=22027 PPID=22023 depth=3 range=[0,2499] time=1776915463.199444
END PID=22028 PPID=22024 depth=3 range=[5000,7499] time=1776915463.199544
END PID=22029 PPID=22023 depth=3 range=[2500,4999] time=1776915463.199582
END PID=22030 PPID=22024 depth=3 range=[7500,9999] time=1776915463.199608
END PID=22031 PPID=22025 depth=3 range=[10000,12499] time=1776915463.199723
END PID=22033 PPID=22025 depth=3 range=[12500,14999] time=1776915463.199746
END PID=22023 PPID=22021 depth=2 range=[0,4999] time=1776915463.199774
END PID=22024 PPID=22021 depth=2 range=[5000,9999] time=1776915463.199782
START PID=22034 PPID=22026 depth=3 range=[17500,19999] time=1776915463.199843
END PID=22025 PPID=22022 depth=2 range=[10000,14999] time=1776915463.199932
END PID=22021 PPID=22020 depth=1 range=[0,9999] time=1776915463.199996
END PID=22034 PPID=22026 depth=3 range=[17500,19999] time=1776915463.200103
END PID=22032 PPID=22026 depth=3 range=[15000,17499] time=1776915463.200222
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
PROC_START pid=41115 ppid=41113 depth=0 l=0 r=19999 ts=1777074730.331155
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
PROC_START pid=41118 ppid=41116 depth=2 l=0 r=4999 ts=1777074730.333202
PROC_START pid=41119 ppid=41117 depth=2 l=10000 r=14999 ts=1777074730.333253
PROC_START pid=41120 ppid=41116 depth=2 l=5000 r=9999 ts=1777074730.333499
PROC_START pid=41121 ppid=41117 depth=2 l=15000 r=19999 ts=1777074730.333522
PROC_START pid=41122 ppid=41118 depth=3 l=0 r=2499 ts=1777074730.333905
PROC_START pid=41123 ppid=41119 depth=3 l=10000 r=12499 ts=1777074730.334001
PROC_START pid=41124 ppid=41121 depth=3 l=15000 r=17499 ts=1777074730.334220
PROC_START pid=41125 ppid=41120 depth=3 l=5000 r=7499 ts=1777074730.334244
PROC_START pid=41127 ppid=41119 depth=3 l=12500 r=14999 ts=1777074730.334636
PROC_START pid=41126 ppid=41118 depth=3 l=2500 r=4999 ts=1777074730.334760
PROC_START pid=41128 ppid=41121 depth=3 l=17500 r=19999 ts=1777074730.334799
PROC_START pid=41129 ppid=41120 depth=3 l=7500 r=9999 ts=1777074730.334870
PROC_END pid=41123 ppid=41119 depth=3 l=10000 r=12499 ts=1777074730.336351
PROC_END pid=41127 ppid=41119 depth=3 l=12500 r=14999 ts=1777074730.336705
PROC_END pid=41124 ppid=41121 depth=3 l=15000 r=17499 ts=1777074730.336857
PROC_END pid=41129 ppid=41120 depth=3 l=7500 r=9999 ts=1777074730.336864
PROC_END pid=41125 ppid=41120 depth=3 l=5000 r=7499 ts=1777074730.337630
PROC_END pid=41119 ppid=41117 depth=2 l=10000 r=14999 ts=1777074730.337559
PROC_END pid=41128 ppid=41121 depth=3 l=17500 r=19999 ts=1777074730.337974
PROC_END pid=41121 ppid=41117 depth=2 l=15000 r=19999 ts=1777074730.338710
PROC_END pid=41120 ppid=41116 depth=2 l=5000 r=9999 ts=1777074730.338724
PROC_END pid=41117 ppid=41115 depth=1 l=10000 r=19999 ts=1777074730.339777
PROC_END pid=41122 ppid=41118 depth=3 l=0 r=2499 ts=1777074730.340717
PROC_END pid=41126 ppid=41118 depth=3 l=2500 r=4999 ts=1777074730.340948
PROC_END pid=41118 ppid=41116 depth=2 l=0 r=4999 ts=1777074730.341717
PROC_END pid=41116 ppid=41115 depth=1 l=0 r=9999 ts=1777074730.342666
PROC_END pid=41115 ppid=41113 depth=0 l=0 r=19999 ts=1777074730.343971
+29 -45
View File
@@ -28,17 +28,33 @@ std::string now() {
return oss.str();
}
/* ========= ONLY MODIFIED PART ========= */
void log_start(int l, int r, int depth) {
std::cout << "START PID=" << getpid() << " PPID=" << getppid() << " depth=" << depth
<< " range=[" << l << "," << r << "] time=" << now() << '\n'
std::cout
<< "PROC_START"
<< " pid=" << getpid()
<< " ppid=" << getppid()
<< " depth=" << depth
<< " l=" << l
<< " r=" << r
<< " ts=" << now()
<< '\n'
<< std::flush;
}
void log_end(int l, int r, int depth) {
std::cout << "END PID=" << getpid() << " PPID=" << getppid() << " depth=" << depth
<< " range=[" << l << "," << r << "] time=" << now() << '\n'
std::cout
<< "PROC_END"
<< " 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) {
std::vector<int> temp;
@@ -55,20 +71,14 @@ void merge_range(int* arr, int l, int m, int r) {
}
}
while (i <= m) {
temp.push_back(arr[i++]);
}
while (j <= r) {
temp.push_back(arr[j++]);
}
while (i <= m) temp.push_back(arr[i++]);
while (j <= r) temp.push_back(arr[j++]);
std::copy(temp.begin(), temp.end(), arr + l);
}
void local_sort(int* arr, int l, int r) {
if (l >= r) {
return;
}
if (l >= r) return;
const int m = l + (r - l) / 2;
local_sort(arr, l, m);
@@ -137,19 +147,11 @@ bool parse_positive_int(const char* value, int& out) {
try {
size_t consumed = 0;
const int parsed = std::stoi(value, &consumed);
if (value[consumed] != '\0') {
return false;
}
if (parsed <= 0) {
return false;
}
if (value[consumed] != '\0') return false;
if (parsed <= 0) return false;
out = parsed;
return true;
} catch (const std::invalid_argument&) {
return false;
} catch (const std::out_of_range&) {
return false;
}
} catch (...) { return false; }
}
} // namespace
@@ -183,30 +185,12 @@ int main(int argc, char* argv[]) {
std::mt19937 rng(std::random_device{}());
std::uniform_int_distribution<int> dist(0, 99999);
for (int i = 0; i < n; ++i) {
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";
for (int i = 0; i < n; ++i) arr[i] = dist(rng);
parallel_sort(arr, 0, n - 1, 0, max_depth);
std::cout << "\nAfter:\n";
for (int i = 0; i < std::min(n, kPreviewCount); ++i) {
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");
}
if (shmdt(arr) < 0) std::perror("shmdt");
if (shmctl(shmid, IPC_RMID, nullptr) < 0) std::perror("shmctl IPC_RMID");
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 |