Merge pull request #20392 from fpetrogalli:aarch64-semihosting
authorFrancesco Petrogalli <25690309+fpetrogalli@users.noreply.github.com>
Wed, 21 Jul 2021 15:46:05 +0000 (16:46 +0100)
committerGitHub <noreply@github.com>
Wed, 21 Jul 2021 15:46:05 +0000 (18:46 +0300)
AArch64 semihosting

* [ts] Disable filesystem support in the TS module.

Because of this change, all the tests loading data will file, but tat
least the core module can be tested with the following line:

    opencv_test_core --gtest_filter=-"*Core_InputOutput*:*Core_globbing.accuracy*"

* [aarch64] Build OpenCV for AArch64 semihosting.

This patch provide a toolchain file that allows to build the library
for semihosting applications [1]. Minimal changes have been applied to
the code to be able to compile with a baremetal toolchain.

[1] https://developer.arm.com/documentation/100863/latest

The option `CV_SEMIHOSTING` is used to guard the bits in the code that
are specific to the target.

To build the code:

    cmake ../opencv/ \
        -DCMAKE_TOOLCHAIN_FILE=../opencv/platforms/semihosting/aarch64-semihosting.toolchain.cmake \
        -DSEMIHOSTING_TOOLCHAIN_PATH=/path/to/baremetal-toolchain/bin/ \
        -DBUILD_EXAMPLES=ON -GNinja

A barematel toolchain for targeting aarch64 semihosting can be found
at [2], under `aarch64-none-elf`.

[2] https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads

The folder `samples/semihosting` provides two example semihosting
applications.

The two binaries can be executed on the host platform with:

    qemu-aarch64 ./bin/example_semihosting_histogram
    qemu-aarch64 ./bin/example_semihosting_norm

Similarly, the test and perf executables of the modules can be run
with:

    qemu-aarch64 ./bin/opecv_[test|perf]_<module>

Notice that filesystem support is disabled by the toolchain file,
hence some of the test that depend on filesystem support will fail.

* [semihosting] Remove blank like at the end of file. [NFC]

The spurious blankline was reported by
https://pullrequest.opencv.org/buildbot/builders/precommit_docs/builds/31158.

* [semihosting] Make the raw pixel file generation OS independent.

Use the facilities provided by Cmake to generate the header file
instead of a shell script, so that the build doesn't fail on systems
that do not have a unix shell.

* [semihosting] Rename variable for semihosting compilation.

* [semihosting] Move the cmake configuration to a variable file.

* [semihosting] Make the guard macro private for the core module.

* [semihosting] Remove space. [NFC]

* [semihosting] Improve comment with information about semihosting. [NFC]

* [semihosting] Update license statement on top of sourvce file. [NFC]

* [semihosting] Replace BM_SUFFIX with SEMIHOSTING_SUFFIX. [NFC]

* [semihosting] Remove double space. [NFC]

* [semihosting] Add some text output to the sample applications.

* [semihosting] Remove duplicate entry in cmake configuration. [NFCI]

* [semihosting] Replace `long` with `int` in sample apps. [NFCI]

* [semihosting] Use `configure_file` to create the random pixels. [NFCI]

* [semihosting][bugfix] Fix name of cmakedefine variable.

* [semihosting][samples] Use CV_8UC1 for grayscale images. [NFCI]

* [semihosting] Add readme file.

* [semihosting] Remove blank like at the end of README. [NFC]

This fixes the failure at
https://pullrequest.opencv.org/buildbot/builders/precommit_docs/builds/31272.

19 files changed:
CMakeLists.txt
cmake/vars/EnableModeVars.cmake
cmake/vars/OPENCV_SEMIHOSTING.cmake [new file with mode: 0644]
modules/calib3d/src/ap3p.cpp
modules/core/CMakeLists.txt
modules/core/src/parallel.cpp
modules/ts/src/ts.cpp
modules/ts/src/ts_gtest.cpp
platforms/semihosting/aarch64-semihosting.toolchain.cmake [new file with mode: 0644]
platforms/semihosting/include/aarch64_semihosting_port.hpp [new file with mode: 0644]
samples/CMakeLists.txt
samples/semihosting/CMakeLists.txt [new file with mode: 0644]
samples/semihosting/README.md [new file with mode: 0644]
samples/semihosting/histogram/CMakeLists.txt [new file with mode: 0644]
samples/semihosting/histogram/histogram.cpp [new file with mode: 0644]
samples/semihosting/include/CMakeLists.txt [new file with mode: 0644]
samples/semihosting/include/raw_pixels.hpp.in [new file with mode: 0644]
samples/semihosting/norm/CMakeLists.txt [new file with mode: 0644]
samples/semihosting/norm/norm.cpp [new file with mode: 0644]

index f4fe038..b7e5b58 100644 (file)
@@ -513,6 +513,7 @@ OCV_OPTION(ENABLE_CONFIG_VERIFICATION "Fail build if actual configuration doesn'
 OCV_OPTION(OPENCV_ENABLE_MEMALIGN     "Enable posix_memalign or memalign usage" ON)
 OCV_OPTION(OPENCV_DISABLE_FILESYSTEM_SUPPORT "Disable filesystem support" OFF)
 OCV_OPTION(OPENCV_DISABLE_THREAD_SUPPORT "Build the library without multi-threaded code." OFF)
+OCV_OPTION(OPENCV_SEMIHOSTING         "Build the library for semihosting target (Arm). See https://developer.arm.com/documentation/100863/latest." OFF)
 
 OCV_OPTION(ENABLE_PYLINT              "Add target with Pylint checks"                            (BUILD_DOCS OR BUILD_EXAMPLES) IF (NOT CMAKE_CROSSCOMPILING AND NOT APPLE_FRAMEWORK) )
 OCV_OPTION(ENABLE_FLAKE8              "Add target with Python flake8 checker"                    (BUILD_DOCS OR BUILD_EXAMPLES) IF (NOT CMAKE_CROSSCOMPILING AND NOT APPLE_FRAMEWORK) )
index b3c4e79..3f017af 100644 (file)
@@ -16,3 +16,6 @@ endmacro()
 
 variable_watch(OPENCV_DISABLE_THREAD_SUPPORT ocv_change_mode_var)
 set(OPENCV_DISABLE_THREAD_SUPPORT "${OPENCV_DISABLE_THREAD_SUPPORT}")
+
+variable_watch(OPENCV_SEMIHOSTING ocv_change_mode_var)
+set(OPENCV_SEMIHOSTING "${OPENCV_SEMIHOSTING}")
diff --git a/cmake/vars/OPENCV_SEMIHOSTING.cmake b/cmake/vars/OPENCV_SEMIHOSTING.cmake
new file mode 100644 (file)
index 0000000..66f21c7
--- /dev/null
@@ -0,0 +1,10 @@
+set(CV_TRACE OFF)
+
+# These third parties libraries are incompatible with the semihosting
+# toolchain.
+set(WITH_JPEG OFF)
+set(WITH_OPENEXR OFF)
+set(WITH_TIFF OFF)
+
+# Turn off `libpng` for some linking issues.
+set(WITH_PNG OFF)
index 386a449..582b201 100644 (file)
@@ -7,8 +7,6 @@
 static inline double cbrt(double x) { return (double)cv::cubeRoot((float)x); };
 #endif
 
-using namespace std;
-
 namespace {
 void solveQuartic(const double *factors, double *realRoots) {
     const double &a4 = factors[0];
@@ -30,29 +28,29 @@ void solveQuartic(const double *factors, double *realRoots) {
     double q3 = (72 * r4 * p4 - 2 * p4 * p4 * p4 - 27 * q4 * q4) / 432; // /=2
 
     double t; // *=2
-    complex<double> w;
+    std::complex<double> w;
     if (q3 >= 0)
-        w = -sqrt(static_cast<complex<double> >(q3 * q3 - p3 * p3 * p3)) - q3;
+        w = -std::sqrt(static_cast<std::complex<double> >(q3 * q3 - p3 * p3 * p3)) - q3;
     else
-        w = sqrt(static_cast<complex<double> >(q3 * q3 - p3 * p3 * p3)) - q3;
+        w = std::sqrt(static_cast<std::complex<double> >(q3 * q3 - p3 * p3 * p3)) - q3;
     if (w.imag() == 0.0) {
-        w.real(cbrt(w.real()));
+        w.real(std::cbrt(w.real()));
         t = 2.0 * (w.real() + p3 / w.real());
     } else {
         w = pow(w, 1.0 / 3);
         t = 4.0 * w.real();
     }
 
-    complex<double> sqrt_2m = sqrt(static_cast<complex<double> >(-2 * p4 / 3 + t));
+    std::complex<double> sqrt_2m = sqrt(static_cast<std::complex<double> >(-2 * p4 / 3 + t));
     double B_4A = -a3 / (4 * a4);
     double complex1 = 4 * p4 / 3 + t;
 #if defined(__clang__) && defined(__arm__) && (__clang_major__ == 3 || __clang_major__ == 4) && !defined(__ANDROID__)
     // details: https://github.com/opencv/opencv/issues/11135
     // details: https://github.com/opencv/opencv/issues/11056
-    complex<double> complex2 = 2 * q4;
-    complex2 = complex<double>(complex2.real() / sqrt_2m.real(), 0);
+    std::complex<double> complex2 = 2 * q4;
+    complex2 = std::complex<double>(complex2.real() / sqrt_2m.real(), 0);
 #else
-    complex<double> complex2 = 2 * q4 / sqrt_2m;
+    std::complex<double> complex2 = 2 * q4 / sqrt_2m;
 #endif
     double sqrt_2m_rh = sqrt_2m.real() / 2;
     double sqrt1 = sqrt(-(complex1 + complex2)).real() / 2;
index 6a969e5..13d0af4 100644 (file)
@@ -157,6 +157,10 @@ if(OPENCV_DISABLE_THREAD_SUPPORT)
   ocv_target_compile_definitions(${the_module} PUBLIC "OPENCV_DISABLE_THREAD_SUPPORT=1")
 endif()
 
+if(OPENCV_SEMIHOSTING)
+  ocv_target_compile_definitions(${the_module} PRIVATE "-DOPENCV_SEMIHOSTING")
+endif(OPENCV_SEMIHOSTING)
+
 if(HAVE_HPX)
   ocv_target_link_libraries(${the_module} LINK_PRIVATE "${HPX_LIBRARIES}")
 endif()
index 1d4179b..8fccd19 100644 (file)
@@ -888,6 +888,7 @@ T minNonZero(const T& val_1, const T& val_2)
 static
 int getNumberOfCPUs_()
 {
+#ifndef OPENCV_SEMIHOSTING
     /*
      * Logic here is to try different methods of getting CPU counts and return
      * the minimum most value as it has high probablity of being right and safe.
@@ -979,6 +980,9 @@ int getNumberOfCPUs_()
 #endif
 
     return ncpus != 0 ? ncpus : 1;
+#else //  OPENCV_SEMIHOSTING
+    return 1;
+#endif //OPENCV_SEMIHOSTING
 }
 
 int getNumberOfCPUs()
index 3aa403a..3af3a7b 100644 (file)
@@ -72,7 +72,9 @@
 #if defined _WIN32 || defined WINCE
 # include <windows.h>
 #else
+#if OPENCV_HAVE_FILESYSTEM_SUPPORT
 # include <dirent.h>
+#endif
 # include <sys/stat.h>
 #endif
 
index a65ef72..b3debd5 100644 (file)
@@ -1067,6 +1067,7 @@ class GTEST_API_ UnitTestImpl {
   void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
                    Test::TearDownTestCaseFunc tear_down_tc,
                    TestInfo* test_info) {
+#if OPENCV_HAVE_FILESYSTEM_SUPPORT
     // In order to support thread-safe death tests, we need to
     // remember the original working directory when the test program
     // was first invoked.  We cannot do this in RUN_ALL_TESTS(), as
@@ -1079,6 +1080,7 @@ class GTEST_API_ UnitTestImpl {
       GTEST_CHECK_(!original_working_dir_.IsEmpty())
           << "Failed to get the current working directory.";
     }
+#endif
 
     GetTestCase(test_info->test_case_name(),
                 test_info->type_param(),
@@ -9165,6 +9167,7 @@ static bool IsPathSeparator(char c) {
 
 // Returns the current working directory, or "" if unsuccessful.
 FilePath FilePath::GetCurrentDir() {
+#if OPENCV_HAVE_FILESYSTEM_SUPPORT
 #if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
   // Windows CE doesn't have a current directory, so we just return
   // something reasonable.
@@ -9183,6 +9186,9 @@ FilePath FilePath::GetCurrentDir() {
 # endif  // GTEST_OS_NACL
   return FilePath(result == NULL ? "" : cwd);
 #endif  // GTEST_OS_WINDOWS_MOBILE
+#else // OPENCV_HAVE_FILESYSTEM_SUPPORT
+  return FilePath("");
+#endif // OPENCV_HAVE_FILESYSTEM_SUPPORT
 }
 
 // Returns a copy of the FilePath with the case-insensitive extension removed.
@@ -9391,6 +9397,7 @@ bool FilePath::CreateDirectoriesRecursively() const {
 // directory for any reason, including if the parent directory does not
 // exist. Not named "CreateDirectory" because that's a macro on Windows.
 bool FilePath::CreateFolder() const {
+#if OPENCV_HAVE_FILESYSTEM_SUPPORT
 #if GTEST_OS_WINDOWS_MOBILE
   FilePath removed_sep(this->RemoveTrailingPathSeparator());
   LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
@@ -9406,6 +9413,9 @@ bool FilePath::CreateFolder() const {
     return this->DirectoryExists();  // An error is OK if the directory exists.
   }
   return true;  // No error.
+#else // OPENCV_HAVE_FILESYSTEM_SUPPORT
+  return false;
+#endif // OPENCV_HAVE_FILESYSTEM_SUPPORT
 }
 
 // If input name has a trailing separator character, remove it and return the
diff --git a/platforms/semihosting/aarch64-semihosting.toolchain.cmake b/platforms/semihosting/aarch64-semihosting.toolchain.cmake
new file mode 100644 (file)
index 0000000..95bbda3
--- /dev/null
@@ -0,0 +1,40 @@
+# This file is part of OpenCV project.
+# It is subject to the license terms in the LICENSE file found in the top-level directory
+# of this distribution and at http://opencv.org/license.html
+
+set(CMAKE_SYSTEM_NAME               Generic)
+set(CMAKE_SYSTEM_PROCESSOR          AArch64)
+
+set(CMAKE_TRY_COMPILE_TARGET_TYPE   STATIC_LIBRARY)
+
+set(PORT_FILE ${CMAKE_SOURCE_DIR}/platforms/semihosting/include/aarch64_semihosting_port.hpp)
+
+set(COMMON_FLAGS "--specs=rdimon.specs -DOPENCV_INCLUDE_PORT_FILE=\\\"${PORT_FILE}\\\"")
+
+set(CMAKE_AR                        ${SEMIHOSTING_TOOLCHAIN_PATH}aarch64-none-elf-ar${CMAKE_EXECUTABLE_SUFFIX})
+set(CMAKE_ASM_COMPILER              ${SEMIHOSTING_TOOLCHAIN_PATH}aarch64-none-elf-gcc${CMAKE_EXECUTABLE_SUFFIX})
+set(CMAKE_C_COMPILER                ${SEMIHOSTING_TOOLCHAIN_PATH}aarch64-none-elf-gcc${CMAKE_EXECUTABLE_SUFFIX})
+set(CMAKE_CXX_COMPILER              ${SEMIHOSTING_TOOLCHAIN_PATH}aarch64-none-elf-g++${CMAKE_EXECUTABLE_SUFFIX})
+set(CMAKE_LINKER                    ${SEMIHOSTING_TOOLCHAIN_PATH}aarch64-none-elf-ld${CMAKE_EXECUTABLE_SUFFIX})
+set(CMAKE_OBJCOPY                   ${SEMIHOSTING_TOOLCHAIN_PATH}aarch64-none-elf-objcopy${CMAKE_EXECUTABLE_SUFFIX} CACHE INTERNAL "")
+set(CMAKE_RANLIB                    ${SEMIHOSTING_TOOLCHAIN_PATH}aarch64-none-elf-ranlib${CMAKE_EXECUTABLE_SUFFIX} CACHE INTERNAL "")
+set(CMAKE_SIZE                      ${SEMIHOSTING_TOOLCHAIN_PATH}aarch64-none-elf-size${CMAKE_EXECUTABLE_SUFFIX} CACHE INTERNAL "")
+set(CMAKE_STRIP                     ${SEMIHOSTING_TOOLCHAIN_PATH}aarch64-none-elf-strip${CMAKE_EXECUTABLE_SUFFIX} CACHE INTERNAL "")
+set(CMAKE_C_FLAGS                   ${COMMON_FLAGS} CACHE INTERNAL "")
+set(CMAKE_CXX_FLAGS                 ${COMMON_FLAGS} CACHE INTERNAL "")
+
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+set(OPENCV_SEMIHOSTING ON)
+set(OPENCV_DISABLE_THREAD_SUPPORT ON)
+set(OPENCV_DISABLE_FILESYSTEM_SUPPORT ON)
+set(BUILD_SHARED_LIBS OFF)
+set(OPENCV_FORCE_3RDPARTY_BUILD OFF)
+
+
+# Enable newlib.
+add_definitions(-D_GNU_SOURCE)
+
+add_definitions(-D_POSIX_PATH_MAX=0)
diff --git a/platforms/semihosting/include/aarch64_semihosting_port.hpp b/platforms/semihosting/include/aarch64_semihosting_port.hpp
new file mode 100644 (file)
index 0000000..d3151c2
--- /dev/null
@@ -0,0 +1,42 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#ifndef AARCH64_BAREMETAL_PORT_HPP
+#define AARCH64_BAREMETAL_PORT_HPP
+
+#include <malloc.h> // Needed for `memalign`.
+#include <sys/errno.h> // Needed for `ENOMEM`.
+
+// -std=c++11 is missing the following definitions when targeting
+// semihosting on aarch64.
+#if __cplusplus == 201103L
+#include <cmath>
+#define M_PI 3.14159265358979323846
+#define M_SQRT2 1.41421356237309504880
+
+namespace std {
+inline double cbrt(double x) {
+    return ::cbrt(x);
+}
+inline double copysign(double mag, double sgn) {
+    return ::copysign(mag, sgn);
+}
+} //namespace std
+#endif // __cplusplus == 201103L
+
+extern "C" {
+// Redirect the implementation of `posix_memalign` to `memalign`
+// as the former is
+// missing at link time. https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_memalign.html
+__attribute__((weak)) int posix_memalign(void **memptr, size_t alignment, size_t size) {
+    void * ptr =  memalign(alignment, size);
+    if (ptr != NULL) {
+        *memptr = ptr;
+        return 0;
+    }
+    return ENOMEM;
+}
+} // extern "C"
+
+#endif
index 0c70698..9bfc2bf 100644 (file)
@@ -45,7 +45,12 @@ endif()
 if(INSTALL_PYTHON_EXAMPLES)
   add_subdirectory(python)
 endif()
-
+# The examples in this folder will work with a semihosting version of
+# OpenCV. For more information about semihosting, see
+# https://developer.arm.com/documentation/100863/latest
+if(OPENCV_SEMIHOSTING)
+  add_subdirectory(semihosting)
+endif()
 ocv_install_example_src("." CMakeLists.txt samples_utils.cmake)
 if(INSTALL_C_EXAMPLES)
   install(DIRECTORY data DESTINATION "${OPENCV_SAMPLES_SRC_INSTALL_PATH}" COMPONENT samples_data)
diff --git a/samples/semihosting/CMakeLists.txt b/samples/semihosting/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9fddb05
--- /dev/null
@@ -0,0 +1,10 @@
+# This file is part of OpenCV project.
+# It is subject to the license terms in the LICENSE file found in the top-level directory
+# of this distribution and at http://opencv.org/license.html
+
+set(SEMIHOSTING_SUFFIX semihosting)
+
+add_subdirectory(include)
+set(RAW_PIXEL_INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/include)
+add_subdirectory(histogram)
+add_subdirectory(norm)
diff --git a/samples/semihosting/README.md b/samples/semihosting/README.md
new file mode 100644 (file)
index 0000000..881b09b
--- /dev/null
@@ -0,0 +1,27 @@
+# Arm semihosting
+
+This folder contain a toolchain file and a couple of examples for
+building OpenCV based applications that can run in an [Arm
+semihosting](https://developer.arm.com/documentation/100863/latest)
+setup.
+
+OpenCV can be compiled to target a semihosting platform as follows:
+
+```
+cmake ../opencv/ \
+    -DCMAKE_TOOLCHAIN_FILE=../opencv/platforms/semihosting/aarch64-semihosting.toolchain.cmake \
+    -DSEMIHOSTING_TOOLCHAIN_PATH=/path/to/baremetal-toolchain/bin/ \
+    -DBUILD_EXAMPLES=ON -GNinja
+```
+
+A barematel toolchain for targeting aarch64 semihosting can be found
+[here](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads),
+under `aarch64-none-elf`.
+
+The code of the examples in the `norm` and `histogram` folders can be
+executed with qemu in Linux userspace:
+
+```
+    qemu-aarch64 ./bin/example_semihosting_histogram
+    qemu-aarch64 ./bin/example_semihosting_norm
+```
diff --git a/samples/semihosting/histogram/CMakeLists.txt b/samples/semihosting/histogram/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d2f065d
--- /dev/null
@@ -0,0 +1,26 @@
+# This file is part of OpenCV project.
+# It is subject to the license terms in the LICENSE file found in the top-level directory
+# of this distribution and at http://opencv.org/license.html
+
+set(PROJECT_NAME histogram)
+project(${PROJECT_NAME})
+
+ocv_install_example_src(histogram *.cpp *.hpp CMakeLists.txt)
+
+set(LOCAL_DEPS
+  opencv_core
+  opencv_imgproc
+  ${OPENCV_MODULES_PUBLIC}
+  ${OpenCV_LIB_COMPONENTS})
+ocv_check_dependencies(${LOCAL_DEPS})
+
+if(NOT OCV_DEPENDENCIES_FOUND)
+  return()
+endif()
+
+ocv_define_sample(histogram histogram.cpp ${SEMIHOSTING_SUFFIX})
+ocv_include_modules_recurse(${LOCAL_DEPS})
+target_include_directories(${histogram} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+target_include_directories(${histogram} PRIVATE ${RAW_PIXEL_INCLUDE})
+ocv_target_link_libraries(${histogram} PRIVATE ${OPENCV_LINKER_LIBS}
+  ${LOCAL_DEPS})
diff --git a/samples/semihosting/histogram/histogram.cpp b/samples/semihosting/histogram/histogram.cpp
new file mode 100644 (file)
index 0000000..daa568d
--- /dev/null
@@ -0,0 +1,43 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html
+
+#include <opencv2/imgproc.hpp>
+#include <opencv2/imgcodecs.hpp>
+
+#include <cstdint>
+#include <array>
+#include <iostream>
+#include "raw_pixels.hpp"
+
+#define IMG_ROWS 100
+#define IMG_COLS 100
+
+static_assert(IMG_ROWS * IMG_COLS <= RAW_PIXELS_SIZE, "Incompatible size");
+
+int main(void)
+{
+    // Number of experiment runs
+    int no_runs = 2;
+
+    // https://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html
+    cv::Mat src_new(IMG_ROWS, IMG_COLS, CV_8UC1, (void *)raw_pixels);
+
+    // Set parameters
+    int imgCount = 1;
+    const int channels[] = {0};
+    cv::Mat mask = cv::Mat();
+    cv::Mat hist;
+    int dims = 1;
+    const int hist_sizes[] = {256};
+    float Range[] = {0,256};
+    const float *ranges[] = {Range};
+
+    // Run calc Hist
+    for(int i=0; i < no_runs; i++){
+        std::cout << "Running iteration # "<< i << std::endl;
+        cv::calcHist(&src_new, imgCount, channels, mask, hist, dims, hist_sizes, ranges);
+    }
+
+    return 0;
+}
diff --git a/samples/semihosting/include/CMakeLists.txt b/samples/semihosting/include/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3c429b8
--- /dev/null
@@ -0,0 +1,16 @@
+# Populate a C array with random data.
+set(RAW_PIXELS_SIZE 102400)
+set(RAW_PIXELS_HEADER ${CMAKE_CURRENT_BINARY_DIR}/raw_pixels.hpp)
+set(RAW_PIXELS_HEADER_IN ${CMAKE_CURRENT_SOURCE_DIR}/raw_pixels.hpp.in)
+
+set(RAW_PIXEL_VALUES "")
+# Seed the random number generator.
+string(RANDOM LENGTH 8 ALPHABET 0123456789abcdf RANDOM_SEED 314 number)
+math(EXPR LOOP_RANGE "${RAW_PIXELS_SIZE} - 1")
+
+foreach(i RANGE ${LOOP_RANGE})
+  string(RANDOM LENGTH 8 ALPHABET 0123456789abcdf number)
+  string(CONCAT RAW_PIXEL_VALUES ${RAW_PIXEL_VALUES} "0x${number}, \\\n")
+endforeach()
+
+configure_file(${RAW_PIXELS_HEADER_IN} ${RAW_PIXELS_HEADER})
diff --git a/samples/semihosting/include/raw_pixels.hpp.in b/samples/semihosting/include/raw_pixels.hpp.in
new file mode 100644 (file)
index 0000000..6ee9822
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef RAW_PIXELS_HPP
+#define RAW_PIXELS_HP
+#include <cstdint>
+
+#cmakedefine RAW_PIXEL_VALUES @RAW_PIXEL_VALUES@
+#cmakedefine RAW_PIXELS_SIZE @RAW_PIXELS_SIZE@
+
+static std::uint32_t raw_pixels[RAW_PIXELS_SIZE] = {
+    RAW_PIXEL_VALUES
+};
+#endif //RAW_PIXELS_HPP
diff --git a/samples/semihosting/norm/CMakeLists.txt b/samples/semihosting/norm/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6f23d74
--- /dev/null
@@ -0,0 +1,25 @@
+# This file is part of OpenCV project.
+# It is subject to the license terms in the LICENSE file found in the top-level directory
+# of this distribution and at http://opencv.org/license.html
+
+set(PROJECT_NAME norm)
+project(${PROJECT_NAME})
+
+ocv_install_example_src(norm *.cpp *.hpp CMakeLists.txt)
+
+set(LOCAL_DEPS
+  opencv_core
+  ${OPENCV_MODULES_PUBLIC}
+  ${OpenCV_LIB_COMPONENTS})
+ocv_check_dependencies(${LOCAL_DEPS})
+
+if(NOT OCV_DEPENDENCIES_FOUND)
+  return()
+endif()
+
+ocv_define_sample(norm norm.cpp ${SEMIHOSTING_SUFFIX})
+ocv_include_modules_recurse(${LOCAL_DEPS})
+target_include_directories(${norm} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+target_include_directories(${norm} PRIVATE ${RAW_PIXEL_INCLUDE})
+ocv_target_link_libraries(${norm} PRIVATE ${OPENCV_LINKER_LIBS}
+  ${LOCAL_DEPS})
diff --git a/samples/semihosting/norm/norm.cpp b/samples/semihosting/norm/norm.cpp
new file mode 100644 (file)
index 0000000..f911754
--- /dev/null
@@ -0,0 +1,33 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html
+
+#include <opencv2/core.hpp>
+#include <opencv2/imgcodecs.hpp>
+
+#include <cstdint>
+#include <array>
+#include <iostream>
+#include "raw_pixels.hpp"
+
+#define IMG_ROWS 100
+#define IMG_COLS 100
+
+static_assert(IMG_ROWS * IMG_COLS <= RAW_PIXELS_SIZE, "Incompatible size");
+
+int main(void)
+{
+    // Number of experiment runs
+    int no_runs = 2;
+
+    // https://docs.opencv.org/master/d3/d63/classcv_1_1Mat.html
+    cv::Mat src(IMG_ROWS, IMG_COLS, CV_8UC1, (void *)raw_pixels);
+
+    // Run calc Hist
+    for(int i=0; i < no_runs; i++){
+        std::cout << "Running iteration # "<< i << std::endl;
+        cv::norm(src);
+    }
+
+    return 0;
+}