성능 테스트 설계 - 100-hours-a-week/5-yeosa-wiki GitHub Wiki
1. 성능 테스트 설계 요약
a. 테스트 목적
- 모델이 이미지 100장을 처리할 때의 실행 시간, CPU 사용량, **메모리 사용량, (GPU 사용량)**을 측정
- 대상 모델을 CPU 환경에서의 실제 서빙 성능 관점에서 평가
b. 측정 환경
- 기기 사양: Apple M2 Pro(10 코어 (6 성능 및 4 효율)), RAM 16GB
- 실행 방식: Python3로 실행되는 서브프로세스(
subprocess.Popen
) 기반 실행- 메인 프로세스와 분리된 리소스 사용량 측정을 위함
- 측정 신뢰성을 높이기 위한 구조
- 측정 시작 시점을 사용자 입력으로 수동 제어
- 모델 로딩, 초기화, 데이터 준비 등 사전 처리 과정에서 발생하는 리소스 소비를 측정 대상에서 제외
- 실제 서비스에서 중요한 "모델 추론(inference)" 구간의 리소스 사용량만 정확히 측정
c. 측정 방식
- 실행 시간:
time.time()
으로 시작~종료 시간 차이 계산 - CPU 사용량:
psutil
을 이용하여 서브프로세스의cpu_percent
를 0.1초 간격으로 샘플링 - 메모리 사용량: RSS 기반
memory_info().rss
를 MB 단위로 측정 - GPU 사용량(사용 시):
GPUtil.getGPUs()
를 통해 GPU 상태를 주기적으로 조회- GPU 연산 부하율 (
load
): 0.0 ~ 1.0 범위 값을 백분율(%)로 변환하여 GPU 사용률 계산 - GPU 메모리 사용량 (
memoryUsed / memoryTotal
): 현재 사용 중인 메모리와 전체 메모리(MB)를 함께 출력
d. 모니터링 구조
monitor_subprocess(pid)
: 주어진 프로세스 ID에 대해 주기적으로 CPU/메모리 사용량 수집- Thread를 이용한 비동기 모니터링: 메인 프로세스가 기다리는 동안 백그라운드로 리소스 모니터링 수행
e. 평균 계산 방식
- 총 5회 테스트 반복
- 각 반복에서의 평균 CPU, 최대 CPU, 평균 메모리, 최대 메모리, 실행 시간 등을 수집 후 종합
2. 성능 테스트 코드
-
CPU, RAM
import time import psutil import subprocess import threading # 주어진 프로세스 ID(pid)를 주기적으로 모니터링하여 # CPU 사용량 (%)과 메모리 사용량 (MB)을 기록하는 함수 def monitor_subprocess(pid, interval=0.1): try: proc = psutil.Process(pid) # 해당 PID의 프로세스 객체 가져오기 except psutil.NoSuchProcess: return [], [] # 프로세스가 없으면 빈 리스트 반환 # 초기 CPU 측정값 세팅 (baseline 설정, 첫 호출은 항상 0) proc.cpu_percent(interval=None) cpu_usages = [] # CPU 사용량 기록 리스트 mem_usages = [] # 메모리 사용량 기록 리스트 # 프로세스가 실행 중인 동안 반복 while proc.is_running(): try: # interval(기본 0.1초)마다 CPU 사용률 측정 cpu = proc.cpu_percent(interval=interval) # RSS(Resident Set Size)를 통해 메모리 사용량 측정 (단위: MB) mem = proc.memory_info().rss / (1024 ** 2) # 수집된 값이 유효하면 리스트에 추가 if cpu is not None: cpu_usages.append(cpu) if mem is not None: mem_usages.append(mem) except (psutil.NoSuchProcess, psutil.AccessDenied): break # 프로세스가 종료되었거나 접근 권한이 없을 경우 종료 return cpu_usages, mem_usages # 측정 대상 Python 스크립트를 실행하고 모니터링하는 메인 함수 def run_and_monitor(script_path): print(f"🔧 Running script: {script_path}") # subprocess를 통해 별도 프로세스로 스크립트 실행 process = subprocess.Popen(["python3", script_path]) # 모니터링 시작 전에 1초 대기 (프로세스 안정화 목적) time.sleep(1) # 수동으로 측정 시작 시점을 지정할 수 있도록 대기 # → 모델 로딩 등 초기화 과정에서 발생하는 리소스 사용은 제외하고, 순수한 "추론(inference)" 구간에 대한 CPU/RAM 측정을 위함 input('측정 시작 전 Enter 키를 누르세요') start_time = time.time() # 측정 시작 시간 기록 result = {} # 모니터링 결과 저장 딕셔너리 # 모니터링 스레드 함수 정의 def monitor(): result['cpu'], result['mem'] = monitor_subprocess(process.pid) # 모니터링 스레드 실행 (main과 병렬) monitor_thread = threading.Thread(target=monitor) monitor_thread.start() process.wait() # subprocess가 종료될 때까지 대기 monitor_thread.join() # 모니터링 스레드 종료까지 대기 end_time = time.time() # 측정 종료 시간 기록 elapsed = end_time - start_time # 전체 실행 시간 계산 # 결과 리스트에서 평균 및 최대값 계산 cpu_usages = result.get('cpu', []) mem_usages = result.get('mem', []) avg_cpu = sum(cpu_usages) / len(cpu_usages) if cpu_usages else 0 max_cpu = max(cpu_usages) if cpu_usages else 0 avg_mem = sum(mem_usages) / len(mem_usages) if mem_usages else 0 max_mem = max(mem_usages) if mem_usages else 0 # 최종 결과 출력 print(f"\nElapsed Time: {elapsed:.2f} seconds") print(f"CPU Usage - Average: {avg_cpu:.2f}% | Peak: {max_cpu:.2f}%") print(f"Memory Usage - Average: {avg_mem:.2f} MB | Peak: {max_mem:.2f} MB") # 예시 실행: clip_test.py 파일에 대해 성능 측정 수행 run_and_monitor("clip_test.py")
-
GPU
import time import shutil import os # GPU 정보 수집을 위한 GPUtil 모듈 임포트 (없으면 자동 설치) try: import GPUtil except ImportError: os.system("pip install -q GPUtil") # 조용히 설치 import GPUtil # GPU 상태를 주기적으로 모니터링하는 함수 def monitor_gpu(interval=10): while True: try: # 시스템에 연결된 GPU 목록을 가져옴 (여러 개일 수 있음) gpus = GPUtil.getGPUs() if gpus: # 첫 번째 GPU 정보만 사용 gpu = gpus[0] # GPU 이름 (예: NVIDIA RTX 3090) name = gpu.name # GPU 사용률 (0.0 ~ 1.0, 백분율로 변환) load = gpu.load * 100 # GPU 메모리 사용량 (단위: MB) used_memory = gpu.memoryUsed total_memory = gpu.memoryTotal # 결과 출력 print( f"[GPU MONITOR] {name} | Load: {load:.1f}% | " f"Memory: {used_memory}/{total_memory} MB" ) else: print("[GPU MONITOR] No GPU detected.") except Exception as e: print(f"[GPU MONITOR] Error occurred: {e}") # 지정된 시간 간격 후 다시 측정 time.sleep(interval) # 예시 실행 (10초 간격으로 GPU 상태 출력) monitor_gpu(interval=10)