@echo off
:: profile.bat -- build a C++ benchmark with RelWithDebInfo and run a
:: gprof/plain-run profile on Windows, or prepare an executable for Visual Studio.
::
:: Usage (run from the repository root):
::   benchmarks\profile.bat [gprof|run|vs] [benchmark target] [--with-upstream-onnx] [extra bench flags]
::
:: Examples:
::   benchmarks\profile.bat gprof  -n 20 -t 1
::   benchmarks\profile.bat run    -n 20 -t 1
::   benchmarks\profile.bat vs     -n 20 -t 1
::   benchmarks\profile.bat run bench_load_file -n 20 -t 1
::   benchmarks\profile.bat run bench_kernel_tuning -n 100000
::   benchmarks\profile.bat run bench_load_file --with-upstream-onnx -n 20
::
:: The default tool is gprof (requires MinGW/MSYS2 g++ with -pg support).
:: Use "run" to build and run the benchmark without any profiling tool.
:: Use "vs" to build and smoke-run the benchmark, then profile it from Visual Studio.
::
:: --with-upstream-onnx (bench_load_file only) sets
:: -DONNX_LIGHT_BENCH_WITH_UPSTREAM_ONNX=ON so CMake fetches and builds the
:: upstream onnx (protobuf-based) C++ library via FetchContent, enabling the
:: side-by-side onnx vs onnx_light comparison block (BENCH_HAS_UPSTREAM_ONNX).
::
:: Note: perf and valgrind are Linux-only and are not supported on Windows.
::
:: Requirements:
::   cmake (on PATH), MinGW g++ for gprof, or any CMake-compatible compiler
::   for the "run" option.

setlocal EnableDelayedExpansion

:: ---------------------------------------------------------------------------
:: Parse arguments
:: ---------------------------------------------------------------------------
set "TOOL=%~1"
if "%TOOL%"=="" set "TOOL=gprof"
set "BENCH_TARGET=%~2"
if "%BENCH_TARGET%"=="" set "BENCH_TARGET=bench_parse_serialize"
set "PARSE_START_ARG=2"
if /I "%BENCH_TARGET%"=="bench_parse_serialize" (
    set "PARSE_START_ARG=3"
) else if /I "%BENCH_TARGET%"=="bench_load_file" (
    set "PARSE_START_ARG=3"
) else if /I "%BENCH_TARGET%"=="bench_save_file" (
    set "PARSE_START_ARG=3"
) else if /I "%BENCH_TARGET%"=="bench_graph_builder" (
    set "PARSE_START_ARG=3"
) else if /I "%BENCH_TARGET%"=="bench_kernel_tuning" (
    set "PARSE_START_ARG=3"
) else (
    set "BENCH_TARGET=bench_parse_serialize"
)

:: Shift extra bench flags into BENCH_ARGS, detecting --with-upstream-onnx
set "BENCH_ARGS="
set "WITH_UPSTREAM_ONNX=0"
if "%PARSE_START_ARG%"=="3" shift
:parse_loop
shift
if "%~1"=="" goto :parse_done
if /I "%~1"=="--with-upstream-onnx" (
    set "WITH_UPSTREAM_ONNX=1"
) else (
    set "BENCH_ARGS=!BENCH_ARGS! %~1"
)
goto :parse_loop
:parse_done

set "EXTRA_CMAKE_FLAGS="
if "%WITH_UPSTREAM_ONNX%"=="1" (
    for /f "usebackq delims=" %%P in (`python -c "import onnx, os; print(os.path.dirname(onnx.__file__))" 2^>nul`) do set "ONNX_PREFIX=%%P"
    if not "!ONNX_PREFIX!"=="" (
        echo pip-installed onnx detected at: !ONNX_PREFIX! ^(informational only^)
    )
    echo --with-upstream-onnx: CMake will fetch and build upstream onnx via FetchContent
    set "EXTRA_CMAKE_FLAGS=-DONNX_LIGHT_BENCH_WITH_UPSTREAM_ONNX=ON"
)

