add test for thread local (#21976)
### Details: - *add test for thread_local* - *thread_local may cause memory leak during AppVerifier check* ### Tickets: - *CVS-129729* --------- Co-authored-by: Chen Peter <peter.chen@intel.com>
This commit is contained in:
parent
9e899af4d8
commit
cf96284f90
|
|
@ -0,0 +1,28 @@
|
|||
BasedOnStyle: Google
|
||||
IndentWidth: 4
|
||||
UseTab: Never
|
||||
ColumnLimit: 120
|
||||
|
||||
Language: Cpp
|
||||
Standard: Cpp11
|
||||
|
||||
AccessModifierOffset: -4
|
||||
AlignConsecutiveMacros: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: Empty
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
CommentPragmas: '^#'
|
||||
DerivePointerAlignment: false
|
||||
FixNamespaceComments: true
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: AfterHash
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- FOREACH_CHILD
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright (C) 2018-2024 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project(appverifier_tests)
|
||||
|
||||
if(NOT WIN32)
|
||||
message(FATAL_ERROR "This test only supports windows OS")
|
||||
endif()
|
||||
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "CMake build type")
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Release" "Debug" "RelWithDebInfo" "MinSizeRel")
|
||||
|
||||
set(OpenVINO_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../")
|
||||
set(ENABLE_CLANG_FORMAT ON)
|
||||
find_package(OpenVINODeveloperScripts REQUIRED
|
||||
PATHS "${OpenVINO_SOURCE_DIR}/cmake/developer_package"
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
NO_DEFAULT_PATH)
|
||||
|
||||
# Define directory where artifacts will be placed
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test")
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test")
|
||||
set(CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test")
|
||||
set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test")
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test")
|
||||
|
||||
add_subdirectory(thread_local)
|
||||
add_subdirectory(appverifier_tests)
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# AppVerifier Tests Suite
|
||||
|
||||
This test suite is used to detect whether AppVerifier will report a memory leak.
|
||||
|
||||
## Getting Started
|
||||
|
||||
AppVerifier tests are based on the googletest framework. You can filter tests with
|
||||
`--gtest_filter` and explore tests available with `--gtest_list_tests` options.
|
||||
|
||||
### Pre-requisites
|
||||
|
||||
- Windows OS to build the tests.
|
||||
|
||||
### Building Tests
|
||||
|
||||
To build the tests, you need to have OpenVINO™ installed or build from source.
|
||||
Before build the tests, open a terminal, set OpenVINO™ environment, and after that
|
||||
run the commands below:
|
||||
``` bash
|
||||
<OpenVINO_install_dir>/setupvars.bat
|
||||
mkdir build && cd build
|
||||
cmake .. && cmake --build . --config Release -j8
|
||||
```
|
||||
|
||||
### Running Tests
|
||||
|
||||
``` bash
|
||||
.\test\Release\ov_appverifier_tests.exe
|
||||
```
|
||||
|
||||
This test can be run directly using the above command, but if you want to detect whether there is a memory leak, the test executable file need to be added in AppVerifier (refer to https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/application-verifier-testing-applications) before running the above command.
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# Copyright (C) 2018-2024 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
set(TARGET_NAME ov_appverifier_tests)
|
||||
|
||||
file (GLOB_RECURSE SRC *.cpp)
|
||||
file (GLOB_RECURSE HDR *.h)
|
||||
|
||||
# Create library file from sources.
|
||||
add_executable(${TARGET_NAME} ${HDR} ${SRC})
|
||||
|
||||
target_link_libraries(${TARGET_NAME}
|
||||
PUBLIC
|
||||
gtest
|
||||
pugixml
|
||||
gflags
|
||||
PRIVATE
|
||||
gtest_main)
|
||||
|
||||
ov_add_clang_format_target(${TARGET_NAME}_clang FOR_TARGETS ${TARGET_NAME})
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
#include <gtest/gtest.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <future>
|
||||
#include <thread>
|
||||
|
||||
typedef void (*TestFunc)(const std::string&);
|
||||
|
||||
class ThreadLocalTest : public ::testing::Test, public ::testing::WithParamInterface<std::string> {
|
||||
public:
|
||||
void SetUp() {
|
||||
target_device = GetParam();
|
||||
}
|
||||
|
||||
static std::string getTestCaseName(testing::TestParamInfo<std::string> obj) {
|
||||
return obj.param;
|
||||
}
|
||||
|
||||
public:
|
||||
std::string target_device = "";
|
||||
};
|
||||
|
||||
TEST(LoadLibraryTest, load_free_library) {
|
||||
std::promise<void> free_promise;
|
||||
std::future<void> free_future = free_promise.get_future();
|
||||
std::promise<void> thread_exit_promise;
|
||||
std::future<void> thread_exit_future = thread_exit_promise.get_future();
|
||||
auto shared_object = LoadLibraryA("openvino.dll");
|
||||
if (!shared_object) {
|
||||
std::cout << "LoadLibrary openvino.dll fail" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::thread sub_thread = std::thread([&] {
|
||||
free_promise.set_value();
|
||||
thread_exit_future.get();
|
||||
});
|
||||
free_future.get();
|
||||
FreeLibrary(shared_object);
|
||||
|
||||
thread_exit_promise.set_value();
|
||||
if (sub_thread.joinable()) {
|
||||
sub_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ThreadLocalTest, get_property_test) {
|
||||
auto shared_object = LoadLibraryA("ov_thread_local.dll");
|
||||
if (!shared_object) {
|
||||
std::cout << "LoadLibrary ov_thread_local.dll fail" << std::endl;
|
||||
return;
|
||||
}
|
||||
auto procAddr = reinterpret_cast<TestFunc>(GetProcAddress(shared_object, "core_get_property_test"));
|
||||
procAddr(target_device);
|
||||
FreeLibrary(shared_object);
|
||||
}
|
||||
|
||||
TEST_P(ThreadLocalTest, infer_test) {
|
||||
auto shared_object = LoadLibraryA("ov_thread_local.dll");
|
||||
if (!shared_object) {
|
||||
std::cout << "LoadLibrary ov_thread_local.dll fail" << std::endl;
|
||||
return;
|
||||
}
|
||||
auto procAddr = reinterpret_cast<TestFunc>(GetProcAddress(shared_object, "core_infer_test"));
|
||||
procAddr(target_device);
|
||||
FreeLibrary(shared_object);
|
||||
}
|
||||
|
||||
void process_sub_thread(const std::string& func_name, const std::string& target_device) {
|
||||
auto shared_object = LoadLibraryA("ov_thread_local.dll");
|
||||
if (!shared_object) {
|
||||
std::cout << "LoadLibrary ov_thread_local.dll fail" << std::endl;
|
||||
return;
|
||||
}
|
||||
auto procAddr = reinterpret_cast<TestFunc>(GetProcAddress(shared_object, func_name.c_str()));
|
||||
std::promise<void> free_promise;
|
||||
std::future<void> free_future = free_promise.get_future();
|
||||
std::promise<void> thread_exit_promise;
|
||||
std::future<void> thread_exit_future = thread_exit_promise.get_future();
|
||||
std::thread sub_thread = std::thread([&] {
|
||||
procAddr(target_device);
|
||||
free_promise.set_value();
|
||||
thread_exit_future.get();
|
||||
});
|
||||
|
||||
free_future.get();
|
||||
FreeLibrary(shared_object);
|
||||
|
||||
thread_exit_promise.set_value();
|
||||
if (sub_thread.joinable()) {
|
||||
sub_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ThreadLocalTest, get_property_test_subthread) {
|
||||
process_sub_thread("core_get_property_test", target_device);
|
||||
}
|
||||
|
||||
TEST_P(ThreadLocalTest, infer_test_subthread) {
|
||||
process_sub_thread("core_infer_test", target_device);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(OV_ThreadLocalTests,
|
||||
ThreadLocalTest,
|
||||
::testing::Values("CPU", "GPU"),
|
||||
ThreadLocalTest::getTestCaseName);
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
# Copyright (C) 2018-2024 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
set(TARGET_NAME ov_thread_local)
|
||||
|
||||
# Search OpenVINO Runtime installed
|
||||
find_package(PkgConfig QUIET)
|
||||
# TODO: fix cross-compilation later
|
||||
if(PkgConfig_FOUND AND NOT CMAKE_CROSSCOMPILING AND CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
pkg_search_module(openvino REQUIRED
|
||||
IMPORTED_TARGET
|
||||
openvino)
|
||||
set(ov_link_libraries PkgConfig::openvino)
|
||||
else()
|
||||
find_package(OpenVINO REQUIRED COMPONENTS Runtime)
|
||||
set(ov_link_libraries openvino::runtime)
|
||||
endif()
|
||||
|
||||
file (GLOB_RECURSE SRC *.cpp)
|
||||
file (GLOB_RECURSE HDR *.h)
|
||||
|
||||
add_library(${TARGET_NAME} SHARED ${SRC} ${HDR})
|
||||
|
||||
target_include_directories(${TARGET_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
|
||||
add_subdirectory(${OpenVINO_SOURCE_DIR}/thirdparty/gflags
|
||||
${CMAKE_CURRENT_BINARY_DIR}/gflags_build
|
||||
EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(${OpenVINO_SOURCE_DIR}/thirdparty/gtest
|
||||
${CMAKE_CURRENT_BINARY_DIR}/gtest_build
|
||||
EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(${OpenVINO_SOURCE_DIR}/thirdparty/pugixml
|
||||
${CMAKE_CURRENT_BINARY_DIR}/pugixml_build
|
||||
EXCLUDE_FROM_ALL)
|
||||
add_subdirectory("${OpenVINO_SOURCE_DIR}/tests/lib" tests_shared_lib)
|
||||
target_link_libraries(${TARGET_NAME} PUBLIC tests_shared_lib)
|
||||
|
||||
ov_add_clang_format_target(${TARGET_NAME}_clang FOR_TARGETS ${TARGET_NAME})
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
extern "C" __declspec(dllexport) void core_get_property_test(const std::string& target_device);
|
||||
extern "C" __declspec(dllexport) void core_infer_test(const std::string& target_device);
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
#include "thread_local.hpp"
|
||||
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "openvino/core/model.hpp"
|
||||
#include "openvino/core/node_vector.hpp"
|
||||
#include "openvino/core/type/element_type.hpp"
|
||||
#include "openvino/op/concat.hpp"
|
||||
#include "openvino/op/constant.hpp"
|
||||
#include "openvino/op/reshape.hpp"
|
||||
#include "openvino/op/split.hpp"
|
||||
#include "openvino/openvino.hpp"
|
||||
#include "openvino/runtime/properties.hpp"
|
||||
|
||||
std::shared_ptr<ov::Model> make_split_concat(std::vector<size_t> inputShape = {1, 4, 24, 24},
|
||||
ov::element::Type_t type = ov::element::Type_t::f32);
|
||||
|
||||
void core_get_property_test(const std::string& target_device) {
|
||||
std::promise<void> call_finish_promise;
|
||||
auto call_finish_future = call_finish_promise.get_future();
|
||||
std::promise<void> thread_exit_promise;
|
||||
auto thread_exit_future = thread_exit_promise.get_future();
|
||||
std::thread sub_thread;
|
||||
{
|
||||
ov::Core ie;
|
||||
sub_thread = std::thread([&] {
|
||||
ie.get_property(target_device, ov::supported_properties);
|
||||
call_finish_promise.set_value();
|
||||
thread_exit_future.get();
|
||||
});
|
||||
call_finish_future.get();
|
||||
}
|
||||
thread_exit_promise.set_value();
|
||||
if (sub_thread.joinable()) {
|
||||
sub_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<ov::Model> make_split_concat(std::vector<size_t> inputShape, ov::element::Type_t type) {
|
||||
auto param1 = std::make_shared<ov::op::v0::Parameter>(type, ov::Shape{inputShape});
|
||||
param1->set_friendly_name("Param1");
|
||||
param1->output(0).get_tensor().set_names({"data1"});
|
||||
auto axis_node = ov::op::v0::Constant::create(ov::element::i64, ov::Shape{}, {1});
|
||||
auto split = std::make_shared<ov::op::v1::Split>(param1, axis_node, 2);
|
||||
split->set_friendly_name("Split");
|
||||
split->output(0).get_tensor().set_names({"tensor_split_1"});
|
||||
split->output(1).get_tensor().set_names({"tensor_split_2"});
|
||||
|
||||
auto concat = std::make_shared<ov::op::v0::Concat>(ov::OutputVector{split->output(0), split->output(1)}, 1);
|
||||
concat->set_friendly_name("Concat_op");
|
||||
concat->output(0).get_tensor().set_names({"Concat"});
|
||||
auto result = std::make_shared<ov::op::v0::Result>(concat);
|
||||
result->set_friendly_name("Result");
|
||||
auto model_ptr = std::make_shared<ov::Model>(ov::ResultVector{result}, ov::ParameterVector{param1});
|
||||
model_ptr->set_friendly_name("SplitConcat");
|
||||
return model_ptr;
|
||||
}
|
||||
|
||||
void core_infer_test(const std::string& target_device) {
|
||||
std::promise<void> call_finish_promise;
|
||||
std::future<void> call_finish_future = call_finish_promise.get_future();
|
||||
std::promise<void> thread_exit_promise;
|
||||
std::future<void> thread_exit_future = thread_exit_promise.get_future();
|
||||
std::thread sub_thread;
|
||||
auto actualNetwork = make_split_concat();
|
||||
{
|
||||
ov::Core ie;
|
||||
sub_thread = std::thread([&] {
|
||||
auto net = ie.compile_model(actualNetwork, target_device);
|
||||
auto infer_req = net.create_infer_request();
|
||||
ie.get_property(target_device, ov::supported_properties);
|
||||
infer_req.infer();
|
||||
call_finish_promise.set_value();
|
||||
thread_exit_future.get();
|
||||
});
|
||||
call_finish_future.get();
|
||||
}
|
||||
thread_exit_promise.set_value();
|
||||
if (sub_thread.joinable()) {
|
||||
sub_thread.join();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue