Files
ExperionCrawler/test_pid_bottleneck_analysis.py
2026-05-08 17:22:10 +09:00

165 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""P&ID 파이프라인 병목 분석 성능 테스트"""
import time
import json
import sys
import os
# mcp-server 디렉토리를 Python 경로에 추가
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'mcp-server'))
from pipeline.extractor import PidGeometricExtractor
from pipeline.topology import PidTopologyBuilder
DXF_FILE = "futurePlan/End-to-End P&ID Graph Pipeline/No-10_Plant_PID.dxf"
OUTPUT_GEO = "/tmp/pid_test_geo.json"
OUTPUT_TOPO = "/tmp/pid_test_topo.json"
def test_phase1_extraction():
"""Phase 1: 기하학적 추출 성능 테스트"""
print("=" * 60)
print("Phase 1: 기하학적 추출 테스트")
print("=" * 60)
# DXF 로드 시간 측정
start = time.time()
extractor = PidGeometricExtractor(DXF_FILE)
load_time = time.time() - start
print(f"DXF 파일 로드 시간: {load_time:.3f}")
# 추출 시간 측정
start = time.time()
output_path = extractor.extract_and_save(OUTPUT_GEO)
extract_time = time.time() - start
print(f"엔티티 추출 시간: {extract_time:.3f}")
# 결과 확인
with open(output_path, 'r') as f:
geo_data = json.load(f)
print(f"추출된 엔티티 수: {len(geo_data)}")
# 엔티티 타입별 분포
type_counts = {}
for item in geo_data:
etype = item['entity_type']
type_counts[etype] = type_counts.get(etype, 0) + 1
print("\n엔티티 타입별 분포:")
for etype, count in sorted(type_counts.items(), key=lambda x: -x[1]):
print(f" {etype}: {count} ({count/len(geo_data)*100:.1f}%)")
total_time = load_time + extract_time
print(f"\nPhase 1 총 시간: {total_time:.3f}")
return geo_data
def test_phase2_topology(geo_data):
"""Phase 2: 위상 빌더 성능 테스트"""
print("\n" + "=" * 60)
print("Phase 2: 위상 빌더 테스트")
print("=" * 60)
# 초기화 시간 측정
start = time.time()
builder = PidTopologyBuilder(geo_data)
init_time = time.time() - start
print(f"위상 빌더 초기화 시간: {init_time:.3f}")
print(f"동적 스케일링 설정: dist_threshold={builder.config['dist_threshold']:.1f}, tag_threshold={builder.config['tag_threshold']:.1f}")
# 그래프 빌드 시간 측정
start = time.time()
builder.build_graph()
build_time = time.time() - start
print(f"그래프 빌드 시간: {build_time:.3f}")
# 그래프 통계
print(f"\n그래프 통계:")
print(f" 노드 수: {builder.G.number_of_nodes()}")
print(f" 엣지 수: {builder.G.number_of_edges()}")
# 검증
validation = builder.validate_topology()
print(f" 고립 노드 수: {len(validation['isolated_nodes'])}")
# 저장 시간 측정
start = time.time()
builder.save_graph(OUTPUT_TOPO)
save_time = time.time() - start
print(f"그래프 저장 시간: {save_time:.3f}")
total_time = init_time + build_time + save_time
print(f"\nPhase 2 총 시간: {total_time:.3f}")
return builder
def analyze_bottlenecks(geo_data, builder):
"""병목 지점 분석"""
print("\n" + "=" * 60)
print("병목 지점 분석")
print("=" * 60)
# 노드 수에 따른 복잡도 분석
num_nodes = len(geo_data)
num_tags = sum(1 for item in geo_data if item['entity_type'] in ['TEXT', 'MTEXT'])
num_lines = sum(1 for item in geo_data if item['entity_type'] in ['LINE', 'LWPOLYLINE'])
num_equipments = sum(1 for item in geo_data if item['entity_type'] not in ['TEXT', 'MTEXT', 'LINE', 'LWPOLYLINE'])
print(f"\n데이터 통계:")
print(f" 총 엔티티: {num_nodes}")
print(f" 텍스트 노드: {num_tags}")
print(f" 배관 노드: {num_lines}")
print(f" 설비 노드: {num_equipments}")
# O(n²) 연산 분석
print(f"\nO(n²) 연산 분석:")
print(f" 태그-설비 매칭: {num_tags} × {num_equipments} = {num_tags * num_equipments:,}회 거리 계산")
print(f" 배관-설비 연결: {num_lines} × {num_equipments} = {num_lines * num_equipments:,}회 거리 계산")
total_operations = num_tags * num_equipments + num_lines * num_equipments
print(f" 총 거리 계산: {total_operations:,}")
# 그래프 구조 분석
print(f"\n그래프 구조 분석:")
nodes_by_type = {}
for n, d in builder.G.nodes(data=True):
t = d.get('type', 'Unknown')
nodes_by_type[t] = nodes_by_type.get(t, 0) + 1
for t, count in sorted(nodes_by_type.items(), key=lambda x: -x[1]):
print(f" {t}: {count}개 노드")
edges_by_relation = {}
for u, v, d in builder.G.edges(data=True):
rel = d.get('relation', 'unknown')
edges_by_relation[rel] = edges_by_relation.get(rel, 0) + 1
print(f"\n엣지 관계별 분포:")
for rel, count in sorted(edges_by_relation.items(), key=lambda x: -x[1]):
print(f" {rel}: {count}개 엣지")
def main():
print("P&ID 파이프라인 병목 분석 성능 테스트")
print(f"대상 파일: {DXF_FILE}")
print()
if not os.path.exists(DXF_FILE):
print(f"오류: 파일을 찾을 수 없습니다: {DXF_FILE}")
return
# Phase 1 테스트
geo_data = test_phase1_extraction()
# Phase 2 테스트
builder = test_phase2_topology(geo_data)
# 병목 분석
analyze_bottlenecks(geo_data, builder)
print("\n" + "=" * 60)
print("테스트 완료")
print("=" * 60)
if __name__ == "__main__":
main()