496 lines
17 KiB
Makefile
496 lines
17 KiB
Makefile
SHELL = /bin/bash
|
|
|
|
CXX = g++
|
|
# CXX = clang++
|
|
|
|
SRC_DIR = src
|
|
GEN_DIR = generator
|
|
VAL_DIR = validator
|
|
INC_DIR = include
|
|
CHK_DIR = checker
|
|
|
|
TEST_DIR = src/test
|
|
|
|
BUILD_DIR = build
|
|
BUILD_TARGET_DIR = $(BUILD_DIR)/target
|
|
BUILD_GEN_DIR = $(BUILD_DIR)/gen
|
|
BUILD_VAL_DIR = $(BUILD_DIR)/val
|
|
BUILD_CHK_DIR = $(BUILD_DIR)/chk
|
|
BUILD_TEST_DIR = $(BUILD_DIR)/test
|
|
LOG_DIR = $(BUILD_DIR)/logs
|
|
|
|
BUILD_IN_DIR = $(BUILD_DIR)/input
|
|
BUILD_OUT_A_DIR = $(BUILD_DIR)/$(SOL_A)_out
|
|
BUILD_OUT_B_DIR = $(BUILD_DIR)/$(SOL_B)_out
|
|
|
|
|
|
DIRS = $(BUILD_DIR) $(BUILD_TARGET_DIR) $(BUILD_GEN_DIR) $(BUILD_VAL_DIR) $(BUILD_CHK_DIR) $(LOG_DIR) $(BUILD_IN_DIR) $(BUILD_OUT_A_DIR) $(BUILD_OUT_B_DIR) $(BUILD_TEST_DIR)
|
|
|
|
CXXFLAGS = -Wall -O3 -std=c++2a
|
|
GENFLAGS = -N $(N) -M $(M) -pm $(pm)
|
|
|
|
SRC_MAIN_FILES = $(wildcard $(SRC_DIR)/*/main.cpp)
|
|
SOLS_EXE = $(patsubst $(SRC_DIR)/%/main.cpp, $(BUILD_TARGET_DIR)/%, $(SRC_MAIN_FILES))
|
|
|
|
SOL_A ?= bsb
|
|
SOL_B ?= dijk
|
|
SOL_A_EXE = $(BUILD_TARGET_DIR)/$(SOL_A)
|
|
SOL_B_EXE = $(BUILD_TARGET_DIR)/$(SOL_B)
|
|
|
|
GEN_SRCS = $(wildcard $(GEN_DIR)/*.cpp)
|
|
GENS_EXE = $(patsubst $(GEN_DIR)/%.cpp, $(BUILD_GEN_DIR)/%, $(GEN_SRCS))
|
|
|
|
gen ?= gen1
|
|
GEN_TO_RUN = $(BUILD_GEN_DIR)/$(gen)
|
|
|
|
VAL_EXE = $(BUILD_VAL_DIR)/validator
|
|
CHK_EXE = $(BUILD_CHK_DIR)/checker
|
|
|
|
PADDED_ID = $(shell printf "%05d" $(id))
|
|
IN_FILE = $(BUILD_IN_DIR)/input$(PADDED_ID)
|
|
OUT_A_FILE = $(BUILD_OUT_A_DIR)/$(SOL_A)$(PADDED_ID).out
|
|
OUT_B_FILE = $(BUILD_OUT_B_DIR)/$(SOL_B)$(PADDED_ID).out
|
|
|
|
TEST_COUNT ?= 100
|
|
N ?= 1000
|
|
M ?= 5000
|
|
pm ?= 0.1
|
|
|
|
.PHONY: all
|
|
all: $(SOLS_EXE) $(GENS_EXE) $(VAL_EXE) $(CHK_EXE) $(DIRS)
|
|
@echo "All executables compiled in $(BUILD_DIR)/"
|
|
|
|
$(BUILD_DIR) $(BUILD_TARGET_DIR) $(BUILD_GEN_DIR) $(BUILD_VAL_DIR) $(BUILD_CHK_DIR) $(LOG_DIR) $(BUILD_IN_DIR) $(BUILD_OUT_A_DIR) $(BUILD_OUT_B_DIR) $(BUILD_TEST_DIR):
|
|
@echo "Creating directory: $@"
|
|
@mkdir -p $@
|
|
|
|
$(BUILD_TARGET_DIR)/%: $(SRC_DIR)/%/main.cpp | $(BUILD_TARGET_DIR)
|
|
@echo "Compiling Solution $< -> $@"
|
|
$(CXX) $(CXXFLAGS) -o $@ $<
|
|
|
|
$(BUILD_GEN_DIR)/%: $(GEN_DIR)/%.cpp | $(BUILD_GEN_DIR)
|
|
@echo "Compiling Generator $< -> $@"
|
|
$(CXX) $(CXXFLAGS) -I$(INC_DIR) -o $@ $<
|
|
|
|
$(BUILD_VAL_DIR)/%: $(VAL_DIR)/%.cpp | $(BUILD_VAL_DIR)
|
|
@echo "Compiling Validator $< -> $@"
|
|
$(CXX) $(CXXFLAGS) -I$(INC_DIR) -o $@ $<
|
|
|
|
$(BUILD_CHK_DIR)/%: $(CHK_DIR)/%.cpp | $(BUILD_CHK_DIR)
|
|
@echo "Compiling Checker $< -> $@"
|
|
$(CXX) $(CXXFLAGS) -I$(INC_DIR) -o $@ $<
|
|
|
|
.PRECIOUS: $(BUILD_IN_DIR)/input%
|
|
$(BUILD_IN_DIR)/input%: $(GEN_TO_RUN) | $(BUILD_IN_DIR)
|
|
@echo "--- Generating Input: $@ (Using [$(gen)]) ---"
|
|
@SEED=$$(export LC_ALL=C; cat /dev/urandom | tr -cd 'a-zA-Z0-9' | head -c 32); \
|
|
echo "Using Seed: $$SEED" >&2; \
|
|
./$(GEN_TO_RUN) $(GENFLAGS) "$$SEED" > $@
|
|
|
|
$(BUILD_TEST_DIR)/%: $(TEST_DIR)/%.cpp | $(BUILD_TEST_DIR)
|
|
@echo "Compiling Unit Test $< -> $@"
|
|
$(CXX) $(CXXFLAGS) -I$(INC_DIR) -I$(SRC_DIR)/bsb -o $@ $< -lgtest -lgtest_main -pthread
|
|
|
|
.PHONY: force
|
|
force:
|
|
|
|
$(BUILD_OUT_A_DIR)/$(SOL_A)%.out: $(BUILD_IN_DIR)/input% $(SOL_A_EXE) force | $(BUILD_OUT_A_DIR)
|
|
@echo "--- Running $(SOL_A) (ID: $*) ---"
|
|
@time ./$(SOL_A_EXE) < $< > $@
|
|
|
|
$(BUILD_OUT_B_DIR)/$(SOL_B)%.out: $(BUILD_IN_DIR)/input% $(SOL_B_EXE) force | $(BUILD_OUT_B_DIR)
|
|
@echo "--- Running $(SOL_B) (ID: $*) ---"
|
|
@time ./$(SOL_B_EXE) < $< > $@
|
|
|
|
.PHONY: gen
|
|
gen: all
|
|
ifeq ($(id),)
|
|
@echo "Error: 'make gen' requires an 'id' variable."
|
|
@echo "Usage: make gen id=<test_id> [gen=gen_name]"
|
|
@exit 1
|
|
else
|
|
@$(MAKE) --no-print-directory $(IN_FILE) id=$(id) gen=$(gen) N=$(N) M=$(M)
|
|
@echo "--- Generated $(IN_FILE) ---"
|
|
endif
|
|
|
|
# # 레거시 gen1 타겟
|
|
# .PHONY: gen1
|
|
# gen1: $(BUILD_GEN_DIR)/gen1
|
|
# @echo "--- gen1 : Generating 1 test case (DEPRECATED: use 'make gen id=1') ---"
|
|
# @SEED=$$(export LC_ALL=C; cat /dev/urandom | tr -cd 'a-zA-Z0-9' | head -c 32); \
|
|
# echo "./$(BUILD_GEN_DIR)/gen1 -N $(N) -M $(M) $$SEED | tee $(BUILD_IN_DIR)/input_legacy"; \
|
|
# ./$(BUILD_GEN_DIR)/gen1 -N $(N) -M $(M) $$SEED | tee $(BUILD_IN_DIR)/input_legacy
|
|
|
|
# # 레거시 gen1-silence 타겟
|
|
# .PHONY: gen1-silence
|
|
# gen1-silence: $(BUILD_GEN_DIR)/gen1
|
|
# @echo "--- gen1 : Generating 1 test case (DEPRECATED: use 'make gen id=1') ---"
|
|
# @SEED=$$(export LC_ALL=C; cat /dev/urandom | tr -cd 'a-zA-Z0-9' | head -c 32); \
|
|
# ./$(BUILD_GEN_DIR)/gen1 -N $(N) -M $(M) "$$SEED" > $(BUILD_IN_DIR)/input_legacy
|
|
|
|
.PHONY: val
|
|
val: all $(VAL_EXE)
|
|
ifeq ($(id),)
|
|
@echo "Error: 'make val' requires an 'id' variable."
|
|
@echo "Usage: make val id=<test_id>"
|
|
@exit 1
|
|
else
|
|
@$(MAKE) --no-print-directory $(IN_FILE) id=$(id) gen=$(gen) N=$(N) M=$(M)
|
|
@echo "--- Validating $(IN_FILE) (ID=$(id)) ---"
|
|
@./$(VAL_EXE) < $(IN_FILE)
|
|
@echo "Validator OK."
|
|
endif
|
|
|
|
.PHONY: check
|
|
check: all $(CHK_EXE)
|
|
ifeq ($(id),)
|
|
@echo "Error: 'make check' requires an 'id' variable."
|
|
@echo "Usage: make check id=<test_id>"
|
|
@exit 1
|
|
else
|
|
@echo "--- Checking ID=$(id) ---"
|
|
@$(MAKE) --no-print-directory $(OUT_A_FILE) id=$(id) gen=$(gen) SOL_A=$(SOL_A) GENARGS=$(GENARGS)
|
|
@$(MAKE) --no-print-directory $(OUT_B_FILE) id=$(id) gen=$(gen) SOL_B=$(SOL_B) GENARGS=$(GENARGS)
|
|
@echo "--- Comparing Outputs (ID=$(id)) ---"
|
|
@./$(CHK_EXE) $(IN_FILE) $(OUT_A_FILE) $(OUT_B_FILE) || ( \
|
|
echo "WA (Wrong Answer): Checker found an issue!" && \
|
|
echo "Input: $(IN_FILE)" && \
|
|
exit 1 \
|
|
)
|
|
@echo "OK: ID=$(id) outputs match!"
|
|
endif
|
|
|
|
UNIT_TEST_SRCS = $(wildcard $(TEST_DIR)/*.cpp)
|
|
UNIT_TEST_NAMES = $(patsubst $(TEST_DIR)/%.cpp, %, $(UNIT_TEST_SRCS))
|
|
|
|
.PHONY: test
|
|
test: all $(LOG_DIR) $(BUILD_OUT_A_DIR) $(BUILD_OUT_B_DIR)
|
|
ifdef target
|
|
@# Case 1: Unit Test 실행 (예: make test target=L33)
|
|
@echo "--- Running Unit Test Target: [$(target)] ---"
|
|
@$(MAKE) --no-print-directory $(BUILD_TEST_DIR)/$(target)
|
|
@echo "-------------------------------------------"
|
|
@./$(BUILD_TEST_DIR)/$(target)
|
|
else ifeq ($(id),)
|
|
@echo "--- Running $(TEST_COUNT) tests (Comparing $(SOL_A) vs $(SOL_B)) ---"
|
|
@echo "--- Using Generator [$(gen)] (N=$(N), M=$(M)) ---"
|
|
@LOG_FILE=$(LOG_DIR)/test_run_$$(date +%Y%m%d_%H%M%S).log; \
|
|
echo "--- Logging to $${LOG_FILE} ---"; \
|
|
script -q -c ' \
|
|
set -o pipefail; \
|
|
for i in {1..$(TEST_COUNT)}; do \
|
|
IN_FILE_LOOP=$(BUILD_IN_DIR)/input$$(printf "%05d" $$i); \
|
|
OUT_A_FILE_LOOP=$(BUILD_OUT_A_DIR)/$(SOL_A)$$(printf "%05d" $$i).out; \
|
|
OUT_B_FILE_LOOP=$(BUILD_OUT_B_DIR)/$(SOL_B)$$(printf "%05d" $$i).out; \
|
|
\
|
|
if [ ! -f $$IN_FILE_LOOP ]; then \
|
|
SEED=$$(export LC_ALL=C; cat /dev/urandom | tr -cd "a-zA-Z0-9" | head -c 32); \
|
|
printf "Test %4d (Seed: %s): " "$$i" "$$SEED"; \
|
|
./$(GEN_TO_RUN) -N $(N) -M $(M) "$$SEED" > $$IN_FILE_LOOP; \
|
|
printf "(GEN) "; \
|
|
else \
|
|
printf "Test %4d (Seed: EXISTING): " "$$i"; \
|
|
fi; \
|
|
\
|
|
printf "$(SOL_A): "; \
|
|
( TIMEFORMAT=%R; time ./$(SOL_A_EXE) < $$IN_FILE_LOOP > $$OUT_A_FILE_LOOP ) 2>&1 | tr "\n" " " ; \
|
|
printf "$(SOL_B): "; \
|
|
( TIMEFORMAT=%R; time ./$(SOL_B_EXE) < $$IN_FILE_LOOP > $$OUT_B_FILE_LOOP ) 2>&1 | tr "\n" " " ; \
|
|
printf "\t CHK: "; \
|
|
( ./$(CHK_EXE) $$IN_FILE_LOOP $$OUT_A_FILE_LOOP $$OUT_B_FILE_LOOP ) 2>&1 || { printf "\nWA! (Input: $$IN_FILE_LOOP)\n"; echo "Input saved to $$IN_FILE_LOOP"; exit 1; }; \
|
|
done; \
|
|
echo "--- All $(TEST_COUNT) tests passed! ---"; \
|
|
' /dev/null | tee $${LOG_FILE}; \
|
|
if [ $${PIPESTATUS[0]} -ne 0 ]; then \
|
|
printf "\n--- TESTS FAILED! See %s ---\n" "$${LOG_FILE}"; \
|
|
exit 1; \
|
|
fi
|
|
else
|
|
@echo "--- Running single test for ID=$(id) ---"
|
|
@$(MAKE) --no-print-directory check id=$(id) gen=$(gen) SOL_A=$(SOL_A) SOL_B=$(SOL_B) N=$(N) M=$(M)
|
|
endif
|
|
|
|
.PHONY: $(UNIT_TEST_NAMES)
|
|
$(UNIT_TEST_NAMES):
|
|
@$(MAKE) --no-print-directory test target=$@
|
|
|
|
.PHONY: bench
|
|
bench: all
|
|
ifeq ($(id),)
|
|
@echo "Error: 'make bench' requires an 'id' variable."
|
|
@exit 1
|
|
else
|
|
@$(MAKE) --no-print-directory $(IN_FILE) id=$(id) gen=$(gen) N=$(N) M=$(M)
|
|
@echo "--- Benchmarking $(SOL_A_EXE) with $(IN_FILE) (ID=$(id)) ---"
|
|
@time ./$(SOL_A_EXE) < $(IN_FILE) > $(OUT_A_FILE)
|
|
endif
|
|
|
|
.PHONY: format
|
|
format:
|
|
@echo "--- Formatting all C/C++ files ---"
|
|
@find $(SRC_DIR) $(GEN_DIR) $(VAL_DIR) $(CHK_DIR) $(INC_DIR) -type f \( -name "*.cpp" -o -name "*.c" -o -name "*.hpp" -o -name "*.h" \) -print0 | xargs -0 clang-format -i
|
|
@echo "Formatting complete."
|
|
|
|
.PHONY: clean-outputs
|
|
clean-outputs:
|
|
@echo "Cleaning up $(BUILD_OUT_A_DIR)/ and $(BUILD_OUT_B_DIR)/..."
|
|
@rm -rf $(BUILD_OUT_A_DIR) $(BUILD_OUT_B_DIR)
|
|
|
|
.PHONY: clean-inputs
|
|
clean-inputs:
|
|
@echo "Cleaning up $(BUILD_IN_DIR)/..."
|
|
@rm -rf $(BUILD_IN_DIR)
|
|
|
|
.PHONY: clean-tests
|
|
clean-tests: clean-inputs clean-outputs
|
|
|
|
.PHONY: clean
|
|
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) ---"
|