:: ---------------------------------------------------------------------------
:: Locate repository root (two levels up from this script)
:: ---------------------------------------------------------------------------
set "SCRIPT_DIR=%~dp0"
:: SCRIPT_DIR ends with a backslash, trim it
for %%I in ("%SCRIPT_DIR%.") do set "SCRIPT_DIR=%%~fI"
for %%I in ("%SCRIPT_DIR%\..") do set "REPO_ROOT=%%~fI"

set "BUILD_BASE=%REPO_ROOT%\build"

:: ---------------------------------------------------------------------------
:: Select build directory and gprof flag
:: ---------------------------------------------------------------------------
if /I "%TOOL%"=="gprof" (
    set "BUILD_DIR=%BUILD_BASE%\bench_gprof"
    set "GPROF_FLAG=-DONNX_LIGHT_BENCH_GPROF=ON"
) else if /I "%TOOL%"=="vs" (
    set "BUILD_DIR=%BUILD_BASE%\bench_vs"
    set "GPROF_FLAG="
) else if /I "%TOOL%"=="run" (
    set "BUILD_DIR=%BUILD_BASE%\bench_rdi"
    set "GPROF_FLAG="
) else (
    echo Unknown tool "%TOOL%". Choose: gprof ^| run ^| vs>&2
    echo Note: perf and valgrind are Linux-only and are not available on Windows.>&2
    exit /b 1
)

set "BENCH=%BUILD_DIR%\%BENCH_TARGET%.exe"

:: ---------------------------------------------------------------------------
:: Step 1 -- build
:: ---------------------------------------------------------------------------
echo === Step 1: cmake configure (%TOOL%) ===
cmake -S "%REPO_ROOT%" -B "%BUILD_DIR%" ^
    -DCMAKE_BUILD_TYPE=RelWithDebInfo ^
    -DONNX_LIGHT_BUILD_BENCHMARKS=ON ^
    -DONNX_LIGHT_BUILD_PYTHON=OFF ^
    %GPROF_FLAG% ^
    %EXTRA_CMAKE_FLAGS%
if errorlevel 1 exit /b 1

echo === Step 1: cmake build ===
cmake --build "%BUILD_DIR%" --target %BENCH_TARGET% --config RelWithDebInfo
if errorlevel 1 exit /b 1

echo.
echo Binary: %BENCH%
echo.

:: ---------------------------------------------------------------------------
:: Step 2 -- profile / run
:: ---------------------------------------------------------------------------
if /I "%TOOL%"=="gprof" (
    echo === Step 2: run with gprof instrumentation ===
    pushd "%BUILD_DIR%"
    "%BENCH%" %BENCH_ARGS%
    if errorlevel 1 ( popd & exit /b 1 )
    popd

    echo.
    echo === Step 3: gprof report (top 40 lines) ===
    gprof -b "%BENCH%" "%BUILD_DIR%\gmon.out" > "%BUILD_DIR%\gprof_report.txt"
    if errorlevel 1 (
        echo gprof failed. Make sure you are using a MinGW g++ build with -pg support.>&2
        exit /b 1
    )
    :: Print the first 40 lines of the report
    set "LINE=0"
    for /f "usebackq delims=" %%L in ("%BUILD_DIR%\gprof_report.txt") do (
        set /a LINE+=1
        if !LINE! leq 40 echo %%L
    )
    echo.
    echo Full report saved to: %BUILD_DIR%\gprof_report.txt
) else if /I "%TOOL%"=="vs" (
    echo === Step 2: smoke run before Visual Studio profiling ===
    "%BENCH%" %BENCH_ARGS%
    if errorlevel 1 exit /b 1
    echo.
    echo === Step 3: profile in Visual Studio ===
    echo 1. Open Visual Studio and start "Debug ^> Performance Profiler".
    echo 2. Choose "Executable" and set: %BENCH%
    echo 3. Set arguments to: %BENCH_ARGS%
    echo 4. Start profiling with CPU Usage (or Instrumentation).
) else (
    echo === Step 2: run (no profiling tool) ===
    "%BENCH%" %BENCH_ARGS%
    if errorlevel 1 exit /b 1
)

endlocal
