From 8e70c1de4c45c6cedce03b680fef1dfe89a0a490 Mon Sep 17 00:00:00 2001 From: TheBlackSheep3 <40034835+TheBlackSheep3@users.noreply.github.com> Date: Mon, 23 Jan 2023 18:46:57 +0100 Subject: [PATCH 01/18] added Python support for JULEA automatically generated Python module using CFFI includes example program and benchmarks --- .gitignore | 6 + benchmark/python/benchmark.py | 32 +++ benchmark/python/benchmarkrun.py | 75 ++++++ benchmark/python/db/common.py | 136 +++++++++++ benchmark/python/db/entry.py | 204 ++++++++++++++++ benchmark/python/db/iterator.py | 130 ++++++++++ benchmark/python/db/schema.py | 78 ++++++ benchmark/python/item/collection.py | 100 ++++++++ benchmark/python/item/item.py | 231 ++++++++++++++++++ benchmark/python/kv/kv.py | 131 ++++++++++ benchmark/python/object/distributed_object.py | 206 ++++++++++++++++ benchmark/python/object/object.py | 194 +++++++++++++++ python/build.py | 5 + python/build_helper.py | 133 ++++++++++ python/cffi-requirements.txt | 2 + python/example/Makefile | 8 + python/example/hello-world.py | 72 ++++++ python/julea.py | 50 ++++ scripts/benchmark.sh | 1 + scripts/common | 25 ++ scripts/environment.sh | 1 + scripts/setup.sh | 1 + scripts/test.sh | 1 + 23 files changed, 1822 insertions(+) create mode 100644 benchmark/python/benchmark.py create mode 100644 benchmark/python/benchmarkrun.py create mode 100644 benchmark/python/db/common.py create mode 100644 benchmark/python/db/entry.py create mode 100644 benchmark/python/db/iterator.py create mode 100644 benchmark/python/db/schema.py create mode 100644 benchmark/python/item/collection.py create mode 100644 benchmark/python/item/item.py create mode 100644 benchmark/python/kv/kv.py create mode 100644 benchmark/python/object/distributed_object.py create mode 100644 benchmark/python/object/object.py create mode 100644 python/build.py create mode 100644 python/build_helper.py create mode 100644 python/cffi-requirements.txt create mode 100644 python/example/Makefile create mode 100644 python/example/hello-world.py create mode 100644 python/julea.py diff --git a/.gitignore b/.gitignore index 3a3f02351..2f46ae79a 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,9 @@ bld*/ # Visual Studio Code .vscode/ + +# Python +**/__pycache__/ + +# C/C++ LSP +.ccls-cache/ diff --git a/benchmark/python/benchmark.py b/benchmark/python/benchmark.py new file mode 100644 index 000000000..1a1f985ea --- /dev/null +++ b/benchmark/python/benchmark.py @@ -0,0 +1,32 @@ +from kv.kv import benchmark_kv +from object.object import benchmark_object +from object.distributed_object import benchmark_distributed_object +from db.entry import benchmark_db_entry +from db.iterator import benchmark_db_iterator +from db.schema import benchmark_db_schema +from item.collection import benchmark_collection +from item.item import benchmark_item +from benchmarkrun import print_header +from sys import argv + +if __name__ == "__main__": + runs = [] + iterations = 1000 + machine_readable = ("-m" in argv) + print_header(machine_readable) + + # KV Client + benchmark_kv(runs, iterations, machine_readable) + + # Object Client + benchmark_distributed_object(runs, iterations, machine_readable) + benchmark_object(runs, iterations, machine_readable) + + # DB Client + benchmark_db_entry(runs, iterations, machine_readable) + benchmark_db_iterator(runs, iterations, machine_readable) + benchmark_db_schema(runs, iterations, machine_readable) + + # Item Client + benchmark_collection(runs, iterations, machine_readable) + benchmark_item(runs, iterations, machine_readable) diff --git a/benchmark/python/benchmarkrun.py b/benchmark/python/benchmarkrun.py new file mode 100644 index 000000000..069d8cb5b --- /dev/null +++ b/benchmark/python/benchmarkrun.py @@ -0,0 +1,75 @@ +from time import perf_counter_ns + +class BenchmarkRun: + def __init__(self, name, iterations, machine_readable): + self.name = name + self.iterations = iterations + self.timer_started = False + self.start = None + self.stop = None + self.operations = iterations + self.machine_readable = machine_readable + + def start_timer(self): + self.timer_started = True + self.start = perf_counter_ns() + + def stop_timer(self): + self.timer_started = False + self.stop = perf_counter_ns() + + def get_runtime_ms(self): + val = self.get_runtime_ns() + return val / 1000000 if val != None else None + + def get_runtime_s(self): + val = self.get_runtime_ns() + return val / 1000000000 if val != None else None + + def get_runtime_ns(self): + if self.timer_started or self.stop == None: + return None + else: + return self.stop - self.start + + def print_result(self): + if self.machine_readable: + print(f"{self.name},{self.get_runtime_s()},{self.operations}") + else: + name_col = self.name.ljust(60," ") + runtime_col = f"{self.get_runtime_s():.3f}".rjust(8," ") + " seconds" + operations_col = f"{int(self.operations/self.get_runtime_s())}/s".rjust(12," ") + print(f"{name_col} | {runtime_col} | {operations_col}") + + def print_empty(self): + if self.machine_readable: + print(f"{self.name},-,-") + else: + name_col = self.name.ljust(60," ") + runtime_col = "-".rjust(8," ") + " seconds" + operations_col = "-/s".rjust(12," ") + print(f"{name_col} | {runtime_col} | {operations_col}") + +def append_to_benchmark_list_and_run(_list, run, func): + _list.append(run) + try: + func(run) + run.print_result() + except: + run.print_empty() + +def print_result_table_header(): + name_col = "Name".ljust(60," ") + runtime_col = "Duration".ljust(16," ") + operations_col = f"Operations/s".rjust(12," ") + header = f"{name_col} | {runtime_col} | {operations_col}" + print(header+"\n"+len(header)*"-") + +def print_machine_readable_header(): + print("name,elapsed,operations") + +def print_header(machine_readable): + if machine_readable: + print_machine_readable_header() + else: + print_result_table_header() diff --git a/benchmark/python/db/common.py b/benchmark/python/db/common.py new file mode 100644 index 000000000..72115de82 --- /dev/null +++ b/benchmark/python/db/common.py @@ -0,0 +1,136 @@ +from julea import lib, encode, ffi + +N = 1 << 12 +N_GET_DIVIDER = N >> 8 +N_PRIME = 11971 +N_MODULUS = 256 +CLASS_MODULUS = N >> 3 +CLASS_LIMIT = CLASS_MODULUS >> 1 +SIGNED_FACTOR = N_PRIME +USIGNED_FACTOR = N_PRIME +FLOAT_FACTOR = 3.1415926 + +def _benchmark_db_prepare_scheme(namespace_encoded, use_batch, use_index_all, + use_index_single, batch, delete_batch): + b_s_error_ptr = ffi.new("GError*") + b_s_error_ptr = ffi.NULL + table_name = encode("table") + string_name = encode("string") + float_name = encode("float") + uint_name = encode("uint") + sint_name = encode("sint") + blob_name = encode("blob") + b_scheme = lib.j_db_schema_new(namespace_encoded, table_name, b_s_error_ptr) + assert b_scheme != ffi.NULL + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_schema_add_field(b_scheme, string_name, + lib.J_DB_TYPE_STRING, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_schema_add_field(b_scheme, float_name, + lib.J_DB_TYPE_FLOAT64, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_schema_add_field(b_scheme, uint_name, lib.J_DB_TYPE_UINT64, + b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_schema_add_field(b_scheme, sint_name, lib.J_DB_TYPE_UINT64, + b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_schema_add_field(b_scheme, blob_name, lib.J_DB_TYPE_BLOB, + b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + if use_index_all: + names = ffi.new("char*[5]") + names[0] = encode("string") + names[1] = encode("float") + names[2] = encode("uint") + names[3] = encode("sint") + names[4] = ffi.NULL + assert lib.j_db_schema_add_index(b_scheme, names, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + if use_index_single: + names = ffi.new("char*[2]") + names[1] = ffi.NULL + names[0] = encode("string") + assert lib.j_db_schema_add_index(b_scheme, names, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + names[0] = encode("float") + assert lib.j_db_schema_add_index(b_scheme, names, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + names[0] = encode("uint") + assert lib.j_db_schema_add_index(b_scheme, names, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + names[0] = encode("sint") + assert lib.j_db_schema_add_index(b_scheme, names, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_schema_create(b_scheme, batch, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_schema_delete(b_scheme, delete_batch, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + if not use_batch: + assert lib.j_batch_execute(batch) + return lib.j_db_schema_ref(b_scheme) + +def _benchmark_db_get_identifier(i): + return f"{i * SIGNED_FACTOR % N_MODULUS:x}-benchmark-{i}" + +def _benchmark_db_insert(run, scheme, namespace, use_batch, use_index_all, + use_index_single, use_timer): + b_scheme = None + b_s_error_ptr = ffi.new("GError*") + b_s_error_ptr = ffi.NULL + namespace_encoded = encode(namespace) + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + delete_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + if use_timer: + assert scheme == None + assert run != None + b_scheme = _benchmark_db_prepare_scheme(namespace_encoded, use_batch, + use_index_all, use_index_single, + batch, delete_batch) + assert b_scheme != None + run.start_timer() + else: + assert use_batch + assert run == None + lib.j_db_schema_ref(scheme) + b_scheme = scheme + for i in range(N): + i_signed_ptr = ffi.new("long*") + i_signed_ptr[0] = ((i * SIGNED_FACTOR) % CLASS_MODULUS) - CLASS_LIMIT + i_usigned_ptr = ffi.new("unsigned long*") + i_usigned_ptr[0] = ((i * USIGNED_FACTOR) % CLASS_MODULUS) + i_float_ptr = ffi.new("double*") + i_float_ptr[0] = i_signed_ptr[0] * FLOAT_FACTOR + string = encode(_benchmark_db_get_identifier(i)) + string_name = encode("string") + float_name = encode("float") + sint_name = encode("sint") + uint_name = encode("uint") + entry = lib.j_db_entry_new(b_scheme, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_entry_set_field(entry, string_name, string, 0, + b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_entry_set_field(entry, float_name, i_float_ptr, 0, + b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_entry_set_field(entry, sint_name, i_signed_ptr, 0, + b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_entry_set_field(entry, uint_name, i_usigned_ptr, 0, + b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_entry_insert(entry, batch, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + if not use_batch: + assert lib.j_batch_execute(batch) + if use_batch or not use_timer: + lib.j_batch_execute(batch) + if use_timer: + run.stop_timer() + assert lib.j_batch_execute(delete_batch) + run.operations = N + lib.j_batch_unref(batch) + lib.j_batch_unref(delete_batch) + lib.j_db_entry_unref(entry) + lib.j_db_schema_unref(b_scheme) diff --git a/benchmark/python/db/entry.py b/benchmark/python/db/entry.py new file mode 100644 index 000000000..c397396eb --- /dev/null +++ b/benchmark/python/db/entry.py @@ -0,0 +1,204 @@ +from benchmarkrun import BenchmarkRun, append_to_benchmark_list_and_run +from julea import lib, encode, ffi +from db.common import _benchmark_db_insert, _benchmark_db_prepare_scheme, _benchmark_db_get_identifier, N, N_GET_DIVIDER, N_PRIME, SIGNED_FACTOR, CLASS_MODULUS, CLASS_LIMIT + +def benchmark_db_entry(benchmarkrun_list, iterations, machine_readable): + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert", iterations, machine_readable), benchmark_db_insert) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-batch", iterations, machine_readable), benchmark_db_insert_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-index-single", iterations, machine_readable), benchmark_db_insert_index_single) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-batch-index-single", iterations, machine_readable), benchmark_db_insert_batch_index_single) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-index-all", iterations, machine_readable), benchmark_db_insert_index_all) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-batch-index-all", iterations, machine_readable), benchmark_db_insert_batch_index_all) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-index-mixed", iterations, machine_readable), benchmark_db_insert_index_mixed) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-batch-index-mixed", iterations, machine_readable), benchmark_db_insert_batch_index_mixed) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete", iterations, machine_readable), benchmark_db_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-batch", iterations, machine_readable), benchmark_db_delete_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-index-single", iterations, machine_readable), benchmark_db_delete_index_single) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-batch-index-single", iterations, machine_readable), benchmark_db_delete_batch_index_single) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-index-all", iterations, machine_readable), benchmark_db_delete_index_all) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-batch-index-all", iterations, machine_readable), benchmark_db_delete_batch_index_all) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-index-mixed", iterations, machine_readable), benchmark_db_delete_index_mixed) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-batch-index-mixed", iterations, machine_readable), benchmark_db_delete_batch_index_mixed) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update", iterations, machine_readable), benchmark_db_update) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-batch", iterations, machine_readable), benchmark_db_update_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-index-single", iterations, machine_readable), benchmark_db_update_index_single) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-batch-index-single", iterations, machine_readable), benchmark_db_update_batch_index_single) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-index-all", iterations, machine_readable), benchmark_db_update_index_all) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-batch-index-all", iterations, machine_readable), benchmark_db_update_batch_index_all) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-index-mixed", iterations, machine_readable), benchmark_db_update_index_mixed) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-batch-index-mixed", iterations, machine_readable), benchmark_db_update_batch_index_mixed) + +def benchmark_db_insert(run): + _benchmark_db_insert(run, None, "benchmark_insert", False, False, False, + True) + +def benchmark_db_insert_batch(run): + _benchmark_db_insert(run, None, "benchmark_insert_batch", True, False, + False, True) + +def benchmark_db_insert_index_single(run): + _benchmark_db_insert(run, None, "benchmark_insert_index_single", False, + False, True, True) + +def benchmark_db_insert_batch_index_single(run): + _benchmark_db_insert(run, None, "benchmark_insert_batch_index_single", True, + False, True, True) + +def benchmark_db_insert_index_all(run): + _benchmark_db_insert(run, None, "benchmark_insert_index_all", False, True, + False, True) + +def benchmark_db_insert_batch_index_all(run): + _benchmark_db_insert(run, None, "benchmark_insert_batch_index_all", True, + True, False, True) + +def benchmark_db_insert_index_mixed(run): + _benchmark_db_insert(run, None, "benchmakr_insert_index_mixed", False, True, + True, True) + +def benchmark_db_insert_batch_index_mixed(run): + _benchmark_db_insert(run, None, "benchmakr_insert_batch_index_mixed", True, + True, True, True) + +def benchmark_db_delete(run): + _benchmark_db_delete(run, "benchmark_delete", False, False, False) + +def benchmark_db_delete_batch(run): + _benchmark_db_delete(run, "benchmark_delete_batch", True, False, False) + +def benchmark_db_delete_index_single(run): + _benchmark_db_delete(run, "benchmark_delete_index_single", False, False, + True) + +def benchmark_db_delete_batch_index_single(run): + _benchmark_db_delete(run, "benchmark_delete_batch_index_single", True, + False, True) + +def benchmark_db_delete_index_all(run): + _benchmark_db_delete(run, "benchmark_delete_index_all", False, True, False) + +def benchmark_db_delete_batch_index_all(run): + _benchmark_db_delete(run, "benchmark_delete_batch_index_all", True, True, + False) + +def benchmark_db_delete_index_mixed(run): + _benchmark_db_delete(run, "benchmark_delete_index_mixed", False, True, True) + +def benchmark_db_delete_batch_index_mixed(run): + _benchmark_db_delete(run, "benchmark_delete_batch_index_mixed", True, True, + True) + +def _benchmark_db_delete(run, namespace, use_batch, use_index_all, + use_index_single): + namespace_encoded = encode(namespace) + b_s_error_ptr = ffi.new("GError*") + b_s_error_ptr = ffi.NULL + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + delete_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + b_scheme = _benchmark_db_prepare_scheme(namespace_encoded, False, + use_index_all, use_index_single, + batch, delete_batch) + assert b_scheme != ffi.NULL + assert run != None + _benchmark_db_insert(None, b_scheme, "\0", True, False, False, False) + run.start_timer() + iterations = N if use_index_all or use_index_single else int(N / N_GET_DIVIDER) + for i in range(iterations): + entry = lib.j_db_entry_new(b_scheme, b_s_error_ptr) + string = encode(_benchmark_db_get_identifier(i)) + string_name = encode("string") + selector = lib.j_db_selector_new(b_scheme, lib.J_DB_SELECTOR_MODE_AND, + b_s_error_ptr) + assert lib.j_db_selector_add_field(selector, string_name, + lib.J_DB_SELECTOR_OPERATOR_EQ, + string, 0, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_entry_delete(entry, selector, batch, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_db_entry_unref(entry) + lib.j_db_selector_unref(selector) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + assert lib.j_batch_execute(delete_batch) + run.operations = iterations + lib.j_batch_unref(batch) + lib.j_batch_unref(delete_batch) + lib.j_db_schema_unref(b_scheme) + +def benchmark_db_update(run): + _benchmark_db_update(run, "benchmark_update", False, False, False) + +def benchmark_db_update_batch(run): + _benchmark_db_update(run, "benchmark_update_batch", True, False, False) + +def benchmark_db_update_index_single(run): + _benchmark_db_update(run, "benchmark_update_index_single", False, False, + True) + +def benchmark_db_update_batch_index_single(run): + _benchmark_db_update(run, "benchmark_update_batch_index_single", True, + False, True) + +def benchmark_db_update_index_all(run): + _benchmark_db_update(run, "benchmark_update_index_all", False, True, False) + +def benchmark_db_update_batch_index_all(run): + _benchmark_db_update(run, "benchmark_update_batch_index_all", True, True, + False) + +def benchmark_db_update_index_mixed(run): + _benchmark_db_update(run, "benchmark_update_index_mixed", False, True, True) + +def benchmark_db_update_batch_index_mixed(run): + _benchmark_db_update(run, "benchmark_update_batch_index_mixed", True, True, + True) + +def _benchmark_db_update(run, namespace, use_batch, use_index_all, + use_index_single): + namespace_encoded = encode(namespace) + b_s_error_ptr = ffi.new("GError*") + b_s_error_ptr = ffi.NULL + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + delete_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + b_scheme = _benchmark_db_prepare_scheme(namespace_encoded, False, + use_index_all, use_index_single, + batch, delete_batch) + assert b_scheme != ffi.NULL + assert run != None + _benchmark_db_insert(None, b_scheme, "\0", True, False, False, False) + run.start_timer() + iterations = N if use_index_all or use_index_single else int(N / N_GET_DIVIDER) + for i in range(iterations): + sint_name = encode("sint") + i_signed_ptr = ffi.new("long*") + i_signed_ptr[0] = (((i + N_PRIME) * SIGNED_FACTOR) & CLASS_MODULUS) - CLASS_LIMIT + selector = lib.j_db_selector_new(b_scheme, lib.J_DB_SELECTOR_MODE_AND, + b_s_error_ptr) + entry = lib.j_db_entry_new(b_scheme, b_s_error_ptr) + string_name = encode("string") + string = encode(_benchmark_db_get_identifier(i)) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_entry_set_field(encode, sint_name, i_signed_ptr, 0, + b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_selector_add_field(selector, string_name, + lib.J_DB_SELECTOR_OPERATOR_EQ, + string, 0, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_entry_update(entry, selector, batch, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_db_selector_unref(selector) + lib.j_db_entry_unref(entry) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + assert lib.j_batch_execute(delete_batch) + run.operations = iterations + lib.j_batch_unref(batch) + lib.j_batch_unref(delete_batch) + lib.j_db_schema_unref(b_scheme) diff --git a/benchmark/python/db/iterator.py b/benchmark/python/db/iterator.py new file mode 100644 index 000000000..a93855db7 --- /dev/null +++ b/benchmark/python/db/iterator.py @@ -0,0 +1,130 @@ +from benchmarkrun import BenchmarkRun, append_to_benchmark_list_and_run +from julea import lib, encode, ffi +from db.common import _benchmark_db_prepare_scheme, _benchmark_db_insert, _benchmark_db_get_identifier, N, N_GET_DIVIDER, CLASS_MODULUS, CLASS_LIMIT + +def benchmark_db_iterator(benchmarkrun_list, iterations, machine_readable): + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-simple", iterations, machine_readable), benchmark_db_get_simple) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-simple-index-single", iterations, machine_readable), benchmark_db_get_simple_index_single) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-simple-index-all", iterations, machine_readable), benchmark_db_get_simple_index_all) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-simple-index-mixed", iterations, machine_readable), benchmark_db_get_simple_index_mixed) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-range", iterations, machine_readable), benchmark_db_get_range) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-range-index-single", iterations, machine_readable), benchmark_db_get_range_index_single) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-range-index-all", iterations, machine_readable), benchmark_db_get_range_index_all) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-range-index-mixed", iterations, machine_readable), benchmark_db_get_range_index_mixed) + +def benchmark_db_get_simple(run): + _benchmark_db_get_simple(run, "benchmark_get_simple", False, False) + +def benchmark_db_get_simple_index_single(run): + _benchmark_db_get_simple(run, "benchmark_get_simple_index_single", False, + True) + +def benchmark_db_get_simple_index_all(run): + _benchmark_db_get_simple(run, "benchmark_get_simple_index_all", True, False) + +def benchmark_db_get_simple_index_mixed(run): + _benchmark_db_get_simple(run, "benchmark_get_simple_index_mixed", True, True) + +def _benchmark_db_get_simple(run, namespace, use_index_all, use_index_single): + namespace_encoded = encode(namespace) + b_s_error_ptr = ffi.new("GError*") + b_s_error_ptr = ffi.NULL + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + delete_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + b_scheme = _benchmark_db_prepare_scheme(namespace_encoded, False, + use_index_all, use_index_single, + batch, delete_batch) + assert b_scheme != ffi.NULL + assert run != None + _benchmark_db_insert(None, b_scheme, "\0", True, False, False, False) + run.start_timer() + iterations = N if use_index_all or use_index_single else int(N / N_GET_DIVIDER) + for i in range(iterations): + field_type_ptr = ffi.new("JDBType*") + field_value_ptr = ffi.new("void**") + field_length_ptr = ffi.new("unsigned long*") + string_name = encode("string") + string = encode(_benchmark_db_get_identifier(i)) + selector = lib.j_db_selector_new(b_scheme, lib.J_DB_SELECTOR_MODE_AND, + b_s_error_ptr) + assert lib.j_db_selector_add_field(selector, string_name, + lib.J_DB_SELECTOR_OPERATOR_EQ, + string, 0, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + iterator = lib.j_db_iterator_new(b_scheme, selector, b_s_error_ptr) + assert iterator != ffi.NULL + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_iterator_next(iterator, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_iterator_get_field(iterator, string_name, field_type_ptr, + field_value_ptr, field_length_ptr, + b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + lib.j_db_selector_unref(selector) + lib.j_db_iterator_unref(iterator) + run.operations = iterations + lib.j_batch_unref(batch) + lib.j_batch_unref(delete_batch) + lib.j_db_schema_unref(b_scheme) + +def benchmark_db_get_range(run): + _benchmark_db_get_range(run, "benchmark_get_range", False, False) + +def benchmark_db_get_range_index_single(run): + _benchmark_db_get_range(run, "benchmark_get_range_index_single", False, + True) + +def benchmark_db_get_range_index_all(run): + _benchmark_db_get_range(run, "benchmark_get_range_index_all", True, False) + +def benchmark_db_get_range_index_mixed(run): + _benchmark_db_get_range(run, "benchmark_get_range_index_mixed", True, True) + +def _benchmark_db_get_range(run, namespace, use_index_all, use_index_single): + namespace_encoded = encode(namespace) + b_s_error_ptr = ffi.new("GError*") + b_s_error_ptr = ffi.NULL + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + delete_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + b_scheme = _benchmark_db_prepare_scheme(namespace_encoded, False, + use_index_all, use_index_single, + batch, delete_batch) + assert b_scheme != ffi.NULL + assert run != None + _benchmark_db_insert(None, b_scheme, "\0", True, False, False, False) + run.start_timer() + for i in range(N_GET_DIVIDER): + field_type_ptr = ffi.new("JDBType*") + field_value_ptr = ffi.new("void**") + field_length_ptr = ffi.new("unsigned long*") + sint_name = encode("sint") + string_name = encode("string") + range_begin_ptr = ffi.new("long*") + range_begin_ptr[0] = int((i * (CLASS_MODULUS / N_GET_DIVIDER)) - CLASS_LIMIT) + range_end_ptr = ffi.new("long*") + range_end_ptr[0] = int(((i + 1) * (CLASS_MODULUS / N_GET_DIVIDER)) - (CLASS_LIMIT + 1)) + selector = lib.j_db_selector_new(b_scheme, lib.J_DB_SELECTOR_MODE_AND, + b_s_error_ptr) + assert lib.j_db_selector_add_field(selector, sint_name, + lib.J_DB_SELECTOR_OPERATOR_GE, + range_begin_ptr, 0 , b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_selector_add_field(selector, sint_name, + lib.J_DB_SELECTOR_OPERATOR_LE, + range_end_ptr, 0, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + iterator = lib.j_db_iterator_new(b_scheme, selector, b_s_error_ptr) + assert iterator != ffi.NULL + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_iterator_next(iterator, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_iterator_get_field(iterator, string_name, field_type_ptr, + field_value_ptr, field_length_ptr, + b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + run.stop_timer() + assert lib.j_batch_execute(delete_batch) + run.operations = N_GET_DIVIDER + lib.j_db_schema_unref(b_scheme) + lib.j_batch_unref(batch) + lib.j_batch_unref(delete_batch) diff --git a/benchmark/python/db/schema.py b/benchmark/python/db/schema.py new file mode 100644 index 000000000..dbdad6446 --- /dev/null +++ b/benchmark/python/db/schema.py @@ -0,0 +1,78 @@ +from benchmarkrun import BenchmarkRun, append_to_benchmark_list_and_run +from julea import lib, encode, ffi + +def benchmark_db_schema(benchmarkrun_list, iterations, machine_readable): + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/schema/create", iterations, machine_readable), benchmark_db_schema_create) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/schema/create-batch", iterations, machine_readable), benchmark_db_schema_create_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/schema/delete", iterations, machine_readable), benchmark_db_schema_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/schema/delete-batch", iterations, machine_readable), benchmark_db_schema_delete_batch) + +def benchmark_db_schema_create(run): + _benchmark_db_schema_create(run, False) + +def benchmark_db_schema_create_batch(run): + _benchmark_db_schema_create(run, True) + +def _benchmark_db_schema_create(run, use_batch): + run.iterations = int(run.iterations / 10) + run.operations = run.iterations + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + delete_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + run.start_timer() + for i in range(run.iterations): + error_ptr = ffi.new("GError*") + error_ptr_ptr = ffi.new("GError**") + error_ptr_ptr[0] = error_ptr + name = encode(f"benchmark-schema-{i}") + namespace = encode("benchmark-ns") + schema = lib.j_db_schema_new(namespace, name, error_ptr_ptr) + for j in range(10): + fname = encode("field{j}") + lib.j_db_schema_add_field(schema, fname, lib.J_DB_TYPE_STRING, + error_ptr_ptr) + lib.j_db_schema_create(schema, batch, ffi.NULL) + lib.j_db_schema_delete(schema, delete_batch, ffi.NULL) + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_db_schema_unref(schema) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + assert lib.j_batch_execute(delete_batch) + lib.j_batch_unref(batch) + lib.j_batch_unref(delete_batch) + +def benchmark_db_schema_delete(run): + _benchmark_db_schema_delete(run, False) + +def benchmark_db_schema_delete_batch(run): + _benchmark_db_schema_delete(run, True) + +def _benchmark_db_schema_delete(run, use_batch): + run.iterations = int(run.iterations / 10) + run.operations = run.iterations + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + for i in range(run.iterations): + name = encode(f"benchmark-schema-{i}") + namespace = encode("benchmark-ns") + schema = lib.j_db_schema_new(namespace, name, ffi.NULL) + for j in range(10): + fname = encode(f"field{j}") + lib.j_db_schema_add_field(schema, fname, lib.J_DB_TYPE_STRING, + ffi.NULL) + lib.j_db_schema_create(schema, batch, ffi.NULL) + lib.j_db_schema_unref(schema) + assert lib.j_batch_execute(batch) + run.start_timer() + for i in range(run.iterations): + name = encode(f"benchmark-schema-{i}") + namespace = encode("benchmark-ns") + schema = lib.j_db_schema_new(namespace, name, ffi.NULL) + lib.j_db_schema_delete(schema, batch, ffi.NULL) + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_db_schema_unref(schema) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + lib.j_batch_unref(batch) diff --git a/benchmark/python/item/collection.py b/benchmark/python/item/collection.py new file mode 100644 index 000000000..03caf40c3 --- /dev/null +++ b/benchmark/python/item/collection.py @@ -0,0 +1,100 @@ +from benchmarkrun import BenchmarkRun, append_to_benchmark_list_and_run +from julea import lib, encode, ffi + +def benchmark_collection(benchmarkrun_list, iterations, machine_readable): + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/create", iterations, machine_readable), benchmark_collection_create) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/create-batch", iterations, machine_readable), benchmark_collection_create_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/delete", iterations, machine_readable), benchmark_collection_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/delete-batch", iterations, machine_readable), benchmark_collection_delete_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/delete-batch-without-get", iterations, machine_readable), benchmark_collection_delete_batch_without_get) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/unordered-create-delete", iterations, machine_readable), benchmark_collection_unordered_create_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/unordered-create-delete-batch", iterations, machine_readable), benchmark_collection_unordered_create_delete_batch) + # TODO: benchmark get (also missing in c benchmark) + +def benchmark_collection_create(run): + _benchmark_collection_create(run, False) + +def benchmark_collection_create_batch(run): + _benchmark_collection_create(run, True) + +def _benchmark_collection_create(run, use_batch): + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + delete_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + run.start_timer() + for i in range(run.iterations): + name = encode(f"benchmark{i}") + collection = lib.j_collection_create(name, batch) + lib.j_collection_delete(collection, delete_batch) + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_collection_unref(collection) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + assert lib.j_batch_execute(delete_batch) + lib.j_batch_unref(batch) + lib.j_batch_unref(delete_batch) + +def benchmark_collection_delete(run): + _benchmark_collection_delete(run, False) + +def benchmark_collection_delete_batch(run): + _benchmark_collection_delete(run, True) + +def _benchmark_collection_delete(run, use_batch): + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + collection = lib.j_collection_create(name, batch) + lib.j_collection_unref(collection) + assert lib.j_batch_execute(batch) + run.start_timer() + for i in range(run.iterations): + collection_ptr = ffi.new("JCollection**") + name = encode(f"benchmark-{i}") + lib.j_collection_get(collection_ptr, name, batch) + assert lib.j_batch_execute(batch) + lib.j_collection_delete(collection_ptr[0], batch) + if not use_batch: + assert lib.j_batch_execute(batch) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + lib.j_batch_unref(batch) + +def benchmark_collection_delete_batch_without_get(run): + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + delete_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + collection = lib.j_collection_create(name, batch) + lib.j_collection_delete(collection, delete_batch) + lib.j_collection_unref(collection) + assert lib.j_batch_execute(batch) + run.start_timer() + assert lib.j_batch_execute(delete_batch) + run.stop_timer() + lib.j_batch_unref(batch) + lib.j_batch_unref(delete_batch) + +def benchmark_collection_unordered_create_delete(run): + _benchmark_collection_unordered_create_delete(run, False) + +def benchmark_collection_unordered_create_delete_batch(run): + _benchmark_collection_unordered_create_delete(run, True) + +def _benchmark_collection_unordered_create_delete(run, use_batch): + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + run.start_timer() + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + collection = lib.j_collection_create(name, batch) + lib.j_collection_delete(collection, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_collection_unref(collection) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + run.operations = run.iterations * 2 + lib.j_batch_unref(batch) diff --git a/benchmark/python/item/item.py b/benchmark/python/item/item.py new file mode 100644 index 000000000..06e3ef848 --- /dev/null +++ b/benchmark/python/item/item.py @@ -0,0 +1,231 @@ +from benchmarkrun import BenchmarkRun, append_to_benchmark_list_and_run +from julea import lib, encode, ffi + +def benchmark_item(benchmarkrun_list, iterations, machine_readable): + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/create", iterations, machine_readable), benchmark_item_create) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/create-batch", iterations, machine_readable), benchmark_item_create_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/delete", iterations, machine_readable), benchmark_item_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/delete-batch", iterations, machine_readable), benchmark_item_delete_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/delete-batch-without-get", iterations, machine_readable), benchmark_item_delete_batch_without_get) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/get-status", iterations, machine_readable), benchmark_item_get_status) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/get-status-batch", iterations, machine_readable), benchmark_item_get_status_batch) + # TODO: benchmark get (also missing in c benchmark) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/read", iterations, machine_readable), benchmark_item_read) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/read-batch", iterations, machine_readable), benchmark_item_read_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/write", iterations, machine_readable), benchmark_item_write) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/write-batch", iterations, machine_readable), benchmark_item_write_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/unordered-create-delete", iterations, machine_readable), benchmark_item_unordered_create_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/unordered-create-delete-batch", iterations, machine_readable), benchmark_item_unordered_create_delete_batch) + +def benchmark_item_create(run): + _benchmark_item_create(run, False) + +def benchmark_item_create_batch(run): + _benchmark_item_create(run, True) + +def _benchmark_item_create(run, use_batch): + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + delete_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + collection_name = encode("benchmark") + collection = lib.j_collection_create(collection_name, batch) + assert lib.j_batch_execute(batch) + run.start_timer() + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + item = lib.j_item_create(collection, name, ffi.NULL, batch) + lib.j_item_delete(item, delete_batch) + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_item_unref(item) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + assert lib.j_batch_execute(delete_batch) + lib.j_collection_unref(collection) + lib.j_batch_unref(batch) + lib.j_batch_unref(delete_batch) + +def benchmark_item_delete(run): + _benchmark_item_delete(run, False) + +def benchmark_item_delete_batch(run): + _benchmark_item_delete(run, True) + +def _benchmark_item_delete(run, use_batch): + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + get_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + collection_name = encode("benchmark") + collection = lib.j_collection_create(collection_name, batch) + assert lib.j_batch_execute(batch) + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + item = lib.j_item_create(collection, name, ffi.NULL, batch) + lib.j_item_unref(item) + assert lib.j_batch_execute(batch) + run.start_timer() + for i in range(run.iterations): + ptr = ffi.new("int**") + item_ptr = ffi.cast("JItem**", ptr) + name = encode(f"benchmark-{i}") + lib.j_item_get(collection, item_ptr, name, get_batch) + assert lib.j_batch_execute(get_batch) + lib.j_item_delete(item_ptr[0], batch) + if not use_batch: + assert lib.j_batch_execute(batch) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + lib.j_collection_delete(collection, batch) + assert lib.j_batch_execute(batch) + lib.j_collection_unref(collection) + lib.j_batch_unref(batch) + lib.j_batch_unref(get_batch) + +def benchmark_item_delete_batch_without_get(run): + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + delete_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + collection_name = encode("benchmark") + collection = lib.j_collection_create(collection_name, batch) + assert lib.j_batch_execute(batch) + for i in range(run.iterations): + name = encode("benchmark-{i}") + item = lib.j_item_create(collection, name, ffi.NULL, batch) + lib.j_item_delete(item, delete_batch) + lib.j_item_unref(item) + assert lib.j_batch_execute(batch) + run.start_timer() + assert lib.j_batch_execute(delete_batch) + run.stop_timer() + lib.j_collection_delete(collection, batch) + lib.j_collection_unref(collection) + lib.j_batch_unref(batch) + lib.j_batch_unref(delete_batch) + +def benchmark_item_get_status(run): + _benchmark_item_get_status(run, False) + +def benchmark_item_get_status_batch(run): + _benchmark_item_get_status(run, True) + +def _benchmark_item_get_status(run, use_batch): + run.iterations = 10 * run.iterations if use_batch else run.iterations + run.operations = run.iterations + dummy = ffi.new("char[1]") + nb_ptr = ffi.new("unsigned long*") + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + collection_name = encode("benchmark") + collection = lib.j_collection_create(collection_name, batch) + item = lib.j_item_create(collection, collection_name, ffi.NULL, batch) + lib.j_item_write(item, dummy, 1, 0, nb_ptr, batch) + assert lib.j_batch_execute(batch) + run.start_timer() + for i in range(run.iterations): + lib.j_item_get_status(item, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + lib.j_item_delete(item, batch) + lib.j_collection_delete(collection, batch) + assert lib.j_batch_execute(batch) + lib.j_item_unref(item) + lib.j_collection_unref(collection) + lib.j_batch_unref(batch) + +def benchmark_item_read(run): + _benchmark_item_read(run, False, 4 * 1024) + +def benchmark_item_read_batch(run): + _benchmark_item_read(run, True, 4 * 1024) + +def _benchmark_item_read(run, use_batch, block_size): + run.iterations = 10 * run.iterations if use_batch else run.iterations + run.operations = run.iterations + nb_ptr = ffi.new("unsigned long*") + dummy = ffi.new("char[]", block_size) + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + collection_name = encode("benchmark") + collection = lib.j_collection_create(collection_name, batch) + item = lib.j_item_create(collection, collection_name, ffi.NULL, batch) + for i in range(run.iterations): + lib.j_item_write(item, dummy, block_size, i * block_size, nb_ptr, batch) + assert lib.j_batch_execute(batch) + assert nb_ptr[0] == run.iterations * block_size + run.start_timer() + for i in range(run.iterations): + lib.j_item_read(item, dummy, block_size, i * block_size, nb_ptr, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + assert nb_ptr[0] == block_size + if use_batch: + assert lib.j_batch_execute(batch) + assert nb_ptr[0] == run.iterations * block_size + run.stop_timer() + lib.j_item_delete(item, batch) + lib.j_collection_delete(collection, batch) + assert lib.j_batch_execute(batch) + lib.j_item_unref(item) + lib.j_collection_unref(collection) + lib.j_batch_unref(batch) + +def benchmark_item_write(run): + _benchmark_item_write(run, False, 4 * 1024) + +def benchmark_item_write_batch(run): + _benchmark_item_write(run, True, 4 * 1024) + +def _benchmark_item_write(run, use_batch, block_size): + run.iterations = 10 * run.iterations if use_batch else run.iterations + run.operations = run.iterations + dummy = ffi.new("char[]", block_size) + nb_ptr = ffi.new("unsigned long*") + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + collection_name = encode("benchmark") + collection = lib.j_collection_create(collection_name, batch) + item = lib.j_item_create(collection, collection_name, ffi.NULL, batch) + assert lib.j_batch_execute(batch) + run.start_timer() + for i in range(run.iterations): + lib.j_item_write(item, dummy, block_size, i * block_size, nb_ptr, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + assert nb_ptr[0] == block_size + if use_batch: + assert lib.j_batch_execute(batch) + assert nb_ptr[0] == run.iterations * block_size + run.stop_timer() + lib.j_item_delete(item, batch) + lib.j_collection_delete(collection, batch) + assert lib.j_batch_execute(batch) + lib.j_item_unref(item) + lib.j_collection_unref(collection) + lib.j_batch_unref(batch) + +def benchmark_item_unordered_create_delete(run): + _benchmark_item_unordered_create_delete(run, False) + +def benchmark_item_unordered_create_delete_batch(run): + _benchmark_item_unordered_create_delete(run, True) + +def _benchmark_item_unordered_create_delete(run, use_batch): + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + collection_name = encode("benchmark") + collection = lib.j_collection_create(collection_name, batch) + assert lib.j_batch_execute(batch) + run.start_timer() + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + item = lib.j_item_create(collection, name, ffi.NULL, batch) + lib.j_item_delete(item, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_item_unref(item) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + lib.j_collection_delete(collection, batch) + assert lib.j_batch_execute(batch) + lib.j_collection_unref(collection) + lib.j_batch_unref(batch) + run.operations = run.iterations * 2 diff --git a/benchmark/python/kv/kv.py b/benchmark/python/kv/kv.py new file mode 100644 index 000000000..a39d91fef --- /dev/null +++ b/benchmark/python/kv/kv.py @@ -0,0 +1,131 @@ +from benchmarkrun import BenchmarkRun, append_to_benchmark_list_and_run +from julea import lib, encode, ffi + +def benchmark_kv(benchmarkrun_list, iterations, machine_readable): + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/put", iterations, machine_readable), benchmark_kv_put) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/put_batch", iterations, machine_readable), benchmark_kv_put_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/get", iterations, machine_readable), benchmark_kv_get) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/get-batch", iterations, machine_readable), benchmark_kv_get_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/delete", iterations, machine_readable), benchmark_kv_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/delete-batch", iterations, machine_readable), benchmark_kv_delete_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/unordered_put_delete", iterations, machine_readable), benchmark_kv_unordered_put_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/unordered_put_delete_batch", iterations, machine_readable), benchmark_kv_unordered_put_delete_batch) + +def benchmark_kv_put(run): + _benchmark_kv_put(run, False) + +def benchmark_kv_put_batch(run): + _benchmark_kv_put(run, True) + +def _benchmark_kv_put(run, use_batch): + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + deletebatch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + run.start_timer() + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + namespace = encode("benchmark") + kv = lib.j_kv_new(namespace, name) + empty = encode("empty") + lib.j_kv_put(kv, empty, 6, ffi.NULL, batch) + lib.j_kv_delete(kv, deletebatch) + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_kv_unref(kv) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + assert lib.j_batch_execute(deletebatch) + lib.j_batch_unref(batch) + lib.j_batch_unref(deletebatch) + +def benchmark_kv_get(run): + _benchmark_kv_get(run, False) + +def benchmark_kv_get_batch(run): + _benchmark_kv_get(run, True) + +@ffi.def_extern() +def cffi_j_kv_get_function(pointer1, integer, pointer2): + return + +def _benchmark_kv_get(run, use_batch): + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + deletebatch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + namespace = encode("benchmark") + kv = lib.j_kv_new(namespace, name) + lib.j_kv_put(kv, name, len(name), ffi.NULL, batch) + lib.j_kv_delete(kv, deletebatch) + lib.j_kv_unref(kv) + assert lib.j_batch_execute(batch) + run.start_timer() + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + namespace = encode("benchmark") + kv = lib.j_kv_new(namespace, name) + lib.j_kv_get_callback(kv, lib.cffi_j_kv_get_function, ffi.NULL, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_kv_unref(kv) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + assert lib.j_batch_execute(deletebatch) + lib.j_batch_unref(batch) + lib.j_batch_unref(deletebatch) + +def benchmark_kv_delete(run): + _benchmark_kv_delete(run, False) + +def benchmark_kv_delete_batch(run): + _benchmark_kv_delete(run, True) + +def _benchmark_kv_delete(run, use_batch): + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + namespace = encode("benchmark") + kv = lib.j_kv_new(namespace, name) + empty = encode("empty") + lib.j_kv_put(kv, empty, 6, ffi.NULL, batch) + lib.j_kv_unref(kv) + assert lib.j_batch_execute(batch) + run.start_timer() + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + namespace = encode("benchmark") + kv = lib.j_kv_new(namespace, name) + lib.j_kv_delete(kv, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_kv_unref(kv) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + lib.j_batch_unref(batch) + +def benchmark_kv_unordered_put_delete(run): + _benchmark_kv_unordered_put_delete(run, False) + +def benchmark_kv_unordered_put_delete_batch(run): + _benchmark_kv_unordered_put_delete(run, True) + +def _benchmark_kv_unordered_put_delete(run, use_batch): + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + run.start_timer() + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + namespace = encode("benchmark") + kv = lib.j_kv_new(namespace, name) + empty = encode("empty") + lib.j_kv_put(kv, empty, 6, ffi.NULL, batch) + lib.j_kv_delete(kv, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_kv_unref(kv) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + lib.j_batch_unref(batch) + run.operations = run.iterations * 2 diff --git a/benchmark/python/object/distributed_object.py b/benchmark/python/object/distributed_object.py new file mode 100644 index 000000000..1f7d4b752 --- /dev/null +++ b/benchmark/python/object/distributed_object.py @@ -0,0 +1,206 @@ +from benchmarkrun import BenchmarkRun, append_to_benchmark_list_and_run +from julea import lib, encode, ffi + +def benchmark_distributed_object(benchmarkrun_list, iterations, machine_readable): + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/create", iterations, machine_readable), benchmark_distributed_object_create) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/create-batch", iterations, machine_readable), benchmark_distributed_object_create_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/delete", iterations, machine_readable), benchmark_distributed_object_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/delete-batch", iterations, machine_readable), benchmark_distributed_object_delete_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/status", iterations, machine_readable), benchmark_distributed_object_status) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/status-batch", iterations, machine_readable), benchmark_distributed_object_status_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/read", iterations, machine_readable), benchmark_distributed_object_read) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/read-batch", iterations, machine_readable), benchmark_distributed_object_read_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/write", iterations, machine_readable), benchmark_distributed_object_write) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/write-batch", iterations, machine_readable), benchmark_distributed_object_write_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/unordered-create-delete", iterations, machine_readable), benchmark_distributed_object_unordered_create_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/unordered-create-delete-batch", iterations, machine_readable), benchmark_distributed_object_unordered_create_delete_batch) + +def benchmark_distributed_object_create(run): + _benchmark_distributed_object_create(run, False) + +def benchmark_distributed_object_create_batch(run): + _benchmark_distributed_object_create(run, True) + +def _benchmark_distributed_object_create(run, use_batch): + distribution = lib.j_distribution_new(lib.J_DISTRIBUTION_ROUND_ROBIN) + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + deletebatch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + run.start_timer() + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + namespace = encode("benchmark") + obj = lib.j_distributed_object_new(namespace, name, distribution) + lib.j_distributed_object_create(obj, batch) + lib.j_distributed_object_delete(obj, deletebatch) + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_distributed_object_unref(obj) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + assert lib.j_batch_execute(deletebatch) + lib.j_batch_unref(batch) + lib.j_batch_unref(deletebatch) + lib.j_distribution_unref(distribution) + +def benchmark_distributed_object_delete(run): + _benchmark_distributed_object_delete(run, False) + +def benchmark_distributed_object_delete_batch(run): + _benchmark_distributed_object_delete(run, True) + +def _benchmark_distributed_object_delete(run, use_batch): + distribution = lib.j_distribution_new(lib.J_DISTRIBUTION_ROUND_ROBIN) + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + namespace = encode("benchmark") + obj = lib.j_distributed_object_new(namespace, name, distribution) + lib.j_distributed_object_create(obj, batch) + lib.j_distributed_object_unref(obj) + assert lib.j_batch_execute(batch) + run.start_timer() + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + namespace = encode("benchmark") + obj = lib.j_distributed_object_new(namespace, name, distribution) + lib.j_distributed_object_delete(obj, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_distributed_object_unref(obj) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + lib.j_batch_unref(batch) + lib.j_distribution_unref(distribution) + +def benchmark_distributed_object_status(run): + _benchmark_distributed_object_status(run, False) + +def benchmark_distributed_object_status_batch(run): + _benchmark_distributed_object_status(run, True) + +def _benchmark_distributed_object_status(run, use_batch): + run.iterations = 10 * run.iterations if use_batch else run.iterations + run.operations = run.iterations + distribution = lib.j_distribution_new(lib.J_DISTRIBUTION_ROUND_ROBIN) + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + name = encode("benchmark") + obj = lib.j_distributed_object_new(name, name, distribution) + lib.j_distributed_object_create(obj, batch) + size_ptr = ffi.new("unsigned long*") + modification_time_ptr = ffi.new("long*") + character = encode("A") + lib.j_distributed_object_write(obj, character, 1, 0, size_ptr, batch) + assert lib.j_batch_execute(batch) + run.start_timer() + for i in range(run.iterations): + lib.j_distributed_object_status(obj, modification_time_ptr, size_ptr, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + lib.j_distributed_object_delete(obj, batch) + assert lib.j_batch_execute(batch) + lib.j_distributed_object_unref(obj) + lib.j_batch_unref(batch) + lib.j_distribution_unref(distribution) + +def benchmark_distributed_object_read(run): + _benchmark_distributed_object_read(run, False, 4 * 1024) + +def benchmark_distributed_object_read_batch(run): + _benchmark_distributed_object_read(run, True, 4 * 1024) + +def _benchmark_distributed_object_read(run, use_batch, block_size): + run.iterations = 10 * run.iterations if use_batch else run.iterations + run.operations = run.iterations + distribution = lib.j_distribution_new(lib.J_DISTRIBUTION_ROUND_ROBIN) + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + name = encode("benchmark") + obj = lib.j_distributed_object_new(name, name, distribution) + dummy = ffi.new("char[]", block_size) + size_ptr = ffi.new("unsigned long*") + lib.j_distributed_object_create(obj, batch) + for i in range(run.iterations): + lib.j_distributed_object_write(obj, dummy, block_size, i*block_size, + size_ptr, batch) + assert lib.j_batch_execute(batch) + assert size_ptr[0] == run.iterations * block_size + run.start_timer() + for i in range(run.iterations): + lib.j_distributed_object_read(obj, dummy, block_size, i * block_size, + size_ptr, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + assert size_ptr[0] == block_size + if use_batch: + assert lib.j_batch_execute(batch) + assert size_ptr[0] == run.iterations * block_size + run.stop_timer() + lib.j_distributed_object_delete(obj, batch) + assert lib.j_batch_execute(batch) + lib.j_distribution_unref(distribution) + lib.j_batch_unref(batch) + lib.j_distributed_object_unref(obj) + +def benchmark_distributed_object_write(run): + _benchmark_distributed_object_write(run, False, 4 * 1024) + +def benchmark_distributed_object_write_batch(run): + _benchmark_distributed_object_write(run, True, 4 * 1024) + +def _benchmark_distributed_object_write(run, use_batch, block_size): + run.iterations = 10 * run.iterations if use_batch else run.iterations + run.operations = run.iterations + distribution = lib.j_distribution_new(lib.J_DISTRIBUTION_ROUND_ROBIN) + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + name = encode("benchmark") + obj = lib.j_distributed_object_new(name, name, distribution) + lib.j_distributed_object_create(obj, batch) + dummy = ffi.new("char[]", block_size) + size_ptr = ffi.new("unsigned long*") + assert lib.j_batch_execute(batch) + run.start_timer() + for i in range(run.iterations): + lib.j_distributed_object_write(obj, dummy, block_size, i*block_size, + size_ptr, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + assert size_ptr[0] == block_size + if use_batch: + assert lib.j_batch_execute(batch) + assert size_ptr[0] == run.iterations * block_size + run.stop_timer() + lib.j_distributed_object_delete(obj, batch) + assert lib.j_batch_execute(batch) + lib.j_distributed_object_unref(obj) + lib.j_batch_unref(batch) + lib.j_distribution_unref(distribution) + +def benchmark_distributed_object_unordered_create_delete(run): + _benchmark_distributed_object_unordered_create_delete(run, False) + +def benchmark_distributed_object_unordered_create_delete_batch(run): + _benchmark_distributed_object_unordered_create_delete(run, True) + +def _benchmark_distributed_object_unordered_create_delete(run, use_batch): + distribution = lib.j_distribution_new(lib.J_DISTRIBUTION_ROUND_ROBIN) + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + run.start_timer() + for i in range(run.iterations): + namespace = encode("benchmark") + name = encode(f"benchmark-{i}") + obj = lib.j_distributed_object_new(namespace, name, distribution) + lib.j_distributed_object_create(obj, batch) + lib.j_distributed_object_delete(obj, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_distributed_object_unref(obj) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + lib.j_batch_unref(batch) + lib.j_distribution_unref(distribution) + run.operations = run.iterations * 2 diff --git a/benchmark/python/object/object.py b/benchmark/python/object/object.py new file mode 100644 index 000000000..7a9d1fc4b --- /dev/null +++ b/benchmark/python/object/object.py @@ -0,0 +1,194 @@ +from benchmarkrun import BenchmarkRun, append_to_benchmark_list_and_run +from julea import lib, encode, ffi + +def benchmark_object(benchmarkrun_list, iterations, machine_readable): + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/create", iterations, machine_readable), benchmark_object_create) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/create-batch", iterations, machine_readable), benchmark_object_create_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/delete", iterations, machine_readable), benchmark_object_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/delete-batch", iterations, machine_readable), benchmark_object_delete_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/status", iterations, machine_readable), benchmark_object_status) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/status-batch", iterations, machine_readable), benchmark_object_status_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/read", iterations, machine_readable), benchmark_object_read) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/read-batch", iterations, machine_readable), benchmark_object_read_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/write", iterations, machine_readable), benchmark_object_write) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/write-batch", iterations, machine_readable), benchmark_object_write_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/unordered-create-delete", iterations, machine_readable), benchmark_object_unordered_create_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/unordered-create-delete-batch", iterations, machine_readable), benchmark_object_unordered_create_delete_batch) + + +def benchmark_object_create(run): + _benchmark_object_create(run, False) + +def benchmark_object_create_batch(run): + _benchmark_object_create(run, True) + +def _benchmark_object_create(run, use_batch): + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + deletebatch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + run.start_timer() + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + namespace = encode("benchmark") + obj = lib.j_object_new(namespace, name) + lib.j_object_create(obj, batch) + lib.j_object_delete(obj, deletebatch) + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_object_unref(obj) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + assert lib.j_batch_execute(deletebatch) + lib.j_batch_unref(batch) + lib.j_batch_unref(deletebatch) + + +def benchmark_object_delete(run): + _benchmark_object_delete(run, False) + +def benchmark_object_delete_batch(run): + _benchmark_object_delete(run, True) + +def _benchmark_object_delete(run, use_batch): + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + namespace = encode("benchmark") + obj = lib.j_object_new(namespace, name) + lib.j_object_create(obj, batch) + lib.j_object_unref(obj) + assert lib.j_batch_execute(batch) + run.start_timer() + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + namespace = encode("benchmark") + obj = lib.j_object_new(namespace, name) + lib.j_object_delete(obj, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_object_unref(obj) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + lib.j_batch_unref(batch) + +def benchmark_object_status(run): + _benchmark_object_status(run, False) + +def benchmark_object_status_batch(run): + _benchmark_object_status(run, True) + +def _benchmark_object_status(run, use_batch): + run.iterations = 10 * run.iterations if use_batch else run.iterations + run.operations = run.iterations + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + name = encode("benchmark") + obj = lib.j_object_new(name, name) + lib.j_object_create(obj, batch) + size_ptr = ffi.new("unsigned long*") + modification_time_ptr = ffi.new("long*") + character = encode("A") + lib.j_object_write(obj, character, 1, 0, size_ptr, batch) + assert lib.j_batch_execute(batch) + run.start_timer() + for i in range(run.iterations): + lib.j_object_status(obj, modification_time_ptr, size_ptr, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + lib.j_object_delete(obj, batch) + assert lib.j_batch_execute(batch) + lib.j_object_unref(obj) + lib.j_batch_unref(batch) + +def benchmark_object_read(run): + _benchmark_object_read(run, False, 4 * 1024) + +def benchmark_object_read_batch(run): + _benchmark_object_read(run, True, 4 * 1024) + +def _benchmark_object_read(run, use_batch, block_size): + run.iterations = 10 * run.iterations if use_batch else run.iterations + run.operations = run.iterations + dummy = ffi.new("char[]", block_size) + nb_ptr = ffi.new("unsigned long*") + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + name = encode("benchmark") + obj = lib.j_object_new(name, name) + lib.j_object_create(obj, batch) + for i in range(run.iterations): + lib.j_object_write(obj, dummy, block_size, i * block_size, nb_ptr, + batch) + assert lib.j_batch_execute(batch) + assert nb_ptr[0] == run.iterations * block_size + run.start_timer() + for i in range(run.iterations): + lib.j_object_read(obj, dummy, block_size, i * block_size, nb_ptr, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + assert nb_ptr[0] == block_size + if use_batch: + assert lib.j_batch_execute(batch) + assert nb_ptr[0] == run.iterations * block_size + run.stop_timer() + lib.j_object_delete(obj, batch) + assert lib.j_batch_execute(batch) + lib.j_object_unref(obj) + lib.j_batch_unref(batch) + +def benchmark_object_write(run): + _benchmark_object_write(run, False, 4 * 1024) + +def benchmark_object_write_batch(run): + _benchmark_object_write(run, True, 4 * 1024) + +def _benchmark_object_write(run, use_batch, block_size): + run.iterations = 10 * run.iterations if use_batch else run.iterations + run.operations = run.iterations + dummy = ffi.new("char[]", block_size) + nb_ptr = ffi.new("unsigned long*") + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + name = encode("benchmark") + obj = lib.j_object_new(name, name) + lib.j_object_create(obj, batch) + run.start_timer() + for i in range(run.iterations): + lib.j_object_write(obj, dummy, block_size, i * block_size, nb_ptr, + batch) + if not use_batch: + assert lib.j_batch_execute(batch) + assert nb_ptr[0] == block_size + if use_batch: + assert lib.j_batch_execute(batch) + assert nb_ptr[0] == run.iterations * block_size + run.stop_timer() + lib.j_object_delete(obj, batch) + assert lib.j_batch_execute(batch) + lib.j_object_unref(obj) + lib.j_batch_unref(batch) + +def benchmark_object_unordered_create_delete(run): + _benchmark_object_unordered_create_delete(run, False) + +def benchmark_object_unordered_create_delete_batch(run): + _benchmark_object_unordered_create_delete(run, True) + +def _benchmark_object_unordered_create_delete(run, use_batch): + batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + run.start_timer() + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + namespace = encode("benchmark") + obj = lib.j_object_new(namespace, name) + lib.j_object_create(obj, batch) + lib.j_object_delete(obj, batch) + if not use_batch: + assert lib.j_batch_execute(batch) + lib.j_object_unref(obj) + if use_batch: + assert lib.j_batch_execute(batch) + run.stop_timer() + lib.j_batch_unref(batch) + run.operations = run.iterations * 2 diff --git a/python/build.py b/python/build.py new file mode 100644 index 000000000..84a7cc286 --- /dev/null +++ b/python/build.py @@ -0,0 +1,5 @@ +from build_helper import build, copy_main_module + +if __name__ == "__main__": + build(["julea", "julea-object", "julea-kv", "julea-db", "julea-item"]) + copy_main_module() diff --git a/python/build_helper.py b/python/build_helper.py new file mode 100644 index 000000000..98675f5f2 --- /dev/null +++ b/python/build_helper.py @@ -0,0 +1,133 @@ +from os import popen, system +from os.path import dirname +import cffi + +def create_header(filename, libraries): + content = """typedef int gint; +typedef unsigned int guint; +typedef gint gboolean; +typedef char gchar; + +typedef unsigned short guint16; +typedef signed int gint32; +typedef unsigned int guint32; +typedef signed long gint64; +typedef unsigned long guint64; + +typedef void* gpointer; +typedef const void *gconstpointer; + +typedef unsigned long gsize; + +typedef guint32 GQuark; + +typedef struct _GError GError; +struct _GError +{ + GQuark domain; + gint code; + gchar *message; +}; + +typedef struct _GModule GModule; + +typedef struct _GInputStream GInputStream; +typedef struct _GOutputStream GOutputStream; + +typedef struct _GKeyFile GKeyFile; + +typedef struct _GSocketConnection GSocketConnection; + +typedef void (*GDestroyNotify) (gpointer data); + +typedef struct _bson_t +{ + uint32_t flags; + uint32_t len; + uint8_t padding[120]; +} bson_t; + +typedef struct JBatch JBatch; +extern "Python" void cffi_j_kv_get_function(gpointer, guint32, gpointer); +extern "Python" void cffi_j_batch_async_callback(JBatch*, gboolean, gpointer); + +""" + for library in libraries: + content+=f"#include <{library}.h>\n" + with open(filename, "w") as file: + file.write(content) + +def get_additional_compiler_flags(libraries, remove_sanitize=True): + flags_buffer = popen(f"pkg-config --cflags {' '.join(libraries)}") + flags = flags_buffer.read().strip().split(' ') + # remove duplicate parameters + flags = [*set(flags)] + if remove_sanitize: + for s in flags: + if "-fsanitize" in s: + flags.remove(s) + return flags + +def get_include_dirs(flags): + return [ str.strip("-I") for str in flags if "-I" in str ] + +def collect_julea(filename, libraries, debug = False): + temp_filename = "temp.h" + create_header(temp_filename, libraries) + includes = get_additional_compiler_flags(libraries) + flags = list(filter(lambda entry: not "dependencies" in entry, includes)) + # create dummy headers for files intentionally not included + with open("glib.h", "w") as file: + file.write("") + with open("gmodule.h", "w") as file: + file.write("") + with open("bson.h", "w") as file: + file.write("") + system("mkdir -p gio") + with open("gio/gio.h", "w") as file: + file.write("") + # list of macros to be ignored + macros = [ + "-D'G_DEFINE_AUTOPTR_CLEANUP_FUNC(x, y)='", + "-D'G_END_DECLS='", + "-D'G_BEGIN_DECLS='", + "-D'G_GNUC_WARN_UNUSED_RESULT='", + "-D'G_GNUC_PRINTF(x, y)='" + ] + # let preprocessor collect all declarations + system(f"gcc -E -P {' '.join(macros)} {temp_filename} -I. {' '.join(flags)} -o {filename}") + # remove temporary files needed to please the preprocessor + system(f"rm -rf glib.h gmodule.h bson.h gio {temp_filename}") + +def process(libs, tempheader, debug=False): + ffi = cffi.FFI() + libraryname = "julea_wrapper" + with open(tempheader, "r") as file: + header_content = file.read() + includes = get_additional_compiler_flags(libs+["glib-2.0"], remove_sanitize=True) + include_dirs = get_include_dirs(includes) + ffi.cdef(header_content, override=True) + outdir = f"{dirname(__file__)}/../bld/" + headerincludes = "" + for lib in libs: + headerincludes += f'#include "{lib}.h"\n' + ffi.set_source( + libraryname, + headerincludes, + libraries=libs+["kv-null"], + include_dirs=include_dirs, + library_dirs=[outdir], + extra_compile_args=includes, + extra_link_args=["-Wl,-rpath,."] + ) + ffi.compile(tmpdir=outdir, verbose=debug) + if not debug: + system(f"rm -f {tempheader} {outdir+libraryname}.o {outdir+libraryname}.c") + +def copy_main_module(): + system(f"cp {dirname(__file__)}/julea.py {dirname(__file__)}/../bld/julea.py") + +def build(include_libs, debug=False): + header_name = "header_julea.h" + collect_julea(header_name, include_libs, debug) + process(include_libs, header_name, debug) diff --git a/python/cffi-requirements.txt b/python/cffi-requirements.txt new file mode 100644 index 000000000..8cb00ea70 --- /dev/null +++ b/python/cffi-requirements.txt @@ -0,0 +1,2 @@ +cffi==1.15.1 +pycparser==2.21 diff --git a/python/example/Makefile b/python/example/Makefile new file mode 100644 index 000000000..943e3ba6f --- /dev/null +++ b/python/example/Makefile @@ -0,0 +1,8 @@ +run: + ../../scripts/setup.sh start + python hello-world.py + ../../scripts/setup.sh stop + +clean: + ../../scripts/setup.sh stop + ../../scripts/setup.sh clean diff --git a/python/example/hello-world.py b/python/example/hello-world.py new file mode 100644 index 000000000..aa9713243 --- /dev/null +++ b/python/example/hello-world.py @@ -0,0 +1,72 @@ +from julea import JBatchResult, JBatch, ffi, lib, encode, read_from_buffer + +if __name__ == "__main__": + try: + value_obj = encode("Hello Object!") + value_kv = encode("Hello Key-Value!") + value_db = encode("Hello Database!") + + result = JBatchResult() + hello = encode("hello") + world = encode("world") + nbytes_ptr = ffi.new("unsigned long*") + _object = lib.j_object_new(hello, world) + kv = lib.j_kv_new(hello, world) + schema = lib.j_db_schema_new(hello, world, ffi.NULL) + lib.j_db_schema_add_field(schema, hello, lib.J_DB_TYPE_STRING, ffi.NULL) + entry = lib.j_db_entry_new(schema, ffi.NULL) + + lib.j_db_entry_set_field(entry, hello, value_db, len(value_db), ffi.NULL) + + with JBatch(result) as batch: + lib.j_object_create(_object, batch) + lib.j_object_write(_object, value_obj, len(value_obj), 0, nbytes_ptr, batch) + lib.j_kv_put(kv, value_kv, len(value_kv), ffi.NULL, batch) + lib.j_db_schema_create(schema, batch, ffi.NULL) + lib.j_db_entry_insert(entry, batch, ffi.NULL) + + if result.IsSuccess: + result = JBatchResult() + buffer = ffi.new("gchar[]", 128) + with JBatch(result) as batch: + lib.j_object_read(_object, buffer, 128, 0, nbytes_ptr, batch) + if result.IsSuccess: + print(f"Object contains: '{read_from_buffer(buffer)}' ({nbytes_ptr[0]} bytes)") + with JBatch(result) as batch: + lib.j_object_delete(_object, batch) + + result = JBatchResult() + with JBatch(result) as batch: + buffer_ptr = ffi.new("void**") + length = ffi.new("unsigned int *") + lib.j_kv_get(kv, buffer_ptr, length, batch) + if result.IsSuccess: + char_buff_ptr = ffi.cast("char**", buffer_ptr) + print(f"KV contains: '{read_from_buffer(char_buff_ptr[0])}' ({length[0]} bytes)") + with JBatch(result) as batch: + lib.j_kv_delete(kv, batch) + + try: + selector = lib.j_db_selector_new(schema, lib.J_DB_SELECTOR_MODE_AND, ffi.NULL) + lib.j_db_selector_add_field(selector, hello, lib.J_DB_SELECTOR_OPERATOR_EQ, value_db, len(value_db), ffi.NULL) + iterator = lib.j_db_iterator_new(schema, selector, ffi.NULL) + + while lib.j_db_iterator_next(iterator, ffi.NULL): + _type = ffi.new("JDBType *") + db_field_ptr = ffi.new("void**") + db_length_ptr = ffi.new("unsigned long*") + lib.j_db_iterator_get_field(iterator, hello, _type, db_field_ptr, db_length_ptr, ffi.NULL) + print(f"DB contains: '{read_from_buffer(db_field_ptr[0])}' ({db_length_ptr[0]} bytes)") + + finally: + with JBatch(result) as batch: + lib.j_db_entry_delete(entry, selector, batch, ffi.NULL) + lib.j_db_schema_delete(schema, batch, ffi.NULL) + lib.j_db_selector_unref(selector) + lib.j_db_iterator_unref(iterator) + + finally: + lib.j_kv_unref(kv) + lib.j_object_unref(_object) + lib.j_db_schema_unref(schema) + lib.j_db_entry_unref(entry) diff --git a/python/julea.py b/python/julea.py new file mode 100644 index 000000000..9020321d8 --- /dev/null +++ b/python/julea.py @@ -0,0 +1,50 @@ +from julea_wrapper import lib, ffi + +encoding = 'utf-8' + +def encode(string): + result = ffi.new('char[]', string.encode(encoding)) + return result + +def read_from_buffer(buffer): + char = ffi.cast('char*', buffer) + bytearr = b'' + i = 0 + byte = char[i] + while byte != b'\x00': + bytearr += byte + i += 1 + byte = char[i] + return bytearr.decode() + +class JBatchResult: + IsSuccess = False + + def __init__(self): + pass + + def Succeed(self): + self.IsSuccess = True + + def Fail(self): + self.IsSuccess = False; + +class JBatch: + def __init__(self, result): + template = lib.J_SEMANTICS_TEMPLATE_DEFAULT + self.batch = lib.j_batch_new_for_template(template) + self.result = result + + def __enter__(self): + return self.batch + + def __exit__(self, exc_type, exc_value, tb): + if lib.j_batch_execute(self.batch): + self.result.Succeed() + else: + self.result.Fail() + lib.j_batch_unref(self.batch) + if exc_type is not None: + return False + else: + return True diff --git a/scripts/benchmark.sh b/scripts/benchmark.sh index e3c0f494b..594a639a7 100755 --- a/scripts/benchmark.sh +++ b/scripts/benchmark.sh @@ -37,6 +37,7 @@ usage () #export G_SLICE=debug-blocks set_path +set_python_path set_library_path set_backend_path set_hdf_path diff --git a/scripts/common b/scripts/common index d3b57cc8c..7098ad0f4 100644 --- a/scripts/common +++ b/scripts/common @@ -65,6 +65,31 @@ set_path () export PATH } +set_python_path() +{ + local build_dir + local old_python_path + + build_dir="$(get_directory "${SELF_DIR}/..")/bld" + old_python_path="${PYTHONPATH}" + + if test -n "${JULEA_PREFIX}" + then + PYTHONPATH="${JULEA_PREFIX}/bin" + else + test -d "${build_dir}" || error_build_directory_not_found + + PYTHONPATH="${build_dir}" + fi + + if test -n "${old_python_path}" + then + PYTHONPATH="${PYTHONPATH}:${old_python_path}" + fi + + export PYTHONPATH +} + set_library_path () { local build_dir diff --git a/scripts/environment.sh b/scripts/environment.sh index 64f28e404..14628c79f 100755 --- a/scripts/environment.sh +++ b/scripts/environment.sh @@ -53,6 +53,7 @@ fi JULEA_ENVIRONMENT=1 set_path +set_python_path set_library_path set_pkg_config_path set_backend_path diff --git a/scripts/setup.sh b/scripts/setup.sh index b03b632b1..5ebaf5fbc 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -68,6 +68,7 @@ MODE="$1" #export G_MESSAGES_DEBUG=JULEA set_path +set_python_path set_library_path set_backend_path diff --git a/scripts/test.sh b/scripts/test.sh index 236ce4512..b9e4e7dcd 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -37,6 +37,7 @@ usage () export G_SLICE=debug-blocks set_path +set_python_path set_library_path set_backend_path set_hdf_path From 241a5742ae30164cd586fa3a128bb8c2b2d2e9ff Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Tue, 13 Jun 2023 14:41:29 +0200 Subject: [PATCH 02/18] make example runnable --- python/build_helper.py | 4 +++- python/example/hello-world.py | 5 +---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/python/build_helper.py b/python/build_helper.py index 98675f5f2..ea3c9cdec 100644 --- a/python/build_helper.py +++ b/python/build_helper.py @@ -7,6 +7,8 @@ def create_header(filename, libraries): typedef unsigned int guint; typedef gint gboolean; typedef char gchar; +typedef double gdouble; +typedef float gfloat; typedef unsigned short guint16; typedef signed int gint32; @@ -95,7 +97,7 @@ def collect_julea(filename, libraries, debug = False): "-D'G_GNUC_PRINTF(x, y)='" ] # let preprocessor collect all declarations - system(f"gcc -E -P {' '.join(macros)} {temp_filename} -I. {' '.join(flags)} -o {filename}") + system(f"cc -E -P {' '.join(macros)} {temp_filename} -I. {' '.join(flags)} -o {filename}") # remove temporary files needed to please the preprocessor system(f"rm -rf glib.h gmodule.h bson.h gio {temp_filename}") diff --git a/python/example/hello-world.py b/python/example/hello-world.py index aa9713243..ec36dffe7 100644 --- a/python/example/hello-world.py +++ b/python/example/hello-world.py @@ -24,7 +24,6 @@ lib.j_kv_put(kv, value_kv, len(value_kv), ffi.NULL, batch) lib.j_db_schema_create(schema, batch, ffi.NULL) lib.j_db_entry_insert(entry, batch, ffi.NULL) - if result.IsSuccess: result = JBatchResult() buffer = ffi.new("gchar[]", 128) @@ -55,16 +54,14 @@ _type = ffi.new("JDBType *") db_field_ptr = ffi.new("void**") db_length_ptr = ffi.new("unsigned long*") - lib.j_db_iterator_get_field(iterator, hello, _type, db_field_ptr, db_length_ptr, ffi.NULL) + lib.j_db_iterator_get_field(iterator, schema, hello, _type, db_field_ptr, db_length_ptr, ffi.NULL) print(f"DB contains: '{read_from_buffer(db_field_ptr[0])}' ({db_length_ptr[0]} bytes)") - finally: with JBatch(result) as batch: lib.j_db_entry_delete(entry, selector, batch, ffi.NULL) lib.j_db_schema_delete(schema, batch, ffi.NULL) lib.j_db_selector_unref(selector) lib.j_db_iterator_unref(iterator) - finally: lib.j_kv_unref(kv) lib.j_object_unref(_object) From 9e21f7448e1c8c254420843a38e4ff3465b1f9ed Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Tue, 13 Jun 2023 14:57:56 +0200 Subject: [PATCH 03/18] Use meson for flags to reduce dependencies --- python/build.py | 8 ++++++-- python/build_helper.py | 41 ++++++++++++++++++++++++----------------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/python/build.py b/python/build.py index 84a7cc286..894adf9c3 100644 --- a/python/build.py +++ b/python/build.py @@ -1,5 +1,9 @@ from build_helper import build, copy_main_module +import sys +import os if __name__ == "__main__": - build(["julea", "julea-object", "julea-kv", "julea-db", "julea-item"]) - copy_main_module() + build_dir = os.path.abspath(sys.argv[1]) + print(build_dir) + build(build_dir, ["julea", "julea-object", "julea-kv", "julea-db", "julea-item"]) + copy_main_module(build_dir) diff --git a/python/build_helper.py b/python/build_helper.py index ea3c9cdec..83c453ca6 100644 --- a/python/build_helper.py +++ b/python/build_helper.py @@ -1,6 +1,9 @@ from os import popen, system from os.path import dirname import cffi +import json +import os +import itertools def create_header(filename, libraries): content = """typedef int gint; @@ -59,16 +62,20 @@ def create_header(filename, libraries): with open(filename, "w") as file: file.write(content) -def get_additional_compiler_flags(libraries, remove_sanitize=True): - flags_buffer = popen(f"pkg-config --cflags {' '.join(libraries)}") - flags = flags_buffer.read().strip().split(' ') - # remove duplicate parameters - flags = [*set(flags)] - if remove_sanitize: - for s in flags: - if "-fsanitize" in s: - flags.remove(s) - return flags +def get_additional_compiler_flags(libraries): + print("HEH") + flags = list(set(itertools.chain.from_iterable(map( + lambda x: x["target_sources"][0]["parameters"], + [x for x in json.load(os.popen(f"meson introspect --targets bld")) if x["name"] in libraries])))) + clean = [] + for s in flags: + if "-W" in s: + pass + elif "-fsanitize" in s: + pass + else: + clean.append(s) + return clean def get_include_dirs(flags): return [ str.strip("-I") for str in flags if "-I" in str ] @@ -101,15 +108,15 @@ def collect_julea(filename, libraries, debug = False): # remove temporary files needed to please the preprocessor system(f"rm -rf glib.h gmodule.h bson.h gio {temp_filename}") -def process(libs, tempheader, debug=False): +def process(build_dir, libs, tempheader, debug=False): ffi = cffi.FFI() libraryname = "julea_wrapper" with open(tempheader, "r") as file: header_content = file.read() - includes = get_additional_compiler_flags(libs+["glib-2.0"], remove_sanitize=True) + includes = get_additional_compiler_flags(libs+["glib-2.0"]) include_dirs = get_include_dirs(includes) ffi.cdef(header_content, override=True) - outdir = f"{dirname(__file__)}/../bld/" + outdir = build_dir headerincludes = "" for lib in libs: headerincludes += f'#include "{lib}.h"\n' @@ -126,10 +133,10 @@ def process(libs, tempheader, debug=False): if not debug: system(f"rm -f {tempheader} {outdir+libraryname}.o {outdir+libraryname}.c") -def copy_main_module(): - system(f"cp {dirname(__file__)}/julea.py {dirname(__file__)}/../bld/julea.py") +def copy_main_module(build_dir): + system(f"cp {dirname(__file__)}/julea.py {build_dir}/julea.py") -def build(include_libs, debug=False): +def build(build_dir, include_libs, debug=False): header_name = "header_julea.h" collect_julea(header_name, include_libs, debug) - process(include_libs, header_name, debug) + process(build_dir, include_libs, header_name, debug) From c890e37614378a1dc978f57c838274b0be2b009d Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Tue, 13 Jun 2023 14:59:29 +0200 Subject: [PATCH 04/18] Remove detailed struct definitons --- python/build_helper.py | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/python/build_helper.py b/python/build_helper.py index 83c453ca6..f4e414df2 100644 --- a/python/build_helper.py +++ b/python/build_helper.py @@ -27,12 +27,7 @@ def create_header(filename, libraries): typedef guint32 GQuark; typedef struct _GError GError; -struct _GError -{ - GQuark domain; - gint code; - gchar *message; -}; +struct _GError { ...; }; typedef struct _GModule GModule; @@ -45,17 +40,9 @@ def create_header(filename, libraries): typedef void (*GDestroyNotify) (gpointer data); -typedef struct _bson_t -{ - uint32_t flags; - uint32_t len; - uint8_t padding[120]; -} bson_t; +typedef struct _bson_t { ...; } bson_t; typedef struct JBatch JBatch; -extern "Python" void cffi_j_kv_get_function(gpointer, guint32, gpointer); -extern "Python" void cffi_j_batch_async_callback(JBatch*, gboolean, gpointer); - """ for library in libraries: content+=f"#include <{library}.h>\n" @@ -63,7 +50,6 @@ def create_header(filename, libraries): file.write(content) def get_additional_compiler_flags(libraries): - print("HEH") flags = list(set(itertools.chain.from_iterable(map( lambda x: x["target_sources"][0]["parameters"], [x for x in json.load(os.popen(f"meson introspect --targets bld")) if x["name"] in libraries])))) From 1f2e27c522da50ec37665cb81fb78820751f380d Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Tue, 13 Jun 2023 16:20:41 +0200 Subject: [PATCH 05/18] Tiden up c definitons --- python/build.py | 73 +++++++++++++++++++++++++++++++++++++++- python/build_helper.py | 76 +++++++++++------------------------------- 2 files changed, 92 insertions(+), 57 deletions(-) diff --git a/python/build.py b/python/build.py index 894adf9c3..9d78aebea 100644 --- a/python/build.py +++ b/python/build.py @@ -2,8 +2,79 @@ import sys import os +# types used in JULEA include headers +# use '...' for types which are not accessed in header files +typedefs = { + # basic glib types + 'gint': 'int', + 'guint': 'unsigned int', + 'gboolean': 'int', + 'gchar': 'char', + 'gdouble': 'double', + 'gfloat': 'float', + 'guint16': 'unsigned short', + 'gint32': 'signed int', + 'guint32': 'unsigned int', + 'gint64': 'signed long', + 'guint64': 'unsigned long', + 'gpointer': 'void*', + 'gconstpointer': 'const void*', + 'gsize': 'unsigned long', + + # glib types + 'GQuark': 'guint32', + 'GError': 'struct _GError', # struct used in static value + 'GModule': '...', + 'GInputStream': '...', + 'GOutputStream': '...', + 'GKeyFile': '...', + 'GSocketConnection': '...', + 'void (*GDestroyNotify) (gpointer data)': '', # function definition + + 'bson_t': 'struct _bson_t', # sturct used in static value + + 'JBatch': '...', +} + +# list of macros to be ignored +macros = [ + 'G_DEFINE_AUTOPTR_CLEANUP_FUNC(x, y)', + 'G_END_DECLS', + 'G_BEGIN_DECLS', + 'G_GNUC_WARN_UNUSED_RESULT', + 'G_GNUC_PRINTF(x, y)' +] + +# JULEA modules which available through the interface +# it is expected that 'include/.h' is a header file! +libraries = [ + "julea", + "julea-object", + "julea-kv", + "julea-db", + "julea-item" +] + +def usage(): + print("Build python bindings for JULEA with cffi.") + print() + print(f"python {sys.argv[0]} ") + print() + print("Make sure to execute it from the JULEA-repo root directory!") + exit(1) + +def err(msg): + print(msg) + exit(1) + if __name__ == "__main__": + if len(sys.argv) < 2: + usage() build_dir = os.path.abspath(sys.argv[1]) + if not os.path.isdir(build_dir): + err(f"Build directory: '{build_dir}' does not exist!") + if not os.path.isfile(os.path.abspath('.') + "/meson.build"): + err("The execution directory is apperntly not the JULEA-repo root directory") print(build_dir) - build(build_dir, ["julea", "julea-object", "julea-kv", "julea-db", "julea-item"]) + build(build_dir, libraries, typedefs, macros, debug=True) copy_main_module(build_dir) diff --git a/python/build_helper.py b/python/build_helper.py index f4e414df2..adc19e951 100644 --- a/python/build_helper.py +++ b/python/build_helper.py @@ -5,54 +5,21 @@ import os import itertools -def create_header(filename, libraries): - content = """typedef int gint; -typedef unsigned int guint; -typedef gint gboolean; -typedef char gchar; -typedef double gdouble; -typedef float gfloat; - -typedef unsigned short guint16; -typedef signed int gint32; -typedef unsigned int guint32; -typedef signed long gint64; -typedef unsigned long guint64; - -typedef void* gpointer; -typedef const void *gconstpointer; - -typedef unsigned long gsize; - -typedef guint32 GQuark; - -typedef struct _GError GError; -struct _GError { ...; }; - -typedef struct _GModule GModule; - -typedef struct _GInputStream GInputStream; -typedef struct _GOutputStream GOutputStream; - -typedef struct _GKeyFile GKeyFile; - -typedef struct _GSocketConnection GSocketConnection; - -typedef void (*GDestroyNotify) (gpointer data); - -typedef struct _bson_t { ...; } bson_t; - -typedef struct JBatch JBatch; -""" +def create_header(filename, libraries, typedefs): + content = "" + for (k, v) in typedefs.items(): + content += f"typedef {v} {k};\n" + if 'struct' in v: + content += f"{v} {{ ...; }};\n" for library in libraries: content+=f"#include <{library}.h>\n" with open(filename, "w") as file: file.write(content) -def get_additional_compiler_flags(libraries): +def get_additional_compiler_flags(libraries, build_dir): flags = list(set(itertools.chain.from_iterable(map( lambda x: x["target_sources"][0]["parameters"], - [x for x in json.load(os.popen(f"meson introspect --targets bld")) if x["name"] in libraries])))) + [x for x in json.load(os.popen(f"meson introspect --targets ${build_dir}")) if x["name"] in libraries])))) clean = [] for s in flags: if "-W" in s: @@ -66,10 +33,10 @@ def get_additional_compiler_flags(libraries): def get_include_dirs(flags): return [ str.strip("-I") for str in flags if "-I" in str ] -def collect_julea(filename, libraries, debug = False): +def collect_julea(filename, libraries, typedefs, macros, debug = False): temp_filename = "temp.h" - create_header(temp_filename, libraries) - includes = get_additional_compiler_flags(libraries) + create_header(temp_filename, libraries, typedefs) + includes = get_additional_compiler_flags(libraries, build_dir) flags = list(filter(lambda entry: not "dependencies" in entry, includes)) # create dummy headers for files intentionally not included with open("glib.h", "w") as file: @@ -81,16 +48,9 @@ def collect_julea(filename, libraries, debug = False): system("mkdir -p gio") with open("gio/gio.h", "w") as file: file.write("") - # list of macros to be ignored - macros = [ - "-D'G_DEFINE_AUTOPTR_CLEANUP_FUNC(x, y)='", - "-D'G_END_DECLS='", - "-D'G_BEGIN_DECLS='", - "-D'G_GNUC_WARN_UNUSED_RESULT='", - "-D'G_GNUC_PRINTF(x, y)='" - ] + macro_flags = map(lambda x: f"-D'{x}='", macros) # let preprocessor collect all declarations - system(f"cc -E -P {' '.join(macros)} {temp_filename} -I. {' '.join(flags)} -o {filename}") + system(f"cc -E -P {' '.join(macro_flags)} {temp_filename} -I. {' '.join(flags)} -o {filename}") # remove temporary files needed to please the preprocessor system(f"rm -rf glib.h gmodule.h bson.h gio {temp_filename}") @@ -101,7 +61,11 @@ def process(build_dir, libs, tempheader, debug=False): header_content = file.read() includes = get_additional_compiler_flags(libs+["glib-2.0"]) include_dirs = get_include_dirs(includes) - ffi.cdef(header_content, override=True) + try: + ffi.cdef(header_content, override=True) + except cffi.CDefError as err: + print(err) + outdir = build_dir headerincludes = "" for lib in libs: @@ -122,7 +86,7 @@ def process(build_dir, libs, tempheader, debug=False): def copy_main_module(build_dir): system(f"cp {dirname(__file__)}/julea.py {build_dir}/julea.py") -def build(build_dir, include_libs, debug=False): +def build(build_dir, include_libs, typedefs, macros, debug=False): header_name = "header_julea.h" - collect_julea(header_name, include_libs, debug) + collect_julea(header_name, include_libs, typedefs, macros, debug) process(build_dir, include_libs, header_name, debug) From 5c1a7766a5ff9b44522708f0fa22376e0e22d5a6 Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Tue, 13 Jun 2023 19:21:59 +0200 Subject: [PATCH 06/18] update readme --- doc/README.md | 1 + doc/python.md | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 doc/python.md diff --git a/doc/README.md b/doc/README.md index 8533cdde1..1c279a717 100644 --- a/doc/README.md +++ b/doc/README.md @@ -19,3 +19,4 @@ Its goal is to provide a solid foundation for storage research and teaching. * [Implementing a Backend](implementing-backend.md) * [JULEA-DB Details](db-code.md) * [HDF5 Support](hdf5.md) +* [Python Library](python.md) diff --git a/doc/python.md b/doc/python.md new file mode 100644 index 000000000..b152a0ba5 --- /dev/null +++ b/doc/python.md @@ -0,0 +1,32 @@ +# Python Bindings + +The JULEA client python bindings are using cffi created bindings. +For that the spack package `py-cffi` must be installed and loaded. + +```sh +. ./scripts/environment.sh +ninja -C bld # ensure binaries are up to date +spack install py-cffi # if not already installed +spack load py-cffi +python python/build.py bld # bld your building directory +``` + +This will create a python library with c bindings resident in the build directory. +After this you can import the library with `import julea` as long as the environment is loaded. +A usage example can be found in `python/example/hello-world.py` + +The JULEA module contains the following parts: + +* `julea.ffi`: basic c defines and functions. Used for null value (`julea.ffi.NULL`) and to allocate heap variables. + (`p = julea.ffi.new(guint*)` will allocate `guint` and return a pointer to it) +* `julea.lib`: JULEA specific defines and functions. (`julea.lib.j_object_new(julea.encode('hello'), julea.encode('world'))`) +* `encode(srt) -> c_str, read_string(c_str) -> str`: string helper to convert python to c strings and the other way around. +* `JBatch` and `JBatchResult`: JULEA works in batches, therefore commands will be queued and then executed at once. + ```python + result = JBatchResult() + with JBatch(result) as batch: + lib.j_object_create(..., batch) + ... + if result.IsSuccess: + ... + ``` From c93b57454ec0d1717b959833dc42bdd2a00922ad Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Tue, 13 Jun 2023 19:22:15 +0200 Subject: [PATCH 07/18] minor fixes --- python/build_helper.py | 8 ++++---- python/example/hello-world.py | 6 +++--- python/julea.py | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/python/build_helper.py b/python/build_helper.py index adc19e951..cd13af453 100644 --- a/python/build_helper.py +++ b/python/build_helper.py @@ -19,7 +19,7 @@ def create_header(filename, libraries, typedefs): def get_additional_compiler_flags(libraries, build_dir): flags = list(set(itertools.chain.from_iterable(map( lambda x: x["target_sources"][0]["parameters"], - [x for x in json.load(os.popen(f"meson introspect --targets ${build_dir}")) if x["name"] in libraries])))) + [x for x in json.load(os.popen(f"meson introspect --targets {build_dir}")) if x["name"] in libraries])))) clean = [] for s in flags: if "-W" in s: @@ -33,7 +33,7 @@ def get_additional_compiler_flags(libraries, build_dir): def get_include_dirs(flags): return [ str.strip("-I") for str in flags if "-I" in str ] -def collect_julea(filename, libraries, typedefs, macros, debug = False): +def collect_julea(filename, libraries, build_dir, typedefs, macros, debug = False): temp_filename = "temp.h" create_header(temp_filename, libraries, typedefs) includes = get_additional_compiler_flags(libraries, build_dir) @@ -59,7 +59,7 @@ def process(build_dir, libs, tempheader, debug=False): libraryname = "julea_wrapper" with open(tempheader, "r") as file: header_content = file.read() - includes = get_additional_compiler_flags(libs+["glib-2.0"]) + includes = get_additional_compiler_flags(libs+["glib-2.0"], build_dir) include_dirs = get_include_dirs(includes) try: ffi.cdef(header_content, override=True) @@ -88,5 +88,5 @@ def copy_main_module(build_dir): def build(build_dir, include_libs, typedefs, macros, debug=False): header_name = "header_julea.h" - collect_julea(header_name, include_libs, typedefs, macros, debug) + collect_julea(header_name, include_libs, build_dir, typedefs, macros, debug) process(build_dir, include_libs, header_name, debug) diff --git a/python/example/hello-world.py b/python/example/hello-world.py index ec36dffe7..2477bea34 100644 --- a/python/example/hello-world.py +++ b/python/example/hello-world.py @@ -30,7 +30,7 @@ with JBatch(result) as batch: lib.j_object_read(_object, buffer, 128, 0, nbytes_ptr, batch) if result.IsSuccess: - print(f"Object contains: '{read_from_buffer(buffer)}' ({nbytes_ptr[0]} bytes)") + print(f"Object contains: '{read_string(buffer)}' ({nbytes_ptr[0]} bytes)") with JBatch(result) as batch: lib.j_object_delete(_object, batch) @@ -41,7 +41,7 @@ lib.j_kv_get(kv, buffer_ptr, length, batch) if result.IsSuccess: char_buff_ptr = ffi.cast("char**", buffer_ptr) - print(f"KV contains: '{read_from_buffer(char_buff_ptr[0])}' ({length[0]} bytes)") + print(f"KV contains: '{read_string(char_buff_ptr[0])}' ({length[0]} bytes)") with JBatch(result) as batch: lib.j_kv_delete(kv, batch) @@ -55,7 +55,7 @@ db_field_ptr = ffi.new("void**") db_length_ptr = ffi.new("unsigned long*") lib.j_db_iterator_get_field(iterator, schema, hello, _type, db_field_ptr, db_length_ptr, ffi.NULL) - print(f"DB contains: '{read_from_buffer(db_field_ptr[0])}' ({db_length_ptr[0]} bytes)") + print(f"DB contains: '{read_string(db_field_ptr[0])}' ({db_length_ptr[0]} bytes)") finally: with JBatch(result) as batch: lib.j_db_entry_delete(entry, selector, batch, ffi.NULL) diff --git a/python/julea.py b/python/julea.py index 9020321d8..9cee7c0e6 100644 --- a/python/julea.py +++ b/python/julea.py @@ -6,7 +6,7 @@ def encode(string): result = ffi.new('char[]', string.encode(encoding)) return result -def read_from_buffer(buffer): +def read_string(buffer): char = ffi.cast('char*', buffer) bytearr = b'' i = 0 From ce2443fa5ef3fd43fc52199bff9eec9afd5c71b3 Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Wed, 14 Jun 2023 13:35:35 +0200 Subject: [PATCH 08/18] Multiplerun benchmarks in python --- benchmark/python/benchmarkrun.py | 50 +++++++++++++++++++++++++++----- benchmark/python/kv/kv.py | 10 +++---- doc/python.md | 2 +- python/build.py | 8 ++++- python/build_helper.py | 14 +++++---- 5 files changed, 63 insertions(+), 21 deletions(-) diff --git a/benchmark/python/benchmarkrun.py b/benchmark/python/benchmarkrun.py index 069d8cb5b..456e5aa6a 100644 --- a/benchmark/python/benchmarkrun.py +++ b/benchmark/python/benchmarkrun.py @@ -7,8 +7,44 @@ def __init__(self, name, iterations, machine_readable): self.timer_started = False self.start = None self.stop = None + self.break_start = None + self.total_break = 0 self.operations = iterations self.machine_readable = machine_readable + self.iteration_count = 0 + self.i = 0 + self.op_duration = 1000 ** 3 + self.batch_send = None + self.batch_clean = None + + def __iter__(self): + self.start_timer() + return self + + def __next__(self): + self.i += 1 + if self.i >= self.operations: + self.i = 0 + self.iteration_count += 1 + if self.batch_send is not None: + if not self.batch_send(): + raise RuntimeError("Failed to execute batch!") + if self.batch_clean is not None: + self.pause_timer() + if not self.batch_clean(): + raise RuntimeError("Failed to clean batch!") + self.continue_timer() + if perf_counter_ns() - self.start > self.op_duration: + self.stop_timer() + raise StopIteration + return self.i + + def pause_timer(self): + self.break_start = perf_counter_ns() + + def continue_timer(self): + self.total_break += perf_counter_ns() - self.break_start + self.break_start = None def start_timer(self): self.timer_started = True @@ -30,7 +66,7 @@ def get_runtime_ns(self): if self.timer_started or self.stop == None: return None else: - return self.stop - self.start + return self.stop - self.start - self.total_break def print_result(self): if self.machine_readable: @@ -38,7 +74,7 @@ def print_result(self): else: name_col = self.name.ljust(60," ") runtime_col = f"{self.get_runtime_s():.3f}".rjust(8," ") + " seconds" - operations_col = f"{int(self.operations/self.get_runtime_s())}/s".rjust(12," ") + operations_col = f"{int(float(self.operations)*self.iteration_count/self.get_runtime_s())}/s".rjust(12," ") print(f"{name_col} | {runtime_col} | {operations_col}") def print_empty(self): @@ -52,11 +88,11 @@ def print_empty(self): def append_to_benchmark_list_and_run(_list, run, func): _list.append(run) - try: - func(run) - run.print_result() - except: - run.print_empty() + # try: + func(run) + run.print_result() + # except: + # run.print_empty() def print_result_table_header(): name_col = "Name".ljust(60," ") diff --git a/benchmark/python/kv/kv.py b/benchmark/python/kv/kv.py index a39d91fef..b7e9f7c2d 100644 --- a/benchmark/python/kv/kv.py +++ b/benchmark/python/kv/kv.py @@ -20,8 +20,10 @@ def benchmark_kv_put_batch(run): def _benchmark_kv_put(run, use_batch): batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) deletebatch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) - run.start_timer() - for i in range(run.iterations): + if use_batch: + run.batch_send = lambda: lib.j_batch_execute(batch) + run.batch_clean = lambda: lib.j_batch_execute(deletebatch) + for i in run: name = encode(f"benchmark-{i}") namespace = encode("benchmark") kv = lib.j_kv_new(namespace, name) @@ -31,10 +33,6 @@ def _benchmark_kv_put(run, use_batch): if not use_batch: assert lib.j_batch_execute(batch) lib.j_kv_unref(kv) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() - assert lib.j_batch_execute(deletebatch) lib.j_batch_unref(batch) lib.j_batch_unref(deletebatch) diff --git a/doc/python.md b/doc/python.md index b152a0ba5..2cbca2815 100644 --- a/doc/python.md +++ b/doc/python.md @@ -12,7 +12,7 @@ python python/build.py bld # bld your building directory ``` This will create a python library with c bindings resident in the build directory. -After this you can import the library with `import julea` as long as the environment is loaded. +After this you can import the library with `import julea` as long as the environment and `py-cffi` is loaded. A usage example can be found in `python/example/hello-world.py` The JULEA module contains the following parts: diff --git a/python/build.py b/python/build.py index 9d78aebea..b7c3b1441 100644 --- a/python/build.py +++ b/python/build.py @@ -55,6 +55,12 @@ "julea-item" ] +# callbacks to python functions to use julea callback functions +callback_functions = [ + "void cffi_j_kv_get_function(gpointer, guint32, gpointer)", + "void cffi_j_batch_async_callback(JBatch*, gboolean, gpointer)", +] + def usage(): print("Build python bindings for JULEA with cffi.") print() @@ -76,5 +82,5 @@ def err(msg): if not os.path.isfile(os.path.abspath('.') + "/meson.build"): err("The execution directory is apperntly not the JULEA-repo root directory") print(build_dir) - build(build_dir, libraries, typedefs, macros, debug=True) + build(build_dir, libraries, typedefs, macros, callback_functions, debug=True) copy_main_module(build_dir) diff --git a/python/build_helper.py b/python/build_helper.py index cd13af453..de2eed349 100644 --- a/python/build_helper.py +++ b/python/build_helper.py @@ -5,14 +5,16 @@ import os import itertools -def create_header(filename, libraries, typedefs): +def create_header(filename, libraries, typedefs, callbacks): content = "" for (k, v) in typedefs.items(): content += f"typedef {v} {k};\n" if 'struct' in v: content += f"{v} {{ ...; }};\n" for library in libraries: - content+=f"#include <{library}.h>\n" + content += f"#include <{library}.h>\n" + for callback in callbacks: + content += f'extern "Python" {callback};' with open(filename, "w") as file: file.write(content) @@ -33,9 +35,9 @@ def get_additional_compiler_flags(libraries, build_dir): def get_include_dirs(flags): return [ str.strip("-I") for str in flags if "-I" in str ] -def collect_julea(filename, libraries, build_dir, typedefs, macros, debug = False): +def collect_julea(filename, libraries, build_dir, typedefs, macros, callbacks, debug): temp_filename = "temp.h" - create_header(temp_filename, libraries, typedefs) + create_header(temp_filename, libraries, typedefs, callbacks) includes = get_additional_compiler_flags(libraries, build_dir) flags = list(filter(lambda entry: not "dependencies" in entry, includes)) # create dummy headers for files intentionally not included @@ -86,7 +88,7 @@ def process(build_dir, libs, tempheader, debug=False): def copy_main_module(build_dir): system(f"cp {dirname(__file__)}/julea.py {build_dir}/julea.py") -def build(build_dir, include_libs, typedefs, macros, debug=False): +def build(build_dir, include_libs, typedefs, macros, callbacks, debug=False): header_name = "header_julea.h" - collect_julea(header_name, include_libs, build_dir, typedefs, macros, debug) + collect_julea(header_name, include_libs, build_dir, typedefs, macros, callbacks, debug) process(build_dir, include_libs, header_name, debug) From f69e8a166b9e57e6a0acc6c85ec45c171053d232 Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Wed, 14 Jun 2023 14:13:37 +0200 Subject: [PATCH 09/18] Updatet kv.py --- benchmark/python/benchmark.py | 15 ++++++------ benchmark/python/benchmarkrun.py | 8 ++++++- benchmark/python/kv/kv.py | 40 ++++++++++++++++---------------- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/benchmark/python/benchmark.py b/benchmark/python/benchmark.py index 1a1f985ea..5d348cc37 100644 --- a/benchmark/python/benchmark.py +++ b/benchmark/python/benchmark.py @@ -12,6 +12,7 @@ if __name__ == "__main__": runs = [] iterations = 1000 + taregt_time = 1000 machine_readable = ("-m" in argv) print_header(machine_readable) @@ -19,14 +20,14 @@ benchmark_kv(runs, iterations, machine_readable) # Object Client - benchmark_distributed_object(runs, iterations, machine_readable) - benchmark_object(runs, iterations, machine_readable) + # benchmark_distributed_object(runs, iterations, machine_readable) + # benchmark_object(runs, iterations, machine_readable) # DB Client - benchmark_db_entry(runs, iterations, machine_readable) - benchmark_db_iterator(runs, iterations, machine_readable) - benchmark_db_schema(runs, iterations, machine_readable) + # benchmark_db_entry(runs, iterations, machine_readable) + # benchmark_db_iterator(runs, iterations, machine_readable) + # benchmark_db_schema(runs, iterations, machine_readable) # Item Client - benchmark_collection(runs, iterations, machine_readable) - benchmark_item(runs, iterations, machine_readable) + # benchmark_collection(runs, iterations, machine_readable) + # benchmark_item(runs, iterations, machine_readable) diff --git a/benchmark/python/benchmarkrun.py b/benchmark/python/benchmarkrun.py index 456e5aa6a..35f72dc07 100644 --- a/benchmark/python/benchmarkrun.py +++ b/benchmark/python/benchmarkrun.py @@ -16,12 +16,18 @@ def __init__(self, name, iterations, machine_readable): self.op_duration = 1000 ** 3 self.batch_send = None self.batch_clean = None + self.batch_setup = None def __iter__(self): self.start_timer() return self def __next__(self): + if self.i == 0 and self.batch_setup is not None: + self.pause_timer() + if not self.batch_setup(): + raise RuntimeError("Failed to setup batch!"); + self.continue_timer() self.i += 1 if self.i >= self.operations: self.i = 0 @@ -34,7 +40,7 @@ def __next__(self): if not self.batch_clean(): raise RuntimeError("Failed to clean batch!") self.continue_timer() - if perf_counter_ns() - self.start > self.op_duration: + if perf_counter_ns() - self.start - self.total_break > self.op_duration: self.stop_timer() raise StopIteration return self.i diff --git a/benchmark/python/kv/kv.py b/benchmark/python/kv/kv.py index b7e9f7c2d..8ae5dd1c5 100644 --- a/benchmark/python/kv/kv.py +++ b/benchmark/python/kv/kv.py @@ -20,9 +20,10 @@ def benchmark_kv_put_batch(run): def _benchmark_kv_put(run, use_batch): batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) deletebatch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) - if use_batch: - run.batch_send = lambda: lib.j_batch_execute(batch) + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) run.batch_clean = lambda: lib.j_batch_execute(deletebatch) + for i in run: name = encode(f"benchmark-{i}") namespace = encode("benchmark") @@ -57,8 +58,10 @@ def _benchmark_kv_get(run, use_batch): lib.j_kv_delete(kv, deletebatch) lib.j_kv_unref(kv) assert lib.j_batch_execute(batch) - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + + for i in run: name = encode(f"benchmark-{i}") namespace = encode("benchmark") kv = lib.j_kv_new(namespace, name) @@ -66,9 +69,7 @@ def _benchmark_kv_get(run, use_batch): if not use_batch: assert lib.j_batch_execute(batch) lib.j_kv_unref(kv) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() + assert lib.j_batch_execute(deletebatch) lib.j_batch_unref(batch) lib.j_batch_unref(deletebatch) @@ -81,27 +82,29 @@ def benchmark_kv_delete_batch(run): def _benchmark_kv_delete(run, use_batch): batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + createbatch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + empty = encode("empty") + for i in range(run.iterations): name = encode(f"benchmark-{i}") namespace = encode("benchmark") kv = lib.j_kv_new(namespace, name) - empty = encode("empty") - lib.j_kv_put(kv, empty, 6, ffi.NULL, batch) + lib.j_kv_put(kv, empty, 6, ffi.NULL, createbatch) lib.j_kv_unref(kv) - assert lib.j_batch_execute(batch) - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + run.batch_setup = lambda: lib.j_batch_execute(createbatch) + for i in run: name = encode(f"benchmark-{i}") namespace = encode("benchmark") kv = lib.j_kv_new(namespace, name) lib.j_kv_delete(kv, batch) + lib.j_kv_put(kv, empty, 6, ffi.NULL, createbatch) if not use_batch: assert lib.j_batch_execute(batch) lib.j_kv_unref(kv) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() lib.j_batch_unref(batch) + lib.j_batch_unref(createbatch) def benchmark_kv_unordered_put_delete(run): _benchmark_kv_unordered_put_delete(run, False) @@ -111,8 +114,8 @@ def benchmark_kv_unordered_put_delete_batch(run): def _benchmark_kv_unordered_put_delete(run, use_batch): batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) - run.start_timer() - for i in range(run.iterations): + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + for i in run: name = encode(f"benchmark-{i}") namespace = encode("benchmark") kv = lib.j_kv_new(namespace, name) @@ -122,8 +125,5 @@ def _benchmark_kv_unordered_put_delete(run, use_batch): if not use_batch: assert lib.j_batch_execute(batch) lib.j_kv_unref(kv) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() lib.j_batch_unref(batch) run.operations = run.iterations * 2 From f1d8e2b32b4423a021e99db2cef84abf9730f9db Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Wed, 14 Jun 2023 15:11:12 +0200 Subject: [PATCH 10/18] update object.py --- benchmark/python/benchmark.py | 4 +- benchmark/python/benchmarkrun.py | 17 +++++---- benchmark/python/object/object.py | 63 ++++++++++++++----------------- 3 files changed, 39 insertions(+), 45 deletions(-) diff --git a/benchmark/python/benchmark.py b/benchmark/python/benchmark.py index 5d348cc37..ad62c14d6 100644 --- a/benchmark/python/benchmark.py +++ b/benchmark/python/benchmark.py @@ -17,11 +17,11 @@ print_header(machine_readable) # KV Client - benchmark_kv(runs, iterations, machine_readable) + # benchmark_kv(runs, iterations, machine_readable) # Object Client # benchmark_distributed_object(runs, iterations, machine_readable) - # benchmark_object(runs, iterations, machine_readable) + benchmark_object(runs, iterations, machine_readable) # DB Client # benchmark_db_entry(runs, iterations, machine_readable) diff --git a/benchmark/python/benchmarkrun.py b/benchmark/python/benchmarkrun.py index 35f72dc07..8fece7b79 100644 --- a/benchmark/python/benchmarkrun.py +++ b/benchmark/python/benchmarkrun.py @@ -12,7 +12,7 @@ def __init__(self, name, iterations, machine_readable): self.operations = iterations self.machine_readable = machine_readable self.iteration_count = 0 - self.i = 0 + self.i = -1 self.op_duration = 1000 ** 3 self.batch_send = None self.batch_clean = None @@ -23,13 +23,8 @@ def __iter__(self): return self def __next__(self): - if self.i == 0 and self.batch_setup is not None: - self.pause_timer() - if not self.batch_setup(): - raise RuntimeError("Failed to setup batch!"); - self.continue_timer() self.i += 1 - if self.i >= self.operations: + if self.i == self.iterations: self.i = 0 self.iteration_count += 1 if self.batch_send is not None: @@ -43,8 +38,14 @@ def __next__(self): if perf_counter_ns() - self.start - self.total_break > self.op_duration: self.stop_timer() raise StopIteration + if self.i == 0 and self.batch_setup is not None: + self.pause_timer() + if not self.batch_setup(): + raise RuntimeError("Failed to setup batch!"); + self.continue_timer() return self.i - + def get_count(self): + return self.iterations def pause_timer(self): self.break_start = perf_counter_ns() diff --git a/benchmark/python/object/object.py b/benchmark/python/object/object.py index 7a9d1fc4b..3db26f30c 100644 --- a/benchmark/python/object/object.py +++ b/benchmark/python/object/object.py @@ -25,8 +25,10 @@ def benchmark_object_create_batch(run): def _benchmark_object_create(run, use_batch): batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) deletebatch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + run.batch_clean = lambda: lib.j_batch_execute(deletebatch) + for i in run: name = encode(f"benchmark-{i}") namespace = encode("benchmark") obj = lib.j_object_new(namespace, name) @@ -35,10 +37,7 @@ def _benchmark_object_create(run, use_batch): if not use_batch: assert lib.j_batch_execute(batch) lib.j_object_unref(obj) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() - assert lib.j_batch_execute(deletebatch) + lib.j_batch_unref(batch) lib.j_batch_unref(deletebatch) @@ -51,25 +50,25 @@ def benchmark_object_delete_batch(run): def _benchmark_object_delete(run, use_batch): batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + createbatch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) for i in range(run.iterations): name = encode(f"benchmark-{i}") namespace = encode("benchmark") obj = lib.j_object_new(namespace, name) - lib.j_object_create(obj, batch) + lib.j_object_create(obj, createbatch) lib.j_object_unref(obj) - assert lib.j_batch_execute(batch) - run.start_timer() - for i in range(run.iterations): + + run.batch_setup = lambda: lib.j_batch_execute(createbatch) + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + for i in run: name = encode(f"benchmark-{i}") namespace = encode("benchmark") obj = lib.j_object_new(namespace, name) lib.j_object_delete(obj, batch) + lib.j_object_create(obj, createbatch) if not use_batch: assert lib.j_batch_execute(batch) lib.j_object_unref(obj) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() lib.j_batch_unref(batch) def benchmark_object_status(run): @@ -90,14 +89,13 @@ def _benchmark_object_status(run, use_batch): character = encode("A") lib.j_object_write(obj, character, 1, 0, size_ptr, batch) assert lib.j_batch_execute(batch) - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + for i in run: lib.j_object_status(obj, modification_time_ptr, size_ptr, batch) if not use_batch: assert lib.j_batch_execute(batch) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() + lib.j_object_delete(obj, batch) assert lib.j_batch_execute(batch) lib.j_object_unref(obj) @@ -123,16 +121,14 @@ def _benchmark_object_read(run, use_batch, block_size): batch) assert lib.j_batch_execute(batch) assert nb_ptr[0] == run.iterations * block_size - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) & (nb_ptr[0] == run.iterations * block_size) + for i in run: lib.j_object_read(obj, dummy, block_size, i * block_size, nb_ptr, batch) if not use_batch: assert lib.j_batch_execute(batch) assert nb_ptr[0] == block_size - if use_batch: - assert lib.j_batch_execute(batch) - assert nb_ptr[0] == run.iterations * block_size - run.stop_timer() + lib.j_object_delete(obj, batch) assert lib.j_batch_execute(batch) lib.j_object_unref(obj) @@ -153,17 +149,15 @@ def _benchmark_object_write(run, use_batch, block_size): name = encode("benchmark") obj = lib.j_object_new(name, name) lib.j_object_create(obj, batch) - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) & (nb_ptr[0] == run.iterations * block_size) + for i in run: lib.j_object_write(obj, dummy, block_size, i * block_size, nb_ptr, batch) if not use_batch: assert lib.j_batch_execute(batch) assert nb_ptr[0] == block_size - if use_batch: - assert lib.j_batch_execute(batch) - assert nb_ptr[0] == run.iterations * block_size - run.stop_timer() + lib.j_object_delete(obj, batch) assert lib.j_batch_execute(batch) lib.j_object_unref(obj) @@ -177,8 +171,9 @@ def benchmark_object_unordered_create_delete_batch(run): def _benchmark_object_unordered_create_delete(run, use_batch): batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + for i in run: name = encode(f"benchmark-{i}") namespace = encode("benchmark") obj = lib.j_object_new(namespace, name) @@ -187,8 +182,6 @@ def _benchmark_object_unordered_create_delete(run, use_batch): if not use_batch: assert lib.j_batch_execute(batch) lib.j_object_unref(obj) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() + lib.j_batch_unref(batch) run.operations = run.iterations * 2 From fbfe5b5e775bf7cbe80df3063fc4bef992518f58 Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Wed, 14 Jun 2023 15:37:31 +0200 Subject: [PATCH 11/18] update db benchmarks to new api --- benchmark/python/benchmark.py | 4 ++-- benchmark/python/benchmarkrun.py | 1 + benchmark/python/db/entry.py | 2 +- benchmark/python/db/iterator.py | 5 +++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/benchmark/python/benchmark.py b/benchmark/python/benchmark.py index ad62c14d6..b839972e6 100644 --- a/benchmark/python/benchmark.py +++ b/benchmark/python/benchmark.py @@ -21,12 +21,12 @@ # Object Client # benchmark_distributed_object(runs, iterations, machine_readable) - benchmark_object(runs, iterations, machine_readable) + # benchmark_object(runs, iterations, machine_readable) # DB Client # benchmark_db_entry(runs, iterations, machine_readable) # benchmark_db_iterator(runs, iterations, machine_readable) - # benchmark_db_schema(runs, iterations, machine_readable) + benchmark_db_schema(runs, iterations, machine_readable) # Item Client # benchmark_collection(runs, iterations, machine_readable) diff --git a/benchmark/python/benchmarkrun.py b/benchmark/python/benchmarkrun.py index 8fece7b79..921e11c01 100644 --- a/benchmark/python/benchmarkrun.py +++ b/benchmark/python/benchmarkrun.py @@ -76,6 +76,7 @@ def get_runtime_ns(self): return self.stop - self.start - self.total_break def print_result(self): + if self.iteration_count == 0: self.iteration_count = 1 if self.machine_readable: print(f"{self.name},{self.get_runtime_s()},{self.operations}") else: diff --git a/benchmark/python/db/entry.py b/benchmark/python/db/entry.py index c397396eb..8070dcdb8 100644 --- a/benchmark/python/db/entry.py +++ b/benchmark/python/db/entry.py @@ -181,7 +181,7 @@ def _benchmark_db_update(run, namespace, use_batch, use_index_all, string_name = encode("string") string = encode(_benchmark_db_get_identifier(i)) assert b_s_error_ptr == ffi.NULL - assert lib.j_db_entry_set_field(encode, sint_name, i_signed_ptr, 0, + assert lib.j_db_entry_set_field(entry, sint_name, i_signed_ptr, 0, b_s_error_ptr) assert b_s_error_ptr == ffi.NULL assert lib.j_db_selector_add_field(selector, string_name, diff --git a/benchmark/python/db/iterator.py b/benchmark/python/db/iterator.py index a93855db7..366847285 100644 --- a/benchmark/python/db/iterator.py +++ b/benchmark/python/db/iterator.py @@ -56,12 +56,13 @@ def _benchmark_db_get_simple(run, namespace, use_index_all, use_index_single): assert b_s_error_ptr == ffi.NULL assert lib.j_db_iterator_next(iterator, b_s_error_ptr) assert b_s_error_ptr == ffi.NULL - assert lib.j_db_iterator_get_field(iterator, string_name, field_type_ptr, + assert lib.j_db_iterator_get_field(iterator, ffi.NULL, string_name, field_type_ptr, field_value_ptr, field_length_ptr, b_s_error_ptr) assert b_s_error_ptr == ffi.NULL lib.j_db_selector_unref(selector) lib.j_db_iterator_unref(iterator) + run.stop_timer() run.operations = iterations lib.j_batch_unref(batch) lib.j_batch_unref(delete_batch) @@ -118,7 +119,7 @@ def _benchmark_db_get_range(run, namespace, use_index_all, use_index_single): assert b_s_error_ptr == ffi.NULL assert lib.j_db_iterator_next(iterator, b_s_error_ptr) assert b_s_error_ptr == ffi.NULL - assert lib.j_db_iterator_get_field(iterator, string_name, field_type_ptr, + assert lib.j_db_iterator_get_field(iterator, ffi.NULL, string_name, field_type_ptr, field_value_ptr, field_length_ptr, b_s_error_ptr) assert b_s_error_ptr == ffi.NULL From c43dda61c579bc5211ab0aefe351c2b770568f51 Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Thu, 15 Jun 2023 14:00:33 +0200 Subject: [PATCH 12/18] make db benchmarks runable --- benchmark/python/db/schema.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/benchmark/python/db/schema.py b/benchmark/python/db/schema.py index dbdad6446..f3ca4c335 100644 --- a/benchmark/python/db/schema.py +++ b/benchmark/python/db/schema.py @@ -20,14 +20,13 @@ def _benchmark_db_schema_create(run, use_batch): delete_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) run.start_timer() for i in range(run.iterations): - error_ptr = ffi.new("GError*") error_ptr_ptr = ffi.new("GError**") - error_ptr_ptr[0] = error_ptr + error_ptr_ptr[0] = ffi.NULL name = encode(f"benchmark-schema-{i}") namespace = encode("benchmark-ns") schema = lib.j_db_schema_new(namespace, name, error_ptr_ptr) for j in range(10): - fname = encode("field{j}") + fname = encode(f"field{j}") lib.j_db_schema_add_field(schema, fname, lib.J_DB_TYPE_STRING, error_ptr_ptr) lib.j_db_schema_create(schema, batch, ffi.NULL) From f418457426d36b652e9a48fab14b0bfdca8eb7ee Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Thu, 15 Jun 2023 14:56:13 +0200 Subject: [PATCH 13/18] distributed object duration fitte --- benchmark/python/benchmark.py | 4 +- benchmark/python/db/schema.py | 45 ++++++------ benchmark/python/object/distributed_object.py | 68 +++++++++---------- 3 files changed, 56 insertions(+), 61 deletions(-) diff --git a/benchmark/python/benchmark.py b/benchmark/python/benchmark.py index b839972e6..90fc2aa8e 100644 --- a/benchmark/python/benchmark.py +++ b/benchmark/python/benchmark.py @@ -20,13 +20,13 @@ # benchmark_kv(runs, iterations, machine_readable) # Object Client - # benchmark_distributed_object(runs, iterations, machine_readable) + benchmark_distributed_object(runs, iterations, machine_readable) # benchmark_object(runs, iterations, machine_readable) # DB Client # benchmark_db_entry(runs, iterations, machine_readable) # benchmark_db_iterator(runs, iterations, machine_readable) - benchmark_db_schema(runs, iterations, machine_readable) + # benchmark_db_schema(runs, iterations, machine_readable) # Item Client # benchmark_collection(runs, iterations, machine_readable) diff --git a/benchmark/python/db/schema.py b/benchmark/python/db/schema.py index f3ca4c335..442c9bfe3 100644 --- a/benchmark/python/db/schema.py +++ b/benchmark/python/db/schema.py @@ -18,8 +18,11 @@ def _benchmark_db_schema_create(run, use_batch): run.operations = run.iterations batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) delete_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + run.batch_clean = lambda: lib.j_batch_execute(delete_batch) + + for i in run: error_ptr_ptr = ffi.new("GError**") error_ptr_ptr[0] = ffi.NULL name = encode(f"benchmark-schema-{i}") @@ -34,10 +37,7 @@ def _benchmark_db_schema_create(run, use_batch): if not use_batch: assert lib.j_batch_execute(batch) lib.j_db_schema_unref(schema) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() - assert lib.j_batch_execute(delete_batch) + lib.j_batch_unref(batch) lib.j_batch_unref(delete_batch) @@ -51,19 +51,23 @@ def _benchmark_db_schema_delete(run, use_batch): run.iterations = int(run.iterations / 10) run.operations = run.iterations batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) - for i in range(run.iterations): - name = encode(f"benchmark-schema-{i}") - namespace = encode("benchmark-ns") - schema = lib.j_db_schema_new(namespace, name, ffi.NULL) - for j in range(10): - fname = encode(f"field{j}") - lib.j_db_schema_add_field(schema, fname, lib.J_DB_TYPE_STRING, - ffi.NULL) - lib.j_db_schema_create(schema, batch, ffi.NULL) - lib.j_db_schema_unref(schema) - assert lib.j_batch_execute(batch) - run.start_timer() - for i in range(run.iterations): + + def setup(): + for i in range(run.iterations): + name = encode(f"benchmark-schema-{i}") + namespace = encode("benchmark-ns") + schema = lib.j_db_schema_new(namespace, name, ffi.NULL) + for j in range(10): + fname = encode(f"field{j}") + lib.j_db_schema_add_field(schema, fname, lib.J_DB_TYPE_STRING, + ffi.NULL) + lib.j_db_schema_create(schema, batch, ffi.NULL) + lib.j_db_schema_unref(schema) + return lib.j_batch_execute(batch) + + run.batch_setup = setup + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + for i in run: name = encode(f"benchmark-schema-{i}") namespace = encode("benchmark-ns") schema = lib.j_db_schema_new(namespace, name, ffi.NULL) @@ -71,7 +75,4 @@ def _benchmark_db_schema_delete(run, use_batch): if not use_batch: assert lib.j_batch_execute(batch) lib.j_db_schema_unref(schema) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() lib.j_batch_unref(batch) diff --git a/benchmark/python/object/distributed_object.py b/benchmark/python/object/distributed_object.py index 1f7d4b752..216c2ff90 100644 --- a/benchmark/python/object/distributed_object.py +++ b/benchmark/python/object/distributed_object.py @@ -25,8 +25,10 @@ def _benchmark_distributed_object_create(run, use_batch): distribution = lib.j_distribution_new(lib.J_DISTRIBUTION_ROUND_ROBIN) batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) deletebatch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + run.batch_clean = lambda: lib.j_batch_execute(deletebatch) + for i in run: name = encode(f"benchmark-{i}") namespace = encode("benchmark") obj = lib.j_distributed_object_new(namespace, name, distribution) @@ -35,10 +37,7 @@ def _benchmark_distributed_object_create(run, use_batch): if not use_batch: assert lib.j_batch_execute(batch) lib.j_distributed_object_unref(obj) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() - assert lib.j_batch_execute(deletebatch) + lib.j_batch_unref(batch) lib.j_batch_unref(deletebatch) lib.j_distribution_unref(distribution) @@ -52,25 +51,26 @@ def benchmark_distributed_object_delete_batch(run): def _benchmark_distributed_object_delete(run, use_batch): distribution = lib.j_distribution_new(lib.J_DISTRIBUTION_ROUND_ROBIN) batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + createbatch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) for i in range(run.iterations): name = encode(f"benchmark-{i}") namespace = encode("benchmark") obj = lib.j_distributed_object_new(namespace, name, distribution) - lib.j_distributed_object_create(obj, batch) + lib.j_distributed_object_create(obj, createbatch) lib.j_distributed_object_unref(obj) - assert lib.j_batch_execute(batch) - run.start_timer() - for i in range(run.iterations): + + run.batch_setup = lambda: lib.j_batch_execute(createbatch) + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + for i in run: name = encode(f"benchmark-{i}") namespace = encode("benchmark") obj = lib.j_distributed_object_new(namespace, name, distribution) lib.j_distributed_object_delete(obj, batch) + lib.j_distributed_object_create(obj, createbatch) if not use_batch: assert lib.j_batch_execute(batch) lib.j_distributed_object_unref(obj) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() + lib.j_batch_unref(batch) lib.j_distribution_unref(distribution) @@ -93,14 +93,13 @@ def _benchmark_distributed_object_status(run, use_batch): character = encode("A") lib.j_distributed_object_write(obj, character, 1, 0, size_ptr, batch) assert lib.j_batch_execute(batch) - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + for i in run: lib.j_distributed_object_status(obj, modification_time_ptr, size_ptr, batch) if not use_batch: assert lib.j_batch_execute(batch) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() + lib.j_distributed_object_delete(obj, batch) assert lib.j_batch_execute(batch) lib.j_distributed_object_unref(obj) @@ -128,17 +127,15 @@ def _benchmark_distributed_object_read(run, use_batch, block_size): size_ptr, batch) assert lib.j_batch_execute(batch) assert size_ptr[0] == run.iterations * block_size - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) & (size_ptr[0] == run.iterations * block_size) + for i in run: lib.j_distributed_object_read(obj, dummy, block_size, i * block_size, size_ptr, batch) if not use_batch: assert lib.j_batch_execute(batch) assert size_ptr[0] == block_size - if use_batch: - assert lib.j_batch_execute(batch) - assert size_ptr[0] == run.iterations * block_size - run.stop_timer() + lib.j_distributed_object_delete(obj, batch) assert lib.j_batch_execute(batch) lib.j_distribution_unref(distribution) @@ -162,19 +159,17 @@ def _benchmark_distributed_object_write(run, use_batch, block_size): dummy = ffi.new("char[]", block_size) size_ptr = ffi.new("unsigned long*") assert lib.j_batch_execute(batch) - run.start_timer() - for i in range(run.iterations): - lib.j_distributed_object_write(obj, dummy, block_size, i*block_size, - size_ptr, batch) + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) & (size_ptr[0] == run.iterations * block_size) + for i in run: + lib.j_distributed_object_write(obj, dummy, block_size, i*block_size, size_ptr, batch) if not use_batch: assert lib.j_batch_execute(batch) assert size_ptr[0] == block_size - if use_batch: - assert lib.j_batch_execute(batch) - assert size_ptr[0] == run.iterations * block_size - run.stop_timer() + lib.j_distributed_object_delete(obj, batch) assert lib.j_batch_execute(batch) + lib.j_distributed_object_unref(obj) lib.j_batch_unref(batch) lib.j_distribution_unref(distribution) @@ -188,8 +183,9 @@ def benchmark_distributed_object_unordered_create_delete_batch(run): def _benchmark_distributed_object_unordered_create_delete(run, use_batch): distribution = lib.j_distribution_new(lib.J_DISTRIBUTION_ROUND_ROBIN) batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + for i in run: namespace = encode("benchmark") name = encode(f"benchmark-{i}") obj = lib.j_distributed_object_new(namespace, name, distribution) @@ -198,9 +194,7 @@ def _benchmark_distributed_object_unordered_create_delete(run, use_batch): if not use_batch: assert lib.j_batch_execute(batch) lib.j_distributed_object_unref(obj) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() + lib.j_batch_unref(batch) lib.j_distribution_unref(distribution) run.operations = run.iterations * 2 From 8cf035f541baa6f149fc1f041ab48ae96a1b0a13 Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Thu, 15 Jun 2023 18:45:39 +0200 Subject: [PATCH 14/18] Enusres minimum runtime for all benchmarks --- benchmark/python/benchmark.py | 10 ++-- benchmark/python/benchmarkrun.py | 4 +- benchmark/python/db/common.py | 86 +++++++++++++++++++------------- benchmark/python/db/entry.py | 31 ++++++------ benchmark/python/db/iterator.py | 19 +++---- 5 files changed, 83 insertions(+), 67 deletions(-) diff --git a/benchmark/python/benchmark.py b/benchmark/python/benchmark.py index 90fc2aa8e..9bb3e928a 100644 --- a/benchmark/python/benchmark.py +++ b/benchmark/python/benchmark.py @@ -17,16 +17,16 @@ print_header(machine_readable) # KV Client - # benchmark_kv(runs, iterations, machine_readable) + benchmark_kv(runs, iterations, machine_readable) # Object Client benchmark_distributed_object(runs, iterations, machine_readable) - # benchmark_object(runs, iterations, machine_readable) + benchmark_object(runs, iterations, machine_readable) # DB Client - # benchmark_db_entry(runs, iterations, machine_readable) - # benchmark_db_iterator(runs, iterations, machine_readable) - # benchmark_db_schema(runs, iterations, machine_readable) + benchmark_db_entry(runs, iterations, machine_readable) + benchmark_db_iterator(runs, iterations, machine_readable) + benchmark_db_schema(runs, iterations, machine_readable) # Item Client # benchmark_collection(runs, iterations, machine_readable) diff --git a/benchmark/python/benchmarkrun.py b/benchmark/python/benchmarkrun.py index 921e11c01..e17f48958 100644 --- a/benchmark/python/benchmarkrun.py +++ b/benchmark/python/benchmarkrun.py @@ -35,7 +35,7 @@ def __next__(self): if not self.batch_clean(): raise RuntimeError("Failed to clean batch!") self.continue_timer() - if perf_counter_ns() - self.start - self.total_break > self.op_duration: + if self.get_runtime_ns() > self.op_duration: self.stop_timer() raise StopIteration if self.i == 0 and self.batch_setup is not None: @@ -71,7 +71,7 @@ def get_runtime_s(self): def get_runtime_ns(self): if self.timer_started or self.stop == None: - return None + return perf_counter_ns() - self.start - self.total_break else: return self.stop - self.start - self.total_break diff --git a/benchmark/python/db/common.py b/benchmark/python/db/common.py index 72115de82..37294f88a 100644 --- a/benchmark/python/db/common.py +++ b/benchmark/python/db/common.py @@ -81,6 +81,7 @@ def _benchmark_db_insert(run, scheme, namespace, use_batch, use_index_all, namespace_encoded = encode(namespace) batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) delete_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + if use_timer: assert scheme == None assert run != None @@ -88,48 +89,61 @@ def _benchmark_db_insert(run, scheme, namespace, use_batch, use_index_all, use_index_all, use_index_single, batch, delete_batch) assert b_scheme != None + run.operations = 0 run.start_timer() else: assert use_batch assert run == None lib.j_db_schema_ref(scheme) b_scheme = scheme - for i in range(N): - i_signed_ptr = ffi.new("long*") - i_signed_ptr[0] = ((i * SIGNED_FACTOR) % CLASS_MODULUS) - CLASS_LIMIT - i_usigned_ptr = ffi.new("unsigned long*") - i_usigned_ptr[0] = ((i * USIGNED_FACTOR) % CLASS_MODULUS) - i_float_ptr = ffi.new("double*") - i_float_ptr[0] = i_signed_ptr[0] * FLOAT_FACTOR - string = encode(_benchmark_db_get_identifier(i)) - string_name = encode("string") - float_name = encode("float") - sint_name = encode("sint") - uint_name = encode("uint") - entry = lib.j_db_entry_new(b_scheme, b_s_error_ptr) - assert b_s_error_ptr == ffi.NULL - assert lib.j_db_entry_set_field(entry, string_name, string, 0, - b_s_error_ptr) - assert b_s_error_ptr == ffi.NULL - assert lib.j_db_entry_set_field(entry, float_name, i_float_ptr, 0, - b_s_error_ptr) - assert b_s_error_ptr == ffi.NULL - assert lib.j_db_entry_set_field(entry, sint_name, i_signed_ptr, 0, - b_s_error_ptr) - assert b_s_error_ptr == ffi.NULL - assert lib.j_db_entry_set_field(entry, uint_name, i_usigned_ptr, 0, - b_s_error_ptr) - assert b_s_error_ptr == ffi.NULL - assert lib.j_db_entry_insert(entry, batch, b_s_error_ptr) - assert b_s_error_ptr == ffi.NULL - if not use_batch: - assert lib.j_batch_execute(batch) - if use_batch or not use_timer: - lib.j_batch_execute(batch) - if use_timer: - run.stop_timer() - assert lib.j_batch_execute(delete_batch) - run.operations = N + while True: + for i in range(N): + i_signed_ptr = ffi.new("long*") + i_signed_ptr[0] = ((i * SIGNED_FACTOR) % CLASS_MODULUS) - CLASS_LIMIT + i_usigned_ptr = ffi.new("unsigned long*") + i_usigned_ptr[0] = ((i * USIGNED_FACTOR) % CLASS_MODULUS) + i_float_ptr = ffi.new("double*") + i_float_ptr[0] = i_signed_ptr[0] * FLOAT_FACTOR + string = encode(_benchmark_db_get_identifier(i)) + string_name = encode("string") + float_name = encode("float") + sint_name = encode("sint") + uint_name = encode("uint") + entry = lib.j_db_entry_new(b_scheme, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_entry_set_field(entry, string_name, string, 0, + b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_entry_set_field(entry, float_name, i_float_ptr, 0, + b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_entry_set_field(entry, sint_name, i_signed_ptr, 0, + b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_entry_set_field(entry, uint_name, i_usigned_ptr, 0, + b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + assert lib.j_db_entry_insert(entry, batch, b_s_error_ptr) + assert b_s_error_ptr == ffi.NULL + if not use_batch: + assert lib.j_batch_execute(batch) + if use_batch or not use_timer: + lib.j_batch_execute(batch) + if use_timer: + run.pause_timer() + assert lib.j_batch_execute(delete_batch) + run.operations += N + if run.get_runtime_ns() >= run.op_duration: + run.stop_timer() + break; + else: + b_scheme = _benchmark_db_prepare_scheme(namespace_encoded, use_batch, + use_index_all, use_index_single, + batch, delete_batch) + run.continue_timer() + else: + break; + lib.j_batch_unref(batch) lib.j_batch_unref(delete_batch) lib.j_db_entry_unref(entry) diff --git a/benchmark/python/db/entry.py b/benchmark/python/db/entry.py index 8070dcdb8..67c2afc97 100644 --- a/benchmark/python/db/entry.py +++ b/benchmark/python/db/entry.py @@ -101,9 +101,12 @@ def _benchmark_db_delete(run, namespace, use_batch, use_index_all, assert b_scheme != ffi.NULL assert run != None _benchmark_db_insert(None, b_scheme, "\0", True, False, False, False) - run.start_timer() - iterations = N if use_index_all or use_index_single else int(N / N_GET_DIVIDER) - for i in range(iterations): + run.iterations = N if use_index_all or use_index_single else int(N / N_GET_DIVIDER) + run.oerations = run.iterations + + run.batch_setup = lambda: _benchmark_db_insert(None, b_scheme, "\0", True, False, False, False) or True + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + for i in run: entry = lib.j_db_entry_new(b_scheme, b_s_error_ptr) string = encode(_benchmark_db_get_identifier(i)) string_name = encode("string") @@ -119,11 +122,8 @@ def _benchmark_db_delete(run, namespace, use_batch, use_index_all, assert lib.j_batch_execute(batch) lib.j_db_entry_unref(entry) lib.j_db_selector_unref(selector) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() + assert lib.j_batch_execute(delete_batch) - run.operations = iterations lib.j_batch_unref(batch) lib.j_batch_unref(delete_batch) lib.j_db_schema_unref(b_scheme) @@ -169,12 +169,16 @@ def _benchmark_db_update(run, namespace, use_batch, use_index_all, assert b_scheme != ffi.NULL assert run != None _benchmark_db_insert(None, b_scheme, "\0", True, False, False, False) - run.start_timer() - iterations = N if use_index_all or use_index_single else int(N / N_GET_DIVIDER) - for i in range(iterations): + run.iterations = N if use_index_all or use_index_single else int(N / N_GET_DIVIDER) + run.operations = run.iterations + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + cnt = 0 + for i in run: + cnt += 1 sint_name = encode("sint") i_signed_ptr = ffi.new("long*") - i_signed_ptr[0] = (((i + N_PRIME) * SIGNED_FACTOR) & CLASS_MODULUS) - CLASS_LIMIT + i_signed_ptr[0] = (((i + N_PRIME) * SIGNED_FACTOR * cnt) & CLASS_MODULUS) - CLASS_LIMIT selector = lib.j_db_selector_new(b_scheme, lib.J_DB_SELECTOR_MODE_AND, b_s_error_ptr) entry = lib.j_db_entry_new(b_scheme, b_s_error_ptr) @@ -194,11 +198,8 @@ def _benchmark_db_update(run, namespace, use_batch, use_index_all, assert lib.j_batch_execute(batch) lib.j_db_selector_unref(selector) lib.j_db_entry_unref(entry) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() + assert lib.j_batch_execute(delete_batch) - run.operations = iterations lib.j_batch_unref(batch) lib.j_batch_unref(delete_batch) lib.j_db_schema_unref(b_scheme) diff --git a/benchmark/python/db/iterator.py b/benchmark/python/db/iterator.py index 366847285..63d53a318 100644 --- a/benchmark/python/db/iterator.py +++ b/benchmark/python/db/iterator.py @@ -37,9 +37,10 @@ def _benchmark_db_get_simple(run, namespace, use_index_all, use_index_single): assert b_scheme != ffi.NULL assert run != None _benchmark_db_insert(None, b_scheme, "\0", True, False, False, False) - run.start_timer() - iterations = N if use_index_all or use_index_single else int(N / N_GET_DIVIDER) - for i in range(iterations): + run.iterations = N if use_index_all or use_index_single else int(N / N_GET_DIVIDER) + run.operations = run.iterations + + for i in run: field_type_ptr = ffi.new("JDBType*") field_value_ptr = ffi.new("void**") field_length_ptr = ffi.new("unsigned long*") @@ -62,8 +63,7 @@ def _benchmark_db_get_simple(run, namespace, use_index_all, use_index_single): assert b_s_error_ptr == ffi.NULL lib.j_db_selector_unref(selector) lib.j_db_iterator_unref(iterator) - run.stop_timer() - run.operations = iterations + lib.j_batch_unref(batch) lib.j_batch_unref(delete_batch) lib.j_db_schema_unref(b_scheme) @@ -93,8 +93,10 @@ def _benchmark_db_get_range(run, namespace, use_index_all, use_index_single): assert b_scheme != ffi.NULL assert run != None _benchmark_db_insert(None, b_scheme, "\0", True, False, False, False) - run.start_timer() - for i in range(N_GET_DIVIDER): + run.iterations = N_GET_DIVIDER + run.operations = run.iterations + + for i in run: field_type_ptr = ffi.new("JDBType*") field_value_ptr = ffi.new("void**") field_length_ptr = ffi.new("unsigned long*") @@ -123,9 +125,8 @@ def _benchmark_db_get_range(run, namespace, use_index_all, use_index_single): field_value_ptr, field_length_ptr, b_s_error_ptr) assert b_s_error_ptr == ffi.NULL - run.stop_timer() + assert lib.j_batch_execute(delete_batch) - run.operations = N_GET_DIVIDER lib.j_db_schema_unref(b_scheme) lib.j_batch_unref(batch) lib.j_batch_unref(delete_batch) From 3e8daf785538bd5bf971bd8886d2e31326df4989 Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Fri, 16 Jun 2023 09:56:45 +0200 Subject: [PATCH 15/18] Ensures minimum runtime for all python benchmarks --- benchmark/python/benchmark.py | 4 +- benchmark/python/item/collection.py | 46 +++++++------- benchmark/python/item/item.py | 94 ++++++++++++++--------------- 3 files changed, 74 insertions(+), 70 deletions(-) diff --git a/benchmark/python/benchmark.py b/benchmark/python/benchmark.py index 9bb3e928a..b3afb3efc 100644 --- a/benchmark/python/benchmark.py +++ b/benchmark/python/benchmark.py @@ -29,5 +29,5 @@ benchmark_db_schema(runs, iterations, machine_readable) # Item Client - # benchmark_collection(runs, iterations, machine_readable) - # benchmark_item(runs, iterations, machine_readable) + benchmark_collection(runs, iterations, machine_readable) + benchmark_item(runs, iterations, machine_readable) diff --git a/benchmark/python/item/collection.py b/benchmark/python/item/collection.py index 03caf40c3..f240cea33 100644 --- a/benchmark/python/item/collection.py +++ b/benchmark/python/item/collection.py @@ -20,18 +20,17 @@ def benchmark_collection_create_batch(run): def _benchmark_collection_create(run, use_batch): batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) delete_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + run.batch_clean = lambda: lib.j_batch_execute(delete_batch) + for i in run: name = encode(f"benchmark{i}") collection = lib.j_collection_create(name, batch) lib.j_collection_delete(collection, delete_batch) if not use_batch: assert lib.j_batch_execute(batch) lib.j_collection_unref(collection) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() - assert lib.j_batch_execute(delete_batch) + lib.j_batch_unref(batch) lib.j_batch_unref(delete_batch) @@ -48,12 +47,13 @@ def _benchmark_collection_delete(run, use_batch): collection = lib.j_collection_create(name, batch) lib.j_collection_unref(collection) assert lib.j_batch_execute(batch) + run.start_timer() for i in range(run.iterations): collection_ptr = ffi.new("JCollection**") name = encode(f"benchmark-{i}") lib.j_collection_get(collection_ptr, name, batch) - assert lib.j_batch_execute(batch) + assert lib.j_batch_execute(batch) # FIXME ignores use_batch!! lib.j_collection_delete(collection_ptr[0], batch) if not use_batch: assert lib.j_batch_execute(batch) @@ -65,15 +65,20 @@ def _benchmark_collection_delete(run, use_batch): def benchmark_collection_delete_batch_without_get(run): batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) delete_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) - for i in range(run.iterations): - name = encode(f"benchmark-{i}") - collection = lib.j_collection_create(name, batch) - lib.j_collection_delete(collection, delete_batch) - lib.j_collection_unref(collection) - assert lib.j_batch_execute(batch) - run.start_timer() - assert lib.j_batch_execute(delete_batch) - run.stop_timer() + iterations = run.iterations + def setup(): + for i in range(iterations): + name = encode(f"benchmark-{i}") + collection = lib.j_collection_create(name, batch) + lib.j_collection_delete(collection, delete_batch) + lib.j_collection_unref(collection) + return lib.j_batch_execute(batch) + + run.batch_setup = setup + run.iterations = 1 + for i in run: + assert lib.j_batch_execute(delete_batch) + lib.j_batch_unref(batch) lib.j_batch_unref(delete_batch) @@ -85,16 +90,15 @@ def benchmark_collection_unordered_create_delete_batch(run): def _benchmark_collection_unordered_create_delete(run, use_batch): batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + for i in run: name = encode(f"benchmark-{i}") collection = lib.j_collection_create(name, batch) lib.j_collection_delete(collection, batch) if not use_batch: assert lib.j_batch_execute(batch) lib.j_collection_unref(collection) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() + run.operations = run.iterations * 2 lib.j_batch_unref(batch) diff --git a/benchmark/python/item/item.py b/benchmark/python/item/item.py index 06e3ef848..e56bc54d2 100644 --- a/benchmark/python/item/item.py +++ b/benchmark/python/item/item.py @@ -29,18 +29,17 @@ def _benchmark_item_create(run, use_batch): collection_name = encode("benchmark") collection = lib.j_collection_create(collection_name, batch) assert lib.j_batch_execute(batch) - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + run.batch_clean: lambda: lib.j_batch_execute(delete_batch) + for i in run: name = encode(f"benchmark-{i}") item = lib.j_item_create(collection, name, ffi.NULL, batch) lib.j_item_delete(item, delete_batch) if not use_batch: assert lib.j_batch_execute(batch) lib.j_item_unref(item) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() - assert lib.j_batch_execute(delete_batch) + lib.j_collection_unref(collection) lib.j_batch_unref(batch) lib.j_batch_unref(delete_batch) @@ -57,13 +56,17 @@ def _benchmark_item_delete(run, use_batch): collection_name = encode("benchmark") collection = lib.j_collection_create(collection_name, batch) assert lib.j_batch_execute(batch) - for i in range(run.iterations): - name = encode(f"benchmark-{i}") - item = lib.j_item_create(collection, name, ffi.NULL, batch) - lib.j_item_unref(item) - assert lib.j_batch_execute(batch) - run.start_timer() - for i in range(run.iterations): + + def setup(): + for i in range(run.iterations): + name = encode(f"benchmark-{i}") + item = lib.j_item_create(collection, name, ffi.NULL, batch) + lib.j_item_unref(item) + return lib.j_batch_execute(batch) + + run.batch_setup = setup + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + for i in run: ptr = ffi.new("int**") item_ptr = ffi.cast("JItem**", ptr) name = encode(f"benchmark-{i}") @@ -72,9 +75,7 @@ def _benchmark_item_delete(run, use_batch): lib.j_item_delete(item_ptr[0], batch) if not use_batch: assert lib.j_batch_execute(batch) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() + lib.j_collection_delete(collection, batch) assert lib.j_batch_execute(batch) lib.j_collection_unref(collection) @@ -84,18 +85,23 @@ def _benchmark_item_delete(run, use_batch): def benchmark_item_delete_batch_without_get(run): batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) delete_batch = lib.j_batch_new_for_template(lib.J_SEMANTICS_TEMPLATE_DEFAULT) + collection_name = encode("benchmark") collection = lib.j_collection_create(collection_name, batch) assert lib.j_batch_execute(batch) - for i in range(run.iterations): - name = encode("benchmark-{i}") - item = lib.j_item_create(collection, name, ffi.NULL, batch) - lib.j_item_delete(item, delete_batch) - lib.j_item_unref(item) - assert lib.j_batch_execute(batch) - run.start_timer() - assert lib.j_batch_execute(delete_batch) - run.stop_timer() + def setup(): + for i in range(run.operations): + name = encode(f"benchmark-{i}") + item = lib.j_item_create(collection, name, ffi.NULL, batch) + lib.j_item_delete(item, delete_batch) + lib.j_item_unref(item) + return lib.j_batch_execute(batch) + + run.batch_setup = setup + run.batch_send = lambda: lib.j_batch_execute(delete_batch) + for _ in run: + pass + lib.j_collection_delete(collection, batch) lib.j_collection_unref(collection) lib.j_batch_unref(batch) @@ -118,14 +124,13 @@ def _benchmark_item_get_status(run, use_batch): item = lib.j_item_create(collection, collection_name, ffi.NULL, batch) lib.j_item_write(item, dummy, 1, 0, nb_ptr, batch) assert lib.j_batch_execute(batch) - run.start_timer() - for i in range(run.iterations): + + if use_batch: batch_send = lambda: lib.j_batch_execute(batch) + for i in run: lib.j_item_get_status(item, batch) if not use_batch: assert lib.j_batch_execute(batch) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() + lib.j_item_delete(item, batch) lib.j_collection_delete(collection, batch) assert lib.j_batch_execute(batch) @@ -152,16 +157,14 @@ def _benchmark_item_read(run, use_batch, block_size): lib.j_item_write(item, dummy, block_size, i * block_size, nb_ptr, batch) assert lib.j_batch_execute(batch) assert nb_ptr[0] == run.iterations * block_size - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) & (nb_ptr[0] == run.iterations * block_size) + for i in run: lib.j_item_read(item, dummy, block_size, i * block_size, nb_ptr, batch) if not use_batch: assert lib.j_batch_execute(batch) assert nb_ptr[0] == block_size - if use_batch: - assert lib.j_batch_execute(batch) - assert nb_ptr[0] == run.iterations * block_size - run.stop_timer() + lib.j_item_delete(item, batch) lib.j_collection_delete(collection, batch) assert lib.j_batch_execute(batch) @@ -185,16 +188,14 @@ def _benchmark_item_write(run, use_batch, block_size): collection = lib.j_collection_create(collection_name, batch) item = lib.j_item_create(collection, collection_name, ffi.NULL, batch) assert lib.j_batch_execute(batch) - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) & (nb_ptr[0] == run.iterations * block_size) + for i in run: lib.j_item_write(item, dummy, block_size, i * block_size, nb_ptr, batch) if not use_batch: assert lib.j_batch_execute(batch) assert nb_ptr[0] == block_size - if use_batch: - assert lib.j_batch_execute(batch) - assert nb_ptr[0] == run.iterations * block_size - run.stop_timer() + lib.j_item_delete(item, batch) lib.j_collection_delete(collection, batch) assert lib.j_batch_execute(batch) @@ -213,17 +214,16 @@ def _benchmark_item_unordered_create_delete(run, use_batch): collection_name = encode("benchmark") collection = lib.j_collection_create(collection_name, batch) assert lib.j_batch_execute(batch) - run.start_timer() - for i in range(run.iterations): + + if use_batch: run.batch_send = lambda: lib.j_batch_execute(batch) + for i in run: name = encode(f"benchmark-{i}") item = lib.j_item_create(collection, name, ffi.NULL, batch) lib.j_item_delete(item, batch) if not use_batch: assert lib.j_batch_execute(batch) lib.j_item_unref(item) - if use_batch: - assert lib.j_batch_execute(batch) - run.stop_timer() + lib.j_collection_delete(collection, batch) assert lib.j_batch_execute(batch) lib.j_collection_unref(collection) From 48e9985b3dc3e9dde781d41dd7e088864b6aa51d Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Sun, 18 Jun 2023 10:50:29 +0200 Subject: [PATCH 16/18] Enabl minimum runtime for each python test --- benchmark/python/benchmark.py | 17 ++++--- benchmark/python/benchmarkrun.py | 4 +- benchmark/python/db/entry.py | 50 +++++++++---------- benchmark/python/db/iterator.py | 18 +++---- benchmark/python/db/schema.py | 10 ++-- benchmark/python/item/collection.py | 16 +++--- benchmark/python/item/item.py | 28 +++++------ benchmark/python/kv/kv.py | 18 +++---- benchmark/python/object/distributed_object.py | 26 +++++----- benchmark/python/object/object.py | 26 +++++----- 10 files changed, 107 insertions(+), 106 deletions(-) diff --git a/benchmark/python/benchmark.py b/benchmark/python/benchmark.py index b3afb3efc..3932f3cc3 100644 --- a/benchmark/python/benchmark.py +++ b/benchmark/python/benchmark.py @@ -13,21 +13,22 @@ runs = [] iterations = 1000 taregt_time = 1000 + op_duration = 2 machine_readable = ("-m" in argv) print_header(machine_readable) # KV Client - benchmark_kv(runs, iterations, machine_readable) + benchmark_kv(runs, iterations, machine_readable, op_duration) # Object Client - benchmark_distributed_object(runs, iterations, machine_readable) - benchmark_object(runs, iterations, machine_readable) + benchmark_distributed_object(runs, iterations, machine_readable, op_duration) + benchmark_object(runs, iterations, machine_readable, op_duration) # DB Client - benchmark_db_entry(runs, iterations, machine_readable) - benchmark_db_iterator(runs, iterations, machine_readable) - benchmark_db_schema(runs, iterations, machine_readable) + benchmark_db_entry(runs, iterations, machine_readable, op_duration) + benchmark_db_iterator(runs, iterations, machine_readable, op_duration) + benchmark_db_schema(runs, iterations, machine_readable, op_duration) # Item Client - benchmark_collection(runs, iterations, machine_readable) - benchmark_item(runs, iterations, machine_readable) + benchmark_collection(runs, iterations, machine_readable, op_duration) + benchmark_item(runs, iterations, machine_readable, op_duration) diff --git a/benchmark/python/benchmarkrun.py b/benchmark/python/benchmarkrun.py index e17f48958..32ce20d03 100644 --- a/benchmark/python/benchmarkrun.py +++ b/benchmark/python/benchmarkrun.py @@ -1,7 +1,7 @@ from time import perf_counter_ns class BenchmarkRun: - def __init__(self, name, iterations, machine_readable): + def __init__(self, name, iterations, machine_readable, op_duration): self.name = name self.iterations = iterations self.timer_started = False @@ -13,7 +13,7 @@ def __init__(self, name, iterations, machine_readable): self.machine_readable = machine_readable self.iteration_count = 0 self.i = -1 - self.op_duration = 1000 ** 3 + self.op_duration = 1000 ** 3 * op_duration self.batch_send = None self.batch_clean = None self.batch_setup = None diff --git a/benchmark/python/db/entry.py b/benchmark/python/db/entry.py index 67c2afc97..4c629d470 100644 --- a/benchmark/python/db/entry.py +++ b/benchmark/python/db/entry.py @@ -2,31 +2,31 @@ from julea import lib, encode, ffi from db.common import _benchmark_db_insert, _benchmark_db_prepare_scheme, _benchmark_db_get_identifier, N, N_GET_DIVIDER, N_PRIME, SIGNED_FACTOR, CLASS_MODULUS, CLASS_LIMIT -def benchmark_db_entry(benchmarkrun_list, iterations, machine_readable): - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert", iterations, machine_readable), benchmark_db_insert) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-batch", iterations, machine_readable), benchmark_db_insert_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-index-single", iterations, machine_readable), benchmark_db_insert_index_single) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-batch-index-single", iterations, machine_readable), benchmark_db_insert_batch_index_single) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-index-all", iterations, machine_readable), benchmark_db_insert_index_all) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-batch-index-all", iterations, machine_readable), benchmark_db_insert_batch_index_all) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-index-mixed", iterations, machine_readable), benchmark_db_insert_index_mixed) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-batch-index-mixed", iterations, machine_readable), benchmark_db_insert_batch_index_mixed) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete", iterations, machine_readable), benchmark_db_delete) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-batch", iterations, machine_readable), benchmark_db_delete_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-index-single", iterations, machine_readable), benchmark_db_delete_index_single) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-batch-index-single", iterations, machine_readable), benchmark_db_delete_batch_index_single) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-index-all", iterations, machine_readable), benchmark_db_delete_index_all) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-batch-index-all", iterations, machine_readable), benchmark_db_delete_batch_index_all) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-index-mixed", iterations, machine_readable), benchmark_db_delete_index_mixed) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-batch-index-mixed", iterations, machine_readable), benchmark_db_delete_batch_index_mixed) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update", iterations, machine_readable), benchmark_db_update) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-batch", iterations, machine_readable), benchmark_db_update_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-index-single", iterations, machine_readable), benchmark_db_update_index_single) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-batch-index-single", iterations, machine_readable), benchmark_db_update_batch_index_single) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-index-all", iterations, machine_readable), benchmark_db_update_index_all) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-batch-index-all", iterations, machine_readable), benchmark_db_update_batch_index_all) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-index-mixed", iterations, machine_readable), benchmark_db_update_index_mixed) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-batch-index-mixed", iterations, machine_readable), benchmark_db_update_batch_index_mixed) +def benchmark_db_entry(benchmarkrun_list, iterations, machine_readable, op_duration): + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert", iterations, machine_readable, op_duration), benchmark_db_insert) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-batch", iterations, machine_readable, op_duration), benchmark_db_insert_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-index-single", iterations, machine_readable, op_duration), benchmark_db_insert_index_single) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-batch-index-single", iterations, machine_readable, op_duration), benchmark_db_insert_batch_index_single) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-index-all", iterations, machine_readable, op_duration), benchmark_db_insert_index_all) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-batch-index-all", iterations, machine_readable, op_duration), benchmark_db_insert_batch_index_all) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-index-mixed", iterations, machine_readable, op_duration), benchmark_db_insert_index_mixed) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/insert-batch-index-mixed", iterations, machine_readable, op_duration), benchmark_db_insert_batch_index_mixed) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete", iterations, machine_readable, op_duration), benchmark_db_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-batch", iterations, machine_readable, op_duration), benchmark_db_delete_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-index-single", iterations, machine_readable, op_duration), benchmark_db_delete_index_single) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-batch-index-single", iterations, machine_readable, op_duration), benchmark_db_delete_batch_index_single) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-index-all", iterations, machine_readable, op_duration), benchmark_db_delete_index_all) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-batch-index-all", iterations, machine_readable, op_duration), benchmark_db_delete_batch_index_all) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-index-mixed", iterations, machine_readable, op_duration), benchmark_db_delete_index_mixed) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/delete-batch-index-mixed", iterations, machine_readable, op_duration), benchmark_db_delete_batch_index_mixed) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update", iterations, machine_readable, op_duration), benchmark_db_update) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-batch", iterations, machine_readable, op_duration), benchmark_db_update_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-index-single", iterations, machine_readable, op_duration), benchmark_db_update_index_single) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-batch-index-single", iterations, machine_readable, op_duration), benchmark_db_update_batch_index_single) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-index-all", iterations, machine_readable, op_duration), benchmark_db_update_index_all) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-batch-index-all", iterations, machine_readable, op_duration), benchmark_db_update_batch_index_all) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-index-mixed", iterations, machine_readable, op_duration), benchmark_db_update_index_mixed) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/entry/update-batch-index-mixed", iterations, machine_readable, op_duration), benchmark_db_update_batch_index_mixed) def benchmark_db_insert(run): _benchmark_db_insert(run, None, "benchmark_insert", False, False, False, diff --git a/benchmark/python/db/iterator.py b/benchmark/python/db/iterator.py index 63d53a318..a4119183a 100644 --- a/benchmark/python/db/iterator.py +++ b/benchmark/python/db/iterator.py @@ -2,15 +2,15 @@ from julea import lib, encode, ffi from db.common import _benchmark_db_prepare_scheme, _benchmark_db_insert, _benchmark_db_get_identifier, N, N_GET_DIVIDER, CLASS_MODULUS, CLASS_LIMIT -def benchmark_db_iterator(benchmarkrun_list, iterations, machine_readable): - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-simple", iterations, machine_readable), benchmark_db_get_simple) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-simple-index-single", iterations, machine_readable), benchmark_db_get_simple_index_single) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-simple-index-all", iterations, machine_readable), benchmark_db_get_simple_index_all) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-simple-index-mixed", iterations, machine_readable), benchmark_db_get_simple_index_mixed) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-range", iterations, machine_readable), benchmark_db_get_range) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-range-index-single", iterations, machine_readable), benchmark_db_get_range_index_single) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-range-index-all", iterations, machine_readable), benchmark_db_get_range_index_all) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-range-index-mixed", iterations, machine_readable), benchmark_db_get_range_index_mixed) +def benchmark_db_iterator(benchmarkrun_list, iterations, machine_readable, op_duration): + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-simple", iterations, machine_readable, op_duration), benchmark_db_get_simple) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-simple-index-single", iterations, machine_readable, op_duration), benchmark_db_get_simple_index_single) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-simple-index-all", iterations, machine_readable, op_duration), benchmark_db_get_simple_index_all) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-simple-index-mixed", iterations, machine_readable, op_duration), benchmark_db_get_simple_index_mixed) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-range", iterations, machine_readable, op_duration), benchmark_db_get_range) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-range-index-single", iterations, machine_readable, op_duration), benchmark_db_get_range_index_single) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-range-index-all", iterations, machine_readable, op_duration), benchmark_db_get_range_index_all) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/iterator/get-range-index-mixed", iterations, machine_readable, op_duration), benchmark_db_get_range_index_mixed) def benchmark_db_get_simple(run): _benchmark_db_get_simple(run, "benchmark_get_simple", False, False) diff --git a/benchmark/python/db/schema.py b/benchmark/python/db/schema.py index 442c9bfe3..ad8576e96 100644 --- a/benchmark/python/db/schema.py +++ b/benchmark/python/db/schema.py @@ -1,11 +1,11 @@ from benchmarkrun import BenchmarkRun, append_to_benchmark_list_and_run from julea import lib, encode, ffi -def benchmark_db_schema(benchmarkrun_list, iterations, machine_readable): - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/schema/create", iterations, machine_readable), benchmark_db_schema_create) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/schema/create-batch", iterations, machine_readable), benchmark_db_schema_create_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/schema/delete", iterations, machine_readable), benchmark_db_schema_delete) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/schema/delete-batch", iterations, machine_readable), benchmark_db_schema_delete_batch) +def benchmark_db_schema(benchmarkrun_list, iterations, machine_readable, op_duration): + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/schema/create", iterations, machine_readable, op_duration), benchmark_db_schema_create) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/schema/create-batch", iterations, machine_readable, op_duration), benchmark_db_schema_create_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/schema/delete", iterations, machine_readable, op_duration), benchmark_db_schema_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/db/schema/delete-batch", iterations, machine_readable, op_duration), benchmark_db_schema_delete_batch) def benchmark_db_schema_create(run): _benchmark_db_schema_create(run, False) diff --git a/benchmark/python/item/collection.py b/benchmark/python/item/collection.py index f240cea33..b4e64bab8 100644 --- a/benchmark/python/item/collection.py +++ b/benchmark/python/item/collection.py @@ -1,14 +1,14 @@ from benchmarkrun import BenchmarkRun, append_to_benchmark_list_and_run from julea import lib, encode, ffi -def benchmark_collection(benchmarkrun_list, iterations, machine_readable): - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/create", iterations, machine_readable), benchmark_collection_create) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/create-batch", iterations, machine_readable), benchmark_collection_create_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/delete", iterations, machine_readable), benchmark_collection_delete) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/delete-batch", iterations, machine_readable), benchmark_collection_delete_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/delete-batch-without-get", iterations, machine_readable), benchmark_collection_delete_batch_without_get) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/unordered-create-delete", iterations, machine_readable), benchmark_collection_unordered_create_delete) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/unordered-create-delete-batch", iterations, machine_readable), benchmark_collection_unordered_create_delete_batch) +def benchmark_collection(benchmarkrun_list, iterations, machine_readable, op_duration): + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/create", iterations, machine_readable, op_duration), benchmark_collection_create) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/create-batch", iterations, machine_readable, op_duration), benchmark_collection_create_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/delete", iterations, machine_readable, op_duration), benchmark_collection_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/delete-batch", iterations, machine_readable, op_duration), benchmark_collection_delete_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/delete-batch-without-get", iterations, machine_readable, op_duration), benchmark_collection_delete_batch_without_get) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/unordered-create-delete", iterations, machine_readable, op_duration), benchmark_collection_unordered_create_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/collection/unordered-create-delete-batch", iterations, machine_readable, op_duration), benchmark_collection_unordered_create_delete_batch) # TODO: benchmark get (also missing in c benchmark) def benchmark_collection_create(run): diff --git a/benchmark/python/item/item.py b/benchmark/python/item/item.py index e56bc54d2..65abbaed4 100644 --- a/benchmark/python/item/item.py +++ b/benchmark/python/item/item.py @@ -1,21 +1,21 @@ from benchmarkrun import BenchmarkRun, append_to_benchmark_list_and_run from julea import lib, encode, ffi -def benchmark_item(benchmarkrun_list, iterations, machine_readable): - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/create", iterations, machine_readable), benchmark_item_create) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/create-batch", iterations, machine_readable), benchmark_item_create_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/delete", iterations, machine_readable), benchmark_item_delete) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/delete-batch", iterations, machine_readable), benchmark_item_delete_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/delete-batch-without-get", iterations, machine_readable), benchmark_item_delete_batch_without_get) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/get-status", iterations, machine_readable), benchmark_item_get_status) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/get-status-batch", iterations, machine_readable), benchmark_item_get_status_batch) +def benchmark_item(benchmarkrun_list, iterations, machine_readable, op_duration): + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/create", iterations, machine_readable, op_duration), benchmark_item_create) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/create-batch", iterations, machine_readable, op_duration), benchmark_item_create_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/delete", iterations, machine_readable, op_duration), benchmark_item_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/delete-batch", iterations, machine_readable, op_duration), benchmark_item_delete_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/delete-batch-without-get", iterations, machine_readable, op_duration), benchmark_item_delete_batch_without_get) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/get-status", iterations, machine_readable, op_duration), benchmark_item_get_status) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/get-status-batch", iterations, machine_readable, op_duration), benchmark_item_get_status_batch) # TODO: benchmark get (also missing in c benchmark) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/read", iterations, machine_readable), benchmark_item_read) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/read-batch", iterations, machine_readable), benchmark_item_read_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/write", iterations, machine_readable), benchmark_item_write) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/write-batch", iterations, machine_readable), benchmark_item_write_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/unordered-create-delete", iterations, machine_readable), benchmark_item_unordered_create_delete) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/unordered-create-delete-batch", iterations, machine_readable), benchmark_item_unordered_create_delete_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/read", iterations, machine_readable, op_duration), benchmark_item_read) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/read-batch", iterations, machine_readable, op_duration), benchmark_item_read_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/write", iterations, machine_readable, op_duration), benchmark_item_write) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/write-batch", iterations, machine_readable, op_duration), benchmark_item_write_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/unordered-create-delete", iterations, machine_readable, op_duration), benchmark_item_unordered_create_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/item/item/unordered-create-delete-batch", iterations, machine_readable, op_duration), benchmark_item_unordered_create_delete_batch) def benchmark_item_create(run): _benchmark_item_create(run, False) diff --git a/benchmark/python/kv/kv.py b/benchmark/python/kv/kv.py index 8ae5dd1c5..4a691071c 100644 --- a/benchmark/python/kv/kv.py +++ b/benchmark/python/kv/kv.py @@ -1,15 +1,15 @@ from benchmarkrun import BenchmarkRun, append_to_benchmark_list_and_run from julea import lib, encode, ffi -def benchmark_kv(benchmarkrun_list, iterations, machine_readable): - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/put", iterations, machine_readable), benchmark_kv_put) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/put_batch", iterations, machine_readable), benchmark_kv_put_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/get", iterations, machine_readable), benchmark_kv_get) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/get-batch", iterations, machine_readable), benchmark_kv_get_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/delete", iterations, machine_readable), benchmark_kv_delete) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/delete-batch", iterations, machine_readable), benchmark_kv_delete_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/unordered_put_delete", iterations, machine_readable), benchmark_kv_unordered_put_delete) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/unordered_put_delete_batch", iterations, machine_readable), benchmark_kv_unordered_put_delete_batch) +def benchmark_kv(benchmarkrun_list, iterations, machine_readable, op_duration): + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/put", iterations, machine_readable, op_duration), benchmark_kv_put) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/put_batch", iterations, machine_readable, op_duration), benchmark_kv_put_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/get", iterations, machine_readable, op_duration), benchmark_kv_get) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/get-batch", iterations, machine_readable, op_duration), benchmark_kv_get_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/delete", iterations, machine_readable, op_duration), benchmark_kv_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/delete-batch", iterations, machine_readable, op_duration), benchmark_kv_delete_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/unordered_put_delete", iterations, machine_readable, op_duration), benchmark_kv_unordered_put_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/kv/unordered_put_delete_batch", iterations, machine_readable, op_duration), benchmark_kv_unordered_put_delete_batch) def benchmark_kv_put(run): _benchmark_kv_put(run, False) diff --git a/benchmark/python/object/distributed_object.py b/benchmark/python/object/distributed_object.py index 216c2ff90..33a4226b1 100644 --- a/benchmark/python/object/distributed_object.py +++ b/benchmark/python/object/distributed_object.py @@ -1,19 +1,19 @@ from benchmarkrun import BenchmarkRun, append_to_benchmark_list_and_run from julea import lib, encode, ffi -def benchmark_distributed_object(benchmarkrun_list, iterations, machine_readable): - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/create", iterations, machine_readable), benchmark_distributed_object_create) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/create-batch", iterations, machine_readable), benchmark_distributed_object_create_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/delete", iterations, machine_readable), benchmark_distributed_object_delete) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/delete-batch", iterations, machine_readable), benchmark_distributed_object_delete_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/status", iterations, machine_readable), benchmark_distributed_object_status) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/status-batch", iterations, machine_readable), benchmark_distributed_object_status_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/read", iterations, machine_readable), benchmark_distributed_object_read) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/read-batch", iterations, machine_readable), benchmark_distributed_object_read_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/write", iterations, machine_readable), benchmark_distributed_object_write) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/write-batch", iterations, machine_readable), benchmark_distributed_object_write_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/unordered-create-delete", iterations, machine_readable), benchmark_distributed_object_unordered_create_delete) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/unordered-create-delete-batch", iterations, machine_readable), benchmark_distributed_object_unordered_create_delete_batch) +def benchmark_distributed_object(benchmarkrun_list, iterations, machine_readable, op_duration): + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/create", iterations, machine_readable, op_duration), benchmark_distributed_object_create) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/create-batch", iterations, machine_readable, op_duration), benchmark_distributed_object_create_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/delete", iterations, machine_readable, op_duration), benchmark_distributed_object_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/delete-batch", iterations, machine_readable, op_duration), benchmark_distributed_object_delete_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/status", iterations, machine_readable, op_duration), benchmark_distributed_object_status) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/status-batch", iterations, machine_readable, op_duration), benchmark_distributed_object_status_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/read", iterations, machine_readable, op_duration), benchmark_distributed_object_read) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/read-batch", iterations, machine_readable, op_duration), benchmark_distributed_object_read_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/write", iterations, machine_readable, op_duration), benchmark_distributed_object_write) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/write-batch", iterations, machine_readable, op_duration), benchmark_distributed_object_write_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/unordered-create-delete", iterations, machine_readable, op_duration), benchmark_distributed_object_unordered_create_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/distributed_object/unordered-create-delete-batch", iterations, machine_readable, op_duration), benchmark_distributed_object_unordered_create_delete_batch) def benchmark_distributed_object_create(run): _benchmark_distributed_object_create(run, False) diff --git a/benchmark/python/object/object.py b/benchmark/python/object/object.py index 3db26f30c..61909de76 100644 --- a/benchmark/python/object/object.py +++ b/benchmark/python/object/object.py @@ -1,19 +1,19 @@ from benchmarkrun import BenchmarkRun, append_to_benchmark_list_and_run from julea import lib, encode, ffi -def benchmark_object(benchmarkrun_list, iterations, machine_readable): - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/create", iterations, machine_readable), benchmark_object_create) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/create-batch", iterations, machine_readable), benchmark_object_create_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/delete", iterations, machine_readable), benchmark_object_delete) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/delete-batch", iterations, machine_readable), benchmark_object_delete_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/status", iterations, machine_readable), benchmark_object_status) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/status-batch", iterations, machine_readable), benchmark_object_status_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/read", iterations, machine_readable), benchmark_object_read) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/read-batch", iterations, machine_readable), benchmark_object_read_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/write", iterations, machine_readable), benchmark_object_write) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/write-batch", iterations, machine_readable), benchmark_object_write_batch) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/unordered-create-delete", iterations, machine_readable), benchmark_object_unordered_create_delete) - append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/unordered-create-delete-batch", iterations, machine_readable), benchmark_object_unordered_create_delete_batch) +def benchmark_object(benchmarkrun_list, iterations, machine_readable, op_duration): + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/create", iterations, machine_readable, op_duration), benchmark_object_create) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/create-batch", iterations, machine_readable, op_duration), benchmark_object_create_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/delete", iterations, machine_readable, op_duration), benchmark_object_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/delete-batch", iterations, machine_readable, op_duration), benchmark_object_delete_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/status", iterations, machine_readable, op_duration), benchmark_object_status) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/status-batch", iterations, machine_readable, op_duration), benchmark_object_status_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/read", iterations, machine_readable, op_duration), benchmark_object_read) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/read-batch", iterations, machine_readable, op_duration), benchmark_object_read_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/write", iterations, machine_readable, op_duration), benchmark_object_write) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/write-batch", iterations, machine_readable, op_duration), benchmark_object_write_batch) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/unordered-create-delete", iterations, machine_readable, op_duration), benchmark_object_unordered_create_delete) + append_to_benchmark_list_and_run(benchmarkrun_list, BenchmarkRun("/object/object/unordered-create-delete-batch", iterations, machine_readable, op_duration), benchmark_object_unordered_create_delete_batch) def benchmark_object_create(run): From 995ef355b566ba4f7161cd913983d6aee05ea084 Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Mon, 19 Jun 2023 18:36:11 +0200 Subject: [PATCH 17/18] correct python docu --- doc/python.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/python.md b/doc/python.md index 2cbca2815..f16eb04e8 100644 --- a/doc/python.md +++ b/doc/python.md @@ -8,7 +8,7 @@ For that the spack package `py-cffi` must be installed and loaded. ninja -C bld # ensure binaries are up to date spack install py-cffi # if not already installed spack load py-cffi -python python/build.py bld # bld your building directory +python python/build.py bld # bld... your building directory ``` This will create a python library with c bindings resident in the build directory. @@ -19,7 +19,7 @@ The JULEA module contains the following parts: * `julea.ffi`: basic c defines and functions. Used for null value (`julea.ffi.NULL`) and to allocate heap variables. (`p = julea.ffi.new(guint*)` will allocate `guint` and return a pointer to it) -* `julea.lib`: JULEA specific defines and functions. (`julea.lib.j_object_new(julea.encode('hello'), julea.encode('world'))`) +* `julea.lib`: The JULEA API, for further information please read the [API-documentation](https://julea-io.github.io/julea/). (`julea.lib.j_object_new(julea.encode('hello'), julea.encode('world'))`) * `encode(srt) -> c_str, read_string(c_str) -> str`: string helper to convert python to c strings and the other way around. * `JBatch` and `JBatchResult`: JULEA works in batches, therefore commands will be queued and then executed at once. ```python From 47a325741194847f67e9b0eceafe645ab316acc3 Mon Sep 17 00:00:00 2001 From: Julian Benda Date: Tue, 11 Jul 2023 17:18:53 +0200 Subject: [PATCH 18/18] Store dummy headers in seperate list * remove outdated import in hello-world.py --- python/build.py | 10 +++++++++- python/build_helper.py | 20 ++++++++------------ python/example/hello-world.py | 2 +- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/python/build.py b/python/build.py index b7c3b1441..b4f868f75 100644 --- a/python/build.py +++ b/python/build.py @@ -61,6 +61,14 @@ "void cffi_j_batch_async_callback(JBatch*, gboolean, gpointer)", ] +# header files which are needed to satisfy includes but to complex to parse +dummy_headers = [ + "glib.h", + "gmodule.h", + "bson.h", + "gio/gio.h", +] + def usage(): print("Build python bindings for JULEA with cffi.") print() @@ -82,5 +90,5 @@ def err(msg): if not os.path.isfile(os.path.abspath('.') + "/meson.build"): err("The execution directory is apperntly not the JULEA-repo root directory") print(build_dir) - build(build_dir, libraries, typedefs, macros, callback_functions, debug=True) + build(build_dir, libraries, typedefs, macros, callback_functions, dummy_headers, debug=False) copy_main_module(build_dir) diff --git a/python/build_helper.py b/python/build_helper.py index de2eed349..76a798567 100644 --- a/python/build_helper.py +++ b/python/build_helper.py @@ -35,21 +35,17 @@ def get_additional_compiler_flags(libraries, build_dir): def get_include_dirs(flags): return [ str.strip("-I") for str in flags if "-I" in str ] -def collect_julea(filename, libraries, build_dir, typedefs, macros, callbacks, debug): +def collect_julea(filename, libraries, build_dir, typedefs, macros, callbacks, dummy_headers, debug): temp_filename = "temp.h" create_header(temp_filename, libraries, typedefs, callbacks) includes = get_additional_compiler_flags(libraries, build_dir) flags = list(filter(lambda entry: not "dependencies" in entry, includes)) # create dummy headers for files intentionally not included - with open("glib.h", "w") as file: - file.write("") - with open("gmodule.h", "w") as file: - file.write("") - with open("bson.h", "w") as file: - file.write("") - system("mkdir -p gio") - with open("gio/gio.h", "w") as file: - file.write("") + for header in dummy_headers: + if path := os.path.dirname(header): + os.makedirs(path, exist_ok=True) + with open(header, "w") as file: + file.write("") macro_flags = map(lambda x: f"-D'{x}='", macros) # let preprocessor collect all declarations system(f"cc -E -P {' '.join(macro_flags)} {temp_filename} -I. {' '.join(flags)} -o {filename}") @@ -88,7 +84,7 @@ def process(build_dir, libs, tempheader, debug=False): def copy_main_module(build_dir): system(f"cp {dirname(__file__)}/julea.py {build_dir}/julea.py") -def build(build_dir, include_libs, typedefs, macros, callbacks, debug=False): +def build(build_dir, include_libs, typedefs, macros, callbacks, dummy_headers, debug=False): header_name = "header_julea.h" - collect_julea(header_name, include_libs, build_dir, typedefs, macros, callbacks, debug) + collect_julea(header_name, include_libs, build_dir, typedefs, macros, callbacks, dummy_headers, debug) process(build_dir, include_libs, header_name, debug) diff --git a/python/example/hello-world.py b/python/example/hello-world.py index 2477bea34..f7499294c 100644 --- a/python/example/hello-world.py +++ b/python/example/hello-world.py @@ -1,4 +1,4 @@ -from julea import JBatchResult, JBatch, ffi, lib, encode, read_from_buffer +from julea import JBatchResult, JBatch, ffi, lib, encode, read_string if __name__ == "__main__": try: