From 6ad3e74f4afa127c3179d5be466284e8771b3ea4 Mon Sep 17 00:00:00 2001 From: Ori Levari Date: Mon, 13 Jan 2020 13:56:14 -0800 Subject: [PATCH 1/5] Filter CPU case for IsFloat16Supported (#2802) --- winml/lib/Api.Image/DeviceHelpers.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/winml/lib/Api.Image/DeviceHelpers.cpp b/winml/lib/Api.Image/DeviceHelpers.cpp index 67824624a7..3174f61fad 100644 --- a/winml/lib/Api.Image/DeviceHelpers.cpp +++ b/winml/lib/Api.Image/DeviceHelpers.cpp @@ -9,6 +9,7 @@ #include #include #include "inc/DeviceHelpers.h" +#include "LearningModelDevice.h" namespace DeviceHelpers { constexpr uint32_t c_intelVendorId = 0x8086; @@ -133,6 +134,10 @@ static HRESULT IsFloat16Blocked(ID3D12Device& device, bool* isBlocked) { } bool IsFloat16Supported(const winrt::Windows::AI::MachineLearning::LearningModelDevice& device) { + auto modelImpl = device.as(); + if (modelImpl->IsCpuDevice()) { + return true; + } winrt::com_ptr d3d12Device; if (FAILED(GetD3D12Device(device, d3d12Device.put()))) { return false; From dbe7d97fa1ab155f1309bced87199527e8f35bd2 Mon Sep 17 00:00:00 2001 From: Tiago Koji Castro Shibata Date: Tue, 14 Jan 2020 15:03:33 -0800 Subject: [PATCH 2/5] CMake cross-generator fixes (#2790) * Fix compilation w/ non-VS CMake generators * Fix custom WINMD target in Ninja * Remove usage of msbuild .targets file * Fix linking using DML in Ninja * Automate SDK kit version choice * Cleanup DML package install * Fix SDK version detection * Fix comment * Revert unittest linkage changes * Fix latest SDK detection * Don't link to non-uapcore libraries * Remove MessageBoxA reference and unused link libs --- cmake/external/dml.cmake | 8 +-- cmake/onnxruntime_common.cmake | 16 +++++ cmake/onnxruntime_mlas.cmake | 6 +- cmake/onnxruntime_providers.cmake | 35 +++++++--- cmake/onnxruntime_unittests.cmake | 12 ++-- cmake/precompiled_header.cmake | 15 ++-- cmake/winml.cmake | 25 ++++--- cmake/winml_cppwinrt.cmake | 69 ++++++++++--------- cmake/winml_sdk_helpers.cmake | 24 +++++-- .../core/platform/windows/debug_alloc.cc | 8 +-- 10 files changed, 135 insertions(+), 83 deletions(-) diff --git a/cmake/external/dml.cmake b/cmake/external/dml.cmake index 41de28fdd2..35c606f641 100644 --- a/cmake/external/dml.cmake +++ b/cmake/external/dml.cmake @@ -20,19 +20,17 @@ if (NOT onnxruntime_USE_CUSTOM_DIRECTML) set(NUGET_CONFIG ${PROJECT_SOURCE_DIR}/../NuGet.config) set(PACKAGES_CONFIG ${PROJECT_SOURCE_DIR}/../packages.config) set(PACKAGES_DIR ${CMAKE_CURRENT_BINARY_DIR}/packages) + set(DML_PACKAGE_DIR ${PACKAGES_DIR}/DirectML.0.0.1) # Restore nuget packages, which will pull down the DirectML redist package add_custom_command( - OUTPUT restore_packages.stamp + OUTPUT ${DML_PACKAGE_DIR}/bin/x64/DirectML.lib ${DML_PACKAGE_DIR}/bin/x86/DirectML.lib DEPENDS ${PACKAGES_CONFIG} ${NUGET_CONFIG} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/nuget/src/nuget restore ${PACKAGES_CONFIG} -PackagesDirectory ${PACKAGES_DIR} -ConfigFile ${NUGET_CONFIG} - COMMAND ${CMAKE_COMMAND} -E touch restore_packages.stamp VERBATIM) - add_custom_target(RESTORE_PACKAGES ALL DEPENDS restore_packages.stamp) + add_custom_target(RESTORE_PACKAGES ALL DEPENDS ${DML_PACKAGE_DIR}/bin/x64/DirectML.lib ${DML_PACKAGE_DIR}/bin/x86/DirectML.lib) add_dependencies(RESTORE_PACKAGES nuget) - - list(APPEND onnxruntime_EXTERNAL_DEPENDENCIES RESTORE_PACKAGES) else() include_directories(${dml_INCLUDE_DIR}) endif() diff --git a/cmake/onnxruntime_common.cmake b/cmake/onnxruntime_common.cmake index 63a8283429..52aa2f3989 100644 --- a/cmake/onnxruntime_common.cmake +++ b/cmake/onnxruntime_common.cmake @@ -44,6 +44,22 @@ else() endif() endif() +if(CMAKE_GENERATOR_PLATFORM) + # Multi-platform generator + set(onnxruntime_target_platform ${CMAKE_GENERATOR_PLATFORM}) +else() + set(onnxruntime_target_platform ${CMAKE_SYSTEM_PROCESSOR}) +endif() +if(onnxruntime_target_platform STREQUAL "ARM64") + set(onnxruntime_target_platform "ARM64") +elseif(onnxruntime_target_platform STREQUAL "ARM" OR CMAKE_GENERATOR MATCHES "ARM") + set(onnxruntime_target_platform "ARM") +elseif(onnxruntime_target_platform STREQUAL "x64" OR onnxruntime_target_platform STREQUAL "x86_64" OR onnxruntime_target_platform STREQUAL "AMD64" OR CMAKE_GENERATOR MATCHES "Win64") + set(onnxruntime_target_platform "x64") +elseif(onnxruntime_target_platform STREQUAL "x86" OR onnxruntime_target_platform STREQUAL "i386" OR onnxruntime_target_platform STREQUAL "i686") + set(onnxruntime_target_platform "x86") +endif() + file(GLOB onnxruntime_common_src CONFIGURE_DEPENDS ${onnxruntime_common_src_patterns} ) diff --git a/cmake/onnxruntime_mlas.cmake b/cmake/onnxruntime_mlas.cmake index e7b4213bc6..38ec173dfc 100644 --- a/cmake/onnxruntime_mlas.cmake +++ b/cmake/onnxruntime_mlas.cmake @@ -19,7 +19,7 @@ set(mlas_common_srcs ) if(MSVC) - if(CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64") + if(onnxruntime_target_platform STREQUAL "ARM64") set(asm_filename ${ONNXRUNTIME_ROOT}/core/mlas/lib/arm64/SgemmKernelNeon.asm) set(pre_filename ${CMAKE_CURRENT_BINARY_DIR}/SgemmKernelNeon.i) set(obj_filename ${CMAKE_CURRENT_BINARY_DIR}/SgemmKernelNeon.obj) @@ -38,11 +38,11 @@ if(MSVC) armasm64.exe ${ARMASM_FLAGS} ${pre_filename} ${obj_filename} ) set(mlas_platform_srcs ${obj_filename}) - elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "ARM" OR CMAKE_GENERATOR MATCHES "ARM") + elseif(onnxruntime_target_platform STREQUAL "ARM") set(mlas_platform_srcs ${ONNXRUNTIME_ROOT}/core/mlas/lib/arm/sgemmc.cpp ) - elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "x64" OR CMAKE_GENERATOR MATCHES "Win64") + elseif(onnxruntime_target_platform STREQUAL "x64") enable_language(ASM_MASM) set(mlas_platform_srcs diff --git a/cmake/onnxruntime_providers.cmake b/cmake/onnxruntime_providers.cmake index 9875955e3c..1b7047318e 100644 --- a/cmake/onnxruntime_providers.cmake +++ b/cmake/onnxruntime_providers.cmake @@ -217,7 +217,7 @@ if (onnxruntime_USE_TENSORRT) if ( CMAKE_COMPILER_IS_GNUCC ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter -Wno-missing-field-initializers") endif() - set(CXX_VERSION_DEFINED TRUE) + set(CXX_VERSION_DEFINED TRUE) add_subdirectory(${ONNXRUNTIME_ROOT}/../cmake/external/onnx-tensorrt) set(CMAKE_CXX_FLAGS ${OLD_CMAKE_CXX_FLAGS}) if (WIN32) @@ -303,7 +303,7 @@ if (onnxruntime_USE_OPENVINO) if(WIN32) set(OPENVINO_LIB_DIR $ENV{INTEL_OPENVINO_DIR}/deployment_tools/inference_engine/lib/intel64/Release) set(OPENVINO_TBB_DIR $ENV{INTEL_OPENVINO_DIR}/deployment_tools/inference_engine/lib/intel64/Release) - set(OPENVINO_MKL_TINY_DIR $ENV{INTEL_OPENVINO_DIR}/deployment_tools/inference_engine/bin/intel64/Release) + set(OPENVINO_MKL_TINY_DIR $ENV{INTEL_OPENVINO_DIR}/deployment_tools/inference_engine/bin/intel64/Release) else() set(OPENVINO_LIB_DIR $ENV{INTEL_OPENVINO_DIR}/deployment_tools/inference_engine/lib/intel64/) set(OPENVINO_TBB_DIR $ENV{INTEL_OPENVINO_DIR}/deployment_tools/inference_engine/external/tbb/lib) @@ -327,9 +327,9 @@ if (onnxruntime_USE_OPENVINO) else() target_include_directories(onnxruntime_providers_openvino SYSTEM PUBLIC ${ONNXRUNTIME_ROOT} ${eigen_INCLUDE_DIRS} ${OPENVINO_INCLUDE_DIR} ${OPENVINO_EXTENSIONS_DIR} ${OPENVINO_LIB_DIR} ${OPENVINO_TBB_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS}) endif() - - if (WIN32) - string(REPLACE "include" "libs" PYTHON_LIB ${PYTHON_INCLUDE_DIRS}) + + if (WIN32) + string(REPLACE "include" "libs" PYTHON_LIB ${PYTHON_INCLUDE_DIRS}) find_package(InferenceEngine 2.1 REQUIRED) set(PYTHON_LIBRARIES ${PYTHON_LIB}) set(OPENVINO_CPU_EXTENSION_DIR ${onnxruntime_BINARY_DIR}/ie_cpu_extension/${CMAKE_BUILD_TYPE}) @@ -430,22 +430,37 @@ if (onnxruntime_USE_DML) onnxruntime_add_include_to_target(onnxruntime_providers_dml onnxruntime_common onnxruntime_framework onnx onnx_proto protobuf::libprotobuf) add_dependencies(onnxruntime_providers_dml ${onnxruntime_EXTERNAL_DEPENDENCIES}) target_include_directories(onnxruntime_providers_dml PRIVATE ${ONNXRUNTIME_ROOT} ${ONNXRUNTIME_ROOT}/../cmake/external/wil/include) - - target_link_libraries(onnxruntime_providers_dml ${CMAKE_CURRENT_BINARY_DIR}/packages/DirectML.0.0.1/build/DirectML.targets) - target_link_libraries(onnxruntime_providers_dml d3d12.lib dxgi.lib) + + if(NOT onnxruntime_target_platform STREQUAL "x86" AND NOT onnxruntime_target_platform STREQUAL "x64") + message(FATAL_ERROR "Target platform ${onnxruntime_target_platform} is not supported by DML") + endif() + foreach(file "DirectML.dll" "DirectML.pdb" "DirectML.Debug.dll" "DirectML.Debug.pdb") + add_custom_command(TARGET onnxruntime_providers_dml + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${DML_PACKAGE_DIR}/bin/${onnxruntime_target_platform}/${file}" $) + endforeach() + + function(target_add_dml target) + target_link_libraries(${target} PRIVATE "${DML_PACKAGE_DIR}/bin/${onnxruntime_target_platform}/DirectML.lib") + target_include_directories(${target} PRIVATE "${DML_PACKAGE_DIR}/include") + endfunction() + + target_add_dml(onnxruntime_providers_dml) + target_link_libraries(onnxruntime_providers_dml PRIVATE d3d12.lib dxgi.lib delayimp.lib) list(APPEND ONNXRUNTIME_LINKER_FLAGS "/DELAYLOAD:DirectML.dll /DELAYLOAD:d3d12.dll /DELAYLOAD:dxgi.dll") # The DML EP requires C++17 set_target_properties(onnxruntime_providers_dml PROPERTIES CXX_STANDARD 17) set_target_properties(onnxruntime_providers_dml PROPERTIES CXX_STANDARD_REQUIRED ON) - + target_compile_definitions(onnxruntime_providers_dml PRIVATE ONNX_NAMESPACE=onnx ONNX_ML LOTUS_LOG_THRESHOLD=2 LOTUS_ENABLE_STDERR_LOGGING PLATFORM_WINDOWS) target_compile_definitions(onnxruntime_providers_dml PRIVATE UNICODE _UNICODE NOMINMAX) if (MSVC) target_compile_definitions(onnxruntime_providers_dml PRIVATE _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING) target_compile_options(onnxruntime_providers_dml PRIVATE "/W3") endif() - + install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/dml DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core/providers) set_target_properties(onnxruntime_providers_dml PROPERTIES LINKER_LANGUAGE CXX) diff --git a/cmake/onnxruntime_unittests.cmake b/cmake/onnxruntime_unittests.cmake index 09aedbe005..1cba4e4720 100644 --- a/cmake/onnxruntime_unittests.cmake +++ b/cmake/onnxruntime_unittests.cmake @@ -44,7 +44,7 @@ function(AddTest) endif() if (onnxruntime_ENABLE_LANGUAGE_INTEROP_OPS AND onnxruntime_ENABLE_PYTHON) target_compile_definitions(${_UT_TARGET} PRIVATE ENABLE_LANGUAGE_INTEROP_OPS) - endif() + endif() if (WIN32) if (onnxruntime_USE_CUDA) # disable a warning from the CUDA headers about unreferenced local functions @@ -318,7 +318,7 @@ if (onnxruntime_USE_DNNL) target_compile_definitions(onnxruntime_test_utils_for_framework PUBLIC USE_DNNL=1) endif() if (onnxruntime_USE_DML) - target_link_libraries(onnxruntime_test_utils_for_framework PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/packages/DirectML.0.0.1/build/DirectML.targets) + target_add_dml(onnxruntime_test_utils_for_framework) endif() add_dependencies(onnxruntime_test_utils_for_framework ${onnxruntime_EXTERNAL_DEPENDENCIES}) target_include_directories(onnxruntime_test_utils_for_framework PUBLIC "${TEST_SRC_DIR}/util/include" PRIVATE ${eigen_INCLUDE_DIRS} ${ONNXRUNTIME_ROOT}) @@ -336,7 +336,7 @@ if (onnxruntime_USE_DNNL) target_compile_definitions(onnxruntime_test_utils PUBLIC USE_DNNL=1) endif() if (onnxruntime_USE_DML) - target_link_libraries(onnxruntime_test_utils PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/packages/DirectML.0.0.1/build/DirectML.targets) + target_add_dml(onnxruntime_test_utils) endif() add_dependencies(onnxruntime_test_utils ${onnxruntime_EXTERNAL_DEPENDENCIES}) target_include_directories(onnxruntime_test_utils PUBLIC "${TEST_SRC_DIR}/util/include" PRIVATE ${eigen_INCLUDE_DIRS} ${ONNXRUNTIME_ROOT}) @@ -722,7 +722,7 @@ if (onnxruntime_BUILD_SERVER) set_source_files_properties("${TEST_SRC_DIR}/server/unit_tests/executor_test.cc" PROPERTIES COMPILE_FLAGS -Wno-unused-parameter) endif() endif() - + add_library(onnxruntime_test_utils_for_server ${onnxruntime_test_server_src}) onnxruntime_add_include_to_target(onnxruntime_test_utils_for_server onnxruntime_test_utils_for_framework gtest gmock onnx onnx_proto server_proto server_grpc_proto) add_dependencies(onnxruntime_test_utils_for_server onnxruntime_server_lib onnxruntime_server_http_core_lib Boost ${onnxruntime_EXTERNAL_DEPENDENCIES}) @@ -751,13 +751,13 @@ if (onnxruntime_BUILD_SERVER) LANGUAGE python TARGET onnxruntime_server_tests OUT_VAR server_test_py) - + set(grpc_py "${CMAKE_CURRENT_BINARY_DIR}/prediction_service_pb2_grpc.py") add_custom_command( TARGET onnxruntime_server_tests COMMAND $ - ARGS + ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" --plugin=protoc-gen-grpc="${_GRPC_PY_PLUGIN_EXECUTABLE}" -I ${grpc_proto_path} diff --git a/cmake/precompiled_header.cmake b/cmake/precompiled_header.cmake index f41310fac5..3bebf73418 100644 --- a/cmake/precompiled_header.cmake +++ b/cmake/precompiled_header.cmake @@ -2,8 +2,7 @@ # header name as input. The function will generate a .cpp file that includes the header and is used # to generate the precompiled header; this source file is added to the target's sources. function(target_precompiled_header target_name header_name) - if (MSVC) - + if (MSVC AND CMAKE_VS_PLATFORM_TOOLSET) # The input precompiled header source (i.e. the '.h' file used for the precompiled header). set(pch_header_path ${header_name}) get_filename_component(header_base_name ${header_name} NAME_WE) @@ -14,14 +13,14 @@ function(target_precompiled_header target_name header_name) set(pch_source_content "// THIS FILE IS GENERATED BY CMAKE\n#include \"${pch_header_path}\"") file(WRITE ${pch_source_path} ${pch_source_content}) set_source_files_properties(${pch_source_path} PROPERTIES COMPILE_FLAGS "/Yc${pch_header_path}") - + # The target's C++ sources use the precompiled header (/Yu). Source-level properties will - # take precedence over target-level properties, so this will not change the generated source + # take precedence over target-level properties, so this will not change the generated source # file's property to create the precompiled header (/Yc). target_compile_options(${target_name} PRIVATE $<$:/Yu${header_name}>) - + # Append generated precompiled source to target's sources. target_sources(${target_name} PRIVATE ${pch_source_path}) - - endif(MSVC) -endfunction() \ No newline at end of file + + endif() +endfunction() diff --git a/cmake/winml.cmake b/cmake/winml.cmake index 71824b3997..f5171158f2 100644 --- a/cmake/winml.cmake +++ b/cmake/winml.cmake @@ -132,7 +132,7 @@ list(APPEND winml_adapter_files ${winml_adapter_dir}/WinMLAdapter.cpp ${winml_adapter_dir}/WinMLAdapter.h ${winml_adapter_dir}/ZeroCopyInputStreamWrapper.cpp - ${winml_adapter_dir}/ZeroCopyInputStreamWrapper.h + ${winml_adapter_dir}/ZeroCopyInputStreamWrapper.h ) if (onnxruntime_USE_DML) @@ -159,6 +159,7 @@ add_dependencies(winml_adapter ${onnxruntime_EXTERNAL_DEPENDENCIES}) target_precompiled_header(winml_adapter pch.h) # Includes +target_include_directories(winml_adapter PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) # windows machine learning generated component headers target_include_directories(winml_adapter PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/winml_api) # windows machine learning generated component headers target_include_directories(winml_adapter PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/winml_api/comp_generated) # windows machine learning generated component headers target_include_directories(winml_adapter PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/winml/sdk/cppwinrt/include) # sdk cppwinrt headers @@ -181,11 +182,11 @@ add_dependencies(winml_adapter winml_api_native_internal) # Link libraries target_link_libraries(winml_adapter PRIVATE wil) if (onnxruntime_USE_DML) - target_link_libraries(winml_adapter PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/packages/DirectML.0.0.1/build/DirectML.targets) + target_add_dml(winml_adapter) endif(onnxruntime_USE_DML) # add it to the onnxruntime shared library -set(onnxruntime_winml windowsapp.lib winml_adapter) +set(onnxruntime_winml winml_adapter) list(APPEND onnxruntime_EXTERNAL_DEPENDENCIES winml_adapter) ########################### @@ -230,6 +231,7 @@ target_compile_definitions(winml_lib_image PRIVATE _SCL_SECURE_NO_WARNINGS) target_precompiled_header(winml_lib_image pch.h) # Includes +target_include_directories(winml_lib_image PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) # windows machine learning generated component headers target_include_directories(winml_lib_image PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/winml_api) # windows machine learning generated component headers target_include_directories(winml_lib_image PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/winml_api/comp_generated) # windows machine learning generated component headers target_include_directories(winml_lib_image PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/winml/sdk/cppwinrt/include) # sdk cppwinrt headers @@ -258,7 +260,7 @@ add_dependencies(winml_lib_image winml_api_native_internal) # Link libraries target_link_libraries(winml_lib_image PRIVATE wil) if (onnxruntime_USE_DML) - target_link_libraries(winml_lib_image PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/packages/DirectML.0.0.1/build/DirectML.targets) + target_add_dml(winml_lib_image) endif(onnxruntime_USE_DML) @@ -360,7 +362,7 @@ add_dependencies(winml_lib_api winml_api_native_internal) # Link libraries target_link_libraries(winml_lib_api PRIVATE wil) if (onnxruntime_USE_DML) - target_link_libraries(winml_lib_api PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/packages/DirectML.0.0.1/build/DirectML.targets) + target_add_dml(winml_lib_api) endif(onnxruntime_USE_DML) @@ -438,10 +440,17 @@ if (onnxruntime_USE_DML) set(delayload_dml "/DELAYLOAD:directml.dll") endif(onnxruntime_USE_DML) +# The default libraries to link with in Windows are kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib +# Remove them and use the onecore umbrella library instead +set(CMAKE_C_STANDARD_LIBRARIES "onecoreuap_apiset.lib") +set(CMAKE_CXX_STANDARD_LIBRARIES "onecoreuap_apiset.lib") +foreach(default_lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdgl32.lib advapi32.lib) + set(removed_libs "${removed_libs} /NODEFAULTLIB:${default_lib}") +endforeach() set_target_properties(winml_dll PROPERTIES LINK_FLAGS - "/DEF:${WINML_DIR}/windows.ai.machinelearning.def ${os_component_link_flags} /DELAYLOAD:d3d12.dll /DELAYLOAD:d3d11.dll /DELAYLOAD:dxgi.dll ${delayload_dml}") + "/DEF:${WINML_DIR}/windows.ai.machinelearning.def ${os_component_link_flags} /DELAYLOAD:d3d12.dll /DELAYLOAD:d3d11.dll /DELAYLOAD:dxgi.dll ${delayload_dml} ${removed_libs}") set_target_properties(winml_dll @@ -467,11 +476,10 @@ endif("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") target_link_libraries(winml_dll PRIVATE onnxruntime) target_link_libraries(winml_dll PRIVATE re2) target_link_libraries(winml_dll PRIVATE wil) -#target_link_libraries(winml_dll PRIVATE windowsapp.lib) target_link_libraries(winml_dll PRIVATE winml_lib_api) target_link_libraries(winml_dll PRIVATE winml_lib_image) target_link_libraries(winml_dll PRIVATE winml_lib_telemetry) -target_link_libraries(winml_dll PRIVATE onecoreuap_apiset.lib) +target_link_libraries(winml_dll PRIVATE delayimp.lib) target_link_libraries(winml_dll PRIVATE ${DBGHELP}) # 1 of 3 projects that fail in link with 'failed to do memory mapped file I/O' (Only release) @@ -483,6 +491,7 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Release") set_target_properties(winml_dll PROPERTIES VS_GLOBAL_PreferredToolArchitecture "x64") endif("${CMAKE_BUILD_TYPE}" STREQUAL "Release") +option(onnxruntime_BUILD_WINML_TESTS "Build WinML tests" ON) if (onnxruntime_BUILD_WINML_TESTS) include(winml_unittests.cmake) endif() diff --git a/cmake/winml_cppwinrt.cmake b/cmake/winml_cppwinrt.cmake index 2d53ade270..ea96a1b289 100644 --- a/cmake/winml_cppwinrt.cmake +++ b/cmake/winml_cppwinrt.cmake @@ -102,7 +102,7 @@ function(target_cppwinrt # Get directory get_filename_component(idl_source_directory ${file} DIRECTORY) - set(target_outputs ${CMAKE_CURRENT_BINARY_DIR}/${target_name}) + set(target_outputs ${CMAKE_CURRENT_BINARY_DIR}/${target_name}) convert_forward_slashes_to_back(${target_outputs}/comp output_dir_back_slash) convert_forward_slashes_to_back(${target_outputs}/temp temp_dir_back_slash) convert_forward_slashes_to_back(${target_outputs}/comp_generated generated_dir_back_slash) @@ -126,50 +126,53 @@ function(target_cppwinrt /tlb ${tlb_filename} ${idl_file_forward_slash} COMMAND - ${cppwinrt_exe} -in \"${winmd_filename}\" -comp \"${output_dir_back_slash}\" -ref \"${sdk_metadata_directory}\" -out \"${generated_dir_back_slash}\" -verbose + ${cppwinrt_exe} -in ${winmd_filename} -comp ${output_dir_back_slash} -ref ${sdk_metadata_directory} -out ${generated_dir_back_slash} -verbose COMMAND # copy the generated component files into a temporary directory where headers exclusions will be applied - xcopy \"${output_dir_back_slash}\" \"${temp_dir_back_slash}\\\" /Y /D + xcopy ${output_dir_back_slash} ${temp_dir_back_slash}\\ /Y /D COMMAND # for each file in the temp directory, ensure it is not in the exclusions list. # if it is, then we need to delete it. - for /f %%I in ('dir /b \"${temp_dir_back_slash}\"') - do - ( - for /f %%E in (${CPPWINRT_COMPONENT_EXCLUSION_LIST}) - do - ( - if %%E == %%I - ( - del \"${temp_dir_back_slash}\\%%I\" - ) - ) - ) + cmd /C "@echo off \ + for /f %I in ('dir /b ${temp_dir_back_slash}') \ + do \ + ( \ + for /f %E in (${CPPWINRT_COMPONENT_EXCLUSION_LIST}) \ + do \ + ( \ + if %E == %I \ + ( \ + del ${temp_dir_back_slash}\\%I \ + ) \ + ) \ + )" COMMAND # for each file in the temp directory, copy the file back into the source tree # unless the file already exists - for /f %%I in ('dir /b \"${temp_dir_back_slash}\"') - do - ( - if not exist \"${out_sources_folder}\\%%I\" - ( - xcopy \"${temp_dir_back_slash}\\%%I\" \"${out_sources_folder}\\%%I\" - ) - ) + cmd /C "@echo off \ + for /f %I in ('dir /b ${temp_dir_back_slash}') \ + do \ + ( \ + if not exist ${out_sources_folder}\\%I \ + ( \ + copy ${temp_dir_back_slash}\\%I ${out_sources_folder}\\%I \ + ) \ + )" COMMAND # open the generated module.g.cpp and strip all the includes (lines) containing excluded headers # write the new file out to module.g.excl.cpp. - powershell -Command \"& { - $exclusions = get-content '${CPPWINRT_COMPONENT_EXCLUSION_LIST}'\; - (get-content '${module_g_cpp_back_slash}') - | where { - $str = $_\; - $matches = ($exclusions | where { $str -match $_ }) \; - $matches.Length -eq 0 } - | Out-File '${module_g_ecxl_cpp_back_slash}' - }\" + powershell -Command "& { \ + $exclusions = get-content '${CPPWINRT_COMPONENT_EXCLUSION_LIST}'; \ + (get-content '${module_g_cpp_back_slash}') \ + | where { \ + $str = $_; \ + $matches = ($exclusions | where { $str -match $_ }); \ + $matches.Length -eq 0 } \ + | Out-File '${module_g_ecxl_cpp_back_slash}' \ + }" BYPRODUCTS ${generated_dir_back_slash}/module.g.excl.cpp + VERBATIM ) add_custom_target( @@ -214,4 +217,4 @@ function(add_generate_cppwinrt_sdk_headers_target set_target_properties(${target_name} PROPERTIES FOLDER ${folder_name}) endif() -endfunction() \ No newline at end of file +endfunction() diff --git a/cmake/winml_sdk_helpers.cmake b/cmake/winml_sdk_helpers.cmake index 03a87653fe..df9db93a6b 100644 --- a/cmake/winml_sdk_helpers.cmake +++ b/cmake/winml_sdk_helpers.cmake @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.0) -# utility +# utility function(convert_forward_slashes_to_back input output) string(REGEX REPLACE "/" "\\\\" backwards ${input}) set(${output} ${backwards} PARENT_SCOPE) @@ -16,7 +16,23 @@ function(get_installed_sdk set(${sdk_folder} ${win10_sdk_root} PARENT_SCOPE) # return the sdk version - set(${output_sdk_version} ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION} PARENT_SCOPE) + if(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION) + set(${output_sdk_version} ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION} PARENT_SCOPE) + else() + # choose the SDK matching the system version, or fallback to the latest + file(GLOB win10_sdks RELATIVE "${win10_sdk_root}/UnionMetadata" "${win10_sdk_root}/UnionMetadata/*.*.*.*") + list(GET win10_sdks 0 latest_sdk) + foreach(sdk IN LISTS win10_sdks) + string(FIND ${sdk} ${CMAKE_SYSTEM_VERSION} is_system_version) + if(NOT ${is_system_version} EQUAL -1) + set(${output_sdk_version} ${sdk} PARENT_SCOPE) + return() + elseif(sdk VERSION_GREATER latest_sdk) + set(latest_sdk ${sdk}) + endif() + endforeach() + set(${output_sdk_version} ${latest_sdk} PARENT_SCOPE) + endif() endfunction() # current sdk binary directory @@ -95,7 +111,7 @@ function(get_sdk set(${output_sdk_version} ${winml_WINDOWS_SDK_VERSION_OVERRIDE} PARENT_SCOPE) else() message( - FATAL_ERROR + FATAL_ERROR "Options winml_WINDOWS_SDK_DIR_OVERRIDE and winml_WINDOWS_SDK_VERSION_OVERRIDE must be defined together, or not at all.") endif() -endfunction() \ No newline at end of file +endfunction() diff --git a/onnxruntime/core/platform/windows/debug_alloc.cc b/onnxruntime/core/platform/windows/debug_alloc.cc index 83c38baa05..57267f146d 100644 --- a/onnxruntime/core/platform/windows/debug_alloc.cc +++ b/onnxruntime/core/platform/windows/debug_alloc.cc @@ -232,12 +232,8 @@ Memory_LeakCheck::~Memory_LeakCheck() { _snprintf_s(buffer, _TRUNCATE, "%d bytes of memory leaked in %d allocations", leaked_bytes, leak_count); string.append(buffer); - // If we're being actively debugged, show a message box to get the dev's attention - if (IsDebuggerPresent()) - MessageBoxA(nullptr, string.c_str(), "Warning", MB_OK | MB_ICONWARNING); - else { - // If we're on the command line (like on a build machine), output to the console and exit(-1) - std::cout << "\n----- MEMORY LEAKS: " << string.c_str() << "\n"; + std::cout << "\n----- MEMORY LEAKS: " << string.c_str() << "\n"; + if (!IsDebuggerPresent()) { exit(-1); } From dcdebb409a1b652c7e308b38472b6705dd4de8c3 Mon Sep 17 00:00:00 2001 From: Ryan Lai Date: Wed, 15 Jan 2020 12:13:56 -0800 Subject: [PATCH 3/5] Refactor WinMLAPI Tests to build both google and taef test based on preprocessor definition (#2829) * Add winml macro wrappers on top of google test macros * change test methods to disabled * Add custom winml macros for both taef and google tests * PR comments * Refactor winml api tests * Move additional gtest specific macro definition into googleTestMacros.h --- cmake/winml_unittests.cmake | 1 + winml/test/api/APITest.h | 54 +-- winml/test/api/LearningModelAPITest.cpp | 367 +++++++++--------- winml/test/api/LearningModelAPITest.h | 41 ++ .../test/api/LearningModelBindingAPITest.cpp | 354 +++++++++-------- winml/test/api/LearningModelBindingAPITest.h | 49 +++ .../test/api/LearningModelSessionAPITest.cpp | 295 ++++++++------ winml/test/api/LearningModelSessionAPITest.h | 44 +++ winml/test/common/googleTestMacros.h | 19 +- winml/test/common/std.h | 17 +- winml/test/common/taefTestMacros.h | 4 +- 11 files changed, 728 insertions(+), 517 deletions(-) create mode 100644 winml/test/api/LearningModelAPITest.h create mode 100644 winml/test/api/LearningModelBindingAPITest.h create mode 100644 winml/test/api/LearningModelSessionAPITest.h diff --git a/cmake/winml_unittests.cmake b/cmake/winml_unittests.cmake index 95661e85d8..4bdbb34432 100644 --- a/cmake/winml_unittests.cmake +++ b/cmake/winml_unittests.cmake @@ -69,6 +69,7 @@ add_winml_test( SOURCES ${winml_test_api_src} LIBS winml_test_common ) +target_compile_definitions(winml_test_api PRIVATE BUILD_GOOGLE_TEST) target_precompiled_header(winml_test_api testPch.h) if (onnxruntime_USE_DML) diff --git a/winml/test/api/APITest.h b/winml/test/api/APITest.h index 68e68f724d..fd40a19b78 100644 --- a/winml/test/api/APITest.h +++ b/winml/test/api/APITest.h @@ -5,37 +5,25 @@ //----------------------------------------------------------------------------- #pragma once - -#include - -class APITest : public ::testing::Test -{ -protected: - void LoadModel(const std::wstring& modelPath) - { - std::wstring fullPath = FileHelpers::GetModulePath() + modelPath; - m_model = winrt::Windows::AI::MachineLearning::LearningModel::LoadFromFilePath(fullPath); - } - - winrt::Windows::AI::MachineLearning::LearningModel m_model = nullptr; - winrt::Windows::AI::MachineLearning::LearningModelDevice m_device = nullptr; - winrt::Windows::AI::MachineLearning::LearningModelSession m_session = nullptr; - - uint64_t GetAdapterIdQuadPart() - { - LARGE_INTEGER id; - id.LowPart = m_device.AdapterId().LowPart; - id.HighPart = m_device.AdapterId().HighPart; - return id.QuadPart; - }; - - _LUID GetAdapterIdAsLUID() - { - _LUID id; - id.LowPart = m_device.AdapterId().LowPart; - id.HighPart = m_device.AdapterId().HighPart; - return id; - } - - bool m_runGPUTests = true; +#include "fileHelpers.h" +namespace APITest { +static void LoadModel(const std::wstring& modelPath, + winrt::Windows::AI::MachineLearning::LearningModel& learningModel) { + std::wstring fullPath = FileHelpers::GetModulePath() + modelPath; + learningModel = winrt::Windows::AI::MachineLearning::LearningModel::LoadFromFilePath(fullPath); }; + +static uint64_t GetAdapterIdQuadPart(winrt::Windows::AI::MachineLearning::LearningModelDevice& device) { + LARGE_INTEGER id; + id.LowPart = device.AdapterId().LowPart; + id.HighPart = device.AdapterId().HighPart; + return id.QuadPart; +}; + +static _LUID GetAdapterIdAsLUID(winrt::Windows::AI::MachineLearning::LearningModelDevice& device) { + _LUID id; + id.LowPart = device.AdapterId().LowPart; + id.HighPart = device.AdapterId().HighPart; + return id; +} +}; // namespace APITest diff --git a/winml/test/api/LearningModelAPITest.cpp b/winml/test/api/LearningModelAPITest.cpp index ad592a9a86..639940551d 100644 --- a/winml/test/api/LearningModelAPITest.cpp +++ b/winml/test/api/LearningModelAPITest.cpp @@ -1,7 +1,6 @@ #include "testPch.h" - +#include "LearningModelAPITest.h" #include "APITest.h" - #include #include #include @@ -15,107 +14,96 @@ using namespace winrt::Windows::Media; using namespace winrt::Windows::Storage; using namespace winrt::Windows::Storage::Streams; -class LearningModelAPITest : public APITest -{ -protected: - LearningModelAPITest() { - init_apartment(); - m_model = nullptr; - m_device = nullptr; - m_session = nullptr; - } -}; - -class LearningModelAPITestGpu : public LearningModelAPITest -{ -protected: - void SetUp() override - { - GPUTEST - } -}; - -TEST_F(LearningModelAPITest, CreateModelFromFilePath) -{ - EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx")); +static void LearningModelAPITestSetup() { + init_apartment(); } -TEST_F(LearningModelAPITest, CreateModelFromIStorage) -{ - std::wstring path = FileHelpers::GetModulePath() + L"squeezenet_modifiedforruntimestests.onnx"; - auto storageFile = winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(path).get(); - EXPECT_NO_THROW(m_model = LearningModel::LoadFromStorageFileAsync(storageFile).get()); - EXPECT_TRUE(m_model != nullptr); - - // check the author so we know the model was populated correctly. - std::wstring author(m_model.Author()); - EXPECT_EQ(L"onnx-caffe2", author); +static void LearningModelAPITestGpuSetup() { + GPUTEST; + init_apartment(); } -TEST_F(LearningModelAPITest, CreateModelFromIStorageOutsideCwd) -{ - std::wstring path = FileHelpers::GetModulePath() + L"ModelSubdirectory\\ModelInSubdirectory.onnx"; - auto storageFile = winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(path).get(); - EXPECT_NO_THROW(m_model = LearningModel::LoadFromStorageFileAsync(storageFile).get()); - EXPECT_TRUE(m_model != nullptr); - - // check the author so we know the model was populated correctly. - std::wstring author(m_model.Author()); - EXPECT_EQ(L"onnx-caffe2", author); +static void CreateModelFromFilePath() { + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel)); } -TEST_F(LearningModelAPITest, CreateModelFromIStream) -{ - std::wstring path = FileHelpers::GetModulePath() + L"squeezenet_modifiedforruntimestests.onnx"; - auto storageFile = winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(path).get(); - winrt::Windows::Storage::Streams::IRandomAccessStreamReference streamref; - storageFile.as(streamref); +static void CreateModelFromIStorage() { + std::wstring path = FileHelpers::GetModulePath() + L"squeezenet_modifiedforruntimestests.onnx"; + auto storageFile = winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(path).get(); + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromStorageFileAsync(storageFile).get()); + WINML_EXPECT_TRUE(learningModel != nullptr); - EXPECT_NO_THROW(m_model = LearningModel::LoadFromStreamAsync(streamref).get()); - EXPECT_TRUE(m_model != nullptr); - - // check the author so we know the model was populated correctly. - std::wstring author(m_model.Author()); - EXPECT_EQ(L"onnx-caffe2", author); + // check the author so we know the model was populated correctly. + std::wstring author(learningModel.Author()); + WINML_EXPECT_EQUAL(L"onnx-caffe2", author); } -TEST_F(LearningModelAPITest, GetAuthor) -{ - EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx")); - std::wstring author(m_model.Author()); - EXPECT_EQ(L"onnx-caffe2", author); +static void CreateModelFromIStorageOutsideCwd() { + std::wstring path = FileHelpers::GetModulePath() + L"ModelSubdirectory\\ModelInSubdirectory.onnx"; + auto storageFile = winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(path).get(); + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromStorageFileAsync(storageFile).get()); + WINML_EXPECT_TRUE(learningModel != nullptr); + + // check the author so we know the model was populated correctly. + std::wstring author(learningModel.Author()); + WINML_EXPECT_EQUAL(L"onnx-caffe2", author); } -TEST_F(LearningModelAPITest, GetName) -{ - EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx")); - std::wstring name(m_model.Name()); - EXPECT_EQ(L"squeezenet_old", name); +static void CreateModelFromIStream() { + std::wstring path = FileHelpers::GetModulePath() + L"squeezenet_modifiedforruntimestests.onnx"; + auto storageFile = winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(path).get(); + winrt::Windows::Storage::Streams::IRandomAccessStreamReference streamref; + storageFile.as(streamref); + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromStreamAsync(streamref).get()); + WINML_EXPECT_TRUE(learningModel != nullptr); + + // check the author so we know the model was populated correctly. + std::wstring author(learningModel.Author()); + WINML_EXPECT_EQUAL(L"onnx-caffe2", author); } -TEST_F(LearningModelAPITest, GetDomain) -{ - EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx")); - std::wstring domain(m_model.Domain()); - EXPECT_EQ(L"test-domain", domain); +static void ModelGetAuthor() { + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel)); + std::wstring author(learningModel.Author()); + WINML_EXPECT_EQUAL(L"onnx-caffe2", author); } -TEST_F(LearningModelAPITest, GetDescription) -{ - EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx")); - std::wstring description(m_model.Description()); - EXPECT_EQ(L"test-doc_string", description); +static void ModelGetName() { + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel)); + std::wstring name(learningModel.Name()); + WINML_EXPECT_EQUAL(L"squeezenet_old", name); } -TEST_F(LearningModelAPITest, GetVersion) -{ - EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx")); - int64_t version(m_model.Version()); - (void)(version); +static void ModelGetDomain() { + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel)); + std::wstring domain(learningModel.Domain()); + WINML_EXPECT_EQUAL(L"test-domain", domain); +} + +static void ModelGetDescription() { + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel)); + std::wstring description(learningModel.Description()); + WINML_EXPECT_EQUAL(L"test-doc_string", description); +} + +static void ModelGetVersion() { + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel)); + int64_t version(learningModel.Version()); + (void)(version); } typedef std::vector> Metadata; +/* class MetadataTest : public LearningModelAPITest, public testing::WithParamInterface> {}; @@ -125,16 +113,16 @@ TEST_P(MetadataTest, GetMetaData) std::vector> keyValuePairs; tie(fileName, keyValuePairs) = GetParam(); - EXPECT_NO_THROW(LoadModel(fileName.c_str())); - EXPECT_TRUE(m_model.Metadata() != nullptr); - EXPECT_EQ(keyValuePairs.size(), m_model.Metadata().Size()); + WINML_EXPECT_NO_THROW(LoadModel(fileName.c_str())); + WINML_EXPECT_TRUE(m_model.Metadata() != nullptr); + WINML_EXPECT_EQUAL(keyValuePairs.size(), m_model.Metadata().Size()); auto iter = m_model.Metadata().First(); for (auto& keyValue : keyValuePairs) { - EXPECT_TRUE(iter.HasCurrent()); - EXPECT_EQ(keyValue.first, std::wstring(iter.Current().Key())); - EXPECT_EQ(keyValue.second, std::wstring(iter.Current().Value())); + WINML_EXPECT_TRUE(iter.HasCurrent()); + WINML_EXPECT_EQUAL(keyValue.first, std::wstring(iter.Current().Key())); + WINML_EXPECT_EQUAL(keyValue.second, std::wstring(iter.Current().Value())); iter.MoveNext(); } } @@ -147,122 +135,141 @@ INSTANTIATE_TEST_SUITE_P( std::pair(L"modelWithMetaData.onnx", Metadata{{L"thisisalongkey", L"thisisalongvalue"}}), std::pair(L"modelWith2MetaData.onnx", Metadata{{L"thisisalongkey", L"thisisalongvalue"}, {L"key2", L"val2"}}) )); +*/ -TEST_F(LearningModelAPITest, EnumerateInputs) -{ - EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx")); +static void EnumerateInputs() { + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel)); - // purposely don't cache "InputFeatures" in order to exercise calling it multiple times - EXPECT_TRUE(m_model.InputFeatures().First().HasCurrent()); + // purposely don't cache "InputFeatures" in order to exercise calling it multiple times + WINML_EXPECT_TRUE(learningModel.InputFeatures().First().HasCurrent()); - std::wstring name(m_model.InputFeatures().First().Current().Name()); - EXPECT_EQ(L"data_0", name); + std::wstring name(learningModel.InputFeatures().First().Current().Name()); + WINML_EXPECT_EQUAL(L"data_0", name); - // make sure it's either tensor or image - TensorFeatureDescriptor tensorDescriptor = nullptr; - m_model.InputFeatures().First().Current().try_as(tensorDescriptor); - if (tensorDescriptor == nullptr) - { - ImageFeatureDescriptor imageDescriptor = nullptr; - EXPECT_NO_THROW(m_model.InputFeatures().First().Current().as(imageDescriptor)); - } + // make sure it's either tensor or image + TensorFeatureDescriptor tensorDescriptor = nullptr; + learningModel.InputFeatures().First().Current().try_as(tensorDescriptor); + if (tensorDescriptor == nullptr) { + ImageFeatureDescriptor imageDescriptor = nullptr; + WINML_EXPECT_NO_THROW(learningModel.InputFeatures().First().Current().as(imageDescriptor)); + } - auto modelDataKind = tensorDescriptor.TensorKind(); - EXPECT_EQ(TensorKind::Float, modelDataKind); + auto modelDataKind = tensorDescriptor.TensorKind(); + WINML_EXPECT_EQUAL(TensorKind::Float, modelDataKind); - EXPECT_TRUE(tensorDescriptor.IsRequired()); + WINML_EXPECT_TRUE(tensorDescriptor.IsRequired()); - std::vector expectedShapes = { 1,3,224,224 }; - EXPECT_EQ(expectedShapes.size(), tensorDescriptor.Shape().Size()); - for (uint32_t j = 0; j < tensorDescriptor.Shape().Size(); j++) - { - EXPECT_EQ(expectedShapes.at(j), tensorDescriptor.Shape().GetAt(j)); - } + std::vector expectedShapes = {1, 3, 224, 224}; + WINML_EXPECT_EQUAL(expectedShapes.size(), tensorDescriptor.Shape().Size()); + for (uint32_t j = 0; j < tensorDescriptor.Shape().Size(); j++) { + WINML_EXPECT_EQUAL(expectedShapes.at(j), tensorDescriptor.Shape().GetAt(j)); + } - auto first = m_model.InputFeatures().First(); - first.MoveNext(); - EXPECT_FALSE(first.HasCurrent()); + auto first = learningModel.InputFeatures().First(); + first.MoveNext(); + WINML_EXPECT_FALSE(first.HasCurrent()); } -TEST_F(LearningModelAPITest, EnumerateOutputs) -{ - EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx")); +static void EnumerateOutputs() { + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel)); - // purposely don't cache "OutputFeatures" in order to exercise calling it multiple times - std::wstring name(m_model.OutputFeatures().First().Current().Name()); - EXPECT_EQ(L"softmaxout_1", name); + // purposely don't cache "OutputFeatures" in order to exercise calling it multiple times + std::wstring name(learningModel.OutputFeatures().First().Current().Name()); + WINML_EXPECT_EQUAL(L"softmaxout_1", name); - TensorFeatureDescriptor tensorDescriptor = nullptr; - EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(tensorDescriptor)); - EXPECT_TRUE(tensorDescriptor != nullptr); + TensorFeatureDescriptor tensorDescriptor = nullptr; + WINML_EXPECT_NO_THROW(learningModel.OutputFeatures().First().Current().as(tensorDescriptor)); + WINML_EXPECT_TRUE(tensorDescriptor != nullptr); - auto tensorName = tensorDescriptor.Name(); - EXPECT_EQ(L"softmaxout_1", tensorName); + auto tensorName = tensorDescriptor.Name(); + WINML_EXPECT_EQUAL(L"softmaxout_1", tensorName); - auto modelDataKind = tensorDescriptor.TensorKind(); - EXPECT_EQ(TensorKind::Float, modelDataKind); + auto modelDataKind = tensorDescriptor.TensorKind(); + WINML_EXPECT_EQUAL(TensorKind::Float, modelDataKind); - EXPECT_TRUE(tensorDescriptor.IsRequired()); + WINML_EXPECT_TRUE(tensorDescriptor.IsRequired()); - std::vector expectedShapes = { 1, 1000, 1, 1 }; - EXPECT_EQ(expectedShapes.size(), tensorDescriptor.Shape().Size()); - for (uint32_t j = 0; j < tensorDescriptor.Shape().Size(); j++) - { - EXPECT_EQ(expectedShapes.at(j), tensorDescriptor.Shape().GetAt(j)); - } + std::vector expectedShapes = {1, 1000, 1, 1}; + WINML_EXPECT_EQUAL(expectedShapes.size(), tensorDescriptor.Shape().Size()); + for (uint32_t j = 0; j < tensorDescriptor.Shape().Size(); j++) { + WINML_EXPECT_EQUAL(expectedShapes.at(j), tensorDescriptor.Shape().GetAt(j)); + } - auto first = m_model.OutputFeatures().First(); - first.MoveNext(); - EXPECT_FALSE(first.HasCurrent()); + auto first = learningModel.OutputFeatures().First(); + first.MoveNext(); + WINML_EXPECT_FALSE(first.HasCurrent()); } -TEST_F(LearningModelAPITest, CloseModelCheckMetadata) -{ - EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx")); - EXPECT_NO_THROW(m_model.Close()); - std::wstring author(m_model.Author()); - EXPECT_EQ(L"onnx-caffe2", author); - std::wstring name(m_model.Name()); - EXPECT_EQ(L"squeezenet_old", name); - std::wstring domain(m_model.Domain()); - EXPECT_EQ(L"test-domain", domain); - std::wstring description(m_model.Description()); - EXPECT_EQ(L"test-doc_string", description); - int64_t version(m_model.Version()); - EXPECT_EQ(123456, version); +static void CloseModelCheckMetadata() { + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel)); + WINML_EXPECT_NO_THROW(learningModel.Close()); + std::wstring author(learningModel.Author()); + WINML_EXPECT_EQUAL(L"onnx-caffe2", author); + std::wstring name(learningModel.Name()); + WINML_EXPECT_EQUAL(L"squeezenet_old", name); + std::wstring domain(learningModel.Domain()); + WINML_EXPECT_EQUAL(L"test-domain", domain); + std::wstring description(learningModel.Description()); + WINML_EXPECT_EQUAL(L"test-doc_string", description); + int64_t version(learningModel.Version()); + WINML_EXPECT_EQUAL(123456, version); } -TEST_F(LearningModelAPITestGpu, CloseModelCheckEval) -{ - EXPECT_NO_THROW(LoadModel(L"model.onnx")); - LearningModelSession session = nullptr; - EXPECT_NO_THROW(session = LearningModelSession(m_model)); - EXPECT_NO_THROW(m_model.Close()); +static void CloseModelCheckEval() { + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel)); + LearningModelSession session = nullptr; + WINML_EXPECT_NO_THROW(session = LearningModelSession(learningModel)); + WINML_EXPECT_NO_THROW(learningModel.Close()); - std::wstring fullImagePath = FileHelpers::GetModulePath() + L"kitten_224.png"; - StorageFile imagefile = StorageFile::GetFileFromPathAsync(fullImagePath).get(); - IRandomAccessStream stream = imagefile.OpenAsync(FileAccessMode::Read).get(); - SoftwareBitmap softwareBitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); - VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(softwareBitmap); + std::wstring fullImagePath = FileHelpers::GetModulePath() + L"kitten_224.png"; + StorageFile imagefile = StorageFile::GetFileFromPathAsync(fullImagePath).get(); + IRandomAccessStream stream = imagefile.OpenAsync(FileAccessMode::Read).get(); + SoftwareBitmap softwareBitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); + VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(softwareBitmap); - LearningModelBinding binding = nullptr; - EXPECT_NO_THROW(binding = LearningModelBinding(session)); - EXPECT_NO_THROW(binding.Bind(m_model.InputFeatures().First().Current().Name(), frame)); + LearningModelBinding binding = nullptr; + WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); + WINML_EXPECT_NO_THROW(binding.Bind(learningModel.InputFeatures().First().Current().Name(), frame)); - EXPECT_NO_THROW(session.Evaluate(binding, L"")); + WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); } -TEST_F(LearningModelAPITest, CloseModelNoNewSessions) -{ - EXPECT_NO_THROW(LoadModel(L"model.onnx")); - EXPECT_NO_THROW(m_model.Close()); - LearningModelSession session = nullptr; - EXPECT_THROW( - try { - session = LearningModelSession(m_model); - } catch (const winrt::hresult_error& e) { - EXPECT_EQ(E_INVALIDARG, e.code()); - throw; - } - , winrt::hresult_error); +static void CloseModelNoNewSessions() { + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel)); + WINML_EXPECT_NO_THROW(learningModel.Close()); + LearningModelSession session = nullptr; + WINML_EXPECT_THROW_SPECIFIC( + session = LearningModelSession(learningModel);, + winrt::hresult_error, + [](const winrt::hresult_error& e) -> bool { + return e.code() == E_INVALIDARG; + }); } + +const LearningModelApiTestApi& getapi() { + static constexpr LearningModelApiTestApi api = + { + LearningModelAPITestSetup, + LearningModelAPITestGpuSetup, + CreateModelFromFilePath, + CreateModelFromIStorage, + CreateModelFromIStorageOutsideCwd, + CreateModelFromIStream, + ModelGetAuthor, + ModelGetName, + ModelGetDomain, + ModelGetDescription, + ModelGetVersion, + EnumerateInputs, + EnumerateOutputs, + CloseModelCheckMetadata, + CloseModelCheckEval, + CloseModelNoNewSessions + }; + return api; +} \ No newline at end of file diff --git a/winml/test/api/LearningModelAPITest.h b/winml/test/api/LearningModelAPITest.h new file mode 100644 index 0000000000..4a723ab2d9 --- /dev/null +++ b/winml/test/api/LearningModelAPITest.h @@ -0,0 +1,41 @@ +#include "test.h" +struct LearningModelApiTestApi +{ + SetupTest LearningModelAPITestSetup; + SetupTest LearningModelAPITestGpuSetup; + VoidTest CreateModelFromFilePath; + VoidTest CreateModelFromIStorage; + VoidTest CreateModelFromIStorageOutsideCwd; + VoidTest CreateModelFromIStream; + VoidTest ModelGetAuthor; + VoidTest ModelGetName; + VoidTest ModelGetDomain; + VoidTest ModelGetDescription; + VoidTest ModelGetVersion; + VoidTest EnumerateInputs; + VoidTest EnumerateOutputs; + VoidTest CloseModelCheckMetadata; + VoidTest CloseModelCheckEval; + VoidTest CloseModelNoNewSessions; +}; +const LearningModelApiTestApi& getapi(); + +WINML_TEST_CLASS_BEGIN_WITH_SETUP(LearningModelAPITest, LearningModelAPITestSetup) +WINML_TEST(LearningModelAPITest, CreateModelFromFilePath) +WINML_TEST(LearningModelAPITest, CreateModelFromIStorage) +WINML_TEST(LearningModelAPITest, CreateModelFromIStorageOutsideCwd) +WINML_TEST(LearningModelAPITest, CreateModelFromIStream) +WINML_TEST(LearningModelAPITest, ModelGetAuthor) +WINML_TEST(LearningModelAPITest, ModelGetName) +WINML_TEST(LearningModelAPITest, ModelGetDomain) +WINML_TEST(LearningModelAPITest, ModelGetDescription) +WINML_TEST(LearningModelAPITest, ModelGetVersion) +WINML_TEST(LearningModelAPITest, EnumerateInputs) +WINML_TEST(LearningModelAPITest, EnumerateOutputs) +WINML_TEST(LearningModelAPITest, CloseModelCheckMetadata) +WINML_TEST(LearningModelAPITest, CloseModelNoNewSessions) +WINML_TEST_CLASS_END() + +WINML_TEST_CLASS_BEGIN_WITH_SETUP(LearningModelAPITestGpu, LearningModelAPITestGpuSetup) +WINML_TEST(LearningModelAPITestGpu, CloseModelCheckEval) +WINML_TEST_CLASS_END() \ No newline at end of file diff --git a/winml/test/api/LearningModelBindingAPITest.cpp b/winml/test/api/LearningModelBindingAPITest.cpp index 969c28ba63..99d9dc6e9b 100644 --- a/winml/test/api/LearningModelBindingAPITest.cpp +++ b/winml/test/api/LearningModelBindingAPITest.cpp @@ -1,13 +1,14 @@ #include "testPch.h" #include "APITest.h" +#include "LearningModelBindingAPITest.h" #include "SqueezeNetValidator.h" #include #include #include "winrt/Windows.Storage.h" #include "DeviceHelpers.h" - +#include using namespace winrt; using namespace winrt::Windows::AI::MachineLearning; using namespace winrt::Windows::Foundation::Collections; @@ -15,25 +16,22 @@ using namespace winrt::Windows::Graphics::Imaging; using namespace winrt::Windows::Media; using namespace winrt::Windows::Storage; -class LearningModelBindingAPITest : public APITest -{}; +static void LearningModelBindingAPITestSetup() { + init_apartment(); +} -class LearningModelBindingAPITestGpu : public LearningModelBindingAPITest -{ -protected: - void SetUp() override - { - GPUTEST - } -}; +static void LearningModelBindingAPITestGpuSetup() { + GPUTEST; + init_apartment(); +} -TEST_F(LearningModelBindingAPITest, CpuSqueezeNet) +static void CpuSqueezeNet() { std::string cpuInstance("CPU"); WinML::Engine::Test::ModelValidator::SqueezeNet(cpuInstance, LearningModelDeviceKind::Cpu, /*dataTolerance*/ 0.00001f, false); } -TEST_F(LearningModelBindingAPITest, CpuSqueezeNetEmptyOutputs) +static void CpuSqueezeNetEmptyOutputs() { std::string cpuInstance("CPU"); WinML::Engine::Test::ModelValidator::SqueezeNet( @@ -44,7 +42,7 @@ TEST_F(LearningModelBindingAPITest, CpuSqueezeNetEmptyOutputs) OutputBindingStrategy::Empty); } -TEST_F(LearningModelBindingAPITest, CpuSqueezeNetUnboundOutputs) +static void CpuSqueezeNetUnboundOutputs() { std::string cpuInstance("CPU"); WinML::Engine::Test::ModelValidator::SqueezeNet( @@ -55,7 +53,7 @@ TEST_F(LearningModelBindingAPITest, CpuSqueezeNetUnboundOutputs) OutputBindingStrategy::Unbound); } -TEST_F(LearningModelBindingAPITest, CpuSqueezeNetBindInputTensorAsInspectable) +static void CpuSqueezeNetBindInputTensorAsInspectable() { std::string cpuInstance("CPU"); WinML::Engine::Test::ModelValidator::SqueezeNet( @@ -67,27 +65,28 @@ TEST_F(LearningModelBindingAPITest, CpuSqueezeNetBindInputTensorAsInspectable) true /* bind inputs as inspectables */); } -TEST_F(LearningModelBindingAPITest, CastMapInt64) +static void CastMapInt64() { - EXPECT_NO_THROW(LoadModel(L"castmap-int64.onnx")); + WINML_EXPECT_NO_THROW(LearningModel::LoadFromFilePath(FileHelpers::GetModulePath() + L"castmap-int64.onnx")); // TODO: Check Descriptor } -TEST_F(LearningModelBindingAPITest, DictionaryVectorizerMapInt64) +static void DictionaryVectorizerMapInt64() { - EXPECT_NO_THROW(LoadModel(L"dictvectorizer-int64.onnx")); + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"dictvectorizer-int64.onnx", learningModel)); - auto inputDescriptor = m_model.InputFeatures().First().Current(); - EXPECT_TRUE(inputDescriptor.Kind() == LearningModelFeatureKind::Map); + auto inputDescriptor = learningModel.InputFeatures().First().Current(); + WINML_EXPECT_TRUE(inputDescriptor.Kind() == LearningModelFeatureKind::Map); auto mapDescriptor = inputDescriptor.as(); - EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::Int64); - EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor); + WINML_EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::Int64); + WINML_EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor); auto tensorDescriptor = mapDescriptor.ValueDescriptor().as(); // empty size means tensor of scalar value - EXPECT_TRUE(tensorDescriptor.Shape().Size() == 0); - EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float); + WINML_EXPECT_TRUE(tensorDescriptor.Shape().Size() == 0); + WINML_EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float); - LearningModelSession modelSession(m_model); + LearningModelSession modelSession(learningModel); LearningModelBinding binding(modelSession); std::unordered_map map; map[1] = 1.f; @@ -102,38 +101,39 @@ TEST_F(LearningModelBindingAPITest, DictionaryVectorizerMapInt64) binding.Bind(mapInputName, abiMap); auto mapInputInspectable = abiMap.as(); auto first = binding.First(); - EXPECT_TRUE(first.Current().Key() == mapInputName); - EXPECT_TRUE(first.Current().Value() == mapInputInspectable); - EXPECT_TRUE(binding.Lookup(mapInputName) == mapInputInspectable); + WINML_EXPECT_TRUE(first.Current().Key() == mapInputName); + WINML_EXPECT_TRUE(first.Current().Value() == mapInputInspectable); + WINML_EXPECT_TRUE(binding.Lookup(mapInputName) == mapInputInspectable); // Bind as IMapView auto mapView = abiMap.GetView(); binding.Bind(mapInputName, mapView); mapInputInspectable = mapView.as(); first = binding.First(); - EXPECT_TRUE(first.Current().Key() == mapInputName); - EXPECT_TRUE(first.Current().Value() == mapView); - EXPECT_TRUE(binding.Lookup(mapInputName) == mapView); + WINML_EXPECT_TRUE(first.Current().Key() == mapInputName); + WINML_EXPECT_TRUE(first.Current().Value() == mapView); + WINML_EXPECT_TRUE(binding.Lookup(mapInputName) == mapView); } -TEST_F(LearningModelBindingAPITest, DictionaryVectorizerMapString) +static void DictionaryVectorizerMapString() { - EXPECT_NO_THROW(LoadModel(L"dictvectorizer-string.onnx")); + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"dictvectorizer-string.onnx", learningModel)); - auto inputDescriptor = m_model.InputFeatures().First().Current(); - EXPECT_TRUE(inputDescriptor.Kind() == LearningModelFeatureKind::Map); + auto inputDescriptor = learningModel.InputFeatures().First().Current(); + WINML_EXPECT_TRUE(inputDescriptor.Kind() == LearningModelFeatureKind::Map); auto mapDescriptor = inputDescriptor.as(); - EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::String); - EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor); + WINML_EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::String); + WINML_EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor); auto tensorDescriptor = mapDescriptor.ValueDescriptor().as(); // empty size means tensor of scalar value - EXPECT_TRUE(tensorDescriptor.Shape().Size() == 0); - EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float); + WINML_EXPECT_TRUE(tensorDescriptor.Shape().Size() == 0); + WINML_EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float); - LearningModelSession modelSession(m_model); + LearningModelSession modelSession(learningModel); LearningModelBinding binding(modelSession); std::unordered_map map; map[L"1"] = 1.f; @@ -146,9 +146,9 @@ TEST_F(LearningModelBindingAPITest, DictionaryVectorizerMapString) auto mapInputInspectable = abiMap.as(); auto first = binding.First(); - EXPECT_TRUE(first.Current().Key() == mapInputName); - EXPECT_TRUE(first.Current().Value() == mapInputInspectable); - EXPECT_TRUE(binding.Lookup(mapInputName) == mapInputInspectable); + WINML_EXPECT_TRUE(first.Current().Key() == mapInputName); + WINML_EXPECT_TRUE(first.Current().Value() == mapInputInspectable); + WINML_EXPECT_TRUE(binding.Lookup(mapInputName) == mapInputInspectable); } static void RunZipMapInt64( @@ -157,15 +157,15 @@ static void RunZipMapInt64( { auto outputFeatures = model.OutputFeatures(); auto outputDescriptor = outputFeatures.First().Current(); - EXPECT_TRUE(outputDescriptor.Kind() == LearningModelFeatureKind::Sequence); + WINML_EXPECT_TRUE(outputDescriptor.Kind() == LearningModelFeatureKind::Sequence); auto seqDescriptor = outputDescriptor.as(); auto mapDescriptor = seqDescriptor.ElementDescriptor().as(); - EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::Int64); + WINML_EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::Int64); - EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor); + WINML_EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor); auto tensorDescriptor = mapDescriptor.ValueDescriptor().as(); - EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float); + WINML_EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float); LearningModelSession session(model); LearningModelBinding binding(session); @@ -199,63 +199,66 @@ static void RunZipMapInt64( // from output binding const auto &out1 = abiOutput.GetAt(0); const auto &out2 = result.Lookup(L"Y").as>().GetAt(0); - SCOPED_TRACE((std::ostringstream() << "size: " << out1.Size()).str()); + WINML_LOG_COMMENT((std::ostringstream() << "size: " << out1.Size()).str()); // check outputs auto iter1 = out1.First(); auto iter2 = out2.First(); for (uint32_t i = 0, size = (uint32_t)inputs.size(); i < size; ++i) { - EXPECT_TRUE(iter1.HasCurrent()); - EXPECT_TRUE(iter2.HasCurrent()); + WINML_EXPECT_TRUE(iter1.HasCurrent()); + WINML_EXPECT_TRUE(iter2.HasCurrent()); const auto &pair1 = iter1.Current(); const auto &pair2 = iter2.Current(); - SCOPED_TRACE((std::ostringstream() << "key: " << pair1.Key() << ", value: " << pair2.Value()).str()); - EXPECT_TRUE(pair1.Key() == i && pair2.Key() == i); - EXPECT_TRUE(pair1.Value() == inputs[i] && pair2.Value() == inputs[i]); + WINML_LOG_COMMENT((std::ostringstream() << "key: " << pair1.Key() << ", value: " << pair2.Value()).str()); + WINML_EXPECT_TRUE(pair1.Key() == i && pair2.Key() == i); + WINML_EXPECT_TRUE(pair1.Value() == inputs[i] && pair2.Value() == inputs[i]); iter1.MoveNext(); iter2.MoveNext(); } - EXPECT_TRUE(!iter1.HasCurrent()); - EXPECT_TRUE(!iter2.HasCurrent()); + WINML_EXPECT_TRUE(!iter1.HasCurrent()); + WINML_EXPECT_TRUE(!iter2.HasCurrent()); } else { abiOutput = result.Lookup(L"Y").as(); - EXPECT_TRUE(abiOutput.Size() == 1); + WINML_EXPECT_TRUE(abiOutput.Size() == 1); ABIMap map = abiOutput.GetAt(0); - EXPECT_TRUE(map.Size() == 3); - EXPECT_TRUE(map.Lookup(0) == 0.5); - EXPECT_TRUE(map.Lookup(1) == .25); - EXPECT_TRUE(map.Lookup(2) == .125); + WINML_EXPECT_TRUE(map.Size() == 3); + WINML_EXPECT_TRUE(map.Lookup(0) == 0.5); + WINML_EXPECT_TRUE(map.Lookup(1) == .25); + WINML_EXPECT_TRUE(map.Lookup(2) == .125); } } -TEST_F(LearningModelBindingAPITest, ZipMapInt64) +static void ZipMapInt64() { - EXPECT_NO_THROW(LoadModel(L"zipmap-int64.onnx")); - RunZipMapInt64(m_model, OutputBindingStrategy::Bound); + LearningModel learningModel= nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"zipmap-int64.onnx", learningModel)); + RunZipMapInt64(learningModel, OutputBindingStrategy::Bound); } -TEST_F(LearningModelBindingAPITest, ZipMapInt64Unbound) +static void ZipMapInt64Unbound() { - EXPECT_NO_THROW(LoadModel(L"zipmap-int64.onnx")); - RunZipMapInt64(m_model, OutputBindingStrategy::Unbound); + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"zipmap-int64.onnx", learningModel)); + RunZipMapInt64(learningModel, OutputBindingStrategy::Unbound); } -TEST_F(LearningModelBindingAPITest, ZipMapString) +static void ZipMapString() { // output constraint: "seq(map(string, float))" or "seq(map(int64, float))" - EXPECT_NO_THROW(LoadModel(L"zipmap-string.onnx")); - auto outputs = m_model.OutputFeatures(); + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"zipmap-string.onnx", learningModel)); + auto outputs = learningModel.OutputFeatures(); auto outputDescriptor = outputs.First().Current(); - EXPECT_TRUE(outputDescriptor.Kind() == LearningModelFeatureKind::Sequence); + WINML_EXPECT_TRUE(outputDescriptor.Kind() == LearningModelFeatureKind::Sequence); auto mapDescriptor = outputDescriptor.as().ElementDescriptor().as(); - EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::String); - EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor); + WINML_EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::String); + WINML_EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor); auto tensorDescriptor = mapDescriptor.ValueDescriptor().as(); - EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float); + WINML_EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float); - LearningModelSession session(m_model); + LearningModelSession session(learningModel); LearningModelBinding binding(session); std::vector inputs = { 0.5f, 0.25f, 0.125f }; @@ -274,27 +277,27 @@ TEST_F(LearningModelBindingAPITest, ZipMapString) // from output binding const auto &out1 = ABIOutput.GetAt(0); const auto &out2 = result.Lookup(L"Y").as>().GetAt(0); - SCOPED_TRACE((std::ostringstream() << "size: " << out1.Size()).str()); + WINML_LOG_COMMENT((std::ostringstream() << "size: " << out1.Size()).str()); // single key,value pair for each map auto iter1 = out1.First(); auto iter2 = out2.First(); for (uint32_t i = 0, size = (uint32_t)inputs.size(); i < size; ++i) { - EXPECT_TRUE(iter2.HasCurrent()); + WINML_EXPECT_TRUE(iter2.HasCurrent()); const auto &pair1 = iter1.Current(); const auto &pair2 = iter2.Current(); - SCOPED_TRACE((std::ostringstream() << "key: " << pair1.Key().c_str() << ", value " << pair2.Value()).str()); - EXPECT_TRUE(std::wstring(pair1.Key().c_str()).compare(labels[i]) == 0); - EXPECT_TRUE(std::wstring(pair2.Key().c_str()).compare(labels[i]) == 0); - EXPECT_TRUE(pair1.Value() == inputs[i] && pair2.Value() == inputs[i]); + WINML_LOG_COMMENT((std::ostringstream() << "key: " << pair1.Key().c_str() << ", value " << pair2.Value()).str()); + WINML_EXPECT_TRUE(std::wstring(pair1.Key().c_str()).compare(labels[i]) == 0); + WINML_EXPECT_TRUE(std::wstring(pair2.Key().c_str()).compare(labels[i]) == 0); + WINML_EXPECT_TRUE(pair1.Value() == inputs[i] && pair2.Value() == inputs[i]); iter1.MoveNext(); iter2.MoveNext(); } - EXPECT_TRUE(!iter1.HasCurrent()); - EXPECT_TRUE(!iter2.HasCurrent()); + WINML_EXPECT_TRUE(!iter1.HasCurrent()); + WINML_EXPECT_TRUE(!iter2.HasCurrent()); } -TEST_F(LearningModelBindingAPITestGpu, GpuSqueezeNet) +static void GpuSqueezeNet() { std::string gpuInstance("GPU"); WinML::Engine::Test::ModelValidator::SqueezeNet( @@ -303,7 +306,7 @@ TEST_F(LearningModelBindingAPITestGpu, GpuSqueezeNet) /*dataTolerance*/ 0.00001f); } -TEST_F(LearningModelBindingAPITestGpu, GpuSqueezeNetEmptyOutputs) +static void GpuSqueezeNetEmptyOutputs() { std::string gpuInstance("GPU"); WinML::Engine::Test::ModelValidator::SqueezeNet( @@ -314,7 +317,7 @@ TEST_F(LearningModelBindingAPITestGpu, GpuSqueezeNetEmptyOutputs) OutputBindingStrategy::Empty); } -TEST_F(LearningModelBindingAPITestGpu, GpuSqueezeNetUnboundOutputs) +static void GpuSqueezeNetUnboundOutputs() { std::string gpuInstance("GPU"); WinML::Engine::Test::ModelValidator::SqueezeNet( @@ -326,44 +329,48 @@ TEST_F(LearningModelBindingAPITestGpu, GpuSqueezeNetUnboundOutputs) } // Validates that when the input image is the same as the model expects, the binding step is executed correctly. -TEST_F(LearningModelBindingAPITestGpu, ImageBindingDimensions) +static void ImageBindingDimensions() { - LearningModelBinding m_binding = nullptr; + LearningModelBinding learningModelBinding = nullptr; + LearningModel learningModel = nullptr; + LearningModelSession learningModelSession = nullptr; + LearningModelDevice leraningModelDevice = nullptr; std::wstring filePath = FileHelpers::GetModulePath() + L"model.onnx"; // load a model with expected input size: 224 x 224 - EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::Default)); - EXPECT_NO_THROW(m_model = LearningModel::LoadFromFilePath(filePath)); - EXPECT_TRUE(m_model != nullptr); - EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device)); - EXPECT_NO_THROW(m_binding = LearningModelBinding(m_session)); + WINML_EXPECT_NO_THROW(leraningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default)); + WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromFilePath(filePath)); + WINML_EXPECT_TRUE(learningModel != nullptr); + WINML_EXPECT_NO_THROW(learningModelSession = LearningModelSession(learningModel, leraningModelDevice)); + WINML_EXPECT_NO_THROW(learningModelBinding = LearningModelBinding(learningModelSession)); // Create input images and execute bind // Test Case 1: both width and height are larger than model expects VideoFrame inputImage1(BitmapPixelFormat::Rgba8, 1000, 1000); ImageFeatureValue inputTensor = ImageFeatureValue::CreateFromVideoFrame(inputImage1); - EXPECT_NO_THROW(m_binding.Bind(L"data_0", inputTensor)); + WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"data_0", inputTensor)); // Test Case 2: only height is larger, while width is smaller VideoFrame inputImage2(BitmapPixelFormat::Rgba8, 20, 1000); inputTensor = ImageFeatureValue::CreateFromVideoFrame(inputImage2); - EXPECT_NO_THROW(m_binding.Bind(L"data_0", inputTensor)); + WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"data_0", inputTensor)); // Test Case 3: only width is larger, while height is smaller VideoFrame inputImage3(BitmapPixelFormat::Rgba8, 1000, 20); inputTensor = ImageFeatureValue::CreateFromVideoFrame(inputImage3); - EXPECT_NO_THROW(m_binding.Bind(L"data_0", inputTensor)); + WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"data_0", inputTensor)); // Test Case 4: both width and height are smaller than model expects VideoFrame inputImage4(BitmapPixelFormat::Rgba8, 20, 20); inputTensor = ImageFeatureValue::CreateFromVideoFrame(inputImage4); - EXPECT_NO_THROW(m_binding.Bind(L"data_0", inputTensor)); + WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"data_0", inputTensor)); } -TEST_F(LearningModelBindingAPITestGpu, VerifyInvalidBindExceptions) +static void VerifyInvalidBindExceptions() { - EXPECT_NO_THROW(LoadModel(L"zipmap-int64.onnx")); + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"zipmap-int64.onnx", learningModel)); - LearningModelSession session(m_model); + LearningModelSession session(learningModel); LearningModelBinding binding(session); std::vector inputs = { 0.5f, 0.25f, 0.125f }; @@ -384,47 +391,47 @@ TEST_F(LearningModelBindingAPITestGpu, VerifyInvalidBindExceptions) // Bind invalid image as tensorfloat input auto image = FileHelpers::LoadImageFeatureValue(L"227x227.png"); - EXPECT_THROW_SPECIFIC(binding.Bind(L"X", image), winrt::hresult_error, ensureWinmlSizeMismatch); + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", image), winrt::hresult_error, ensureWinmlSizeMismatch); // Bind invalid map as tensorfloat input std::unordered_map map; auto abiMap = winrt::single_threaded_map(std::move(map)); - EXPECT_THROW_SPECIFIC(binding.Bind(L"X", abiMap), winrt::hresult_error, ensureWinmlInvalidBinding); + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", abiMap), winrt::hresult_error, ensureWinmlInvalidBinding); // Bind invalid sequence as tensorfloat input std::vector sequence; auto abiSequence = winrt::single_threaded_vector(std::move(sequence)); - EXPECT_THROW_SPECIFIC(binding.Bind(L"X", abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding); + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding); // Bind invalid tensor size as tensorfloat input auto tensorBoolean = TensorBoolean::Create(); - EXPECT_THROW_SPECIFIC(binding.Bind(L"X", tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding); + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding); // Bind invalid tensor shape as tensorfloat input auto tensorInvalidShape = TensorFloat::Create(std::vector { 2, 3, 4 }); - EXPECT_THROW_SPECIFIC(binding.Bind(L"X", tensorInvalidShape), winrt::hresult_error, ensureWinmlInvalidBinding); + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", tensorInvalidShape), winrt::hresult_error, ensureWinmlInvalidBinding); /* Verify sequence bindings throw correct bind exceptions */ // Bind invalid image as sequence output - EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", image), winrt::hresult_error, ensureWinmlInvalidBinding); + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", image), winrt::hresult_error, ensureWinmlInvalidBinding); // Bind invalid map as sequence output - EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", abiMap), winrt::hresult_error, ensureWinmlInvalidBinding); + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", abiMap), winrt::hresult_error, ensureWinmlInvalidBinding); // Bind invalid sequence as sequence output - EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding); + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding); // Bind invalid tensor as sequence output - EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding); + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding); /* Verify image bindings throw correct bind exceptions */ - // EXPECT_NO_THROW(LoadModel(L"fns-candy.onnx")); + // WINML_EXPECT_NO_THROW(LoadModel(L"fns-candy.onnx")); // LearningModelSession imageSession(m_model); // LearningModelBinding imageBinding(imageSession); @@ -432,74 +439,77 @@ TEST_F(LearningModelBindingAPITestGpu, VerifyInvalidBindExceptions) // auto inputName = m_model.InputFeatures().First().Current().Name(); // // Bind invalid map as image input - // EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, abiMap), winrt::hresult_error, ensureWinmlInvalidBinding); + // WINML_EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, abiMap), winrt::hresult_error, ensureWinmlInvalidBinding); // // Bind invalid sequence as image input - // EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding); + // WINML_EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding); // // Bind invalid tensor type as image input - // EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding); + // WINML_EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding); // // Bind invalid tensor size as image input // auto tensorFloat = TensorFloat::Create(std::vector { 1, 1, 100, 100 }); - // EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, tensorFloat), winrt::hresult_error, ensureWinmlInvalidBinding); + // WINML_EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, tensorFloat), winrt::hresult_error, ensureWinmlInvalidBinding); // // Bind invalid tensor shape as image input - // EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, tensorInvalidShape), winrt::hresult_error, ensureWinmlInvalidBinding); + // WINML_EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, tensorInvalidShape), winrt::hresult_error, ensureWinmlInvalidBinding); /* Verify map bindings throw correct bind exceptions */ - EXPECT_NO_THROW(LoadModel(L"dictvectorizer-int64.onnx")); + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"dictvectorizer-int64.onnx", learningModel)); - LearningModelSession mapSession(m_model); + LearningModelSession mapSession(learningModel); LearningModelBinding mapBinding(mapSession); - auto inputName = m_model.InputFeatures().First().Current().Name(); + auto inputName = learningModel.InputFeatures().First().Current().Name(); // Bind invalid image as image input auto smallImage = FileHelpers::LoadImageFeatureValue(L"100x100.png"); - EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, smallImage), winrt::hresult_error, ensureWinmlInvalidBinding); + WINML_EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, smallImage), winrt::hresult_error, ensureWinmlInvalidBinding); // Bind invalid map as image input - EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, abiMap), winrt::hresult_error, ensureWinmlInvalidBinding); + WINML_EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, abiMap), winrt::hresult_error, ensureWinmlInvalidBinding); // Bind invalid sequence as image input - EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding); + WINML_EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding); // Bind invalid tensor type as image input - EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding); + WINML_EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding); } // Verify that it throws an error when binding an invalid name. -TEST_F(LearningModelBindingAPITestGpu, BindInvalidInputName) +static void BindInvalidInputName() { - LearningModelBinding m_binding = nullptr; + LearningModel learningModel = nullptr; + LearningModelBinding learningModelBinding = nullptr; + LearningModelDevice learningModelDevice = nullptr; + LearningModelSession learningModelSession = nullptr; std::wstring modelPath = FileHelpers::GetModulePath() + L"Add_ImageNet1920.onnx"; - EXPECT_NO_THROW(m_model = LearningModel::LoadFromFilePath(modelPath)); - EXPECT_TRUE(m_model != nullptr); - EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::Default)); - EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device)); - EXPECT_NO_THROW(m_binding = LearningModelBinding(m_session)); + WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromFilePath(modelPath)); + WINML_EXPECT_TRUE(learningModel != nullptr); + WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default)); + WINML_EXPECT_NO_THROW(learningModelSession = LearningModelSession(learningModel, learningModelDevice)); + WINML_EXPECT_NO_THROW(learningModelBinding = LearningModelBinding(learningModelSession)); VideoFrame iuputImage(BitmapPixelFormat::Rgba8, 1920, 1080); ImageFeatureValue inputTensor = ImageFeatureValue::CreateFromVideoFrame(iuputImage); - auto first = m_model.InputFeatures().First(); + auto first = learningModel.InputFeatures().First(); std::wstring testInvalidName = L"0"; // Verify that testInvalidName is not in model's InputFeatures while (first.HasCurrent()) { - EXPECT_NE(testInvalidName, first.Current().Name()); + WINML_EXPECT_NOT_EQUAL(testInvalidName, first.Current().Name()); first.MoveNext(); } // Bind inputTensor to a valid input name - EXPECT_NO_THROW(m_binding.Bind(L"input_39:0", inputTensor)); + WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"input_39:0", inputTensor)); // Bind inputTensor to an invalid input name - EXPECT_THROW_SPECIFIC(m_binding.Bind(testInvalidName, inputTensor), + WINML_EXPECT_THROW_SPECIFIC(learningModelBinding.Bind(testInvalidName, inputTensor), winrt::hresult_error, [](const winrt::hresult_error& e) -> bool { @@ -507,15 +517,18 @@ TEST_F(LearningModelBindingAPITestGpu, BindInvalidInputName) }); } -TEST_F(LearningModelBindingAPITest, VerifyOutputAfterEvaluateAsyncCalledTwice) +static void VerifyOutputAfterEvaluateAsyncCalledTwice() { - LearningModelBinding m_binding = nullptr; + LearningModel learningModel = nullptr; + LearningModelBinding learningModelBinding = nullptr; + LearningModelDevice learningModelDevice = nullptr; + LearningModelSession learningModelSession = nullptr; std::wstring filePath = FileHelpers::GetModulePath() + L"relu.onnx"; - EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::Default)); - EXPECT_NO_THROW(m_model = LearningModel::LoadFromFilePath(filePath)); - EXPECT_TRUE(m_model != nullptr); - EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device)); - EXPECT_NO_THROW(m_binding = LearningModelBinding(m_session)); + WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default)); + WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromFilePath(filePath)); + WINML_EXPECT_TRUE(learningModel != nullptr); + WINML_EXPECT_NO_THROW(learningModelSession = LearningModelSession(learningModel, learningModelDevice)); + WINML_EXPECT_NO_THROW(learningModelBinding = LearningModelBinding(learningModelSession)); auto inputShape = std::vector{ 5 }; auto inputData1 = std::vector{ -50.f, -25.f, 0.f, 25.f, 50.f }; @@ -530,22 +543,22 @@ TEST_F(LearningModelBindingAPITest, VerifyOutputAfterEvaluateAsyncCalledTwice) inputShape, single_threaded_vector(std::move(inputData2)).GetView()); - EXPECT_NO_THROW(m_binding.Bind(L"X", inputValue1)); + WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"X", inputValue1)); auto outputValue = TensorFloat::Create(); - EXPECT_NO_THROW(m_binding.Bind(L"Y", outputValue)); + WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"Y", outputValue)); - EXPECT_NO_THROW(m_session.Evaluate(m_binding, L"")); + WINML_EXPECT_NO_THROW(learningModelSession.Evaluate(learningModelBinding, L"")); auto buffer1 = outputValue.GetAsVectorView(); - EXPECT_TRUE(buffer1 != nullptr); + WINML_EXPECT_TRUE(buffer1 != nullptr); // The second evaluation // If we don't bind output again, the output value will not change - EXPECT_NO_THROW(m_binding.Bind(L"X", inputValue2)); - EXPECT_NO_THROW(m_session.Evaluate(m_binding, L"")); + WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"X", inputValue2)); + WINML_EXPECT_NO_THROW(learningModelSession.Evaluate(learningModelBinding, L"")); auto buffer2 = outputValue.GetAsVectorView(); - EXPECT_EQ(buffer1.Size(), buffer2.Size()); + WINML_EXPECT_EQUAL(buffer1.Size(), buffer2.Size()); bool isSame = true; for (uint32_t i = 0; i < buffer1.Size(); ++i) { @@ -555,7 +568,7 @@ TEST_F(LearningModelBindingAPITest, VerifyOutputAfterEvaluateAsyncCalledTwice) break; } } - EXPECT_FALSE(isSame); + WINML_EXPECT_FALSE(isSame); } static VideoFrame CreateVideoFrame(const wchar_t* path) @@ -567,7 +580,7 @@ static VideoFrame CreateVideoFrame(const wchar_t* path) return VideoFrame::CreateWithSoftwareBitmap(softwareBitmap); } -TEST_F(LearningModelBindingAPITest, VerifyOutputAfterImageBindCalledTwice) +static void VerifyOutputAfterImageBindCalledTwice() { std::wstring fullModelPath = FileHelpers::GetModulePath() + L"model.onnx"; std::wstring fullImagePath1 = FileHelpers::GetModulePath() + L"kitten_224.png"; @@ -575,9 +588,9 @@ TEST_F(LearningModelBindingAPITest, VerifyOutputAfterImageBindCalledTwice) // winml model creation LearningModel model = nullptr; - EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(fullModelPath)); + WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(fullModelPath)); LearningModelSession modelSession = nullptr; - EXPECT_NO_THROW(modelSession = LearningModelSession(model, LearningModelDevice(LearningModelDeviceKind::Default))); + WINML_EXPECT_NO_THROW(modelSession = LearningModelSession(model, LearningModelDevice(LearningModelDeviceKind::Default))); LearningModelBinding modelBinding(modelSession); // create the tensor for the actual output @@ -587,8 +600,8 @@ TEST_F(LearningModelBindingAPITest, VerifyOutputAfterImageBindCalledTwice) // Bind image 1 and evaluate auto frame = CreateVideoFrame(fullImagePath1.c_str()); auto imageTensor = ImageFeatureValue::CreateFromVideoFrame(frame); - EXPECT_NO_THROW(modelBinding.Bind(L"data_0", imageTensor)); - EXPECT_NO_THROW(modelSession.Evaluate(modelBinding, L"")); + WINML_EXPECT_NO_THROW(modelBinding.Bind(L"data_0", imageTensor)); + WINML_EXPECT_NO_THROW(modelSession.Evaluate(modelBinding, L"")); // Store 1st result auto outputVectorView1 = output.GetAsVectorView(); @@ -598,13 +611,13 @@ TEST_F(LearningModelBindingAPITest, VerifyOutputAfterImageBindCalledTwice) // The expected result is that the videoframe will be re-tensorized at bind auto frame2 = CreateVideoFrame(fullImagePath2.c_str()); frame2.CopyToAsync(frame).get(); - EXPECT_NO_THROW(modelBinding.Bind(L"data_0", imageTensor)); - EXPECT_NO_THROW(modelSession.Evaluate(modelBinding, L"")); + WINML_EXPECT_NO_THROW(modelBinding.Bind(L"data_0", imageTensor)); + WINML_EXPECT_NO_THROW(modelSession.Evaluate(modelBinding, L"")); // Store 2nd result auto outputVectorView2 = output.GetAsVectorView(); - EXPECT_EQ(outputVectorView1.Size(), outputVectorView2.Size()); + WINML_EXPECT_EQUAL(outputVectorView1.Size(), outputVectorView2.Size()); bool isSame = true; for (uint32_t i = 0; i < outputVectorView1.Size(); ++i) { @@ -614,5 +627,32 @@ TEST_F(LearningModelBindingAPITest, VerifyOutputAfterImageBindCalledTwice) break; } } - EXPECT_FALSE(isSame); + WINML_EXPECT_FALSE(isSame); } + +const LearningModelBindingAPITestApi& getapi() { + static constexpr LearningModelBindingAPITestApi api = + { + LearningModelBindingAPITestSetup, + LearningModelBindingAPITestGpuSetup, + CpuSqueezeNet, + CpuSqueezeNetEmptyOutputs, + CpuSqueezeNetUnboundOutputs, + CpuSqueezeNetBindInputTensorAsInspectable, + CastMapInt64, + DictionaryVectorizerMapInt64, + DictionaryVectorizerMapString, + ZipMapInt64, + ZipMapInt64Unbound, + ZipMapString, + GpuSqueezeNet, + GpuSqueezeNetEmptyOutputs, + GpuSqueezeNetUnboundOutputs, + ImageBindingDimensions, + VerifyInvalidBindExceptions, + BindInvalidInputName, + VerifyOutputAfterEvaluateAsyncCalledTwice, + VerifyOutputAfterImageBindCalledTwice + }; + return api; +} \ No newline at end of file diff --git a/winml/test/api/LearningModelBindingAPITest.h b/winml/test/api/LearningModelBindingAPITest.h new file mode 100644 index 0000000000..c93be87c3c --- /dev/null +++ b/winml/test/api/LearningModelBindingAPITest.h @@ -0,0 +1,49 @@ +#include "test.h" + +struct LearningModelBindingAPITestApi { + SetupTest LearningModelBindingAPITestSetup; + SetupTest LearningModelBindingAPITestGpuSetup; + VoidTest CpuSqueezeNet; + VoidTest CpuSqueezeNetEmptyOutputs; + VoidTest CpuSqueezeNetUnboundOutputs; + VoidTest CpuSqueezeNetBindInputTensorAsInspectable; + VoidTest CastMapInt64; + VoidTest DictionaryVectorizerMapInt64; + VoidTest DictionaryVectorizerMapString; + VoidTest ZipMapInt64; + VoidTest ZipMapInt64Unbound; + VoidTest ZipMapString; + VoidTest GpuSqueezeNet; + VoidTest GpuSqueezeNetEmptyOutputs; + VoidTest GpuSqueezeNetUnboundOutputs; + VoidTest ImageBindingDimensions; + VoidTest VerifyInvalidBindExceptions; + VoidTest BindInvalidInputName; + VoidTest VerifyOutputAfterEvaluateAsyncCalledTwice; + VoidTest VerifyOutputAfterImageBindCalledTwice; +}; +const LearningModelBindingAPITestApi& getapi(); + +WINML_TEST_CLASS_BEGIN_WITH_SETUP(LearningModelBindingAPITest, LearningModelBindingAPITestSetup) +WINML_TEST(LearningModelBindingAPITest, CpuSqueezeNet) +WINML_TEST(LearningModelBindingAPITest, CpuSqueezeNetEmptyOutputs) +WINML_TEST(LearningModelBindingAPITest, CpuSqueezeNetUnboundOutputs) +WINML_TEST(LearningModelBindingAPITest, CpuSqueezeNetBindInputTensorAsInspectable) +WINML_TEST(LearningModelBindingAPITest, CastMapInt64) +WINML_TEST(LearningModelBindingAPITest, DictionaryVectorizerMapInt64) +WINML_TEST(LearningModelBindingAPITest, DictionaryVectorizerMapString) +WINML_TEST(LearningModelBindingAPITest, ZipMapInt64) +WINML_TEST(LearningModelBindingAPITest, ZipMapInt64Unbound) +WINML_TEST(LearningModelBindingAPITest, ZipMapString) +WINML_TEST(LearningModelBindingAPITest, VerifyOutputAfterEvaluateAsyncCalledTwice) +WINML_TEST(LearningModelBindingAPITest, VerifyOutputAfterImageBindCalledTwice) +WINML_TEST_CLASS_END() + +WINML_TEST_CLASS_BEGIN_WITH_SETUP(LearningModelBindingAPITestGpu, LearningModelBindingAPITestGpuSetup) +WINML_TEST(LearningModelBindingAPITestGpu, GpuSqueezeNet) +WINML_TEST(LearningModelBindingAPITestGpu, GpuSqueezeNetEmptyOutputs) +WINML_TEST(LearningModelBindingAPITestGpu, GpuSqueezeNetUnboundOutputs) +WINML_TEST(LearningModelBindingAPITestGpu, ImageBindingDimensions) +WINML_TEST(LearningModelBindingAPITestGpu, VerifyInvalidBindExceptions) +WINML_TEST(LearningModelBindingAPITestGpu, BindInvalidInputName) +WINML_TEST_CLASS_END() \ No newline at end of file diff --git a/winml/test/api/LearningModelSessionAPITest.cpp b/winml/test/api/LearningModelSessionAPITest.cpp index bc6494a3a7..6ee0b3d57f 100644 --- a/winml/test/api/LearningModelSessionAPITest.cpp +++ b/winml/test/api/LearningModelSessionAPITest.cpp @@ -1,6 +1,6 @@ #include "testPch.h" #include "APITest.h" - +#include "LearningModelSessionAPITest.h" #include "winrt/Windows.Storage.h" #include "DeviceHelpers.h" @@ -16,144 +16,151 @@ using namespace winrt::Windows::Foundation::Collections; using winrt::Windows::Foundation::IPropertyValue; -class LearningModelSessionAPITests : public APITest -{}; - -class LearningModelSessionAPITestsGpu : public APITest -{ -protected: - void SetUp() override - { - GPUTEST - } -}; - -class LearningModelSessionAPITestsSkipEdgeCore : public LearningModelSessionAPITestsGpu -{ -protected: - void SetUp() override - { - LearningModelSessionAPITestsGpu::SetUp(); - SKIP_EDGECORE - } -}; - -TEST_F(LearningModelSessionAPITests, CreateSessionDeviceDefault) -{ - EXPECT_NO_THROW(LoadModel(L"model.onnx")); - - EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::Default)); - EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device)); +static void LearningModelSessionAPITestSetup() { + init_apartment(); } -TEST_F(LearningModelSessionAPITests, CreateSessionDeviceCpu) -{ - EXPECT_NO_THROW(LoadModel(L"model.onnx")); +static void LearningModelSessionAPITestGpuSetup() { + GPUTEST; + init_apartment(); +} - EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::Cpu)); - EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device)); +static void LearningModelSessionAPITestsSkipEdgeCoreSetup() { + LearningModelSessionAPITestGpuSetup(); + SKIP_EDGECORE +} + +static void CreateSessionDeviceDefault() +{ + LearningModel learningModel = nullptr; + LearningModelDevice learningModelDevice = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel)); + + WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default)); + WINML_EXPECT_NO_THROW(LearningModelSession(learningModel, learningModelDevice)); +} + +static void CreateSessionDeviceCpu() +{ + LearningModel learningModel = nullptr; + LearningModelDevice learningModelDevice = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel)); + + WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::Cpu)); + WINML_EXPECT_NO_THROW(LearningModelSession(learningModel, learningModelDevice)); // for the CPU device, make sure that we get back NULL and 0 for any device properties - EXPECT_FALSE(m_device.Direct3D11Device()); + WINML_EXPECT_EQUAL(learningModelDevice.Direct3D11Device(), nullptr); LARGE_INTEGER id; - id.QuadPart = GetAdapterIdQuadPart(); - EXPECT_EQ(id.LowPart, static_cast(0)); - EXPECT_EQ(id.HighPart, 0); + id.QuadPart = APITest::GetAdapterIdQuadPart(learningModelDevice); + WINML_EXPECT_EQUAL(id.LowPart, static_cast(0)); + WINML_EXPECT_EQUAL(id.HighPart, 0); } -TEST_F(LearningModelSessionAPITests, CreateSessionWithModelLoadedFromStream) +static void CreateSessionWithModelLoadedFromStream() { + LearningModel learningModel = nullptr; + LearningModelDevice learningModelDevice = nullptr; std::wstring path = FileHelpers::GetModulePath() + L"model.onnx"; auto storageFile = winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(path).get(); - EXPECT_NO_THROW(m_model = LearningModel::LoadFromStream(storageFile)); + WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromStream(storageFile)); - EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::Default)); - EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device)); + WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default)); + WINML_EXPECT_NO_THROW(LearningModelSession(learningModel, learningModelDevice)); } -TEST_F(LearningModelSessionAPITestsGpu, CreateSessionDeviceDirectX) +static void CreateSessionDeviceDirectX() { - EXPECT_NO_THROW(LoadModel(L"model.onnx")); + LearningModel learningModel = nullptr; + LearningModelDevice learningModelDevice = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel)); - EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::DirectX)); - EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device)); + WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::DirectX)); + WINML_EXPECT_NO_THROW(LearningModelSession(learningModel, learningModelDevice)); } -TEST_F(LearningModelSessionAPITestsGpu, CreateSessionDeviceDirectXHighPerformance) +static void CreateSessionDeviceDirectXHighPerformance() { - EXPECT_NO_THROW(LoadModel(L"model.onnx")); + LearningModel learningModel = nullptr; + LearningModelDevice learningModelDevice = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel)); - EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::DirectXHighPerformance)); - EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device)); + WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::DirectXHighPerformance)); + WINML_EXPECT_NO_THROW(LearningModelSession(learningModel, learningModelDevice)); } -TEST_F(LearningModelSessionAPITestsGpu, CreateSessionDeviceDirectXMinimumPower) +static void CreateSessionDeviceDirectXMinimumPower() { - EXPECT_NO_THROW(LoadModel(L"model.onnx")); + LearningModel learningModel = nullptr; + LearningModelDevice learningModelDevice = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel)); - EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::DirectXMinPower)); - EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device)); + WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::DirectXMinPower)); + WINML_EXPECT_NO_THROW(LearningModelSession(learningModel, learningModelDevice)); } -TEST_F(LearningModelSessionAPITestsSkipEdgeCore, AdapterIdAndDevice) -{ - EXPECT_NO_THROW(LoadModel(L"model.onnx")); +static void AdapterIdAndDevice() { + LearningModel learningModel = nullptr; + LearningModelDevice learningModelDevice = nullptr; + LearningModelSession learningModelSession = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel)); com_ptr factory; - EXPECT_HRESULT_SUCCEEDED(CreateDXGIFactory1(__uuidof(IDXGIFactory6), factory.put_void())); + WINML_EXPECT_HRESULT_SUCCEEDED(CreateDXGIFactory1(__uuidof(IDXGIFactory6), factory.put_void())); com_ptr adapter; - m_device = LearningModelDevice(LearningModelDeviceKind::DirectX); - EXPECT_HRESULT_SUCCEEDED(factory->EnumAdapters(0, adapter.put())); + learningModelDevice = LearningModelDevice(LearningModelDeviceKind::DirectX); + WINML_EXPECT_HRESULT_SUCCEEDED(factory->EnumAdapters(0, adapter.put())); DXGI_ADAPTER_DESC desc; - EXPECT_HRESULT_SUCCEEDED(adapter->GetDesc(&desc)); + WINML_EXPECT_HRESULT_SUCCEEDED(adapter->GetDesc(&desc)); LARGE_INTEGER id; - id.QuadPart = GetAdapterIdQuadPart(); - EXPECT_EQ(desc.AdapterLuid.LowPart, id.LowPart); - EXPECT_EQ(desc.AdapterLuid.HighPart, id.HighPart); - EXPECT_TRUE(m_device.Direct3D11Device() != nullptr); + id.QuadPart = APITest::GetAdapterIdQuadPart(learningModelDevice); + WINML_EXPECT_EQUAL(desc.AdapterLuid.LowPart, id.LowPart); + WINML_EXPECT_EQUAL(desc.AdapterLuid.HighPart, id.HighPart); + WINML_EXPECT_TRUE(learningModelDevice.Direct3D11Device() != nullptr); - m_device = LearningModelDevice(LearningModelDeviceKind::DirectXHighPerformance); + learningModelDevice = LearningModelDevice(LearningModelDeviceKind::DirectXHighPerformance); adapter = nullptr; - EXPECT_HRESULT_SUCCEEDED(factory->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, __uuidof(IDXGIAdapter), adapter.put_void())); - EXPECT_HRESULT_SUCCEEDED(adapter->GetDesc(&desc)); - id.QuadPart = GetAdapterIdQuadPart(); - EXPECT_EQ(desc.AdapterLuid.LowPart, id.LowPart); - EXPECT_EQ(desc.AdapterLuid.HighPart, id.HighPart); - EXPECT_TRUE(m_device.Direct3D11Device() != nullptr); + WINML_EXPECT_HRESULT_SUCCEEDED(factory->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, __uuidof(IDXGIAdapter), adapter.put_void())); + WINML_EXPECT_HRESULT_SUCCEEDED(adapter->GetDesc(&desc)); + id.QuadPart = APITest::GetAdapterIdQuadPart(learningModelDevice); + WINML_EXPECT_EQUAL(desc.AdapterLuid.LowPart, id.LowPart); + WINML_EXPECT_EQUAL(desc.AdapterLuid.HighPart, id.HighPart); + WINML_EXPECT_TRUE(learningModelDevice.Direct3D11Device() != nullptr); adapter = nullptr; - m_device = LearningModelDevice(LearningModelDeviceKind::DirectXMinPower); - EXPECT_HRESULT_SUCCEEDED(factory->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_MINIMUM_POWER, __uuidof(IDXGIAdapter), adapter.put_void())); - EXPECT_HRESULT_SUCCEEDED(adapter->GetDesc(&desc)); - id.QuadPart = GetAdapterIdQuadPart(); - EXPECT_EQ(desc.AdapterLuid.LowPart, id.LowPart); - EXPECT_EQ(desc.AdapterLuid.HighPart, id.HighPart); - EXPECT_TRUE(m_device.Direct3D11Device() != nullptr); + learningModelDevice = LearningModelDevice(LearningModelDeviceKind::DirectXMinPower); + WINML_EXPECT_HRESULT_SUCCEEDED(factory->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_MINIMUM_POWER, __uuidof(IDXGIAdapter), adapter.put_void())); + WINML_EXPECT_HRESULT_SUCCEEDED(adapter->GetDesc(&desc)); + id.QuadPart = APITest::GetAdapterIdQuadPart(learningModelDevice); + WINML_EXPECT_EQUAL(desc.AdapterLuid.LowPart, id.LowPart); + WINML_EXPECT_EQUAL(desc.AdapterLuid.HighPart, id.HighPart); + WINML_EXPECT_TRUE(learningModelDevice.Direct3D11Device() != nullptr); - EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device)); - EXPECT_EQ(m_session.Device().AdapterId(), m_device.AdapterId()); + WINML_EXPECT_NO_THROW(learningModelSession = LearningModelSession(learningModel, learningModelDevice)); + WINML_EXPECT_EQUAL(learningModelSession.Device().AdapterId(), learningModelDevice.AdapterId()); } -TEST_F(LearningModelSessionAPITests, EvaluateFeatures) +static void EvaluateFeatures() { std::vector shape = { 4 }; std::vector data = { L"one", L"two", L"three", L"four" }; // create from buffer auto tensor = TensorString::CreateFromArray(shape, data); - EXPECT_EQ(tensor.GetAsVectorView().Size(), data.size()); - EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView()))); + WINML_EXPECT_EQUAL(tensor.GetAsVectorView().Size(), data.size()); + WINML_EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView()))); // create from vector view auto dataCopy = data; tensor = TensorString::CreateFromIterable( shape, winrt::single_threaded_vector(std::move(dataCopy)).GetView()); - EXPECT_EQ(tensor.GetAsVectorView().Size(), data.size()); - EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView()))); + WINML_EXPECT_EQUAL(tensor.GetAsVectorView().Size(), data.size()); + WINML_EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView()))); - EXPECT_NO_THROW(LoadModel(L"id-tensor-string.onnx")); - LearningModelSession session(m_model); + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"id-tensor-string.onnx", learningModel)); + LearningModelSession session(learningModel); auto outputTensor = TensorString::Create(); @@ -164,29 +171,30 @@ TEST_F(LearningModelSessionAPITests, EvaluateFeatures) session.EvaluateFeatures(featureswinrtmap, L"0"); // verify identity model round-trip works - EXPECT_EQ(outputTensor.GetAsVectorView().Size(), data.size()); - EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(outputTensor.GetAsVectorView()))); + WINML_EXPECT_EQUAL(outputTensor.GetAsVectorView().Size(), data.size()); + WINML_EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(outputTensor.GetAsVectorView()))); } -TEST_F(LearningModelSessionAPITests, EvaluateFeaturesAsync) +static void EvaluateFeaturesAsync() { std::vector shape = { 4 }; std::vector data = { L"one", L"two", L"three", L"four" }; // create from buffer auto tensor = TensorString::CreateFromArray(shape, data); - EXPECT_EQ(tensor.GetAsVectorView().Size(), data.size()); - EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView()))); + WINML_EXPECT_EQUAL(tensor.GetAsVectorView().Size(), data.size()); + WINML_EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView()))); // create from vector view auto dataCopy = data; tensor = TensorString::CreateFromIterable( shape, winrt::single_threaded_vector(std::move(dataCopy)).GetView()); - EXPECT_EQ(tensor.GetAsVectorView().Size(), data.size()); - EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView()))); + WINML_EXPECT_EQUAL(tensor.GetAsVectorView().Size(), data.size()); + WINML_EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView()))); - EXPECT_NO_THROW(LoadModel(L"id-tensor-string.onnx")); - LearningModelSession session(m_model); + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"id-tensor-string.onnx", learningModel)); + LearningModelSession session(learningModel); auto outputTensor = TensorString::Create(shape); @@ -197,37 +205,39 @@ TEST_F(LearningModelSessionAPITests, EvaluateFeaturesAsync) session.EvaluateFeaturesAsync(featureswinrtmap, L"0").get(); // verify identity model round-trip works - EXPECT_EQ(outputTensor.GetAsVectorView().Size(), data.size()); - EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(outputTensor.GetAsVectorView()))); + WINML_EXPECT_EQUAL(outputTensor.GetAsVectorView().Size(), data.size()); + WINML_EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(outputTensor.GetAsVectorView()))); } -TEST_F(LearningModelSessionAPITests, EvaluationProperties) +static void EvaluationProperties() { // load a model - EXPECT_NO_THROW(LoadModel(L"model.onnx")); + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel)); // create a session - m_session = LearningModelSession(m_model); + LearningModelSession learningModelSession = nullptr; + learningModelSession = LearningModelSession(learningModel); // set a property auto value = winrt::Windows::Foundation::PropertyValue::CreateBoolean(true); - m_session.EvaluationProperties().Insert(L"propName1", value); + learningModelSession.EvaluationProperties().Insert(L"propName1", value); // get the property and make sure it's there with the right value - auto value2 = m_session.EvaluationProperties().Lookup(L"propName1"); - EXPECT_EQ(value2.as().GetBoolean(), true); + auto value2 = learningModelSession.EvaluationProperties().Lookup(L"propName1"); + WINML_EXPECT_EQUAL(value2.as().GetBoolean(), true); } static LearningModelSession CreateSession(LearningModel model) { LearningModelDevice device(nullptr); - EXPECT_NO_THROW(device = LearningModelDevice(LearningModelDeviceKind::DirectX)); + WINML_EXPECT_NO_THROW(device = LearningModelDevice(LearningModelDeviceKind::DirectX)); LearningModelSession session(nullptr); if (DeviceHelpers::IsFloat16Supported(device)) { - EXPECT_NO_THROW(session = LearningModelSession(model, device)); + WINML_EXPECT_NO_THROW(session = LearningModelSession(model, device)); } else { - EXPECT_THROW_SPECIFIC( + WINML_EXPECT_THROW_SPECIFIC( session = LearningModelSession(model, device), winrt::hresult_error, [](const winrt::hresult_error& e) -> bool @@ -239,26 +249,28 @@ static LearningModelSession CreateSession(LearningModel model) return session; } -TEST_F(LearningModelSessionAPITestsGpu, CreateSessionWithCastToFloat16InModel) +static void CreateSessionWithCastToFloat16InModel() { // load a model - EXPECT_NO_THROW(LoadModel(L"fp16-truncate-with-cast.onnx")); + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"fp16-truncate-with-cast.onnx", learningModel)); - CreateSession(m_model); + CreateSession(learningModel); } -TEST_F(LearningModelSessionAPITestsGpu, DISABLED_CreateSessionWithFloat16InitializersInModel) +static void DISABLED_CreateSessionWithFloat16InitializersInModel() { // Disabled due to https://microsoft.visualstudio.com/DefaultCollection/OS/_workitems/edit/21624720: // Model fails to resolve due to ORT using incorrect IR version within partition // load a model - EXPECT_NO_THROW(LoadModel(L"fp16-initializer.onnx")); + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"fp16-initializer.onnx", learningModel)); - CreateSession(m_model); + CreateSession(learningModel); } -static void EvaluateSessionAndCloseModel( +static void EvaluateSessionAndCloseModelHelper( LearningModelDeviceKind kind, bool close_model_on_session_creation) { @@ -275,7 +287,7 @@ static void EvaluateSessionAndCloseModel( // ensure you can create a session from the model LearningModelSession session(nullptr); - EXPECT_NO_THROW(session = LearningModelSession(model, device, options)); + WINML_EXPECT_NO_THROW(session = LearningModelSession(model, device, options)); std::vector input(1000); std::iota(std::begin(input), std::end(input), 0.0f); @@ -284,12 +296,12 @@ static void EvaluateSessionAndCloseModel( binding.Bind(L"input", tensor_input); LearningModelEvaluationResult result(nullptr); - EXPECT_NO_THROW(result = session.Evaluate(binding, L"")); + WINML_EXPECT_NO_THROW(result = session.Evaluate(binding, L"")); if (close_model_on_session_creation) { // ensure that the model has been closed - EXPECT_THROW_SPECIFIC( + WINML_EXPECT_THROW_SPECIFIC( LearningModelSession(model, device, options), winrt::hresult_error, [](const winrt::hresult_error& e) -> bool @@ -299,19 +311,20 @@ static void EvaluateSessionAndCloseModel( } else { - EXPECT_NO_THROW(LearningModelSession(model, device, options)); + WINML_EXPECT_NO_THROW(LearningModelSession(model, device, options)); } } -TEST_F(LearningModelSessionAPITests, EvaluateSessionAndCloseModel) +static void EvaluateSessionAndCloseModel() { - EXPECT_NO_THROW(::EvaluateSessionAndCloseModel(LearningModelDeviceKind::Cpu, true)); - EXPECT_NO_THROW(::EvaluateSessionAndCloseModel(LearningModelDeviceKind::Cpu, false)); + WINML_EXPECT_NO_THROW(::EvaluateSessionAndCloseModelHelper(LearningModelDeviceKind::Cpu, true)); + WINML_EXPECT_NO_THROW(::EvaluateSessionAndCloseModelHelper(LearningModelDeviceKind::Cpu, false)); } -TEST_F(LearningModelSessionAPITests, CloseSession) +static void CloseSession() { - EXPECT_NO_THROW(LoadModel(L"model.onnx")); + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel)); LearningModelSession session = nullptr; /* @@ -329,7 +342,7 @@ TEST_F(LearningModelSessionAPITests, CloseSession) SIZE_T afterSessionCloseWorkingSetSize = 0; bool getProcessMemoryInfoSuccess = false; */ - EXPECT_NO_THROW(session = LearningModelSession(m_model)); + WINML_EXPECT_NO_THROW(session = LearningModelSession(learningModel)); /* // Get the current process memory info after session creation. @@ -341,7 +354,7 @@ TEST_F(LearningModelSessionAPITests, CloseSession) beforeSessionCloseWorkingSetSize = pmc.WorkingSetSize; pmc = { 0 }; */ - EXPECT_NO_THROW(session.Close()); + WINML_EXPECT_NO_THROW(session.Close()); /* Bug 23659026: Working set difference tolerance is too tight for LearningModelSessionAPITests::CloseSession @@ -367,17 +380,41 @@ TEST_F(LearningModelSessionAPITests, CloseSession) */ // verify that model still has metadata info after session close - std::wstring author(m_model.Author()); - EXPECT_EQ(author, L"onnx-caffe2"); + std::wstring author(learningModel.Author()); + WINML_EXPECT_EQUAL(author, L"onnx-caffe2"); // verify that session throws RO_E_CLOSED error std::vector input(1 * 3 * 224 * 224, 0); std::vector shape = { 1, 3, 224, 224 }; auto tensor_input = TensorFloat::CreateFromShapeArrayAndDataArray(shape, input); - EXPECT_THROW_SPECIFIC(LearningModelBinding binding(session), + WINML_EXPECT_THROW_SPECIFIC(LearningModelBinding binding(session), winrt::hresult_error, [](const winrt::hresult_error &e) -> bool { return e.code() == RO_E_CLOSED; }); } + +const LearningModelSesssionAPITestApi& getapi() { + static constexpr LearningModelSesssionAPITestApi api = + { + LearningModelSessionAPITestSetup, + LearningModelSessionAPITestGpuSetup, + LearningModelSessionAPITestsSkipEdgeCoreSetup, + CreateSessionDeviceDefault, + CreateSessionDeviceCpu, + CreateSessionWithModelLoadedFromStream, + CreateSessionDeviceDirectX, + CreateSessionDeviceDirectXHighPerformance, + CreateSessionDeviceDirectXMinimumPower, + AdapterIdAndDevice, + EvaluateFeatures, + EvaluateFeaturesAsync, + EvaluationProperties, + CreateSessionWithCastToFloat16InModel, + DISABLED_CreateSessionWithFloat16InitializersInModel, + EvaluateSessionAndCloseModel, + CloseSession, + }; + return api; +} \ No newline at end of file diff --git a/winml/test/api/LearningModelSessionAPITest.h b/winml/test/api/LearningModelSessionAPITest.h new file mode 100644 index 0000000000..b98cb56f9f --- /dev/null +++ b/winml/test/api/LearningModelSessionAPITest.h @@ -0,0 +1,44 @@ +#include "test.h" + +struct LearningModelSesssionAPITestApi { + SetupTest LearningModelSessionAPITestSetup; + SetupTest LearningModelSessionAPITestGpuSetup; + SetupTest LearningModelSessionAPITestsSkipEdgeCoreSetup; + VoidTest CreateSessionDeviceDefault; + VoidTest CreateSessionDeviceCpu; + VoidTest CreateSessionWithModelLoadedFromStream; + VoidTest CreateSessionDeviceDirectX; + VoidTest CreateSessionDeviceDirectXHighPerformance; + VoidTest CreateSessionDeviceDirectXMinimumPower; + VoidTest AdapterIdAndDevice; + VoidTest EvaluateFeatures; + VoidTest EvaluateFeaturesAsync; + VoidTest EvaluationProperties; + VoidTest CreateSessionWithCastToFloat16InModel; + VoidTest DISABLED_CreateSessionWithFloat16InitializersInModel; + VoidTest EvaluateSessionAndCloseModel; + VoidTest CloseSession; +}; +const LearningModelSesssionAPITestApi& getapi(); + +WINML_TEST_CLASS_BEGIN_WITH_SETUP(LearningModelSessionAPITest, LearningModelSessionAPITestSetup) +WINML_TEST(LearningModelSessionAPITest, CreateSessionDeviceDefault) +WINML_TEST(LearningModelSessionAPITest,CreateSessionDeviceCpu) +WINML_TEST(LearningModelSessionAPITest,CreateSessionWithModelLoadedFromStream) +WINML_TEST(LearningModelSessionAPITest,EvaluateFeatures) +WINML_TEST(LearningModelSessionAPITest,EvaluateFeaturesAsync) +WINML_TEST(LearningModelSessionAPITest,EvaluationProperties) +WINML_TEST(LearningModelSessionAPITest,EvaluateSessionAndCloseModel) +WINML_TEST_CLASS_END() + +WINML_TEST_CLASS_BEGIN_WITH_SETUP(LearningModelSessionAPITestGpu, LearningModelSessionAPITestGpuSetup) +WINML_TEST(LearningModelSessionAPITestGpu, CreateSessionDeviceDirectX) +WINML_TEST(LearningModelSessionAPITestGpu, CreateSessionDeviceDirectXHighPerformance) +WINML_TEST(LearningModelSessionAPITestGpu, CreateSessionDeviceDirectXMinimumPower) +WINML_TEST(LearningModelSessionAPITestGpu, CreateSessionWithCastToFloat16InModel) +WINML_TEST(LearningModelSessionAPITestGpu, DISABLED_CreateSessionWithFloat16InitializersInModel) +WINML_TEST_CLASS_END() + +WINML_TEST_CLASS_BEGIN_WITH_SETUP(LearningModelSessionAPITestsSkipEdgeCore, LearningModelSessionAPITestsSkipEdgeCoreSetup) +WINML_TEST(LearningModelSessionAPITestsSkipEdgeCore, AdapterIdAndDevice) +WINML_TEST_CLASS_END() \ No newline at end of file diff --git a/winml/test/common/googleTestMacros.h b/winml/test/common/googleTestMacros.h index 55fb2f7f74..dc38c6402f 100644 --- a/winml/test/common/googleTestMacros.h +++ b/winml/test/common/googleTestMacros.h @@ -30,17 +30,34 @@ #define GTEST_SKIP GTEST_SKIP_("") #endif +#define EXPECT_THROW_SPECIFIC(statement, exception, condition) \ + EXPECT_THROW( \ + try { \ + statement; \ + } catch (const exception& e) { \ + EXPECT_TRUE(condition(e)); \ + throw; \ + } \ + , exception); + +#ifndef INSTANTIATE_TEST_SUITE_P +// Use the old name, removed in newer versions of googletest +#define INSTANTIATE_TEST_SUITE_P INSTANTIATE_TEST_CASE_P +#endif + #define WINML_SKIP_TEST(message) \ GTEST_SKIP() << message; #define WINML_EXPECT_NO_THROW(statement) EXPECT_NO_THROW(statement) #define WINML_EXPECT_TRUE(statement) EXPECT_TRUE(statement) +#define WINML_EXPECT_FALSE(statement) EXPECT_FALSE(statement) #define WINML_EXPECT_EQUAL(val1, val2) EXPECT_EQ(val1, val2) #define WINML_EXPECT_NOT_EQUAL(val1, val2) EXPECT_NE(val1, val2) #define WINML_LOG_ERROR(message) \ ADD_FAILURE() << message - +#define WINML_LOG_COMMENT(message)\ + SCOPED_TRACE(message) #define WINML_EXPECT_HRESULT_SUCCEEDED(hresult_expression) EXPECT_HRESULT_SUCCEEDED(hresult_expression) #define WINML_EXPECT_HRESULT_FAILED(hresult_expression) EXPECT_HRESULT_FAILED(hresult_expression) #define WINML_EXPECT_THROW_SPECIFIC(statement, exception, condition) EXPECT_THROW_SPECIFIC(statement, exception, condition) diff --git a/winml/test/common/std.h b/winml/test/common/std.h index 162915abd0..d6eab75f64 100644 --- a/winml/test/common/std.h +++ b/winml/test/common/std.h @@ -29,19 +29,4 @@ #include "comp_generated/winrt/windows.ai.machinelearning.h" // WinML -#include "Windows.AI.MachineLearning.Native.h" - -#define EXPECT_THROW_SPECIFIC(statement, exception, condition) \ - EXPECT_THROW( \ - try { \ - statement; \ - } catch (const exception& e) { \ - EXPECT_TRUE(condition(e)); \ - throw; \ - } \ - , exception); - -#ifndef INSTANTIATE_TEST_SUITE_P -// Use the old name, removed in newer versions of googletest -#define INSTANTIATE_TEST_SUITE_P INSTANTIATE_TEST_CASE_P -#endif \ No newline at end of file +#include "Windows.AI.MachineLearning.Native.h" \ No newline at end of file diff --git a/winml/test/common/taefTestMacros.h b/winml/test/common/taefTestMacros.h index 7c7636b7a4..06d9048d7c 100644 --- a/winml/test/common/taefTestMacros.h +++ b/winml/test/common/taefTestMacros.h @@ -30,11 +30,13 @@ using namespace WEX::TestExecution; #define WINML_EXPECT_NO_THROW(statement) VERIFY_NO_THROW(statement) #define WINML_EXPECT_TRUE(statement) VERIFY_IS_TRUE(statement) +#define WINML_EXPECT_FALSE(statement) VERIFY_IS_FALSE(statement) #define WINML_EXPECT_EQUAL(val1, val2) VERIFY_ARE_EQUAL(val1, val2) #define WINML_EXPECT_NOT_EQUAL(val1, val2) VERIFY_ARE_NOT_EQUAL(val1, val2) #define WINML_LOG_ERROR(message) \ VERIFY_FAIL(std::wstring_convert>().from_bytes(message).c_str()) - +#define WINML_LOG_COMMENT(message)\ + WEX::Logging::Log::Comment(std::wstring_convert>().from_bytes(message).c_str()) #define WINML_EXPECT_HRESULT_SUCCEEDED(hresult_expression) VERIFY_SUCCEEDED(hresult_expression) #define WINML_EXPECT_THROW_SPECIFIC(statement, exception, condition) VERIFY_THROWS_SPECIFIC(statement, exception, condition) #define WINML_EXPECT_HRESULT_FAILED(hresult_expression) VERIFY_FAILED(hresult_expression) From 39c9f98a5d85ebe6458fc2b01e75f1dfbb95e3ec Mon Sep 17 00:00:00 2001 From: Ryan Lai Date: Wed, 15 Jan 2020 12:45:34 -0800 Subject: [PATCH 4/5] Fix test build break since winml_lib_api needs to be statically linked to tests since winmlp::learningmodeldevice::iscpu() is being used in devicehelpers.cpp (#2837) --- cmake/winml_unittests.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/winml_unittests.cmake b/cmake/winml_unittests.cmake index 4bdbb34432..bd91611a6d 100644 --- a/cmake/winml_unittests.cmake +++ b/cmake/winml_unittests.cmake @@ -44,7 +44,7 @@ function(add_winml_test) if (_UT_DEPENDS) add_dependencies(${_UT_TARGET} ${_UT_DEPENDS}) endif() - target_link_libraries(${_UT_TARGET} PRIVATE ${_UT_LIBS} gtest windowsapp winml_lib_image ${onnxruntime_EXTERNAL_LIBRARIES} winml_lib_telemetry) + target_link_libraries(${_UT_TARGET} PRIVATE ${_UT_LIBS} gtest windowsapp winml_lib_image ${onnxruntime_EXTERNAL_LIBRARIES} winml_lib_telemetry winml_lib_api onnxruntime) add_test(NAME ${_UT_TARGET} COMMAND ${_UT_TARGET} From 408e600bf3c8ce5ce3754f5afa7d8aeaeee14429 Mon Sep 17 00:00:00 2001 From: Tiago Koji Castro Shibata Date: Wed, 15 Jan 2020 15:35:55 -0800 Subject: [PATCH 5/5] Enforce WINML_TEST_CLASS_BEGIN_* matches w/ a WINML_TEST_CLASS_END (#2841) --- winml/test/common/googleTestMacros.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/winml/test/common/googleTestMacros.h b/winml/test/common/googleTestMacros.h index dc38c6402f..f0507435b9 100644 --- a/winml/test/common/googleTestMacros.h +++ b/winml/test/common/googleTestMacros.h @@ -10,18 +10,20 @@ } #define WINML_TEST_CLASS_BEGIN_NO_SETUP(test_class_name) \ - class test_class_name : public ::testing::Test { \ - }; + namespace { \ + class test_class_name : public ::testing::Test { \ + }; #define WINML_TEST_CLASS_BEGIN_WITH_SETUP(test_class_name, setup_method) \ - class test_class_name : public ::testing::Test { \ - protected: \ - void SetUp() override { \ - getapi().setup_method(); \ - } \ - }; + namespace { \ + class test_class_name : public ::testing::Test { \ + protected: \ + void SetUp() override { \ + getapi().setup_method(); \ + } \ + }; -#define WINML_TEST_CLASS_END() +#define WINML_TEST_CLASS_END() } // For old versions of gtest without GTEST_SKIP, stream the message and return success instead #ifndef GTEST_SKIP @@ -77,4 +79,4 @@ if (auto isEdgeCore = RuntimeParameters::Parameters.find("EdgeCore"); \ isEdgeCore != RuntimeParameters::Parameters.end() && isEdgeCore->second != "0") { \ WINML_SKIP_TEST("Test can't be run in EdgeCore"); \ - } \ No newline at end of file + }