From 6db0ff5b4bb49f834c7caa532a7feab228df10f9 Mon Sep 17 00:00:00 2001 From: Anthony Barbier Date: Fri, 5 Jan 2018 10:59:12 +0000 Subject: COMPMID-771 Allow examples to be profiled Change-Id: I180281e796e1670b9ad391d82d66ecde0119ef78 Note: this is for internal use only which is why I think the hackiness of RunExample.cpp is acceptable. Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/115154 Tested-by: Jenkins Reviewed-by: Pablo Tello Reviewed-by: Georgios Pinitas --- arm_compute/runtime/CL/CLScheduler.h | 35 +++--- examples/cl_convolution.cpp | 106 +++++++++-------- examples/cl_events.cpp | 6 +- examples/cl_sgemm.cpp | 6 +- examples/gc_absdiff.cpp | 6 +- examples/gc_dc.cpp | 6 +- examples/graph_alexnet.cpp | 6 +- examples/graph_googlenet.cpp | 6 +- examples/graph_lenet.cpp | 6 +- examples/graph_mobilenet.cpp | 6 +- examples/graph_squeezenet.cpp | 8 +- examples/graph_vgg16.cpp | 6 +- examples/graph_vgg19.cpp | 6 +- examples/neon_cartoon_effect.cpp | 6 +- examples/neon_cnn.cpp | 8 +- examples/neon_convolution.cpp | 6 +- examples/neon_copy_objects.cpp | 6 +- examples/neon_scale.cpp | 6 +- examples/neoncl_scale_median_gaussian.cpp | 6 +- tests/SConscript | 50 +++++++- tests/benchmark_examples/RunExample.cpp | 157 ++++++++++++++++++++++++ tests/framework/command_line/CommonOptions.cpp | 158 +++++++++++++++++++++++++ tests/framework/command_line/CommonOptions.h | 88 ++++++++++++++ tests/main.cpp | 131 +++----------------- utils/Utils.cpp | 43 ++++++- utils/Utils.h | 48 ++++++-- 26 files changed, 676 insertions(+), 246 deletions(-) create mode 100644 tests/benchmark_examples/RunExample.cpp create mode 100644 tests/framework/command_line/CommonOptions.cpp create mode 100644 tests/framework/command_line/CommonOptions.h diff --git a/arm_compute/runtime/CL/CLScheduler.h b/arm_compute/runtime/CL/CLScheduler.h index 3985829a49..c76ee3f273 100644 --- a/arm_compute/runtime/CL/CLScheduler.h +++ b/arm_compute/runtime/CL/CLScheduler.h @@ -72,23 +72,30 @@ public: */ void default_init(ICLTuner *cl_tuner = nullptr) { -#if defined(ARM_COMPUTE_DEBUG_ENABLED) - // Create a cl_context with a printf_callback and user specified buffer size. - cl_context_properties properties[] = + if(!_is_initialised) { - // Enable a printf callback function for this context. - CL_PRINTF_CALLBACK_ARM, reinterpret_cast(printf_callback), - // Request a minimum printf buffer size of 4MB for devices in the - // context that support this extension. - CL_PRINTF_BUFFERSIZE_ARM, static_cast(0x100000), - CL_CONTEXT_PLATFORM, reinterpret_cast(cl::Platform::get()()), - 0 - }; - cl::Context::setDefault(cl::Context(CL_DEVICE_TYPE_DEFAULT, properties)); +#if defined(ARM_COMPUTE_DEBUG_ENABLED) + // Create a cl_context with a printf_callback and user specified buffer size. + cl_context_properties properties[] = + { + // Enable a printf callback function for this context. + CL_PRINTF_CALLBACK_ARM, reinterpret_cast(printf_callback), + // Request a minimum printf buffer size of 4MB for devices in the + // context that support this extension. + CL_PRINTF_BUFFERSIZE_ARM, static_cast(0x100000), + CL_CONTEXT_PLATFORM, reinterpret_cast(cl::Platform::get()()), + 0 + }; + cl::Context::setDefault(cl::Context(CL_DEVICE_TYPE_DEFAULT, properties)); #endif // defined(ARM_COMPUTE_DEBUG_ENABLED) - CLKernelLibrary::get().init("./cl_kernels/", cl::Context::getDefault(), cl::Device::getDefault()); - init(cl::Context::getDefault(), cl::CommandQueue::getDefault(), cl::Device::getDefault(), cl_tuner); + CLKernelLibrary::get().init("./cl_kernels/", cl::Context::getDefault(), cl::Device::getDefault()); + init(cl::Context::getDefault(), cl::CommandQueue::getDefault(), cl::Device::getDefault(), cl_tuner); + } + else + { + _cl_tuner = cl_tuner; + } } /** Schedule the execution of the passed kernel if possible. * diff --git a/examples/cl_convolution.cpp b/examples/cl_convolution.cpp index b780193f14..24ad7c180e 100644 --- a/examples/cl_convolution.cpp +++ b/examples/cl_convolution.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017 ARM Limited. + * Copyright (c) 2016, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -53,69 +53,77 @@ const int16_t gaussian5x5[] = 1, 4, 6, 4, 1 }; -void main_cl_convolution(int argc, const char **argv) +class CLConvolutionExample : public Example { - PPMLoader ppm; - CLImage src, tmp, dst; - - CLScheduler::get().default_init(); - - if(argc < 2) - { - // Print help - std::cout << "Usage: ./build/cl_convolution [input_image.ppm]\n\n"; - std::cout << "No input_image provided, creating a dummy 640x480 image\n"; - // Create an empty grayscale 640x480 image - src.allocator()->init(TensorInfo(640, 480, Format::U8)); - } - else +public: + void do_setup(int argc, char **argv) override { - ppm.open(argv[1]); - ppm.init_image(src, Format::U8); - } + PPMLoader ppm; - // Configure the temporary and destination images - tmp.allocator()->init(*src.info()); - dst.allocator()->init(*src.info()); + CLScheduler::get().default_init(); - CLConvolution3x3 conv3x3; - CLConvolution5x5 conv5x5; + if(argc < 2) + { + // Print help + std::cout << "Usage: ./build/cl_convolution [input_image.ppm]\n\n"; + std::cout << "No input_image provided, creating a dummy 640x480 image\n"; + // Create an empty grayscale 640x480 image + src.allocator()->init(TensorInfo(640, 480, Format::U8)); + } + else + { + ppm.open(argv[1]); + ppm.init_image(src, Format::U8); + } - // Apply a Gaussian 3x3 filter to the source image followed by a Gaussian 5x5: - conv3x3.configure(&src, &tmp, gaussian3x3, 0 /* Let arm_compute calculate the scale */, BorderMode::UNDEFINED); - conv5x5.configure(&tmp, &dst, gaussian5x5, 0 /* Let arm_compute calculate the scale */, BorderMode::UNDEFINED); + // Configure the temporary and destination images + tmp.allocator()->init(*src.info()); + dst.allocator()->init(*src.info()); - // Allocate all the images - src.allocator()->allocate(); - tmp.allocator()->allocate(); - dst.allocator()->allocate(); - // Fill the input image with the content of the PPM image if a filename was provided: - if(ppm.is_open()) - { - ppm.fill_image(src); - } + // Apply a Gaussian 3x3 filter to the source image followed by a Gaussian 5x5: + conv3x3.configure(&src, &tmp, gaussian3x3, 0 /* Let arm_compute calculate the scale */, BorderMode::UNDEFINED); + conv5x5.configure(&tmp, &dst, gaussian5x5, 0 /* Let arm_compute calculate the scale */, BorderMode::UNDEFINED); - // Execute the functions: - conv3x3.run(); - conv5x5.run(); - - // Make sure all the OpenCL jobs are done executing: - CLScheduler::get().sync(); + // Allocate all the images + src.allocator()->allocate(); + tmp.allocator()->allocate(); + dst.allocator()->allocate(); + // Fill the input image with the content of the PPM image if a filename was provided: + if(ppm.is_open()) + { + ppm.fill_image(src); + output_filename = std::string(argv[1]) + "_out.ppm"; + } + } + void do_run() override + { + // Execute the functions: + conv3x3.run(); + conv5x5.run(); - // Save the result to file: - if(ppm.is_open()) + // Make sure all the OpenCL jobs are done executing: + CLScheduler::get().sync(); + } + void do_teardown() override { - const std::string output_filename = std::string(argv[1]) + "_out.ppm"; - save_to_ppm(dst, output_filename); // save_to_ppm maps and unmaps the image to store as PPM + // Save the result to file: + if(!output_filename.empty()) + { + save_to_ppm(dst, output_filename); // save_to_ppm maps and unmaps the image to store as PPM + } } -} + CLImage src{}, tmp{}, dst{}; + CLConvolution3x3 conv3x3{}; + CLConvolution5x5 conv5x5{}; + std::string output_filename{}; +}; /** Main program for convolution test * * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Path to PPM image to process ) */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { - return utils::run_example(argc, argv, main_cl_convolution); + return utils::run_example(argc, argv); } diff --git a/examples/cl_events.cpp b/examples/cl_events.cpp index 213f4a19df..c9c3e5d039 100644 --- a/examples/cl_events.cpp +++ b/examples/cl_events.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -33,7 +33,7 @@ using namespace arm_compute; using namespace utils; -void main_cl_events(int argc, const char **argv) +void main_cl_events(int argc, char **argv) { /** [OpenCL events] **/ PPMLoader ppm; @@ -111,7 +111,7 @@ void main_cl_events(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Path to PPM image to process ) */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return utils::run_example(argc, argv, main_cl_events); } diff --git a/examples/cl_sgemm.cpp b/examples/cl_sgemm.cpp index e1729a85b0..939870fabf 100644 --- a/examples/cl_sgemm.cpp +++ b/examples/cl_sgemm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -36,7 +36,7 @@ using namespace arm_compute; using namespace utils; -void main_cl_sgemm(int argc, const char **argv) +void main_cl_sgemm(int argc, char **argv) { NPYLoader npy0, npy1, npy2; CLTensor src0, src1, src2, dst; @@ -210,7 +210,7 @@ void main_cl_sgemm(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Matrix A, [optional] Matrix B, [optional] Matrix C, [optional] alpha, [optional] beta ) */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return utils::run_example(argc, argv, main_cl_sgemm); } diff --git a/examples/gc_absdiff.cpp b/examples/gc_absdiff.cpp index 18043e3fca..997feed8e8 100644 --- a/examples/gc_absdiff.cpp +++ b/examples/gc_absdiff.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -34,7 +34,7 @@ using namespace arm_compute; using namespace utils; -void main_gc_absdiff(int argc, const char **argv) +void main_gc_absdiff(int argc, char **argv) { PPMLoader ppm1, ppm2; GCImage src1, src2, dst; @@ -105,7 +105,7 @@ void main_gc_absdiff(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Path to the first PPM image to process, [optional] Path the the second PPM image to process ) */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return utils::run_example(argc, argv, main_gc_absdiff); } diff --git a/examples/gc_dc.cpp b/examples/gc_dc.cpp index 270ca2d08f..174c88458d 100644 --- a/examples/gc_dc.cpp +++ b/examples/gc_dc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -50,7 +50,7 @@ TensorShape get_output_shape(TensorShape in_shape, TensorShape kernel_shape, con } } // namespace -void main_gc_dc(int argc, const char **argv) +void main_gc_dc(int argc, char **argv) { ARM_COMPUTE_UNUSED(argc); ARM_COMPUTE_UNUSED(argv); @@ -117,7 +117,7 @@ void main_gc_dc(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return utils::run_example(argc, argv, main_gc_dc); } diff --git a/examples/graph_alexnet.cpp b/examples/graph_alexnet.cpp index 0d5531f282..6423fe48d3 100644 --- a/examples/graph_alexnet.cpp +++ b/examples/graph_alexnet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -39,7 +39,7 @@ using namespace arm_compute::graph_utils; * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -void main_graph_alexnet(int argc, const char **argv) +void main_graph_alexnet(int argc, char **argv) { std::string data_path; /* Path to the trainable data */ std::string image; /* Image data */ @@ -161,7 +161,7 @@ void main_graph_alexnet(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return arm_compute::utils::run_example(argc, argv, main_graph_alexnet); } diff --git a/examples/graph_googlenet.cpp b/examples/graph_googlenet.cpp index d08382ab8e..746d558389 100644 --- a/examples/graph_googlenet.cpp +++ b/examples/graph_googlenet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -97,7 +97,7 @@ BranchLayer get_inception_node(const std::string &data_path, std::string &¶m * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -void main_graph_googlenet(int argc, const char **argv) +void main_graph_googlenet(int argc, char **argv) { std::string data_path; /* Path to the trainable data */ std::string image; /* Image data */ @@ -198,7 +198,7 @@ void main_graph_googlenet(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return arm_compute::utils::run_example(argc, argv, main_graph_googlenet); } diff --git a/examples/graph_lenet.cpp b/examples/graph_lenet.cpp index d4a44382b4..3e4727f189 100644 --- a/examples/graph_lenet.cpp +++ b/examples/graph_lenet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -61,7 +61,7 @@ std::unique_ptr get_accessor(const std::string &path, const std * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] batches ) */ -void main_graph_lenet(int argc, const char **argv) +void main_graph_lenet(int argc, char **argv) { std::string data_path; /** Path to the trainable data */ unsigned int batches = 4; /** Number of batches */ @@ -132,7 +132,7 @@ void main_graph_lenet(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] batches ) */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return arm_compute::utils::run_example(argc, argv, main_graph_lenet); } diff --git a/examples/graph_mobilenet.cpp b/examples/graph_mobilenet.cpp index 553253383f..c468093e56 100644 --- a/examples/graph_mobilenet.cpp +++ b/examples/graph_mobilenet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -75,7 +75,7 @@ BranchLayer get_dwsc_node(const std::string &data_path, std::string &¶m_path * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -void main_graph_mobilenet(int argc, const char **argv) +void main_graph_mobilenet(int argc, char **argv) { std::string data_path; /* Path to the trainable data */ std::string image; /* Image data */ @@ -171,7 +171,7 @@ void main_graph_mobilenet(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return arm_compute::utils::run_example(argc, argv, main_graph_mobilenet); } diff --git a/examples/graph_squeezenet.cpp b/examples/graph_squeezenet.cpp index c8c411aa8b..11a80a7bd8 100644 --- a/examples/graph_squeezenet.cpp +++ b/examples/graph_squeezenet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -65,7 +65,7 @@ BranchLayer get_expand_fire_node(const std::string &data_path, std::string &&par * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -void main_graph_squeezenet(int argc, const char **argv) +void main_graph_squeezenet(int argc, char **argv) { std::string data_path; /* Path to the trainable data */ std::string image; /* Image data */ @@ -201,7 +201,7 @@ void main_graph_squeezenet(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return arm_compute::utils::run_example(argc, argv, main_graph_squeezenet); -} \ No newline at end of file +} diff --git a/examples/graph_vgg16.cpp b/examples/graph_vgg16.cpp index cac38d30a7..fcaa6182cb 100644 --- a/examples/graph_vgg16.cpp +++ b/examples/graph_vgg16.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -37,7 +37,7 @@ using namespace arm_compute::graph_utils; * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -void main_graph_vgg16(int argc, const char **argv) +void main_graph_vgg16(int argc, char **argv) { std::string data_path; /* Path to the trainable data */ std::string image; /* Image data */ @@ -216,7 +216,7 @@ void main_graph_vgg16(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return arm_compute::utils::run_example(argc, argv, main_graph_vgg16); } diff --git a/examples/graph_vgg19.cpp b/examples/graph_vgg19.cpp index 49ae0fe51c..1f6cba4441 100644 --- a/examples/graph_vgg19.cpp +++ b/examples/graph_vgg19.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -37,7 +37,7 @@ using namespace arm_compute::graph_utils; * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -void main_graph_vgg19(int argc, const char **argv) +void main_graph_vgg19(int argc, char **argv) { std::string data_path; /* Path to the trainable data */ std::string image; /* Image data */ @@ -225,7 +225,7 @@ void main_graph_vgg19(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return arm_compute::utils::run_example(argc, argv, main_graph_vgg19); } diff --git a/examples/neon_cartoon_effect.cpp b/examples/neon_cartoon_effect.cpp index f4f2003201..0ecd9410a1 100644 --- a/examples/neon_cartoon_effect.cpp +++ b/examples/neon_cartoon_effect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -30,7 +30,7 @@ using namespace arm_compute; using namespace utils; -void main_neon_cartoon_effect(int argc, const char **argv) +void main_neon_cartoon_effect(int argc, char **argv) { // Open PPM file PPMLoader ppm; @@ -97,7 +97,7 @@ void main_neon_cartoon_effect(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Path to PPM image to process ) */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return utils::run_example(argc, argv, main_neon_cartoon_effect); } diff --git a/examples/neon_cnn.cpp b/examples/neon_cnn.cpp index 198890c9ba..2be5acfbaf 100644 --- a/examples/neon_cnn.cpp +++ b/examples/neon_cnn.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017 ARM Limited. + * Copyright (c) 2016, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -33,7 +33,7 @@ using namespace arm_compute; using namespace utils; -void main_cnn(int argc, const char **argv) +void main_cnn(int argc, char **argv) { ARM_COMPUTE_UNUSED(argc); ARM_COMPUTE_UNUSED(argv); @@ -291,7 +291,7 @@ void main_cnn(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return utils::run_example(argc, argv, main_cnn); -} \ No newline at end of file +} diff --git a/examples/neon_convolution.cpp b/examples/neon_convolution.cpp index 222c8f9a37..79800ae897 100644 --- a/examples/neon_convolution.cpp +++ b/examples/neon_convolution.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017 ARM Limited. + * Copyright (c) 2016, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -49,7 +49,7 @@ const int16_t gaussian5x5[] = 1, 4, 6, 4, 1 }; -void main_neon_convolution(int argc, const char **argv) +void main_neon_convolution(int argc, char **argv) { /** [Accurate padding] **/ PPMLoader ppm; @@ -111,7 +111,7 @@ void main_neon_convolution(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Path to PPM image to process ) */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return utils::run_example(argc, argv, main_neon_convolution); } diff --git a/examples/neon_copy_objects.cpp b/examples/neon_copy_objects.cpp index 04024530d5..55d03dd8bf 100644 --- a/examples/neon_copy_objects.cpp +++ b/examples/neon_copy_objects.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017 ARM Limited. + * Copyright (c) 2016, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -32,7 +32,7 @@ using namespace arm_compute; -void main_neon_copy_objects(int argc, const char **argv) +void main_neon_copy_objects(int argc, char **argv) { ARM_COMPUTE_UNUSED(argc); ARM_COMPUTE_UNUSED(argv); @@ -146,7 +146,7 @@ void main_neon_copy_objects(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return utils::run_example(argc, argv, main_neon_copy_objects); } diff --git a/examples/neon_scale.cpp b/examples/neon_scale.cpp index 75780c9bdb..3911f5b3ef 100644 --- a/examples/neon_scale.cpp +++ b/examples/neon_scale.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017 ARM Limited. + * Copyright (c) 2016, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -29,7 +29,7 @@ using namespace arm_compute; using namespace utils; -void main_neon_scale(int argc, const char **argv) +void main_neon_scale(int argc, char **argv) { PPMLoader ppm; Image src, dst; @@ -84,7 +84,7 @@ void main_neon_scale(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Path to PPM image to process ) */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return utils::run_example(argc, argv, main_neon_scale); } diff --git a/examples/neoncl_scale_median_gaussian.cpp b/examples/neoncl_scale_median_gaussian.cpp index e53a48e07d..0b72314f7b 100644 --- a/examples/neoncl_scale_median_gaussian.cpp +++ b/examples/neoncl_scale_median_gaussian.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017 ARM Limited. + * Copyright (c) 2016, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -39,7 +39,7 @@ using namespace utils; * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Path to PPM image to process ) */ -void main_neoncl_scale_median_gaussian(int argc, const char **argv) +void main_neoncl_scale_median_gaussian(int argc, char **argv) { /** [NEON / OpenCL Interop] */ PPMLoader ppm; @@ -123,7 +123,7 @@ void main_neoncl_scale_median_gaussian(int argc, const char **argv) * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Path to PPM image to process ) */ -int main(int argc, const char **argv) +int main(int argc, char **argv) { return utils::run_example(argc, argv, main_neoncl_scale_median_gaussian); } diff --git a/tests/SConscript b/tests/SConscript index e4c561d844..4261331d43 100644 --- a/tests/SConscript +++ b/tests/SConscript @@ -31,6 +31,7 @@ SConscript('./framework/SConscript', duplicate=0) variables = [ BoolVariable("validation_tests", "Build validation test programs", True), BoolVariable("benchmark_tests", "Build benchmark test programs", True), + BoolVariable("benchmark_examples", "Build benchmark examples programs", True), ("test_filter", "Pattern to specify the tests' filenames to be compiled", "*.cpp") ] @@ -50,6 +51,9 @@ vars.Update(test_env) Help(new_options.GenerateHelpText(test_env)) +Import("arm_compute_test_framework") +test_env.Append(LIBS = arm_compute_test_framework) + if env['os'] in ['android', 'bare_metal'] or env['standalone']: Import("arm_compute_a") Import("arm_compute_core_a") @@ -69,9 +73,6 @@ test_env.Append(LIBPATH = ["#3rdparty/%s/%s" % (env['os'], env['arch'])]) test_env.Append(LIBPATH = ["#build/%s" % env['build_dir']]) test_env.Append(LIBPATH = ["#build/%s/opencl-1.2-stubs" % env['build_dir']]) -Import("arm_compute_test_framework") -test_env.Append(LIBS = arm_compute_test_framework) - common_files = Glob('*.cpp') common_objects = [test_env.StaticObject(f) for f in common_files] @@ -162,3 +163,46 @@ if test_env['validation_tests']: Default(arm_compute_validation) Export('arm_compute_validation') + +if test_env['benchmark_examples']: + files_benchmark_examples = test_env.Object('benchmark_examples/RunExample.cpp') + arm_compute_benchmark_examples = [] + if test_env['neon']: + for file in Glob("../examples/neon_*.cpp"): + example = "benchmark_" + os.path.basename(os.path.splitext(str(file))[0]) + arm_compute_benchmark_examples += [ test_env.Program(example, [ test_env.Object(source=file, target=example) ] + files_benchmark_examples) ] + if test_env['opencl']: + cl_examples = [] + files = Glob("../examples/cl_*.cpp") + if test_env['neon']: + files += Glob("../examples/neoncl_*.cpp") + for file in files: + example = "benchmark_" + os.path.basename(os.path.splitext(str(file))[0]) + cl_examples += [ test_env.Program(example, [ test_env.Object(source=file, target=example) ] + files_benchmark_examples, CPPDEFINES=['ARM_COMPUTE_CL'], LIBS = test_env["LIBS"] + ["OpenCL"]) ] + Depends(cl_examples, opencl) + arm_compute_benchmark_examples += cl_examples + if test_env['opencl'] and test_env['neon']: + if env['os'] == 'android': + Import('arm_compute_graph_a') + graph_dependency = arm_compute_graph_a + else: + Import('arm_compute_graph_so') + graph_dependency = arm_compute_graph_so + + graph_utils = test_env.Object(source="../utils/GraphUtils.cpp", target="GraphUtils") + for file in Glob("../examples/graph_*.cpp"): + example = "benchmark_" + os.path.basename(os.path.splitext(str(file))[0]) + if env['os'] == 'android': + prog = test_env.Program(example, [ test_env.Object(source=file, target=example), graph_utils]+ files_benchmark_examples, LIBS = test_env["LIBS"] + ["OpenCL"], LINKFLAGS=test_env["LINKFLAGS"]+['-Wl,--whole-archive',graph_dependency,'-Wl,--no-whole-archive']) + Depends(prog, [graph_dependency, opencl]) + arm_compute_benchmark_examples += [ prog ] + else: + #-Wl,--allow-shlib-undefined: Ignore dependencies of dependencies + prog = test_env.Program(example, [ test_env.Object(source=file, target=example), graph_utils]+ files_benchmark_examples, LIBS = test_env["LIBS"] + ["arm_compute_graph"], LINKFLAGS=test_env["LINKFLAGS"]+['-Wl,--allow-shlib-undefined'] ) + Depends(prog, graph_dependency) + arm_compute_benchmark_examples += [ prog ] + Depends(arm_compute_benchmark_examples, arm_compute_test_framework) + Depends(arm_compute_benchmark_examples, arm_compute_lib) + Default(arm_compute_benchmark_examples) + Export('arm_compute_benchmark_examples') + diff --git a/tests/benchmark_examples/RunExample.cpp b/tests/benchmark_examples/RunExample.cpp new file mode 100644 index 0000000000..dea9d9b2e3 --- /dev/null +++ b/tests/benchmark_examples/RunExample.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2018 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. + */ +#include "utils/Utils.h" +//FIXME / INTERNAL_ONLY: This file should not be released! + +#define BENCHMARK_EXAMPLES +#include "utils/Utils.cpp" + +#include "arm_compute/runtime/Scheduler.h" +#include "tests/framework/Framework.h" +#include "tests/framework/Macros.h" +#include "tests/framework/command_line/CommandLineParser.h" +#include "tests/framework/command_line/CommonOptions.h" +#include "tests/framework/instruments/Instruments.h" + +#ifdef ARM_COMPUTE_CL +#include "arm_compute/runtime/CL/CLScheduler.h" +#endif /* ARM_COMPUTE_CL */ +#ifdef ARM_COMPUTE_GC +#include "arm_compute/runtime/GLES_COMPUTE/GCScheduler.h" +#endif /* ARM_COMPUTE_GC */ + +using namespace arm_compute; +using namespace arm_compute::test; + +namespace arm_compute +{ +namespace utils +{ +static Example *g_example = nullptr; +class ExampleTest : public arm_compute::test::framework::TestCase +{ +public: + ExampleTest() = default; + void do_run() override + { + g_example->do_run(); + } + void do_teardown() override + { + g_example->do_teardown(); + } +}; + +int run_example(int argc, char **argv, Example &example) +{ + framework::CommandLineParser parser; + framework::CommonOptions options(parser); + auto example_args = parser.add_option>("example_args"); + example_args->set_help("Arguments to pass to the example"); + framework::Framework &framework = framework::Framework::get(); + + parser.parse(argc, argv); + + if(options.help->is_set() && options.help->value()) + { + parser.print_help(argv[0]); + return 0; + } + + std::vector> printers = options.create_printers(); + g_example = &example; + std::vector example_argv = {}; + example_argv.clear(); + example_argv.emplace_back(argv[0]); + for(auto &arg : example_args->value()) + { + example_argv.emplace_back(const_cast(arg.c_str())); // NOLINT + } + // We need to do the setup here because framework.init() will need CL / GLES to be initialised + try + { + example.do_setup(example_argv.size(), &example_argv[0]); + } +#ifdef ARM_COMPUTE_CL + catch(cl::Error &err) + { + std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cerr << std::endl + << "ERROR " << err.what() << "(" << err.err() << ")" << std::endl; + std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + return 1; + } +#endif /* ARM_COMPUTE_CL */ + catch(std::runtime_error &err) + { + std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cerr << std::endl + << "ERROR " << err.what() << " " << (errno ? strerror(errno) : "") << std::endl; + std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + return 1; + } + + Scheduler::get().set_num_threads(options.threads->value()); + + if(options.log_level->value() > framework::LogLevel::NONE) + { + for(auto &p : printers) + { + p->print_global_header(); + } + } + + if(options.log_level->value() >= framework::LogLevel::CONFIG) + { + for(auto &p : printers) + { + p->print_entry("Iterations", support::cpp11::to_string(options.iterations->value())); + p->print_entry("Threads", support::cpp11::to_string(options.threads->value())); + } + } + + framework.init(options.instruments->value(), options.iterations->value(), framework::DatasetMode::ALL, "", "", options.log_level->value()); + for(auto &p : printers) + { + framework.add_printer(p.get()); + } + framework.set_throw_errors(options.throw_errors->value()); + arm_compute::test::framework::detail::TestSuiteRegistrar suite{ "Examples" }; + framework.add_test_case(argv[0], framework::DatasetMode::ALL, arm_compute::test::framework::TestCaseFactory::Status::ACTIVE); + + //func(argc, argv); + bool success = framework.run(); + if(options.log_level->value() > framework::LogLevel::NONE) + { + for(auto &p : printers) + { + p->print_global_footer(); + } + } + + return (success ? 0 : 1); +} + +} // namespace utils +} // namespace arm_compute diff --git a/tests/framework/command_line/CommonOptions.cpp b/tests/framework/command_line/CommonOptions.cpp new file mode 100644 index 0000000000..631981be3d --- /dev/null +++ b/tests/framework/command_line/CommonOptions.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2018 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. + */ +#include "CommonOptions.h" + +#include "../Framework.h" +#include "../printers/Printers.h" +#include "CommandLineParser.h" + +namespace arm_compute +{ +namespace test +{ +namespace framework +{ +CommonOptions::CommonOptions(CommandLineParser &parser) + : help(parser.add_option("help")), + instruments(), + iterations(parser.add_option>("iterations", 1)), + threads(parser.add_option>("threads", 1)), + log_format(), + log_file(parser.add_option>("log-file")), + log_level(), + throw_errors(parser.add_option("throw-errors")), + color_output(parser.add_option("color-output", true)), + pretty_console(parser.add_option("pretty-console", false)), + json_file(parser.add_option>("json-file")), + pretty_file(parser.add_option>("pretty-file")), + log_streams() +{ + Framework &framework = Framework::get(); + std::set allowed_instruments + { + std::pair(InstrumentType::ALL, ScaleFactor::NONE), + std::pair(InstrumentType::NONE, ScaleFactor::NONE), + }; + + for(const auto &type : framework.available_instruments()) + { + allowed_instruments.insert(type); + } + + std::set supported_log_formats + { + LogFormat::NONE, + LogFormat::PRETTY, + LogFormat::JSON, + }; + + std::set supported_log_levels + { + LogLevel::NONE, + LogLevel::CONFIG, + LogLevel::TESTS, + LogLevel::ERRORS, + LogLevel::DEBUG, + LogLevel::MEASUREMENTS, + LogLevel::ALL, + }; + + instruments = parser.add_option>("instruments", allowed_instruments, std::initializer_list { std::pair(InstrumentType::WALL_CLOCK_TIMER, ScaleFactor::NONE) }); + log_format = parser.add_option>("log-format", supported_log_formats, LogFormat::PRETTY); + log_level = parser.add_option>("log-level", supported_log_levels, LogLevel::ALL); + + help->set_help("Show this help message"); + instruments->set_help("Set the profiling instruments to use"); + iterations->set_help("Number of iterations per test case"); + threads->set_help("Number of threads to use"); + log_format->set_help("Output format for measurements and failures (affects only log-file)"); + log_file->set_help("Write output to file instead of to the console (affected by log-format)"); + log_level->set_help("Verbosity of the output"); + throw_errors->set_help("Don't catch fatal errors (useful for debugging)"); + color_output->set_help("Produce colored output on the console"); + pretty_console->set_help("Produce pretty output on the console"); + json_file->set_help("Write output to a json file."); + pretty_file->set_help("Write output to a text file"); +} +std::vector> CommonOptions::create_printers() +{ + std::vector> printers; + + if(pretty_console->value() && (log_file->is_set() || log_format->value() != LogFormat::PRETTY)) + { + auto pretty_printer = support::cpp14::make_unique(); + pretty_printer->set_color_output(color_output->value()); + printers.push_back(std::move(pretty_printer)); + } + + std::unique_ptr printer; + switch(log_format->value()) + { + case LogFormat::JSON: + printer = support::cpp14::make_unique(); + break; + case LogFormat::NONE: + break; + case LogFormat::PRETTY: + default: + auto pretty_printer = support::cpp14::make_unique(); + // Don't use colours if we print to a file: + pretty_printer->set_color_output((!log_file->is_set()) && color_output->value()); + printer = std::move(pretty_printer); + break; + } + + if(log_file->is_set()) + { + log_streams.push_back(std::make_shared(log_file->value())); + if(printer != nullptr) + { + printer->set_stream(*log_streams.back().get()); + } + } + + if(printer != nullptr) + { + printers.push_back(std::move(printer)); + } + + if(json_file->is_set()) + { + printers.push_back(support::cpp14::make_unique()); + log_streams.push_back(std::make_shared(json_file->value())); + printers.back()->set_stream(*log_streams.back().get()); + } + + if(pretty_file->is_set()) + { + printers.push_back(support::cpp14::make_unique()); + log_streams.push_back(std::make_shared(pretty_file->value())); + printers.back()->set_stream(*log_streams.back().get()); + } + + return printers; +} +} // namespace framework +} // namespace test +} // namespace arm_compute diff --git a/tests/framework/command_line/CommonOptions.h b/tests/framework/command_line/CommonOptions.h new file mode 100644 index 0000000000..2da2c99874 --- /dev/null +++ b/tests/framework/command_line/CommonOptions.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2018 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_TEST_COMMONOPTIONS +#define ARM_COMPUTE_TEST_COMMONOPTIONS + +#include "../instruments/Instruments.h" +#include "CommandLineOptions.h" +#include + +namespace arm_compute +{ +namespace test +{ +namespace framework +{ +class CommandLineParser; +class Printer; +enum class LogFormat; +enum class LogLevel; + +/** Common command line options used to configure the framework + * + * The options in this object get populated when "parse()" is called on the parser used to construct it. + * The expected workflow is: + * + * CommandLineParser parser; + * CommonOptions options( parser ); + * parser.parse(argc, argv); + * if(options.log_level->value() > LogLevel::NONE) --> Use the options values + */ +class CommonOptions +{ +public: + /** Constructor + * + * @param[in,out] parser A parser on which "parse()" hasn't been called yet. + */ + CommonOptions(CommandLineParser &parser); + CommonOptions(const CommonOptions &) = delete; + CommonOptions &operator=(const CommonOptions &) = delete; + /** Create the printers based on parsed command line options + * + * @pre "parse()" has been called on the parser used to construct this object + * + * @return List of printers + */ + std::vector> create_printers(); + + ToggleOption *help; + EnumListOption *instruments; + SimpleOption *iterations; + SimpleOption *threads; + EnumOption *log_format; + SimpleOption *log_file; + EnumOption *log_level; + ToggleOption *throw_errors; + ToggleOption *color_output; + ToggleOption *pretty_console; + SimpleOption *json_file; + SimpleOption *pretty_file; + std::vector> log_streams; +}; + +} // namespace framework +} // namespace test +} // namespace arm_compute +#endif /* ARM_COMPUTE_TEST_COMMONOPTIONS */ diff --git a/tests/main.cpp b/tests/main.cpp index c62de66588..1797b21114 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -30,6 +30,7 @@ #include "tests/framework/Profiler.h" #include "tests/framework/command_line/CommandLineOptions.h" #include "tests/framework/command_line/CommandLineParser.h" +#include "tests/framework/command_line/CommonOptions.h" #include "tests/framework/instruments/Instruments.h" #include "tests/framework/printers/Printers.h" @@ -73,17 +74,6 @@ int main(int argc, char **argv) framework::CommandLineParser parser; - std::set allowed_instruments - { - std::pair(framework::InstrumentType::ALL, framework::ScaleFactor::NONE), - std::pair(framework::InstrumentType::NONE, framework::ScaleFactor::NONE), - }; - - for(const auto &type : framework.available_instruments()) - { - allowed_instruments.insert(type); - } - std::set allowed_modes { framework::DatasetMode::PRECOMMIT, @@ -91,52 +81,18 @@ int main(int argc, char **argv) framework::DatasetMode::ALL }; - std::set supported_log_formats - { - framework::LogFormat::NONE, - framework::LogFormat::PRETTY, - framework::LogFormat::JSON, - }; - - std::set supported_log_levels - { - framework::LogLevel::NONE, - framework::LogLevel::CONFIG, - framework::LogLevel::TESTS, - framework::LogLevel::ERRORS, - framework::LogLevel::DEBUG, - framework::LogLevel::MEASUREMENTS, - framework::LogLevel::ALL, - }; + framework::CommonOptions options(parser); - auto help = parser.add_option("help"); - help->set_help("Show this help message"); auto dataset_mode = parser.add_option>("mode", allowed_modes, framework::DatasetMode::PRECOMMIT); dataset_mode->set_help("For managed datasets select which group to use"); - auto instruments = parser.add_option>("instruments", allowed_instruments, std::initializer_list { std::pair(framework::InstrumentType::WALL_CLOCK_TIMER, framework::ScaleFactor::NONE) }); - instruments->set_help("Set the profiling instruments to use"); - auto iterations = parser.add_option>("iterations", 1); - iterations->set_help("Number of iterations per test case"); - auto threads = parser.add_option>("threads", 1); - threads->set_help("Number of threads to use"); - auto log_format = parser.add_option>("log-format", supported_log_formats, framework::LogFormat::PRETTY); - log_format->set_help("Output format for measurements and failures (affects only log-file)"); auto filter = parser.add_option>("filter", ".*"); filter->set_help("Regular expression to select test cases"); auto filter_id = parser.add_option>("filter-id"); filter_id->set_help("List of test ids. ... can be used to define a range."); - auto log_file = parser.add_option>("log-file"); - log_file->set_help("Write output to file instead of to the console (affected by log-format)"); - auto log_level = parser.add_option>("log-level", supported_log_levels, framework::LogLevel::ALL); - log_level->set_help("Verbosity of the output"); - auto throw_errors = parser.add_option("throw-errors"); - throw_errors->set_help("Don't catch fatal errors (useful for debugging)"); auto stop_on_error = parser.add_option("stop-on-error"); stop_on_error->set_help("Abort execution after the first failed test (useful for debugging)"); auto seed = parser.add_option>("seed", std::random_device()()); seed->set_help("Global seed for random number generation"); - auto color_output = parser.add_option("color-output", true); - color_output->set_help("Produce colored output on the console"); auto list_tests = parser.add_option("list-tests", false); list_tests->set_help("List all test names"); auto test_instruments = parser.add_option("test-instruments", false); @@ -145,81 +101,22 @@ int main(int argc, char **argv) error_on_missing_assets->set_help("Mark a test as failed instead of skipping it when assets are missing"); auto assets = parser.add_positional_option>("assets"); assets->set_help("Path to the assets directory"); - auto pretty_console = parser.add_option("pretty-console", false); - pretty_console->set_help("Produce pretty output on the console"); - auto json_file = parser.add_option>("json-file"); - json_file->set_help("Write output to a json file."); - auto pretty_file = parser.add_option>("pretty-file"); - pretty_file->set_help("Write output to a text file"); try { parser.parse(argc, argv); - if(help->is_set() && help->value()) + if(options.help->is_set() && options.help->value()) { parser.print_help(argv[0]); return 0; } - std::vector> printers; - std::vector> log_streams; - - if(pretty_console->value() && (log_file->is_set() || log_format->value() != framework::LogFormat::PRETTY)) - { - auto pretty_printer = support::cpp14::make_unique(); - pretty_printer->set_color_output(color_output->value()); - printers.push_back(std::move(pretty_printer)); - } - - std::unique_ptr printer; - switch(log_format->value()) - { - case framework::LogFormat::JSON: - printer = support::cpp14::make_unique(); - break; - case framework::LogFormat::NONE: - break; - case framework::LogFormat::PRETTY: - default: - auto pretty_printer = support::cpp14::make_unique(); - // Don't use colours if we print to a file: - pretty_printer->set_color_output((!log_file->is_set()) && color_output->value()); - printer = std::move(pretty_printer); - break; - } - - if(log_file->is_set()) - { - log_streams.push_back(std::make_shared(log_file->value())); - if(printer != nullptr) - { - printer->set_stream(*log_streams.back().get()); - } - } - - if(printer != nullptr) - { - printers.push_back(std::move(printer)); - } - - if(json_file->is_set()) - { - printers.push_back(support::cpp14::make_unique()); - log_streams.push_back(std::make_shared(json_file->value())); - printers.back()->set_stream(*log_streams.back().get()); - } - - if(pretty_file->is_set()) - { - printers.push_back(support::cpp14::make_unique()); - log_streams.push_back(std::make_shared(pretty_file->value())); - printers.back()->set_stream(*log_streams.back().get()); - } + std::vector> printers = options.create_printers(); - Scheduler::get().set_num_threads(threads->value()); + Scheduler::get().set_num_threads(options.threads->value()); - if(log_level->value() > framework::LogLevel::NONE) + if(options.log_level->value() > framework::LogLevel::NONE) { for(auto &p : printers) { @@ -227,13 +124,13 @@ int main(int argc, char **argv) } } - if(log_level->value() >= framework::LogLevel::CONFIG) + if(options.log_level->value() >= framework::LogLevel::CONFIG) { for(auto &p : printers) { p->print_entry("Seed", support::cpp11::to_string(seed->value())); - p->print_entry("Iterations", support::cpp11::to_string(iterations->value())); - p->print_entry("Threads", support::cpp11::to_string(threads->value())); + p->print_entry("Iterations", support::cpp11::to_string(options.iterations->value())); + p->print_entry("Threads", support::cpp11::to_string(options.threads->value())); { using support::cpp11::to_string; p->print_entry("Dataset mode", to_string(dataset_mode->value())); @@ -241,12 +138,12 @@ int main(int argc, char **argv) } } - framework.init(instruments->value(), iterations->value(), dataset_mode->value(), filter->value(), filter_id->value(), log_level->value()); + framework.init(options.instruments->value(), options.iterations->value(), dataset_mode->value(), filter->value(), filter_id->value(), options.log_level->value()); for(auto &p : printers) { framework.add_printer(p.get()); } - framework.set_throw_errors(throw_errors->value()); + framework.set_throw_errors(options.throw_errors->value()); framework.set_stop_on_error(stop_on_error->value()); framework.set_error_on_missing_assets(error_on_missing_assets->value()); @@ -285,7 +182,7 @@ int main(int argc, char **argv) success = framework.run(); - if(log_level->value() > framework::LogLevel::NONE) + if(options.log_level->value() > framework::LogLevel::NONE) { for(auto &p : printers) { @@ -299,7 +196,7 @@ int main(int argc, char **argv) { std::cerr << error.what() << "\n"; - if(throw_errors->value()) + if(options.throw_errors->value()) { throw; } diff --git a/utils/Utils.cpp b/utils/Utils.cpp index f6aff6f92d..c2f5449a28 100644 --- a/utils/Utils.cpp +++ b/utils/Utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -66,7 +66,8 @@ void discard_comments_and_spaces(std::ifstream &fs) } } // namespace -int run_example(int argc, const char **argv, example &func) +//FIXME: Delete once tests have been ported (COMPMID-782) +int run_example(int argc, char **argv, example &func) { std::cout << "\n" << argv[0] << "\n\n"; @@ -100,6 +101,44 @@ int run_example(int argc, const char **argv, example &func) return -1; } +#ifndef BENCHMARK_EXAMPLES +int run_example(int argc, char **argv, Example &example) +{ + std::cout << "\n" + << argv[0] << "\n\n"; + + try + { + example.do_setup(argc, argv); + example.do_run(); + example.do_teardown(); + + std::cout << "\nTest passed\n"; + return 0; + } +#ifdef ARM_COMPUTE_CL + catch(cl::Error &err) + { + std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cerr << std::endl + << "ERROR " << err.what() << "(" << err.err() << ")" << std::endl; + std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + } +#endif /* ARM_COMPUTE_CL */ + catch(std::runtime_error &err) + { + std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cerr << std::endl + << "ERROR " << err.what() << " " << (errno ? strerror(errno) : "") << std::endl; + std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + } + + std::cout << "\nTest FAILED\n"; + + return -1; +} +#endif /* BENCHMARK_EXAMPLES */ + void draw_detection_rectangle(ITensor *tensor, const DetectionWindow &rect, uint8_t r, uint8_t g, uint8_t b) { ARM_COMPUTE_ERROR_ON_FORMAT_NOT_IN(tensor, Format::RGB888); diff --git a/utils/Utils.h b/utils/Utils.h index eb4e846e80..9b5d0c4aa9 100644 --- a/utils/Utils.h +++ b/utils/Utils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017 ARM Limited. + * Copyright (c) 2016, 2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -55,20 +55,52 @@ namespace arm_compute { namespace utils { +//FIXME: Delete once tests have been ported (COMPMID-782) /** Signature of an example to run * * @param[in] argc Number of command line arguments * @param[in] argv Command line arguments */ -using example = void(int argc, const char **argv); +using example = void(int argc, char **argv); +//FIXME: Delete once tests have been ported (COMPMID-782) /** Run an example and handle the potential exceptions it throws * * @param[in] argc Number of command line arguments * @param[in] argv Command line arguments * @param[in] func Pointer to the function containing the code to run */ -int run_example(int argc, const char **argv, example &func); +int run_example(int argc, char **argv, example &func); + +/** Abstract Example class. + * + * All examples have to inherit from this class. + */ +class Example +{ +public: + virtual void do_setup(int argc, char **argv) {}; + virtual void do_run() {}; + virtual void do_teardown() {}; + + /** Default destructor. */ + virtual ~Example() = default; +}; + +/** Run an example and handle the potential exceptions it throws + * + * @param[in] argc Number of command line arguments + * @param[in] argv Command line arguments + * @param[in] example Example to run + */ +int run_example(int argc, char **argv, Example &example); + +template +int run_example(int argc, char **argv) +{ + T example; + return run_example(argc, argv, example); +} /** Draw a RGB rectangular window for the detected object * @@ -258,7 +290,7 @@ public: ARM_COMPUTE_ERROR_ON_MSG(max_val >= 256, "2 bytes per colour channel not supported in file %s", ppm_filename.c_str()); } - catch(const std::ifstream::failure &e) + catch(std::runtime_error &e) { ARM_COMPUTE_ERROR("Accessing %s: %s", ppm_filename.c_str(), e.what()); } @@ -545,7 +577,7 @@ public: void fill_tensor(T &tensor) { ARM_COMPUTE_ERROR_ON(!is_open()); - ARM_COMPUTE_ERROR_ON_FORMAT_NOT_IN(&tensor, arm_compute::DataType::F32); + ARM_COMPUTE_ERROR_ON_DATA_TYPE_NOT_IN(&tensor, arm_compute::DataType::F32); try { // Map buffer if creating a CLTensor @@ -566,19 +598,19 @@ public: ARM_COMPUTE_ERROR_ON_MSG(_typestring != expect_typestr, "Typestrings mismatch"); // Validate tensor shape - ARM_COMPUTE_ERROR_ON_MSG(_shape.size() != tensor.shape().num_dimensions(), "Tensor ranks mismatch"); + ARM_COMPUTE_ERROR_ON_MSG(_shape.size() != tensor.info()->tensor_shape().num_dimensions(), "Tensor ranks mismatch"); if(_fortran_order) { for(size_t i = 0; i < _shape.size(); ++i) { - ARM_COMPUTE_ERROR_ON_MSG(tensor.shape()[i] != _shape[i], "Tensor dimensions mismatch"); + ARM_COMPUTE_ERROR_ON_MSG(tensor.info()->tensor_shape()[i] != _shape[i], "Tensor dimensions mismatch"); } } else { for(size_t i = 0; i < _shape.size(); ++i) { - ARM_COMPUTE_ERROR_ON_MSG(tensor.shape()[i] != _shape[_shape.size() - i - 1], "Tensor dimensions mismatch"); + ARM_COMPUTE_ERROR_ON_MSG(tensor.info()->tensor_shape()[i] != _shape[_shape.size() - i - 1], "Tensor dimensions mismatch"); } } -- cgit v1.2.1