feat: add benchmar Make target
This commit is contained in:
+2
-1
@@ -3,7 +3,9 @@
|
|||||||
# Dirs
|
# Dirs
|
||||||
!/docs
|
!/docs
|
||||||
!/exl
|
!/exl
|
||||||
|
!/benchmarks
|
||||||
!/include
|
!/include
|
||||||
|
!/scripts
|
||||||
!/src
|
!/src
|
||||||
!/tests
|
!/tests
|
||||||
|
|
||||||
@@ -15,4 +17,3 @@
|
|||||||
!/Makefile
|
!/Makefile
|
||||||
!/README.md
|
!/README.md
|
||||||
!/README.ru.md
|
!/README.ru.md
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
.PHONY: build debug-c debug-vm test
|
.PHONY: build debug-c debug-vm test bench
|
||||||
|
|
||||||
|
BENCH_FILE ?= benchmarks/loop.fzs
|
||||||
|
RUNS ?= 7
|
||||||
|
WARMUP ?= 2
|
||||||
|
MAX_ITER ?= 2000000
|
||||||
|
|
||||||
build:
|
build:
|
||||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
|
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
|
||||||
@@ -17,3 +22,8 @@ debug-vm: build
|
|||||||
test: build
|
test: build
|
||||||
ctest --output-on-failure --test-dir build
|
ctest --output-on-failure --test-dir build
|
||||||
|
|
||||||
|
# Compile the benchmark once, then measure only VM process execution.
|
||||||
|
bench: build-release
|
||||||
|
./build/fzc -o build/benchmark.fzb $(BENCH_FILE)
|
||||||
|
python3 scripts/benchmark.py --runs $(RUNS) --warmup $(WARMUP) \
|
||||||
|
--max-iter $(MAX_ITER) --vm ./build/fz --program build/benchmark.fzb
|
||||||
|
|||||||
@@ -51,3 +51,20 @@ $ make debug-c FILE=exl/hw.fzs
|
|||||||
|
|
||||||
Для проверки новых фич, нужно использовать make-таргет `test`, а тесты писать в `CMakeLists.txt`.
|
Для проверки новых фич, нужно использовать make-таргет `test`, а тесты писать в `CMakeLists.txt`.
|
||||||
|
|
||||||
|
### Бенчмаркинг
|
||||||
|
|
||||||
|
`make bench` собирает Release-версию, компилирует `benchmarks/loop.fzs` один раз и
|
||||||
|
измеряет время запуска программы в виртуальной машине. По умолчанию выполняются
|
||||||
|
2 прогрева и 7 замеров; выводятся медиана, среднее, минимум и максимум. Компиляция
|
||||||
|
исходника в измерения не входит.
|
||||||
|
|
||||||
|
Параметры можно переопределить:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
make bench RUNS=15 WARMUP=3
|
||||||
|
make bench BENCH_FILE=path/to/program.fzs MAX_ITER=2000000
|
||||||
|
```
|
||||||
|
|
||||||
|
Измеряется полное время запуска процесса `fz` (включая загрузку программы), а не
|
||||||
|
только цикл интерпретации. Для сопоставимых результатов запускайте бенчмарк на
|
||||||
|
одной машине и не меняйте нагрузку между прогонами.
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// Integer loop workload for measuring VM execution without I/O.
|
||||||
|
uint i = 0;
|
||||||
|
uint sum = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 1000000; i = i + 1)
|
||||||
|
{
|
||||||
|
sum = sum + i;
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Run an FZL VM benchmark and report wall-clock timing statistics."""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import statistics
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument("--runs", type=int, default=7, help="measured runs")
|
||||||
|
parser.add_argument("--warmup", type=int, default=2, help="warm-up runs")
|
||||||
|
parser.add_argument("--max-iter", type=int, default=2_000_000)
|
||||||
|
parser.add_argument("--vm", required=True, help="path to the fz executable")
|
||||||
|
parser.add_argument("--program", required=True, help="compiled .fzb program")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.runs < 1 or args.warmup < 0 or args.max_iter < 1:
|
||||||
|
parser.error("runs/max-iter must be positive and warmup must be non-negative")
|
||||||
|
|
||||||
|
command = [args.vm, "--max-iter", str(args.max_iter), args.program]
|
||||||
|
|
||||||
|
for _ in range(args.warmup):
|
||||||
|
result = subprocess.run(command, capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
sys.stderr.write(result.stdout)
|
||||||
|
sys.stderr.write(result.stderr)
|
||||||
|
raise SystemExit(result.returncode)
|
||||||
|
|
||||||
|
measurements = []
|
||||||
|
for _ in range(args.runs):
|
||||||
|
start = time.perf_counter()
|
||||||
|
result = subprocess.run(
|
||||||
|
command, capture_output=True, text=True
|
||||||
|
)
|
||||||
|
elapsed = time.perf_counter() - start
|
||||||
|
if result.returncode != 0:
|
||||||
|
sys.stderr.write(result.stdout)
|
||||||
|
sys.stderr.write(result.stderr)
|
||||||
|
raise SystemExit(result.returncode)
|
||||||
|
measurements.append(elapsed)
|
||||||
|
|
||||||
|
print(f"Runs: {args.runs} (warm-up: {args.warmup})")
|
||||||
|
print(f"Median: {statistics.median(measurements):.6f} s")
|
||||||
|
print(f"Mean: {statistics.mean(measurements):.6f} s")
|
||||||
|
print(f"Min: {min(measurements):.6f} s")
|
||||||
|
print(f"Max: {max(measurements):.6f} s")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
+1
-1
@@ -232,7 +232,7 @@ int fzl_vm_run(fzl_vm_t *vm)
|
|||||||
while (vm->ip < vm->ops_count)
|
while (vm->ip < vm->ops_count)
|
||||||
{
|
{
|
||||||
fzl_opcode_t opcode = vm->ops[vm->ip];
|
fzl_opcode_t opcode = vm->ops[vm->ip];
|
||||||
size_t op_group = (opcode >> 16);
|
size_t op_group = (opcode >> 16) & 0xFF;
|
||||||
size_t op_fnnum = (opcode & 0xFF);
|
size_t op_fnnum = (opcode & 0xFF);
|
||||||
|
|
||||||
if (master_tbl[op_group] == NULL || master_tbl[op_group][op_fnnum] == NULL)
|
if (master_tbl[op_group] == NULL || master_tbl[op_group][op_fnnum] == NULL)
|
||||||
|
|||||||
Reference in New Issue
Block a user