jstzwjr commited on
Commit
17f9599
·
1 Parent(s): 6c5da37
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. SampleApp/CMakeLists.txt +11 -0
  2. SampleApp/Makefile +146 -0
  3. SampleApp/README.txt +2 -0
  4. SampleApp/make/Android.mk +44 -0
  5. SampleApp/make/Application.mk +13 -0
  6. SampleApp/make/Makefile.hexagon +145 -0
  7. SampleApp/make/Makefile.linux-x86_64 +116 -0
  8. SampleApp/make/Makefile.oe-linux-aarch64-gcc11.2 +114 -0
  9. SampleApp/make/Makefile.oe-linux-aarch64-gcc8.2 +114 -0
  10. SampleApp/make/Makefile.oe-linux-aarch64-gcc9.3 +114 -0
  11. SampleApp/make/Makefile.ubuntu-aarch64-gcc7.5 +114 -0
  12. SampleApp/make/Makefile.ubuntu-aarch64-gcc9.4 +114 -0
  13. SampleApp/src/CMakeLists.txt +40 -0
  14. SampleApp/src/DspLog/LogUtils.cpp +22 -0
  15. SampleApp/src/Log/LogUtils.cpp +45 -0
  16. SampleApp/src/Log/LogUtils.hpp +29 -0
  17. SampleApp/src/Log/Logger.cpp +105 -0
  18. SampleApp/src/Log/Logger.hpp +107 -0
  19. SampleApp/src/PAL/include/PAL/Debug.hpp +21 -0
  20. SampleApp/src/PAL/include/PAL/Directory.hpp +80 -0
  21. SampleApp/src/PAL/include/PAL/DynamicLoading.hpp +99 -0
  22. SampleApp/src/PAL/include/PAL/FileOp.hpp +239 -0
  23. SampleApp/src/PAL/include/PAL/GetOpt.hpp +93 -0
  24. SampleApp/src/PAL/include/PAL/Path.hpp +50 -0
  25. SampleApp/src/PAL/include/PAL/StringOp.hpp +60 -0
  26. SampleApp/src/PAL/src/common/GetOpt.cpp +154 -0
  27. SampleApp/src/PAL/src/common/StringOp.cpp +63 -0
  28. SampleApp/src/PAL/src/linux/Directory.cpp +153 -0
  29. SampleApp/src/PAL/src/linux/DynamicLoading.cpp +75 -0
  30. SampleApp/src/PAL/src/linux/FileOp.cpp +356 -0
  31. SampleApp/src/PAL/src/linux/Path.cpp +48 -0
  32. SampleApp/src/PAL/src/windows/Common.cpp +46 -0
  33. SampleApp/src/PAL/src/windows/Common.hpp +37 -0
  34. SampleApp/src/PAL/src/windows/Directory.cpp +105 -0
  35. SampleApp/src/PAL/src/windows/DynamicLoading.cpp +220 -0
  36. SampleApp/src/PAL/src/windows/FileOp.cpp +297 -0
  37. SampleApp/src/PAL/src/windows/Path.cpp +72 -0
  38. SampleApp/src/QnnSampleApp.cpp +668 -0
  39. SampleApp/src/QnnSampleApp.hpp +128 -0
  40. SampleApp/src/QnnTypeMacros.hpp +668 -0
  41. SampleApp/src/SampleApp.hpp +43 -0
  42. SampleApp/src/Utils/BuildId.hpp +17 -0
  43. SampleApp/src/Utils/DataUtil.cpp +408 -0
  44. SampleApp/src/Utils/DataUtil.hpp +127 -0
  45. SampleApp/src/Utils/DynamicLoadUtil.cpp +179 -0
  46. SampleApp/src/Utils/DynamicLoadUtil.hpp +36 -0
  47. SampleApp/src/Utils/IOTensor.cpp +838 -0
  48. SampleApp/src/Utils/IOTensor.hpp +115 -0
  49. SampleApp/src/Utils/QnnSampleAppUtils.cpp +394 -0
  50. SampleApp/src/Utils/QnnSampleAppUtils.hpp +79 -0
SampleApp/CMakeLists.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #=============================================================================
2
+ #
3
+ # Copyright (c) 2022 Qualcomm Technologies, Inc.
4
+ # All Rights Reserved.
5
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ #
7
+ #=============================================================================
8
+
9
+ cmake_minimum_required (VERSION 3.14)
10
+ project(SampleApp)
11
+ add_subdirectory(src)
SampleApp/Makefile ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Copyright (c) 2020-2024 Qualcomm Technologies, Inc.
3
+ # All Rights Reserved.
4
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
5
+ #
6
+
7
+ # define default
8
+ default: all
9
+
10
+ # define package name
11
+ PACKAGE_NAME := $(notdir $(shell pwd))
12
+
13
+ # define library prerequisites list
14
+ sample_app := src
15
+ make_dir := make
16
+ EXE_SOURCES = $(sample_app)
17
+
18
+ # define target_architecture
19
+ export TARGET_AARCH_VARS:= -march=x86-64
20
+
21
+ # define target name
22
+ export TARGET = linux-x86_64
23
+
24
+ # specify compiler
25
+ export CXX := clang++
26
+
27
+ .PHONY: all $(EXE_SOURCES) all_x86 all_android hexagon
28
+
29
+ all: $(EXE_SOURCES) all_x86 all_android all_linux_oe_aarch64_gcc82 all_linux_oe_aarch64_gcc93 all_linux_oe_aarch64_gcc112 all_ubuntu_aarch64_gcc75 all_ubuntu_aarch64_gcc94
30
+
31
+ # Combined Targets
32
+ clean: clean_x86 clean_android clean_qnx
33
+
34
+ all_x86: clean_x86
35
+ $(call build_if_exists,$(sample_app),-$(MAKE) -f $(make_dir)/Makefile.linux-x86_64)
36
+
37
+ clean_x86:
38
+ @rm -rf bin obj include
39
+
40
+ # Android Targets
41
+
42
+ all_android: aarch64-android
43
+
44
+ aarch64-android: check_ndk clean_aarch64-android
45
+ $(call build_if_exists,$(sample_app),$(ANDROID_NDK_ROOT)/ndk-build APP_ALLOW_MISSING_DEPS=true APP_ABI="arm64-v8a" NDK_PROJECT_PATH=./ NDK_APPLICATION_MK=$(make_dir)/Application.mk APP_BUILD_SCRIPT=$(make_dir)/Android.mk)
46
+ @$(rename_target_dirs)
47
+
48
+ clean_android: check_ndk clean_aarch64-android
49
+
50
+ clean_aarch64-android:
51
+ @rm -rf bin/aarch64-android
52
+ @rm -rf obj/local/aarch64-android
53
+
54
+ # QNX Target
55
+
56
+ all_qnx: check_qnx
57
+ $(call build_if_exists,$(sample_app),-$(MAKE) -f $(make_dir)/Makefile.qnx-aarch64)
58
+
59
+ clean_qnx:
60
+ @rm -rf bin obj include
61
+
62
+ all_linux_oe_aarch64_gcc112: check_linux_oe_aarch64_gcc112
63
+ $(call build_if_exists,$(sample_app),-$(MAKE) -f $(make_dir)/Makefile.oe-linux-aarch64-gcc11.2)
64
+
65
+ clean_linux_oe_aarch64_gcc112:
66
+ @rm -rf bin/aarch64-oe-linux-gcc11.2 obj/aarch64-oe-linux-gcc11.2
67
+
68
+ check_linux_oe_aarch64_gcc112:
69
+ ifeq ($(QNN_AARCH64_LINUX_OE_GCC_112),)
70
+ $(error ERROR: QNN_AARCH64_LINUX_OE_GCC_112 not set, skipping compilation for Linux OE platform.)
71
+ endif
72
+
73
+
74
+ all_linux_oe_aarch64_gcc93: check_linux_oe_aarch64_gcc93
75
+ $(call build_if_exists,$(sample_app),-$(MAKE) -f $(make_dir)/Makefile.oe-linux-aarch64-gcc9.3)
76
+
77
+ clean_linux_oe_aarch64_gcc93:
78
+ @rm -rf bin/aarch64-oe-linux-gcc9.3 obj/aarch64-oe-linux-gcc9.3
79
+
80
+ check_linux_oe_aarch64_gcc93:
81
+ ifeq ($(QNN_AARCH64_LINUX_OE_GCC_93),)
82
+ $(error ERROR: QNN_AARCH64_LINUX_OE_GCC_93 not set, skipping compilation for Linux OE platform.)
83
+ endif
84
+
85
+
86
+ all_linux_oe_aarch64_gcc82: check_linux_oe_aarch64_gcc82
87
+ $(call build_if_exists,$(sample_app),-$(MAKE) -f $(make_dir)/Makefile.oe-linux-aarch64-gcc8.2)
88
+
89
+ clean_linux_oe_aarch64_gcc82:
90
+ @rm -rf bin/aarch64-oe-linux-gcc8.2 obj/aarch64-oe-linux-gcc8.2
91
+
92
+ check_linux_oe_aarch64_gcc82:
93
+ ifeq ($(QNN_AARCH64_LINUX_OE_GCC_82),)
94
+ $(error ERROR: QNN_AARCH64_LINUX_OE_GCC_82 not set, skipping compilation for Linux OE platform.)
95
+ endif
96
+
97
+
98
+ all_ubuntu_aarch64_gcc75: check_ubuntu_aarch64_gcc75
99
+ $(call build_if_exists,$(sample_app),-$(MAKE) -f $(make_dir)/Makefile.ubuntu-aarch64-gcc7.5)
100
+
101
+ clean_ubuntu_aarch64_gcc75:
102
+ @rm -rf bin/aarch64-ubuntu-gcc7.5 obj/aarch64-ubuntu-gcc7.5
103
+
104
+ check_ubuntu_aarch64_gcc75:
105
+ ifeq ($(QNN_AARCH64_UBUNTU_GCC_75),)
106
+ $(error ERROR: QNN_AARCH64_UBUNTU_GCC_75 not set, skipping compilation for Ubuntu platform.)
107
+ endif
108
+
109
+ all_ubuntu_aarch64_gcc94: check_ubuntu_aarch64_gcc94
110
+ $(call build_if_exists,$(sample_app),-$(MAKE) -f $(make_dir)/Makefile.ubuntu-aarch64-gcc9.4)
111
+
112
+ clean_ubuntu_aarch64_gcc94:
113
+ @rm -rf bin/aarch64-ubuntu-gcc9.4 obj/aarch64-ubuntu-gcc9.4
114
+
115
+ check_ubuntu_aarch64_gcc94:
116
+ ifeq ($(QNN_AARCH64_UBUNTU_GCC_94),)
117
+ $(error ERROR: QNN_AARCH64_UBUNTU_GCC_94 not set, skipping compilation for Ubuntu platform.)
118
+ endif
119
+
120
+
121
+ # utilities
122
+ # Syntax: $(call build_if_exists <dir>,<cmd>)
123
+ build_if_exists = $(if $(wildcard $(1)),$(2),$(warning WARNING: $(1) does not exist. Skipping Compilation))
124
+ rename_target_dirs = find . -type d -execdir rename 's/arm64-v8a/aarch64-android/' '{}' \+ \
125
+ && mv libs/* bin/ \
126
+ && rm -rf libs \
127
+
128
+ check_ndk:
129
+ ifeq ($(ANDROID_NDK_ROOT),)
130
+ $(error ERROR: ANDROID_NDK_ROOT not set, skipping compilation for Android platform(s).)
131
+ endif
132
+
133
+ check_qnx:
134
+ ifeq ($(QNX_HOST),)
135
+ $(error ERROR: QNX_HOST not set, skipping compilation for QNX platform.)
136
+ endif
137
+ ifeq ($(QNX_TARGET),)
138
+ $(error ERROR: QNX_TARGET not set, skipping compilation for QNX platform.)
139
+ endif
140
+
141
+ # Hexagon Target
142
+ hexagon: clean_hexagon
143
+ $(call build_if_exists,$(sample_app),-$(MAKE) -f $(make_dir)/Makefile.hexagon)
144
+
145
+ clean_hexagon:
146
+ @rm -rf bin/hexagon obj/hexagon
SampleApp/README.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ For information on how to build and execute qnn-sample-app,
2
+ please point your web browser to ${QNN_SDK_ROOT}/docs/QNN/general/sample_app.html.
SampleApp/make/Android.mk ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ==============================================================================
2
+ #
3
+ # Copyright (c) 2020, 2022-2024 Qualcomm Technologies, Inc.
4
+ # All Rights Reserved.
5
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ #
7
+ # ===============================================================
8
+
9
+ LOCAL_PATH := $(call my-dir)
10
+ SUPPORTED_TARGET_ABI := arm64-v8a x86 x86_64
11
+
12
+ #============================ Verify Target Info and Application Variables =========================================
13
+ ifneq ($(filter $(TARGET_ARCH_ABI),$(SUPPORTED_TARGET_ABI)),)
14
+ ifneq ($(APP_STL), c++_static)
15
+ $(error Unsupported APP_STL: "$(APP_STL)")
16
+ endif
17
+ else
18
+ $(error Unsupported TARGET_ARCH_ABI: '$(TARGET_ARCH_ABI)')
19
+ endif
20
+
21
+ #============================ Define Common Variables ===============================================================
22
+ # Include paths
23
+ PACKAGE_C_INCLUDES += -I $(LOCAL_PATH)/../../../../include/QNN
24
+ PACKAGE_C_INCLUDES += -I $(LOCAL_PATH)/../src/
25
+ PACKAGE_C_INCLUDES += -I $(LOCAL_PATH)/../src/CachingUtil
26
+ PACKAGE_C_INCLUDES += -I $(LOCAL_PATH)/../src/Log
27
+ PACKAGE_C_INCLUDES += -I $(LOCAL_PATH)/../src/PAL/include
28
+ PACKAGE_C_INCLUDES += -I $(LOCAL_PATH)/../src/Utils
29
+ PACKAGE_C_INCLUDES += -I $(LOCAL_PATH)/../src/WrapperUtils
30
+ PACKAGE_C_INCLUDES += -I $(LOCAL_PATH)/../include/flatbuffers
31
+
32
+ #========================== Define OpPackage Library Build Variables =============================================
33
+ include $(CLEAR_VARS)
34
+ LOCAL_C_INCLUDES := $(PACKAGE_C_INCLUDES)
35
+ MY_SRC_FILES := $(wildcard $(LOCAL_PATH)/../src/*.cpp)
36
+ MY_SRC_FILES += $(wildcard $(LOCAL_PATH)/../src/Log/*.cpp)
37
+ MY_SRC_FILES += $(wildcard $(LOCAL_PATH)/../src/PAL/src/linux/*.cpp)
38
+ MY_SRC_FILES += $(wildcard $(LOCAL_PATH)/../src/PAL/src/common/*.cpp)
39
+ MY_SRC_FILES += $(wildcard $(LOCAL_PATH)/../src/Utils/*.cpp)
40
+ MY_SRC_FILES += $(wildcard $(LOCAL_PATH)/../src/WrapperUtils/*.cpp)
41
+ LOCAL_MODULE := qnn-sample-app
42
+ LOCAL_SRC_FILES := $(subst make/,,$(MY_SRC_FILES))
43
+ LOCAL_LDLIBS := -lGLESv2 -lEGL
44
+ include $(BUILD_EXECUTABLE)
SampleApp/make/Application.mk ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ==============================================================================
2
+ #
3
+ # Copyright (c) 2020, 2022-2024 Qualcomm Technologies, Inc.
4
+ # All Rights Reserved.
5
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ #
7
+ # ===============================================================
8
+
9
+ APP_ABI := arm64-v8a
10
+ APP_STL := c++_static
11
+ APP_PLATFORM := android-21
12
+ APP_CPPFLAGS += -std=c++11 -O3 -Wall -Werror -fvisibility=hidden -DQNN_API="__attribute__((visibility(\"default\")))"
13
+ APP_LDFLAGS += -lc -lm -ldl
SampleApp/make/Makefile.hexagon ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Copyright (c) 2024 Qualcomm Technologies, Inc.
3
+ # All Rights Reserved.
4
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
5
+ #
6
+
7
+ # define relevant directories
8
+
9
+ ifndef HEXAGON_SDK_ROOT
10
+ $(error "Hexagon SDK environment not set")
11
+ endif
12
+
13
+ ifndef HEXAGON_TOOLS_ROOT
14
+ HEXAGON_TOOLS_ROOT = $(DEFAULT_HEXAGON_TOOLS_ROOT)
15
+ endif
16
+
17
+ ifndef V
18
+ V=v69
19
+ endif
20
+
21
+ SRC_DIR := src
22
+ SRC_DIR_LOG := src/Log
23
+ SRC_DIR_DSP_LOG := src/DspLog
24
+ SRC_DIR_PAL_LINUX := src/PAL/src/linux
25
+ SRC_DIR_PAL_COMMON := src/PAL/src/common
26
+ SRC_DIR_UTILS := src/Utils
27
+ SRC_DIR_WRAPPER_UTILS := src/WrapperUtils
28
+ QNN_API_INCLUDE := ../../../include/QNN
29
+ PAL_INCLUDE := src/PAL/include
30
+ QURT_INCLUDE := $(HEXAGON_SDK_ROOT)/rtos/qurt/compute$(V)/include/qurt/
31
+ POSIX_INCLUDE := $(HEXAGON_SDK_ROOT)/rtos/qurt/compute$(V)/include/posix/
32
+ HEXAGON_INCLUDES := $(HEXAGON_SDK_ROOT)/incs
33
+ HEXAGON_STDEF_INCLUDES := $(HEXAGON_SDK_ROOT)/incs/stddef
34
+
35
+ QNN_TARGET ?= hexagon
36
+ export TARGET_DIR := ./bin/$(QNN_TARGET)
37
+
38
+ CXX = $(HEXAGON_TOOLS_ROOT)/Tools/bin/hexagon-clang++
39
+
40
+ shared_library := $(TARGET_DIR)/libQnnSampleApp$(V).so
41
+ sample_app_libs := libfile.a
42
+
43
+ .PHONY: sample_app_all
44
+ .DEFAULT: sample_app_all
45
+ sample_app_all: shared_library
46
+
47
+ # Include paths
48
+ INCLUDES += -I$(SRC_DIR) -I$(SRC_DIR_LOG) -I$(SRC_DIR_UTILS) -I$(SRC_DIR_WRAPPER_UTILS) -I$(PAL_INCLUDE) -I$(QNN_API_INCLUDE) -I$(QURT_INCLUDE) -I$(POSIX_INCLUDE) -I$(HEXAGON_INCLUDES) -I$(HEXAGON_STDEF_INCLUDES)
49
+
50
+ # set compiler flags
51
+ # pthread is needed for AIC and HTP-MCP Backend
52
+ COMMON_CXXFLAGS = -fPIC -Wall -Werror -fno-exceptions $(INCLUDES)
53
+ COMMON_LDFLAGS = -shared -s -fPIC
54
+
55
+ ifdef QNN_DEBUG_ENABLE
56
+ CXXFLAGS += $(COMMON_CXXFLAGS) -O0 -g -DQNN_API=""
57
+ LDFLAGS += $(COMMON_LDFLAGS)
58
+ else
59
+ CXXFLAGS += $(COMMON_CXXFLAGS) -O3 -g
60
+ LDFLAGS += $(COMMON_LDFLAGS) -G0 -Wl
61
+ endif
62
+
63
+ # define library sources
64
+ SOURCES := $(wildcard $(SRC_DIR)/*.cpp)
65
+ SOURCES_LOG := src/Log/Logger.cpp
66
+ SOURCES_DSP_LOG := src/DspLog/LogUtils.cpp
67
+ SOURCES_PAL := src/PAL/src/linux/DynamicLoading.cpp
68
+ SOURCES_PAL += $(wildcard $(SRC_DIR_PAL_COMMON)/*.cpp)
69
+ SOURCES_UTILS := $(wildcard $(SRC_DIR_UTILS)/*.cpp)
70
+ SOURCES_WRAPPER_UTILS := $(wildcard $(SRC_DIR_WRAPPER_UTILS)/*.cpp)
71
+
72
+ # define object directory
73
+ OBJ_ROOT := obj
74
+ OBJ_DIR := obj/$(QNN_TARGET)
75
+ OBJ_DIR_LOG := obj/$(QNN_TARGET)/Log/
76
+ OBJ_DIR_DSP_LOG := obj/$(QNN_TARGET)/DspLog/
77
+ OBJ_DIR_PAL := obj/$(QNN_TARGET)/PAL
78
+ OBJ_DIR_UTILS := obj/$(QNN_TARGET)/Utils/
79
+ OBJ_DIR_WRAPPER_UTILS := obj/$(QNN_TARGET)/WrapperUtils/
80
+
81
+ # setup object files in object directory
82
+ OBJECTS := $(patsubst %.cpp,$(OBJ_DIR)/%.o,$(foreach x,$(SOURCES),$(notdir $(x))))
83
+ OBJECTS_LOG := $(patsubst %.cpp,$(OBJ_DIR_LOG)/%.o,$(foreach x,$(SOURCES_LOG),$(notdir $(x))))
84
+ OBJECTS_DSP_LOG := $(patsubst %.cpp,$(OBJ_DIR_DSP_LOG)/%.o,$(foreach x,$(SOURCES_DSP_LOG),$(notdir $(x))))
85
+ OBJECTS_PAL := $(patsubst %.cpp,$(OBJ_DIR_PAL)/%.o,$(foreach x,$(SOURCES_PAL),$(notdir $(x))))
86
+ OBJECTS_UTILS := $(patsubst %.cpp,$(OBJ_DIR_UTILS)/%.o,$(foreach x,$(SOURCES_UTILS),$(notdir $(x))))
87
+ OBJECTS_WRAPPER_UTILS := $(patsubst %.cpp,$(OBJ_DIR_WRAPPER_UTILS)/%.o,$(foreach x,$(SOURCES_WRAPPER_UTILS),$(notdir $(x))))
88
+
89
+ # Rule to make executable
90
+ .PHONY: shared_library
91
+ shared_library: $(sample_app_libs) $(shared_library)
92
+
93
+ # Implicit rule to compile and link object files
94
+ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
95
+ $(CXX) $(CXXFLAGS) $(INCLUDES) -c $^ -o $@
96
+
97
+ $(OBJ_DIR_LOG)/%.o: $(SRC_DIR_LOG)/%.cpp
98
+ $(CXX) $(CXXFLAGS) $(INCLUDES) -c $^ -o $@
99
+
100
+ $(OBJ_DIR_DSP_LOG)/%.o: $(SRC_DIR_DSP_LOG)/%.cpp
101
+ $(CXX) $(CXXFLAGS) $(INCLUDES) -c $^ -o $@
102
+
103
+ $(OBJ_DIR_PAL)/%.o: $(SRC_DIR_PAL_LINUX)/%.cpp
104
+ $(CXX) $(CXXFLAGS) $(INCLUDES) -c $^ -o $@
105
+
106
+ $(OBJ_DIR_PAL)/%.o: $(SRC_DIR_PAL_COMMON)/%.cpp
107
+ $(CXX) $(CXXFLAGS) $(INCLUDES) -c $^ -o $@
108
+
109
+ $(OBJ_DIR_UTILS)/%.o: $(SRC_DIR_UTILS)/%.cpp
110
+ $(CXX) $(CXXFLAGS) $(INCLUDES) -c $^ -o $@
111
+
112
+ $(OBJ_DIR_WRAPPER_UTILS)/%.o: $(SRC_DIR_WRAPPER_UTILS)/%.cpp
113
+ $(CXX) $(CXXFLAGS) $(INCLUDES) -c $^ -o $@
114
+
115
+ # set up resources
116
+ directories := $(TARGET_DIR) $(OBJ_DIR) $(OBJ_DIR_LOG) $(OBJ_DIR_DSP_LOG) $(OBJ_DIR_PAL) $(OBJ_DIR_UTILS) $(OBJ_DIR_WRAPPER_UTILS)
117
+
118
+ $(sample_app_libs): obj/hexagon/QnnSampleApp.o $(OBJECTS_LOG) $(OBJECTS_DSP_LOG) $(OBJECTS_PAL) $(OBJECTS_UTILS) $(OBJECTS_WRAPPER_UTILS) | $(directories)
119
+ ar rcs $@ $^
120
+ mv $@ $(TARGET_DIR)
121
+
122
+ #Compile
123
+ $(shared_library): obj/hexagon/main.o
124
+ cp $(HEXAGON_TOOLS_ROOT)/Tools/target/hexagon/lib/$(V)/G0/pic/libc++.so.1 .
125
+ cp $(HEXAGON_TOOLS_ROOT)/Tools/target/hexagon/lib/$(V)/G0/pic/libc++.so.1.0 .
126
+ cp $(HEXAGON_TOOLS_ROOT)/Tools/target/hexagon/lib/$(V)/G0/pic/libc++abi.so.1 .
127
+ cp $(HEXAGON_TOOLS_ROOT)/Tools/target/hexagon/lib/$(V)/G0/pic/libc++abi.so.1.0 .
128
+ $(CXX) $(LDFLAGS) $(INCLUDES) -o $@ $< $(TARGET_DIR)/$(sample_app_libs)
129
+ rm $(TARGET_DIR)/$(sample_app_libs)
130
+
131
+ # rule for object directory resource
132
+ $(OBJECTS): | $(OBJ_DIR)
133
+ $(OBJECTS_LOG): | $(OBJ_DIR_LOG)
134
+ $(OBJECTS_DSP_LOG): | $(OBJ_DIR_DSP_LOG)
135
+ $(OBJECTS_PAL): | $(OBJ_DIR_PAL)
136
+ $(OBJECTS_UTILS): | $(OBJ_DIR_UTILS)
137
+ $(OBJECTS_WRAPPER_UTILS): | $(OBJ_DIR_WRAPPER_UTILS)
138
+
139
+ # rule to create directories
140
+ $(directories):
141
+ mkdir -p $@
142
+
143
+ .PHONY: clean
144
+ clean:
145
+ rm -rf $(OBJ_ROOT) $(TARGET_DIR)
SampleApp/make/Makefile.linux-x86_64 ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Copyright (c) 2020, 2022-2024 Qualcomm Technologies, Inc.
3
+ # All Rights Reserved.
4
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
5
+ #
6
+
7
+ # define relevant directories
8
+ SRC_DIR := src
9
+ SRC_DIR_LOG := src/Log
10
+ SRC_DIR_PAL_LINUX := src/PAL/src/linux
11
+ SRC_DIR_PAL_COMMON := src/PAL/src/common
12
+ SRC_DIR_UTILS := src/Utils
13
+ SRC_DIR_WRAPPER_UTILS := src/WrapperUtils
14
+ QNN_API_INCLUDE := ../../../include/QNN
15
+ PAL_INCLUDE := src/PAL/include
16
+
17
+ QNN_TARGET ?= x86_64-linux-clang
18
+ export TARGET_DIR := ./bin/$(QNN_TARGET)
19
+
20
+ qnn-sample-app := $(TARGET_DIR)/qnn-sample-app
21
+
22
+ # define target architecture if not previously defined, default is x86
23
+ ifndef TARGET_AARCH_VARS
24
+ TARGET_AARCH_VARS:= -march=x86-64
25
+ endif
26
+
27
+ .PHONY: sample_app_all
28
+ .DEFAULT: sample_app_all
29
+ sample_app_all: $(qnn-sample-app)
30
+
31
+ # Include paths
32
+ INCLUDES += -I$(SRC_DIR) -I$(SRC_DIR_LOG) -I$(SRC_DIR_UTILS) -I$(SRC_DIR_WRAPPER_UTILS) -I$(PAL_INCLUDE) -I$(QNN_API_INCLUDE)
33
+
34
+ # set compiler flags
35
+ # pthread is needed for AIC and HTP-MCP Backend
36
+ COMMON_CXXFLAGS = -std=c++11 -fno-exceptions -fno-rtti -fPIC -Wall -Werror -pg -pthread $(INCLUDES)
37
+ COMMON_LDFLAGS = -shared -s -fPIC -pthread
38
+
39
+ ifdef QNN_DEBUG_ENABLE
40
+ CXXFLAGS += $(COMMON_CXXFLAGS) -march=x86-64 -O0 -g -DQNN_API=""
41
+ LDFLAGS += $(COMMON_LDFLAGS)
42
+ else
43
+ CXXFLAGS += $(COMMON_CXXFLAGS) -march=x86-64 -O3 -Wno-write-strings -fvisibility=hidden -DQNN_API="__attribute__((visibility(\"default\")))"
44
+ LDFLAGS += $(COMMON_LDFLAGS) -fvisibility=hidden -flto
45
+ endif
46
+
47
+ # define library sources
48
+ SOURCES := $(wildcard $(SRC_DIR)/*.cpp)
49
+ SOURCES_LOG := $(wildcard $(SRC_DIR_LOG)/*.cpp)
50
+ SOURCES_PAL := $(wildcard $(SRC_DIR_PAL_LINUX)/*.cpp)
51
+ SOURCES_PAL += $(wildcard $(SRC_DIR_PAL_COMMON)/*.cpp)
52
+ SOURCES_UTILS := $(wildcard $(SRC_DIR_UTILS)/*.cpp)
53
+ SOURCES_WRAPPER_UTILS := $(wildcard $(SRC_DIR_WRAPPER_UTILS)/*.cpp)
54
+
55
+ # define object directory
56
+ OBJ_ROOT := obj
57
+ OBJ_DIR := obj/$(QNN_TARGET)
58
+ OBJ_DIR_LOG := obj/$(QNN_TARGET)/Log/
59
+ OBJ_DIR_PAL := obj/$(QNN_TARGET)/PAL
60
+ OBJ_DIR_UTILS := obj/$(QNN_TARGET)/Utils/
61
+ OBJ_DIR_WRAPPER_UTILS := obj/$(QNN_TARGET)/WrapperUtils/
62
+
63
+ # setup object files in object directory
64
+ OBJECTS := $(patsubst %.cpp,$(OBJ_DIR)/%.o,$(foreach x,$(SOURCES),$(notdir $(x))))
65
+ OBJECTS_LOG := $(patsubst %.cpp,$(OBJ_DIR_LOG)/%.o,$(foreach x,$(SOURCES_LOG),$(notdir $(x))))
66
+ OBJECTS_PAL := $(patsubst %.cpp,$(OBJ_DIR_PAL)/%.o,$(foreach x,$(SOURCES_PAL),$(notdir $(x))))
67
+ OBJECTS_UTILS := $(patsubst %.cpp,$(OBJ_DIR_UTILS)/%.o,$(foreach x,$(SOURCES_UTILS),$(notdir $(x))))
68
+ OBJECTS_WRAPPER_UTILS := $(patsubst %.cpp,$(OBJ_DIR_WRAPPER_UTILS)/%.o,$(foreach x,$(SOURCES_WRAPPER_UTILS),$(notdir $(x))))
69
+
70
+ #LIBS=-l/usr/lib/x86_64-linux-gnu/libflatbuffers.a
71
+ LIBS=-ldl
72
+
73
+ # Rule to make executable
74
+ .PHONY: qnn-sample-app
75
+ qnn-sample-app: $(qnn-sample-app)
76
+
77
+ # Implicit rule to compile and link object files
78
+ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
79
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
80
+
81
+ $(OBJ_DIR_LOG)/%.o: $(SRC_DIR_LOG)/%.cpp
82
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
83
+
84
+ $(OBJ_DIR_PAL)/%.o: $(SRC_DIR_PAL_LINUX)/%.cpp
85
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
86
+
87
+ $(OBJ_DIR_PAL)/%.o: $(SRC_DIR_PAL_COMMON)/%.cpp
88
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
89
+
90
+ $(OBJ_DIR_UTILS)/%.o: $(SRC_DIR_UTILS)/%.cpp
91
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
92
+
93
+ $(OBJ_DIR_WRAPPER_UTILS)/%.o: $(SRC_DIR_WRAPPER_UTILS)/%.cpp
94
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
95
+
96
+ # set up resources
97
+ directories := $(TARGET_DIR) $(OBJ_DIR) $(OBJ_DIR_LOG) $(OBJ_DIR_PAL) $(OBJ_DIR_UTILS) $(OBJ_DIR_WRAPPER_UTILS)
98
+
99
+ # Compile
100
+ $(qnn-sample-app): obj/x86_64-linux-clang/main.o obj/x86_64-linux-clang/QnnSampleApp.o $(OBJECTS_LOG) $(OBJECTS_PAL) $(OBJECTS_UTILS) $(OBJECTS_WRAPPER_UTILS) | $(directories)
101
+ $(CXX) $(CXXFLAGS) $(LINKFLAGS) -o $@ $^ $(LIBS)
102
+
103
+ # rule for object directory resource
104
+ $(OBJECTS): | $(OBJ_DIR)
105
+ $(OBJECTS_LOG): | $(OBJ_DIR_LOG)
106
+ $(OBJECTS_PAL): | $(OBJ_DIR_PAL)
107
+ $(OBJECTS_UTILS): | $(OBJ_DIR_UTILS)
108
+ $(OBJECTS_WRAPPER_UTILS): | $(OBJ_DIR_WRAPPER_UTILS)
109
+
110
+ # rule to create directories
111
+ $(directories):
112
+ mkdir -p $@
113
+
114
+ .PHONY: clean
115
+ clean:
116
+ rm -rf $(OBJ_ROOT) $(TARGET_DIR)
SampleApp/make/Makefile.oe-linux-aarch64-gcc11.2 ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Copyright (c) 2023 Qualcomm Technologies, Inc.
3
+ # All Rights Reserved.
4
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
5
+ #
6
+
7
+ # define relevant directories
8
+ SRC_DIR := src
9
+ SRC_DIR_LOG := src/Log
10
+ SRC_DIR_PAL_LINUX := src/PAL/src/linux
11
+ SRC_DIR_PAL_COMMON := src/PAL/src/common
12
+ SRC_DIR_UTILS := src/Utils
13
+ SRC_DIR_WRAPPER_UTILS := src/WrapperUtils
14
+ ifeq ($(shell test -d ../../target && echo 0),0)
15
+ QNN_API_INCLUDE := ../../include
16
+ else
17
+ QNN_API_INCLUDE := ../../../include/QNN
18
+ endif
19
+ PAL_INCLUDE := src/PAL/include
20
+
21
+ QNN_TARGET ?= aarch64-oe-linux-gcc11.2
22
+ export TARGET_DIR := ./bin/$(QNN_TARGET)
23
+ CXX=$(QNN_AARCH64_LINUX_OE_GCC_112)/sysroots/x86_64-qtisdk-linux/usr/bin/aarch64-oe-linux/aarch64-oe-linux-g++ --sysroot=$(QNN_AARCH64_LINUX_OE_GCC_112)/sysroots/armv8a-oe-linux
24
+
25
+ qnn-sample-app := $(TARGET_DIR)/qnn-sample-app
26
+
27
+ .PHONY: sample_app_all
28
+ .DEFAULT: sample_app_all
29
+ sample_app_all: $(qnn-sample-app)
30
+
31
+ # Include paths
32
+ INCLUDES += -I$(SRC_DIR) -I$(SRC_DIR_LOG) -I$(SRC_DIR_UTILS) -I$(SRC_DIR_WRAPPER_UTILS) -I$(PAL_INCLUDE) -I$(QNN_API_INCLUDE)
33
+
34
+ # set compiler flags
35
+ COMMON_CXXFLAGS = -ldl -std=gnu++11 -fPIC -Wl,-lstdc++ -Wall -Werror -fno-exceptions -fno-rtti -fPIC -pg $(INCLUDES)
36
+ COMMON_LDFLAGS = -shared -s -fPIC
37
+
38
+ ifdef QNN_DEBUG_ENABLE
39
+ CXXFLAGS += $(COMMON_CXXFLAGS) -g -DQNN_API=""
40
+ LDFLAGS += $(COMMON_LDFLAGS)
41
+ else
42
+ CXXFLAGS += $(COMMON_CXXFLAGS) -Wno-write-strings -fvisibility=hidden -DQNN_API="__attribute__((visibility(\"default\")))"
43
+ LDFLAGS += $(COMMON_LDFLAGS) -fvisibility=hidden -flto
44
+ endif
45
+
46
+ # define library sources
47
+ SOURCES := $(wildcard $(SRC_DIR)/*.cpp)
48
+ SOURCES_LOG := $(wildcard $(SRC_DIR_LOG)/*.cpp)
49
+ SOURCES_PAL := $(wildcard $(SRC_DIR_PAL_LINUX)/*.cpp)
50
+ SOURCES_PAL += $(wildcard $(SRC_DIR_PAL_COMMON)/*.cpp)
51
+ SOURCES_UTILS := $(wildcard $(SRC_DIR_UTILS)/*.cpp)
52
+ SOURCES_WRAPPER_UTILS := $(wildcard $(SRC_DIR_WRAPPER_UTILS)/*.cpp)
53
+
54
+ # define object directory
55
+ OBJ_ROOT := obj
56
+ OBJ_DIR := obj/$(QNN_TARGET)
57
+ OBJ_DIR_LOG := obj/$(QNN_TARGET)/Log/
58
+ OBJ_DIR_PAL := obj/$(QNN_TARGET)/PAL
59
+ OBJ_DIR_UTILS := obj/$(QNN_TARGET)/Utils/
60
+ OBJ_DIR_WRAPPER_UTILS := obj/$(QNN_TARGET)/WrapperUtils/
61
+
62
+ # setup object files in object directory
63
+ OBJECTS := $(patsubst %.cpp,$(OBJ_DIR)/%.o,$(foreach x,$(SOURCES),$(notdir $(x))))
64
+ OBJECTS_LOG := $(patsubst %.cpp,$(OBJ_DIR_LOG)/%.o,$(foreach x,$(SOURCES_LOG),$(notdir $(x))))
65
+ OBJECTS_PAL := $(patsubst %.cpp,$(OBJ_DIR_PAL)/%.o,$(foreach x,$(SOURCES_PAL),$(notdir $(x))))
66
+ OBJECTS_UTILS := $(patsubst %.cpp,$(OBJ_DIR_UTILS)/%.o,$(foreach x,$(SOURCES_UTILS),$(notdir $(x))))
67
+ OBJECTS_WRAPPER_UTILS := $(patsubst %.cpp,$(OBJ_DIR_WRAPPER_UTILS)/%.o,$(foreach x,$(SOURCES_WRAPPER_UTILS),$(notdir $(x))))
68
+
69
+ LIBS=-ldl
70
+
71
+ # Rule to make executable
72
+ .PHONY: qnn-sample-app
73
+ qnn-sample-app: $(qnn-sample-app)
74
+
75
+ # Implicit rule to compile and link object files
76
+ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
77
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
78
+
79
+ $(OBJ_DIR_LOG)/%.o: $(SRC_DIR_LOG)/%.cpp
80
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
81
+
82
+ $(OBJ_DIR_PAL)/%.o: $(SRC_DIR_PAL_LINUX)/%.cpp
83
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
84
+
85
+ $(OBJ_DIR_PAL)/%.o: $(SRC_DIR_PAL_COMMON)/%.cpp
86
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
87
+
88
+ $(OBJ_DIR_UTILS)/%.o: $(SRC_DIR_UTILS)/%.cpp
89
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
90
+
91
+ $(OBJ_DIR_WRAPPER_UTILS)/%.o: $(SRC_DIR_WRAPPER_UTILS)/%.cpp
92
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
93
+
94
+ # set up resources
95
+ directories := $(TARGET_DIR) $(OBJ_DIR) $(OBJ_DIR_LOG) $(OBJ_DIR_PAL) $(OBJ_DIR_UTILS) $(OBJ_DIR_WRAPPER_UTILS)
96
+
97
+ # Compile
98
+ $(qnn-sample-app): obj/$(QNN_TARGET)/main.o obj/$(QNN_TARGET)/QnnSampleApp.o $(OBJECTS_LOG) $(OBJECTS_PAL) $(OBJECTS_UTILS) $(OBJECTS_WRAPPER_UTILS) | $(directories)
99
+ $(CXX) $(CXXFLAGS) $(LINKFLAGS) -o $@ $^ $(LIBS)
100
+
101
+ # rule for object directory resource
102
+ $(OBJECTS): | $(OBJ_DIR)
103
+ $(OBJECTS_LOG): | $(OBJ_DIR_LOG)
104
+ $(OBJECTS_PAL): | $(OBJ_DIR_PAL)
105
+ $(OBJECTS_UTILS): | $(OBJ_DIR_UTILS)
106
+ $(OBJECTS_WRAPPER_UTILS): | $(OBJ_DIR_WRAPPER_UTILS)
107
+
108
+ # rule to create directories
109
+ $(directories):
110
+ mkdir -p $@
111
+
112
+ .PHONY: clean
113
+ clean:
114
+ rm -rf $(OBJ_ROOT) $(TARGET_DIR)
SampleApp/make/Makefile.oe-linux-aarch64-gcc8.2 ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Copyright (c) 2021-2023 Qualcomm Technologies, Inc.
3
+ # All Rights Reserved.
4
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
5
+ #
6
+
7
+ # define relevant directories
8
+ SRC_DIR := src
9
+ SRC_DIR_LOG := src/Log
10
+ SRC_DIR_PAL_LINUX := src/PAL/src/linux
11
+ SRC_DIR_PAL_COMMON := src/PAL/src/common
12
+ SRC_DIR_UTILS := src/Utils
13
+ SRC_DIR_WRAPPER_UTILS := src/WrapperUtils
14
+ ifeq ($(shell test -d ../../target && echo 0),0)
15
+ QNN_API_INCLUDE := ../../include
16
+ else
17
+ QNN_API_INCLUDE := ../../../include/QNN
18
+ endif
19
+ PAL_INCLUDE := src/PAL/include
20
+
21
+ QNN_TARGET ?= aarch64-oe-linux-gcc8.2
22
+ export TARGET_DIR := ./bin/$(QNN_TARGET)
23
+ CXX=$(QNN_AARCH64_LINUX_OE_GCC_82)/sysroots/x86_64-oesdk-linux/usr/bin/aarch64-oe-linux/aarch64-oe-linux-g++ --sysroot=$(QNN_AARCH64_LINUX_OE_GCC_82)/sysroots/aarch64-oe-linux
24
+
25
+ qnn-sample-app := $(TARGET_DIR)/qnn-sample-app
26
+
27
+ .PHONY: sample_app_all
28
+ .DEFAULT: sample_app_all
29
+ sample_app_all: $(qnn-sample-app)
30
+
31
+ # Include paths
32
+ INCLUDES += -I$(SRC_DIR) -I$(SRC_DIR_LOG) -I$(SRC_DIR_UTILS) -I$(SRC_DIR_WRAPPER_UTILS) -I$(PAL_INCLUDE) -I$(QNN_API_INCLUDE)
33
+
34
+ # set compiler flags
35
+ COMMON_CXXFLAGS = -ldl -std=gnu++11 -fPIC -Wl,-lstdc++ -Wall -Werror -fno-exceptions -fno-rtti -fPIC -pg $(INCLUDES)
36
+ COMMON_LDFLAGS = -shared -s -fPIC
37
+
38
+ ifdef QNN_DEBUG_ENABLE
39
+ CXXFLAGS += $(COMMON_CXXFLAGS) -g -DQNN_API=""
40
+ LDFLAGS += $(COMMON_LDFLAGS)
41
+ else
42
+ CXXFLAGS += $(COMMON_CXXFLAGS) -Wno-write-strings -fvisibility=hidden -DQNN_API="__attribute__((visibility(\"default\")))"
43
+ LDFLAGS += $(COMMON_LDFLAGS) -fvisibility=hidden -flto
44
+ endif
45
+
46
+ # define library sources
47
+ SOURCES := $(wildcard $(SRC_DIR)/*.cpp)
48
+ SOURCES_LOG := $(wildcard $(SRC_DIR_LOG)/*.cpp)
49
+ SOURCES_PAL := $(wildcard $(SRC_DIR_PAL_LINUX)/*.cpp)
50
+ SOURCES_PAL += $(wildcard $(SRC_DIR_PAL_COMMON)/*.cpp)
51
+ SOURCES_UTILS := $(wildcard $(SRC_DIR_UTILS)/*.cpp)
52
+ SOURCES_WRAPPER_UTILS := $(wildcard $(SRC_DIR_WRAPPER_UTILS)/*.cpp)
53
+
54
+ # define object directory
55
+ OBJ_ROOT := obj
56
+ OBJ_DIR := obj/$(QNN_TARGET)
57
+ OBJ_DIR_LOG := obj/$(QNN_TARGET)/Log/
58
+ OBJ_DIR_PAL := obj/$(QNN_TARGET)/PAL
59
+ OBJ_DIR_UTILS := obj/$(QNN_TARGET)/Utils/
60
+ OBJ_DIR_WRAPPER_UTILS := obj/$(QNN_TARGET)/WrapperUtils/
61
+
62
+ # setup object files in object directory
63
+ OBJECTS := $(patsubst %.cpp,$(OBJ_DIR)/%.o,$(foreach x,$(SOURCES),$(notdir $(x))))
64
+ OBJECTS_LOG := $(patsubst %.cpp,$(OBJ_DIR_LOG)/%.o,$(foreach x,$(SOURCES_LOG),$(notdir $(x))))
65
+ OBJECTS_PAL := $(patsubst %.cpp,$(OBJ_DIR_PAL)/%.o,$(foreach x,$(SOURCES_PAL),$(notdir $(x))))
66
+ OBJECTS_UTILS := $(patsubst %.cpp,$(OBJ_DIR_UTILS)/%.o,$(foreach x,$(SOURCES_UTILS),$(notdir $(x))))
67
+ OBJECTS_WRAPPER_UTILS := $(patsubst %.cpp,$(OBJ_DIR_WRAPPER_UTILS)/%.o,$(foreach x,$(SOURCES_WRAPPER_UTILS),$(notdir $(x))))
68
+
69
+ LIBS=-ldl
70
+
71
+ # Rule to make executable
72
+ .PHONY: qnn-sample-app
73
+ qnn-sample-app: $(qnn-sample-app)
74
+
75
+ # Implicit rule to compile and link object files
76
+ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
77
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
78
+
79
+ $(OBJ_DIR_LOG)/%.o: $(SRC_DIR_LOG)/%.cpp
80
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
81
+
82
+ $(OBJ_DIR_PAL)/%.o: $(SRC_DIR_PAL_LINUX)/%.cpp
83
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
84
+
85
+ $(OBJ_DIR_PAL)/%.o: $(SRC_DIR_PAL_COMMON)/%.cpp
86
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
87
+
88
+ $(OBJ_DIR_UTILS)/%.o: $(SRC_DIR_UTILS)/%.cpp
89
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
90
+
91
+ $(OBJ_DIR_WRAPPER_UTILS)/%.o: $(SRC_DIR_WRAPPER_UTILS)/%.cpp
92
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
93
+
94
+ # set up resources
95
+ directories := $(TARGET_DIR) $(OBJ_DIR) $(OBJ_DIR_LOG) $(OBJ_DIR_PAL) $(OBJ_DIR_UTILS) $(OBJ_DIR_WRAPPER_UTILS)
96
+
97
+ # Compile
98
+ $(qnn-sample-app): obj/$(QNN_TARGET)/main.o obj/$(QNN_TARGET)/QnnSampleApp.o $(OBJECTS_LOG) $(OBJECTS_PAL) $(OBJECTS_UTILS) $(OBJECTS_WRAPPER_UTILS) | $(directories)
99
+ $(CXX) $(CXXFLAGS) $(LINKFLAGS) -o $@ $^ $(LIBS)
100
+
101
+ # rule for object directory resource
102
+ $(OBJECTS): | $(OBJ_DIR)
103
+ $(OBJECTS_LOG): | $(OBJ_DIR_LOG)
104
+ $(OBJECTS_PAL): | $(OBJ_DIR_PAL)
105
+ $(OBJECTS_UTILS): | $(OBJ_DIR_UTILS)
106
+ $(OBJECTS_WRAPPER_UTILS): | $(OBJ_DIR_WRAPPER_UTILS)
107
+
108
+ # rule to create directories
109
+ $(directories):
110
+ mkdir -p $@
111
+
112
+ .PHONY: clean
113
+ clean:
114
+ rm -rf $(OBJ_ROOT) $(TARGET_DIR)
SampleApp/make/Makefile.oe-linux-aarch64-gcc9.3 ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Copyright (c) 2021-2023 Qualcomm Technologies, Inc.
3
+ # All Rights Reserved.
4
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
5
+ #
6
+
7
+ # define relevant directories
8
+ SRC_DIR := src
9
+ SRC_DIR_LOG := src/Log
10
+ SRC_DIR_PAL_LINUX := src/PAL/src/linux
11
+ SRC_DIR_PAL_COMMON := src/PAL/src/common
12
+ SRC_DIR_UTILS := src/Utils
13
+ SRC_DIR_WRAPPER_UTILS := src/WrapperUtils
14
+ ifeq ($(shell test -d ../../target && echo 0),0)
15
+ QNN_API_INCLUDE := ../../include
16
+ else
17
+ QNN_API_INCLUDE := ../../../include/QNN
18
+ endif
19
+ PAL_INCLUDE := src/PAL/include
20
+
21
+ QNN_TARGET ?= aarch64-oe-linux-gcc9.3
22
+ export TARGET_DIR := ./bin/$(QNN_TARGET)
23
+ CXX=$(QNN_AARCH64_LINUX_OE_GCC_93)/sysroots/x86_64-oesdk-linux/usr/bin/aarch64-oe-linux/aarch64-oe-linux-g++ --sysroot=$(QNN_AARCH64_LINUX_OE_GCC_93)/sysroots/aarch64-oe-linux
24
+
25
+ qnn-sample-app := $(TARGET_DIR)/qnn-sample-app
26
+
27
+ .PHONY: sample_app_all
28
+ .DEFAULT: sample_app_all
29
+ sample_app_all: $(qnn-sample-app)
30
+
31
+ # Include paths
32
+ INCLUDES += -I$(SRC_DIR) -I$(SRC_DIR_LOG) -I$(SRC_DIR_UTILS) -I$(SRC_DIR_WRAPPER_UTILS) -I$(PAL_INCLUDE) -I$(QNN_API_INCLUDE)
33
+
34
+ # set compiler flags
35
+ COMMON_CXXFLAGS = -ldl -std=gnu++11 -fPIC -Wl,-lstdc++ -Wall -Werror -fno-exceptions -fno-rtti -fPIC -pg $(INCLUDES)
36
+ COMMON_LDFLAGS = -shared -s -fPIC
37
+
38
+ ifdef QNN_DEBUG_ENABLE
39
+ CXXFLAGS += $(COMMON_CXXFLAGS) -g -DQNN_API=""
40
+ LDFLAGS += $(COMMON_LDFLAGS)
41
+ else
42
+ CXXFLAGS += $(COMMON_CXXFLAGS) -Wno-write-strings -fvisibility=hidden -DQNN_API="__attribute__((visibility(\"default\")))"
43
+ LDFLAGS += $(COMMON_LDFLAGS) -fvisibility=hidden -flto
44
+ endif
45
+
46
+ # define library sources
47
+ SOURCES := $(wildcard $(SRC_DIR)/*.cpp)
48
+ SOURCES_LOG := $(wildcard $(SRC_DIR_LOG)/*.cpp)
49
+ SOURCES_PAL := $(wildcard $(SRC_DIR_PAL_LINUX)/*.cpp)
50
+ SOURCES_PAL += $(wildcard $(SRC_DIR_PAL_COMMON)/*.cpp)
51
+ SOURCES_UTILS := $(wildcard $(SRC_DIR_UTILS)/*.cpp)
52
+ SOURCES_WRAPPER_UTILS := $(wildcard $(SRC_DIR_WRAPPER_UTILS)/*.cpp)
53
+
54
+ # define object directory
55
+ OBJ_ROOT := obj
56
+ OBJ_DIR := obj/$(QNN_TARGET)
57
+ OBJ_DIR_LOG := obj/$(QNN_TARGET)/Log/
58
+ OBJ_DIR_PAL := obj/$(QNN_TARGET)/PAL
59
+ OBJ_DIR_UTILS := obj/$(QNN_TARGET)/Utils/
60
+ OBJ_DIR_WRAPPER_UTILS := obj/$(QNN_TARGET)/WrapperUtils/
61
+
62
+ # setup object files in object directory
63
+ OBJECTS := $(patsubst %.cpp,$(OBJ_DIR)/%.o,$(foreach x,$(SOURCES),$(notdir $(x))))
64
+ OBJECTS_LOG := $(patsubst %.cpp,$(OBJ_DIR_LOG)/%.o,$(foreach x,$(SOURCES_LOG),$(notdir $(x))))
65
+ OBJECTS_PAL := $(patsubst %.cpp,$(OBJ_DIR_PAL)/%.o,$(foreach x,$(SOURCES_PAL),$(notdir $(x))))
66
+ OBJECTS_UTILS := $(patsubst %.cpp,$(OBJ_DIR_UTILS)/%.o,$(foreach x,$(SOURCES_UTILS),$(notdir $(x))))
67
+ OBJECTS_WRAPPER_UTILS := $(patsubst %.cpp,$(OBJ_DIR_WRAPPER_UTILS)/%.o,$(foreach x,$(SOURCES_WRAPPER_UTILS),$(notdir $(x))))
68
+
69
+ LIBS=-ldl
70
+
71
+ # Rule to make executable
72
+ .PHONY: qnn-sample-app
73
+ qnn-sample-app: $(qnn-sample-app)
74
+
75
+ # Implicit rule to compile and link object files
76
+ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
77
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
78
+
79
+ $(OBJ_DIR_LOG)/%.o: $(SRC_DIR_LOG)/%.cpp
80
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
81
+
82
+ $(OBJ_DIR_PAL)/%.o: $(SRC_DIR_PAL_LINUX)/%.cpp
83
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
84
+
85
+ $(OBJ_DIR_PAL)/%.o: $(SRC_DIR_PAL_COMMON)/%.cpp
86
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
87
+
88
+ $(OBJ_DIR_UTILS)/%.o: $(SRC_DIR_UTILS)/%.cpp
89
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
90
+
91
+ $(OBJ_DIR_WRAPPER_UTILS)/%.o: $(SRC_DIR_WRAPPER_UTILS)/%.cpp
92
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
93
+
94
+ # set up resources
95
+ directories := $(TARGET_DIR) $(OBJ_DIR) $(OBJ_DIR_LOG) $(OBJ_DIR_PAL) $(OBJ_DIR_UTILS) $(OBJ_DIR_WRAPPER_UTILS)
96
+
97
+ # Compile
98
+ $(qnn-sample-app): obj/$(QNN_TARGET)/main.o obj/$(QNN_TARGET)/QnnSampleApp.o $(OBJECTS_LOG) $(OBJECTS_PAL) $(OBJECTS_UTILS) $(OBJECTS_WRAPPER_UTILS) | $(directories)
99
+ $(CXX) $(CXXFLAGS) $(LINKFLAGS) -o $@ $^ $(LIBS)
100
+
101
+ # rule for object directory resource
102
+ $(OBJECTS): | $(OBJ_DIR)
103
+ $(OBJECTS_LOG): | $(OBJ_DIR_LOG)
104
+ $(OBJECTS_PAL): | $(OBJ_DIR_PAL)
105
+ $(OBJECTS_UTILS): | $(OBJ_DIR_UTILS)
106
+ $(OBJECTS_WRAPPER_UTILS): | $(OBJ_DIR_WRAPPER_UTILS)
107
+
108
+ # rule to create directories
109
+ $(directories):
110
+ mkdir -p $@
111
+
112
+ .PHONY: clean
113
+ clean:
114
+ rm -rf $(OBJ_ROOT) $(TARGET_DIR)
SampleApp/make/Makefile.ubuntu-aarch64-gcc7.5 ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Copyright (c) 2021-2023 Qualcomm Technologies, Inc.
3
+ # All Rights Reserved.
4
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
5
+ #
6
+
7
+ # define relevant directories
8
+ SRC_DIR := src
9
+ SRC_DIR_LOG := src/Log
10
+ SRC_DIR_PAL_LINUX := src/PAL/src/linux
11
+ SRC_DIR_PAL_COMMON := src/PAL/src/common
12
+ SRC_DIR_UTILS := src/Utils
13
+ SRC_DIR_WRAPPER_UTILS := src/WrapperUtils
14
+ ifeq ($(shell test -d ../../target && echo 0),0)
15
+ QNN_API_INCLUDE := ../../include
16
+ else
17
+ QNN_API_INCLUDE := ../../../include/QNN
18
+ endif
19
+ PAL_INCLUDE := src/PAL/include
20
+
21
+ QNN_TARGET ?= aarch64-ubuntu-gcc7.5
22
+ export TARGET_DIR := ./bin/$(QNN_TARGET)
23
+ CXX=$(QNN_AARCH64_UBUNTU_GCC_75)/root/bin/aarch64-linux-gnu-g++
24
+
25
+ qnn-sample-app := $(TARGET_DIR)/qnn-sample-app
26
+
27
+ .PHONY: sample_app_all
28
+ .DEFAULT: sample_app_all
29
+ sample_app_all: $(qnn-sample-app)
30
+
31
+ # Include paths
32
+ INCLUDES += -I$(SRC_DIR) -I$(SRC_DIR_LOG) -I$(SRC_DIR_UTILS) -I$(SRC_DIR_WRAPPER_UTILS) -I$(PAL_INCLUDE) -I$(QNN_API_INCLUDE)
33
+
34
+ # set compiler flags
35
+ COMMON_CXXFLAGS = -ldl -std=gnu++11 -fPIC -Wl,-lstdc++ -Wall -Werror -fno-exceptions -fno-rtti -fPIC -pg $(INCLUDES)
36
+ COMMON_LDFLAGS = -shared -s -fPIC
37
+
38
+ ifdef QNN_DEBUG_ENABLE
39
+ CXXFLAGS += $(COMMON_CXXFLAGS) -g -DQNN_API=""
40
+ LDFLAGS += $(COMMON_LDFLAGS)
41
+ else
42
+ CXXFLAGS += $(COMMON_CXXFLAGS) -Wno-write-strings -fvisibility=hidden -DQNN_API="__attribute__((visibility(\"default\")))"
43
+ LDFLAGS += $(COMMON_LDFLAGS) -fvisibility=hidden -flto
44
+ endif
45
+
46
+ # define library sources
47
+ SOURCES := $(wildcard $(SRC_DIR)/*.cpp)
48
+ SOURCES_LOG := $(wildcard $(SRC_DIR_LOG)/*.cpp)
49
+ SOURCES_PAL := $(wildcard $(SRC_DIR_PAL_LINUX)/*.cpp)
50
+ SOURCES_PAL += $(wildcard $(SRC_DIR_PAL_COMMON)/*.cpp)
51
+ SOURCES_UTILS := $(wildcard $(SRC_DIR_UTILS)/*.cpp)
52
+ SOURCES_WRAPPER_UTILS := $(wildcard $(SRC_DIR_WRAPPER_UTILS)/*.cpp)
53
+
54
+ # define object directory
55
+ OBJ_ROOT := obj
56
+ OBJ_DIR := obj/$(QNN_TARGET)
57
+ OBJ_DIR_LOG := obj/$(QNN_TARGET)/Log/
58
+ OBJ_DIR_PAL := obj/$(QNN_TARGET)/PAL
59
+ OBJ_DIR_UTILS := obj/$(QNN_TARGET)/Utils/
60
+ OBJ_DIR_WRAPPER_UTILS := obj/$(QNN_TARGET)/WrapperUtils/
61
+
62
+ # setup object files in object directory
63
+ OBJECTS := $(patsubst %.cpp,$(OBJ_DIR)/%.o,$(foreach x,$(SOURCES),$(notdir $(x))))
64
+ OBJECTS_LOG := $(patsubst %.cpp,$(OBJ_DIR_LOG)/%.o,$(foreach x,$(SOURCES_LOG),$(notdir $(x))))
65
+ OBJECTS_PAL := $(patsubst %.cpp,$(OBJ_DIR_PAL)/%.o,$(foreach x,$(SOURCES_PAL),$(notdir $(x))))
66
+ OBJECTS_UTILS := $(patsubst %.cpp,$(OBJ_DIR_UTILS)/%.o,$(foreach x,$(SOURCES_UTILS),$(notdir $(x))))
67
+ OBJECTS_WRAPPER_UTILS := $(patsubst %.cpp,$(OBJ_DIR_WRAPPER_UTILS)/%.o,$(foreach x,$(SOURCES_WRAPPER_UTILS),$(notdir $(x))))
68
+
69
+ LIBS=-ldl
70
+
71
+ # Rule to make executable
72
+ .PHONY: qnn-sample-app
73
+ qnn-sample-app: $(qnn-sample-app)
74
+
75
+ # Implicit rule to compile and link object files
76
+ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
77
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
78
+
79
+ $(OBJ_DIR_LOG)/%.o: $(SRC_DIR_LOG)/%.cpp
80
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
81
+
82
+ $(OBJ_DIR_PAL)/%.o: $(SRC_DIR_PAL_LINUX)/%.cpp
83
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
84
+
85
+ $(OBJ_DIR_PAL)/%.o: $(SRC_DIR_PAL_COMMON)/%.cpp
86
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
87
+
88
+ $(OBJ_DIR_UTILS)/%.o: $(SRC_DIR_UTILS)/%.cpp
89
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
90
+
91
+ $(OBJ_DIR_WRAPPER_UTILS)/%.o: $(SRC_DIR_WRAPPER_UTILS)/%.cpp
92
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
93
+
94
+ # set up resources
95
+ directories := $(TARGET_DIR) $(OBJ_DIR) $(OBJ_DIR_LOG) $(OBJ_DIR_PAL) $(OBJ_DIR_UTILS) $(OBJ_DIR_WRAPPER_UTILS)
96
+
97
+ # Compile
98
+ $(qnn-sample-app): obj/$(QNN_TARGET)/main.o obj/$(QNN_TARGET)/QnnSampleApp.o $(OBJECTS_LOG) $(OBJECTS_PAL) $(OBJECTS_UTILS) $(OBJECTS_WRAPPER_UTILS) | $(directories)
99
+ $(CXX) $(CXXFLAGS) $(LINKFLAGS) -o $@ $^ $(LIBS)
100
+
101
+ # rule for object directory resource
102
+ $(OBJECTS): | $(OBJ_DIR)
103
+ $(OBJECTS_LOG): | $(OBJ_DIR_LOG)
104
+ $(OBJECTS_PAL): | $(OBJ_DIR_PAL)
105
+ $(OBJECTS_UTILS): | $(OBJ_DIR_UTILS)
106
+ $(OBJECTS_WRAPPER_UTILS): | $(OBJ_DIR_WRAPPER_UTILS)
107
+
108
+ # rule to create directories
109
+ $(directories):
110
+ mkdir -p $@
111
+
112
+ .PHONY: clean
113
+ clean:
114
+ rm -rf $(OBJ_ROOT) $(TARGET_DIR)
SampleApp/make/Makefile.ubuntu-aarch64-gcc9.4 ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Copyright (c) 2023 Qualcomm Technologies, Inc.
3
+ # All Rights Reserved.
4
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
5
+ #
6
+
7
+ # define relevant directories
8
+ SRC_DIR := src
9
+ SRC_DIR_LOG := src/Log
10
+ SRC_DIR_PAL_LINUX := src/PAL/src/linux
11
+ SRC_DIR_PAL_COMMON := src/PAL/src/common
12
+ SRC_DIR_UTILS := src/Utils
13
+ SRC_DIR_WRAPPER_UTILS := src/WrapperUtils
14
+ ifeq ($(shell test -d ../../target && echo 0),0)
15
+ QNN_API_INCLUDE := ../../include
16
+ else
17
+ QNN_API_INCLUDE := ../../../include/QNN
18
+ endif
19
+ PAL_INCLUDE := src/PAL/include
20
+
21
+ QNN_TARGET ?= aarch64-ubuntu-gcc9.4
22
+ export TARGET_DIR := ./bin/$(QNN_TARGET)
23
+ CXX=$(QNN_AARCH64_UBUNTU_GCC_94)/usr/bin/aarch64-linux-gnu-g++ --sysroot=$(QNN_AARCH64_UBUNTU_GCC_94)
24
+
25
+ qnn-sample-app := $(TARGET_DIR)/qnn-sample-app
26
+
27
+ .PHONY: sample_app_all
28
+ .DEFAULT: sample_app_all
29
+ sample_app_all: $(qnn-sample-app)
30
+
31
+ # Include paths
32
+ INCLUDES += -I$(SRC_DIR) -I$(SRC_DIR_LOG) -I$(SRC_DIR_UTILS) -I$(SRC_DIR_WRAPPER_UTILS) -I$(PAL_INCLUDE) -I$(QNN_API_INCLUDE)
33
+
34
+ # set compiler flags
35
+ COMMON_CXXFLAGS = -ldl -std=gnu++11 -fPIC -Wl,-lstdc++ -Wall -Werror -fno-exceptions -fno-rtti -fPIC -pg $(INCLUDES)
36
+ COMMON_LDFLAGS = -shared -s -fPIC
37
+
38
+ ifdef QNN_DEBUG_ENABLE
39
+ CXXFLAGS += $(COMMON_CXXFLAGS) -g -DQNN_API=""
40
+ LDFLAGS += $(COMMON_LDFLAGS)
41
+ else
42
+ CXXFLAGS += $(COMMON_CXXFLAGS) -Wno-write-strings -fvisibility=hidden -DQNN_API="__attribute__((visibility(\"default\")))"
43
+ LDFLAGS += $(COMMON_LDFLAGS) -fvisibility=hidden -flto
44
+ endif
45
+
46
+ # define library sources
47
+ SOURCES := $(wildcard $(SRC_DIR)/*.cpp)
48
+ SOURCES_LOG := $(wildcard $(SRC_DIR_LOG)/*.cpp)
49
+ SOURCES_PAL := $(wildcard $(SRC_DIR_PAL_LINUX)/*.cpp)
50
+ SOURCES_PAL += $(wildcard $(SRC_DIR_PAL_COMMON)/*.cpp)
51
+ SOURCES_UTILS := $(wildcard $(SRC_DIR_UTILS)/*.cpp)
52
+ SOURCES_WRAPPER_UTILS := $(wildcard $(SRC_DIR_WRAPPER_UTILS)/*.cpp)
53
+
54
+ # define object directory
55
+ OBJ_ROOT := obj
56
+ OBJ_DIR := obj/$(QNN_TARGET)
57
+ OBJ_DIR_LOG := obj/$(QNN_TARGET)/Log/
58
+ OBJ_DIR_PAL := obj/$(QNN_TARGET)/PAL
59
+ OBJ_DIR_UTILS := obj/$(QNN_TARGET)/Utils/
60
+ OBJ_DIR_WRAPPER_UTILS := obj/$(QNN_TARGET)/WrapperUtils/
61
+
62
+ # setup object files in object directory
63
+ OBJECTS := $(patsubst %.cpp,$(OBJ_DIR)/%.o,$(foreach x,$(SOURCES),$(notdir $(x))))
64
+ OBJECTS_LOG := $(patsubst %.cpp,$(OBJ_DIR_LOG)/%.o,$(foreach x,$(SOURCES_LOG),$(notdir $(x))))
65
+ OBJECTS_PAL := $(patsubst %.cpp,$(OBJ_DIR_PAL)/%.o,$(foreach x,$(SOURCES_PAL),$(notdir $(x))))
66
+ OBJECTS_UTILS := $(patsubst %.cpp,$(OBJ_DIR_UTILS)/%.o,$(foreach x,$(SOURCES_UTILS),$(notdir $(x))))
67
+ OBJECTS_WRAPPER_UTILS := $(patsubst %.cpp,$(OBJ_DIR_WRAPPER_UTILS)/%.o,$(foreach x,$(SOURCES_WRAPPER_UTILS),$(notdir $(x))))
68
+
69
+ LIBS=-ldl
70
+
71
+ # Rule to make executable
72
+ .PHONY: qnn-sample-app
73
+ qnn-sample-app: $(qnn-sample-app)
74
+
75
+ # Implicit rule to compile and link object files
76
+ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
77
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
78
+
79
+ $(OBJ_DIR_LOG)/%.o: $(SRC_DIR_LOG)/%.cpp
80
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
81
+
82
+ $(OBJ_DIR_PAL)/%.o: $(SRC_DIR_PAL_LINUX)/%.cpp
83
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
84
+
85
+ $(OBJ_DIR_PAL)/%.o: $(SRC_DIR_PAL_COMMON)/%.cpp
86
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
87
+
88
+ $(OBJ_DIR_UTILS)/%.o: $(SRC_DIR_UTILS)/%.cpp
89
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
90
+
91
+ $(OBJ_DIR_WRAPPER_UTILS)/%.o: $(SRC_DIR_WRAPPER_UTILS)/%.cpp
92
+ $(CXX) $(CXXFLAGS) -c $^ -o $@
93
+
94
+ # set up resources
95
+ directories := $(TARGET_DIR) $(OBJ_DIR) $(OBJ_DIR_LOG) $(OBJ_DIR_PAL) $(OBJ_DIR_UTILS) $(OBJ_DIR_WRAPPER_UTILS)
96
+
97
+ # Compile
98
+ $(qnn-sample-app): obj/$(QNN_TARGET)/main.o obj/$(QNN_TARGET)/QnnSampleApp.o $(OBJECTS_LOG) $(OBJECTS_PAL) $(OBJECTS_UTILS) $(OBJECTS_WRAPPER_UTILS) | $(directories)
99
+ $(CXX) $(CXXFLAGS) $(LINKFLAGS) -o $@ $^ $(LIBS)
100
+
101
+ # rule for object directory resource
102
+ $(OBJECTS): | $(OBJ_DIR)
103
+ $(OBJECTS_LOG): | $(OBJ_DIR_LOG)
104
+ $(OBJECTS_PAL): | $(OBJ_DIR_PAL)
105
+ $(OBJECTS_UTILS): | $(OBJ_DIR_UTILS)
106
+ $(OBJECTS_WRAPPER_UTILS): | $(OBJ_DIR_WRAPPER_UTILS)
107
+
108
+ # rule to create directories
109
+ $(directories):
110
+ mkdir -p $@
111
+
112
+ .PHONY: clean
113
+ clean:
114
+ rm -rf $(OBJ_ROOT) $(TARGET_DIR)
SampleApp/src/CMakeLists.txt ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #==============================================================================
2
+ #
3
+ # Copyright (c) 2022 Qualcomm Technologies, Inc.
4
+ # All Rights Reserved.
5
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ #
7
+ #==============================================================================
8
+
9
+ set(APP "qnn-sample-app")
10
+ set(APP_SOURCES "QnnSampleApp.cpp"
11
+ "main.cpp"
12
+ "Log/Logger.cpp"
13
+ "Log/LogUtils.cpp"
14
+ "PAL/src/windows/Common.cpp"
15
+ "PAL/src/windows/Directory.cpp"
16
+ "PAL/src/windows/DynamicLoading.cpp"
17
+ "PAL/src/windows/FileOp.cpp"
18
+ "PAL/src/windows/Path.cpp"
19
+ "PAL/src/common/GetOpt.cpp"
20
+ "PAL/src/common/StringOp.cpp"
21
+ "Utils/DataUtil.cpp"
22
+ "Utils/DynamicLoadUtil.cpp"
23
+ "Utils/IOTensor.cpp"
24
+ "Utils/QnnSampleAppUtils.cpp"
25
+ "WrapperUtils/QnnWrapperUtils.cpp")
26
+
27
+ add_executable(${APP} ${APP_SOURCES})
28
+
29
+ target_compile_definitions(${APP} PUBLIC "-DNOMINMAX")
30
+ target_link_libraries(${APP} PRIVATE Shlwapi Shell32)
31
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
32
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT /O2 /Ob3")
33
+ target_include_directories(${APP} PUBLIC CachingUtil
34
+ Log
35
+ PAL/include
36
+ Utils
37
+ WrapperUtils
38
+ ${CMAKE_BINARY_DIR}
39
+ ../../../../include/QNN
40
+ ./)
SampleApp/src/DspLog/LogUtils.cpp ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2024 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #include "HAP_farf.h"
10
+ #include "LogUtils.hpp"
11
+
12
+ #define PRINTLEN 1024
13
+
14
+ void qnn::log::utils::logDefaultCallback(const char* fmt,
15
+ QnnLog_Level_t level,
16
+ uint64_t timestamp,
17
+ va_list argp) {
18
+ char buffer[PRINTLEN] = "";
19
+ std::lock_guard<std::mutex> lock(sg_logUtilMutex);
20
+ vsnprintf(buffer, sizeof(buffer), fmt, argp);
21
+ FARF(ALWAYS, "[%x] %s", level, buffer);
22
+ }
SampleApp/src/Log/LogUtils.cpp ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2020, 2022, 2024 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #include "LogUtils.hpp"
10
+
11
+ void qnn::log::utils::logDefaultCallback(const char* fmt,
12
+ QnnLog_Level_t level,
13
+ uint64_t timestamp,
14
+ va_list argp) {
15
+ const char* levelStr = "";
16
+ switch (level) {
17
+ case QNN_LOG_LEVEL_ERROR:
18
+ levelStr = " ERROR ";
19
+ break;
20
+ case QNN_LOG_LEVEL_WARN:
21
+ levelStr = "WARNING";
22
+ break;
23
+ case QNN_LOG_LEVEL_INFO:
24
+ levelStr = " INFO ";
25
+ break;
26
+ case QNN_LOG_LEVEL_DEBUG:
27
+ levelStr = " DEBUG ";
28
+ break;
29
+ case QNN_LOG_LEVEL_VERBOSE:
30
+ levelStr = "VERBOSE";
31
+ break;
32
+ case QNN_LOG_LEVEL_MAX:
33
+ levelStr = "UNKNOWN";
34
+ break;
35
+ }
36
+
37
+ double ms = (double)timestamp / 1000000.0;
38
+ // To avoid interleaved messages
39
+ {
40
+ std::lock_guard<std::mutex> lock(sg_logUtilMutex);
41
+ fprintf(stdout, "%8.1fms [%-7s] ", ms, levelStr);
42
+ vfprintf(stdout, fmt, argp);
43
+ fprintf(stdout, "\n");
44
+ }
45
+ }
SampleApp/src/Log/LogUtils.hpp ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2020, 2022, 2024 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #pragma once
10
+
11
+ #include <cstdarg>
12
+ #include <cstdio>
13
+ #include <mutex>
14
+ #include <string>
15
+
16
+ #include "QnnLog.h"
17
+
18
+ namespace qnn {
19
+ namespace log {
20
+ namespace utils {
21
+
22
+ // In non-hexagon app stdout is used and for hexagon farf logging is used
23
+ void logDefaultCallback(const char* fmt, QnnLog_Level_t level, uint64_t timestamp, va_list argp);
24
+
25
+ static std::mutex sg_logUtilMutex;
26
+
27
+ } // namespace utils
28
+ } // namespace log
29
+ } // namespace qnn
SampleApp/src/Log/Logger.cpp ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //=============================================================================
2
+ //
3
+ // Copyright (c) 2020-2022, 2024 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //=============================================================================
8
+
9
+ #include <chrono>
10
+ #include <cstdio>
11
+ #include <iostream>
12
+ #include <sstream>
13
+
14
+ #include "LogUtils.hpp"
15
+ #include "Logger.hpp"
16
+
17
+ using namespace qnn::log;
18
+
19
+ std::shared_ptr<Logger> Logger::s_logger = nullptr;
20
+
21
+ std::mutex Logger::s_logMutex;
22
+
23
+ std::shared_ptr<Logger> Logger::createLogger(QnnLog_Callback_t callback,
24
+ QnnLog_Level_t maxLevel,
25
+ QnnLog_Error_t* status) {
26
+ std::lock_guard<std::mutex> lock(s_logMutex);
27
+ if ((maxLevel > QNN_LOG_LEVEL_VERBOSE) || (maxLevel == 0)) {
28
+ if (status) {
29
+ *status = QNN_LOG_ERROR_INVALID_ARGUMENT;
30
+ }
31
+ return nullptr;
32
+ }
33
+ if (!s_logger) {
34
+ s_logger = std::shared_ptr<Logger>(new (std::nothrow) Logger(callback, maxLevel, status));
35
+ }
36
+ *status = QNN_LOG_NO_ERROR;
37
+ return s_logger;
38
+ }
39
+
40
+ Logger::Logger(QnnLog_Callback_t callback, QnnLog_Level_t maxLevel, QnnLog_Error_t* status)
41
+ : m_callback(callback), m_maxLevel(maxLevel), m_epoch(getTimestamp()) {
42
+ if (!callback) {
43
+ m_callback = utils::logDefaultCallback;
44
+ }
45
+ }
46
+
47
+ void Logger::log(QnnLog_Level_t level, const char* file, long line, const char* fmt, ...) {
48
+ if (m_callback) {
49
+ if (level > m_maxLevel.load(std::memory_order_seq_cst)) {
50
+ return;
51
+ }
52
+ va_list argp;
53
+ va_start(argp, fmt);
54
+ std::string logString(fmt);
55
+ std::ignore = file;
56
+ std::ignore = line;
57
+ (*m_callback)(logString.c_str(), level, getTimestamp() - m_epoch, argp);
58
+ va_end(argp);
59
+ }
60
+ }
61
+
62
+ uint64_t Logger::getTimestamp() const {
63
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(
64
+ std::chrono::system_clock::now().time_since_epoch())
65
+ .count();
66
+ }
67
+
68
+ std::shared_ptr<::qnn::log::Logger> g_logger{nullptr};
69
+
70
+ bool qnn::log::initializeLogging() {
71
+ QnnLog_Level_t logLevel;
72
+ QnnLog_Error_t status;
73
+ #ifdef QNN_ENABLE_DEBUG
74
+ logLevel = QNN_LOG_LEVEL_DEBUG;
75
+ #else
76
+ logLevel = QNN_LOG_LEVEL_INFO;
77
+ #endif
78
+ // Default log stream is enabled in Core/Logger component
79
+ g_logger = ::qnn::log::Logger::createLogger(nullptr, logLevel, &status);
80
+ if (QNN_LOG_NO_ERROR != status || !g_logger) {
81
+ return false;
82
+ }
83
+ return true;
84
+ }
85
+
86
+ QnnLog_Callback_t qnn::log::getLogCallback() { return g_logger->getLogCallback(); }
87
+
88
+ QnnLog_Level_t qnn::log::getLogLevel() { return g_logger->getMaxLevel(); }
89
+
90
+ bool qnn::log::isLogInitialized() {
91
+ if (g_logger == nullptr) {
92
+ return false;
93
+ }
94
+ return true;
95
+ }
96
+
97
+ bool qnn::log::setLogLevel(QnnLog_Level_t maxLevel) {
98
+ if (!::qnn::log::Logger::isValid() ||
99
+ !(maxLevel >= QNN_LOG_LEVEL_ERROR && maxLevel <= QNN_LOG_LEVEL_DEBUG)) {
100
+ return false;
101
+ }
102
+
103
+ g_logger->setMaxLevel(maxLevel);
104
+ return true;
105
+ }
SampleApp/src/Log/Logger.hpp ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2020-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #pragma once
10
+
11
+ #include <atomic>
12
+ #include <cstdarg>
13
+ #include <cstring>
14
+ #include <memory>
15
+ #include <mutex>
16
+
17
+ #include "QnnLog.h"
18
+
19
+ #define __FILENAME__ (strrchr(__FILE__, '/') + 1)
20
+
21
+ /**
22
+ * @brief Log something with the current logger. Always valid to call, though
23
+ * it won't do something if no logger has been set.
24
+ */
25
+
26
+ #define QNN_LOG_LEVEL(level, fmt, ...) \
27
+ do { \
28
+ auto logger = ::qnn::log::Logger::getLogger(); \
29
+ if (logger) { \
30
+ logger->log(level, __FILENAME__, __LINE__, fmt, ##__VA_ARGS__); \
31
+ } \
32
+ } while (0)
33
+
34
+ #define QNN_ERROR(fmt, ...) QNN_LOG_LEVEL(QNN_LOG_LEVEL_ERROR, fmt, ##__VA_ARGS__)
35
+
36
+ #define QNN_ERROR_EXIT(fmt, ...) \
37
+ { \
38
+ QNN_ERROR(fmt, ##__VA_ARGS__); \
39
+ exit(EXIT_FAILURE); \
40
+ }
41
+
42
+ #define QNN_WARN(fmt, ...) QNN_LOG_LEVEL(QNN_LOG_LEVEL_WARN, fmt, ##__VA_ARGS__)
43
+
44
+ #define QNN_INFO(fmt, ...) QNN_LOG_LEVEL(QNN_LOG_LEVEL_INFO, fmt, ##__VA_ARGS__)
45
+
46
+ #define QNN_DEBUG(fmt, ...) QNN_LOG_LEVEL(QNN_LOG_LEVEL_DEBUG, fmt, ##__VA_ARGS__)
47
+
48
+ #define QNN_VERBOSE(fmt, ...) QNN_LOG_LEVEL(QNN_LOG_LEVEL_VERBOSE, fmt, ##__VA_ARGS__)
49
+
50
+ #define QNN_FUNCTION_ENTRY_LOG QNN_LOG_LEVEL(QNN_LOG_LEVEL_VERBOSE, "Entering %s", __func__)
51
+
52
+ #define QNN_FUNCTION_EXIT_LOG QNN_LOG_LEVEL(QNN_LOG_LEVEL_VERBOSE, "Returning from %s", __func__)
53
+
54
+ namespace qnn {
55
+ namespace log {
56
+
57
+ bool initializeLogging();
58
+
59
+ QnnLog_Callback_t getLogCallback();
60
+
61
+ QnnLog_Level_t getLogLevel();
62
+
63
+ bool isLogInitialized();
64
+
65
+ bool setLogLevel(QnnLog_Level_t maxLevel);
66
+
67
+ class Logger final {
68
+ public:
69
+ Logger(const Logger&) = delete;
70
+ Logger& operator=(const Logger&) = delete;
71
+ Logger(Logger&&) = delete;
72
+ Logger& operator=(Logger&&) = delete;
73
+
74
+ void setMaxLevel(QnnLog_Level_t maxLevel) {
75
+ m_maxLevel.store(maxLevel, std::memory_order_seq_cst);
76
+ }
77
+
78
+ QnnLog_Level_t getMaxLevel() { return m_maxLevel.load(std::memory_order_seq_cst); }
79
+
80
+ QnnLog_Callback_t getLogCallback() { return m_callback; }
81
+
82
+ void log(QnnLog_Level_t level, const char* file, long line, const char* fmt, ...);
83
+
84
+ static std::shared_ptr<Logger> createLogger(QnnLog_Callback_t callback,
85
+ QnnLog_Level_t maxLevel,
86
+ QnnLog_Error_t* status);
87
+
88
+ static bool isValid() { return (s_logger != nullptr); }
89
+
90
+ static std::shared_ptr<Logger> getLogger() { return s_logger; }
91
+
92
+ static void reset() { s_logger = nullptr; }
93
+
94
+ private:
95
+ Logger(QnnLog_Callback_t callback, QnnLog_Level_t maxLevel, QnnLog_Error_t* status);
96
+
97
+ uint64_t getTimestamp() const;
98
+
99
+ QnnLog_Callback_t m_callback;
100
+ std::atomic<QnnLog_Level_t> m_maxLevel;
101
+ uint64_t m_epoch;
102
+ static std::shared_ptr<Logger> s_logger;
103
+ static std::mutex s_logMutex;
104
+ };
105
+
106
+ } // namespace log
107
+ } // namespace qnn
SampleApp/src/PAL/include/PAL/Debug.hpp ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //============================================================================
2
+ //
3
+ // Copyright (c) 2020-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //============================================================================
8
+
9
+ #pragma once
10
+
11
+ #define DEBUG_ON 0
12
+
13
+ #if DEBUG_ON
14
+ #define DEBUG_MSG(...) \
15
+ { \
16
+ fprintf(stderr, __VA_ARGS__); \
17
+ fprintf(stderr, "\n"); \
18
+ }
19
+ #else
20
+ #define DEBUG_MSG(...)
21
+ #endif
SampleApp/src/PAL/include/PAL/Directory.hpp ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2008-2014, 2020-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ //---------------------------------------------------------------------------
10
+ /// @file
11
+ /// This file includes APIs for directory operations on supported platforms
12
+ //---------------------------------------------------------------------------
13
+
14
+ #pragma once
15
+
16
+ #include <string>
17
+
18
+ #include "PAL/FileOp.hpp"
19
+
20
+ namespace pal {
21
+ class Directory;
22
+ }
23
+
24
+ class pal::Directory {
25
+ public:
26
+ using DirMode = pal::FileOp::FileMode;
27
+ //---------------------------------------------------------------------------
28
+ /// @brief
29
+ /// Creates a directory in the file system.
30
+ /// @param path
31
+ /// Name of directory to create.
32
+ /// @param dirmode
33
+ /// Directory mode
34
+ /// @return
35
+ /// True if
36
+ /// 1. create a directory successfully
37
+ /// 2. or directory exist already
38
+ /// False otherwise
39
+ ///
40
+ /// For example:
41
+ ///
42
+ /// - Create a directory in default.
43
+ /// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
44
+ /// pal::Directory::Create(path, pal::Directory::DirMode::S_DEFAULT_);
45
+ /// pal::Directory::Create(path);
46
+ /// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47
+ ///
48
+ /// - Create a directory with specific permission.
49
+ /// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
50
+ /// pal::Directory::Create(path, pal::Directory::DirMode::S_IRWXU_|
51
+ /// pal::Directory::DirMode::S_IRWXG_|
52
+ /// pal::Directory::DirMode::S_IRWXO_);
53
+ /// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
54
+ ///
55
+ /// @note For windows, dirmode is not used.
56
+ /// @note For linux, dirmode is used to set the permission of the folder.
57
+ //---------------------------------------------------------------------------
58
+ static bool create(const std::string &path,
59
+ pal::Directory::DirMode dirmode = pal::Directory::DirMode::S_DEFAULT_);
60
+
61
+ //---------------------------------------------------------------------------
62
+ /// @brief
63
+ /// Removes the entire directory whether it's empty or not.
64
+ /// @param path
65
+ /// Name of directory to delete.
66
+ /// @return
67
+ /// True if the directory was successfully deleted, false otherwise.
68
+ //---------------------------------------------------------------------------
69
+ static bool remove(const std::string &path);
70
+
71
+ //---------------------------------------------------------------------------
72
+ /// @brief
73
+ /// Creates a directory and all parent directories required.
74
+ /// @param path
75
+ /// Path of directory to create.
76
+ /// @return
77
+ /// True if the directory was successfully created, false otherwise.
78
+ //---------------------------------------------------------------------------
79
+ static bool makePath(const std::string &path);
80
+ };
SampleApp/src/PAL/include/PAL/DynamicLoading.hpp ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2020-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ //---------------------------------------------------------------------------
10
+ /// @file
11
+ /// This file includes APIs for dynamic loading on supported platforms
12
+ //---------------------------------------------------------------------------
13
+
14
+ #pragma once
15
+
16
+ #include <string>
17
+
18
+ namespace pal {
19
+ namespace dynamicloading {
20
+ // we only support subset of POSIX of dlopen/dlsym/dladdr/dlerror/dlclose
21
+ // except the following flags for dlopen, others should be done only
22
+ // when we really need them
23
+ // DL_NOW is MUST
24
+ // DL_LOCAL is enabled if not specified
25
+ enum {
26
+ DL_NOW = 0x0001,
27
+ DL_LOCAL = 0x0002,
28
+ DL_GLOBAL = 0x0004,
29
+ };
30
+
31
+ // specify this address to distingiush from NULL pointer
32
+ #define DL_DEFAULT (void *)(0x4)
33
+
34
+ //---------------------------------------------------------------------------
35
+ /// @brief
36
+ /// Loads the dynamic shared object
37
+ /// @param filename
38
+ /// If contains path separators, treat it as relative or absolute pathname
39
+ /// or search it for the rule of dynamic linker
40
+ /// @param flags
41
+ /// - DL_NOW: resolve undefined symbols before return. MUST be specified.
42
+ /// - DL_LOCAL: optional, but the default specified. Symbols defined in this
43
+ /// shared object are not made available to resolve references in subsequently
44
+ /// loaded shared objects
45
+ /// - DL_GLOBAL: optional, resolve symbol globally
46
+ /// @return
47
+ /// On success, a non-NULL handle for the loaded library.
48
+ /// On error, NULL
49
+ //---------------------------------------------------------------------------
50
+ void *dlOpen(const char *filename, int flags);
51
+
52
+ //---------------------------------------------------------------------------
53
+ /// @brief
54
+ /// Obtain address of a symbol in a shared object or executable
55
+ /// @param handle
56
+ /// A handle of a dynamic loaded shared object returned by dlopen
57
+ /// @param symbol
58
+ /// A null-terminated symbol name
59
+ /// @return
60
+ /// On success, return the address associated with symbol
61
+ /// On error, NULL
62
+ //---------------------------------------------------------------------------
63
+ void *dlSym(void *handle, const char *symbol);
64
+
65
+ //---------------------------------------------------------------------------
66
+ /// @brief
67
+ /// Translate the address of a symbol to the path of the belonging shared object
68
+ /// @param addr
69
+ /// Address of symbol in a shared object
70
+ /// @param path
71
+ /// Full name of shared object that contains address, usually it is an absolute path
72
+ /// @return
73
+ /// On success, return a non-zero value
74
+ /// On error, return 0
75
+ //---------------------------------------------------------------------------
76
+ int dlAddrToLibName(void *addr, std::string &name);
77
+
78
+ //---------------------------------------------------------------------------
79
+ /// @brief
80
+ /// Decrements the reference count on the dynamically loaded shared object
81
+ /// referred to by handle. If the reference count drops to 0, then the
82
+ /// object is unloaded.
83
+ /// @return
84
+ /// On success, 0; on error, a nonzero value
85
+ //---------------------------------------------------------------------------
86
+ int dlClose(void *handle);
87
+
88
+ //---------------------------------------------------------------------------
89
+ /// @brief
90
+ /// Obtain error diagnostic for functions in the dl-family APIs.
91
+ /// @return
92
+ /// Returns a human-readable, null-terminated string describing the most
93
+ /// recent error that occurred from a call to one of the functions in the
94
+ /// dl-family APIs.
95
+ //---------------------------------------------------------------------------
96
+ char *dlError(void);
97
+
98
+ } // namespace dynamicloading
99
+ } // namespace pal
SampleApp/src/PAL/include/PAL/FileOp.hpp ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2008-2023 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ //------------------------------------------------------------------------------
10
+ /// @file
11
+ /// This file includes APIs for file operations on the supported platforms
12
+ //------------------------------------------------------------------------------
13
+
14
+ #pragma once
15
+
16
+ #include <fcntl.h>
17
+
18
+ #include <cstdint>
19
+ #include <string>
20
+ #include <vector>
21
+
22
+ namespace pal {
23
+ class FileOp;
24
+ }
25
+
26
+ //------------------------------------------------------------------------------
27
+ /// @brief
28
+ /// FileOp contains OS Specific file system functionality.
29
+ //------------------------------------------------------------------------------
30
+ class pal::FileOp {
31
+ public:
32
+ // enum for symbolic constants mode, strictly follow linux usage
33
+ // windows or another OS user should transfer the usage
34
+ // ref : http://man7.org/linux/man-pages/man2/open.2.html
35
+ enum class FileMode : uint32_t {
36
+ S_DEFAULT_ = 0777,
37
+ S_IRWXU_ = 0700,
38
+ S_IRUSR_ = 0400,
39
+ S_IWUSR_ = 0200,
40
+ S_IXUSR_ = 0100,
41
+ S_IRWXG_ = 0070,
42
+ S_IRGRP_ = 0040,
43
+ S_IWGRP_ = 0020,
44
+ S_IXGRP_ = 0010,
45
+ S_IRWXO_ = 0007,
46
+ S_IROTH_ = 0004,
47
+ S_IWOTH_ = 0002,
48
+ S_IXOTH_ = 0001
49
+ };
50
+
51
+ //---------------------------------------------------------------------------
52
+ /// @brief
53
+ /// Copies a file from one location to another, overwrites if the
54
+ /// destination already exists.
55
+ /// @param source
56
+ /// File name of the source file.
57
+ /// @param target
58
+ /// File name of the target file.
59
+ /// @return
60
+ /// True on success, otherwise false.
61
+ //---------------------------------------------------------------------------
62
+ static bool copyOverFile(const std::string &source, const std::string &target);
63
+
64
+ //---------------------------------------------------------------------------
65
+ /// @brief
66
+ /// Checks whether the file exists or not.
67
+ /// @param fileName
68
+ /// File name of the source file, including its complete path.
69
+ /// @return
70
+ /// True on success, otherwise false.
71
+ //---------------------------------------------------------------------------
72
+ static bool checkFileExists(const std::string &fileName);
73
+
74
+ //---------------------------------------------------------------------------
75
+ /// @brief
76
+ /// Renames an existing file. If the file with target name exists, this call
77
+ /// overwrites it with the file with source name.
78
+ /// @param source
79
+ /// Current File name.
80
+ /// @param target
81
+ /// New name of the file.
82
+ /// @param overwrite
83
+ /// Flag indicating to overwrite existing file with newName
84
+ /// @return
85
+ /// True if successful, otherwise false.
86
+ /// @warning
87
+ /// Does not work if source and target are on different filesystems.
88
+ //---------------------------------------------------------------------------
89
+ static bool move(const std::string &source, const std::string &target, bool overwrite);
90
+
91
+ //---------------------------------------------------------------------------
92
+ /// @brief
93
+ /// Delete an existing file
94
+ /// @param fileName
95
+ /// File name of the file to be deleted.
96
+ /// @return
97
+ /// True if successful, otherwise false.
98
+ //---------------------------------------------------------------------------
99
+ static bool deleteFile(const std::string &fileName);
100
+
101
+ //---------------------------------------------------------------------------
102
+ /// @brief
103
+ /// Check if path is a directory or not
104
+ /// @param path
105
+ /// Path to check
106
+ /// @return
107
+ /// True if successful, otherwise false.
108
+ //---------------------------------------------------------------------------
109
+ static bool checkIsDir(const std::string &path);
110
+
111
+ //---------------------------------------------------------------------------
112
+ /// @brief Data type representing parts of a filename
113
+ //---------------------------------------------------------------------------
114
+ typedef struct {
115
+ //---------------------------------------------------------------------------
116
+ /// @brief Name of the file without the extension (i.e., basename)
117
+ //---------------------------------------------------------------------------
118
+ std::string basename;
119
+
120
+ //---------------------------------------------------------------------------
121
+ /// @brief Name of the file extension (i.e., .txt or .hlnd, .html)
122
+ //---------------------------------------------------------------------------
123
+ std::string extension;
124
+
125
+ //---------------------------------------------------------------------------
126
+ /// @brief
127
+ /// Location of the file (i.e., /abc/xyz/foo.bar <-- /abc/xyz/).
128
+ /// If the file name has no location then the Directory points to
129
+ /// empty string
130
+ //---------------------------------------------------------------------------
131
+ std::string directory;
132
+ } FilenamePartsType_t;
133
+
134
+ //---------------------------------------------------------------------------
135
+ /// @brief
136
+ /// Determines the components of a given filename, being the directory,
137
+ /// basename and extension. If the file has no location or extension, these
138
+ /// components remain empty
139
+ /// @param filename
140
+ /// Path of the file for which the components are to be determined
141
+ /// @param filenameParts
142
+ /// Will contain the file name components when this function returns
143
+ /// @return
144
+ /// True if successful, false otherwise
145
+ //---------------------------------------------------------------------------
146
+ static bool getFileInfo(const std::string &filename, FilenamePartsType_t &filenameParts);
147
+
148
+ //---------------------------------------------------------------------------
149
+ /// @brief
150
+ /// Typedef for a vector of FilenamePartsType_t
151
+ //---------------------------------------------------------------------------
152
+ typedef std::vector<FilenamePartsType_t> FilenamePartsListType_t;
153
+
154
+ //---------------------------------------------------------------------------
155
+ /// @brief
156
+ /// Typedef for a vector of FilenamePartsType_t const iterator
157
+ //---------------------------------------------------------------------------
158
+ typedef std::vector<FilenamePartsType_t>::const_iterator FilenamePartsListTypeIter_t;
159
+
160
+ //---------------------------------------------------------------------------
161
+ /// @brief
162
+ /// Returns a vector of FilenamePartsType_t objects for a given directory
163
+ /// @param path
164
+ /// Path to scan for files
165
+ /// @return
166
+ /// True if successful, false otherwise
167
+ //---------------------------------------------------------------------------
168
+ static bool getFileInfoList(const std::string &path, FilenamePartsListType_t &filenamePartsList);
169
+
170
+ //---------------------------------------------------------------------------
171
+ /// @brief
172
+ /// Returns a vector of FilenamePartsType_t objects for a given directory
173
+ /// and the child directories inside.
174
+ /// @param path
175
+ /// Path to directory to scan for files for
176
+ /// @note if path is not a directory - the function will return false
177
+ /// @param filenamePartList
178
+ /// List to append to
179
+ /// @param ignoreDirs
180
+ /// If this flag is set to true, directories (and symbolic links to directories)
181
+ /// are not included in the list. Only actual files below the specified
182
+ /// directory path will be appended.
183
+ /// @return True if successful, false otherwise
184
+ /// @note Directories in list only populate Directory member variable of the struct.
185
+ /// That is Basename and Extension will be empty strings.
186
+ /// @note Symbolic links to directories are not followed. This is to avoid possible
187
+ /// infinite recursion. However the initial call to this method can have
188
+ /// path to be a symbolic link to a directory. If ignoreDirs is true,
189
+ /// symbolic links to directories are also ignored.
190
+ /// @note The order in which the files/directories are listed is platform
191
+ /// dependent. However files inside a directory always come before the
192
+ /// directory itself.
193
+ //---------------------------------------------------------------------------
194
+ static bool getFileInfoListRecursive(const std::string &path,
195
+ FilenamePartsListType_t &filenamePartsList,
196
+ const bool ignoreDirs);
197
+
198
+ //---------------------------------------------------------------------------
199
+ /// @brief
200
+ /// Create an absolute path from the supplied path
201
+ /// @param path
202
+ /// Path should not contain trailing '/' or '\\'
203
+ /// @return
204
+ /// Return absolute path without trailing '/' or '\\'
205
+ //---------------------------------------------------------------------------
206
+ static std::string getAbsolutePath(const std::string &path);
207
+
208
+ //---------------------------------------------------------------------------
209
+ /// @brief Get the file name from a path
210
+ //---------------------------------------------------------------------------
211
+ static std::string getFileName(const std::string &file);
212
+
213
+ //---------------------------------------------------------------------------
214
+ /// @brief Get the directory path to a file
215
+ //---------------------------------------------------------------------------
216
+ static std::string getDirectory(const std::string &file);
217
+
218
+ //---------------------------------------------------------------------------
219
+ /// @brief Get the current working directory.
220
+ /// @returns The absolute CWD or empty string if the path could not be
221
+ /// retrieved (because it was too long or deleted for example).
222
+ //---------------------------------------------------------------------------
223
+ static std::string getCurrentWorkingDirectory();
224
+
225
+ //---------------------------------------------------------------------------
226
+ /// @brief Set the current working directory
227
+ //---------------------------------------------------------------------------
228
+ static bool setCurrentWorkingDirectory(const std::string &workingDir);
229
+
230
+ //---------------------------------------------------------------------------
231
+ /// @brief Returns true if the file contains any extension or false.
232
+ //---------------------------------------------------------------------------
233
+ static bool hasFileExtension(const std::string &file);
234
+
235
+ //---------------------------------------------------------------------------
236
+ /// @brief Returns full path of file, Directory/Basename(.Extension, if any)
237
+ //---------------------------------------------------------------------------
238
+ static std::string partsToString(const FilenamePartsType_t &filenameParts);
239
+ };
SampleApp/src/PAL/include/PAL/GetOpt.hpp ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2020-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ //--------------------------------------------------------------------------------
10
+ /// @file
11
+ /// This file includes APIs for the command line parsing on supported platforms
12
+ //--------------------------------------------------------------------------------
13
+
14
+ #pragma once
15
+
16
+ namespace pal {
17
+ // we implement a similar API for POSIX.2
18
+ // so that some global var are necessary
19
+
20
+ extern const char *g_optArg;
21
+ extern int g_optInd;
22
+
23
+ enum {
24
+ no_argument = 0,
25
+ required_argument = 1,
26
+ optional_argument = 2,
27
+ };
28
+
29
+ //--------------------------------------------------------------------------------------------------
30
+ /// @brief
31
+ /// This structure describes a single long option name for the sake of getopt_long. The argument
32
+ /// longopts must be an array of these structures, one for each long option. Terminate the array
33
+ /// with an element containing all zeros.
34
+ //--------------------------------------------------------------------------------------------------
35
+ struct Option {
36
+ //--------------------------------------------------------------------------------------------------
37
+ /// @brief The name of the long option.
38
+ //--------------------------------------------------------------------------------------------------
39
+ const char *name;
40
+
41
+ //--------------------------------------------------------------------------------------------------
42
+ /// @brief
43
+ /// If the option does not take an argument, no_argument (or 0).
44
+ /// If the option requires an argument, required_argument (or 1).
45
+ //--------------------------------------------------------------------------------------------------
46
+ int hasArg;
47
+
48
+ //--------------------------------------------------------------------------------------------------
49
+ /// @brief
50
+ /// Specifies how results are returned for a long option.
51
+ /// If flag is NULL, then GetOptLongOnly() returns val. Otherwise, it returns 0, and flag
52
+ /// points to a variable which is set to val if the option is found, but
53
+ /// left unchanged if the option is not found.
54
+ //--------------------------------------------------------------------------------------------------
55
+ int *flag;
56
+
57
+ //--------------------------------------------------------------------------------------------------
58
+ /// @brief
59
+ /// The value to return, or to load into the variable pointed to by flag.
60
+ /// The last element of the array has to be filled with zeros.
61
+ //--------------------------------------------------------------------------------------------------
62
+ int val;
63
+ };
64
+
65
+ //--------------------------------------------------------------------------------------------------
66
+ /// @brief
67
+ /// This parses command-line options as POSIX getopt_long_only()
68
+ /// but we don't support optstring and optonal_argument now
69
+ /// @param argc
70
+ /// Argument count
71
+ /// @param argv
72
+ /// Argument array
73
+ /// @param optstring
74
+ /// Legitimate option characters, short options, don't support now
75
+ /// @param longopts
76
+ /// A pointer to the first element of an array of struct option,
77
+ /// has_arg field in the struct option indicates 3 possibilities,
78
+ /// no_argument, required_argument or optional_argument. we don't
79
+ /// support optional_argument now
80
+ /// @param longindex
81
+ /// If longindex is not NULL, it points to a variable which is set
82
+ /// to the index of the long option relative to longopts
83
+ /// @return
84
+ /// -1 for parsing done, '?' for non-recognized arguments, 0 for
85
+ /// flag in longopts is not NULL and saved the val to it
86
+ //--------------------------------------------------------------------------------------------------
87
+ int getOptLongOnly(int argc,
88
+ const char *const argv[],
89
+ const char *optstring,
90
+ const struct Option *longopts,
91
+ int *longindex);
92
+
93
+ } // namespace pal
SampleApp/src/PAL/include/PAL/Path.hpp ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2008-2014, 2020-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //==============================================================================
7
+
8
+ //------------------------------------------------------------------------------
9
+ /// @file
10
+ /// The file includes APIs for path related operations on supported platforms
11
+ //------------------------------------------------------------------------------
12
+
13
+ #pragma once
14
+
15
+ #include <string>
16
+ #include <vector>
17
+
18
+ namespace pal {
19
+ class Path;
20
+ }
21
+
22
+ class pal::Path {
23
+ public:
24
+ //---------------------------------------------------------------------------
25
+ /// @brief Returns path separator for the system
26
+ //---------------------------------------------------------------------------
27
+ static char getSeparator();
28
+
29
+ //---------------------------------------------------------------------------
30
+ /// @brief Concatenate s1 and s2
31
+ //---------------------------------------------------------------------------
32
+ static std::string combine(const std::string &s1, const std::string &s2);
33
+
34
+ //---------------------------------------------------------------------------
35
+ /// @brief Get the directory name
36
+ //---------------------------------------------------------------------------
37
+ static std::string getDirectoryName(const std::string &path);
38
+
39
+ //---------------------------------------------------------------------------
40
+ /// @brief Get absolute path
41
+ //---------------------------------------------------------------------------
42
+ static std::string getAbsolute(const std::string &path);
43
+
44
+ //---------------------------------------------------------------------------
45
+ /// @brief Check if the input path is absolute path
46
+ //---------------------------------------------------------------------------
47
+ static bool isAbsolute(const std::string &path);
48
+
49
+ private:
50
+ };
SampleApp/src/PAL/include/PAL/StringOp.hpp ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2018-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ //-----------------------------------------------------------------------------
10
+ /// @file
11
+ /// The file inludes APIs for string operations on supported platforms
12
+ //-----------------------------------------------------------------------------
13
+
14
+ #pragma once
15
+
16
+ #include <sys/types.h>
17
+
18
+ namespace pal {
19
+ class StringOp;
20
+ }
21
+
22
+ //------------------------------------------------------------------------------
23
+ /// @brief
24
+ /// FileOp contains OS Specific file system functionality.
25
+ //------------------------------------------------------------------------------
26
+ class pal::StringOp {
27
+ public:
28
+ //---------------------------------------------------------------------------
29
+ /// @brief
30
+ /// Copy copy_size bytes from buffer src to buffer dst. Behaviour of the
31
+ /// function is undefined if src and dst overlap.
32
+ /// @param dst
33
+ /// Destination buffer
34
+ /// @param dst_size
35
+ /// Size of destination buffer
36
+ /// @param src
37
+ /// Source buffer
38
+ /// @param copy_size
39
+ /// Number of bytes to copy
40
+ /// @return
41
+ /// Number of bytes copied
42
+ //---------------------------------------------------------------------------
43
+ static size_t memscpy(void *dst, size_t dstSize, const void *src, size_t copySize);
44
+
45
+ //---------------------------------------------------------------------------
46
+ /// @brief
47
+ /// Returns a pointer to a null-terminated byte string, which contains copies
48
+ /// of at most size bytes from the string pointed to by str. If the null
49
+ /// terminator is not encountered in the first size bytes, it is added to the
50
+ /// duplicated string.
51
+ /// @param source
52
+ /// Source string
53
+ /// @param maxlen
54
+ /// Max number of bytes to copy from str
55
+ /// @return
56
+ /// A pointer to the newly allocated string, or a null pointer if an error
57
+ /// occurred.
58
+ //---------------------------------------------------------------------------
59
+ static char *strndup(const char *source, size_t maxlen);
60
+ };
SampleApp/src/PAL/src/common/GetOpt.cpp ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //=============================================================================
2
+ //
3
+ // Copyright (c) 2020-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //=============================================================================
8
+
9
+ #include <string.h>
10
+
11
+ #include <string>
12
+
13
+ #include "PAL/GetOpt.hpp"
14
+
15
+ using namespace std;
16
+
17
+ namespace pal {
18
+
19
+ const char *g_optArg = nullptr;
20
+ int g_optInd = 1;
21
+
22
+ static const struct Option *findOpt(const string str,
23
+ const struct Option *longopts,
24
+ int *longindex) {
25
+ const struct Option *opt = nullptr;
26
+ int idx = 0;
27
+ size_t searchEnd = str.find_first_of("=");
28
+
29
+ for (opt = longopts; opt->name && strlen(opt->name) > 0; opt++, idx++) {
30
+ if (str.substr(0, searchEnd) == opt->name) {
31
+ if (longindex) {
32
+ *longindex = idx;
33
+ }
34
+ break;
35
+ }
36
+ }
37
+ // if not found, opt would point to the last element of longopts
38
+ // whose name MUST be empty
39
+ return opt->name ? opt : nullptr;
40
+ }
41
+
42
+ int getOptLongOnly(int argc,
43
+ const char *const argv[],
44
+ const char *,
45
+ const struct Option *longopts,
46
+ int *longindex) {
47
+ const struct Option *opt;
48
+ int argLen = 0;
49
+ bool isShort = false;
50
+ const char *arg = "";
51
+
52
+ g_optArg = nullptr;
53
+ // no arg, means the end of command
54
+ if (g_optInd >= argc) {
55
+ return -1;
56
+ }
57
+
58
+ arg = argv[g_optInd];
59
+
60
+ if (arg[0] != '-') {
61
+ g_optInd += 1;
62
+ return '?';
63
+ }
64
+
65
+ argLen = strlen(arg);
66
+
67
+ if (argLen < 2) {
68
+ g_optInd += 1;
69
+ return '?';
70
+ }
71
+
72
+ if (!longopts) {
73
+ g_optInd += 1;
74
+ return '?';
75
+ }
76
+
77
+ // check short options with this form, -a arg
78
+ if (argLen == 2) {
79
+ isShort = true;
80
+ // check short options with this form, -a=arg
81
+ } else if (argLen > 3 && arg[2] == '=') {
82
+ isShort = true;
83
+ // check for long options, can be used for both forms
84
+ } else if (argLen > 2 && arg[1] != '=') {
85
+ if (arg[1] != '-') {
86
+ g_optInd += 1;
87
+ return '?';
88
+ }
89
+ isShort = false;
90
+ }
91
+
92
+ // start after -- to find the option
93
+ const char *const optStr = isShort ? &arg[1] : &arg[2];
94
+ opt = findOpt(optStr, longopts, longindex);
95
+ if (!opt) {
96
+ g_optInd += 1;
97
+ return '?';
98
+ }
99
+
100
+ if (opt->hasArg == no_argument) {
101
+ g_optInd += 1;
102
+
103
+ if (!opt->flag) {
104
+ return opt->val;
105
+ } else {
106
+ *(opt->flag) = opt->val;
107
+ return 0;
108
+ }
109
+ }
110
+
111
+ if (opt->hasArg == required_argument) {
112
+ string optStr = argv[g_optInd];
113
+ size_t assignIdx = optStr.find_first_of("=");
114
+ bool advance = (assignIdx == string::npos);
115
+
116
+ // if it is --opt arg form, this will be true,
117
+ // so we need to advance one step to get arg
118
+ // otherwise, need to stop advance step & extract arg from argv[g_optInd]
119
+ if (advance) {
120
+ g_optInd += 1;
121
+ }
122
+
123
+ if (g_optInd >= argc) {
124
+ return '?';
125
+ } else {
126
+ // if advance, means it is the form --opt arg
127
+ // otherwise, the form, --opt=arg
128
+ if (advance) {
129
+ // since g_optInd is advanced, g_optArg can be assigned directly
130
+ g_optArg = argv[g_optInd];
131
+ } else {
132
+ if (assignIdx == optStr.size()) {
133
+ return '?';
134
+ }
135
+ // for not advanced form,
136
+ // g_optArg should point to the address right after "="
137
+ g_optArg = &argv[g_optInd][assignIdx + 1];
138
+ }
139
+ // OK, now we are ready to handle the next pair
140
+ g_optInd += 1;
141
+
142
+ if (!opt->flag) {
143
+ return opt->val;
144
+ } else {
145
+ *(opt->flag) = opt->val;
146
+ return 0;
147
+ }
148
+ }
149
+ }
150
+
151
+ return '?';
152
+ } // end of getOptLongOnly
153
+
154
+ } // namespace pal
SampleApp/src/PAL/src/common/StringOp.cpp ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2018-2022,2024 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #include <stdlib.h>
10
+ #include <string.h>
11
+
12
+ #include "PAL/StringOp.hpp"
13
+
14
+ //---------------------------------------------------------------------------
15
+ // pal::StringOp::memscpy
16
+ //---------------------------------------------------------------------------
17
+ size_t pal::StringOp::memscpy(void *dst, size_t dstSize, const void *src, size_t copySize) {
18
+ if (!dst || !src || !dstSize || !copySize) return 0;
19
+
20
+ size_t minSize = dstSize < copySize ? dstSize : copySize;
21
+
22
+ memcpy(dst, src, minSize);
23
+
24
+ return minSize;
25
+ }
26
+
27
+ #ifdef __hexagon__
28
+ size_t strnlen(const char *s, size_t n) {
29
+ size_t i;
30
+ for (i = 0; i < n && s[i] != '\0'; i++) continue;
31
+ return i;
32
+ }
33
+ #endif
34
+
35
+ //---------------------------------------------------------------------------
36
+ // pal::StringOp::strndup
37
+ //---------------------------------------------------------------------------
38
+ char *pal::StringOp::strndup(const char *source, size_t maxlen) {
39
+ #ifdef _WIN32
40
+ size_t length = ::strnlen(source, maxlen);
41
+
42
+ char *destination = (char *)malloc((length + 1) * sizeof(char));
43
+ if (destination == nullptr) return nullptr;
44
+
45
+ // copy length bytes to destination and leave destination[length] to be
46
+ // null terminator
47
+ strncpy_s(destination, length + 1, source, length);
48
+
49
+ return destination;
50
+ #elif __hexagon__
51
+ size_t length = strnlen(source, maxlen);
52
+
53
+ char *destination = (char *)malloc((length + 1) * sizeof(char));
54
+ if (destination == nullptr) return nullptr;
55
+ // copy length bytes to destination and leave destination[length] to be
56
+ // null terminator
57
+ strncpy(destination, source, length);
58
+ destination[length] = '\0';
59
+ return destination;
60
+ #else
61
+ return ::strndup(source, maxlen);
62
+ #endif
63
+ }
SampleApp/src/PAL/src/linux/Directory.cpp ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2008-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #include <fcntl.h>
10
+ #include <stdio.h>
11
+ #include <stdlib.h>
12
+ #ifndef __QNXNTO__
13
+ #include <sys/sendfile.h>
14
+ #endif
15
+ #include <dirent.h>
16
+ #include <errno.h>
17
+ #include <sys/stat.h>
18
+ #include <sys/types.h>
19
+ #include <unistd.h>
20
+
21
+ #include <cstring>
22
+ #include <sstream>
23
+ #include <string>
24
+ #include <vector>
25
+
26
+ #include "PAL/Directory.hpp"
27
+ #include "PAL/FileOp.hpp"
28
+ #include "PAL/Path.hpp"
29
+
30
+ //------------------------------------------------------------------------------
31
+ //------------------------------------------------------------------------------
32
+ #ifdef __QNXNTO__
33
+ static bool is_qnx_dir(const struct dirent *ep) {
34
+ struct dirent_extra *exp;
35
+ bool is_dir = false;
36
+
37
+ for (exp = _DEXTRA_FIRST(ep); _DEXTRA_VALID(exp, ep); exp = _DEXTRA_NEXT(exp)) {
38
+ if (exp->d_type == _DTYPE_STAT || exp->d_type == _DTYPE_LSTAT) {
39
+ struct stat *statbuff = &((dirent_extra_stat *)exp)->d_stat;
40
+ if (statbuff && S_ISDIR(statbuff->st_mode)) {
41
+ is_dir = true;
42
+ break;
43
+ }
44
+ }
45
+ }
46
+ return is_dir;
47
+ }
48
+ #endif
49
+
50
+ // ------------------------------------------------------------------------------
51
+ // pal::Directory::create
52
+ // ------------------------------------------------------------------------------
53
+ bool pal::Directory::create(const std::string &path, pal::Directory::DirMode dirmode) {
54
+ struct stat st;
55
+ int status = 0;
56
+ if (stat(path.c_str(), &st) != 0) {
57
+ // Directory does not exist
58
+ status = mkdir(path.c_str(), static_cast<mode_t>(dirmode));
59
+ } else if (!S_ISDIR(st.st_mode)) {
60
+ errno = ENOTDIR;
61
+ status = -1;
62
+ }
63
+ return (status == 0);
64
+ }
65
+
66
+ //------------------------------------------------------------------------------
67
+ //------------------------------------------------------------------------------
68
+ bool pal::Directory::remove(const std::string &dirName) {
69
+ DIR *dir;
70
+ struct dirent *entry;
71
+
72
+ dir = opendir(dirName.c_str());
73
+ if (dir == nullptr) {
74
+ // If the directory doesn't exist then just return true.
75
+ if (errno == ENOENT) {
76
+ return true;
77
+ }
78
+ return false;
79
+ }
80
+
81
+ #ifdef __QNXNTO__
82
+ if (dircntl(dir, D_SETFLAG, D_FLAG_STAT) == -1) {
83
+ return false;
84
+ }
85
+ #endif
86
+
87
+ // Recursively traverse the directory tree.
88
+ while ((entry = readdir(dir)) != nullptr) {
89
+ if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
90
+ std::stringstream ss;
91
+ ss << dirName << Path::getSeparator() << entry->d_name;
92
+ std::string path = ss.str();
93
+ #ifdef __QNXNTO__
94
+ if (is_qnx_dir(entry))
95
+ #else
96
+ if (entry->d_type == DT_DIR)
97
+ #endif
98
+ {
99
+ // It's a directory so we need to drill down into it and delete
100
+ // its contents.
101
+ if (!remove(path)) {
102
+ return false;
103
+ }
104
+ } else {
105
+ if (::remove(path.c_str())) {
106
+ return false;
107
+ }
108
+ }
109
+ }
110
+ }
111
+
112
+ closedir(dir);
113
+
114
+ if (::remove(dirName.c_str())) {
115
+ return false;
116
+ }
117
+
118
+ return true;
119
+ }
120
+
121
+ bool pal::Directory::makePath(const std::string &path) {
122
+ struct stat st;
123
+ bool rc = false;
124
+
125
+ if (path == ".") {
126
+ rc = true;
127
+ } else if (stat(path.c_str(), &st) == 0) {
128
+ if (st.st_mode & S_IFDIR) {
129
+ rc = true;
130
+ }
131
+ } else {
132
+ size_t offset = path.find_last_of(Path::getSeparator());
133
+ if (offset != std::string::npos) {
134
+ std::string newPath = path.substr(0, offset);
135
+ if (!makePath(newPath)) {
136
+ return false;
137
+ }
138
+ }
139
+
140
+ // There is a possible race condition, where a file/directory can be
141
+ // created in between the stat() above, and the mkdir() call here.
142
+ // So, ignore the return code from the mkdir() call, and then re-check
143
+ // for existence of the directory after it. Ensure both that it exists
144
+ // and that it is a directory - just like above.
145
+ mkdir(path.c_str(), 0777);
146
+
147
+ if ((stat(path.c_str(), &st) == 0) && (st.st_mode & S_IFDIR)) {
148
+ rc = true;
149
+ }
150
+ }
151
+
152
+ return rc;
153
+ }
SampleApp/src/PAL/src/linux/DynamicLoading.cpp ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2020-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #include <dlfcn.h>
10
+ #include <stdlib.h>
11
+
12
+ #include "PAL/Debug.hpp"
13
+ #include "PAL/DynamicLoading.hpp"
14
+
15
+ void *pal::dynamicloading::dlOpen(const char *filename, int flags) {
16
+ int realFlags = 0;
17
+
18
+ if (flags & DL_NOW) {
19
+ realFlags |= RTLD_NOW;
20
+ }
21
+
22
+ if (flags & DL_LOCAL) {
23
+ realFlags |= RTLD_LOCAL;
24
+ }
25
+
26
+ if (flags & DL_GLOBAL) {
27
+ realFlags |= RTLD_GLOBAL;
28
+ }
29
+
30
+ return ::dlopen(filename, realFlags);
31
+ }
32
+
33
+ void *pal::dynamicloading::dlSym(void *handle, const char *symbol) {
34
+ if (handle == DL_DEFAULT) {
35
+ return ::dlsym(RTLD_DEFAULT, symbol);
36
+ }
37
+
38
+ return ::dlsym(handle, symbol);
39
+ }
40
+
41
+ int pal::dynamicloading::dlAddrToLibName(void *addr, std::string &name) {
42
+ // Clean the output buffer
43
+ name = std::string();
44
+
45
+ // If the address is empty, return zero as treating failure
46
+ if (!addr) {
47
+ DEBUG_MSG("Input address is nullptr.");
48
+ return 0;
49
+ }
50
+
51
+ // Dl_info do not maintain the lifetime of its string members,
52
+ // it would be maintained by dlopen() and dlclose(),
53
+ // so we do not need to release it manually
54
+ Dl_info info;
55
+ int result = ::dladdr(addr, &info);
56
+
57
+ // If dladdr() successes, set name to the library name
58
+ if (result) {
59
+ name = std::string(info.dli_fname);
60
+ } else {
61
+ DEBUG_MSG("Input address could not be matched to a shared object.");
62
+ }
63
+
64
+ return result;
65
+ }
66
+
67
+ int pal::dynamicloading::dlClose(void *handle) {
68
+ if (!handle) {
69
+ return 0;
70
+ }
71
+
72
+ return ::dlclose(handle);
73
+ }
74
+
75
+ char *pal::dynamicloading::dlError(void) { return ::dlerror(); }
SampleApp/src/PAL/src/linux/FileOp.cpp ADDED
@@ -0,0 +1,356 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2008-2013,2015,2019-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #include <fcntl.h>
10
+ #include <stdio.h>
11
+ #include <stdlib.h>
12
+ #ifndef __QNXNTO__
13
+ #include <sys/sendfile.h>
14
+ #endif
15
+ #include <dirent.h>
16
+ #include <errno.h>
17
+ #include <limits.h>
18
+ #include <sys/file.h>
19
+ #include <sys/stat.h>
20
+ #include <sys/types.h>
21
+ #include <unistd.h>
22
+
23
+ #include <cstring>
24
+ #include <iostream>
25
+ #include <limits>
26
+ #include <sstream>
27
+ #include <string>
28
+ #include <vector>
29
+
30
+ #include "PAL/Debug.hpp"
31
+ #include "PAL/FileOp.hpp"
32
+ #include "PAL/Path.hpp"
33
+
34
+ typedef struct stat Stat_t;
35
+
36
+ //---------------------------------------------------------------------------
37
+ // pal::FileOp::HasFileExtension
38
+ //---------------------------------------------------------------------------
39
+ bool pal::FileOp::checkFileExists(const std::string& fileName) {
40
+ Stat_t sb;
41
+
42
+ if (stat(fileName.c_str(), &sb) == -1) {
43
+ return false;
44
+ } else {
45
+ return true;
46
+ }
47
+ }
48
+
49
+ //---------------------------------------------------------------------------
50
+ // pal::FileOp::move
51
+ //---------------------------------------------------------------------------
52
+ bool pal::FileOp::move(const std::string& currentName, const std::string& newName, bool overwrite) {
53
+ if (overwrite) {
54
+ remove(newName.c_str());
55
+ }
56
+ return (rename(currentName.c_str(), newName.c_str()) == 0);
57
+ }
58
+
59
+ //---------------------------------------------------------------------------
60
+ // pal::FileOp::deleteFile
61
+ //---------------------------------------------------------------------------
62
+ bool pal::FileOp::deleteFile(const std::string& fileName) {
63
+ return (remove(fileName.c_str()) == 0);
64
+ }
65
+
66
+ //------------------------------------------------------------------------------
67
+ // pal::FileOp::checkIsDir
68
+ //------------------------------------------------------------------------------
69
+ bool pal::FileOp::checkIsDir(const std::string& fileName) {
70
+ bool retVal = false;
71
+ Stat_t sb;
72
+ if (stat(fileName.c_str(), &sb) == 0) {
73
+ if (sb.st_mode & S_IFDIR) {
74
+ retVal = true;
75
+ }
76
+ }
77
+ return retVal;
78
+ }
79
+
80
+ //------------------------------------------------------------------------------
81
+ // pal::FileOp::getFileInfo
82
+ //------------------------------------------------------------------------------
83
+ bool pal::FileOp::getFileInfo(const std::string& filename,
84
+ pal::FileOp::FilenamePartsType_t& filenameParts) {
85
+ std::string name;
86
+
87
+ // Clear the result
88
+ filenameParts.basename.clear();
89
+ filenameParts.extension.clear();
90
+ filenameParts.directory.clear();
91
+
92
+ size_t lastPathSeparator = filename.find_last_of(Path::getSeparator());
93
+ if (lastPathSeparator == std::string::npos) {
94
+ // No directory
95
+ name = filename;
96
+ } else {
97
+ // has a directory part
98
+ filenameParts.directory = filename.substr(0, lastPathSeparator);
99
+ name = filename.substr(lastPathSeparator + 1);
100
+ }
101
+
102
+ size_t ext = name.find_last_of(".");
103
+ if (ext == std::string::npos) {
104
+ // no extension
105
+ filenameParts.basename = name;
106
+ } else {
107
+ // has extension
108
+ filenameParts.basename = name.substr(0, ext);
109
+ filenameParts.extension = name.substr(ext + 1);
110
+ }
111
+
112
+ return true;
113
+ }
114
+
115
+ //---------------------------------------------------------------------------
116
+ // pal::FileOp::copyOverFile
117
+ //---------------------------------------------------------------------------
118
+ bool pal::FileOp::copyOverFile(const std::string& fromFile, const std::string& toFile) {
119
+ bool rc = false;
120
+ int readFd;
121
+ int writeFd;
122
+ struct stat statBuf;
123
+
124
+ // Open the input file.
125
+ readFd = ::open(fromFile.c_str(), O_RDONLY);
126
+ if (readFd == -1) {
127
+ close(readFd);
128
+ return false;
129
+ }
130
+
131
+ // Stat the input file to obtain its size. */
132
+ if (fstat(readFd, &statBuf) != 0) {
133
+ close(readFd);
134
+ return false;
135
+ }
136
+
137
+ // Open the output file for writing, with the same permissions as the input
138
+ writeFd = ::open(toFile.c_str(), O_WRONLY | O_CREAT | O_TRUNC, statBuf.st_mode);
139
+ if (writeFd == -1) {
140
+ close(readFd);
141
+ return false;
142
+ }
143
+
144
+ // Copy the file in a non-kernel specific way */
145
+ char fileBuf[8192];
146
+ ssize_t rBytes, wBytes;
147
+ while (true) {
148
+ rBytes = read(readFd, fileBuf, sizeof(fileBuf));
149
+
150
+ if (!rBytes) {
151
+ rc = true;
152
+ break;
153
+ }
154
+
155
+ if (rBytes < 0) {
156
+ rc = false;
157
+ break;
158
+ }
159
+
160
+ wBytes = write(writeFd, fileBuf, (size_t)rBytes);
161
+
162
+ if (!wBytes) {
163
+ rc = true;
164
+ break;
165
+ }
166
+
167
+ if (wBytes < 0) {
168
+ rc = false;
169
+ break;
170
+ }
171
+ }
172
+
173
+ /* Close up. */
174
+ close(readFd);
175
+ close(writeFd);
176
+ return rc;
177
+ }
178
+
179
+ static bool getFileInfoListRecursiveImpl(const std::string& path,
180
+ pal::FileOp::FilenamePartsListType_t& filenamePartsList,
181
+ const bool ignoreDirs,
182
+ size_t maxDepth) {
183
+ struct dirent** namelist = nullptr;
184
+ int entryCount = 0;
185
+
186
+ // Base case
187
+ if (maxDepth == 0) {
188
+ return true;
189
+ }
190
+
191
+ #ifdef __ANDROID__
192
+ // android dirent.h has the wrong signature for alphasort so it had to be disabled or fixed
193
+ entryCount = scandir(path.c_str(), &namelist, 0, 0);
194
+ #else
195
+ entryCount = scandir(path.c_str(), &namelist, 0, alphasort);
196
+ #endif
197
+ if (entryCount < 0) {
198
+ return false;
199
+ } else {
200
+ while (entryCount--) {
201
+ const std::string dName(namelist[entryCount]->d_name);
202
+ free(namelist[entryCount]);
203
+
204
+ // skip current directory, prev directory and empty string
205
+ if (dName.empty() || dName == "." || dName == "..") {
206
+ continue;
207
+ }
208
+
209
+ std::string curPath = path;
210
+ curPath += pal::Path::getSeparator();
211
+ curPath += dName;
212
+
213
+ // recurse if directory but avoid symbolic links to directories
214
+ if (pal::FileOp::checkIsDir(curPath)) {
215
+ Stat_t sb;
216
+ if (lstat(curPath.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) {
217
+ if (!getFileInfoListRecursiveImpl(curPath, filenamePartsList, ignoreDirs, maxDepth - 1)) {
218
+ return false;
219
+ }
220
+ }
221
+
222
+ if (ignoreDirs) {
223
+ continue;
224
+ }
225
+
226
+ // Append training / to make this path look like a directory for
227
+ // getFileInfo()
228
+ if (curPath.back() != pal::Path::getSeparator()) {
229
+ curPath += pal::Path::getSeparator();
230
+ }
231
+ }
232
+
233
+ // add to vector
234
+ pal::FileOp::FilenamePartsType_t filenameParts;
235
+ if (pal::FileOp::getFileInfo(curPath, filenameParts)) {
236
+ filenamePartsList.push_back(filenameParts);
237
+ }
238
+ }
239
+
240
+ free(namelist);
241
+ }
242
+
243
+ return true;
244
+ }
245
+
246
+ //---------------------------------------------------------------------------
247
+ // pal::FileOp::getFileInfoList
248
+ //---------------------------------------------------------------------------
249
+ bool pal::FileOp::getFileInfoList(const std::string& path,
250
+ FilenamePartsListType_t& filenamePartsList) {
251
+ return getFileInfoListRecursiveImpl(path, filenamePartsList, false, 1);
252
+ }
253
+
254
+ //---------------------------------------------------------------------------
255
+ // pal::FileOp::getFileInfoListRecursive
256
+ //---------------------------------------------------------------------------
257
+ bool pal::FileOp::getFileInfoListRecursive(const std::string& path,
258
+ FilenamePartsListType_t& filenamePartsList,
259
+ const bool ignoreDirs) {
260
+ return getFileInfoListRecursiveImpl(
261
+ path, filenamePartsList, ignoreDirs, std::numeric_limits<size_t>::max());
262
+ }
263
+
264
+ //---------------------------------------------------------------------------
265
+ // pal::FileOp::getAbsolutePath
266
+ //---------------------------------------------------------------------------
267
+ std::string pal::FileOp::getAbsolutePath(const std::string& path) {
268
+ // NOTE: This implementation is broken currently when a path with
269
+ // non-existant components is passed! NEO-19723 was created to address.
270
+ char absPath[PATH_MAX + 1] = {0};
271
+
272
+ if (realpath(path.c_str(), absPath) == NULL) {
273
+ DEBUG_MSG("GetAbsolute path fail! Error code : %d", errno);
274
+ return std::string();
275
+ }
276
+ return std::string(absPath);
277
+ }
278
+
279
+ //---------------------------------------------------------------------------
280
+ // pal::FileOp::setCWD
281
+ //---------------------------------------------------------------------------
282
+ bool pal::FileOp::setCurrentWorkingDirectory(const std::string& workingDir) {
283
+ return chdir(workingDir.c_str()) == 0;
284
+ }
285
+
286
+ //---------------------------------------------------------------------------
287
+ // pal::FileOp::getDirectory
288
+ //---------------------------------------------------------------------------
289
+ std::string pal::FileOp::getDirectory(const std::string& file) {
290
+ std::string rc = file;
291
+ size_t offset = file.find_last_of(Path::getSeparator());
292
+ if (offset != std::string::npos) {
293
+ rc = file.substr(0, offset);
294
+ }
295
+ return rc;
296
+ }
297
+
298
+ //---------------------------------------------------------------------------
299
+ // pal::FileOp::getFileName
300
+ //---------------------------------------------------------------------------
301
+ std::string pal::FileOp::getFileName(const std::string& file) {
302
+ std::string rc = file;
303
+ size_t offset = file.find_last_of(Path::getSeparator());
304
+ if (offset != std::string::npos) {
305
+ rc = file.substr(offset + 1); // +1 to skip path separator
306
+ }
307
+ return rc;
308
+ }
309
+
310
+ //---------------------------------------------------------------------------
311
+ // pal::FileOp::hasFileExtension
312
+ //---------------------------------------------------------------------------
313
+ bool pal::FileOp::hasFileExtension(const std::string& file) {
314
+ FilenamePartsType_t parts;
315
+ getFileInfo(file, parts);
316
+
317
+ return !parts.extension.empty();
318
+ }
319
+
320
+ //---------------------------------------------------------------------------
321
+ // pal::FileOp::getCWD
322
+ //---------------------------------------------------------------------------
323
+ std::string pal::FileOp::getCurrentWorkingDirectory() {
324
+ char buffer[PATH_MAX + 1];
325
+ buffer[0] = '\0';
326
+
327
+ // If there is any failure return empty string. It is technically possible
328
+ // to handle paths exceeding PATH_MAX on some flavors of *nix but platforms
329
+ // like Android (Bionic) do no provide such capability. For consistency we
330
+ // will not handle extra long path names.
331
+ if (nullptr == getcwd(buffer, PATH_MAX)) {
332
+ return std::string();
333
+ } else {
334
+ return std::string(buffer);
335
+ }
336
+ }
337
+
338
+ //---------------------------------------------------------------------------
339
+ // pal::FileOp::partsToString
340
+ //---------------------------------------------------------------------------
341
+ std::string pal::FileOp::partsToString(const FilenamePartsType_t& filenameParts) {
342
+ std::string path;
343
+
344
+ if (!filenameParts.directory.empty()) {
345
+ path += filenameParts.directory;
346
+ path += Path::getSeparator();
347
+ }
348
+ if (!filenameParts.basename.empty()) {
349
+ path += filenameParts.basename;
350
+ }
351
+ if (!filenameParts.extension.empty()) {
352
+ path += ".";
353
+ path += filenameParts.extension;
354
+ }
355
+ return path;
356
+ }
SampleApp/src/PAL/src/linux/Path.cpp ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2008-2014, 2015, 2020-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #include <stdlib.h>
10
+
11
+ #include <sstream>
12
+ #ifndef PATH_MAX
13
+ #include <limits.h>
14
+ #endif
15
+
16
+ #include "PAL/FileOp.hpp"
17
+ #include "PAL/Path.hpp"
18
+
19
+ char pal::Path::getSeparator() { return '/'; }
20
+
21
+ std::string pal::Path::combine(const std::string &s1, const std::string &s2) {
22
+ std::stringstream ss;
23
+ ss << s1;
24
+ if (s1.size() > 0 && s1[s1.size() - 1] != getSeparator()) {
25
+ ss << getSeparator();
26
+ }
27
+ ss << s2;
28
+ return ss.str();
29
+ }
30
+
31
+ std::string pal::Path::getDirectoryName(const std::string &path) {
32
+ std::string rc = path;
33
+ size_t index = path.find_last_of(pal::Path::getSeparator());
34
+ if (index != std::string::npos) {
35
+ rc = path.substr(0, index);
36
+ }
37
+ return rc;
38
+ }
39
+
40
+ std::string pal::Path::getAbsolute(const std::string &path) {
41
+ // Functionality was duplicated of function in FileOp
42
+ // Just call that function directly instead
43
+ return pal::FileOp::getAbsolutePath(path);
44
+ }
45
+
46
+ bool pal::Path::isAbsolute(const std::string &path) {
47
+ return path.size() > 0 && path[0] == getSeparator();
48
+ }
SampleApp/src/PAL/src/windows/Common.cpp ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2020-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #include <Windows.h>
10
+ #include <io.h>
11
+ #include <stdlib.h>
12
+ #include <sys/stat.h>
13
+ #include <time.h>
14
+
15
+ #include <algorithm>
16
+ #include <iostream>
17
+ #include <vector>
18
+
19
+ #include "Common.hpp"
20
+ #include "PAL/Debug.hpp"
21
+
22
+ int32_t pal::scanDir(const std::string &path, std::vector<WIN32_FIND_DATAA> &namelist) {
23
+ // example : "C:/Users/guest" scan nothing, "C:/Users/guest/*" can scan the
24
+ // entire directory instead
25
+ std::string scanPath = path + "/*";
26
+ WIN32_FIND_DATAA findFileData;
27
+ HANDLE hFind = FindFirstFileA(scanPath.c_str(), &findFileData);
28
+ if (hFind == INVALID_HANDLE_VALUE) {
29
+ DEBUG_MSG("scanDir fail! Error code : %d", GetLastError());
30
+ return -1;
31
+ }
32
+
33
+ do {
34
+ // will compare char until '\0' to allow filename with first char = '.'
35
+ if (strncmp(findFileData.cFileName, ".", 2) == 0 ||
36
+ strncmp(findFileData.cFileName, "..", 3) == 0) {
37
+ continue;
38
+ }
39
+ namelist.push_back(findFileData);
40
+ } while (FindNextFileA(hFind, &findFileData));
41
+ FindClose(hFind);
42
+
43
+ return namelist.size();
44
+ }
45
+
46
+ void pal::normalizeSeparator(std::string &path) { replace(path.begin(), path.end(), '\\', '/'); }
SampleApp/src/PAL/src/windows/Common.hpp ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2020-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #pragma once
10
+
11
+ #include <Windows.h>
12
+ #include <io.h>
13
+
14
+ #include <iostream>
15
+ #include <vector>
16
+
17
+ namespace pal {
18
+ /**
19
+ * @brief
20
+ * Scans elements in a directory.
21
+ * @param path
22
+ * Path in string which we are going to scan.
23
+ * @param namelist
24
+ * Data struct for each element, which will be stored as WIN32_FIND_DATAA.
25
+ * @return
26
+ * Number of elements in this path, return -1 if fail.
27
+ */
28
+ int32_t scanDir(const std::string &path, std::vector<WIN32_FIND_DATAA> &namelist);
29
+
30
+ /**
31
+ * @brief
32
+ * Replace all the '\\' in path with '/' to keep consistency.
33
+ * @param path
34
+ * The string which you want to format.
35
+ */
36
+ void normalizeSeparator(std::string &path);
37
+ } // namespace pal
SampleApp/src/PAL/src/windows/Directory.cpp ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //=====================================================================================
2
+ //
3
+ // Copyright (c) 2020-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //=====================================================================================
8
+
9
+ #include <Windows.h>
10
+ #include <stdlib.h>
11
+ #include <sys/stat.h>
12
+
13
+ #include <algorithm>
14
+ #include <iostream>
15
+
16
+ #include "Common.hpp"
17
+ #include "PAL/Debug.hpp"
18
+ #include "PAL/Directory.hpp"
19
+ #include "PAL/FileOp.hpp"
20
+ #include "PAL/Path.hpp"
21
+
22
+ //--------------------------------------------------------------------------------------
23
+ // pal::Directory::Create
24
+ //--------------------------------------------------------------------------------------
25
+ bool pal::Directory::create(const std::string &path, pal::Directory::DirMode dirmode) {
26
+ struct stat st;
27
+ // it create a directory successfully or directory exists already, return true.
28
+ if ((stat(path.c_str(), &st) != 0 && (CreateDirectoryA(path.c_str(), NULL) != 0)) ||
29
+ ((st.st_mode & S_IFDIR) != 0)) {
30
+ return true;
31
+ } else {
32
+ DEBUG_MSG("Create Folder fail! Error code : %d", GetLastError());
33
+ }
34
+ return false;
35
+ }
36
+
37
+ //--------------------------------------------------------------------------------------
38
+ // pal::Directory::Remove
39
+ //--------------------------------------------------------------------------------------
40
+ bool pal::Directory::remove(const std::string &dirName) {
41
+ struct stat st;
42
+ if (stat(dirName.c_str(), &st) == 0) {
43
+ if ((st.st_mode & S_IFDIR) != 0) {
44
+ // a directory exist and remove it !
45
+ std::string fullPath = dirName;
46
+ if (pal::Path::isAbsolute(dirName) == 0) {
47
+ fullPath = pal::Path::getAbsolute(dirName);
48
+ }
49
+ // Note This string MUST be double-null terminated.
50
+ fullPath = fullPath + '\0' + '\0';
51
+ SHFILEOPSTRUCTA fileOp = {
52
+ NULL, // hwnd
53
+ FO_DELETE, // wFunc, delete usage
54
+ fullPath.c_str(), // pFrom, delete target folder
55
+ "", // pTo, delete operation can ignore this
56
+ FOF_NO_UI, // Perform operation silently, presenting no UI to user
57
+ false, // fAnyOperationsAborted,
58
+ 0, // hNameMappings
59
+ "" // lpszProgressTitle, used only if for FOF_SIMPLEPROGRESS
60
+ };
61
+ if (SHFileOperationA(&fileOp) == 0) {
62
+ return true;
63
+ } else {
64
+ DEBUG_MSG("Delete folder fail! Error code : %d", GetLastError());
65
+ }
66
+ }
67
+ } else {
68
+ // If the directory doesn't exist then just, return true. Behaves like Linux
69
+ if (errno == ENOENT) {
70
+ return true;
71
+ } else {
72
+ DEBUG_MSG("Remove stat fail! Error code : %d", errno);
73
+ }
74
+ }
75
+ return false;
76
+ }
77
+
78
+ //--------------------------------------------------------------------------------------
79
+ // pal::Directory::MakePath
80
+ //--------------------------------------------------------------------------------------
81
+ bool pal::Directory::makePath(const std::string &path) {
82
+ struct stat st;
83
+ bool rc = false;
84
+ if (path == ".") {
85
+ rc = true;
86
+ } else if (stat(path.c_str(), &st) == 0) {
87
+ if ((st.st_mode & S_IFDIR) != 0) {
88
+ // if a directory path is already exist
89
+ rc = true;
90
+ }
91
+ } else {
92
+ size_t offset = std::min(path.find_last_of('/'), path.find_last_of('\\'));
93
+ if (offset != std::string::npos) {
94
+ std::string newPath = path.substr(0, offset);
95
+ if (!makePath(newPath)) {
96
+ return false;
97
+ }
98
+ }
99
+ pal::Directory::create(path.c_str());
100
+ if ((stat(path.c_str(), &st) == 0) && ((st.st_mode & S_IFDIR) != 0)) {
101
+ rc = true;
102
+ }
103
+ }
104
+ return rc;
105
+ }
SampleApp/src/PAL/src/windows/DynamicLoading.cpp ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2020-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ // clang-format off
10
+ #include <stdlib.h>
11
+ #include <windows.h>
12
+ #include <libloaderapi.h>
13
+ #include <psapi.h>
14
+ #include <winevt.h>
15
+ // clang-format on
16
+
17
+ #include <set>
18
+ #include <string>
19
+
20
+ #include "PAL/Debug.hpp"
21
+ #include "PAL/DynamicLoading.hpp"
22
+
23
+ #define STRINGIFY(x) #x
24
+ #define TOSTRING(x) STRINGIFY(x)
25
+
26
+ static std::set<HMODULE> mod_handles;
27
+ static thread_local char *sg_lastErrMsg = "";
28
+
29
+ void *pal::dynamicloading::dlOpen(const char *filename, int flags) {
30
+ HMODULE mod;
31
+ HANDLE cur_proc;
32
+ DWORD as_is, to_be;
33
+ bool loadedBefore = false;
34
+
35
+ if (!filename || ::strlen(filename) == 0) {
36
+ // TODO: we don't support empty filename now
37
+ sg_lastErrMsg = "filename is null or empty";
38
+ return NULL;
39
+ }
40
+
41
+ // POSIX asks one of symbol resolving approaches:
42
+ // NOW or LAZY must be specified
43
+ if (!(flags & DL_NOW)) {
44
+ // TODO: since Windows does not provide existing API so lazy
45
+ // symbol resolving needs to do relocation by ourself
46
+ // that would be too costly. SNPE didn't use this feature now
47
+ // , wait until we really need it. keep the flexibility here
48
+ // ask caller MUST pass DL_NOW
49
+ sg_lastErrMsg = "flags must include DL_NOW";
50
+ return NULL;
51
+ }
52
+
53
+ cur_proc = GetCurrentProcess();
54
+
55
+ if (EnumProcessModules(cur_proc, NULL, 0, &as_is) == 0) {
56
+ sg_lastErrMsg = "enumerate modules failed before loading module";
57
+ return NULL;
58
+ }
59
+
60
+ // search from system lib path first
61
+ mod = LoadLibraryExA(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
62
+ if (!mod) {
63
+ sg_lastErrMsg = "load library failed";
64
+ return NULL;
65
+ }
66
+
67
+ if (EnumProcessModules(cur_proc, NULL, 0, &to_be) == 0) {
68
+ sg_lastErrMsg = "enumerate modules failed after loading module";
69
+ FreeLibrary(mod);
70
+ return NULL;
71
+ }
72
+
73
+ if (as_is == to_be) {
74
+ loadedBefore = true;
75
+ }
76
+
77
+ // (not loadedBefore) and DL_LOCAL means this lib was not loaded yet
78
+ // add it into the local set
79
+ //
80
+ // If loadedBefore and DL_LOCAL, means this lib was already loaded
81
+ // 2 cases here for how it was loaded before:
82
+ // a. with DL_LOCAL, just ignore since it was already in local set
83
+ // b. with DL_GLOBAL, POSIX asks it in global, ignore it, too
84
+ if ((!loadedBefore) && (flags & DL_LOCAL)) {
85
+ mod_handles.insert(mod);
86
+ }
87
+
88
+ // once callers ask for global, needs to be in global thereafter
89
+ // so the lib should be removed from local set
90
+ if (flags & DL_GLOBAL) {
91
+ mod_handles.erase(mod);
92
+ }
93
+
94
+ return static_cast<void *>(mod);
95
+ }
96
+
97
+ void *pal::dynamicloading::dlSym(void *handle, const char *symbol) {
98
+ FARPROC sym_addr = NULL;
99
+ HANDLE cur_proc;
100
+ DWORD size, size_needed;
101
+ HMODULE *mod_list;
102
+ HMODULE mod = 0;
103
+
104
+ if ((!handle) || (!symbol)) {
105
+ return NULL;
106
+ }
107
+
108
+ cur_proc = GetCurrentProcess();
109
+
110
+ if (EnumProcessModules(cur_proc, NULL, 0, &size) == 0) {
111
+ sg_lastErrMsg = "enumerate modules failed before memory allocation";
112
+ return NULL;
113
+ }
114
+
115
+ mod_list = static_cast<HMODULE *>(malloc(size));
116
+ if (!mod_list) {
117
+ sg_lastErrMsg = "malloc failed";
118
+ return NULL;
119
+ }
120
+
121
+ if (EnumProcessModules(cur_proc, mod_list, size, &size_needed) == 0) {
122
+ sg_lastErrMsg = "enumerate modules failed after memory allocation";
123
+ free(mod_list);
124
+ return NULL;
125
+ }
126
+
127
+ // DL_DEFAULT needs to bypass those modules with DL_LOCAL flag
128
+ if (handle == DL_DEFAULT) {
129
+ for (size_t i = 0; i < (size / sizeof(HMODULE)); i++) {
130
+ auto iter = mod_handles.find(mod_list[i]);
131
+ if (iter != mod_handles.end()) {
132
+ continue;
133
+ }
134
+ // once find the first non-local module with symbol
135
+ // return its address here to avoid unnecessary looping
136
+ sym_addr = GetProcAddress(mod_list[i], symbol);
137
+ if (sym_addr) {
138
+ free(mod_list);
139
+ return *(void **)(&sym_addr);
140
+ }
141
+ }
142
+ } else {
143
+ mod = static_cast<HMODULE>(handle);
144
+ }
145
+
146
+ free(mod_list);
147
+ sym_addr = GetProcAddress(mod, symbol);
148
+ if (!sym_addr) {
149
+ sg_lastErrMsg = "can't resolve symbol";
150
+ return NULL;
151
+ }
152
+
153
+ return *(void **)(&sym_addr);
154
+ }
155
+
156
+ int pal::dynamicloading::dlAddrToLibName(void *addr, std::string &name) {
157
+ // Clean the output buffer
158
+ name = std::string();
159
+
160
+ // If the address is empty, return zero as treating failure
161
+ if (!addr) {
162
+ DEBUG_MSG("Input address is nullptr.");
163
+ return 0;
164
+ }
165
+
166
+ HMODULE hModule = NULL;
167
+ // TODO: Need to use TCHAR for the compatibility of ASCII and Unicode
168
+ CHAR nameBuf[MAX_PATH];
169
+
170
+ // (1st flag) The lpModuleName parameter is an address in the module
171
+ // (2nd flag) The reference count for the module is not incremented
172
+ DWORD flags =
173
+ GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
174
+
175
+ // Retrieves a module handle for the specified module by its symbol address
176
+ if (!GetModuleHandleExA(flags, reinterpret_cast<LPCSTR>(addr), &hModule) || hModule == NULL) {
177
+ DEBUG_MSG("Failed to get module handle. Error code: %d", GetLastError());
178
+ return 0;
179
+ }
180
+
181
+ // Retrieves the fully qualified path for the file that contains the specified module
182
+ DWORD dwSize = GetModuleFileNameA(hModule, nameBuf, sizeof(nameBuf));
183
+
184
+ // dwSize == 0 indicates function failure
185
+ // If the path is too long (greater than MAX_PATH), treat it as failure
186
+ if (dwSize == 0 || ERROR_INSUFFICIENT_BUFFER == GetLastError()) {
187
+ DEBUG_MSG("Failed to get module file name. Error code: %d", GetLastError());
188
+ return 0;
189
+ }
190
+
191
+ name = std::string(nameBuf);
192
+
193
+ // Return a non-zero value to represent the function successes
194
+ return 1;
195
+ }
196
+
197
+ int pal::dynamicloading::dlClose(void *handle) {
198
+ if (!handle) {
199
+ return 0;
200
+ }
201
+
202
+ HMODULE mod = static_cast<HMODULE>(handle);
203
+
204
+ if (FreeLibrary(mod) == 0) {
205
+ sg_lastErrMsg = "free library failed";
206
+ return -1;
207
+ }
208
+
209
+ mod_handles.erase(mod);
210
+
211
+ return 0;
212
+ }
213
+
214
+ char *pal::dynamicloading::dlError(void) {
215
+ char *retStr = sg_lastErrMsg;
216
+
217
+ sg_lastErrMsg = "";
218
+
219
+ return retStr;
220
+ }
SampleApp/src/PAL/src/windows/FileOp.cpp ADDED
@@ -0,0 +1,297 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2020-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #include <direct.h>
10
+ #include <errno.h>
11
+ #include <fcntl.h>
12
+ #include <io.h>
13
+ #include <limits.h>
14
+ #include <process.h>
15
+ #include <stdio.h>
16
+ #include <stdlib.h>
17
+ #include <sys/locking.h>
18
+ #include <windows.h>
19
+
20
+ #include <algorithm>
21
+ #include <cstring>
22
+ #include <iostream>
23
+ #include <sstream>
24
+ #include <string>
25
+ #include <vector>
26
+
27
+ #include "Common.hpp"
28
+ #include "PAL/Debug.hpp"
29
+ #include "PAL/Directory.hpp"
30
+ #include "PAL/FileOp.hpp"
31
+ #include "PAL/Path.hpp"
32
+
33
+ //-------------------------------------------------------------------------------
34
+ // pal::FileOp::checkFileExists
35
+ //-------------------------------------------------------------------------------
36
+ bool pal::FileOp::checkFileExists(const std::string &fileName) {
37
+ struct stat st;
38
+ if (stat(fileName.c_str(), &st) != 0) {
39
+ DEBUG_MSG("Check File fail! Error code : %d", errno);
40
+ return false;
41
+ }
42
+ return true;
43
+ }
44
+
45
+ //-------------------------------------------------------------------------------
46
+ // pal::FileOp::copyOverFile
47
+ //-------------------------------------------------------------------------------
48
+ bool pal::FileOp::copyOverFile(const std::string &fromFile, const std::string &toFile) {
49
+ if (CopyFileA(fromFile.c_str(), toFile.c_str(), 0) == 0) {
50
+ DEBUG_MSG("Copy file fail! Error code : %d", GetLastError());
51
+ return false;
52
+ }
53
+ return true;
54
+ }
55
+
56
+ //-------------------------------------------------------------------------------
57
+ // pal::FileOp::move
58
+ //-------------------------------------------------------------------------------
59
+ bool pal::FileOp::move(const std::string &currentName, const std::string &newName, bool overwrite) {
60
+ struct stat st;
61
+ // if currentName doesn't exist, return false in case newName got deleted
62
+ if (stat(currentName.c_str(), &st) != 0) {
63
+ DEBUG_MSG("CurrentName check status fail! Error code : %d", errno);
64
+ return false;
65
+ }
66
+ if (stat(newName.c_str(), &st) == 0) {
67
+ if ((st.st_mode & S_IFDIR) != 0) {
68
+ // if newName is directory and overwrite = false, cannot move, return false
69
+ // if newName is directory and overwrite = true, delete it and rename
70
+ if (overwrite == false) {
71
+ return false;
72
+ }
73
+ pal::Directory::remove(newName);
74
+ } else {
75
+ deleteFile(newName);
76
+ }
77
+ }
78
+ // in windows, if newName exist already, rename will return -1
79
+ // only when newName doesn't exist, rename will return 0
80
+ return (rename(currentName.c_str(), newName.c_str()) == 0);
81
+ }
82
+
83
+ //-------------------------------------------------------------------------------
84
+ // pal::FileOp::deleteFile
85
+ //-------------------------------------------------------------------------------
86
+ bool pal::FileOp::deleteFile(const std::string &fileName) {
87
+ return (DeleteFileA(fileName.c_str()) != 0);
88
+ }
89
+
90
+ //-------------------------------------------------------------------------------
91
+ // pal::FileOp::checkIsDir
92
+ //-------------------------------------------------------------------------------
93
+ bool pal::FileOp::checkIsDir(const std::string &fileName) {
94
+ DWORD result = GetFileAttributesA(fileName.c_str());
95
+ if (result == static_cast<DWORD>(FILE_INVALID_FILE_ID)) {
96
+ DEBUG_MSG("File attribute is invalid_file_id!");
97
+ return false;
98
+ }
99
+ return (result & FILE_ATTRIBUTE_DIRECTORY) != 0;
100
+ }
101
+
102
+ //-------------------------------------------------------------------------------
103
+ // pal::FileOp::getFileInfo
104
+ //-------------------------------------------------------------------------------
105
+ bool pal::FileOp::getFileInfo(const std::string &filename,
106
+ pal::FileOp::FilenamePartsType_t &filenameParts) {
107
+ std::string name;
108
+ int32_t lastPathSeparator = std::max(static_cast<int32_t>(filename.find_last_of('\\')),
109
+ static_cast<int32_t>(filename.find_last_of('/')));
110
+ if (lastPathSeparator == static_cast<int32_t>(std::string::npos)) {
111
+ // No directory
112
+ name = filename;
113
+ } else {
114
+ // has a directory part
115
+ filenameParts.directory = filename.substr(0, lastPathSeparator);
116
+ name = filename.substr(lastPathSeparator + 1);
117
+ }
118
+
119
+ size_t ext = name.find_last_of(".");
120
+ if (ext == std::string::npos) {
121
+ // no extension
122
+ filenameParts.basename = name;
123
+ } else {
124
+ // has extension
125
+ filenameParts.basename = name.substr(0, ext);
126
+ filenameParts.extension = name.substr(ext + 1);
127
+ }
128
+ pal::normalizeSeparator(filenameParts.directory);
129
+ return true;
130
+ }
131
+
132
+ //-------------------------------------------------------------------------------
133
+ // pal::FileOp::getFileInfoListRecursiveImpl
134
+ //-------------------------------------------------------------------------------
135
+ static bool getFileInfoListRecursiveImpl(const std::string &path,
136
+ pal::FileOp::FilenamePartsListType_t &filenamePartsList,
137
+ const bool ignoreDirs,
138
+ size_t maxDepth) {
139
+ // base case
140
+ if (maxDepth == 0) {
141
+ return true;
142
+ }
143
+ if (pal::FileOp::checkIsDir(path) == false) {
144
+ return false;
145
+ }
146
+ int32_t entryCount = 0;
147
+ std::vector<WIN32_FIND_DATAA> nameList;
148
+ entryCount = pal::scanDir(path.c_str(), nameList);
149
+ if (entryCount < 0) {
150
+ return false;
151
+ }
152
+ while (entryCount--) {
153
+ const std::string dName = std::string(nameList[entryCount].cFileName);
154
+ // skip current directory, previous directory and empty string
155
+ if (dName.empty() || dName == "." || dName == "..") {
156
+ continue;
157
+ }
158
+ std::string curPath = path + pal::Path::getSeparator() + dName;
159
+ // recursive if directory but avoid symbolic links to directories
160
+ if (pal::FileOp::checkIsDir(curPath)) {
161
+ struct stat st;
162
+ if (stat(curPath.c_str(), &st) == 0 && ((st.st_mode & S_IFDIR) != 0) &&
163
+ (!getFileInfoListRecursiveImpl(curPath, filenamePartsList, ignoreDirs, maxDepth - 1))) {
164
+ return false;
165
+ }
166
+ if (curPath.back() != pal::Path::getSeparator()) {
167
+ curPath += pal::Path::getSeparator();
168
+ }
169
+ // continue here to prevent this object from adding filenameparts in
170
+ // vector but we still need this directory to go recursive
171
+ if (ignoreDirs) {
172
+ continue;
173
+ }
174
+ }
175
+ // add to vector
176
+ pal::FileOp::FilenamePartsType_t filenameParts = {std::string(), std::string(), std::string()};
177
+ if (pal::FileOp::getFileInfo(curPath, filenameParts)) {
178
+ filenamePartsList.push_back(filenameParts);
179
+ }
180
+ }
181
+ return true;
182
+ }
183
+
184
+ //-------------------------------------------------------------------------------
185
+ // pal::FileOp::getFileInfoList
186
+ //-------------------------------------------------------------------------------
187
+ bool pal::FileOp::getFileInfoList(const std::string &path,
188
+ FilenamePartsListType_t &filenamePartsList) {
189
+ return getFileInfoListRecursiveImpl(path, filenamePartsList, false, 1);
190
+ }
191
+
192
+ //-------------------------------------------------------------------------------
193
+ // pal::FileOp::getFileInfoListRecursive
194
+ //-------------------------------------------------------------------------------
195
+ bool pal::FileOp::getFileInfoListRecursive(const std::string &path,
196
+ FilenamePartsListType_t &filenamePartsList,
197
+ const bool ignoreDirs) {
198
+ return getFileInfoListRecursiveImpl(path, filenamePartsList, ignoreDirs, UINT_MAX);
199
+ }
200
+
201
+ //-------------------------------------------------------------------------------
202
+ // pal::FileOp::getAbsolutePath
203
+ //-------------------------------------------------------------------------------
204
+ std::string pal::FileOp::getAbsolutePath(const std::string &path) {
205
+ char fullPath[MAX_PATH];
206
+ if (_fullpath(fullPath, path.c_str(), MAX_PATH) == NULL) {
207
+ DEBUG_MSG("GetAbsolute path fail! Error code : %d", errno);
208
+ return std::string();
209
+ }
210
+ std::string reStr = std::string(fullPath);
211
+ pal::normalizeSeparator(reStr);
212
+ return reStr;
213
+ }
214
+
215
+ //-------------------------------------------------------------------------------
216
+ // pal::FileOp::getDirectory
217
+ //-------------------------------------------------------------------------------
218
+ std::string pal::FileOp::getDirectory(const std::string &file) {
219
+ std::string rc = file;
220
+ int32_t index = std::max(static_cast<int32_t>(file.find_last_of('\\')),
221
+ static_cast<int32_t>(file.find_last_of('/')));
222
+ if (index != static_cast<int32_t>(std::string::npos)) {
223
+ rc = file.substr(0, index);
224
+ }
225
+ pal::normalizeSeparator(rc);
226
+ return rc;
227
+ }
228
+
229
+ //-------------------------------------------------------------------------------
230
+ // pal::FileOp::GetFileName
231
+ //-------------------------------------------------------------------------------
232
+ std::string pal::FileOp::getFileName(const std::string &file) {
233
+ std::string rc = file;
234
+ int32_t index = std::max(static_cast<int32_t>(file.find_last_of('\\')),
235
+ static_cast<int32_t>(file.find_last_of('/')));
236
+ if (index != static_cast<int32_t>(std::string::npos)) {
237
+ rc = file.substr(index + 1); // +1 to skip path separator
238
+ }
239
+ return rc;
240
+ }
241
+
242
+ //-------------------------------------------------------------------------------
243
+ // pal::FileOp::hasFileExtension
244
+ //-------------------------------------------------------------------------------
245
+ bool pal::FileOp::hasFileExtension(const std::string &file) {
246
+ FilenamePartsType_t parts = {std::string(), std::string(), std::string()};
247
+ getFileInfo(file, parts);
248
+ return !parts.extension.empty();
249
+ }
250
+
251
+ //-------------------------------------------------------------------------------
252
+ // pal::FileOp::getCurrentWorkingDirectory
253
+ //-------------------------------------------------------------------------------
254
+ std::string pal::FileOp::getCurrentWorkingDirectory() {
255
+ char buffer[MAX_PATH + 1];
256
+ buffer[0] = '\0';
257
+
258
+ // If there is any failure return empty string. It is technically possible
259
+ // to handle paths exceeding PATH_MAX on some flavors of *nix but platforms
260
+ // like Android (Bionic) do no provide such capability. For consistency we
261
+ // will not handle extra long path names.
262
+ if (0 == GetCurrentDirectoryA(MAX_PATH, buffer)) {
263
+ DEBUG_MSG("Get current working directory fail! Error code : %d", GetLastError());
264
+ return std::string();
265
+ }
266
+ std::string res = std::string(buffer);
267
+ pal::normalizeSeparator(res);
268
+ return res;
269
+ }
270
+
271
+ //-------------------------------------------------------------------------------
272
+ // pal::FileOp::setCurrentWorkingDirectory
273
+ //-------------------------------------------------------------------------------
274
+ bool pal::FileOp::setCurrentWorkingDirectory(const std::string &workingDir) {
275
+ return _chdir(workingDir.c_str()) == 0;
276
+ }
277
+
278
+ //-------------------------------------------------------------------------------
279
+ // pal::FileOp::PartsToString
280
+ //-------------------------------------------------------------------------------
281
+ std::string pal::FileOp::partsToString(const FilenamePartsType_t &filenameParts) {
282
+ std::string path;
283
+
284
+ if (!filenameParts.directory.empty()) {
285
+ path += filenameParts.directory;
286
+ path += Path::getSeparator();
287
+ }
288
+ if (!filenameParts.basename.empty()) {
289
+ path += filenameParts.basename;
290
+ }
291
+ if (!filenameParts.extension.empty()) {
292
+ path += ".";
293
+ path += filenameParts.extension;
294
+ }
295
+ pal::normalizeSeparator(path);
296
+ return path;
297
+ }
SampleApp/src/PAL/src/windows/Path.cpp ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2020-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #include <shlwapi.h>
10
+ #include <stdlib.h>
11
+
12
+ #include <algorithm>
13
+ #include <iostream>
14
+ #include <sstream>
15
+
16
+ #include "Common.hpp"
17
+ #include "PAL/FileOp.hpp"
18
+ #include "PAL/Path.hpp"
19
+
20
+ //------------------------------------------------------------------------------
21
+ // PAL::Path::GetSeparator
22
+ //------------------------------------------------------------------------------
23
+ char pal::Path::getSeparator() { return '/'; }
24
+
25
+ //------------------------------------------------------------------------------
26
+ // pal::Path::Combine
27
+ //------------------------------------------------------------------------------
28
+ std::string pal::Path::combine(const std::string &s1, const std::string &s2) {
29
+ std::stringstream ss;
30
+ ss << s1;
31
+ if (s1.size() > 0 && ((s1[s1.size() - 1] != '/') && (s1[s1.size() - 1] != '\\'))) {
32
+ ss << getSeparator();
33
+ }
34
+ ss << s2;
35
+ return ss.str();
36
+ }
37
+
38
+ //------------------------------------------------------------------------------
39
+ // pal::Path::getDirectoryName
40
+ //------------------------------------------------------------------------------
41
+ std::string pal::Path::getDirectoryName(const std::string &path) {
42
+ std::string rc = path;
43
+ int32_t index = std::max(static_cast<int32_t>(path.find_last_of('\\')),
44
+ static_cast<int32_t>(path.find_last_of('/')));
45
+ if (index != static_cast<int32_t>(std::string::npos)) {
46
+ rc = path.substr(0, index);
47
+ }
48
+ pal::normalizeSeparator(rc);
49
+ return rc;
50
+ }
51
+
52
+ //------------------------------------------------------------------------------
53
+ // pal::Path::getAbsolute
54
+ //------------------------------------------------------------------------------
55
+ std::string pal::Path::getAbsolute(const std::string &path) {
56
+ std::string res = pal::FileOp::getAbsolutePath(path);
57
+ pal::normalizeSeparator(res);
58
+ return res;
59
+ }
60
+
61
+ //------------------------------------------------------------------------------
62
+ // PAL::Path::isAbsolute
63
+ // requirement : shlwapi.lib
64
+ //------------------------------------------------------------------------------
65
+ bool pal::Path::isAbsolute(const std::string &path) {
66
+ std::string windowsPath = path;
67
+ // in windows, when we need to check relative or absolute path,
68
+ // separator MUST be '\\' rather than '/'
69
+ // for more information : https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats
70
+ replace(windowsPath.begin(), windowsPath.end(), '/', '\\');
71
+ return PathIsRelativeA(windowsPath.c_str()) == false;
72
+ }
SampleApp/src/QnnSampleApp.cpp ADDED
@@ -0,0 +1,668 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2019-2024 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #include <inttypes.h>
10
+
11
+ #include <cstring>
12
+ #include <fstream>
13
+ #include <iostream>
14
+
15
+ #include "DataUtil.hpp"
16
+ #include "Logger.hpp"
17
+ #ifndef __hexagon__
18
+ #include "PAL/Directory.hpp"
19
+ #include "PAL/FileOp.hpp"
20
+ #include "PAL/Path.hpp"
21
+ #endif
22
+ #include "PAL/StringOp.hpp"
23
+ #include "QnnSampleApp.hpp"
24
+ #include "QnnSampleAppUtils.hpp"
25
+ #include "QnnWrapperUtils.hpp"
26
+
27
+ using namespace qnn;
28
+ using namespace qnn::tools;
29
+
30
+ // Default path where the outputs will be stored if outputPath is
31
+ // not supplied.
32
+ const std::string sample_app::QnnSampleApp::s_defaultOutputPath = "./output/";
33
+
34
+ sample_app::QnnSampleApp::QnnSampleApp(QnnFunctionPointers qnnFunctionPointers,
35
+ std::string inputListPaths,
36
+ std::string opPackagePaths,
37
+ void* backendLibraryHandle,
38
+ std::string outputPath,
39
+ bool debug,
40
+ iotensor::OutputDataType outputDataType,
41
+ iotensor::InputDataType inputDataType,
42
+ sample_app::ProfilingLevel profilingLevel,
43
+ bool dumpOutputs,
44
+ std::string cachedBinaryPath,
45
+ std::string saveBinaryName)
46
+ : m_qnnFunctionPointers(qnnFunctionPointers),
47
+ m_outputPath(outputPath),
48
+ m_saveBinaryName(saveBinaryName),
49
+ m_cachedBinaryPath(cachedBinaryPath),
50
+ m_debug(debug),
51
+ m_outputDataType(outputDataType),
52
+ m_inputDataType(inputDataType),
53
+ m_profilingLevel(profilingLevel),
54
+ m_dumpOutputs(dumpOutputs),
55
+ m_backendLibraryHandle(backendLibraryHandle),
56
+ m_isBackendInitialized(false),
57
+ m_isContextCreated(false) {
58
+ split(m_inputListPaths, inputListPaths, ',');
59
+ split(m_opPackagePaths, opPackagePaths, ',');
60
+ if (m_outputPath.empty()) {
61
+ m_outputPath = s_defaultOutputPath;
62
+ }
63
+ return;
64
+ }
65
+
66
+ sample_app::QnnSampleApp::~QnnSampleApp() {
67
+ // Free Profiling object if it was created
68
+ if (nullptr != m_profileBackendHandle) {
69
+ QNN_DEBUG("Freeing backend profile object.");
70
+ if (QNN_PROFILE_NO_ERROR !=
71
+ m_qnnFunctionPointers.qnnInterface.profileFree(m_profileBackendHandle)) {
72
+ QNN_ERROR("Could not free backend profile handle.");
73
+ }
74
+ }
75
+ // Free context if not already done
76
+ if (m_isContextCreated) {
77
+ QNN_DEBUG("Freeing context");
78
+ if (QNN_CONTEXT_NO_ERROR !=
79
+ m_qnnFunctionPointers.qnnInterface.contextFree(m_context, nullptr)) {
80
+ QNN_ERROR("Could not free context");
81
+ }
82
+ }
83
+ m_isContextCreated = false;
84
+ // Terminate backend
85
+ if (m_isBackendInitialized && nullptr != m_qnnFunctionPointers.qnnInterface.backendFree) {
86
+ QNN_DEBUG("Freeing backend");
87
+ if (QNN_BACKEND_NO_ERROR != m_qnnFunctionPointers.qnnInterface.backendFree(m_backendHandle)) {
88
+ QNN_ERROR("Could not free backend");
89
+ }
90
+ }
91
+ m_isBackendInitialized = false;
92
+ // Terminate logging in the backend
93
+ if (nullptr != m_qnnFunctionPointers.qnnInterface.logFree && nullptr != m_logHandle) {
94
+ if (QNN_SUCCESS != m_qnnFunctionPointers.qnnInterface.logFree(m_logHandle)) {
95
+ QNN_WARN("Unable to terminate logging in the backend.");
96
+ }
97
+ }
98
+ return;
99
+ }
100
+
101
+ std::string sample_app::QnnSampleApp::getBackendBuildId() {
102
+ char* backendBuildId{nullptr};
103
+ if (QNN_SUCCESS !=
104
+ m_qnnFunctionPointers.qnnInterface.backendGetBuildId((const char**)&backendBuildId)) {
105
+ QNN_ERROR("Unable to get build Id from the backend.");
106
+ }
107
+ return (backendBuildId == nullptr ? std::string("") : std::string(backendBuildId));
108
+ }
109
+
110
+ // Initialize QnnSampleApp. Things it does:
111
+ // 1. Create output directory
112
+ // 2. Read all input list paths provided
113
+ // during creation.
114
+ sample_app::StatusCode sample_app::QnnSampleApp::initialize() {
115
+ // Create Output Directory
116
+ #ifndef __hexagon__
117
+ if (m_dumpOutputs && !::pal::FileOp::checkFileExists(m_outputPath) &&
118
+ !pal::Directory::makePath(m_outputPath)) {
119
+ exitWithMessage("Could not create output directory: " + m_outputPath, EXIT_FAILURE);
120
+ }
121
+ #endif
122
+ // Read Input File List
123
+ bool readSuccess;
124
+ std::tie(m_inputFileLists, m_inputNameToIndex, readSuccess) = readInputLists(m_inputListPaths);
125
+ if (!readSuccess) {
126
+ exitWithMessage("Could not read input lists", EXIT_FAILURE);
127
+ }
128
+ // initialize logging in the backend
129
+ if (log::isLogInitialized()) {
130
+ auto logCallback = log::getLogCallback();
131
+ auto logLevel = log::getLogLevel();
132
+ QNN_INFO("Initializing logging in the backend. Callback: [%p], Log Level: [%d]",
133
+ logCallback,
134
+ logLevel);
135
+ if (QNN_SUCCESS !=
136
+ m_qnnFunctionPointers.qnnInterface.logCreate(logCallback, logLevel, &m_logHandle)) {
137
+ QNN_WARN("Unable to initialize logging in the backend.");
138
+ }
139
+ } else {
140
+ QNN_WARN("Logging not available in the backend.");
141
+ }
142
+ return StatusCode::SUCCESS;
143
+ }
144
+
145
+ sample_app::StatusCode sample_app::QnnSampleApp::initializeProfiling() {
146
+ if (ProfilingLevel::OFF != m_profilingLevel) {
147
+ QNN_INFO("Profiling turned on; level = %d", m_profilingLevel);
148
+ if (ProfilingLevel::BASIC == m_profilingLevel) {
149
+ QNN_INFO("Basic profiling requested. Creating Qnn Profile object.");
150
+ if (QNN_PROFILE_NO_ERROR !=
151
+ m_qnnFunctionPointers.qnnInterface.profileCreate(
152
+ m_backendHandle, QNN_PROFILE_LEVEL_BASIC, &m_profileBackendHandle)) {
153
+ QNN_WARN("Unable to create profile handle in the backend.");
154
+ return StatusCode::FAILURE;
155
+ }
156
+ } else if (ProfilingLevel::DETAILED == m_profilingLevel) {
157
+ QNN_INFO("Detailed profiling requested. Creating Qnn Profile object.");
158
+ if (QNN_PROFILE_NO_ERROR !=
159
+ m_qnnFunctionPointers.qnnInterface.profileCreate(
160
+ m_backendHandle, QNN_PROFILE_LEVEL_DETAILED, &m_profileBackendHandle)) {
161
+ QNN_ERROR("Unable to create profile handle in the backend.");
162
+ return StatusCode::FAILURE;
163
+ }
164
+ }
165
+ }
166
+ return StatusCode::SUCCESS;
167
+ }
168
+
169
+ // Simple method to report error from app to lib.
170
+ int32_t sample_app::QnnSampleApp::reportError(const std::string& err) {
171
+ QNN_ERROR("%s", err.c_str());
172
+ return EXIT_FAILURE;
173
+ }
174
+
175
+ // Initialize a QnnBackend.
176
+ sample_app::StatusCode sample_app::QnnSampleApp::initializeBackend() {
177
+ auto qnnStatus = m_qnnFunctionPointers.qnnInterface.backendCreate(
178
+ m_logHandle, (const QnnBackend_Config_t**)m_backendConfig, &m_backendHandle);
179
+ if (QNN_BACKEND_NO_ERROR != qnnStatus) {
180
+ QNN_ERROR("Could not initialize backend due to error = %d", qnnStatus);
181
+ return StatusCode::FAILURE;
182
+ }
183
+ QNN_INFO("Initialize Backend Returned Status = %d", qnnStatus);
184
+ m_isBackendInitialized = true;
185
+ return StatusCode::SUCCESS;
186
+ }
187
+
188
+ // Terminate the backend after done.
189
+ sample_app::StatusCode sample_app::QnnSampleApp::terminateBackend() {
190
+ if ((m_isBackendInitialized && nullptr != m_qnnFunctionPointers.qnnInterface.backendFree) &&
191
+ QNN_BACKEND_NO_ERROR != m_qnnFunctionPointers.qnnInterface.backendFree(m_backendHandle)) {
192
+ QNN_ERROR("Could not terminate backend");
193
+ return StatusCode::FAILURE;
194
+ }
195
+ m_isBackendInitialized = false;
196
+ return StatusCode::SUCCESS;
197
+ }
198
+
199
+ // Register op packages and interface providers supplied during
200
+ // object creation. If there are multiple op packages, register
201
+ // them sequentially in the order provided.
202
+ sample_app::StatusCode sample_app::QnnSampleApp::registerOpPackages() {
203
+ const size_t pathIdx = 0;
204
+ const size_t interfaceProviderIdx = 1;
205
+ for (auto const& opPackagePath : m_opPackagePaths) {
206
+ std::vector<std::string> opPackage;
207
+ split(opPackage, opPackagePath, ':');
208
+ QNN_DEBUG("opPackagePath: %s", opPackagePath.c_str());
209
+ const char* target = nullptr;
210
+ const size_t targetIdx = 2;
211
+ if (opPackage.size() != 2 && opPackage.size() != 3) {
212
+ QNN_ERROR("Malformed opPackageString provided: %s", opPackagePath.c_str());
213
+ return StatusCode::FAILURE;
214
+ }
215
+ if (opPackage.size() == 3) {
216
+ target = (char*)opPackage[targetIdx].c_str();
217
+ }
218
+ if (nullptr == m_qnnFunctionPointers.qnnInterface.backendRegisterOpPackage) {
219
+ QNN_ERROR("backendRegisterOpPackageFnHandle is nullptr.");
220
+ return StatusCode::FAILURE;
221
+ }
222
+ if (QNN_BACKEND_NO_ERROR != m_qnnFunctionPointers.qnnInterface.backendRegisterOpPackage(
223
+ m_backendHandle,
224
+ (char*)opPackage[pathIdx].c_str(),
225
+ (char*)opPackage[interfaceProviderIdx].c_str(),
226
+ target)) {
227
+ QNN_ERROR("Could not register Op Package: %s and interface provider: %s",
228
+ opPackage[pathIdx].c_str(),
229
+ opPackage[interfaceProviderIdx].c_str());
230
+ return StatusCode::FAILURE;
231
+ }
232
+ QNN_INFO("Registered Op Package: %s and interface provider: %s",
233
+ opPackage[pathIdx].c_str(),
234
+ opPackage[interfaceProviderIdx].c_str());
235
+ }
236
+ return StatusCode::SUCCESS;
237
+ }
238
+
239
+ // Create a Context in a backend.
240
+ sample_app::StatusCode sample_app::QnnSampleApp::createContext() {
241
+ if (QNN_CONTEXT_NO_ERROR !=
242
+ m_qnnFunctionPointers.qnnInterface.contextCreate(m_backendHandle,
243
+ m_deviceHandle,
244
+ (const QnnContext_Config_t**)m_contextConfig,
245
+ &m_context)) {
246
+ QNN_ERROR("Could not create context");
247
+ return StatusCode::FAILURE;
248
+ }
249
+ m_isContextCreated = true;
250
+ return StatusCode::SUCCESS;
251
+ }
252
+
253
+ // Free context after done.
254
+ sample_app::StatusCode sample_app::QnnSampleApp::freeContext() {
255
+ if (QNN_CONTEXT_NO_ERROR !=
256
+ m_qnnFunctionPointers.qnnInterface.contextFree(m_context, m_profileBackendHandle)) {
257
+ QNN_ERROR("Could not free context");
258
+ return StatusCode::FAILURE;
259
+ }
260
+ m_isContextCreated = false;
261
+ return StatusCode::SUCCESS;
262
+ }
263
+
264
+ // Calls composeGraph function in QNN's model.so.
265
+ // composeGraphs is supposed to populate graph related
266
+ // information in m_graphsInfo and m_graphsCount.
267
+ // m_debug is the option supplied to composeGraphs to
268
+ // say that all intermediate tensors including output tensors
269
+ // are expected to be read by the app.
270
+ sample_app::StatusCode sample_app::QnnSampleApp::composeGraphs() {
271
+ auto returnStatus = StatusCode::SUCCESS;
272
+ if (qnn_wrapper_api::ModelError_t::MODEL_NO_ERROR !=
273
+ m_qnnFunctionPointers.composeGraphsFnHandle(
274
+ m_backendHandle,
275
+ m_qnnFunctionPointers.qnnInterface,
276
+ m_context,
277
+ (const qnn_wrapper_api::GraphConfigInfo_t**)m_graphConfigsInfo,
278
+ m_graphConfigsInfoCount,
279
+ &m_graphsInfo,
280
+ &m_graphsCount,
281
+ m_debug,
282
+ log::getLogCallback(),
283
+ log::getLogLevel())) {
284
+ QNN_ERROR("Failed in composeGraphs()");
285
+ returnStatus = StatusCode::FAILURE;
286
+ }
287
+ return returnStatus;
288
+ }
289
+
290
+ sample_app::StatusCode sample_app::QnnSampleApp::finalizeGraphs() {
291
+ for (size_t graphIdx = 0; graphIdx < m_graphsCount; graphIdx++) {
292
+ if (QNN_GRAPH_NO_ERROR !=
293
+ m_qnnFunctionPointers.qnnInterface.graphFinalize(
294
+ (*m_graphsInfo)[graphIdx].graph, m_profileBackendHandle, nullptr)) {
295
+ return StatusCode::FAILURE;
296
+ }
297
+ }
298
+ if (ProfilingLevel::OFF != m_profilingLevel) {
299
+ extractBackendProfilingInfo(m_profileBackendHandle);
300
+ }
301
+ auto returnStatus = StatusCode::SUCCESS;
302
+ if (!m_saveBinaryName.empty()) {
303
+ QNN_INFO("Before saveBinary(): saving context and metadata.");
304
+ returnStatus = saveBinary();
305
+ } else {
306
+ QNN_DEBUG("m_saveBinaryName is empty()");
307
+ }
308
+ return returnStatus;
309
+ }
310
+
311
+ sample_app::StatusCode sample_app::QnnSampleApp::createFromBinary() {
312
+ if (m_cachedBinaryPath.empty()) {
313
+ QNN_ERROR("No name provided to read binary file from.");
314
+ return StatusCode::FAILURE;
315
+ }
316
+ if (nullptr == m_qnnFunctionPointers.qnnSystemInterface.systemContextCreate ||
317
+ nullptr == m_qnnFunctionPointers.qnnSystemInterface.systemContextGetBinaryInfo ||
318
+ nullptr == m_qnnFunctionPointers.qnnSystemInterface.systemContextFree) {
319
+ QNN_ERROR("QNN System function pointers are not populated.");
320
+ return StatusCode::FAILURE;
321
+ }
322
+ uint64_t bufferSize{0};
323
+ std::shared_ptr<uint8_t> buffer{nullptr};
324
+ // read serialized binary into a byte buffer
325
+ tools::datautil::StatusCode status{tools::datautil::StatusCode::SUCCESS};
326
+ std::tie(status, bufferSize) = tools::datautil::getFileSize(m_cachedBinaryPath);
327
+ if (0 == bufferSize) {
328
+ QNN_ERROR("Received path to an empty file. Nothing to deserialize.");
329
+ return StatusCode::FAILURE;
330
+ }
331
+ buffer = std::shared_ptr<uint8_t>(new uint8_t[bufferSize], std::default_delete<uint8_t[]>());
332
+ if (!buffer) {
333
+ QNN_ERROR("Failed to allocate memory.");
334
+ return StatusCode::FAILURE;
335
+ }
336
+
337
+ status = tools::datautil::readBinaryFromFile(
338
+ m_cachedBinaryPath, reinterpret_cast<uint8_t*>(buffer.get()), bufferSize);
339
+ if (status != tools::datautil::StatusCode::SUCCESS) {
340
+ QNN_ERROR("Failed to read binary data.");
341
+ return StatusCode::FAILURE;
342
+ }
343
+
344
+ // inspect binary info
345
+ auto returnStatus = StatusCode::SUCCESS;
346
+ QnnSystemContext_Handle_t sysCtxHandle{nullptr};
347
+ if (QNN_SUCCESS != m_qnnFunctionPointers.qnnSystemInterface.systemContextCreate(&sysCtxHandle)) {
348
+ QNN_ERROR("Could not create system handle.");
349
+ returnStatus = StatusCode::FAILURE;
350
+ }
351
+ const QnnSystemContext_BinaryInfo_t* binaryInfo{nullptr};
352
+ Qnn_ContextBinarySize_t binaryInfoSize{0};
353
+ if (StatusCode::SUCCESS == returnStatus &&
354
+ QNN_SUCCESS != m_qnnFunctionPointers.qnnSystemInterface.systemContextGetBinaryInfo(
355
+ sysCtxHandle,
356
+ static_cast<void*>(buffer.get()),
357
+ bufferSize,
358
+ &binaryInfo,
359
+ &binaryInfoSize)) {
360
+ QNN_ERROR("Failed to get context binary info");
361
+ returnStatus = StatusCode::FAILURE;
362
+ }
363
+
364
+ // fill GraphInfo_t based on binary info
365
+ if (StatusCode::SUCCESS == returnStatus &&
366
+ !copyMetadataToGraphsInfo(binaryInfo, m_graphsInfo, m_graphsCount)) {
367
+ QNN_ERROR("Failed to copy metadata.");
368
+ returnStatus = StatusCode::FAILURE;
369
+ }
370
+ m_qnnFunctionPointers.qnnSystemInterface.systemContextFree(sysCtxHandle);
371
+ sysCtxHandle = nullptr;
372
+
373
+ if (StatusCode::SUCCESS == returnStatus &&
374
+ nullptr == m_qnnFunctionPointers.qnnInterface.contextCreateFromBinary) {
375
+ QNN_ERROR("contextCreateFromBinaryFnHandle is nullptr.");
376
+ returnStatus = StatusCode::FAILURE;
377
+ }
378
+ if (StatusCode::SUCCESS == returnStatus &&
379
+ m_qnnFunctionPointers.qnnInterface.contextCreateFromBinary(
380
+ m_backendHandle,
381
+ m_deviceHandle,
382
+ (const QnnContext_Config_t**)m_contextConfig,
383
+ static_cast<void*>(buffer.get()),
384
+ bufferSize,
385
+ &m_context,
386
+ m_profileBackendHandle)) {
387
+ QNN_ERROR("Could not create context from binary.");
388
+ returnStatus = StatusCode::FAILURE;
389
+ }
390
+ if (ProfilingLevel::OFF != m_profilingLevel) {
391
+ extractBackendProfilingInfo(m_profileBackendHandle);
392
+ }
393
+ m_isContextCreated = true;
394
+ if (StatusCode::SUCCESS == returnStatus) {
395
+ for (size_t graphIdx = 0; graphIdx < m_graphsCount; graphIdx++) {
396
+ if (nullptr == m_qnnFunctionPointers.qnnInterface.graphRetrieve) {
397
+ QNN_ERROR("graphRetrieveFnHandle is nullptr.");
398
+ returnStatus = StatusCode::FAILURE;
399
+ break;
400
+ }
401
+ if (QNN_SUCCESS !=
402
+ m_qnnFunctionPointers.qnnInterface.graphRetrieve(
403
+ m_context, (*m_graphsInfo)[graphIdx].graphName, &((*m_graphsInfo)[graphIdx].graph))) {
404
+ QNN_ERROR("Unable to retrieve graph handle for graph Idx: %d", graphIdx);
405
+ returnStatus = StatusCode::FAILURE;
406
+ }
407
+ }
408
+ }
409
+ if (StatusCode::SUCCESS != returnStatus) {
410
+ QNN_DEBUG("Cleaning up graph Info structures.");
411
+ qnn_wrapper_api::freeGraphsInfo(&m_graphsInfo, m_graphsCount);
412
+ }
413
+ return returnStatus;
414
+ }
415
+
416
+ sample_app::StatusCode sample_app::QnnSampleApp::saveBinary() {
417
+ if (m_saveBinaryName.empty()) {
418
+ QNN_ERROR("No name provided to save binary file.");
419
+ return StatusCode::FAILURE;
420
+ }
421
+ if (nullptr == m_qnnFunctionPointers.qnnInterface.contextGetBinarySize ||
422
+ nullptr == m_qnnFunctionPointers.qnnInterface.contextGetBinary) {
423
+ QNN_ERROR("contextGetBinarySizeFnHandle or contextGetBinaryFnHandle is nullptr.");
424
+ return StatusCode::FAILURE;
425
+ }
426
+ uint64_t requiredBufferSize{0};
427
+ if (QNN_CONTEXT_NO_ERROR !=
428
+ m_qnnFunctionPointers.qnnInterface.contextGetBinarySize(m_context, &requiredBufferSize)) {
429
+ QNN_ERROR("Could not get the required binary size.");
430
+ return StatusCode::FAILURE;
431
+ }
432
+ std::unique_ptr<uint8_t[]> saveBuffer(new uint8_t[requiredBufferSize]);
433
+ if (nullptr == saveBuffer) {
434
+ QNN_ERROR("Could not allocate buffer to save binary.");
435
+ return StatusCode::FAILURE;
436
+ }
437
+ uint64_t writtenBufferSize{0};
438
+ if (QNN_CONTEXT_NO_ERROR !=
439
+ m_qnnFunctionPointers.qnnInterface.contextGetBinary(m_context,
440
+ reinterpret_cast<void*>(saveBuffer.get()),
441
+ requiredBufferSize,
442
+ &writtenBufferSize)) {
443
+ QNN_ERROR("Could not get binary.");
444
+ return StatusCode::FAILURE;
445
+ }
446
+ if (requiredBufferSize < writtenBufferSize) {
447
+ QNN_ERROR(
448
+ "Illegal written buffer size [%d] bytes. Cannot exceed allocated memory of [%d] bytes",
449
+ writtenBufferSize,
450
+ requiredBufferSize);
451
+ return StatusCode::FAILURE;
452
+ }
453
+ #ifndef __hexagon__
454
+ auto dataUtilStatus = tools::datautil::writeBinaryToFile(
455
+ m_outputPath, m_saveBinaryName + ".bin", (uint8_t*)saveBuffer.get(), writtenBufferSize);
456
+ if (tools::datautil::StatusCode::SUCCESS != dataUtilStatus) {
457
+ QNN_ERROR("Error while writing binary to file.");
458
+ return StatusCode::FAILURE;
459
+ }
460
+ #endif
461
+ return StatusCode::SUCCESS;
462
+ }
463
+
464
+ sample_app::StatusCode sample_app::QnnSampleApp::extractBackendProfilingInfo(
465
+ Qnn_ProfileHandle_t profileHandle) {
466
+ if (nullptr == m_profileBackendHandle) {
467
+ QNN_ERROR("Backend Profile handle is nullptr; may not be initialized.");
468
+ return StatusCode::FAILURE;
469
+ }
470
+ const QnnProfile_EventId_t* profileEvents{nullptr};
471
+ uint32_t numEvents{0};
472
+ if (QNN_PROFILE_NO_ERROR != m_qnnFunctionPointers.qnnInterface.profileGetEvents(
473
+ profileHandle, &profileEvents, &numEvents)) {
474
+ QNN_ERROR("Failure in profile get events.");
475
+ return StatusCode::FAILURE;
476
+ }
477
+ QNN_DEBUG("ProfileEvents: [%p], numEvents: [%d]", profileEvents, numEvents);
478
+ for (size_t event = 0; event < numEvents; event++) {
479
+ extractProfilingEvent(*(profileEvents + event));
480
+ extractProfilingSubEvents(*(profileEvents + event));
481
+ }
482
+ return StatusCode::SUCCESS;
483
+ }
484
+
485
+ sample_app::StatusCode sample_app::QnnSampleApp::extractProfilingSubEvents(
486
+ QnnProfile_EventId_t profileEventId) {
487
+ const QnnProfile_EventId_t* profileSubEvents{nullptr};
488
+ uint32_t numSubEvents{0};
489
+ if (QNN_PROFILE_NO_ERROR != m_qnnFunctionPointers.qnnInterface.profileGetSubEvents(
490
+ profileEventId, &profileSubEvents, &numSubEvents)) {
491
+ QNN_ERROR("Failure in profile get sub events.");
492
+ return StatusCode::FAILURE;
493
+ }
494
+ QNN_DEBUG("ProfileSubEvents: [%p], numSubEvents: [%d]", profileSubEvents, numSubEvents);
495
+ for (size_t subEvent = 0; subEvent < numSubEvents; subEvent++) {
496
+ extractProfilingEvent(*(profileSubEvents + subEvent));
497
+ extractProfilingSubEvents(*(profileSubEvents + subEvent));
498
+ }
499
+ return StatusCode::SUCCESS;
500
+ }
501
+
502
+ sample_app::StatusCode sample_app::QnnSampleApp::extractProfilingEvent(
503
+ QnnProfile_EventId_t profileEventId) {
504
+ QnnProfile_EventData_t eventData;
505
+ if (QNN_PROFILE_NO_ERROR !=
506
+ m_qnnFunctionPointers.qnnInterface.profileGetEventData(profileEventId, &eventData)) {
507
+ QNN_ERROR("Failure in profile get event type.");
508
+ return StatusCode::FAILURE;
509
+ }
510
+ QNN_DEBUG("Printing Event Info - Event Type: [%d], Event Value: [%" PRIu64
511
+ "], Event Identifier: [%s], Event Unit: [%d]",
512
+ eventData.type,
513
+ eventData.value,
514
+ eventData.identifier,
515
+ eventData.unit);
516
+ return StatusCode::SUCCESS;
517
+ }
518
+
519
+ sample_app::StatusCode sample_app::QnnSampleApp::verifyFailReturnStatus(Qnn_ErrorHandle_t errCode) {
520
+ auto returnStatus = sample_app::StatusCode::FAILURE;
521
+ switch (errCode) {
522
+ case QNN_COMMON_ERROR_SYSTEM_COMMUNICATION:
523
+ returnStatus = sample_app::StatusCode::FAILURE_SYSTEM_COMMUNICATION_ERROR;
524
+ break;
525
+ case QNN_COMMON_ERROR_SYSTEM:
526
+ returnStatus = sample_app::StatusCode::FAILURE_SYSTEM_ERROR;
527
+ break;
528
+ case QNN_COMMON_ERROR_NOT_SUPPORTED:
529
+ returnStatus = sample_app::StatusCode::QNN_FEATURE_UNSUPPORTED;
530
+ break;
531
+ default:
532
+ break;
533
+ }
534
+ return returnStatus;
535
+ }
536
+
537
+ sample_app::StatusCode sample_app::QnnSampleApp::isDevicePropertySupported() {
538
+ if (nullptr != m_qnnFunctionPointers.qnnInterface.propertyHasCapability) {
539
+ auto qnnStatus =
540
+ m_qnnFunctionPointers.qnnInterface.propertyHasCapability(QNN_PROPERTY_GROUP_DEVICE);
541
+ if (QNN_PROPERTY_NOT_SUPPORTED == qnnStatus) {
542
+ QNN_WARN("Device property is not supported");
543
+ }
544
+ if (QNN_PROPERTY_ERROR_UNKNOWN_KEY == qnnStatus) {
545
+ QNN_ERROR("Device property is not known to backend");
546
+ return StatusCode::FAILURE;
547
+ }
548
+ }
549
+ return StatusCode::SUCCESS;
550
+ }
551
+
552
+ sample_app::StatusCode sample_app::QnnSampleApp::createDevice() {
553
+ if (nullptr != m_qnnFunctionPointers.qnnInterface.deviceCreate) {
554
+ auto qnnStatus =
555
+ m_qnnFunctionPointers.qnnInterface.deviceCreate(m_logHandle, nullptr, &m_deviceHandle);
556
+ if (QNN_SUCCESS != qnnStatus && QNN_DEVICE_ERROR_UNSUPPORTED_FEATURE != qnnStatus) {
557
+ QNN_ERROR("Failed to create device");
558
+ return verifyFailReturnStatus(qnnStatus);
559
+ }
560
+ }
561
+ return StatusCode::SUCCESS;
562
+ }
563
+
564
+ sample_app::StatusCode sample_app::QnnSampleApp::freeDevice() {
565
+ if (nullptr != m_qnnFunctionPointers.qnnInterface.deviceFree) {
566
+ auto qnnStatus = m_qnnFunctionPointers.qnnInterface.deviceFree(m_deviceHandle);
567
+ if (QNN_SUCCESS != qnnStatus && QNN_DEVICE_ERROR_UNSUPPORTED_FEATURE != qnnStatus) {
568
+ QNN_ERROR("Failed to free device");
569
+ return verifyFailReturnStatus(qnnStatus);
570
+ }
571
+ }
572
+ return StatusCode::SUCCESS;
573
+ }
574
+
575
+ // executeGraphs() that is currently used by qnn-sample-app's main.cpp.
576
+ // This function runs all the graphs present in model.so by reading
577
+ // inputs from input_list based files and writes output to .raw files.
578
+ sample_app::StatusCode sample_app::QnnSampleApp::executeGraphs() {
579
+ auto returnStatus = StatusCode::SUCCESS;
580
+ for (size_t graphIdx = 0; graphIdx < m_graphsCount; graphIdx++) {
581
+ QNN_DEBUG("Starting execution for graphIdx: %d", graphIdx);
582
+ if (graphIdx >= m_inputFileLists.size()) {
583
+ QNN_ERROR("No Inputs available for: %d", graphIdx);
584
+ returnStatus = StatusCode::FAILURE;
585
+ break;
586
+ }
587
+ Qnn_Tensor_t* inputs = nullptr;
588
+ Qnn_Tensor_t* outputs = nullptr;
589
+ if (iotensor::StatusCode::SUCCESS !=
590
+ m_ioTensor.setupInputAndOutputTensors(&inputs, &outputs, (*m_graphsInfo)[graphIdx])) {
591
+ QNN_ERROR("Error in setting up Input and output Tensors for graphIdx: %d", graphIdx);
592
+ returnStatus = StatusCode::FAILURE;
593
+ break;
594
+ }
595
+ auto inputFileList = m_inputFileLists[graphIdx];
596
+ auto graphInfo = (*m_graphsInfo)[graphIdx];
597
+ if (!inputFileList.empty()) {
598
+ size_t totalCount = inputFileList[0].size();
599
+ size_t inputFileIndexOffset = 0;
600
+ while (inputFileIndexOffset < totalCount) {
601
+ iotensor::StatusCode iotReturnStatus;
602
+ size_t numInputFilesPopulated;
603
+ size_t batchSize;
604
+ std::tie(iotReturnStatus, numInputFilesPopulated, batchSize) =
605
+ m_ioTensor.populateInputTensors(graphIdx,
606
+ inputFileList,
607
+ inputFileIndexOffset,
608
+ false,
609
+ m_inputNameToIndex[graphIdx],
610
+ inputs,
611
+ graphInfo,
612
+ m_inputDataType);
613
+ if (iotensor::StatusCode::SUCCESS != iotReturnStatus) {
614
+ returnStatus = StatusCode::FAILURE;
615
+ }
616
+ if (StatusCode::SUCCESS == returnStatus) {
617
+ QNN_DEBUG("Successfully populated input tensors for graphIdx: %d", graphIdx);
618
+ Qnn_ErrorHandle_t executeStatus = QNN_GRAPH_NO_ERROR;
619
+ executeStatus =
620
+ m_qnnFunctionPointers.qnnInterface.graphExecute(graphInfo.graph,
621
+ inputs,
622
+ graphInfo.numInputTensors,
623
+ outputs,
624
+ graphInfo.numOutputTensors,
625
+ m_profileBackendHandle,
626
+ nullptr);
627
+ if (QNN_GRAPH_NO_ERROR != executeStatus) {
628
+ returnStatus = StatusCode::FAILURE;
629
+ }
630
+ if (StatusCode::SUCCESS == returnStatus) {
631
+ QNN_DEBUG("Successfully executed graphIdx: %d ", graphIdx);
632
+ #ifndef __hexagon__
633
+ if (iotensor::StatusCode::SUCCESS !=
634
+ m_ioTensor.writeOutputTensors(graphIdx,
635
+ inputFileIndexOffset,
636
+ graphInfo.graphName,
637
+ outputs,
638
+ graphInfo.numOutputTensors,
639
+ m_outputDataType,
640
+ m_graphsCount,
641
+ m_outputPath,
642
+ numInputFilesPopulated,
643
+ batchSize)) {
644
+ returnStatus = StatusCode::FAILURE;
645
+ }
646
+ #endif
647
+ }
648
+ inputFileIndexOffset += numInputFilesPopulated;
649
+ }
650
+ if (StatusCode::SUCCESS != returnStatus) {
651
+ QNN_ERROR("Execution of Graph: %d failed!", graphIdx);
652
+ break;
653
+ }
654
+ }
655
+ }
656
+ m_ioTensor.tearDownInputAndOutputTensors(
657
+ inputs, outputs, graphInfo.numInputTensors, graphInfo.numOutputTensors);
658
+ inputs = nullptr;
659
+ outputs = nullptr;
660
+ if (StatusCode::SUCCESS != returnStatus) {
661
+ break;
662
+ }
663
+ }
664
+
665
+ qnn_wrapper_api::freeGraphsInfo(&m_graphsInfo, m_graphsCount);
666
+ m_graphsInfo = nullptr;
667
+ return returnStatus;
668
+ }
SampleApp/src/QnnSampleApp.hpp ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2020-2023 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+ #pragma once
9
+
10
+ #include <memory>
11
+ #include <queue>
12
+
13
+ #include "IOTensor.hpp"
14
+ #include "SampleApp.hpp"
15
+
16
+ namespace qnn {
17
+ namespace tools {
18
+ namespace sample_app {
19
+
20
+ enum class StatusCode {
21
+ SUCCESS,
22
+ FAILURE,
23
+ FAILURE_INPUT_LIST_EXHAUSTED,
24
+ FAILURE_SYSTEM_ERROR,
25
+ FAILURE_SYSTEM_COMMUNICATION_ERROR,
26
+ QNN_FEATURE_UNSUPPORTED
27
+ };
28
+
29
+ class QnnSampleApp {
30
+ public:
31
+ QnnSampleApp(QnnFunctionPointers qnnFunctionPointers,
32
+ std::string inputListPaths,
33
+ std::string opPackagePaths,
34
+ void *backendHandle,
35
+ std::string outputPath = s_defaultOutputPath,
36
+ bool debug = false,
37
+ iotensor::OutputDataType outputDataType = iotensor::OutputDataType::FLOAT_ONLY,
38
+ iotensor::InputDataType inputDataType = iotensor::InputDataType::FLOAT,
39
+ ProfilingLevel profilingLevel = ProfilingLevel::OFF,
40
+ bool dumpOutputs = false,
41
+ std::string cachedBinaryPath = "",
42
+ std::string saveBinaryName = "");
43
+
44
+ // @brief Print a message to STDERR then return a nonzero
45
+ // exit status.
46
+ int32_t reportError(const std::string &err);
47
+
48
+ StatusCode initialize();
49
+
50
+ StatusCode initializeBackend();
51
+
52
+ StatusCode createContext();
53
+
54
+ StatusCode composeGraphs();
55
+
56
+ StatusCode finalizeGraphs();
57
+
58
+ StatusCode executeGraphs();
59
+
60
+ StatusCode registerOpPackages();
61
+
62
+ StatusCode createFromBinary();
63
+
64
+ StatusCode saveBinary();
65
+
66
+ StatusCode freeContext();
67
+
68
+ StatusCode terminateBackend();
69
+
70
+ StatusCode freeGraphs();
71
+
72
+ Qnn_ContextHandle_t getContext();
73
+
74
+ StatusCode initializeProfiling();
75
+
76
+ std::string getBackendBuildId();
77
+
78
+ StatusCode isDevicePropertySupported();
79
+
80
+ StatusCode createDevice();
81
+
82
+ StatusCode freeDevice();
83
+
84
+ StatusCode verifyFailReturnStatus(Qnn_ErrorHandle_t errCode);
85
+
86
+ virtual ~QnnSampleApp();
87
+
88
+ private:
89
+ StatusCode extractBackendProfilingInfo(Qnn_ProfileHandle_t profileHandle);
90
+
91
+ StatusCode extractProfilingSubEvents(QnnProfile_EventId_t profileEventId);
92
+
93
+ StatusCode extractProfilingEvent(QnnProfile_EventId_t profileEventId);
94
+
95
+ static const std::string s_defaultOutputPath;
96
+
97
+ QnnFunctionPointers m_qnnFunctionPointers;
98
+ std::vector<std::string> m_inputListPaths;
99
+ std::vector<std::vector<std::vector<std::string>>> m_inputFileLists;
100
+ std::vector<std::unordered_map<std::string, uint32_t>> m_inputNameToIndex;
101
+ std::vector<std::string> m_opPackagePaths;
102
+ std::string m_outputPath;
103
+ std::string m_saveBinaryName;
104
+ std::string m_cachedBinaryPath;
105
+ QnnBackend_Config_t **m_backendConfig = nullptr;
106
+ Qnn_ContextHandle_t m_context = nullptr;
107
+ QnnContext_Config_t **m_contextConfig = nullptr;
108
+ bool m_debug;
109
+ iotensor::OutputDataType m_outputDataType;
110
+ iotensor::InputDataType m_inputDataType;
111
+ ProfilingLevel m_profilingLevel;
112
+ bool m_dumpOutputs;
113
+ qnn_wrapper_api::GraphInfo_t **m_graphsInfo;
114
+ uint32_t m_graphsCount;
115
+ void *m_backendLibraryHandle;
116
+ iotensor::IOTensor m_ioTensor;
117
+ bool m_isBackendInitialized;
118
+ bool m_isContextCreated;
119
+ Qnn_ProfileHandle_t m_profileBackendHandle = nullptr;
120
+ qnn_wrapper_api::GraphConfigInfo_t **m_graphConfigsInfo = nullptr;
121
+ uint32_t m_graphConfigsInfoCount;
122
+ Qnn_LogHandle_t m_logHandle = nullptr;
123
+ Qnn_BackendHandle_t m_backendHandle = nullptr;
124
+ Qnn_DeviceHandle_t m_deviceHandle = nullptr;
125
+ };
126
+ } // namespace sample_app
127
+ } // namespace tools
128
+ } // namespace qnn
SampleApp/src/QnnTypeMacros.hpp ADDED
@@ -0,0 +1,668 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2021-2024 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #pragma once
10
+
11
+ #include "QnnTypes.h"
12
+
13
+ #define QNN_OP_CFG_VALID(opConfig) ((opConfig).version == QNN_OPCONFIG_VERSION_1)
14
+
15
+ inline Qnn_OpConfig_t createQnnOpConfig(const Qnn_OpConfigVersion_t version) {
16
+ Qnn_OpConfig_t opConfig = QNN_OPCONFIG_INIT;
17
+ opConfig.version = version;
18
+ if (version == QNN_OPCONFIG_VERSION_1) {
19
+ opConfig.v1 = QNN_OPCONFIG_V1_INIT;
20
+ }
21
+ return opConfig;
22
+ }
23
+
24
+ inline const char* getQnnOpConfigName(const Qnn_OpConfig_t& opConfig) {
25
+ if (opConfig.version == QNN_OPCONFIG_VERSION_1) {
26
+ return opConfig.v1.name;
27
+ }
28
+ return NULL;
29
+ }
30
+
31
+ inline const char* getQnnOpConfigName(const Qnn_OpConfig_t* const opConfig) {
32
+ return getQnnOpConfigName(*opConfig);
33
+ }
34
+
35
+ inline const char* getQnnOpConfigPackageName(const Qnn_OpConfig_t& opConfig) {
36
+ if (opConfig.version == QNN_OPCONFIG_VERSION_1) {
37
+ return opConfig.v1.packageName;
38
+ }
39
+ return NULL;
40
+ }
41
+
42
+ inline const char* getQnnOpConfigPackageName(const Qnn_OpConfig_t* const opConfig) {
43
+ return getQnnOpConfigPackageName(*opConfig);
44
+ }
45
+
46
+ inline const char* getQnnOpConfigTypeName(const Qnn_OpConfig_t& opConfig) {
47
+ if (opConfig.version == QNN_OPCONFIG_VERSION_1) {
48
+ return opConfig.v1.typeName;
49
+ }
50
+ return NULL;
51
+ }
52
+
53
+ inline const char* getQnnOpConfigTypeName(const Qnn_OpConfig_t* const opConfig) {
54
+ return getQnnOpConfigTypeName(*opConfig);
55
+ }
56
+
57
+ inline uint32_t getQnnOpConfigNumParams(const Qnn_OpConfig_t& opConfig) {
58
+ if (opConfig.version == QNN_OPCONFIG_VERSION_1) {
59
+ return opConfig.v1.numOfParams;
60
+ }
61
+ return 0u;
62
+ }
63
+
64
+ inline uint32_t getQnnOpConfigNumParams(const Qnn_OpConfig_t* const opConfig) {
65
+ return getQnnOpConfigNumParams(*opConfig);
66
+ }
67
+
68
+ inline const Qnn_Param_t* getQnnOpConfigParams(const Qnn_OpConfig_t& opConfig) {
69
+ if (opConfig.version == QNN_OPCONFIG_VERSION_1) {
70
+ return opConfig.v1.params;
71
+ }
72
+ return NULL;
73
+ }
74
+
75
+ inline const Qnn_Param_t* getQnnOpConfigParams(const Qnn_OpConfig_t* const opConfig) {
76
+ return getQnnOpConfigParams(*opConfig);
77
+ }
78
+
79
+ inline uint32_t getQnnOpConfigNumInputs(const Qnn_OpConfig_t& opConfig) {
80
+ if (opConfig.version == QNN_OPCONFIG_VERSION_1) {
81
+ return opConfig.v1.numOfInputs;
82
+ }
83
+ return 0u;
84
+ }
85
+
86
+ inline uint32_t getQnnOpConfigNumInputs(const Qnn_OpConfig_t* const opConfig) {
87
+ return getQnnOpConfigNumInputs(*opConfig);
88
+ }
89
+
90
+ inline const Qnn_Tensor_t* getQnnOpConfigInputs(const Qnn_OpConfig_t& opConfig) {
91
+ if (opConfig.version == QNN_OPCONFIG_VERSION_1) {
92
+ return opConfig.v1.inputTensors;
93
+ }
94
+ return NULL;
95
+ }
96
+
97
+ inline const Qnn_Tensor_t* getQnnOpConfigInputs(const Qnn_OpConfig_t* const opConfig) {
98
+ return getQnnOpConfigInputs(*opConfig);
99
+ }
100
+
101
+ inline uint32_t getQnnOpConfigNumOutputs(const Qnn_OpConfig_t& opConfig) {
102
+ if (opConfig.version == QNN_OPCONFIG_VERSION_1) {
103
+ return opConfig.v1.numOfOutputs;
104
+ }
105
+ return 0u;
106
+ }
107
+
108
+ inline uint32_t getQnnOpConfigNumOutputs(const Qnn_OpConfig_t* const opConfig) {
109
+ return getQnnOpConfigNumOutputs(*opConfig);
110
+ }
111
+
112
+ inline const Qnn_Tensor_t* getQnnOpConfigOutputs(const Qnn_OpConfig_t& opConfig) {
113
+ if (opConfig.version == QNN_OPCONFIG_VERSION_1) {
114
+ return opConfig.v1.outputTensors;
115
+ }
116
+ return NULL;
117
+ }
118
+
119
+ inline const Qnn_Tensor_t* getQnnOpConfigOutputs(const Qnn_OpConfig_t* const opConfig) {
120
+ return getQnnOpConfigOutputs(*opConfig);
121
+ }
122
+
123
+ inline void setQnnOpConfigName(Qnn_OpConfig_t& opConfig, const char* const name) {
124
+ if (opConfig.version == QNN_OPCONFIG_VERSION_1) {
125
+ opConfig.v1.name = name;
126
+ }
127
+ }
128
+
129
+ inline void setQnnOpConfigName(Qnn_OpConfig_t* const opConfig, const char* const name) {
130
+ setQnnOpConfigName(*opConfig, name);
131
+ }
132
+
133
+ inline void setQnnOpConfigPackageName(Qnn_OpConfig_t& opConfig, const char* const packageName) {
134
+ if (opConfig.version == QNN_OPCONFIG_VERSION_1) {
135
+ opConfig.v1.packageName = packageName;
136
+ }
137
+ }
138
+
139
+ inline void setQnnOpConfigPackageName(Qnn_OpConfig_t* const opConfig,
140
+ const char* const packageName) {
141
+ setQnnOpConfigPackageName(*opConfig, packageName);
142
+ }
143
+
144
+ inline void setQnnOpConfigTypeName(Qnn_OpConfig_t& opConfig, const char* const typeName) {
145
+ if (opConfig.version == QNN_OPCONFIG_VERSION_1) {
146
+ opConfig.v1.typeName = typeName;
147
+ }
148
+ }
149
+
150
+ inline void setQnnOpConfigTypeName(Qnn_OpConfig_t* const opConfig, const char* const typeName) {
151
+ setQnnOpConfigTypeName(*opConfig, typeName);
152
+ }
153
+
154
+ inline void setQnnOpConfigParams(Qnn_OpConfig_t& opConfig,
155
+ uint32_t const numOfParams,
156
+ Qnn_Param_t* const params) {
157
+ if (opConfig.version == QNN_OPCONFIG_VERSION_1) {
158
+ opConfig.v1.numOfParams = numOfParams;
159
+ opConfig.v1.params = params;
160
+ }
161
+ }
162
+
163
+ inline void setQnnOpConfigParams(Qnn_OpConfig_t* const opConfig,
164
+ uint32_t const numOfParams,
165
+ Qnn_Param_t* const params) {
166
+ setQnnOpConfigParams(*opConfig, numOfParams, params);
167
+ }
168
+
169
+ inline void setQnnOpConfigInputs(Qnn_OpConfig_t& opConfig,
170
+ uint32_t const numOfInputs,
171
+ Qnn_Tensor_t* const inputTensors) {
172
+ if (opConfig.version == QNN_OPCONFIG_VERSION_1) {
173
+ opConfig.v1.numOfInputs = numOfInputs;
174
+ opConfig.v1.inputTensors = inputTensors;
175
+ }
176
+ }
177
+
178
+ inline void setQnnOpConfigInputs(Qnn_OpConfig_t* const opConfig,
179
+ uint32_t const numOfInputs,
180
+ Qnn_Tensor_t* const inputTensors) {
181
+ setQnnOpConfigInputs(*opConfig, numOfInputs, inputTensors);
182
+ }
183
+
184
+ inline void setQnnOpConfigOutputs(Qnn_OpConfig_t& opConfig,
185
+ uint32_t const numOfOutputs,
186
+ Qnn_Tensor_t* const outputTensors) {
187
+ if (opConfig.version == QNN_OPCONFIG_VERSION_1) {
188
+ opConfig.v1.numOfOutputs = numOfOutputs;
189
+ opConfig.v1.outputTensors = outputTensors;
190
+ }
191
+ }
192
+
193
+ inline void setQnnOpConfigOutputs(Qnn_OpConfig_t* const opConfig,
194
+ uint32_t const numOfOutputs,
195
+ Qnn_Tensor_t* const outputTensors) {
196
+ setQnnOpConfigOutputs(*opConfig, numOfOutputs, outputTensors);
197
+ }
198
+
199
+ inline Qnn_Tensor_t createQnnTensor(const Qnn_TensorVersion_t version) {
200
+ Qnn_Tensor_t tensor = QNN_TENSOR_INIT;
201
+ tensor.version = version;
202
+ if (version == QNN_TENSOR_VERSION_1) {
203
+ tensor.v1 = QNN_TENSOR_V1_INIT;
204
+ } else if (version == QNN_TENSOR_VERSION_2) {
205
+ tensor.v2 = QNN_TENSOR_V2_INIT;
206
+ }
207
+ return tensor;
208
+ }
209
+
210
+ inline uint32_t getQnnTensorId(const Qnn_Tensor_t& tensor) {
211
+ // TensorCompatTest justifies no need to check version
212
+ return tensor.v1.id;
213
+ }
214
+
215
+ inline uint32_t getQnnTensorId(const Qnn_Tensor_t* const tensor) { return getQnnTensorId(*tensor); }
216
+
217
+ inline const char* getQnnTensorName(const Qnn_Tensor_t& tensor) {
218
+ // TensorCompatTest justifies no need to check version
219
+ return tensor.v1.name;
220
+ }
221
+
222
+ inline const char* getQnnTensorName(const Qnn_Tensor_t* const tensor) {
223
+ return getQnnTensorName(*tensor);
224
+ }
225
+
226
+ inline Qnn_TensorType_t getQnnTensorType(const Qnn_Tensor_t& tensor) {
227
+ // TensorCompatTest justifies no need to check version
228
+ return tensor.v1.type;
229
+ }
230
+
231
+ inline Qnn_TensorType_t getQnnTensorType(const Qnn_Tensor_t* const tensor) {
232
+ return getQnnTensorType(*tensor);
233
+ }
234
+
235
+ inline Qnn_TensorDataFormat_t getQnnTensorDataFormat(const Qnn_Tensor_t& tensor) {
236
+ // TensorCompatTest justifies no need to check version
237
+ return tensor.v1.dataFormat;
238
+ }
239
+
240
+ inline Qnn_TensorDataFormat_t getQnnTensorDataFormat(const Qnn_Tensor_t* const tensor) {
241
+ return getQnnTensorDataFormat(*tensor);
242
+ }
243
+
244
+ inline Qnn_DataType_t getQnnTensorDataType(const Qnn_Tensor_t& tensor) {
245
+ // TensorCompatTest justifies no need to check version
246
+ return tensor.v1.dataType;
247
+ }
248
+
249
+ inline Qnn_DataType_t getQnnTensorDataType(const Qnn_Tensor_t* const tensor) {
250
+ return getQnnTensorDataType(*tensor);
251
+ }
252
+
253
+ inline Qnn_QuantizeParams_t getQnnTensorQuantParams(const Qnn_Tensor_t& tensor) {
254
+ // TensorCompatTest justifies no need to check version
255
+ return tensor.v1.quantizeParams;
256
+ }
257
+
258
+ inline Qnn_QuantizeParams_t getQnnTensorQuantParams(const Qnn_Tensor_t* const tensor) {
259
+ if (tensor != nullptr) {
260
+ return getQnnTensorQuantParams(*tensor);
261
+ }
262
+ return QNN_QUANTIZE_PARAMS_INIT;
263
+ }
264
+
265
+ inline uint32_t getQnnTensorRank(const Qnn_Tensor_t& tensor) {
266
+ // TensorCompatTest justifies no need to check version
267
+ return tensor.v1.rank;
268
+ }
269
+
270
+ inline uint32_t getQnnTensorRank(const Qnn_Tensor_t* const tensor) {
271
+ if (tensor != nullptr) {
272
+ return getQnnTensorRank(*tensor);
273
+ }
274
+ return 0u;
275
+ }
276
+
277
+ inline uint32_t* getQnnTensorDimensions(const Qnn_Tensor_t& tensor) {
278
+ // TensorCompatTest justifies no need to check version
279
+ return tensor.v1.dimensions;
280
+ }
281
+
282
+ inline uint32_t* getQnnTensorDimensions(const Qnn_Tensor_t* const tensor) {
283
+ return getQnnTensorDimensions(*tensor);
284
+ }
285
+
286
+ inline uint8_t* getQnnTensorIsDynamicDimensions(const Qnn_Tensor_t& tensor) {
287
+ if (tensor.version == QNN_TENSOR_VERSION_1) {
288
+ return NULL;
289
+ } else if (tensor.version == QNN_TENSOR_VERSION_2) {
290
+ return tensor.v2.isDynamicDimensions;
291
+ }
292
+ return NULL;
293
+ }
294
+
295
+ inline uint8_t* getQnnTensorIsDynamicDimensions(const Qnn_Tensor_t* tensor) {
296
+ return getQnnTensorIsDynamicDimensions(*tensor);
297
+ }
298
+
299
+ inline Qnn_SparseParams_t getQnnTensorSparseParams(const Qnn_Tensor_t& tensor) {
300
+ if (tensor.version == QNN_TENSOR_VERSION_1) {
301
+ return QNN_SPARSE_PARAMS_INIT;
302
+ } else if (tensor.version == QNN_TENSOR_VERSION_2) {
303
+ return tensor.v2.sparseParams;
304
+ }
305
+ return QNN_SPARSE_PARAMS_INIT;
306
+ }
307
+
308
+ inline Qnn_SparseParams_t getQnnTensorSparseParams(const Qnn_Tensor_t* tensor) {
309
+ return getQnnTensorSparseParams(*tensor);
310
+ }
311
+
312
+ inline Qnn_TensorMemType_t getQnnTensorMemType(const Qnn_Tensor_t& tensor) {
313
+ // TensorCompatTest justifies no need to check version
314
+ return tensor.v1.memType;
315
+ }
316
+
317
+ inline Qnn_TensorMemType_t getQnnTensorMemType(const Qnn_Tensor_t* const tensor) {
318
+ return getQnnTensorMemType(*tensor);
319
+ }
320
+
321
+ inline Qnn_ClientBuffer_t getQnnTensorClientBuf(const Qnn_Tensor_t& tensor) {
322
+ // TensorCompatTest justifies no need to check version
323
+ return tensor.v1.clientBuf;
324
+ }
325
+
326
+ inline Qnn_ClientBuffer_t getQnnTensorClientBuf(const Qnn_Tensor_t* const tensor) {
327
+ return getQnnTensorClientBuf(*tensor);
328
+ }
329
+
330
+ inline Qnn_MemHandle_t getQnnTensorMemHandle(const Qnn_Tensor_t& tensor) {
331
+ // TensorCompatTest justifies no need to check version
332
+ return tensor.v1.memHandle;
333
+ }
334
+
335
+ inline Qnn_MemHandle_t getQnnTensorMemHandle(const Qnn_Tensor_t* const tensor) {
336
+ return getQnnTensorMemHandle(*tensor);
337
+ }
338
+
339
+ inline void setQnnTensorId(Qnn_Tensor_t& tensor, const uint32_t id) {
340
+ // TensorCompatTest justifies no need to check version
341
+ tensor.v1.id = id;
342
+ }
343
+
344
+ inline void setQnnTensorId(Qnn_Tensor_t* const tensor, const uint32_t id) {
345
+ setQnnTensorId(*tensor, id);
346
+ }
347
+
348
+ inline void setQnnTensorName(Qnn_Tensor_t& tensor, const char* const name) {
349
+ // TensorCompatTest justifies no need to check version
350
+ tensor.v1.name = name;
351
+ }
352
+
353
+ inline void setQnnTensorName(Qnn_Tensor_t* const tensor, const char* const name) {
354
+ setQnnTensorName(*tensor, name);
355
+ }
356
+
357
+ inline void setQnnTensorType(Qnn_Tensor_t& tensor, const Qnn_TensorType_t type) {
358
+ // TensorCompatTest justifies no need to check version
359
+ tensor.v1.type = type;
360
+ }
361
+
362
+ inline void setQnnTensorType(Qnn_Tensor_t* const tensor, const Qnn_TensorType_t type) {
363
+ setQnnTensorType(*tensor, type);
364
+ }
365
+
366
+ inline void setQnnTensorDataFormat(Qnn_Tensor_t& tensor, const Qnn_TensorDataFormat_t dataFormat) {
367
+ // TensorCompatTest justifies no need to check version
368
+ tensor.v1.dataFormat = dataFormat;
369
+ }
370
+
371
+ inline void setQnnTensorDataFormat(Qnn_Tensor_t* const tensor,
372
+ const Qnn_TensorDataFormat_t format) {
373
+ setQnnTensorDataFormat(*tensor, format);
374
+ }
375
+
376
+ inline void setQnnTensorDataType(Qnn_Tensor_t& tensor, const Qnn_DataType_t dataType) {
377
+ // TensorCompatTest justifies no need to check version
378
+ tensor.v1.dataType = dataType;
379
+ }
380
+
381
+ inline void setQnnTensorDataType(Qnn_Tensor_t* const tensor, const Qnn_DataType_t dataType) {
382
+ setQnnTensorDataType(*tensor, dataType);
383
+ }
384
+
385
+ inline void setQnnTensorQuantParams(Qnn_Tensor_t& tensor,
386
+ const Qnn_QuantizeParams_t quantizeParams) {
387
+ // TensorCompatTest justifies no need to check version
388
+ tensor.v1.quantizeParams = quantizeParams;
389
+ }
390
+
391
+ inline void setQnnTensorQuantParams(Qnn_Tensor_t* const tensor, const Qnn_QuantizeParams_t params) {
392
+ setQnnTensorQuantParams(*tensor, params);
393
+ }
394
+
395
+ inline void setQnnTensorRank(Qnn_Tensor_t& tensor, const uint32_t rank) {
396
+ // TensorCompatTest justifies no need to check version
397
+ tensor.v1.rank = rank;
398
+ }
399
+
400
+ inline void setQnnTensorRank(Qnn_Tensor_t* const tensor, const uint32_t rank) {
401
+ setQnnTensorRank(*tensor, rank);
402
+ }
403
+
404
+ inline void setQnnTensorDimensions(Qnn_Tensor_t& tensor, uint32_t* const dimensions) {
405
+ // TensorCompatTest justifies no need to check version
406
+ tensor.v1.dimensions = dimensions;
407
+ }
408
+
409
+ inline void setQnnTensorDimensions(Qnn_Tensor_t* const tensor, uint32_t* const dimensions) {
410
+ setQnnTensorDimensions(*tensor, dimensions);
411
+ }
412
+
413
+ inline void setQnnTensorIsDynamicDimensions(Qnn_Tensor_t& tensor,
414
+ uint8_t* const isDynamicDimensions) {
415
+ if (tensor.version == QNN_TENSOR_VERSION_2) {
416
+ tensor.v2.isDynamicDimensions = isDynamicDimensions;
417
+ }
418
+ }
419
+
420
+ inline void setQnnTensorIsDynamicDimensions(Qnn_Tensor_t* tensor,
421
+ uint8_t* const isDynamicDimensions) {
422
+ setQnnTensorIsDynamicDimensions(*tensor, isDynamicDimensions);
423
+ }
424
+
425
+ inline void setQnnTensorSparseParams(Qnn_Tensor_t& tensor, const Qnn_SparseParams_t sparseParams) {
426
+ if (tensor.version == QNN_TENSOR_VERSION_2) {
427
+ tensor.v2.sparseParams = sparseParams;
428
+ }
429
+ }
430
+
431
+ inline void setQnnTensorSparseParams(Qnn_Tensor_t* tensor, Qnn_SparseParams_t sparseParams) {
432
+ setQnnTensorSparseParams(*tensor, sparseParams);
433
+ }
434
+
435
+ inline void setQnnTensorMemType(Qnn_Tensor_t& tensor, const Qnn_TensorMemType_t memType) {
436
+ // TensorCompatTest justifies no need to check version
437
+ tensor.v1.memType = memType;
438
+ }
439
+
440
+ inline void setQnnTensorMemType(Qnn_Tensor_t* const tensor, const Qnn_TensorMemType_t memType) {
441
+ setQnnTensorMemType(*tensor, memType);
442
+ }
443
+
444
+ inline void setQnnTensorClientBuf(Qnn_Tensor_t& tensor, const Qnn_ClientBuffer_t clientBuf) {
445
+ // TensorCompatTest justifies no need to check version
446
+ tensor.v1.clientBuf = clientBuf;
447
+ }
448
+
449
+ inline void setQnnTensorClientBuf(Qnn_Tensor_t* const tensor, const Qnn_ClientBuffer_t clientBuf) {
450
+ setQnnTensorClientBuf(*tensor, clientBuf);
451
+ }
452
+
453
+ inline void setQnnTensorMemHandle(Qnn_Tensor_t& tensor, const Qnn_MemHandle_t memHandle) {
454
+ // TensorCompatTest justifies no need to check version
455
+ tensor.v1.memHandle = memHandle;
456
+ }
457
+
458
+ inline void setQnnTensorMemHandle(Qnn_Tensor_t* const tensor, const Qnn_MemHandle_t handle) {
459
+ setQnnTensorMemHandle(*tensor, handle);
460
+ }
461
+
462
+ inline Qnn_TensorSet_t createQnnTensorSet(const Qnn_TensorSetVersion_t version) {
463
+ Qnn_TensorSet_t tensorSet = QNN_TENSOR_SET_INIT;
464
+ tensorSet.version = version;
465
+ if (version == QNN_TENSOR_SET_VERSION_1) {
466
+ tensorSet.v1 = QNN_TENSOR_SET_V1_INIT;
467
+ }
468
+ return tensorSet;
469
+ }
470
+
471
+ inline uint32_t getQnnTensorSetNumInputs(const Qnn_TensorSet_t& tensorSet) {
472
+ if (tensorSet.version == QNN_TENSOR_SET_VERSION_1) {
473
+ return tensorSet.v1.numInputs;
474
+ }
475
+ return 0;
476
+ }
477
+
478
+ inline uint32_t getQnnTensorSetNumInputs(const Qnn_TensorSet_t* tensorSet) {
479
+ return getQnnTensorSetNumInputs(*tensorSet);
480
+ }
481
+
482
+ inline Qnn_Tensor_t* getQnnTensorSetInputTensors(const Qnn_TensorSet_t& tensorSet) {
483
+ if (tensorSet.version == QNN_TENSOR_SET_VERSION_1) {
484
+ return tensorSet.v1.inputs;
485
+ }
486
+ return 0;
487
+ }
488
+
489
+ inline Qnn_Tensor_t* getQnnTensorSetInputTensors(const Qnn_TensorSet_t* tensorSet) {
490
+ return getQnnTensorSetInputTensors(*tensorSet);
491
+ }
492
+
493
+ inline uint32_t getQnnTensorSetNumOutputs(const Qnn_TensorSet_t& tensorSet) {
494
+ if (tensorSet.version == QNN_TENSOR_SET_VERSION_1) {
495
+ return tensorSet.v1.numOutputs;
496
+ }
497
+ return 0;
498
+ }
499
+
500
+ inline uint32_t getQnnTensorSetNumOutputs(const Qnn_TensorSet_t* tensorSet) {
501
+ return getQnnTensorSetNumOutputs(*tensorSet);
502
+ }
503
+
504
+ inline Qnn_Tensor_t* getQnnTensorSetOutputTensors(const Qnn_TensorSet_t& tensorSet) {
505
+ if (tensorSet.version == QNN_TENSOR_SET_VERSION_1) {
506
+ return tensorSet.v1.outputs;
507
+ }
508
+ return 0;
509
+ }
510
+
511
+ inline Qnn_Tensor_t* getQnnTensorSetOutputTensors(const Qnn_TensorSet_t* tensorSet) {
512
+ return getQnnTensorSetOutputTensors(*tensorSet);
513
+ }
514
+
515
+ inline void setQnnTensorSetInputTensors(Qnn_TensorSet_t& tensorSet,
516
+ Qnn_Tensor_t* inputTensors,
517
+ uint32_t const numInputs) {
518
+ if (tensorSet.version == QNN_TENSOR_SET_VERSION_1) {
519
+ tensorSet.v1.inputs = inputTensors;
520
+ tensorSet.v1.numInputs = numInputs;
521
+ }
522
+ }
523
+
524
+ inline void setQnnTensorSetInputTensors(Qnn_TensorSet_t* tensorSet,
525
+ Qnn_Tensor_t* inputTensors,
526
+ uint32_t const numInputs) {
527
+ setQnnTensorSetInputTensors(*tensorSet, inputTensors, numInputs);
528
+ }
529
+
530
+ inline void setQnnTensorSetOutputTensors(Qnn_TensorSet_t& tensorSet,
531
+ Qnn_Tensor_t* outputTensors,
532
+ const uint32_t numOutputs) {
533
+ if (tensorSet.version == QNN_TENSOR_SET_VERSION_1) {
534
+ tensorSet.v1.outputs = outputTensors;
535
+ tensorSet.v1.numOutputs = numOutputs;
536
+ }
537
+ }
538
+
539
+ inline void setQnnTensorSetOutputTensors(Qnn_TensorSet_t* tensorSet,
540
+ Qnn_Tensor_t* outputTensors,
541
+ const uint32_t numOutputs) {
542
+ setQnnTensorSetOutputTensors(*tensorSet, outputTensors, numOutputs);
543
+ }
544
+
545
+ // Creator for QNN Op Config
546
+ #define QNN_OP_CFG_CREATE(version) createQnnOpConfig(version)
547
+
548
+ // Accessors for QNN Op Config
549
+ #define QNN_OP_CFG_GET_NAME(opConfig) getQnnOpConfigName(opConfig)
550
+ #define QNN_OP_CFG_GET_PACKAGE_NAME(opConfig) getQnnOpConfigPackageName(opConfig)
551
+ #define QNN_OP_CFG_GET_TYPE_NAME(opConfig) getQnnOpConfigTypeName(opConfig)
552
+ #define QNN_OP_CFG_GET_NUM_PARAMS(opConfig) getQnnOpConfigNumParams(opConfig)
553
+ #define QNN_OP_CFG_GET_PARAMS(opConfig) getQnnOpConfigParams(opConfig)
554
+ #define QNN_OP_CFG_GET_NUM_INPUTS(opConfig) getQnnOpConfigNumInputs(opConfig)
555
+ #define QNN_OP_CFG_GET_INPUTS(opConfig) getQnnOpConfigInputs(opConfig)
556
+ #define QNN_OP_CFG_GET_NUM_OUTPUTS(opConfig) getQnnOpConfigNumOutputs(opConfig)
557
+ #define QNN_OP_CFG_GET_OUTPUTS(opConfig) getQnnOpConfigOutputs(opConfig)
558
+
559
+ // Modifiers for QNN Op Config
560
+ #define QNN_OP_CFG_SET_NAME(opConfig, value) setQnnOpConfigName(opConfig, value)
561
+ #define QNN_OP_CFG_SET_PACKAGE_NAME(opConfig, value) setQnnOpConfigPackageName(opConfig, value)
562
+ #define QNN_OP_CFG_SET_TYPE_NAME(opConfig, value) setQnnOpConfigTypeName(opConfig, value)
563
+ #define QNN_OP_CFG_SET_PARAMS(opConfig, numOfParams, params) \
564
+ setQnnOpConfigParams(opConfig, numOfParams, params)
565
+ #define QNN_OP_CFG_SET_INPUTS(opConfig, numOfInputs, inputTensors) \
566
+ setQnnOpConfigInputs(opConfig, numOfInputs, inputTensors)
567
+ #define QNN_OP_CFG_SET_OUTPUTS(opConfig, numOfOutputs, outputTensors) \
568
+ setQnnOpConfigOutputs(opConfig, numOfOutputs, outputTensors)
569
+
570
+ // Creator for QNN Tensor
571
+ #define QNN_TENSOR_CREATE(version) createQnnTensor(version)
572
+
573
+ // Accessors for QNN Tensor
574
+ #define QNN_TENSOR_GET_ID(tensor) getQnnTensorId(tensor)
575
+ #define QNN_TENSOR_GET_NAME(tensor) getQnnTensorName(tensor)
576
+ #define QNN_TENSOR_GET_TYPE(tensor) getQnnTensorType(tensor)
577
+ #define QNN_TENSOR_GET_DATA_FORMAT(tensor) getQnnTensorDataFormat(tensor)
578
+ #define QNN_TENSOR_GET_DATA_TYPE(tensor) getQnnTensorDataType(tensor)
579
+ #define QNN_TENSOR_GET_QUANT_PARAMS(tensor) getQnnTensorQuantParams(tensor)
580
+ #define QNN_TENSOR_GET_RANK(tensor) getQnnTensorRank(tensor)
581
+ #define QNN_TENSOR_GET_DIMENSIONS(tensor) getQnnTensorDimensions(tensor)
582
+ #define QNN_TENSOR_GET_IS_DYNAMIC_DIMENSIONS(tensor) getQnnTensorIsDynamicDimensions(tensor)
583
+ #define QNN_TENSOR_GET_SPARSE_PARAMS(tensor) getQnnTensorSparseParams(tensor)
584
+ #define QNN_TENSOR_GET_MEM_TYPE(tensor) getQnnTensorMemType(tensor)
585
+ #define QNN_TENSOR_GET_CLIENT_BUF(tensor) getQnnTensorClientBuf(tensor)
586
+ #define QNN_TENSOR_GET_MEM_HANDLE(tensor) getQnnTensorMemHandle(tensor)
587
+
588
+ // Modifiers for QNN Tensor
589
+ #define QNN_TENSOR_SET_ID(tensor, value) setQnnTensorId(tensor, value)
590
+ #define QNN_TENSOR_SET_NAME(tensor, value) setQnnTensorName(tensor, value)
591
+ #define QNN_TENSOR_SET_TYPE(tensor, value) setQnnTensorType(tensor, value)
592
+ #define QNN_TENSOR_SET_DATA_FORMAT(tensor, value) setQnnTensorDataFormat(tensor, value)
593
+ #define QNN_TENSOR_SET_DATA_TYPE(tensor, value) setQnnTensorDataType(tensor, value)
594
+ #define QNN_TENSOR_SET_QUANT_PARAMS(tensor, value) setQnnTensorQuantParams(tensor, value)
595
+ #define QNN_TENSOR_SET_RANK(tensor, value) setQnnTensorRank(tensor, value)
596
+ #define QNN_TENSOR_SET_DIMENSIONS(tensor, value) setQnnTensorDimensions(tensor, value)
597
+ #define QNN_TENSOR_SET_IS_DYNAMIC_DIMENSIONS(tensor, value) \
598
+ setQnnTensorIsDynamicDimensions(tensor, value)
599
+ #define QNN_TENSOR_SET_SPARSE_PARAMS(tensor, value) setQnnTensorSparseParams(tensor, value)
600
+ #define QNN_TENSOR_SET_MEM_TYPE(tensor, value) setQnnTensorMemType(tensor, value)
601
+ #define QNN_TENSOR_SET_CLIENT_BUF(tensor, value) setQnnTensorClientBuf(tensor, value)
602
+ #define QNN_TENSOR_SET_MEM_HANDLE(tensor, value) setQnnTensorMemHandle(tensor, value)
603
+
604
+ // Creator for QNN Tensor Set
605
+ #define QNN_TENSORSET_CREATE(version) createQnnTensorSet(version)
606
+
607
+ // Accessors for QNN Tensor Set
608
+ #define QNN_TENSORSET_GET_NUM_INPUTS(tensorSet) getQnnTensorSetNumInputs(tensorSet)
609
+ #define QNN_TENSORSET_GET_INPUT_TENSORS(tensorSet) getQnnTensorSetInputTensors(tensorSet)
610
+ #define QNN_TENSORSET_GET_NUM_OUTPUTS(tensorSet) getQnnTensorSetNumOutputs(tensorSet)
611
+ #define QNN_TENSORSET_GET_OUTPUT_TENSORS(tensorSet) getQnnTensorSetOutputTensors(tensorSet)
612
+
613
+ // Modifiers for QNN Tensor Set
614
+ #define QNN_TENSORSET_SET_INPUT_TENSORS(tensorSet, inputTensors, numInputs) \
615
+ setQnnTensorSetInputTensors(tensorSet, inputTensors, numInputs)
616
+ #define QNN_TENSORSET_SET_OUTPUT_TENSORS(tensorSet, outputTensors, numOutputs) \
617
+ setQnnTensorSetOutputTensors(tensorSet, outputTensors, numOutputs)
618
+
619
+ inline bool isQnnTensorV1Compatible(const Qnn_Tensor_t& tensor) {
620
+ if (tensor.version == QNN_TENSOR_VERSION_2) {
621
+ if (tensor.v2.isDynamicDimensions != NULL) {
622
+ return false;
623
+ }
624
+
625
+ if (tensor.v2.dataFormat == QNN_TENSOR_DATA_FORMAT_SPARSE) {
626
+ return false;
627
+ }
628
+ }
629
+
630
+ return true;
631
+ }
632
+
633
+ inline bool isQnnTensorV1Compatible(const Qnn_Tensor_t* const tensor) {
634
+ return isQnnTensorV1Compatible(*tensor);
635
+ }
636
+
637
+ inline bool isQnnTensorV1Compatible(const Qnn_OpConfig_t& opConfig) {
638
+ if ((QNN_OP_CFG_GET_INPUTS(opConfig) != NULL) && (QNN_OP_CFG_GET_NUM_INPUTS(opConfig) > 0u)) {
639
+ for (uint32_t tensorIdx = 0u; tensorIdx < QNN_OP_CFG_GET_NUM_INPUTS(opConfig); tensorIdx++) {
640
+ if (!isQnnTensorV1Compatible(QNN_OP_CFG_GET_INPUTS(opConfig)[tensorIdx])) {
641
+ return false;
642
+ }
643
+ }
644
+ }
645
+ if ((QNN_OP_CFG_GET_OUTPUTS(opConfig) != NULL) && (QNN_OP_CFG_GET_NUM_OUTPUTS(opConfig) > 0u)) {
646
+ for (uint32_t tensorIdx = 0u; tensorIdx < QNN_OP_CFG_GET_NUM_OUTPUTS(opConfig); tensorIdx++) {
647
+ if (!isQnnTensorV1Compatible(QNN_OP_CFG_GET_OUTPUTS(opConfig)[tensorIdx])) {
648
+ return false;
649
+ }
650
+ }
651
+ }
652
+ if ((QNN_OP_CFG_GET_PARAMS(opConfig) != NULL) && (QNN_OP_CFG_GET_NUM_PARAMS(opConfig) > 0)) {
653
+ for (uint32_t paramIdx = 0u; paramIdx < QNN_OP_CFG_GET_NUM_PARAMS(opConfig); paramIdx++) {
654
+ const Qnn_Param_t& param = QNN_OP_CFG_GET_PARAMS(opConfig)[paramIdx];
655
+ if (QNN_PARAMTYPE_TENSOR == param.paramType) {
656
+ if (!isQnnTensorV1Compatible(param.tensorParam)) {
657
+ return false;
658
+ }
659
+ }
660
+ }
661
+ }
662
+
663
+ return true;
664
+ }
665
+
666
+ inline bool isQnnTensorV1Compatible(const Qnn_OpConfig_t* const opConfig) {
667
+ return isQnnTensorV1Compatible(*opConfig);
668
+ }
SampleApp/src/SampleApp.hpp ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2020-2023 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #pragma once
10
+
11
+ #include "QnnInterface.h"
12
+ #include "QnnWrapperUtils.hpp"
13
+ #include "System/QnnSystemInterface.h"
14
+
15
+ namespace qnn {
16
+ namespace tools {
17
+ namespace sample_app {
18
+
19
+ // Graph Related Function Handle Types
20
+ typedef qnn_wrapper_api::ModelError_t (*ComposeGraphsFnHandleType_t)(
21
+ Qnn_BackendHandle_t,
22
+ QNN_INTERFACE_VER_TYPE,
23
+ Qnn_ContextHandle_t,
24
+ const qnn_wrapper_api::GraphConfigInfo_t **,
25
+ const uint32_t,
26
+ qnn_wrapper_api::GraphInfo_t ***,
27
+ uint32_t *,
28
+ bool,
29
+ QnnLog_Callback_t,
30
+ QnnLog_Level_t);
31
+ typedef qnn_wrapper_api::ModelError_t (*FreeGraphInfoFnHandleType_t)(
32
+ qnn_wrapper_api::GraphInfo_t ***, uint32_t);
33
+
34
+ typedef struct QnnFunctionPointers {
35
+ ComposeGraphsFnHandleType_t composeGraphsFnHandle;
36
+ FreeGraphInfoFnHandleType_t freeGraphInfoFnHandle;
37
+ QNN_INTERFACE_VER_TYPE qnnInterface;
38
+ QNN_SYSTEM_INTERFACE_VER_TYPE qnnSystemInterface;
39
+ } QnnFunctionPointers;
40
+
41
+ } // namespace sample_app
42
+ } // namespace tools
43
+ } // namespace qnn
SampleApp/src/Utils/BuildId.hpp ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2020, 2024 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #pragma once
10
+
11
+ namespace qnn {
12
+ namespace tools {
13
+
14
+ inline std::string getBuildId() { return std::string("v2.24.0.240626131148_96320"); }
15
+
16
+ } // namespace tools
17
+ } // namespace qnn
SampleApp/src/Utils/DataUtil.cpp ADDED
@@ -0,0 +1,408 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2019-2024 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+ #include <cmath>
9
+ #include <fstream>
10
+ #include <iostream>
11
+ #include <numeric>
12
+ #include <queue>
13
+
14
+ #include "DataUtil.hpp"
15
+ #include "Logger.hpp"
16
+ #ifndef __hexagon__
17
+ #include "PAL/Directory.hpp"
18
+ #include "PAL/FileOp.hpp"
19
+ #include "PAL/Path.hpp"
20
+ #endif
21
+
22
+ using namespace qnn;
23
+ using namespace qnn::tools;
24
+
25
+ std::tuple<datautil::StatusCode, size_t> datautil::getDataTypeSizeInBytes(Qnn_DataType_t dataType) {
26
+ if (g_dataTypeToSize.find(dataType) == g_dataTypeToSize.end()) {
27
+ QNN_ERROR("Invalid qnn data type provided");
28
+ return std::make_tuple(StatusCode::INVALID_DATA_TYPE, 0);
29
+ }
30
+ return std::make_tuple(StatusCode::SUCCESS, g_dataTypeToSize.find(dataType)->second);
31
+ }
32
+
33
+ size_t datautil::calculateElementCount(std::vector<size_t> dims) {
34
+ if (dims.size() == 0) {
35
+ return 0;
36
+ }
37
+ return std::accumulate(dims.begin(), dims.end(), 1, std::multiplies<size_t>());
38
+ }
39
+
40
+ std::tuple<datautil::StatusCode, size_t> datautil::calculateLength(std::vector<size_t> dims,
41
+ Qnn_DataType_t dataType) {
42
+ if (dims.size() == 0) {
43
+ QNN_ERROR("dims.size() is zero");
44
+ return std::make_tuple(StatusCode::INVALID_DIMENSIONS, 0);
45
+ }
46
+ StatusCode returnStatus{StatusCode::SUCCESS};
47
+ size_t length{0};
48
+ std::tie(returnStatus, length) = getDataTypeSizeInBytes(dataType);
49
+ if (StatusCode::SUCCESS != returnStatus) {
50
+ return std::make_tuple(returnStatus, 0);
51
+ }
52
+ length *= calculateElementCount(dims);
53
+ return std::make_tuple(StatusCode::SUCCESS, length);
54
+ }
55
+
56
+ datautil::StatusCode datautil::readDataFromFile(std::string filePath,
57
+ std::vector<size_t> dims,
58
+ Qnn_DataType_t dataType,
59
+ uint8_t* buffer) {
60
+ if (nullptr == buffer) {
61
+ QNN_ERROR("buffer is nullptr");
62
+ return StatusCode::INVALID_BUFFER;
63
+ }
64
+ std::ifstream in(filePath, std::ifstream::binary);
65
+ if (!in) {
66
+ QNN_ERROR("Failed to open input file: %s", filePath.c_str());
67
+ return StatusCode::FILE_OPEN_FAIL;
68
+ }
69
+ in.seekg(0, in.end);
70
+ const size_t length = in.tellg();
71
+ in.seekg(0, in.beg);
72
+ StatusCode err{StatusCode::SUCCESS};
73
+ size_t l{0};
74
+ std::tie(err, l) = datautil::calculateLength(dims, dataType);
75
+ if (StatusCode::SUCCESS != err) {
76
+ return err;
77
+ }
78
+ if (length != l) {
79
+ QNN_ERROR("Input file %s: file size in bytes (%d), should be equal to: %d",
80
+ filePath.c_str(),
81
+ length,
82
+ l);
83
+ return StatusCode::DATA_SIZE_MISMATCH;
84
+ }
85
+
86
+ if (!in.read(reinterpret_cast<char*>(buffer), length)) {
87
+ QNN_ERROR("Failed to read the contents of: %s", filePath.c_str());
88
+ return StatusCode::DATA_READ_FAIL;
89
+ }
90
+ return StatusCode::SUCCESS;
91
+ }
92
+
93
+ datautil::ReadBatchDataRetType_t datautil::readBatchData(const std::vector<std::string>& filePaths,
94
+ const size_t filePathsIndexOffset,
95
+ const bool loopBackToStart,
96
+ const std::vector<size_t>& dims,
97
+ const Qnn_DataType_t dataType,
98
+ uint8_t* buffer) {
99
+ if (nullptr == buffer) {
100
+ QNN_ERROR("buffer is nullptr");
101
+ return std::make_tuple(StatusCode::INVALID_BUFFER, 0, 0);
102
+ }
103
+ StatusCode err{StatusCode::SUCCESS};
104
+ size_t tensorLength{0};
105
+ std::tie(err, tensorLength) = datautil::calculateLength(dims, dataType);
106
+ if (StatusCode::SUCCESS != err) {
107
+ return std::make_tuple(err, 0, 0);
108
+ }
109
+ size_t numInputsCopied = 0;
110
+ size_t numBatchSize = 0;
111
+ size_t totalLength = 0;
112
+ size_t fileIndex = filePathsIndexOffset;
113
+ while (true) {
114
+ if (fileIndex >= filePaths.size()) {
115
+ if (loopBackToStart) {
116
+ fileIndex = fileIndex % filePaths.size();
117
+ } else {
118
+ numBatchSize += (tensorLength - totalLength) / (totalLength / numBatchSize);
119
+ // pad the vector with zeros
120
+ memset(buffer + totalLength, 0, (tensorLength - totalLength) * sizeof(char));
121
+ break;
122
+ }
123
+ }
124
+ std::ifstream in(filePaths[fileIndex], std::ifstream::binary);
125
+ if (!in) {
126
+ QNN_ERROR("Failed to open input file: %s", (filePaths[fileIndex]).c_str());
127
+ return std::make_tuple(StatusCode::FILE_OPEN_FAIL, numInputsCopied, numBatchSize);
128
+ }
129
+ in.seekg(0, in.end);
130
+ const size_t fileSize = in.tellg();
131
+ in.seekg(0, in.beg);
132
+ if ((tensorLength % fileSize) != 0 || fileSize > tensorLength || fileSize == 0) {
133
+ QNN_ERROR(
134
+ "Given input file %s with file size in bytes %d. If the model expects a batch size of "
135
+ "one, the file size should match the tensor extent: %d bytes. If the model expects a "
136
+ "batch size > 1, the file size should evenly divide the tensor extent: %d bytes.",
137
+ filePaths[fileIndex].c_str(),
138
+ fileSize,
139
+ tensorLength,
140
+ tensorLength);
141
+ return std::make_tuple(StatusCode::DATA_SIZE_MISMATCH, numInputsCopied, numBatchSize);
142
+ }
143
+ if (!in.read(reinterpret_cast<char*>(buffer + (numInputsCopied * fileSize)), fileSize)) {
144
+ QNN_ERROR("Failed to read the contents of: %s", filePaths.front().c_str());
145
+ return std::make_tuple(StatusCode::DATA_READ_FAIL, numInputsCopied, numBatchSize);
146
+ }
147
+ totalLength += fileSize;
148
+ numInputsCopied += 1;
149
+ numBatchSize += 1;
150
+ fileIndex += 1;
151
+ if (totalLength >= tensorLength) {
152
+ break;
153
+ }
154
+ }
155
+ return std::make_tuple(StatusCode::SUCCESS, numInputsCopied, numBatchSize);
156
+ }
157
+
158
+ std::tuple<datautil::StatusCode, size_t> datautil::getFileSize(std::string filePath) {
159
+ std::ifstream in(filePath, std::ifstream::binary);
160
+ if (!in) {
161
+ QNN_ERROR("Failed to open input file: %s", filePath.c_str());
162
+ return std::make_tuple(StatusCode::FILE_OPEN_FAIL, 0);
163
+ }
164
+ in.seekg(0, in.end);
165
+ const size_t length = in.tellg();
166
+ in.seekg(0, in.beg);
167
+ return std::make_tuple(StatusCode::SUCCESS, length);
168
+ }
169
+
170
+ datautil::StatusCode datautil::readBinaryFromFile(std::string filePath,
171
+ uint8_t* buffer,
172
+ size_t bufferSize) {
173
+ if (nullptr == buffer) {
174
+ QNN_ERROR("buffer is nullptr");
175
+ return StatusCode::INVALID_BUFFER;
176
+ }
177
+ std::ifstream in(filePath, std::ifstream::binary);
178
+ if (!in) {
179
+ QNN_ERROR("Failed to open input file: %s", filePath.c_str());
180
+ return StatusCode::FILE_OPEN_FAIL;
181
+ }
182
+ if (!in.read(reinterpret_cast<char*>(buffer), bufferSize)) {
183
+ QNN_ERROR("Failed to read the contents of: %s", filePath.c_str());
184
+ return StatusCode::DATA_READ_FAIL;
185
+ }
186
+ return StatusCode::SUCCESS;
187
+ }
188
+
189
+ #ifndef __hexagon__
190
+ datautil::StatusCode datautil::writeDataToFile(std::string fileDir,
191
+ std::string fileName,
192
+ std::vector<size_t> dims,
193
+ Qnn_DataType_t dataType,
194
+ uint8_t* buffer) {
195
+ if (nullptr == buffer) {
196
+ QNN_ERROR("buffer is nullptr");
197
+ return StatusCode::INVALID_BUFFER;
198
+ }
199
+ if (!pal::Directory::makePath(fileDir)) {
200
+ QNN_ERROR("Failed to create output directory: %s", fileDir.c_str());
201
+ return StatusCode::DIRECTORY_CREATE_FAIL;
202
+ }
203
+ const std::string outputPath(fileDir + pal::Path::getSeparator() + fileName);
204
+ std::ofstream os(outputPath, std::ofstream::binary);
205
+ if (!os) {
206
+ QNN_ERROR("Failed to open output file for writing: %s", outputPath.c_str());
207
+ return StatusCode::FILE_OPEN_FAIL;
208
+ }
209
+ StatusCode err{StatusCode::SUCCESS};
210
+ size_t length{0};
211
+ std::tie(err, length) = datautil::calculateLength(dims, dataType);
212
+ if (StatusCode::SUCCESS != err) {
213
+ return err;
214
+ }
215
+ for (size_t l = 0; l < length; l++) {
216
+ os.write(reinterpret_cast<char*>(&(*(buffer + l))), 1);
217
+ }
218
+ return StatusCode::SUCCESS;
219
+ }
220
+
221
+ datautil::StatusCode datautil::writeBatchDataToFile(std::vector<std::string> fileDirs,
222
+ std::string fileName,
223
+ std::vector<size_t> dims,
224
+ Qnn_DataType_t dataType,
225
+ uint8_t* buffer,
226
+ const size_t batchSize) {
227
+ if (nullptr == buffer) {
228
+ QNN_ERROR("buffer is nullptr");
229
+ return StatusCode::INVALID_BUFFER;
230
+ }
231
+ StatusCode err{StatusCode::SUCCESS};
232
+ size_t length{0};
233
+ std::tie(err, length) = datautil::calculateLength(dims, dataType);
234
+ if (StatusCode::SUCCESS != err) {
235
+ return err;
236
+ }
237
+ auto outputSize = (length / batchSize);
238
+ for (size_t batchIndex = 0; batchIndex < fileDirs.size(); batchIndex++) {
239
+ std::string fileDir = fileDirs[batchIndex];
240
+ if (!pal::Directory::makePath(fileDir)) {
241
+ QNN_ERROR("Failed to create output directory: %s", fileDir.c_str());
242
+ return StatusCode::DIRECTORY_CREATE_FAIL;
243
+ }
244
+ const std::string outputPath(fileDir + pal::Path::getSeparator() + fileName);
245
+ std::ofstream os(outputPath, std::ofstream::binary);
246
+ if (!os) {
247
+ QNN_ERROR("Failed to open output file for writing: %s", outputPath.c_str());
248
+ return StatusCode::FILE_OPEN_FAIL;
249
+ }
250
+ for (size_t l = 0; l < outputSize; l++) {
251
+ size_t bufferIndex = l + (batchIndex * outputSize);
252
+ os.write(reinterpret_cast<char*>(&(*(buffer + bufferIndex))), 1);
253
+ }
254
+ }
255
+ return StatusCode::SUCCESS;
256
+ }
257
+
258
+ datautil::StatusCode datautil::writeBinaryToFile(std::string fileDir,
259
+ std::string fileName,
260
+ uint8_t* buffer,
261
+ size_t bufferSize) {
262
+ if (nullptr == buffer) {
263
+ QNN_ERROR("buffer is nullptr");
264
+ return StatusCode::INVALID_BUFFER;
265
+ }
266
+ if (!pal::Directory::makePath(fileDir)) {
267
+ QNN_ERROR("Failed to create output directory: %s", fileDir.c_str());
268
+ return StatusCode::DIRECTORY_CREATE_FAIL;
269
+ }
270
+ const std::string outputPath(fileDir + pal::Path::getSeparator() + fileName);
271
+ std::ofstream os(outputPath, std::ofstream::binary);
272
+ if (!os) {
273
+ QNN_ERROR("Failed to open output file for writing: %s", outputPath.c_str());
274
+ return StatusCode::FILE_OPEN_FAIL;
275
+ }
276
+ os.write(reinterpret_cast<char*>(buffer), bufferSize);
277
+ return StatusCode::SUCCESS;
278
+ }
279
+ #endif
280
+
281
+ template <typename T_QuantType>
282
+ datautil::StatusCode datautil::floatToTfN(
283
+ T_QuantType* out, float* in, int32_t offset, float scale, size_t numElements) {
284
+ static_assert(std::is_unsigned<T_QuantType>::value, "floatToTfN supports unsigned only!");
285
+
286
+ if (nullptr == out || nullptr == in) {
287
+ QNN_ERROR("Received a nullptr");
288
+ return StatusCode::INVALID_BUFFER;
289
+ }
290
+
291
+ size_t dataTypeSizeInBytes = sizeof(T_QuantType);
292
+ size_t bitWidth = dataTypeSizeInBytes * g_bitsPerByte;
293
+ double trueBitWidthMax = pow(2, bitWidth) - 1;
294
+ double encodingMin = offset * scale;
295
+ double encodingMax = (trueBitWidthMax + offset) * scale;
296
+ double encodingRange = encodingMax - encodingMin;
297
+
298
+ for (size_t i = 0; i < numElements; ++i) {
299
+ int quantizedValue = round(trueBitWidthMax * (in[i] - encodingMin) / encodingRange);
300
+ if (quantizedValue < 0)
301
+ quantizedValue = 0;
302
+ else if (quantizedValue > (int)trueBitWidthMax)
303
+ quantizedValue = (int)trueBitWidthMax;
304
+ out[i] = static_cast<T_QuantType>(quantizedValue);
305
+ }
306
+ return StatusCode::SUCCESS;
307
+ }
308
+
309
+ template datautil::StatusCode datautil::floatToTfN<uint8_t>(
310
+ uint8_t* out, float* in, int32_t offset, float scale, size_t numElements);
311
+
312
+ template datautil::StatusCode datautil::floatToTfN<uint16_t>(
313
+ uint16_t* out, float* in, int32_t offset, float scale, size_t numElements);
314
+
315
+ template <typename T_QuantType>
316
+ datautil::StatusCode datautil::tfNToFloat(
317
+ float* out, T_QuantType* in, int32_t offset, float scale, size_t numElements) {
318
+ static_assert(std::is_unsigned<T_QuantType>::value, "tfNToFloat supports unsigned only!");
319
+
320
+ if (nullptr == out || nullptr == in) {
321
+ QNN_ERROR("Received a nullptr");
322
+ return StatusCode::INVALID_BUFFER;
323
+ }
324
+ for (size_t i = 0; i < numElements; i++) {
325
+ double quantizedValue = static_cast<double>(in[i]);
326
+ double offsetDouble = static_cast<double>(offset);
327
+ out[i] = static_cast<double>((quantizedValue + offsetDouble) * scale);
328
+ }
329
+ return StatusCode::SUCCESS;
330
+ }
331
+
332
+ template datautil::StatusCode datautil::tfNToFloat<uint8_t>(
333
+ float* out, uint8_t* in, int32_t offset, float scale, size_t numElements);
334
+
335
+ template datautil::StatusCode datautil::tfNToFloat<uint16_t>(
336
+ float* out, uint16_t* in, int32_t offset, float scale, size_t numElements);
337
+
338
+ template <typename T_QuantType>
339
+ datautil::StatusCode datautil::castToFloat(float* out, T_QuantType* in, size_t numElements) {
340
+ if (nullptr == out || nullptr == in) {
341
+ QNN_ERROR("Received a nullptr");
342
+ return StatusCode::INVALID_BUFFER;
343
+ }
344
+ for (size_t i = 0; i < numElements; i++) {
345
+ out[i] = static_cast<float>(in[i]);
346
+ }
347
+ return StatusCode::SUCCESS;
348
+ }
349
+
350
+ template datautil::StatusCode datautil::castToFloat<uint8_t>(float* out,
351
+ uint8_t* in,
352
+ size_t numElements);
353
+
354
+ template datautil::StatusCode datautil::castToFloat<uint16_t>(float* out,
355
+ uint16_t* in,
356
+ size_t numElements);
357
+
358
+ template datautil::StatusCode datautil::castToFloat<uint32_t>(float* out,
359
+ uint32_t* in,
360
+ size_t numElements);
361
+
362
+ template datautil::StatusCode datautil::castToFloat<int8_t>(float* out,
363
+ int8_t* in,
364
+ size_t numElements);
365
+
366
+ template datautil::StatusCode datautil::castToFloat<int16_t>(float* out,
367
+ int16_t* in,
368
+ size_t numElements);
369
+
370
+ template datautil::StatusCode datautil::castToFloat<int32_t>(float* out,
371
+ int32_t* in,
372
+ size_t numElements);
373
+
374
+ template <typename T_QuantType>
375
+ datautil::StatusCode datautil::castFromFloat(T_QuantType* out, float* in, size_t numElements) {
376
+ if (nullptr == out || nullptr == in) {
377
+ QNN_ERROR("Received a nullptr");
378
+ return StatusCode::INVALID_BUFFER;
379
+ }
380
+ for (size_t i = 0; i < numElements; i++) {
381
+ out[i] = static_cast<T_QuantType>(in[i]);
382
+ }
383
+ return StatusCode::SUCCESS;
384
+ }
385
+
386
+ template datautil::StatusCode datautil::castFromFloat<uint8_t>(uint8_t* out,
387
+ float* in,
388
+ size_t numElements);
389
+
390
+ template datautil::StatusCode datautil::castFromFloat<uint16_t>(uint16_t* out,
391
+ float* in,
392
+ size_t numElements);
393
+
394
+ template datautil::StatusCode datautil::castFromFloat<uint32_t>(uint32_t* out,
395
+ float* in,
396
+ size_t numElements);
397
+
398
+ template datautil::StatusCode datautil::castFromFloat<int8_t>(int8_t* out,
399
+ float* in,
400
+ size_t numElements);
401
+
402
+ template datautil::StatusCode datautil::castFromFloat<int16_t>(int16_t* out,
403
+ float* in,
404
+ size_t numElements);
405
+
406
+ template datautil::StatusCode datautil::castFromFloat<int32_t>(int32_t* out,
407
+ float* in,
408
+ size_t numElements);
SampleApp/src/Utils/DataUtil.hpp ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2019-2024 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+ #pragma once
9
+
10
+ #include <map>
11
+ #include <queue>
12
+ #include <vector>
13
+
14
+ #include "QnnTypes.h"
15
+
16
+ namespace qnn {
17
+ namespace tools {
18
+ namespace datautil {
19
+ enum class StatusCode {
20
+ SUCCESS,
21
+ DATA_READ_FAIL,
22
+ DATA_WRITE_FAIL,
23
+ FILE_OPEN_FAIL,
24
+ DIRECTORY_CREATE_FAIL,
25
+ INVALID_DIMENSIONS,
26
+ INVALID_DATA_TYPE,
27
+ DATA_SIZE_MISMATCH,
28
+ INVALID_BUFFER,
29
+ };
30
+
31
+ const size_t g_bitsPerByte = 8;
32
+
33
+ using ReadBatchDataRetType_t = std::tuple<StatusCode, size_t, size_t>;
34
+
35
+ std::tuple<StatusCode, size_t> getDataTypeSizeInBytes(Qnn_DataType_t dataType);
36
+
37
+ std::tuple<StatusCode, size_t> calculateLength(std::vector<size_t> dims, Qnn_DataType_t dataType);
38
+
39
+ size_t calculateElementCount(std::vector<size_t> dims);
40
+
41
+ std::tuple<StatusCode, size_t> getFileSize(std::string filePath);
42
+
43
+ StatusCode readDataFromFile(std::string filePath,
44
+ std::vector<size_t> dims,
45
+ Qnn_DataType_t dataType,
46
+ uint8_t* buffer);
47
+
48
+ /*
49
+ * Read data in batches from vector and try to matches the model input's
50
+ * batches. If the vector is empty while matching the batch size of model,
51
+ * pad the remaining buffer with zeros
52
+ * @param filePaths image paths vector
53
+ * @param filePathsIndexOffset index offset in the vector
54
+ * @param loopBackToStart loop the vector to fill the remaining tensor data
55
+ * @param dims model input dimensions
56
+ * @param dataType to create input buffer from file
57
+ * @param buffer to fill the input image data
58
+ *
59
+ * @return ReadBatchDataRetType_t returns numFilesCopied and batchSize along
60
+ * with status
61
+ */
62
+ ReadBatchDataRetType_t readBatchData(const std::vector<std::string>& filePaths,
63
+ const size_t filePathsIndexOffset,
64
+ const bool loopBackToStart,
65
+ const std::vector<size_t>& dims,
66
+ const Qnn_DataType_t dataType,
67
+ uint8_t* buffer);
68
+
69
+ StatusCode readBinaryFromFile(std::string filePath, uint8_t* buffer, size_t bufferSize);
70
+
71
+ #ifndef __hexagon__
72
+ StatusCode writeDataToFile(std::string fileDir,
73
+ std::string fileName,
74
+ std::vector<size_t> dims,
75
+ Qnn_DataType_t dataType,
76
+ uint8_t* buffer);
77
+
78
+ StatusCode writeBatchDataToFile(std::vector<std::string> fileDirs,
79
+ std::string fileName,
80
+ std::vector<size_t> dims,
81
+ Qnn_DataType_t dataType,
82
+ uint8_t* buffer,
83
+ const size_t batchSize);
84
+
85
+ StatusCode writeBinaryToFile(std::string fileDir,
86
+ std::string fileName,
87
+ uint8_t* buffer,
88
+ size_t bufferSize);
89
+ #endif
90
+
91
+ template <typename T_QuantType>
92
+ datautil::StatusCode floatToTfN(
93
+ T_QuantType* out, float* in, int32_t offset, float scale, size_t numElements);
94
+
95
+ template <typename T_QuantType>
96
+ datautil::StatusCode tfNToFloat(
97
+ float* out, T_QuantType* in, int32_t offset, float scale, size_t numElements);
98
+
99
+ template <typename T_QuantType>
100
+ datautil::StatusCode castToFloat(float* out, T_QuantType* in, size_t numElements);
101
+
102
+ template <typename T_QuantType>
103
+ datautil::StatusCode castFromFloat(T_QuantType* out, float* in, size_t numElements);
104
+
105
+ const std::map<Qnn_DataType_t, size_t> g_dataTypeToSize = {
106
+ {QNN_DATATYPE_INT_8, 1},
107
+ {QNN_DATATYPE_INT_16, 2},
108
+ {QNN_DATATYPE_INT_32, 4},
109
+ {QNN_DATATYPE_INT_64, 8},
110
+ {QNN_DATATYPE_UINT_8, 1},
111
+ {QNN_DATATYPE_UINT_16, 2},
112
+ {QNN_DATATYPE_UINT_32, 4},
113
+ {QNN_DATATYPE_UINT_64, 8},
114
+ {QNN_DATATYPE_FLOAT_16, 2},
115
+ {QNN_DATATYPE_FLOAT_32, 4},
116
+ {QNN_DATATYPE_FLOAT_64, 8},
117
+ {QNN_DATATYPE_SFIXED_POINT_8, 1},
118
+ {QNN_DATATYPE_SFIXED_POINT_16, 2},
119
+ {QNN_DATATYPE_SFIXED_POINT_32, 4},
120
+ {QNN_DATATYPE_UFIXED_POINT_8, 1},
121
+ {QNN_DATATYPE_UFIXED_POINT_16, 2},
122
+ {QNN_DATATYPE_UFIXED_POINT_32, 4},
123
+ {QNN_DATATYPE_BOOL_8, 1},
124
+ };
125
+ } // namespace datautil
126
+ } // namespace tools
127
+ } // namespace qnn
SampleApp/src/Utils/DynamicLoadUtil.cpp ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2019-2024 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #include <iostream>
10
+
11
+ #include "DynamicLoadUtil.hpp"
12
+ #include "Logger.hpp"
13
+ #include "PAL/DynamicLoading.hpp"
14
+
15
+ using namespace qnn;
16
+ using namespace qnn::tools;
17
+
18
+ typedef Qnn_ErrorHandle_t (*QnnInterfaceGetProvidersFn_t)(const QnnInterface_t*** providerList,
19
+ uint32_t* numProviders);
20
+
21
+ typedef Qnn_ErrorHandle_t (*QnnSystemInterfaceGetProvidersFn_t)(
22
+ const QnnSystemInterface_t*** providerList, uint32_t* numProviders);
23
+
24
+ template <class T>
25
+ static inline T resolveSymbol(void* libHandle, const char* sym) {
26
+ T ptr = (T)pal::dynamicloading::dlSym(libHandle, sym);
27
+ if (ptr == nullptr) {
28
+ QNN_ERROR("Unable to access symbol [%s]. pal::dynamicloading::dlError(): %s",
29
+ sym,
30
+ pal::dynamicloading::dlError());
31
+ }
32
+ return ptr;
33
+ }
34
+
35
+ dynamicloadutil::StatusCode dynamicloadutil::getQnnFunctionPointers(
36
+ std::string backendPath,
37
+ std::string modelPath,
38
+ sample_app::QnnFunctionPointers* qnnFunctionPointers,
39
+ void** backendHandleRtn,
40
+ bool loadModelLib,
41
+ void** modelHandleRtn) {
42
+ #if defined(__ANDROID__)
43
+ void* libBackendHandle = pal::dynamicloading::dlOpen(
44
+ backendPath.c_str(), pal::dynamicloading::DL_NOW | pal::dynamicloading::DL_LOCAL);
45
+ #else
46
+ void* libBackendHandle = pal::dynamicloading::dlOpen(
47
+ backendPath.c_str(), pal::dynamicloading::DL_NOW | pal::dynamicloading::DL_GLOBAL);
48
+ #endif
49
+ if (nullptr == libBackendHandle) {
50
+ QNN_ERROR("Unable to load backend. pal::dynamicloading::dlError(): %s",
51
+ pal::dynamicloading::dlError());
52
+ return StatusCode::FAIL_LOAD_BACKEND;
53
+ }
54
+ if (nullptr != backendHandleRtn) {
55
+ *backendHandleRtn = libBackendHandle;
56
+ }
57
+ // Get QNN Interface
58
+ QnnInterfaceGetProvidersFn_t getInterfaceProviders{nullptr};
59
+ getInterfaceProviders =
60
+ resolveSymbol<QnnInterfaceGetProvidersFn_t>(libBackendHandle, "QnnInterface_getProviders");
61
+ if (nullptr == getInterfaceProviders) {
62
+ return StatusCode::FAIL_SYM_FUNCTION;
63
+ }
64
+ QnnInterface_t** interfaceProviders{nullptr};
65
+ uint32_t numProviders{0};
66
+ if (QNN_SUCCESS !=
67
+ getInterfaceProviders((const QnnInterface_t***)&interfaceProviders, &numProviders)) {
68
+ QNN_ERROR("Failed to get interface providers.");
69
+ return StatusCode::FAIL_GET_INTERFACE_PROVIDERS;
70
+ }
71
+ if (nullptr == interfaceProviders) {
72
+ QNN_ERROR("Failed to get interface providers: null interface providers received.");
73
+ return StatusCode::FAIL_GET_INTERFACE_PROVIDERS;
74
+ }
75
+ if (0 == numProviders) {
76
+ QNN_ERROR("Failed to get interface providers: 0 interface providers.");
77
+ return StatusCode::FAIL_GET_INTERFACE_PROVIDERS;
78
+ }
79
+ bool foundValidInterface{false};
80
+ for (size_t pIdx = 0; pIdx < numProviders; pIdx++) {
81
+ if (QNN_API_VERSION_MAJOR == interfaceProviders[pIdx]->apiVersion.coreApiVersion.major &&
82
+ QNN_API_VERSION_MINOR <= interfaceProviders[pIdx]->apiVersion.coreApiVersion.minor) {
83
+ foundValidInterface = true;
84
+ qnnFunctionPointers->qnnInterface = interfaceProviders[pIdx]->QNN_INTERFACE_VER_NAME;
85
+ break;
86
+ }
87
+ }
88
+ if (!foundValidInterface) {
89
+ QNN_ERROR("Unable to find a valid interface.");
90
+ libBackendHandle = nullptr;
91
+ return StatusCode::FAIL_GET_INTERFACE_PROVIDERS;
92
+ }
93
+
94
+ if (true == loadModelLib) {
95
+ QNN_INFO("Loading model shared library ([model].so)");
96
+ void* libModelHandle = pal::dynamicloading::dlOpen(
97
+ modelPath.c_str(), pal::dynamicloading::DL_NOW | pal::dynamicloading::DL_LOCAL);
98
+ if (nullptr == libModelHandle) {
99
+ QNN_ERROR("Unable to load model. pal::dynamicloading::dlError(): %s",
100
+ pal::dynamicloading::dlError());
101
+ return StatusCode::FAIL_LOAD_MODEL;
102
+ }
103
+ if (nullptr != modelHandleRtn) {
104
+ *modelHandleRtn = libModelHandle;
105
+ }
106
+
107
+ std::string modelPrepareFunc = "QnnModel_composeGraphs";
108
+ qnnFunctionPointers->composeGraphsFnHandle =
109
+ resolveSymbol<sample_app::ComposeGraphsFnHandleType_t>(libModelHandle,
110
+ modelPrepareFunc.c_str());
111
+ if (nullptr == qnnFunctionPointers->composeGraphsFnHandle) {
112
+ return StatusCode::FAIL_SYM_FUNCTION;
113
+ }
114
+
115
+ std::string modelFreeFunc = "QnnModel_freeGraphsInfo";
116
+ qnnFunctionPointers->freeGraphInfoFnHandle =
117
+ resolveSymbol<sample_app::FreeGraphInfoFnHandleType_t>(libModelHandle,
118
+ modelFreeFunc.c_str());
119
+ if (nullptr == qnnFunctionPointers->freeGraphInfoFnHandle) {
120
+ return StatusCode::FAIL_SYM_FUNCTION;
121
+ }
122
+ } else {
123
+ QNN_INFO("Model wasn't loaded from a shared library.");
124
+ }
125
+ return StatusCode::SUCCESS;
126
+ }
127
+
128
+ dynamicloadutil::StatusCode dynamicloadutil::getQnnSystemFunctionPointers(
129
+ std::string systemLibraryPath, sample_app::QnnFunctionPointers* qnnFunctionPointers) {
130
+ QNN_FUNCTION_ENTRY_LOG;
131
+ if (!qnnFunctionPointers) {
132
+ QNN_ERROR("nullptr provided for qnnFunctionPointers");
133
+ return StatusCode::FAILURE;
134
+ }
135
+ void* systemLibraryHandle = pal::dynamicloading::dlOpen(
136
+ systemLibraryPath.c_str(), pal::dynamicloading::DL_NOW | pal::dynamicloading::DL_LOCAL);
137
+ if (nullptr == systemLibraryHandle) {
138
+ QNN_ERROR("Unable to load system library. pal::dynamicloading::dlError(): %s",
139
+ pal::dynamicloading::dlError());
140
+ return StatusCode::FAIL_LOAD_SYSTEM_LIB;
141
+ }
142
+ QnnSystemInterfaceGetProvidersFn_t getSystemInterfaceProviders{nullptr};
143
+ getSystemInterfaceProviders = resolveSymbol<QnnSystemInterfaceGetProvidersFn_t>(
144
+ systemLibraryHandle, "QnnSystemInterface_getProviders");
145
+ if (nullptr == getSystemInterfaceProviders) {
146
+ return StatusCode::FAIL_SYM_FUNCTION;
147
+ }
148
+ QnnSystemInterface_t** systemInterfaceProviders{nullptr};
149
+ uint32_t numProviders{0};
150
+ if (QNN_SUCCESS != getSystemInterfaceProviders(
151
+ (const QnnSystemInterface_t***)&systemInterfaceProviders, &numProviders)) {
152
+ QNN_ERROR("Failed to get system interface providers.");
153
+ return StatusCode::FAIL_GET_INTERFACE_PROVIDERS;
154
+ }
155
+ if (nullptr == systemInterfaceProviders) {
156
+ QNN_ERROR("Failed to get system interface providers: null interface providers received.");
157
+ return StatusCode::FAIL_GET_INTERFACE_PROVIDERS;
158
+ }
159
+ if (0 == numProviders) {
160
+ QNN_ERROR("Failed to get interface providers: 0 interface providers.");
161
+ return StatusCode::FAIL_GET_INTERFACE_PROVIDERS;
162
+ }
163
+ bool foundValidSystemInterface{false};
164
+ for (size_t pIdx = 0; pIdx < numProviders; pIdx++) {
165
+ if (QNN_SYSTEM_API_VERSION_MAJOR == systemInterfaceProviders[pIdx]->systemApiVersion.major &&
166
+ QNN_SYSTEM_API_VERSION_MINOR <= systemInterfaceProviders[pIdx]->systemApiVersion.minor) {
167
+ foundValidSystemInterface = true;
168
+ qnnFunctionPointers->qnnSystemInterface =
169
+ systemInterfaceProviders[pIdx]->QNN_SYSTEM_INTERFACE_VER_NAME;
170
+ break;
171
+ }
172
+ }
173
+ if (!foundValidSystemInterface) {
174
+ QNN_ERROR("Unable to find a valid system interface.");
175
+ return StatusCode::FAIL_GET_INTERFACE_PROVIDERS;
176
+ }
177
+ QNN_FUNCTION_EXIT_LOG;
178
+ return StatusCode::SUCCESS;
179
+ }
SampleApp/src/Utils/DynamicLoadUtil.hpp ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2019-2022 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #pragma once
10
+
11
+ #include "SampleApp.hpp"
12
+
13
+ namespace qnn {
14
+ namespace tools {
15
+ namespace dynamicloadutil {
16
+ enum class StatusCode {
17
+ SUCCESS,
18
+ FAILURE,
19
+ FAIL_LOAD_BACKEND,
20
+ FAIL_LOAD_MODEL,
21
+ FAIL_SYM_FUNCTION,
22
+ FAIL_GET_INTERFACE_PROVIDERS,
23
+ FAIL_LOAD_SYSTEM_LIB,
24
+ };
25
+
26
+ StatusCode getQnnFunctionPointers(std::string backendPath,
27
+ std::string modelPath,
28
+ sample_app::QnnFunctionPointers* qnnFunctionPointers,
29
+ void** backendHandle,
30
+ bool loadModelLib,
31
+ void** modelHandleRtn);
32
+ StatusCode getQnnSystemFunctionPointers(std::string systemLibraryPath,
33
+ sample_app::QnnFunctionPointers* qnnFunctionPointers);
34
+ } // namespace dynamicloadutil
35
+ } // namespace tools
36
+ } // namespace qnn
SampleApp/src/Utils/IOTensor.cpp ADDED
@@ -0,0 +1,838 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2020-2024 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+ #include <algorithm>
9
+ #include <cstring>
10
+ #include <fstream>
11
+ #include <iostream>
12
+
13
+ #include "DataUtil.hpp"
14
+ #include "IOTensor.hpp"
15
+ #include "Logger.hpp"
16
+ #ifndef __hexagon__
17
+ #include "PAL/Directory.hpp"
18
+ #include "PAL/FileOp.hpp"
19
+ #include "PAL/Path.hpp"
20
+ #endif
21
+ #include "PAL/StringOp.hpp"
22
+ #include "QnnTypeMacros.hpp"
23
+
24
+ using namespace qnn;
25
+ using namespace qnn::tools;
26
+
27
+ // Helper method to read data from files to a buffer.
28
+ iotensor::PopulateInputTensorsRetType_t iotensor::IOTensor::readDataAndAllocateBuffer(
29
+ const std::vector<std::string>& filePaths,
30
+ const size_t filePathsIndexOffset,
31
+ const bool loopBackToStart,
32
+ std::vector<size_t> dims,
33
+ Qnn_DataType_t dataType,
34
+ uint8_t** bufferToCopy) {
35
+ StatusCode returnStatus = StatusCode::SUCCESS;
36
+ *bufferToCopy = nullptr;
37
+ returnStatus = allocateBuffer(bufferToCopy, dims, dataType);
38
+ size_t numFilesPopulated = 0;
39
+ size_t batchSize = 0;
40
+ datautil::StatusCode status;
41
+ std::tie(status, numFilesPopulated, batchSize) =
42
+ datautil::readBatchData(filePaths,
43
+ filePathsIndexOffset,
44
+ loopBackToStart,
45
+ dims,
46
+ dataType,
47
+ reinterpret_cast<uint8_t*>(*bufferToCopy));
48
+ if (datautil::StatusCode::SUCCESS != status) {
49
+ QNN_ERROR("Failure in datautil::readBatchData");
50
+ returnStatus = StatusCode::FAILURE;
51
+ }
52
+ if (StatusCode::SUCCESS != returnStatus) {
53
+ if (nullptr != *bufferToCopy) {
54
+ free(*bufferToCopy);
55
+ *bufferToCopy = nullptr;
56
+ }
57
+ }
58
+ return {returnStatus, numFilesPopulated, batchSize};
59
+ }
60
+
61
+ // Helper method to copy a float buffer, quantize it, and copy
62
+ // it to a tensor (Qnn_Tensor_t) buffer.
63
+ iotensor::StatusCode iotensor::IOTensor::copyFromFloatToNative(float* floatBuffer,
64
+ Qnn_Tensor_t* tensor) {
65
+ if (nullptr == floatBuffer || nullptr == tensor) {
66
+ QNN_ERROR("copyFromFloatToNative(): received a nullptr");
67
+ return StatusCode::FAILURE;
68
+ }
69
+
70
+ StatusCode returnStatus = StatusCode::SUCCESS;
71
+ std::vector<size_t> dims;
72
+ fillDims(dims, QNN_TENSOR_GET_DIMENSIONS(tensor), QNN_TENSOR_GET_RANK(tensor));
73
+
74
+ switch (QNN_TENSOR_GET_DATA_TYPE(tensor)) {
75
+ case QNN_DATATYPE_UFIXED_POINT_8:
76
+ datautil::floatToTfN<uint8_t>(static_cast<uint8_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
77
+ floatBuffer,
78
+ QNN_TENSOR_GET_QUANT_PARAMS(tensor).scaleOffsetEncoding.offset,
79
+ QNN_TENSOR_GET_QUANT_PARAMS(tensor).scaleOffsetEncoding.scale,
80
+ datautil::calculateElementCount(dims));
81
+ break;
82
+
83
+ case QNN_DATATYPE_UFIXED_POINT_16:
84
+ datautil::floatToTfN<uint16_t>(static_cast<uint16_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
85
+ floatBuffer,
86
+ QNN_TENSOR_GET_QUANT_PARAMS(tensor).scaleOffsetEncoding.offset,
87
+ QNN_TENSOR_GET_QUANT_PARAMS(tensor).scaleOffsetEncoding.scale,
88
+ datautil::calculateElementCount(dims));
89
+ break;
90
+
91
+ case QNN_DATATYPE_UINT_8:
92
+ if (datautil::StatusCode::SUCCESS !=
93
+ datautil::castFromFloat<uint8_t>(
94
+ static_cast<uint8_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
95
+ floatBuffer,
96
+ datautil::calculateElementCount(dims))) {
97
+ QNN_ERROR("failure in castFromFloat<uint8_t>");
98
+ returnStatus = StatusCode::FAILURE;
99
+ }
100
+ break;
101
+
102
+ case QNN_DATATYPE_UINT_16:
103
+ if (datautil::StatusCode::SUCCESS !=
104
+ datautil::castFromFloat<uint16_t>(
105
+ static_cast<uint16_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
106
+ floatBuffer,
107
+ datautil::calculateElementCount(dims))) {
108
+ QNN_ERROR("failure in castFromFloat<uint16_t>");
109
+ returnStatus = StatusCode::FAILURE;
110
+ }
111
+ break;
112
+
113
+ case QNN_DATATYPE_UINT_32:
114
+ if (datautil::StatusCode::SUCCESS !=
115
+ datautil::castFromFloat<uint32_t>(
116
+ static_cast<uint32_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
117
+ floatBuffer,
118
+ datautil::calculateElementCount(dims))) {
119
+ QNN_ERROR("failure in castFromFloat<uint32_t>");
120
+ returnStatus = StatusCode::FAILURE;
121
+ }
122
+ break;
123
+
124
+ case QNN_DATATYPE_INT_8:
125
+ if (datautil::StatusCode::SUCCESS !=
126
+ datautil::castFromFloat<int8_t>(
127
+ static_cast<int8_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
128
+ floatBuffer,
129
+ datautil::calculateElementCount(dims))) {
130
+ QNN_ERROR("failure in castFromFloat<int8_t>");
131
+ returnStatus = StatusCode::FAILURE;
132
+ }
133
+ break;
134
+
135
+ case QNN_DATATYPE_INT_16:
136
+ if (datautil::StatusCode::SUCCESS !=
137
+ datautil::castFromFloat<int16_t>(
138
+ static_cast<int16_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
139
+ floatBuffer,
140
+ datautil::calculateElementCount(dims))) {
141
+ QNN_ERROR("failure in castFromFloat<int16_t>");
142
+ returnStatus = StatusCode::FAILURE;
143
+ }
144
+ break;
145
+
146
+ case QNN_DATATYPE_INT_32:
147
+ if (datautil::StatusCode::SUCCESS !=
148
+ datautil::castFromFloat<int32_t>(
149
+ static_cast<int32_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
150
+ floatBuffer,
151
+ datautil::calculateElementCount(dims))) {
152
+ QNN_ERROR("failure in castFromFloat<int32_t>");
153
+ returnStatus = StatusCode::FAILURE;
154
+ }
155
+ break;
156
+
157
+ case QNN_DATATYPE_BOOL_8:
158
+ if (datautil::StatusCode::SUCCESS !=
159
+ datautil::castFromFloat<uint8_t>(
160
+ static_cast<uint8_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
161
+ floatBuffer,
162
+ datautil::calculateElementCount(dims))) {
163
+ QNN_ERROR("failure in castFromFloat<bool>");
164
+ returnStatus = StatusCode::FAILURE;
165
+ }
166
+ break;
167
+
168
+ default:
169
+ QNN_ERROR("Datatype not supported yet!");
170
+ returnStatus = StatusCode::FAILURE;
171
+ break;
172
+ }
173
+ return returnStatus;
174
+ }
175
+
176
+ // Helper method to populate an input tensor in the graph during execution.
177
+ // It relies on reading data from files provided during app creation.
178
+ iotensor::PopulateInputTensorsRetType_t iotensor::IOTensor::populateInputTensor(
179
+ const std::vector<std::string>& filePaths,
180
+ const size_t filePathsIndexOffset,
181
+ const bool loopBackToStart,
182
+ Qnn_Tensor_t* input,
183
+ iotensor::InputDataType inputDataType) {
184
+ if (nullptr == input) {
185
+ QNN_ERROR("input is nullptr");
186
+ return {StatusCode::FAILURE, 0, 0};
187
+ }
188
+
189
+ auto returnStatus = StatusCode::SUCCESS;
190
+ size_t numFilesPopulated = 0;
191
+ size_t batchSize = 0;
192
+ std::vector<size_t> dims;
193
+ fillDims(dims, QNN_TENSOR_GET_DIMENSIONS(input), QNN_TENSOR_GET_RANK(input));
194
+
195
+ if (inputDataType == InputDataType::FLOAT &&
196
+ QNN_TENSOR_GET_DATA_TYPE(input) != QNN_DATATYPE_FLOAT_32) {
197
+ uint8_t* fileToBuffer = nullptr;
198
+ std::tie(returnStatus, numFilesPopulated, batchSize) =
199
+ readDataAndAllocateBuffer(filePaths,
200
+ filePathsIndexOffset,
201
+ loopBackToStart,
202
+ dims,
203
+ QNN_DATATYPE_FLOAT_32,
204
+ &fileToBuffer);
205
+ if (StatusCode::SUCCESS == returnStatus) {
206
+ QNN_DEBUG("readDataFromFileToBuffer successful");
207
+ returnStatus = copyFromFloatToNative(reinterpret_cast<float*>(fileToBuffer), input);
208
+ }
209
+ if (nullptr != fileToBuffer) {
210
+ free(fileToBuffer);
211
+ fileToBuffer = nullptr;
212
+ }
213
+ } else {
214
+ datautil::StatusCode status;
215
+ std::tie(status, numFilesPopulated, batchSize) =
216
+ datautil::readBatchData(filePaths,
217
+ filePathsIndexOffset,
218
+ loopBackToStart,
219
+ dims,
220
+ QNN_TENSOR_GET_DATA_TYPE(input),
221
+ static_cast<uint8_t*>(QNN_TENSOR_GET_CLIENT_BUF(input).data));
222
+ if (datautil::StatusCode::SUCCESS != status) {
223
+ QNN_ERROR("Failure in datautil::readBatchData");
224
+ returnStatus = StatusCode::FAILURE;
225
+ }
226
+ }
227
+ return {returnStatus, numFilesPopulated, batchSize};
228
+ }
229
+
230
+ // Helper method to populate all input tensors during execution.
231
+ iotensor::PopulateInputTensorsRetType_t iotensor::IOTensor::populateInputTensors(
232
+ uint32_t graphIdx,
233
+ const std::vector<std::vector<std::string>>& filePathsVector,
234
+ const size_t filePathsIndexOffset,
235
+ const bool loopBackToStart,
236
+ const std::unordered_map<std::string, uint32_t>& inputNameToIndex,
237
+ Qnn_Tensor_t* inputs,
238
+ qnn_wrapper_api::GraphInfo_t graphInfo,
239
+ iotensor::InputDataType inputDataType) {
240
+ QNN_DEBUG("populateInputTensors() graphIndx %d", graphIdx);
241
+ if (nullptr == inputs) {
242
+ QNN_ERROR("inputs is nullptr");
243
+ return {StatusCode::FAILURE, 0, 0};
244
+ }
245
+ auto inputCount = graphInfo.numInputTensors;
246
+ if (filePathsVector.size() != inputCount) {
247
+ QNN_ERROR(
248
+ "Incorrect amount of Input files for graphIdx: %d. Expected: %d, "
249
+ "received: %d",
250
+ graphIdx,
251
+ inputCount,
252
+ filePathsVector.size());
253
+ return {StatusCode::FAILURE, 0, 0};
254
+ }
255
+ size_t numFilesPopulated = 0;
256
+ size_t numBatchSize = 0;
257
+ for (size_t inputIdx = 0; inputIdx < inputCount; inputIdx++) {
258
+ size_t inputNameIdx = inputIdx;
259
+ QNN_DEBUG("index = %d input column index = %d", inputIdx, inputNameIdx);
260
+ std::string inputNodeName;
261
+ if (QNN_TENSOR_GET_NAME(graphInfo.inputTensors[inputIdx]))
262
+ inputNodeName = QNN_TENSOR_GET_NAME(graphInfo.inputTensors[inputIdx]);
263
+ if (!inputNodeName.empty() && inputNameToIndex.find(inputNodeName) != inputNameToIndex.end()) {
264
+ inputNameIdx = inputNameToIndex.at(inputNodeName);
265
+ }
266
+ StatusCode returnStatus;
267
+ size_t currentInputNumFilesPopulated = 0;
268
+ size_t currentInputNumBatchSize = 0;
269
+ std::tie(returnStatus, currentInputNumFilesPopulated, currentInputNumBatchSize) =
270
+ populateInputTensor(filePathsVector[inputNameIdx],
271
+ filePathsIndexOffset,
272
+ loopBackToStart,
273
+ &(inputs[inputIdx]),
274
+ inputDataType);
275
+ if (StatusCode::SUCCESS != returnStatus) {
276
+ QNN_ERROR("populateInputTensorFromFiles failed for input %s with index %d",
277
+ inputNodeName.c_str(),
278
+ inputIdx);
279
+ return {StatusCode::FAILURE, currentInputNumFilesPopulated, currentInputNumBatchSize};
280
+ }
281
+ if (inputIdx == 0) {
282
+ numFilesPopulated = currentInputNumFilesPopulated;
283
+ numBatchSize = currentInputNumBatchSize;
284
+ } else {
285
+ if (numFilesPopulated != currentInputNumFilesPopulated ||
286
+ numBatchSize != currentInputNumBatchSize) {
287
+ QNN_ERROR(
288
+ "Current input tensor with name: %s with index %d files populated = %d, batch size = %d"
289
+ " does not match with expected files populated = %d, batch size = %d",
290
+ inputNodeName.c_str(),
291
+ inputIdx,
292
+ currentInputNumFilesPopulated,
293
+ currentInputNumBatchSize,
294
+ numFilesPopulated,
295
+ numBatchSize);
296
+ return {StatusCode::FAILURE, numFilesPopulated, numBatchSize};
297
+ }
298
+ }
299
+ }
300
+ return {StatusCode::SUCCESS, numFilesPopulated, numBatchSize};
301
+ }
302
+
303
+ // Setup details for Qnn_Tensor_t for execution
304
+ // based on information in Qnn_TensorWrapper_t provided by model.so.
305
+ iotensor::StatusCode iotensor::IOTensor::setupTensors(Qnn_Tensor_t** tensors,
306
+ uint32_t tensorCount,
307
+ Qnn_Tensor_t* tensorWrappers) {
308
+ if (nullptr == tensorWrappers) {
309
+ QNN_ERROR("tensorWrappers is nullptr");
310
+ return StatusCode::FAILURE;
311
+ }
312
+ if (0 == tensorCount) {
313
+ QNN_INFO("tensor count is 0. Nothing to setup.");
314
+ return StatusCode::SUCCESS;
315
+ }
316
+ auto returnStatus = StatusCode::SUCCESS;
317
+ *tensors = (Qnn_Tensor_t*)calloc(1, tensorCount * sizeof(Qnn_Tensor_t));
318
+ if (nullptr == *tensors) {
319
+ QNN_ERROR("mem alloc failed for *tensors");
320
+ returnStatus = StatusCode::FAILURE;
321
+ return returnStatus;
322
+ }
323
+ for (size_t tensorIdx = 0; tensorIdx < tensorCount; tensorIdx++) {
324
+ Qnn_Tensor_t wrapperTensor = tensorWrappers[tensorIdx];
325
+ std::vector<size_t> dims;
326
+ fillDims(dims, QNN_TENSOR_GET_DIMENSIONS(wrapperTensor), QNN_TENSOR_GET_RANK(wrapperTensor));
327
+ if (StatusCode::SUCCESS == returnStatus) {
328
+ QNN_DEBUG("allocateBuffer successful");
329
+ (*tensors)[tensorIdx] = QNN_TENSOR_INIT;
330
+ returnStatus =
331
+ (sample_app::deepCopyQnnTensorInfo(((*tensors) + tensorIdx), &wrapperTensor) == true
332
+ ? StatusCode::SUCCESS
333
+ : StatusCode::FAILURE);
334
+ }
335
+ if (StatusCode::SUCCESS == returnStatus) {
336
+ QNN_DEBUG("deepCopyQnnTensorInfo successful");
337
+ QNN_TENSOR_SET_MEM_TYPE(((*tensors) + tensorIdx), QNN_TENSORMEMTYPE_RAW);
338
+ }
339
+ Qnn_ClientBuffer_t clientBuffer = QNN_CLIENT_BUFFER_INIT;
340
+ returnStatus = allocateBuffer(reinterpret_cast<uint8_t**>(&clientBuffer.data),
341
+ dims,
342
+ QNN_TENSOR_GET_DATA_TYPE((*tensors) + tensorIdx));
343
+ datautil::StatusCode datautilStatus{datautil::StatusCode::SUCCESS};
344
+ size_t length{0};
345
+ std::tie(datautilStatus, length) =
346
+ datautil::calculateLength(dims, QNN_TENSOR_GET_DATA_TYPE((*tensors) + tensorIdx));
347
+ if (datautilStatus != datautil::StatusCode::SUCCESS) {
348
+ returnStatus = StatusCode::FAILURE;
349
+ }
350
+ clientBuffer.dataSize = length;
351
+ QNN_TENSOR_SET_CLIENT_BUF(((*tensors) + tensorIdx), clientBuffer);
352
+ if (StatusCode::SUCCESS != returnStatus) {
353
+ QNN_ERROR("Failure in setupTensors, cleaning up resources");
354
+ if (nullptr != (QNN_TENSOR_GET_CLIENT_BUF((*tensors) + tensorIdx)).data) {
355
+ free(QNN_TENSOR_GET_CLIENT_BUF((*tensors) + tensorIdx).data);
356
+ }
357
+ tearDownTensors(*tensors, tensorIdx);
358
+ *tensors = nullptr;
359
+ returnStatus = StatusCode::FAILURE;
360
+ QNN_ERROR("Failure in setupTensors, done cleaning up resources");
361
+ return returnStatus;
362
+ }
363
+ }
364
+ return returnStatus;
365
+ }
366
+
367
+ // Setup details for all input and output tensors for graph execution.
368
+ iotensor::StatusCode iotensor::IOTensor::setupInputAndOutputTensors(
369
+ Qnn_Tensor_t** inputs, Qnn_Tensor_t** outputs, qnn_wrapper_api::GraphInfo_t graphInfo) {
370
+ auto returnStatus = StatusCode::SUCCESS;
371
+ if (StatusCode::SUCCESS !=
372
+ setupTensors(inputs, graphInfo.numInputTensors, (graphInfo.inputTensors))) {
373
+ QNN_ERROR("Failure in setting up input tensors");
374
+ returnStatus = StatusCode::FAILURE;
375
+ }
376
+ if (StatusCode::SUCCESS !=
377
+ setupTensors(outputs, graphInfo.numOutputTensors, (graphInfo.outputTensors))) {
378
+ QNN_ERROR("Failure in setting up output tensors");
379
+ returnStatus = StatusCode::FAILURE;
380
+ }
381
+ if (StatusCode::SUCCESS != returnStatus) {
382
+ QNN_ERROR("Failure in setupInputAndOutputTensors, cleaning up resources");
383
+ if (nullptr != *inputs) {
384
+ QNN_DEBUG("cleaning up input tensors");
385
+ tearDownTensors(*inputs, graphInfo.numInputTensors);
386
+ *inputs = nullptr;
387
+ }
388
+ if (nullptr != *outputs) {
389
+ QNN_DEBUG("cleaning up output tensors");
390
+ tearDownTensors(*outputs, graphInfo.numOutputTensors);
391
+ *outputs = nullptr;
392
+ }
393
+ QNN_ERROR("Failure in setupInputAndOutputTensors, done cleaning up resources");
394
+ }
395
+ return returnStatus;
396
+ }
397
+
398
+ // Clean up all tensors related data after execution.
399
+ iotensor::StatusCode iotensor::IOTensor::tearDownTensors(Qnn_Tensor_t* tensors,
400
+ uint32_t tensorCount) {
401
+ for (size_t tensorIdx = 0; tensorIdx < tensorCount; tensorIdx++) {
402
+ QNN_DEBUG("freeing resources for tensor: %d", tensorIdx);
403
+ if (nullptr != QNN_TENSOR_GET_DIMENSIONS(tensors[tensorIdx])) {
404
+ QNN_DEBUG("freeing dimensions");
405
+ free(QNN_TENSOR_GET_DIMENSIONS(tensors[tensorIdx]));
406
+ }
407
+ if (nullptr != QNN_TENSOR_GET_CLIENT_BUF(tensors[tensorIdx]).data) {
408
+ QNN_DEBUG("freeing clientBuf.data");
409
+ free(QNN_TENSOR_GET_CLIENT_BUF(tensors[tensorIdx]).data);
410
+ }
411
+ }
412
+ free(tensors);
413
+ return StatusCode::SUCCESS;
414
+ }
415
+
416
+ // Clean up all input and output tensors after execution.
417
+ iotensor::StatusCode iotensor::IOTensor::tearDownInputAndOutputTensors(Qnn_Tensor_t* inputs,
418
+ Qnn_Tensor_t* outputs,
419
+ size_t numInputTensors,
420
+ size_t numOutputTensors) {
421
+ if (nullptr != inputs) {
422
+ QNN_INFO("cleaning up resources for input tensors");
423
+ tearDownTensors(inputs, numInputTensors);
424
+ inputs = nullptr;
425
+ }
426
+ if (nullptr != outputs) {
427
+ QNN_INFO("cleaning up resources for output tensors");
428
+ tearDownTensors(outputs, numOutputTensors);
429
+ outputs = nullptr;
430
+ }
431
+ return StatusCode::SUCCESS;
432
+ }
433
+
434
+ // Helper method to allocate a buffer.
435
+ iotensor::StatusCode iotensor::IOTensor::allocateBuffer(uint8_t** buffer,
436
+ std::vector<size_t> dims,
437
+ Qnn_DataType_t dataType) {
438
+ size_t elementCount = datautil::calculateElementCount(dims);
439
+ auto returnStatus = StatusCode::SUCCESS;
440
+ switch (dataType) {
441
+ case QNN_DATATYPE_FLOAT_32:
442
+ QNN_DEBUG("allocating float buffer");
443
+ returnStatus = allocateBuffer<float>(reinterpret_cast<float**>(buffer), elementCount);
444
+ break;
445
+
446
+ case QNN_DATATYPE_UINT_8:
447
+ case QNN_DATATYPE_UFIXED_POINT_8:
448
+ QNN_DEBUG("allocating uint8_t buffer");
449
+ returnStatus = allocateBuffer<uint8_t>(reinterpret_cast<uint8_t**>(buffer), elementCount);
450
+ break;
451
+
452
+ case QNN_DATATYPE_UINT_16:
453
+ case QNN_DATATYPE_UFIXED_POINT_16:
454
+ QNN_DEBUG("allocating uint16_t buffer");
455
+ returnStatus = allocateBuffer<uint16_t>(reinterpret_cast<uint16_t**>(buffer), elementCount);
456
+ break;
457
+
458
+ case QNN_DATATYPE_UINT_32:
459
+ QNN_DEBUG("allocating uint32_t buffer");
460
+ returnStatus = allocateBuffer<uint32_t>(reinterpret_cast<uint32_t**>(buffer), elementCount);
461
+ break;
462
+
463
+ case QNN_DATATYPE_INT_8:
464
+ QNN_DEBUG("allocating int8_t buffer");
465
+ returnStatus = allocateBuffer<int8_t>(reinterpret_cast<int8_t**>(buffer), elementCount);
466
+ break;
467
+
468
+ case QNN_DATATYPE_INT_16:
469
+ QNN_DEBUG("allocating int16_t buffer");
470
+ returnStatus = allocateBuffer<int16_t>(reinterpret_cast<int16_t**>(buffer), elementCount);
471
+ break;
472
+
473
+ case QNN_DATATYPE_INT_32:
474
+ QNN_DEBUG("allocating int32_t buffer");
475
+ returnStatus = allocateBuffer<int32_t>(reinterpret_cast<int32_t**>(buffer), elementCount);
476
+ break;
477
+
478
+ case QNN_DATATYPE_BOOL_8:
479
+ QNN_DEBUG("allocating bool buffer");
480
+ returnStatus = allocateBuffer<uint8_t>(reinterpret_cast<uint8_t**>(buffer), elementCount);
481
+ break;
482
+
483
+ default:
484
+ QNN_ERROR("Datatype not supported yet!");
485
+ returnStatus = StatusCode::FAILURE;
486
+ break;
487
+ }
488
+ return returnStatus;
489
+ }
490
+
491
+ // Helper method to allocate a buffer.
492
+ template <typename T>
493
+ iotensor::StatusCode iotensor::IOTensor::allocateBuffer(T** buffer, size_t& elementCount) {
494
+ QNN_DEBUG("ElementCount: %d, sizeof(T): %d, total size: %d",
495
+ elementCount,
496
+ sizeof(T),
497
+ elementCount * sizeof(T));
498
+ *buffer = (T*)malloc(elementCount * sizeof(T));
499
+ if (nullptr == *buffer) {
500
+ QNN_ERROR("mem alloc failed for *buffer");
501
+ return StatusCode::FAILURE;
502
+ }
503
+ return StatusCode::SUCCESS;
504
+ }
505
+
506
+ // Convert data to float or de-quantization. This is used when
507
+ // user requests for float output and the model produces
508
+ // non-float output.
509
+ #ifndef __hexagon__
510
+ iotensor::StatusCode iotensor::IOTensor::convertToFloat(float** out, Qnn_Tensor_t* tensor) {
511
+ if (nullptr == tensor) {
512
+ QNN_ERROR("tensors is nullptr");
513
+ return StatusCode::FAILURE;
514
+ }
515
+ std::vector<size_t> dims;
516
+ fillDims(dims, QNN_TENSOR_GET_DIMENSIONS(tensor), QNN_TENSOR_GET_RANK(tensor));
517
+ auto returnStatus = StatusCode::SUCCESS;
518
+ size_t elementCount = datautil::calculateElementCount(dims);
519
+ returnStatus = allocateBuffer<float>(out, elementCount);
520
+ if (StatusCode::SUCCESS != returnStatus) {
521
+ QNN_ERROR("failure in allocateBuffer<float>");
522
+ return returnStatus;
523
+ }
524
+ switch (QNN_TENSOR_GET_DATA_TYPE(tensor)) {
525
+ case QNN_DATATYPE_UFIXED_POINT_8:
526
+ if (datautil::StatusCode::SUCCESS !=
527
+ datautil::tfNToFloat<uint8_t>(
528
+ *out,
529
+ reinterpret_cast<uint8_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
530
+ QNN_TENSOR_GET_QUANT_PARAMS(tensor).scaleOffsetEncoding.offset,
531
+ QNN_TENSOR_GET_QUANT_PARAMS(tensor).scaleOffsetEncoding.scale,
532
+ elementCount)) {
533
+ QNN_ERROR("failure in tfNToFloat<uint8_t>");
534
+ returnStatus = StatusCode::FAILURE;
535
+ }
536
+ break;
537
+
538
+ case QNN_DATATYPE_UFIXED_POINT_16:
539
+ if (datautil::StatusCode::SUCCESS !=
540
+ datautil::tfNToFloat<uint16_t>(
541
+ *out,
542
+ reinterpret_cast<uint16_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
543
+ QNN_TENSOR_GET_QUANT_PARAMS(tensor).scaleOffsetEncoding.offset,
544
+ QNN_TENSOR_GET_QUANT_PARAMS(tensor).scaleOffsetEncoding.scale,
545
+ elementCount)) {
546
+ QNN_ERROR("failure in tfNToFloat<uint8_t>");
547
+ returnStatus = StatusCode::FAILURE;
548
+ }
549
+ break;
550
+
551
+ case QNN_DATATYPE_UINT_8:
552
+ if (datautil::StatusCode::SUCCESS !=
553
+ datautil::castToFloat<uint8_t>(
554
+ *out,
555
+ reinterpret_cast<uint8_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
556
+ elementCount)) {
557
+ QNN_ERROR("failure in castToFloat<uint8_t>");
558
+ returnStatus = StatusCode::FAILURE;
559
+ }
560
+ break;
561
+
562
+ case QNN_DATATYPE_UINT_16:
563
+ if (datautil::StatusCode::SUCCESS !=
564
+ datautil::castToFloat<uint16_t>(
565
+ *out,
566
+ reinterpret_cast<uint16_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
567
+ elementCount)) {
568
+ QNN_ERROR("failure in castToFloat<uint16_t>");
569
+ returnStatus = StatusCode::FAILURE;
570
+ }
571
+ break;
572
+
573
+ case QNN_DATATYPE_UINT_32:
574
+ if (datautil::StatusCode::SUCCESS !=
575
+ datautil::castToFloat<uint32_t>(
576
+ *out,
577
+ reinterpret_cast<uint32_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
578
+ elementCount)) {
579
+ QNN_ERROR("failure in castToFloat<uint32_t>");
580
+ returnStatus = StatusCode::FAILURE;
581
+ }
582
+ break;
583
+
584
+ case QNN_DATATYPE_INT_8:
585
+ if (datautil::StatusCode::SUCCESS !=
586
+ datautil::castToFloat<int8_t>(
587
+ *out,
588
+ reinterpret_cast<int8_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
589
+ elementCount)) {
590
+ QNN_ERROR("failure in castToFloat<int8_t>");
591
+ returnStatus = StatusCode::FAILURE;
592
+ }
593
+ break;
594
+
595
+ case QNN_DATATYPE_INT_16:
596
+ if (datautil::StatusCode::SUCCESS !=
597
+ datautil::castToFloat<int16_t>(
598
+ *out,
599
+ reinterpret_cast<int16_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
600
+ elementCount)) {
601
+ QNN_ERROR("failure in castToFloat<int16_t>");
602
+ returnStatus = StatusCode::FAILURE;
603
+ }
604
+ break;
605
+
606
+ case QNN_DATATYPE_INT_32:
607
+ if (datautil::StatusCode::SUCCESS !=
608
+ datautil::castToFloat<int32_t>(
609
+ *out,
610
+ reinterpret_cast<int32_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
611
+ elementCount)) {
612
+ QNN_ERROR("failure in castToFloat<int32_t>");
613
+ returnStatus = StatusCode::FAILURE;
614
+ }
615
+ break;
616
+
617
+ case QNN_DATATYPE_BOOL_8:
618
+ if (datautil::StatusCode::SUCCESS !=
619
+ datautil::castToFloat<uint8_t>(
620
+ *out,
621
+ reinterpret_cast<uint8_t*>(QNN_TENSOR_GET_CLIENT_BUF(tensor).data),
622
+ elementCount)) {
623
+ QNN_ERROR("failure in castToFloat<bool>");
624
+ returnStatus = StatusCode::FAILURE;
625
+ }
626
+ break;
627
+
628
+ default:
629
+ QNN_ERROR("Datatype not supported yet!");
630
+ returnStatus = StatusCode::FAILURE;
631
+ break;
632
+ }
633
+ if (StatusCode::SUCCESS != returnStatus) {
634
+ QNN_DEBUG("freeing *out");
635
+ if (*out != nullptr) {
636
+ free(*out);
637
+ *out = nullptr;
638
+ }
639
+ }
640
+ return returnStatus;
641
+ }
642
+
643
+ // Helper method to convert Output tensors to float and write them
644
+ // out to files.
645
+ iotensor::StatusCode iotensor::IOTensor::convertAndWriteOutputTensorInFloat(
646
+ Qnn_Tensor_t* output,
647
+ std::vector<std::string> outputPaths,
648
+ std::string fileName,
649
+ size_t outputBatchSize) {
650
+ if (nullptr == output) {
651
+ QNN_ERROR("output is nullptr");
652
+ return StatusCode::FAILURE;
653
+ }
654
+
655
+ auto returnStatus = StatusCode::SUCCESS;
656
+ std::vector<size_t> dims;
657
+ fillDims(dims, QNN_TENSOR_GET_DIMENSIONS(output), QNN_TENSOR_GET_RANK(output));
658
+ float* floatBuffer = nullptr;
659
+ returnStatus = convertToFloat(&floatBuffer, output);
660
+ if (StatusCode::SUCCESS != returnStatus) {
661
+ QNN_ERROR("failure in convertToFloat");
662
+ return StatusCode::FAILURE;
663
+ }
664
+ uint8_t* bufferToWrite = reinterpret_cast<uint8_t*>(floatBuffer);
665
+ if (datautil::StatusCode::SUCCESS !=
666
+ datautil::writeBatchDataToFile(
667
+ outputPaths, fileName, dims, QNN_DATATYPE_FLOAT_32, bufferToWrite, outputBatchSize)) {
668
+ QNN_ERROR("failure in writeBatchDataToFile");
669
+ returnStatus = StatusCode::FAILURE;
670
+ }
671
+ if (nullptr != floatBuffer) {
672
+ QNN_DEBUG("freeing floatBuffer");
673
+ free(floatBuffer);
674
+ floatBuffer = nullptr;
675
+ }
676
+ return returnStatus;
677
+ }
678
+
679
+ // Helper method to write out output. There is no de-quantization here.
680
+ // Just write output as is to files.
681
+ iotensor::StatusCode iotensor::IOTensor::writeOutputTensor(Qnn_Tensor_t* output,
682
+ std::vector<std::string> outputPaths,
683
+ std::string fileName,
684
+ size_t outputBatchSize) {
685
+ if (nullptr == output) {
686
+ QNN_ERROR("output is nullptr");
687
+ return StatusCode::FAILURE;
688
+ }
689
+ auto returnStatus = StatusCode::SUCCESS;
690
+ std::vector<size_t> dims;
691
+ fillDims(dims, QNN_TENSOR_GET_DIMENSIONS(output), QNN_TENSOR_GET_RANK(output));
692
+ uint8_t* bufferToWrite = reinterpret_cast<uint8_t*>(QNN_TENSOR_GET_CLIENT_BUF(output).data);
693
+ if (datautil::StatusCode::SUCCESS !=
694
+ datautil::writeBatchDataToFile(outputPaths,
695
+ fileName,
696
+ dims,
697
+ QNN_TENSOR_GET_DATA_TYPE(output),
698
+ bufferToWrite,
699
+ outputBatchSize)) {
700
+ QNN_ERROR("failure in writeBatchDataToFile");
701
+ returnStatus = StatusCode::FAILURE;
702
+ }
703
+ return returnStatus;
704
+ }
705
+
706
+ // Write out all output tensors to files. If output_data_type is float,
707
+ // then all outputs will be raw floats regardless of what the model outputs.
708
+ // If the output_data_type is native, then output is written as produced by the model.
709
+ // Also, for native option, a json with quantization parameters is written out.
710
+ // If output_data_type is float_and_native, both above are done.
711
+ // If the output in the graph is float, then output_data_type has no effect.
712
+ iotensor::StatusCode iotensor::IOTensor::writeOutputTensors(uint32_t graphIdx,
713
+ size_t startIdx,
714
+ char* graphName,
715
+ Qnn_Tensor_t* outputs,
716
+ uint32_t numOutputs,
717
+ iotensor::OutputDataType outputDatatype,
718
+ uint32_t graphsCount,
719
+ std::string outputPath,
720
+ size_t numInputFilesPopulated,
721
+ size_t outputBatchSize) {
722
+ if (nullptr == outputs) {
723
+ QNN_ERROR("Received nullptr");
724
+ return StatusCode::FAILURE;
725
+ }
726
+ if (graphsCount > 1) {
727
+ if (nullptr != graphName && strlen(graphName) > 0) {
728
+ outputPath += (pal::Path::getSeparator() + std::string(graphName));
729
+ } else {
730
+ outputPath += (pal::Path::getSeparator() + std::string("Graph_") + std::to_string(graphIdx));
731
+ }
732
+ }
733
+ auto returnStatus = StatusCode::SUCCESS;
734
+ std::vector<std::string> outputPaths;
735
+ for (size_t idx = 0; idx < numInputFilesPopulated; idx++) {
736
+ std::string output = outputPath + (pal::Path::getSeparator() + std::string("Result_") +
737
+ std::to_string(startIdx + idx));
738
+ outputPaths.push_back(output);
739
+ }
740
+ for (size_t outputIdx = 0; outputIdx < numOutputs; outputIdx++) {
741
+ QNN_DEBUG("Writing output for outputIdx: %d", outputIdx);
742
+ std::string outputFilePrefix;
743
+ if (nullptr != QNN_TENSOR_GET_NAME(outputs[outputIdx]) &&
744
+ strlen(QNN_TENSOR_GET_NAME(outputs[outputIdx])) > 0) {
745
+ outputFilePrefix = std::string(QNN_TENSOR_GET_NAME(outputs[outputIdx]));
746
+ } else {
747
+ outputFilePrefix = std::string("Output_") + std::to_string(outputIdx);
748
+ }
749
+ auto outputFile = outputFilePrefix + std::string(".raw");
750
+ auto outputFileNative = outputFilePrefix + std::string("_native.raw");
751
+ if (QNN_TENSOR_GET_DATA_TYPE(outputs[outputIdx]) == QNN_DATATYPE_FLOAT_32) {
752
+ QNN_DEBUG("Writing in output->dataType == QNN_DATATYPE_FLOAT_32");
753
+ returnStatus =
754
+ writeOutputTensor(&(outputs[outputIdx]), outputPaths, outputFile, outputBatchSize);
755
+ } else if (outputDatatype == OutputDataType::FLOAT_ONLY) {
756
+ QNN_DEBUG("Writing in output->dataType == OutputDataType::FLOAT_ONLY");
757
+ returnStatus = convertAndWriteOutputTensorInFloat(
758
+ &(outputs[outputIdx]), outputPaths, outputFile, outputBatchSize);
759
+ } else if (outputDatatype == OutputDataType::NATIVE_ONLY) {
760
+ QNN_DEBUG("Writing in output->dataType == OutputDataType::NATIVE_ONLY");
761
+ returnStatus =
762
+ writeOutputTensor(&(outputs[outputIdx]), outputPaths, outputFileNative, outputBatchSize);
763
+ } else if (outputDatatype == OutputDataType::FLOAT_AND_NATIVE) {
764
+ QNN_DEBUG("Writing in output->dataType == OutputDataType::FLOAT_AND_NATIVE");
765
+ returnStatus = convertAndWriteOutputTensorInFloat(
766
+ &(outputs[outputIdx]), outputPaths, outputFile, outputBatchSize);
767
+ if (StatusCode::SUCCESS == returnStatus) {
768
+ returnStatus = writeOutputTensor(
769
+ &(outputs[outputIdx]), outputPaths, outputFileNative, outputBatchSize);
770
+ }
771
+ }
772
+ }
773
+ return returnStatus;
774
+ }
775
+ #endif
776
+
777
+ // Helper method to allocate a buffer and copy data to it.
778
+ iotensor::StatusCode iotensor::IOTensor::allocateAndCopyBuffer(uint8_t** buffer,
779
+ Qnn_Tensor_t* tensor) {
780
+ if (nullptr == tensor) {
781
+ return StatusCode::FAILURE;
782
+ }
783
+ std::vector<size_t> dims;
784
+ fillDims(dims, QNN_TENSOR_GET_DIMENSIONS(tensor), QNN_TENSOR_GET_RANK(tensor));
785
+ datautil::StatusCode datautilStatus;
786
+ size_t length;
787
+ std::tie(datautilStatus, length) =
788
+ datautil::calculateLength(dims, QNN_TENSOR_GET_DATA_TYPE(tensor));
789
+ if (datautilStatus != datautil::StatusCode::SUCCESS) {
790
+ return StatusCode::FAILURE;
791
+ }
792
+ if (StatusCode::SUCCESS != allocateBuffer(buffer, dims, QNN_TENSOR_GET_DATA_TYPE(tensor))) {
793
+ QNN_ERROR("failure in allocateBuffer");
794
+ return StatusCode::FAILURE;
795
+ }
796
+ pal::StringOp::memscpy(*buffer,
797
+ length * sizeof(uint8_t),
798
+ QNN_TENSOR_GET_CLIENT_BUF(tensor).data,
799
+ length * sizeof(uint8_t));
800
+ return StatusCode::SUCCESS;
801
+ }
802
+
803
+ iotensor::StatusCode iotensor::IOTensor::fillDims(std::vector<size_t>& dims,
804
+ uint32_t* inDimensions,
805
+ uint32_t rank) {
806
+ if (nullptr == inDimensions) {
807
+ QNN_ERROR("input dimensions is nullptr");
808
+ return StatusCode::FAILURE;
809
+ }
810
+ for (size_t r = 0; r < rank; r++) {
811
+ dims.push_back(inDimensions[r]);
812
+ }
813
+ return StatusCode::SUCCESS;
814
+ }
815
+
816
+ iotensor::OutputDataType iotensor::parseOutputDataType(std::string dataTypeString) {
817
+ std::transform(dataTypeString.begin(), dataTypeString.end(), dataTypeString.begin(), ::tolower);
818
+ OutputDataType parsedDataType = OutputDataType::INVALID;
819
+ if (dataTypeString == "float_only") {
820
+ parsedDataType = OutputDataType::FLOAT_ONLY;
821
+ } else if (dataTypeString == "native_only") {
822
+ parsedDataType = OutputDataType::NATIVE_ONLY;
823
+ } else if (dataTypeString == "float_and_native") {
824
+ parsedDataType = OutputDataType::FLOAT_AND_NATIVE;
825
+ }
826
+ return parsedDataType;
827
+ }
828
+
829
+ iotensor::InputDataType iotensor::parseInputDataType(std::string dataTypeString) {
830
+ std::transform(dataTypeString.begin(), dataTypeString.end(), dataTypeString.begin(), ::tolower);
831
+ InputDataType parsedDataType = InputDataType::INVALID;
832
+ if (dataTypeString == "float") {
833
+ parsedDataType = InputDataType::FLOAT;
834
+ } else if (dataTypeString == "native") {
835
+ parsedDataType = InputDataType::NATIVE;
836
+ }
837
+ return parsedDataType;
838
+ }
SampleApp/src/Utils/IOTensor.hpp ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2020, 2022-2024 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+ #pragma once
9
+
10
+ #include <memory>
11
+ #include <queue>
12
+
13
+ #include "QnnBackend.h"
14
+ #include "QnnCommon.h"
15
+ #include "QnnContext.h"
16
+ #include "QnnGraph.h"
17
+ #include "QnnProperty.h"
18
+ #include "QnnSampleAppUtils.hpp"
19
+ #include "QnnTensor.h"
20
+ #include "QnnTypes.h"
21
+ #include "QnnWrapperUtils.hpp"
22
+
23
+ namespace qnn {
24
+ namespace tools {
25
+ namespace iotensor {
26
+
27
+ enum class StatusCode { SUCCESS, FAILURE };
28
+ enum class OutputDataType { FLOAT_ONLY, NATIVE_ONLY, FLOAT_AND_NATIVE, INVALID };
29
+ enum class InputDataType { FLOAT, NATIVE, INVALID };
30
+
31
+ OutputDataType parseOutputDataType(std::string dataTypeString);
32
+ InputDataType parseInputDataType(std::string dataTypeString);
33
+
34
+ using PopulateInputTensorsRetType_t = std::tuple<StatusCode, size_t, size_t>;
35
+
36
+ class IOTensor {
37
+ public:
38
+ StatusCode setupInputAndOutputTensors(Qnn_Tensor_t **inputs,
39
+ Qnn_Tensor_t **outputs,
40
+ qnn_wrapper_api::GraphInfo_t graphInfo);
41
+
42
+ #ifndef __hexagon__
43
+ StatusCode writeOutputTensors(uint32_t graphIdx,
44
+ size_t startIdx,
45
+ char *graphName,
46
+ Qnn_Tensor_t *outputs,
47
+ uint32_t numOutputs,
48
+ OutputDataType outputDatatype,
49
+ uint32_t graphsCount,
50
+ std::string outputPath,
51
+ size_t numInputFilesPopulated,
52
+ size_t outputBatchSize);
53
+ #endif
54
+
55
+ PopulateInputTensorsRetType_t populateInputTensors(
56
+ uint32_t graphIdx,
57
+ const std::vector<std::vector<std::string>> &filePathsVector,
58
+ const size_t filePathsIndexOffset,
59
+ const bool loopBackToStart,
60
+ const std::unordered_map<std::string, uint32_t> &inputNameToIndex,
61
+ Qnn_Tensor_t *inputs,
62
+ qnn_wrapper_api::GraphInfo_t graphInfo,
63
+ iotensor::InputDataType inputDataType);
64
+
65
+ StatusCode tearDownInputAndOutputTensors(Qnn_Tensor_t *inputs,
66
+ Qnn_Tensor_t *outputs,
67
+ size_t numInputTensors,
68
+ size_t numOutputTensors);
69
+
70
+ private:
71
+ PopulateInputTensorsRetType_t populateInputTensor(const std::vector<std::string> &filePaths,
72
+ const size_t filePathsIndexOffset,
73
+ const bool loopBackToStart,
74
+ Qnn_Tensor_t *input,
75
+ InputDataType inputDataType);
76
+
77
+ PopulateInputTensorsRetType_t readDataAndAllocateBuffer(const std::vector<std::string> &filePaths,
78
+ const size_t filePathsIndexOffset,
79
+ const bool loopBackToStart,
80
+ std::vector<size_t> dims,
81
+ Qnn_DataType_t dataType,
82
+ uint8_t **bufferToCopy);
83
+
84
+ template <typename T>
85
+ StatusCode allocateBuffer(T **buffer, size_t &elementCount);
86
+
87
+ #ifndef __hexagon__
88
+ StatusCode convertToFloat(float **out, Qnn_Tensor_t *output);
89
+
90
+ StatusCode convertAndWriteOutputTensorInFloat(Qnn_Tensor_t *output,
91
+ std::vector<std::string> outputPaths,
92
+ std::string fileName,
93
+ size_t outputBatchSize);
94
+
95
+ StatusCode writeOutputTensor(Qnn_Tensor_t *output,
96
+ std::vector<std::string> outputPaths,
97
+ std::string fileName,
98
+ size_t outputBatchSize);
99
+ #endif
100
+
101
+ StatusCode allocateAndCopyBuffer(uint8_t **buffer, Qnn_Tensor_t *tensor);
102
+
103
+ StatusCode tearDownTensors(Qnn_Tensor_t *tensors, uint32_t tensorCount);
104
+
105
+ StatusCode allocateBuffer(uint8_t **buffer, std::vector<size_t> dims, Qnn_DataType_t dataType);
106
+
107
+ StatusCode copyFromFloatToNative(float *floatBuffer, Qnn_Tensor_t *tensor);
108
+
109
+ StatusCode setupTensors(Qnn_Tensor_t **tensors, uint32_t tensorCount, Qnn_Tensor_t *tensorsInfo);
110
+
111
+ StatusCode fillDims(std::vector<size_t> &dims, uint32_t *inDimensions, uint32_t rank);
112
+ };
113
+ } // namespace iotensor
114
+ } // namespace tools
115
+ } // namespace qnn
SampleApp/src/Utils/QnnSampleAppUtils.cpp ADDED
@@ -0,0 +1,394 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2019-2024 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+
9
+ #include <algorithm>
10
+ #include <cstring>
11
+ #include <fstream>
12
+ #include <iostream>
13
+ #include <sstream>
14
+ #include <string>
15
+ #include <tuple>
16
+
17
+ #include "Logger.hpp"
18
+ #ifndef __hexagon__
19
+ #include "PAL/Directory.hpp"
20
+ #include "PAL/FileOp.hpp"
21
+ #include "PAL/Path.hpp"
22
+ #endif
23
+ #include "PAL/StringOp.hpp"
24
+ #include "QnnSampleAppUtils.hpp"
25
+ #include "QnnTypeMacros.hpp"
26
+
27
+ using namespace qnn;
28
+ using namespace qnn::tools;
29
+
30
+ void sample_app::split(std::vector<std::string> &splitString,
31
+ const std::string &tokenizedString,
32
+ const char separator) {
33
+ splitString.clear();
34
+ std::istringstream tokenizedStringStream(tokenizedString);
35
+ while (!tokenizedStringStream.eof()) {
36
+ std::string value;
37
+ getline(tokenizedStringStream, value, separator);
38
+ if (!value.empty()) {
39
+ splitString.push_back(value);
40
+ }
41
+ }
42
+ }
43
+
44
+ void sample_app::parseInputFilePaths(std::vector<std::string> &inputFilePaths,
45
+ std::vector<std::string> &paths,
46
+ std::string separator) {
47
+ for (auto &inputInfo : inputFilePaths) {
48
+ auto position = inputInfo.find(separator);
49
+ if (position != std::string::npos) {
50
+ auto path = inputInfo.substr(position + separator.size());
51
+ paths.push_back(path);
52
+ } else {
53
+ paths.push_back(inputInfo);
54
+ }
55
+ }
56
+ }
57
+
58
+ sample_app::ReadInputListsRetType_t sample_app::readInputLists(
59
+ std::vector<std::string> inputFileListPaths) {
60
+ std::vector<std::vector<std::vector<std::string>>> filePathsLists;
61
+ std::vector<std::unordered_map<std::string, uint32_t>> inputNameToIndexMaps;
62
+ for (auto const &path : inputFileListPaths) {
63
+ bool readSuccess;
64
+ std::vector<std::vector<std::string>> filePathList;
65
+ std::unordered_map<std::string, uint32_t> inputNameToIndex;
66
+ std::tie(filePathList, inputNameToIndex, readSuccess) = readInputList(path);
67
+ if (!readSuccess) {
68
+ filePathsLists.clear();
69
+ return std::make_tuple(filePathsLists, inputNameToIndexMaps, false);
70
+ }
71
+ filePathsLists.push_back(filePathList);
72
+ inputNameToIndexMaps.push_back(inputNameToIndex);
73
+ }
74
+ return std::make_tuple(filePathsLists, inputNameToIndexMaps, true);
75
+ }
76
+
77
+ sample_app::ReadInputListRetType_t sample_app::readInputList(const std::string inputFileListPath) {
78
+ std::queue<std::string> lines;
79
+ std::ifstream fileListStream(inputFileListPath);
80
+ if (!fileListStream) {
81
+ QNN_ERROR("Failed to open input file: %s", inputFileListPath.c_str());
82
+ return std::make_tuple(std::vector<std::vector<std::string>>{},
83
+ std::unordered_map<std::string, uint32_t>{},
84
+ false);
85
+ }
86
+
87
+ std::string fileLine;
88
+ while (std::getline(fileListStream, fileLine)) {
89
+ if (fileLine.empty()) continue;
90
+ lines.push(fileLine);
91
+ }
92
+
93
+ if (!lines.empty() && lines.front().compare(0, 1, "#") == 0) {
94
+ lines.pop();
95
+ }
96
+
97
+ if (!lines.empty() && lines.front().compare(0, 1, "%") == 0) {
98
+ lines.pop();
99
+ }
100
+
101
+ std::string separator = ":=";
102
+ std::vector<std::vector<std::string>> filePathsList;
103
+ std::unordered_map<std::string, uint32_t> inputNameToIndex;
104
+ if (!lines.empty()) {
105
+ inputNameToIndex = extractInputNameIndices(lines.front(), separator);
106
+ }
107
+ while (!lines.empty()) {
108
+ std::vector<std::string> paths{};
109
+ std::vector<std::string> inputFilePaths;
110
+ split(inputFilePaths, lines.front(), ' ');
111
+ parseInputFilePaths(inputFilePaths, paths, separator);
112
+ filePathsList.reserve(paths.size());
113
+ for (size_t idx = 0; idx < paths.size(); idx++) {
114
+ if (idx >= filePathsList.size()) {
115
+ filePathsList.push_back(std::vector<std::string>());
116
+ }
117
+ filePathsList[idx].push_back(paths[idx]);
118
+ }
119
+ lines.pop();
120
+ }
121
+ return std::make_tuple(filePathsList, inputNameToIndex, true);
122
+ }
123
+
124
+ std::unordered_map<std::string, uint32_t> sample_app::extractInputNameIndices(
125
+ const std::string &inputLine, const std::string &separator) {
126
+ std::vector<std::string> inputFilePaths;
127
+ std::unordered_map<std::string, uint32_t> inputNameToIndex;
128
+ split(inputFilePaths, inputLine, ' ');
129
+ size_t inputCount = 0;
130
+ for (uint32_t idx = 0; idx < inputFilePaths.size(); idx++) {
131
+ auto position = inputFilePaths[idx].find(separator);
132
+ if (position != std::string::npos) {
133
+ auto unsanitizedTensorName = inputFilePaths[idx].substr(0, position);
134
+ auto sanitizedTensorName = sanitizeTensorName(unsanitizedTensorName);
135
+ if (sanitizedTensorName != unsanitizedTensorName) {
136
+ inputNameToIndex[unsanitizedTensorName] = idx;
137
+ }
138
+ inputNameToIndex[sanitizedTensorName] = idx;
139
+ inputCount = inputCount + 1;
140
+ }
141
+ }
142
+ return inputCount == inputFilePaths.size() ? inputNameToIndex
143
+ : std::unordered_map<std::string, uint32_t>{};
144
+ }
145
+
146
+ std::string sample_app::sanitizeTensorName(std::string name) {
147
+ std::string sanitizedName = std::regex_replace(name, std::regex("\\W+"), "_");
148
+ if (!std::isalpha(sanitizedName[0]) && sanitizedName[0] != '_') {
149
+ sanitizedName = "_" + sanitizedName;
150
+ }
151
+ return sanitizedName;
152
+ }
153
+
154
+ sample_app::ProfilingLevel sample_app::parseProfilingLevel(std::string profilingLevelString) {
155
+ std::transform(profilingLevelString.begin(),
156
+ profilingLevelString.end(),
157
+ profilingLevelString.begin(),
158
+ ::tolower);
159
+ ProfilingLevel parsedProfilingLevel = ProfilingLevel::INVALID;
160
+ if (profilingLevelString == "off") {
161
+ parsedProfilingLevel = ProfilingLevel::OFF;
162
+ } else if (profilingLevelString == "basic") {
163
+ parsedProfilingLevel = ProfilingLevel::BASIC;
164
+ } else if (profilingLevelString == "detailed") {
165
+ parsedProfilingLevel = ProfilingLevel::DETAILED;
166
+ }
167
+ return parsedProfilingLevel;
168
+ }
169
+
170
+ bool sample_app::deepCopyQnnTensorInfo(Qnn_Tensor_t *dst, const Qnn_Tensor_t *src) {
171
+ if (nullptr == dst || nullptr == src) {
172
+ QNN_ERROR("Received nullptr");
173
+ return false;
174
+ }
175
+ // set tensor.version before using QNN_TENSOR_SET macros, as they require the version to be set
176
+ // to correctly assign values
177
+ dst->version = src->version;
178
+ const char *tensorName = QNN_TENSOR_GET_NAME(src);
179
+ if (!tensorName) {
180
+ QNN_TENSOR_SET_NAME(dst, nullptr);
181
+ } else {
182
+ QNN_TENSOR_SET_NAME(dst, pal::StringOp::strndup(tensorName, strlen(tensorName)));
183
+ }
184
+ QNN_TENSOR_SET_ID(dst, QNN_TENSOR_GET_ID(src));
185
+ QNN_TENSOR_SET_TYPE(dst, QNN_TENSOR_GET_TYPE(src));
186
+ QNN_TENSOR_SET_DATA_FORMAT(dst, QNN_TENSOR_GET_DATA_FORMAT(src));
187
+ QNN_TENSOR_SET_DATA_TYPE(dst, QNN_TENSOR_GET_DATA_TYPE(src));
188
+ Qnn_QuantizeParams_t qParams = QNN_QUANTIZE_PARAMS_INIT;
189
+ qParams.encodingDefinition = QNN_TENSOR_GET_QUANT_PARAMS(src).encodingDefinition;
190
+ qParams.quantizationEncoding = QNN_QUANTIZATION_ENCODING_UNDEFINED;
191
+ if (QNN_TENSOR_GET_QUANT_PARAMS(src).quantizationEncoding ==
192
+ QNN_QUANTIZATION_ENCODING_SCALE_OFFSET) {
193
+ qParams.quantizationEncoding = QNN_TENSOR_GET_QUANT_PARAMS(src).quantizationEncoding;
194
+ qParams.scaleOffsetEncoding = QNN_TENSOR_GET_QUANT_PARAMS(src).scaleOffsetEncoding;
195
+ } else if (QNN_TENSOR_GET_QUANT_PARAMS(src).quantizationEncoding ==
196
+ QNN_QUANTIZATION_ENCODING_AXIS_SCALE_OFFSET) {
197
+ qParams.quantizationEncoding = QNN_TENSOR_GET_QUANT_PARAMS(src).quantizationEncoding;
198
+ qParams.axisScaleOffsetEncoding.axis =
199
+ QNN_TENSOR_GET_QUANT_PARAMS(src).axisScaleOffsetEncoding.axis;
200
+ qParams.axisScaleOffsetEncoding.numScaleOffsets =
201
+ QNN_TENSOR_GET_QUANT_PARAMS(src).axisScaleOffsetEncoding.numScaleOffsets;
202
+ if (QNN_TENSOR_GET_QUANT_PARAMS(src).axisScaleOffsetEncoding.numScaleOffsets > 0) {
203
+ qParams.axisScaleOffsetEncoding.scaleOffset = (Qnn_ScaleOffset_t *)malloc(
204
+ QNN_TENSOR_GET_QUANT_PARAMS(src).axisScaleOffsetEncoding.numScaleOffsets *
205
+ sizeof(Qnn_ScaleOffset_t));
206
+ if (qParams.axisScaleOffsetEncoding.scaleOffset) {
207
+ for (size_t idx = 0;
208
+ idx < QNN_TENSOR_GET_QUANT_PARAMS(src).axisScaleOffsetEncoding.numScaleOffsets;
209
+ idx++) {
210
+ qParams.axisScaleOffsetEncoding.scaleOffset[idx].scale =
211
+ QNN_TENSOR_GET_QUANT_PARAMS(src).axisScaleOffsetEncoding.scaleOffset[idx].scale;
212
+ qParams.axisScaleOffsetEncoding.scaleOffset[idx].offset =
213
+ QNN_TENSOR_GET_QUANT_PARAMS(src).axisScaleOffsetEncoding.scaleOffset[idx].offset;
214
+ }
215
+ }
216
+ }
217
+ }
218
+ QNN_TENSOR_SET_QUANT_PARAMS(dst, qParams);
219
+ QNN_TENSOR_SET_RANK(dst, QNN_TENSOR_GET_RANK(src));
220
+ QNN_TENSOR_SET_DIMENSIONS(dst, nullptr);
221
+ if (QNN_TENSOR_GET_RANK(src) > 0) {
222
+ QNN_TENSOR_SET_DIMENSIONS(dst, (uint32_t *)malloc(QNN_TENSOR_GET_RANK(src) * sizeof(uint32_t)));
223
+ if (QNN_TENSOR_GET_DIMENSIONS(dst)) {
224
+ pal::StringOp::memscpy(QNN_TENSOR_GET_DIMENSIONS(dst),
225
+ QNN_TENSOR_GET_RANK(src) * sizeof(uint32_t),
226
+ QNN_TENSOR_GET_DIMENSIONS(src),
227
+ QNN_TENSOR_GET_RANK(src) * sizeof(uint32_t));
228
+ }
229
+ if (QNN_TENSOR_GET_IS_DYNAMIC_DIMENSIONS(src)) {
230
+ QNN_TENSOR_SET_IS_DYNAMIC_DIMENSIONS(
231
+ dst, (uint8_t *)malloc(QNN_TENSOR_GET_RANK(src) * sizeof(uint8_t)));
232
+ pal::StringOp::memscpy(QNN_TENSOR_GET_IS_DYNAMIC_DIMENSIONS(dst),
233
+ QNN_TENSOR_GET_RANK(src) * sizeof(uint8_t),
234
+ QNN_TENSOR_GET_IS_DYNAMIC_DIMENSIONS(src),
235
+ QNN_TENSOR_GET_RANK(src) * sizeof(uint8_t));
236
+ }
237
+ }
238
+ QNN_TENSOR_SET_SPARSE_PARAMS(dst, QNN_TENSOR_GET_SPARSE_PARAMS(src));
239
+ return true;
240
+ }
241
+
242
+ bool sample_app::copyTensorsInfo(const Qnn_Tensor_t *tensorsInfoSrc,
243
+ Qnn_Tensor_t *&tensorWrappers,
244
+ uint32_t tensorsCount) {
245
+ QNN_FUNCTION_ENTRY_LOG;
246
+ auto returnStatus = true;
247
+ tensorWrappers = (Qnn_Tensor_t *)calloc(tensorsCount, sizeof(Qnn_Tensor_t));
248
+ if (nullptr == tensorWrappers) {
249
+ QNN_ERROR("Failed to allocate memory for tensorWrappers.");
250
+ return false;
251
+ }
252
+ if (returnStatus) {
253
+ for (size_t tIdx = 0; tIdx < tensorsCount; tIdx++) {
254
+ QNN_DEBUG("Extracting tensorInfo for tensor Idx: %d", tIdx);
255
+ tensorWrappers[tIdx] = QNN_TENSOR_INIT;
256
+ deepCopyQnnTensorInfo(&tensorWrappers[tIdx], &tensorsInfoSrc[tIdx]);
257
+ }
258
+ }
259
+ QNN_FUNCTION_EXIT_LOG;
260
+ return returnStatus;
261
+ }
262
+
263
+ bool sample_app::copyGraphsInfoV1(const QnnSystemContext_GraphInfoV1_t *graphInfoSrc,
264
+ qnn_wrapper_api::GraphInfo_t *graphInfoDst) {
265
+ graphInfoDst->graphName = nullptr;
266
+ if (graphInfoSrc->graphName) {
267
+ graphInfoDst->graphName =
268
+ pal::StringOp::strndup(graphInfoSrc->graphName, strlen(graphInfoSrc->graphName));
269
+ }
270
+ graphInfoDst->inputTensors = nullptr;
271
+ graphInfoDst->numInputTensors = 0;
272
+ if (graphInfoSrc->graphInputs) {
273
+ if (!copyTensorsInfo(
274
+ graphInfoSrc->graphInputs, graphInfoDst->inputTensors, graphInfoSrc->numGraphInputs)) {
275
+ return false;
276
+ }
277
+ graphInfoDst->numInputTensors = graphInfoSrc->numGraphInputs;
278
+ }
279
+ graphInfoDst->outputTensors = nullptr;
280
+ graphInfoDst->numOutputTensors = 0;
281
+ if (graphInfoSrc->graphOutputs) {
282
+ if (!copyTensorsInfo(graphInfoSrc->graphOutputs,
283
+ graphInfoDst->outputTensors,
284
+ graphInfoSrc->numGraphOutputs)) {
285
+ return false;
286
+ }
287
+ graphInfoDst->numOutputTensors = graphInfoSrc->numGraphOutputs;
288
+ }
289
+ return true;
290
+ }
291
+
292
+ bool sample_app::copyGraphsInfo(const QnnSystemContext_GraphInfo_t *graphsInput,
293
+ const uint32_t numGraphs,
294
+ qnn_wrapper_api::GraphInfo_t **&graphsInfo) {
295
+ QNN_FUNCTION_ENTRY_LOG;
296
+ if (!graphsInput) {
297
+ QNN_ERROR("Received nullptr for graphsInput.");
298
+ return false;
299
+ }
300
+ auto returnStatus = true;
301
+ graphsInfo =
302
+ (qnn_wrapper_api::GraphInfo_t **)calloc(numGraphs, sizeof(qnn_wrapper_api::GraphInfo_t *));
303
+ qnn_wrapper_api::GraphInfo_t *graphInfoArr =
304
+ (qnn_wrapper_api::GraphInfo_t *)calloc(numGraphs, sizeof(qnn_wrapper_api::GraphInfo_t));
305
+ if (nullptr == graphsInfo || nullptr == graphInfoArr) {
306
+ QNN_ERROR("Failure to allocate memory for *graphInfo");
307
+ returnStatus = false;
308
+ }
309
+ if (true == returnStatus) {
310
+ for (size_t gIdx = 0; gIdx < numGraphs; gIdx++) {
311
+ QNN_DEBUG("Extracting graphsInfo for graph Idx: %d", gIdx);
312
+ if (graphsInput[gIdx].version == QNN_SYSTEM_CONTEXT_GRAPH_INFO_VERSION_1) {
313
+ copyGraphsInfoV1(&graphsInput[gIdx].graphInfoV1, &graphInfoArr[gIdx]);
314
+ }
315
+ graphsInfo[gIdx] = graphInfoArr + gIdx;
316
+ }
317
+ }
318
+ if (true != returnStatus) {
319
+ QNN_ERROR("Received an ERROR during extractGraphsInfo. Freeing resources.");
320
+ if (graphsInfo) {
321
+ for (uint32_t gIdx = 0; gIdx < numGraphs; gIdx++) {
322
+ if (graphsInfo[gIdx]) {
323
+ if (nullptr != graphsInfo[gIdx]->graphName) {
324
+ free(graphsInfo[gIdx]->graphName);
325
+ graphsInfo[gIdx]->graphName = nullptr;
326
+ }
327
+ qnn_wrapper_api::freeQnnTensors(graphsInfo[gIdx]->inputTensors,
328
+ graphsInfo[gIdx]->numInputTensors);
329
+ qnn_wrapper_api::freeQnnTensors(graphsInfo[gIdx]->outputTensors,
330
+ graphsInfo[gIdx]->numOutputTensors);
331
+ }
332
+ }
333
+ free(*graphsInfo);
334
+ }
335
+ free(graphsInfo);
336
+ graphsInfo = nullptr;
337
+ }
338
+ QNN_FUNCTION_EXIT_LOG;
339
+ return true;
340
+ }
341
+
342
+ bool sample_app::copyMetadataToGraphsInfo(const QnnSystemContext_BinaryInfo_t *binaryInfo,
343
+ qnn_wrapper_api::GraphInfo_t **&graphsInfo,
344
+ uint32_t &graphsCount) {
345
+ if (nullptr == binaryInfo) {
346
+ QNN_ERROR("binaryInfo is nullptr.");
347
+ return false;
348
+ }
349
+ graphsCount = 0;
350
+ if (binaryInfo->version == QNN_SYSTEM_CONTEXT_BINARY_INFO_VERSION_1) {
351
+ if (binaryInfo->contextBinaryInfoV1.graphs) {
352
+ if (!copyGraphsInfo(binaryInfo->contextBinaryInfoV1.graphs,
353
+ binaryInfo->contextBinaryInfoV1.numGraphs,
354
+ graphsInfo)) {
355
+ QNN_ERROR("Failed while copying graphs Info.");
356
+ return false;
357
+ }
358
+ graphsCount = binaryInfo->contextBinaryInfoV1.numGraphs;
359
+ return true;
360
+ }
361
+ } else if (binaryInfo->version == QNN_SYSTEM_CONTEXT_BINARY_INFO_VERSION_2) {
362
+ if (binaryInfo->contextBinaryInfoV2.graphs) {
363
+ if (!copyGraphsInfo(binaryInfo->contextBinaryInfoV2.graphs,
364
+ binaryInfo->contextBinaryInfoV2.numGraphs,
365
+ graphsInfo)) {
366
+ QNN_ERROR("Failed while copying graphs Info.");
367
+ return false;
368
+ }
369
+ graphsCount = binaryInfo->contextBinaryInfoV2.numGraphs;
370
+ return true;
371
+ }
372
+ }
373
+ QNN_ERROR("Unrecognized system context binary info version.");
374
+ return false;
375
+ }
376
+
377
+ QnnLog_Level_t sample_app::parseLogLevel(std::string logLevelString) {
378
+ QNN_FUNCTION_ENTRY_LOG;
379
+ std::transform(logLevelString.begin(), logLevelString.end(), logLevelString.begin(), ::tolower);
380
+ QnnLog_Level_t parsedLogLevel = QNN_LOG_LEVEL_MAX;
381
+ if (logLevelString == "error") {
382
+ parsedLogLevel = QNN_LOG_LEVEL_ERROR;
383
+ } else if (logLevelString == "warn") {
384
+ parsedLogLevel = QNN_LOG_LEVEL_WARN;
385
+ } else if (logLevelString == "info") {
386
+ parsedLogLevel = QNN_LOG_LEVEL_INFO;
387
+ } else if (logLevelString == "verbose") {
388
+ parsedLogLevel = QNN_LOG_LEVEL_VERBOSE;
389
+ } else if (logLevelString == "debug") {
390
+ parsedLogLevel = QNN_LOG_LEVEL_DEBUG;
391
+ }
392
+ QNN_FUNCTION_EXIT_LOG;
393
+ return parsedLogLevel;
394
+ }
SampleApp/src/Utils/QnnSampleAppUtils.hpp ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //==============================================================================
2
+ //
3
+ // Copyright (c) 2019-2023 Qualcomm Technologies, Inc.
4
+ // All Rights Reserved.
5
+ // Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ //
7
+ //==============================================================================
8
+ #pragma once
9
+
10
+ #include <iostream>
11
+ #include <map>
12
+ #include <queue>
13
+ #include <regex>
14
+ #include <string>
15
+ #include <tuple>
16
+ #include <unordered_map>
17
+ #include <vector>
18
+
19
+ #include "SampleApp.hpp"
20
+
21
+ namespace qnn {
22
+ namespace tools {
23
+ namespace sample_app {
24
+
25
+ enum class ProfilingLevel { OFF, BASIC, DETAILED, INVALID };
26
+
27
+ using ReadInputListRetType_t = std::
28
+ tuple<std::vector<std::vector<std::string>>, std::unordered_map<std::string, uint32_t>, bool>;
29
+
30
+ ReadInputListRetType_t readInputList(std::string inputFileListPath);
31
+
32
+ using ReadInputListsRetType_t = std::tuple<std::vector<std::vector<std::vector<std::string>>>,
33
+ std::vector<std::unordered_map<std::string, uint32_t>>,
34
+ bool>;
35
+
36
+ ReadInputListsRetType_t readInputLists(std::vector<std::string> inputFileListPath);
37
+
38
+ std::unordered_map<std::string, uint32_t> extractInputNameIndices(const std::string &inputLine,
39
+ const std::string &separator);
40
+
41
+ std::string sanitizeTensorName(std::string name);
42
+
43
+ ProfilingLevel parseProfilingLevel(std::string profilingLevelString);
44
+
45
+ void parseInputFilePaths(std::vector<std::string> &inputFilePaths,
46
+ std::vector<std::string> &paths,
47
+ std::string separator);
48
+
49
+ void split(std::vector<std::string> &splitString,
50
+ const std::string &tokenizedString,
51
+ const char separator);
52
+
53
+ bool copyMetadataToGraphsInfo(const QnnSystemContext_BinaryInfo_t *binaryInfo,
54
+ qnn_wrapper_api::GraphInfo_t **&graphsInfo,
55
+ uint32_t &graphsCount);
56
+
57
+ bool copyGraphsInfo(const QnnSystemContext_GraphInfo_t *graphsInput,
58
+ const uint32_t numGraphs,
59
+ qnn_wrapper_api::GraphInfo_t **&graphsInfo);
60
+
61
+ bool copyGraphsInfoV1(const QnnSystemContext_GraphInfoV1_t *graphInfoSrc,
62
+ qnn_wrapper_api::GraphInfo_t *graphInfoDst);
63
+
64
+ bool copyTensorsInfo(const Qnn_Tensor_t *tensorsInfoSrc,
65
+ Qnn_Tensor_t *&tensorWrappers,
66
+ uint32_t tensorsCount);
67
+
68
+ bool deepCopyQnnTensorInfo(Qnn_Tensor_t *dst, const Qnn_Tensor_t *src);
69
+
70
+ QnnLog_Level_t parseLogLevel(std::string logLevelString);
71
+
72
+ void inline exitWithMessage(std::string &&msg, int code) {
73
+ std::cerr << msg << std::endl;
74
+ std::exit(code);
75
+ }
76
+
77
+ } // namespace sample_app
78
+ } // namespace tools
79
+ } // namespace qnn