makefile update: implement the csv output

This commit is contained in:
2025-12-09 01:48:09 +09:00
parent 2011104d10
commit a4b981898d

246
Makefile
View File

@@ -248,3 +248,249 @@ clean-tests: clean-inputs clean-outputs
clean:
@echo "Cleaning up $(BUILD_DIR)/..."
@rm -rf $(BUILD_DIR)
# -----------------------------------------------------------------------------
# Benchmark Target (Advanced)
# - N, M 증가 (Step)
# - 동일 조건 반복 (Repeat)
# - 유효성 검사 (Validator) 포함
# - 상세 정보(Seed, Command) CSV 기록
# -----------------------------------------------------------------------------
BENCH_TIMESTAMP = $(shell date +%Y%m%d_%H%M%S)
BENCH_CSV = $(LOG_DIR)/benchmark_results_$(BENCH_TIMESTAMP).csv
BENCH_META = $(LOG_DIR)/benchmark_results_$(BENCH_TIMESTAMP).meta
START_N ?= 10000
END_N ?= 50000
STEP_N ?= 1000
# M 계산식 (bash arithmetic expansion 문법)
M_CALC ?= n * 4
# 동일 조건 반복 횟수
REPEAT ?= 5
.PHONY: benchmark
benchmark: all $(CHK_EXE) $(LOG_DIR)
@echo "--- Starting Benchmark ---"
@echo "Data: $(BENCH_CSV)"
@echo "Meta: $(BENCH_META)"
@# 1. 메타 파일(.meta)에 실행 정보 기록
@echo "Execution Info: Date=$(BENCH_TIMESTAMP) | Host=$(shell hostname)" > $(BENCH_META)
@echo "Reproduce Command: make benchmark START_N=$(START_N) END_N=$(END_N) STEP_N=$(STEP_N) REPEAT=$(REPEAT) M_CALC='$(M_CALC)' SOL_A=$(SOL_A) SOL_B=$(SOL_B) gen=$(gen)" >> $(BENCH_META)
@# 2. CSV 파일(.csv)에는 순수 헤더만 기록 (엑셀 호환성 확보)
@echo "N,M,Iter,Seed,$(SOL_A)_Time,$(SOL_B)_Time,Gen_Cmd,Sol_A_Cmd,Sol_B_Cmd" > $(BENCH_CSV)
@bash -c ' \
export LC_ALL=C; \
TIMEFORMAT=%R; \
\
for (( n=$(START_N); n<=$(END_N); n+=$(STEP_N) )); do \
m=$$(( $(M_CALC) )); \
\
for (( r=1; r<=$(REPEAT); r++ )); do \
SEED=$$(cat /dev/urandom | tr -cd "a-zA-Z0-9" | head -c 32); \
\
TMP_IN="$(BUILD_IN_DIR)/bench_in_$(BENCH_TIMESTAMP)_$$$$.tmp"; \
TMP_OUT_A="$(BUILD_DIR)/bench_out_a_$(BENCH_TIMESTAMP)_$$$$.tmp"; \
TMP_OUT_B="$(BUILD_DIR)/bench_out_b_$(BENCH_TIMESTAMP)_$$$$.tmp"; \
\
CMD_GEN="./$(GEN_TO_RUN) -N $$n -M $$m $$SEED"; \
CMD_SOL_A="./$(SOL_A_EXE) < input"; \
CMD_SOL_B="./$(SOL_B_EXE) < input"; \
\
printf "Run: N=%-5d M=%-5d Iter=%-2d ... " $$n $$m $$r; \
\
$$CMD_GEN > $$TMP_IN; \
\
t_a=$$( { time ./$(SOL_A_EXE) < $$TMP_IN > $$TMP_OUT_A; } 2>&1 ); \
t_b=$$( { time ./$(SOL_B_EXE) < $$TMP_IN > $$TMP_OUT_B; } 2>&1 ); \
\
if ! ./$(CHK_EXE) $$TMP_IN $$TMP_OUT_A $$TMP_OUT_B > /dev/null 2>&1; then \
printf "\n[FAIL] Checker found mismatch!\n"; \
echo "Seed: $$SEED"; \
echo "Check Metafile: $(BENCH_META)"; \
exit 1; \
fi; \
\
echo "$$n,$$m,$$r,$$SEED,$$t_a,$$t_b,\"$$CMD_GEN\",\"$$CMD_SOL_A\",\"$$CMD_SOL_B\"" >> $(BENCH_CSV); \
\
echo "OK. [A: $${t_a}s] [B: $${t_b}s]"; \
\
rm -f $$TMP_IN $$TMP_OUT_A $$TMP_OUT_B; \
done; \
done \
'
@echo "--- Benchmark Complete! ---"
@echo "CSV Data: $(BENCH_CSV)"
@echo "Metadata: $(BENCH_META)"
# .PHONY: benchmark
# benchmark: all $(CHK_EXE) $(LOG_DIR)
# @echo "--- Starting Benchmark with Checker ---"
# @echo "Range: N=[$(START_N) .. $(END_N)], Step=$(STEP_N)"
# @echo "Formula: M = $(M_CALC)"
# @echo "Checker: $(CHK_EXE)"
# @echo "Output: $(BENCH_CSV)"
# @echo "N,M,Iter,Seed,$(SOL_A)_Time,$(SOL_B)_Time,Gen_Cmd,Sol_A_Cmd,Sol_B_Cmd" > $(BENCH_CSV)
# @bash -c ' \
# export LC_ALL=C; \
# TIMEFORMAT=%R; \
# \
# for (( n=$(START_N); n<=$(END_N); n+=$(STEP_N) )); do \
# m=$$(( $(M_CALC) )); \
# \
# for (( r=1; r<=$(REPEAT); r++ )); do \
# SEED=$$(cat /dev/urandom | tr -cd "a-zA-Z0-9" | head -c 32); \
# \
# # 병렬 실행을 위한 임시 파일명 설정 (Input, OutA, OutB) \
# TMP_IN="$(BUILD_IN_DIR)/bench_in_$(BENCH_TIMESTAMP)_$$$$.tmp"; \
# TMP_OUT_A="$(BUILD_DIR)/bench_out_a_$(BENCH_TIMESTAMP)_$$$$.tmp"; \
# TMP_OUT_B="$(BUILD_DIR)/bench_out_b_$(BENCH_TIMESTAMP)_$$$$.tmp"; \
# \
# CMD_GEN="./$(GEN_TO_RUN) -N $$n -M $$m $$SEED"; \
# CMD_SOL_A="./$(SOL_A_EXE) < input"; \
# CMD_SOL_B="./$(SOL_B_EXE) < input"; \
# \
# printf "Run: N=%-5d M=%-5d Iter=%-2d ... " $$n $$m $$r; \
# \
# # 1. Generator 실행 \
# $$CMD_GEN > $$TMP_IN; \
# \
# # 2. Sol A 실행 (시간 측정 + 출력 저장) \
# t_a=$$( { time ./$(SOL_A_EXE) < $$TMP_IN > $$TMP_OUT_A; } 2>&1 ); \
# \
# # 3. Sol B 실행 (시간 측정 + 출력 저장) \
# t_b=$$( { time ./$(SOL_B_EXE) < $$TMP_IN > $$TMP_OUT_B; } 2>&1 ); \
# \
# # 4. Checker 실행 (비교) \
# if ! ./$(CHK_EXE) $$TMP_IN $$TMP_OUT_A $$TMP_OUT_B > /dev/null 2>&1; then \
# printf "\n[FAIL] Checker found mismatch!\n"; \
# echo "Seed: $$SEED"; \
# echo "Input saved to: $$TMP_IN"; \
# echo "Out A saved to: $$TMP_OUT_A"; \
# echo "Out B saved to: $$TMP_OUT_B"; \
# exit 1; \
# fi; \
# \
# # 5. 통과 시 CSV 기록 \
# echo "$$n,$$m,$$r,$$SEED,$$t_a,$$t_b,\"$$CMD_GEN\",\"$$CMD_SOL_A\",\"$$CMD_SOL_B\"" >> $(BENCH_CSV); \
# \
# echo "OK. [A: $${t_a}s] [B: $${t_b}s]"; \
# \
# # 6. 임시 파일 삭제 \
# rm -f $$TMP_IN $$TMP_OUT_A $$TMP_OUT_B; \
# done; \
# done \
# '
# @echo "--- Benchmark Complete! Data saved to $(BENCH_CSV) ---"
# .PHONY: benchmark
# benchmark: all $(LOG_DIR)
# @echo "--- Starting Advanced Benchmark ---"
# @echo "Range: N=[$(START_N) .. $(END_N)], Step=$(STEP_N)"
# @echo "Formula: M = $(M_CALC)"
# @echo "Repeat: $(REPEAT) times per setting"
# @echo "Output: $(BENCH_CSV)"
# @echo "N,M,Iter,Seed,$(SOL_A)_Time,$(SOL_B)_Time,Gen_Cmd,Sol_A_Cmd,Sol_B_Cmd" > $(BENCH_CSV)
# @bash -c ' \
# export LC_ALL=C; \
# TIMEFORMAT=%R; \
# \
# for (( n=$(START_N); n<=$(END_N); n+=$(STEP_N) )); do \
# m=$$(( $(M_CALC) )); \
# \
# for (( r=1; r<=$(REPEAT); r++ )); do \
# SEED=$$(cat /dev/urandom | tr -cd "a-zA-Z0-9" | head -c 32); \
# \
# # [변경] 파일명에 타임스탬프와 PID($$)를 포함하여 충돌 방지 \
# TMP_IN="$(BUILD_IN_DIR)/bench_input_$(BENCH_TIMESTAMP)_$$$$.tmp"; \
# \
# CMD_GEN="./$(GEN_TO_RUN) -N $$n -M $$m $$SEED"; \
# CMD_SOL_A="./$(SOL_A_EXE) < input"; \
# CMD_SOL_B="./$(SOL_B_EXE) < input"; \
# \
# printf "Run: N=%-5d M=%-5d Iter=%-2d ... " $$n $$m $$r; \
# \
# $$CMD_GEN > $$TMP_IN; \
# \
# if ! ./$(VAL_EXE) < $$TMP_IN > /dev/null 2>&1; then \
# echo " [FAIL] Validator rejected input! Seed: $$SEED"; \
# rm -f $$TMP_IN; \
# exit 1; \
# fi; \
# \
# t_a=$$( { time ./$(SOL_A_EXE) < $$TMP_IN > /dev/null; } 2>&1 ); \
# t_b=$$( { time ./$(SOL_B_EXE) < $$TMP_IN > /dev/null; } 2>&1 ); \
# \
# echo "$$n,$$m,$$r,$$SEED,$$t_a,$$t_b,\"$$CMD_GEN\",\"$$CMD_SOL_A\",\"$$CMD_SOL_B\"" >> $(BENCH_CSV); \
# \
# echo "OK. [A: $${t_a}s] [B: $${t_b}s]"; \
# \
# rm -f $$TMP_IN; \
# done; \
# done \
# '
# @echo "--- Benchmark Complete! Data saved to $(BENCH_CSV) ---"
# .PHONY: benchmark
# benchmark: all $(LOG_DIR)
# @echo "--- Starting Advanced Benchmark ---"
# @echo "Range: N=[$(START_N) .. $(END_N)], Step=$(STEP_N)"
# @echo "Formula: M = $(M_CALC)"
# @echo "Repeat: $(REPEAT) times per setting"
# @echo "Validator: $(VAL_EXE)"
# @echo "Output: $(BENCH_CSV)"
# @# CSV Header 작성
# @echo "N,M,Iter,Seed,$(SOL_A)_Time,$(SOL_B)_Time,Gen_Cmd,Sol_A_Cmd,Sol_B_Cmd" > $(BENCH_CSV)
# @bash -c ' \
# export LC_ALL=C; \
# TIMEFORMAT=%R; \
# \
# # 1. N 루프 \
# for (( n=$(START_N); n<=$(END_N); n+=$(STEP_N) )); do \
# m=$$(( $(M_CALC) )); \
# \
# # 2. 반복 루프 (Repeat) \
# for (( r=1; r<=$(REPEAT); r++ )); do \
# SEED=$$(cat /dev/urandom | tr -cd "a-zA-Z0-9" | head -c 32); \
# TMP_IN="$(BUILD_IN_DIR)/bench_input.tmp"; \
# \
# # 명령어 문자열 구성 (CSV 기록용) \
# CMD_GEN="./$(GEN_TO_RUN) -N $$n -M $$m $$SEED"; \
# CMD_SOL_A="./$(SOL_A_EXE) < input"; \
# CMD_SOL_B="./$(SOL_B_EXE) < input"; \
# \
# printf "Run: N=%-5d M=%-5d Iter=%-2d ... " $$n $$m $$r; \
# \
# # 3. Generator 실행 \
# $$CMD_GEN > $$TMP_IN; \
# \
# # 4. Validator 실행 (실패 시 즉시 종료) \
# if ! ./$(VAL_EXE) < $$TMP_IN > /dev/null 2>&1; then \
# echo " [FAIL] Validator rejected input! Seed: $$SEED"; \
# exit 1; \
# fi; \
# \
# # 5. 솔루션 실행 및 시간 측정 \
# t_a=$$( { time ./$(SOL_A_EXE) < $$TMP_IN > /dev/null; } 2>&1 ); \
# t_b=$$( { time ./$(SOL_B_EXE) < $$TMP_IN > /dev/null; } 2>&1 ); \
# \
# # 6. CSV 저장 (명령어에 콤마가 포함될 수 있으므로 따옴표로 감싸는 것이 안전하나, 여기선 단순화) \
# echo "$$n,$$m,$$r,$$SEED,$$t_a,$$t_b,\"$$CMD_GEN\",\"$$CMD_SOL_A\",\"$$CMD_SOL_B\"" >> $(BENCH_CSV); \
# \
# echo "OK. [A: $${t_a}s] [B: $${t_b}s]"; \
# \
# rm -f $$TMP_IN; \
# done; \
# done \
# '
# @echo "--- Benchmark Complete! Data saved to $(BENCH_CSV) ---"