- `docs/` 를 .gitignore 에서 빼 git 추적 대상으로 전환 (위키·완료 이력·검증 기록) - `docs/raw/PLAN.md` · `docs/raw/OWNERS.md` 를 저장소 최상위로 이동 후 .gitignore 에 등록 — 창끼리 공유하되 저장소에는 안 올리는 장부 - 살아 있는 경로 참조 7개 파일 정정 (아카이브 107건은 그때 사실이라 그대로 둠) - graphify 날짜별 산출물(`docs/wiki/graphify-out/20*/`) 제외 — `graphify update` 가 다시 만듦 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
13 KiB
유역 속도 개선 — 안 하기로 한 갈래 셋 (보관본)
2026-09-07 사용자 판단으로 종료 — 「속도개선은 이제 안해도 될것같아. 충분히 빨라. 안한건 계획서에 삭제하고 항목 완료처리하자. 필요시 나중에 다시 하겠음.」
[확인] 한 번이 293초 → 약 90초가 된 상태에서 멈춘 것이며, 아래 셋은 그 뒤로 더 줄이려던
갈래다. 설계·실측이 다 되어 있으므로 다시 꺼낼 때 여기서부터 이어가면 된다.
계획서(docs/raw/PLAN.md) 0-11 에서 이리로 옮겼다 — 계획서에는 실측 표만 남겼다.
- (보류) 🔴 다음 병목 —
expand_by_red_boundary. 2026-09-07 사용자가 목표를 구조물·계획노선 쪽으로 돌려 유역 속도 작업은 여기서 멈춤. 아래는 그때까지의 기록. 원래 102초(전체의 85%)였고 EDT 타일·등고선 캐시로 줄인 상태임. 확장 9회, 최종 셀 1,352,325개.-
9회 중 7회가 격자를 넓힘 (로그 실측) — 1·2회차만 여유(
_pad_spec, band_cells×2 = 100칸) 안에서 끝나고, 3회차부터 매번band_cells(50칸)씩 커짐: 745×1035 → 795 → 845×1085 → 895×1135 → 945×1185 → 995×1235 → 1045 → 1095×1235. 격자가 커지면descent재사용 조건(grown_spec == current,Expand.py:159)이 깨져build_contour_descent를 7번 통째로 다시 만듦. -
그 안은
distance_transform_edt를 등고 단계마다 한 번씩 돎(..._Descent.py:157~167). 보조 창 계측에 따르면 단계가 약 100개 — 격자 1,352,325셀 × 100회 = 회차 1번에만 1.35억 셀-연산. 이것이 7번 돎. -
고칠 길 둘 — 갈림길은 계측이 정함 ⓐ EDT 창 좁히기(결과 보존) — 쓰는 값은
members(그 밴드 셀)뿐이고 한 단 아래 등고선은 보통 수십 셀 안에 있음(주곡선 5m·셀 1m).members바운딩박스를 여유만큼 넓힌 창에서만 EDT 를 돌리고, 나온 최대 거리가 여유에 닿으면 그 단계만 전체로 다시 돎 → 결과가 반드시 같음. 격자를 안 키우므로 아래 ⓑ 의 위험도 없음. ⓑ 여유를 처음부터 크게 잡기 — 빠르지만 ⚠ 결과가 미세하게 달라짐.build_contour_descent의 EDT 가 격자 전체를 보므로, 격자가 커지면 밖에 있던 등고선이 시야에 들어와 가장자리 셀의 밴드 표고가 바뀜 → 유역 면적·관경이 움직임. 수량에 닿으므로 사용자 확인 전에는 안 감. -
계측으로 갈림길 확정 (2026-09-07, 보조 창 커밋
5c22c367) — ⓐ 가 맞음.조각 초 [확인] 116초 중 밴드별 하강거리 EDT 50.4 43% classify_flow25.7 22% 등고선 굽기( rasterize_contours)16.3 14% 1차 영역 4.4 4% _prepare4.9 4% B06 확정 2.5 2% 나머지 6 5% 방향장 1회 = 6.3s(745×1035) ~ 10.4s(1095×1235)이고 그중 EDT 가 66
75%. 8회 합계 69.4s. 시간은 셀 수가 아니라 격자 bbox 에 선형(8·9회차는 셀이 거의 안 늘었는데도 1314초). 재사용과 무관하게 도는 넷은 회차당 2.6s = 10회 25.7s인데 사실상 전부classify_flow임. 검산 69.4 + 25.7 = 95.1 ≈ 실측 95.8 ✅ -
ⓐ 구현·검증 끝(보조 창 커밋
56d5fb26) — 밴드별 EDT 10.8s → 2.9s(3.7배), 값 완전 동일.- 첫 시도(밴드 바운딩박스 하나로 창 씌우기)는 안 통했음 —
analyze_domain이build_contour_descent에domain을 안 넘겨inside가 격자 전체가 되고, 밴드가 격자 전역에 흩어져 바운딩박스가 사실상 격자 전체였음. - 그래서 타일로 쪼갬 — 밴드 셀을 타일로 나눠 타일마다 창을 씌우고, 타일별로 같은 폴백 장치(창 최대거리가 여유에 닿으면 그 타일만 전체 격자로). 채택값 타일 256 · 여유 32 (폴백 9/91). 근거표는 그 파일 주석에 남김.
- 검증 — 거리·목표행·목표열 91단 전부
np.array_equal, 옛 코드를 별도로 적재해build_contour_descent결과(band_elevation·valid·receiver·step_length·azimuth·levels) 전부 동일. 시험tmp/tests/test_descent_edt_window.py11건. - ⚠ 함정 —
distance_transform_edt(return_indices=True)가 주는 좌표는 창 좌표라 전체 격자 좌표로 옮겨 적어야 함. 안 하면 시간은 줄고 흐름 경로만 틀어져 빨라졌다고 착각하기 쉬움. 그래서 검증 기준을 「배열이 완전히 같은가」로 둠.
- 첫 시도(밴드 바운딩박스 하나로 창 씌우기)는 안 통했음 —
-
- 지금 남은 그림 ([확인] ≈ 100초 기준) — 확장 78
89s(88%) 안에서 방향장 재생성 8회 ≈ 50s(등고선 굽기 ≈ 19s · 밴드 EDT ≈ 16s · 나머지 ≈ 15s) ·7s · B06 확정 4.4s · solve 2.4s.classify_flow10회 ≈ 28s. 그 밖_prepare6s · 1차 영역 2 - (보류) ②
classify_flow(≈28s) — 재사용과 무관하게 회차마다 도는 유일한 큰 조각. 2026-09-07 사용자가 목표를 구조물·계획노선 쪽으로 돌려 유역 속도 작업은 여기서 멈춤. [확인] 이 293초 → 약 90초가 된 상태로 두고, 더 줄이는 것은 나중에 판단.- 자리 —
_walk_from(..._Watershed_Flow.py:394)이 셀 1,352,325개를 파이썬 루프로 훑음. 셀마다 수신 셀을 따라가는 사슬이라 전체로는 O(N) 이지만 파이썬이라 회차당 2.6초. - 고칠 법(설계 확정) — 이건 「함수형 그래프에서 뿌리 찾기」임. 각 셀은 수신 셀 하나만
가리키고, 사슬은 ⓐ 흡수 셀(도로·세류 → 적색) ⓑ 싱크(자기 자신 → 파랑) ⓒ 해석영역 밖
(→ 파랑) 셋 중 하나에서 끝남. 그러니 포인터 더블링(
nxt = nxt[nxt]를 고정점까지, 약 log₂N ≈ 20회)으로 전 셀의 뿌리를 한 번에 구하고 그 뿌리의 판정을 뿌리면 됨. numpy 가져오기 20회 × 1.35M ≈ 0.1초 — 25배 기대. - 순서 무관함을 확인해 둠 — 겉보기에 순서에 걸리는 곳은
:430의if not valid[following] and state[following] != 2하나뿐인데, 무효 셀이state==2가 되는 경우는 세류 선확정 셀뿐이고 그건 시작 전에 못박힘. 무효 셀은path에 절대 안 들어감(들어가기 전에state==2로 break). 그래서 단계 함수가 정적이고 벡터화가 정확함. 순환은 원래 코드도 파랑으로 처리하므로 더블링 반복 상한에 걸린 것을 파랑으로 두면 같음. - ⚠ 막힌 곳 하나 — 진단 카운터 둘.
outer_seeds·interior_seeds는 「1단계(최외곽 출발)가 몇 셀을 판정했나 / 2단계가 몇 셀을 판정했나」인데, 한 번에 푸는 방식에는 단계가 없음. 이 값을 그대로 내려면 「최외곽에서 출발한 사슬이 지나간 셀 집합」이 필요하고, 그건 함수형 그래프에서 조상 집합 구하기라 더블링으로는 안 나옴(같은 뿌리·같은 깊이여도 다른 가지일 수 있음). 닫힘 계산은 사슬 길이만큼 반복해야 해서 이득이 사라짐. - 쓰는 곳 확인 — 두 값은 응답 페이로드와 TS 타입에만 있고 계산에 쓰는 곳이 없음
(
B04_PreProcess_Api_Fetch.ts:397). 순수 진단값임. - 그래서 결정 — 값을 바꾸는 일이라 혼자 처리하지 않음. 할 때는 ①
reaches·analyzed·direction이np.array_equal로 같은지 증명하고 ② 두 카운터는 뜻이 바뀜을 사용자에게 알린 뒤(또는 필드를 없애기로 하고) 진행할 것.
- 자리 —
- 안 하기로 한 것 ③ 방향장 자체를 옛 격자에서 옮겨 붙이기 — 이득은 가장 크나 코드·위험도
가장 큼. 위 둘을 끝내고 숫자를 다시 본 뒤 판단.
ode_modulesorest-road-webapp
→ **저장소 루트 자신** (npm 이 로컬 패키지를 링크하며 만든 것). 리로더가 B07 을 훑다가 그리로 되돌아가venv·storage` 를 다시 훑고 또 되감겼음.- 실측 — 감시 폴더를
rglob하면 파일 486,809개, 한 바퀴 1,045초. PowerShell 로 세면config4개·B0723개뿐임. 파이썬rglob은 정션을 따라 들어가고 PowerShell 은 안 따라가서 눈으로는 안 보였음. - 갈래 실험 — 리로드 끔 0% / 켬 64% 로 갈렸음. 「앱이 먹는다」로 두 번 오진한 것은 프로세스 역할이 뒤바뀌어 보였기 때문임(띄운 것은 껍데기, 자식이 리로더, 손자가 서버).
- 고침 —
main.py의_reload_dirs가 ⓐ 소스 폴더만 보고(351db312) ⓑnode_modules를 품은 폴더를 빼고(e7d30327·7a1d7db6) ⓒ 링크(정션) 폴더를 통째로 건너뛰게(70b25a5c). CPU 85% → 18%. ⓒ 로 정션이 또 생겨도 재발 안 함. - 부작용 —
main.py와config/를 고치면 자동 리로드가 안 됨. 손으로 재시작할 것. - 남은 18% 는 감시 탓으로 보기 어려움(감시 대상 파이썬 143개) — 급하지 않아 남겨 둠.
- 아직 안 한 것:
watchfiles설치(이벤트 방식, 거의 0%) — 사용자 허락 대기. - 창 둘이 각각 그러니 기기가 늘 140% 눌린 채임. 속도 계측이 회차마다 3배씩 흔들린(1차 영역 2.3s vs 29.4s) 진짜 배경으로 보임.
- 확인한 것 — 새로 띄운 직후에도, 몇 분 놀린 뒤에도 **63~74%**로 일정함. 로그는 한 줄도 안 늘어남. 메모리는 260 → 430MB 로 서서히 늚.
- 범인은 감시(리로더)가 아님 — 감시 프로세스는 0%, CPU 를 먹는 것은 앱 프로세스임
(
Get-NetTCPConnection이 가리키는 쪽이 앱 자식임을 부모-자식으로 확인). - 배경 태스크 셋(세션 정리 1시간 · 리소스 계측 2분 · 임시파일 정리 6시간)은 전부
sleep간격이 길어 후보가 아님. - 스택을 떠 봤으나(리로드 없이 8099 로 따로 띄워 60초 뒤
faulthandler) 스레드 3개뿐이고 메인은run_forever에서 대기 중이라 파이썬 층에서는 도는 것이 안 보였음. → C 확장이나 이벤트 루프 폴링 쪽일 가능성.py-spy가 있으면 몇 초면 잡힐 자리인데 지금 환경에 없음. 설치 여부는 사용자 판단. - 곁가지 하나는 고침(커밋
351db312+7a1d7db6) — 자동 리로드가storage(27GB)·venv(파이썬 파일만 7,530개)·node_modules까지 0.25초마다 훑고 있었음. 파이썬이 사는 폴더만, 그중에서도node_modules를 품지 않은 것만 보게 함. 근거 — 루트 전체 훑기는 이 기기에서 300초에도 한 줄을 못 뱉음(옛 방식이 0.25초 주기를 지킬 수 없었다는 뜻). 다만 기기가 계속 눌려 있어 정확한 전후 수치는 못 냈음. ⚠ 이것이 70% 를 고치지는 못했음. 감시 낭비만 걷어낸 것임. (부작용 —main.py와config/를 고칠 때는 손으로 재시작할 것. 둘 다 자주 고치는 자리가 아님.)
- 실측 — 감시 폴더를
- ⚠ 측정 함정(2026-09-07 실사고) — 내 8000 이 옛 코드로 돌고 있었음. uvicorn
StatReload 가
..._Watershed_Stream.py변경을 안 물어, 고친 뒤에 잰 [확인] 이 488초로 나왔음(고치기 전 293초보다도 나쁨). 수정 로그가 한 줄도 안 찍힌 것으로 발각. 속도를 재기 전에 ① 백엔드를 확실히 재시작하고 ② 그 수정의 로그가 실제로 찍히는지 먼저 볼 것. - (보류) [확인] 이 유역을 안 기다리게 미루기 — 보조 창이 설계까지 마쳐 둔 안.
재측정이 여전히 느릴 때만 꺼냄. 요지: 기본 관 자리(
_base_pipes)는 유역 해석과 무관하나build_detail(common_util_drainage_detail.py:184)이read_road_routing없으면 404 라 통째로 막힘 → 관 목록만 담은 얕은 갈래를 하나 두고,_base_pipes를 공용으로 옮겨 한 벌을 같이 부르게 함.pipe_points.json에pending표식 하나. ⚠ 위험 — 배경 계산 중 사용자가 관을 만지면confirmed_chainages갈래를 타place_pipes를 아예 안 불러 300m 규칙이 영구 미적용됨. 막으려면 배경 채우기를 덮어쓰기가 아니라 합치기로 해야 함(보조 창 권고). 보충 관이 늘면 측점 재생성·B06 확정이 각각 1회씩 더 필요함. 조사 결론(2026-09-07) — 관 자리(_base_pipes)는 「도로 × 세류선 교차점」이라 무거운 흐름 해석과 무관함이 확인됨. 유역을 배경으로 미루면 [확인] 이 7초대까지 떨어질 수 있음. 그러나 위 ⚠ 위험 때문에 지금은 안 감 — 대신 유역 자체를 줄이는 쪽(0-11 ①②)으로 감. (윗줄과 같은 항목이라 하나로 합침.) - ⚠ 속도개선 코드(코리도 캐시·묶음쓰기·
recompute_server_side)는 계측 단계에서 건드리지 않음.