diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/AllocatorWrapper.cpp | 66 | ||||
-rw-r--r-- | src/common/AllocatorWrapper.h | 81 | ||||
-rw-r--r-- | src/common/IContext.h | 151 | ||||
-rw-r--r-- | src/common/IOperator.cpp | 73 | ||||
-rw-r--r-- | src/common/IOperator.h | 137 | ||||
-rw-r--r-- | src/common/IQueue.h | 100 | ||||
-rw-r--r-- | src/common/ITensorV2.cpp | 41 | ||||
-rw-r--r-- | src/common/ITensorV2.h | 139 | ||||
-rw-r--r-- | src/common/TensorPack.cpp | 74 | ||||
-rw-r--r-- | src/common/TensorPack.h | 131 | ||||
-rw-r--r-- | src/common/Types.h | 62 | ||||
-rw-r--r-- | src/common/cpuinfo/CpuInfo.cpp | 561 | ||||
-rw-r--r-- | src/common/cpuinfo/CpuInfo.h | 140 | ||||
-rw-r--r-- | src/common/cpuinfo/CpuIsaInfo.cpp | 167 | ||||
-rw-r--r-- | src/common/cpuinfo/CpuIsaInfo.h | 84 | ||||
-rw-r--r-- | src/common/cpuinfo/CpuModel.cpp | 203 | ||||
-rw-r--r-- | src/common/cpuinfo/CpuModel.h | 71 | ||||
-rw-r--r-- | src/common/utils/LegacySupport.cpp | 162 | ||||
-rw-r--r-- | src/common/utils/LegacySupport.h | 60 | ||||
-rw-r--r-- | src/common/utils/Log.h | 233 | ||||
-rw-r--r-- | src/common/utils/Macros.h | 37 | ||||
-rw-r--r-- | src/common/utils/Object.h | 64 | ||||
-rw-r--r-- | src/common/utils/Utils.h | 82 | ||||
-rw-r--r-- | src/common/utils/Validate.h | 41 |
24 files changed, 2960 insertions, 0 deletions
diff --git a/src/common/AllocatorWrapper.cpp b/src/common/AllocatorWrapper.cpp new file mode 100644 index 0000000000..28d81a9fa4 --- /dev/null +++ b/src/common/AllocatorWrapper.cpp @@ -0,0 +1,66 @@ +/* + * 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..bbf70a2cb1 --- /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 */ diff --git a/src/common/IContext.h b/src/common/IContext.h new file mode 100644 index 0000000000..a221e5db61 --- /dev/null +++ b/src/common/IContext.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2021,2023 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> +#include <tuple> + +struct AclContext_ +{ + arm_compute::detail::Header header{arm_compute::detail::ObjectType::Context, nullptr}; + +protected: + AclContext_() = default; + ~AclContext_() = default; +}; + +namespace arm_compute +{ +// Forward declarations +class ITensorV2; +class IQueue; +class IOperator; + +/**< 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; + } + /** Create a tensor object + * + * @param[in] desc Descriptor to use + * @param[in] allocate Flag to allocate tensor + * + * @return A pointer to the created tensor object + */ + virtual ITensorV2 *create_tensor(const AclTensorDescriptor &desc, bool allocate) = 0; + /** Create a queue object + * + * @param[in] options Queue options to be used + * + * @return A pointer to the created queue object + */ + virtual IQueue *create_queue(const AclQueueOptions *options) = 0; + virtual std::tuple<IOperator *, StatusCode> create_activation(const AclTensorDescriptor &src, + const AclTensorDescriptor &dst, + const AclActivationDescriptor &act, + bool is_validate) = 0; + +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/IOperator.cpp b/src/common/IOperator.cpp new file mode 100644 index 0000000000..90e3473814 --- /dev/null +++ b/src/common/IOperator.cpp @@ -0,0 +1,73 @@ +/* + * 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/IOperator.h" + +#include "src/common/utils/Validate.h" + +namespace arm_compute +{ +#ifndef DOXYGEN_SKIP_THIS +IOperator::IOperator(IContext *ctx) : AclOperator_() +{ + ARM_COMPUTE_ASSERT_NOT_NULLPTR(ctx); + this->header.ctx = ctx; + this->header.ctx->inc_ref(); +} + +IOperator::~IOperator() +{ + this->header.ctx->dec_ref(); + this->header.type = detail::ObjectType::Invalid; +} + +bool IOperator::is_valid() const +{ + return this->header.type == detail::ObjectType::Operator; +} + +StatusCode IOperator::run(ITensorPack &tensors) +{ + _op->run(tensors); + return StatusCode::Success; +} + +StatusCode IOperator::run(IQueue &queue, ITensorPack &tensors) +{ + ARM_COMPUTE_UNUSED(queue); + _op->run(tensors); + return StatusCode::Success; +} + +StatusCode IOperator::prepare(ITensorPack &tensors) +{ + _op->prepare(tensors); + return StatusCode::Success; +} + +MemoryRequirements IOperator::workspace() const +{ + return _op->workspace(); +} +#endif /* DOXYGEN_SKIP_THIS */ +} // namespace arm_compute diff --git a/src/common/IOperator.h b/src/common/IOperator.h new file mode 100644 index 0000000000..e86e11fe25 --- /dev/null +++ b/src/common/IOperator.h @@ -0,0 +1,137 @@ +/* + * 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_IOPERATOR_H_ +#define SRC_COMMON_IOPERATOR_H_ + +#include "src/common/IContext.h" +#include "src/common/IQueue.h" + +// TODO: Remove when all functions have been ported +#include "arm_compute/core/experimental/Types.h" +#include "arm_compute/runtime/IOperator.h" + +#include "src/common/utils/Validate.h" + +#include <vector> + +struct AclOperator_ +{ + arm_compute::detail::Header header{arm_compute::detail::ObjectType::Operator, nullptr}; + +protected: + AclOperator_() = default; + ~AclOperator_() = default; +}; + +namespace arm_compute +{ +// Forward declarations +class ITensorPack; +namespace experimental +{ +class IOperator; +} // namespace experimental + +using MemoryRequirements = experimental::MemoryRequirements; + +/** Base class specifying the operator interface */ +class IOperator : public AclOperator_ +{ +public: + /** Explict Operator Constructor + * + * @param[in] ctx Context to be used by the operator + */ + explicit IOperator(IContext *ctx); + /** Destructor */ + virtual ~IOperator(); + /** Checks if an operator is valid + * + * @return True if successful otherwise false + */ + bool is_valid() const; + /** Run the kernels contained in the function + * + * @param[in] queue Queue to use + * @param[in] tensors Vector that contains the tensors to operate on + */ + virtual StatusCode run(IQueue &queue, ITensorPack &tensors); + /** Run the kernels contained in the function + * + * @param[in] tensors Vector that contains the tensors to operate on + */ + virtual StatusCode run(ITensorPack &tensors); + /** Prepare the operator for execution + * + * Any one off pre-processing step required by the function is handled here + * + * @param[in] tensors Vector that contains the preparation tensors. + * + * @note Prepare stage might not need all the function's buffers' backing memory to be available in order to execute + */ + virtual StatusCode prepare(ITensorPack &tensors); + /** Return the memory requirements required by the workspace + */ + virtual MemoryRequirements workspace() const; + + void set_internal_operator(std::unique_ptr<experimental::IOperator> op) + { + _op = std::move(op); + } + +private: + std::unique_ptr<experimental::IOperator> _op{nullptr}; +}; + +/** Extract internal representation of an Operator + * + * @param[in] op Opaque operator pointer + * + * @return The internal representation as an IOperator + */ +inline IOperator *get_internal(AclOperator op) +{ + return static_cast<IOperator *>(op); +} + +namespace detail +{ +/** Check if an internal operator is valid + * + * @param[in] op Internal operator to check + * + * @return A status code + */ +inline StatusCode validate_internal_operator(const IOperator *op) +{ + if (op == nullptr || !op->is_valid()) + { + ARM_COMPUTE_LOG_ERROR_ACL("[IOperator]: Invalid operator object"); + return StatusCode::InvalidArgument; + } + return StatusCode::Success; +} +} // namespace detail +} // namespace arm_compute +#endif /* SRC_COMMON_IOPERATOR_H_ */ diff --git a/src/common/IQueue.h b/src/common/IQueue.h new file mode 100644 index 0000000000..60745d206e --- /dev/null +++ b/src/common/IQueue.h @@ -0,0 +1,100 @@ +/* + * 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_IQUEUE_H_ +#define SRC_COMMON_IQUEUE_H_ + +#include "src/common/IContext.h" + +struct AclQueue_ +{ + arm_compute::detail::Header header{arm_compute::detail::ObjectType::Queue, nullptr}; + +protected: + AclQueue_() = default; + ~AclQueue_() = default; +}; + +namespace arm_compute +{ +/** Base class specifying the queue interface */ +class IQueue : public AclQueue_ +{ +public: + /** Explict Operator Constructor + * + * @param[in] ctx Context to be used by the operator + */ + explicit IQueue(IContext *ctx) + { + this->header.ctx = ctx; + this->header.ctx->inc_ref(); + } + /** Destructor */ + virtual ~IQueue() + { + this->header.ctx->dec_ref(); + this->header.type = detail::ObjectType::Invalid; + }; + /** Checks if a queue is valid + * + * @return True if successful otherwise false + */ + bool is_valid() const + { + return this->header.type == detail::ObjectType::Queue; + }; + virtual StatusCode finish() = 0; +}; + +/** Extract internal representation of a Queue + * + * @param[in] queue Opaque queue pointer + * + * @return The internal representation as an IQueue + */ +inline IQueue *get_internal(AclQueue queue) +{ + return static_cast<IQueue *>(queue); +} + +namespace detail +{ +/** Check if an internal queue is valid + * + * @param[in] queue Internal queue to check + * + * @return A status code + */ +inline StatusCode validate_internal_queue(const IQueue *queue) +{ + if (queue == nullptr || !queue->is_valid()) + { + ARM_COMPUTE_LOG_ERROR_ACL("[IQueue]: Invalid queue object"); + return StatusCode::InvalidArgument; + } + return StatusCode::Success; +} +} // namespace detail +} // namespace arm_compute +#endif /* SRC_COMMON_IQUEUE_H_ */ diff --git a/src/common/ITensorV2.cpp b/src/common/ITensorV2.cpp new file mode 100644 index 0000000000..bf3d963926 --- /dev/null +++ b/src/common/ITensorV2.cpp @@ -0,0 +1,41 @@ +/* + * 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/ITensorV2.h" + +#include "arm_compute/core/TensorInfo.h" + +#include "src/common/utils/LegacySupport.h" + +namespace arm_compute +{ +size_t ITensorV2::get_size() const +{ + return tensor()->info()->total_size(); +} + +AclTensorDescriptor ITensorV2::get_descriptor() const +{ + return detail::convert_to_descriptor(*tensor()->info()); +} +} // namespace arm_compute diff --git a/src/common/ITensorV2.h b/src/common/ITensorV2.h new file mode 100644 index 0000000000..903bfad66a --- /dev/null +++ b/src/common/ITensorV2.h @@ -0,0 +1,139 @@ +/* + * 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_ITENSOR_H_ +#define SRC_COMMON_ITENSOR_H_ + +#include "src/common/IContext.h" +#include "src/common/utils/Validate.h" + +struct AclTensor_ +{ + arm_compute::detail::Header header{arm_compute::detail::ObjectType::Tensor, nullptr}; + +protected: + AclTensor_() = default; + ~AclTensor_() = default; +}; + +namespace arm_compute +{ +// Forward declaration +class ITensor; + +/** Base class specifying the tensor interface */ +class ITensorV2 : public AclTensor_ +{ +public: + /** Explict Operator Constructor + * + * @param[in] ctx Context to be used by the operator + */ + explicit ITensorV2(IContext *ctx) : AclTensor_() + { + ARM_COMPUTE_ASSERT_NOT_NULLPTR(ctx); + this->header.ctx = ctx; + this->header.ctx->inc_ref(); + } + /** Destructor */ + virtual ~ITensorV2() + { + this->header.ctx->dec_ref(); + this->header.type = detail::ObjectType::Invalid; + }; + /** Checks if a queue is valid + * + * @return True if successful otherwise false + */ + bool is_valid() const + { + return this->header.type == detail::ObjectType::Tensor; + }; + /** Map tensor to a host pointer + * + * @return A pointer to the underlying backing memory if successful else nullptr + */ + virtual void *map() = 0; + /** Unmap tensor + * + * @return AclStatus A status cod + */ + virtual StatusCode unmap() = 0; + /** Import external memory handle + * + * @param[in] handle Memory to import + * @param[in] type Type of imported memory + * + * @return Status code + */ + virtual StatusCode import(void *handle, ImportMemoryType type) = 0; + /** Get the legacy tensor object + * + * @return The legacy underlying tensor object + */ + virtual arm_compute::ITensor *tensor() const = 0; + /** Get the size of the tensor in byte + * + * @note The size isn't based on allocated memory, but based on information in its descriptor (dimensions, data type, etc.). + * + * @return The size of the tensor in byte + */ + size_t get_size() const; + /** Get the descriptor of this tensor + * + * @return The descriptor describing the characteristics of this tensor + */ + AclTensorDescriptor get_descriptor() const; +}; + +/** Extract internal representation of a Tensor + * + * @param[in] tensor Opaque tensor pointer + * + * @return The internal representation as an ITensor + */ +inline ITensorV2 *get_internal(AclTensor tensor) +{ + return static_cast<ITensorV2 *>(tensor); +} + +namespace detail +{ +/** Check if an internal tensor is valid + * + * @param[in] tensor Internal tensor to check + * + * @return A status code + */ +inline StatusCode validate_internal_tensor(const ITensorV2 *tensor) +{ + if (tensor == nullptr || !tensor->is_valid()) + { + ARM_COMPUTE_LOG_ERROR_ACL("[ITensorV2]: Invalid tensor object"); + return StatusCode::InvalidArgument; + } + return StatusCode::Success; +} +} // namespace detail +} // namespace arm_compute +#endif /* SRC_COMMON_ITENSOR_H_ */ diff --git a/src/common/TensorPack.cpp b/src/common/TensorPack.cpp new file mode 100644 index 0000000000..b51fc0bdd8 --- /dev/null +++ b/src/common/TensorPack.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/common/TensorPack.h" + +#include "src/common/ITensorV2.h" +#include "src/common/utils/Validate.h" + +namespace arm_compute +{ +TensorPack::TensorPack(IContext *ctx) : AclTensorPack_(), _pack() +{ + ARM_COMPUTE_ASSERT_NOT_NULLPTR(ctx); + this->header.ctx = ctx; + this->header.ctx->inc_ref(); +} + +TensorPack::~TensorPack() +{ + this->header.ctx->dec_ref(); + this->header.type = detail::ObjectType::Invalid; +} + +AclStatus TensorPack::add_tensor(ITensorV2 *tensor, int32_t slot_id) +{ + _pack.add_tensor(slot_id, tensor->tensor()); + return AclStatus::AclSuccess; +} + +size_t TensorPack::size() const +{ + return _pack.size(); +} + +bool TensorPack::empty() const +{ + return _pack.empty(); +} + +bool TensorPack::is_valid() const +{ + return this->header.type == detail::ObjectType::TensorPack; +} + +arm_compute::ITensor *TensorPack::get_tensor(int32_t slot_id) +{ + return _pack.get_tensor(slot_id); +} + +arm_compute::ITensorPack &TensorPack::get_tensor_pack() +{ + return _pack; +} +} // namespace arm_compute diff --git a/src/common/TensorPack.h b/src/common/TensorPack.h new file mode 100644 index 0000000000..b3d1624dae --- /dev/null +++ b/src/common/TensorPack.h @@ -0,0 +1,131 @@ +/* + * 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_ITENSORPACK_H_ +#define SRC_COMMON_ITENSORPACK_H_ + +#include "arm_compute/core/ITensorPack.h" + +#include "src/common/IContext.h" + +struct AclTensorPack_ +{ + arm_compute::detail::Header header{arm_compute::detail::ObjectType::TensorPack, nullptr}; + +protected: + AclTensorPack_() = default; + ~AclTensorPack_() = default; +}; + +namespace arm_compute +{ +// Forward declaration +class ITensor; +class ITensorV2; + +/** Tensor packing service + * + * Class is responsible for creating and managing a collection of tensors. + * Tensor packs can be passed to operators to be part of the mutable data of the execution. + */ +class TensorPack : public AclTensorPack_ +{ +public: + /** Constructor + * + * @param[in] ctx Context to be used + */ + explicit TensorPack(IContext *ctx); + /** Destructor */ + ~TensorPack(); + /** Add tensor to the pack + * + * @param[in] tensor Tensor to add + * @param[in] slot_id Slot identification in respect to the operator of the tensor to add + * + * @return Status code + */ + AclStatus add_tensor(ITensorV2 *tensor, int32_t slot_id); + /** Pack size accessor + * + * @return Number of tensors registered to the pack + */ + size_t size() const; + /** Checks if pack is empty + * + * @return True if empty else false + */ + bool empty() const; + /** Checks if an object is valid + * + * @return True if valid else false + */ + bool is_valid() const; + /** Get tensor of a given id from the pac + * + * @param[in] slot_id Slot identification of tensor to extract + * + * @return The pointer to the tensor if exist and is non-const else nullptr + */ + arm_compute::ITensor *get_tensor(int32_t slot_id); + /** Get legacy tensor pack + * + * @return Legacy tensor pack + */ + arm_compute::ITensorPack &get_tensor_pack(); + +private: + arm_compute::ITensorPack _pack; /**< Pack that currently redirects to the existing TensorPack */ +}; + +/** Extract internal representation of a TensoPack + * + * @param[in] pack Opaque tensor pack pointer + * + * @return The internal representation as an TensorPack + */ +inline TensorPack *get_internal(AclTensorPack pack) +{ + return static_cast<TensorPack *>(pack); +} + +namespace detail +{ +/** Check if an internal TensorPack is valid + * + * @param[in] pack Internal tensor pack to check + * + * @return A status code + */ +inline StatusCode validate_internal_pack(const TensorPack *pack) +{ + if (pack == nullptr || !pack->is_valid()) + { + ARM_COMPUTE_LOG_ERROR_ACL("[TensorPack]: Invalid tensor pack object"); + return StatusCode::InvalidArgument; + } + return StatusCode::Success; +} +} // namespace detail +} // namespace arm_compute +#endif /* SRC_COMMON_ITENSORPACK_H_ */ diff --git a/src/common/Types.h b/src/common/Types.h new file mode 100644 index 0000000000..25ee32353a --- /dev/null +++ b/src/common/Types.h @@ -0,0 +1,62 @@ +/* + * 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/AclDescriptors.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, +}; + +enum class ImportMemoryType +{ + HostPtr = AclImportMemoryType::AclHostPtr +}; +} // namespace arm_compute +#endif /* SRC_COMMON_TYPES_H_ */ diff --git a/src/common/cpuinfo/CpuInfo.cpp b/src/common/cpuinfo/CpuInfo.cpp new file mode 100644 index 0000000000..92ba5223c9 --- /dev/null +++ b/src/common/cpuinfo/CpuInfo.cpp @@ -0,0 +1,561 @@ +/* + * Copyright (c) 2021-2024 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/cpuinfo/CpuInfo.h" + +#include "arm_compute/core/Error.h" +#include "arm_compute/core/Log.h" + +#include "support/StringSupport.h" +#include "support/ToolchainSupport.h" + +#include <map> +#include <sstream> + +#if !defined(BARE_METAL) +#include <algorithm> +#include <cstring> +#include <fstream> +#if !defined(_WIN64) +#include <regex.h> /* C++ std::regex takes up a lot of space in the standalone builds */ +#include <sched.h> +#endif /* !defined(_WIN64) */ + +#include <thread> +#include <unordered_map> +#endif /* !defined(BARE_METAL) */ + +#if !defined(_WIN64) +#if !defined(BARE_METAL) && !defined(__APPLE__) && !defined(__OpenBSD__) && (defined(__arm__) || defined(__aarch64__)) +#include <asm/hwcap.h> /* Get HWCAP bits from asm/hwcap.h */ +#include <sys/auxv.h> +#elif defined(__APPLE__) && defined(__aarch64__) +#include <sys/sysctl.h> +#include <sys/types.h> +#endif /* defined(__APPLE__) && defined(__aarch64__)) */ +#endif /* !defined(BARE_METAL) && !defined(__APPLE__) && !defined(__OpenBSD__) && (defined(__arm__) || defined(__aarch64__)) */ + +#define ARM_COMPUTE_CPU_FEATURE_HWCAP_CPUID (1 << 11) +#define ARM_COMPUTE_GET_FEATURE_REG(var, freg) __asm __volatile("MRS %0, " #freg : "=r"(var)) +namespace arm_compute +{ +namespace cpuinfo +{ +namespace +{ +#if !defined(_WIN64) && !defined(BARE_METAL) && !defined(__APPLE__) && !defined(__OpenBSD__) && \ + (defined(__arm__) || defined(__aarch64__)) +/** Extract MIDR using CPUID information that are exposed to user-space + * + * @param[in] max_num_cpus Maximum number of possible CPUs + * + * @return std::vector<uint32_t> A list of the MIDR of each core + */ +std::vector<uint32_t> midr_from_cpuid(uint32_t max_num_cpus) +{ + std::vector<uint32_t> cpus; + for (unsigned int i = 0; i < max_num_cpus; ++i) + { + std::stringstream str; + str << "/sys/devices/system/cpu/cpu" << i << "/regs/identification/midr_el1"; + std::ifstream file(str.str(), std::ios::in); + if (file.is_open()) + { + std::string line; + if (bool(getline(file, line))) + { + cpus.emplace_back(support::cpp11::stoul(line, nullptr, support::cpp11::NumericBase::BASE_16)); + } + } + } + return cpus; +} + +/** Extract MIDR by parsing the /proc/cpuinfo meta-data + * + * @param[in] max_num_cpus Maximum number of possible CPUs + * + * @return std::vector<uint32_t> A list of the MIDR of each core + */ +std::vector<uint32_t> midr_from_proc_cpuinfo(int max_num_cpus) +{ + std::vector<uint32_t> cpus; + + regex_t proc_regex; + regex_t imp_regex; + regex_t var_regex; + regex_t part_regex; + regex_t rev_regex; + + memset(&proc_regex, 0, sizeof(regex_t)); + memset(&imp_regex, 0, sizeof(regex_t)); + memset(&var_regex, 0, sizeof(regex_t)); + memset(&part_regex, 0, sizeof(regex_t)); + memset(&rev_regex, 0, sizeof(regex_t)); + + int ret_status = 0; + // If "long-form" cpuinfo is present, parse that to populate models. + ret_status |= regcomp(&proc_regex, R"(^processor.*([[:digit:]]+)$)", REG_EXTENDED); + ret_status |= regcomp(&imp_regex, R"(^CPU implementer.*0x(..)$)", REG_EXTENDED); + ret_status |= regcomp(&var_regex, R"(^CPU variant.*0x(.)$)", REG_EXTENDED); + ret_status |= regcomp(&part_regex, R"(^CPU part.*0x(...)$)", REG_EXTENDED); + ret_status |= regcomp(&rev_regex, R"(^CPU revision.*([[:digit:]]+)$)", REG_EXTENDED); + ARM_COMPUTE_UNUSED(ret_status); + ARM_COMPUTE_ERROR_ON_MSG(ret_status != 0, "Regex compilation failed."); + + std::ifstream file("/proc/cpuinfo", std::ios::in); + if (file.is_open()) + { + std::string line; + int midr = 0; + int curcpu = -1; + + while (bool(getline(file, line))) + { + std::array<regmatch_t, 2> match; + ret_status = regexec(&proc_regex, line.c_str(), 2, match.data(), 0); + if (ret_status == 0) + { + std::string id = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); + int newcpu = support::cpp11::stoi(id, nullptr); + + if (curcpu >= 0 && midr == 0) + { + // Matched a new CPU ID without any description of the previous one - looks like old format. + return {}; + } + + if (curcpu >= 0 && curcpu < max_num_cpus) + { + cpus.emplace_back(midr); + } + else + { + ARM_COMPUTE_LOG_INFO_MSG_CORE( + "Trying to populate a core id with id greater than the expected number of cores!"); + } + + midr = 0; + curcpu = newcpu; + + continue; + } + + ret_status = regexec(&imp_regex, line.c_str(), 2, match.data(), 0); + if (ret_status == 0) + { + std::string subexp = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); + int impv = support::cpp11::stoi(subexp, nullptr, support::cpp11::NumericBase::BASE_16); + midr |= (impv << 24); + + continue; + } + + ret_status = regexec(&var_regex, line.c_str(), 2, match.data(), 0); + if (ret_status == 0) + { + std::string subexp = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); + int varv = support::cpp11::stoi(subexp, nullptr, support::cpp11::NumericBase::BASE_16); + midr |= (varv << 20); + + continue; + } + + ret_status = regexec(&part_regex, line.c_str(), 2, match.data(), 0); + if (ret_status == 0) + { + std::string subexp = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); + int partv = support::cpp11::stoi(subexp, nullptr, support::cpp11::NumericBase::BASE_16); + midr |= (partv << 4); + + continue; + } + + ret_status = regexec(&rev_regex, line.c_str(), 2, match.data(), 0); + if (ret_status == 0) + { + std::string subexp = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); + int regv = support::cpp11::stoi(subexp, nullptr); + midr |= (regv); + midr |= (0xf << 16); + + continue; + } + } + + if (curcpu >= 0 && curcpu < max_num_cpus) + { + cpus.emplace_back(midr); + } + else + { + ARM_COMPUTE_LOG_INFO_MSG_CORE( + "Trying to populate a core id with id greater than the expected number of cores!"); + } + } + + // Free allocated memory + regfree(&proc_regex); + regfree(&imp_regex); + regfree(&var_regex); + regfree(&part_regex); + regfree(&rev_regex); + + return cpus; +} + +/** Get the maximim number of CPUs in the system by parsing /sys/devices/system/cpu/present + * + * @return int Maximum number of CPUs + */ +int get_max_cpus() +{ + int max_cpus = 1; + std::ifstream CPUspresent; + CPUspresent.open("/sys/devices/system/cpu/present", std::ios::in); + bool success = false; + + if (CPUspresent.is_open()) + { + std::string line; + + if (bool(getline(CPUspresent, line))) + { + /* The content of this file is a list of ranges or single values, e.g. + * 0-5, or 1-3,5,7 or similar. As we are interested in the + * max valid ID, we just need to find the last valid + * delimiter ('-' or ',') and parse the integer immediately after that. + */ + auto startfrom = line.begin(); + + for (auto i = line.begin(); i < line.end(); ++i) + { + if (*i == '-' || *i == ',') + { + startfrom = i + 1; + } + } + + line.erase(line.begin(), startfrom); + + max_cpus = support::cpp11::stoi(line, nullptr) + 1; + success = true; + } + } + + // Return std::thread::hardware_concurrency() as a fallback. + if (!success) + { + max_cpus = std::thread::hardware_concurrency(); + } + return max_cpus; +} + +const static std::map<std::string, std::vector<uint32_t>> known_configurations_with_little_cores = { + {"xiaomi14-pro", {379, 379, 923, 923, 923, 867, 867, 1024}}}; + +const static std::map<std::string, uint32_t> number_of_cores_to_use = {{"xiaomi14-pro", 6}}; + +#if defined(__ANDROID__) +std::vector<uint32_t> get_cpu_capacities() +{ + std::vector<uint32_t> cpu_capacities; + for (int i = 0; i < get_max_cpus(); ++i) + { + std::stringstream str; + str << "/sys/devices/system/cpu/cpu" << i << "/cpu_capacity"; + std::ifstream file(str.str(), std::ios::in); + if (file.is_open()) + { + std::string line; + if (bool(getline(file, line))) + { + cpu_capacities.emplace_back(support::cpp11::stoul(line)); + } + } + } + + return cpu_capacities; +} + +uint32_t not_little_num_cpus_internal() +{ + std::vector<uint32_t> cpus_all = get_cpu_capacities(); + std::vector<uint32_t> cpus_not_little; + + for (auto &it : known_configurations_with_little_cores) + { + if (it.second == cpus_all) + { + return number_of_cores_to_use.find(it.first)->second; + } + } + + std::vector<uint32_t>::iterator result = std::max_element(cpus_all.begin(), cpus_all.end()); + uint32_t max_capacity = *result; + uint32_t threshold = max_capacity / 2; + for (unsigned int i = 0; i < cpus_all.size(); i++) + { + if (!(cpus_all[i] < threshold)) + { + cpus_not_little.emplace_back(cpus_all[i]); + } + } + return cpus_not_little.size(); +} + +bool has_little_mid_big_internal() +{ + std::vector<uint32_t> cpus_all = get_cpu_capacities(); + std::vector<uint32_t> cpus_not_little; + + for (auto &it : known_configurations_with_little_cores) + { + if (it.second == cpus_all) + { + return true; + } + } + std::sort(cpus_all.begin(), cpus_all.end()); + std::vector<uint32_t>::iterator ip; + ip = std::unique(cpus_all.begin(), cpus_all.end()); + cpus_all.resize(std::distance(cpus_all.begin(), ip)); + + if (cpus_all.size() == 3) + { + return true; + } + else + { + return false; + } +} +#endif /* defined(__ANDROID__) */ +#elif defined(__aarch64__) && \ + defined(__APPLE__) /* !defined(BARE_METAL) && !defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) */ +/** Query features through sysctlbyname + * + * @return int value queried + */ +int get_hw_capability(const std::string &cap) +{ + int64_t result(0); + size_t size = sizeof(result); + sysctlbyname(cap.c_str(), &result, &size, NULL, 0); + return result; +} +#endif /* !defined(BARE_METAL) && !defined(__APPLE__) && !defined(__OpenBSD__) && (defined(__arm__) || defined(__aarch64__)) */ + +#if defined(BARE_METAL) && defined(__aarch64__) +uint64_t get_sve_feature_reg() +{ + uint64_t svefr0 = 0; + __asm __volatile(".inst 0xd5380483 // mrs x3, ID_AA64ZFR0_EL1\n" + "MOV %0, X3" + : "=r"(svefr0) + : + : "x3"); + return svefr0; +} +#endif /* defined(BARE_METAL) && defined(__aarch64__) */ +} // namespace + +CpuInfo::CpuInfo(CpuIsaInfo isa, std::vector<CpuModel> cpus) : _isa(std::move(isa)), _cpus(std::move(cpus)) +{ +} + +CpuInfo CpuInfo::build() +{ +#if !defined(_WIN64) && !defined(BARE_METAL) && !defined(__APPLE__) && !defined(__OpenBSD__) && \ + (defined(__arm__) || defined(__aarch64__)) + const uint32_t hwcaps = getauxval(AT_HWCAP); + const uint32_t hwcaps2 = getauxval(AT_HWCAP2); + const uint32_t max_cpus = get_max_cpus(); + + // Populate midr values + std::vector<uint32_t> cpus_midr; + if (hwcaps & ARM_COMPUTE_CPU_FEATURE_HWCAP_CPUID) + { + cpus_midr = midr_from_cpuid(max_cpus); + } + if (cpus_midr.empty()) + { + cpus_midr = midr_from_proc_cpuinfo(max_cpus); + } + if (cpus_midr.empty()) + { + cpus_midr.resize(max_cpus, 0); + } + + // Populate isa (Assume homogeneous ISA specification) + CpuIsaInfo isa = init_cpu_isa_from_hwcaps(hwcaps, hwcaps2, cpus_midr.back()); + + // Convert midr to models + std::vector<CpuModel> cpus_model; + std::transform(std::begin(cpus_midr), std::end(cpus_midr), std::back_inserter(cpus_model), + [](uint32_t midr) -> CpuModel { return midr_to_model(midr); }); + + CpuInfo info(isa, cpus_model); + return info; + +#elif (BARE_METAL) && \ + defined( \ + __aarch64__) /* !defined(BARE_METAL) && !defined(__APPLE__) && !defined(__OpenBSD__) && (defined(__arm__) || defined(__aarch64__)) */ + + // Assume single CPU in bare metal mode. Just read the ID register and feature bits directly. + uint64_t isar0 = 0, isar1 = 0, pfr0 = 0, pfr1 = 0, svefr0 = 0, midr = 0; + ARM_COMPUTE_GET_FEATURE_REG(isar0, ID_AA64ISAR0_EL1); + ARM_COMPUTE_GET_FEATURE_REG(isar1, ID_AA64ISAR1_EL1); + ARM_COMPUTE_GET_FEATURE_REG(pfr0, ID_AA64PFR0_EL1); + ARM_COMPUTE_GET_FEATURE_REG(pfr1, ID_AA64PFR1_EL1); + ARM_COMPUTE_GET_FEATURE_REG(midr, MIDR_EL1); + if ((pfr0 >> 32) & 0xf) + { + svefr0 = get_sve_feature_reg(); + } + + CpuIsaInfo isa = init_cpu_isa_from_regs(isar0, isar1, pfr0, pfr1, svefr0, midr); + std::vector<CpuModel> cpus_model(1, midr_to_model(midr)); + CpuInfo info(isa, cpus_model); + return info; +#elif defined(__aarch64__) && defined(__APPLE__) /* #elif(BARE_METAL) && defined(__aarch64__) */ + int ncpus = get_hw_capability("hw.perflevel0.logicalcpu"); + CpuIsaInfo isainfo; + std::vector<CpuModel> cpus_model(ncpus); + isainfo.neon = get_hw_capability("hw.optional.neon"); + isainfo.fp16 = get_hw_capability("hw.optional.neon_fp16"); + isainfo.dot = get_hw_capability("hw.optional.arm.FEAT_DotProd"); + isainfo.bf16 = get_hw_capability("hw.optional.arm.FEAT_BF16"); + isainfo.i8mm = get_hw_capability("hw.optional.arm.FEAT_I8MM"); + CpuInfo info(isainfo, cpus_model); + return info; +#elif defined(__aarch64__) && defined(_WIN64) /* #elif defined(__aarch64__) && defined(__APPLE__) */ + CpuIsaInfo isainfo; + isainfo.neon = true; + CpuInfo info(isainfo, {CpuModel::GENERIC}); + return info; +#else /* #elif defined(__aarch64__) && defined(_WIN64) */ + CpuInfo info(CpuIsaInfo(), {CpuModel::GENERIC}); + return info; +#endif /* !defined(BARE_METAL) && !defined(__APPLE__) && !defined(__OpenBSD__) && (defined(__arm__) || defined(__aarch64__)) */ +} + +CpuModel CpuInfo::cpu_model(uint32_t cpuid) const +{ + if (cpuid < _cpus.size()) + { + return _cpus[cpuid]; + } + return CpuModel::GENERIC; +} + +CpuModel CpuInfo::cpu_model() const +{ +#if defined(_WIN64) || defined(BARE_METAL) || defined(__APPLE__) || defined(__OpenBSD__) || \ + (!defined(__arm__) && !defined(__aarch64__)) + return cpu_model(0); +#else /* defined(BARE_METAL) || defined(__APPLE__) || defined(__OpenBSD__) || (!defined(__arm__) && !defined(__aarch64__)) */ + return cpu_model(sched_getcpu()); +#endif /* defined(BARE_METAL) || defined(__APPLE__) || defined(__OpenBSD__) || (!defined(__arm__) && !defined(__aarch64__)) */ +} + +uint32_t CpuInfo::num_cpus() const +{ + return _cpus.size(); +} + +uint32_t CpuInfo::not_little_num_cpus() const +{ +#if defined(__ANDROID__) + return not_little_num_cpus_internal(); +#else /* defined(__ANDROID__) */ + return num_cpus(); +#endif /* defined(__ANDROID__) */ +} + +bool CpuInfo::has_little_mid_big() const +{ +#if defined(__ANDROID__) + return has_little_mid_big_internal(); +#else /* defined(__ANDROID__) */ + return false; +#endif /* defined(__ANDROID__) */ +} + +uint32_t num_threads_hint() +{ + unsigned int num_threads_hint = 1; + +#if !defined(BARE_METAL) && !defined(_WIN64) && !defined(ARM_COMPUTE_DISABLE_THREADS_HINT) + std::vector<std::string> cpus; + cpus.reserve(64); + + // CPU part regex + regex_t cpu_part_rgx; + memset(&cpu_part_rgx, 0, sizeof(regex_t)); + int ret_status = regcomp(&cpu_part_rgx, R"(.*CPU part.+/?\:[[:space:]]+([[:alnum:]]+).*)", REG_EXTENDED); + ARM_COMPUTE_UNUSED(ret_status); + ARM_COMPUTE_ERROR_ON_MSG(ret_status != 0, "Regex compilation failed."); + + // Read cpuinfo and get occurrence of each core + std::ifstream cpuinfo_file("/proc/cpuinfo", std::ios::in); + if (cpuinfo_file.is_open()) + { + std::string line; + while (bool(getline(cpuinfo_file, line))) + { + std::array<regmatch_t, 2> match; + if (regexec(&cpu_part_rgx, line.c_str(), 2, match.data(), 0) == 0) + { + cpus.emplace_back(line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so))); + } + } + } + regfree(&cpu_part_rgx); + + // Get min number of threads + std::sort(std::begin(cpus), std::end(cpus)); + auto least_frequent_cpu_occurences = [](const std::vector<std::string> &cpus) -> uint32_t + { + std::unordered_map<std::string, uint32_t> cpus_freq; + for (const auto &cpu : cpus) + { + cpus_freq[cpu]++; + } + + uint32_t vmin = cpus.size() + 1; + for (const auto &cpu_freq : cpus_freq) + { + vmin = std::min(vmin, cpu_freq.second); + } + return vmin; + }; + + // Set thread hint + num_threads_hint = cpus.empty() ? std::thread::hardware_concurrency() : least_frequent_cpu_occurences(cpus); +#endif /* !defined(BARE_METAL) && !defined(_WIN64) && !defined(ARM_COMPUTE_DISABLE_THREADS_HINT) */ + + return num_threads_hint; +} +} // namespace cpuinfo +} // namespace arm_compute diff --git a/src/common/cpuinfo/CpuInfo.h b/src/common/cpuinfo/CpuInfo.h new file mode 100644 index 0000000000..506830aa81 --- /dev/null +++ b/src/common/cpuinfo/CpuInfo.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2021-2022, 2024 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 ACL_SRC_COMMON_CPUINFO_CPUINFO_H +#define ACL_SRC_COMMON_CPUINFO_CPUINFO_H + +#include "src/common/cpuinfo/CpuIsaInfo.h" +#include "src/common/cpuinfo/CpuModel.h" + +#include <string> +#include <vector> + +namespace arm_compute +{ +namespace cpuinfo +{ +/** Aggregate class that contains CPU related information + * + * Contains information about the numbers of the CPUs, the model of each CPU, + * ISA related information and more + * + * @note We can safely assume that the ISA is common between different clusters of cores + */ +class CpuInfo +{ +public: + /** Default constructor */ + CpuInfo() = default; + /** Construct a new Cpu Info object + * + * @param[in] isa ISA capabilities information + * @param[in] cpus CPU models information + */ + CpuInfo(CpuIsaInfo isa, std::vector<CpuModel> cpus); + /** CpuInfo builder function from system related information + * + * @return CpuInfo A populated CpuInfo structure + */ + static CpuInfo build(); + +public: + bool has_neon() const + { + return _isa.neon; + } + bool has_sve() const + { + return _isa.sve; + } + bool has_sve2() const + { + return _isa.sve2; + } + bool has_sme() const + { + return _isa.sme; + } + bool has_sme2() const + { + return _isa.sme2; + } + bool has_fp16() const + { + return _isa.fp16; + } + bool has_bf16() const + { + return _isa.bf16; + } + bool has_svebf16() const + { + return _isa.svebf16; + } + bool has_dotprod() const + { + return _isa.dot; + } + bool has_i8mm() const + { + return _isa.i8mm; + } + bool has_svei8mm() const + { + return _isa.svei8mm; + } + bool has_svef32mm() const + { + return _isa.svef32mm; + } + + const CpuIsaInfo &isa() const + { + return _isa; + } + const std::vector<CpuModel> &cpus() const + { + return _cpus; + } + + CpuModel cpu_model(uint32_t cpuid) const; + CpuModel cpu_model() const; + uint32_t num_cpus() const; + uint32_t not_little_num_cpus() const; + bool has_little_mid_big() const; + +private: + CpuIsaInfo _isa{}; + std::vector<CpuModel> _cpus{}; +}; + +/** Some systems have both big and small cores, this fuction computes the minimum number of cores + * that are exactly the same on the system. To maximize performance the library attempts to process + * workloads concurrently using as many threads as big cores are available on the system. + * + * @return The minumum number of common cores. + */ +uint32_t num_threads_hint(); +} // namespace cpuinfo +} // namespace arm_compute +#endif // ACL_SRC_COMMON_CPUINFO_CPUINFO_H diff --git a/src/common/cpuinfo/CpuIsaInfo.cpp b/src/common/cpuinfo/CpuIsaInfo.cpp new file mode 100644 index 0000000000..c9e39b9a08 --- /dev/null +++ b/src/common/cpuinfo/CpuIsaInfo.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2021-2022, 2024 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/cpuinfo/CpuIsaInfo.h" + +#include "arm_compute/core/Error.h" + +#include "src/common/cpuinfo/CpuModel.h" + +/* Arm Feature flags */ +#define ARM_COMPUTE_CPU_FEATURE_HWCAP_HALF (1 << 1) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP_NEON (1 << 12) + +/* Arm64 Feature flags */ +#define ARM_COMPUTE_CPU_FEATURE_HWCAP_ASIMD (1 << 1) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP_FPHP (1 << 9) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP_ASIMDHP (1 << 10) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP_ASIMDDP (1 << 20) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP_SVE (1 << 22) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP2_SVE2 (1 << 1) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP2_SVEI8MM (1 << 9) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP2_SVEF32MM (1 << 10) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP2_SVEBF16 (1 << 12) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP2_I8MM (1 << 13) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP2_BF16 (1 << 14) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP2_SME (1 << 23) + +namespace arm_compute +{ +namespace cpuinfo +{ +namespace +{ +inline bool is_feature_supported(uint64_t features, uint64_t feature_mask) +{ + return (features & feature_mask); +} + +#if defined(__arm__) +void decode_hwcaps(CpuIsaInfo &isa, const uint32_t hwcaps, const uint32_t hwcaps2) +{ + ARM_COMPUTE_UNUSED(hwcaps2); + isa.fp16 = false; + isa.neon = is_feature_supported(hwcaps, ARM_COMPUTE_CPU_FEATURE_HWCAP_NEON); +} +#elif defined(__aarch64__) +void decode_hwcaps(CpuIsaInfo &isa, const uint32_t hwcaps, const uint32_t hwcaps2) +{ + // High-level SIMD support + isa.neon = is_feature_supported(hwcaps, ARM_COMPUTE_CPU_FEATURE_HWCAP_ASIMD); + isa.sve = is_feature_supported(hwcaps, ARM_COMPUTE_CPU_FEATURE_HWCAP_SVE); + isa.sve2 = is_feature_supported(hwcaps2, ARM_COMPUTE_CPU_FEATURE_HWCAP2_SVE2); + + // Detection of SME from type HWCAP2 in the auxillary vector + isa.sme = is_feature_supported(hwcaps2, ARM_COMPUTE_CPU_FEATURE_HWCAP2_SME); + isa.sme2 = isa.sme; // Needs to be set properly + + // Data-type support + isa.fp16 = is_feature_supported(hwcaps, ARM_COMPUTE_CPU_FEATURE_HWCAP_FPHP | ARM_COMPUTE_CPU_FEATURE_HWCAP_ASIMDHP); + isa.bf16 = is_feature_supported(hwcaps2, ARM_COMPUTE_CPU_FEATURE_HWCAP2_BF16); + isa.svebf16 = is_feature_supported(hwcaps2, ARM_COMPUTE_CPU_FEATURE_HWCAP2_SVEBF16); + + // Instruction extensions + isa.dot = is_feature_supported(hwcaps, ARM_COMPUTE_CPU_FEATURE_HWCAP_ASIMDDP); + isa.i8mm = is_feature_supported(hwcaps2, ARM_COMPUTE_CPU_FEATURE_HWCAP2_I8MM); + isa.svei8mm = is_feature_supported(hwcaps2, ARM_COMPUTE_CPU_FEATURE_HWCAP2_SVEI8MM); + isa.svef32mm = is_feature_supported(hwcaps2, ARM_COMPUTE_CPU_FEATURE_HWCAP2_SVEF32MM); +} +#else /* defined(__aarch64__) */ +void decode_hwcaps(CpuIsaInfo &isa, const uint32_t hwcaps, const uint32_t hwcaps2) +{ + ARM_COMPUTE_UNUSED(isa, hwcaps, hwcaps2); +} +#endif /* defined(__aarch64__) */ + +void decode_regs(CpuIsaInfo &isa, + const uint64_t isar0, + const uint64_t isar1, + const uint64_t pfr0, + const uint64_t pfr1, + const uint64_t svefr0) +{ + auto is_supported = [](uint64_t feature_reg, uint8_t feature_pos) -> bool + { return ((feature_reg >> feature_pos) & 0xf); }; + + // High-level SIMD support + isa.sve = is_supported(pfr0, 32); + isa.sve2 = is_supported(svefr0, 0); + isa.sme = is_supported(pfr1, 24); + isa.sme2 = (((pfr1 >> 24) & 0xf) > 1); + + // Data-type support + isa.fp16 = is_supported(pfr0, 16); + isa.bf16 = is_supported(isar1, 44); + isa.svebf16 = is_supported(svefr0, 20); + + // Instruction extensions + isa.dot = is_supported(isar0, 44); + isa.i8mm = is_supported(isar1, 48); + isa.svei8mm = is_supported(svefr0, 44); + isa.svef32mm = is_supported(svefr0, 52); +} + +/** Handle features from allow-listed models in case of problematic kernels + * + * @param[in, out] isa ISA to update + * @param[in] model CPU model type + */ +void allowlisted_model_features(CpuIsaInfo &isa, CpuModel model) +{ + if (isa.dot == false) + { + isa.dot = model_supports_dot(model); + } + if (isa.fp16 == false) + { + isa.fp16 = model_supports_fp16(model); + } +} +} // namespace + +CpuIsaInfo init_cpu_isa_from_hwcaps(uint32_t hwcaps, uint32_t hwcaps2, uint32_t midr) +{ + CpuIsaInfo isa; + + decode_hwcaps(isa, hwcaps, hwcaps2); + + const CpuModel model = midr_to_model(midr); + allowlisted_model_features(isa, model); + + return isa; +} + +CpuIsaInfo +init_cpu_isa_from_regs(uint64_t isar0, uint64_t isar1, uint64_t pfr0, uint64_t pfr1, uint64_t svefr0, uint64_t midr) +{ + CpuIsaInfo isa; + + decode_regs(isa, isar0, isar1, pfr0, pfr1, svefr0); + + const CpuModel model = midr_to_model(midr); + allowlisted_model_features(isa, model); + + return isa; +} +} // namespace cpuinfo +} // namespace arm_compute diff --git a/src/common/cpuinfo/CpuIsaInfo.h b/src/common/cpuinfo/CpuIsaInfo.h new file mode 100644 index 0000000000..9d6bc07b67 --- /dev/null +++ b/src/common/cpuinfo/CpuIsaInfo.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2021-2022 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_CPUINFO_CPUISAINFO_H +#define SRC_COMMON_CPUINFO_CPUISAINFO_H + +#include <cstdint> + +namespace arm_compute +{ +namespace cpuinfo +{ +/** CPU ISA (Instruction Set Architecture) information + * + * Contains ISA related information around the Arm architecture + */ +struct CpuIsaInfo +{ + /* SIMD extension support */ + bool neon{false}; + bool sve{false}; + bool sve2{false}; + bool sme{false}; + bool sme2{false}; + + /* Data-type extensions support */ + bool fp16{false}; + bool bf16{false}; + bool svebf16{false}; + + /* Instruction support */ + bool dot{false}; + bool i8mm{false}; + bool svei8mm{false}; + bool svef32mm{false}; +}; + +/** Identify ISA related information through system information + * + * @param[in] hwcaps HWCAPS feature information + * @param[in] hwcaps2 HWCAPS2 feature information + * @param[in] midr MIDR value + * + * @return CpuIsaInfo A populated ISA feature structure + */ +CpuIsaInfo init_cpu_isa_from_hwcaps(uint32_t hwcaps, uint32_t hwcaps2, uint32_t midr); + +/** Identify ISA related information through register information + * + * @param[in] isar0 Value of Instruction Set Attribute Register 0 (ID_AA64ISAR0_EL1) + * @param[in] isar1 Value of Instruction Set Attribute Register 1 (ID_AA64ISAR1_EL1) + * @param[in] pfr0 Value of Processor Feature Register 0 (ID_AA64PFR0_EL1) + * @param[in] pfr1 Value of Processor Feature Register 1 (ID_AA64PFR1_EL1) + * @param[in] svefr0 Value of SVE feature ID register 0 (ID_AA64ZFR0_EL1) + * @param[in] midr Value of Main ID Register (MIDR) + * + * @return CpuIsaInfo A populated ISA feature structure + */ +CpuIsaInfo +init_cpu_isa_from_regs(uint64_t isar0, uint64_t isar1, uint64_t pfr0, uint64_t pfr1, uint64_t svefr0, uint64_t midr); +} // namespace cpuinfo +} // namespace arm_compute + +#endif /* SRC_COMMON_CPUINFO_CPUISAINFO_H */ diff --git a/src/common/cpuinfo/CpuModel.cpp b/src/common/cpuinfo/CpuModel.cpp new file mode 100644 index 0000000000..8c3f8a8faf --- /dev/null +++ b/src/common/cpuinfo/CpuModel.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2021-2023 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/cpuinfo/CpuModel.h" + +namespace arm_compute +{ +namespace cpuinfo +{ +std::string cpu_model_to_string(CpuModel model) +{ + switch (model) + { +#define X(MODEL) \ + case CpuModel::MODEL: \ + return #MODEL; + ARM_COMPUTE_CPU_MODEL_LIST +#undef X + default: + { + return std::string("GENERIC"); + } + }; +} + +bool model_supports_fp16(CpuModel model) +{ + switch (model) + { + case CpuModel::GENERIC_FP16: + case CpuModel::GENERIC_FP16_DOT: + case CpuModel::A55r1: + case CpuModel::A510: + case CpuModel::X1: + case CpuModel::V1: + case CpuModel::A64FX: + case CpuModel::N1: + return true; + default: + return false; + } +} + +bool model_supports_dot(CpuModel model) +{ + switch (model) + { + case CpuModel::GENERIC_FP16_DOT: + case CpuModel::A55r1: + case CpuModel::A510: + case CpuModel::X1: + case CpuModel::V1: + case CpuModel::N1: + return true; + default: + return false; + } +} + +CpuModel midr_to_model(uint32_t midr) +{ + CpuModel model = CpuModel::GENERIC; + + // Unpack variant and CPU ID + const int implementer = (midr >> 24) & 0xFF; + const int variant = (midr >> 20) & 0xF; + const int cpunum = (midr >> 4) & 0xFFF; + + // Only CPUs we have code paths for are detected. All other CPUs can be safely classed as "GENERIC" + if (implementer == 0x41) // Arm CPUs + { + switch (cpunum) + { + case 0xd03: // A53 + case 0xd04: // A35 + model = CpuModel::A53; + break; + case 0xd05: // A55 + if (variant != 0) + { + model = CpuModel::A55r1; + } + else + { + model = CpuModel::A55r0; + } + break; + case 0xd09: // A73 + model = CpuModel::A73; + break; + case 0xd0a: // A75 + if (variant != 0) + { + model = CpuModel::GENERIC_FP16_DOT; + } + else + { + model = CpuModel::GENERIC_FP16; + } + break; + case 0xd0c: // N1 + model = CpuModel::N1; + break; + case 0xd06: // A65 + case 0xd0b: // A76 + case 0xd0d: // A77 + case 0xd0e: // A76AE + case 0xd41: // A78 + case 0xd42: // A78AE + case 0xd4a: // E1 + model = CpuModel::GENERIC_FP16_DOT; + break; + case 0xd40: // V1 + model = CpuModel::V1; + break; + case 0xd44: // X1 + model = CpuModel::X1; + break; + case 0xd46: // A510 + case 0xd80: // A520 + model = CpuModel::A510; + break; + case 0xd15: // R82 + model = CpuModel::A55r1; + break; + default: + model = CpuModel::GENERIC; + break; + } + } + else if (implementer == 0x46) + { + switch (cpunum) + { + case 0x001: // A64FX + model = CpuModel::A64FX; + break; + default: + model = CpuModel::GENERIC; + break; + } + } + else if (implementer == 0x48) + { + switch (cpunum) + { + case 0xd40: // A76 + model = CpuModel::GENERIC_FP16_DOT; + break; + default: + model = CpuModel::GENERIC; + break; + } + } + else if (implementer == 0x51) + { + switch (cpunum) + { + case 0x800: // A73 + model = CpuModel::A73; + break; + case 0x801: // A53 + model = CpuModel::A53; + break; + case 0x803: // A55r0 + model = CpuModel::A55r0; + break; + case 0x804: // A76 + model = CpuModel::GENERIC_FP16_DOT; + break; + case 0x805: // A55r1 + model = CpuModel::A55r1; + break; + default: + model = CpuModel::GENERIC; + break; + } + } + + return model; +} +} // namespace cpuinfo +} // namespace arm_compute diff --git a/src/common/cpuinfo/CpuModel.h b/src/common/cpuinfo/CpuModel.h new file mode 100644 index 0000000000..3b9d9e3494 --- /dev/null +++ b/src/common/cpuinfo/CpuModel.h @@ -0,0 +1,71 @@ +/* + * 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_CPUINFO_CPUMODEL_H +#define SRC_COMMON_CPUINFO_CPUMODEL_H + +#include "arm_compute/core/CPP/CPPTypes.h" + +#include <cstdint> +#include <string> + +namespace arm_compute +{ +namespace cpuinfo +{ +using CpuModel = arm_compute::CPUModel; + +/** Convert a CPU model value to a string + * + * @param model CpuModel value to be converted + * + * @return String representing the corresponding CpuModel + */ +std::string cpu_model_to_string(CpuModel model); + +/** Extract the model type from the MIDR value + * + * @param[in] midr MIDR information + * + * @return CpuModel a mapped CPU model + */ +CpuModel midr_to_model(uint32_t midr); + +/** Check if a model supports half-precision floating point arithmetic + * + * @note This is used in case of old kernel configurations where some capabilities are not exposed. + * + * @param[in] model Model to check for allowlisted capabilities + */ +bool model_supports_fp16(CpuModel model); + +/** Check if a model supports dot product + * + * @note This is used in case of old kernel configurations where some capabilities are not exposed. + * + * @param[in] model Model to check for allowlisted capabilities + */ +bool model_supports_dot(CpuModel model); +} // namespace cpuinfo +} // namespace arm_compute +#endif /* SRC_COMMON_CPUINFO_CPUMODEL_H */ diff --git a/src/common/utils/LegacySupport.cpp b/src/common/utils/LegacySupport.cpp new file mode 100644 index 0000000000..102644227e --- /dev/null +++ b/src/common/utils/LegacySupport.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2021, 2023 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/utils/LegacySupport.h" + +#include "arm_compute/function_info/ActivationLayerInfo.h" + +namespace arm_compute +{ +namespace detail +{ +namespace +{ +DataType convert_to_legacy_data_type(AclDataType data_type) +{ + switch (data_type) + { + case AclDataType::AclFloat32: + return DataType::F32; + case AclDataType::AclFloat16: + return DataType::F16; + case AclDataType::AclBFloat16: + return DataType::BFLOAT16; + default: + return DataType::UNKNOWN; + } +} + +AclDataType convert_to_c_data_type(DataType data_type) +{ + switch (data_type) + { + case DataType::F32: + return AclDataType::AclFloat32; + case DataType::F16: + return AclDataType::AclFloat16; + case DataType::BFLOAT16: + return AclDataType::AclBFloat16; + default: + return AclDataType::AclDataTypeUnknown; + } +} + +TensorShape create_legacy_tensor_shape(int32_t ndims, int32_t *shape) +{ + TensorShape legacy_shape{}; + for (int32_t d = 0; d < ndims; ++d) + { + legacy_shape.set(d, shape[d], false); + } + return legacy_shape; +} +int32_t *create_tensor_shape_array(const TensorInfo &info) +{ + const auto num_dims = info.num_dimensions(); + if (num_dims <= 0) + { + return nullptr; + } + + int32_t *shape_array = new int32_t[num_dims]; + + for (size_t d = 0; d < num_dims; ++d) + { + shape_array[d] = info.tensor_shape()[d]; + } + + return shape_array; +} +} // namespace + +TensorInfo convert_to_legacy_tensor_info(const AclTensorDescriptor &desc) +{ + TensorInfo legacy_desc; + legacy_desc.init(create_legacy_tensor_shape(desc.ndims, desc.shape), 1, + convert_to_legacy_data_type(desc.data_type)); + return legacy_desc; +} + +AclTensorDescriptor convert_to_descriptor(const TensorInfo &info) +{ + const auto num_dims = info.num_dimensions(); + AclTensorDescriptor desc{static_cast<int32_t>(num_dims), create_tensor_shape_array(info), + convert_to_c_data_type(info.data_type()), nullptr, 0}; + return desc; +} + +ActivationLayerInfo convert_to_activation_info(const AclActivationDescriptor &desc) +{ + ActivationLayerInfo::ActivationFunction act; + switch (desc.type) + { + case AclActivationType::AclIdentity: + act = ActivationLayerInfo::ActivationFunction::IDENTITY; + break; + case AclActivationType::AclLogistic: + act = ActivationLayerInfo::ActivationFunction::LOGISTIC; + break; + case AclActivationType::AclTanh: + act = ActivationLayerInfo::ActivationFunction::TANH; + break; + case AclActivationType::AclRelu: + act = ActivationLayerInfo::ActivationFunction::RELU; + break; + case AclActivationType::AclBoundedRelu: + act = ActivationLayerInfo::ActivationFunction::BOUNDED_RELU; + break; + case AclActivationType::AclLuBoundedRelu: + act = ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU; + break; + case AclActivationType::AclLeakyRelu: + act = ActivationLayerInfo::ActivationFunction::LEAKY_RELU; + break; + case AclActivationType::AclSoftRelu: + act = ActivationLayerInfo::ActivationFunction::SOFT_RELU; + break; + case AclActivationType::AclElu: + act = ActivationLayerInfo::ActivationFunction::ELU; + break; + case AclActivationType::AclAbs: + act = ActivationLayerInfo::ActivationFunction::ABS; + break; + case AclActivationType::AclSquare: + act = ActivationLayerInfo::ActivationFunction::SQUARE; + break; + case AclActivationType::AclSqrt: + act = ActivationLayerInfo::ActivationFunction::SQRT; + break; + case AclActivationType::AclLinear: + act = ActivationLayerInfo::ActivationFunction::LINEAR; + break; + case AclActivationType::AclHardSwish: + act = ActivationLayerInfo::ActivationFunction::HARD_SWISH; + break; + default: + return ActivationLayerInfo(); + } + + return ActivationLayerInfo(act, desc.a, desc.b); +} +} // namespace detail +} // namespace arm_compute diff --git a/src/common/utils/LegacySupport.h b/src/common/utils/LegacySupport.h new file mode 100644 index 0000000000..05a70fc2c6 --- /dev/null +++ b/src/common/utils/LegacySupport.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021, 2023 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_LEGACY_SUPPORT_H +#define SRC_COMMON_LEGACY_SUPPORT_H + +#include "arm_compute/Acl.h" +#include "arm_compute/core/TensorInfo.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/function_info/ActivationLayerInfo.h" + +namespace arm_compute +{ +namespace detail +{ +/** Convert a descriptor to a legacy format one + * + * @param[in] desc Descriptor to convert + * + * @return Legacy tensor meta-data + */ +TensorInfo convert_to_legacy_tensor_info(const AclTensorDescriptor &desc); +/** Convert a legacy tensor meta-data to a descriptor + * + * @param[in] info Legacy tensor meta-data + * + * @return A converted descriptor + */ +AclTensorDescriptor convert_to_descriptor(const TensorInfo &info); +/** Convert an AclActivation descriptor to an internal one + * + * @param[in] desc Descriptor to convert + * + * @return Legacy tensor meta-data + */ +ActivationLayerInfo convert_to_activation_info(const AclActivationDescriptor &desc); +} // namespace detail +} // namespace arm_compute + +#endif /* SRC_COMMON_LEGACY_SUPPORT_H */ diff --git a/src/common/utils/Log.h b/src/common/utils/Log.h new file mode 100644 index 0000000000..6ebfed366e --- /dev/null +++ b/src/common/utils/Log.h @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2021,2023 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 + +#ifndef ARM_COMPUTE_LOGGING_ENABLED + +#define ARM_COMPUTE_CREATE_ACL_LOGGER() +#define ARM_COMPUTE_LOG_MSG_ACL(log_level, msg) +#define ARM_COMPUTE_LOG_MSG_WITH_FORMAT_ACL(log_level, fmt, ...) +#define ARM_COMPUTE_LOG_ERROR_ACL(msg) +#define ARM_COMPUTE_LOG_ERROR_WITH_FUNCNAME_ACL(msg) +#define ARM_COMPUTE_LOG_INFO_WITH_FUNCNAME_ACL(msg) +#define ARM_COMPUTE_LOG_PARAMS(...) + +#else /* ARM_COMPUTE_LOGGING_ENABLED */ + +#include "arm_compute/core/Error.h" +#include "arm_compute/core/utils/logging/Macros.h" + +#include "utils/TypePrinter.h" + +/** 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) + +/** 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) + +/** Log an error message to the logger with function name before the message + * + * @param[in] msg Message to log + */ +#define ARM_COMPUTE_LOG_ERROR_WITH_FUNCNAME_ACL(msg) \ + do \ + { \ + ARM_COMPUTE_CREATE_ACL_LOGGER(); \ + ARM_COMPUTE_LOG_MSG_WITH_FUNCNAME("ComputeLibrary", arm_compute::logging::LogLevel::ERROR, msg); \ + } while (false) + +/** Log an information message to the logger with function name before the message + * + * @param[in] msg Message to log + */ +#define ARM_COMPUTE_LOG_INFO_WITH_FUNCNAME_ACL(msg) \ + do \ + { \ + ARM_COMPUTE_CREATE_ACL_LOGGER(); \ + ARM_COMPUTE_LOG_MSG_WITH_FUNCNAME("ComputeLibrary", arm_compute::logging::LogLevel::INFO, msg); \ + } while (false) + +/** Function template specialization for the out of bound element at index = tuple_size + * + * @param[in,out] data_registry Reference to the input parameters data in a string format + * @param[in] in_params_tuple Tuple of different input data types + */ +template <std::size_t Index, typename... Tp> +inline typename std::enable_if<Index == sizeof...(Tp), void>::type +logParamsImpl(std::vector<std::string> &data_registry, const std::tuple<Tp...> &in_params_tuple) +{ + // Because it is out of bound index so do nothing + ARM_COMPUTE_UNUSED(data_registry); + ARM_COMPUTE_UNUSED(in_params_tuple); +} + +/** Function template to iterate over all input parameters tuple at compile time: + * + * @param[in,out] data_registry Reference to a vector of input parameters data in a string format + * @param[in] in_params_tuple Constant reference to a tuple of different input data types + */ +template <std::size_t Index, typename... Tp> + inline typename std::enable_if < + Index<sizeof...(Tp), void>::type logParamsImpl(std::vector<std::string> &data_registry, + const std::tuple<Tp...> &in_params_tuple) +{ + data_registry.push_back(arm_compute::to_string(std::get<Index>(in_params_tuple))); + // Unfold the next tuple element + logParamsImpl<Index + 1, Tp...>(data_registry, in_params_tuple); +} + +/** Function Template with variable number of inputs to collect all the passed parameters from + * the logging macro ARM_COMPUTE_LOG_PARAMS(...) + * + * @param[in] ...ins The input parameters in the variadic template, taken by universal references Ts.. &&, (not by value) + * to avoid detecting T as an abstract data type when passing any of these parameters as an L-value + * reference to an abstract type. + * + * @return Vector of the parameters' data in a string format + */ +template <typename... Ts> +const std::vector<std::string> logParams(Ts &&...ins) +{ + std::vector<std::string> data_registry{}; + std::tuple<Ts...> in_params_tuple{ins...}; + + // Start logging the tuple elements, starting from 0 to tuple_size-1 + logParamsImpl<0>(data_registry, in_params_tuple); + return data_registry; +} + +/** Inline function to parse the input parameters string passed from strignizing of the variadic macro input + * #__VA_ARGS__. + * It is Inline to avoid the redefinition of this function each time this header is included + * + * @param[in] in_params_str Constant reference to a string consists of the names of the input parameters provided + * as:ARM_COMPUTE_LOG_PARAMS(src0, src1) the params_names = "src0, src1" + * + * @return Vector of strings containing all the names of the input parameters + */ +inline const std::vector<std::string> getParamsNames(const std::string &in_params_str) +{ + std::stringstream ss(in_params_str); + + // Vector containing all the names of the input parameters + std::vector<std::string> names; + std::string temp; + + // Usually the input parameters string would be name of parameters separated + // by ',' e.g. "src0, src1, policy" + while (std::getline(ss, temp, ',')) + { + names.push_back(temp); + } + for (auto &name : names) + { + // Totally get rid of white space characters + name.erase(std::remove(name.begin(), name.end(), ' '), name.end()); + } + return names; +} + +/** It constructs the log message to be displayed by the logger by writing each parameter name and its + * corresponding data info string. + * + * @param[in] params_names Constant reference to a string consists of the the input parameters' names + * provided e.g.: ARM_COMPUTE_LOG_PARAMS(src0, src1) then params_names = "src0, src1" + * @param[in] data_registry Constant reference to a registry of all parameters' data in string format, + * stringnized by arm_compute::to_string() + * + * @return Log message string to be displayed + */ +inline const std::string constructDataLog(const std::vector<std::string> ¶ms_names, + const std::vector<std::string> &data_registry) +{ + std::string dataLog = "\n "; + ARM_COMPUTE_ERROR_ON(params_names.size() != data_registry.size()); + for (uint8_t i = 0; i < params_names.size(); ++i) + { + dataLog += params_names[i] + ": " + data_registry.at(i) + "\n "; + } + + return dataLog; +} + +/** Macro for logging input Parameters from any function. + * It detects the input parameters names, and their corresponding values before stringizing them using + * the overloaded arm_compute::to_string() type printer. Finally, displayed using the printer configured + * in the logger. + * + * @param[in] ... Input parameters + */ +#define ARM_COMPUTE_LOG_PARAMS(...) \ + do \ + { \ + ARM_COMPUTE_LOG_INFO_WITH_FUNCNAME_ACL( \ + constructDataLog(getParamsNames(#__VA_ARGS__), logParams(__VA_ARGS__))); \ + } while (false) +#endif /* ARM_COMPUTE_LOGGING_ENABLED */ +#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..35f7e759d3 --- /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..b73de8e430 --- /dev/null +++ b/src/common/utils/Object.h @@ -0,0 +1,64 @@ +/* + * 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_) noexcept : 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..33fe6c0e81 --- /dev/null +++ b/src/common/utils/Utils.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2021,2023 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 <algorithm> +#include <initializer_list> +#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(const SE v) noexcept +{ + return static_cast<E>(static_cast<std::underlying_type_t<SE>>(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(const E val) noexcept +{ + return static_cast<SE>(val); +} + +/** 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(list.begin(), list.end(), [&check](E e) { return check == e; }); +} +} // namespace utils +} // namespace arm_compute + +#endif /* SRC_COMMON_UTILS_H */ diff --git a/src/common/utils/Validate.h b/src/common/utils/Validate.h new file mode 100644 index 0000000000..97819c619f --- /dev/null +++ b/src/common/utils/Validate.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020-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_CORE_COMMON_VALIDATE_H +#define SRC_CORE_COMMON_VALIDATE_H + +#if defined(ARM_COMPUTE_ASSERTS_ENABLED) + +#include <cassert> + +#define ARM_COMPUTE_ASSERT(cond) assert(cond) +#define ARM_COMPUTE_ASSERT_NOT_NULLPTR(ptr) assert((ptr) != nullptr) + +#else /* defined(ARM_COMPUTE_ASSERTS_ENABLED) */ + +#define ARM_COMPUTE_ASSERT(cond) +#define ARM_COMPUTE_ASSERT_NOT_NULLPTR(ptr) + +#endif /* defined(ARM_COMPUTE_ASSERTS_ENABLED) */ +#endif /* SRC_CORE_COMMON_VALIDATE_H */ |