diff --git a/CHANGELOG.md b/CHANGELOG.md index 17cf85e..77d2844 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,28 @@ --- +## 2026-05-08 + +### [merge] Gitea s-canvas 원격(raw upload, 184185c)과 로컬 lint+Phase 0 history 통합 + +- **상황**: 원격 `https://gitea.hmac.kr/HYUNJUNGLEE/s-canvas.git` 에 사용자가 site에서 raw upload 한 1회 commit (`184185c`)이 존재. 로컬은 `53d8b53` → `b9342f6` (import + iter1~7 lint cleanup) → `e9cc6bf` (Phase 0 of expert feedback) history. **공통 조상 없음 (unrelated histories)**. +- **분석**: 원격에만 있는 파일 0개 (원격은 로컬의 부분집합). 양쪽 다 있고 내용 다른 파일 29개 (raw upload vs lint-applied 버전). 로컬에만 있는 파일 80+ (Phase 0 산출물 + workspace/`_unused/` 등). +- **전략**: `git merge --allow-unrelated-histories -X ours`. 충돌 시 로컬 우선으로 lint cleanup 보존. +- **결과**: 머지 commit `8c6d7f0`. 자동 머지된 31파일 중 README.md 만 실질 변경 (로컬 0줄 → 원격 404줄 README 흡수 — 빈 파일 vs 내용있음은 `-X ours` 적용 외 단순 합병). 나머지 source/config 28개는 로컬 lint 버전 유지. +- **푸시**: 머지 후 fast-forward push 가능. 원격 history 손실 없이 통합. + +### [feat] `harness/perf.py` 신규 — ms 단위 wall/CPU instrumentation (#11 scaffold) + +- **신규 파일**: `harness/perf.py` (54 LOC) +- **사용자 피드백 #11**: "로딩이 오래 걸리는 부분(위성지도 결합·구조물 빌드 시 등)은 CPU 이용률이 대폭 증가하는 프로세스를 ms 단위로 추적해서 원인을 규명하고 최적화하는 조치 필요". +- **API**: + - `perf_block(label)` — 컨텍스트 매니저. `with perf_block("XYZ tiles"): ...` 형태로 블록 실행 시간(wall + CPU)을 ms 단위로 측정. + - `set_perf_log(callable)` — 외부 sink 등록 (예: `set_perf_log(app.log)` 시 GUI 로그 패널에도 표시). +- **출력 형식**: `[PERF] {label}: wall={NNN}ms cpu={NNN}ms ({CPU|I/O/Net}-bound)`. `cpu/wall > 0.5` 면 CPU-bound로 분류. +- **상태**: scaffold만 추가. **scanvas_maker.py wire는 다음 세션** — Phase C TIN densify (line ~4430), 위성 타일 다운로드 (line ~5383), capture pipeline (line ~5864) 3개 핫스팟에 `with perf_block(...)` 래핑 예정. 현재는 dead module (이번 세션은 prompt-injection 분류로 인한 하니스 차단으로 wire 미완). + +--- + ## 2026-04-28 ### [fix] 화면비 버튼이 텍스트만 떠서 안 보이는 문제 — vtkButtonWidget 로 교체 diff --git a/harness/perf.py b/harness/perf.py new file mode 100644 index 0000000..864d16c --- /dev/null +++ b/harness/perf.py @@ -0,0 +1,65 @@ +"""S-CANVAS perf instrumentation — ms 단위 wall/CPU 시간 측정. + +피드백 #11: "로딩이 오래 걸리는 부분(위성지도 결합·구조물 빌드 시 등)은 +CPU 이용률이 대폭 증가하는 프로세스를 ms 단위로 추적해서 원인을 규명하고 +최적화하는 조치 필요" + +사용: + from harness.perf import perf_block, set_perf_log + + set_perf_log(app.log) # GUI 로그에 함께 기록 (옵션) + + with perf_block("XYZ tiles 5x5"): + download_tiles(...) + +출력: + [PERF] XYZ tiles 5x5: wall=2540.3ms cpu=120.1ms (I/O/Net-bound) + +판별: cpu/wall > 0.5 → CPU-bound, 그 외 → I/O/Net-bound (GIL 풀린 시간 비율). +""" +from __future__ import annotations + +import logging +import time +from collections.abc import Callable +from contextlib import contextmanager +from typing import Optional + +_log_callable: Optional[Callable[[str], None]] = None +_logger = logging.getLogger("scanvas.perf") + + +def set_perf_log(fn: Callable[[str], None] | None) -> None: + """app.log 등 외부 sink로 perf 라인 라우팅. None이면 logger 만.""" + global _log_callable # noqa: PLW0603 (module-level singleton) + _log_callable = fn + + +def _emit(line: str) -> None: + _logger.info(line) + if _log_callable is not None: + try: + _log_callable(line) + except Exception: # noqa: BLE001 (로그 sink 실패가 측정 흐름을 끊으면 안 됨) + pass + + +@contextmanager +def perf_block(label: str): + """블록 단위 wall-clock + CPU 시간을 한 줄로 출력. + + Args: + label: 출력 prefix (예: "TIN densify Phase C", "capture x3"). + + 측정 단위는 ms. CPU-bound vs I/O/Net-bound를 cpu/wall 비율로 거칠게 분류. + """ + t_wall = time.perf_counter() + t_cpu = time.process_time() + try: + yield + finally: + dt_wall = (time.perf_counter() - t_wall) * 1000 + dt_cpu = (time.process_time() - t_cpu) * 1000 + ratio = dt_cpu / dt_wall if dt_wall > 1e-3 else 0.0 + kind = "CPU" if ratio > 0.5 else "I/O/Net" + _emit(f"[PERF] {label}: wall={dt_wall:.1f}ms cpu={dt_cpu:.1f}ms ({kind}-bound)")