165 lines
5.5 KiB
Python
165 lines
5.5 KiB
Python
#!/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()
|