diff --git a/DiscoPoP/DiscoPoP.cpp b/DiscoPoP/DiscoPoP.cpp index f628b5c07..ca6c6931f 100644 --- a/DiscoPoP/DiscoPoP.cpp +++ b/DiscoPoP/DiscoPoP.cpp @@ -2004,7 +2004,7 @@ void DiscoPoP::dp_reduction_insert_functions() { llvm::FunctionType *loop_incr_fn_type = llvm::FunctionType::get( llvm::Type::getVoidTy(*ctx_), loop_incr_fn_args, false); FunctionCallee incr_loop_counter_callee = - module_->getOrInsertFunction("incr_loop_counter", loop_incr_fn_type); + module_->getOrInsertFunction("__dp_loop_incr", loop_incr_fn_type); for (auto const &loop_info : loops_) { llvm::Value *val = @@ -2019,11 +2019,11 @@ void DiscoPoP::dp_reduction_insert_functions() { loop_metadata_file.close(); // add a function to output the final data - // loop_counter_output + // dp_loop_output llvm::FunctionType *output_fn_type = llvm::FunctionType::get(llvm::Type::getVoidTy(*ctx_), false); FunctionCallee loop_counter_output_callee = - module_->getOrInsertFunction("loop_counter_output", output_fn_type); + module_->getOrInsertFunction("__dp_loop_output", output_fn_type); FunctionCallee cu_taken_branch_counter_output_callee = module_->getOrInsertFunction("__dp_taken_branch_counter_output", output_fn_type); diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index fec629138..501b90ad4 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -32,6 +32,7 @@ target_sources( DiscoPoP_BM PRIVATE benchmarks.cpp + memory_region_tree/benchmark_memory_region_tree.cpp perfect_shadow/benchmark_perfect_shadow.cpp scope/benchmark_scope.cpp) diff --git a/benchmark/memory_region_tree/benchmark_memory_region_tree.cpp b/benchmark/memory_region_tree/benchmark_memory_region_tree.cpp new file mode 100644 index 000000000..a1af10505 --- /dev/null +++ b/benchmark/memory_region_tree/benchmark_memory_region_tree.cpp @@ -0,0 +1,193 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#include + +#include +#include +#include +#include + +#include "../../rtlib/memory/MemoryRegionTree.hpp" + +// General functions + +static std::vector convert_to_address(const std::int64_t number_iterations) { + auto mt = std::mt19937{0}; + auto uid = std::uniform_int_distribution{0, 0x7FFFFFFFFFFFFFFF}; + + auto addresses = std::vector{}; + addresses.resize(number_iterations); + + for (auto i = std::int64_t(0); i < number_iterations; i++) { + addresses[i] = uid(mt); + } + + std::sort(addresses.begin(), addresses.end()); + + return addresses; +} + +// Benchmarks for old version (i.e., establishing a base line) + +static void benchmark_mrt_allocate_region(benchmark::State& state) { + const auto number_iterations = state.range(0); + + const auto addresses = convert_to_address(number_iterations * 2); + + // This exists so that the destructor call does not interfere with the timing + auto dumping_ground = std::vector<__dp::MemoryRegionTree>{}; + + for (auto _ : state) { + state.PauseTiming(); + auto tree = __dp::MemoryRegionTree{}; + state.ResumeTiming(); + + for (auto i = 0; i < number_iterations * 2; i += 2) { + tree.allocate_region(addresses[i], addresses[i + 1], i + 1); + } + + state.PauseTiming(); + dumping_ground.emplace_back(std::move(tree)); + state.ResumeTiming(); + } +} + +static void benchmark_mrt_get_memory_region_id(benchmark::State& state) { + const auto number_iterations = state.range(0); + + const auto addresses = convert_to_address(number_iterations * 2); + + auto tree = __dp::MemoryRegionTree{}; + + for (auto i = 0; i < number_iterations * 2; i += 2) { + tree.allocate_region(addresses[i], addresses[i + 1], i + 1); + } + + for (auto _ : state) { + for (auto i = 0; i < number_iterations * 2; i++) { + benchmark::DoNotOptimize(tree.get_memory_region_id(addresses[i])); + } + } +} + +static void benchmark_mrt_get_memory_region_id_string_found(benchmark::State& state) { + const auto number_iterations = state.range(0); + + const auto addresses = convert_to_address(number_iterations * 2); + + auto tree = __dp::MemoryRegionTree{}; + + for (auto i = 0; i < number_iterations * 2; i += 2) { + tree.allocate_region(addresses[i], addresses[i + 1], i + 1); + } + + // This exists so that the destructor call does not interfere with the timing + auto dumping_ground = std::vector{}; + dumping_ground.reserve(number_iterations); + + for (auto _ : state) { + for (auto i = 0; i < number_iterations * 2; i++) { + dumping_ground.emplace_back(tree.get_memory_region_id_string(addresses[i], "fallback")); + } + } +} + +static void benchmark_mrt_get_memory_region_id_string_fallback(benchmark::State& state) { + const auto number_iterations = state.range(0); + + const auto addresses = convert_to_address(number_iterations * 2); + + auto tree = __dp::MemoryRegionTree{}; + + for (auto i = 0; i < number_iterations * 2; i += 2) { + tree.allocate_region(addresses[i], addresses[i + 1], i + 1); + } + + // This exists so that the destructor call does not interfere with the timing + auto dumping_ground = std::vector{}; + dumping_ground.reserve(number_iterations); + + for (auto _ : state) { + for (auto i = 0; i < number_iterations * 2; i++) { + const auto base_address = addresses[i]; + const auto address = (i % 2 == 0) ? base_address - 1 : base_address + 1; + + dumping_ground.emplace_back(tree.get_memory_region_id_string(address, "fallback")); + } + } +} + +static void benchmark_mrt_destructor(benchmark::State& state) { + const auto number_iterations = state.range(0); + + const auto addresses = convert_to_address(number_iterations * 2); + + for (auto _ : state) { + state.PauseTiming(); + auto tree = __dp::MemoryRegionTree{}; + for (auto i = 0; i < number_iterations * 2; i += 2) { + tree.allocate_region(addresses[i], addresses[i + 1], i + 1); + } + state.ResumeTiming(); + } +} + +static void benchmark_mrt_free_region(benchmark::State& state) { + const auto number_iterations = state.range(0); + + const auto addresses = convert_to_address(number_iterations * 2); + + // This exists so that the destructor call does not interfere with the timing + auto dumping_ground = std::vector<__dp::MemoryRegionTree>{}; + + auto tree = __dp::MemoryRegionTree{}; + + for (auto i = 0; i < number_iterations * 2; i += 2) { + tree.allocate_region(addresses[i], addresses[i + 1], i + 1); + } + + for (auto _ : state) { + state.PauseTiming(); + auto tree = __dp::MemoryRegionTree{}; + for (auto i = 0; i < number_iterations * 2; i += 2) { + tree.allocate_region(addresses[i], addresses[i + 1], i + 1); + } + state.ResumeTiming(); + + for (auto i = 0; i < number_iterations * 2; i += 2) { + tree.free_region(addresses[i]); + } + + state.PauseTiming(); + dumping_ground.emplace_back(std::move(tree)); + state.ResumeTiming(); + } +} + +BENCHMARK(benchmark_mrt_allocate_region)->Unit(benchmark::kMillisecond)->Arg(32)->Iterations(100); +BENCHMARK(benchmark_mrt_allocate_region)->Unit(benchmark::kMillisecond)->Arg(1024)->Iterations(100); + +BENCHMARK(benchmark_mrt_get_memory_region_id)->Unit(benchmark::kMillisecond)->Arg(32)->Iterations(100); +BENCHMARK(benchmark_mrt_get_memory_region_id)->Unit(benchmark::kMillisecond)->Arg(1024)->Iterations(100); + +BENCHMARK(benchmark_mrt_get_memory_region_id_string_found)->Unit(benchmark::kMillisecond)->Arg(32)->Iterations(100); +BENCHMARK(benchmark_mrt_get_memory_region_id_string_found)->Unit(benchmark::kMillisecond)->Arg(1024)->Iterations(100); + +BENCHMARK(benchmark_mrt_get_memory_region_id_string_fallback)->Unit(benchmark::kMillisecond)->Arg(32)->Iterations(100); +BENCHMARK(benchmark_mrt_get_memory_region_id_string_fallback)->Unit(benchmark::kMillisecond)->Arg(1024)->Iterations(100); + +BENCHMARK(benchmark_mrt_destructor)->Unit(benchmark::kMillisecond)->Arg(32)->Iterations(100); +BENCHMARK(benchmark_mrt_destructor)->Unit(benchmark::kMillisecond)->Arg(1024)->Iterations(100); + +BENCHMARK(benchmark_mrt_free_region)->Unit(benchmark::kMillisecond)->Arg(32)->Iterations(100); +BENCHMARK(benchmark_mrt_free_region)->Unit(benchmark::kMillisecond)->Arg(1024)->Iterations(100); diff --git a/benchmark/perfect_shadow/benchmark_perfect_shadow.cpp b/benchmark/perfect_shadow/benchmark_perfect_shadow.cpp index dcc7edca0..34b7c23dd 100644 --- a/benchmark/perfect_shadow/benchmark_perfect_shadow.cpp +++ b/benchmark/perfect_shadow/benchmark_perfect_shadow.cpp @@ -15,7 +15,7 @@ #include #include -#include "../../rtlib/perfect_shadow.hpp" +#include "../../rtlib/memory/PerfectShadow.hpp" // General functions diff --git a/benchmark/scope/benchmark_scope.cpp b/benchmark/scope/benchmark_scope.cpp index ad34c9b4e..44ceb3491 100644 --- a/benchmark/scope/benchmark_scope.cpp +++ b/benchmark/scope/benchmark_scope.cpp @@ -15,7 +15,7 @@ #include #include -#include "../../rtlib/scope.hpp" +#include "../../rtlib/memory/Scope.hpp" // General functions diff --git a/docs/setup/discopop.md b/docs/setup/discopop.md index 43f10d6df..b388087f9 100644 --- a/docs/setup/discopop.md +++ b/docs/setup/discopop.md @@ -1,39 +1,39 @@ ---- -layout: default -title: DiscoPoP -parent: Setup -nav_order: 1 ---- - -# DiscoPoP Setup -## Prerequisites -- LLVM/clang version 11 -- Python version 3.6 or greater - -## Setup -``` -git clone git@github.com:discopop-project/discopop.git -cd discopop -mkdir build -``` - -## Build libraries and install Python modules -``` -cd build -cmake .. -make -cd .. -``` - -where `` can consist of any combination of the following flags and commonly used CMAKE_FLAGS: -- In case you want to use a specific Version of LLVM, it is possible to specify the `-DUSE_LLVM_VERSION=` flag. -- In case you want to use a specific LLVM installation, specify the location via the `-DLLVM_DIST_PATH=` flag. -- In case your application uses PThreads, please specify `-DDP_PTHREAD_COMPATIBILITY_MODE=[0|1]`. Note, however, that this can influence the runtime of the profiling. -- In case you require a more verbose output of the runtime library, specify the `-DDP_RTLIB_VERBOSE=[0|1]` flag. -- In case you want to specify the number of Workers available for the profiling step, specify the `-DDP_NUM_WORKERS=` flag. By default, `3` worker threads are used to analyze the observed memory accesses. `0` might be used to disable the creation of additional threads for the analysis. - -## Testing the installation -To test the installation, it is possible to execute the provided set of unit tests. -``` -python -m unittest -v -``` +--- +layout: default +title: DiscoPoP +parent: Setup +nav_order: 1 +--- + +# DiscoPoP Setup +## Prerequisites +- LLVM/clang version 11 +- Python version 3.6 or greater + +## Setup +``` +git clone git@github.com:discopop-project/discopop.git +cd discopop +mkdir build +``` + +## Build libraries and install Python modules +``` +cd build +cmake .. +make +cd .. +``` + +where `` can consist of any combination of the following flags and commonly used CMAKE_FLAGS: +- In case you want to use a specific Version of LLVM, it is possible to specify the `-DUSE_LLVM_VERSION=` flag. +- In case you want to use a specific LLVM installation, specify the location via the `-DLLVM_DIST_PATH=` flag. +- In case your application uses PThreads, please specify `-DDP_PTHREAD_COMPATIBILITY_MODE=[0|1]`. Note, however, that this can influence the runtime of the profiling. +- In case you require a more verbose output of the runtime library, specify the `-DDP_RTLIB_VERBOSE=[0|1]` flag. +- In case you want to specify the number of Workers available for the profiling step, specify the `-DDP_NUM_WORKERS=` flag. By default, `3` worker threads are used to analyze the observed memory accesses. `0` might be used to disable the creation of additional threads for the analysis. + +## Testing the installation +To test the installation, it is possible to execute the provided set of unit tests. +``` +python -m unittest -v +``` diff --git a/rtlib/CMakeLists.txt b/rtlib/CMakeLists.txt index 49d6878d3..a3d8b4c49 100644 --- a/rtlib/CMakeLists.txt +++ b/rtlib/CMakeLists.txt @@ -14,28 +14,29 @@ set(DiscoPoP_SOURCES iFunctions.cpp iFunctionsGlobals.cpp - iFunctionsTypes.cpp - signature.cpp - loop_counter.cpp - cu_taken_branch_counter.cpp - ../share/lib/timer.cpp - MemoryRegionTree.cpp + + memory/MemoryManager.cpp + memory/Signature.cpp - functions/dp_add_bb_deps.cpp - functions/dp_alloca.cpp - functions/dp_call.cpp - functions/dp_decl.cpp - functions/dp_delete.cpp - functions/dp_finalize.cpp - functions/dp_func_entry.cpp - functions/dp_func_exit.cpp - functions/dp_loop_entry.cpp - functions/dp_loop_exit.cpp - functions/dp_new.cpp - functions/dp_read.cpp - functions/dp_report_bb.cpp - functions/dp_report_bb_pair.cpp - functions/dp_write.cpp + injected_functions/dp_add_bb_deps.cpp + injected_functions/dp_alloca.cpp + injected_functions/dp_call.cpp + injected_functions/dp_decl.cpp + injected_functions/dp_delete.cpp + injected_functions/dp_finalize.cpp + injected_functions/dp_func_entry.cpp + injected_functions/dp_func_exit.cpp + injected_functions/dp_incr_taken_branch_counter.cpp + injected_functions/dp_loop_entry.cpp + injected_functions/dp_loop_exit.cpp + injected_functions/dp_loop_incr.cpp + injected_functions/dp_loop_output.cpp + injected_functions/dp_new.cpp + injected_functions/dp_read.cpp + injected_functions/dp_report_bb.cpp + injected_functions/dp_report_bb_pair.cpp + injected_functions/dp_taken_branch_counter_output.cpp + injected_functions/dp_write.cpp ) set(CMAKE_CXX_FLAGS @@ -70,4 +71,4 @@ install(TARGETS DiscoPoP_RT ARCHIVE DESTINATION lib) # compile simple-alias-detection #exec_program(${CMAKE_CURRENT_SOURCE_DIR}/simple-alias-detection/compile.sh # ARGS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} -#) +#) \ No newline at end of file diff --git a/rtlib/DPTypes.hpp b/rtlib/DPTypes.hpp index 213120943..cc01d0c98 100644 --- a/rtlib/DPTypes.hpp +++ b/rtlib/DPTypes.hpp @@ -25,6 +25,12 @@ // #define SKIP_DUP_INSTR 1 +// To manually enable/disable internal timing +// #define DP_SKIP_INTERNAL_TIMER +#ifndef DP_SKIP_INTERNAL_TIMER +#define DP_INTERNAL_TIMER +#endif + typedef std::int64_t LID; typedef std::int64_t ADDR; typedef std::int64_t sigElement; diff --git a/rtlib/MemoryRegionTree.cpp b/rtlib/MemoryRegionTree.cpp deleted file mode 100644 index fb5d5e3cc..000000000 --- a/rtlib/MemoryRegionTree.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - * This file is part of the DiscoPoP software - * (http://www.discopop.tu-darmstadt.de) - * - * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany - * - * This software may be modified and distributed under the terms of - * the 3-Clause BSD License. See the LICENSE file in the package base - * directory for details. - * - */ - -#include "MemoryRegionTree.hpp" - -MemoryRegionTree::MemoryRegionTree() { - if (MRTVerbose) - cout << "DBG: MRT: creating new Tree.\n"; - root = new MRTNode(0xFFFFFFFFFFFFFFFF, -1); - if (MRTVerbose) { - cout << "DBG: RootNode: " << root << "\n"; - cout << "DBG: MRT: Done.\n"; - } -} - -void MemoryRegionTree::allocate_region(ADDR startAddr, ADDR endAddr, - int64_t memoryRegionId, - int32_t *tempAddrCount, - int32_t NUM_WORKERS) { - if (MRTVerbose) - cout << "DBG: MRT: allocating: " << startAddr << " - " << endAddr << " as " - << memoryRegionId << "\n"; - - // create leaf node for start of the allocated region - MRTNode *currentNode = root; - MRTNode *next_level_node = nullptr; - ADDR current_addr = 0x0; - int level = 0; - for (; level < 16; level++) { - int64_t char_at_level = get_char_at_level(startAddr, level); - // append char to currently visited address - current_addr = current_addr | (((char_at_level << 60) >> (4 * level)) & - get_level_shifting_mask(level)); - // traverse tree downwards - next_level_node = currentNode->children[char_at_level]; - if (next_level_node == nullptr) { - // create next node - next_level_node = new MRTNode(currentNode, current_addr, level); - currentNode->children[char_at_level] = next_level_node; - } - // proceed to next level - currentNode = next_level_node; - next_level_node = nullptr; - } - if (MRTVerbose) - cout << "DBG: MRT: found leaf node for startAddr: " << startAddr << "\n"; - // set memory region id in lead node - currentNode->memoryRegionId = memoryRegionId; - - // traverse upwards to find end address of the region - MRTNode *parent = nullptr; - MRTNode *child = nullptr; - ADDR child_addr = 0; - for (; level > 0;) { - // get parent at current level - parent = currentNode->parent; - // remove region entry if existing - parent->memoryRegionId = 0; - - // register or set memory region of missing children - for (ADDR child_id = 0; child_id < 16; child_id++) { - child = parent->children[child_id]; - // construct addr of child - child_addr = parent->addr; - child_addr = (child_addr | (((child_id << 60) >> 4 * (level - 1)) & - get_level_shifting_mask(level - 1))); - - // if child is missing create it: - if (child == nullptr) { - // check if child is contained in registered memory region - if (startAddr > child_addr && child_addr < endAddr) { - // create node and mark as contained - child = new MRTNode(parent, child_addr, level - 1); - child->memoryRegionId = memoryRegionId; - parent->children[child_id] = child; - if (MRTVerbose) - cout << "Registered missing child to region.\n"; - } - } else { - // child exists already, overwrite memory region id if necessary - if (startAddr > child_addr && child_addr < endAddr) { - child->memoryRegionId = memoryRegionId; - if (MRTVerbose) - cout << "child exists. Overwritten MemoryRegionId: " - << child->memoryRegionId << " with " << memoryRegionId << "\n"; - } - } - } - currentNode = currentNode->parent; - level--; - } - - // create leaf node for end of the allocated region - // and create contained children along the way - //(SEE slide set for example) - currentNode = root; - next_level_node = nullptr; - current_addr = 0x0; - level = 0; - for (; level < 16; level++) { - int64_t char_at_level = get_char_at_level(endAddr, level); - // append char to currently visited address - ADDR TMPVAL2 = ((char_at_level << 60) >> (4 * level)); - current_addr = current_addr | (((char_at_level << 60) >> (4 * level)) & - get_level_shifting_mask(level)); - // traverse tree downwards - next_level_node = currentNode->children[char_at_level]; - if (next_level_node == nullptr) { - // create next node - next_level_node = new MRTNode(currentNode, current_addr, level); - currentNode->children[char_at_level] = next_level_node; - } - // proceed to next level - currentNode = next_level_node; - next_level_node = nullptr; - // register missing children and mark as contained in region - // skip last level - if (level == 15) { - continue; - } - for (int64_t j = 0; j < char_at_level; j++) { - child = currentNode->children[j]; - if (child == nullptr) { - // create child node and register region id - ADDR child_addr = - currentNode->addr | (((j << 60) >> (4 * (level + 1))) & - get_level_shifting_mask(level + 1)); - if (child_addr <= endAddr) { - MRTNode *child_node = new MRTNode(currentNode, child_addr, level + 1); - currentNode->children[j] = child_node; - child_node->memoryRegionId = memoryRegionId; - if (MRTVerbose) - cout << "DBG: MRT: registered contained child\n"; - } - } - } - } - if (MRTVerbose) - cout << "DBG: MRT: found leaf node for endAddr: " << endAddr << "\n"; - // set memory region id in leaf node - currentNode->memoryRegionId = memoryRegionId; -} - -string MemoryRegionTree::get_memory_region_id(string fallback, ADDR addr) { - if (MRTVerbose) - cout << "Retrieving MemoryRegionID for ADDR: " << addr << " --> "; - MRTNode *currentNode = root; - MRTNode *next_level_node = nullptr; - ADDR current_addr = 0x0; - int level = 0; - uint memoryRegionId = 0; - uint readMemoryRegionId = 0; - int64_t char_at_level = 0; - for (; level < 16; level++) { - char_at_level = get_char_at_level(addr, level); - // append char to currently visited address - current_addr = current_addr | (((char_at_level << 60) >> (4 * level)) & - get_level_shifting_mask(level)); - - // save memory region of current node for return - readMemoryRegionId = currentNode->memoryRegionId; - if (readMemoryRegionId != 0) { - memoryRegionId = readMemoryRegionId; - } - - // traverse tree downwards - next_level_node = currentNode->children[char_at_level]; - if (next_level_node == nullptr) { - break; - } - // proceed to next level - currentNode = next_level_node; - next_level_node = nullptr; - } - - if (MRTVerbose) - cout << memoryRegionId << "\n"; - - if (memoryRegionId == 0) { - return fallback; - } - return std::to_string(memoryRegionId); -} diff --git a/rtlib/MemoryRegionTree.hpp b/rtlib/MemoryRegionTree.hpp deleted file mode 100644 index 47dbfc8ff..000000000 --- a/rtlib/MemoryRegionTree.hpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This file is part of the DiscoPoP software - * (http://www.discopop.tu-darmstadt.de) - * - * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany - * - * This software may be modified and distributed under the terms of - * the 3-Clause BSD License. See the LICENSE file in the package base - * directory for details. - * - */ - -#pragma once - -#include "DPUtils.hpp" - -#define MRTVerbose false - -#define get_char_at_level(addr, level) \ - (((addr << (level * 4)) >> 60) & 0x000000000000000F) - -inline ADDR get_level_shifting_mask(int level) { - switch (level) { - case 0: - return 0xF000000000000000; - case 1: - return 0x0F00000000000000; - case 2: - return 0x00F0000000000000; - case 3: - return 0x000F000000000000; - case 4: - return 0x0000F00000000000; - case 5: - return 0x00000F0000000000; - case 6: - return 0x000000F000000000; - case 7: - return 0x0000000F00000000; - case 8: - return 0x00000000F0000000; - case 9: - return 0x000000000F000000; - case 10: - return 0x0000000000F00000; - case 11: - return 0x00000000000F0000; - case 12: - return 0x000000000000F000; - case 13: - return 0x0000000000000F00; - case 14: - return 0x00000000000000F0; - case 15: - return 0x000000000000000F; - default: - return 0xFFFFFFFFFFFFFFFF; - } -} - -struct MRTNode { - // Constructors - MRTNode() = delete; - MRTNode(const MRTNode &) = delete; - - MRTNode(ADDR addr_i, short level) : addr(addr_i), level(level), children{} { - if (MRTVerbose) - cout << "DBG: MRT: Creating Node addr: " << addr << " at level: " << level - << " childArrPtr: " << children << "\n"; - }; - MRTNode(MRTNode *parent_node, ADDR addr_i, short level) - : parent(parent_node), addr(addr_i), level(level), children{} { - if (MRTVerbose) - cout << "DBG: MRT: Creating Node addr: " << addr << " at level: " << level - << " with parent addr: " << parent_node->addr - << " childArrPtr: " << children << "\n"; - }; - MRTNode(MRTNode *parent_node, ADDR addr_i, uint memRegId, short level) - : parent(parent_node), addr(addr_i), memoryRegionId(memRegId), - level(level), children{} { - if (MRTVerbose) - cout << "DBG: MRT: Creating Node addr: " << addr << " at level: " << level - << " childArrPtr: " << children << "\n"; - }; - - // Values - ADDR addr; - short level; - MRTNode *parent; - uint memoryRegionId; - MRTNode *children[16]; // 16 to split 64 bit addresses into 16 levels using - // Hex representation -}; - -struct MemoryRegionTree { - // Constructors - MemoryRegionTree(); - // Destructors - ~MemoryRegionTree(); // TODO - - // Functions - void allocate_region(ADDR startAddr, ADDR endAddr, int64_t memory_region_id, - int32_t *tempAddrCount, int32_t NUM_WORKERS); // TODO-WIP - void free_region(ADDR startADDR); // TODO - string get_memory_region_id(string fallback, ADDR addr); // TODO - void wait_for_empty_chunks(int32_t *tempAddrCount, int32_t NUM_WORKERS); - - // Values - MRTNode *root; // Root has ADDR 0xFF...FF and level -1 such that level 0 - // corresponds to first character of hex code -}; diff --git a/rtlib/abstract_shadow.hpp b/rtlib/abstract_shadow.hpp deleted file mode 100644 index 7e08f0238..000000000 --- a/rtlib/abstract_shadow.hpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of the DiscoPoP software - * (http://www.discopop.tu-darmstadt.de) - * - * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany - * - * This software may be modified and distributed under the terms of - * the 3-Clause BSD License. See the LICENSE file in the package base - * directory for details. - * - */ - -#pragma once - -#include "DPTypes.hpp" - -#include -#include - -namespace __dp { - -class Shadow { -public: - virtual ~Shadow() {} - - virtual sigElement testInRead(int64_t memAddr) = 0; - - virtual sigElement testInWrite(int64_t memAddr) = 0; - - virtual sigElement insertToRead(int64_t memAddr, sigElement value) = 0; - - virtual sigElement insertToWrite(int64_t memAddr, sigElement value) = 0; - - virtual void updateInRead(int64_t memAddr, sigElement newValue) = 0; - - virtual void updateInWrite(int64_t memAddr, sigElement newValue) = 0; - - virtual void removeFromRead(int64_t memAddr) = 0; - - virtual void removeFromWrite(int64_t memAddr) = 0; - - virtual std::unordered_set getAddrsInRange(int64_t startAddr, - int64_t endAddr) = 0; -}; - -} // namespace __dp diff --git a/rtlib/functions/FunctionManager.hpp b/rtlib/functions/FunctionManager.hpp new file mode 100644 index 000000000..810d5461e --- /dev/null +++ b/rtlib/functions/FunctionManager.hpp @@ -0,0 +1,109 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +#include "../DPTypes.hpp" +#include "../DPUtils.hpp" + +#include +#include + +namespace __dp { + +// For function merging +// 1) when two BGN func are identical + +typedef std::unordered_map> BGNFuncList; + +// 2) when two END func are identical + +typedef std::set ENDFuncList; + +class FunctionManager { +public: + FunctionManager() { + } + + ~FunctionManager() { + } + + void log_call(const LID current_lid) { + lastCallOrInvoke = current_lid; + } + + void reset_call(const LID current_lid) { + lastCallOrInvoke = 0; + lastProcessedLine = current_lid; + } + + void increase_stack_level() { + ++FuncStackLevel; + } + + void decrease_stack_level() { + --FuncStackLevel; + } + + void register_function_end(const LID current_lid) { + endFuncs.insert(current_lid); + } + + std::int32_t get_current_stack_level() { + return FuncStackLevel; + } + + void register_function_start(const LID current_lid) { + // Process ordinary function call/invoke. + + if (lastCallOrInvoke == 0) + lastCallOrInvoke = lastProcessedLine; + ++FuncStackLevel; + +#ifdef DP_DEBUG + std::cout << "Entering function LID " << std::dec << dputil::decodeLID(lid) << std::endl; + std::cout << "Function stack level = " << std::dec << FuncStackLevel << std::endl; +#endif + + BGNFuncList::iterator func = beginFuncs.find(lastCallOrInvoke); + if (func == beginFuncs.end()) { + std::set tmp{}; + tmp.insert(current_lid); + beginFuncs.emplace(lastCallOrInvoke, std::move(tmp)); + } else { + func->second.insert(current_lid); + } + } + + void output_functions(std::ostream& stream) { + for (const auto &func_begin : beginFuncs) { + for (auto fb : func_begin.second) { + stream << dputil::decodeLID(func_begin.first) << " BGN func "; + stream << dputil::decodeLID(fb) << std::endl; + } + } + + for (auto fe : endFuncs) { + stream << dputil::decodeLID(fe) << " END func" << std::endl; + } + } + +private: + BGNFuncList beginFuncs; // function entries + ENDFuncList endFuncs; // function returns + + LID lastCallOrInvoke = 0; + LID lastProcessedLine = 0; + std::int32_t FuncStackLevel = 0; +}; + +} // namespace __dp diff --git a/rtlib/functions/dp_alloca.cpp b/rtlib/functions/dp_alloca.cpp deleted file mode 100644 index e48aa38c5..000000000 --- a/rtlib/functions/dp_alloca.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * This file is part of the DiscoPoP software - * (http://www.discopop.tu-darmstadt.de) - * - * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany - * - * This software may be modified and distributed under the terms of - * the 3-Clause BSD License. See the LICENSE file in the package base - * directory for details. - * - */ - -#include "../DPTypes.hpp" -#include "../DPUtils.hpp" - -#include "../iFunctionsGlobals.hpp" - -#include "../../share/include/timer.hpp" - -#include -#include -#include -#include -#include - -using namespace std; - -namespace __dp { - -/******* Instrumentation function *******/ -extern "C" { - -void __dp_alloca(LID lid, char *var, ADDR startAddr, ADDR endAddr, - int64_t numBytes, int64_t numElements) { - if ((!dpInited) || (targetTerminated)){ - return; - } - -#ifdef DP_PTHREAD_COMPATIBILITY_MODE - std::lock_guard guard(pthread_compatibility_mutex); -#endif -#ifdef DP_RTLIB_VERBOSE - std::cout << "enter __dp_alloca\n"; -#endif - timers->start(TimerRegion::ALLOCA); - - std::int64_t buffer = nextFreeMemoryRegionId; - std::string allocId = std::to_string(buffer); - nextFreeMemoryRegionId++; - // create entry to list of allocatedMemoryRegions - std::string var_name = allocId; - if (DP_DEBUG) { - cout << "alloca: " << var << " (" << var_name << ") @ " << dputil::decodeLID(lid) - << " : " << std::hex << startAddr << " - " << std::hex << endAddr - << " -> #allocations: " << allocatedMemoryRegions->size() - << "\n"; - } - allocatedMemoryRegions->emplace_back( - lid, var_name, startAddr, endAddr, numBytes, numElements); - allocatedMemRegTree->allocate_region(startAddr, endAddr, buffer, - tempAddrCount, NUM_WORKERS); - - // update known min and max ADDR - if (startAddr < smallestAllocatedADDR) { - smallestAllocatedADDR = startAddr; - } - if (endAddr > largestAllocatedADDR) { - largestAllocatedADDR = endAddr; - } - - // TEST - // update stack base address, if not already set - if (stackAddrs->top().first == 0) { - // cout << "SET STACK BASE!\n"; - stackAddrs->top().first = startAddr; - } - // else{ - // cout << "NOT NECESSARY: SET STACK BASE\n"; - // } - - // update stack top address (note: stack grows top down!) - if (stackAddrs->top().second == 0) { - // initialize stack top address - stackAddrs->top().second = endAddr; - } else if (stackAddrs->top().second > endAddr) { - // update stack top - // cout << "UPDATE STACK TOP: " << stackAddrs->top().second << " - // --> " << endAddr << "\n"; - stackAddrs->top().second = endAddr; - } - - // cout << "STACK REGION: " << stackAddrs->top().first << " - " << - // stackAddrs->top().second << "\n"; - // !TEST - -#ifdef DP_RTLIB_VERBOSE - cout << "exit __dp_alloca\n"; -#endif - - timers->stop_and_add(TimerRegion::ALLOCA); -} - - -} - -} // namespace __dp diff --git a/rtlib/functions/dp_decl.cpp b/rtlib/functions/dp_decl.cpp deleted file mode 100644 index a086fbb28..000000000 --- a/rtlib/functions/dp_decl.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* - * This file is part of the DiscoPoP software - * (http://www.discopop.tu-darmstadt.de) - * - * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany - * - * This software may be modified and distributed under the terms of - * the 3-Clause BSD License. See the LICENSE file in the package base - * directory for details. - * - */ - -#include "../DPTypes.hpp" - -#include "../iFunctionsGlobals.hpp" -#include "../iFunctions.hpp" - -#include "../../share/include/timer.hpp" - -#include -#include -#include -#include -#include - -using namespace std; - -namespace __dp { - -/******* Instrumentation function *******/ -extern "C" { - -#ifdef SKIP_DUP_INSTR -void __dp_decl(LID lid, ADDR addr, char *var, ADDR lastaddr, int64_t count) { -#else -void __dp_decl(LID lid, ADDR addr, char *var) { -#endif - - if ((!dpInited) || (targetTerminated)){ - return; - } - -#ifdef DP_PTHREAD_COMPATIBILITY_MODE - std::lock_guard guard(pthread_compatibility_mutex); -#endif -#ifdef DP_RTLIB_VERBOSE - cout << "enter __dp_decl\n"; -#endif - timers->start(TimerRegion::DECL); - - if (targetTerminated) { - if (DP_DEBUG) { - cout << "__dp_write() is not executed since target program has returned " - "from main()." - << endl; - } - timers->stop_and_add(TimerRegion::DECL); - return; - } - // For tracking function call or invoke -#ifdef SKIP_DUP_INSTR - if (lastaddr == addr && count >= 2) { - timers->stop_and_add(TimerRegion::DECL); - return; - } -#endif - // For tracking function call or invoke - lastCallOrInvoke = 0; - lastProcessedLine = lid; - - if (DP_DEBUG) { - cout << "instStore at encoded LID " << std::dec << dputil::decodeLID(lid) - << " and addr " << std::hex << addr << endl; - } - - int64_t workerID = - ((addr - (addr % 4)) % (NUM_WORKERS * 4)) / 4; // implicit "floor" - AccessInfo ¤t = tempAddrChunks[workerID][tempAddrCount[workerID]++]; - current.isRead = false; - current.lid = 0; - current.var = var; - current.AAvar = getMemoryRegionIdFromAddr(var, addr); - current.addr = addr; - current.skip = true; - // store loop iteration metadata (last 8 bits for loop id, 1 bit to mark loop - // iteration count as valid, last 7 bits for loop iteration) last 8 bits are - // sufficient, since metadata is only used to check for different iterations, - // not exact values. first 32 bits of current.lid are reserved for metadata - // and thus empty - if (loopStack->size() > 0) { - if (loopStack->size() == 1) { - current.lid = current.lid | (((LID)(loopStack->first().loopID & 0xFF)) - << 56); // add masked loop id - current.lid = current.lid | (((LID)(loopStack->top().count & 0x7F)) - << 48); // add masked loop count - current.lid = - current.lid | (LID)0x0080000000000000; // mark loop count valid - } else if (loopStack->size() == 2) { - current.lid = current.lid | (((LID)(loopStack->first().loopID & 0xFF)) - << 56); // add masked loop id - current.lid = current.lid | (((LID)(loopStack->top().count & 0x7F)) - << 48); // add masked loop count - current.lid = - current.lid | (LID)0x0080000000000000; // mark loop count valid - current.lid = current.lid | (((LID)(loopStack->topMinusN(1).count & 0x7F)) - << 40); // add masked loop count - current.lid = - current.lid | (LID)0x0000800000000000; // mark loop count valid - } else { // (loopStack->size() >= 3) - current.lid = current.lid | (((LID)(loopStack->first().loopID & 0xFF)) - << 56); // add masked loop id - current.lid = current.lid | (((LID)(loopStack->top().count & 0x7F)) - << 48); // add masked loop count - current.lid = - current.lid | (LID)0x0080000000000000; // mark loop count valid - current.lid = current.lid | (((LID)(loopStack->topMinusN(1).count & 0x7F)) - << 40); // add masked loop count - current.lid = - current.lid | (LID)0x0000800000000000; // mark loop count valid - current.lid = current.lid | (((LID)(loopStack->topMinusN(2).count & 0x7F)) - << 32); // add masked loop count - current.lid = - current.lid | (LID)0x0000008000000000; // mark loop count valid - } - } else { - // mark loopID as invalid (0xFF to allow 0 as valid loop id) - current.lid = current.lid | (((LID)0xFF) << 56); - } - - if (tempAddrCount[workerID] == CHUNK_SIZE) { - pthread_mutex_lock(&addrChunkMutexes[workerID]); - addrChunkPresent[workerID] = true; - chunks[workerID].push(tempAddrChunks[workerID]); - pthread_cond_signal(&addrChunkPresentConds[workerID]); - pthread_mutex_unlock(&addrChunkMutexes[workerID]); - tempAddrChunks[workerID] = new AccessInfo[CHUNK_SIZE]; - tempAddrCount[workerID] = 0; - } - - timers->stop_and_add(TimerRegion::DECL); -} - -} - -} // namespace __dp diff --git a/rtlib/functions/dp_finalize.cpp b/rtlib/functions/dp_finalize.cpp deleted file mode 100644 index 989990c3a..000000000 --- a/rtlib/functions/dp_finalize.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * This file is part of the DiscoPoP software - * (http://www.discopop.tu-darmstadt.de) - * - * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany - * - * This software may be modified and distributed under the terms of - * the 3-Clause BSD License. See the LICENSE file in the package base - * directory for details. - * - */ - -#include "../DPTypes.hpp" - -#include "../iFunctionsGlobals.hpp" -#include "../iFunctions.hpp" - -#include "../../share/include/timer.hpp" - -#include "dp_func_exit.hpp" - -#include -#include -#include -#include -#include - -using namespace std; - -namespace __dp { - -/******* Instrumentation function *******/ -extern "C" { - -void __dp_finalize(LID lid) { - if(targetTerminated){ - return; - } - -#ifdef DP_PTHREAD_COMPATIBILITY_MODE - pthread_compatibility_mutex.lock(); -#endif -#ifdef DP_RTLIB_VERBOSE - cout << "enter __dp_finalize\n"; -#endif - timers->start(TimerRegion::FINALIZE); - - if (targetTerminated) { - if (DP_DEBUG) { - cout << "__dp_finalize() has been called before. Doing nothing this time " - "to avoid double free." - << endl; - } -#ifdef DP_PTHREAD_COMPATIBILITY_MODE - pthread_compatibility_mutex.unlock(); -#endif - timers->stop_and_add(TimerRegion::FINALIZE); - timers->print(std::cout); - return; - } - - // release mutex so it can be re-aquired in the called __dp_func_exit -#ifdef DP_PTHREAD_COMPATIBILITY_MODE - pthread_compatibility_mutex.unlock(); -#endif - - while (FuncStackLevel >= 0) { - __dp_func_exit(lid, 1); - } - - // use lock_guard here, since no other mutex-aquiring function is called -#ifdef DP_PTHREAD_COMPATIBILITY_MODE - std::lock_guard guard(pthread_compatibility_mutex); -#endif - - // Returning from main or exit from somewhere, clear up everything. - assert(FuncStackLevel == -1 && - "Program terminates without clearing function stack!"); - assert(loopStack->empty() && - "Program terminates but loop stack is not empty!"); - - if (DP_DEBUG) { - cout << "Program terminates at LID " << std::dec << dputil::decodeLID(lid) - << ", clearing up" << endl; - } - - if(NUM_WORKERS > 0){ - finalizeParallelization(); - } - else{ - finalizeSingleThreadedExecution(); - } - - outputLoops(); - outputFuncs(); - outputAllocations(); - // hybrid analysis - generateStringDepMap(); - // End HA - outputDeps(); - - delete loopStack; - delete endFuncs; - // hybrid analysis - delete allDeps; - delete outPutDeps; - delete bbList; - // End HA - - for (auto loop : *loops) { - delete loop.second; - } - delete loops; - - for (auto fb : *beginFuncs) { - delete fb.second; - } - delete beginFuncs; - - // TEST - delete scopeManager; - // !TEST - - *out << dputil::decodeLID(lid) << " END program" << endl; - out->flush(); - out->close(); - - delete out; - - dpInited = false; - targetTerminated = true; // mark the target program has returned from main() - - if (DP_DEBUG) { - cout << "Program terminated." << endl; - } - -#ifdef DP_RTLIB_VERBOSE - cout << "exit __dp_finalize\n"; -#endif - - timers->stop_and_add(TimerRegion::FINALIZE); - timers->print(std::cout); - - delete timers; -} - -} - -} // namespace __dp diff --git a/rtlib/functions/dp_func_exit.cpp b/rtlib/functions/dp_func_exit.cpp deleted file mode 100644 index 93e86920e..000000000 --- a/rtlib/functions/dp_func_exit.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * This file is part of the DiscoPoP software - * (http://www.discopop.tu-darmstadt.de) - * - * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany - * - * This software may be modified and distributed under the terms of - * the 3-Clause BSD License. See the LICENSE file in the package base - * directory for details. - * - */ - -#include "../DPTypes.hpp" - -#include "../iFunctionsGlobals.hpp" -#include "../iFunctions.hpp" - -#include "../../share/include/timer.hpp" - -#include -#include -#include -#include -#include - -using namespace std; - -namespace __dp { - -/******* Instrumentation function *******/ -extern "C" { - -void __dp_func_exit(LID lid, int32_t isExit) { - - if (targetTerminated) { - if (DP_DEBUG) { - cout << "Exiting function LID " << std::dec << dputil::decodeLID(lid); - cout << " but target program has returned from main(). Destructors?" - << endl; - } - return; - } - -#ifdef DP_PTHREAD_COMPATIBILITY_MODE - std::lock_guard guard(pthread_compatibility_mutex); -#endif -#ifdef DP_RTLIB_VERBOSE - cout << "__dp_func_exit\n"; -#endif - timers->start(TimerRegion::FUNC_EXIT); - - - lastCallOrInvoke = 0; - lastProcessedLine = lid; - - // Clear up all unfinished loops in the function. - // This usually happens when using return inside loop. - while (!loopStack->empty() && - (loopStack->top().funcLevel == FuncStackLevel)) { - - // No way to get the real end line of loop. Use the line where - // function returns instead. - LoopRecords::iterator loop = loops->find(loopStack->top().begin); - assert(loop != loops->end() && - "A loop ends without its entry being recorded."); - if (loop->second->end == 0) { - loop->second->end = lid; - } else { - // TODO: FIXME: loop end line > return line - } - loop->second->total += loopStack->top().count; - ++loop->second->nEntered; - - if (DP_DEBUG) { - cout << "(" << std::dec << loopStack->top().funcLevel << ")"; - cout << "Loop " << loopStack->top().loopID - << " exits since function returns." << endl; - } - - loopStack->pop(); - - if (DP_DEBUG) { - if (loopStack->empty()) - cout << "Loop Stack is empty." << endl; - else { - cout << "TOP: (" << std::dec << loopStack->top().funcLevel << ")"; - cout << "Loop " << loopStack->top().loopID << "." << endl; - } - } - } - --FuncStackLevel; - - // TEST - // clear information on allocated stack addresses - // if(stackAddrs->size() > 0){ - // cout << "POP STACK ENTRY: " << hex << stackAddrs->top().first << - // " -> " << hex << stackAddrs->top().second << " \n"; - // } - clearStackAccesses( - stackAddrs->top().first, - stackAddrs->top().second); // insert accesses with LID 0 to the queues - stackAddrs->pop(); - // if(stackAddrs->size() > 0){ - // cout << "\tNEW TOP STACK ENTRY: " << hex << - // stackAddrs->top().first << " -> " << hex << - // stackAddrs->top().second << " \n"; - // } - scopeManager->leaveScope("function", lid); - // !TEST - - if (isExit == 0) - endFuncs->insert(lid); - - if (DP_DEBUG) { - cout << "Exiting fucntion LID " << std::dec << dputil::decodeLID(lid) << endl; - cout << "Function stack level = " << std::dec << FuncStackLevel << endl; - } - - timers->stop_and_add(TimerRegion::FUNC_EXIT); -} - -} - -} // namespace __dp diff --git a/rtlib/functions/dp_loop_exit.cpp b/rtlib/functions/dp_loop_exit.cpp deleted file mode 100644 index 344b3bc2e..000000000 --- a/rtlib/functions/dp_loop_exit.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * This file is part of the DiscoPoP software - * (http://www.discopop.tu-darmstadt.de) - * - * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany - * - * This software may be modified and distributed under the terms of - * the 3-Clause BSD License. See the LICENSE file in the package base - * directory for details. - * - */ - -#include "../DPTypes.hpp" - -#include "../iFunctionsGlobals.hpp" - -#include "../../share/include/timer.hpp" - -#include -#include -#include -#include -#include - -using namespace std; - -namespace __dp { - -/******* Instrumentation function *******/ -extern "C" { - -void __dp_loop_exit(LID lid, int32_t loopID) { - if((!dpInited) || (targetTerminated)){ - return; - } - -#ifdef DP_PTHREAD_COMPATIBILITY_MODE - std::lock_guard guard(pthread_compatibility_mutex); -#endif -#ifdef DP_RTLIB_VERBOSE - cout << "__dp_loop_exit\n"; -#endif - timers->start(TimerRegion::LOOP_EXIT); - - if (targetTerminated) { - if (DP_DEBUG) { - cout << "__dp_loop_exit() is not executed since target program has " - "returned from main()." - << endl; - } - timers->stop_and_add(TimerRegion::LOOP_EXIT); - return; - } - assert((loopStack != nullptr) && "Loop stack is not available!"); - - // __dp_loop_exit() can be called without __dp_loop_entry() - // being called. This can happen when a loop is encapsulated - // by an "if" strucutre, and the condition of "if" fails - bool singleExit = false; - if (loopStack->empty()) - singleExit = true; - else if (loopStack->top().loopID != loopID) - singleExit = true; - - if (singleExit) { - if (DP_DEBUG) { - cout << "Ignored signle exit of loop " << loopStack->top().loopID << endl; - } - timers->stop_and_add(TimerRegion::LOOP_EXIT); - return; - } - - // See comments in __dp_loop_entry() for explanation. - if (loopStack->top().funcLevel != FuncStackLevel) { - if (DP_DEBUG) { - cout << "WARNING: changing funcLevel of Loop " << loopStack->top().loopID - << " from " << loopStack->top().funcLevel << " to " << FuncStackLevel - << endl; - } - loopStack->top().funcLevel = FuncStackLevel; - } - - LoopRecords::iterator loop = loops->find(loopStack->top().begin); - assert(loop != loops->end() && - "A loop ends without its entry being recorded."); - if (loop->second->end == 0) { - loop->second->end = lid; - } else { - // New loop exit found and it's smaller than before. That means - // the current exit point can be the break inside the loop. - // In this case we ignore the current exit point and keep the - // regular one. - - // Note: keep, as i may be necessary in the future? - if (lid < loop->second->end) { - // loop->second->end = lid; - } - // New loop exit found and it's bigger than before. This can - // happen when the previous exit is a break inside the loop. - // In this case we update the loop exit to the bigger one. - else if (lid > loop->second->end) { - loop->second->end = lid; - } - // New loop exit found and it's the same as before. Good. - } - if (loop->second->maxIterationCount < loopStack->top().count) { - loop->second->maxIterationCount = loopStack->top().count; - } - loop->second->total += loopStack->top().count; - ++loop->second->nEntered; - - if (DP_DEBUG) { - cout << "(" << std::dec << loopStack->top().funcLevel << ")"; - cout << "Loop " << loopStack->top().loopID << " exits." << endl; - } - - loopStack->pop(); - - if (DP_DEBUG) { - if (loopStack->empty()) - cout << "Loop Stack is empty." << endl; - else { - cout << "TOP: (" << std::dec << loopStack->top().funcLevel << ")"; - cout << "Loop " << loopStack->top().loopID << "." << endl; - } - } - - scopeManager->leaveScope("loop", lid); - timers->stop_and_add(TimerRegion::LOOP_EXIT); -} - -} - -} // namespace __dp diff --git a/rtlib/functions/dp_read.cpp b/rtlib/functions/dp_read.cpp deleted file mode 100644 index deddc8c45..000000000 --- a/rtlib/functions/dp_read.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* - * This file is part of the DiscoPoP software - * (http://www.discopop.tu-darmstadt.de) - * - * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany - * - * This software may be modified and distributed under the terms of - * the 3-Clause BSD License. See the LICENSE file in the package base - * directory for details. - * - */ - -#include "../DPTypes.hpp" - -#include "../iFunctionsGlobals.hpp" -#include "../iFunctions.hpp" - -#include "../../share/include/timer.hpp" - -#include -#include -#include -#include -#include - -using namespace std; - -namespace __dp { - -/******* Instrumentation function *******/ -extern "C" { -#ifdef SKIP_DUP_INSTR -void __dp_read(LID lid, ADDR addr, char *var, ADDR lastaddr, int64_t count) { -#else -void __dp_read(LID lid, ADDR addr, char *var) { -#endif - - if ((!dpInited) || (targetTerminated)){ - return; - } - -#ifdef DP_PTHREAD_COMPATIBILITY_MODE - std::lock_guard guard(pthread_compatibility_mutex); -#endif -#ifdef DP_RTLIB_VERBOSE - cout << "enter __dp_read\n"; -#endif - timers->start(TimerRegion::READ); - - if (targetTerminated) { - if (DP_DEBUG) { - cout << "__dp_read() is not executed since target program has returned " - "from main()." - << endl; - } - timers->stop_and_add(TimerRegion::READ); - return; - } - // For tracking function call or invoke -#ifdef SKIP_DUP_INSTR - if (lastaddr == addr && count >= 2) { - timers->stop_and_add(TimerRegion::READ); - return; - } -#endif - - lastCallOrInvoke = 0; - lastProcessedLine = lid; - - if (DP_DEBUG) { - cout << "instLoad at encoded LID " << std::dec << dputil::decodeLID(lid) - << " and addr " << std::hex << addr << endl; - } - - // TEST - // check for stack access - timers->start(TimerRegion::STACK_CHECK_READ_ACCESS); - bool is_stack_access = false; - if (stackAddrs->top().first && stackAddrs->top().second) { - if ((addr <= stackAddrs->top().first) && - (addr >= stackAddrs->top().second)) { - timers->start(TimerRegion::STACK_FOUND_READ_ACCESS); - is_stack_access = true; - timers->stop_and_add(TimerRegion::STACK_FOUND_READ_ACCESS); - } - } - timers->stop_and_add(TimerRegion::STACK_CHECK_READ_ACCESS); - // !TEST - -#if defined DP_NUM_WORKERS && DP_NUM_WORKERS == 0 - AccessInfo current; -#else - int64_t workerID = - ((addr - (addr % 4)) % (NUM_WORKERS * 4)) / 4; // implicit "floor" - AccessInfo ¤t = tempAddrChunks[workerID][tempAddrCount[workerID]++]; - -#endif - current.isRead = true; - current.lid = lid; - current.var = var; - current.AAvar = getMemoryRegionIdFromAddr(var, addr); - current.addr = addr; - current.isStackAccess = is_stack_access; - timers->start(TimerRegion::STACK_CHECK_ADDR_IS_OWNED_BY_SCOPE); - current.addrIsOwnedByScope = - scopeManager->isOwnedByScope(addr, false); - timers->stop_and_add(TimerRegion::STACK_CHECK_ADDR_IS_OWNED_BY_SCOPE); - if(current.addrIsOwnedByScope){ - timers->start(TimerRegion::STACK_CHECK_ADDR_IS_OWNED_BY_SCOPE_TRUE); - timers->stop_and_add(TimerRegion::STACK_CHECK_ADDR_IS_OWNED_BY_SCOPE_TRUE); - } - current.positiveScopeChangeOccuredSinceLastAccess = - scopeManager->positiveScopeChangeOccuredSinceLastAccess(addr); - - if (is_stack_access) { - // register stack read after check for - // positiveScopeChangeOccuredSinceLastAccess - scopeManager->registerStackRead(addr, lid, var); - } - - // store loop iteration metadata (last 8 bits for loop id, 1 bit to mark loop - // iteration count as valid, last 7 bits for loop iteration) last 8 bits are - // sufficient, since metadata is only used to check for different iterations, - // not exact values. first 32 bits of current.lid are reserved for metadata - // and thus empty - if (loopStack->size() > 0) { - if (loopStack->size() == 1) { - current.lid = current.lid | (((LID)(loopStack->first().loopID & 0xFF)) - << 56); // add masked loop id - current.lid = current.lid | (((LID)(loopStack->top().count & 0x7F)) - << 48); // add masked loop count - current.lid = - current.lid | (LID)0x0080000000000000; // mark loop count valid - } else if (loopStack->size() == 2) { - current.lid = current.lid | (((LID)(loopStack->first().loopID & 0xFF)) - << 56); // add masked loop id - current.lid = current.lid | (((LID)(loopStack->top().count & 0x7F)) - << 48); // add masked loop count - current.lid = - current.lid | (LID)0x0080000000000000; // mark loop count valid - current.lid = current.lid | (((LID)(loopStack->topMinusN(1).count & 0x7F)) - << 40); // add masked loop count - current.lid = - current.lid | (LID)0x0000800000000000; // mark loop count valid - } else { // (loopStack->size() >= 3) - current.lid = current.lid | (((LID)(loopStack->first().loopID & 0xFF)) - << 56); // add masked loop id - current.lid = current.lid | (((LID)(loopStack->top().count & 0x7F)) - << 48); // add masked loop count - current.lid = - current.lid | (LID)0x0080000000000000; // mark loop count valid - current.lid = current.lid | (((LID)(loopStack->topMinusN(1).count & 0x7F)) - << 40); // add masked loop count - current.lid = - current.lid | (LID)0x0000800000000000; // mark loop count valid - current.lid = current.lid | (((LID)(loopStack->topMinusN(2).count & 0x7F)) - << 32); // add masked loop count - current.lid = - current.lid | (LID)0x0000008000000000; // mark loop count valid - } - } else { - // mark loopID as invalid (0xFF to allow 0 as valid loop id) - current.lid = current.lid | (((LID)0xFF) << 56); - } - -#if defined DP_NUM_WORKERS && DP_NUM_WORKERS == 0 - analyzeSingleAccess(singleThreadedExecutionSMem, current); -#else - if (tempAddrCount[workerID] == CHUNK_SIZE) { - pthread_mutex_lock(&addrChunkMutexes[workerID]); - addrChunkPresent[workerID] = true; - chunks[workerID].push(tempAddrChunks[workerID]); - pthread_cond_signal(&addrChunkPresentConds[workerID]); - pthread_mutex_unlock(&addrChunkMutexes[workerID]); - tempAddrChunks[workerID] = new AccessInfo[CHUNK_SIZE]; - tempAddrCount[workerID] = 0; - } -#endif -#ifdef DP_RTLIB_VERBOSE - cout << "exit __dp_read\n"; -#endif - - timers->stop_and_add(TimerRegion::READ); -} -} - -} // namespace __dp diff --git a/rtlib/functions/dp_write.cpp b/rtlib/functions/dp_write.cpp deleted file mode 100644 index 066c3d293..000000000 --- a/rtlib/functions/dp_write.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - * This file is part of the DiscoPoP software - * (http://www.discopop.tu-darmstadt.de) - * - * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany - * - * This software may be modified and distributed under the terms of - * the 3-Clause BSD License. See the LICENSE file in the package base - * directory for details. - * - */ - -#include "../DPTypes.hpp" - -#include "../iFunctionsGlobals.hpp" -#include "../iFunctions.hpp" - -#include "../../share/include/timer.hpp" - -#include -#include -#include -#include -#include - -using namespace std; - -namespace __dp { - -/******* Instrumentation function *******/ -extern "C" { - -#ifdef SKIP_DUP_INSTR -void __dp_write(LID lid, ADDR addr, char *var, ADDR lastaddr, int64_t count) { -#else -void __dp_write(LID lid, ADDR addr, char *var) { -#endif - - if ((!dpInited) || (targetTerminated)){ - return; - } - -#ifdef DP_PTHREAD_COMPATIBILITY_MODE - std::lock_guard guard(pthread_compatibility_mutex); -#endif -#ifdef DP_RTLIB_VERBOSE - cout << "enter __dp_write\n"; -#endif - timers->start(TimerRegion::WRITE); - - if (targetTerminated) { - if (DP_DEBUG) { - cout << "__dp_write() is not executed since target program has returned " - "from main()." - << endl; - } - timers->stop_and_add(TimerRegion::WRITE); - return; - } - // For tracking function call or invoke -#ifdef SKIP_DUP_INSTR - if (lastaddr == addr && count >= 2) { - timers->stop_and_add(TimerRegion::WRITE); - return; - } -#endif - - // For tracking function call or invoke - lastCallOrInvoke = 0; - lastProcessedLine = lid; - - if (DP_DEBUG) { - cout << "instStore at encoded LID " << std::dec << dputil::decodeLID(lid) - << " and addr " << std::hex << addr << endl; - } - - // TEST - // check for stack access - timers->start(TimerRegion::STACK_CHECK_WRITE_ACCESS); - bool is_stack_access = false; - if (stackAddrs->top().first && stackAddrs->top().second) { - if ((addr <= stackAddrs->top().first) && - (addr >= stackAddrs->top().second)) { - // cout << "WRITE STACK ACCESS DETECTED! " << - // dputil::decodeLID(lid) << " " << var << "\n"; - timers->start(TimerRegion::STACK_FOUND_WRITE_ACCESS); - is_stack_access = true; - timers->stop_and_add(TimerRegion::STACK_FOUND_WRITE_ACCESS); - } - } - timers->stop_and_add(TimerRegion::STACK_CHECK_WRITE_ACCESS); - // !TEST - -#if defined DP_NUM_WORKERS && DP_NUM_WORKERS == 0 - AccessInfo current; -#else - int64_t workerID = ((addr - (addr % 4)) % (NUM_WORKERS * 4)) / 4; // implicit "floor" - AccessInfo ¤t = tempAddrChunks[workerID][tempAddrCount[workerID]++]; -#endif - - current.isRead = false; - current.lid = lid; - current.var = var; - current.AAvar = getMemoryRegionIdFromAddr(var, addr); - current.addr = addr; - current.isStackAccess = is_stack_access; - timers->start(TimerRegion::STACK_CHECK_ADDR_IS_OWNED_BY_SCOPE); - current.addrIsOwnedByScope = - scopeManager->isOwnedByScope(addr, true); - timers->stop_and_add(TimerRegion::STACK_CHECK_ADDR_IS_OWNED_BY_SCOPE); - if(current.addrIsOwnedByScope){ - timers->start(TimerRegion::STACK_CHECK_ADDR_IS_OWNED_BY_SCOPE_TRUE); - timers->stop_and_add(TimerRegion::STACK_CHECK_ADDR_IS_OWNED_BY_SCOPE_TRUE); - } - current.positiveScopeChangeOccuredSinceLastAccess = - scopeManager->positiveScopeChangeOccuredSinceLastAccess(addr); - - if (is_stack_access) { - // register stack write after check for - // positiveScopeChangeOccuredSinceLastAccess - scopeManager->registerStackWrite(addr, lid, var); - } - - // store loop iteration metadata (last 8 bits for loop id, 1 bit to mark loop - // iteration count as valid, last 7 bits for loop iteration) last 8 bits are - // sufficient, since metadata is only used to check for different iterations, - // not exact values. first 32 bits of current.lid are reserved for metadata - // and thus empty - if (loopStack->size() > 0) { - if (loopStack->size() == 1) { - current.lid = current.lid | (((LID)(loopStack->first().loopID & 0xFF)) - << 56); // add masked loop id - current.lid = current.lid | (((LID)(loopStack->top().count & 0x7F)) - << 48); // add masked loop count - current.lid = - current.lid | (LID)0x0080000000000000; // mark loop count valid - } else if (loopStack->size() == 2) { - current.lid = current.lid | (((LID)(loopStack->first().loopID & 0xFF)) - << 56); // add masked loop id - current.lid = current.lid | (((LID)(loopStack->top().count & 0x7F)) - << 48); // add masked loop count - current.lid = - current.lid | (LID)0x0080000000000000; // mark loop count valid - current.lid = current.lid | (((LID)(loopStack->topMinusN(1).count & 0x7F)) - << 40); // add masked loop count - current.lid = - current.lid | (LID)0x0000800000000000; // mark loop count valid - } else { // (loopStack->size() >= 3) - current.lid = current.lid | (((LID)(loopStack->first().loopID & 0xFF)) - << 56); // add masked loop id - current.lid = current.lid | (((LID)(loopStack->top().count & 0x7F)) - << 48); // add masked loop count - current.lid = - current.lid | (LID)0x0080000000000000; // mark loop count valid - current.lid = current.lid | (((LID)(loopStack->topMinusN(1).count & 0x7F)) - << 40); // add masked loop count - current.lid = - current.lid | (LID)0x0000800000000000; // mark loop count valid - current.lid = current.lid | (((LID)(loopStack->topMinusN(2).count & 0x7F)) - << 32); // add masked loop count - current.lid = - current.lid | (LID)0x0000008000000000; // mark loop count valid - } - } else { - // mark loopID as invalid (0xFF to allow 0 as valid loop id) - current.lid = current.lid | (((LID)0xFF) << 56); - } - -#if defined DP_NUM_WORKERS && DP_NUM_WORKERS == 0 - analyzeSingleAccess(singleThreadedExecutionSMem, current); -#else - if (tempAddrCount[workerID] == CHUNK_SIZE) { - pthread_mutex_lock(&addrChunkMutexes[workerID]); - addrChunkPresent[workerID] = true; - chunks[workerID].push(tempAddrChunks[workerID]); - pthread_cond_signal(&addrChunkPresentConds[workerID]); - pthread_mutex_unlock(&addrChunkMutexes[workerID]); - tempAddrChunks[workerID] = new AccessInfo[CHUNK_SIZE]; - tempAddrCount[workerID] = 0; - } -#endif - -#ifdef DP_RTLIB_VERBOSE - cout << "exit __dp_write\n"; -#endif - - timers->stop_and_add(TimerRegion::WRITE); -} - -} - -} // namespace __dp diff --git a/rtlib/iFunctions.cpp b/rtlib/iFunctions.cpp index cf692ae52..e69fe2c45 100644 --- a/rtlib/iFunctions.cpp +++ b/rtlib/iFunctions.cpp @@ -11,16 +11,17 @@ */ #include "iFunctions.hpp" -#include "perfect_shadow.hpp" -#include "shadow.hpp" -#include "signature.hpp" -#include "functions/all.hpp" +#include "iFunctionsGlobals.hpp" + #include "DPUtils.hpp" -#include "MemoryRegionTree.hpp" -#include "scope.hpp" -#include "../share/include/timer.hpp" -#include "iFunctionsGlobals.hpp" +#include "loop/Makros.hpp" +#include "memory/PerfectShadow.hpp" +#include "memory/ShadowMemory.hpp" +#include "memory/Signature.hpp" +#include "injected_functions/all.hpp" +#include "../share/include/debug_print.hpp" +#include "../share/include/timer.hpp" #include #include @@ -31,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -51,14 +53,14 @@ using namespace dputil; namespace __dp { - - /******* Helper functions *******/ void addDep(depType type, LID curr, LID depOn, char *var, string AAvar, bool isStackAccess, ADDR addr, bool addrIsFirstWrittenInScope, bool positiveScopeChangeOccuredSinceLastAccess) { - timers->start(TimerRegion::ADD_DEP); +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::ADD_DEP); +#endif // hybrid analysis if (depOn == 0 && type == WAW) @@ -363,17 +365,17 @@ void addDep(depType type, LID curr, LID depOn, char *var, string AAvar, << myMap->size() << ")" << endl; } } - - timers->stop_and_add(TimerRegion::ADD_DEP); } // hybrid analysis void generateStringDepMap() { - timers->start(TimerRegion::GENERATE_STRING_DEP_MAP); - #ifdef DP_RTLIB_VERBOSE - cout << "enter generateStringDepMap\n"; + const auto debug_print = make_debug_print("generateStringDepMap"); #endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::GENERATE_STRING_DEP_MAP); +#endif + for (auto &dline : *allDeps) { if (dline.first) { string lid = decodeLID(dline.first); @@ -438,19 +440,16 @@ void generateStringDepMap() { delete dline.second; } } -#ifdef DP_RTLIB_VERBOSE - cout << "enter generateStringDepMap\n"; -#endif - - timers->stop_and_add(TimerRegion::GENERATE_STRING_DEP_MAP); } -void outputDeps() { - timers->start(TimerRegion::OUTPUT_DEPS); - +void outputDeps() { #ifdef DP_RTLIB_VERBOSE - cout << "enter outputDeps\n"; + const auto debug_print = make_debug_print("outputDeps"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::OUTPUT_DEPS); #endif + for (auto pair : *outPutDeps) { *out << pair.first << " NOM "; for (auto dep : pair.second) { @@ -458,105 +457,14 @@ void outputDeps() { } *out << endl; } -#ifdef DP_RTLIB_VERBOSE - cout << "exit outputDeps\n"; -#endif - - timers->stop_and_add(TimerRegion::OUTPUT_DEPS); } // End HA -void outputLoops() { - timers->start(TimerRegion::OUTPUT_LOOPS); - -#ifdef DP_RTLIB_VERBOSE - cout << "enter outputLoops\n"; -#endif - assert((loops != nullptr) && "Loop map is not available!"); - for (auto &loop : *loops) { - *out << decodeLID(loop.first) << " BGN loop "; - *out << loop.second->total << ' '; - *out << loop.second->nEntered << ' '; - *out << static_cast(loop.second->total / loop.second->nEntered) - << ' '; - *out << loop.second->maxIterationCount << endl; - *out << decodeLID(loop.second->end) << " END loop" << endl; - } -#ifdef DP_RTLIB_VERBOSE - cout << "exit outputLoops\n"; -#endif - - timers->stop_and_add(TimerRegion::OUTPUT_LOOPS); -} - -void outputFuncs() { - timers->start(TimerRegion::OUTPUT_FUNCS); - -#ifdef DP_RTLIB_VERBOSE - cout << "enter outputFunc\n"; -#endif - assert(beginFuncs != nullptr && endFuncs != nullptr && - "Function maps are not available!"); - for (auto &func_begin : *beginFuncs) { - for (auto fb : *(func_begin.second)) { - *out << decodeLID(func_begin.first) << " BGN func "; - *out << decodeLID(fb) << endl; - } - } - - for (auto fe : *endFuncs) { - *out << decodeLID(fe) << " END func" << endl; - } -#ifdef DP_RTLIB_VERBOSE - cout << "exit outputFunc\n"; -#endif - - timers->stop_and_add(TimerRegion::OUTPUT_FUNCS); -} - -void outputAllocations() { - timers->start(TimerRegion::OUTPUT_ALLOCATIONS); - -#ifdef DP_RTLIB_VERBOSE - cout << "enter outputAllocations\n"; -#endif - const auto prepare_environment = [](){ - // prepare environment variables - const char *discopop_env = getenv("DOT_DISCOPOP"); - if (discopop_env == NULL) { - - // DOT_DISCOPOP needs to be initialized - setenv("DOT_DISCOPOP", ".discopop", 1); - discopop_env = ".discopop"; - } - - auto discopop_profiler_str = std::string(discopop_env) + "/profiler"; - setenv("DOT_DISCOPOP_PROFILER", discopop_profiler_str.data(), 1); - - return discopop_profiler_str + "/memory_regions.txt"; - }; - const auto path = prepare_environment(); - - auto allocationsFileStream = ofstream(path, ios::out); - for (const auto& memoryRegion : *allocatedMemoryRegions) { - const auto lid = get<0>(memoryRegion); - const auto& id = get<1>(memoryRegion); - const auto num_bytes = get<4>(memoryRegion); - - decodeLID(lid, allocationsFileStream); - allocationsFileStream << ' ' << id << ' ' << num_bytes << endl; - } - -#ifdef DP_RTLIB_VERBOSE - cout << "exit outputAllocations\n"; -#endif - timers->stop_and_add(TimerRegion::OUTPUT_ALLOCATIONS); -} - void readRuntimeInfo() { #ifdef DP_RTLIB_VERBOSE cout << "enter readRuntimeInfo\n"; #endif + ifstream conf(get_exe_dir() + "/dp.conf"); string line; if (conf.is_open()) { @@ -603,17 +511,20 @@ void readRuntimeInfo() { cout << "chunk_size = " << CHUNK_SIZE << "\n"; sleep(2); } + #ifdef DP_RTLIB_VERBOSE cout << "exit readRuntimeInfo\n"; #endif } -void initParallelization() { - timers->start(TimerRegion::INIT_PARALLELIZATION); - +void initParallelization() { #ifdef DP_RTLIB_VERBOSE - cout << "enter initParallelization\n"; + const auto debug_print = make_debug_print("initParallelization"); #endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::INIT_PARALLELIZATION); +#endif + // initialize global variables addrChunkPresentConds = new pthread_cond_t[NUM_WORKERS]; addrChunkMutexes = new pthread_mutex_t[NUM_WORKERS]; @@ -644,92 +555,31 @@ void initParallelization() { } pthread_attr_destroy(&attr); -#ifdef DP_RTLIB_VERBOSE - cout << "exit initParallelization\n"; -#endif - - timers->stop_and_add(TimerRegion::INIT_PARALLELIZATION); } void initSingleThreadedExecution() { #ifdef DP_RTLIB_VERBOSE - cout << "enter initSingleThreadedExecution\n"; + const auto debug_print = make_debug_print("initSingleThreadedExecution"); #endif -timers->start(TimerRegion::ANALYZE_DEPS); - +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::ANALYZE_DEPS); +#endif + if (USE_PERFECT) { singleThreadedExecutionSMem = new PerfectShadow(SIG_ELEM_BIT, SIG_NUM_ELEM, SIG_NUM_HASH); } else { singleThreadedExecutionSMem = new ShadowMemory(SIG_ELEM_BIT, SIG_NUM_ELEM, SIG_NUM_HASH); } - myMap = new depMap(); - -#ifdef DP_RTLIB_VERBOSE - cout << "exit initSingleThreadedExecution\n"; -#endif -} - -void finalizeSingleThreadedExecution() { -#ifdef DP_RTLIB_VERBOSE - cout << "enter finalizeSingleThreadedExecution\n"; -#endif - if (DP_DEBUG) { - cout << "BEGIN: finalize Single Threaded Execution... \n"; - } - - delete singleThreadedExecutionSMem; - mergeDeps(); - - if (DP_DEBUG) { - cout << "END: finalize Single Threaded Execution... \n"; - } -#ifdef DP_RTLIB_VERBOSE - cout << "exit finalizeSingleThreadedExecution\n"; -#endif + myMap = new depMap(); } string getMemoryRegionIdFromAddr(string fallback, ADDR addr) { - timers->start(TimerRegion::GET_MEMORY_REGION_ID_FROM_ADDR); - - // use tree - const auto return_value = fallback + "-" + - allocatedMemRegTree->get_memory_region_id(fallback, addr); - - timers->stop_and_add(TimerRegion::GET_MEMORY_REGION_ID_FROM_ADDR); - return return_value; - - /*// check if accessed addr in knwon range. If not, return fallback - immediately if(addr >= smallestAllocatedADDR && addr <= largestAllocatedADDR){ - // FOR NOW, ONLY SEARCH BACKWARDS TO FIND THE LATEST ALLOCA ENTRY IN CASE - MEMORY ADDRESSES ARE REUSED if(allocatedMemoryRegions->size() != 0){ - // search backwards in the list - auto bw_it = allocatedMemoryRegions->end(); - bw_it--; - bool search_backwards = true; - - while(true){ - if(*bw_it == allocatedMemoryRegions->front()){ - search_backwards = false; - } - if(get<2>(*bw_it) <= addr && get<3>(*bw_it) >= addr){ - lastHitIterator = bw_it; - return get<1>(*bw_it); - } - - if(search_backwards){ - bw_it--; - } - else{ - break; - } - } - } - - } +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::GET_MEMORY_REGION_ID_FROM_ADDR); +#endif - return fallback; - */ + return fallback + '-' + memory_manager->get_memory_region_id(addr, fallback); } void mergeDeps() { @@ -737,7 +587,9 @@ void mergeDeps() { depMap::iterator globalPos; // position of the current processing lid in allDeps pthread_mutex_lock(&allDepsLock); - timers->start(TimerRegion::MERGE_DEPS); +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::MERGE_DEPS); +#endif for (auto &dep : *myMap) { // if a lid occurs the first time, then add it in to the global hash table. @@ -756,19 +608,19 @@ void mergeDeps() { } } - timers->stop_and_add(TimerRegion::MERGE_DEPS); pthread_mutex_unlock(&allDepsLock); } -void analyzeSingleAccess(__dp::Shadow* SMem, __dp::AccessInfo& access){ +void analyzeSingleAccess(__dp::AbstractShadow* SMem, __dp::AccessInfo& access){ // analyze data dependences - timers->start(TimerRegion::ANALYZE_SINGLE_ACCESS); +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::ANALYZE_SINGLE_ACCESS); +#endif if (access.isRead) { // hybrid analysis if (access.skip) { SMem->insertToRead(access.addr, access.lid); - timers->stop_and_add(TimerRegion::ANALYZE_SINGLE_ACCESS); return; } // End HA @@ -808,14 +660,15 @@ void analyzeSingleAccess(__dp::Shadow* SMem, __dp::AccessInfo& access){ } } } - timers->stop_and_add(TimerRegion::ANALYZE_SINGLE_ACCESS); } -void *analyzeDeps(void *arg) { - timers->start(TimerRegion::ANALYZE_DEPS); +void* analyzeDeps(void *arg) { +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::ANALYZE_DEPS); +#endif int64_t id = (int64_t)arg; - Shadow *SMem; + AbstractShadow *SMem; if (USE_PERFECT) { SMem = new PerfectShadow(SIG_ELEM_BIT, SIG_NUM_ELEM, SIG_NUM_HASH); } else { @@ -879,16 +732,18 @@ void *analyzeDeps(void *arg) { cout << "thread " << id << " exits... \n"; } - timers->stop_and_add(TimerRegion::ANALYZE_DEPS); pthread_exit(NULL); + return nullptr; } void finalizeParallelization() { - timers->start(TimerRegion::FINALIZE_PARALLELIZATION); - #ifdef DP_RTLIB_VERBOSE - cout << "enter finalizeParallelization\n"; + const auto debug_print = make_debug_print("finalizeParallelization"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::FINALIZE_PARALLELIZATION); #endif + if (DP_DEBUG) { cout << "BEGIN: finalize parallelization... \n"; } @@ -931,24 +786,38 @@ void finalizeParallelization() { if (DP_DEBUG) { cout << "END: finalize parallelization... \n"; } +} + +void finalizeSingleThreadedExecution() { #ifdef DP_RTLIB_VERBOSE - cout << "exit finalizeParallelization\n"; + const auto debug_print = make_debug_print("finalizeSingleThreadedExecution"); #endif - timers->stop_and_add(TimerRegion::FINALIZE_PARALLELIZATION); + if (DP_DEBUG) { + std::cout << "BEGIN: finalize Single Threaded Execution... \n"; + } + + delete singleThreadedExecutionSMem; + mergeDeps(); + + if (DP_DEBUG) { + std::cout << "END: finalize Single Threaded Execution... \n"; + } } void clearStackAccesses(ADDR stack_lower_bound, ADDR stack_upper_bound) { - timers->start(TimerRegion::CLEAR_STACK_ACCESSES); +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::CLEAR_STACK_ACCESSES); +#endif - for (ADDR addr : scopeManager->getCurrentScope().get_first_write()) { + const auto& current_scope = memory_manager->getCurrentScope(); + const auto& writes = current_scope.get_first_write(); + for (ADDR addr : writes) { //cleanup reads __dp_read(0, addr, ""); //cleanup writes __dp_write(0, addr, ""); } - - timers->stop_and_add(TimerRegion::CLEAR_STACK_ACCESSES); } } // namespace __dp diff --git a/rtlib/iFunctions.hpp b/rtlib/iFunctions.hpp index 8cba38977..f77a456ed 100644 --- a/rtlib/iFunctions.hpp +++ b/rtlib/iFunctions.hpp @@ -14,7 +14,7 @@ #include "DPTypes.hpp" #include "iFunctionsTypes.hpp" -#include "abstract_shadow.hpp" +#include "memory/AbstractShadow.hpp" #include @@ -25,12 +25,6 @@ void addDep(depType type, LID curr, LID depOn, char *var, char *AAvar); void outputDeps(); -void outputLoops(); - -void outputFuncs(); - -void outputAllocations(); - void generateStringDepMap(); void readRuntimeInfo(); @@ -41,9 +35,9 @@ void initSingleThreadedExecution(); void mergeDeps(); -void *analyzeDeps(void *arg); +void* analyzeDeps(void *arg); -void analyzeSingleAccess(__dp::Shadow* SMem, __dp::AccessInfo& access); +void analyzeSingleAccess(__dp::AbstractShadow* SMem, __dp::AccessInfo& access); std::string getMemoryRegionIdFromAddr(std::string fallback, ADDR addr); diff --git a/rtlib/iFunctionsGlobals.cpp b/rtlib/iFunctionsGlobals.cpp index 71ba233fd..7b007ed43 100644 --- a/rtlib/iFunctionsGlobals.cpp +++ b/rtlib/iFunctionsGlobals.cpp @@ -29,16 +29,16 @@ Timers* timers = nullptr; std::mutex pthread_compatibility_mutex; +FunctionManager* function_manager = nullptr; +LoopManager* loop_manager= nullptr; +MemoryManager* memory_manager = nullptr; + // hybrid analysis ReportedBBSet *bbList = nullptr; stringDepMap *outPutDeps = nullptr; -// end hybrid analysis - -std::int64_t nextFreeMemoryRegionId = 1; // 0 is reserved as the identifier for "no region" in the MemoryRegionTree +// end hybrid analysis -/// (LID, identifier, startAddr, endAddr, numBytes, numElements) -std::vector>::iterator lastHitIterator; -std::vector> *allocatedMemoryRegions = nullptr; +std::unordered_map cuec; bool dpInited = false; // library initialization flag bool targetTerminated = false; // whether the target program has returned from main() @@ -51,24 +51,7 @@ bool targetTerminated = false; // whether the target program has returned from m // Runtime merging structures depMap *allDeps = nullptr; -LoopTable *loopStack = nullptr; // loop stack tracking -LoopRecords *loops = nullptr; // loop merging -BGNFuncList *beginFuncs = nullptr; // function entries -ENDFuncList *endFuncs = nullptr; // function returns std::ofstream *out = nullptr; -std::ofstream *outInsts = nullptr; -std::stack> *stackAddrs = nullptr; // track stack adresses for entered functions -ScopeManager *scopeManager = nullptr; - -LID lastCallOrInvoke = 0; -LID lastProcessedLine = 0; -std::int32_t FuncStackLevel = 0; - -MemoryRegionTree *allocatedMemRegTree = nullptr; - -ADDR smallestAllocatedADDR = std::numeric_limits::max(); -ADDR largestAllocatedADDR = std::numeric_limits::min(); - /******* BEGIN: parallelization section *******/ pthread_cond_t *addrChunkPresentConds = nullptr; // condition variables @@ -85,8 +68,10 @@ int32_t NUM_WORKERS = DP_NUM_WORKERS; int32_t NUM_WORKERS = 3; // default number of worker threads (multiple workers // can potentially lead to non-deterministic results) #endif + #pragma message "Profiler: set NUM_WORKERS to " XSTR(NUM_WORKERS) -extern Shadow* singleThreadedExecutionSMem = nullptr; // used if NUM_WORKERS==0 +AbstractShadow* singleThreadedExecutionSMem = nullptr; // used if NUM_WORKERS==0 + int32_t CHUNK_SIZE = 500; // default number of addresses in each chunk std::queue *chunks = nullptr; // one queue of access info chunks for each worker thread diff --git a/rtlib/iFunctionsGlobals.hpp b/rtlib/iFunctionsGlobals.hpp index 110757648..7c5c0f111 100644 --- a/rtlib/iFunctionsGlobals.hpp +++ b/rtlib/iFunctionsGlobals.hpp @@ -13,10 +13,8 @@ #pragma once #include "iFunctionsTypes.hpp" -#include "scope.hpp" -#include "MemoryRegionTree.hpp" #include "../share/include/timer.hpp" -#include "shadow.hpp" +#include "memory/AbstractShadow.hpp" #include @@ -28,6 +26,7 @@ #include #include #include +#include #include extern bool USE_PERFECT; @@ -47,16 +46,16 @@ extern Timers* timers; extern std::mutex pthread_compatibility_mutex; +extern FunctionManager* function_manager; +extern LoopManager* loop_manager; +extern MemoryManager* memory_manager; + // hybrid analysis extern ReportedBBSet *bbList; extern stringDepMap *outPutDeps; // end hybrid analysis -extern std::int64_t nextFreeMemoryRegionId; // 0 is reserved as the identifier for "no region" in the MemoryRegionTree - -/// (LID, identifier, startAddr, endAddr, numBytes, numElements) -extern std::vector>::iterator lastHitIterator; -extern std::vector> *allocatedMemoryRegions; +extern std::unordered_map cuec; extern bool dpInited; // library initialization flag extern bool targetTerminated; // whether the target program has returned from main() @@ -69,32 +68,16 @@ extern bool targetTerminated; // whether the target program has returned from ma // Runtime merging structures extern depMap *allDeps; -extern LoopTable *loopStack; // loop stack tracking -extern LoopRecords *loops; // loop merging -extern BGNFuncList *beginFuncs; // function entries -extern ENDFuncList *endFuncs; // function returns extern std::ofstream *out; -extern std::ofstream *outInsts; -extern std::stack> *stackAddrs; // track stack adresses for entered functions -extern ScopeManager *scopeManager; - -extern LID lastCallOrInvoke; -extern LID lastProcessedLine; -extern std::int32_t FuncStackLevel; - -extern MemoryRegionTree *allocatedMemRegTree; - -extern ADDR smallestAllocatedADDR; -extern ADDR largestAllocatedADDR; - extern pthread_cond_t *addrChunkPresentConds; // condition variables extern pthread_mutex_t *addrChunkMutexes; // associated mutexes extern pthread_mutex_t allDepsLock; extern pthread_t *workers; // worker threads +extern AbstractShadow* singleThreadedExecutionSMem; + extern int32_t NUM_WORKERS; -extern Shadow* singleThreadedExecutionSMem; extern int32_t CHUNK_SIZE; // default number of addresses in each chunk extern std::queue *chunks; // one queue of access info chunks for each worker thread diff --git a/rtlib/iFunctionsTypes.hpp b/rtlib/iFunctionsTypes.hpp index 0f84423e9..aca7c72a8 100644 --- a/rtlib/iFunctionsTypes.hpp +++ b/rtlib/iFunctionsTypes.hpp @@ -14,6 +14,10 @@ #include "DPTypes.hpp" +#include "functions/FunctionManager.hpp" +#include "loop/LoopManager.hpp" +#include "memory/MemoryManager.hpp" + #include #include #include @@ -100,85 +104,15 @@ struct compDep { typedef std::set depSet; typedef std::unordered_map depMap; + // Hybrid anaysis typedef std::unordered_map> stringDepMap; -// End HA - -// For loop tracking -struct LoopTableEntry { - LoopTableEntry(std::int32_t l, std::int32_t id, std::int32_t c, LID b) - : funcLevel(l), loopID(id), count(c), begin(b) {} - - std::int32_t funcLevel; - std::int32_t loopID; - std::int32_t count; - LID begin; -}; - -// typedef std::stack LoopTable; -struct LoopTable { - LoopTable(){}; - - std::vector contents; - - inline LoopTableEntry &top() { return contents.back(); } - - inline LoopTableEntry &first() { return contents[0]; } - - inline LoopTableEntry &topMinusN(std::size_t n) { - return contents[contents.size() - 1 - n]; - } - - inline void pop() { contents.pop_back(); } - - inline bool empty() { return contents.empty(); } - - inline void push(LoopTableEntry newElement) { - contents.push_back(newElement); - } - - inline std::size_t size() { return contents.size(); } -}; - -// For loop merging -// Assumption: no more than one loops can begin at the same line -struct LoopRecord { - LoopRecord(LID e, std::int32_t t, std::int32_t n) : end(e), total(t), nEntered(n) {} - - LID end; - std::int32_t total; - std::int32_t maxIterationCount = - 0; // maximum iterations executed during a single loop entry - std::int32_t nEntered; -}; - -typedef std::unordered_map LoopRecords; - -// For function merging -// 1) when two BGN func are identical - -typedef std::unordered_map *> BGNFuncList; - -// Hybrid analysis typedef std::set ReportedBBSet; typedef std::set ReportedBBPairSet; // End HA -// 2) when two END func are identical -typedef std::set ENDFuncList; } // namespace __dp -#define unpackLIDMetadata_getLoopID(lid) (lid >> 56) -#define unpackLIDMetadata_getLoopIteration_0(lid) ((lid >> 48) & 0x7F) -#define unpackLIDMetadata_getLoopIteration_1(lid) ((lid >> 40) & 0x7F) -#define unpackLIDMetadata_getLoopIteration_2(lid) ((lid >> 32) & 0x7F) -#define checkLIDMetadata_getLoopIterationValidity_0(lid) \ - ((lid & 0x0080000000000000) >> 55) -#define checkLIDMetadata_getLoopIterationValidity_1(lid) \ - ((lid & 0x0000800000000000) >> 47) -#define checkLIDMetadata_getLoopIterationValidity_2(lid) \ - ((lid & 0x0000008000000000) >> 39) - // issue a warning if DP_PTHREAD_COMPATIBILITY_MODE is enabled #ifdef DP_PTHREAD_COMPATIBILITY_MODE #warning \ diff --git a/rtlib/functions/all.hpp b/rtlib/injected_functions/all.hpp similarity index 80% rename from rtlib/functions/all.hpp rename to rtlib/injected_functions/all.hpp index 6d3b6cf0e..d94ba814f 100644 --- a/rtlib/functions/all.hpp +++ b/rtlib/injected_functions/all.hpp @@ -20,10 +20,14 @@ #include "dp_finalize.hpp" #include "dp_func_entry.hpp" #include "dp_func_exit.hpp" +#include "dp_incr_taken_branch_counter.hpp" #include "dp_loop_entry.hpp" #include "dp_loop_exit.hpp" +#include "dp_loop_incr.hpp" +#include "dp_loop_output.hpp" #include "dp_new.hpp" #include "dp_read.hpp" #include "dp_report_bb.hpp" #include "dp_report_bb_pair.hpp" +#include "dp_taken_branch_counter_output.hpp" #include "dp_write.hpp" diff --git a/rtlib/functions/dp_add_bb_deps.cpp b/rtlib/injected_functions/dp_add_bb_deps.cpp similarity index 84% rename from rtlib/functions/dp_add_bb_deps.cpp rename to rtlib/injected_functions/dp_add_bb_deps.cpp index 8832338d4..7c4b63fa6 100644 --- a/rtlib/functions/dp_add_bb_deps.cpp +++ b/rtlib/injected_functions/dp_add_bb_deps.cpp @@ -14,6 +14,7 @@ #include "../iFunctionsGlobals.hpp" +#include "../../share/include/debug_print.hpp" #include "../../share/include/timer.hpp" #include @@ -29,7 +30,7 @@ namespace __dp { extern "C" { // hybrid analysis void __dp_add_bb_deps(char *depStringPtr) { - if((!dpInited) || (targetTerminated)){ + if (!dpInited || targetTerminated) { return; } @@ -37,10 +38,11 @@ void __dp_add_bb_deps(char *depStringPtr) { std::lock_guard guard(pthread_compatibility_mutex); #endif #ifdef DP_RTLIB_VERBOSE - std::cout << "enter __dp_add_bb_deps\n"; + const auto debug_print = make_debug_print("__dp_add_bb_deps"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::ADD_BB_DEPS); #endif - - timers->start(TimerRegion::ADD_BB_DEPS); std::string depString(depStringPtr); std::regex r0("[^\\/]+"), r1("[^=]+"), r2("[^,]+"), r3("[0-9]+:[0-9]+"), @@ -75,8 +77,6 @@ void __dp_add_bb_deps(char *depStringPtr) { } depString = res0.suffix(); } - - timers->stop_and_add(TimerRegion::ADD_BB_DEPS); } // End HA } diff --git a/rtlib/functions/dp_add_bb_deps.hpp b/rtlib/injected_functions/dp_add_bb_deps.hpp similarity index 100% rename from rtlib/functions/dp_add_bb_deps.hpp rename to rtlib/injected_functions/dp_add_bb_deps.hpp diff --git a/rtlib/injected_functions/dp_alloca.cpp b/rtlib/injected_functions/dp_alloca.cpp new file mode 100644 index 000000000..79d2fd3ab --- /dev/null +++ b/rtlib/injected_functions/dp_alloca.cpp @@ -0,0 +1,63 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#include "../DPTypes.hpp" +#include "../DPUtils.hpp" + +#include "../iFunctionsGlobals.hpp" + +#include "../../share/include/debug_print.hpp" +#include "../../share/include/timer.hpp" + +#include +#include +#include +#include +#include + +using namespace std; + +namespace __dp { + +/******* Instrumentation function *******/ +extern "C" { + +void __dp_alloca(LID lid, char *var, ADDR startAddr, ADDR endAddr, + int64_t numBytes, int64_t numElements) { + if (!dpInited || targetTerminated) { + return; + } + +#ifdef DP_PTHREAD_COMPATIBILITY_MODE + std::lock_guard guard(pthread_compatibility_mutex); +#endif +#ifdef DP_RTLIB_VERBOSE + const auto debug_print = make_debug_print("__dp_alloca"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::ALLOCA); +#endif + + // create entry to list of allocatedMemoryRegions + const std::string allocId = memory_manager->allocate_stack_memory(lid, startAddr, endAddr, numBytes, numElements); + // std::cout << "alloca: " << var << " (" << allocId << ") @ " << dputil::decodeLID(lid) << " : " << std::hex << startAddr << " - " << std::hex << endAddr << " -> #allocations: " << memory_manager->get_number_allocations() << "\n"; +#ifdef DP_DEBUG + cout << "alloca: " << var << " (" << allocId << ") @ " << dputil::decodeLID(lid) + << " : " << std::hex << startAddr << " - " << std::hex << endAddr + << " -> #allocations: " << memory_manager->get_number_allocations() + << "\n"; +#endif +} + +} + +} // namespace __dp diff --git a/rtlib/functions/dp_alloca.hpp b/rtlib/injected_functions/dp_alloca.hpp similarity index 100% rename from rtlib/functions/dp_alloca.hpp rename to rtlib/injected_functions/dp_alloca.hpp diff --git a/rtlib/functions/dp_call.cpp b/rtlib/injected_functions/dp_call.cpp similarity index 72% rename from rtlib/functions/dp_call.cpp rename to rtlib/injected_functions/dp_call.cpp index 19c903930..3ee9fa9ce 100644 --- a/rtlib/functions/dp_call.cpp +++ b/rtlib/injected_functions/dp_call.cpp @@ -14,6 +14,7 @@ #include "../iFunctionsGlobals.hpp" +#include "../../share/include/debug_print.hpp" #include "../../share/include/timer.hpp" #include @@ -30,7 +31,7 @@ namespace __dp { extern "C" { void __dp_call(LID lid) { - if ((!dpInited) || (targetTerminated)){ + if (!dpInited || targetTerminated) { return; } @@ -38,13 +39,13 @@ void __dp_call(LID lid) { std::lock_guard guard(pthread_compatibility_mutex); #endif #ifdef DP_RTLIB_VERBOSE - cout << "__dp_call\n"; + const auto debug_print = make_debug_print("__dp_call"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::CALL); #endif - timers->start(TimerRegion::CALL); - - lastCallOrInvoke = lid; - timers->stop_and_add(TimerRegion::CALL); + function_manager->log_call(lid); } } diff --git a/rtlib/functions/dp_call.hpp b/rtlib/injected_functions/dp_call.hpp similarity index 100% rename from rtlib/functions/dp_call.hpp rename to rtlib/injected_functions/dp_call.hpp diff --git a/rtlib/injected_functions/dp_decl.cpp b/rtlib/injected_functions/dp_decl.cpp new file mode 100644 index 000000000..b88b99b1a --- /dev/null +++ b/rtlib/injected_functions/dp_decl.cpp @@ -0,0 +1,97 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#include "../DPTypes.hpp" + +#include "../iFunctionsGlobals.hpp" +#include "../iFunctions.hpp" + +#include "../../share/include/debug_print.hpp" +#include "../../share/include/timer.hpp" + +#include +#include +#include +#include +#include + +using namespace std; + +namespace __dp { + +/******* Instrumentation function *******/ +extern "C" { + +#ifdef SKIP_DUP_INSTR +void __dp_decl(LID lid, ADDR addr, char *var, ADDR lastaddr, int64_t count) { +#else +void __dp_decl(LID lid, ADDR addr, char *var) { +#endif + + if (!dpInited || targetTerminated) { + return; + } + +#ifdef DP_PTHREAD_COMPATIBILITY_MODE + std::lock_guard guard(pthread_compatibility_mutex); +#endif +#ifdef DP_RTLIB_VERBOSE + const auto debug_print = make_debug_print("__dp_decl"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::DECL); +#endif + + if (targetTerminated) { + if (DP_DEBUG) { + std::cout << "__dp_write() is not executed since target program has returned from main().\n"; + } + return; + } + +#ifdef SKIP_DUP_INSTR + if (lastaddr == addr && count >= 2) { + return; + } +#endif + + function_manager->reset_call(lid); + + if (DP_DEBUG) { + cout << "instStore at encoded LID " << std::dec << dputil::decodeLID(lid) + << " and addr " << std::hex << addr << endl; + } + + int64_t workerID = + ((addr - (addr % 4)) % (NUM_WORKERS * 4)) / 4; // implicit "floor" + AccessInfo ¤t = tempAddrChunks[workerID][tempAddrCount[workerID]++]; + current.isRead = false; + current.lid = loop_manager->update_lid(0); + current.var = var; + current.AAvar = getMemoryRegionIdFromAddr(var, addr); + current.addr = addr; + current.skip = true; + + if (tempAddrCount[workerID] == CHUNK_SIZE) { + pthread_mutex_lock(&addrChunkMutexes[workerID]); + addrChunkPresent[workerID] = true; + chunks[workerID].push(tempAddrChunks[workerID]); + pthread_cond_signal(&addrChunkPresentConds[workerID]); + pthread_mutex_unlock(&addrChunkMutexes[workerID]); + tempAddrChunks[workerID] = new AccessInfo[CHUNK_SIZE]; + tempAddrCount[workerID] = 0; + } +} + +} + +} // namespace __dp diff --git a/rtlib/functions/dp_decl.hpp b/rtlib/injected_functions/dp_decl.hpp similarity index 100% rename from rtlib/functions/dp_decl.hpp rename to rtlib/injected_functions/dp_decl.hpp diff --git a/rtlib/functions/dp_delete.cpp b/rtlib/injected_functions/dp_delete.cpp similarity index 83% rename from rtlib/functions/dp_delete.cpp rename to rtlib/injected_functions/dp_delete.cpp index c4663fb1c..a858da1a3 100644 --- a/rtlib/functions/dp_delete.cpp +++ b/rtlib/injected_functions/dp_delete.cpp @@ -14,6 +14,7 @@ #include "../iFunctionsGlobals.hpp" +#include "../../share/include/debug_print.hpp" #include "../../share/include/timer.hpp" #include @@ -30,7 +31,7 @@ namespace __dp { extern "C" { void __dp_delete(LID lid, ADDR startAddr) { - if ((!dpInited) || (targetTerminated)){ + if (!dpInited || targetTerminated) { return; } @@ -38,9 +39,11 @@ void __dp_delete(LID lid, ADDR startAddr) { std::lock_guard guard(pthread_compatibility_mutex); #endif #ifdef DP_RTLIB_VERBOSE - cout << "enter __dp_delete\n"; + const auto debug_print = make_debug_print("__dp_delete"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::DELETE); #endif - timers->start(TimerRegion::DELETE); // DO NOT DELETE MEMORY REGIONS AS THEY ARE STILL REQUIRED FOR LOGGING @@ -59,11 +62,6 @@ void __dp_delete(LID lid, ADDR startAddr) { cout << "__dp_delete: Could not find base addr: " << std::hex << startAddr << "\n"; */ -#ifdef DP_RTLIB_VERBOSE - cout << "exit __dp_delete\n"; -#endif - - timers->stop_and_add(TimerRegion::DELETE); } } diff --git a/rtlib/functions/dp_delete.hpp b/rtlib/injected_functions/dp_delete.hpp similarity index 100% rename from rtlib/functions/dp_delete.hpp rename to rtlib/injected_functions/dp_delete.hpp diff --git a/rtlib/injected_functions/dp_finalize.cpp b/rtlib/injected_functions/dp_finalize.cpp new file mode 100644 index 000000000..12c322d21 --- /dev/null +++ b/rtlib/injected_functions/dp_finalize.cpp @@ -0,0 +1,175 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#include "../DPTypes.hpp" + +#include "../iFunctionsGlobals.hpp" +#include "../iFunctions.hpp" + +#include "../../share/include/debug_print.hpp" +#include "../../share/include/timer.hpp" + +#include "dp_func_exit.hpp" + +#include +#include +#include +#include +#include + +using namespace std; + +namespace __dp { + +/******* Instrumentation function *******/ +extern "C" { + +void __dp_finalize(LID lid) { + if (targetTerminated) { + return; + } +#ifdef DP_PTHREAD_COMPATIBILITY_MODE + pthread_compatibility_mutex.lock(); +#endif +#ifdef DP_RTLIB_VERBOSE + const auto debug_print = make_debug_print("__dp_loop_exit"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::FINALIZE, true); +#endif + + if (targetTerminated) { + if (DP_DEBUG) { + cout << "__dp_finalize() has been called before. Doing nothing this time " + "to avoid double free." + << endl; + } +#ifdef DP_PTHREAD_COMPATIBILITY_MODE + pthread_compatibility_mutex.unlock(); +#endif + return; + } + + // release mutex so it can be re-aquired in the called __dp_func_exit +#ifdef DP_PTHREAD_COMPATIBILITY_MODE + pthread_compatibility_mutex.unlock(); +#endif + + while (function_manager->get_current_stack_level() >= 0) { + __dp_func_exit(lid, 1); + } + + // use lock_guard here, since no other mutex-aquiring function is called +#ifdef DP_PTHREAD_COMPATIBILITY_MODE + std::lock_guard guard(pthread_compatibility_mutex); +#endif + + // Returning from main or exit from somewhere, clear up everything. + assert(function_manager->get_current_stack_level() == -1 && + "Program terminates without clearing function stack!"); + assert(loop_manager->empty() && + "Program terminates but loop stack is not empty!"); + +#ifdef DP_DEBUG + std::cout << "Program terminates at LID " << std::dec << dputil::decodeLID(lid) << ", clearing up" << std::endl; +#endif + + if (NUM_WORKERS > 0) { + finalizeParallelization(); + } else { + finalizeSingleThreadedExecution(); + } + + const auto output_loops = []() { +#ifdef DP_RTLIB_VERBOSE + const auto debug_print = make_debug_print("outputLoops"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::OUTPUT_LOOPS); +#endif + + loop_manager->output(*out); + }; + output_loops(); + + const auto output_functions = []() { +#ifdef DP_RTLIB_VERBOSE + const auto debug_print = make_debug_print("outputFunc"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::OUTPUT_FUNCS); +#endif + function_manager->output_functions(*out); + }; + output_functions(); + + const auto output_allocations = []() { +#ifdef DP_RTLIB_VERBOSE + const auto debug_print = make_debug_print("outputAllocations"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::OUTPUT_ALLOCATIONS); +#endif + + const auto prepare_environment = [](){ + // prepare environment variables + const char *discopop_env = getenv("DOT_DISCOPOP"); + if (discopop_env == NULL) { + + // DOT_DISCOPOP needs to be initialized + setenv("DOT_DISCOPOP", ".discopop", 1); + discopop_env = ".discopop"; + } + + auto discopop_profiler_str = std::string(discopop_env) + "/profiler"; + setenv("DOT_DISCOPOP_PROFILER", discopop_profiler_str.data(), 1); + + return discopop_profiler_str + "/memory_regions.txt"; + }; + const auto path = prepare_environment(); + + auto allocationsFileStream = ofstream(path, ios::out); + memory_manager->output_memory_regions(allocationsFileStream); + }; + output_allocations(); + + // hybrid analysis + generateStringDepMap(); + // End HA + outputDeps(); + + // hybrid analysis + delete allDeps; + delete outPutDeps; + delete bbList; + // End HA + + delete function_manager; + delete loop_manager; + + *out << dputil::decodeLID(lid) << " END program" << endl; + out->flush(); + out->close(); + + delete out; + + dpInited = false; + targetTerminated = true; // mark the target program has returned from main() + +#ifdef DP_DEBUG + std::cout << "Program terminated." << std::endl; +#endif +} + +} + +} // namespace __dp diff --git a/rtlib/functions/dp_finalize.hpp b/rtlib/injected_functions/dp_finalize.hpp similarity index 100% rename from rtlib/functions/dp_finalize.hpp rename to rtlib/injected_functions/dp_finalize.hpp diff --git a/rtlib/functions/dp_func_entry.cpp b/rtlib/injected_functions/dp_func_entry.cpp similarity index 54% rename from rtlib/functions/dp_func_entry.cpp rename to rtlib/injected_functions/dp_func_entry.cpp index 254aa7a45..3bb7fa1cf 100644 --- a/rtlib/functions/dp_func_entry.cpp +++ b/rtlib/injected_functions/dp_func_entry.cpp @@ -15,6 +15,7 @@ #include "../iFunctionsGlobals.hpp" #include "../iFunctions.hpp" +#include "../../share/include/debug_print.hpp" #include "../../share/include/timer.hpp" #include @@ -43,51 +44,29 @@ void __dp_func_entry(LID lid, int32_t isStart) { std::lock_guard guard(pthread_compatibility_mutex); #endif #ifdef DP_RTLIB_VERBOSE - cout << "enter __dp_func_entry\n"; + const auto debug_print = make_debug_print("__dp_func_entry"); #endif - const auto dp_inited_previous = dpInited; - if (dp_inited_previous) { - timers->start(TimerRegion::FUNC_ENTRY); - } if (!dpInited) { // This part should be executed only once. readRuntimeInfo(); timers = new Timers(); +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::FUNC_ENTRY); +#endif + function_manager = new FunctionManager(); + loop_manager = new LoopManager(); + memory_manager = new MemoryManager(); - loopStack = new LoopTable(); - loops = new LoopRecords(); - beginFuncs = new BGNFuncList(); - endFuncs = new ENDFuncList(); out = new ofstream(); - // TEST - stackAddrs = new std::stack>(); - scopeManager = new ScopeManager(); - // !TEST - // hybrid analysis allDeps = new depMap(); outPutDeps = new stringDepMap(); bbList = new ReportedBBSet(); // End HA - // initialize AllocatedMemoryRegions: - - allocatedMemRegTree = new MemoryRegionTree(); - allocatedMemoryRegions = - new vector>; - - if (allocatedMemoryRegions->size() == 0 && - allocatedMemoryRegions->empty() == 0) { - // re-initialize the list, as something went wrong - allocatedMemoryRegions = - new vector>(); - } - // initialize lastHitIterator to dummy element - allocatedMemoryRegions->emplace_back(0, "%%dummy%%", 0, 0, 0, 0); - lastHitIterator = allocatedMemoryRegions->end(); - lastHitIterator--; + memory_manager->allocate_dummy_region(); #ifdef __linux__ // try to get an output file name w.r.t. the target application @@ -123,13 +102,11 @@ void __dp_func_entry(LID lid, int32_t isStart) { cout << "DP initialized at LID " << std::dec << dputil::decodeLID(lid) << endl; } dpInited = true; - if(NUM_WORKERS > 0){ + if(NUM_WORKERS > 0) { initParallelization(); - } - else{ + } else { initSingleThreadedExecution(); } - } else if (targetTerminated) { if (DP_DEBUG) { cout << "Entering function LID " << std::dec << dputil::decodeLID(lid); @@ -137,50 +114,22 @@ void __dp_func_entry(LID lid, int32_t isStart) { << endl; } } else { - // Process ordinary function call/invoke. - assert((lastCallOrInvoke != 0 || lastProcessedLine != 0) && - "Error: lastCalledFunc == lastProcessedLine == 0"); - if (lastCallOrInvoke == 0) - lastCallOrInvoke = lastProcessedLine; - ++FuncStackLevel; - - if (DP_DEBUG) { - cout << "Entering function LID " << std::dec << dputil::decodeLID(lid) << endl; - cout << "Function stack level = " << std::dec << FuncStackLevel << endl; - } - BGNFuncList::iterator func = beginFuncs->find(lastCallOrInvoke); - if (func == beginFuncs->end()) { - set *tmp = new set(); - tmp->insert(lid); - beginFuncs->insert(pair *>(lastCallOrInvoke, tmp)); - } else { - func->second->insert(lid); - } + function_manager->register_function_start(lid); } +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::FUNC_ENTRY); +#endif // TEST - // initialize stack addresses for function - // if(stackAddrs->size() > 0){ - // cout << "PUSH STACK ENTRY, PREV: " << hex << - // stackAddrs->top().first << " -> " << hex << - // stackAddrs->top().second << " \n"; - // } - stackAddrs->push(std::pair(0, 0)); - scopeManager->enterScope("function", lid); + memory_manager->enter_new_function(); + memory_manager->enterScope("function", lid); // !TEST if (isStart) *out << "START " << dputil::decodeLID(lid) << endl; // Reset last call tracker - lastCallOrInvoke = 0; -#ifdef DP_RTLIB_VERBOSE - cout << "exit __dp_func_entry\n"; -#endif - - if (dp_inited_previous) { - timers->stop_and_add(TimerRegion::FUNC_ENTRY); - } + function_manager->log_call(0); } } diff --git a/rtlib/functions/dp_func_entry.hpp b/rtlib/injected_functions/dp_func_entry.hpp similarity index 100% rename from rtlib/functions/dp_func_entry.hpp rename to rtlib/injected_functions/dp_func_entry.hpp diff --git a/rtlib/injected_functions/dp_func_exit.cpp b/rtlib/injected_functions/dp_func_exit.cpp new file mode 100644 index 000000000..9b77aae80 --- /dev/null +++ b/rtlib/injected_functions/dp_func_exit.cpp @@ -0,0 +1,79 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#include "../DPTypes.hpp" + +#include "../iFunctionsGlobals.hpp" +#include "../iFunctions.hpp" + +#include "../../share/include/debug_print.hpp" +#include "../../share/include/timer.hpp" + +#include +#include +#include +#include +#include + +using namespace std; + +namespace __dp { + +/******* Instrumentation function *******/ +extern "C" { + +void __dp_func_exit(LID lid, int32_t isExit) { + if (targetTerminated) { + if (DP_DEBUG) { + cout << "Exiting function LID " << std::dec << dputil::decodeLID(lid); + cout << " but target program has returned from main(). Destructors?" + << endl; + } + return; + } + +#ifdef DP_PTHREAD_COMPATIBILITY_MODE + std::lock_guard guard(pthread_compatibility_mutex); +#endif +#ifdef DP_RTLIB_VERBOSE + const auto debug_print = make_debug_print("__dp_func_exit"); +#endif +#ifdef DP_INTERNAL_TIMER + timers->start(TimerRegion::FUNC_EXIT); + const auto timer = Timer(timers, TimerRegion::FUNC_EXIT); +#endif + + loop_manager->clean_function_exit(function_manager->get_current_stack_level(), lid); + + function_manager->reset_call(lid); + function_manager->decrease_stack_level(); + + // TEST + // clear information on allocated stack addresses + const auto last_addresses = memory_manager->pop_last_stack_address(); + clearStackAccesses(last_addresses.first, last_addresses.second); // insert accesses with LID 0 to the queues + memory_manager->leaveScope("function", lid); + // !TEST + + if (isExit == 0){ + function_manager->register_function_end(lid); + } + + if (DP_DEBUG) { + cout << "Exiting fucntion LID " << std::dec << dputil::decodeLID(lid) << endl; + cout << "Function stack level = " << std::dec << function_manager->get_current_stack_level() << endl; + } +} + +} + +} // namespace __dp diff --git a/rtlib/functions/dp_func_exit.hpp b/rtlib/injected_functions/dp_func_exit.hpp similarity index 100% rename from rtlib/functions/dp_func_exit.hpp rename to rtlib/injected_functions/dp_func_exit.hpp diff --git a/rtlib/injected_functions/dp_incr_taken_branch_counter.cpp b/rtlib/injected_functions/dp_incr_taken_branch_counter.cpp new file mode 100644 index 000000000..15d6b87ec --- /dev/null +++ b/rtlib/injected_functions/dp_incr_taken_branch_counter.cpp @@ -0,0 +1,38 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#include "../DPTypes.hpp" + +#include "../iFunctionsGlobals.hpp" + +namespace __dp { + +/******* Instrumentation function *******/ +extern "C" { + +void __dp_incr_taken_branch_counter(char *source_and_target, int cmp_res, int active_on) { + if (!dpInited || targetTerminated) { + return; + } + + if (cmp_res == active_on) { + if (cuec.count(source_and_target) == 0) { + cuec[source_and_target] = 1; + } else { + cuec[source_and_target] = cuec[source_and_target] + 1; + } + } +} + +} + +} // namespace __dp diff --git a/rtlib/injected_functions/dp_incr_taken_branch_counter.hpp b/rtlib/injected_functions/dp_incr_taken_branch_counter.hpp new file mode 100644 index 000000000..323340e1a --- /dev/null +++ b/rtlib/injected_functions/dp_incr_taken_branch_counter.hpp @@ -0,0 +1,26 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +#include "../DPTypes.hpp" + +namespace __dp { + +/******* Instrumentation function *******/ +extern "C" { + +void __dp_incr_taken_branch_counter(char *source_and_target, int cmp_res, int active_on); + +} + +} // namespace __dp diff --git a/rtlib/functions/dp_loop_entry.cpp b/rtlib/injected_functions/dp_loop_entry.cpp similarity index 52% rename from rtlib/functions/dp_loop_entry.cpp rename to rtlib/injected_functions/dp_loop_entry.cpp index 301163e9f..245256621 100644 --- a/rtlib/functions/dp_loop_entry.cpp +++ b/rtlib/injected_functions/dp_loop_entry.cpp @@ -14,6 +14,7 @@ #include "../iFunctionsGlobals.hpp" +#include "../../share/include/debug_print.hpp" #include "../../share/include/timer.hpp" #include @@ -30,7 +31,7 @@ namespace __dp { extern "C" { void __dp_loop_entry(LID lid, int32_t loopID) { - if ((!dpInited) || (targetTerminated)){ + if (!dpInited || targetTerminated) { return; } @@ -38,9 +39,11 @@ void __dp_loop_entry(LID lid, int32_t loopID) { std::lock_guard guard(pthread_compatibility_mutex); #endif #ifdef DP_RTLIB_VERBOSE - cout << "__dp_loop_entry\n"; + const auto debug_print = make_debug_print("__dp_loop_entry"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::LOOP_ENTRY); #endif - timers->start(TimerRegion::LOOP_ENTRY); if (targetTerminated) { if (DP_DEBUG) { @@ -48,30 +51,18 @@ void __dp_loop_entry(LID lid, int32_t loopID) { "returned from main()." << endl; } - timers->stop_and_add(TimerRegion::LOOP_ENTRY); return; } - assert((loopStack != nullptr) && "Loop stack is not available!"); - - if (loopStack->empty() || (loopStack->top().loopID != loopID)) { - // A new loop - loopStack->push(LoopTableEntry(FuncStackLevel, loopID, 0, lid)); - if (loops->find(lid) == loops->end()) { - loops->insert(pair(lid, new LoopRecord(0, 0, 0))); - } - if (DP_DEBUG) { - cout << "(" << std::dec << FuncStackLevel << ")Loop " << loopID - << " enters." << endl; - } - scopeManager->enterScope("loop", lid); + + const auto function_stack_level = function_manager->get_current_stack_level(); + const auto is_new_loop = loop_manager->is_new_loop(loopID); + + if (is_new_loop) { + loop_manager->create_new_loop(function_stack_level, loopID, lid); + memory_manager->enterScope("loop", lid); } else { // The same loop iterates again - loopStack->top().count++; - if (DP_DEBUG) { - cout << "(" << std::dec << loopStack->top().funcLevel << ")"; - cout << "Loop " << loopStack->top().loopID << " iterates " - << loopStack->top().count << " times." << endl; - } + loop_manager->iterate_loop(function_stack_level); // Handle error made in instrumentation. // When recorded loopStack->top().funcLevel is different @@ -84,20 +75,12 @@ void __dp_loop_entry(LID lid, int32_t loopID) { // the second case has never been seen. Thus whenever we // encounter such problem, we trust the current FuncStackLevel // and update top().funcLevel. - if (loopStack->top().funcLevel != FuncStackLevel) { - if (DP_DEBUG) { - cout << "WARNING: changing funcLevel of Loop " - << loopStack->top().loopID << " from " - << loopStack->top().funcLevel << " to " << FuncStackLevel << endl; - } - loopStack->top().funcLevel = FuncStackLevel; - } - scopeManager->leaveScope("loop_iteration", lid); - scopeManager->enterScope("loop_iteration", lid); + loop_manager->correct_func_level(function_stack_level); + + memory_manager->leaveScope("loop_iteration", lid); + memory_manager->enterScope("loop_iteration", lid); } - - timers->stop_and_add(TimerRegion::LOOP_ENTRY); } } diff --git a/rtlib/functions/dp_loop_entry.hpp b/rtlib/injected_functions/dp_loop_entry.hpp similarity index 100% rename from rtlib/functions/dp_loop_entry.hpp rename to rtlib/injected_functions/dp_loop_entry.hpp diff --git a/rtlib/injected_functions/dp_loop_exit.cpp b/rtlib/injected_functions/dp_loop_exit.cpp new file mode 100644 index 000000000..d7feea33e --- /dev/null +++ b/rtlib/injected_functions/dp_loop_exit.cpp @@ -0,0 +1,77 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#include "../DPTypes.hpp" + +#include "../iFunctionsGlobals.hpp" + +#include "../../share/include/debug_print.hpp" +#include "../../share/include/timer.hpp" + +#include +#include +#include +#include +#include + +using namespace std; + +namespace __dp { + +/******* Instrumentation function *******/ +extern "C" { + +void __dp_loop_exit(LID lid, int32_t loopID) { + if (!dpInited || targetTerminated) { + return; + } + +#ifdef DP_PTHREAD_COMPATIBILITY_MODE + std::lock_guard guard(pthread_compatibility_mutex); +#endif +#ifdef DP_RTLIB_VERBOSE + const auto debug_print = make_debug_print("__dp_loop_exit"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::LOOP_EXIT); +#endif + + if (targetTerminated) { + if (DP_DEBUG) { + cout << "__dp_loop_exit() is not executed since target program has " + "returned from main()." + << endl; + } + return; + } + + // __dp_loop_exit() can be called without __dp_loop_entry() + // being called. This can happen when a loop is encapsulated + // by an "if" structure, and the condition of "if" fails + if (loop_manager->is_single_exit(loopID)) { + if (DP_DEBUG) { + std::cout << "Ignored single exit of loop " << loop_manager->get_current_loop_id() << endl; + } + return; + } + + // See comments in __dp_loop_entry() for explanation. + const auto function_stack_level = function_manager->get_current_stack_level(); + loop_manager->correct_func_level(function_stack_level); + loop_manager->exit_loop(lid); + + memory_manager->leaveScope("loop", lid); +} + +} + +} // namespace __dp diff --git a/rtlib/functions/dp_loop_exit.hpp b/rtlib/injected_functions/dp_loop_exit.hpp similarity index 100% rename from rtlib/functions/dp_loop_exit.hpp rename to rtlib/injected_functions/dp_loop_exit.hpp diff --git a/rtlib/injected_functions/dp_loop_incr.cpp b/rtlib/injected_functions/dp_loop_incr.cpp new file mode 100644 index 000000000..6e1949255 --- /dev/null +++ b/rtlib/injected_functions/dp_loop_incr.cpp @@ -0,0 +1,36 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#include "../DPTypes.hpp" + +#include "../iFunctionsGlobals.hpp" + +namespace __dp { + +/******* Instrumentation function *******/ +extern "C" { + +void __dp_loop_incr(const int loop_id){ + if (!dpInited || targetTerminated) { + return; + } + + if (loop_manager->is_done()) { + return; + } + + loop_manager->incr_loop_counter(loop_id); +} + +} + +} // namespace __dp diff --git a/share/lib/timer.cpp b/rtlib/injected_functions/dp_loop_incr.hpp similarity index 66% rename from share/lib/timer.cpp rename to rtlib/injected_functions/dp_loop_incr.hpp index 5afddff72..e6134b38f 100644 --- a/share/lib/timer.cpp +++ b/rtlib/injected_functions/dp_loop_incr.hpp @@ -10,3 +10,15 @@ * */ +#pragma once + +namespace __dp { + +/******* Instrumentation function *******/ +extern "C" { + +void __dp_loop_incr(int loop_id); + +} + +} // namespace __dp diff --git a/rtlib/injected_functions/dp_loop_output.cpp b/rtlib/injected_functions/dp_loop_output.cpp new file mode 100644 index 000000000..7360f27df --- /dev/null +++ b/rtlib/injected_functions/dp_loop_output.cpp @@ -0,0 +1,76 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#include "../DPTypes.hpp" + +#include "../iFunctionsGlobals.hpp" + +#include "../loop/LoopInfo.hpp" + +#include +#include +#include + +namespace __dp { + +/******* Instrumentation function *******/ +extern "C" { + +void __dp_loop_output() { + if (loop_manager->is_done()) { + return; + } + + std::cout << "Outputting instrumentation results... "; + + std::ifstream ifile; + std::string line; + std::ofstream ofile; + + // get meta information about the loops + std::vector loop_infos; + loop_infos.push_back(loop_info_t()); // dummy + std::string tmp(getenv("DOT_DISCOPOP_PROFILER")); + tmp += "/loop_meta.txt"; + ifile.open(tmp.data()); + while (std::getline(ifile, line)) { + loop_info_t loop_info; + int cnt = sscanf(line.c_str(), "%d %d %d", &loop_info.file_id_, + &loop_info.loop_id_, &loop_info.line_nr_); + if (cnt == 3) { + loop_infos.push_back(loop_info); + } + } + ifile.close(); + + // output information about the loops + std::string tmp2(getenv("DOT_DISCOPOP_PROFILER")); + tmp2 += "/loop_counter_output.txt"; + ofile.open(tmp2.data()); + const auto& loop_counters = loop_manager->get_loop_counters(); + + for (auto i = 1; i < loop_counters.size(); ++i) { + loop_info_t &loop_info = loop_infos[i]; + ofile << loop_info.file_id_ << " "; + ofile << loop_info.line_nr_ << " "; + ofile << loop_counters[i] << "\n"; + } + ofile.close(); + + std::cout << "done" << std::endl; + + loop_manager->set_done(); +} + +} + +} // namespace __dp diff --git a/rtlib/cu_taken_branch_counter.hpp b/rtlib/injected_functions/dp_loop_output.hpp similarity index 70% rename from rtlib/cu_taken_branch_counter.hpp rename to rtlib/injected_functions/dp_loop_output.hpp index 468c28717..c602bbab9 100644 --- a/rtlib/cu_taken_branch_counter.hpp +++ b/rtlib/injected_functions/dp_loop_output.hpp @@ -1,19 +1,24 @@ -/* - * This file is part of the DiscoPoP software - * (http://www.discopop.tu-darmstadt.de) - * - * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany - * - * This software may be modified and distributed under the terms of - * the 3-Clause BSD License. See the LICENSE file in the package base - * directory for details. - * - */ - -#pragma once - -#include -#include -#include -#include -#include +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +namespace __dp { + +/******* Instrumentation function *******/ +extern "C" { + +void __dp_loop_output(); + +} + +} // namespace __dp diff --git a/rtlib/functions/dp_new.cpp b/rtlib/injected_functions/dp_new.cpp similarity index 54% rename from rtlib/functions/dp_new.cpp rename to rtlib/injected_functions/dp_new.cpp index 89b85be01..b2a64e2ea 100644 --- a/rtlib/functions/dp_new.cpp +++ b/rtlib/injected_functions/dp_new.cpp @@ -14,6 +14,7 @@ #include "../iFunctionsGlobals.hpp" +#include "../../share/include/debug_print.hpp" #include "../../share/include/timer.hpp" #include @@ -30,7 +31,7 @@ namespace __dp { extern "C" { void __dp_new(LID lid, ADDR startAddr, ADDR endAddr, int64_t numBytes) { - if ((!dpInited) || (targetTerminated)){ + if (!dpInited || targetTerminated) { return; } @@ -38,42 +39,23 @@ void __dp_new(LID lid, ADDR startAddr, ADDR endAddr, int64_t numBytes) { std::lock_guard guard(pthread_compatibility_mutex); #endif #ifdef DP_RTLIB_VERBOSE - cout << "enter __dp_new\n"; + const auto debug_print = make_debug_print("__dp_new"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::NEW); #endif - timers->start(TimerRegion::NEW); - - // instrumentation function for new and malloc - int64_t buffer = nextFreeMemoryRegionId; - string allocId = to_string(buffer); - nextFreeMemoryRegionId++; // calculate endAddr of memory region endAddr = startAddr + numBytes; - allocatedMemRegTree->allocate_region(startAddr, endAddr, buffer, - tempAddrCount, NUM_WORKERS); + // -1 indicates 'on heap' + std::string allocID = memory_manager->allocate_memory(lid, startAddr, endAddr, numBytes, -1); if (DP_DEBUG) { - cout << "new/malloc: " << dputil::decodeLID(lid) << ", " << allocId << ", " + cout << "new/malloc: " << dputil::decodeLID(lid) << ", " << allocID << ", " << std::hex << startAddr << " - " << std::hex << endAddr; printf(" NumBytes: %lld\n", numBytes); } - - allocatedMemoryRegions->emplace_back(lid, allocId, startAddr, endAddr, numBytes, -1); - lastHitIterator = allocatedMemoryRegions->end(); - lastHitIterator--; - - // update known min and max ADDR - if (startAddr < smallestAllocatedADDR) { - smallestAllocatedADDR = startAddr; - } - if (endAddr > largestAllocatedADDR) { - largestAllocatedADDR = endAddr; - } -#ifdef DP_RTLIB_VERBOSE - cout << "exit __dp_new\n"; -#endif - timers->stop_and_add(TimerRegion::NEW); } } diff --git a/rtlib/functions/dp_new.hpp b/rtlib/injected_functions/dp_new.hpp similarity index 100% rename from rtlib/functions/dp_new.hpp rename to rtlib/injected_functions/dp_new.hpp diff --git a/rtlib/injected_functions/dp_read.cpp b/rtlib/injected_functions/dp_read.cpp new file mode 100644 index 000000000..7d9fe79a7 --- /dev/null +++ b/rtlib/injected_functions/dp_read.cpp @@ -0,0 +1,121 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#include "../DPTypes.hpp" + +#include "../iFunctionsGlobals.hpp" +#include "../iFunctions.hpp" + +#include "../../share/include/debug_print.hpp" +#include "../../share/include/timer.hpp" + +#include +#include +#include +#include +#include + +using namespace std; + +namespace __dp { + +/******* Instrumentation function *******/ +extern "C" { +#ifdef SKIP_DUP_INSTR +void __dp_read(LID lid, ADDR addr, char *var, ADDR lastaddr, int64_t count) { +#else +void __dp_read(LID lid, ADDR addr, char *var) { +#endif + + if (!dpInited || targetTerminated) { + return; + } + +#ifdef DP_PTHREAD_COMPATIBILITY_MODE + std::lock_guard guard(pthread_compatibility_mutex); +#endif +#ifdef DP_RTLIB_VERBOSE + const auto debug_print = make_debug_print("__dp_read"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::READ); +#endif + + if (targetTerminated) { + if (DP_DEBUG) { + cout << "__dp_read() is not executed since target program has returned " + "from main()." + << endl; + } + return; + } + // For tracking function call or invoke +#ifdef SKIP_DUP_INSTR + if (lastaddr == addr && count >= 2) { + return; + } +#endif + + function_manager->reset_call(lid); + + if (DP_DEBUG) { + cout << "instLoad at encoded LID " << std::dec << dputil::decodeLID(lid) + << " and addr " << std::hex << addr << endl; + } + + // TEST + // check for stack access + bool is_stack_access = memory_manager->is_stack_access(addr); + // !TEST + +#if defined DP_NUM_WORKERS && DP_NUM_WORKERS == 0 + AccessInfo current; +#else + int64_t workerID = + ((addr - (addr % 4)) % (NUM_WORKERS * 4)) / 4; // implicit "floor" + AccessInfo ¤t = tempAddrChunks[workerID][tempAddrCount[workerID]++]; +#endif + current.isRead = true; + current.lid = loop_manager->update_lid(lid); + current.var = var; + current.AAvar = getMemoryRegionIdFromAddr(var, addr); + current.addr = addr; + current.isStackAccess = is_stack_access; + current.addrIsOwnedByScope = + memory_manager->isFirstWrittenInScope(addr, false); + current.positiveScopeChangeOccuredSinceLastAccess = + memory_manager->positiveScopeChangeOccuredSinceLastAccess(addr); + + if (is_stack_access) { + // register stack read after check for + // positiveScopeChangeOccuredSinceLastAccess + memory_manager->registerStackRead(addr, lid, var); + } + +#if defined DP_NUM_WORKERS && DP_NUM_WORKERS == 0 + analyzeSingleAccess(singleThreadedExecutionSMem, current); +#else + if (tempAddrCount[workerID] == CHUNK_SIZE) { + pthread_mutex_lock(&addrChunkMutexes[workerID]); + addrChunkPresent[workerID] = true; + chunks[workerID].push(tempAddrChunks[workerID]); + pthread_cond_signal(&addrChunkPresentConds[workerID]); + pthread_mutex_unlock(&addrChunkMutexes[workerID]); + tempAddrChunks[workerID] = new AccessInfo[CHUNK_SIZE]; + tempAddrCount[workerID] = 0; + } +#endif +} + +} + +} // namespace __dp diff --git a/rtlib/functions/dp_read.hpp b/rtlib/injected_functions/dp_read.hpp similarity index 100% rename from rtlib/functions/dp_read.hpp rename to rtlib/injected_functions/dp_read.hpp diff --git a/rtlib/functions/dp_report_bb.cpp b/rtlib/injected_functions/dp_report_bb.cpp similarity index 71% rename from rtlib/functions/dp_report_bb.cpp rename to rtlib/injected_functions/dp_report_bb.cpp index 94637726d..95411c28f 100644 --- a/rtlib/functions/dp_report_bb.cpp +++ b/rtlib/injected_functions/dp_report_bb.cpp @@ -14,6 +14,7 @@ #include "../iFunctionsGlobals.hpp" +#include "../../share/include/debug_print.hpp" #include "../../share/include/timer.hpp" #include @@ -30,7 +31,7 @@ namespace __dp { extern "C" { void __dp_report_bb(uint32_t bbIndex) { - if ((!dpInited) || (targetTerminated)){ + if (!dpInited || targetTerminated) { return; } @@ -38,17 +39,14 @@ void __dp_report_bb(uint32_t bbIndex) { std::lock_guard guard(pthread_compatibility_mutex); #endif #ifdef DP_RTLIB_VERBOSE - cout << "enter __dp_report_bb\n"; - cout << "bbIndex: " << std::to_string(bbIndex) << "\n"; + const auto debug_print = make_debug_print("__dp_report_bb"); + std::cout << "bbIndex: " << std::to_string(bbIndex) << '\n'; #endif - timers->start(TimerRegion::REPORT_BB); - - bbList->insert(bbIndex); -#ifdef DP_RTLIB_VERBOSE - cout << "exit __dp_report_bb\n"; +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::REPORT_BB); #endif - timers->stop_and_add(TimerRegion::REPORT_BB); + bbList->insert(bbIndex); } } diff --git a/rtlib/functions/dp_report_bb.hpp b/rtlib/injected_functions/dp_report_bb.hpp similarity index 100% rename from rtlib/functions/dp_report_bb.hpp rename to rtlib/injected_functions/dp_report_bb.hpp diff --git a/rtlib/functions/dp_report_bb_pair.cpp b/rtlib/injected_functions/dp_report_bb_pair.cpp similarity index 73% rename from rtlib/functions/dp_report_bb_pair.cpp rename to rtlib/injected_functions/dp_report_bb_pair.cpp index 5c1cb81d5..1ae18757d 100644 --- a/rtlib/functions/dp_report_bb_pair.cpp +++ b/rtlib/injected_functions/dp_report_bb_pair.cpp @@ -14,6 +14,7 @@ #include "../iFunctionsGlobals.hpp" +#include "../../share/include/debug_print.hpp" #include "../../share/include/timer.hpp" #include @@ -30,7 +31,7 @@ namespace __dp { extern "C" { void __dp_report_bb_pair(int32_t semaphore, uint32_t bbIndex) { - if ((!dpInited) || (targetTerminated)){ + if (!dpInited || targetTerminated) { return; } @@ -38,14 +39,15 @@ void __dp_report_bb_pair(int32_t semaphore, uint32_t bbIndex) { std::lock_guard guard(pthread_compatibility_mutex); #endif #ifdef DP_RTLIB_VERBOSE - cout << "enter __dp_report_bb_pair\n"; + const auto debug_print = make_debug_print("__dp_report_bb_pair"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::REPORT_BB_PAIR); #endif - timers->start(TimerRegion::REPORT_BB_PAIR); - if (semaphore) + if (semaphore) { bbList->insert(bbIndex); - - timers->stop_and_add(TimerRegion::REPORT_BB_PAIR); + } } } diff --git a/rtlib/functions/dp_report_bb_pair.hpp b/rtlib/injected_functions/dp_report_bb_pair.hpp similarity index 100% rename from rtlib/functions/dp_report_bb_pair.hpp rename to rtlib/injected_functions/dp_report_bb_pair.hpp diff --git a/rtlib/cu_taken_branch_counter.cpp b/rtlib/injected_functions/dp_taken_branch_counter_output.cpp similarity index 64% rename from rtlib/cu_taken_branch_counter.cpp rename to rtlib/injected_functions/dp_taken_branch_counter_output.cpp index 72bb24bb6..6fa1b99ba 100644 --- a/rtlib/cu_taken_branch_counter.cpp +++ b/rtlib/injected_functions/dp_taken_branch_counter_output.cpp @@ -1,50 +1,47 @@ -/* - * This file is part of the DiscoPoP software - * (http://www.discopop.tu-darmstadt.de) - * - * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany - * - * This software may be modified and distributed under the terms of - * the 3-Clause BSD License. See the LICENSE file in the package base - * directory for details. - * - */ - -#include "cu_taken_branch_counter.hpp" - -static std::unordered_map cuec; - -extern "C" { - -void __dp_incr_taken_branch_counter(char *source_and_target, int cmp_res, - int active_on) { - if (cmp_res == active_on) { - if (cuec.count(source_and_target) == 0) { - cuec[source_and_target] = 1; - } else { - cuec[source_and_target] = cuec[source_and_target] + 1; - } - } -} - -void __dp_taken_branch_counter_output() { - std::cout << "Outputting instrumentation results (taken branches)... "; - - std::ifstream ifile; - std::string line; - std::ofstream ofile; - - // output information about the loops - std::string tmp(getenv("DOT_DISCOPOP_PROFILER")); - tmp += "/cu_taken_branch_counter_output.txt"; - ofile.open(tmp.data()); - - for (auto pair : cuec) { - ofile << pair.first << ";" << pair.second << "\n"; - } - - ofile.close(); - - std::cout << "done" << std::endl; -} -} +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#include "../DPTypes.hpp" + +#include "../iFunctionsGlobals.hpp" + +#include +#include +#include + +namespace __dp { + +/******* Instrumentation function *******/ +extern "C" { + +void __dp_taken_branch_counter_output() { + std::cout << "Outputting instrumentation results (taken branches)... "; + + std::ofstream ofile; + + // output information about the loops + std::string tmp(getenv("DOT_DISCOPOP_PROFILER")); + tmp += "/cu_taken_branch_counter_output.txt"; + ofile.open(tmp.data()); + + for (auto pair : cuec) { + ofile << pair.first << ";" << pair.second << "\n"; + } + + ofile.close(); + + std::cout << "done" << std::endl; +} + +} + +} // namespace __dp diff --git a/rtlib/iFunctionsTypes.cpp b/rtlib/injected_functions/dp_taken_branch_counter_output.hpp similarity index 60% rename from rtlib/iFunctionsTypes.cpp rename to rtlib/injected_functions/dp_taken_branch_counter_output.hpp index 342efa937..4f10469e0 100644 --- a/rtlib/iFunctionsTypes.cpp +++ b/rtlib/injected_functions/dp_taken_branch_counter_output.hpp @@ -1,11 +1,26 @@ -/* - * This file is part of the DiscoPoP software - * (http://www.discopop.tu-darmstadt.de) - * - * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany - * - * This software may be modified and distributed under the terms of - * the 3-Clause BSD License. See the LICENSE file in the package base - * directory for details. - * - */ \ No newline at end of file +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +#include "../DPTypes.hpp" + +namespace __dp { + +/******* Instrumentation function *******/ +extern "C" { + +void __dp_taken_branch_counter_output(); + +} + +} // namespace __dp diff --git a/rtlib/injected_functions/dp_write.cpp b/rtlib/injected_functions/dp_write.cpp new file mode 100644 index 000000000..8ab88df20 --- /dev/null +++ b/rtlib/injected_functions/dp_write.cpp @@ -0,0 +1,123 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#include "../DPTypes.hpp" + +#include "../iFunctionsGlobals.hpp" +#include "../iFunctions.hpp" + +#include "../../share/include/debug_print.hpp" +#include "../../share/include/timer.hpp" + +#include +#include +#include +#include +#include + +using namespace std; + +namespace __dp { + +/******* Instrumentation function *******/ +extern "C" { + +#ifdef SKIP_DUP_INSTR +void __dp_write(LID lid, ADDR addr, char *var, ADDR lastaddr, int64_t count) { +#else +void __dp_write(LID lid, ADDR addr, char *var) { +#endif + + if (!dpInited || targetTerminated) { + return; + } + +#ifdef DP_PTHREAD_COMPATIBILITY_MODE + std::lock_guard guard(pthread_compatibility_mutex); +#endif +#ifdef DP_RTLIB_VERBOSE + const auto debug_print = make_debug_print("__dp_write"); +#endif +#ifdef DP_INTERNAL_TIMER + const auto timer = Timer(timers, TimerRegion::WRITE); +#endif + + if (targetTerminated) { + if (DP_DEBUG) { + cout << "__dp_write() is not executed since target program has returned " + "from main()." + << endl; + } + return; + } + // For tracking function call or invoke +#ifdef SKIP_DUP_INSTR + if (lastaddr == addr && count >= 2) { + return; + } +#endif + + // For tracking function call or invoke + function_manager->reset_call(lid); + + if (DP_DEBUG) { + cout << "instStore at encoded LID " << std::dec << dputil::decodeLID(lid) + << " and addr " << std::hex << addr << endl; + } + + // TEST + // check for stack access + bool is_stack_access = memory_manager->is_stack_access(addr); + // !TEST + +#if defined DP_NUM_WORKERS && DP_NUM_WORKERS == 0 + AccessInfo current; +#else + int64_t workerID = + ((addr - (addr % 4)) % (NUM_WORKERS * 4)) / 4; // implicit "floor" + AccessInfo ¤t = tempAddrChunks[workerID][tempAddrCount[workerID]++]; +#endif + current.isRead = false; + current.lid = loop_manager->update_lid(lid); + current.var = var; + current.AAvar = getMemoryRegionIdFromAddr(var, addr); + current.addr = addr; + current.isStackAccess = is_stack_access; + current.addrIsOwnedByScope = + memory_manager->isFirstWrittenInScope(addr, true); + current.positiveScopeChangeOccuredSinceLastAccess = + memory_manager->positiveScopeChangeOccuredSinceLastAccess(addr); + + if (is_stack_access) { + // register stack write after check for + // positiveScopeChangeOccuredSinceLastAccess + memory_manager->registerStackWrite(addr, lid, var); + } + +#if defined DP_NUM_WORKERS && DP_NUM_WORKERS == 0 + analyzeSingleAccess(singleThreadedExecutionSMem, current); +#else + if (tempAddrCount[workerID] == CHUNK_SIZE) { + pthread_mutex_lock(&addrChunkMutexes[workerID]); + addrChunkPresent[workerID] = true; + chunks[workerID].push(tempAddrChunks[workerID]); + pthread_cond_signal(&addrChunkPresentConds[workerID]); + pthread_mutex_unlock(&addrChunkMutexes[workerID]); + tempAddrChunks[workerID] = new AccessInfo[CHUNK_SIZE]; + tempAddrCount[workerID] = 0; + } +#endif +} + +} + +} // namespace __dp diff --git a/rtlib/functions/dp_write.hpp b/rtlib/injected_functions/dp_write.hpp similarity index 100% rename from rtlib/functions/dp_write.hpp rename to rtlib/injected_functions/dp_write.hpp diff --git a/rtlib/loop/LoopCounter.hpp b/rtlib/loop/LoopCounter.hpp new file mode 100644 index 000000000..999e8d96f --- /dev/null +++ b/rtlib/loop/LoopCounter.hpp @@ -0,0 +1,39 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +#include "VarCounter.hpp" + +#include + +namespace __dp { + +class LoopCounter { +public: + void incr_loop_counter(int loop_id) { + if (loop_counters_.size() < loop_id + 1) { + loop_counters_.resize(loop_id + 1); + } + + loop_counters_[loop_id] += 1; + } + + const std::vector& get_loop_counters() const noexcept { + return loop_counters_; + } + +private: + std::vector loop_counters_; +}; + +} // namespace __dp diff --git a/rtlib/loop/LoopInfo.hpp b/rtlib/loop/LoopInfo.hpp new file mode 100644 index 000000000..45d6f71d8 --- /dev/null +++ b/rtlib/loop/LoopInfo.hpp @@ -0,0 +1,29 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +namespace __dp { + +struct loop_info_t { + int line_nr_ = 0; + int loop_id_ = 0; + int file_id_ = 0; + + bool operator==(const loop_info_t& other) const noexcept { + return line_nr_ == other.line_nr_ && loop_id_ == other.loop_id_ && file_id_ == other.file_id_; + } + + bool operator!=(const loop_info_t& other) const noexcept { return !(*this == other); } +}; + +} // namespace __dp diff --git a/rtlib/loop/LoopManager.hpp b/rtlib/loop/LoopManager.hpp new file mode 100644 index 000000000..050f6d9b5 --- /dev/null +++ b/rtlib/loop/LoopManager.hpp @@ -0,0 +1,181 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +#include "LoopCounter.hpp" +#include "LoopRecord.hpp" +#include "LoopTable.hpp" + +#include "../DPUtils.hpp" + +#include + +namespace __dp { + +class LoopManager { +public: + LoopManager() { + } + + ~LoopManager() { + for (auto loop : loops) { + delete loop.second; + } + } + + void create_new_loop(const std::int32_t function_level, const std::int32_t loop_id, const LID begin_line) { + loopStack.push(LoopTableEntry(function_level, loop_id, 0, begin_line)); + if (loops.find(begin_line) == loops.end()) { + loops.insert(pair(begin_line, new LoopRecord(0, 0, 0))); + } +#ifdef DP_DEBUG + std::cout << "(" << std::dec << FuncStackLevel << ")Loop " << loop_id << " enters." << std::endl; +#endif + } + + bool is_new_loop(const std::int32_t loop_id) const { + return loopStack.empty() || (loopStack.top().loopID != loop_id); + } + + void iterate_loop(const std::int32_t function_level) { + loopStack.increment_top_count(); +#ifdef DP_DEBUG + std::cout << "(" << std::dec << loopStack.top().funcLevel << ")"; + std::cout << "Loop " << loopStack.top().loopID << " iterates " + << loopStack.top().count << " times." << std::endl; +#endif + } + + void clean_function_exit(const std::int32_t function_level, const LID end_line) { + // Clear up all unfinished loops in the function. + // This usually happens when using return inside loop. + while (!loopStack.empty() && + (loopStack.top().funcLevel == function_level)) { + + // No way to get the real end line of loop. Use the line where + // function returns instead. + LoopRecords::iterator loop = loops.find(loopStack.top().begin); + assert(loop != loops.end() && "A loop ends without its entry being recorded."); + + if (loop->second->end == 0) { + loop->second->end = end_line; + } else { + // TODO: FIXME: loop end line > return line + } + + loop->second->total += loopStack.top().get_count(); + ++loop->second->nEntered; + + loopStack.debug_output(); + loopStack.pop(); + loopStack.debug_output(); + } + } + + LID update_lid(LID lid) { + return loopStack.update_lid(lid); + } + + void exit_loop(const LID lid) { + LoopRecords::iterator loop = loops.find(loopStack.top().begin); + assert(loop != loops.end() && "A loop ends without its entry being recorded."); + if (loop->second->end == 0) { + loop->second->end = lid; + } else { + // New loop exit found and it's smaller than before. That means + // the current exit point can be the break inside the loop. + // In this case we ignore the current exit point and keep the + // regular one. + if (lid < loop->second->end) { + // loop->second->end = lid; + } + // New loop exit found and it's bigger than before. This can + // happen when the previous exit is a break inside the loop. + // In this case we update the loop exit to the bigger one. + else if (lid > loop->second->end) { + loop->second->end = lid; + } + // New loop exit found and it's the same as before. Good. + } + + if (loop->second->maxIterationCount < loopStack.top().get_count()) { + loop->second->maxIterationCount = loopStack.top().get_count(); + } + + loop->second->total += loopStack.top().get_count(); + ++loop->second->nEntered; + + loopStack.debug_output(); + loopStack.pop(); + loopStack.debug_output(); + } + + bool is_single_exit(const std::int32_t loop_id) { + return loopStack.is_single_exit(loop_id); + } + + void correct_func_level(const std::int32_t function_level) { + loopStack.correct_func_level(function_level); + } + + std::int32_t get_current_loop_id() { + return loopStack.top().loopID; + } + + bool empty() { + return loopStack.empty(); + } + + void output(std::ostream& stream) { + for (const auto& loop : loops) { + stream << dputil::decodeLID(loop.first) << " BGN loop "; + stream << loop.second->total << ' '; + stream << loop.second->nEntered << ' '; + stream << static_cast(loop.second->total / loop.second->nEntered) << ' '; + stream << loop.second->maxIterationCount << std::endl; + stream << dputil::decodeLID(loop.second->end) << " END loop" << std::endl; + } + } + + const LoopTable& get_stack() const { + return loopStack; + } + + const LoopRecords& get_loops() const { + return loops; + } + + bool is_done() const noexcept { + return alreadyDone; + } + + void set_done() noexcept { + alreadyDone = true; + } + + void incr_loop_counter(int loop_id) { + lc.incr_loop_counter(loop_id); + } + + const std::vector& get_loop_counters() const { + return lc.get_loop_counters(); + } + +private: + LoopTable loopStack; // loop stack tracking + LoopRecords loops; // loop merging + LoopCounter lc; // loop counter + bool alreadyDone; +}; + +} // namespace __dp diff --git a/rtlib/loop/LoopRecord.hpp b/rtlib/loop/LoopRecord.hpp new file mode 100644 index 000000000..6add957ee --- /dev/null +++ b/rtlib/loop/LoopRecord.hpp @@ -0,0 +1,43 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +#include "../DPTypes.hpp" + +#include +#include + +namespace __dp { + +// For loop merging +// Assumption: no more than one loops can begin at the same line +struct LoopRecord { + LoopRecord(LID e, std::int32_t t, std::int32_t n) : end(e), total(t), nEntered(n) {} + + LID end; + std::int32_t total; + std::int32_t nEntered; + + // maximum iterations executed during a single loop entry + std::int32_t maxIterationCount = 0; + + bool operator==(const LoopRecord& other) const noexcept { + return end == other.end && total == other.total && nEntered == other.nEntered && maxIterationCount == other.maxIterationCount; + } + + bool operator!=(const LoopRecord& other) const noexcept { return !(*this == other); } +}; + +typedef std::unordered_map LoopRecords; + +} // namespace __dp diff --git a/rtlib/loop/LoopTable.hpp b/rtlib/loop/LoopTable.hpp new file mode 100644 index 000000000..956259f13 --- /dev/null +++ b/rtlib/loop/LoopTable.hpp @@ -0,0 +1,131 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +#include "LoopTableEntry.hpp" + +#include +#include +#include + +namespace __dp { + +struct LoopTable { +public: + LoopTable() { + contents.reserve(32); + } + + const LoopTableEntry &top() const { + return contents.back(); + } + + const LoopTableEntry &first() const { + return contents[0]; + } + + const LoopTableEntry &topMinusN(const std::size_t n) const { + return contents[contents.size() - 1 - n]; + } + + void pop() { + contents.pop_back(); + } + + bool empty() const { + return contents.empty(); + } + + bool is_single_exit(const std::int32_t loopID) const { + if (empty()) + return true; + + if (top().loopID != loopID) + return true; + + return false; + } + + void correct_func_level(const std::int32_t func_level) { + if (top().funcLevel != func_level) { +#ifdef DP_DEBUG + std::cout << "WARNING: changing funcLevel of Loop " << top().loopID + << " from " << top().funcLevel << " to " << func_level + << std::endl; +#endif + contents.back().funcLevel = func_level; + } + } + + void push(const LoopTableEntry newElement) { + contents.push_back(newElement); + } + + std::size_t size() const { + return contents.size(); + } + + LID update_lid(const LID old_lid) const { + auto lid = old_lid; + + if (empty()) { + return lid | (((LID)0xFF) << 56); + } + + // store loop iteration metadata (last 8 bits for loop id, 1 bit to mark loop + // iteration count as valid, last 7 bits for loop iteration) last 8 bits are + // sufficient, since metadata is only used to check for different iterations, + // not exact values. first 32 bits of lid are reserved for metadata + // and thus empty + + if (size() > 0) { + lid = lid | (((LID)(first().loopID & 0xFF)) << 56); // add masked loop id + lid = lid | (((LID)(top().get_count() & 0x7F)) << 48); // add masked loop count + lid = lid | (LID)0x0080000000000000; // mark loop count valid + } + + if (size() > 1) { + lid = lid | (((LID)(topMinusN(1).get_count() & 0x7F)) << 40); // add masked loop count + lid = lid | (LID)0x0000800000000000; // mark loop count valid + } + + if (size() > 2) { + lid = lid | (((LID)(topMinusN(2).get_count() & 0x7F)) << 32); // add masked loop count + lid = lid | (LID)0x0000008000000000; // mark loop count valid + } + + return lid; + } + + void increment_top_count() { + contents.back().increment_count(); + } + + void debug_output() const { +#ifdef DP_DEBUG + if (empty()) + std::cout << "Loop Stack is empty." << endl; + else { + std::cout << "TOP: (" << std::dec << top().funcLevel << ")"; + std::cout << "Loop " << top().loopID << "." << std::endl; + } +#endif + } + +private: + + + std::vector contents; +}; + +} // namespace __dp diff --git a/rtlib/loop/LoopTableEntry.hpp b/rtlib/loop/LoopTableEntry.hpp new file mode 100644 index 000000000..774ff6140 --- /dev/null +++ b/rtlib/loop/LoopTableEntry.hpp @@ -0,0 +1,44 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +#include "../DPTypes.hpp" + +#include + +namespace __dp { + +// For loop tracking +struct LoopTableEntry { + LoopTableEntry(std::int32_t function_level, std::int32_t loop_id, std::int32_t number_hits, LID begin_line) + : funcLevel(function_level), loopID(loop_id), count(number_hits), begin(begin_line) {} + + std::int32_t funcLevel; + std::int32_t loopID; + LID begin; + + bool operator==(const LoopTableEntry& other) const noexcept { + return funcLevel == other.funcLevel && loopID == other.loopID && count == other.count && begin == other.begin; + } + + bool operator!=(const LoopTableEntry& other) const noexcept { return !(*this == other); } + + std::int32_t get_count() const noexcept { return count; } + + void increment_count() noexcept { ++count; } + +private: + std::int32_t count; +}; + +} // namespace __dp diff --git a/rtlib/loop/Makros.hpp b/rtlib/loop/Makros.hpp new file mode 100644 index 000000000..9795ae997 --- /dev/null +++ b/rtlib/loop/Makros.hpp @@ -0,0 +1,34 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +#define unpackLIDMetadata_getLoopID(lid) \ + ((lid) >> 56) + +#define unpackLIDMetadata_getLoopIteration_0(lid) \ + (((lid) >> 48) & 0x7F) + +#define unpackLIDMetadata_getLoopIteration_1(lid) \ + (((lid) >> 40) & 0x7F) + +#define unpackLIDMetadata_getLoopIteration_2(lid) \ + (((lid) >> 32) & 0x7F) + +#define checkLIDMetadata_getLoopIterationValidity_0(lid) \ + (((lid) & 0x0080000000000000) >> 55) + +#define checkLIDMetadata_getLoopIterationValidity_1(lid) \ + (((lid) & 0x0000800000000000) >> 47) + +#define checkLIDMetadata_getLoopIterationValidity_2(lid) \ + (((lid) & 0x0000008000000000) >> 39) diff --git a/rtlib/loop/VarCounter.hpp b/rtlib/loop/VarCounter.hpp new file mode 100644 index 000000000..29e099ce4 --- /dev/null +++ b/rtlib/loop/VarCounter.hpp @@ -0,0 +1,29 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +namespace __dp { + +struct VarCounter { + unsigned int counters_[2] = {0, 0}; + long long mem_addr_ = 0; + bool valid_ = true; + + bool operator==(const VarCounter& other) const noexcept { + return counters_[0] == other.counters_[0] && counters_[1] == other.counters_[1] && mem_addr_ == other.mem_addr_ && valid_ == other.valid_; + } + + bool operator!=(const VarCounter& other) const noexcept { return !(*this == other); } +}; + +} // namespace __dp diff --git a/rtlib/loop/VarInfo.hpp b/rtlib/loop/VarInfo.hpp new file mode 100644 index 000000000..cce392a27 --- /dev/null +++ b/rtlib/loop/VarInfo.hpp @@ -0,0 +1,35 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +#include + +namespace __dp { + +struct var_info_t { + std::string var_name_; + int file_id_ = 0; + int instr_id_ = 0; + int loop_line_nr_ = 0; + int instr_line_ = 0; + char operation_ = 0; + + bool operator==(const var_info_t& other) const noexcept { + return var_name_ == other.var_name_ && file_id_ == other.file_id_ && instr_id_ == other.instr_id_ && + loop_line_nr_ == other.loop_line_nr_ && instr_line_ == other.instr_line_ && operation_ == other.operation_; + } + + bool operator!=(const var_info_t& other) const noexcept { return !(*this == other); } +}; + +} // namespace __dp diff --git a/rtlib/loop_counter.cpp b/rtlib/loop_counter.cpp deleted file mode 100644 index f492bc1c2..000000000 --- a/rtlib/loop_counter.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * This file is part of the DiscoPoP software - * (http://www.discopop.tu-darmstadt.de) - * - * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany - * - * This software may be modified and distributed under the terms of - * the 3-Clause BSD License. See the LICENSE file in the package base - * directory for details. - * - */ - -#include "loop_counter.hpp" - -#include -#include -#include -#include - -static LoopCounter lc; -static bool alreadyDone; - -extern "C" { - -// 0 = load instruction, 1 = store instruction -void add_instr_rec(int loopLineNumber, long long var_id, int instruction_type) { - if (alreadyDone) - return; - lc.incr_counter((int)var_id, instruction_type); -} - -// 0 = load instruction, 1 = store instruction -void add_ptr_instr_rec(int loopLineNumber, long long var_id, - int instruction_type, long long addr) { - if (alreadyDone) - return; - lc.incr_counter((int)var_id, instruction_type); - lc.update_ptr((int)var_id, instruction_type, addr); -} - -void incr_loop_counter(int loop_id) { - if (alreadyDone) - return; - lc.incr_loop_counter(loop_id); -} - -void loop_counter_output() { - if (alreadyDone) - return; - - std::cout << "Outputting instrumentation results... "; - - std::ifstream ifile; - std::string line; - std::ofstream ofile; - - // get meta information about the loops - std::vector loop_infos; - loop_infos.push_back(loop_info_t()); // dummy - std::string tmp(getenv("DOT_DISCOPOP_PROFILER")); - tmp += "/loop_meta.txt"; - ifile.open(tmp.data()); - while (std::getline(ifile, line)) { - loop_info_t loop_info; - int cnt = sscanf(line.c_str(), "%d %d %d", &loop_info.file_id_, - &loop_info.loop_id_, &loop_info.line_nr_); - if (cnt == 3) { - loop_infos.push_back(loop_info); - } - } - ifile.close(); - - // output information about the loops - std::string tmp2(getenv("DOT_DISCOPOP_PROFILER")); - tmp2 += "/loop_counter_output.txt"; - ofile.open(tmp2.data()); - for (auto i = 1; i < lc.loop_counters_.size(); ++i) { - loop_info_t &loop_info = loop_infos[i]; - ofile << loop_info.file_id_ << " "; - ofile << loop_info.line_nr_ << " "; - ofile << lc.loop_counters_[i] << "\n"; - } - ofile.close(); - - std::cout << "done" << std::endl; - - alreadyDone = true; -} -} - -void LoopCounter::incr_counter(int var_id, int instr_type) { - if (var_counters_.size() < var_id + 1) { - var_counters_.resize(var_id + 1); - } - var_counters_[var_id].counters_[instr_type] += 1; -} - -void LoopCounter::incr_loop_counter(int loop_id) { - if (loop_counters_.size() < loop_id + 1) { - loop_counters_.resize(loop_id + 1); - } - loop_counters_[loop_id] += 1; -} - -void LoopCounter::update_ptr(int var_id, int instr_type, long long addr) { -#ifdef ONLY_CONST_INDICES - if (var_counters_[var_id].valid_) { - if (var_counters_[var_id].mem_addr_ == 0) { - var_counters_[var_id].mem_addr_ = addr; - } else if (var_counters_[var_id].mem_addr_ != addr) { - var_counters_[var_id].valid_ = false; - } - } -#else - if (instr_type == 1) { - if (var_counters_[var_id].mem_addr_ != addr) { - var_counters_[var_id].valid_ = false; - } - } else { - var_counters_[var_id].mem_addr_ = addr; - } -#endif -} diff --git a/rtlib/loop_counter.hpp b/rtlib/loop_counter.hpp deleted file mode 100644 index e504186cc..000000000 --- a/rtlib/loop_counter.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of the DiscoPoP software - * (http://www.discopop.tu-darmstadt.de) - * - * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany - * - * This software may be modified and distributed under the terms of - * the 3-Clause BSD License. See the LICENSE file in the package base - * directory for details. - * - */ - -#pragma once - -#include -#include - -struct var_info_t { - int file_id_; - int instr_id_; - std::string var_name_; - int loop_line_nr_; - int instr_line_; - char operation_; -}; - -struct loop_info_t { - int line_nr_; - int loop_id_; - int file_id_; -}; - -struct VarCounter { - VarCounter() : counters_{0, 0}, mem_addr_(0), valid_(true) {} - - unsigned counters_[2]; - long long mem_addr_; - bool valid_; -}; - -class LoopCounter { -public: - void incr_loop_counter(int loop_id); - - void incr_counter(int var_id, int instr_type); - - void update_ptr(int var_id, int instr_type, long long addr); - - std::vector var_counters_; - std::vector loop_counters_; -}; diff --git a/rtlib/memory/AbstractShadow.hpp b/rtlib/memory/AbstractShadow.hpp new file mode 100644 index 000000000..6eaf27086 --- /dev/null +++ b/rtlib/memory/AbstractShadow.hpp @@ -0,0 +1,46 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +#include "../DPTypes.hpp" + +#include +#include + +namespace __dp { + +class AbstractShadow { +public: + virtual ~AbstractShadow() {} + + virtual sigElement testInRead(std::int64_t memAddr) = 0; + + virtual sigElement testInWrite(std::int64_t memAddr) = 0; + + virtual sigElement insertToRead(std::int64_t memAddr, sigElement value) = 0; + + virtual sigElement insertToWrite(std::int64_t memAddr, sigElement value) = 0; + + virtual void updateInRead(std::int64_t memAddr, sigElement newValue) = 0; + + virtual void updateInWrite(std::int64_t memAddr, sigElement newValue) = 0; + + virtual void removeFromRead(std::int64_t memAddr) = 0; + + virtual void removeFromWrite(std::int64_t memAddr) = 0; + + virtual std::unordered_set getAddrsInRange(std::int64_t startAddr, + std::int64_t endAddr) = 0; +}; + +} // namespace __dp diff --git a/rtlib/memory/MemoryManager.cpp b/rtlib/memory/MemoryManager.cpp new file mode 100644 index 000000000..ac6e2ae85 --- /dev/null +++ b/rtlib/memory/MemoryManager.cpp @@ -0,0 +1,57 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#include "MemoryManager.hpp" + +#include "../iFunctionsGlobals.hpp" + +std::string __dp::MemoryManager::allocate_memory(const LID line_id, const ADDR start_address, const ADDR end_address, const std::int64_t number_bytes, const std::int64_t number_elements) { + const auto memory_region_id = get_next_free_memory_region_id(); + const auto memory_region_id_str = std::to_string(memory_region_id); + + allocatedMemRegTree.allocate_region(start_address, end_address, memory_region_id); + allocatedMemoryRegions.emplace_back(line_id, memory_region_id_str, start_address, end_address, number_bytes, number_elements); + + if (start_address < smallestAllocatedADDR) { + smallestAllocatedADDR = start_address; + } + + if (end_address > largestAllocatedADDR) { + largestAllocatedADDR = end_address; + } + + return memory_region_id_str; +} + +std::string __dp::MemoryManager::allocate_stack_memory(const LID line_id, const ADDR start_address, const ADDR end_address, const std::int64_t number_bytes, const std::int64_t number_elements) { + const auto memory_region_id = get_next_free_memory_region_id(); + const auto memory_region_id_str = std::to_string(memory_region_id); + + allocatedMemRegTree.allocate_region(start_address, end_address, memory_region_id); + allocatedMemoryRegions.emplace_back(line_id, memory_region_id_str, start_address, end_address, number_bytes, number_elements); + + if (start_address < smallestAllocatedADDR) { + smallestAllocatedADDR = start_address; + } + + if (end_address > largestAllocatedADDR) { + largestAllocatedADDR = end_address; + } + + if (number_elements >= 0) { + assert (start_address <= end_address && "start_address <= end_address is violated!"); + // update stack base address, if not already set + update_stack_addresses(start_address, end_address); + } + + return memory_region_id_str; +} diff --git a/rtlib/memory/MemoryManager.hpp b/rtlib/memory/MemoryManager.hpp new file mode 100644 index 000000000..4841aaa4b --- /dev/null +++ b/rtlib/memory/MemoryManager.hpp @@ -0,0 +1,179 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +#include "../DPTypes.hpp" +#include "../DPUtils.hpp" + +#include "MemoryRegionTree.hpp" +#include "Scope.hpp" + +#include +#include +#include +#include +#include + +namespace __dp { + +class MemoryManager { +public: + MemoryManager() { + nextFreeMemoryRegionId = 1; + + smallestAllocatedADDR = std::numeric_limits::max(); + largestAllocatedADDR = std::numeric_limits::min(); + } + + MemoryManager(const MemoryManager& other) = delete; + MemoryManager(MemoryManager&& other) = delete; + + MemoryManager& operator=(const MemoryManager& other) = delete; + MemoryManager& operator=(MemoryManager&& other) = delete; + + std::int64_t get_next_free_memory_region_id() noexcept { + const auto old_value = nextFreeMemoryRegionId; + nextFreeMemoryRegionId++; + return old_value; + } + + void enter_new_function() { + stackAddrs.emplace(0, 0); + } + + void update_stack_addresses(const ADDR start, const ADDR end) { + auto& top = stackAddrs.top(); + if (top.first == 0) { + top.first = start; + } + else if (top.first > start) { + top.first = start; + } + + if (top.second == 0) { + top.second = end; + } + else if (top.second < end) { + top.second = end; + } + } + + std::pair pop_last_stack_address() { + const auto val = stackAddrs.top(); + stackAddrs.pop(); + return val; + } + + bool is_stack_access(const ADDR address) noexcept { + if (stackAddrs.empty()) { + return false; + } + + const auto& addrs = stackAddrs.top(); + if (addrs.first == 0 || addrs.second == 0) { + return false; + } + + return addrs.first <= address && address <= addrs.second; + // return address <= addrs.first && addrs.second <= address; + } + + void enterScope(std::string type, const LID debug_lid) { + scopeManager.enterScope(type.c_str(), debug_lid); + } + + void leaveScope(std::string type, const LID debug_lid) { + scopeManager.leaveScope(type.c_str(), debug_lid); + } + + void registerStackRead(const ADDR address, const LID debug_lid, char *debug_var) { + scopeManager.registerStackRead(address, debug_lid, debug_var); + } + + void registerStackWrite(const ADDR address, const LID debug_lid, char *debug_var) { + scopeManager.registerStackWrite(address, debug_lid, debug_var); + } + + bool isFirstWrittenInScope(const ADDR addr, const bool currentAccessIsWrite) { + return scopeManager.isOwnedByScope(addr, currentAccessIsWrite); + } + + bool positiveScopeChangeOccuredSinceLastAccess(const ADDR addr) { + return scopeManager.positiveScopeChangeOccuredSinceLastAccess(addr); + } + + const Scope& getCurrentScope() { + return scopeManager.getCurrentScope(); + } + + std::size_t number_open_scopes() const noexcept { + return scopeManager.number_open_scopes(); + } + + std::string get_memory_region_id(const ADDR addr, std::string fallback) { + return allocatedMemRegTree.get_memory_region_id_string(addr, fallback.c_str()); + } + + std::string allocate_memory(const LID line_id, const ADDR start_address, const ADDR end_address, const std::int64_t number_bytes, const std::int64_t number_elements); + + std::string allocate_stack_memory(const LID line_id, const ADDR start_address, const ADDR end_address, const std::int64_t number_bytes, const std::int64_t number_elements); + + void allocate_dummy_region() { + allocatedMemoryRegions.emplace_back(0, std::string("%%dummy%%"), 0, 0, 0, 0); + } + + std::size_t get_number_allocations() { + return allocatedMemoryRegions.size(); + } + + const std::vector>& + get_allocated_memory_regions() { + return allocatedMemoryRegions; + } + + void output_memory_regions(std::ostream& stream) { + for (const auto& memoryRegion : allocatedMemoryRegions) { + const auto lid = get<0>(memoryRegion); + const auto& id = get<1>(memoryRegion); + const auto num_bytes = get<4>(memoryRegion); + + dputil::decodeLID(lid, stream); + stream << ' ' << id << ' ' << num_bytes << endl; + } + } + + ADDR get_smallest_allocated_addr() const noexcept { + return smallestAllocatedADDR; + } + + ADDR get_largest_allocated_addr() const noexcept { + return largestAllocatedADDR; + } + +private: + std::int64_t nextFreeMemoryRegionId; // 0 is reserved as the identifier for "no region" in the MemoryRegionTree + + ADDR smallestAllocatedADDR; + ADDR largestAllocatedADDR; + + std::stack> stackAddrs; // track stack adresses for entered functions + + ScopeManager scopeManager; + + MemoryRegionTree allocatedMemRegTree; + + // (LID, identifier, startAddr, endAddr, numBytes, numElements) + std::vector> allocatedMemoryRegions; +}; + +} // namespace __dp diff --git a/rtlib/memory/MemoryRegionTree.hpp b/rtlib/memory/MemoryRegionTree.hpp new file mode 100644 index 000000000..9419510d5 --- /dev/null +++ b/rtlib/memory/MemoryRegionTree.hpp @@ -0,0 +1,362 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +#include "../DPUtils.hpp" + +#define get_char_at_level(addr, level) \ + ((((addr) << ((level) * 4)) >> 60) & 0x000000000000000F) + +inline ADDR get_level_shifting_mask(int level) { + switch (level) { + case 0: + return 0xF000000000000000; + case 1: + return 0x0F00000000000000; + case 2: + return 0x00F0000000000000; + case 3: + return 0x000F000000000000; + case 4: + return 0x0000F00000000000; + case 5: + return 0x00000F0000000000; + case 6: + return 0x000000F000000000; + case 7: + return 0x0000000F00000000; + case 8: + return 0x00000000F0000000; + case 9: + return 0x000000000F000000; + case 10: + return 0x0000000000F00000; + case 11: + return 0x00000000000F0000; + case 12: + return 0x000000000000F000; + case 13: + return 0x0000000000000F00; + case 14: + return 0x00000000000000F0; + case 15: + return 0x000000000000000F; + default: + return 0xFFFFFFFFFFFFFFFF; + } +} + +inline int get_shift(int level) { + switch (level) { + case 0: + return 60; + case 1: + return 56; + case 2: + return 52; + case 3: + return 48; + case 4: + return 44; + case 5: + return 40; + case 6: + return 36; + case 7: + return 32; + case 8: + return 28; + case 9: + return 24; + case 10: + return 20; + case 11: + return 16; + case 12: + return 12; + case 13: + return 8; + case 14: + return 4; + case 15: + return 0; + default: + return -1; + } +} + +namespace __dp { + +class MRTNode { +public: + MRTNode(const ADDR first_addr, const ADDR last_addr, const short level) : first_addr(first_addr), last_addr(last_addr), level(level) {} + + ADDR get_first_addr() const noexcept { + return first_addr; + } + + ADDR get_last_addr() const noexcept { + return last_addr; + } + + void set_memory_region_id(const unsigned int memory_region_id) noexcept { + this->memory_region_id = memory_region_id; + } + + unsigned int get_memory_region_id() const noexcept { + return memory_region_id; + } + + short get_level() const noexcept { + return level; + } + + const std::array& get_children() const noexcept { + return children; + } + + void delete_child(const unsigned int index) { + delete children[index]; + children[index] = nullptr; + } + + MRTNode* get_child(const unsigned int index) const noexcept { + return children[index]; + } + + int get_child_index(const ADDR addr) const noexcept { + if (addr < first_addr || addr > last_addr) { + return -1; + } + + const auto shift = get_shift(level); + const auto mask = get_level_shifting_mask(level); + const auto index = (addr & mask) >> shift; + + return index; + } + + void add_child(const unsigned int index) { + assert(children[index] == nullptr && "Child already exists"); + + const auto shift = get_shift(level); + + const auto child_start = first_addr | (static_cast(index) << shift); + const auto child_end = child_start | ((1ULL << shift) - 1ULL); + + children[index] = new MRTNode(child_start, child_end, level + 1); + } + +private: + ADDR first_addr = 0x0000000000000000; + ADDR last_addr = 0x7FFFFFFFFFFFFFFF; + + unsigned int memory_region_id = 0U; + unsigned short level = 65535; + + std::array children = {}; +}; + +class MemoryRegionTree { +public: + MemoryRegionTree() { + root = new MRTNode(0x0000000000000000, 0x7FFFFFFFFFFFFFFF, 0); + } + + MemoryRegionTree(const MemoryRegionTree&) = delete; + MemoryRegionTree& operator=(const MemoryRegionTree&) = delete; + + MemoryRegionTree(MemoryRegionTree&& other) noexcept { + root = other.root; + other.root = nullptr; + } + + MemoryRegionTree& operator=(MemoryRegionTree&& other) noexcept { + auto* temp = root; + root = other.root; + other.root = temp; + return *this; + } + + ~MemoryRegionTree() { + delete_nodes(root); + delete root; + } + + MRTNode* get_root() noexcept { + return root; + } + + const MRTNode* get_root() const noexcept { + return root; + } + + void allocate_region(const ADDR start, const ADDR end, const unsigned int memory_region_id) { + assert(start <= end && "Invalid memory region"); + assert(memory_region_id != 0 && "Invalid memory region id"); + allocate(start, end, memory_region_id, root); + } + + unsigned int get_memory_region_id(const ADDR addr) { + auto* node = root; + + while (true) { + if (node->get_memory_region_id() != 0) { + if (addr >= node->get_first_addr() && addr <= node->get_last_addr()) { + return node->get_memory_region_id(); + } + + return 0xFFFF'FFFFU; + } + + const auto index = node->get_child_index(addr); + if (index == -1) { + return 0xFFFF'FFFFU; + } + + const auto child = node->get_child(index); + if (child == nullptr) { + return 0xFFFF'FFFFU; + } + + node = child; + } + + return 0xFFFF'FFFFU; + } + + std::string get_memory_region_id_string(const ADDR addr, const char* fallback) { + const auto memory_region_id = get_memory_region_id(addr); + if (memory_region_id == 0xFFFF'FFFFU) { + return fallback; + } + + return std::to_string(memory_region_id); + } + + void free_region(const ADDR start) { + // NOTE: Given an allocation [start, end], this function can also handle free(x) for x in (start, end]. + // Not sure if this functionality is required. + + const auto memory_region_id = get_memory_region_id(start); + if (memory_region_id == 0xFFFF'FFFFU) { + return; + } + + // This actually searches the whole tree again, but it's fine for now + const auto clean_root = free(start, memory_region_id, root); + + // We never delete the root node + } + +private: + static void allocate(const ADDR start, const ADDR end, const unsigned int memory_region_id, MRTNode* node) { + assert(node != nullptr && "Node is null"); + assert(start >= node->get_first_addr() && end <= node->get_last_addr() && "Invalid memory region for node"); + + if (start == node->get_first_addr() && end == node->get_last_addr()) { + // This assert is valid once dp_delete is implemented + // assert(node->get_memory_region_id() == 0 && "Memory region already allocated"); + node->set_memory_region_id(memory_region_id); + + return; + } + + const auto child_start_index = node->get_child_index(start); + const auto child_end_index = node->get_child_index(end); + + for (auto index = child_start_index; index <= child_end_index; ++index) { + if (node->get_child(index) == nullptr) { + node->add_child(index); + } + + auto* child = node->get_child(index); + + const auto child_start = child->get_first_addr(); + const auto child_end = child->get_last_addr(); + + const auto clamped_start = std::max(start, child_start); + const auto clamped_end = std::min(end, child_end); + + allocate(clamped_start, clamped_end, memory_region_id, child); + } + } + + static bool free(const ADDR start, const unsigned int memory_region_id, MRTNode* node) { + assert(node != nullptr && "Node is null"); + + const auto memory_region_id_node = node->get_memory_region_id(); + if (memory_region_id_node == memory_region_id) { + // node is a leaf with the correct id -> free it + node->set_memory_region_id(0); + + return true; + } + + if (memory_region_id_node != 0) { + // node is a leaf with a different id -> Overstepped the allocation + return false; + } + + const auto start_index = node->get_child_index(start); + if (start_index == -1) { + // start is not in the node -> Technically a bug? + return false; + } + + for (auto index = start_index; index < 16; index++) { + auto* child = node->get_child(index); + if (child == nullptr) { + // We might need to clean node -> no return here + break; + } + + const auto belongs_to_allocation = free(start, memory_region_id, child); + if (!belongs_to_allocation) { + // We found a child that doesn't belong to the allocation -> We are done + return false; + } + + // Child belongs to the allocation -> Free it + node->delete_child(index); + } + + for (auto i = 0; i < 16; i++) { + if (node->get_child(i) != nullptr) { + // There are still children -> We do not need to clean node + return false; + } + } + + // There are no children left -> Clean node + return true; + } + + static void delete_nodes(MRTNode* node) { + if (node == nullptr) { + return; + } + + for (auto i = 0; i < 16; i++) { + auto* child = node->get_child(i); + if (child != nullptr) { + delete_nodes(child); + delete child; + } + } + } + + MRTNode* root{}; +}; + +} // namespace __dp diff --git a/rtlib/perfect_shadow.hpp b/rtlib/memory/PerfectShadow.hpp similarity index 75% rename from rtlib/perfect_shadow.hpp rename to rtlib/memory/PerfectShadow.hpp index 45c92dde6..bc3876706 100644 --- a/rtlib/perfect_shadow.hpp +++ b/rtlib/memory/PerfectShadow.hpp @@ -12,14 +12,17 @@ #pragma once -#include "abstract_shadow.hpp" +#include "AbstractShadow.hpp" + +#include "../DPTypes.hpp" #include #include +#include namespace __dp { -class PerfectShadow : public Shadow { +class PerfectShadow : public AbstractShadow { public: PerfectShadow(int slotSize, int size, int numHash) : PerfectShadow() {} @@ -50,40 +53,40 @@ class PerfectShadow : public Shadow { delete sigWrite; } - inline sigElement testInRead(int64_t memAddr) { + inline sigElement testInRead(std::int64_t memAddr) { return (*sigRead)[memAddr]; } - inline sigElement testInWrite(int64_t memAddr) { + inline sigElement testInWrite(std::int64_t memAddr) { return (*sigWrite)[memAddr]; } - inline sigElement insertToRead(int64_t memAddr, sigElement value) { + inline sigElement insertToRead(std::int64_t memAddr, sigElement value) { sigElement oldValue = testInRead(memAddr); (*sigRead)[memAddr] = value; return oldValue; } - inline sigElement insertToWrite(int64_t memAddr, sigElement value) { + inline sigElement insertToWrite(std::int64_t memAddr, sigElement value) { sigElement oldValue = testInWrite(memAddr); (*sigWrite)[memAddr] = value; return oldValue; } - inline void updateInRead(int64_t memAddr, sigElement newValue) { + inline void updateInRead(std::int64_t memAddr, sigElement newValue) { (*sigRead)[memAddr] = newValue; } - inline void updateInWrite(int64_t memAddr, sigElement newValue) { + inline void updateInWrite(std::int64_t memAddr, sigElement newValue) { (*sigWrite)[memAddr] = newValue; } - inline void removeFromRead(int64_t memAddr) { (*sigRead)[memAddr] = 0; } + inline void removeFromRead(std::int64_t memAddr) { (*sigRead)[memAddr] = 0; } - inline void removeFromWrite(int64_t memAddr) { (*sigWrite)[memAddr] = 0; } + inline void removeFromWrite(std::int64_t memAddr) { (*sigWrite)[memAddr] = 0; } - inline std::unordered_set getAddrsInRange(int64_t startAddr, - int64_t endAddr) { + inline std::unordered_set getAddrsInRange(std::int64_t startAddr, + std::int64_t endAddr) { std::unordered_set result; for (auto pair : (*sigWrite)) { if ((pair.first >= startAddr) && (pair.first <= endAddr)) { @@ -98,22 +101,22 @@ class PerfectShadow : public Shadow { return result; } - const std::unordered_map* getSigRead() const noexcept { + const std::unordered_map* getSigRead() const noexcept { return sigRead; } - const std::unordered_map* getSigWrite() const noexcept { + const std::unordered_map* getSigWrite() const noexcept { return sigWrite; } private: - std::unordered_map *sigRead; - std::unordered_map *sigWrite; + std::unordered_map *sigRead; + std::unordered_map *sigWrite; }; // Hopefully faster version -class PerfectShadow2 : public Shadow { +class PerfectShadow2 : public AbstractShadow { public: PerfectShadow2() { read_cache.reserve(1024); diff --git a/rtlib/scope.hpp b/rtlib/memory/Scope.hpp similarity index 93% rename from rtlib/scope.hpp rename to rtlib/memory/Scope.hpp index e2628a02b..ca78c4246 100644 --- a/rtlib/scope.hpp +++ b/rtlib/memory/Scope.hpp @@ -12,7 +12,7 @@ #pragma once -#include "DPTypes.hpp" +#include "../DPTypes.hpp" #include #include @@ -59,10 +59,14 @@ struct Scope { // Data structure for stack access management in scopes struct ScopeManager { - Scope getCurrentScope() { + const Scope& getCurrentScope() { return scopeStack.back(); } + std::size_t number_open_scopes() const noexcept { + return scopeStack.size(); + } + void enterScope(std::string type, LID debug_lid) { scopeStack.push_back(Scope(next_scope_id++)); } @@ -199,6 +203,10 @@ struct ScopeManager2 { return scopeStack.back(); } + std::size_t number_open_scopes() const noexcept { + return scopeStack.size(); + } + void enterScope(const char* type, LID debug_lid) { scopeStack.emplace_back(next_scope_id++); } diff --git a/rtlib/shadow.hpp b/rtlib/memory/ShadowMemory.hpp similarity index 55% rename from rtlib/shadow.hpp rename to rtlib/memory/ShadowMemory.hpp index 83297a8fa..187f24cc2 100644 --- a/rtlib/shadow.hpp +++ b/rtlib/memory/ShadowMemory.hpp @@ -12,17 +12,17 @@ #pragma once -#include "abstract_shadow.hpp" -#include "signature.hpp" +#include "AbstractShadow.hpp" +#include "Signature.hpp" #include -#include +#include using namespace std; namespace __dp { -class ShadowMemory : public Shadow { +class ShadowMemory : public AbstractShadow { public: ShadowMemory(int slotSize, int size, int numHash) { sigRead = new Signature(slotSize, size, numHash); @@ -34,36 +34,36 @@ class ShadowMemory : public Shadow { delete sigWrite; } - inline sigElement testInRead(int64_t memAddr) { + inline sigElement testInRead(std::int64_t memAddr) { return sigRead->membershipCheck(memAddr); } - inline sigElement testInWrite(int64_t memAddr) { + inline sigElement testInWrite(std::int64_t memAddr) { return sigWrite->membershipCheck(memAddr); } - inline sigElement insertToRead(int64_t memAddr, sigElement value) { + inline sigElement insertToRead(std::int64_t memAddr, sigElement value) { return sigRead->insert(memAddr, value); } - inline sigElement insertToWrite(int64_t memAddr, sigElement value) { + inline sigElement insertToWrite(std::int64_t memAddr, sigElement value) { return sigWrite->insert(memAddr, value); } - inline void updateInRead(int64_t memAddr, sigElement newValue) { + inline void updateInRead(std::int64_t memAddr, sigElement newValue) { sigRead->update(memAddr, newValue); } - inline void updateInWrite(int64_t memAddr, sigElement newValue) { + inline void updateInWrite(std::int64_t memAddr, sigElement newValue) { sigWrite->update(memAddr, newValue); } - inline void removeFromRead(int64_t memAddr) { sigRead->remove(memAddr); } + inline void removeFromRead(std::int64_t memAddr) { sigRead->remove(memAddr); } - inline void removeFromWrite(int64_t memAddr) { sigWrite->remove(memAddr); } + inline void removeFromWrite(std::int64_t memAddr) { sigWrite->remove(memAddr); } - inline std::unordered_set getAddrsInRange(int64_t startAddr, - int64_t endAddr) { + inline std::unordered_set getAddrsInRange(std::int64_t startAddr, + std::int64_t endAddr) { // not possible for Shadow, since not all addresses are kept std::unordered_set result; return result; diff --git a/rtlib/signature.cpp b/rtlib/memory/Signature.cpp similarity index 94% rename from rtlib/signature.cpp rename to rtlib/memory/Signature.cpp index 9f15d7ebc..cae41f966 100644 --- a/rtlib/signature.cpp +++ b/rtlib/memory/Signature.cpp @@ -10,9 +10,9 @@ * */ -#include "signature.hpp" +#include "Signature.hpp" -#include "stdint.h" +#include #include using namespace std; diff --git a/rtlib/signature.hpp b/rtlib/memory/Signature.hpp similarity index 52% rename from rtlib/signature.hpp rename to rtlib/memory/Signature.hpp index 4c02ab510..8b863b80f 100644 --- a/rtlib/signature.hpp +++ b/rtlib/memory/Signature.hpp @@ -12,26 +12,25 @@ #pragma once -#include -#include +#include "../DPTypes.hpp" -#include "DPTypes.hpp" +#include +#include #include -using namespace std; - namespace __dp { + class Signature { public: - Signature(int32_t slotSize, int32_t size, int32_t numOfHash = 1) + Signature(std::int32_t slotSize, std::int32_t size, std::int32_t numOfHash = 1) : sigSlotSize(slotSize), numSlot(size), numHash(numOfHash) { assert((slotSize % 8 == 0) && (slotSize <= 32 && slotSize >= 8) && "slotSize must be byte aligned!"); sigSlotSizeInByte = sigSlotSize / 8; sigSizeInByte = sigSlotSizeInByte * numSlot; - sigarray = new uint8_t[sigSizeInByte]; + sigarray = new std::uint8_t[sigSizeInByte]; for (int i = 0; i < sigSizeInByte; ++i) { sigarray[i] = 0; } @@ -42,31 +41,32 @@ class Signature { ~Signature() { delete[] sigarray; } - sigElement insert(int64_t elem, sigElement value); + sigElement insert(std::int64_t elem, sigElement value); - void update(int64_t elem, sigElement newValue); + void update(std::int64_t elem, sigElement newValue); - void remove(int64_t elem); + void remove(std::int64_t elem); - sigElement membershipCheck(int64_t elem); + sigElement membershipCheck(std::int64_t elem); bool intersect(Signature &other); double expectedFalsePositiveRate(); private: - int32_t sigSlotSize; // in bits - int32_t numSlot; - int32_t numHash; // 1 by default - int32_t sigSlotSizeInByte; // slot size in byte - int32_t sigSizeInByte; // total size in byte - uint8_t *sigarray; - - int32_t insertedElem; - int32_t conflictElem; - - uint32_t hash(int64_t value) { - return (uint32_t)((value >> 8) + value) % numSlot; + std::int32_t sigSlotSize; // in bits + std::int32_t numSlot; + std::int32_t numHash; // 1 by default + std::int32_t sigSlotSizeInByte; // slot size in byte + std::int32_t sigSizeInByte; // total size in byte + std::uint8_t *sigarray; + + std::int32_t insertedElem; + std::int32_t conflictElem; + + std::uint32_t hash(std::int64_t value) { + return (std::uint32_t)((value >> 8) + value) % numSlot; } }; + } // namespace __dp diff --git a/scripts/dev/clang-format.sh b/scripts/dev/clang-format.sh index 0c4925b90..558d41811 100755 --- a/scripts/dev/clang-format.sh +++ b/scripts/dev/clang-format.sh @@ -1,36 +1,36 @@ -#!/usr/bin/env bash - -# This file is part of the DiscoPoP software (http://www.discopop.tu-darmstadt.de) -# -# Copyright (c) 2020, Technische Universitaet Darmstadt, Germany -# -# This software may be modified and distributed under the terms of -# the 3-Clause BSD License. See the LICENSE file in the package base -# directory for details. - -# This script executes clang-format on all C/C++ files in the project - -# Usage: ./clang-format.sh - -# change directory to discopop -cd ../.. - -# loop over all C/C++ source and header files in the project -C_CPP_FILES=$(find . -name *.c -or -name *.cpp -or -name *.h -or -name *.hpp) -for file in $C_CPP_FILES; do - # execute clang-format for each file - - # ignore third-party libraries - if [[ "$file" == "./third_party/"* ]]; then - echo "Skipping third-party file: $file" - continue - fi - - # ignore build folder - if [[ "$file" == "./build/"* ]]; then - echo "Skipping build file: $file" - continue - fi - - clang-format $file -i --verbose +#!/usr/bin/env bash + +# This file is part of the DiscoPoP software (http://www.discopop.tu-darmstadt.de) +# +# Copyright (c) 2020, Technische Universitaet Darmstadt, Germany +# +# This software may be modified and distributed under the terms of +# the 3-Clause BSD License. See the LICENSE file in the package base +# directory for details. + +# This script executes clang-format on all C/C++ files in the project + +# Usage: ./clang-format.sh + +# change directory to discopop +cd ../.. + +# loop over all C/C++ source and header files in the project +C_CPP_FILES=$(find . -name *.c -or -name *.cpp -or -name *.h -or -name *.hpp) +for file in $C_CPP_FILES; do + # execute clang-format for each file + + # ignore third-party libraries + if [[ "$file" == "./third_party/"* ]]; then + echo "Skipping third-party file: $file" + continue + fi + + # ignore build folder + if [[ "$file" == "./build/"* ]]; then + echo "Skipping build file: $file" + continue + fi + + clang-format $file -i --verbose done \ No newline at end of file diff --git a/share/include/debug_print.hpp b/share/include/debug_print.hpp new file mode 100644 index 000000000..a4a7aab53 --- /dev/null +++ b/share/include/debug_print.hpp @@ -0,0 +1,39 @@ +/* + * This file is part of the DiscoPoP software + * (http://www.discopop.tu-darmstadt.de) + * + * Copyright (c) 2020, Technische Universitaet Darmstadt, Germany + * + * This software may be modified and distributed under the terms of + * the 3-Clause BSD License. See the LICENSE file in the package base + * directory for details. + * + */ + +#pragma once + +#include + +template +class DebugPrint { +public: + DebugPrint(const char message[N]) { + for (auto i = 0; i < N; i++) { + buffer[i] = message[i]; + } + + std::cout << "enter: " << buffer << '\n'; + } + + ~DebugPrint() { + std::cout << "exit: " << buffer << '\n'; + } + +private: + char buffer[N]; +}; + +template +inline DebugPrint make_debug_print(const char(&message)[N]) { + return DebugPrint(message); +} diff --git a/share/include/timer.hpp b/share/include/timer.hpp index 498bd9645..9c4bb7726 100644 --- a/share/include/timer.hpp +++ b/share/include/timer.hpp @@ -19,9 +19,6 @@ #include #include -// To manually enable/disable internal timing -// #define DP_SKIP_INTERNAL_TIMER - /** * This type allows type-safe specification of a specific timer */ @@ -97,9 +94,6 @@ class Timers { * @param timer The timer to start */ void start(const TimerRegion timer) { -#ifdef DP_SKIP_INTERNAL_TIMER - return; -#endif const auto timer_id = get_timer_index(timer); number_called[timer_id]++; time_start[timer_id] = std::chrono::high_resolution_clock::now(); @@ -110,9 +104,6 @@ class Timers { * @param timer The timer to stops */ void stop(const TimerRegion timer) { -#ifdef DP_SKIP_INTERNAL_TIMER - return; -#endif const auto timer_id = get_timer_index(timer); time_stop[timer_id] = std::chrono::high_resolution_clock::now(); } @@ -122,9 +113,6 @@ class Timers { * @param timer The timer to stops */ void stop_and_add(const TimerRegion timer) { -#ifdef DP_SKIP_INTERNAL_TIMER - return; -#endif stop(timer); add_start_stop_diff_to_elapsed(timer); } @@ -134,9 +122,6 @@ class Timers { * @param timer The timer for which to add the difference */ void add_start_stop_diff_to_elapsed(const TimerRegion timer) { -#ifdef DP_SKIP_INTERNAL_TIMER - return; -#endif const auto timer_id = get_timer_index(timer); time_elapsed[timer_id] += (time_stop[timer_id] - time_start[timer_id]); } @@ -146,9 +131,6 @@ class Timers { * @param timer The timer for which to reset the elapsed time */ void reset_elapsed(const TimerRegion timer) { -#ifdef DP_SKIP_INTERNAL_TIMER - return; -#endif const auto timer_id = get_timer_index(timer); time_elapsed[timer_id] = std::chrono::nanoseconds(0); } @@ -159,9 +141,6 @@ class Timers { * @return The elapsed time */ [[nodiscard]] std::chrono::nanoseconds get_elapsed(const TimerRegion timer) { -#ifdef DP_SKIP_INTERNAL_TIMER - return std::chrono::nanoseconds{}; -#endif const auto timer_id = get_timer_index(timer); return time_elapsed[timer_id]; } @@ -202,8 +181,8 @@ class Timers { print(stream, " Generate the dependency map : ", TimerRegion::GENERATE_STRING_DEP_MAP); print(stream, " Add a dependency : ", TimerRegion::ADD_DEP); print(stream, " Merge dendencies : ", TimerRegion::MERGE_DEPS); - print(stream, " Analyze the dependencies (incorrect! : ", TimerRegion::ANALYZE_DEPS); // Incorrect due to multithreading - print(stream, " Analyze single accesses : ", TimerRegion::ANALYZE_SINGLE_ACCESS); + print(stream, " Analyze the dependencies (incorrect!) : ", TimerRegion::ANALYZE_DEPS); // Incorrect due to multithreading + print(stream, " Analyze singe accesses : ", TimerRegion::ANALYZE_SINGLE_ACCESS); stream << '\n'; print(stream, " Output the dependencies : ", TimerRegion::OUTPUT_DEPS); print(stream, " Output the loops : ", TimerRegion::OUTPUT_LOOPS); @@ -287,3 +266,24 @@ class Timers { std::vector number_called; std::vector time_elapsed; }; + +class Timer { +public: + Timer(Timers* timers, TimerRegion region, bool also_print = false) + : timers(timers), region(region), print(also_print) { + assert(timers != nullptr && "Timer started but timers is nullptr"); + timers->start(region); + } + + ~Timer() { + timers->stop_and_add(region); + if (print) { + timers->print(std::cout); + } + } + +private: + Timers* timers; + TimerRegion region; + bool print; +}; diff --git a/test/unit_tests/CMakeLists.txt b/test/unit_tests/CMakeLists.txt index e27c3c8b2..e76c48326 100644 --- a/test/unit_tests/CMakeLists.txt +++ b/test/unit_tests/CMakeLists.txt @@ -25,8 +25,20 @@ target_sources( DiscoPoP_UT PRIVATE tests.cpp - perfect_shadow/test_perfect_shadow.cpp - scope/test_scope.cpp) + loops/loop_counter/test_loop_counter.cpp + loops/loop_info/test_loop_info.cpp + loops/loop_manager/test_loop_manager.cpp + loops/loop_record/test_loop_record.cpp + loops/loop_table/test_loop_table.cpp + loops/loop_table_entry/test_loop_table_entry.cpp + loops/makros/test_makros.cpp + loops/var_counter/test_var_counter.cpp + loops/var_info/test_var_info.cpp + memory/memory_manager/test_memory_manager.cpp + memory/memory_region_tree/test_memory_region_tree.cpp + memory/mrtnode/test_mrtnode.cpp + memory/perfect_shadow/test_perfect_shadow.cpp + memory/scope/test_scope.cpp) target_include_directories(DiscoPoP_UT PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(DiscoPoP_UT PRIVATE DiscoPoP_RT) diff --git a/test/unit_tests/loops/loop_counter/test_loop_counter.cpp b/test/unit_tests/loops/loop_counter/test_loop_counter.cpp new file mode 100644 index 000000000..39d31995f --- /dev/null +++ b/test/unit_tests/loops/loop_counter/test_loop_counter.cpp @@ -0,0 +1,44 @@ +#include + +#include "../../../../rtlib/loop/LoopCounter.hpp" + +// Tests for old version (i.e., capturing functionality) + +class LoopCounterTest : public ::testing::Test { }; + +TEST_F(LoopCounterTest, testInit) { + const auto lc = __dp::LoopCounter{}; + + const auto loop_counters = lc.get_loop_counters(); + EXPECT_EQ(loop_counters.size(), 0); +} + +TEST_F(LoopCounterTest, testIncreaseLoopCounter) { + auto lc = __dp::LoopCounter{}; + + lc.incr_loop_counter(0); + lc.incr_loop_counter(1); + lc.incr_loop_counter(0); + + const auto loop_counters = lc.get_loop_counters(); + EXPECT_EQ(loop_counters.size(), 2); + EXPECT_EQ(loop_counters[0], 2); + EXPECT_EQ(loop_counters[1], 1); + + lc.incr_loop_counter(4); + lc.incr_loop_counter(3); + lc.incr_loop_counter(9); + + const auto loop_counters2 = lc.get_loop_counters(); + EXPECT_EQ(loop_counters2.size(), 10); + EXPECT_EQ(loop_counters2[0], 2); + EXPECT_EQ(loop_counters2[1], 1); + EXPECT_EQ(loop_counters2[2], 0); + EXPECT_EQ(loop_counters2[3], 1); + EXPECT_EQ(loop_counters2[4], 1); + EXPECT_EQ(loop_counters2[5], 0); + EXPECT_EQ(loop_counters2[6], 0); + EXPECT_EQ(loop_counters2[7], 0); + EXPECT_EQ(loop_counters2[8], 0); + EXPECT_EQ(loop_counters2[9], 1); +} diff --git a/test/unit_tests/loops/loop_info/test_loop_info.cpp b/test/unit_tests/loops/loop_info/test_loop_info.cpp new file mode 100644 index 000000000..29b5a423d --- /dev/null +++ b/test/unit_tests/loops/loop_info/test_loop_info.cpp @@ -0,0 +1,51 @@ +#include + +#include "../../../../rtlib/loop/LoopInfo.hpp" + +// Tests for old version (i.e., capturing functionality) + +class LoopInfoTest : public ::testing::Test { }; + +TEST_F(LoopInfoTest, testZeroInitialization) { + const auto li = __dp::loop_info_t{}; + + ASSERT_EQ(li.line_nr_, 0); + ASSERT_EQ(li.loop_id_, 0); + ASSERT_EQ(li.file_id_, 0); +} + +TEST_F(LoopInfoTest, testInitialization) { + const auto li = __dp::loop_info_t{1, 2, 3}; + + ASSERT_EQ(li.line_nr_, 1); + ASSERT_EQ(li.loop_id_, 2); + ASSERT_EQ(li.file_id_, 3); +} + +TEST_F(LoopInfoTest, testInitializationWithNegativeValues) { + const auto li = __dp::loop_info_t{-1, -2, -3}; + + ASSERT_EQ(li.line_nr_, -1); + ASSERT_EQ(li.loop_id_, -2); + ASSERT_EQ(li.file_id_, -3); +} + +TEST_F(LoopInfoTest, testEquality) { + const auto li1 = __dp::loop_info_t{1, 2, 3}; + const auto li2 = __dp::loop_info_t{1, 2, 3}; + const auto li3 = __dp::loop_info_t{1, 2, 4}; + const auto li4 = __dp::loop_info_t{1, 3, 3}; + const auto li5 = __dp::loop_info_t{2, 2, 3}; + + ASSERT_EQ(li1, li1); + + ASSERT_EQ(li1, li2); + ASSERT_NE(li1, li3); + ASSERT_NE(li1, li4); + ASSERT_NE(li1, li5); + + ASSERT_EQ(li2, li1); + ASSERT_NE(li3, li1); + ASSERT_NE(li4, li1); + ASSERT_NE(li5, li1); +} diff --git a/test/unit_tests/loops/loop_manager/test_loop_manager.cpp b/test/unit_tests/loops/loop_manager/test_loop_manager.cpp new file mode 100644 index 000000000..3dee98170 --- /dev/null +++ b/test/unit_tests/loops/loop_manager/test_loop_manager.cpp @@ -0,0 +1,299 @@ +#include + +#include "../../../../rtlib/loop/LoopManager.hpp" + +// Tests for old version (i.e., capturing functionality) + +class LoopManagerTest : public ::testing::Test { }; + +TEST_F(LoopManagerTest, testInitialization) { + auto lm = __dp::LoopManager(); + ASSERT_TRUE(lm.empty()); + + for (auto i = 0; i < 10; i++) { + for (auto j = 1; j < 1024; j *= 2) { + ASSERT_NO_THROW(lm.clean_function_exit(i, j)); + } + } + + for (auto i = 0; i < 100; i++) { + ASSERT_TRUE(lm.is_new_loop(i)); + } + + for (auto i = 0; i < 100; i++) { + ASSERT_TRUE(lm.is_single_exit(i)); + } + + const auto lid = (LID)0; + ASSERT_EQ(lm.update_lid(lid), 0xFF00000000000000LL); +} + +TEST_F(LoopManagerTest, testCreateNewLoop) { + auto lm = __dp::LoopManager(); + + const auto& table = lm.get_stack(); + const auto& loops = lm.get_loops(); + + lm.create_new_loop(1, 3, 0); + lm.create_new_loop(2, 2, 1); + lm.create_new_loop(1, 3, 0); + + ASSERT_EQ(table.size(), 3); + ASSERT_EQ(loops.size(), 2); + + ASSERT_FALSE(lm.empty()); +} + +TEST_F(LoopManagerTest, testIsNewLoop) { + auto lm = __dp::LoopManager(); + + lm.create_new_loop(1, 3, 0); + lm.create_new_loop(2, 2, 1); + lm.create_new_loop(1, 3, 0); + + ASSERT_TRUE(lm.is_new_loop(1)); + ASSERT_TRUE(lm.is_new_loop(2)); + ASSERT_FALSE(lm.is_new_loop(3)); +} + +TEST_F(LoopManagerTest, testIterateLoop) { + auto lm = __dp::LoopManager(); + + const auto& table = lm.get_stack(); + const auto& loops = lm.get_loops(); + + lm.create_new_loop(1, 3, 0); + lm.create_new_loop(2, 2, 1); + lm.create_new_loop(1, 3, 0); + + lm.iterate_loop(1); + lm.iterate_loop(2); + lm.iterate_loop(1); + + ASSERT_EQ(table.size(), 3); + ASSERT_EQ(loops.size(), 2); + + ASSERT_EQ(table.top().get_count(), 3); + ASSERT_EQ(table.topMinusN(1).get_count(), 0); + ASSERT_EQ(table.topMinusN(2).get_count(), 0); +} + +TEST_F(LoopManagerTest, testCleanFunctionExit) { + auto lm = __dp::LoopManager(); + + const auto& table = lm.get_stack(); + const auto& loops = lm.get_loops(); + + lm.create_new_loop(1, 3, 0); + lm.create_new_loop(2, 2, 1); + lm.create_new_loop(1, 3, 0); + + lm.clean_function_exit(0, 0); + + ASSERT_EQ(table.size(), 3); + ASSERT_EQ(loops.size(), 2); + + lm.clean_function_exit(2, 0); + + ASSERT_EQ(table.size(), 3); + ASSERT_EQ(loops.size(), 2); + + lm.clean_function_exit(1, 12); + + ASSERT_EQ(table.size(), 2); + ASSERT_EQ(loops.size(), 2); + + const auto it = loops.find(0); + ASSERT_NE(it, loops.end()); + + const auto loop = it->second; + + ASSERT_EQ(loop->end, 12); + ASSERT_EQ(loop->maxIterationCount, 0); + ASSERT_EQ(loop->nEntered, 1); + ASSERT_EQ(loop->total, 0); +} + +TEST_F(LoopManagerTest, testUpdateLid) { + auto lm = __dp::LoopManager(); + + const auto& table = lm.get_stack(); + const auto& loops = lm.get_loops(); + + lm.create_new_loop(1, 2, 0); + lm.create_new_loop(4, 5, 0); + lm.create_new_loop(7, 8, 0); + lm.create_new_loop(10, 11, 0); + lm.create_new_loop(13, 14, 0); + + const auto lid_1 = 0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_2 = 0b1111'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_3 = 0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto lid_4 = 0b0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto lid_5 = 0b1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + const auto expected_lid_1 = table.update_lid(lid_1); + const auto expected_lid_2 = table.update_lid(lid_2); + const auto expected_lid_3 = table.update_lid(lid_3); + const auto expected_lid_4 = table.update_lid(lid_4); + const auto expected_lid_5 = table.update_lid(lid_5); + const auto expected_lid_6 = table.update_lid(lid_6); + const auto expected_lid_7 = table.update_lid(lid_7); + const auto expected_lid_8 = table.update_lid(lid_8); + + ASSERT_EQ(expected_lid_1, lm.update_lid(lid_1)); + ASSERT_EQ(expected_lid_2, lm.update_lid(lid_2)); + ASSERT_EQ(expected_lid_3, lm.update_lid(lid_3)); + ASSERT_EQ(expected_lid_4, lm.update_lid(lid_4)); + ASSERT_EQ(expected_lid_5, lm.update_lid(lid_5)); + ASSERT_EQ(expected_lid_6, lm.update_lid(lid_6)); + ASSERT_EQ(expected_lid_7, lm.update_lid(lid_7)); + ASSERT_EQ(expected_lid_8, lm.update_lid(lid_8)); +} + +TEST_F(LoopManagerTest, testExitLoop) { + auto lm = __dp::LoopManager(); + + const auto& table = lm.get_stack(); + const auto& loops = lm.get_loops(); + + lm.create_new_loop(1, 2, 3); + lm.create_new_loop(4, 5, 6); + lm.create_new_loop(7, 8, 9); + lm.create_new_loop(10, 11, 12); + lm.create_new_loop(13, 14, 15); + + lm.iterate_loop(1); + lm.iterate_loop(4); + lm.iterate_loop(7); + lm.iterate_loop(10); + lm.iterate_loop(13); + + lm.exit_loop(15); + lm.exit_loop(12); + lm.exit_loop(9); + + ASSERT_EQ(table.size(), 2); + ASSERT_EQ(loops.size(), 5); + + const auto loop_3 = *loops.find(3)->second; + const auto loop_6 = *loops.find(6)->second; + const auto loop_9 = *loops.find(9)->second; + const auto loop_12 = *loops.find(12)->second; + const auto loop_15 = *loops.find(15)->second; + + ASSERT_EQ(loop_3.end, 0); + ASSERT_EQ(loop_6.end, 0); + ASSERT_EQ(loop_9.end, 9); + ASSERT_EQ(loop_12.end, 12); + ASSERT_EQ(loop_15.end, 15); + + ASSERT_EQ(loop_3.maxIterationCount, 0); + ASSERT_EQ(loop_6.maxIterationCount, 0); + ASSERT_EQ(loop_9.maxIterationCount, 0); + ASSERT_EQ(loop_12.maxIterationCount, 0); + ASSERT_EQ(loop_15.maxIterationCount, 5); + + ASSERT_EQ(loop_3.nEntered, 0); + ASSERT_EQ(loop_6.nEntered, 0); + ASSERT_EQ(loop_9.nEntered, 1); + ASSERT_EQ(loop_12.nEntered, 1); + ASSERT_EQ(loop_15.nEntered, 1); + + ASSERT_EQ(loop_3.total, 0); + ASSERT_EQ(loop_6.total, 0); + ASSERT_EQ(loop_9.total, 0); + ASSERT_EQ(loop_12.total, 0); + ASSERT_EQ(loop_15.total, 5); +} + +TEST_F(LoopManagerTest, testIsSingleExit) { + auto lm = __dp::LoopManager(); + + const auto& table = lm.get_stack(); + const auto& loops = lm.get_loops(); + + lm.create_new_loop(1, 2, 3); + lm.create_new_loop(4, 5, 6); + lm.create_new_loop(7, 8, 9); + lm.create_new_loop(10, 11, 12); + lm.create_new_loop(13, 14, 15); + + lm.iterate_loop(1); + lm.iterate_loop(4); + lm.iterate_loop(7); + lm.iterate_loop(10); + lm.iterate_loop(13); + + ASSERT_FALSE(lm.empty()); + + for (auto i = 0; i < 20; i++) { + ASSERT_EQ(table.is_single_exit(i), lm.is_single_exit(i)); + } + + lm.exit_loop(15); + ASSERT_FALSE(lm.empty()); + + lm.exit_loop(12); + ASSERT_FALSE(lm.empty()); + + lm.exit_loop(9); + ASSERT_FALSE(lm.empty()); + + for (auto i = 0; i < 20; i++) { + ASSERT_EQ(table.is_single_exit(i), lm.is_single_exit(i)); + } + + lm.exit_loop(3); + ASSERT_FALSE(lm.empty()); + + for (auto i = 0; i < 20; i++) { + ASSERT_EQ(table.is_single_exit(i), lm.is_single_exit(i)); + } +} + +TEST_F(LoopManagerTest, testCorrectFuncLevel) { + auto lm = __dp::LoopManager(); + + const auto& table = lm.get_stack(); + const auto& loops = lm.get_loops(); + + lm.create_new_loop(1, 2, 3); + lm.create_new_loop(4, 5, 6); + lm.create_new_loop(7, 8, 9); + lm.create_new_loop(10, 11, 12); + lm.create_new_loop(13, 14, 15); + + lm.iterate_loop(1); + lm.iterate_loop(4); + lm.iterate_loop(7); + lm.iterate_loop(10); + lm.iterate_loop(13); + + lm.correct_func_level(103); + + const auto& loop_3 = table.topMinusN(4); + const auto& loop_6 = table.topMinusN(3); + const auto& loop_9 = table.topMinusN(2); + const auto& loop_12 = table.topMinusN(1); + const auto& loop_15 = table.topMinusN(0); + + ASSERT_EQ(loop_3.funcLevel, 1); + ASSERT_EQ(loop_6.funcLevel, 4); + ASSERT_EQ(loop_9.funcLevel, 7); + ASSERT_EQ(loop_12.funcLevel, 10); + ASSERT_EQ(loop_15.funcLevel, 103); + + lm.exit_loop(15); + + lm.correct_func_level(104); + + ASSERT_EQ(loop_3.funcLevel, 1); + ASSERT_EQ(loop_6.funcLevel, 4); + ASSERT_EQ(loop_9.funcLevel, 7); + ASSERT_EQ(loop_12.funcLevel, 104); + ASSERT_EQ(loop_15.funcLevel, 103); +} diff --git a/test/unit_tests/loops/loop_record/test_loop_record.cpp b/test/unit_tests/loops/loop_record/test_loop_record.cpp new file mode 100644 index 000000000..962ffc078 --- /dev/null +++ b/test/unit_tests/loops/loop_record/test_loop_record.cpp @@ -0,0 +1,63 @@ +#include + +#include "../../../../rtlib/loop/LoopRecord.hpp" + +// Tests for old version (i.e., capturing functionality) + +class LoopRecordTest : public ::testing::Test { }; + +TEST_F(LoopRecordTest, testInitialization) { + const auto lr = __dp::LoopRecord{1, 2, 3}; + + ASSERT_EQ(lr.end, 1); + ASSERT_EQ(lr.total, 2); + ASSERT_EQ(lr.nEntered, 3); + ASSERT_EQ(lr.maxIterationCount, 0); +} + +TEST_F(LoopRecordTest, testNegativeInitialization) { + const auto lr = __dp::LoopRecord{-1, -2, -3}; + + ASSERT_EQ(lr.end, -1); + ASSERT_EQ(lr.total, -2); + ASSERT_EQ(lr.nEntered, -3); + ASSERT_EQ(lr.maxIterationCount, 0); +} + +TEST_F(LoopRecordTest, testLongInitialization) { + const auto lr = __dp::LoopRecord{4'000'000'000LL, 1'000'000'000LL, 2'000'000'000LL}; + + ASSERT_EQ(lr.end, 4'000'000'000LL); + ASSERT_EQ(lr.total, 1'000'000'000LL); + ASSERT_EQ(lr.nEntered, 2'000'000'000LL); + ASSERT_EQ(lr.maxIterationCount, 0); +} + +TEST_F(LoopRecordTest, testLongNegativeInitialization) { + const auto lr = __dp::LoopRecord{-4'000'000'000LL, -1'000'000'000LL, -2'000'000'000LL}; + + ASSERT_EQ(lr.end, -4'000'000'000LL); + ASSERT_EQ(lr.total, -1'000'000'000LL); + ASSERT_EQ(lr.nEntered, -2'000'000'000LL); + ASSERT_EQ(lr.maxIterationCount, 0); +} + +TEST_F(LoopRecordTest, testEquality) { + const auto lr1 = __dp::LoopRecord{1, 2, 3}; + const auto lr2 = __dp::LoopRecord{1, 2, 3}; + const auto lr3 = __dp::LoopRecord{1, 2, 4}; + const auto lr4 = __dp::LoopRecord{1, 3, 3}; + const auto lr5 = __dp::LoopRecord{2, 2, 3}; + + ASSERT_EQ(lr1, lr1); + + ASSERT_EQ(lr1, lr2); + ASSERT_NE(lr1, lr3); + ASSERT_NE(lr1, lr4); + ASSERT_NE(lr1, lr5); + + ASSERT_EQ(lr2, lr1); + ASSERT_NE(lr3, lr1); + ASSERT_NE(lr4, lr1); + ASSERT_NE(lr5, lr1); +} diff --git a/test/unit_tests/loops/loop_table/test_loop_table.cpp b/test/unit_tests/loops/loop_table/test_loop_table.cpp new file mode 100644 index 000000000..ad7693f45 --- /dev/null +++ b/test/unit_tests/loops/loop_table/test_loop_table.cpp @@ -0,0 +1,445 @@ +#include + +#include "../../../../rtlib/loop/LoopTable.hpp" + +// Tests for old version (i.e., capturing functionality) + +class LoopTableTest : public ::testing::Test { }; + +TEST_F(LoopTableTest, testInitialization) { + const auto lt = __dp::LoopTable{}; + + ASSERT_EQ(lt.size(), 0); + ASSERT_TRUE(lt.empty()); + + for (auto lid = 0; lid < 10; ++lid) { + ASSERT_TRUE(lt.is_single_exit(lid)); + } + + ASSERT_NO_THROW(lt.debug_output()); +} + +TEST_F(LoopTableTest, testPushBack) { + auto lt = __dp::LoopTable{}; + + lt.push(__dp::LoopTableEntry{1, 2, 3, 0}); + ASSERT_EQ(lt.size(), 1); + ASSERT_FALSE(lt.empty()); + for (auto lid = 0; lid < 10 && lid != 2; ++lid) { + ASSERT_TRUE(lt.is_single_exit(lid)); + } + ASSERT_FALSE(lt.is_single_exit(2)); + + lt.push(__dp::LoopTableEntry{4, 5, 6, 0}); + ASSERT_EQ(lt.size(), 2); + ASSERT_FALSE(lt.empty()); + for (auto lid = 0; lid < 10 && lid != 5; ++lid) { + ASSERT_TRUE(lt.is_single_exit(lid)); + } + ASSERT_FALSE(lt.is_single_exit(5)); + + ASSERT_NO_THROW(lt.debug_output()); +} + +TEST_F(LoopTableTest, testGetters) { + auto lt = __dp::LoopTable{}; + + const auto first_entry = __dp::LoopTableEntry{1, 2, 3, 0}; + const auto second_entry = __dp::LoopTableEntry{4, 5, 6, 0}; + + lt.push(first_entry); + lt.push(second_entry); + + ASSERT_NO_THROW(lt.debug_output()); + + const auto top_entry_from_lt = lt.top(); + ASSERT_EQ(top_entry_from_lt, second_entry); + + const auto first_entry_from_lt = lt.first(); + ASSERT_EQ(first_entry_from_lt, first_entry); + + const auto top_minus_0_entry_from_lt = lt.topMinusN(0); + ASSERT_EQ(top_minus_0_entry_from_lt, second_entry); + + const auto top_minus_1_entry_from_lt = lt.topMinusN(1); + ASSERT_EQ(top_minus_1_entry_from_lt, first_entry); + + ASSERT_EQ(lt.size(), 2); + ASSERT_FALSE(lt.empty()); + + lt.pop(); + + const auto top_entry_from_lt_after_pop = lt.top(); + ASSERT_EQ(top_entry_from_lt_after_pop, first_entry); + + const auto first_entry_from_lt_after_pop = lt.first(); + ASSERT_EQ(first_entry_from_lt_after_pop, first_entry); + + const auto top_minus_0_entry_from_lt_after_pop = lt.topMinusN(0); + ASSERT_EQ(top_minus_0_entry_from_lt_after_pop, first_entry); + + ASSERT_EQ(lt.size(), 1); + ASSERT_FALSE(lt.empty()); + + ASSERT_NO_THROW(lt.debug_output()); + + lt.pop(); + + ASSERT_EQ(lt.size(), 0); + ASSERT_TRUE(lt.empty()); +} + +TEST_F(LoopTableTest, testCorrectFunctionLevel) { + auto lt = __dp::LoopTable{}; + + const auto first_entry = __dp::LoopTableEntry{1, 2, 3, 0}; + const auto second_entry = __dp::LoopTableEntry{4, 5, 6, 0}; + + lt.push(first_entry); + lt.push(second_entry); + + lt.correct_func_level(7); + + const auto top_entry_from_lt = lt.top(); + ASSERT_EQ(top_entry_from_lt, __dp::LoopTableEntry(7, 5, 6, 0)); + + lt.pop(); + + const auto top_entry_from_lt_after_pop = lt.top(); + ASSERT_EQ(top_entry_from_lt_after_pop, first_entry); + + lt.pop(); + + ASSERT_TRUE(lt.empty()); + + lt.push(first_entry); + lt.push(second_entry); + + lt.correct_func_level(4); + + const auto top_entry_from_lt_2 = lt.top(); + ASSERT_EQ(top_entry_from_lt_2, second_entry); + + lt.pop(); + + const auto top_entry_from_lt_after_pop_2 = lt.top(); + ASSERT_EQ(top_entry_from_lt_after_pop_2, first_entry); + + lt.pop(); + + ASSERT_TRUE(lt.empty()); +} + +TEST_F(LoopTableTest, testIncrementTopCount) { + auto lt = __dp::LoopTable{}; + + const auto first_entry = __dp::LoopTableEntry{1, 2, 3, 0}; + const auto second_entry = __dp::LoopTableEntry{4, 5, 6, 0}; + + lt.push(first_entry); + lt.push(second_entry); + + lt.increment_top_count(); + + const auto top_entry_from_lt = lt.top(); + ASSERT_EQ(top_entry_from_lt, __dp::LoopTableEntry(4, 5, 7, 0)); + + lt.pop(); + + const auto top_entry_from_lt_after_pop = lt.top(); + ASSERT_EQ(top_entry_from_lt_after_pop, first_entry); + + lt.pop(); + + ASSERT_TRUE(lt.empty()); + + lt.push(first_entry); + lt.push(second_entry); + + const auto top_entry_from_lt_2 = lt.top(); + ASSERT_EQ(top_entry_from_lt_2, second_entry); + + lt.pop(); + + lt.increment_top_count(); + + const auto top_entry_from_lt_after_pop_2 = lt.top(); + ASSERT_EQ(top_entry_from_lt_after_pop_2, __dp::LoopTableEntry(1, 2, 4, 0)); + + lt.pop(); + + ASSERT_TRUE(lt.empty()); +} + +TEST_F(LoopTableTest, testUpdateLidSize0) { + auto lt = __dp::LoopTable{}; + + const auto lid_1 = 0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_2 = 0b1111'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_3 = 0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto lid_4 = 0b0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto lid_5 = 0b1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + const auto expected_lid_1 = 0b1111'1111'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto expected_lid_2 = 0b1111'1111'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto expected_lid_3 = 0b1111'1111'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto expected_lid_4 = 0b1111'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto expected_lid_5 = 0b1111'1111'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto expected_lid_6 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto expected_lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto expected_lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + ASSERT_EQ(expected_lid_1, lt.update_lid(lid_1)); + ASSERT_EQ(expected_lid_2, lt.update_lid(lid_2)); + ASSERT_EQ(expected_lid_3, lt.update_lid(lid_3)); + ASSERT_EQ(expected_lid_4, lt.update_lid(lid_4)); + ASSERT_EQ(expected_lid_5, lt.update_lid(lid_5)); + ASSERT_EQ(expected_lid_6, lt.update_lid(lid_6)); + ASSERT_EQ(expected_lid_7, lt.update_lid(lid_7)); + ASSERT_EQ(expected_lid_8, lt.update_lid(lid_8)); +} + +TEST_F(LoopTableTest, testUpdateLidSize1) { + auto lt = __dp::LoopTable{}; + + const auto first_entry = __dp::LoopTableEntry{1, 2, 3, 0}; + + lt.push(first_entry); + + const auto lid_1 = 0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_2 = 0b1111'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_3 = 0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto lid_4 = 0b0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto lid_5 = 0b1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + const auto expected_lid_1 = 0b0000'0010'1000'0011'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto expected_lid_2 = 0b1111'0010'1000'0011'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto expected_lid_3 = 0b0000'0010'1000'0011'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto expected_lid_4 = 0b0000'1111'1000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto expected_lid_5 = 0b1111'0010'1111'0011'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto expected_lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto expected_lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto expected_lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + ASSERT_EQ(expected_lid_1, lt.update_lid(lid_1)); + ASSERT_EQ(expected_lid_2, lt.update_lid(lid_2)); + ASSERT_EQ(expected_lid_3, lt.update_lid(lid_3)); + ASSERT_EQ(expected_lid_4, lt.update_lid(lid_4)); + ASSERT_EQ(expected_lid_5, lt.update_lid(lid_5)); + ASSERT_EQ(expected_lid_6, lt.update_lid(lid_6)); + ASSERT_EQ(expected_lid_7, lt.update_lid(lid_7)); + ASSERT_EQ(expected_lid_8, lt.update_lid(lid_8)); +} + +TEST_F(LoopTableTest, testUpdateLidSize2) { + auto lt = __dp::LoopTable{}; + + const auto first_entry = __dp::LoopTableEntry{1, 2, 3, 0}; + const auto second_entry = __dp::LoopTableEntry{4, 5, 6, 0}; + + lt.push(first_entry); + lt.push(second_entry); + + const auto lid_1 = 0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_2 = 0b1111'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_3 = 0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto lid_4 = 0b0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto lid_5 = 0b1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + const auto expected_lid_1 = 0b0000'0010'1000'0110'1000'0011'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto expected_lid_2 = 0b1111'0010'1000'0110'1000'0011'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto expected_lid_3 = 0b0000'0010'1000'0110'1000'0011'0000'0000'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto expected_lid_4 = 0b0000'1111'1000'1111'1000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto expected_lid_5 = 0b1111'0010'1111'0110'1111'0011'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto expected_lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto expected_lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto expected_lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + ASSERT_EQ(expected_lid_1, lt.update_lid(lid_1)); + ASSERT_EQ(expected_lid_2, lt.update_lid(lid_2)); + ASSERT_EQ(expected_lid_3, lt.update_lid(lid_3)); + ASSERT_EQ(expected_lid_4, lt.update_lid(lid_4)); + ASSERT_EQ(expected_lid_5, lt.update_lid(lid_5)); + ASSERT_EQ(expected_lid_6, lt.update_lid(lid_6)); + ASSERT_EQ(expected_lid_7, lt.update_lid(lid_7)); + ASSERT_EQ(expected_lid_8, lt.update_lid(lid_8)); +} + +TEST_F(LoopTableTest, testUpdateLidSize3) { + auto lt = __dp::LoopTable{}; + + const auto first_entry = __dp::LoopTableEntry{1, 2, 3, 0}; + const auto second_entry = __dp::LoopTableEntry{4, 5, 6, 0}; + const auto third_entry = __dp::LoopTableEntry{7, 8, 9, 0}; + + lt.push(first_entry); + lt.push(second_entry); + lt.push(third_entry); + + const auto lid_1 = 0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_2 = 0b1111'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_3 = 0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto lid_4 = 0b0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto lid_5 = 0b1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + const auto expected_lid_1 = 0b0000'0010'1000'1001'1000'0110'1000'0011'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto expected_lid_2 = 0b1111'0010'1000'1001'1000'0110'1000'0011'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto expected_lid_3 = 0b0000'0010'1000'1001'1000'0110'1000'0011'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto expected_lid_4 = 0b0000'1111'1000'1111'1000'1111'1000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto expected_lid_5 = 0b1111'0010'1111'1001'1111'0110'1111'0011'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto expected_lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto expected_lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto expected_lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + ASSERT_EQ(expected_lid_1, lt.update_lid(lid_1)); + ASSERT_EQ(expected_lid_2, lt.update_lid(lid_2)); + ASSERT_EQ(expected_lid_3, lt.update_lid(lid_3)); + ASSERT_EQ(expected_lid_4, lt.update_lid(lid_4)); + ASSERT_EQ(expected_lid_5, lt.update_lid(lid_5)); + ASSERT_EQ(expected_lid_6, lt.update_lid(lid_6)); + ASSERT_EQ(expected_lid_7, lt.update_lid(lid_7)); + ASSERT_EQ(expected_lid_8, lt.update_lid(lid_8)); +} + +TEST_F(LoopTableTest, testUpdateLidSize4) { + auto lt = __dp::LoopTable{}; + + const auto first_entry = __dp::LoopTableEntry{1, 2, 3, 0}; + const auto second_entry = __dp::LoopTableEntry{4, 5, 6, 0}; + const auto third_entry = __dp::LoopTableEntry{7, 8, 9, 0}; + const auto fourth_entry = __dp::LoopTableEntry{10, 11, 12, 0}; + + lt.push(first_entry); + lt.push(second_entry); + lt.push(third_entry); + lt.push(fourth_entry); + + const auto lid_1 = 0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_2 = 0b1111'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_3 = 0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto lid_4 = 0b0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto lid_5 = 0b1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + const auto expected_lid_1 = 0b0000'0010'1000'1100'1000'1001'1000'0110'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto expected_lid_2 = 0b1111'0010'1000'1100'1000'1001'1000'0110'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto expected_lid_3 = 0b0000'0010'1000'1100'1000'1001'1000'0110'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto expected_lid_4 = 0b0000'1111'1000'1111'1000'1111'1000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto expected_lid_5 = 0b1111'0010'1111'1100'1111'1001'1111'0110'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto expected_lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto expected_lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto expected_lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + ASSERT_EQ(expected_lid_1, lt.update_lid(lid_1)); + ASSERT_EQ(expected_lid_2, lt.update_lid(lid_2)); + ASSERT_EQ(expected_lid_3, lt.update_lid(lid_3)); + ASSERT_EQ(expected_lid_4, lt.update_lid(lid_4)); + ASSERT_EQ(expected_lid_5, lt.update_lid(lid_5)); + ASSERT_EQ(expected_lid_6, lt.update_lid(lid_6)); + ASSERT_EQ(expected_lid_7, lt.update_lid(lid_7)); + ASSERT_EQ(expected_lid_8, lt.update_lid(lid_8)); +} + +TEST_F(LoopTableTest, testUpdateLidSize5) { + auto lt = __dp::LoopTable{}; + + const auto first_entry = __dp::LoopTableEntry{1, 2, 3, 0}; + const auto second_entry = __dp::LoopTableEntry{4, 5, 6, 0}; + const auto third_entry = __dp::LoopTableEntry{7, 8, 9, 0}; + const auto fourth_entry = __dp::LoopTableEntry{10, 11, 12, 0}; + const auto fifth_entry = __dp::LoopTableEntry{13, 14, 15, 0}; + + lt.push(first_entry); + lt.push(second_entry); + lt.push(third_entry); + lt.push(fourth_entry); + lt.push(fifth_entry); + + const auto lid_1 = 0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_2 = 0b1111'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_3 = 0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto lid_4 = 0b0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto lid_5 = 0b1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + const auto expected_lid_1 = 0b0000'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto expected_lid_2 = 0b1111'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto expected_lid_3 = 0b0000'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto expected_lid_4 = 0b0000'1111'1000'1111'1000'1111'1000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto expected_lid_5 = 0b1111'0010'1111'1111'1111'1100'1111'1001'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto expected_lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto expected_lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto expected_lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + ASSERT_EQ(expected_lid_1, lt.update_lid(lid_1)); + ASSERT_EQ(expected_lid_2, lt.update_lid(lid_2)); + ASSERT_EQ(expected_lid_3, lt.update_lid(lid_3)); + ASSERT_EQ(expected_lid_4, lt.update_lid(lid_4)); + ASSERT_EQ(expected_lid_5, lt.update_lid(lid_5)); + ASSERT_EQ(expected_lid_6, lt.update_lid(lid_6)); + ASSERT_EQ(expected_lid_7, lt.update_lid(lid_7)); + ASSERT_EQ(expected_lid_8, lt.update_lid(lid_8)); +} + + +TEST_F(LoopTableTest, testUpdateLidSize6) { + auto lt = __dp::LoopTable{}; + + const auto first_entry = __dp::LoopTableEntry{1, 2, 3, 0}; + const auto second_entry = __dp::LoopTableEntry{4, 5, 6, 0}; + const auto third_entry = __dp::LoopTableEntry{7, 8, 9, 0}; + const auto fourth_entry = __dp::LoopTableEntry{10, 11, 12, 0}; + const auto fifth_entry = __dp::LoopTableEntry{13, 14, 15, 0}; + const auto sixth_entry = __dp::LoopTableEntry{16, 17, 18, 0}; + + lt.push(first_entry); + lt.push(second_entry); + lt.push(third_entry); + lt.push(fourth_entry); + lt.push(fifth_entry); + lt.push(sixth_entry); + + const auto lid_1 = 0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_2 = 0b1111'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_3 = 0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto lid_4 = 0b0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto lid_5 = 0b1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + const auto expected_lid_1 = 0b0000'0010'1001'0010'1000'1111'1000'1100'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto expected_lid_2 = 0b1111'0010'1001'0010'1000'1111'1000'1100'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto expected_lid_3 = 0b0000'0010'1001'0010'1000'1111'1000'1100'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto expected_lid_4 = 0b0000'1111'1001'1111'1000'1111'1000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto expected_lid_5 = 0b1111'0010'1111'0010'1111'1111'1111'1100'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto expected_lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto expected_lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto expected_lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + ASSERT_EQ(expected_lid_1, lt.update_lid(lid_1)); + ASSERT_EQ(expected_lid_2, lt.update_lid(lid_2)); + ASSERT_EQ(expected_lid_3, lt.update_lid(lid_3)); + ASSERT_EQ(expected_lid_4, lt.update_lid(lid_4)); + ASSERT_EQ(expected_lid_5, lt.update_lid(lid_5)); + ASSERT_EQ(expected_lid_6, lt.update_lid(lid_6)); + ASSERT_EQ(expected_lid_7, lt.update_lid(lid_7)); + ASSERT_EQ(expected_lid_8, lt.update_lid(lid_8)); +} + diff --git a/test/unit_tests/loops/loop_table_entry/test_loop_table_entry.cpp b/test/unit_tests/loops/loop_table_entry/test_loop_table_entry.cpp new file mode 100644 index 000000000..b047ba5d0 --- /dev/null +++ b/test/unit_tests/loops/loop_table_entry/test_loop_table_entry.cpp @@ -0,0 +1,66 @@ +#include + +#include "../../../../rtlib/loop/LoopTableEntry.hpp" + +// Tests for old version (i.e., capturing functionality) + +class LoopTableEntryTest : public ::testing::Test { }; + +TEST_F(LoopTableEntryTest, testInitialization) { + const auto lte = __dp::LoopTableEntry{1, 2, 3, 4}; + + ASSERT_EQ(lte.funcLevel, 1); + ASSERT_EQ(lte.loopID, 2); + ASSERT_EQ(lte.get_count(), 3); + ASSERT_EQ(lte.begin, 4); +} + +TEST_F(LoopTableEntryTest, testNegativeInitialization) { + const auto lte = __dp::LoopTableEntry{-1, -2, -3, -4}; + + ASSERT_EQ(lte.funcLevel, -1); + ASSERT_EQ(lte.loopID, -2); + ASSERT_EQ(lte.get_count(), -3); + ASSERT_EQ(lte.begin, -4); +} + +TEST_F(LoopTableEntryTest, testLongInitialization) { + const auto lte = __dp::LoopTableEntry{1'000'000'000, 1'500'000'000, 2'000'000'000, 4'000'000'000LL}; + + ASSERT_EQ(lte.funcLevel, 1'000'000'000); + ASSERT_EQ(lte.loopID, 1'500'000'000); + ASSERT_EQ(lte.get_count(), 2'000'000'000); + ASSERT_EQ(lte.begin, 4'000'000'000LL); +} + +TEST_F(LoopTableEntryTest, testNegativeLongInitialization) { + const auto lte = __dp::LoopTableEntry{-1'000'000'000, -1'500'000'000, -2'000'000'000, -4'000'000'000LL}; + + ASSERT_EQ(lte.funcLevel, -1'000'000'000); + ASSERT_EQ(lte.loopID, -1'500'000'000); + ASSERT_EQ(lte.get_count(), -2'000'000'000); + ASSERT_EQ(lte.begin, -4'000'000'000LL); +} + +TEST_F(LoopTableEntryTest, testEquality) { + const auto lte1 = __dp::LoopTableEntry{1, 2, 3, 4}; + const auto lte2 = __dp::LoopTableEntry{1, 2, 3, 4}; + const auto lte3 = __dp::LoopTableEntry{1, 2, 3, 5}; + const auto lte4 = __dp::LoopTableEntry{1, 2, 4, 4}; + const auto lte5 = __dp::LoopTableEntry{1, 3, 3, 4}; + const auto lte6 = __dp::LoopTableEntry{2, 2, 3, 4}; + + ASSERT_EQ(lte1, lte1); + + ASSERT_EQ(lte1, lte2); + ASSERT_NE(lte1, lte3); + ASSERT_NE(lte1, lte4); + ASSERT_NE(lte1, lte5); + ASSERT_NE(lte1, lte6); + + ASSERT_EQ(lte2, lte1); + ASSERT_NE(lte3, lte1); + ASSERT_NE(lte4, lte1); + ASSERT_NE(lte5, lte1); + ASSERT_NE(lte6, lte1); +} diff --git a/test/unit_tests/loops/makros/test_makros.cpp b/test/unit_tests/loops/makros/test_makros.cpp new file mode 100644 index 000000000..163096e15 --- /dev/null +++ b/test/unit_tests/loops/makros/test_makros.cpp @@ -0,0 +1,210 @@ +#include + +#include "../../../../rtlib/loop/Makros.hpp" + +// Tests for old version (i.e., capturing functionality) + +class MakrosTest : public ::testing::Test { }; + +TEST_F(MakrosTest, testGetLoopId) { + const auto lid_1 = 0b0000'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_2 = 0b1111'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_3 = 0b0000'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto lid_4 = 0b0000'1111'1000'1111'1000'1111'1000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto lid_5 = 0b1111'0010'1111'1111'1111'1100'1111'1001'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + const auto expected_lid_1 = 0b0000'0010LL; + const auto expected_lid_2 = 0b1111'0010LL; + const auto expected_lid_3 = 0b0000'0010LL; + const auto expected_lid_4 = 0b0000'1111LL; + const auto expected_lid_5 = 0b1111'0010LL; + const auto expected_lid_6 = 0b0000'1111LL; + const auto expected_lid_7 = 0b1111'1111LL; + const auto expected_lid_8 = 0b1111'1111LL; + + ASSERT_EQ(unpackLIDMetadata_getLoopID(lid_1), expected_lid_1); + ASSERT_EQ(unpackLIDMetadata_getLoopID(lid_2), expected_lid_2); + ASSERT_EQ(unpackLIDMetadata_getLoopID(lid_3), expected_lid_3); + ASSERT_EQ(unpackLIDMetadata_getLoopID(lid_4), expected_lid_4); + ASSERT_EQ(unpackLIDMetadata_getLoopID(lid_5), expected_lid_5); + ASSERT_EQ(unpackLIDMetadata_getLoopID(lid_6), expected_lid_6); + ASSERT_EQ(unpackLIDMetadata_getLoopID(lid_7), expected_lid_7); + ASSERT_EQ(unpackLIDMetadata_getLoopID(lid_8), expected_lid_8); +} + +TEST_F(MakrosTest, testGetLoopIteration0) { + const auto lid_1 = 0b0000'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_2 = 0b1111'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_3 = 0b0000'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto lid_4 = 0b0000'1111'1000'1111'1000'1111'1000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto lid_5 = 0b1111'0010'1111'1111'1111'1100'1111'1001'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + const auto expected_lid_1 = 0b0000'1111LL; + const auto expected_lid_2 = 0b0000'1111LL; + const auto expected_lid_3 = 0b0000'1111LL; + const auto expected_lid_4 = 0b0000'1111LL; + const auto expected_lid_5 = 0b0111'1111LL; + const auto expected_lid_6 = 0b0111'1111LL; + const auto expected_lid_7 = 0b0111'1111LL; + const auto expected_lid_8 = 0b0111'1111LL; + + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_0(lid_1), expected_lid_1); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_0(lid_2), expected_lid_2); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_0(lid_3), expected_lid_3); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_0(lid_4), expected_lid_4); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_0(lid_5), expected_lid_5); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_0(lid_6), expected_lid_6); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_0(lid_7), expected_lid_7); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_0(lid_8), expected_lid_8); +} + +TEST_F(MakrosTest, testGetLoopIteration1) { + const auto lid_1 = 0b0000'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_2 = 0b1111'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_3 = 0b0000'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto lid_4 = 0b0000'1111'1000'1111'1000'1111'1000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto lid_5 = 0b1111'0010'1111'1111'1111'1100'1111'1001'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + const auto expected_lid_1 = 0b0000'1100LL; + const auto expected_lid_2 = 0b0000'1100LL; + const auto expected_lid_3 = 0b0000'1100LL; + const auto expected_lid_4 = 0b0000'1111LL; + const auto expected_lid_5 = 0b0111'1100LL; + const auto expected_lid_6 = 0b0111'1111LL; + const auto expected_lid_7 = 0b0111'1111LL; + const auto expected_lid_8 = 0b0111'1111LL; + + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_1(lid_1), expected_lid_1); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_1(lid_2), expected_lid_2); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_1(lid_3), expected_lid_3); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_1(lid_4), expected_lid_4); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_1(lid_5), expected_lid_5); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_1(lid_6), expected_lid_6); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_1(lid_7), expected_lid_7); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_1(lid_8), expected_lid_8); +} + +TEST_F(MakrosTest, testGetLoopIteration2) { + const auto lid_1 = 0b0000'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_2 = 0b1111'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_3 = 0b0000'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto lid_4 = 0b0000'1111'1000'1111'1000'1111'1000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto lid_5 = 0b1111'0010'1111'1111'1111'1100'1111'1001'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + const auto expected_lid_1 = 0b0000'1001LL; + const auto expected_lid_2 = 0b0000'1001LL; + const auto expected_lid_3 = 0b0000'1001LL; + const auto expected_lid_4 = 0b0000'1111LL; + const auto expected_lid_5 = 0b0111'1001LL; + const auto expected_lid_6 = 0b0111'1111LL; + const auto expected_lid_7 = 0b0111'1111LL; + const auto expected_lid_8 = 0b0111'1111LL; + + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_2(lid_1), expected_lid_1); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_2(lid_2), expected_lid_2); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_2(lid_3), expected_lid_3); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_2(lid_4), expected_lid_4); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_2(lid_5), expected_lid_5); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_2(lid_6), expected_lid_6); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_2(lid_7), expected_lid_7); + ASSERT_EQ(unpackLIDMetadata_getLoopIteration_2(lid_8), expected_lid_8); +} + +TEST_F(MakrosTest, testValidity0) { + const auto lid_1 = 0b0000'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_2 = 0b1111'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_3 = 0b0000'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto lid_4 = 0b0000'1111'1000'1111'1000'1111'1000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto lid_5 = 0b1111'0010'1111'1111'1111'1100'1111'1001'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + const auto expected_lid_1 = 0b0000'0001LL; + const auto expected_lid_2 = 0b0000'0001LL; + const auto expected_lid_3 = 0b0000'0001LL; + const auto expected_lid_4 = 0b0000'0001LL; + const auto expected_lid_5 = 0b0000'0001LL; + const auto expected_lid_6 = 0b0000'0001LL; + const auto expected_lid_7 = 0b0000'0001LL; + const auto expected_lid_8 = 0b0000'0001LL; + + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_0(lid_1), expected_lid_1); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_0(lid_2), expected_lid_2); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_0(lid_3), expected_lid_3); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_0(lid_4), expected_lid_4); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_0(lid_5), expected_lid_5); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_0(lid_6), expected_lid_6); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_0(lid_7), expected_lid_7); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_0(lid_8), expected_lid_8); +} + +TEST_F(MakrosTest, testValidity1) { + const auto lid_1 = 0b0000'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_2 = 0b1111'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_3 = 0b0000'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto lid_4 = 0b0000'1111'1000'1111'1000'1111'1000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto lid_5 = 0b1111'0010'1111'1111'1111'1100'1111'1001'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + const auto expected_lid_1 = 0b0000'0001LL; + const auto expected_lid_2 = 0b0000'0001LL; + const auto expected_lid_3 = 0b0000'0001LL; + const auto expected_lid_4 = 0b0000'0001LL; + const auto expected_lid_5 = 0b0000'0001LL; + const auto expected_lid_6 = 0b0000'0001LL; + const auto expected_lid_7 = 0b0000'0001LL; + const auto expected_lid_8 = 0b0000'0001LL; + + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_0(lid_1), expected_lid_1); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_0(lid_2), expected_lid_2); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_0(lid_3), expected_lid_3); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_0(lid_4), expected_lid_4); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_0(lid_5), expected_lid_5); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_0(lid_6), expected_lid_6); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_0(lid_7), expected_lid_7); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_0(lid_8), expected_lid_8); +} + +TEST_F(MakrosTest, testValidity2) { + const auto lid_1 = 0b0000'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_2 = 0b1111'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'0000LL; + const auto lid_3 = 0b0000'0010'1000'1111'1000'1100'1000'1001'0000'0000'0000'0000'0000'0000'0000'1111LL; + const auto lid_4 = 0b0000'1111'1000'1111'1000'1111'1000'1111'0000'1111'0000'1111'0000'1111'0000'1111LL; + const auto lid_5 = 0b1111'0010'1111'1111'1111'1100'1111'1001'1111'0000'1111'0000'1111'0000'1111'0000LL; + const auto lid_6 = 0b0000'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + const auto lid_7 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'0000LL; + const auto lid_8 = 0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111LL; + + const auto expected_lid_1 = 0b0000'0001LL; + const auto expected_lid_2 = 0b0000'0001LL; + const auto expected_lid_3 = 0b0000'0001LL; + const auto expected_lid_4 = 0b0000'0001LL; + const auto expected_lid_5 = 0b0000'0001LL; + const auto expected_lid_6 = 0b0000'0001LL; + const auto expected_lid_7 = 0b0000'0001LL; + const auto expected_lid_8 = 0b0000'0001LL; + + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_2(lid_1), expected_lid_1); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_2(lid_2), expected_lid_2); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_2(lid_3), expected_lid_3); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_2(lid_4), expected_lid_4); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_2(lid_5), expected_lid_5); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_2(lid_6), expected_lid_6); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_2(lid_7), expected_lid_7); + ASSERT_EQ(checkLIDMetadata_getLoopIterationValidity_2(lid_8), expected_lid_8); +} diff --git a/test/unit_tests/loops/var_counter/test_var_counter.cpp b/test/unit_tests/loops/var_counter/test_var_counter.cpp new file mode 100644 index 000000000..5fa72c816 --- /dev/null +++ b/test/unit_tests/loops/var_counter/test_var_counter.cpp @@ -0,0 +1,57 @@ +#include + +#include "../../../../rtlib/loop/VarCounter.hpp" + +// Tests for old version (i.e., capturing functionality) + +class VarCounterTest : public ::testing::Test { }; + +TEST_F(VarCounterTest, testZeroInitialization) { + const auto vc = __dp::VarCounter{}; + + ASSERT_EQ(vc.counters_[0], 0); + ASSERT_EQ(vc.counters_[1], 0); + ASSERT_EQ(vc.mem_addr_, 0); + ASSERT_TRUE(vc.valid_); +} + +TEST_F(VarCounterTest, testInitialization) { + const auto vc = __dp::VarCounter{1, 2, 3, false}; + + ASSERT_EQ(vc.counters_[0], 1); + ASSERT_EQ(vc.counters_[1], 2); + ASSERT_EQ(vc.mem_addr_, 3); + ASSERT_FALSE(vc.valid_); +} + +TEST_F(VarCounterTest, testNegativeInitialization) { + const auto vc = __dp::VarCounter{1, 2, -3, false}; + + ASSERT_EQ(vc.counters_[0], 1); + ASSERT_EQ(vc.counters_[1], 2); + ASSERT_EQ(vc.mem_addr_, -3); + ASSERT_FALSE(vc.valid_); +} + +TEST_F(VarCounterTest, testEquality) { + const auto vc1 = __dp::VarCounter{1, 2, 3, false}; + const auto vc2 = __dp::VarCounter{1, 2, 3, false}; + const auto vc3 = __dp::VarCounter{1, 2, 4, false}; + const auto vc4 = __dp::VarCounter{1, 3, 3, false}; + const auto vc5 = __dp::VarCounter{2, 2, 3, false}; + const auto vc6 = __dp::VarCounter{1, 2, 3, true}; + + ASSERT_EQ(vc1, vc1); + + ASSERT_EQ(vc1, vc2); + ASSERT_NE(vc1, vc3); + ASSERT_NE(vc1, vc4); + ASSERT_NE(vc1, vc5); + ASSERT_NE(vc1, vc6); + + ASSERT_EQ(vc2, vc1); + ASSERT_NE(vc3, vc1); + ASSERT_NE(vc4, vc1); + ASSERT_NE(vc5, vc1); + ASSERT_NE(vc6, vc1); +} diff --git a/test/unit_tests/loops/var_info/test_var_info.cpp b/test/unit_tests/loops/var_info/test_var_info.cpp new file mode 100644 index 000000000..05f42296a --- /dev/null +++ b/test/unit_tests/loops/var_info/test_var_info.cpp @@ -0,0 +1,72 @@ +#include + +#include "../../../../rtlib/loop/VarInfo.hpp" + +// Tests for old version (i.e., capturing functionality) + +class VarInfoTest : public ::testing::Test { }; + +TEST_F(VarInfoTest, testZeroInitialization) { + const auto vi = __dp::var_info_t{}; + + ASSERT_TRUE(vi.var_name_.empty()); + ASSERT_EQ(vi.file_id_, 0); + ASSERT_EQ(vi.instr_id_, 0); + ASSERT_EQ(vi.loop_line_nr_, 0); + ASSERT_EQ(vi.instr_line_, 0); + ASSERT_EQ(vi.operation_, 0); +} + +TEST_F(VarInfoTest, testInitialization) { + const auto vi = __dp::var_info_t{"var", 1, 2, 3, 4, 'a'}; + + ASSERT_EQ(vi.var_name_, "var"); + ASSERT_EQ(vi.file_id_, 1); + ASSERT_EQ(vi.instr_id_, 2); + ASSERT_EQ(vi.loop_line_nr_, 3); + ASSERT_EQ(vi.instr_line_, 4); + ASSERT_EQ(vi.operation_, 'a'); +} + +TEST_F(VarInfoTest, testNegativeInitialization) { + const auto vi = __dp::var_info_t{"negative", -1, -2, -3, -4, 'n'}; + + ASSERT_EQ(vi.var_name_, "negative"); + ASSERT_EQ(vi.file_id_, -1); + ASSERT_EQ(vi.instr_id_, -2); + ASSERT_EQ(vi.loop_line_nr_, -3); + ASSERT_EQ(vi.instr_line_, -4); + ASSERT_EQ(vi.operation_, 'n'); +} + +TEST_F(VarInfoTest, testEquality) { + const auto vi1 = __dp::var_info_t{"var", 1, 2, 3, 4, 'a'}; + const auto vi2 = __dp::var_info_t{"var", 1, 2, 3, 4, 'a'}; + const auto vi3 = __dp::var_info_t{"var", 1, 2, 3, 4, 'b'}; + const auto vi4 = __dp::var_info_t{"var", 1, 2, 3, 5, 'a'}; + const auto vi5 = __dp::var_info_t{"var", 1, 2, 4, 4, 'a'}; + const auto vi6 = __dp::var_info_t{"var", 1, 3, 3, 4, 'a'}; + const auto vi7 = __dp::var_info_t{"var", 2, 2, 3, 4, 'a'}; + const auto vi8 = __dp::var_info_t{"var", 1, 2, 3, 4, 'c'}; + const auto vi9 = __dp::var_info_t{"VAR", 1, 2, 3, 4, 'c'}; + + ASSERT_EQ(vi1, vi1); + + ASSERT_EQ(vi1, vi2); + ASSERT_NE(vi1, vi3); + ASSERT_NE(vi1, vi4); + ASSERT_NE(vi1, vi5); + ASSERT_NE(vi1, vi6); + ASSERT_NE(vi1, vi7); + ASSERT_NE(vi1, vi8); + ASSERT_NE(vi1, vi9); + + ASSERT_EQ(vi2, vi1); + ASSERT_NE(vi3, vi1); + ASSERT_NE(vi4, vi1); + ASSERT_NE(vi5, vi1); + ASSERT_NE(vi6, vi1); + ASSERT_NE(vi7, vi1); + ASSERT_NE(vi8, vi1); + ASSERT_NE(vi9, vi1); +} diff --git a/test/unit_tests/memory/memory_manager/test_memory_manager.cpp b/test/unit_tests/memory/memory_manager/test_memory_manager.cpp new file mode 100644 index 000000000..8aeec70b5 --- /dev/null +++ b/test/unit_tests/memory/memory_manager/test_memory_manager.cpp @@ -0,0 +1,1001 @@ +#include + +#include "../../../../rtlib/memory/MemoryManager.hpp" + +#include +#include + +// Tests for old version (i.e., capturing functionality) + +class MemoryManagerTest : public ::testing::Test { }; + +TEST_F(MemoryManagerTest, testConstructor) { + auto mm = __dp::MemoryManager{}; + + ASSERT_EQ(mm.get_smallest_allocated_addr(), std::numeric_limits::max()); + ASSERT_EQ(mm.get_largest_allocated_addr(), std::numeric_limits::min()); + + for (auto i = 1; i < 1024; i++) { + ASSERT_EQ(mm.get_next_free_memory_region_id(), i); + } + + ASSERT_EQ(mm.get_smallest_allocated_addr(), std::numeric_limits::max()); + ASSERT_EQ(mm.get_largest_allocated_addr(), std::numeric_limits::min()); +} + +TEST_F(MemoryManagerTest, testStack) { + auto mm = __dp::MemoryManager{}; + + mm.enter_new_function(); + mm.update_stack_addresses(0x1000, 0x2000); + mm.enter_new_function(); + mm.update_stack_addresses(0x3000, 0x4000); + mm.enter_new_function(); + mm.update_stack_addresses(0x5000, 0x6000); + + auto addr = mm.pop_last_stack_address(); + ASSERT_EQ(addr.first, 0x5000); + ASSERT_EQ(addr.second, 0x6000); + + addr = mm.pop_last_stack_address(); + ASSERT_EQ(addr.first, 0x3000); + ASSERT_EQ(addr.second, 0x4000); + + addr = mm.pop_last_stack_address(); + ASSERT_EQ(addr.first, 0x1000); + ASSERT_EQ(addr.second, 0x2000); +} + +TEST_F(MemoryManagerTest, testUpdateStackAddresses) { + auto mm = __dp::MemoryManager{}; + + mm.enter_new_function(); + mm.update_stack_addresses(0x2000, 0x3000); + mm.update_stack_addresses(0x1000, 0x4000); + + auto addr = mm.pop_last_stack_address(); + ASSERT_EQ(addr.first, 0x1000); + ASSERT_EQ(addr.second, 0x4000); +} + +TEST_F(MemoryManagerTest, testIsStackAccess) { + auto mm = __dp::MemoryManager{}; + + mm.enter_new_function(); + + ASSERT_FALSE(mm.is_stack_access(0x1000)); + ASSERT_FALSE(mm.is_stack_access(0x1500)); + ASSERT_FALSE(mm.is_stack_access(0x2000)); + ASSERT_FALSE(mm.is_stack_access(0x2500)); + ASSERT_FALSE(mm.is_stack_access(0x3000)); + ASSERT_FALSE(mm.is_stack_access(0x3500)); + ASSERT_FALSE(mm.is_stack_access(0x4000)); + ASSERT_FALSE(mm.is_stack_access(0x4500)); + ASSERT_FALSE(mm.is_stack_access(0x5000)); + ASSERT_FALSE(mm.is_stack_access(0x5500)); + ASSERT_FALSE(mm.is_stack_access(0x6000)); + ASSERT_FALSE(mm.is_stack_access(0x6500)); + + mm.update_stack_addresses(0x1000, 0x2000); + mm.enter_new_function(); + + ASSERT_FALSE(mm.is_stack_access(0x1000)); + ASSERT_FALSE(mm.is_stack_access(0x1500)); + ASSERT_FALSE(mm.is_stack_access(0x2000)); + ASSERT_FALSE(mm.is_stack_access(0x2500)); + ASSERT_FALSE(mm.is_stack_access(0x3000)); + ASSERT_FALSE(mm.is_stack_access(0x3500)); + ASSERT_FALSE(mm.is_stack_access(0x4000)); + ASSERT_FALSE(mm.is_stack_access(0x4500)); + ASSERT_FALSE(mm.is_stack_access(0x5000)); + ASSERT_FALSE(mm.is_stack_access(0x5500)); + ASSERT_FALSE(mm.is_stack_access(0x6000)); + ASSERT_FALSE(mm.is_stack_access(0x6500)); + + mm.update_stack_addresses(0x3000, 0x4000); + mm.enter_new_function(); + + ASSERT_FALSE(mm.is_stack_access(0x1000)); + ASSERT_FALSE(mm.is_stack_access(0x1500)); + ASSERT_FALSE(mm.is_stack_access(0x2000)); + ASSERT_FALSE(mm.is_stack_access(0x2500)); + ASSERT_FALSE(mm.is_stack_access(0x3000)); + ASSERT_FALSE(mm.is_stack_access(0x3500)); + ASSERT_FALSE(mm.is_stack_access(0x4000)); + ASSERT_FALSE(mm.is_stack_access(0x4500)); + ASSERT_FALSE(mm.is_stack_access(0x5000)); + ASSERT_FALSE(mm.is_stack_access(0x5500)); + ASSERT_FALSE(mm.is_stack_access(0x6000)); + ASSERT_FALSE(mm.is_stack_access(0x6500)); + + mm.update_stack_addresses(0x5000, 0x6000); + + ASSERT_FALSE(mm.is_stack_access(0x1000)); + ASSERT_FALSE(mm.is_stack_access(0x1500)); + ASSERT_FALSE(mm.is_stack_access(0x2000)); + ASSERT_FALSE(mm.is_stack_access(0x2500)); + ASSERT_FALSE(mm.is_stack_access(0x3000)); + ASSERT_FALSE(mm.is_stack_access(0x3500)); + ASSERT_FALSE(mm.is_stack_access(0x4000)); + ASSERT_FALSE(mm.is_stack_access(0x4500)); + ASSERT_TRUE(mm.is_stack_access(0x5000)); + ASSERT_TRUE(mm.is_stack_access(0x5500)); + ASSERT_TRUE(mm.is_stack_access(0x6000)); + ASSERT_FALSE(mm.is_stack_access(0x6500)); + + auto addr = mm.pop_last_stack_address(); + + ASSERT_FALSE(mm.is_stack_access(0x1000)); + ASSERT_FALSE(mm.is_stack_access(0x1500)); + ASSERT_FALSE(mm.is_stack_access(0x2000)); + ASSERT_FALSE(mm.is_stack_access(0x2500)); + ASSERT_TRUE(mm.is_stack_access(0x3000)); + ASSERT_TRUE(mm.is_stack_access(0x3500)); + ASSERT_TRUE(mm.is_stack_access(0x4000)); + ASSERT_FALSE(mm.is_stack_access(0x4500)); + ASSERT_FALSE(mm.is_stack_access(0x5000)); + ASSERT_FALSE(mm.is_stack_access(0x5500)); + ASSERT_FALSE(mm.is_stack_access(0x6000)); + ASSERT_FALSE(mm.is_stack_access(0x6500)); + + addr = mm.pop_last_stack_address(); + + ASSERT_TRUE(mm.is_stack_access(0x1000)); + ASSERT_TRUE(mm.is_stack_access(0x1500)); + ASSERT_TRUE(mm.is_stack_access(0x2000)); + ASSERT_FALSE(mm.is_stack_access(0x2500)); + ASSERT_FALSE(mm.is_stack_access(0x3000)); + ASSERT_FALSE(mm.is_stack_access(0x3500)); + ASSERT_FALSE(mm.is_stack_access(0x4000)); + ASSERT_FALSE(mm.is_stack_access(0x4500)); + ASSERT_FALSE(mm.is_stack_access(0x5000)); + ASSERT_FALSE(mm.is_stack_access(0x5500)); + ASSERT_FALSE(mm.is_stack_access(0x6000)); + ASSERT_FALSE(mm.is_stack_access(0x6500)); + + addr = mm.pop_last_stack_address(); + + ASSERT_FALSE(mm.is_stack_access(0x1000)); + ASSERT_FALSE(mm.is_stack_access(0x1500)); + ASSERT_FALSE(mm.is_stack_access(0x2000)); + ASSERT_FALSE(mm.is_stack_access(0x2500)); + ASSERT_FALSE(mm.is_stack_access(0x3000)); + ASSERT_FALSE(mm.is_stack_access(0x3500)); + ASSERT_FALSE(mm.is_stack_access(0x4000)); + ASSERT_FALSE(mm.is_stack_access(0x4500)); + ASSERT_FALSE(mm.is_stack_access(0x5000)); + ASSERT_FALSE(mm.is_stack_access(0x5500)); + ASSERT_FALSE(mm.is_stack_access(0x6000)); + ASSERT_FALSE(mm.is_stack_access(0x6500)); +} + +TEST_F(MemoryManagerTest, testScoping) { + auto manager = __dp::MemoryManager{}; + + manager.enterScope("First scope", 0); + const auto first_scope = manager.getCurrentScope(); + manager.leaveScope("Already gone", 0); + + ASSERT_EQ(first_scope.get_id(), 1); + ASSERT_TRUE(first_scope.get_first_read().empty()); + ASSERT_TRUE(first_scope.get_first_write().empty()); + + manager.enterScope("Hello", 1); + manager.enterScope(" ", 20); + manager.enterScope("world", 10); + manager.enterScope("!\n", 1); + + for (auto i = 0; i < 4; i++) { + const auto scope = manager.getCurrentScope(); + ASSERT_EQ(scope.get_id(), 5 - i); + ASSERT_TRUE(scope.get_first_read().empty()); + ASSERT_TRUE(scope.get_first_write().empty()); + + const auto scope_again = manager.getCurrentScope(); + ASSERT_EQ(scope_again.get_id(), 5 - i); + ASSERT_TRUE(scope_again.get_first_read().empty()); + ASSERT_TRUE(scope_again.get_first_write().empty()); + + manager.leaveScope("leave!", 55); + } + + manager.enterScope("New version", 2); + manager.enterScope("...\n", 5); + + const auto scope = manager.getCurrentScope(); + ASSERT_EQ(scope.get_id(), 7); + ASSERT_TRUE(scope.get_first_read().empty()); + ASSERT_TRUE(scope.get_first_write().empty()); + + manager.leaveScope("Leave.", 4); + + const auto last_scope = manager.getCurrentScope(); + ASSERT_EQ(last_scope.get_id(), 6); + ASSERT_TRUE(last_scope.get_first_read().empty()); + ASSERT_TRUE(last_scope.get_first_write().empty()); + + manager.leaveScope("Leave the last time", 0); +} + +TEST_F(MemoryManagerTest, testRegisterRead) { + auto manager = __dp::MemoryManager{}; + + manager.enterScope("First", 1); + + manager.enterScope("Second", 2); + manager.registerStackRead(24, 2, ""); + manager.registerStackRead(32, 1, ""); + + manager.enterScope("Third", 3); + manager.registerStackRead(1024, 0, ""); + + manager.enterScope("Fourth", 4); + + const auto scope4 = manager.getCurrentScope(); + + ASSERT_TRUE(scope4.get_first_read().empty()); + ASSERT_TRUE(scope4.get_first_write().empty()); + + manager.leaveScope("Fourth", 4); + + manager.registerStackRead(52, 0, ""); + + const auto scope3 = manager.getCurrentScope(); + const auto reads3 = scope3.get_first_read(); + + ASSERT_TRUE(scope3.get_first_write().empty()); + ASSERT_EQ(reads3.size(), 2); + ASSERT_NE(reads3.find(52), reads3.end()); + ASSERT_NE(reads3.find(1024), reads3.end()); + + manager.leaveScope("Third", 3); + + manager.registerStackRead(24, 2, ""); + + const auto scope2 = manager.getCurrentScope(); + const auto reads2 = scope2.get_first_read(); + + ASSERT_TRUE(scope2.get_first_write().empty()); + ASSERT_EQ(reads2.size(), 2); + ASSERT_NE(reads2.find(24), reads3.end()); + ASSERT_NE(reads2.find(32), reads3.end()); + + manager.leaveScope("Second", 2); + + const auto scope1 = manager.getCurrentScope(); + + ASSERT_TRUE(scope1.get_first_read().empty()); + ASSERT_TRUE(scope1.get_first_write().empty()); + + manager.leaveScope("First", 1); +} + +TEST_F(MemoryManagerTest, testRegisterWrite) { + auto manager = __dp::MemoryManager{}; + + manager.enterScope("First", 1); + + manager.enterScope("Second", 2); + manager.registerStackWrite(24, 2, ""); + manager.registerStackWrite(32, 1, ""); + + manager.enterScope("Third", 3); + manager.registerStackWrite(1024, 0, ""); + + manager.enterScope("Fourth", 4); + + const auto scope4 = manager.getCurrentScope(); + + ASSERT_TRUE(scope4.get_first_read().empty()); + ASSERT_TRUE(scope4.get_first_write().empty()); + + manager.leaveScope("Fourth", 4); + + manager.registerStackWrite(52, 0, ""); + + const auto scope3 = manager.getCurrentScope(); + const auto writes3 = scope3.get_first_write(); + + ASSERT_TRUE(scope3.get_first_read().empty()); + ASSERT_EQ(writes3.size(), 2); + ASSERT_NE(writes3.find(52), writes3.end()); + ASSERT_NE(writes3.find(1024), writes3.end()); + + manager.leaveScope("Third", 3); + + manager.registerStackWrite(24, 2, ""); + + const auto scope2 = manager.getCurrentScope(); + const auto writes2 = scope2.get_first_write(); + + ASSERT_TRUE(scope2.get_first_read().empty()); + ASSERT_EQ(writes2.size(), 2); + ASSERT_NE(writes2.find(24), writes2.end()); + ASSERT_NE(writes2.find(32), writes2.end()); + + manager.leaveScope("Second", 2); + + const auto scope1 = manager.getCurrentScope(); + + ASSERT_TRUE(scope1.get_first_read().empty()); + ASSERT_TRUE(scope1.get_first_write().empty()); + + manager.leaveScope("First", 1); +} + +TEST_F(MemoryManagerTest, testRegister) { + auto manager = __dp::MemoryManager{}; + + manager.enterScope("First", 1); + + manager.registerStackRead(32, 0, ""); + manager.registerStackRead(24, 1, ""); + + manager.enterScope("Second", 2); + + manager.registerStackRead(32, 3, ""); + manager.registerStackWrite(24, 4, ""); + + manager.enterScope("Third", 3); + + manager.registerStackRead(24, 5, ""); + manager.registerStackWrite(24, 6, ""); + + const auto scope3 = manager.getCurrentScope(); + const auto reads3 = scope3.get_first_read(); + const auto writes3 = scope3.get_first_write(); + + manager.leaveScope("Third", 3); + + const auto scope2 = manager.getCurrentScope(); + const auto reads2 = scope2.get_first_read(); + const auto writes2 = scope2.get_first_write(); + + manager.leaveScope("Second", 2); + + const auto scope1 = manager.getCurrentScope(); + const auto reads1 = scope1.get_first_read(); + const auto writes1 = scope1.get_first_write(); + + manager.leaveScope("First", 1); + + ASSERT_TRUE(writes1.empty()); + ASSERT_EQ(reads1.size(), 2); + ASSERT_NE(reads1.find(24), reads1.end()); + ASSERT_NE(reads1.find(32), reads1.end()); + + ASSERT_EQ(reads2.size(), 1); + ASSERT_EQ(writes2.size(), 1); + ASSERT_NE(reads2.find(32), reads2.end()); + ASSERT_NE(writes2.find(24), writes2.end()); + + ASSERT_TRUE(writes3.empty()); + ASSERT_EQ(reads3.size(), 1); + ASSERT_NE(reads3.find(24), reads3.end()); +} + +TEST_F(MemoryManagerTest, testFirstWritten) { + auto manager = __dp::MemoryManager{}; + + manager.enterScope("First", 1); + manager.registerStackRead(24, 0, ""); + manager.registerStackWrite(24, 1, ""); + manager.registerStackWrite(12, 2, ""); + manager.registerStackRead(12, 3, ""); + + manager.enterScope("Second", 2); + manager.registerStackWrite(24, 2, ""); + manager.registerStackRead(24, 3, ""); + manager.registerStackRead(12, 0, ""); + manager.registerStackWrite(12, 1, ""); + + manager.enterScope("Third", 3); + manager.registerStackRead(32, 4, ""); + manager.registerStackWrite(36, 5, ""); + manager.registerStackRead(40, 6, ""); + + ASSERT_TRUE(manager.isFirstWrittenInScope(36, true)); + ASSERT_TRUE(manager.isFirstWrittenInScope(1012, true)); + ASSERT_TRUE(manager.isFirstWrittenInScope(1024, true)); + + ASSERT_FALSE(manager.isFirstWrittenInScope(12, true)); + ASSERT_FALSE(manager.isFirstWrittenInScope(24, true)); + ASSERT_FALSE(manager.isFirstWrittenInScope(32, true)); + ASSERT_FALSE(manager.isFirstWrittenInScope(32, false)); + ASSERT_FALSE(manager.isFirstWrittenInScope(40, true)); + ASSERT_FALSE(manager.isFirstWrittenInScope(40, false)); + ASSERT_FALSE(manager.isFirstWrittenInScope(1012, false)); + ASSERT_FALSE(manager.isFirstWrittenInScope(1024, false)); +} + +TEST_F(MemoryManagerTest, testPositiveChange) { + auto scope = __dp::MemoryManager{}; + + scope.enterScope("First", 1); + scope.registerStackRead(24, 0, ""); + scope.registerStackRead(64, 1, ""); + + scope.enterScope("Second", 2); + scope.registerStackWrite(32, 2, ""); + + scope.enterScope("Third", 3); + scope.registerStackWrite(64, 3, ""); + + ASSERT_TRUE(scope.positiveScopeChangeOccuredSinceLastAccess(12)); + ASSERT_TRUE(scope.positiveScopeChangeOccuredSinceLastAccess(24)); + ASSERT_TRUE(scope.positiveScopeChangeOccuredSinceLastAccess(32)); + ASSERT_FALSE(scope.positiveScopeChangeOccuredSinceLastAccess(64)); + + scope.leaveScope("Third", 3); + + ASSERT_TRUE(scope.positiveScopeChangeOccuredSinceLastAccess(12)); + ASSERT_TRUE(scope.positiveScopeChangeOccuredSinceLastAccess(24)); + ASSERT_FALSE(scope.positiveScopeChangeOccuredSinceLastAccess(32)); + ASSERT_FALSE(scope.positiveScopeChangeOccuredSinceLastAccess(64)); + + scope.leaveScope("Second", 2); + + ASSERT_TRUE(scope.positiveScopeChangeOccuredSinceLastAccess(12)); + ASSERT_FALSE(scope.positiveScopeChangeOccuredSinceLastAccess(24)); + ASSERT_FALSE(scope.positiveScopeChangeOccuredSinceLastAccess(32)); + ASSERT_FALSE(scope.positiveScopeChangeOccuredSinceLastAccess(64)); + + scope.leaveScope("First", 1); + + // TODO(Lukas): Currently, there is no active scope. + // Think about your error handling. + + // ASSERT_TRUE(scope.positiveScopeChangeOccuredSinceLastAccess(12)); + // ASSERT_FALSE(scope.positiveScopeChangeOccuredSinceLastAccess(24)); + // ASSERT_FALSE(scope.positiveScopeChangeOccuredSinceLastAccess(32)); + // ASSERT_FALSE(scope.positiveScopeChangeOccuredSinceLastAccess(64)); + + scope.enterScope("Forth", 4); + + scope.registerStackRead(24, 4, ""); + + ASSERT_TRUE(scope.positiveScopeChangeOccuredSinceLastAccess(12)); + ASSERT_FALSE(scope.positiveScopeChangeOccuredSinceLastAccess(24)); + ASSERT_TRUE(scope.positiveScopeChangeOccuredSinceLastAccess(32)); + ASSERT_TRUE(scope.positiveScopeChangeOccuredSinceLastAccess(64)); + + scope.enterScope("Fifth", 5); + + ASSERT_TRUE(scope.positiveScopeChangeOccuredSinceLastAccess(12)); + ASSERT_TRUE(scope.positiveScopeChangeOccuredSinceLastAccess(24)); + ASSERT_TRUE(scope.positiveScopeChangeOccuredSinceLastAccess(32)); + ASSERT_TRUE(scope.positiveScopeChangeOccuredSinceLastAccess(64)); +} + +TEST_F(MemoryManagerTest, testAllocateDummyRegion) { + auto manager = __dp::MemoryManager{}; + + ASSERT_EQ(manager.get_number_allocations(), 0); + + manager.allocate_dummy_region(); + + ASSERT_EQ(manager.get_number_allocations(), 1); + + manager.allocate_dummy_region(); + + ASSERT_EQ(manager.get_number_allocations(), 2); + + const auto& allocations = manager.get_allocated_memory_regions(); + ASSERT_EQ(allocations.size(), 2); + + for (const auto& allocation : allocations) { + ASSERT_EQ(std::get<0>(allocation), 0); + ASSERT_EQ(std::get<1>(allocation), "%%dummy%%"); + ASSERT_EQ(std::get<2>(allocation), 0); + ASSERT_EQ(std::get<3>(allocation), 0); + ASSERT_EQ(std::get<4>(allocation), 0); + ASSERT_EQ(std::get<5>(allocation), 0); + } +} + +TEST_F(MemoryManagerTest, testAllocateRegion1) { + auto manager = __dp::MemoryManager{}; + + const auto lid = 43; + const auto start_address = 0x2000'0000'0000'0000LL; + const auto end_address = 0x2000'0000'0000'1000LL; + const auto num_bytes = 0x1000LL; + const auto num_elements = 0x100LL; + + manager.allocate_memory(lid, start_address, end_address, num_bytes, num_elements); + + for (auto i = start_address; i <= end_address; i++) { + ASSERT_EQ(manager.get_memory_region_id(i, ""), "1"); + } + + ASSERT_EQ(manager.get_memory_region_id(0x0000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x1000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x5687'1400'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x3FF0'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x1242'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x4FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x2225'1684'6ac4'd4b6LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x2FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x3000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x5300'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x530F'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x53FF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + + ASSERT_EQ(manager.get_smallest_allocated_addr(), start_address); + ASSERT_EQ(manager.get_largest_allocated_addr(), end_address); + + const auto& allocations = manager.get_allocated_memory_regions(); + ASSERT_EQ(allocations.size(), 1); + ASSERT_EQ(manager.get_number_allocations(), 1); + + const auto& allocation = allocations[0]; + ASSERT_EQ(std::get<0>(allocation), lid); + ASSERT_EQ(std::get<1>(allocation), "1"); + ASSERT_EQ(std::get<2>(allocation), start_address); + ASSERT_EQ(std::get<3>(allocation), end_address); + ASSERT_EQ(std::get<4>(allocation), num_bytes); + ASSERT_EQ(std::get<5>(allocation), num_elements); + + ASSERT_EQ(manager.get_next_free_memory_region_id(), 2); +} + +TEST_F(MemoryManagerTest, testAllocateRegion2) { + auto manager = __dp::MemoryManager{}; + + const auto lid_1 = 43; + const auto start_address_1 = 0x2000'0000'0000'0000LL; + const auto end_address_1 = 0x2000'0000'0000'1000LL; + const auto num_bytes_1 = 0x1000LL; + const auto num_elements_1 = 0x100LL; + + manager.allocate_memory(lid_1, start_address_1, end_address_1, num_bytes_1, num_elements_1); + + const auto lid_2 = 44; + const auto start_address_2 = 0x3000'0000'0000'0000LL; + const auto end_address_2 = 0x3000'0000'0000'5000LL; + const auto num_bytes_2 = 0x5000LL; + const auto num_elements_2 = 0x400LL; + + manager.allocate_memory(lid_2, start_address_2, end_address_2, num_bytes_2, num_elements_2); + + for (auto i = start_address_1; i <= end_address_1; i++) { + ASSERT_EQ(manager.get_memory_region_id(i, ""), "1"); + } + + for (auto i = start_address_2; i <= end_address_2; i++) { + ASSERT_EQ(manager.get_memory_region_id(i, ""), "2"); + } + + ASSERT_EQ(manager.get_memory_region_id(0x0000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x1000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x5687'1400'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x3FF0'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x1242'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x4FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x2225'1684'6ac4'd4b6LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x2FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x5300'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x530F'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x53FF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + + ASSERT_EQ(manager.get_smallest_allocated_addr(), start_address_1); + ASSERT_EQ(manager.get_largest_allocated_addr(), end_address_2); + + const auto& allocations = manager.get_allocated_memory_regions(); + ASSERT_EQ(allocations.size(), 2); + ASSERT_EQ(manager.get_number_allocations(), 2); + + const auto& allocation_1 = allocations[0]; + ASSERT_EQ(std::get<0>(allocation_1), lid_1); + ASSERT_EQ(std::get<1>(allocation_1), "1"); + ASSERT_EQ(std::get<2>(allocation_1), start_address_1); + ASSERT_EQ(std::get<3>(allocation_1), end_address_1); + ASSERT_EQ(std::get<4>(allocation_1), num_bytes_1); + ASSERT_EQ(std::get<5>(allocation_1), num_elements_1); + + const auto& allocation_2 = allocations[1]; + ASSERT_EQ(std::get<0>(allocation_2), lid_2); + ASSERT_EQ(std::get<1>(allocation_2), "2"); + ASSERT_EQ(std::get<2>(allocation_2), start_address_2); + ASSERT_EQ(std::get<3>(allocation_2), end_address_2); + ASSERT_EQ(std::get<4>(allocation_2), num_bytes_2); + ASSERT_EQ(std::get<5>(allocation_2), num_elements_2); + + ASSERT_EQ(manager.get_next_free_memory_region_id(), 3); +} + +TEST_F(MemoryManagerTest, testAllocateStackRegion1) { + auto manager = __dp::MemoryManager{}; + + manager.enter_new_function(); + + const auto lid = 43; + const auto start_address = 0x2000'0000'0000'0000LL; + const auto end_address = 0x2000'0000'0000'1000LL; + const auto num_bytes = 0x1000LL; + const auto num_elements = 0x100LL; + + manager.allocate_stack_memory(lid, start_address, end_address, num_bytes, num_elements); + + for (auto i = start_address; i <= end_address; i++) { + ASSERT_EQ(manager.get_memory_region_id(i, ""), "1"); + } + + ASSERT_EQ(manager.get_memory_region_id(0x0000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x1000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x5687'1400'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x3FF0'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x1242'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x4FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x2225'1684'6ac4'd4b6LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x2FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x3000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x5300'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x530F'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x53FF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + + ASSERT_EQ(manager.get_smallest_allocated_addr(), start_address); + ASSERT_EQ(manager.get_largest_allocated_addr(), end_address); + + const auto& allocations = manager.get_allocated_memory_regions(); + ASSERT_EQ(allocations.size(), 1); + ASSERT_EQ(manager.get_number_allocations(), 1); + + const auto& allocation = allocations[0]; + ASSERT_EQ(std::get<0>(allocation), lid); + ASSERT_EQ(std::get<1>(allocation), "1"); + ASSERT_EQ(std::get<2>(allocation), start_address); + ASSERT_EQ(std::get<3>(allocation), end_address); + ASSERT_EQ(std::get<4>(allocation), num_bytes); + ASSERT_EQ(std::get<5>(allocation), num_elements); + + ASSERT_EQ(manager.get_next_free_memory_region_id(), 2); + + const auto stack_addresses = manager.pop_last_stack_address(); + ASSERT_EQ(stack_addresses.first, start_address); + ASSERT_EQ(stack_addresses.second, end_address); +} + +TEST_F(MemoryManagerTest, testAllocateStackRegion2) { + auto manager = __dp::MemoryManager{}; + + manager.enter_new_function(); + + const auto lid_1 = 43; + const auto start_address_1 = 0x2000'0000'0000'0000LL; + const auto end_address_1 = 0x2000'0000'0000'1000LL; + const auto num_bytes_1 = 0x1000LL; + const auto num_elements_1 = 0x100LL; + + manager.allocate_stack_memory(lid_1, start_address_1, end_address_1, num_bytes_1, num_elements_1); + + const auto lid_2 = 44; + const auto start_address_2 = 0x3000'0000'0000'0000LL; + const auto end_address_2 = 0x3000'0000'0000'5000LL; + const auto num_bytes_2 = 0x5000LL; + const auto num_elements_2 = 0x400LL; + + manager.allocate_stack_memory(lid_2, start_address_2, end_address_2, num_bytes_2, num_elements_2); + + for (auto i = start_address_1; i <= end_address_1; i++) { + ASSERT_EQ(manager.get_memory_region_id(i, ""), "1"); + } + + for (auto i = start_address_2; i <= end_address_2; i++) { + ASSERT_EQ(manager.get_memory_region_id(i, ""), "2"); + } + + ASSERT_EQ(manager.get_memory_region_id(0x0000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x1000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x5687'1400'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x3FF0'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x1242'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x4FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x2225'1684'6ac4'd4b6LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x2FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x5300'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x530F'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x53FF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + + ASSERT_EQ(manager.get_smallest_allocated_addr(), start_address_1); + ASSERT_EQ(manager.get_largest_allocated_addr(), end_address_2); + + const auto& allocations = manager.get_allocated_memory_regions(); + ASSERT_EQ(allocations.size(), 2); + ASSERT_EQ(manager.get_number_allocations(), 2); + + const auto& allocation_1 = allocations[0]; + ASSERT_EQ(std::get<0>(allocation_1), lid_1); + ASSERT_EQ(std::get<1>(allocation_1), "1"); + ASSERT_EQ(std::get<2>(allocation_1), start_address_1); + ASSERT_EQ(std::get<3>(allocation_1), end_address_1); + ASSERT_EQ(std::get<4>(allocation_1), num_bytes_1); + ASSERT_EQ(std::get<5>(allocation_1), num_elements_1); + + const auto& allocation_2 = allocations[1]; + ASSERT_EQ(std::get<0>(allocation_2), lid_2); + ASSERT_EQ(std::get<1>(allocation_2), "2"); + ASSERT_EQ(std::get<2>(allocation_2), start_address_2); + ASSERT_EQ(std::get<3>(allocation_2), end_address_2); + ASSERT_EQ(std::get<4>(allocation_2), num_bytes_2); + ASSERT_EQ(std::get<5>(allocation_2), num_elements_2); + + ASSERT_EQ(manager.get_next_free_memory_region_id(), 3); + + const auto stack_addresses = manager.pop_last_stack_address(); + ASSERT_EQ(stack_addresses.first, start_address_1); + ASSERT_EQ(stack_addresses.second, end_address_2); +} + +TEST_F(MemoryManagerTest, testAllocateStackRegion3) { + auto manager = __dp::MemoryManager{}; + + manager.enter_new_function(); + + const auto lid_1 = 43; + const auto start_address_1 = 0x2000'0000'0000'0000LL; + const auto end_address_1 = 0x2000'0000'0000'1000LL; + const auto num_bytes_1 = 0x1000LL; + const auto num_elements_1 = 0x100LL; + + manager.allocate_stack_memory(lid_1, start_address_1, end_address_1, num_bytes_1, num_elements_1); + + manager.enter_new_function(); + + const auto lid_2 = 44; + const auto start_address_2 = 0x3000'0000'0000'0000LL; + const auto end_address_2 = 0x3000'0000'0000'5000LL; + const auto num_bytes_2 = 0x5000LL; + const auto num_elements_2 = 0x400LL; + + manager.allocate_stack_memory(lid_2, start_address_2, end_address_2, num_bytes_2, num_elements_2); + + for (auto i = start_address_1; i <= end_address_1; i++) { + ASSERT_EQ(manager.get_memory_region_id(i, ""), "1"); + } + + for (auto i = start_address_2; i <= end_address_2; i++) { + ASSERT_EQ(manager.get_memory_region_id(i, ""), "2"); + } + + ASSERT_EQ(manager.get_memory_region_id(0x0000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x1000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x5687'1400'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x3FF0'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x1242'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x4FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x2225'1684'6ac4'd4b6LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x2FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x5300'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x530F'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x53FF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + + ASSERT_EQ(manager.get_smallest_allocated_addr(), start_address_1); + ASSERT_EQ(manager.get_largest_allocated_addr(), end_address_2); + + const auto& allocations = manager.get_allocated_memory_regions(); + ASSERT_EQ(allocations.size(), 2); + ASSERT_EQ(manager.get_number_allocations(), 2); + + const auto& allocation_1 = allocations[0]; + ASSERT_EQ(std::get<0>(allocation_1), lid_1); + ASSERT_EQ(std::get<1>(allocation_1), "1"); + ASSERT_EQ(std::get<2>(allocation_1), start_address_1); + ASSERT_EQ(std::get<3>(allocation_1), end_address_1); + ASSERT_EQ(std::get<4>(allocation_1), num_bytes_1); + ASSERT_EQ(std::get<5>(allocation_1), num_elements_1); + + const auto& allocation_2 = allocations[1]; + ASSERT_EQ(std::get<0>(allocation_2), lid_2); + ASSERT_EQ(std::get<1>(allocation_2), "2"); + ASSERT_EQ(std::get<2>(allocation_2), start_address_2); + ASSERT_EQ(std::get<3>(allocation_2), end_address_2); + ASSERT_EQ(std::get<4>(allocation_2), num_bytes_2); + ASSERT_EQ(std::get<5>(allocation_2), num_elements_2); + + ASSERT_EQ(manager.get_next_free_memory_region_id(), 3); + + const auto stack_addresses = manager.pop_last_stack_address(); + ASSERT_EQ(stack_addresses.first, start_address_2); + ASSERT_EQ(stack_addresses.second, end_address_2); +} + +TEST_F(MemoryManagerTest, testAllocate1) { + auto manager = __dp::MemoryManager{}; + + manager.enter_new_function(); + + const auto lid_1 = 43; + const auto start_address_1 = 0x2000'0000'0000'0000LL; + const auto end_address_1 = 0x2000'0000'0000'1000LL; + const auto num_bytes_1 = 0x1000LL; + const auto num_elements_1 = 0x100LL; + + manager.allocate_stack_memory(lid_1, start_address_1, end_address_1, num_bytes_1, num_elements_1); + + const auto lid_2 = 44; + const auto start_address_2 = 0x3000'0000'0000'0000LL; + const auto end_address_2 = 0x3000'0000'0000'5000LL; + const auto num_bytes_2 = 0x5000LL; + const auto num_elements_2 = 0x400LL; + + manager.allocate_stack_memory(lid_2, start_address_2, end_address_2, num_bytes_2, num_elements_2); + + const auto lid_3 = 45; + const auto start_address_3 = 0x1000'0000'0000'0000LL; + const auto end_address_3 = 0x1000'0000'0000'2000LL; + const auto num_bytes_3 = 0x2000LL; + const auto num_elements_3 = 0x2000LL; + + manager.allocate_memory(lid_3, start_address_3, end_address_3, num_bytes_3, num_elements_3); + + for (auto i = start_address_1; i <= end_address_1; i++) { + ASSERT_EQ(manager.get_memory_region_id(i, ""), "1"); + } + + for (auto i = start_address_2; i <= end_address_2; i++) { + ASSERT_EQ(manager.get_memory_region_id(i, ""), "2"); + } + + for (auto i = start_address_3; i <= end_address_3; i++) { + ASSERT_EQ(manager.get_memory_region_id(i, ""), "3"); + } + + ASSERT_EQ(manager.get_memory_region_id(0x0000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x5687'1400'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x3FF0'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x1242'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x4FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x2225'1684'6ac4'd4b6LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x2FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x5300'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x530F'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x53FF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + + ASSERT_EQ(manager.get_smallest_allocated_addr(), start_address_3); + ASSERT_EQ(manager.get_largest_allocated_addr(), end_address_2); + + const auto& allocations = manager.get_allocated_memory_regions(); + ASSERT_EQ(allocations.size(), 3); + ASSERT_EQ(manager.get_number_allocations(), 3); + + const auto& allocation_1 = allocations[0]; + ASSERT_EQ(std::get<0>(allocation_1), lid_1); + ASSERT_EQ(std::get<1>(allocation_1), "1"); + ASSERT_EQ(std::get<2>(allocation_1), start_address_1); + ASSERT_EQ(std::get<3>(allocation_1), end_address_1); + ASSERT_EQ(std::get<4>(allocation_1), num_bytes_1); + ASSERT_EQ(std::get<5>(allocation_1), num_elements_1); + + const auto& allocation_2 = allocations[1]; + ASSERT_EQ(std::get<0>(allocation_2), lid_2); + ASSERT_EQ(std::get<1>(allocation_2), "2"); + ASSERT_EQ(std::get<2>(allocation_2), start_address_2); + ASSERT_EQ(std::get<3>(allocation_2), end_address_2); + ASSERT_EQ(std::get<4>(allocation_2), num_bytes_2); + ASSERT_EQ(std::get<5>(allocation_2), num_elements_2); + + const auto& allocation_3 = allocations[2]; + ASSERT_EQ(std::get<0>(allocation_3), lid_3); + ASSERT_EQ(std::get<1>(allocation_3), "3"); + ASSERT_EQ(std::get<2>(allocation_3), start_address_3); + ASSERT_EQ(std::get<3>(allocation_3), end_address_3); + ASSERT_EQ(std::get<4>(allocation_3), num_bytes_3); + ASSERT_EQ(std::get<5>(allocation_3), num_elements_3); + + ASSERT_EQ(manager.get_next_free_memory_region_id(), 4); + + const auto stack_addresses = manager.pop_last_stack_address(); + ASSERT_EQ(stack_addresses.first, start_address_1); + ASSERT_EQ(stack_addresses.second, end_address_2); +} + +TEST_F(MemoryManagerTest, testAllocate2) { + auto manager = __dp::MemoryManager{}; + + manager.enter_new_function(); + + const auto lid_1 = 43; + const auto start_address_1 = 0x2000'0000'0000'0000LL; + const auto end_address_1 = 0x2000'0000'0000'1000LL; + const auto num_bytes_1 = 0x1000LL; + const auto num_elements_1 = 0x100LL; + + manager.allocate_stack_memory(lid_1, start_address_1, end_address_1, num_bytes_1, num_elements_1); + + const auto lid_2 = 44; + const auto start_address_2 = 0x3000'0000'0000'0000LL; + const auto end_address_2 = 0x3000'0000'0000'5000LL; + const auto num_bytes_2 = 0x5000LL; + const auto num_elements_2 = 0x400LL; + + manager.allocate_stack_memory(lid_2, start_address_2, end_address_2, num_bytes_2, num_elements_2); + + const auto lid_3 = 45; + const auto start_address_3 = 0x1000'0000'0000'0000LL; + const auto end_address_3 = 0x1000'0000'0000'2000LL; + const auto num_bytes_3 = 0x2000LL; + const auto num_elements_3 = 0x2000LL; + + manager.allocate_memory(lid_3, start_address_3, end_address_3, num_bytes_3, num_elements_3); + + const auto lid_4 = 46; + const auto start_address_4 = 0x5000'0000'0000'0000LL; + const auto end_address_4 = 0x5000'0000'0000'0200LL; + const auto num_bytes_4 = 0x200LL; + const auto num_elements_4 = 0x2LL; + + manager.allocate_memory(lid_4, start_address_4, end_address_4, num_bytes_4, num_elements_4); + + for (auto i = start_address_1; i <= end_address_1; i++) { + ASSERT_EQ(manager.get_memory_region_id(i, ""), "1"); + } + + for (auto i = start_address_2; i <= end_address_2; i++) { + ASSERT_EQ(manager.get_memory_region_id(i, ""), "2"); + } + + for (auto i = start_address_3; i <= end_address_3; i++) { + ASSERT_EQ(manager.get_memory_region_id(i, ""), "3"); + } + + for (auto i = start_address_4; i <= end_address_4; i++) { + ASSERT_EQ(manager.get_memory_region_id(i, ""), "4"); + } + + ASSERT_EQ(manager.get_memory_region_id(0x0000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x5687'1400'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x3FF0'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x1242'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x4FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x2225'1684'6ac4'd4b6LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x2FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x5300'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x530F'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(manager.get_memory_region_id(0x53FF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + + ASSERT_EQ(manager.get_smallest_allocated_addr(), start_address_3); + ASSERT_EQ(manager.get_largest_allocated_addr(), end_address_4); + + const auto& allocations = manager.get_allocated_memory_regions(); + ASSERT_EQ(allocations.size(), 4); + ASSERT_EQ(manager.get_number_allocations(), 4); + + const auto& allocation_1 = allocations[0]; + ASSERT_EQ(std::get<0>(allocation_1), lid_1); + ASSERT_EQ(std::get<1>(allocation_1), "1"); + ASSERT_EQ(std::get<2>(allocation_1), start_address_1); + ASSERT_EQ(std::get<3>(allocation_1), end_address_1); + ASSERT_EQ(std::get<4>(allocation_1), num_bytes_1); + ASSERT_EQ(std::get<5>(allocation_1), num_elements_1); + + const auto& allocation_2 = allocations[1]; + ASSERT_EQ(std::get<0>(allocation_2), lid_2); + ASSERT_EQ(std::get<1>(allocation_2), "2"); + ASSERT_EQ(std::get<2>(allocation_2), start_address_2); + ASSERT_EQ(std::get<3>(allocation_2), end_address_2); + ASSERT_EQ(std::get<4>(allocation_2), num_bytes_2); + ASSERT_EQ(std::get<5>(allocation_2), num_elements_2); + + const auto& allocation_3 = allocations[2]; + ASSERT_EQ(std::get<0>(allocation_3), lid_3); + ASSERT_EQ(std::get<1>(allocation_3), "3"); + ASSERT_EQ(std::get<2>(allocation_3), start_address_3); + ASSERT_EQ(std::get<3>(allocation_3), end_address_3); + ASSERT_EQ(std::get<4>(allocation_3), num_bytes_3); + ASSERT_EQ(std::get<5>(allocation_3), num_elements_3); + + const auto& allocation_4 = allocations[3]; + ASSERT_EQ(std::get<0>(allocation_4), lid_4); + ASSERT_EQ(std::get<1>(allocation_4), "4"); + ASSERT_EQ(std::get<2>(allocation_4), start_address_4); + ASSERT_EQ(std::get<3>(allocation_4), end_address_4); + ASSERT_EQ(std::get<4>(allocation_4), num_bytes_4); + ASSERT_EQ(std::get<5>(allocation_4), num_elements_4); + + ASSERT_EQ(manager.get_next_free_memory_region_id(), 5); + + const auto stack_addresses = manager.pop_last_stack_address(); + ASSERT_EQ(stack_addresses.first, start_address_1); + ASSERT_EQ(stack_addresses.second, end_address_2); +} diff --git a/test/unit_tests/memory/memory_region_tree/test_memory_region_tree.cpp b/test/unit_tests/memory/memory_region_tree/test_memory_region_tree.cpp new file mode 100644 index 000000000..e16e70617 --- /dev/null +++ b/test/unit_tests/memory/memory_region_tree/test_memory_region_tree.cpp @@ -0,0 +1,687 @@ +#include + +#include "../../../../rtlib/memory/MemoryRegionTree.hpp" + +#include +#include + +class MemoryRegionTreeTest : public ::testing::Test { }; + +TEST_F(MemoryRegionTreeTest, testConstructor) { + const auto tree = __dp::MemoryRegionTree{}; + + const auto* root = tree.get_root(); + + ASSERT_EQ(root->get_first_addr(), 0x0000000000000000LL); + ASSERT_EQ(root->get_last_addr(), 0x7FFFFFFFFFFFFFFFLL); + ASSERT_EQ(root->get_memory_region_id(), 0); + + for (auto i = 0; i < 16; i++) { + ASSERT_EQ(root->get_child(i), nullptr); + } +} + +TEST_F(MemoryRegionTreeTest, testAllocateRegion1) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr = 0x0000000000000000LL; + const auto end_addr = 0x7FFFFFFFFFFFFFFFLL; + const auto memory_region_id = 0x1234; + + tree.allocate_region(start_addr, end_addr, memory_region_id); + + auto* root = tree.get_root(); + + ASSERT_EQ(root->get_memory_region_id(), memory_region_id); + for (auto i = 0; i < 16; i++) { + ASSERT_EQ(root->get_child(i), nullptr); + } +} + +TEST_F(MemoryRegionTreeTest, testAllocateRegion2) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr = 0x0000000000000000LL; + const auto end_addr = 0x0FFFFFFFFFFFFFFFLL; + const auto memory_region_id = 0x2345; + + tree.allocate_region(start_addr, end_addr, memory_region_id); + + auto* root = tree.get_root(); + + ASSERT_EQ(root->get_memory_region_id(), 0); + for (auto i = 1; i < 16; i++) { + ASSERT_EQ(root->get_child(i), nullptr); + } + + auto child = root->get_child(0); + + ASSERT_EQ(child->get_memory_region_id(), memory_region_id); + for (auto i = 0; i < 16; i++) { + ASSERT_EQ(child->get_child(i), nullptr); + } +} + +TEST_F(MemoryRegionTreeTest, testAllocateRegion3) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr = 0x1000000000000000LL; + const auto end_addr = 0x3FFFFFFFFFFFFFFFLL; + const auto memory_region_id = 0x2345; + + tree.allocate_region(start_addr, end_addr, memory_region_id); + + auto* root = tree.get_root(); + + ASSERT_EQ(root->get_child(0), nullptr); + ASSERT_NE(root->get_child(1), nullptr); + ASSERT_NE(root->get_child(2), nullptr); + ASSERT_NE(root->get_child(3), nullptr); + ASSERT_EQ(root->get_child(4), nullptr); + ASSERT_EQ(root->get_child(5), nullptr); + ASSERT_EQ(root->get_child(6), nullptr); + ASSERT_EQ(root->get_child(7), nullptr); + ASSERT_EQ(root->get_child(8), nullptr); + ASSERT_EQ(root->get_child(9), nullptr); + ASSERT_EQ(root->get_child(10), nullptr); + ASSERT_EQ(root->get_child(11), nullptr); + ASSERT_EQ(root->get_child(12), nullptr); + ASSERT_EQ(root->get_child(13), nullptr); + ASSERT_EQ(root->get_child(14), nullptr); + ASSERT_EQ(root->get_child(15), nullptr); + + auto* child1 = root->get_child(1); + auto* child2 = root->get_child(2); + auto* child3 = root->get_child(3); + + ASSERT_EQ(child1->get_memory_region_id(), memory_region_id); + ASSERT_EQ(child2->get_memory_region_id(), memory_region_id); + ASSERT_EQ(child3->get_memory_region_id(), memory_region_id); + + for (auto i = 0; i < 16; i++) { + ASSERT_EQ(child1->get_child(i), nullptr); + ASSERT_EQ(child2->get_child(i), nullptr); + ASSERT_EQ(child3->get_child(i), nullptr); + } +} + +TEST_F(MemoryRegionTreeTest, testAllocateRegion4) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr = 0x1000000000000000LL; + const auto end_addr = 0x2CFFFFFFFFFFFFFFLL; + const auto memory_region_id = 0x1111; + + tree.allocate_region(start_addr, end_addr, memory_region_id); + + auto* root = tree.get_root(); + + ASSERT_EQ(root->get_child(0), nullptr); + ASSERT_NE(root->get_child(1), nullptr); + ASSERT_NE(root->get_child(2), nullptr); + ASSERT_EQ(root->get_child(3), nullptr); + ASSERT_EQ(root->get_child(4), nullptr); + ASSERT_EQ(root->get_child(5), nullptr); + ASSERT_EQ(root->get_child(6), nullptr); + ASSERT_EQ(root->get_child(7), nullptr); + ASSERT_EQ(root->get_child(8), nullptr); + ASSERT_EQ(root->get_child(9), nullptr); + ASSERT_EQ(root->get_child(10), nullptr); + ASSERT_EQ(root->get_child(11), nullptr); + ASSERT_EQ(root->get_child(12), nullptr); + ASSERT_EQ(root->get_child(13), nullptr); + ASSERT_EQ(root->get_child(14), nullptr); + ASSERT_EQ(root->get_child(15), nullptr); + + auto* child1 = root->get_child(1); + auto* child2 = root->get_child(2); + + ASSERT_EQ(child1->get_memory_region_id(), memory_region_id); + ASSERT_EQ(child2->get_memory_region_id(), 0); + + for (auto i = 0; i < 16; i++) { + ASSERT_EQ(child1->get_child(i), nullptr); + } + + for (auto i = 0; i < 13; i++) { + ASSERT_NE(child2->get_child(i), nullptr); + for (auto* gc : child2->get_child(i)->get_children()) { + ASSERT_EQ(gc, nullptr); + } + + ASSERT_EQ(child2->get_child(i)->get_memory_region_id(), memory_region_id); + } + + for (auto i = 13; i < 16; i++) { + ASSERT_EQ(child2->get_child(i), nullptr); + } +} + +TEST_F(MemoryRegionTreeTest, testAllocateRegion5) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr = 0x13542698001FAB52LL; + const auto end_addr = 0x13542698001FAB52LL; + const auto memory_region_id = 0x1111; + + tree.allocate_region(start_addr, end_addr, memory_region_id); + + auto* node = tree.get_root(); + + while (true) { + const auto node_start = node->get_first_addr(); + const auto node_end = node->get_last_addr(); + + if (node_start == start_addr && node_end == end_addr) { + ASSERT_EQ(node->get_memory_region_id(), memory_region_id); + ASSERT_EQ(node_start, start_addr); + ASSERT_EQ(node_end, end_addr); + + for (auto i = 0; i < 16; i++) { + ASSERT_EQ(node->get_child(i), nullptr); + } + break; + } + + auto counter = 0; + __dp::MRTNode* new_node = nullptr; + + for (auto i = 0; i < 16; i++) { + auto* child = node->get_child(i); + if (child != nullptr) { + new_node = child; + counter++; + } + } + + node = new_node; + + ASSERT_EQ(counter, 1); + } +} + +TEST_F(MemoryRegionTreeTest, testAllocateRegion6) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr_1 = 0x1000000000000000LL; + const auto end_addr_1 = 0x1FFFFFFFFFFFFFFFLL; + const auto memory_region_id_1 = 0x1111; + + const auto start_addr_2 = 0x5000000000000000LL; + const auto end_addr_2 = 0x5FFFFFFFFFFFFFFFLL; + const auto memory_region_id_2 = 0x2222; + + tree.allocate_region(start_addr_1, end_addr_1, memory_region_id_1); + tree.allocate_region(start_addr_2, end_addr_2, memory_region_id_2); + + auto* root = tree.get_root(); + + ASSERT_EQ(root->get_child(0), nullptr); + ASSERT_NE(root->get_child(1), nullptr); + ASSERT_EQ(root->get_child(2), nullptr); + ASSERT_EQ(root->get_child(3), nullptr); + ASSERT_EQ(root->get_child(4), nullptr); + ASSERT_NE(root->get_child(5), nullptr); + ASSERT_EQ(root->get_child(6), nullptr); + ASSERT_EQ(root->get_child(7), nullptr); + ASSERT_EQ(root->get_child(8), nullptr); + ASSERT_EQ(root->get_child(9), nullptr); + ASSERT_EQ(root->get_child(10), nullptr); + ASSERT_EQ(root->get_child(11), nullptr); + ASSERT_EQ(root->get_child(12), nullptr); + ASSERT_EQ(root->get_child(13), nullptr); + ASSERT_EQ(root->get_child(14), nullptr); + ASSERT_EQ(root->get_child(15), nullptr); + + auto* child1 = root->get_child(1); + auto* child5 = root->get_child(5); + + ASSERT_EQ(child1->get_memory_region_id(), memory_region_id_1); + ASSERT_EQ(child5->get_memory_region_id(), memory_region_id_2); + + for (auto i = 0; i < 16; i++) { + ASSERT_EQ(child1->get_child(i), nullptr); + ASSERT_EQ(child5->get_child(i), nullptr); + } +} + +TEST_F(MemoryRegionTreeTest, testAllocateRegion7) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr_1 = 0x1000000000000000LL; + const auto end_addr_1 = 0x1FFFFFFFFFFFFFFFLL; + const auto memory_region_id_1 = 0x1111; + + const auto start_addr_2 = 0x5300000000000000LL; + const auto end_addr_2 = 0x53FFFFFFFFFFFFFFLL; + const auto memory_region_id_2 = 0x2222; + + tree.allocate_region(start_addr_1, end_addr_1, memory_region_id_1); + tree.allocate_region(start_addr_2, end_addr_2, memory_region_id_2); + + auto* root = tree.get_root(); + + ASSERT_EQ(root->get_child(0), nullptr); + ASSERT_NE(root->get_child(1), nullptr); + ASSERT_EQ(root->get_child(2), nullptr); + ASSERT_EQ(root->get_child(3), nullptr); + ASSERT_EQ(root->get_child(4), nullptr); + ASSERT_NE(root->get_child(5), nullptr); + ASSERT_EQ(root->get_child(6), nullptr); + ASSERT_EQ(root->get_child(7), nullptr); + ASSERT_EQ(root->get_child(8), nullptr); + ASSERT_EQ(root->get_child(9), nullptr); + ASSERT_EQ(root->get_child(10), nullptr); + ASSERT_EQ(root->get_child(11), nullptr); + ASSERT_EQ(root->get_child(12), nullptr); + ASSERT_EQ(root->get_child(13), nullptr); + ASSERT_EQ(root->get_child(14), nullptr); + ASSERT_EQ(root->get_child(15), nullptr); + + auto* child1 = root->get_child(1); + ASSERT_EQ(child1->get_memory_region_id(), memory_region_id_1); + + for (auto i = 0; i < 16; i++) { + ASSERT_EQ(child1->get_child(i), nullptr); + } + + auto* child5 = root->get_child(5); + ASSERT_EQ(child5->get_memory_region_id(), 0); + + for (auto i = 0; i < 16; i++) { + if (i == 3) { + ASSERT_NE(child5->get_child(i), nullptr); + ASSERT_EQ(child5->get_child(i)->get_memory_region_id(), memory_region_id_2); + + for (auto j = 0; j < 16; j++) { + ASSERT_EQ(child5->get_child(i)->get_child(j), nullptr); + } + } else { + ASSERT_EQ(child5->get_child(i), nullptr); + } + } +} + +TEST_F(MemoryRegionTreeTest, testGetMemoryRegionId1) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr = 0x0000000000000000LL; + const auto end_addr = 0x7FFFFFFFFFFFFFFFLL; + const auto memory_region_id = 0x1234; + + tree.allocate_region(start_addr, end_addr, memory_region_id); + + ASSERT_EQ(tree.get_memory_region_id(0x0000000000000000LL), memory_region_id); + ASSERT_EQ(tree.get_memory_region_id(0x7FFFFFFFFFFFFFFFLL), memory_region_id); + ASSERT_EQ(tree.get_memory_region_id(0x5687140000000000LL), memory_region_id); + ASSERT_EQ(tree.get_memory_region_id(0x3FF0000000000000LL), memory_region_id); + ASSERT_EQ(tree.get_memory_region_id(0x1000000000000000LL), memory_region_id); + ASSERT_EQ(tree.get_memory_region_id(0x5000000000000000LL), memory_region_id); + ASSERT_EQ(tree.get_memory_region_id(0x4FFFFFFFFFFFFFFFLL), memory_region_id); + ASSERT_EQ(tree.get_memory_region_id(0x622516846acd64b6LL), memory_region_id); +} + +TEST_F(MemoryRegionTreeTest, testGetMemoryRegionId2) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr = 0x0000000000000000LL; + const auto end_addr = 0x7FFFFFFFFFFFFFFFLL; + const auto memory_region_id = 0x1234; + + tree.allocate_region(start_addr, end_addr, memory_region_id); + + ASSERT_EQ(tree.get_memory_region_id(0x8000000000000000LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0xFFFFFFFFFFFFFFFFLL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0xA687140000000000LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0xCFF0000000000000LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x9000000000000000LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0xE000000000000000LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0xDFFFFFFFFFFFFFFFLL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0xF22516846acd64b6LL), 0xFFFF'FFFFU); +} + +TEST_F(MemoryRegionTreeTest, testGetMemoryRegionId3) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr = 0x1000'0000'0000'0000LL; + const auto end_addr = 0x2000'0000'0000'0000LL; + const auto memory_region_id = 12; + + tree.allocate_region(start_addr, end_addr, 12); + + ASSERT_EQ(tree.get_memory_region_id(0x0000'0000'0000'0000LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x1000'0000'0000'0000LL), memory_region_id); + ASSERT_EQ(tree.get_memory_region_id(0x5687'1400'0000'0000LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x3FF0'0000'0000'0000LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x1242'0000'0000'0000LL), memory_region_id); + ASSERT_EQ(tree.get_memory_region_id(0x2000'0000'0000'0000LL), memory_region_id); + ASSERT_EQ(tree.get_memory_region_id(0x4FFF'FFFF'FFFF'FFFFLL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x8225'1684'6ac4'd4b6LL), 0xFFFF'FFFFU); +} + +TEST_F(MemoryRegionTreeTest, testGetMemoryRegionId4) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr_1 = 0x1000000000000000LL; + const auto end_addr_1 = 0x1FFFFFFFFFFFFFFFLL; + const auto memory_region_id_1 = 0x1111; + + const auto start_addr_2 = 0x2000000000000000LL; + const auto end_addr_2 = 0x2FFFFFFFFFFFFFFFLL; + const auto memory_region_id_2 = 0x2222; + + tree.allocate_region(start_addr_1, end_addr_1, memory_region_id_1); + tree.allocate_region(start_addr_2, end_addr_2, memory_region_id_2); + + ASSERT_EQ(tree.get_memory_region_id(0x0000'0000'0000'0000LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x1000'0000'0000'0000LL), memory_region_id_1); + ASSERT_EQ(tree.get_memory_region_id(0x5687'1400'0000'0000LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x3FF0'0000'0000'0000LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x1242'0000'0000'0000LL), memory_region_id_1); + ASSERT_EQ(tree.get_memory_region_id(0x2000'0000'0000'0000LL), memory_region_id_2); + ASSERT_EQ(tree.get_memory_region_id(0x4FFF'FFFF'FFFF'FFFFLL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x2225'1684'6ac4'd4b6LL), memory_region_id_2); + ASSERT_EQ(tree.get_memory_region_id(0x2FFF'FFFF'FFFF'FFFFLL), memory_region_id_2); + ASSERT_EQ(tree.get_memory_region_id(0x3000'0000'0000'0000LL), 0xFFFF'FFFFU); +} + +TEST_F(MemoryRegionTreeTest, testGetMemoryRegionId5) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr_1 = 0x1000000000000000LL; + const auto end_addr_1 = 0x1FFFFFFFFFFFFFFFLL; + const auto memory_region_id_1 = 0x1111; + + const auto start_addr_2 = 0x5300000000000000LL; + const auto end_addr_2 = 0x53FFFFFFFFFFFFFFLL; + const auto memory_region_id_2 = 0x2222; + + tree.allocate_region(start_addr_1, end_addr_1, memory_region_id_1); + tree.allocate_region(start_addr_2, end_addr_2, memory_region_id_2); + + ASSERT_EQ(tree.get_memory_region_id(0x0000'0000'0000'0000LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x1000'0000'0000'0000LL), memory_region_id_1); + ASSERT_EQ(tree.get_memory_region_id(0x5687'1400'0000'0000LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x3FF0'0000'0000'0000LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x1242'0000'0000'0000LL), memory_region_id_1); + ASSERT_EQ(tree.get_memory_region_id(0x2000'0000'0000'0000LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x4FFF'FFFF'FFFF'FFFFLL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x2225'1684'6ac4'd4b6LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x2FFF'FFFF'FFFF'FFFFLL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x3000'0000'0000'0000LL), 0xFFFF'FFFFU); + ASSERT_EQ(tree.get_memory_region_id(0x5300'0000'0000'0000LL), memory_region_id_2); + ASSERT_EQ(tree.get_memory_region_id(0x530F'FFFF'FFFF'FFFFLL), memory_region_id_2); + ASSERT_EQ(tree.get_memory_region_id(0x53FF'FFFF'FFFF'FFFFLL), memory_region_id_2); +} + +TEST_F(MemoryRegionTreeTest, testGetMemoryRegionIdStr1) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr = 0x0000000000000000LL; + const auto end_addr = 0x7FFFFFFFFFFFFFFFLL; + const auto memory_region_id = 0x1234; + + tree.allocate_region(start_addr, end_addr, memory_region_id); + + ASSERT_EQ(tree.get_memory_region_id_string(0x0000000000000000LL, "fallback"), std::to_string(memory_region_id)); + ASSERT_EQ(tree.get_memory_region_id_string(0x7FFFFFFFFFFFFFFFLL, "fallback"), std::to_string(memory_region_id)); + ASSERT_EQ(tree.get_memory_region_id_string(0x5687140000000000LL, "fallback"), std::to_string(memory_region_id)); + ASSERT_EQ(tree.get_memory_region_id_string(0x3FF0000000000000LL, "fallback"), std::to_string(memory_region_id)); + ASSERT_EQ(tree.get_memory_region_id_string(0x1000000000000000LL, "fallback"), std::to_string(memory_region_id)); + ASSERT_EQ(tree.get_memory_region_id_string(0x5000000000000000LL, "fallback"), std::to_string(memory_region_id)); + ASSERT_EQ(tree.get_memory_region_id_string(0x4FFFFFFFFFFFFFFFLL, "fallback"), std::to_string(memory_region_id)); + ASSERT_EQ(tree.get_memory_region_id_string(0x622516846acd64b6LL, "fallback"), std::to_string(memory_region_id)); +} + +TEST_F(MemoryRegionTreeTest, testGetMemoryRegionIdStr2) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr = 0x0000000000000000LL; + const auto end_addr = 0x7FFFFFFFFFFFFFFFLL; + const auto memory_region_id = 0x1234; + + tree.allocate_region(start_addr, end_addr, memory_region_id); + + ASSERT_EQ(tree.get_memory_region_id_string(0x8000000000000000LL, "fallback1"), std::string("fallback1")); + ASSERT_EQ(tree.get_memory_region_id_string(0xFFFFFFFFFFFFFFFFLL, "fallback2"), std::string("fallback2")); + ASSERT_EQ(tree.get_memory_region_id_string(0xA687140000000000LL, "fallback3"), std::string("fallback3")); + ASSERT_EQ(tree.get_memory_region_id_string(0xCFF0000000000000LL, "fallback4"), std::string("fallback4")); + ASSERT_EQ(tree.get_memory_region_id_string(0x9000000000000000LL, "fallback5"), std::string("fallback5")); + ASSERT_EQ(tree.get_memory_region_id_string(0xE000000000000000LL, "fallback6"), std::string("fallback6")); + ASSERT_EQ(tree.get_memory_region_id_string(0xDFFFFFFFFFFFFFFFLL, "fallback7"), std::string("fallback7")); + ASSERT_EQ(tree.get_memory_region_id_string(0xF22516846acd64b6LL, "fallback8"), std::string("fallback8")); +} + +TEST_F(MemoryRegionTreeTest, testGetMemoryRegionIdStr3) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr = 0x1000'0000'0000'0000LL; + const auto end_addr = 0x2000'0000'0000'0000LL; + const auto memory_region_id = 12; + + tree.allocate_region(start_addr, end_addr, 12); + + ASSERT_EQ(tree.get_memory_region_id_string(0x0000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(tree.get_memory_region_id_string(0x1000'0000'0000'0000LL, "fallback"), std::to_string(memory_region_id)); + ASSERT_EQ(tree.get_memory_region_id_string(0x5687'1400'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(tree.get_memory_region_id_string(0x3FF0'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(tree.get_memory_region_id_string(0x1242'0000'0000'0000LL, "fallback"), std::to_string(memory_region_id)); + ASSERT_EQ(tree.get_memory_region_id_string(0x2000'0000'0000'0000LL, "fallback"), std::to_string(memory_region_id)); + ASSERT_EQ(tree.get_memory_region_id_string(0x4FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(tree.get_memory_region_id_string(0x8225'1684'6ac4'd4b6LL, "fallback"), std::string("fallback")); +} + +TEST_F(MemoryRegionTreeTest, testGetMemoryRegionIdStr4) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr_1 = 0x1000000000000000LL; + const auto end_addr_1 = 0x1FFFFFFFFFFFFFFFLL; + const auto memory_region_id_1 = 0x1111; + + const auto start_addr_2 = 0x2000000000000000LL; + const auto end_addr_2 = 0x2FFFFFFFFFFFFFFFLL; + const auto memory_region_id_2 = 0x2222; + + tree.allocate_region(start_addr_1, end_addr_1, memory_region_id_1); + tree.allocate_region(start_addr_2, end_addr_2, memory_region_id_2); + + ASSERT_EQ(tree.get_memory_region_id_string(0x0000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(tree.get_memory_region_id_string(0x1000'0000'0000'0000LL, "fallback"), std::to_string(memory_region_id_1)); + ASSERT_EQ(tree.get_memory_region_id_string(0x5687'1400'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(tree.get_memory_region_id_string(0x3FF0'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(tree.get_memory_region_id_string(0x1242'0000'0000'0000LL, "fallback"), std::to_string(memory_region_id_1)); + ASSERT_EQ(tree.get_memory_region_id_string(0x2000'0000'0000'0000LL, "fallback"), std::to_string(memory_region_id_2)); + ASSERT_EQ(tree.get_memory_region_id_string(0x4FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(tree.get_memory_region_id_string(0x2225'1684'6ac4'd4b6LL, "fallback"), std::to_string(memory_region_id_2)); + ASSERT_EQ(tree.get_memory_region_id_string(0x2FFF'FFFF'FFFF'FFFFLL, "fallback"), std::to_string(memory_region_id_2)); + ASSERT_EQ(tree.get_memory_region_id_string(0x3000'0000'0000'0000LL, "fallback"), std::string("fallback")); +} + +TEST_F(MemoryRegionTreeTest, testGetMemoryRegionIdStr5) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr_1 = 0x1000000000000000LL; + const auto end_addr_1 = 0x1FFFFFFFFFFFFFFFLL; + const auto memory_region_id_1 = 0x1111; + + const auto start_addr_2 = 0x5300000000000000LL; + const auto end_addr_2 = 0x53FFFFFFFFFFFFFFLL; + const auto memory_region_id_2 = 0x2222; + + tree.allocate_region(start_addr_1, end_addr_1, memory_region_id_1); + tree.allocate_region(start_addr_2, end_addr_2, memory_region_id_2); + + ASSERT_EQ(tree.get_memory_region_id_string(0x0000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(tree.get_memory_region_id_string(0x1000'0000'0000'0000LL, "fallback"), std::to_string(memory_region_id_1)); + ASSERT_EQ(tree.get_memory_region_id_string(0x5687'1400'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(tree.get_memory_region_id_string(0x3FF0'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(tree.get_memory_region_id_string(0x1242'0000'0000'0000LL, "fallback"), std::to_string(memory_region_id_1)); + ASSERT_EQ(tree.get_memory_region_id_string(0x2000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(tree.get_memory_region_id_string(0x4FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(tree.get_memory_region_id_string(0x2225'1684'6ac4'd4b6LL, "fallback"), std::string("fallback")); + ASSERT_EQ(tree.get_memory_region_id_string(0x2FFF'FFFF'FFFF'FFFFLL, "fallback"), std::string("fallback")); + ASSERT_EQ(tree.get_memory_region_id_string(0x3000'0000'0000'0000LL, "fallback"), std::string("fallback")); + ASSERT_EQ(tree.get_memory_region_id_string(0x5300'0000'0000'0000LL, "fallback"), std::to_string(memory_region_id_2)); + ASSERT_EQ(tree.get_memory_region_id_string(0x530F'FFFF'FFFF'FFFFLL, "fallback"), std::to_string(memory_region_id_2)); + ASSERT_EQ(tree.get_memory_region_id_string(0x53FF'FFFF'FFFF'FFFFLL, "fallback"), std::to_string(memory_region_id_2)); +} + +TEST_F(MemoryRegionTreeTest, testFreeRegion1) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr = 0x0000000000000000LL; + + tree.free_region(start_addr); + + auto* root = tree.get_root(); + + ASSERT_EQ(root->get_memory_region_id(), 0); + for (auto i = 0; i < 16; i++) { + ASSERT_EQ(root->get_child(i), nullptr); + } +} + +TEST_F(MemoryRegionTreeTest, testFreeRegion2) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr = 0x7FFFFFFFFFFFFFFFLL; + + tree.free_region(start_addr); + + auto* root = tree.get_root(); + + ASSERT_EQ(root->get_memory_region_id(), 0); + for (auto i = 0; i < 16; i++) { + ASSERT_EQ(root->get_child(i), nullptr); + } +} + +TEST_F(MemoryRegionTreeTest, testFreeRegion3) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr = 0x9472dcab36975afaLL; + + tree.free_region(start_addr); + + auto* root = tree.get_root(); + + ASSERT_EQ(root->get_memory_region_id(), 0); + for (auto i = 0; i < 16; i++) { + ASSERT_EQ(root->get_child(i), nullptr); + } +} + +TEST_F(MemoryRegionTreeTest, testFreeRegion4) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr = 0x1000'0000'0000'0000LL; + const auto end_addr = 0x1FFF'FFFF'FFFF'FFFFLL; + const auto memory_region_id = 0x1111; + + tree.allocate_region(start_addr, end_addr, memory_region_id); + + tree.free_region(start_addr); + + auto* root = tree.get_root(); + + ASSERT_EQ(root->get_memory_region_id(), 0); + for (auto i = 0; i < 16; i++) { + ASSERT_EQ(root->get_child(i), nullptr); + } +} + +TEST_F(MemoryRegionTreeTest, testFreeRegion5) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr = 0x0000'0000'0000'0000LL; + const auto end_addr = 0x7FFF'FFFF'FFFF'FFFFLL; + const auto memory_region_id = 0x1111; + + tree.allocate_region(start_addr, end_addr, memory_region_id); + + tree.free_region(start_addr); + + auto* root = tree.get_root(); + + ASSERT_EQ(root->get_memory_region_id(), 0); + for (auto i = 0; i < 16; i++) { + ASSERT_EQ(root->get_child(i), nullptr); + } +} + +TEST_F(MemoryRegionTreeTest, testFreeRegion6) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr_1 = 0x1000000000000000LL; + const auto end_addr_1 = 0x1FFFFFFFFFFFFFFFLL; + const auto memory_region_id_1 = 0x1111; + + const auto start_addr_2 = 0x5300000000000000LL; + const auto end_addr_2 = 0x53FFFFFFFFFFFFFFLL; + const auto memory_region_id_2 = 0x2222; + + tree.allocate_region(start_addr_1, end_addr_1, memory_region_id_1); + tree.allocate_region(start_addr_2, end_addr_2, memory_region_id_2); + + tree.free_region(start_addr_1); + + auto* root = tree.get_root(); + + ASSERT_EQ(root->get_child(0), nullptr); + ASSERT_EQ(root->get_child(1), nullptr); + ASSERT_EQ(root->get_child(2), nullptr); + ASSERT_EQ(root->get_child(3), nullptr); + ASSERT_EQ(root->get_child(4), nullptr); + ASSERT_NE(root->get_child(5), nullptr); + ASSERT_EQ(root->get_child(6), nullptr); + ASSERT_EQ(root->get_child(7), nullptr); + ASSERT_EQ(root->get_child(8), nullptr); + ASSERT_EQ(root->get_child(9), nullptr); + ASSERT_EQ(root->get_child(10), nullptr); + ASSERT_EQ(root->get_child(11), nullptr); + ASSERT_EQ(root->get_child(12), nullptr); + ASSERT_EQ(root->get_child(13), nullptr); + ASSERT_EQ(root->get_child(14), nullptr); + ASSERT_EQ(root->get_child(15), nullptr); + + auto* child5 = root->get_child(5); + ASSERT_EQ(child5->get_memory_region_id(), 0); + + for (auto i = 0; i < 16; i++) { + if (i == 3) { + ASSERT_NE(child5->get_child(i), nullptr); + ASSERT_EQ(child5->get_child(i)->get_memory_region_id(), memory_region_id_2); + + for (auto j = 0; j < 16; j++) { + ASSERT_EQ(child5->get_child(i)->get_child(j), nullptr); + } + } else { + ASSERT_EQ(child5->get_child(i), nullptr); + } + } +} + +TEST_F(MemoryRegionTreeTest, testFreeRegion7) { + auto tree = __dp::MemoryRegionTree{}; + + const auto start_addr_1 = 0x1000000000000000LL; + const auto end_addr_1 = 0x1FFFFFFFFFFFFFFFLL; + const auto memory_region_id_1 = 0x1111; + + const auto start_addr_2 = 0x5300000000000000LL; + const auto end_addr_2 = 0x53FFFFFFFFFFFFFFLL; + const auto memory_region_id_2 = 0x2222; + + tree.allocate_region(start_addr_1, end_addr_1, memory_region_id_1); + tree.allocate_region(start_addr_2, end_addr_2, memory_region_id_2); + + tree.free_region(start_addr_1); + tree.free_region(start_addr_2); + + auto* root = tree.get_root(); + + ASSERT_EQ(root->get_memory_region_id(), 0); + for (auto i = 0; i < 16; i++) { + ASSERT_EQ(root->get_child(i), nullptr); + } +} diff --git a/test/unit_tests/memory/mrtnode/test_mrtnode.cpp b/test/unit_tests/memory/mrtnode/test_mrtnode.cpp new file mode 100644 index 000000000..d8feeb41a --- /dev/null +++ b/test/unit_tests/memory/mrtnode/test_mrtnode.cpp @@ -0,0 +1,122 @@ +#include + +#include "../../../../rtlib/memory/MemoryRegionTree.hpp" + +#include +#include + +class MRTNodeTest : public ::testing::Test { }; + +TEST_F(MRTNodeTest, testConstructor) { + const auto start_addr = 0x1234567890ABCDEFLL; + const auto end_addr = 0x2234567890ABCDEFLL; + const auto level = 0x1234; + + const auto node = __dp::MRTNode(start_addr, end_addr, level); + + ASSERT_EQ(node.get_first_addr(), start_addr); + ASSERT_EQ(node.get_last_addr(), end_addr); + ASSERT_EQ(node.get_level(), level); + ASSERT_EQ(node.get_memory_region_id(), 0); + + for (auto i = 0; i < 16; i++) { + ASSERT_EQ(node.get_child(i), nullptr); + } + + for (const auto* child : node.get_children()) { + ASSERT_EQ(child, nullptr); + } +} + +TEST_F(MRTNodeTest, testGetChildIndex) { + const auto start_addr = 0x1200000000000000LL; + const auto end_addr = 0x12FFFFFFFFFFFFFFLL; + + const auto level = 2; + + const auto node = __dp::MRTNode(start_addr, end_addr, level); + + const auto base_addr = 0x010000000000000LL; + for (auto i = 0; i < 16; i++) { + const auto inquiry_addr = start_addr + (base_addr * i); + const auto calculated_index = node.get_child_index(inquiry_addr); + + ASSERT_EQ(calculated_index, i); + } + + ASSERT_EQ(node.get_child_index(start_addr - 1), -1); + ASSERT_EQ(node.get_child_index(end_addr + 1), -1); + ASSERT_EQ(node.get_child_index(0x1100000000000000LL), -1); + ASSERT_EQ(node.get_child_index(0x1400000000000000LL), -1); + ASSERT_EQ(node.get_child_index(0x1863453534300000LL), -1); + ASSERT_EQ(node.get_child_index(0x0000000000000000LL), -1); + ASSERT_EQ(node.get_child_index(0x1000000000000000LL), -1); + ASSERT_EQ(node.get_child_index(0x2000000000000000LL), -1); + ASSERT_EQ(node.get_child_index(0xEFFFFFFFFFFFFFFFLL), -1); +} + +TEST_F(MRTNodeTest, testAddChild0) { + const auto start_addr = 0x1000000000000000LL; + const auto end_addr = 0x1FFFFFFFFFFFFFFFLL; + + const auto level = 1; + + auto node = __dp::MRTNode(start_addr, end_addr, level); + + node.add_child(0); + + for (auto i = 0; i < 16; i++) { + if (i == 0) { + ASSERT_NE(node.get_child(i), nullptr); + ASSERT_EQ(node.get_child(i)->get_first_addr(), 0x1000000000000000LL) << std::hex << node.get_child(i)->get_first_addr(); + ASSERT_EQ(node.get_child(i)->get_last_addr(), 0x10FFFFFFFFFFFFFFLL) << std::hex << node.get_child(i)->get_last_addr(); + ASSERT_EQ(node.get_child(i)->get_level(), 2); + + for (auto j = 0; j < 16; j++) { + ASSERT_EQ(node.get_child(i)->get_child(j), nullptr); + } + } else { + ASSERT_EQ(node.get_child(i), nullptr); + } + } +} + +TEST_F(MRTNodeTest, testAddChild1) { + const auto start_addr = 0x2E00000000000000LL; + const auto end_addr = 0x2EFFFFFFFFFFFFFFLL; + + const auto level = 2; + + auto node = __dp::MRTNode(start_addr, end_addr, level); + + node.add_child(3); + + for (auto i = 0; i < 16; i++) { + if (i == 3) { + ASSERT_NE(node.get_child(i), nullptr); + ASSERT_EQ(node.get_child(i)->get_first_addr(), 0x2E30000000000000LL) << std::hex << node.get_child(i)->get_first_addr(); + ASSERT_EQ(node.get_child(i)->get_last_addr(), 0x2E3FFFFFFFFFFFFFLL) << std::hex << node.get_child(i)->get_last_addr(); + ASSERT_EQ(node.get_child(i)->get_level(), 3); + + for (auto j = 0; j < 16; j++) { + ASSERT_EQ(node.get_child(i)->get_child(j), nullptr); + } + } else { + ASSERT_EQ(node.get_child(i), nullptr); + } + } +} + +TEST_F(MRTNodeTest, testSetMemoryRegionId) { + const auto start_addr = 0x1000000000000000LL; + const auto end_addr = 0x1FFFFFFFFFFFFFFFLL; + + const auto level = 1; + + auto node = __dp::MRTNode(start_addr, end_addr, level); + + const auto memory_region_id = 0x1234; + node.set_memory_region_id(memory_region_id); + + ASSERT_EQ(node.get_memory_region_id(), memory_region_id); +} diff --git a/test/unit_tests/perfect_shadow/test_perfect_shadow.cpp b/test/unit_tests/memory/perfect_shadow/test_perfect_shadow.cpp similarity index 96% rename from test/unit_tests/perfect_shadow/test_perfect_shadow.cpp rename to test/unit_tests/memory/perfect_shadow/test_perfect_shadow.cpp index 5be0fe84b..8e7c85a3b 100644 --- a/test/unit_tests/perfect_shadow/test_perfect_shadow.cpp +++ b/test/unit_tests/memory/perfect_shadow/test_perfect_shadow.cpp @@ -3,7 +3,7 @@ #include #include -#include "../../../rtlib/perfect_shadow.hpp" +#include "../../../../rtlib/memory/PerfectShadow.hpp" // Tests for old version (i.e., capturing functionality) diff --git a/test/unit_tests/scope/test_scope.cpp b/test/unit_tests/memory/scope/test_scope.cpp similarity index 79% rename from test/unit_tests/scope/test_scope.cpp rename to test/unit_tests/memory/scope/test_scope.cpp index 6f8808d7d..31d422833 100644 --- a/test/unit_tests/scope/test_scope.cpp +++ b/test/unit_tests/memory/scope/test_scope.cpp @@ -1,6 +1,6 @@ #include -#include "../../../rtlib/scope.hpp" +#include "../../../../rtlib/memory/Scope.hpp" // Tests for old version (i.e., capturing functionality) @@ -105,6 +105,83 @@ TEST_F(ScopeTest, testRegister) { ASSERT_NE(writes.find(1876), writes.end()); } +TEST_F(ScopeTest, testCopy1) { + const auto scope_1 = __dp::Scope(4); + const auto scope_2 = __dp::Scope(scope_1); + + ASSERT_EQ(scope_1.get_id(), scope_2.get_id()); + ASSERT_TRUE(scope_1.get_first_read().empty()); + ASSERT_TRUE(scope_1.get_first_write().empty()); + ASSERT_TRUE(scope_2.get_first_read().empty()); + ASSERT_TRUE(scope_2.get_first_write().empty()); +} + +TEST_F(ScopeTest, testCopy2) { + auto scope_1 = __dp::Scope(4); + scope_1.registerStackRead(24, 0, ""); + scope_1.registerStackRead(32, 1, ""); + scope_1.registerStackWrite(1024, 0, ""); + scope_1.registerStackWrite(1032, 1, ""); + + const auto scope_2 = __dp::Scope(scope_1); + + ASSERT_EQ(scope_1.get_id(), scope_2.get_id()); + ASSERT_EQ(scope_1.get_first_read(), scope_2.get_first_read()); + ASSERT_EQ(scope_1.get_first_write(), scope_2.get_first_write()); +} + +TEST_F(ScopeTest, testCopy3) { + auto scope_1 = __dp::Scope(4); + scope_1.registerStackRead(24, 0, ""); + scope_1.registerStackRead(32, 1, ""); + scope_1.registerStackWrite(1024, 0, ""); + scope_1.registerStackWrite(1032, 1, ""); + + auto scope_2 = __dp::Scope(scope_1); + auto scope_3 = __dp::Scope(scope_1); + + scope_2.registerStackRead(72, 1, ""); + scope_2.registerStackRead(24, 6, ""); + scope_2.registerStackRead(32, 1, ""); + + scope_2.registerStackWrite(1072, 1, ""); + scope_2.registerStackWrite(1024, 6, ""); + scope_2.registerStackWrite(1032, 1, ""); + + ASSERT_EQ(scope_1.get_id(), scope_3.get_id()); + ASSERT_EQ(scope_1.get_first_read(), scope_3.get_first_read()); + ASSERT_EQ(scope_1.get_first_write(), scope_3.get_first_write()); +} + +TEST_F(ScopeTest, testCopy4) { + auto scope_1 = __dp::Scope(4); + scope_1.registerStackRead(24, 0, ""); + scope_1.registerStackRead(32, 1, ""); + scope_1.registerStackWrite(1024, 0, ""); + scope_1.registerStackWrite(1032, 1, ""); + + auto scope_2 = __dp::Scope(scope_1); + auto scope_3 = __dp::Scope(scope_1); + + scope_2.registerStackRead(72, 1, ""); + scope_2.registerStackRead(24, 6, ""); + scope_2.registerStackRead(32, 1, ""); + + scope_2.registerStackWrite(1072, 1, ""); + scope_2.registerStackWrite(1024, 6, ""); + scope_2.registerStackWrite(1032, 1, ""); + + scope_2 = scope_3; + + ASSERT_EQ(scope_1.get_id(), scope_2.get_id()); + ASSERT_EQ(scope_1.get_first_read(), scope_2.get_first_read()); + ASSERT_EQ(scope_1.get_first_write(), scope_2.get_first_write()); + + ASSERT_EQ(scope_1.get_id(), scope_3.get_id()); + ASSERT_EQ(scope_1.get_first_read(), scope_3.get_first_read()); + ASSERT_EQ(scope_1.get_first_write(), scope_3.get_first_write()); +} + TEST_F(ScopeManagerTest, testScoping) { auto manager = __dp::ScopeManager{}; @@ -381,10 +458,10 @@ TEST_F(ScopeManagerTest, testPositiveChange) { // TODO(Lukas): Currently, there is no active scope. // Think about your error handling. - ASSERT_TRUE(scope.positiveScopeChangeOccuredSinceLastAccess(12)); - ASSERT_FALSE(scope.positiveScopeChangeOccuredSinceLastAccess(24)); - ASSERT_FALSE(scope.positiveScopeChangeOccuredSinceLastAccess(32)); - ASSERT_FALSE(scope.positiveScopeChangeOccuredSinceLastAccess(64)); + // ASSERT_TRUE(scope.positiveScopeChangeOccuredSinceLastAccess(12)); + // ASSERT_FALSE(scope.positiveScopeChangeOccuredSinceLastAccess(24)); + // ASSERT_FALSE(scope.positiveScopeChangeOccuredSinceLastAccess(32)); + // ASSERT_FALSE(scope.positiveScopeChangeOccuredSinceLastAccess(64)); scope.enterScope("Forth", 4); @@ -416,7 +493,7 @@ TEST_F(Scope2Test, testConstructor) { ASSERT_TRUE(scope_1.get_first_read().empty()); ASSERT_TRUE(scope_1.get_first_write().empty()); - const auto scope_2 = __dp::Scope(9); + const auto scope_2 = __dp::Scope2(9); ASSERT_EQ(scope_2.get_id(), 9); ASSERT_TRUE(scope_2.get_first_read().empty()); @@ -506,6 +583,84 @@ TEST_F(Scope2Test, testRegister) { ASSERT_NE(writes.find(1876), writes.end()); } +TEST_F(Scope2Test, testCopy1) { + const auto scope_1 = __dp::Scope2(4); + const auto scope_2 = __dp::Scope2(scope_1); + + ASSERT_EQ(scope_1.get_id(), scope_2.get_id()); + ASSERT_TRUE(scope_1.get_first_read().empty()); + ASSERT_TRUE(scope_1.get_first_write().empty()); + ASSERT_TRUE(scope_2.get_first_read().empty()); + ASSERT_TRUE(scope_2.get_first_write().empty()); +} + +TEST_F(Scope2Test, testCopy2) { + auto scope_1 = __dp::Scope2(4); + scope_1.registerStackRead(24, 0, ""); + scope_1.registerStackRead(32, 1, ""); + scope_1.registerStackWrite(1024, 0, ""); + scope_1.registerStackWrite(1032, 1, ""); + + const auto scope_2 = __dp::Scope2(scope_1); + + ASSERT_EQ(scope_1.get_id(), scope_2.get_id()); + ASSERT_EQ(scope_1.get_first_read(), scope_2.get_first_read()); + ASSERT_EQ(scope_1.get_first_write(), scope_2.get_first_write()); +} + +TEST_F(Scope2Test, testCopy3) { + auto scope_1 = __dp::Scope2(4); + scope_1.registerStackRead(24, 0, ""); + scope_1.registerStackRead(32, 1, ""); + scope_1.registerStackWrite(1024, 0, ""); + scope_1.registerStackWrite(1032, 1, ""); + + auto scope_2 = __dp::Scope2(scope_1); + auto scope_3 = __dp::Scope2(scope_1); + + scope_2.registerStackRead(72, 1, ""); + scope_2.registerStackRead(24, 6, ""); + scope_2.registerStackRead(32, 1, ""); + + scope_2.registerStackWrite(1072, 1, ""); + scope_2.registerStackWrite(1024, 6, ""); + scope_2.registerStackWrite(1032, 1, ""); + + ASSERT_EQ(scope_1.get_id(), scope_3.get_id()); + ASSERT_EQ(scope_1.get_first_read(), scope_3.get_first_read()); + ASSERT_EQ(scope_1.get_first_write(), scope_3.get_first_write()); +} + +TEST_F(Scope2Test, testCopy4) { + auto scope_1 = __dp::Scope2(4); + scope_1.registerStackRead(24, 0, ""); + scope_1.registerStackRead(32, 1, ""); + scope_1.registerStackWrite(1024, 0, ""); + scope_1.registerStackWrite(1032, 1, ""); + + auto scope_2 = __dp::Scope2(scope_1); + auto scope_3 = __dp::Scope2(scope_1); + + scope_2.registerStackRead(72, 1, ""); + scope_2.registerStackRead(24, 6, ""); + scope_2.registerStackRead(32, 1, ""); + + scope_2.registerStackWrite(1072, 1, ""); + scope_2.registerStackWrite(1024, 6, ""); + scope_2.registerStackWrite(1032, 1, ""); + + scope_2 = scope_3; + + ASSERT_EQ(scope_1.get_id(), scope_2.get_id()); + ASSERT_EQ(scope_1.get_first_read(), scope_2.get_first_read()); + ASSERT_EQ(scope_1.get_first_write(), scope_2.get_first_write()); + + ASSERT_EQ(scope_1.get_id(), scope_3.get_id()); + ASSERT_EQ(scope_1.get_first_read(), scope_3.get_first_read()); + ASSERT_EQ(scope_1.get_first_write(), scope_3.get_first_write()); +} + + TEST_F(ScopeManager2Test, testScoping) { auto manager = __dp::ScopeManager2{};