From af37226a00e3076030bc8e336d06b66fae59bab1 Mon Sep 17 00:00:00 2001 From: Alejandro Valerio Date: Tue, 3 Feb 2026 15:54:20 -0600 Subject: [PATCH 1/5] - Added performance test script to test local DBPA agent scenarios. --- .gitignore | 3 + CMakeLists.txt | 16 ++ src/scripts/performance_test.cpp | 462 +++++++++++++++++++++++++++++++ 3 files changed, 481 insertions(+) create mode 100644 src/scripts/performance_test.cpp diff --git a/.gitignore b/.gitignore index 0f24aca..130724f 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,6 @@ _deps/ # Testing credentials file testing_credentials.json + +# Performance test values files +random_*.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index b9e24eb..7ed3dc7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -237,6 +237,21 @@ target_include_directories(dbpa_remote_testapp PRIVATE ${CMAKE_BINARY_DIR}/_deps/snappy-src ) +# Performance Test Script executable +add_executable(performance_test src/scripts/performance_test.cpp) +target_link_libraries(performance_test + dbps_remote_lib + dbps_client_lib + dbps_common_lib + dbps_server_lib + dbps_local_lib +) +target_include_directories(performance_test PRIVATE + ${CMAKE_BINARY_DIR}/_deps/cxxopts-src/include + src/processing + ${CMAKE_BINARY_DIR}/_deps/snappy-src +) + # ============================================================================= # Test Executables # ============================================================================= @@ -486,6 +501,7 @@ add_custom_target(executables DEPENDS dbps_api_server dbpa_remote_testapp + performance_test COMMENT "Building main executables" ) diff --git a/src/scripts/performance_test.cpp b/src/scripts/performance_test.cpp new file mode 100644 index 0000000..2c2f873 --- /dev/null +++ b/src/scripts/performance_test.cpp @@ -0,0 +1,462 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/dbpa_local.h" +#include "../common/enums.h" +#include "../common/enum_utils.h" +#include "../common/bytes_utils.h" +#include "../processing/compression_utils.h" +#include "../processing/parquet_utils.h" +#include "tcb/span.hpp" + +using namespace dbps::external; +using namespace dbps::enum_utils; +using namespace dbps::compression; + +template +using span = tcb::span; + +namespace { + std::vector MakeByteArrayListPayload(const std::vector& items) { + std::vector elements; + elements.reserve(items.size()); + for (const auto& s : items) { + elements.emplace_back(s.begin(), s.end()); + } + return CombineRawBytesIntoValueBytes( + elements, Type::BYTE_ARRAY, std::nullopt, Encoding::PLAIN); + } + + std::vector BuildFloatValueBytes(const std::vector& values) { + std::vector bytes; + bytes.reserve(values.size() * sizeof(float)); + for (const auto& value : values) { + append_f32_le(bytes, std::stof(value)); + } + return bytes; + } + + std::vector BuildInt32ValueBytes(const std::vector& values) { + std::vector bytes; + bytes.reserve(values.size() * sizeof(int32_t)); + for (const auto& value : values) { + append_i32_le(bytes, static_cast(std::stol(value))); + } + return bytes; + } + + std::vector BuildInt64ValueBytes(const std::vector& values) { + std::vector bytes; + bytes.reserve(values.size() * sizeof(int64_t)); + for (const auto& value : values) { + append_i64_le(bytes, static_cast(std::stoll(value))); + } + return bytes; + } + + std::vector ReadLines(const std::string& path, std::optional max_rows) { + auto try_open = [](const std::filesystem::path& candidate) -> std::ifstream { + std::ifstream file(candidate); + return file; + }; + + std::filesystem::path input_path(path); + std::vector attempts; + attempts.push_back(input_path); + std::ifstream file = try_open(input_path); + if (!file.is_open() && input_path.is_relative()) { + std::filesystem::path source_dir = std::filesystem::path(__FILE__).parent_path(); + std::filesystem::path alt_path = source_dir / input_path; + attempts.push_back(alt_path); + file = try_open(alt_path); + } + if (!file.is_open()) { + std::ostringstream oss; + oss << "Failed to open values file. Tried:"; + for (const auto& attempt : attempts) { + oss << " " << attempt.string(); + } + throw std::runtime_error(oss.str()); + } + + std::vector lines; + std::string line; + while (std::getline(file, line)) { + if (!line.empty()) { + lines.push_back(line); + if (max_rows.has_value() && lines.size() >= max_rows.value()) { + break; + } + } + } + return lines; + } + + struct DataPageBuildResult { + std::vector payload; + std::map attrs; + std::vector level_bytes; + int32_t def_levels_byte_length = 0; + int32_t rep_levels_byte_length = 0; + }; + + DataPageBuildResult BuildDataPageV2Payload( + const std::vector& value_bytes, + size_t num_values, + CompressionCodec::type compression_type, + const std::string& page_encoding, + int32_t max_definition_level = 1, + int32_t max_repetition_level = 0, + int32_t definition_levels_byte_length = 2, + int32_t repetition_levels_byte_length = 1, + int32_t num_nulls = 0, + bool is_compressed = true) { + DataPageBuildResult result; + result.def_levels_byte_length = definition_levels_byte_length; + result.rep_levels_byte_length = repetition_levels_byte_length; + result.level_bytes = std::vector( + static_cast(definition_levels_byte_length + repetition_levels_byte_length), 0x00); + + std::vector value_payload = value_bytes; + if (is_compressed) { + value_payload = Compress(value_bytes, compression_type); + } + result.payload = Join(result.level_bytes, value_payload); + + result.attrs = { + {"page_type", "DATA_PAGE_V2"}, + {"data_page_num_values", std::to_string(num_values)}, + {"data_page_max_definition_level", std::to_string(max_definition_level)}, + {"data_page_max_repetition_level", std::to_string(max_repetition_level)}, + {"page_v2_definition_levels_byte_length", std::to_string(definition_levels_byte_length)}, + {"page_v2_repetition_levels_byte_length", std::to_string(repetition_levels_byte_length)}, + {"page_v2_num_nulls", std::to_string(num_nulls)}, + {"page_v2_is_compressed", is_compressed ? "true" : "false"}, + {"page_encoding", page_encoding} + }; + + return result; + } + + DataPageBuildResult BuildDataPageV1Payload( + const std::vector& value_bytes, + size_t num_values, + CompressionCodec::type compression_type, + const std::string& page_encoding, + int32_t max_definition_level = 1, + int32_t max_repetition_level = 1, + uint32_t repetition_level_block_length = 1, + uint32_t definition_level_block_length = 2) { + DataPageBuildResult result; + result.level_bytes.clear(); + append_u32_le(result.level_bytes, repetition_level_block_length); // repetition level block length + result.level_bytes.push_back(0xAA); + append_u32_le(result.level_bytes, definition_level_block_length); // definition level block length + result.level_bytes.push_back(0xBB); + result.level_bytes.push_back(0xCC); + auto combined_uncompressed = Join(result.level_bytes, value_bytes); + result.payload = Compress(combined_uncompressed, compression_type); + result.attrs = { + {"page_type", "DATA_PAGE_V1"}, + {"data_page_num_values", std::to_string(num_values)}, + {"data_page_max_repetition_level", std::to_string(max_repetition_level)}, + {"data_page_max_definition_level", std::to_string(max_definition_level)}, + {"page_v1_repetition_level_encoding", "RLE"}, + {"page_v1_definition_level_encoding", "RLE"}, + {"page_encoding", page_encoding} + }; + + return result; + } + + DataPageBuildResult BuildDictionaryPagePayload( + const std::vector& value_bytes, + CompressionCodec::type compression_type, + const std::string& page_encoding) { + DataPageBuildResult result; + result.level_bytes.clear(); + result.payload = Compress(value_bytes, compression_type); + result.attrs = { + {"page_type", "DICTIONARY_PAGE"}, + {"page_encoding", page_encoding} + }; + return result; + } + + std::unique_ptr BuildLocalDbpaAgent( + CompressionCodec::type compression_type, + Type::type datatype, + std::optional datatype_length, + std::optional> column_encryption_metadata = std::nullopt) { + std::string app_context = R"({"user_id": "demo_user_123"})"; + auto agent = std::make_unique(); + + agent->init( + "local_demo_column", // column_name + {}, // configuration_map + app_context, // app_context + "local_demo_key_001", // column_key_id + datatype, // datatype + datatype_length, // datatype_length + compression_type, // compression_type + column_encryption_metadata // column_encryption_metadata + ); + + return agent; + } + + struct Scenario { + std::string name; + std::string page_type; + CompressionCodec::type compression; + std::string page_encoding; + }; + + const std::vector kScenarios = { + {"data_page_v1, compression=None, encoding=PLAIN", "DATA_PAGE_V1", CompressionCodec::UNCOMPRESSED, "PLAIN"}, + {"dictionary_page, compression=SNAPPY, encoding=PLAIN", "DICTIONARY_PAGE", CompressionCodec::SNAPPY, "PLAIN"}, + {"dictionary_page, compression=None, encoding=PLAIN", "DICTIONARY_PAGE", CompressionCodec::UNCOMPRESSED, "PLAIN"}, + {"data_page_v1, compression=SNAPPY, encoding=PLAIN", "DATA_PAGE_V1", CompressionCodec::SNAPPY, "PLAIN"}, + {"data_page_v2, compression=SNAPPY, encoding=PLAIN", "DATA_PAGE_V2", CompressionCodec::SNAPPY, "PLAIN"}, + {"data_page_v1, compression=None, encoding=RLE_DICTIONARY", "DATA_PAGE_V1", CompressionCodec::UNCOMPRESSED, "RLE_DICTIONARY"} + }; +} + +class DBPALocalTestApp { +public: + DBPALocalTestApp() { + std::cout << "DBPA Local Performance Test" << std::endl; + std::cout << "===========================" << std::endl; + std::cout << std::endl; + } + + bool TestLocalDbpaAgentScenarios( + int scenario_number, + Type::type datatype, + const std::vector& value_bytes, + size_t num_values, + std::optional datatype_length) { + std::cout << "\n=== Local DBPA Agent Scenarios ===" << std::endl; + + if (scenario_number <= 0 || scenario_number > static_cast(kScenarios.size())) { + std::cout << "ERROR: Invalid scenario number: " << scenario_number << std::endl; + return false; + } + + const auto& scenario = kScenarios[static_cast(scenario_number - 1)]; + std::cout << "\nScenario: " << scenario.name + << " | datatype=" << to_string(datatype) << std::endl; + + DataPageBuildResult page; + if (scenario.page_type == "DATA_PAGE_V1") { + page = BuildDataPageV1Payload( + value_bytes, + num_values, + scenario.compression, + scenario.page_encoding); + } else if (scenario.page_type == "DATA_PAGE_V2") { + page = BuildDataPageV2Payload( + value_bytes, + num_values, + scenario.compression, + scenario.page_encoding); + } else if (scenario.page_type == "DICTIONARY_PAGE") { + page = BuildDictionaryPagePayload( + value_bytes, + scenario.compression, + scenario.page_encoding); + } else { + std::cout << " ERROR: Unknown page type: " << scenario.page_type << std::endl; + return false; + } + + auto encrypt_agent = BuildLocalDbpaAgent( + scenario.compression, + datatype, + datatype_length); + auto encrypt_result = encrypt_agent->Encrypt(span(page.payload), page.attrs); + if (!encrypt_result || !encrypt_result->success()) { + std::cout << " ERROR: Encryption failed" << std::endl; + if (encrypt_result) { + std::cout << " Error: " << encrypt_result->error_message() << std::endl; + } + return false; + } + + auto encryption_metadata = encrypt_result->encryption_metadata(); + if (!encryption_metadata) { + std::cout << " ERROR: Missing encryption metadata" << std::endl; + return false; + } + const std::string mode_key = (scenario.page_type == "DICTIONARY_PAGE") + ? "encrypt_mode_dict_page" + : "encrypt_mode_data_page"; + auto mode_it = encryption_metadata->find(mode_key); + if (mode_it == encryption_metadata->end()) { + std::cout << " ERROR: Missing " << mode_key << " in encryption metadata" << std::endl; + return false; + } + std::cout << " Encryption mode: " << mode_it->second << std::endl; + + auto decrypt_agent = BuildLocalDbpaAgent( + scenario.compression, + datatype, + datatype_length, + encryption_metadata); + auto decrypt_result = decrypt_agent->Decrypt( + span(encrypt_result->ciphertext()), + page.attrs); + if (!decrypt_result || !decrypt_result->success()) { + std::cout << " ERROR: Decryption failed" << std::endl; + if (decrypt_result) { + std::cout << " Error: " << decrypt_result->error_message() << std::endl; + } + return false; + } + + auto decrypted_plaintext = decrypt_result->plaintext(); + if (decrypted_plaintext.size() != page.payload.size() || + !std::equal(decrypted_plaintext.begin(), decrypted_plaintext.end(), page.payload.begin())) { + std::cout << " ERROR: Round-trip payload mismatch" << std::endl; + return false; + } + + std::cout << " OK: Encrypt/decrypt round-trip succeeded" << std::endl; + return true; + } + + void RunDemo( + int scenario_number, + Type::type datatype, + const std::string& values_file_path, + std::optional max_rows) { + std::cout << "Starting DBPA Local Performance Test..." << std::endl; + std::cout << std::endl; + std::cout << "\n--- Local DBPA Scenario ---" << std::endl; + std::vector lines = ReadLines(values_file_path, max_rows); + if (lines.empty()) { + std::cout << "ERROR: Values file is empty: " << values_file_path << std::endl; + std::cout << "\n=== Demo Summary ===" << std::endl; + std::cout << "Local DBPA Scenarios: FAIL" << std::endl; + return; + } + + std::vector value_bytes; + size_t num_values = 0; + if (datatype == Type::BYTE_ARRAY) { + num_values = lines.size(); + value_bytes = MakeByteArrayListPayload(lines); + } else if (datatype == Type::FLOAT) { + num_values = lines.size(); + value_bytes = BuildFloatValueBytes(lines); + } else if (datatype == Type::INT32) { + num_values = lines.size(); + value_bytes = BuildInt32ValueBytes(lines); + } else if (datatype == Type::INT64) { + num_values = lines.size(); + value_bytes = BuildInt64ValueBytes(lines); + } else { + std::cout << "ERROR: Unsupported datatype for values file: " << to_string(datatype) << std::endl; + std::cout << "\n=== Demo Summary ===" << std::endl; + std::cout << "Local DBPA Scenarios: FAIL" << std::endl; + return; + } + + bool local_dbpa_ok = TestLocalDbpaAgentScenarios( + scenario_number, + datatype, + value_bytes, + num_values, + std::nullopt); + + std::cout << "\n=== Demo Summary ===" << std::endl; + const auto& scenario = kScenarios[static_cast(scenario_number - 1)]; + std::cout << "Scenario: " << scenario.name << " (#" << scenario_number << ")" << std::endl; + std::cout << "Datatype: " << to_string(datatype) << std::endl; + std::cout << "Values file: " << values_file_path << std::endl; + std::cout << "Rows read: " << num_values << std::endl; + std::cout << "Local DBPA Scenarios: " << (local_dbpa_ok ? "PASS" : "FAIL") << std::endl; + } +}; + +int main(int argc, char* argv[]) { + cxxopts::Options options("performance_test", "DBPA Local Performance Test"); + + options.add_options() + ("scenario_number", "Local DBPA scenario number (1-N).", + cxxopts::value()->default_value("1")) + ("datatype", "Datatype to test (BYTE_ARRAY, FLOAT, INT32, INT64).", + cxxopts::value()->default_value("BYTE_ARRAY")) + ("values_file", "Path to text file with one value per line.", + cxxopts::value()) + ("max_rows", "Maximum number of rows to read from values_file (0 = no limit).", + cxxopts::value()->default_value("0")) + ("h,help", "Display this help message"); + + try { + auto result = options.parse(argc, argv); + if (result.count("help")) { + std::cout << options.help() << std::endl; + return 0; + } + + int scenario_number = result["scenario_number"].as(); + std::string datatype_arg = result["datatype"].as(); + std::string values_file_path = result["values_file"].as(); + size_t max_rows_raw = result["max_rows"].as(); + + if (values_file_path.empty()) { + std::cout << "Error: --values_file is required." << std::endl; + std::cout << options.help() << std::endl; + return 1; + } + + auto datatype_opt = to_datatype_enum(datatype_arg); + if (!datatype_opt.has_value()) { + std::cout << "Error: Unknown datatype: " << datatype_arg << std::endl; + std::cout << options.help() << std::endl; + return 1; + } + + std::optional max_rows; + if (max_rows_raw > 0) { + max_rows = max_rows_raw; + } + + DBPALocalTestApp demo; + demo.RunDemo(scenario_number, datatype_opt.value(), values_file_path, max_rows); + return 0; + } catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + std::cout << options.help() << std::endl; + return 1; + } +} From 06b15bcc248c4743b965dd6cfb4e231bd797099e Mon Sep 17 00:00:00 2001 From: Alejandro Valerio Date: Tue, 3 Feb 2026 16:08:36 -0600 Subject: [PATCH 2/5] - Added more printouts. --- src/scripts/performance_test.cpp | 90 +++++++++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 8 deletions(-) diff --git a/src/scripts/performance_test.cpp b/src/scripts/performance_test.cpp index 2c2f873..e8db897 100644 --- a/src/scripts/performance_test.cpp +++ b/src/scripts/performance_test.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -357,7 +358,9 @@ class DBPALocalTestApp { int scenario_number, Type::type datatype, const std::string& values_file_path, - std::optional max_rows) { + std::optional max_rows, + size_t iterations, + size_t warmup_rounds) { std::cout << "Starting DBPA Local Performance Test..." << std::endl; std::cout << std::endl; std::cout << "\n--- Local DBPA Scenario ---" << std::endl; @@ -390,12 +393,25 @@ class DBPALocalTestApp { return; } - bool local_dbpa_ok = TestLocalDbpaAgentScenarios( - scenario_number, - datatype, - value_bytes, - num_values, - std::nullopt); + bool local_dbpa_ok = true; + std::vector timings_ms; + size_t total_loops = warmup_rounds + iterations; + timings_ms.reserve(total_loops); + for (size_t i = 0; i < total_loops; ++i) { + auto start = std::chrono::steady_clock::now(); + bool ok = TestLocalDbpaAgentScenarios( + scenario_number, + datatype, + value_bytes, + num_values, + std::nullopt); + auto end = std::chrono::steady_clock::now(); + auto elapsed_ms = std::chrono::duration(end - start).count(); + timings_ms.push_back(elapsed_ms); + if (i >= warmup_rounds && !ok) { + local_dbpa_ok = false; + } + } std::cout << "\n=== Demo Summary ===" << std::endl; const auto& scenario = kScenarios[static_cast(scenario_number - 1)]; @@ -403,6 +419,53 @@ class DBPALocalTestApp { std::cout << "Datatype: " << to_string(datatype) << std::endl; std::cout << "Values file: " << values_file_path << std::endl; std::cout << "Rows read: " << num_values << std::endl; + std::cout << "Iterations: " << iterations << std::endl; + std::cout << "Warmup: " << warmup_rounds << std::endl; + std::cout << "Total loops: " << total_loops << std::endl; + if (!timings_ms.empty()) { + size_t warmup_clamped = std::min(warmup_rounds, timings_ms.size()); + size_t measured_count = timings_ms.size() - warmup_clamped; + if (measured_count == 0) { + std::cout << "Timing: no measured iterations after warmup" << std::endl; + } else { + double sum_ms = 0.0; + double min_ms = timings_ms[warmup_clamped]; + double max_ms = timings_ms[warmup_clamped]; + for (size_t i = warmup_clamped; i < timings_ms.size(); ++i) { + double v = timings_ms[i]; + sum_ms += v; + min_ms = std::min(min_ms, v); + max_ms = std::max(max_ms, v); + } + double avg_ms = sum_ms / static_cast(measured_count); + std::cout << "Timing (milliseconds): avg=" << avg_ms + << " min=" << min_ms + << " max=" << max_ms + << " measured=" << measured_count << std::endl; + + std::vector measured_timings(timings_ms.begin() + static_cast(warmup_clamped), + timings_ms.end()); + std::sort(measured_timings.begin(), measured_timings.end()); + size_t sample_count = std::min(5, measured_timings.size()); + std::cout << "Lowest " << sample_count << " (ms): "; + for (size_t i = 0; i < sample_count; ++i) { + if (i > 0) { + std::cout << ", "; + } + std::cout << measured_timings[i]; + } + std::cout << std::endl; + + std::cout << "Highest " << sample_count << " (ms): "; + for (size_t i = 0; i < sample_count; ++i) { + if (i > 0) { + std::cout << ", "; + } + std::cout << measured_timings[measured_timings.size() - sample_count + i]; + } + std::cout << std::endl; + } + } std::cout << "Local DBPA Scenarios: " << (local_dbpa_ok ? "PASS" : "FAIL") << std::endl; } }; @@ -419,6 +482,10 @@ int main(int argc, char* argv[]) { cxxopts::value()) ("max_rows", "Maximum number of rows to read from values_file (0 = no limit).", cxxopts::value()->default_value("0")) + ("iterations", "Number of iterations to run.", + cxxopts::value()->default_value("20")) + ("warmup", "Warmup iterations to discard from timing.", + cxxopts::value()->default_value("3")) ("h,help", "Display this help message"); try { @@ -432,6 +499,8 @@ int main(int argc, char* argv[]) { std::string datatype_arg = result["datatype"].as(); std::string values_file_path = result["values_file"].as(); size_t max_rows_raw = result["max_rows"].as(); + size_t iterations = result["iterations"].as(); + size_t warmup = result["warmup"].as(); if (values_file_path.empty()) { std::cout << "Error: --values_file is required." << std::endl; @@ -445,6 +514,11 @@ int main(int argc, char* argv[]) { std::cout << options.help() << std::endl; return 1; } + if (iterations <= 0) { + std::cout << "Error: --iterations must be > 0." << std::endl; + std::cout << options.help() << std::endl; + return 1; + } std::optional max_rows; if (max_rows_raw > 0) { @@ -452,7 +526,7 @@ int main(int argc, char* argv[]) { } DBPALocalTestApp demo; - demo.RunDemo(scenario_number, datatype_opt.value(), values_file_path, max_rows); + demo.RunDemo(scenario_number, datatype_opt.value(), values_file_path, max_rows, iterations, warmup); return 0; } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; From 107db04d2aa3bfd1b664e899f3c6e2703b46aac4 Mon Sep 17 00:00:00 2001 From: Alejandro Valerio Date: Tue, 3 Feb 2026 16:53:14 -0600 Subject: [PATCH 3/5] - Skip decrypt option added to performance test script --- src/scripts/performance_test.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/scripts/performance_test.cpp b/src/scripts/performance_test.cpp index e8db897..5b73d6e 100644 --- a/src/scripts/performance_test.cpp +++ b/src/scripts/performance_test.cpp @@ -264,7 +264,8 @@ class DBPALocalTestApp { Type::type datatype, const std::vector& value_bytes, size_t num_values, - std::optional datatype_length) { + std::optional datatype_length, + bool skip_decrypt) { std::cout << "\n=== Local DBPA Agent Scenarios ===" << std::endl; if (scenario_number <= 0 || scenario_number > static_cast(kScenarios.size())) { @@ -327,6 +328,11 @@ class DBPALocalTestApp { } std::cout << " Encryption mode: " << mode_it->second << std::endl; + if (skip_decrypt) { + std::cout << " OK: Encryption succeeded (decrypt skipped)" << std::endl; + return true; + } + auto decrypt_agent = BuildLocalDbpaAgent( scenario.compression, datatype, @@ -360,7 +366,8 @@ class DBPALocalTestApp { const std::string& values_file_path, std::optional max_rows, size_t iterations, - size_t warmup_rounds) { + size_t warmup_rounds, + bool skip_decrypt) { std::cout << "Starting DBPA Local Performance Test..." << std::endl; std::cout << std::endl; std::cout << "\n--- Local DBPA Scenario ---" << std::endl; @@ -404,7 +411,8 @@ class DBPALocalTestApp { datatype, value_bytes, num_values, - std::nullopt); + std::nullopt, + skip_decrypt); auto end = std::chrono::steady_clock::now(); auto elapsed_ms = std::chrono::duration(end - start).count(); timings_ms.push_back(elapsed_ms); @@ -486,6 +494,8 @@ int main(int argc, char* argv[]) { cxxopts::value()->default_value("20")) ("warmup", "Warmup iterations to discard from timing.", cxxopts::value()->default_value("3")) + ("skip_decrypt", "Skip decryption step.", + cxxopts::value()->default_value("true")) ("h,help", "Display this help message"); try { @@ -501,6 +511,7 @@ int main(int argc, char* argv[]) { size_t max_rows_raw = result["max_rows"].as(); size_t iterations = result["iterations"].as(); size_t warmup = result["warmup"].as(); + bool skip_decrypt = result["skip_decrypt"].as(); if (values_file_path.empty()) { std::cout << "Error: --values_file is required." << std::endl; @@ -526,7 +537,7 @@ int main(int argc, char* argv[]) { } DBPALocalTestApp demo; - demo.RunDemo(scenario_number, datatype_opt.value(), values_file_path, max_rows, iterations, warmup); + demo.RunDemo(scenario_number, datatype_opt.value(), values_file_path, max_rows, iterations, warmup, skip_decrypt); return 0; } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; From 052760f8003a5d64c303ae728c4fdb856d2ae192 Mon Sep 17 00:00:00 2001 From: Alejandro Valerio Date: Tue, 3 Feb 2026 20:48:48 -0600 Subject: [PATCH 4/5] - Updated variables names and updated default params for data page generation consistently. --- src/scripts/performance_test.cpp | 41 +++++++++++++++++--------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/scripts/performance_test.cpp b/src/scripts/performance_test.cpp index 5b73d6e..5e82ac5 100644 --- a/src/scripts/performance_test.cpp +++ b/src/scripts/performance_test.cpp @@ -135,16 +135,16 @@ namespace { CompressionCodec::type compression_type, const std::string& page_encoding, int32_t max_definition_level = 1, - int32_t max_repetition_level = 0, - int32_t definition_levels_byte_length = 2, - int32_t repetition_levels_byte_length = 1, + int32_t max_repetition_level = 2, + int32_t definition_levels_byte_length = 3, + int32_t repetition_levels_byte_length = 5, int32_t num_nulls = 0, bool is_compressed = true) { DataPageBuildResult result; result.def_levels_byte_length = definition_levels_byte_length; result.rep_levels_byte_length = repetition_levels_byte_length; result.level_bytes = std::vector( - static_cast(definition_levels_byte_length + repetition_levels_byte_length), 0x00); + static_cast(definition_levels_byte_length + repetition_levels_byte_length), 0xCC); std::vector value_payload = value_bytes; if (is_compressed) { @@ -173,16 +173,19 @@ namespace { CompressionCodec::type compression_type, const std::string& page_encoding, int32_t max_definition_level = 1, - int32_t max_repetition_level = 1, - uint32_t repetition_level_block_length = 1, - uint32_t definition_level_block_length = 2) { + int32_t max_repetition_level = 2, + uint32_t definition_level_block_length = 3, + uint32_t repetition_level_block_length = 5) { DataPageBuildResult result; result.level_bytes.clear(); append_u32_le(result.level_bytes, repetition_level_block_length); // repetition level block length - result.level_bytes.push_back(0xAA); + result.level_bytes.insert(result.level_bytes.end(), + repetition_level_block_length, + 0xAA); append_u32_le(result.level_bytes, definition_level_block_length); // definition level block length - result.level_bytes.push_back(0xBB); - result.level_bytes.push_back(0xCC); + result.level_bytes.insert(result.level_bytes.end(), + definition_level_block_length, + 0xBB); auto combined_uncompressed = Join(result.level_bytes, value_bytes); result.payload = Compress(combined_uncompressed, compression_type); result.attrs = { @@ -499,19 +502,19 @@ int main(int argc, char* argv[]) { ("h,help", "Display this help message"); try { - auto result = options.parse(argc, argv); - if (result.count("help")) { + auto parsed_options = options.parse(argc, argv); + if (parsed_options.count("help")) { std::cout << options.help() << std::endl; return 0; } - int scenario_number = result["scenario_number"].as(); - std::string datatype_arg = result["datatype"].as(); - std::string values_file_path = result["values_file"].as(); - size_t max_rows_raw = result["max_rows"].as(); - size_t iterations = result["iterations"].as(); - size_t warmup = result["warmup"].as(); - bool skip_decrypt = result["skip_decrypt"].as(); + int scenario_number = parsed_options["scenario_number"].as(); + std::string datatype_arg = parsed_options["datatype"].as(); + std::string values_file_path = parsed_options["values_file"].as(); + size_t max_rows_raw = parsed_options["max_rows"].as(); + size_t iterations = parsed_options["iterations"].as(); + size_t warmup = parsed_options["warmup"].as(); + bool skip_decrypt = parsed_options["skip_decrypt"].as(); if (values_file_path.empty()) { std::cout << "Error: --values_file is required." << std::endl; From 260cf530345d02409656cdabbf0f2f23e3a60fd5 Mon Sep 17 00:00:00 2001 From: Alejandro Valerio Date: Tue, 3 Feb 2026 21:35:30 -0600 Subject: [PATCH 5/5] - Small updates to dbpa_remote_testapp for consistency on data page generation params. --- src/scripts/dbpa_remote_testapp.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/scripts/dbpa_remote_testapp.cpp b/src/scripts/dbpa_remote_testapp.cpp index b87e623..e236671 100644 --- a/src/scripts/dbpa_remote_testapp.cpp +++ b/src/scripts/dbpa_remote_testapp.cpp @@ -451,9 +451,9 @@ class DBPARemoteTestApp { std::cout << "Binary size: " << float_binary_data.size() << " bytes" << std::endl; // Build DATA_PAGE_V2 payload: level bytes (uncompressed) + compressed value bytes - const int32_t def_len = 2; - const int32_t rep_len = 1; - std::vector level_bytes(static_cast(def_len + rep_len), 0x00); + const int32_t def_len = 3; + const int32_t rep_len = 5; + std::vector level_bytes(static_cast(def_len + rep_len), 0xCC); auto compressed_values = Compress(float_binary_data, CompressionCodec::SNAPPY); auto joined_plaintext = Join(level_bytes, compressed_values); @@ -461,7 +461,7 @@ class DBPARemoteTestApp { {"page_type", "DATA_PAGE_V2"}, {"data_page_num_values", std::to_string(float_test_data.size())}, {"data_page_max_definition_level", "1"}, - {"data_page_max_repetition_level", "0"}, + {"data_page_max_repetition_level", "2"}, {"page_v2_definition_levels_byte_length", std::to_string(def_len)}, {"page_v2_repetition_levels_byte_length", std::to_string(rep_len)}, {"page_v2_num_nulls", "0"}, @@ -620,19 +620,18 @@ class DBPARemoteTestApp { // Build DATA_PAGE_V1 payload: level bytes use RLE blocks with length prefixes std::vector level_bytes; - append_u32_le(level_bytes, 1); // repetition level block length - level_bytes.push_back(0xAA); - append_u32_le(level_bytes, 2); // definition level block length - level_bytes.push_back(0xBB); - level_bytes.push_back(0xCC); + append_u32_le(level_bytes, 3); // repetition level block length + level_bytes.insert(level_bytes.end(), 3, 0xAA); + append_u32_le(level_bytes, 5); // definition level block length + level_bytes.insert(level_bytes.end(), 5, 0xBB); auto combined_uncompressed = Join(level_bytes, fixed_length_data); auto joined_plaintext = Compress(combined_uncompressed, CompressionCodec::SNAPPY); std::cout << "Compressed size: " << joined_plaintext.size() << " bytes" << std::endl; std::map fixed_len_encoding_attributes = { {"page_type", "DATA_PAGE_V1"}, - {"data_page_num_values", "3"}, - {"data_page_max_repetition_level", "1"}, + {"data_page_num_values", std::to_string(std::size(test_strings))}, {"data_page_max_definition_level", "1"}, + {"data_page_max_repetition_level", "2"}, {"page_v1_repetition_level_encoding", "RLE"}, {"page_v1_definition_level_encoding", "RLE"}, {"page_encoding", "PLAIN"} @@ -718,7 +717,7 @@ class DBPARemoteTestApp { decompressed_combined.begin() + static_cast(offset + def_len)); offset += def_len; - if (rep_bytes != std::vector{0xAA} || def_bytes != std::vector{0xBB, 0xCC}) { + if (rep_bytes != std::vector{0xAA, 0xAA, 0xAA} || def_bytes != std::vector{0xBB, 0xBB, 0xBB, 0xBB, 0xBB}) { std::cout << "ERROR: Level bytes content mismatch" << std::endl; return false; }