diff options
58 files changed, 2956 insertions, 28 deletions
diff --git a/Android.bp b/Android.bp index 6d0d6b6fa6..c5980c3170 100644 --- a/Android.bp +++ b/Android.bp @@ -51,6 +51,10 @@ cc_library_static { "src/core/NEON/kernels/convolution/winograd"], export_include_dirs: [".", "./include"], srcs: [ + "src/c/AclContext.cpp", + "src/c/AclVersion.cpp", + "src/c/cl/AclOpenClExt.cpp", + "src/common/AllocatorWrapper.cpp", "src/core/AccessWindowAutoPadding.cpp", "src/core/AccessWindowStatic.cpp", "src/core/AccessWindowTranspose.cpp", @@ -342,6 +346,8 @@ cc_library_static { "src/core/NEON/kernels/convolution/winograd/winograd_transforms/weights_4x4_3x3_fp16_fp16_integers.cpp", "src/core/NEON/kernels/convolution/winograd/winograd_transforms/weights_4x4_3x3_fp32_fp32_integers.cpp", "src/core/NEON/kernels/convolution/winograd/winograd_transforms/weights_6_3_fp32_fp32_integers.cpp", + "src/core/NEON/kernels/scale/impl/NEON/fp16.cpp", + "src/core/NEON/kernels/scale/impl/NEON/integer.cpp", "src/core/NEON/kernels/scale/impl/NEON/qasymm8.cpp", "src/core/NEON/kernels/scale/impl/NEON/qasymm8_signed.cpp", "src/core/NEON/kernels/scale/impl/SVE/fp16.cpp", @@ -431,6 +437,8 @@ cc_library_static { "src/core/utils/logging/LoggerRegistry.cpp", "src/core/utils/misc/MMappedFile.cpp", "src/core/utils/quantization/AsymmHelpers.cpp", + "src/cpu/CpuContext.cpp", + "src/gpu/cl/ClContext.cpp", "src/runtime/Allocator.cpp", "src/runtime/BlobLifetimeManager.cpp", "src/runtime/BlobMemoryPool.cpp", diff --git a/SConscript b/SConscript index c89abef81c..9894e30481 100644 --- a/SConscript +++ b/SConscript @@ -165,7 +165,6 @@ arm_compute_env.Append(CPPDEFINES = [('ARM_COMPUTE_VERSION_MAJOR', LIBRARY_VERSI ('ARM_COMPUTE_VERSION_MINOR', LIBRARY_VERSION_MINOR), ('ARM_COMPUTE_VERSION_PATCH', LIBRARY_VERSION_PATCH)]) - # Don't allow undefined references in the libraries: undefined_flag = '-Wl,-undefined,error' if 'macos' in arm_compute_env["os"] else '-Wl,--no-undefined' arm_compute_env.Append(LINKFLAGS=[undefined_flag]) @@ -189,6 +188,10 @@ runtime_files = Glob('src/runtime/*.cpp') runtime_files += Glob('src/runtime/CPP/ICPPSimpleFunction.cpp') runtime_files += Glob('src/runtime/CPP/functions/*.cpp') +runtime_files += Glob('src/c/*.cpp') +runtime_files += Glob('src/common/*.cpp') +runtime_files += Glob('src/cpu/*.cpp') + # CLHarrisCorners uses the Scheduler to run CPP kernels runtime_files += Glob('src/runtime/CPP/SingleThreadScheduler.cpp') @@ -220,6 +223,9 @@ if env['opencl']: runtime_files += Glob('src/runtime/CL/mlgo/*.cpp') runtime_files += Glob('src/runtime/CL/gemm_auto_heuristics/*.cpp') + runtime_files += Glob('src/gpu/cl/*.cpp') + runtime_files += Glob('src/c/cl/*.cpp') + graph_files += Glob('src/graph/backends/CL/*.cpp') diff --git a/SConstruct b/SConstruct index 8892626b90..ad9a3aca1d 100644 --- a/SConstruct +++ b/SConstruct @@ -340,7 +340,11 @@ if env['os'] == 'linux' and env['arch'] == 'armv7a': if env['specs_file'] != "": env.Append(LINKFLAGS = ['-specs='+env['specs_file']]) +if env['neon']: + env.Append(CPPDEFINES = ['ARM_COMPUTE_CPU_ENABLED']) + if env['opencl']: + env.Append(CPPDEFINES = ['ARM_COMPUTE_OPENCL_ENABLED']) if env['os'] in ['bare_metal'] or env['standalone']: print("Cannot link OpenCL statically, which is required for bare metal / standalone builds") Exit(1) diff --git a/arm_compute/Acl.h b/arm_compute/Acl.h new file mode 100644 index 0000000000..6958f60bfd --- /dev/null +++ b/arm_compute/Acl.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 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_ACL_H_ +#define ARM_COMPUTE_ACL_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Core headers */ +#include "arm_compute/AclEntrypoints.h" +#include "arm_compute/AclTypes.h" +#include "arm_compute/AclVersion.h" + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* ARM_COMPUTE_ACL_H_ */ diff --git a/arm_compute/Acl.hpp b/arm_compute/Acl.hpp new file mode 100644 index 0000000000..b74e65430c --- /dev/null +++ b/arm_compute/Acl.hpp @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2021 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_ACL_HPP_ +#define ARM_COMPUTE_ACL_HPP_ + +#include "arm_compute/Acl.h" + +#include <cstdlib> +#include <memory> +#include <string> + +#if defined(ARM_COMPUTE_EXCEPTIONS_ENABLED) +#include <exception> +#endif /* defined(ARM_COMPUTE_EXCEPTIONS_ENABLED) */ + +// Helper Macros +#define ARM_COMPUTE_IGNORE_UNUSED(x) (void)(x) + +namespace acl +{ +// Forward declarations +class Context; + +/**< Status code enum */ +enum class StatusCode +{ + Success = AclSuccess, + RuntimeError = AclRuntimeError, + OutOfMemory = AclOutOfMemory, + Unimplemented = AclUnimplemented, + UnsupportedTarget = AclUnsupportedTarget, + InvalidArgument = AclInvalidArgument, + InvalidTarget = AclInvalidTarget, + UnsupportedConfig = AclUnsupportedConfig, + InvalidObjectState = AclInvalidObjectState, +}; + +/**< Utility namespace containing helpers functions */ +namespace detail +{ +/** Construct to handle destruction of objects + * + * @tparam T Object base type + */ +template <typename T> +struct ObjectDeleter +{ +}; + +#define OBJECT_DELETER(obj, func) \ + template <> \ + struct ObjectDeleter<obj> \ + \ + { \ + static inline AclStatus Destroy(obj v) \ + { \ + return func(v); \ + } \ + }; + +OBJECT_DELETER(AclContext, AclDestroyContext) + +#undef OBJECT_DELETER + +/** Convert a strongly typed enum to an old plain c enum + * + * @tparam E Plain old C enum + * @tparam SE Strongly typed resulting enum + * + * @param[in] v Value to convert + * + * @return A corresponding plain old C enumeration + */ +template <typename E, typename SE> +constexpr E as_cenum(SE v) noexcept +{ + return static_cast<E>(static_cast<typename std::underlying_type<SE>::type>(v)); +} + +/** Convert plain old enumeration to a strongly typed enum + * + * @tparam SE Strongly typed resulting enum + * @tparam E Plain old C enum + * + * @param[in] val Value to convert + * + * @return A corresponding strongly typed enumeration + */ +template <typename SE, typename E> +constexpr SE as_enum(E val) noexcept +{ + return static_cast<SE>(val); +} + +/** Object base class for library objects + * + * Class is defining basic common interface for all the library objects + * + * @tparam T Object type to be templated on + */ +template <typename T> +class ObjectBase +{ +public: + /** Destructor */ + ~ObjectBase() = default; + /** Copy constructor */ + ObjectBase(const ObjectBase<T> &) = default; + /** Move Constructor */ + ObjectBase(ObjectBase<T> &&) = default; + /** Copy assignment operator */ + ObjectBase<T> &operator=(const ObjectBase<T> &) = default; + /** Move assignment operator */ + ObjectBase<T> &operator=(ObjectBase<T> &&) = default; + /** Reset object value + * + * @param [in] val Value to set + */ + void reset(T *val) + { + _object.reset(val, detail::ObjectDeleter<T *>::Destroy); + } + /** Access uderlying object + * + * @return Underlying object + */ + const T *get() const + { + return _object.get(); + } + /** Access uderlying object + * + * @return Underlying object + */ + T *get() + { + return _object.get(); + } + +protected: + /** Constructor */ + ObjectBase() = default; + +protected: + std::shared_ptr<T> _object{ nullptr }; /**< Library object */ +}; + +/** Equality operator for library object + * + * @tparam T Parameter to template on + * + * @param[in] lhs Left hand-side argument + * @param[in] rhs Right hand-side argument + * + * @return True if objects are equal, else false + */ +template <typename T> +bool operator==(const ObjectBase<T> &lhs, const ObjectBase<T> &rhs) +{ + return lhs.get() == rhs.get(); +} + +/** Inequality operator for library object + * + * @tparam T Parameter to template on + * + * @param[in] lhs Left hand-side argument + * @param[in] rhs Right hand-side argument + * + * @return True if objects are equal, else false + */ +template <typename T> +bool operator!=(const ObjectBase<T> &lhs, const ObjectBase<T> &rhs) +{ + return !(lhs == rhs); +} +} // namespace detail + +#if defined(ARM_COMPUTE_EXCEPTIONS_ENABLED) +/** Status class + * + * Class is an extension of std::exception and contains the underlying + * status construct and an error explanatory message to be reported. + * + * @note Class is visible only when exceptions are enabled during compilation + */ +class Status : public std::exception +{ +public: + /** Constructor + * + * @param[in] status Status returned + * @param[in] msg Error message to be bound with the exception + */ + Status(StatusCode status, const std::string &msg) + : _status(status), _msg(msg) + { + } + /** Returns an explanatory exception message + * + * @return Status message + */ + const char *what() const noexcept override + { + return _msg.c_str(); + } + /** Underlying status accessor + * + * @return Status code + */ + StatusCode status() const + { + return _status; + } + /** Explicit status converter + * + * @return Status code + */ + explicit operator StatusCode() const + { + return _status; + } + +private: + StatusCode _status; /**< Status code */ + std::string _msg; /**< Status message */ +}; + +/** Reports an error status and throws an exception object in case of failure + * + * @note This implementation is used when exceptions are enabled during compilation + * + * @param[in] status Status to report + * @param[in] msg Explanatory error messaged + * + * @return Status code + */ +static inline StatusCode report_status(StatusCode status, const std::string &msg) +{ + if(status != StatusCode::Success) + { + throw Status(status, msg); + } + return status; +} +#else /* defined(ARM_COMPUTE_EXCEPTIONS_ENABLED) */ +/** Reports a status code + * + * @note This implementation is used when exceptions are disabled during compilation + * @note Message is surpressed and not reported in this case + * + * @param[in] status Status to report + * @param[in] msg Explanatory error messaged + * + * @return Status code + */ +static inline StatusCode report_status(StatusCode status, const std::string &msg) +{ + ARM_COMPUTE_IGNORE_UNUSED(msg); + return status; +} +#endif /* defined(ARM_COMPUTE_EXCEPTIONS_ENABLED) */ + +/**< Target enum */ +enum class Target +{ + Cpu = AclCpu, /**< Cpu target that leverages SIMD */ + GpuOcl = AclGpuOcl /**< Gpu target that leverages OpenCL */ +}; + +/**< Available execution modes */ +enum class ExecutionMode +{ + FastRerun = AclPreferFastRerun, /**< Prefer minimum latency in consecutive runs, might introduce higher startup times */ + FastStart = AclPreferFastStart, /**< Prefer minimizing startup time */ +}; + +/** Context class + * + * Context acts as a central aggregate service for further objects created from it. + * It provides, internally, common facilities in order to avoid the use of global + * statically initialized objects that can lead to important side-effect under + * specific execution contexts. + * + * For example context contains allocators for object creation, for further backing memory allocation, + * any serialization interfaces and other modules that affect the construction of objects, + * like program caches for OpenCL. + */ +class Context : public detail::ObjectBase<AclContext_> +{ +public: + /**< Context options */ + struct Options + { + /** Default Constructor + * + * @note By default no precision loss is enabled for operators + * @note By default the preferred execution mode is to favor multiple consecutive reruns of an operator + */ + Options() = default; + /** Constructor + * + * @param[in] mode Execution mode to be used + * @param[in] caps Capabilities to be used + * @param[in] enable_fast_math Allow precision loss in favor of performance + * @param[in] kernel_config Kernel configuration file containing construction tuning meta-data + * @param[in] max_compute_units Max compute units that are expected to used + * @param[in] allocator Allocator to be used for internal memory allocation + */ + Options(ExecutionMode mode, + AclTargetCapabilities caps, + bool enable_fast_math, + const char *kernel_config, + int32_t max_compute_units, + AclAllocator *allocator) + { + opts.mode = detail::as_cenum<AclExecutionMode>(mode); + opts.capabilities = caps; + opts.enable_fast_math = enable_fast_math; + opts.kernel_config_file = kernel_config; + opts.max_compute_units = max_compute_units; + opts.allocator = allocator; + } + AclContextOptions opts{ acl_default_ctx_options }; + }; + +public: + /** Constructor + * + * @note Serves as a simpler delegate constructor + * @note As context options, default conservative options will be used + * + * @param[in] target Target to create context for + * @param[out] status Status information if requested + */ + explicit Context(Target target, StatusCode *status = nullptr) + : Context(target, Options(), status) + { + } + /** Constructor + * + * @param[in] target Target to create context for + * @param[in] options Context construction options + * @param[out] status Status information if requested + */ + Context(Target target, const Options &options, StatusCode *status = nullptr) + { + AclContext ctx; + const auto st = detail::as_enum<StatusCode>(AclCreateContext(&ctx, detail::as_cenum<AclTarget>(target), &options.opts)); + reset(ctx); + report_status(st, "Failure during context creation"); + if(status) + { + *status = st; + } + } +}; +} // namespace acl +#undef ARM_COMPUTE_IGNORE_UNUSED +#endif /* ARM_COMPUTE_ACL_HPP_ */ diff --git a/arm_compute/AclEntrypoints.h b/arm_compute/AclEntrypoints.h new file mode 100644 index 0000000000..02e072f826 --- /dev/null +++ b/arm_compute/AclEntrypoints.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2021 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_ACLENTRYPOINTS_H_ +#define ARM_COMPUTE_ACLENTRYPOINTS_H_ + +#include "arm_compute/AclTypes.h" + +#ifdef __cplusplus +extern "C" { +#endif /** __cplusplus */ + +/** Create a context object + * + * Context is responsible for retaining internal information and work as an aggregate service mechanism + * + * @param[in, out] ctx A valid non-zero context object if no failure occurs + * @param[in] target Target to create the context for + * @param[in] options Context options to be used for all the kernels that are created under the context + * + * @return Status code + * + * Returns: + * - @ref AclSuccess if function was completed successfully + * - @ref AclOutOfMemory if there was a failure allocating memory resources + * - @ref AclUnsupportedTarget if the requested target is unsupported + * - @ref AclInvalidArgument if a given argument is invalid + */ +AclStatus AclCreateContext(AclContext *ctx, + AclTarget target, + const AclContextOptions *options); + +/** Destroy a given context object + * + * @param[in] ctx A valid context object to destroy + * + * @return Status code + * + * Returns: + * - @ref AclSuccess if functions was completed successfully + * - @ref AclInvalidArgument if the provided context is invalid + */ +AclStatus AclDestroyContext(AclContext ctx); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* ARM_COMPUTE_ACLENTRYPOINTS_H_ */ diff --git a/arm_compute/AclOpenClExt.h b/arm_compute/AclOpenClExt.h new file mode 100644 index 0000000000..f71cd37299 --- /dev/null +++ b/arm_compute/AclOpenClExt.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2021 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_ACLOPENCLEXT_H_ +#define ARM_COMPUTE_ACLOPENCLEXT_H_ + +#include "arm_compute/AclTypes.h" + +#ifndef CL_TARGET_OPENCL_VERSION +#define CL_TARGET_OPENCL_VERSION 200 +#define CL_USE_DEPRECATED_OPENCL_1_1_APIS +#define CL_USE_DEPRECATED_OPENCL_1_2_APIS +#endif /* CL_TARGET_OPENCL_VERSION */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Weffc++" +#include "include/CL/cl.h" +#pragma GCC diagnostic pop + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Extract the underlying OpenCL context used by a given Compute Library context object + * + * @note @ref AclContext should be of an OpenCL backend target + * @note @ref AclContext refcount should be 0, meaning not used by other objects + * + * @param[in] ctx A valid non-zero context + * @param[out] opencl_context Underlying OpenCL context used + * + * @return Status code + */ +AclStatus AclGetClContext(AclContext ctx, cl_context *opencl_context); + +/** Set the underlying OpenCL context used by a given Compute Library context object + * + * @note @ref AclContext should be of an OpenCL backend target + * + * @param[in] ctx A valid non-zero context object + * @param[out] opencl_context Underlying OpenCL context to be used + * + * @return Status code + */ +AclStatus AclSetClContext(AclContext ctx, cl_context opencl_context); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* ARM_COMPUTE_ACLOPENCLEXT_H_ */ diff --git a/arm_compute/AclTypes.h b/arm_compute/AclTypes.h new file mode 100644 index 0000000000..3b022b7106 --- /dev/null +++ b/arm_compute/AclTypes.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2021 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_ACLTYPES_H_ +#define ARM_COMPUTE_ACLTYPES_H_ + +#include <stddef.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/**< Opaque Context object */ +typedef struct AclContext_ *AclContext; + +// Capabilities bitfield (Note: if multiple are enabled ComputeLibrary will pick the best possible) +typedef uint64_t AclTargetCapabilities; + +/**< Error codes returned by the public entry-points */ +typedef enum AclStatus : int32_t +{ + AclSuccess = 0, /**< Call succeeded, leading to valid state for all involved objects/data */ + AclRuntimeError = 1, /**< Call failed during execution */ + AclOutOfMemory = 2, /**< Call failed due to failure to allocate resources */ + AclUnimplemented = 3, /**< Call failed as requested capability is not implemented */ + AclUnsupportedTarget = 4, /**< Call failed as an invalid backend was requested */ + AclInvalidTarget = 5, /**< Call failed as invalid argument was passed */ + AclInvalidArgument = 6, /**< Call failed as invalid argument was passed */ + AclUnsupportedConfig = 7, /**< Call failed as configuration is unsupported */ + AclInvalidObjectState = 8, /**< Call failed as an object has invalid state */ +} AclStatus; + +/**< Supported CPU targets */ +typedef enum AclTarget +{ + AclCpu = 0, /**< Cpu target that uses SIMD extensions */ + AclGpuOcl = 1, /**< OpenCL target for GPU */ +} AclTarget; + +/** Execution mode types */ +typedef enum AclExecutionMode +{ + AclPreferFastRerun = 0, /**< Prioritize performance when multiple iterations are performed */ + AclPreferFastStart = 1, /**< Prioritize performance when a single iterations is expected to be performed */ +} AclExecutionMode; + +/** Available CPU capabilities */ +typedef enum AclCpuCapabalities +{ + AclCpuCapabilitiesAuto = 0, /**< Automatic discovery of capabilities */ + + AclCpuCapabilitiesNeon = (1 << 0), /**< Enable NEON optimized paths */ + AclCpuCapabilitiesSve = (1 << 1), /**< Enable SVE optimized paths */ + AclCpuCapabilitiesSve2 = (1 << 2), /**< Enable SVE2 optimized paths */ + // Reserve 3, 4, 5, 6 + + AclCpuCapabilitiesFp16 = (1 << 7), /**< Enable float16 data-type support */ + AclCpuCapabilitiesBf16 = (1 << 8), /**< Enable bfloat16 data-type support */ + // Reserve 9, 10, 11, 12 + + AclCpuCapabilitiesDot = (1 << 13), /**< Enable paths that use the udot/sdot instructions */ + AclCpuCapabilitiesMmlaInt8 = (1 << 14), /**< Enable paths that use the mmla integer instructions */ + AclCpuCapabilitiesMmlaFp = (1 << 15), /**< Enable paths that use the mmla float instructions */ + + AclCpuCapabilitiesAll = ~0 /**< Enable all paths */ +} AclCpuCapabalities; + +/**< Allocator interface that can be passed to a context */ +typedef struct AclAllocator +{ + /** Allocate a block of size bytes of memory. + * + * @param[in] user_data User provided data that can be used by the allocator + * @param[in] size Size of the allocation + * + * @return A pointer to the allocated block if successfull else NULL + */ + void *(*alloc)(void *user_data, size_t size); + /** Release a block of size bytes of memory. + * + * @param[in] user_data User provided data that can be used by the allocator + * @param[in] size Size of the allocation + */ + void (*free)(void *user_data, void *ptr); + /** Allocate a block of size bytes of memory. + * + * @param[in] user_data User provided data that can be used by the allocator + * @param[in] size Size of the allocation + * + * @return A pointer to the allocated block if successfull else NULL + */ + void *(*aligned_alloc)(void *user_data, size_t size, size_t alignment); + /** Allocate a block of size bytes of memory. + * + * @param[in] user_data User provided data that can be used by the allocator + * @param[in] size Size of the allocation + */ + void (*aligned_free)(void *user_data, void *ptr); + + /**< User provided information */ + void *user_data; +} AclAllocator; + +/**< Context options */ +typedef struct AclContextOptions +{ + AclExecutionMode mode; /**< Execution mode to use */ + AclTargetCapabilities capabilities; /**< Target capabilities */ + bool enable_fast_math; /**< Allow precision loss */ + const char *kernel_config_file; /**< Kernel cofiguration file */ + int32_t max_compute_units; /**< Max compute units that can be used by a queue created from the context. + If <=0 the system will use the hw concurency insted */ + AclAllocator *allocator; /**< Allocator to be used by all the memory internally */ +} AclContextOptions; + +/** Default context */ +const AclContextOptions acl_default_ctx_options = +{ + AclPreferFastRerun, /* mode */ + AclCpuCapabilitiesAuto, /* capabilities */ + false, /* enable_fast_math */ + "default.mlgo", /* kernel_config_file */ + -1, /* max_compute_units */ + nullptr /* allocator */ +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* ARM_COMPUTE_ACLTYPES_H_ */ diff --git a/arm_compute/AclVersion.h b/arm_compute/AclVersion.h new file mode 100644 index 0000000000..3a2f30791d --- /dev/null +++ b/arm_compute/AclVersion.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 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_ACLVERSION_H_ +#define ARM_COMPUTE_ACLVERSION_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Semantic versioning information */ +typedef struct AclVersion +{ + int major; /**< Major version, is increased on API incompatible changes */ + int minor; /**< Minor version, is increased on adding back-ward compatible functionality */ + int patch; /**< Patch version, is increased when doing backward compatible fixes */ + const char *build_info; /**< Build related information */ +} AclVersion; + +/**< Major version, is increased on API incompatible changes */ +#define ARM_COMPUTE_LIBRARY_VERSION_MAJOR 0 +/**< Minor version, is increased on adding back-ward compatible functionality */ +#define ARM_COMPUTE_LIBRARY_VERSION_MINOR 1 +/**< Patch version, is increased when doing backward compatible fixes */ +#define ARM_COMPUTE_LIBRARY_VERSION_PATCH 0 + +/** Get library's version meta-data + * + * @return Version information + */ +const AclVersion *AclVersionInfo(); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* ARM_COMPUTE_ACLVERSION_H_ */ diff --git a/scripts/arm_compute_library_nn_driver.go b/scripts/arm_compute_library_nn_driver.go index 61c8b992cf..8b1b80a7a7 100644 --- a/scripts/arm_compute_library_nn_driver.go +++ b/scripts/arm_compute_library_nn_driver.go @@ -57,6 +57,9 @@ func globalFlags(ctx android.BaseContext) []string { } } + cppflags = append(cppflags, "-ARM_COMPUTE_CPU_ENABLED") + cppflags = append(cppflags, "-ARM_COMPUTE_OPENCL_ENABLED") + return cppflags } diff --git a/src/c/AclContext.cpp b/src/c/AclContext.cpp new file mode 100644 index 0000000000..e88995bcff --- /dev/null +++ b/src/c/AclContext.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2021 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 "arm_compute/AclEntrypoints.h" + +#include "src/common/IContext.h" +#include "src/common/utils/Macros.h" +#include "src/common/utils/Validate.h" + +#ifdef ARM_COMPUTE_CPU_ENABLED +#include "src/cpu/CpuContext.h" +#endif /* ARM_COMPUTE_CPU_ENABLED */ + +#ifdef ARM_COMPUTE_OPENCL_ENABLED +#include "src/gpu/cl/ClContext.h" +#endif /* ARM_COMPUTE_OPENCL_ENABLED */ + +namespace +{ +template <typename ContextType> +arm_compute::IContext *create_backend_ctx(const AclContextOptions *options) +{ + return new(std::nothrow) ContextType(options); +} + +bool is_target_valid(AclTarget target) +{ + return arm_compute::utils::is_in(target, { AclCpu, AclGpuOcl }); +} + +bool are_context_options_valid(const AclContextOptions *options) +{ + ARM_COMPUTE_ASSERT_NOT_NULLPTR(options); + return arm_compute::utils::is_in(options->mode, { AclPreferFastRerun, AclPreferFastStart }); +} + +arm_compute::IContext *create_context(AclTarget target, const AclContextOptions *options) +{ + switch(target) + { +#ifdef ARM_COMPUTE_CPU_ENABLED + case AclCpu: + return create_backend_ctx<arm_compute::cpu::CpuContext>(options); +#endif /* ARM_COMPUTE_CPU_ENABLED */ +#ifdef ARM_COMPUTE_OPENCL_ENABLED + case AclGpuOcl: + return create_backend_ctx<arm_compute::gpu::opencl::ClContext>(options); +#endif /* ARM_COMPUTE_OPENCL_ENABLED */ + default: + return nullptr; + } + return nullptr; +} +} // namespace + +extern "C" AclStatus AclCreateContext(AclContext *ctx, + AclTarget target, + const AclContextOptions *options) +{ + if(!is_target_valid(target)) + { + ARM_COMPUTE_LOG_ERROR_ACL("Target is invalid"); + return AclUnsupportedTarget; + } + + if(options != nullptr && !are_context_options_valid(options)) + { + ARM_COMPUTE_LOG_ERROR_ACL("Context options are invalid"); + return AclInvalidArgument; + } + + auto acl_ctx = create_context(target, options); + if(ctx == nullptr) + { + ARM_COMPUTE_LOG_ERROR_ACL("Couldn't allocate internal resources for context creation"); + return AclOutOfMemory; + } + *ctx = acl_ctx; + + return AclSuccess; +} + +extern "C" AclStatus AclDestroyContext(AclContext external_ctx) +{ + using namespace arm_compute; + + IContext *ctx = get_internal(external_ctx); + + StatusCode status = StatusCode::Success; + status = detail::validate_internal_context(ctx); + ARM_COMPUTE_RETURN_CENUM_ON_FAILURE(status); + + if(ctx->refcount() != 0) + { + ARM_COMPUTE_LOG_ERROR_ACL("Context has references on it that haven't been released"); + // TODO: Fix the refcount with callback when reaches 0 + } + + delete ctx; + + return utils::as_cenum<AclStatus>(status); +} diff --git a/src/c/AclVersion.cpp b/src/c/AclVersion.cpp new file mode 100644 index 0000000000..971189a6d4 --- /dev/null +++ b/src/c/AclVersion.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 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 "arm_compute/AclVersion.h" + +namespace +{ +constexpr AclVersion version_info +{ + ARM_COMPUTE_LIBRARY_VERSION_MAJOR, + ARM_COMPUTE_LIBRARY_VERSION_MINOR, + ARM_COMPUTE_LIBRARY_VERSION_PATCH, +#ifndef DOXYGEN_SKIP_THIS +#include "arm_compute_version.embed" +#endif /* DOXYGEN_SKIP_THIS */ +}; +} // namespace + +extern "C" const AclVersion *AclVersionInfo() +{ + return &version_info; +} diff --git a/src/c/cl/AclOpenClExt.cpp b/src/c/cl/AclOpenClExt.cpp new file mode 100644 index 0000000000..5f2bb47c16 --- /dev/null +++ b/src/c/cl/AclOpenClExt.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2021 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 "arm_compute/AclOpenClExt.h" + +#include "src/common/Types.h" +#include "src/gpu/cl/ClContext.h" + +#include "support/Cast.h" + +extern "C" AclStatus AclGetClContext(AclContext external_ctx, cl_context *opencl_context) +{ + using namespace arm_compute; + IContext *ctx = get_internal(external_ctx); + + if(detail::validate_internal_context(ctx) != StatusCode::Success) + { + return AclStatus::AclInvalidArgument; + } + + if(ctx->type() != Target::GpuOcl) + { + return AclStatus::AclInvalidTarget; + } + + if(opencl_context == nullptr) + { + return AclStatus::AclInvalidArgument; + } + + *opencl_context = utils::cast::polymorphic_downcast<arm_compute::gpu::opencl::ClContext *>(ctx)->cl_ctx().get(); + + return AclStatus::AclSuccess; +} + +extern "C" AclStatus AclSetClContext(AclContext external_ctx, cl_context opencl_context) +{ + using namespace arm_compute; + IContext *ctx = get_internal(external_ctx); + + if(detail::validate_internal_context(ctx) != StatusCode::Success) + { + return AclStatus::AclInvalidArgument; + } + + if(ctx->type() != Target::GpuOcl) + { + return AclStatus::AclInvalidTarget; + } + + if(ctx->refcount() != 0) + { + return AclStatus::AclUnsupportedConfig; + } + + auto cl_ctx = utils::cast::polymorphic_downcast<arm_compute::gpu::opencl::ClContext *>(ctx); + if(!cl_ctx->set_cl_ctx(::cl::Context(opencl_context))) + { + return AclStatus::AclRuntimeError; + } + + return AclStatus::AclSuccess; +}
\ No newline at end of file diff --git a/src/common/AllocatorWrapper.cpp b/src/common/AllocatorWrapper.cpp new file mode 100644 index 0000000000..7b5bb34433 --- /dev/null +++ b/src/common/AllocatorWrapper.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2021 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 "src/common/AllocatorWrapper.h" +#include "arm_compute/core/Error.h" + +namespace arm_compute +{ +AllocatorWrapper::AllocatorWrapper(const AclAllocator &backing_allocator) noexcept + : _backing_allocator(backing_allocator) +{ +} + +void *AllocatorWrapper::alloc(size_t size) +{ + ARM_COMPUTE_ERROR_ON(_backing_allocator.alloc == nullptr); + return _backing_allocator.alloc(_backing_allocator.user_data, size); +} + +void AllocatorWrapper::free(void *ptr) +{ + ARM_COMPUTE_ERROR_ON(_backing_allocator.free == nullptr); + _backing_allocator.free(_backing_allocator.user_data, ptr); +} + +void *AllocatorWrapper::aligned_alloc(size_t size, size_t alignment) +{ + ARM_COMPUTE_ERROR_ON(_backing_allocator.aligned_alloc == nullptr); + return _backing_allocator.aligned_alloc(_backing_allocator.user_data, size, alignment); +} + +void AllocatorWrapper::aligned_free(void *ptr) +{ + ARM_COMPUTE_ERROR_ON(_backing_allocator.aligned_free == nullptr); + _backing_allocator.aligned_free(_backing_allocator.user_data, ptr); +} + +void AllocatorWrapper::set_user_data(void *user_data) +{ + if(user_data != nullptr) + { + _backing_allocator.user_data = user_data; + } +} +} // namespace arm_compute diff --git a/src/common/AllocatorWrapper.h b/src/common/AllocatorWrapper.h new file mode 100644 index 0000000000..5e1f138f16 --- /dev/null +++ b/src/common/AllocatorWrapper.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021 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 SRC_COMMON_ALLOCATORWRAPPER_H +#define SRC_COMMON_ALLOCATORWRAPPER_H + +#include "arm_compute/AclTypes.h" + +namespace arm_compute +{ +/** Default malloc allocator implementation */ +class AllocatorWrapper final +{ +public: + /** Default Constructor + * + * @param[in] backing_allocator Backing memory allocator to be used + */ + AllocatorWrapper(const AclAllocator &backing_allocator) noexcept; + AllocatorWrapper(const AllocatorWrapper &) noexcept = default; + AllocatorWrapper(AllocatorWrapper &&) noexcept = default; + AllocatorWrapper &operator=(const AllocatorWrapper &) noexcept = delete; + AllocatorWrapper &operator=(AllocatorWrapper &&other) noexcept = default; + /** Allocate a chunk of memory of a given size in bytes + * + * @param[in] size Size of memory to allocate in bytes + * + * @return A pointer to the allocated memory if successful else nullptr + */ + void *alloc(size_t size); + /** Free an allocated memory block + * + * @param[in] ptr Pointer to allocated memory + */ + void free(void *ptr); + /** Allocate a chunk of memory of a given size in bytes, + * while honoring a given alignment requirement + * + * @param[in] size Size of memory to allocate in bytes + * @param[in] alignment Alignment requirements + * + * @return A pointer to the allocated memory if successful else nullptr + */ + void *aligned_alloc(size_t size, size_t alignment); + /** Free an aligned memory block + * + * @param[in] ptr Pointer to the memory to release + */ + void aligned_free(void *ptr); + /** Set user data to be used by the allocator + * + * @param[in] user_data User data to be used by the allocator + */ + void set_user_data(void *user_data); + +private: + AclAllocator _backing_allocator; +}; +} // namespace arm_compute + +#endif /* SRC_COMMON_ALLOCATORWRAPPER_H */
\ No newline at end of file diff --git a/src/common/IContext.h b/src/common/IContext.h new file mode 100644 index 0000000000..0d23abd2be --- /dev/null +++ b/src/common/IContext.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2021 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 SRC_COMMON_ICONTEXT_H +#define SRC_COMMON_ICONTEXT_H + +#include "src/common/Types.h" +#include "src/common/utils/Log.h" +#include "src/common/utils/Object.h" + +#include <atomic> + +struct AclContext_ +{ + arm_compute::detail::Header header{ arm_compute::detail::ObjectType::Context, nullptr }; + +protected: + AclContext_() = default; + ~AclContext_() = default; +}; + +namespace arm_compute +{ +/**< Context interface */ +class IContext : public AclContext_ +{ +public: + IContext(Target target) + : AclContext_(), _target(target), _refcount(0) + { + } + /** Virtual Destructor */ + virtual ~IContext() + { + header.type = detail::ObjectType::Invalid; + }; + /** Target type accessor + * + * @return Target that the context is associated with + */ + Target type() const + { + return _target; + } + /** Increment context refcount */ + void inc_ref() const + { + ++_refcount; + } + /** Decrement context refcount */ + void dec_ref() const + { + --_refcount; + } + /** Reference counter accessor + * + * @return The number of references pointing to this object + */ + int refcount() const + { + return _refcount; + } + /** Checks if an object is valid + * + * @return True if sucessful otherwise false + */ + bool is_valid() const + { + return header.type == detail::ObjectType::Context; + } + +private: + Target _target; /**< Target type of context */ + mutable std::atomic<int> _refcount; /**< Reference counter */ +}; + +/** Extract internal representation of a Context + * + * @param[in] ctx Opaque context pointer + * + * @return The internal representation as an IContext + */ +inline IContext *get_internal(AclContext ctx) +{ + return static_cast<IContext *>(ctx); +} + +namespace detail +{ +/** Check if an internal context is valid + * + * @param[in] ctx Internal context to check + * + * @return A status code + */ +inline StatusCode validate_internal_context(const IContext *ctx) +{ + if(ctx == nullptr || !ctx->is_valid()) + { + ARM_COMPUTE_LOG_ERROR_ACL("Invalid context object"); + return StatusCode::InvalidArgument; + } + return StatusCode::Success; +} +} // namespace detail +} // namespace arm_compute +#endif /* SRC_COMMON_ICONTEXT_H */ diff --git a/src/common/Types.h b/src/common/Types.h new file mode 100644 index 0000000000..60a11b04ec --- /dev/null +++ b/src/common/Types.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 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 SRC_COMMON_TYPES_H_ +#define SRC_COMMON_TYPES_H_ + +#include "arm_compute/AclTypes.h" + +namespace arm_compute +{ +enum class StatusCode +{ + Success = AclSuccess, + RuntimeError = AclRuntimeError, + OutOfMemory = AclOutOfMemory, + Unimplemented = AclUnimplemented, + UnsupportedTarget = AclUnsupportedTarget, + InvalidTarget = AclInvalidTarget, + InvalidArgument = AclInvalidArgument, + UnsupportedConfig = AclUnsupportedConfig, + InvalidObjectState = AclInvalidObjectState, +}; + +enum class Target +{ + Cpu = AclTarget::AclCpu, + GpuOcl = AclTarget::AclGpuOcl, +}; + +enum class ExecutionMode +{ + FastRerun = AclPreferFastRerun, + FastStart = AclPreferFastStart, +}; +} // namespace arm_compute +#endif /* SRC_COMMON_TYPES_H_ */ diff --git a/src/common/utils/Log.h b/src/common/utils/Log.h new file mode 100644 index 0000000000..0d6a50da92 --- /dev/null +++ b/src/common/utils/Log.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2021 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 SRC_COMMON_LOG_H +#define SRC_COMMON_LOG_H + +#include "arm_compute/core/Error.h" +#include "arm_compute/core/utils/logging/Macros.h" + +#ifdef ARM_COMPUTE_LOGGING_ENABLED +/** Create a logger + * + * @note It will eventually create all default loggers in don't exist + */ +#define ARM_COMPUTE_CREATE_ACL_LOGGER() \ + do \ + { \ + if(arm_compute::logging::LoggerRegistry::get().logger("ComputeLibrary") == nullptr) \ + { \ + arm_compute::logging::LoggerRegistry::get().create_logger("ComputeLibrary", arm_compute::logging::LogLevel::INFO); \ + } \ + } while(false) +#else /* ARM_COMPUTE_LOGGING_ENABLED */ +#define ARM_COMPUTE_CREATE_ACL_LOGGER() +#endif /* ARM_COMPUTE_LOGGING_ENABLED */ +/** Log a message to the logger + * + * @param[in] log_level Logging level + * @param[in] msg Message to log + */ +#define ARM_COMPUTE_LOG_MSG_ACL(log_level, msg) \ + do \ + { \ + ARM_COMPUTE_CREATE_ACL_LOGGER(); \ + ARM_COMPUTE_LOG_MSG("ComputeLibrary", log_level, msg); \ + } while(false) +/** Log a message with format to the logger + * + * @param[in] log_level Logging level + * @param[in] fmt String format (printf style) + * @param[in] ... Message arguments + */ +#define ARM_COMPUTE_LOG_MSG_WITH_FORMAT_ACL(log_level, fmt, ...) \ + do \ + { \ + ARM_COMPUTE_CREATE_ACL_LOGGER(); \ + ARM_COMPUTE_LOG_MSG_WITH_FORMAT("ComputeLibrary", log_level, fmt, __VA_ARGS__); \ + } while(false) +/** Log an error message to the logger + * + * @param[in] msg Message to log + */ +#define ARM_COMPUTE_LOG_ERROR_ACL(msg) \ + do \ + { \ + ARM_COMPUTE_CREATE_ACL_LOGGER(); \ + ARM_COMPUTE_LOG_MSG("ComputeLibrary", arm_compute::logging::LogLevel::ERROR, msg); \ + } while(false) + +#endif /* SRC_COMMON_LOG_H */ diff --git a/src/common/utils/Macros.h b/src/common/utils/Macros.h new file mode 100644 index 0000000000..2e44ea599e --- /dev/null +++ b/src/common/utils/Macros.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 SRC_COMMON_MACROS_H_ +#define SRC_COMMON_MACROS_H_ + +#include "src/common/utils/Utils.h" + +#define ARM_COMPUTE_RETURN_CENUM_ON_FAILURE(status) \ + { \ + if(status != arm_compute::StatusCode::Success) \ + { \ + return arm_compute::utils::as_cenum<AclStatus>(status); \ + } \ + } + +#endif /* SRC_COMMON_MACROS_H_ */ diff --git a/src/common/utils/Object.h b/src/common/utils/Object.h new file mode 100644 index 0000000000..6f56f77d3c --- /dev/null +++ b/src/common/utils/Object.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2021 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 SRC_COMMON_OBJECT_H_ +#define SRC_COMMON_OBJECT_H_ + +#include <cstdint> + +namespace arm_compute +{ +// Forward declarations +class IContext; + +namespace detail +{ +/**< Object type enumerations */ +enum class ObjectType : uint32_t +{ + Context = 1, + Queue = 2, + Tensor = 3, + TensorPack = 4, + Operator = 5, + Invalid = 0x56DEAD78 +}; + +/**< API Header meta-data construct used by all opaque constructs */ +struct Header +{ + /** Constructor + * + * @param[in] type_ Object identification type + * @param[in] ctx_ Context to reference + */ + Header(ObjectType type_, IContext *ctx_) + : type(type_), ctx(ctx_) + { + } + + ObjectType type{ ObjectType::Invalid }; + IContext *ctx{ nullptr }; +}; +} // namespace detail +} // namespace arm_compute +#endif /* SRC_COMMON_OBJECT_H_ */ diff --git a/src/common/utils/Utils.h b/src/common/utils/Utils.h new file mode 100644 index 0000000000..9602c32f62 --- /dev/null +++ b/src/common/utils/Utils.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021 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 SRC_COMMON_UTILS_H +#define SRC_COMMON_UTILS_H + +#include <type_traits> + +namespace arm_compute +{ +namespace utils +{ +/** Convert a strongly typed enum to an old plain c enum + * + * @tparam E Plain old C enum + * @tparam SE Strongly typed resulting enum + * + * @param[in] v Value to convert + * + * @return A corresponding plain old C enumeration + */ +template <typename E, typename SE> +constexpr E as_cenum(SE v) noexcept +{ + return static_cast<E>(static_cast<std::underlying_type_t<SE>>(v)); +} +/** Check if the given value is in the given enum value list + * + * @tparam E The type of the enum + * + * @param[in] check Value to check + * @param[in] list List of enum values to check against + * + * @return True if the given value is found in the list + */ +template <typename E> +bool is_in(E check, std::initializer_list<E> list) +{ + return std::any_of(std::cbegin(list), std::cend(list), [&check](E e) + { + return check == e; + }); +} +} // namespace utils +} // namespace arm_compute + +#endif /* SRC_COMMON_UTILS_H */ diff --git a/src/core/common/Validate.h b/src/common/utils/Validate.h index fa24bf5fa7..4e8807273a 100644 --- a/src/core/common/Validate.h +++ b/src/common/utils/Validate.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Arm Limited. + * Copyright (c) 2020-2021 Arm Limited. * * SPDX-License-Identifier: MIT * diff --git a/src/core/NEON/kernels/NELogicalKernel.cpp b/src/core/NEON/kernels/NELogicalKernel.cpp index 27605e15c6..d98694ffe1 100644 --- a/src/core/NEON/kernels/NELogicalKernel.cpp +++ b/src/core/NEON/kernels/NELogicalKernel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Arm Limited. + * Copyright (c) 2020-2021 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -25,7 +25,7 @@ #include "arm_compute/core/Helpers.h" #include "arm_compute/core/Validate.h" -#include "src/core/common/Validate.h" +#include "src/common/utils/Validate.h" #include "src/core/helpers/AutoConfiguration.h" #include "src/core/helpers/WindowHelpers.h" diff --git a/src/core/NEON/kernels/batchnormalization/impl/NEON/fp16.cpp b/src/core/NEON/kernels/batchnormalization/impl/NEON/fp16.cpp index 4108d79a5a..c105adac70 100644 --- a/src/core/NEON/kernels/batchnormalization/impl/NEON/fp16.cpp +++ b/src/core/NEON/kernels/batchnormalization/impl/NEON/fp16.cpp @@ -27,7 +27,6 @@ #include "src/core/NEON/NEMath.h" #include "src/core/NEON/kernels/detail/NEActivationFunctionDetail.h" #include "src/core/NEON/wrapper/wrapper.h" -#include "src/core/common/Validate.h" #include <arm_neon.h> #include <cmath> diff --git a/src/core/NEON/kernels/batchnormalization/impl/NEON/fp32.cpp b/src/core/NEON/kernels/batchnormalization/impl/NEON/fp32.cpp index 1fdc5bd5b1..4a90a211c7 100644 --- a/src/core/NEON/kernels/batchnormalization/impl/NEON/fp32.cpp +++ b/src/core/NEON/kernels/batchnormalization/impl/NEON/fp32.cpp @@ -27,7 +27,6 @@ #include "src/core/NEON/NEMath.h" #include "src/core/NEON/kernels/detail/NEActivationFunctionDetail.h" #include "src/core/NEON/wrapper/wrapper.h" -#include "src/core/common/Validate.h" #include <arm_neon.h> #include <cmath> diff --git a/src/core/NEON/kernels/batchnormalization/impl/SVE/fp16.cpp b/src/core/NEON/kernels/batchnormalization/impl/SVE/fp16.cpp index 5638dcef0a..3e3e81d044 100644 --- a/src/core/NEON/kernels/batchnormalization/impl/SVE/fp16.cpp +++ b/src/core/NEON/kernels/batchnormalization/impl/SVE/fp16.cpp @@ -25,7 +25,6 @@ #include "arm_compute/core/ITensorPack.h" #include "arm_compute/core/Window.h" #include "src/core/NEON/SVEMath.h" -#include "src/core/common/Validate.h" #include <cmath> #include <cstddef> diff --git a/src/core/NEON/kernels/batchnormalization/impl/SVE/fp32.cpp b/src/core/NEON/kernels/batchnormalization/impl/SVE/fp32.cpp index 51397aca3a..b0d4cbb684 100644 --- a/src/core/NEON/kernels/batchnormalization/impl/SVE/fp32.cpp +++ b/src/core/NEON/kernels/batchnormalization/impl/SVE/fp32.cpp @@ -25,7 +25,6 @@ #include "arm_compute/core/ITensorPack.h" #include "arm_compute/core/Window.h" #include "src/core/NEON/SVEMath.h" -#include "src/core/common/Validate.h" #include <cmath> #include <cstddef> diff --git a/src/core/NEON/kernels/scale/impl/NEON/fp16.cpp b/src/core/NEON/kernels/scale/impl/NEON/fp16.cpp new file mode 100644 index 0000000000..0ad66cab1c --- /dev/null +++ b/src/core/NEON/kernels/scale/impl/NEON/fp16.cpp @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2021 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 "arm_compute/core/Helpers.h" +#include "arm_compute/core/ITensorPack.h" +#include "arm_compute/core/Window.h" +#include "src/core/NEON/NEMath.h" +#include "src/core/NEON/wrapper/wrapper.h" +#include "src/core/helpers/ScaleHelpers.h" +#include "src/core/utils/ScaleUtils.h" +#include "support/Rounding.h" + +#include <arm_neon.h> +#include <cmath> +#include <cstddef> + +#if defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC) && defined(ENABLE_FP16_KERNELS) + +namespace arm_compute +{ +namespace +{ +void fp16_neon_scale_nearest(const ITensor *src, ITensor *dst, const ITensor *offsets, + float sampling_offset, bool align_corners, const Window &window) +{ + const size_t in_stride_c = src->info()->dimension(0) + src->info()->padding().left + src->info()->padding().right; + const size_t in_stride_w = src->info()->dimension(1) + src->info()->padding().top + src->info()->padding().bottom; + const size_t in_stride_wc = in_stride_w * in_stride_c; + const size_t in_dim_h = src->info()->dimension(2); + + // Compute the ratio between source height and destination height + const auto hr = scale_utils::calculate_resize_ratio(in_dim_h, dst->info()->dimension(2), align_corners); + const auto window_start_x = static_cast<int32_t>(window.x().start()); + const auto window_end_x = static_cast<int32_t>(window.x().end()); + const int window_step_x = 8; + + Window win(window); + win.set(Window::DimX, Window::Dimension(0, 1, 1)); + Iterator out(dst, win); + + const uint8_t *in_ptr_start = src->buffer() + src->info()->offset_first_element_in_bytes(); + const unsigned int in_stride_bytes_hwc = src->info()->strides_in_bytes()[3]; + + execute_window_loop(win, [&](const Coordinates & id) + { + const int32_t offset = *reinterpret_cast<const int32_t *>(offsets->ptr_to_element(Coordinates(id.y(), id.z()))) * in_stride_c; + const auto in_hi = static_cast<int>(align_corners ? utils::rounding::round_half_away_from_zero((id.z() + sampling_offset) * hr) : std::floor((id.z() + sampling_offset) * hr)); + const int offset_row = in_hi * in_stride_wc; + int32_t x = window_start_x; + const float16_t *in_ptr = reinterpret_cast<const float16_t *>(in_ptr_start + in_stride_bytes_hwc * id[3]); + + for(; x <= window_end_x - window_step_x; x += window_step_x) + { + wrapper::vstore(reinterpret_cast<float16_t *>(out.ptr()) + x, + wrapper::vloadq(in_ptr + offset + offset_row + x)); + } + for(; x < window_end_x; ++x) + { + *(reinterpret_cast<float16_t *>(out.ptr()) + x) = *(in_ptr + offset + offset_row + x); + } + }, + out); +} + +void fp16_neon_scale_bilinear(const ITensor *src, ITensor *dst, const ITensor *offsets, const ITensor *dx, const ITensor *dy, + BorderMode border_mode, PixelValue constant_border_value, float sampling_offset, + bool align_corners, const Window &window) +{ + // Compute the ratio between source height and destination height + const auto hr = scale_utils::calculate_resize_ratio(src->info()->dimension(2), dst->info()->dimension(2), align_corners); + + Iterator out(dst, window); + const int in_stride_c = src->info()->dimension(0) + src->info()->padding().left + src->info()->padding().right; + const int in_dim_w = src->info()->dimension(1); + const int in_dim_h = src->info()->dimension(2); + const int in_stride_wc = in_stride_c * (in_dim_w + src->info()->padding().top + src->info()->padding().bottom); + + // Don't increment in Y and Z direction for the input tensor + // A pointer to the start of this plane is needed as base for the precomputed offsets + Window win_in(window); + win_in.set(Window::DimY, Window::Dimension(0, 0, 0)); + win_in.set(Window::DimZ, Window::Dimension(0, 0, 0)); + Iterator in(src, win_in); + + if(border_mode == BorderMode::CONSTANT) + { + using ConstType = typename std::conditional<std::is_same<float16_t, float16_t>::value, half, float16_t>::type; + + const float16_t const_border_value = static_cast<float16_t>(constant_border_value.get<ConstType>()); + execute_window_loop(window, [&](const Coordinates & id) + { + const auto offset = *reinterpret_cast<const int32_t *>(offsets->ptr_to_element(Coordinates(id.y(), id.z()))); + const auto dx_val = *reinterpret_cast<const float *>(dx->ptr_to_element(Coordinates(id.y(), id.z()))); + const auto dy_val = *reinterpret_cast<const float *>(dy->ptr_to_element(Coordinates(id.y(), id.z()))); + const int32_t in_hi = std::floor((id.z() + sampling_offset) * hr - sampling_offset); + const float16_t *in_ptr = reinterpret_cast<const float16_t *>(in.ptr()) + offset * in_stride_c + in_hi * in_stride_wc; + + const auto a00 = (0 <= offset && offset < in_dim_w && 0 <= in_hi && in_hi < in_dim_h) ? *in_ptr : const_border_value; + const auto a01 = (-1 <= offset && offset < in_dim_w - 1 && 0 <= in_hi && in_hi < in_dim_h) ? *(in_ptr + in_stride_c) : const_border_value; + const auto a10 = (0 <= offset && offset < in_dim_w && -1 <= in_hi && in_hi < in_dim_h - 1) ? *(in_ptr + in_stride_wc) : const_border_value; + const auto a11 = (-1 <= offset && offset < in_dim_w - 1 && -1 <= in_hi && in_hi < in_dim_h - 1) ? *(in_ptr + in_stride_c + in_stride_wc) : const_border_value; + + *reinterpret_cast<float16_t *>(out.ptr()) = static_cast<float16_t>(scale_helpers::delta_bilinear(a00, a01, a10, a11, dx_val, dy_val)); + }, + in, out); + } + else if(border_mode == BorderMode::REPLICATE) + { + execute_window_loop(window, [&](const Coordinates & id) + { + const auto offset = *reinterpret_cast<const int32_t *>(offsets->ptr_to_element(Coordinates(id.y(), id.z()))); + const auto dx_val = *reinterpret_cast<const float *>(dx->ptr_to_element(Coordinates(id.y(), id.z()))); + const auto dy_val = *reinterpret_cast<const float *>(dy->ptr_to_element(Coordinates(id.y(), id.z()))); + const int in_hi = std::floor((id.z() + sampling_offset) * hr - sampling_offset); + + auto clamped_w = utility::clamp<int>(offset, 0, in_dim_w - 1); + auto clamped_w1 = utility::clamp<int>(offset + 1, 0, in_dim_w - 1); + auto clamped_h = utility::clamp<int>(in_hi, 0, in_dim_h - 1); + auto clamped_h1 = utility::clamp<int>(in_hi + 1, 0, in_dim_h - 1); + + const auto a00 = *(reinterpret_cast<const float16_t *>(in.ptr()) + clamped_w * in_stride_c + clamped_h * in_stride_wc); + const auto a01 = *(reinterpret_cast<const float16_t *>(in.ptr()) + clamped_w1 * in_stride_c + clamped_h * in_stride_wc); + const auto a10 = *(reinterpret_cast<const float16_t *>(in.ptr()) + clamped_w * in_stride_c + clamped_h1 * in_stride_wc); + const auto a11 = *(reinterpret_cast<const float16_t *>(in.ptr()) + clamped_w1 * in_stride_c + clamped_h1 * in_stride_wc); + + *reinterpret_cast<float16_t *>(out.ptr()) = static_cast<float16_t>(scale_helpers::delta_bilinear(a00, a01, a10, a11, dx_val, dy_val)); + }, + in, out); + } + else + { + ARM_COMPUTE_ERROR("Not implemented"); + } +} +} +namespace cpu +{ +void fp16_neon_scale(const ITensor *src, ITensor *dst, const ITensor *offsets, const ITensor *dx, const ITensor *dy, + InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, float sampling_offset, + bool align_corners, const Window &window) +{ + if(policy == InterpolationPolicy::BILINEAR) + { + fp16_neon_scale_bilinear(src, dst, offsets, dx, dy, border_mode, constant_border_value, sampling_offset, align_corners, window); + } + else if(policy == InterpolationPolicy::NEAREST_NEIGHBOR) + { + fp16_neon_scale_nearest(src, dst, offsets, sampling_offset, align_corners, window); + } +} +} // namespace cpu +} // namespace arm_compute + +#endif /* defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC) && defined(ENABLE_FP16_KERNELS) */
\ No newline at end of file diff --git a/src/core/NEON/kernels/scale/impl/NEON/integer.cpp b/src/core/NEON/kernels/scale/impl/NEON/integer.cpp new file mode 100644 index 0000000000..a2359aac94 --- /dev/null +++ b/src/core/NEON/kernels/scale/impl/NEON/integer.cpp @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2021 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 "arm_compute/core/Helpers.h" +#include "arm_compute/core/ITensorPack.h" +#include "arm_compute/core/Window.h" +#include "src/core/NEON/NEMath.h" +#include "src/core/NEON/wrapper/wrapper.h" +#include "src/core/helpers/ScaleHelpers.h" +#include "src/core/utils/ScaleUtils.h" +#include "support/Rounding.h" + +#include <arm_neon.h> +#include <cmath> +#include <cstddef> + +namespace arm_compute +{ +namespace +{ +void u8_neon_scale_nearest(const ITensor *src, ITensor *dst, const ITensor *offsets, + float sampling_offset, bool align_corners, const Window &window) +{ + const size_t in_stride_c = src->info()->dimension(0) + src->info()->padding().left + src->info()->padding().right; + const size_t in_stride_w = src->info()->dimension(1) + src->info()->padding().top + src->info()->padding().bottom; + const size_t in_stride_wc = in_stride_w * in_stride_c; + const size_t in_dim_h = src->info()->dimension(2); + + // Compute the ratio between source height and destination height + const auto hr = scale_utils::calculate_resize_ratio(in_dim_h, dst->info()->dimension(2), align_corners); + const auto window_start_x = static_cast<int32_t>(window.x().start()); + const auto window_end_x = static_cast<int32_t>(window.x().end()); + const int window_step_x = 16; + + Window win(window); + win.set(Window::DimX, Window::Dimension(0, 1, 1)); + Iterator out(dst, win); + + const uint8_t *in_ptr_start = src->buffer() + src->info()->offset_first_element_in_bytes(); + const unsigned int in_stride_bytes_hwc = src->info()->strides_in_bytes()[3]; + + execute_window_loop(win, [&](const Coordinates & id) + { + const int32_t offset = *reinterpret_cast<const int32_t *>(offsets->ptr_to_element(Coordinates(id.y(), id.z()))) * in_stride_c; + const auto in_hi = static_cast<int>(align_corners ? utils::rounding::round_half_away_from_zero((id.z() + sampling_offset) * hr) : std::floor((id.z() + sampling_offset) * hr)); + const int offset_row = in_hi * in_stride_wc; + int32_t x = window_start_x; + const uint8_t *in_ptr = reinterpret_cast<const uint8_t *>(in_ptr_start + in_stride_bytes_hwc * id[3]); + + for(; x <= window_end_x - window_step_x; x += window_step_x) + { + wrapper::vstore(reinterpret_cast<uint8_t *>(out.ptr()) + x, + wrapper::vloadq(in_ptr + offset + offset_row + x)); + } + for(; x < window_end_x; ++x) + { + *(reinterpret_cast<uint8_t *>(out.ptr()) + x) = *(in_ptr + offset + offset_row + x); + } + }, + out); +} + +void u8_neon_scale_bilinear(const ITensor *src, ITensor *dst, const ITensor *offsets, const ITensor *dx, const ITensor *dy, + BorderMode border_mode, PixelValue constant_border_value, float sampling_offset, + bool align_corners, const Window &window) +{ + // Compute the ratio between source height and destination height + const auto hr = scale_utils::calculate_resize_ratio(src->info()->dimension(2), dst->info()->dimension(2), align_corners); + + Iterator out(dst, window); + const int in_stride_c = src->info()->dimension(0) + src->info()->padding().left + src->info()->padding().right; + const int in_dim_w = src->info()->dimension(1); + const int in_dim_h = src->info()->dimension(2); + const int in_stride_wc = in_stride_c * (in_dim_w + src->info()->padding().top + src->info()->padding().bottom); + + // Don't increment in Y and Z direction for the input tensor + // A pointer to the start of this plane is needed as base for the precomputed offsets + Window win_in(window); + win_in.set(Window::DimY, Window::Dimension(0, 0, 0)); + win_in.set(Window::DimZ, Window::Dimension(0, 0, 0)); + Iterator in(src, win_in); + + if(border_mode == BorderMode::CONSTANT) + { + const uint8_t const_border_value = static_cast<uint8_t>(constant_border_value.get<uint8_t>()); + execute_window_loop(window, [&](const Coordinates & id) + { + const auto offset = *reinterpret_cast<const int32_t *>(offsets->ptr_to_element(Coordinates(id.y(), id.z()))); + const auto dx_val = *reinterpret_cast<const float *>(dx->ptr_to_element(Coordinates(id.y(), id.z()))); + const auto dy_val = *reinterpret_cast<const float *>(dy->ptr_to_element(Coordinates(id.y(), id.z()))); + const int32_t in_hi = std::floor((id.z() + sampling_offset) * hr - sampling_offset); + const uint8_t *in_ptr = reinterpret_cast<const uint8_t *>(in.ptr()) + offset * in_stride_c + in_hi * in_stride_wc; + + const auto a00 = (0 <= offset && offset < in_dim_w && 0 <= in_hi && in_hi < in_dim_h) ? *in_ptr : const_border_value; + const auto a01 = (-1 <= offset && offset < in_dim_w - 1 && 0 <= in_hi && in_hi < in_dim_h) ? *(in_ptr + in_stride_c) : const_border_value; + const auto a10 = (0 <= offset && offset < in_dim_w && -1 <= in_hi && in_hi < in_dim_h - 1) ? *(in_ptr + in_stride_wc) : const_border_value; + const auto a11 = (-1 <= offset && offset < in_dim_w - 1 && -1 <= in_hi && in_hi < in_dim_h - 1) ? *(in_ptr + in_stride_c + in_stride_wc) : const_border_value; + + *reinterpret_cast<uint8_t *>(out.ptr()) = static_cast<uint8_t>(scale_helpers::delta_bilinear(a00, a01, a10, a11, dx_val, dy_val)); + }, + in, out); + } + else if(border_mode == BorderMode::REPLICATE) + { + execute_window_loop(window, [&](const Coordinates & id) + { + const auto offset = *reinterpret_cast<const int32_t *>(offsets->ptr_to_element(Coordinates(id.y(), id.z()))); + const auto dx_val = *reinterpret_cast<const float *>(dx->ptr_to_element(Coordinates(id.y(), id.z()))); + const auto dy_val = *reinterpret_cast<const float *>(dy->ptr_to_element(Coordinates(id.y(), id.z()))); + const int in_hi = std::floor((id.z() + sampling_offset) * hr - sampling_offset); + + auto clamped_w = utility::clamp<int>(offset, 0, in_dim_w - 1); + auto clamped_w1 = utility::clamp<int>(offset + 1, 0, in_dim_w - 1); + auto clamped_h = utility::clamp<int>(in_hi, 0, in_dim_h - 1); + auto clamped_h1 = utility::clamp<int>(in_hi + 1, 0, in_dim_h - 1); + + const auto a00 = *(reinterpret_cast<const uint8_t *>(in.ptr()) + clamped_w * in_stride_c + clamped_h * in_stride_wc); + const auto a01 = *(reinterpret_cast<const uint8_t *>(in.ptr()) + clamped_w1 * in_stride_c + clamped_h * in_stride_wc); + const auto a10 = *(reinterpret_cast<const uint8_t *>(in.ptr()) + clamped_w * in_stride_c + clamped_h1 * in_stride_wc); + const auto a11 = *(reinterpret_cast<const uint8_t *>(in.ptr()) + clamped_w1 * in_stride_c + clamped_h1 * in_stride_wc); + + *reinterpret_cast<uint8_t *>(out.ptr()) = static_cast<uint8_t>(scale_helpers::delta_bilinear(a00, a01, a10, a11, dx_val, dy_val)); + }, + in, out); + } + else + { + ARM_COMPUTE_ERROR("Not implemented"); + } +} + +void s16_neon_scale_nearest(const ITensor *src, ITensor *dst, const ITensor *offsets, + float sampling_offset, bool align_corners, const Window &window) +{ + const size_t in_stride_c = src->info()->dimension(0) + src->info()->padding().left + src->info()->padding().right; + const size_t in_stride_w = src->info()->dimension(1) + src->info()->padding().top + src->info()->padding().bottom; + const size_t in_stride_wc = in_stride_w * in_stride_c; + const size_t in_dim_h = src->info()->dimension(2); + + // Compute the ratio between source height and destination height + const auto hr = scale_utils::calculate_resize_ratio(in_dim_h, dst->info()->dimension(2), align_corners); + const auto window_start_x = static_cast<int32_t>(window.x().start()); + const auto window_end_x = static_cast<int32_t>(window.x().end()); + const int window_step_x = 8; + + Window win(window); + win.set(Window::DimX, Window::Dimension(0, 1, 1)); + Iterator out(dst, win); + + const uint8_t *in_ptr_start = src->buffer() + src->info()->offset_first_element_in_bytes(); + const unsigned int in_stride_bytes_hwc = src->info()->strides_in_bytes()[3]; + + execute_window_loop(win, [&](const Coordinates & id) + { + const int32_t offset = *reinterpret_cast<const int32_t *>(offsets->ptr_to_element(Coordinates(id.y(), id.z()))) * in_stride_c; + const auto in_hi = static_cast<int>(align_corners ? utils::rounding::round_half_away_from_zero((id.z() + sampling_offset) * hr) : std::floor((id.z() + sampling_offset) * hr)); + const int offset_row = in_hi * in_stride_wc; + int32_t x = window_start_x; + const int16_t *in_ptr = reinterpret_cast<const int16_t *>(in_ptr_start + in_stride_bytes_hwc * id[3]); + + for(; x <= window_end_x - window_step_x; x += window_step_x) + { + wrapper::vstore(reinterpret_cast<int16_t *>(out.ptr()) + x, + wrapper::vloadq(in_ptr + offset + offset_row + x)); + } + for(; x < window_end_x; ++x) + { + *(reinterpret_cast<int16_t *>(out.ptr()) + x) = *(in_ptr + offset + offset_row + x); + } + }, + out); +} + +void s16_neon_scale_bilinear(const ITensor *src, ITensor *dst, const ITensor *offsets, const ITensor *dx, const ITensor *dy, + BorderMode border_mode, PixelValue constant_border_value, float sampling_offset, + bool align_corners, const Window &window) +{ + // Compute the ratio between source height and destination height + const auto hr = scale_utils::calculate_resize_ratio(src->info()->dimension(2), dst->info()->dimension(2), align_corners); + + Iterator out(dst, window); + const int in_stride_c = src->info()->dimension(0) + src->info()->padding().left + src->info()->padding().right; + const int in_dim_w = src->info()->dimension(1); + const int in_dim_h = src->info()->dimension(2); + const int in_stride_wc = in_stride_c * (in_dim_w + src->info()->padding().top + src->info()->padding().bottom); + + // Don't increment in Y and Z direction for the input tensor + // A pointer to the start of this plane is needed as base for the precomputed offsets + Window win_in(window); + win_in.set(Window::DimY, Window::Dimension(0, 0, 0)); + win_in.set(Window::DimZ, Window::Dimension(0, 0, 0)); + Iterator in(src, win_in); + + if(border_mode == BorderMode::CONSTANT) + { + const int16_t const_border_value = static_cast<int16_t>(constant_border_value.get<int16_t>()); + execute_window_loop(window, [&](const Coordinates & id) + { + const auto offset = *reinterpret_cast<const int32_t *>(offsets->ptr_to_element(Coordinates(id.y(), id.z()))); + const auto dx_val = *reinterpret_cast<const float *>(dx->ptr_to_element(Coordinates(id.y(), id.z()))); + const auto dy_val = *reinterpret_cast<const float *>(dy->ptr_to_element(Coordinates(id.y(), id.z()))); + const int32_t in_hi = std::floor((id.z() + sampling_offset) * hr - sampling_offset); + const int16_t *in_ptr = reinterpret_cast<const int16_t *>(in.ptr()) + offset * in_stride_c + in_hi * in_stride_wc; + + const auto a00 = (0 <= offset && offset < in_dim_w && 0 <= in_hi && in_hi < in_dim_h) ? *in_ptr : const_border_value; + const auto a01 = (-1 <= offset && offset < in_dim_w - 1 && 0 <= in_hi && in_hi < in_dim_h) ? *(in_ptr + in_stride_c) : const_border_value; + const auto a10 = (0 <= offset && offset < in_dim_w && -1 <= in_hi && in_hi < in_dim_h - 1) ? *(in_ptr + in_stride_wc) : const_border_value; + const auto a11 = (-1 <= offset && offset < in_dim_w - 1 && -1 <= in_hi && in_hi < in_dim_h - 1) ? *(in_ptr + in_stride_c + in_stride_wc) : const_border_value; + + *reinterpret_cast<int16_t *>(out.ptr()) = static_cast<int16_t>(scale_helpers::delta_bilinear(a00, a01, a10, a11, dx_val, dy_val)); + }, + in, out); + } + else if(border_mode == BorderMode::REPLICATE) + { + execute_window_loop(window, [&](const Coordinates & id) + { + const auto offset = *reinterpret_cast<const int32_t *>(offsets->ptr_to_element(Coordinates(id.y(), id.z()))); + const auto dx_val = *reinterpret_cast<const float *>(dx->ptr_to_element(Coordinates(id.y(), id.z()))); + const auto dy_val = *reinterpret_cast<const float *>(dy->ptr_to_element(Coordinates(id.y(), id.z()))); + const int in_hi = std::floor((id.z() + sampling_offset) * hr - sampling_offset); + + auto clamped_w = utility::clamp<int>(offset, 0, in_dim_w - 1); + auto clamped_w1 = utility::clamp<int>(offset + 1, 0, in_dim_w - 1); + auto clamped_h = utility::clamp<int>(in_hi, 0, in_dim_h - 1); + auto clamped_h1 = utility::clamp<int>(in_hi + 1, 0, in_dim_h - 1); + + const auto a00 = *(reinterpret_cast<const int16_t *>(in.ptr()) + clamped_w * in_stride_c + clamped_h * in_stride_wc); + const auto a01 = *(reinterpret_cast<const int16_t *>(in.ptr()) + clamped_w1 * in_stride_c + clamped_h * in_stride_wc); + const auto a10 = *(reinterpret_cast<const int16_t *>(in.ptr()) + clamped_w * in_stride_c + clamped_h1 * in_stride_wc); + const auto a11 = *(reinterpret_cast<const int16_t *>(in.ptr()) + clamped_w1 * in_stride_c + clamped_h1 * in_stride_wc); + + *reinterpret_cast<int16_t *>(out.ptr()) = static_cast<int16_t>(scale_helpers::delta_bilinear(a00, a01, a10, a11, dx_val, dy_val)); + }, + in, out); + } + else + { + ARM_COMPUTE_ERROR("Not implemented"); + } +} +} +namespace cpu +{ +void u8_neon_scale(const ITensor *src, ITensor *dst, const ITensor *offsets, const ITensor *dx, const ITensor *dy, + InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, float sampling_offset, + bool align_corners, const Window &window) +{ + if(policy == InterpolationPolicy::BILINEAR) + { + u8_neon_scale_bilinear(src, dst, offsets, dx, dy, border_mode, constant_border_value, sampling_offset, align_corners, window); + } + else if(policy == InterpolationPolicy::NEAREST_NEIGHBOR) + { + u8_neon_scale_nearest(src, dst, offsets, sampling_offset, align_corners, window); + } +} + +void s16_neon_scale(const ITensor *src, ITensor *dst, const ITensor *offsets, const ITensor *dx, const ITensor *dy, + InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, float sampling_offset, + bool align_corners, const Window &window) +{ + if(policy == InterpolationPolicy::BILINEAR) + { + s16_neon_scale_bilinear(src, dst, offsets, dx, dy, border_mode, constant_border_value, sampling_offset, align_corners, window); + } + else if(policy == InterpolationPolicy::NEAREST_NEIGHBOR) + { + s16_neon_scale_nearest(src, dst, offsets, sampling_offset, align_corners, window); + } +} +} // namespace cpu +} // namespace arm_compute
\ No newline at end of file diff --git a/src/core/NEON/kernels/scale/impl/NEON/list.h b/src/core/NEON/kernels/scale/impl/NEON/list.h index 11cac26071..c91242f5b2 100644 --- a/src/core/NEON/kernels/scale/impl/NEON/list.h +++ b/src/core/NEON/kernels/scale/impl/NEON/list.h @@ -29,7 +29,6 @@ #include "arm_compute/core/Window.h" #include "src/core/NEON/NEMath.h" #include "src/core/NEON/wrapper/wrapper.h" -#include "src/core/common/Validate.h" #include "src/core/helpers/ScaleHelpers.h" #include "src/core/utils/ScaleUtils.h" #include "support/Rounding.h" diff --git a/src/core/NEON/kernels/scale/impl/NEON/qasymm8_signed.cpp b/src/core/NEON/kernels/scale/impl/NEON/qasymm8_signed.cpp index 7b1860802f..149cdf478f 100644 --- a/src/core/NEON/kernels/scale/impl/NEON/qasymm8_signed.cpp +++ b/src/core/NEON/kernels/scale/impl/NEON/qasymm8_signed.cpp @@ -21,7 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - #include "src/core/NEON/kernels/scale/impl/NEON/list.h" namespace arm_compute diff --git a/src/core/NEON/kernels/scale/impl/SVE/fp16.cpp b/src/core/NEON/kernels/scale/impl/SVE/fp16.cpp index 91c3dc3b4e..99f08dbdf9 100644 --- a/src/core/NEON/kernels/scale/impl/SVE/fp16.cpp +++ b/src/core/NEON/kernels/scale/impl/SVE/fp16.cpp @@ -26,7 +26,6 @@ #include "arm_compute/core/Window.h" #include "src/core/NEON/NEMath.h" #include "src/core/NEON/wrapper/wrapper.h" -#include "src/core/common/Validate.h" #include "src/core/helpers/ScaleHelpers.h" #include "src/core/utils/ScaleUtils.h" #include "support/Rounding.h" diff --git a/src/core/NEON/kernels/scale/impl/SVE/fp32.cpp b/src/core/NEON/kernels/scale/impl/SVE/fp32.cpp index abb4faa6c5..94055ae953 100644 --- a/src/core/NEON/kernels/scale/impl/SVE/fp32.cpp +++ b/src/core/NEON/kernels/scale/impl/SVE/fp32.cpp @@ -26,7 +26,6 @@ #include "arm_compute/core/Window.h" #include "src/core/NEON/NEMath.h" #include "src/core/NEON/wrapper/wrapper.h" -#include "src/core/common/Validate.h" #include "src/core/helpers/ScaleHelpers.h" #include "src/core/utils/ScaleUtils.h" #include "support/Rounding.h" diff --git a/src/core/NEON/kernels/scale/impl/SVE/integer.cpp b/src/core/NEON/kernels/scale/impl/SVE/integer.cpp index 5f5263c5d3..2a724ece31 100644 --- a/src/core/NEON/kernels/scale/impl/SVE/integer.cpp +++ b/src/core/NEON/kernels/scale/impl/SVE/integer.cpp @@ -26,7 +26,6 @@ #include "arm_compute/core/Window.h" #include "src/core/NEON/NEMath.h" #include "src/core/NEON/wrapper/wrapper.h" -#include "src/core/common/Validate.h" #include "src/core/helpers/ScaleHelpers.h" #include "src/core/utils/ScaleUtils.h" #include "support/Rounding.h" diff --git a/src/core/NEON/kernels/scale/impl/SVE/qasymm8.cpp b/src/core/NEON/kernels/scale/impl/SVE/qasymm8.cpp index fc65ff44f0..c475ad615c 100644 --- a/src/core/NEON/kernels/scale/impl/SVE/qasymm8.cpp +++ b/src/core/NEON/kernels/scale/impl/SVE/qasymm8.cpp @@ -26,7 +26,6 @@ #include "arm_compute/core/Window.h" #include "src/core/NEON/NEMath.h" #include "src/core/NEON/wrapper/wrapper.h" -#include "src/core/common/Validate.h" #include "src/core/helpers/ScaleHelpers.h" #include "src/core/helpers/ScaleHelpers.h" #include "src/core/utils/ScaleUtils.h" diff --git a/src/core/NEON/kernels/scale/impl/SVE/qasymm8_signed.cpp b/src/core/NEON/kernels/scale/impl/SVE/qasymm8_signed.cpp index 676ca94fb0..b39b75abba 100644 --- a/src/core/NEON/kernels/scale/impl/SVE/qasymm8_signed.cpp +++ b/src/core/NEON/kernels/scale/impl/SVE/qasymm8_signed.cpp @@ -26,7 +26,6 @@ #include "arm_compute/core/Window.h" #include "src/core/NEON/NEMath.h" #include "src/core/NEON/wrapper/wrapper.h" -#include "src/core/common/Validate.h" #include "src/core/helpers/ScaleHelpers.h" #include "src/core/helpers/ScaleHelpers.h" #include "src/core/utils/ScaleUtils.h" diff --git a/src/core/cpu/kernels/activation/NEON/fp16.cpp b/src/core/cpu/kernels/activation/NEON/fp16.cpp index 7fe4ab3f63..0ddd43ea0e 100644 --- a/src/core/cpu/kernels/activation/NEON/fp16.cpp +++ b/src/core/cpu/kernels/activation/NEON/fp16.cpp @@ -26,7 +26,6 @@ #include "arm_compute/core/Helpers.h" #include "arm_compute/core/Validate.h" #include "src/core/NEON/wrapper/wrapper.h" -#include "src/core/common/Validate.h" #include <arm_neon.h> #include <cmath> diff --git a/src/core/cpu/kernels/activation/NEON/fp32.cpp b/src/core/cpu/kernels/activation/NEON/fp32.cpp index f1f2753813..244ca5739f 100644 --- a/src/core/cpu/kernels/activation/NEON/fp32.cpp +++ b/src/core/cpu/kernels/activation/NEON/fp32.cpp @@ -26,7 +26,6 @@ #include "arm_compute/core/Window.h" #include "src/core/NEON/NEMath.h" #include "src/core/NEON/wrapper/wrapper.h" -#include "src/core/common/Validate.h" #include <arm_neon.h> #include <cmath> diff --git a/src/core/cpu/kernels/activation/NEON/qasymm8.cpp b/src/core/cpu/kernels/activation/NEON/qasymm8.cpp index 7506a8294f..a1217435b6 100644 --- a/src/core/cpu/kernels/activation/NEON/qasymm8.cpp +++ b/src/core/cpu/kernels/activation/NEON/qasymm8.cpp @@ -27,7 +27,6 @@ #include "src/core/NEON/NEAsymm.h" #include "src/core/NEON/NEMath.h" #include "src/core/NEON/wrapper/wrapper.h" -#include "src/core/common/Validate.h" #include <arm_neon.h> #include <cmath> diff --git a/src/core/cpu/kernels/activation/NEON/qasymm8_signed.cpp b/src/core/cpu/kernels/activation/NEON/qasymm8_signed.cpp index 8f75abea8e..8b40bf8e72 100644 --- a/src/core/cpu/kernels/activation/NEON/qasymm8_signed.cpp +++ b/src/core/cpu/kernels/activation/NEON/qasymm8_signed.cpp @@ -26,7 +26,6 @@ #include "src/core/NEON/NEAsymm.h" #include "src/core/NEON/NEMath.h" #include "src/core/NEON/wrapper/wrapper.h" -#include "src/core/common/Validate.h" #include <arm_neon.h> #include <cmath> diff --git a/src/core/cpu/kernels/activation/NEON/qsymm16.cpp b/src/core/cpu/kernels/activation/NEON/qsymm16.cpp index 9eee360427..54b41820f2 100644 --- a/src/core/cpu/kernels/activation/NEON/qsymm16.cpp +++ b/src/core/cpu/kernels/activation/NEON/qsymm16.cpp @@ -28,7 +28,6 @@ #include "src/core/NEON/NEMath.h" #include "src/core/NEON/NESymm.h" #include "src/core/NEON/wrapper/wrapper.h" -#include "src/core/common/Validate.h" #include <arm_neon.h> #include <cmath> diff --git a/src/core/cpu/kernels/activation/SVE/fp16.cpp b/src/core/cpu/kernels/activation/SVE/fp16.cpp index 8208813cd3..bf31fd7d93 100644 --- a/src/core/cpu/kernels/activation/SVE/fp16.cpp +++ b/src/core/cpu/kernels/activation/SVE/fp16.cpp @@ -24,7 +24,6 @@ #include "arm_compute/core/Helpers.h" #include "arm_compute/core/ITensorPack.h" #include "arm_compute/core/Window.h" -#include "src/core/common/Validate.h" #include <cmath> #include <cstddef> diff --git a/src/core/cpu/kernels/activation/SVE/fp32.cpp b/src/core/cpu/kernels/activation/SVE/fp32.cpp index 55bdc9999e..75f9f8a4c3 100644 --- a/src/core/cpu/kernels/activation/SVE/fp32.cpp +++ b/src/core/cpu/kernels/activation/SVE/fp32.cpp @@ -25,7 +25,6 @@ #include "arm_compute/core/ITensorPack.h" #include "arm_compute/core/Window.h" #include "src/core/NEON/SVEMath.h" -#include "src/core/common/Validate.h" #include <cmath> #include <cstddef> diff --git a/src/core/cpu/kernels/activation/SVE/qasymm8.cpp b/src/core/cpu/kernels/activation/SVE/qasymm8.cpp index 3d9476ac56..228b4ae530 100644 --- a/src/core/cpu/kernels/activation/SVE/qasymm8.cpp +++ b/src/core/cpu/kernels/activation/SVE/qasymm8.cpp @@ -24,7 +24,6 @@ #include "arm_compute/core/Helpers.h" #include "arm_compute/core/Window.h" -#include "src/core/common/Validate.h" #include <cmath> #include <cstddef> diff --git a/src/core/cpu/kernels/activation/SVE/qasymm8_signed.cpp b/src/core/cpu/kernels/activation/SVE/qasymm8_signed.cpp index 0b3d798942..989f825eb9 100644 --- a/src/core/cpu/kernels/activation/SVE/qasymm8_signed.cpp +++ b/src/core/cpu/kernels/activation/SVE/qasymm8_signed.cpp @@ -24,7 +24,6 @@ #include "arm_compute/core/Helpers.h" #include "arm_compute/core/Window.h" #include "src/core/NEON/wrapper/wrapper.h" -#include "src/core/common/Validate.h" #include <cmath> #include <cstddef> diff --git a/src/core/cpu/kernels/activation/SVE/qsymm16.cpp b/src/core/cpu/kernels/activation/SVE/qsymm16.cpp index dbaf267bf9..66974875da 100644 --- a/src/core/cpu/kernels/activation/SVE/qsymm16.cpp +++ b/src/core/cpu/kernels/activation/SVE/qsymm16.cpp @@ -25,7 +25,6 @@ #include "arm_compute/core/ITensorPack.h" #include "arm_compute/core/Window.h" #include "arm_compute/core/experimental/Types.h" -#include "src/core/common/Validate.h" #include <cmath> #include <cstddef> diff --git a/src/core/cpu/kernels/floor/NEON/fp16.cpp b/src/core/cpu/kernels/floor/NEON/fp16.cpp index 0d31eb77f8..f362676a36 100644 --- a/src/core/cpu/kernels/floor/NEON/fp16.cpp +++ b/src/core/cpu/kernels/floor/NEON/fp16.cpp @@ -23,8 +23,8 @@ */ #if defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC) && defined(ENABLE_FP16_KERNELS) +#include "src/common/utils/Validate.h" #include "src/core/NEON/NEMath.h" -#include "src/core/common/Validate.h" #include <arm_neon.h> #include <cmath> diff --git a/src/core/cpu/kernels/floor/NEON/fp32.cpp b/src/core/cpu/kernels/floor/NEON/fp32.cpp index dd63f9f9d7..f5efb2e849 100644 --- a/src/core/cpu/kernels/floor/NEON/fp32.cpp +++ b/src/core/cpu/kernels/floor/NEON/fp32.cpp @@ -21,8 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include "src/common/utils/Validate.h" #include "src/core/NEON/NEMath.h" -#include "src/core/common/Validate.h" #include <arm_neon.h> #include <cmath> diff --git a/src/core/gpu/cl/kernels/ClElementwiseKernel.cpp b/src/core/gpu/cl/kernels/ClElementwiseKernel.cpp index 7d204b1348..8f12eb2215 100644 --- a/src/core/gpu/cl/kernels/ClElementwiseKernel.cpp +++ b/src/core/gpu/cl/kernels/ClElementwiseKernel.cpp @@ -25,8 +25,8 @@ #include "arm_compute/core/CL/CLHelpers.h" #include "arm_compute/core/CL/ICLTensor.h" +#include "src/common/utils/Validate.h" #include "src/core/CL/CLValidate.h" -#include "src/core/common/Validate.h" #include "src/core/helpers/AutoConfiguration.h" #include "src/core/helpers/WindowHelpers.h" #include "support/Cast.h" diff --git a/src/cpu/CpuContext.cpp b/src/cpu/CpuContext.cpp new file mode 100644 index 0000000000..5980a5ab0d --- /dev/null +++ b/src/cpu/CpuContext.cpp @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2021 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 "src/cpu/CpuContext.h" + +#include "arm_compute/core/CPP/CPPTypes.h" +#include "src/runtime/CPUUtils.h" + +#include <cstdlib> + +namespace arm_compute +{ +namespace cpu +{ +namespace +{ +void *default_allocate(void *user_data, size_t size) +{ + ARM_COMPUTE_UNUSED(user_data); + return ::operator new(size); +} +void default_free(void *user_data, void *ptr) +{ + ARM_COMPUTE_UNUSED(user_data); + ::operator delete(ptr); +} +void *default_aligned_allocate(void *user_data, size_t size, size_t alignment) +{ + ARM_COMPUTE_UNUSED(user_data); + void *ptr = nullptr; +#if defined(BARE_METAL) || defined(__APPLE__) + size_t rem = size % alignment; + size_t real_size = (rem) ? (size + alignment - rem) : size; + ptr = aligned_alloc(alignment, real_size); +#else /* defined(BARE_METAL) || defined(__APPLE__) */ + posix_memalign(&ptr, alignment, size); +#endif /* defined(BARE_METAL) || defined(__APPLE__) */ + return ptr; +} +void default_aligned_free(void *user_data, void *ptr) +{ + ARM_COMPUTE_UNUSED(user_data); + free(ptr); +} +static AclAllocator default_allocator = { &default_allocate, + &default_free, + &default_aligned_allocate, + &default_aligned_free, + nullptr + }; + +AllocatorWrapper populate_allocator(AclAllocator *external_allocator) +{ + bool is_valid = (external_allocator != nullptr); + if(is_valid) + { + is_valid = is_valid && (external_allocator->alloc != nullptr); + is_valid = is_valid && (external_allocator->free != nullptr); + is_valid = is_valid && (external_allocator->aligned_alloc != nullptr); + is_valid = is_valid && (external_allocator->aligned_free != nullptr); + } + return is_valid ? AllocatorWrapper(*external_allocator) : AllocatorWrapper(default_allocator); +} + +CpuCapabilities populate_capabilities_legacy(const CPUInfo &cpu_info) +{ + CpuCapabilities caps; + + // Extract SIMD extension + caps.neon = true; +#ifdef SVE2 + caps.sve2 = true; +#endif /* SVE2 */ + // Extract data-type support + caps.fp16 = cpu_info.has_fp16(); +#ifdef V8P6_BF + caps.bf16 = true; +#endif /* V8P6_BF */ + + // Extract ISA extensions + caps.dot = cpu_info.has_dotprod(); +#ifdef MMLA_FP32 + caps.mmla_fp = true; +#endif /* MMLA_FP32 */ +#ifdef MMLA_INT8 + caps.mmla_int8 = true; +#endif /* MMLA_INT8 */ + + return caps; +} + +CpuCapabilities populate_capabilities_flags(AclTargetCapabilities external_caps) +{ + CpuCapabilities caps; + + // Extract SIMD extension + caps.neon = external_caps & AclCpuCapabilitiesNeon; + caps.sve = external_caps & AclCpuCapabilitiesSve; + caps.sve2 = external_caps & AclCpuCapabilitiesSve2; + // Extract data-type support + caps.fp16 = external_caps & AclCpuCapabilitiesFp16; + caps.bf16 = external_caps & AclCpuCapabilitiesBf16; + // Extract ISA extensions + caps.dot = external_caps & AclCpuCapabilitiesDot; + caps.mmla_fp = external_caps & AclCpuCapabilitiesMmlaFp; + caps.mmla_int8 = external_caps & AclCpuCapabilitiesMmlaInt8; + + return caps; +} + +CpuCapabilities populate_capabilities(AclTargetCapabilities external_caps, + int32_t max_threads) +{ + // Extract legacy structure + CPUInfo cpu_info; + arm_compute::utils::cpu::get_cpu_configuration(cpu_info); + + CpuCapabilities caps; + if(external_caps != AclCpuCapabilitiesAuto) + { + caps = populate_capabilities_flags(external_caps); + } + else + { + caps = populate_capabilities_legacy(cpu_info); + } + + // Set max number of threads +#if defined(BARE_METAL) + ARM_COMPUTE_UNUSED(max_threads); + caps.max_threads = 1; +#else /* defined(BARE_METAL) */ + caps.max_threads = (max_threads > 0) ? max_threads : std::thread::hardware_concurrency(); +#endif /* defined(BARE_METAL) */ + + return caps; +} +} // namespace + +CpuContext::CpuContext(const AclContextOptions *options) + : IContext(Target::Cpu), + _allocator(default_allocator), + _caps(populate_capabilities(AclCpuCapabilitiesAuto, -1)) +{ + if(options != nullptr) + { + _allocator = populate_allocator(options->allocator); + _caps = populate_capabilities(options->capabilities, options->max_compute_units); + } +} + +const CpuCapabilities &CpuContext::capabilities() const +{ + return _caps; +} + +AllocatorWrapper &CpuContext::allocator() +{ + return _allocator; +} +} // namespace cpu +} // namespace arm_compute diff --git a/src/cpu/CpuContext.h b/src/cpu/CpuContext.h new file mode 100644 index 0000000000..81bab97b8e --- /dev/null +++ b/src/cpu/CpuContext.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2021 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 SRC_CPU_CPUCONTEXT_H +#define SRC_CPU_CPUCONTEXT_H + +#include "src/common/AllocatorWrapper.h" +#include "src/common/IContext.h" + +namespace arm_compute +{ +namespace cpu +{ +/** Structure that encodes the CPU capabilities to be used */ +struct CpuCapabilities +{ + bool neon{ false }; + bool sve{ false }; + bool sve2{ false }; + + bool fp16{ false }; + bool bf16{ false }; + bool dot{ false }; + bool mmla_int8{ false }; + bool mmla_fp{ false }; + + int32_t max_threads{ -1 }; +}; + +/** CPU context implementation class */ +class CpuContext final : public IContext +{ +public: + /** Default Constructor + * + * @param[in] options Creational options + */ + explicit CpuContext(const AclContextOptions *options); + /** Cpu Capabilities accessor + * + * @return The ISA capabilities to be used by the CPU + */ + const CpuCapabilities &capabilities() const; + /** Backing memory allocator accessor + * + * @return Allocator that allocates CPU memory + */ + AllocatorWrapper &allocator(); + +private: + AllocatorWrapper _allocator; + CpuCapabilities _caps; +}; +} // namespace cpu +} // namespace arm_compute + +#endif /* SRC_CPU_CPUCONTEXT_H */
\ No newline at end of file diff --git a/src/gpu/cl/ClContext.cpp b/src/gpu/cl/ClContext.cpp new file mode 100644 index 0000000000..2bd8b8dd0e --- /dev/null +++ b/src/gpu/cl/ClContext.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2021 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 "src/gpu/cl/ClContext.h" + +namespace arm_compute +{ +namespace gpu +{ +namespace opencl +{ +namespace +{ +mlgo::MLGOHeuristics populate_mlgo(const char *filename) +{ + mlgo::MLGOHeuristics heuristics; + bool status = heuristics.reload_from_file(filename); + return status ? std::move(heuristics) : mlgo::MLGOHeuristics(); +} +} // namespace + +ClContext::ClContext(const AclContextOptions *options) + : IContext(Target::GpuOcl), + _mlgo_heuristics(), + _cl_context() +{ + if(options != nullptr) + { + _mlgo_heuristics = populate_mlgo(options->kernel_config_file); + } +} + +const mlgo::MLGOHeuristics &ClContext::mlgo() const +{ + return _mlgo_heuristics; +} + +::cl::Context ClContext::cl_ctx() +{ + return _cl_context; +} + +bool ClContext::set_cl_ctx(::cl::Context ctx) +{ + if(this->refcount() == 0) + { + _cl_context = ctx; + return true; + } + return false; +} +} // namespace opencl +} // namespace gpu +} // namespace arm_compute diff --git a/src/gpu/cl/ClContext.h b/src/gpu/cl/ClContext.h new file mode 100644 index 0000000000..e3f16b1c3f --- /dev/null +++ b/src/gpu/cl/ClContext.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2021 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 SRC_GPU_CL_CPUCONTEXT_H +#define SRC_GPU_CL_CPUCONTEXT_H + +#include "src/common/IContext.h" +#include "src/runtime/CL/mlgo/MLGOHeuristics.h" + +#include "arm_compute/core/CL/OpenCL.h" + +namespace arm_compute +{ +namespace gpu +{ +namespace opencl +{ +/** OpenCL context implementation class */ +class ClContext final : public IContext +{ +public: + /** Default Constructor + * + * @param[in] options Creational options + */ + explicit ClContext(const AclContextOptions *options); + /** Extract MLGO heuristics + * + * @return Heuristics tree + */ + const mlgo::MLGOHeuristics &mlgo() const; + + /** Underlying cl context accessor + * + * @return the cl context used + */ + ::cl::Context cl_ctx(); + /** Update/inject an underlying cl context object + * + * @warning Context will be able to set if the object doesn't have any pending reference to other objects + * + * @param[in] ctx Underlying cl context to be used + * + * @return true if the context was set successfully else falseS + */ + bool set_cl_ctx(::cl::Context ctx); + +private: + mlgo::MLGOHeuristics _mlgo_heuristics; + ::cl::Context _cl_context; +}; +} // namespace opencl +} // namespace gpu +} // namespace arm_compute + +#endif /* SRC_GPU_CL_CPUCONTEXT_H */
\ No newline at end of file diff --git a/tests/SConscript b/tests/SConscript index 8eebe5f2d8..fea68e0fe9 100644 --- a/tests/SConscript +++ b/tests/SConscript @@ -127,6 +127,7 @@ if env['opencl']: files_validation += Glob('validation/CL/' + filter_pattern) if env['external_tests_dir']: files_validation += Glob(env['external_tests_dir'] + '/tests/validation/CL/' + filter_pattern) + files_validation += Glob('validation/gpu/unit/*.cpp') if env['neon']: filter_pattern = test_env['test_filter'] @@ -144,6 +145,7 @@ if env['neon']: files_validation += Glob('validation/NEON/*/' + filter_pattern) if env['external_tests_dir']: files_validation += Glob(env['external_tests_dir'] + '/tests/validation/NEON/' + filter_pattern) + files_validation += Glob('validation/cpu/unit/*.cpp') extra_link_flags = [] if env['os'] == 'android': diff --git a/tests/validation/CL/UNIT/Extensions.cpp b/tests/validation/CL/UNIT/Extensions.cpp new file mode 100644 index 0000000000..8119290d4b --- /dev/null +++ b/tests/validation/CL/UNIT/Extensions.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 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 "arm_compute/AclVersion.h" +#include "tests/framework/Asserts.h" +#include "tests/framework/Macros.h" +#include "tests/validation/Validation.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +TEST_SUITE(CL) +TEST_SUITE(UNIT) +TEST_CASE(GetClContext, framework::DatasetMode::ALL) +{ + const auto ver = AclVersionInfo(); + ARM_COMPUTE_EXPECT(ver->major == ARM_COMPUTE_LIBRARY_VERSION_MAJOR, framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(ver->minor == ARM_COMPUTE_LIBRARY_VERSION_MINOR, framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(ver->patch == ARM_COMPUTE_LIBRARY_VERSION_PATCH, framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(!std::string(ver->build_info).empty(), framework::LogLevel::ERRORS); +} +TEST_SUITE_END() // UNIT +TEST_SUITE_END() // CL +} // namespace validation +} // namespace test +} // namespace arm_compute diff --git a/tests/validation/UNIT/Version.cpp b/tests/validation/UNIT/Version.cpp new file mode 100644 index 0000000000..72e2d48113 --- /dev/null +++ b/tests/validation/UNIT/Version.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 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 "arm_compute/AclVersion.h" +#include "tests/framework/Asserts.h" +#include "tests/framework/Macros.h" +#include "tests/validation/Validation.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +TEST_SUITE(UNIT) +TEST_CASE(Version, framework::DatasetMode::ALL) +{ + const auto ver = AclVersionInfo(); + ARM_COMPUTE_EXPECT(ver->major == ARM_COMPUTE_LIBRARY_VERSION_MAJOR, framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(ver->minor == ARM_COMPUTE_LIBRARY_VERSION_MINOR, framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(ver->patch == ARM_COMPUTE_LIBRARY_VERSION_PATCH, framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(!std::string(ver->build_info).empty(), framework::LogLevel::ERRORS); +} +TEST_SUITE_END() // UNIT +} // namespace validation +} // namespace test +} // namespace arm_compute diff --git a/tests/validation/cpu/unit/Context.cpp b/tests/validation/cpu/unit/Context.cpp new file mode 100644 index 0000000000..bf2a02df5d --- /dev/null +++ b/tests/validation/cpu/unit/Context.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2021 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 "tests/framework/Asserts.h" +#include "tests/framework/Macros.h" +#include "tests/validation/Validation.h" + +#include "arm_compute/Acl.hpp" + +#include "src/cpu/CpuContext.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +TEST_SUITE(CPU) +TEST_SUITE(UNIT) +TEST_SUITE(Context) + +/** Test-case for AclCreateContext + * + * Validate that AclCreateContext behaves as expected on invalid target + * + * Test Steps: + * - Call AclCreateContext with invalid target + * - Confirm that AclUnsupportedTarget is reported + * - Confirm that context is still nullptr + */ +TEST_CASE(CreateContextWithInvalidTarget, framework::DatasetMode::ALL) +{ + AclTarget invalid_target = static_cast<AclTarget>(-1); + AclContext ctx = nullptr; + ARM_COMPUTE_ASSERT(AclCreateContext(&ctx, invalid_target, nullptr) == AclStatus::AclUnsupportedTarget); + ARM_COMPUTE_ASSERT(ctx == nullptr); +} + +/** Test-case for AclCreateContext + * + * Validate that AclCreateContext behaves as expected on invalid context options + * + * Test Steps: + * - Call AclCreateContext with valid target but invalid context options + * - Confirm that AclInvalidArgument is reported + * - Confirm that context is still nullptr + */ +TEST_CASE(CreateContextWithInvalidOptions, framework::DatasetMode::ALL) +{ + AclContextOptions invalid_ctx_opts; + invalid_ctx_opts.mode = static_cast<AclExecutionMode>(-1); + invalid_ctx_opts.capabilities = AclCpuCapabilitiesAuto; + invalid_ctx_opts.max_compute_units = 0; + invalid_ctx_opts.enable_fast_math = false; + invalid_ctx_opts.kernel_config_file = ""; + AclContext ctx = nullptr; + ARM_COMPUTE_ASSERT(AclCreateContext(&ctx, AclCpu, &invalid_ctx_opts) == AclStatus::AclInvalidArgument); + ARM_COMPUTE_ASSERT(ctx == nullptr); +} + +/** Test-case for AclDestroyContext + * + * Validate that AclDestroyContext behaves as expected when invalid inputs as context are given + * + * Test Steps: + * - Call AclDestroyContext with null context + * - Confirm that AclInvalidArgument is reported + * - Call AclDestroyContext on empty array + * - Confirm that AclInvalidArgument is reported + * - Call AclDestroyContext on an ACL object other than AclContext + * - Confirm that AclInvalidArgument is reported + * - Confirm that context is still nullptr + */ +TEST_CASE(DestroyInvalidContext, framework::DatasetMode::ALL) +{ + AclContext ctx = nullptr; + std::array<char, 256> empty_array{}; + AclContext valid_ctx = nullptr; + ARM_COMPUTE_ASSERT(AclCreateContext(&valid_ctx, AclCpu, nullptr) == AclStatus::AclSuccess); + ARM_COMPUTE_ASSERT(AclDestroyContext(ctx) == AclStatus::AclInvalidArgument); + ARM_COMPUTE_ASSERT(AclDestroyContext(reinterpret_cast<AclContext>(empty_array.data())) == AclStatus::AclInvalidArgument); + ARM_COMPUTE_ASSERT(ctx == nullptr); + ARM_COMPUTE_ASSERT(AclDestroyContext(valid_ctx) == AclStatus::AclSuccess); +} + +/** Test-case for AclCreateContext and AclDestroy Context + * + * Validate that AclCreateContext can create and destroy a context + * + * Test Steps: + * - Call AclCreateContext with valid target + * - Confirm that context is not nullptr and error code is AclSuccess + * - Destroy context + * - Confirm that AclSuccess is reported + */ +TEST_CASE(SimpleContextCApi, framework::DatasetMode::ALL) +{ + AclContext ctx = nullptr; + ARM_COMPUTE_ASSERT(AclCreateContext(&ctx, AclCpu, nullptr) == AclStatus::AclSuccess); + ARM_COMPUTE_ASSERT(ctx != nullptr); + ARM_COMPUTE_ASSERT(AclDestroyContext(ctx) == AclStatus::AclSuccess); +} + +/** Test-case for Context from the C++ interface + * + * Test Steps: + * - Create a Context obejct + * - Confirm that StatusCode::Success is reported + * - Confirm that equality operator works + * - Confirm that inequality operator works + */ +TEST_CASE(SimpleContextCppApi, framework::DatasetMode::ALL) +{ + acl::StatusCode status = acl::StatusCode::Success; + acl::Context ctx(acl::Target::Cpu, &status); + ARM_COMPUTE_ASSERT(status == acl::StatusCode::Success); + + auto ctx_eq = ctx; + ARM_COMPUTE_ASSERT(ctx_eq == ctx); + + acl::Context ctx_ienq(acl::Target::Cpu, &status); + ARM_COMPUTE_ASSERT(status == acl::StatusCode::Success); + ARM_COMPUTE_ASSERT(ctx_ienq != ctx); +} + +/** Test-case for CpuCapabilities + * + * Validate that AclCreateContext can create/destroy multiple contexts with different options + * + * Test Steps: + * - Call AclCreateContext with different targets + * - Confirm that AclSuccess is reported + * - Destroy all contexts + * - Confirm that AclSuccess is reported + */ +TEST_CASE(MultipleContexts, framework::DatasetMode::ALL) +{ + const unsigned int num_tests = 5; + std::array<AclContext, num_tests> ctxs{}; + for(unsigned int i = 0; i < num_tests; ++i) + { + ARM_COMPUTE_ASSERT(AclCreateContext(&ctxs[i], AclTarget::AclCpu, nullptr) == AclStatus::AclSuccess); + ARM_COMPUTE_ASSERT(ctxs[i] != nullptr); + ARM_COMPUTE_ASSERT(AclDestroyContext(ctxs[i]) == AclStatus::AclSuccess); + } +} + +/** Test-case for CpuCapabilities + * + * Validate that CpuCapabilities are set correctly + * + * Test Steps: + * - Create a context with a given list of capabilities + * - Confirm that AclSuccess is reported + * - Validate that all capabilities are set correctly + */ +TEST_CASE(CpuCapabilities, framework::DatasetMode::ALL) +{ + AclContextOptions opts = acl_default_ctx_options; + opts.capabilities = AclCpuCapabilitiesDot | AclCpuCapabilitiesMmlaInt8 | AclCpuCapabilitiesSve2; + arm_compute::cpu::CpuContext ctx(&opts); + + ARM_COMPUTE_ASSERT(ctx.capabilities().dot == true); + ARM_COMPUTE_ASSERT(ctx.capabilities().mmla_int8 == true); + ARM_COMPUTE_ASSERT(ctx.capabilities().sve2 == true); + ARM_COMPUTE_ASSERT(ctx.capabilities().fp16 == false); + + arm_compute::cpu::CpuContext ctx_legacy(nullptr); + ARM_COMPUTE_ASSERT(ctx_legacy.capabilities().neon == true); +} + +TEST_SUITE_END() // Context +TEST_SUITE_END() // UNIT +TEST_SUITE_END() // CPU +} // namespace validation +} // namespace test +} // namespace arm_compute diff --git a/tests/validation/gpu/unit/Context.cpp b/tests/validation/gpu/unit/Context.cpp new file mode 100644 index 0000000000..06b4a83925 --- /dev/null +++ b/tests/validation/gpu/unit/Context.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2021 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 "tests/framework/Asserts.h" +#include "tests/framework/Macros.h" +#include "tests/validation/Validation.h" + +#include "arm_compute/Acl.hpp" + +#include "src/gpu/cl/ClContext.h" + +using namespace arm_compute::mlgo; + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +TEST_SUITE(CL) +TEST_SUITE(UNIT) +TEST_SUITE(Context) + +/** Test-case for AclCreateContext and AclDestroy Context + * + * Validate that AclCreateContext can create and destroy a context + * + * Test Steps: + * - Call AclCreateContext with valid target + * - Confirm that context is not nullptr and error code is AclSuccess + * - Destroy context + * - Confirm that AclSuccess is reported + */ +TEST_CASE(SimpleContextCApi, framework::DatasetMode::ALL) +{ + AclContext ctx = nullptr; + ARM_COMPUTE_ASSERT(AclCreateContext(&ctx, AclGpuOcl, nullptr) == AclStatus::AclSuccess); + ARM_COMPUTE_ASSERT(ctx != nullptr); + ARM_COMPUTE_ASSERT(AclDestroyContext(ctx) == AclStatus::AclSuccess); +} + +/** Test-case for Context from the C++ interface + * + * Test Steps: + * - Create a Context obejct + * - Confirm that StatusCode::Success is reported + * - Confirm that equality operator works + * - Confirm that inequality operator works + */ +TEST_CASE(SimpleContextCppApi, framework::DatasetMode::ALL) +{ + acl::StatusCode status = acl::StatusCode::Success; + acl::Context ctx(acl::Target::GpuOcl, &status); + ARM_COMPUTE_ASSERT(status == acl::StatusCode::Success); + + auto ctx_eq = ctx; + ARM_COMPUTE_ASSERT(ctx_eq == ctx); + + acl::Context ctx_ienq(acl::Target::GpuOcl, &status); + ARM_COMPUTE_ASSERT(status == acl::StatusCode::Success); + ARM_COMPUTE_ASSERT(ctx_ienq != ctx); +} + +/** Test-case for CpuCapabilities + * + * Validate that AclCreateContext can create/destroy multiple contexts with different options + * + * Test Steps: + * - Call AclCreateContext with different targets + * - Confirm that AclSuccess is reported + * - Destroy all contexts + * - Confirm that AclSuccess is reported + */ +TEST_CASE(MultipleContexts, framework::DatasetMode::ALL) +{ + const unsigned int num_tests = 5; + std::array<AclContext, num_tests> ctxs{}; + for(unsigned int i = 0; i < num_tests; ++i) + { + ARM_COMPUTE_ASSERT(AclCreateContext(&ctxs[i], AclTarget::AclGpuOcl, nullptr) == AclStatus::AclSuccess); + ARM_COMPUTE_ASSERT(ctxs[i] != nullptr); + ARM_COMPUTE_ASSERT(AclDestroyContext(ctxs[i]) == AclStatus::AclSuccess); + } +} + +/** Test-case for MLGO kernel configuration file + * + * Validate that CpuCapabilities are set correctly + * + * Test Steps: + * - Create a file with the MLGO configuration + * - Pass the kernel file to the Context during creation + * - Validate that the MLGO file has been parsed successfully + */ +TEST_CASE(CheckMLGO, framework::DatasetMode::ALL) +{ + // Create test mlgo file + std::string mlgo_str = R"_( + + <header> + + gemm-version, [1,2,1] + ip-type,gpu + </header> + <heuristics-table> + 0, g76 , 8, f32, best-performance, static, gemm-type, [m,n,k,n] + 1, g76 , 8, f16, best-performance, static, gemm-config-reshaped, [m,n,k,n] + </heuristics-table> + <heuristic, 0> + b , 0, var, m, ==, num, 10., 1, 2 + l , 1, gemm-type, reshaped + b , 2, var, r_mn, >=, num, 2., 3, 6 + + b , 3, var, n, >=, num, 200., 4, 5 + l, 4, gemm-type, reshaped-only-rhs + l , 5, gemm-type, reshaped + l , 6, gemm-type, reshaped-only-rhs + </heuristic> + + <heuristic, 1> + l ,0,gemm-config-reshaped,[4,2,4,2,8,1,0,1,0] + </heuristic> + + )_"; + const std::string mlgo_filename = "test.mlgo"; + std::ofstream ofs(mlgo_filename, std::ofstream::trunc); + ARM_COMPUTE_EXPECT(ofs, framework::LogLevel::ERRORS); + ofs << mlgo_str; + ofs.close(); + + AclContextOptions opts = acl_default_ctx_options; + opts.kernel_config_file = mlgo_filename.c_str(); + arm_compute::gpu::opencl::ClContext ctx(&opts); + + const MLGOHeuristics &heuristics = ctx.mlgo(); + + ARM_COMPUTE_EXPECT(heuristics.query_gemm_type(Query{ "g76", DataType::F32, 10, 1024, 20, 1 }).second == GEMMType::RESHAPED, + framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT((heuristics.query_gemm_config_reshaped(Query{ "g76", DataType::F16, 100, 100, 20, 32 }).second == GEMMConfigReshaped{ 4, 2, 4, 2, 8, true, false, true, false }), + framework::LogLevel::ERRORS); +} + +TEST_SUITE_END() // Context +TEST_SUITE_END() // UNIT +TEST_SUITE_END() // CL +} // namespace validation +} // namespace test +} // namespace arm_compute |