diff options
Diffstat (limited to 'runtime/contrib/heap_trace')
34 files changed, 1730 insertions, 0 deletions
diff --git a/runtime/contrib/heap_trace/CMakeLists.txt b/runtime/contrib/heap_trace/CMakeLists.txt new file mode 100644 index 000000000..1f18152d8 --- /dev/null +++ b/runtime/contrib/heap_trace/CMakeLists.txt @@ -0,0 +1,18 @@ +if(NOT BUILD_HEAP_TRACE) + return() +endif(NOT BUILD_HEAP_TRACE) + +add_library(heap_trace SHARED src/cl_create_buffer_stub.cc + src/cl_release_mem_object.cc + src/free_stub.cc + src/malloc_stub.cc + src/realloc_stub.cc + src/valloc_stub.cc + src/symbol_searcher.cc + src/trace.cc +) +target_link_libraries(heap_trace PRIVATE ${CMAKE_DL_LIBS}) + +add_subdirectory(tests) + +install(TARGETS heap_trace DESTINATION lib) diff --git a/runtime/contrib/heap_trace/src/cl_create_buffer_stub.cc b/runtime/contrib/heap_trace/src/cl_create_buffer_stub.cc new file mode 100644 index 000000000..d9d2700ee --- /dev/null +++ b/runtime/contrib/heap_trace/src/cl_create_buffer_stub.cc @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "trace.h" +#include "function_resolver.h" + +#include <CL/cl.h> + +#include <memory> + +extern std::unique_ptr<Trace> GlobalTrace; + +extern "C" { + +cl_mem clCreateBuffer(cl_context context, cl_mem_flags flags, size_t size, void *host_ptr, + cl_int *errcode_ret) +{ + static auto isOriginalFunctionCallSuccessful = [](cl_mem result) -> bool { return result; }; + + static auto originalFunction = + findFunctionByName<cl_mem, cl_context, cl_mem_flags, size_t, void *, cl_int *>( + "clCreateBuffer"); + cl_mem result = originalFunction(context, flags, size, host_ptr, errcode_ret); + if (isOriginalFunctionCallSuccessful(result) && !Trace::Guard{}.isActive()) + { + GlobalTrace->logAllocationEvent(result, size); + } + + return result; +} +} diff --git a/runtime/contrib/heap_trace/src/cl_release_mem_object.cc b/runtime/contrib/heap_trace/src/cl_release_mem_object.cc new file mode 100644 index 000000000..f2f249e0b --- /dev/null +++ b/runtime/contrib/heap_trace/src/cl_release_mem_object.cc @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "trace.h" +#include "function_resolver.h" + +#include <CL/cl.h> + +#include <memory> + +extern std::unique_ptr<Trace> GlobalTrace; + +extern "C" { + +cl_int clReleaseMemObject(cl_mem mem) +{ + static auto isOriginalFunctionCallSuccessful = [](cl_int result) -> bool { + return result == CL_SUCCESS; + }; + + auto originalFunction = findFunctionByName<cl_int, cl_mem>("clReleaseMemObject"); + cl_int result = originalFunction(mem); + if (isOriginalFunctionCallSuccessful(result) && !Trace::Guard{}.isActive()) + { + GlobalTrace->logDeallocationEvent(mem); + } + + return result; +} +} diff --git a/runtime/contrib/heap_trace/src/free_stub.cc b/runtime/contrib/heap_trace/src/free_stub.cc new file mode 100644 index 000000000..31af63c8a --- /dev/null +++ b/runtime/contrib/heap_trace/src/free_stub.cc @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "trace.h" +#include "function_resolver.h" + +#include <memory> + +extern std::unique_ptr<Trace> GlobalTrace; + +extern "C" { + +void free(void *p) noexcept +{ + static auto originalFunction = findFunctionByName<void, void *>("free"); + originalFunction(p); + if (!Trace::Guard{}.isActive()) + { + GlobalTrace->logDeallocationEvent(p); + } +} +} diff --git a/runtime/contrib/heap_trace/src/function_resolver.h b/runtime/contrib/heap_trace/src/function_resolver.h new file mode 100644 index 000000000..9b6879539 --- /dev/null +++ b/runtime/contrib/heap_trace/src/function_resolver.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FUNCTION_RESOLVER_H +#define FUNCTION_RESOLVER_H + +#include "symbol_searcher.h" + +template <typename ReturnType, typename... ArgTypes> +ReturnType (*findFunctionByName(const char *function_name))(ArgTypes...) +{ + auto found_symbol = findSymbol(function_name); + return reinterpret_cast<ReturnType (*)(ArgTypes...)>(found_symbol); +} + +#endif // ! FUNCTION_RESOLVER_H diff --git a/runtime/contrib/heap_trace/src/malloc_stub.cc b/runtime/contrib/heap_trace/src/malloc_stub.cc new file mode 100644 index 000000000..50124d164 --- /dev/null +++ b/runtime/contrib/heap_trace/src/malloc_stub.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "trace.h" +#include "function_resolver.h" + +#include <memory> + +extern std::unique_ptr<Trace> GlobalTrace; + +extern "C" { + +void *malloc(size_t sz) noexcept +{ + static auto isOriginalFunctionCallSuccessful = [](void *result) -> bool { return result; }; + + static auto originalFunction = findFunctionByName<void *, size_t>("malloc"); + void *result = originalFunction(sz); + if (isOriginalFunctionCallSuccessful(result) && !Trace::Guard{}.isActive()) + { + GlobalTrace->logAllocationEvent(result, sz); + } + + return result; +} +} diff --git a/runtime/contrib/heap_trace/src/realloc_stub.cc b/runtime/contrib/heap_trace/src/realloc_stub.cc new file mode 100644 index 000000000..ce4569b0e --- /dev/null +++ b/runtime/contrib/heap_trace/src/realloc_stub.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "trace.h" +#include "function_resolver.h" + +#include <memory> + +extern std::unique_ptr<Trace> GlobalTrace; + +extern "C" { + +void *realloc(void *ptr, size_t sz) noexcept +{ + static auto isOriginalFunctionCallSuccessful = [](void *result) -> bool { return result; }; + + static auto originalFunction = findFunctionByName<void *, void *, size_t>("realloc"); + void *result = originalFunction(ptr, sz); + if (isOriginalFunctionCallSuccessful(result) && !Trace::Guard{}.isActive()) + { + GlobalTrace->logDeallocationEvent(ptr); + GlobalTrace->logAllocationEvent(result, sz); + } + + return result; +} +} diff --git a/runtime/contrib/heap_trace/src/symbol_searcher.cc b/runtime/contrib/heap_trace/src/symbol_searcher.cc new file mode 100644 index 000000000..cf83f2f7b --- /dev/null +++ b/runtime/contrib/heap_trace/src/symbol_searcher.cc @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "symbol_searcher.h" + +#include <dlfcn.h> +#include <link.h> + +struct SymbolDescription +{ + const char *name; + void *address = nullptr; // address in memory where this symbol can be found + + SymbolDescription(const char *name) : name(name) {} +}; + +using InfoAboutLoadedLib = struct dl_phdr_info *; + +static void tryToFindSymbolInLinkedLibraries(SymbolDescription &symbol); +static void tryToFindSymbolInAllLoadedLibraries(SymbolDescription &symbol); +static int checkIfLibraryContainsSymbol(InfoAboutLoadedLib library_description, size_t /* size */, + void *data); +static bool isSymbolAddressNotInTheSameTranslationUnit(SymbolDescription *symbol); +void *findSymbol(const char *name) +{ + SymbolDescription symbol(name); + tryToFindSymbolInLinkedLibraries(symbol); + if (!symbol.address) + { + tryToFindSymbolInAllLoadedLibraries(symbol); + } + + return symbol.address; +} + +static void tryToFindSymbolInLinkedLibraries(SymbolDescription &symbol) +{ + symbol.address = dlsym(RTLD_NEXT, symbol.name); +} + +static void tryToFindSymbolInAllLoadedLibraries(SymbolDescription &symbol) +{ + dl_iterate_phdr(checkIfLibraryContainsSymbol, &symbol); +} + +static int checkIfLibraryContainsSymbol(InfoAboutLoadedLib library_description, size_t /* size */, + void *data) +{ + SymbolDescription *symbol = (SymbolDescription *)data; + + void *handle = dlopen(library_description->dlpi_name, RTLD_NOW); + symbol->address = dlsym(handle, symbol->name); + dlclose(handle); + if (symbol->address && isSymbolAddressNotInTheSameTranslationUnit(symbol)) + { + return 1; + } + return 0; +} + +static bool isSymbolAddressNotInTheSameTranslationUnit(SymbolDescription *symbol) +{ + void *handle = dlopen("", RTLD_NOW); + void *addressInTheSameTranslationUnit = dlsym(handle, symbol->name); + dlclose(handle); + + return addressInTheSameTranslationUnit == nullptr || + addressInTheSameTranslationUnit != symbol->address; +} diff --git a/runtime/contrib/heap_trace/src/symbol_searcher.h b/runtime/contrib/heap_trace/src/symbol_searcher.h new file mode 100644 index 000000000..f70a4e46f --- /dev/null +++ b/runtime/contrib/heap_trace/src/symbol_searcher.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYMBOL_SEARCHER_H +#define SYMBOL_SEARCHER_H + +void *findSymbol(const char *name); + +#endif // ! SYMBOL_SEARCHER_H diff --git a/runtime/contrib/heap_trace/src/trace.cc b/runtime/contrib/heap_trace/src/trace.cc new file mode 100644 index 000000000..82f2915cb --- /dev/null +++ b/runtime/contrib/heap_trace/src/trace.cc @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "trace.h" + +#include <memory> + +std::unique_ptr<Trace> GlobalTrace(new Trace); + +bool Trace::Guard::_is_trace_not_available = true; +thread_local bool Trace::Guard::_is_recursion_detected = false; + +Trace::Trace() +{ + if (!_out.is_open()) + { + _out.open(getLogFileNameFromEnvVariable("HEAP_TRACE_LOG")); + } + + Guard{}.markTraceAsReady(); +} + +const char *Trace::getLogFileNameFromEnvVariable(const char *env_variable_name) +{ + return getenv(env_variable_name); +} + +void Trace::logAllocationEvent(void *memory_ptr, size_t size_of_allocated_space_in_bytes) +{ + Guard{}.signalizeAboutPossibleRecursion(); + std::lock_guard<std::mutex> guard(_lock); + _total_allocated_bytes_on_cpu += size_of_allocated_space_in_bytes; + if (_peak_heap_usage_on_cpu < _total_allocated_bytes_on_cpu - _total_deallocated_bytes_on_cpu) + { + _peak_heap_usage_on_cpu = _total_allocated_bytes_on_cpu - _total_deallocated_bytes_on_cpu; + } + _memory_in_use_on_cpu[memory_ptr] = size_of_allocated_space_in_bytes; + Guard{}.signalizeThatDangerOfRecursionHAsPassed(); +} + +void Trace::logDeallocationEvent(void *memory_ptr) +{ + Guard{}.signalizeAboutPossibleRecursion(); + std::lock_guard<std::mutex> guard(_lock); + auto found_memory_space_description = _memory_in_use_on_cpu.find(memory_ptr); + if (found_memory_space_description != _memory_in_use_on_cpu.end()) + { + _total_deallocated_bytes_on_cpu += found_memory_space_description->second; + _memory_in_use_on_cpu.erase(found_memory_space_description); + } + Guard{}.signalizeThatDangerOfRecursionHAsPassed(); +} + +void Trace::logAllocationEvent(cl_mem memory_ptr, size_t size_of_allocated_space_in_bytes) +{ + Guard{}.signalizeAboutPossibleRecursion(); + std::lock_guard<std::mutex> guard(_lock); + _total_allocated_bytes_on_gpu += size_of_allocated_space_in_bytes; + if (_peak_heap_usage_on_gpu < _total_allocated_bytes_on_gpu - _total_deallocated_bytes_on_gpu) + { + _peak_heap_usage_on_gpu = _total_allocated_bytes_on_gpu - _total_deallocated_bytes_on_gpu; + } + _memory_in_use_on_gpu[memory_ptr] = size_of_allocated_space_in_bytes; + Guard{}.signalizeThatDangerOfRecursionHAsPassed(); +} + +void Trace::logDeallocationEvent(cl_mem memory_ptr) +{ + Guard{}.signalizeAboutPossibleRecursion(); + std::lock_guard<std::mutex> guard(_lock); + auto found_memory_space_description = _memory_in_use_on_gpu.find(memory_ptr); + if (found_memory_space_description != _memory_in_use_on_gpu.end()) + { + _total_deallocated_bytes_on_gpu += found_memory_space_description->second; + _memory_in_use_on_gpu.erase(found_memory_space_description); + } + Guard{}.signalizeThatDangerOfRecursionHAsPassed(); +} + +Trace::~Trace() +{ + Guard{}.markTraceAsNotReady(); + + _out << "On CPU - Peak heap usage: " << _peak_heap_usage_on_cpu + << " B, Total allocated: " << _total_allocated_bytes_on_cpu + << " B, Total deallocated: " << _total_deallocated_bytes_on_cpu << " B\n"; + _out << "On GPU - Peak mem usage: " << _peak_heap_usage_on_gpu + << " B, Total allocated: " << _total_allocated_bytes_on_gpu + << " B, Total deallocated: " << _total_deallocated_bytes_on_gpu << " B\n"; +} diff --git a/runtime/contrib/heap_trace/src/trace.h b/runtime/contrib/heap_trace/src/trace.h new file mode 100644 index 000000000..f03a65a58 --- /dev/null +++ b/runtime/contrib/heap_trace/src/trace.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TRACE_H_ +#define TRACE_H_ + +#include <CL/cl.h> + +#include <unordered_map> +#include <fstream> +#include <mutex> + +class Trace +{ +public: + class Guard + { + friend class Trace; + + public: + bool isActive() { return _is_trace_not_available || _is_recursion_detected; } + + private: + void markTraceAsReady() { _is_trace_not_available = false; } + void markTraceAsNotReady() { _is_trace_not_available = true; } + void signalizeAboutPossibleRecursion() { _is_recursion_detected = true; } + void signalizeThatDangerOfRecursionHAsPassed() { _is_recursion_detected = false; } + + private: + static bool _is_trace_not_available; + static thread_local bool _is_recursion_detected; + }; + +public: + Trace(); + Trace(const Trace &) = delete; + const Trace &operator=(const Trace &) = delete; + + void logAllocationEvent(void *memory_ptr, size_t size_of_allocated_space_in_bytes); + void logAllocationEvent(cl_mem memory_ptr, size_t size_of_allocated_space_in_bytes); + void logDeallocationEvent(void *memory_ptr); + void logDeallocationEvent(cl_mem memory_ptr); + + ~Trace(); + +private: + const char *getLogFileNameFromEnvVariable(const char *env_variable_name); + +private: + std::mutex _lock; + std::ofstream _out; + size_t _total_allocated_bytes_on_cpu = 0; + size_t _total_deallocated_bytes_on_cpu = 0; + size_t _peak_heap_usage_on_cpu = 0; + size_t _total_allocated_bytes_on_gpu = 0; + size_t _total_deallocated_bytes_on_gpu = 0; + size_t _peak_heap_usage_on_gpu = 0; + std::unordered_map<void *, size_t> _memory_in_use_on_cpu; + std::unordered_map<cl_mem, size_t> _memory_in_use_on_gpu; +}; + +#endif // !TRACE_H diff --git a/runtime/contrib/heap_trace/src/valloc_stub.cc b/runtime/contrib/heap_trace/src/valloc_stub.cc new file mode 100644 index 000000000..24e91bd11 --- /dev/null +++ b/runtime/contrib/heap_trace/src/valloc_stub.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "trace.h" +#include "function_resolver.h" + +#include <memory> + +extern std::unique_ptr<Trace> GlobalTrace; + +extern "C" { + +void *valloc(size_t sz) noexcept +{ + static auto isOriginalFunctionCallSuccessful = [](void *result) -> bool { return result; }; + + static auto originalFunction = findFunctionByName<void *, size_t>("valloc"); + void *result = originalFunction(sz); + if (isOriginalFunctionCallSuccessful(result) && !Trace::Guard{}.isActive()) + { + GlobalTrace->logAllocationEvent(result, sz); + } + + return result; +} +} diff --git a/runtime/contrib/heap_trace/tests/CMakeLists.txt b/runtime/contrib/heap_trace/tests/CMakeLists.txt new file mode 100644 index 000000000..8fbe5dec1 --- /dev/null +++ b/runtime/contrib/heap_trace/tests/CMakeLists.txt @@ -0,0 +1,43 @@ +set(HEAP_TRACE_TESTS heap_trace_test) + +find_package(OpenCL REQUIRED) + +add_library(test_sample1 SHARED src/test_sample1/test_sample1.cc) + +add_library(test_sample2 SHARED src/test_sample2/test_sample2.cc) +target_link_libraries(test_sample2 test_sample3) + +add_library(test_sample3 SHARED src/test_sample3/test_sample3.cc) + +add_library(test_sample4 SHARED src/test_sample4/test_sample4.cc) + +add_executable(${HEAP_TRACE_TESTS} src/cl_release_mem_object_interception_test.cc + src/symbol_searcher_test.cc + src/cl_create_buffer_interception_test.cc + src/free_interception_test.cc + src/main.cc + src/common_test_environment.cc + src/trace_test.cc + src/malloc_interception_test.cc + src/realloc_interception_test.cc + src/valloc_interception_test.cc + src/file_content_manipulations.cc + ) +target_include_directories(${HEAP_TRACE_TESTS} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../src) +target_link_libraries(${HEAP_TRACE_TESTS} test_sample1) +target_link_libraries(${HEAP_TRACE_TESTS} heap_trace) +target_link_libraries(${HEAP_TRACE_TESTS} test_sample4) +target_link_libraries(${HEAP_TRACE_TESTS} gtest) +target_link_libraries(${HEAP_TRACE_TESTS} gtest_main) +target_link_libraries(${HEAP_TRACE_TESTS} ${LIB_PTHREAD}) +target_link_libraries(${HEAP_TRACE_TESTS} ${CMAKE_DL_LIBS}) +target_link_libraries(${HEAP_TRACE_TESTS} ${OpenCL_LIBRARY}) +target_link_libraries(${HEAP_TRACE_TESTS} stdc++fs) + +add_test(${HEAP_TRACE_TESTS} ${HEAP_TRACE_TESTS}) + +install(TARGETS test_sample1 DESTINATION unittest) +install(TARGETS test_sample2 DESTINATION unittest) +install(TARGETS test_sample3 DESTINATION unittest) +install(TARGETS test_sample4 DESTINATION unittest) +install(TARGETS ${HEAP_TRACE_TESTS} DESTINATION unittest) diff --git a/runtime/contrib/heap_trace/tests/src/cl_create_buffer_interception_test.cc b/runtime/contrib/heap_trace/tests/src/cl_create_buffer_interception_test.cc new file mode 100644 index 000000000..33d01868e --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/cl_create_buffer_interception_test.cc @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common_test_environment.h" +#include "file_content_manipulations.h" + +#include "trace.h" + +#include <CL/cl.h> + +extern std::unique_ptr<Trace> GlobalTrace; + +namespace backstage +{ + +struct ClCreateBufferStub : public TestEnv +{ + cl_context context; + + ClCreateBufferStub() : TestEnv("./cl_create_buffer_interception_test.log") {} + + void SetUp() final + { + cl_device_id device_id; + int err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_GPU, 1, &device_id, NULL); + context = clCreateContext(0, 1, &device_id, NULL, NULL, &err); + + TestEnv::SetUp(); + } + + void TearDown() final + { + TestEnv::TearDown(); + + clReleaseContext(context); + } +}; + +TEST_F(ClCreateBufferStub, must_allocate_space_as_standard_ocl_function) +{ + cl_mem mem = clCreateBuffer(context, CL_MEM_READ_WRITE, 1024 * 1024, NULL, NULL); + + ASSERT_TRUE(mem); + + clReleaseMemObject(mem); +} + +TEST_F(ClCreateBufferStub, must_log_allocation_events_if_trace_is_ready_for_it) +{ + GlobalTrace.reset(); + clReleaseMemObject(clCreateBuffer(context, CL_MEM_READ_WRITE, 1024, NULL, NULL)); + + GlobalTrace.reset(new Trace); + clReleaseMemObject(clCreateBuffer(context, CL_MEM_READ_WRITE, 128, NULL, NULL)); + clReleaseMemObject(clCreateBuffer(context, CL_MEM_READ_WRITE, 64, NULL, NULL)); + GlobalTrace.reset(); + + ASSERT_STREQ(getContentOfFile("./cl_create_buffer_interception_test.log").c_str(), + "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn " + "GPU - Peak mem usage: 128 B, Total allocated: 192 B, Total deallocated: 192 B\n"); +} + +TEST_F(ClCreateBufferStub, + must_not_do_the_record_about_allocation_event_if_original_function_failed) +{ + cl_context badContext = nullptr; + cl_mem p = clCreateBuffer(badContext, CL_MEM_READ_WRITE, 1024, nullptr, nullptr); + GlobalTrace.reset(); + + ASSERT_FALSE(p); + ASSERT_STREQ(getContentOfFile("./cl_create_buffer_interception_test.log").c_str(), + "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn " + "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n"); +} + +} // namespace backstage diff --git a/runtime/contrib/heap_trace/tests/src/cl_release_mem_object_interception_test.cc b/runtime/contrib/heap_trace/tests/src/cl_release_mem_object_interception_test.cc new file mode 100644 index 000000000..ddd1a0d5c --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/cl_release_mem_object_interception_test.cc @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common_test_environment.h" +#include "file_content_manipulations.h" + +#include "trace.h" + +#include <CL/cl.h> + +extern std::unique_ptr<Trace> GlobalTrace; + +namespace backstage +{ + +struct ClReleaseMemObjectStub : public TestEnv +{ + cl_context context; + + ClReleaseMemObjectStub() : TestEnv("./cl_release_mem_object_interception_test.log") {} + + void SetUp() final + { + cl_device_id device_id; + int err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_GPU, 1, &device_id, NULL); + context = clCreateContext(0, 1, &device_id, NULL, NULL, &err); + + TestEnv::SetUp(); + } + + void TearDown() final + { + TestEnv::TearDown(); + + clReleaseContext(context); + } +}; + +TEST_F(ClReleaseMemObjectStub, should_work_as_standard_version) +{ + cl_mem mem = clCreateBuffer(context, CL_MEM_READ_WRITE, 1024, NULL, NULL); + clReleaseMemObject(mem); + ASSERT_TRUE(mem); +} + +TEST_F(ClReleaseMemObjectStub, must_log_deallocation_events_if_trace_is_ready_for_it) +{ + GlobalTrace.reset(); + cl_mem mem1 = clCreateBuffer(context, CL_MEM_READ_WRITE, 1024, NULL, NULL); + ASSERT_TRUE(mem1); + clReleaseMemObject(mem1); + + GlobalTrace.reset(new Trace); + cl_mem mem2 = clCreateBuffer(context, CL_MEM_READ_WRITE, 128, NULL, NULL); + cl_mem mem3 = clCreateBuffer(context, CL_MEM_READ_WRITE, 64, NULL, NULL); + ASSERT_TRUE(mem2 && mem3); + clReleaseMemObject(mem2); + clReleaseMemObject(mem3); + GlobalTrace.reset(); + + ASSERT_STREQ(getContentOfFile("./cl_release_mem_object_interception_test.log").c_str(), + "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn " + "GPU - Peak mem usage: 192 B, Total allocated: 192 B, Total deallocated: 192 B\n"); +} + +TEST_F(ClReleaseMemObjectStub, must_not_log_deallocation_event_if_original_function_failed) +{ + cl_mem mem; + ASSERT_NE(clReleaseMemObject(mem), CL_SUCCESS); + + GlobalTrace.reset(); + + ASSERT_STREQ(getContentOfFile("./cl_release_mem_object_interception_test.log").c_str(), + "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn " + "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n"); +} + +} // namespace backstage diff --git a/runtime/contrib/heap_trace/tests/src/common_test_environment.cc b/runtime/contrib/heap_trace/tests/src/common_test_environment.cc new file mode 100644 index 000000000..e5c4dc121 --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/common_test_environment.cc @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common_test_environment.h" + +#include "trace.h" + +#include <experimental/filesystem> + +namespace fs = std::experimental::filesystem; + +extern std::unique_ptr<Trace> GlobalTrace; + +void TestEnv::SetUp() { configureTraceToMakeLogInFile(); } + +void TestEnv::TearDown() { removeOldTraceLogIfNeed(); } + +void TestEnv::configureTraceToMakeLogInFile() +{ + removeOldTraceLogIfNeed(); + setNewNameOfTraceLog(); +} + +void TestEnv::removeOldTraceLogIfNeed() +{ + GlobalTrace.reset(); + const char *trace_log_name = getenv("HEAP_TRACE_LOG"); + if (trace_log_name) + { + fs::remove(trace_log_name); + } +} + +void TestEnv::setNewNameOfTraceLog() +{ + setenv("HEAP_TRACE_LOG", test_log_file.c_str(), 1); + GlobalTrace.reset(new ::Trace); +} diff --git a/runtime/contrib/heap_trace/tests/src/common_test_environment.h b/runtime/contrib/heap_trace/tests/src/common_test_environment.h new file mode 100644 index 000000000..8c4c9e396 --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/common_test_environment.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COMMON_TEST_ENVIRONMENT_H +#define COMMON_TEST_ENVIRONMENT_H + +#include "gtest/gtest.h" + +struct TestEnv : public ::testing::Test +{ + TestEnv(const char *log_file) : test_log_file(log_file) {} + + void SetUp() override; + void TearDown() override; + +private: + void configureTraceToMakeLogInFile(); + void removeOldTraceLogIfNeed(); + void setNewNameOfTraceLog(); + +private: + std::string test_log_file; +}; + +#endif // ! COMMON_TEST_ENVIRONMENT_H diff --git a/runtime/contrib/heap_trace/tests/src/file_content_manipulations.cc b/runtime/contrib/heap_trace/tests/src/file_content_manipulations.cc new file mode 100644 index 000000000..0c968ab4b --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/file_content_manipulations.cc @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "file_content_manipulations.h" + +#include <fstream> + +std::string getContentOfFile(const char *file_name) +{ + std::ifstream in(file_name); + return std::string((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>()); +} diff --git a/runtime/contrib/heap_trace/tests/src/file_content_manipulations.h b/runtime/contrib/heap_trace/tests/src/file_content_manipulations.h new file mode 100644 index 000000000..ba938931c --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/file_content_manipulations.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TEST_SUPPORT_H +#define TEST_SUPPORT_H + +#include <string> + +std::string getContentOfFile(const char *file_name); + +#endif //! TEST_SUPPORT_H diff --git a/runtime/contrib/heap_trace/tests/src/free_interception_test.cc b/runtime/contrib/heap_trace/tests/src/free_interception_test.cc new file mode 100644 index 000000000..e690718d0 --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/free_interception_test.cc @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common_test_environment.h" +#include "file_content_manipulations.h" + +#include "trace.h" + +extern std::unique_ptr<Trace> GlobalTrace; + +namespace backstage +{ + +struct FreeStub : public TestEnv +{ + FreeStub() : TestEnv("./free_interception_test.log") {} +}; + +TEST_F(FreeStub, should_work_as_standard_version) +{ + void *p = malloc(1024); + free(p); + ASSERT_TRUE(p); + // TODO Bad test. Need use death test from Google test framework +} + +TEST_F(FreeStub, must_log_deallocation_events_if_trace_is_ready_for_it) +{ + GlobalTrace.reset(); + void *p1 = malloc(1024); + ASSERT_TRUE(p1); + free(p1); + + GlobalTrace.reset(new Trace); + void *p2 = malloc(128); + void *p3 = malloc(64); + ASSERT_TRUE(p2 && p3); + free(p2); + free(p3); + GlobalTrace.reset(); + + ASSERT_STREQ(getContentOfFile("./free_interception_test.log").c_str(), + "On CPU - Peak heap usage: 192 B, Total allocated: 192 B, Total deallocated: 192 " + "B\nOn GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n"); +} + +} // namespace backstage diff --git a/runtime/contrib/heap_trace/tests/src/main.cc b/runtime/contrib/heap_trace/tests/src/main.cc new file mode 100644 index 000000000..b53b2030b --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/main.cc @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gtest/gtest.h" + +int main(int argc, char *argv[]) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/runtime/contrib/heap_trace/tests/src/malloc_interception_test.cc b/runtime/contrib/heap_trace/tests/src/malloc_interception_test.cc new file mode 100644 index 000000000..7a2f5a915 --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/malloc_interception_test.cc @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common_test_environment.h" +#include "file_content_manipulations.h" + +#include "trace.h" + +#include <experimental/filesystem> +#include <limits> + +extern std::unique_ptr<Trace> GlobalTrace; + +namespace backstage +{ + +struct MallocStub : public TestEnv +{ + MallocStub() : TestEnv("./malloc_interception_test.log") {} +}; + +TEST_F(MallocStub, must_allocate_space_as_standard_malloc) +{ + void *p = malloc(128); + + ASSERT_TRUE(p); + free(p); +} + +TEST_F(MallocStub, must_log_allocation_events_if_trace_is_ready_for_it) +{ + GlobalTrace.reset(); + void *p1 = malloc(1024); + + GlobalTrace.reset(new Trace); + void *p2 = malloc(128); + void *p3 = malloc(64); + GlobalTrace.reset(); + + ASSERT_TRUE(p1 && p2 && p3); + ASSERT_STREQ(getContentOfFile("./malloc_interception_test.log").c_str(), + "On CPU - Peak heap usage: 192 B, Total allocated: 192 B, Total deallocated: 0 " + "B\nOn GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n"); + free(p1); + free(p2); + free(p3); +} + +TEST_F(MallocStub, must_not_do_the_record_about_allocation_event_if_original_function_failed) +{ + void *p = malloc(std::numeric_limits<size_t>::max()); + GlobalTrace.reset(); + + ASSERT_FALSE(p); + ASSERT_STREQ(getContentOfFile("./malloc_interception_test.log").c_str(), + "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn " + "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n"); +} + +TEST_F( + MallocStub, + should_not_influence_on_trace_results_even_if_orignal_function_return_any_not_null_ptr_when_incoming_size_is_zero) +{ + void *p = malloc(0); + free(p); + GlobalTrace.reset(); + + ASSERT_TRUE(p); + ASSERT_STREQ(getContentOfFile("./malloc_interception_test.log").c_str(), + "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn " + "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n"); +} + +} // namespace backstage diff --git a/runtime/contrib/heap_trace/tests/src/realloc_interception_test.cc b/runtime/contrib/heap_trace/tests/src/realloc_interception_test.cc new file mode 100644 index 000000000..160a19beb --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/realloc_interception_test.cc @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common_test_environment.h" +#include "file_content_manipulations.h" + +#include "trace.h" + +#include <experimental/filesystem> +#include <limits> +#include <cstring> + +extern std::unique_ptr<Trace> GlobalTrace; + +namespace backstage +{ + +struct ReallocStub : public TestEnv +{ + ReallocStub() : TestEnv("./realloc_interception_test.log") {} +}; + +TEST_F(ReallocStub, must_allocate_space_as_standard_realloc) +{ + void *p = malloc(128); + p = realloc(p, 1024); + + ASSERT_TRUE(p); + free(p); +} + +TEST_F(ReallocStub, must_log_allocation_deallocation_events_if_trace_is_ready_for_it) +{ + std::array<char, 1024> reference_data; + reference_data.fill('a'); + void *p1 = malloc(1024); + memcpy(p1, reference_data.data(), reference_data.size()); + void *p2 = realloc(p1, 64); + void *p3 = realloc(p2, 128); + GlobalTrace.reset(); + + ASSERT_TRUE(p3); + ASSERT_TRUE(memcmp(p3, reference_data.data(), 64) == 0); + ASSERT_STREQ(getContentOfFile("./realloc_interception_test.log").c_str(), + "On CPU - Peak heap usage: 1024 B, Total allocated: 1216 B, Total deallocated: 1088 " + "B\nOn GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n"); + free(p3); +} + +TEST_F(ReallocStub, + must_not_do_the_record_about_allocation_deallocation_events_if_original_function_failed) +{ + GlobalTrace.reset(); + void *p = malloc(128); + GlobalTrace.reset(new Trace); + + void *ptr_after_realloc = realloc(p, std::numeric_limits<size_t>::max()); + ptr_after_realloc = realloc(p, 0); + GlobalTrace.reset(); + + ASSERT_FALSE(ptr_after_realloc); + ASSERT_STREQ(getContentOfFile("./realloc_interception_test.log").c_str(), + "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn " + "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n"); + + free(p); +} + +TEST_F(ReallocStub, should_work_as_malloc_when_incoming_ptr_is_equal_to_nullptr) +{ + void *p = realloc(nullptr, 1024); + GlobalTrace.reset(); + + ASSERT_TRUE(p); + ASSERT_STREQ( + getContentOfFile("./realloc_interception_test.log").c_str(), + "On CPU - Peak heap usage: 1024 B, Total allocated: 1024 B, Total deallocated: 0 B\nOn " + "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n"); + + free(p); +} + +TEST_F( + ReallocStub, + should_not_influence_on_trace_results_even_if_orignal_function_return_any_not_null_ptr_when_incoming_size_is_zero_and_ptr_is_null) +{ + void *p = realloc(nullptr, 0); + free(p); + GlobalTrace.reset(); + + ASSERT_TRUE(p); + ASSERT_STREQ(getContentOfFile("./realloc_interception_test.log").c_str(), + "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn " + "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n"); +} + +} // namespace backstage diff --git a/runtime/contrib/heap_trace/tests/src/symbol_searcher_test.cc b/runtime/contrib/heap_trace/tests/src/symbol_searcher_test.cc new file mode 100644 index 000000000..d615cc928 --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/symbol_searcher_test.cc @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gtest/gtest.h" +#include "test_sample1.h" +#include "test_sample2.h" +#include "test_sample4.h" + +#include "symbol_searcher.h" + +#include <dlfcn.h> +#include <linux/limits.h> +#include <unistd.h> + +#include <cstdlib> + +#include <experimental/filesystem> + +namespace fs = std::experimental::filesystem; + +fs::path exePath() +{ + char result[PATH_MAX] = {0}; + ssize_t count = readlink("/proc/self/exe", result, PATH_MAX); + return fs::path(result).parent_path(); +} + +namespace backstage +{ + +struct SymbolSearcher : public ::testing::Test +{ +}; + +TEST_F(SymbolSearcher, should_find_symbol_in_linked_library) +{ + ASSERT_TRUE((void *)funcDefinedOnlyInTestSample4 == findSymbol("funcDefinedOnlyInTestSample4")); +} + +TEST_F(SymbolSearcher, should_find_symbol_in_library_which_have_been_loaded_in_runtime) +{ + fs::path pathToTestLib = exePath() / "libtest_sample2.so"; + void *handle = dlopen(pathToTestLib.c_str(), RTLD_NOW); + + ASSERT_TRUE(handle); + ASSERT_TRUE(dlsym(handle, "funcDefinedOnlyInTestSample2") == + findSymbol("funcDefinedOnlyInTestSample2")); + dlclose(handle); +} + +TEST_F(SymbolSearcher, + should_ignore_symbols_found_in_current_translation_unit_if_there_is_another_alternative) +{ + fs::path pathToTestSample2 = exePath() / "libtest_sample2.so"; + void *test_sample2_handle = dlopen(pathToTestSample2.c_str(), RTLD_NOW); + void *func_addr_in_test_sample2 = + dlsym(test_sample2_handle, "funcWhichCallFuncDefinedInTestSample3"); + + ASSERT_TRUE(test_sample2_handle); + ASSERT_TRUE((void *)funcDefinedInTestSample3_ButWrappedInTestSample1 != + reinterpret_cast<void *(*)()>(func_addr_in_test_sample2)()); + + dlclose(test_sample2_handle); +} + +} // namespace backstage diff --git a/runtime/contrib/heap_trace/tests/src/test_sample1.h b/runtime/contrib/heap_trace/tests/src/test_sample1.h new file mode 100644 index 000000000..3abea56a3 --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/test_sample1.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TEST_SAMPLE1_H +#define TEST_SAMPLE1_H + +extern "C" { + +void *funcDefinedInTestSample3_ButWrappedInTestSample1(); +} + +#endif // ! TEST_SAMPLE1_H diff --git a/runtime/contrib/heap_trace/tests/src/test_sample1/test_sample1.cc b/runtime/contrib/heap_trace/tests/src/test_sample1/test_sample1.cc new file mode 100644 index 000000000..1d2843707 --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/test_sample1/test_sample1.cc @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../test_sample1.h" + +#include "../../../src/symbol_searcher.h" + +extern "C" { + +void *funcDefinedInTestSample3_ButWrappedInTestSample1() +{ + return findSymbol("funcDefinedInTestSample3_ButWrappedInTestSample1"); +} +} diff --git a/runtime/contrib/heap_trace/tests/src/test_sample2.h b/runtime/contrib/heap_trace/tests/src/test_sample2.h new file mode 100644 index 000000000..785fc252d --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/test_sample2.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TEST_SAMPLE2_H +#define TEST_SAMPLE2_H + +extern "C" { + +void funcDefinedOnlyInTestSample2(); +void funcWhichCallFuncDefinedInTestSample3(); +} + +#endif // ! TEST_SAMPLE2_H diff --git a/runtime/contrib/heap_trace/tests/src/test_sample2/test_sample2.cc b/runtime/contrib/heap_trace/tests/src/test_sample2/test_sample2.cc new file mode 100644 index 000000000..792dba665 --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/test_sample2/test_sample2.cc @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../test_sample2.h" +#include "../test_sample3.h" + +extern "C" { + +void funcDefinedOnlyInTestSample2() {} +void funcWhichCallFuncDefinedInTestSample3() { funcDefinedInTestSample3_ButWrappedInTestSample1(); } +} diff --git a/runtime/contrib/heap_trace/tests/src/test_sample3.h b/runtime/contrib/heap_trace/tests/src/test_sample3.h new file mode 100644 index 000000000..8f85b8bd6 --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/test_sample3.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TEST_SAMPLE3_H +#define TEST_SAMPLE3_H + +extern "C" { + +void funcDefinedInTestSample3_ButWrappedInTestSample1(); +} + +#endif // ! TEST_SAMPLE3_H diff --git a/runtime/contrib/heap_trace/tests/src/test_sample3/test_sample3.cc b/runtime/contrib/heap_trace/tests/src/test_sample3/test_sample3.cc new file mode 100644 index 000000000..ded78db85 --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/test_sample3/test_sample3.cc @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern "C" { + +void funcDefinedInTestSample3_ButWrappedInTestSample1() {} +} diff --git a/runtime/contrib/heap_trace/tests/src/test_sample4.h b/runtime/contrib/heap_trace/tests/src/test_sample4.h new file mode 100644 index 000000000..47c9e8c92 --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/test_sample4.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TEST_SAMPLE4_H +#define TEST_SAMPLE4_H + +extern "C" { + +void funcDefinedOnlyInTestSample4(); +} + +#endif // ! TEST_SAMPLE4_H diff --git a/runtime/contrib/heap_trace/tests/src/test_sample4/test_sample4.cc b/runtime/contrib/heap_trace/tests/src/test_sample4/test_sample4.cc new file mode 100644 index 000000000..55c96cb0e --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/test_sample4/test_sample4.cc @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../test_sample4.h" + +extern "C" { +void funcDefinedOnlyInTestSample4() {} +} diff --git a/runtime/contrib/heap_trace/tests/src/trace_test.cc b/runtime/contrib/heap_trace/tests/src/trace_test.cc new file mode 100644 index 000000000..1cf4c530b --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/trace_test.cc @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common_test_environment.h" +#include "file_content_manipulations.h" + +#include "trace.h" + +#include <CL/cl.h> + +#include <experimental/filesystem> +#include <thread> +#include <atomic> + +using namespace std; +namespace fs = experimental::filesystem; + +extern unique_ptr<::Trace> GlobalTrace; + +namespace backstage +{ + +struct Trace : TestEnv +{ + Trace() : TestEnv("./trace_test.log") {} + + void generateGarbageInTestLogFile(); + template <typename MemType> + static void emulateAllocationEvent(size_t eventsPoolId, size_t numberOfEmulation, + size_t numberOfBytesPerOneEmulation, atomic_bool &isPauseNeed); +}; + +TEST_F(Trace, + must_create_log_file_with_name_defined_in_env_var_HEAP_TRACE_LOG_during_initialization) +{ + ASSERT_TRUE(fs::exists("./trace_test.log")); +} + +TEST_F(Trace, must_truncate_log_file_if_it_exists_during_initialization) +{ + GlobalTrace.reset(); + generateGarbageInTestLogFile(); + GlobalTrace.reset(new ::Trace); + GlobalTrace.reset(); + + ASSERT_STREQ(getContentOfFile("./trace_test.log").c_str(), + "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn " + "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n"); +} + +void Trace::generateGarbageInTestLogFile() +{ + ofstream log("./trace_test.log"); + log << string(256, 'a'); +} + +TEST_F(Trace, should_not_generate_any_records_in_log_during_creation) +{ + GlobalTrace.reset(); + + ASSERT_STREQ(getContentOfFile("./trace_test.log").c_str(), + "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn " + "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n"); +} + +TEST_F(Trace, can_signalize_to_users_if_it_is_ready_for_using) +{ + ASSERT_FALSE(::Trace::Guard().isActive()); +} + +TEST_F(Trace, must_signalize_that_it_is_not_ready_for_using_until_it_is_not_created) +{ + GlobalTrace.reset(); + ASSERT_TRUE(::Trace::Guard().isActive()); +} + +TEST_F(Trace, should_work_correctly_in_multithreaded_environment) +{ + constexpr size_t numberOfThreads = 10, numberOfEmulations = 100, + numberOfBytesPerOneEmulation = 1024; + atomic_bool isPauseNeed{true}; + array<thread, numberOfThreads> threads; + for (size_t i = 0; i < numberOfThreads / 2; ++i) + { + threads[i] = thread(emulateAllocationEvent<void *>, i, numberOfEmulations, + numberOfBytesPerOneEmulation, ref(isPauseNeed)); + } + for (size_t i = numberOfThreads / 2; i < numberOfThreads; ++i) + { + threads[i] = thread(emulateAllocationEvent<cl_mem>, i, numberOfEmulations, + numberOfBytesPerOneEmulation, ref(isPauseNeed)); + } + + GlobalTrace.reset(new ::Trace); + isPauseNeed = false; + + for (size_t i = 0; i < numberOfThreads; ++i) + { + threads[i].join(); + } + GlobalTrace.reset(); + + string thisShouldBeInLogFile = + "Total allocated: " + + to_string(numberOfThreads / 2 * numberOfEmulations * numberOfBytesPerOneEmulation) + + " B, Total deallocated: " + + to_string(numberOfThreads / 2 * numberOfEmulations * numberOfBytesPerOneEmulation) + " B\n"; + string andThisToo = + "Total allocated: " + + to_string(numberOfThreads / 2 * numberOfEmulations * numberOfBytesPerOneEmulation) + + " B, Total deallocated: " + + to_string(numberOfThreads / 2 * numberOfEmulations * numberOfBytesPerOneEmulation) + " B\n"; + ASSERT_TRUE(getContentOfFile("./trace_test.log").find(thisShouldBeInLogFile) != string::npos); + ASSERT_TRUE(getContentOfFile("./trace_test.log").find(andThisToo) != string::npos); +} + +template <typename MemType> +void Trace::emulateAllocationEvent(size_t eventsPoolId, size_t numberOfEmulation, + size_t numberOfBytesPerOneEmulation, atomic_bool &isPauseNeed) +{ + while (isPauseNeed) + { + continue; + } + + for (size_t i = 1; i <= numberOfEmulation; ++i) + { + GlobalTrace->logAllocationEvent((MemType)(i + numberOfEmulation * eventsPoolId), + numberOfBytesPerOneEmulation); + } + + for (size_t i = 1; i <= numberOfEmulation; ++i) + { + GlobalTrace->logDeallocationEvent((MemType)(i + numberOfEmulation * eventsPoolId)); + } +} + +TEST_F(Trace, must_log_allocation_and_deallocation_events) +{ + void *memOnCPU1 = (void *)1, *memOnCPU2 = (void *)3; + cl_mem memOnGPU1 = (cl_mem)2, memOnGPU2 = (cl_mem)4; + GlobalTrace->logAllocationEvent(memOnCPU1, 347); + GlobalTrace->logDeallocationEvent(memOnCPU1); + GlobalTrace->logAllocationEvent(memOnGPU2, 592); + GlobalTrace->logDeallocationEvent(memOnGPU2); + GlobalTrace->logAllocationEvent(memOnGPU1, 349); + GlobalTrace->logDeallocationEvent(memOnGPU1); + GlobalTrace->logAllocationEvent(memOnCPU2, 568); + GlobalTrace->logDeallocationEvent(memOnCPU2); + GlobalTrace.reset(); + + string shouldBeInLogFile = "On CPU - Peak heap usage: " + to_string(568) + + " B, Total allocated: " + to_string(347 + 568) + + " B, Total deallocated: " + to_string(347 + 568) + + " B\n" + "On GPU - Peak mem usage: " + + to_string(592) + " B, Total allocated: " + to_string(592 + 349) + + " B, Total deallocated: " + to_string(592 + 349) + " B\n"; + ASSERT_STREQ(getContentOfFile("./trace_test.log").c_str(), shouldBeInLogFile.c_str()); +} + +} // namespace backstage diff --git a/runtime/contrib/heap_trace/tests/src/valloc_interception_test.cc b/runtime/contrib/heap_trace/tests/src/valloc_interception_test.cc new file mode 100644 index 000000000..6b3d6df82 --- /dev/null +++ b/runtime/contrib/heap_trace/tests/src/valloc_interception_test.cc @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common_test_environment.h" +#include "file_content_manipulations.h" + +#include "trace.h" + +#include <experimental/filesystem> +#include <limits> + +extern std::unique_ptr<Trace> GlobalTrace; + +namespace backstage +{ + +struct VallocStub : public TestEnv +{ + VallocStub() : TestEnv("./valloc_interception_test.log") {} +}; + +TEST_F(VallocStub, must_allocate_space_as_standard_valloc) +{ + void *p = valloc(128); + + ASSERT_TRUE(p); + free(p); +} + +TEST_F(VallocStub, must_log_allocation_events_if_trace_is_ready_for_it) +{ + GlobalTrace.reset(); + void *p1 = valloc(1024); + + GlobalTrace.reset(new Trace); + void *p2 = valloc(128); + void *p3 = valloc(64); + GlobalTrace.reset(); + + ASSERT_TRUE(p1 && p2 && p3); + ASSERT_STREQ(getContentOfFile("./valloc_interception_test.log").c_str(), + "On CPU - Peak heap usage: 192 B, Total allocated: 192 B, Total deallocated: 0 " + "B\nOn GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n"); + free(p1); + free(p2); + free(p3); +} + +TEST_F(VallocStub, must_not_do_the_record_about_allocation_event_if_original_function_failed) +{ + void *p = valloc(std::numeric_limits<size_t>::max()); + GlobalTrace.reset(); + + ASSERT_FALSE(p); + ASSERT_STREQ(getContentOfFile("./valloc_interception_test.log").c_str(), + "On CPU - Peak heap usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\nOn " + "GPU - Peak mem usage: 0 B, Total allocated: 0 B, Total deallocated: 0 B\n"); +} + +} // namespace backstage |