Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 172 additions & 10 deletions port/linux/benchmark/main.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include <benchmark/benchmark.h>
#include <algorithm>
#include <chrono>
#include "test_common.h"

extern "C" {
Expand Down Expand Up @@ -183,32 +185,192 @@ static void function_call_starred_1000(benchmark::State& state) {
}
BENCHMARK(function_call_starred_1000)->Unit(benchmark::kMillisecond);

static const char* fibonacci_source =
"def fib(n):\n"
" if n < 2:\n"
" return n\n"
" return fib(n - 1) + fib(n - 2)\n"
"result = fib(20)\n"
"\n";

static void fibonacci_recursive_20(benchmark::State& state) {
using clock = std::chrono::steady_clock;
auto nanoseconds = [](clock::duration duration) {
return std::chrono::duration_cast<std::chrono::nanoseconds>(duration)
.count();
};
auto compile_start = clock::now();
Args* buffs = New_strBuff();
char* pikaAsm = pika_lines2Asm(
buffs, (char*)
"def fib(n):\n"
" if n < 2:\n"
" return n\n"
" return fib(n - 1) + fib(n - 2)\n"
"result = fib(20)\n"
"\n");
char* pikaAsm = pika_lines2Asm(buffs, (char*)fibonacci_source);
ByteCodeFrame bytecode_frame;
byteCodeFrame_init(&bytecode_frame);
byteCodeFrame_appendFromAsm(&bytecode_frame, pikaAsm);
auto compile_end = clock::now();

pikaMemAllocationCountReset();
auto root_create_start = clock::now();
PikaObj* pikaMain = newRootObj((char*)"pikaMain", New_PikaMain);
auto root_create_end = clock::now();
uint64_t root_create_allocations = pikaMemAllocationCount();
uint32_t warm_heap_baseline_bytes = pikaMemNow();

uint64_t execute_ns = 0;
uint64_t execute_allocations = 0;
pikaMemMaxReset();
pikaMemAllocationCountReset();
for (auto _ : state) {
PikaObj* pikaMain = newRootObj((char*)"pikaMain", New_PikaMain);
uint32_t before_execute_allocations = pikaMemAllocationCount();
auto execute_start = clock::now();
pikaVM_runByteCodeFrame(pikaMain, &bytecode_frame);
auto execute_end = clock::now();
execute_allocations +=
pikaMemAllocationCount() - before_execute_allocations;
if (6765 != obj_getInt(pikaMain, (char*)"result")) {
state.SkipWithError("recursive fibonacci result mismatch");
}
obj_deinit(pikaMain);
execute_ns += nanoseconds(execute_end - execute_start);
}
uint32_t heap_peak_bytes = pikaMemMax();
uint32_t before_destroy_allocations = pikaMemAllocationCount();
auto root_destroy_start = clock::now();
obj_deinit(pikaMain);
auto root_destroy_end = clock::now();
uint64_t root_destroy_allocations =
pikaMemAllocationCount() - before_destroy_allocations;
byteCodeFrame_deinit(&bytecode_frame);
args_deinit(buffs);

state.counters["compile_once_ns"] =
nanoseconds(compile_end - compile_start);
state.counters["setup_root_create_ns"] =
nanoseconds(root_create_end - root_create_start);
state.counters["warm_execute_ns"] = benchmark::Counter(
execute_ns, benchmark::Counter::kAvgIterations);
state.counters["teardown_root_destroy_ns"] =
nanoseconds(root_destroy_end - root_destroy_start);
state.counters["setup_root_create_allocations"] =
root_create_allocations;
state.counters["execute_allocations"] = benchmark::Counter(
execute_allocations, benchmark::Counter::kAvgIterations);
state.counters["teardown_root_destroy_allocations"] =
root_destroy_allocations;
state.counters["heap_allocations"] = benchmark::Counter(
execute_allocations, benchmark::Counter::kAvgIterations);
state.counters["heap_peak_bytes"] = heap_peak_bytes;
state.counters["warm_heap_baseline_bytes"] =
warm_heap_baseline_bytes;
state.counters["heap_residual_bytes"] = pikaMemNow();
state.counters["root_destroy_count"] = 1;
}
BENCHMARK(fibonacci_recursive_20)->Unit(benchmark::kMillisecond);

static void fibonacci_recursive_20_cold_start(benchmark::State& state) {
using clock = std::chrono::steady_clock;
auto nanoseconds = [](clock::duration duration) {
return std::chrono::duration_cast<std::chrono::nanoseconds>(duration)
.count();
};
uint64_t root_create_ns = 0;
uint64_t compile_ns = 0;
uint64_t first_execute_ns = 0;
uint64_t root_destroy_ns = 0;
uint64_t cleanup_ns = 0;
uint64_t root_create_allocations = 0;
uint64_t compile_allocations = 0;
uint64_t execute_allocations = 0;
uint64_t destroy_allocations = 0;
uint64_t cleanup_allocations = 0;
uint32_t heap_peak_bytes = 0;
uint32_t heap_residual_bytes = 0;

for (auto _ : state) {
pikaMemMaxReset();
pikaMemAllocationCountReset();

auto root_create_start = clock::now();
PikaObj* pikaMain = newRootObj((char*)"pikaMain", New_PikaMain);
auto root_create_end = clock::now();
uint32_t after_root_allocations = pikaMemAllocationCount();

auto compile_start = clock::now();
Args* buffs = New_strBuff();
char* pikaAsm = pika_lines2Asm(buffs, (char*)fibonacci_source);
ByteCodeFrame bytecode_frame;
byteCodeFrame_init(&bytecode_frame);
byteCodeFrame_appendFromAsm(&bytecode_frame, pikaAsm);
auto compile_end = clock::now();
uint32_t after_compile_allocations = pikaMemAllocationCount();

auto execute_start = clock::now();
pikaVM_runByteCodeFrame(pikaMain, &bytecode_frame);
auto execute_end = clock::now();
uint32_t after_execute_allocations = pikaMemAllocationCount();
if (6765 != obj_getInt(pikaMain, (char*)"result")) {
state.SkipWithError("cold fibonacci result mismatch");
}

auto root_destroy_start = clock::now();
obj_deinit(pikaMain);
auto root_destroy_end = clock::now();
uint32_t after_destroy_allocations = pikaMemAllocationCount();

auto cleanup_start = clock::now();
byteCodeFrame_deinit(&bytecode_frame);
args_deinit(buffs);
auto cleanup_end = clock::now();
uint32_t after_cleanup_allocations = pikaMemAllocationCount();

root_create_ns +=
nanoseconds(root_create_end - root_create_start);
compile_ns += nanoseconds(compile_end - compile_start);
first_execute_ns += nanoseconds(execute_end - execute_start);
root_destroy_ns +=
nanoseconds(root_destroy_end - root_destroy_start);
cleanup_ns += nanoseconds(cleanup_end - cleanup_start);
root_create_allocations += after_root_allocations;
compile_allocations +=
after_compile_allocations - after_root_allocations;
execute_allocations +=
after_execute_allocations - after_compile_allocations;
destroy_allocations +=
after_destroy_allocations - after_execute_allocations;
cleanup_allocations +=
after_cleanup_allocations - after_destroy_allocations;
heap_peak_bytes = std::max(heap_peak_bytes, pikaMemMax());
heap_residual_bytes = std::max(heap_residual_bytes, pikaMemNow());
}

state.counters["root_create_ns"] = benchmark::Counter(
root_create_ns, benchmark::Counter::kAvgIterations);
state.counters["compile_ns"] = benchmark::Counter(
compile_ns, benchmark::Counter::kAvgIterations);
state.counters["first_execute_ns"] = benchmark::Counter(
first_execute_ns, benchmark::Counter::kAvgIterations);
state.counters["root_destroy_ns"] = benchmark::Counter(
root_destroy_ns, benchmark::Counter::kAvgIterations);
state.counters["cleanup_ns"] = benchmark::Counter(
cleanup_ns, benchmark::Counter::kAvgIterations);
state.counters["root_create_allocations"] = benchmark::Counter(
root_create_allocations, benchmark::Counter::kAvgIterations);
state.counters["compile_allocations"] = benchmark::Counter(
compile_allocations, benchmark::Counter::kAvgIterations);
state.counters["execute_allocations"] = benchmark::Counter(
execute_allocations, benchmark::Counter::kAvgIterations);
state.counters["root_destroy_allocations"] = benchmark::Counter(
destroy_allocations, benchmark::Counter::kAvgIterations);
state.counters["cleanup_allocations"] = benchmark::Counter(
cleanup_allocations, benchmark::Counter::kAvgIterations);
state.counters["heap_allocations"] = benchmark::Counter(
root_create_allocations + compile_allocations +
execute_allocations + destroy_allocations +
cleanup_allocations,
benchmark::Counter::kAvgIterations);
state.counters["heap_peak_bytes"] = heap_peak_bytes;
state.counters["heap_residual_bytes"] = heap_residual_bytes;
}
BENCHMARK(fibonacci_recursive_20_cold_start)
->Unit(benchmark::kMillisecond);

static void embedded_control_loop_1000(benchmark::State& state) {
Args* buffs = New_strBuff();
char* pikaAsm = pika_lines2Asm(
Expand Down
39 changes: 39 additions & 0 deletions port/linux/test/benchmark-lifecycle-test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include <gtest/gtest.h>

extern "C" {
#include "PikaMain.h"
#include "PikaParser.h"
#include "PikaVM.h"
#include "dataArgs.h"
#include "dataMemory.h"
}

TEST(benchmark_lifecycle, root_survives_repeated_execution_and_one_teardown) {
ASSERT_EQ(0u, pikaMemNow());
Args* buffers = New_strBuff();
char* assembly = pika_lines2Asm(
buffers, (char*)
"def fib(n):\n"
" if n < 2:\n"
" return n\n"
" return fib(n - 1) + fib(n - 2)\n"
"result = fib(15)\n");
ByteCodeFrame bytecode_frame;
byteCodeFrame_init(&bytecode_frame);
byteCodeFrame_appendFromAsm(&bytecode_frame, assembly);
PikaObj* root = newRootObj((char*)"pikaMain", New_PikaMain);

for (int iteration = 0; iteration < 500; ++iteration) {
ASSERT_NE(nullptr, pikaVM_runByteCodeFrame(root, &bytecode_frame));
ASSERT_EQ(610, obj_getInt(root, (char*)"result")) << iteration;
}

ASSERT_NE(nullptr, pikaVM_run(root, (char*)"missing_name()\n"));
ASSERT_NE(nullptr, pikaVM_runByteCodeFrame(root, &bytecode_frame));
EXPECT_EQ(610, obj_getInt(root, (char*)"result"));

obj_deinit(root);
byteCodeFrame_deinit(&bytecode_frame);
args_deinit(buffers);
EXPECT_EQ(0u, pikaMemNow());
}
9 changes: 9 additions & 0 deletions src/dataMemory.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ void* pikaMalloc(uint32_t size) {
if (g_PikaMemInfo.heapUsedMax < g_PikaMemInfo.heapUsed) {
g_PikaMemInfo.heapUsedMax = g_PikaMemInfo.heapUsed;
}
g_PikaMemInfo.allocationCount++;
pika_platform_disable_irq_handle();
void* mem = pika_user_malloc(size);
pika_platform_enable_irq_handle();
Expand Down Expand Up @@ -90,6 +91,14 @@ void pikaMemMaxReset(void) {
g_PikaMemInfo.heapUsedMax = 0;
}

uint32_t pikaMemAllocationCount(void) {
return g_PikaMemInfo.allocationCount;
}

void pikaMemAllocationCountReset(void) {
g_PikaMemInfo.allocationCount = 0;
}

#if PIKA_POOL_ENABLE
uint32_t pool_getBlockIndex_byMemSize(Pool* pool, uint32_t size) {
if (0 == size) {
Expand Down
3 changes: 3 additions & 0 deletions src/dataMemory.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ extern "C" {
typedef struct {
uint32_t heapUsed;
uint32_t heapUsedMax;
uint32_t allocationCount;
#if PIKA_ARG_CACHE_ENABLE
uint8_t* cache_pool[PIKA_ARG_CACHE_POOL_SIZE];
uint32_t cache_pool_top;
Expand Down Expand Up @@ -76,6 +77,8 @@ void* pikaMalloc(uint32_t size);
uint32_t pikaMemNow(void);
uint32_t pikaMemMax(void);
void pikaMemMaxReset(void);
uint32_t pikaMemAllocationCount(void);
void pikaMemAllocationCountReset(void);

BitMap bitmap_init(uint32_t size);
void bitmap_set(BitMap bitmap, uint32_t index, uint8_t bit);
Expand Down
Loading