Initial
This commit is contained in:
commit
d4c558a59a
34 changed files with 3850 additions and 0 deletions
0
tools/MemBenchmark/BenchmarkEntry.cpp
Normal file
0
tools/MemBenchmark/BenchmarkEntry.cpp
Normal file
172
tools/MemBenchmark/benchmark_simple.cpp
Normal file
172
tools/MemBenchmark/benchmark_simple.cpp
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
|
||||
|
||||
#include "allocators.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "timer.h"
|
||||
|
||||
struct AllocSpeedTets {
|
||||
const char* test_desc = NULL;
|
||||
virtual void exec() {};
|
||||
};
|
||||
|
||||
struct Test1 : AllocSpeedTets {
|
||||
Test1() {
|
||||
test_desc = "allocate lots of memory of same sizes, then free it all";
|
||||
}
|
||||
|
||||
const int len = 1000;
|
||||
int size = 100;
|
||||
void* buff[1000];
|
||||
|
||||
void exec_util(tp::AbstractAllocator* alloc) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
buff[i] = alloc->Alloc(size);
|
||||
}
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
alloc->Free(buff[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void exec() {
|
||||
tp::time_ms start, end;
|
||||
|
||||
tp::HeapAlloc malloc;
|
||||
tp::PoolAlloc pool(0, 0);
|
||||
tp::ChunkAlloc chunck(0, 0);
|
||||
tp::PickAlloc pick;
|
||||
|
||||
start = tp::get_time();
|
||||
|
||||
end = tp::get_time();
|
||||
printf("Malloc : %lli ms \n", end - start);
|
||||
|
||||
start = tp::get_time();
|
||||
end = tp::get_time();
|
||||
printf("Pool : %lli ms \n", end - start);
|
||||
|
||||
start = tp::get_time();
|
||||
end = tp::get_time();
|
||||
printf("Chunk : %lli ms \n", end - start);
|
||||
|
||||
start = tp::get_time();
|
||||
end = tp::get_time();
|
||||
printf("Pick : %lli ms \n", end - start);
|
||||
}
|
||||
};
|
||||
|
||||
struct Test2 : AllocSpeedTets {
|
||||
Test2() {
|
||||
test_desc = "allocate lots of memory of different sizes, then free it all";
|
||||
}
|
||||
|
||||
void exec() {
|
||||
tp::time_ms start, end;
|
||||
|
||||
tp::HeapAlloc malloc;
|
||||
tp::PoolAlloc pool(0, 0);
|
||||
tp::ChunkAlloc chunck(0, 0);
|
||||
tp::PickAlloc pick;
|
||||
|
||||
start = tp::get_time();
|
||||
end = tp::get_time();
|
||||
printf("Malloc : %lli ms \n", end - start);
|
||||
|
||||
start = tp::get_time();
|
||||
end = tp::get_time();
|
||||
printf("Pool : %lli ms \n", end - start);
|
||||
|
||||
start = tp::get_time();
|
||||
end = tp::get_time();
|
||||
printf("Chunk : %lli ms \n", end - start);
|
||||
|
||||
start = tp::get_time();
|
||||
end = tp::get_time();
|
||||
printf("Pick : %lli ms \n", end - start);
|
||||
}
|
||||
};
|
||||
|
||||
struct Test3 : AllocSpeedTets {
|
||||
Test3() {
|
||||
test_desc = "allocate only a few blocks of memory, free them, and repeat this loop several times \
|
||||
\n (repeat for same - sized blocks and different - sized blocks)\n";
|
||||
}
|
||||
|
||||
void exec() {
|
||||
tp::time_ms start, end;
|
||||
|
||||
tp::HeapAlloc malloc;
|
||||
tp::PoolAlloc pool(0, 0);
|
||||
tp::ChunkAlloc chunck(0, 0);
|
||||
tp::PickAlloc pick;
|
||||
|
||||
start = tp::get_time();
|
||||
end = tp::get_time();
|
||||
printf("Malloc : %lli ms \n", end - start);
|
||||
|
||||
start = tp::get_time();
|
||||
end = tp::get_time();
|
||||
printf("Pool : %lli ms \n", end - start);
|
||||
|
||||
start = tp::get_time();
|
||||
end = tp::get_time();
|
||||
printf("Chunk : %lli ms \n", end - start);
|
||||
|
||||
start = tp::get_time();
|
||||
end = tp::get_time();
|
||||
printf("Pick : %lli ms \n", end - start);
|
||||
}
|
||||
};
|
||||
|
||||
struct Test4 : AllocSpeedTets {
|
||||
Test4() {
|
||||
test_desc = "allocate lots of memory of different sizes, free half of it(e.g.the even allocations), then allocateand free memory in a loop\n";
|
||||
}
|
||||
|
||||
void exec() {
|
||||
tp::time_ms start, end;
|
||||
|
||||
tp::HeapAlloc malloc;
|
||||
tp::PoolAlloc pool(0, 0);
|
||||
tp::ChunkAlloc chunck(0, 0);
|
||||
tp::PickAlloc pick;
|
||||
|
||||
start = tp::get_time();
|
||||
end = tp::get_time();
|
||||
printf("Malloc : %lli ms \n", end - start);
|
||||
|
||||
start = tp::get_time();
|
||||
end = tp::get_time();
|
||||
printf("Pool : %lli ms \n", end - start);
|
||||
|
||||
start = tp::get_time();
|
||||
end = tp::get_time();
|
||||
printf("Chunk : %lli ms \n", end - start);
|
||||
|
||||
start = tp::get_time();
|
||||
end = tp::get_time();
|
||||
printf("Pick : %lli ms \n", end - start);
|
||||
}
|
||||
};
|
||||
|
||||
void banckmark() {
|
||||
|
||||
tp::alloc_init();
|
||||
|
||||
const int tests_len = 1;
|
||||
AllocSpeedTets* tests[] = {
|
||||
new Test1(),
|
||||
new Test2(),
|
||||
new Test3(),
|
||||
new Test4(),
|
||||
};
|
||||
|
||||
for (int i = 0; i < tests_len; i++) {
|
||||
printf("Test %i: \n %s\n", i, tests[i]->test_desc);
|
||||
tests[i]->exec();
|
||||
|
||||
delete tests[i];
|
||||
}
|
||||
|
||||
tp::alloc_uninit();
|
||||
}
|
||||
563
tools/MemBenchmark/benchmarker.cpp
Normal file
563
tools/MemBenchmark/benchmarker.cpp
Normal file
|
|
@ -0,0 +1,563 @@
|
|||
|
||||
#include "benchmarker.h"
|
||||
|
||||
#include "implot.h"
|
||||
#include "ImGuiUtils.h"
|
||||
|
||||
tp::alni hash(const tp::string& val) {
|
||||
return tp::hash(val.cstr());
|
||||
}
|
||||
|
||||
config glb_cfg = {
|
||||
|
||||
.live_update = false,
|
||||
|
||||
.heap = true,
|
||||
.pool = true,
|
||||
.chunk = true,
|
||||
|
||||
.current_sizing_pattern = 0,
|
||||
.current_loading_pattern = 0,
|
||||
.current_ordering_pattern = 0,
|
||||
|
||||
.update = 0,
|
||||
|
||||
.time_per_instruction = true,
|
||||
.mem_per_instruction = true,
|
||||
.avreging = 1,
|
||||
|
||||
.chunk_bsize = 100,
|
||||
.chunk_blen = 100,
|
||||
|
||||
.pool_bsize = 100,
|
||||
.pool_blen = 100,
|
||||
};
|
||||
|
||||
benchmarker::benchmarker() /*: ImGui::CompleteApp()*/ {
|
||||
|
||||
i_count = 0;
|
||||
pattern_out = NULL;
|
||||
out.reserve(3);
|
||||
|
||||
patterns.put("constant", new const_pattern());
|
||||
patterns.put("linear", new linear_pattern());
|
||||
patterns.put("random", new random_pattern());
|
||||
}
|
||||
|
||||
void benchmarker::output_draw() {
|
||||
if (ImGui::Begin("Overview")) {
|
||||
|
||||
if (is_output) {
|
||||
if (ImGui::TreeNode("total time")) {
|
||||
for (auto& i : tp::Range(0, 3)) {
|
||||
if (out[i]) {
|
||||
if (out[i]->total_time < 1000) {
|
||||
ImGui::Text("%s : %f 10e-9", out[i]->alloc_type, out[i]->total_time);
|
||||
} else if (out[i]->total_time < 1000000) {
|
||||
ImGui::Text("%s : %f 10e-6", out[i]->alloc_type, out[i]->total_time / 1000.f);
|
||||
} else if (out[i]->total_time < 1000000000) {
|
||||
ImGui::Text("%s : %f 10e-3", out[i]->alloc_type, out[i]->total_time / 1000000.f);
|
||||
} else {
|
||||
ImGui::Text("%s : %f ", out[i]->alloc_type, out[i]->total_time / 1000000000.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("failures")) {
|
||||
if ((out[0] && out[0]->failed) || (out[1] && out[1]->failed) || (out[2] && out[2]->failed)) {
|
||||
for (auto& i : tp::Range(0, 3)) {
|
||||
if (out[i] && out[i]->failed)
|
||||
ImGui::Text("%s failed", out[i]->alloc_type);
|
||||
}
|
||||
} else {
|
||||
ImGui::Text("all succeeded");
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
|
||||
if (cfg.time_per_instruction) {
|
||||
if (ImGui::Begin("Graphs")) {
|
||||
if (is_output) {
|
||||
if (ImPlot::BeginPlot("Time(ns) vs Alloc / Free inst")) {
|
||||
if (cfg.heap) ImPlot::PlotLine("halloc", x_axis, out[0]->time.buff(), (int) i_count);
|
||||
if (cfg.pool) ImPlot::PlotLine("pool", x_axis, out[1]->time.buff(), (int) i_count);
|
||||
if (cfg.chunk) ImPlot::PlotLine("chunk", x_axis, out[2]->time.buff(), (int) i_count);
|
||||
ImPlot::EndPlot();
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (cfg.mem_per_instruction) {
|
||||
if (ImGui::Begin("Graphs")) {
|
||||
if (is_output) {
|
||||
if (ImPlot::BeginPlot("Memory (bytes) at Instruction state")) {
|
||||
if (cfg.heap) ImPlot::PlotLine("halloc", x_axis, out[0]->mem.buff(), (int) i_count);
|
||||
if (cfg.pool) ImPlot::PlotLine("pool", x_axis, out[1]->mem.buff(), (int) i_count);
|
||||
if (cfg.chunk) ImPlot::PlotLine("chunk", x_axis, out[2]->mem.buff(), (int) i_count);
|
||||
ImPlot::EndPlot();
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (ImGui::Begin("Pattern")) {
|
||||
if (is_output) {
|
||||
if (ImPlot::BeginPlot("Alloc/Free instruction info vs instruction idx")) {
|
||||
if (cfg.current_sizing_pattern) ImPlot::PlotLine("allocated item size", x_axis, pattern_out->alloc_size.buff(), (int) i_count);
|
||||
if (cfg.current_ordering_pattern) ImPlot::PlotLine("used data item idx", x_axis, pattern_out->data_idx.buff(), (int) i_count);
|
||||
if (cfg.current_loading_pattern) ImPlot::PlotLine("total items allocated", x_axis, pattern_out->items_loaded.buff(), (int) i_count);
|
||||
ImPlot::EndPlot();
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
benchmarker::~benchmarker() {
|
||||
for (auto iter : patterns) {
|
||||
delete iter->val;
|
||||
}
|
||||
clear_out();
|
||||
}
|
||||
|
||||
void benchmarker::select_pattern() {
|
||||
if (patterns.size()) {
|
||||
const char** pattern_names = new const char* [patterns.size()];
|
||||
|
||||
const char* current_opattern_name = NULL;
|
||||
const char* current_lpattern_name = NULL;
|
||||
const char* current_spattern_name = NULL;
|
||||
|
||||
for (auto pattern_name : patterns) {
|
||||
pattern_names[pattern_name.entry_idx] = pattern_name->key.cstr();
|
||||
if (pattern_name->val == glb_cfg.current_ordering_pattern)
|
||||
current_opattern_name = pattern_name->key.cstr();
|
||||
if (pattern_name->val == glb_cfg.current_sizing_pattern)
|
||||
current_spattern_name = pattern_name->key.cstr();
|
||||
if (pattern_name->val == glb_cfg.current_loading_pattern)
|
||||
current_lpattern_name = pattern_name->key.cstr();
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Ordering", current_opattern_name)) {
|
||||
for (int n = 0; n < patterns.size(); n++) {
|
||||
bool is_selected = (current_opattern_name == pattern_names[n]);
|
||||
if (ImGui::Selectable(pattern_names[n], is_selected)) {
|
||||
current_opattern_name = pattern_names[n];
|
||||
glb_cfg.current_ordering_pattern = patterns.get(pattern_names[n]);
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Loading", current_lpattern_name)) {
|
||||
for (int n = 0; n < patterns.size(); n++) {
|
||||
bool is_selected = (current_lpattern_name == pattern_names[n]);
|
||||
if (ImGui::Selectable(pattern_names[n], is_selected)) {
|
||||
current_lpattern_name = pattern_names[n];
|
||||
glb_cfg.current_loading_pattern = patterns.get(pattern_names[n]);
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Sizing", current_spattern_name)) {
|
||||
for (int n = 0; n < patterns.size(); n++) {
|
||||
bool is_selected = (current_spattern_name == pattern_names[n]);
|
||||
if (ImGui::Selectable(pattern_names[n], is_selected)) {
|
||||
current_spattern_name = pattern_names[n];
|
||||
glb_cfg.current_sizing_pattern = patterns.get(pattern_names[n]);
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
delete pattern_names;
|
||||
}
|
||||
}
|
||||
|
||||
void benchmarker::pattern_combo(const char*& current) {
|
||||
if (patterns.size()) {
|
||||
const char** pattern_names = new const char* [patterns.size()];
|
||||
|
||||
for (auto pattern_name : patterns) {
|
||||
pattern_names[pattern_name.entry_idx] = pattern_name->key.cstr();
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Patterns", current)) {
|
||||
for (int n = 0; n < patterns.size(); n++) {
|
||||
bool is_selected = (current == pattern_names[n]);
|
||||
if (ImGui::Selectable(pattern_names[n], is_selected)) {
|
||||
current = pattern_names[n];
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
delete pattern_names;
|
||||
}
|
||||
}
|
||||
|
||||
void benchmarker::pattern_generator() {
|
||||
|
||||
|
||||
static tp::alni selected_idx = -1;
|
||||
static pattern* child_pattern_active = NULL;
|
||||
|
||||
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.1f);
|
||||
|
||||
pattern* pattern_edit = NULL;
|
||||
if (ImGui::Begin("Pattern Generator")) {
|
||||
|
||||
if (ImGui::SubMenuBegin("Selector", 1)) {
|
||||
|
||||
const char* prev_pattern = pattern_generator_active;
|
||||
pattern_combo(pattern_generator_active);
|
||||
|
||||
child_pattern_active = (prev_pattern == pattern_generator_active) ? child_pattern_active : NULL;
|
||||
|
||||
if (pattern_generator_active) {
|
||||
tp::alni idx = patterns.presents(pattern_generator_active);
|
||||
if (!MAP_VALID_IDX(idx)) {
|
||||
pattern_edit = 0;
|
||||
pattern_generator_active = 0;
|
||||
} else {
|
||||
pattern_edit = patterns[idx];
|
||||
}
|
||||
}
|
||||
|
||||
//ImGui::Separator();
|
||||
|
||||
static char create_name[100] = {"new pattern name"};
|
||||
ImGui::InputText("pattern name", create_name, 100);
|
||||
|
||||
if (ImGui::Button("Create")) {
|
||||
if (!patterns.presents(create_name)) {
|
||||
pattern* new_pt = new pattern();
|
||||
new_pt->build_in = false;
|
||||
new_pt->pattern_name = create_name;
|
||||
tp::string id = create_name;
|
||||
id.capture();
|
||||
patterns.put(id, new_pt);
|
||||
} else {
|
||||
ImGui::Notify("Such Pattern Already Exists", 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (pattern_edit) {
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Delete")) {
|
||||
if (pattern_edit->build_in) {
|
||||
ImGui::Notify("Cant Remove Built-in Patterns", 3);
|
||||
} else {
|
||||
patterns.remove(pattern_generator_active);
|
||||
delete pattern_edit;
|
||||
pattern_edit = NULL;
|
||||
pattern_generator_active = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Rename")) {
|
||||
if (pattern_edit->build_in) {
|
||||
ImGui::Notify("Cant Rename Built-in Patterns", 3);
|
||||
} else {
|
||||
patterns.remove(pattern_generator_active);
|
||||
patterns.put(create_name, pattern_edit);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::SubMenuEnd(1);
|
||||
}
|
||||
|
||||
if (pattern_generator_active) {
|
||||
tp::alni idx = patterns.presents(pattern_generator_active);
|
||||
if (!MAP_VALID_IDX(idx)) {
|
||||
pattern_edit = 0;
|
||||
pattern_generator_active = 0;
|
||||
} else {
|
||||
pattern_edit = patterns[idx];
|
||||
}
|
||||
}
|
||||
|
||||
if (!pattern_edit) {
|
||||
ImGui::Text("Select pattern to edit or create one");
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ImGui::SubMenuBegin("Preview", 1)) {
|
||||
static float preview_res_scale = 0.05f;
|
||||
int resolution = (int) (1000 * preview_res_scale);
|
||||
CLAMP(resolution, 3, 10000);
|
||||
float* x_axis = new float[resolution];
|
||||
float* y_axis = new float[resolution];
|
||||
|
||||
float x = 0;
|
||||
float step = 1.f / (resolution - 1);
|
||||
for (tp::alni idx = 0; idx < resolution; idx++) {
|
||||
x_axis[idx] = x;
|
||||
y_axis[idx] = (tp::flt4) pattern_edit->get_y(&patterns, x);
|
||||
x += step;
|
||||
}
|
||||
|
||||
|
||||
if (ImPlot::BeginPlot("Pattern")) {
|
||||
ImPlot::PlotLine("toggle", x_axis, y_axis, resolution);
|
||||
ImPlot::EndPlot();
|
||||
}
|
||||
|
||||
delete x_axis;
|
||||
delete y_axis;
|
||||
ImGui::SliderFloat("graph resolution", &preview_res_scale, 0.f, 1.f);
|
||||
ImGui::SubMenuEnd(1);
|
||||
}
|
||||
|
||||
if (ImGui::SubMenuBegin("Compositor", 1)) {
|
||||
|
||||
if (!pattern_edit->build_in) {
|
||||
|
||||
if (ImGui::SubMenuBegin("Child Patterns", 2)) {
|
||||
ImGui::BeginListBox("");
|
||||
for (tp::alni idx = 0; idx < pattern_edit->regions.length(); idx++) {
|
||||
ImGui::PushID((int) idx);
|
||||
if (ImGui::Button(pattern_edit->regions[idx].name.cstr())) {
|
||||
child_pattern_active = patterns.get(pattern_edit->regions[idx].name);
|
||||
selected_idx = idx;
|
||||
}
|
||||
if (selected_idx == idx) {
|
||||
ImGui::SameLine(); ImGui::Text(" - Active");
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::EndListBox();
|
||||
|
||||
if (selected_idx >= pattern_edit->regions.length()) {
|
||||
selected_idx = -1;
|
||||
}
|
||||
|
||||
static const char* append_pattern = NULL;
|
||||
bool add = ImGui::Button(" + ");
|
||||
ImGui::SameLine();
|
||||
pattern_combo(append_pattern);
|
||||
if (add) {
|
||||
if (append_pattern) {
|
||||
pattern_edit->regions.pushBack(child_pattern(append_pattern));
|
||||
} else {
|
||||
ImGui::Notify("Select a Pattern to Append");
|
||||
}
|
||||
}
|
||||
|
||||
if (child_pattern_active && selected_idx != -1) {
|
||||
|
||||
if (ImGui::Button(" Up ")) {
|
||||
if (selected_idx > 0) {
|
||||
tp::string tmp = pattern_edit->regions[selected_idx].name;
|
||||
pattern_edit->regions[selected_idx] = pattern_edit->regions[selected_idx - 1];
|
||||
pattern_edit->regions[selected_idx - 1] = tmp;
|
||||
selected_idx--;
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Down")) {
|
||||
if (selected_idx < pattern_edit->regions.length() - 1) {
|
||||
tp::string tmp = pattern_edit->regions[selected_idx].name;
|
||||
pattern_edit->regions[selected_idx] = pattern_edit->regions[selected_idx + 1];
|
||||
pattern_edit->regions[selected_idx + 1] = tmp;
|
||||
selected_idx++;
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Remove")) {
|
||||
pattern_edit->regions.remove(selected_idx);
|
||||
selected_idx = pattern_edit->regions.length() - 1;
|
||||
}
|
||||
} else {
|
||||
ImGui::Text("Select Child Pattern");
|
||||
}
|
||||
ImGui::SubMenuEnd(2);
|
||||
}
|
||||
|
||||
if (child_pattern_active && selected_idx != -1) {
|
||||
if (ImGui::SubMenuBegin("child Pattern Properties", 2)) {
|
||||
ImGui::SliderFloat("Point", &pattern_edit->regions[selected_idx].point, 0.f, 1.f);
|
||||
ImGui::SliderFloat("Lower lim", &pattern_edit->regions[selected_idx].lowerlim, 0.f, 1.f);
|
||||
ImGui::SliderFloat("Upper lim", &pattern_edit->regions[selected_idx].uppernlim, 0.f, 1.f);
|
||||
if (child_pattern_active->build_in) {
|
||||
}
|
||||
ImGui::SubMenuEnd(2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ImGui::Text("Can't Edit Built-In Patterns");
|
||||
}
|
||||
ImGui::SubMenuEnd(1);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void benchmarker::MainDrawTick() {
|
||||
|
||||
analize(glb_cfg);
|
||||
|
||||
|
||||
ImGui::BeginGroup();
|
||||
|
||||
if (ImGui::WindowEditor("Properties")) {
|
||||
|
||||
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.5f);
|
||||
|
||||
{
|
||||
if (ImGui::Button("Run")) {
|
||||
glb_cfg.update = true;
|
||||
}
|
||||
|
||||
bool prev_val = glb_cfg.live_update;
|
||||
ImGui::SameLine(); ImGui::Checkbox("Live Update", &glb_cfg.live_update);
|
||||
if (prev_val != glb_cfg.live_update) {
|
||||
glb_cfg.update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::SubMenuBegin("General", 1)) {
|
||||
ImGui::InputInt("Averaging", &glb_cfg.avreging, 1, 100); ImGui::ToolTip("Number of tests to be averaged");
|
||||
ImGui::Checkbox("Collect time per instruction", &glb_cfg.time_per_instruction);
|
||||
ImGui::Checkbox("Collect mem per instruction", &glb_cfg.mem_per_instruction);
|
||||
|
||||
ImGui::SubMenuEnd(1);
|
||||
}
|
||||
|
||||
if (ImGui::SubMenuBegin("Testing Pattern", 1)) {
|
||||
|
||||
select_pattern();
|
||||
|
||||
ImGui::InputInt("size", &glb_cfg.pt_scale.size, 1, 100); ImGui::ToolTip("Y Scale of sizing pattern");
|
||||
ImGui::InputInt("items", &glb_cfg.pt_scale.items, 1, 100); ImGui::ToolTip("Y Scale of ordering and loading patterns");
|
||||
ImGui::InputInt("iterations", &glb_cfg.pt_scale.iterations, 1, 100); ImGui::ToolTip("X Scale of all patterns");
|
||||
|
||||
ImGui::SubMenuEnd(1);
|
||||
}
|
||||
|
||||
if (ImGui::SubMenuBegin("Allocators", 1)) {
|
||||
ImGui::Checkbox("heap", &glb_cfg.heap); ImGui::SameLine(); ImGui::Checkbox("pool", &glb_cfg.pool); ImGui::SameLine(); ImGui::Checkbox("chunk", &glb_cfg.chunk);
|
||||
|
||||
if (glb_cfg.chunk && ImGui::SubMenuBegin("Chunk", 2)) {
|
||||
ImGui::InputInt("size", &glb_cfg.chunk_bsize, 1, 100); ImGui::ToolTip("Size of a slot in the chunk buffer");
|
||||
ImGui::InputInt("length", &glb_cfg.chunk_blen, 1, 100); ImGui::ToolTip("Number of slots in the chunk buffer");
|
||||
ImGui::SubMenuEnd(2);
|
||||
}
|
||||
if (glb_cfg.pool && ImGui::SubMenuBegin("Pool", 2)) {
|
||||
ImGui::ToolTip("Generalized use of chunk allocator");
|
||||
ImGui::InputInt("size", &glb_cfg.pool_bsize, 1, 100);
|
||||
ImGui::InputInt("length", &glb_cfg.pool_blen, 1, 100);
|
||||
ImGui::SubMenuEnd(2);
|
||||
}
|
||||
ImGui::SubMenuEnd(1);
|
||||
}
|
||||
|
||||
//ImGui::PopItemWidth();
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
output_draw();
|
||||
|
||||
pattern_generator();
|
||||
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
|
||||
void benchmarker::analize(config pcfg) {
|
||||
|
||||
if (!((pcfg.update) || (!(this->cfg == pcfg) && cfg.live_update))) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->cfg = pcfg;
|
||||
|
||||
clear_out();
|
||||
|
||||
if (!pattern_analizer.init(&patterns, cfg.current_loading_pattern, cfg.current_ordering_pattern, cfg.current_sizing_pattern, &cfg.pt_scale)) {
|
||||
if (pcfg.update) ImGui::Notify("invalid pattern configuration", 3);
|
||||
glb_cfg.update = false;
|
||||
cfg.update = false;
|
||||
is_output = false;
|
||||
return;
|
||||
}
|
||||
|
||||
reserve_out(&pattern_analizer);
|
||||
|
||||
for (tp::alni iter = 0; iter < pcfg.avreging; iter++) {
|
||||
init_allocators(pcfg);
|
||||
if (cfg.heap) collect(&pattern_analizer, halloc, out[0]);
|
||||
if (cfg.pool) collect(&pattern_analizer, palloc, out[1]);
|
||||
if (cfg.chunk) collect(&pattern_analizer, calloc, out[2]);
|
||||
dest_allocators();
|
||||
}
|
||||
|
||||
for (auto& i : tp::Range(0, 3)) {
|
||||
if (out[i]) out[i]->scale_all(1.f / pcfg.avreging);
|
||||
}
|
||||
|
||||
i_count = pattern_analizer.max_iterations();
|
||||
if (x_axis) {
|
||||
delete x_axis;
|
||||
x_axis = NULL;
|
||||
}
|
||||
x_axis = new tp::alnf[i_count];
|
||||
for (tp::alni iter = 0; iter < i_count; iter++) {
|
||||
x_axis[iter] = (tp::alnf) iter;
|
||||
}
|
||||
|
||||
glb_cfg.update = false;
|
||||
cfg.update = false;
|
||||
is_output = true;
|
||||
}
|
||||
|
||||
void benchmarker::init_allocators(config& pcfg) {
|
||||
if (cfg.heap) halloc = new tp::HeapAlloc();
|
||||
if (cfg.pool) palloc = new tp::PoolAlloc(pcfg.pool_bsize, pcfg.pool_blen);
|
||||
if (cfg.chunk) calloc = new tp::ChunkAlloc(pcfg.chunk_bsize, pcfg.chunk_blen);
|
||||
}
|
||||
|
||||
void benchmarker::dest_allocators() {
|
||||
try {
|
||||
if (cfg.heap) delete halloc;
|
||||
if (cfg.pool) delete palloc;
|
||||
if (cfg.chunk) delete calloc;
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
halloc = NULL;
|
||||
palloc = NULL;
|
||||
calloc = NULL;
|
||||
}
|
||||
|
||||
void benchmarker::clear_out() {
|
||||
for (auto i : tp::Range(0, 3)) {
|
||||
if (out[i]) {
|
||||
delete out[i];
|
||||
out[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (pattern_out) delete pattern_out;
|
||||
pattern_out = NULL;
|
||||
}
|
||||
|
||||
void benchmarker::reserve_out(test_pattern* pattern) {
|
||||
pattern_out = new pattern_histogram(pattern);
|
||||
if (cfg.heap) out[0] = new allocator_histogram(pattern, "heap", cfg.time_per_instruction, cfg.mem_per_instruction);
|
||||
if (cfg.pool) out[1] = new allocator_histogram(pattern, "pool", cfg.time_per_instruction, cfg.mem_per_instruction);
|
||||
if (cfg.chunk) out[2] = new allocator_histogram(pattern, "chunk", cfg.time_per_instruction, cfg.mem_per_instruction);
|
||||
}
|
||||
100
tools/MemBenchmark/benchmarker.h
Normal file
100
tools/MemBenchmark/benchmarker.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "patterns.h"
|
||||
|
||||
#include "allocators.h"
|
||||
#include "array.h"
|
||||
|
||||
#include "gl.h"
|
||||
#include "glcommon.h"
|
||||
#include "window.h"
|
||||
|
||||
enum class load_type {
|
||||
LINEAR,
|
||||
SINE,
|
||||
STEPS,
|
||||
RANDOM
|
||||
};
|
||||
|
||||
enum class order_type {
|
||||
LINEAR,
|
||||
LINEAR_REVERSED,
|
||||
RANDOM,
|
||||
};
|
||||
|
||||
struct config {
|
||||
// general
|
||||
bool live_update = false;
|
||||
|
||||
bool heap = true;
|
||||
bool pool = true;
|
||||
bool chunk = true;
|
||||
|
||||
// pattern
|
||||
pattern* current_sizing_pattern = 0;
|
||||
pattern* current_loading_pattern = 0;
|
||||
pattern* current_ordering_pattern = 0;
|
||||
pattern_scale pt_scale;
|
||||
|
||||
tp::alni update = 0;
|
||||
bool time_per_instruction = 0;
|
||||
bool mem_per_instruction = 0;
|
||||
int avreging;
|
||||
|
||||
// allocators
|
||||
int chunk_bsize = 0;
|
||||
int chunk_blen = 0;
|
||||
|
||||
int pool_bsize = 0;
|
||||
int pool_blen = 0;
|
||||
|
||||
bool operator==(const config& in) {
|
||||
return tp::memequal(this, (config*)(&in), sizeof(config));
|
||||
}
|
||||
};
|
||||
|
||||
struct benchmarker {
|
||||
|
||||
config cfg;
|
||||
bool is_output = false;
|
||||
|
||||
// allocators
|
||||
tp::HeapAlloc* halloc = NULL;
|
||||
tp::PoolAlloc* palloc = NULL;
|
||||
tp::ChunkAlloc* calloc = NULL;
|
||||
|
||||
|
||||
tp::Array<allocator_histogram*> out;
|
||||
pattern_histogram* pattern_out;
|
||||
|
||||
tp::alni i_count;
|
||||
tp::alnf* x_axis = NULL;
|
||||
|
||||
tp::HashMap<pattern*, tp::string> patterns;
|
||||
|
||||
pattern_reader pattern_analizer;
|
||||
|
||||
const char* pattern_generator_active = NULL;
|
||||
|
||||
benchmarker();
|
||||
~benchmarker();
|
||||
|
||||
test_pattern* get_pattern(config& cfg);
|
||||
|
||||
void pattern_combo(const char*&);
|
||||
void analize(config cfg);
|
||||
void select_pattern();
|
||||
void output_draw();
|
||||
|
||||
void MainDrawTick();
|
||||
|
||||
void pattern_generator();
|
||||
|
||||
void init_allocators(config& cfg);
|
||||
|
||||
void dest_allocators();
|
||||
|
||||
void clear_out();
|
||||
void reserve_out(test_pattern* pattern);
|
||||
};
|
||||
119
tools/MemBenchmark/collector.cpp
Normal file
119
tools/MemBenchmark/collector.cpp
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
|
||||
#include "collector.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
allocator_histogram::allocator_histogram(test_pattern* pt, const char* alloc_type, bool p_time_per_inst, bool p_mem_per_inst) {
|
||||
this->alloc_type = alloc_type;
|
||||
time_per_inst = p_time_per_inst;
|
||||
mem_per_inst = p_mem_per_inst;
|
||||
|
||||
if (time_per_inst) {
|
||||
time.reserve(pt->max_iterations());
|
||||
}
|
||||
if (mem_per_inst) {
|
||||
mem.reserve(pt->max_iterations());
|
||||
}
|
||||
data.reserve(pt->data_count());
|
||||
|
||||
total_time = 0;
|
||||
failed = false;
|
||||
}
|
||||
|
||||
void allocator_histogram::scale_all(tp::alnf fac) {
|
||||
for (auto& iter : time) {
|
||||
iter.data() = fac * iter.data();
|
||||
}
|
||||
for (auto& iter : mem) {
|
||||
iter.data() = fac * iter.data();
|
||||
}
|
||||
total_time = fac * total_time;
|
||||
}
|
||||
|
||||
allocator_histogram::~allocator_histogram() {
|
||||
}
|
||||
|
||||
void allocator_histogram::mark_resourses_usage(tp::alni idx, tp::alnf p_time, tp::alni p_mem, bool add) {
|
||||
if (mem.length() > idx)
|
||||
add ? mem[idx] += (tp::alnf)p_mem : mem[idx] = (tp::alnf)p_mem;
|
||||
if (time.length() > idx)
|
||||
add ? time[idx] += p_time : time[idx] = p_time;
|
||||
}
|
||||
|
||||
bool execute_instruction(tp::AbstractAllocator* alloc, bool load, tp::alni size, tp::uint1*& data) {
|
||||
bool failed = false;
|
||||
try {
|
||||
if (load) {
|
||||
if (!data) {
|
||||
data = (tp::uint1*)alloc->Alloc(size);
|
||||
if (!data) {
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (data) {
|
||||
alloc->Free(data);
|
||||
data = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
failed = true;
|
||||
}
|
||||
return !failed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void collect(test_pattern* pattern, tp::AbstractAllocator* alloc, allocator_histogram* histogram) {
|
||||
|
||||
tp::alni iter_idx = 0;
|
||||
tp::alni nimtems_loaded = 0;
|
||||
|
||||
auto total_st = std::chrono::high_resolution_clock::now();
|
||||
|
||||
for (iter_idx = 0; iter_idx < pattern->max_iterations(); iter_idx++) {
|
||||
|
||||
tp::alni target_nimtems_loaded = pattern->pick_alloc_count(iter_idx);
|
||||
tp::alni data_idx = pattern->pick_idx(iter_idx);
|
||||
tp::alni load_size = pattern->pick_size(iter_idx);
|
||||
|
||||
auto iter_st = std::chrono::high_resolution_clock::now();
|
||||
while (nimtems_loaded != target_nimtems_loaded) {
|
||||
bool load = nimtems_loaded < target_nimtems_loaded;
|
||||
if (!execute_instruction(alloc, load, load_size, histogram->data[data_idx])) {
|
||||
histogram->mark_resourses_usage(iter_idx, 0, 0, 0);
|
||||
histogram->failed = true;
|
||||
break;
|
||||
}
|
||||
nimtems_loaded += (tp::alni)load + (-1 * (tp::alni)(!load));
|
||||
}
|
||||
auto iter_nd = std::chrono::high_resolution_clock::now();
|
||||
tp::alni dur = std::chrono::duration_cast<std::chrono::nanoseconds>(iter_nd - iter_st).count();
|
||||
histogram->mark_resourses_usage(iter_idx, tp::alnf(dur), alloc->sizeReserved(), 1);
|
||||
}
|
||||
|
||||
// clear all out
|
||||
for (iter_idx = 0; iter_idx < pattern->max_iterations(); iter_idx++) {
|
||||
if (histogram->data[iter_idx]) {
|
||||
execute_instruction(alloc, false, 0, histogram->data[iter_idx]);
|
||||
}
|
||||
}
|
||||
|
||||
auto total_nd = std::chrono::high_resolution_clock::now();
|
||||
tp::alni dur = std::chrono::duration_cast<std::chrono::nanoseconds>(total_nd - total_st).count();
|
||||
histogram->total_time += dur;
|
||||
}
|
||||
|
||||
pattern_histogram::pattern_histogram(test_pattern* pt) {
|
||||
alloc_size.reserve(pt->max_iterations());
|
||||
data_idx.reserve(pt->max_iterations());
|
||||
items_loaded.reserve(pt->max_iterations());
|
||||
|
||||
for (auto& i : tp::Range(0, pt->max_iterations())) {
|
||||
alloc_size[i] = (tp::alnf) pt->pick_size(i);
|
||||
data_idx[i] = (tp::alnf)pt->pick_idx(i);
|
||||
items_loaded[i] = (tp::alnf)pt->pick_alloc_count(i);
|
||||
}
|
||||
}
|
||||
43
tools/MemBenchmark/collector.h
Normal file
43
tools/MemBenchmark/collector.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "array.h"
|
||||
|
||||
class test_pattern {
|
||||
public:
|
||||
virtual tp::alni pick_size(tp::alni iter) { return 0; };
|
||||
virtual tp::alni max_size() { return 0; };
|
||||
virtual tp::alni pick_alloc_count(tp::alni iter) { return 0; };
|
||||
virtual tp::alni max_iterations() { return 0; };
|
||||
virtual tp::alni pick_idx(tp::alni iter) { return 0; };
|
||||
virtual tp::alni data_count() { return 0; };
|
||||
};
|
||||
|
||||
struct pattern_histogram {
|
||||
tp::Array<tp::alnf> alloc_size;
|
||||
tp::Array<tp::alnf> data_idx;
|
||||
tp::Array<tp::alnf> items_loaded;
|
||||
|
||||
pattern_histogram(test_pattern* pt);
|
||||
};
|
||||
|
||||
struct allocator_histogram {
|
||||
const char* alloc_type;
|
||||
|
||||
tp::alnf total_time;
|
||||
tp::Array<tp::alnf> time;
|
||||
tp::Array<tp::alnf> mem;
|
||||
bool failed;
|
||||
|
||||
tp::Array<tp::uint1*> data;
|
||||
bool time_per_inst;
|
||||
bool mem_per_inst;
|
||||
|
||||
allocator_histogram(test_pattern* pt, const char* alloc_type, bool time_per_inst, bool mem_per_inst);
|
||||
~allocator_histogram();
|
||||
|
||||
void mark_resourses_usage(tp::alni idx, tp::alnf time, tp::alni mem, bool add);
|
||||
void scale_all(tp::alnf fac);
|
||||
};
|
||||
|
||||
void collect(test_pattern* pattern, tp::AbstractAllocator* alloc, allocator_histogram* histogram);
|
||||
0
tools/MemBenchmark/patterns.cpp
Normal file
0
tools/MemBenchmark/patterns.cpp
Normal file
174
tools/MemBenchmark/patterns.h
Normal file
174
tools/MemBenchmark/patterns.h
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "strings.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "collector.h"
|
||||
|
||||
tp::alni hash(const tp::string& val);
|
||||
|
||||
#include "map.h"
|
||||
|
||||
enum class leav_pattern_type {
|
||||
LINEAR,
|
||||
RANDOM,
|
||||
SINE,
|
||||
CONST,
|
||||
};
|
||||
|
||||
struct child_pattern {
|
||||
child_pattern() {}
|
||||
|
||||
child_pattern(tp::string _name) { name = _name; }
|
||||
|
||||
float uppernlim = 1.f;
|
||||
float lowerlim = 0.f;
|
||||
float point = 1.f;
|
||||
tp::string name;
|
||||
};
|
||||
|
||||
struct pattern {
|
||||
|
||||
leav_pattern_type type = leav_pattern_type::CONST;
|
||||
tp::string pattern_name;
|
||||
|
||||
tp::Array<child_pattern> regions;
|
||||
bool build_in = true;
|
||||
|
||||
pattern() {
|
||||
}
|
||||
|
||||
tp::alnf get_y(tp::HashMap<pattern*, tp::string>* patterns, tp::alnf x) {
|
||||
assert(x <= 1.0001f && x >= -0.00001f);
|
||||
|
||||
if (!regions.length()) {
|
||||
return pure_get_y(x);
|
||||
}
|
||||
|
||||
float offset = 0.f;
|
||||
for (tp::alni i = 0; i < regions.length(); i++) {
|
||||
tp::alni idx = patterns->presents(regions[i].name);
|
||||
if (!MAP_VALID_IDX(idx)) {
|
||||
return 0.f;
|
||||
}
|
||||
pattern* child = (*patterns)[idx];
|
||||
assert(child);
|
||||
|
||||
float range = regions[i].point * (1.f - offset);
|
||||
if (offset + range > x) {
|
||||
return regions[i].lowerlim +
|
||||
(child->get_y(patterns, (x - offset) / range) *
|
||||
(regions[i].uppernlim - regions[i].lowerlim));
|
||||
}
|
||||
offset += range;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual tp::alnf pure_get_y(tp::alnf x) { return 0; }
|
||||
|
||||
~pattern() {}
|
||||
};
|
||||
|
||||
// -------------------- build-in patterns ---------------------------- //
|
||||
|
||||
struct const_pattern : pattern {
|
||||
float val = 1.f;
|
||||
const_pattern() {
|
||||
type = leav_pattern_type::CONST;
|
||||
pattern_name = "const";
|
||||
build_in = true;
|
||||
}
|
||||
|
||||
tp::alnf pure_get_y(tp::alnf x) override { return val; }
|
||||
};
|
||||
|
||||
struct linear_pattern : pattern {
|
||||
bool reversed = false;
|
||||
linear_pattern() {
|
||||
type = leav_pattern_type::LINEAR;
|
||||
pattern_name = "linear";
|
||||
build_in = true;
|
||||
}
|
||||
|
||||
tp::alnf pure_get_y(tp::alnf x) override { return reversed ? 1.f - x : x; }
|
||||
};
|
||||
|
||||
struct random_pattern : pattern {
|
||||
random_pattern() {
|
||||
type = leav_pattern_type::RANDOM;
|
||||
build_in = true;
|
||||
}
|
||||
|
||||
tp::alnf pure_get_y(tp::alnf x) override { return tp::randf(); }
|
||||
};
|
||||
|
||||
// -------------------- build-in patterns end ---------------------------- //
|
||||
|
||||
struct pattern_scale {
|
||||
int items = 0;
|
||||
int size = 0;
|
||||
int iterations = 0;
|
||||
};
|
||||
|
||||
class pattern_reader : public test_pattern {
|
||||
public:
|
||||
bool init(tp::HashMap<pattern*, tp::string>* p_patterns, pattern* p_lpattern,
|
||||
pattern* p_opattern, pattern* p_spattern, pattern_scale* p_scale) {
|
||||
lpattern = p_lpattern;
|
||||
opattern = p_opattern;
|
||||
spattern = p_spattern;
|
||||
|
||||
scale = p_scale;
|
||||
|
||||
patterns = p_patterns;
|
||||
return verify_rulles();
|
||||
}
|
||||
|
||||
bool verify_rulles() {
|
||||
if (!lpattern || !opattern || !spattern) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool out = true;
|
||||
out &= scale->items > 0;
|
||||
out &= scale->size > 0;
|
||||
out &= scale->iterations > 0;
|
||||
return out;
|
||||
}
|
||||
|
||||
tp::HashMap<pattern*, tp::string>* patterns;
|
||||
|
||||
pattern* lpattern = NULL;
|
||||
pattern* opattern = NULL;
|
||||
pattern* spattern = NULL;
|
||||
|
||||
pattern_scale* scale = 0;
|
||||
|
||||
tp::alnf get_x_val(tp::alni iter) {
|
||||
tp::alnf out = iter / (tp::alnf)scale->iterations;
|
||||
return out > 1 ? 1.f : out;
|
||||
}
|
||||
|
||||
tp::alni pick_size(tp::alni iter) override {
|
||||
return (tp::alni)(scale->size * spattern->get_y(patterns, get_x_val(iter)));
|
||||
}
|
||||
|
||||
tp::alni pick_alloc_count(tp::alni iter) override {
|
||||
return (tp::alni)(scale->items * lpattern->get_y(patterns, get_x_val(iter)));
|
||||
}
|
||||
|
||||
tp::alni pick_idx(tp::alni iter) override {
|
||||
tp::alni out = (tp::alni) (scale->items * opattern->get_y(patterns, get_x_val(iter)));
|
||||
CLAMP(out, 0, scale->items - 1);
|
||||
return out;
|
||||
}
|
||||
|
||||
tp::alni max_size() override { return scale->size; }
|
||||
|
||||
tp::alni max_iterations() override { return scale->iterations; }
|
||||
|
||||
tp::alni data_count() override { return scale->iterations; }
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue