COMPMID-2564 - Add CLGEMMNative example

* Add gemm native example.
* Update shell script to run gemm native example.

Signed-off-by: SiCong Li <sicong.li@arm.com>
Change-Id: I0252f556b6f94adb776b8cb84b45971f1eb317e4
Reviewed-on: https://review.mlplatform.org/c/1992
Tested-by: Arm Jenkins <bsgcomp@arm.com>
Reviewed-by: Georgios Pinitas <georgios.pinitas@arm.com>
diff --git a/examples/gemm_tuner/benchmark_gemm_examples.sh b/examples/gemm_tuner/benchmark_gemm_examples.sh
index 7782b11..fd5f71d 100755
--- a/examples/gemm_tuner/benchmark_gemm_examples.sh
+++ b/examples/gemm_tuner/benchmark_gemm_examples.sh
@@ -29,9 +29,10 @@
 CMD=$( basename $0 )
 
 # All supported strategy options
-ALL_STRATEGY_OPTIONS=("reshaped_rhs_only" "reshaped")
+ALL_STRATEGY_OPTIONS=("native" "reshaped_rhs_only" "reshaped")
 
 # Names of example binary for each strategy
+EXAMPLE_BIN_NATIVE="benchmark_cl_gemm_native"
 EXAMPLE_BIN_RESHAPED_RHS_ONLY="benchmark_cl_gemm_reshaped_rhs_only"
 EXAMPLE_BIN_RESHAPED="benchmark_cl_gemm_reshaped"
 
@@ -73,6 +74,38 @@
 }
 
 #######################################
+# Print gemm config file for native help message
+# Globals:
+#   None
+# Arguments:
+#   None
+# Returns:
+#   None
+#######################################
+function help_gemm_config_file_native() {
+  cat >&2 << EOF
+Gemm config file (Strategy native):
+  Gemm config file is a headerless csv file with fields separated by commas and commas only (there cannot be whitespaces
+  around each field).
+  A gemm config is a list of 4 positive integers <m0, n0, k0, h0> and 2 boolean values interleave_rhs and transpose_rhs, with:
+  m0 - Number of rows processed by the matrix multiplication
+  n0 - Number of columns processed by the matrix multiplication
+  k0 - Number of partial accumulations performed by the matrix multiplication
+
+  Only the following configurations of M0, N0 and K0 are currently supported:
+  M0 = 1, 2, 3, 4, 5, 6, 7, 8
+  N0 = 2, 3, 4, 8, 16
+  K0 = 2, 3, 4, 8, 16
+
+  An example gemm config file looks like:
+  1,4,4
+  2,3,8
+  ...
+
+EOF
+}
+
+#######################################
 # Print gemm config file for reshaped_rhs_only help message
 # Globals:
 #   None
@@ -195,6 +228,7 @@
 EOF
 # Print help messages about gemm shapes and various gemm configs
 $HELP && help_gemm_shape_file
+$HELP && ( [ "${STRATEGY_OPTION}" == "" ] || [ "${STRATEGY_OPTION}" == "native" ] ) && help_gemm_config_file_native
 $HELP && ( [ "${STRATEGY_OPTION}" == "" ] || [ "${STRATEGY_OPTION}" == "reshaped_rhs_only" ] ) && help_gemm_config_file_reshaped_rhs_only
 $HELP && ( [ "${STRATEGY_OPTION}" == "" ] || [ "${STRATEGY_OPTION}" == "reshaped" ] ) && help_gemm_config_file_reshaped
 exit 1
@@ -360,6 +394,7 @@
 mkdir ${OUT_DIR}
 
 # Run selected strategy with all configurations
+[ "${STRATEGY_OPTION}" == "native" ] && run $EXAMPLE_BIN_NATIVE
 [ "${STRATEGY_OPTION}" == "reshaped_rhs_only" ] && run $EXAMPLE_BIN_RESHAPED_RHS_ONLY
 [ "${STRATEGY_OPTION}" == "reshaped" ] && run $EXAMPLE_BIN_RESHAPED
 # Main: Main script }}}
diff --git a/examples/gemm_tuner/cl_gemm_native.cpp b/examples/gemm_tuner/cl_gemm_native.cpp
new file mode 100644
index 0000000..0cacd82
--- /dev/null
+++ b/examples/gemm_tuner/cl_gemm_native.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2019 ARM Limited.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef ARM_COMPUTE_CL /* Needed by Utils.cpp to handle OpenCL exceptions properly */
+#error "This example needs to be built with -DARM_COMPUTE_CL"
+#endif /* ARM_COMPUTE_CL */
+
+#include "CommonGemmExampleOptions.h"
+#include "arm_compute/core/CL/kernels/CLGEMMMatrixMultiplyNativeKernel.h"
+#include "arm_compute/core/Helpers.h"
+#include "arm_compute/core/KernelDescriptors.h"
+#include "arm_compute/core/Types.h"
+#include "arm_compute/core/utils/misc/ShapeCalculator.h"
+#include "arm_compute/runtime/CL/CLFunctions.h"
+#include "arm_compute/runtime/CL/CLScheduler.h"
+#include "arm_compute/runtime/CL/CLTuner.h"
+#include "tests/CL/Helper.h"
+#include "utils/Utils.h"
+#include "utils/command_line/CommandLineOptions.h"
+#include "utils/command_line/CommandLineParser.h"
+
+#include <cstdlib>
+
+using namespace arm_compute;
+using namespace utils;
+using namespace arm_compute::misc::shape_calculator;
+using namespace gemm_tuner;
+
+namespace
+{
+/** Structure holding all tunable gemm configs specific to this example/strategy */
+struct GemmConfigs
+{
+    size_t m0{ 4 }; /**< Number of rows processed by the matrix multiplication */
+    size_t n0{ 4 }; /**< Number of columns processed by the matrix multiplication */
+    size_t k0{ 4 }; /**< Number of partial accumulations performed by the matrix multiplication */
+};
+
+/** Formatted output of the GemmConfigs type
+ *
+ * @param[out] os      Output stream.
+ * @param[in]  configs Tunable configurations to output
+ *
+ * @return Modified output stream.
+ */
+::std::ostream &operator<<(::std::ostream &os, const GemmConfigs &configs)
+{
+    std::string false_str = std::string("false");
+    std::string true_str  = std::string("true");
+
+    os << "m0 : " << configs.m0 << std::endl;
+    os << "n0 : " << configs.n0 << std::endl;
+    os << "k0 : " << configs.k0 << std::endl;
+    return os;
+}
+
+/** Command line options for gemm configs */
+class GemmConfigOptions
+{
+public:
+    /** Constructor
+     *
+     * @param[in,out] parser A parser on which "parse()" hasn't been called yet.
+     */
+    GemmConfigOptions(CommandLineParser &parser)
+        : m0(parser.add_positional_option<SimpleOption<size_t>>("m0", 4)),
+          n0(parser.add_positional_option<SimpleOption<size_t>>("n0", 4)),
+          k0(parser.add_positional_option<SimpleOption<size_t>>("k0", 4))
+    {
+        m0->set_help("Number of rows processed by the matrix multiplication");
+        n0->set_help("Number of columns processed by the matrix multiplication");
+        k0->set_help("Number of partial accumulations performed by the matrix multiplication");
+    }
+    /** Prevent instances of this class from being copied (As this class contains pointers) */
+    GemmConfigOptions(const GemmConfigOptions &) = delete;
+    /** Prevent instances of this class from being copied (As this class contains pointers) */
+    GemmConfigOptions &operator=(const GemmConfigOptions &) = delete;
+    /** Allow instances of this class to be moved */
+    GemmConfigOptions(GemmConfigOptions &&) = default;
+    /** Allow instances of this class to be moved */
+    GemmConfigOptions &operator=(GemmConfigOptions &&) = default;
+    /** Default destructor */
+    ~GemmConfigOptions() = default;
+
+    SimpleOption<size_t> *m0; /**< Number of rows processed by the matrix multiplication option */
+    SimpleOption<size_t> *n0; /**< Number of columns processed by the matrix multiplication option */
+    SimpleOption<size_t> *k0; /**< Number of partial accumulations performed by the matrix multiplication option */
+};
+
+/** Consumes the gemm configuration options and creates a structure containing all information
+ *
+ * @param[in] options Options to consume
+ *
+ * @return Structure containing the gemm configurations
+ */
+GemmConfigs consume_gemm_configs(const GemmConfigOptions &options)
+{
+    GemmConfigs configs;
+    configs.m0 = options.m0->value();
+    configs.n0 = options.n0->value();
+    configs.k0 = options.k0->value();
+    return configs;
+}
+
+} // namespace
+// Create function for CLGEMMMatrixMultiplyNativeKernel
+using CLGEMMMatrixMultiplyNative = test::CLSynthetizeFunction<CLGEMMMatrixMultiplyNativeKernel>;
+
+class CLGEMMMatrixMultiplyNativeExample : public Example
+{
+public:
+    bool do_setup(int argc, char **argv) override
+    {
+        // Default parameters
+        const DataType            data_type = DataType::F32;
+        const float               alpha     = 1.0f;
+        const float               beta      = 0.0f;
+        const ActivationLayerInfo act_info  = ActivationLayerInfo();
+        CommonGemmExampleParams   params;
+        GemmConfigs               configs;
+
+        // Set up command line parser and options
+        CommandLineParser        parser;
+        CommonGemmExampleOptions param_options(parser);
+        GemmConfigOptions        config_options(parser);
+
+        // Parse command line options
+        parser.parse(argc, argv);
+        if(param_options.help->is_set() && param_options.help->value())
+        {
+            // Print help message
+            parser.print_help(argv[0]);
+            return false;
+        }
+        if(!parser.validate())
+        {
+            // Invalid arguments. Use default parameters and configs
+            std::cerr << "Invalid arguments." << std::endl;
+            parser.print_help(argv[0]);
+            std::cerr << "Falling back to default parameters and configs" << std::endl;
+        }
+        else
+        {
+            // Get parameters and configs from command-line options
+            params  = consume_common_gemm_example_parameters(param_options);
+            configs = consume_gemm_configs(config_options);
+        }
+
+        // Print gemm parameters and configurations
+        std::cerr << "Gemm parameters:" << std::endl;
+        std::cerr << params << std::endl;
+        std::cerr << "Gemm configurations:" << std::endl;
+        std::cerr << configs << std::endl;
+
+        CLScheduler::get().default_init(&tuner);
+
+        lhs.allocator()->init(TensorInfo(TensorShape(params.K, params.M, params.B), 1, data_type));
+        rhs.allocator()->init(TensorInfo(TensorShape(params.N, params.K, params.B), 1, data_type));
+        bias.allocator()->init(TensorInfo(TensorShape(params.N, 1, params.B), 1, data_type));
+
+        GEMMLHSMatrixInfo lhs_info;
+        lhs_info.m0 = configs.m0;
+        lhs_info.k0 = configs.k0;
+
+        GEMMRHSMatrixInfo rhs_info;
+        rhs_info.n0 = configs.n0;
+        rhs_info.k0 = configs.k0;
+
+        GEMMKernelInfo kernel_info;
+        kernel_info.m                       = params.M;
+        kernel_info.n                       = params.N;
+        kernel_info.k                       = params.K;
+        kernel_info.depth_output_gemm3d     = 0;
+        kernel_info.reinterpret_input_as_3d = false;
+        kernel_info.broadcast_bias          = true;
+        kernel_info.activation_info         = act_info;
+
+        // Configure function
+        gemm.configure(&lhs, &rhs, &bias, &dst, alpha, beta, lhs_info, rhs_info, kernel_info);
+
+        // Allocate tensors
+        lhs.allocator()->allocate();
+        rhs.allocator()->allocate();
+        bias.allocator()->allocate();
+        dst.allocator()->allocate();
+
+        return true;
+    }
+    void do_run() override
+    {
+        // Execute the function
+        gemm.run();
+
+        // Make sure all the OpenCL jobs are done executing:
+        CLScheduler::get().sync();
+    }
+
+    void do_teardown() override
+    {
+    }
+
+private:
+    CLTensor                   lhs{};
+    CLTensor                   rhs{};
+    CLTensor                   bias{};
+    CLTensor                   dst{};
+    CLTuner                    tuner{};
+    CLGEMMMatrixMultiplyNative gemm{};
+};
+
+/** Main program for gemm native test
+ *
+ * @param[in] argc Number of arguments
+ * @param[in] argv Arguments ( [optional] M, [optional] N, [optional] K, [optional] B, [optional] m0, [optional] n0, [optional] k0 )
+ */
+int main(int argc, char **argv)
+{
+    return run_example<CLGEMMMatrixMultiplyNativeExample>(argc, argv);
+}