blob: 7791c5633eceb1615c0c02620efb3c71aba08d76 [file] [log] [blame]
Georgios Pinitas8a5146f2021-01-12 15:51:07 +00001/*
2 * Copyright (c) 2021 Arm Limited.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#ifndef ARM_COMPUTE_ACL_HPP_
25#define ARM_COMPUTE_ACL_HPP_
26
27#include "arm_compute/Acl.h"
28
29#include <cstdlib>
30#include <memory>
31#include <string>
Georgios Pinitas3f26ef42021-02-23 10:01:33 +000032#include <vector>
Georgios Pinitas8a5146f2021-01-12 15:51:07 +000033
34#if defined(ARM_COMPUTE_EXCEPTIONS_ENABLED)
35#include <exception>
36#endif /* defined(ARM_COMPUTE_EXCEPTIONS_ENABLED) */
37
38// Helper Macros
39#define ARM_COMPUTE_IGNORE_UNUSED(x) (void)(x)
40
41namespace acl
42{
43// Forward declarations
44class Context;
Georgios Pinitasc3c352e2021-03-18 10:59:40 +000045class Queue;
Georgios Pinitas3f26ef42021-02-23 10:01:33 +000046class Tensor;
47class TensorPack;
Georgios Pinitas8a5146f2021-01-12 15:51:07 +000048
49/**< Status code enum */
50enum class StatusCode
51{
52 Success = AclSuccess,
53 RuntimeError = AclRuntimeError,
54 OutOfMemory = AclOutOfMemory,
55 Unimplemented = AclUnimplemented,
56 UnsupportedTarget = AclUnsupportedTarget,
57 InvalidArgument = AclInvalidArgument,
58 InvalidTarget = AclInvalidTarget,
59 UnsupportedConfig = AclUnsupportedConfig,
60 InvalidObjectState = AclInvalidObjectState,
61};
62
63/**< Utility namespace containing helpers functions */
64namespace detail
65{
66/** Construct to handle destruction of objects
67 *
68 * @tparam T Object base type
69 */
70template <typename T>
71struct ObjectDeleter
72{
73};
74
75#define OBJECT_DELETER(obj, func) \
76 template <> \
77 struct ObjectDeleter<obj> \
78 \
79 { \
80 static inline AclStatus Destroy(obj v) \
81 { \
82 return func(v); \
83 } \
84 };
85
86OBJECT_DELETER(AclContext, AclDestroyContext)
Georgios Pinitasc3c352e2021-03-18 10:59:40 +000087OBJECT_DELETER(AclQueue, AclDestroyQueue)
Georgios Pinitas3f26ef42021-02-23 10:01:33 +000088OBJECT_DELETER(AclTensor, AclDestroyTensor)
89OBJECT_DELETER(AclTensorPack, AclDestroyTensorPack)
Georgios Pinitas8a5146f2021-01-12 15:51:07 +000090
91#undef OBJECT_DELETER
92
93/** Convert a strongly typed enum to an old plain c enum
94 *
95 * @tparam E Plain old C enum
96 * @tparam SE Strongly typed resulting enum
97 *
98 * @param[in] v Value to convert
99 *
100 * @return A corresponding plain old C enumeration
101 */
102template <typename E, typename SE>
103constexpr E as_cenum(SE v) noexcept
104{
105 return static_cast<E>(static_cast<typename std::underlying_type<SE>::type>(v));
106}
107
108/** Convert plain old enumeration to a strongly typed enum
109 *
110 * @tparam SE Strongly typed resulting enum
111 * @tparam E Plain old C enum
112 *
113 * @param[in] val Value to convert
114 *
115 * @return A corresponding strongly typed enumeration
116 */
117template <typename SE, typename E>
118constexpr SE as_enum(E val) noexcept
119{
120 return static_cast<SE>(val);
121}
122
123/** Object base class for library objects
124 *
125 * Class is defining basic common interface for all the library objects
126 *
127 * @tparam T Object type to be templated on
128 */
129template <typename T>
130class ObjectBase
131{
132public:
133 /** Destructor */
134 ~ObjectBase() = default;
135 /** Copy constructor */
136 ObjectBase(const ObjectBase<T> &) = default;
137 /** Move Constructor */
138 ObjectBase(ObjectBase<T> &&) = default;
139 /** Copy assignment operator */
140 ObjectBase<T> &operator=(const ObjectBase<T> &) = default;
141 /** Move assignment operator */
142 ObjectBase<T> &operator=(ObjectBase<T> &&) = default;
143 /** Reset object value
144 *
145 * @param [in] val Value to set
146 */
147 void reset(T *val)
148 {
149 _object.reset(val, detail::ObjectDeleter<T *>::Destroy);
150 }
151 /** Access uderlying object
152 *
153 * @return Underlying object
154 */
155 const T *get() const
156 {
157 return _object.get();
158 }
159 /** Access uderlying object
160 *
161 * @return Underlying object
162 */
163 T *get()
164 {
165 return _object.get();
166 }
167
168protected:
169 /** Constructor */
170 ObjectBase() = default;
171
172protected:
173 std::shared_ptr<T> _object{ nullptr }; /**< Library object */
174};
175
176/** Equality operator for library object
177 *
178 * @tparam T Parameter to template on
179 *
180 * @param[in] lhs Left hand-side argument
181 * @param[in] rhs Right hand-side argument
182 *
183 * @return True if objects are equal, else false
184 */
185template <typename T>
186bool operator==(const ObjectBase<T> &lhs, const ObjectBase<T> &rhs)
187{
188 return lhs.get() == rhs.get();
189}
190
191/** Inequality operator for library object
192 *
193 * @tparam T Parameter to template on
194 *
195 * @param[in] lhs Left hand-side argument
196 * @param[in] rhs Right hand-side argument
197 *
198 * @return True if objects are equal, else false
199 */
200template <typename T>
201bool operator!=(const ObjectBase<T> &lhs, const ObjectBase<T> &rhs)
202{
203 return !(lhs == rhs);
204}
205} // namespace detail
206
207#if defined(ARM_COMPUTE_EXCEPTIONS_ENABLED)
208/** Status class
209 *
210 * Class is an extension of std::exception and contains the underlying
211 * status construct and an error explanatory message to be reported.
212 *
213 * @note Class is visible only when exceptions are enabled during compilation
214 */
215class Status : public std::exception
216{
217public:
218 /** Constructor
219 *
220 * @param[in] status Status returned
221 * @param[in] msg Error message to be bound with the exception
222 */
223 Status(StatusCode status, const std::string &msg)
224 : _status(status), _msg(msg)
225 {
226 }
227 /** Returns an explanatory exception message
228 *
229 * @return Status message
230 */
231 const char *what() const noexcept override
232 {
233 return _msg.c_str();
234 }
235 /** Underlying status accessor
236 *
237 * @return Status code
238 */
239 StatusCode status() const
240 {
241 return _status;
242 }
243 /** Explicit status converter
244 *
245 * @return Status code
246 */
247 explicit operator StatusCode() const
248 {
249 return _status;
250 }
251
252private:
253 StatusCode _status; /**< Status code */
254 std::string _msg; /**< Status message */
255};
256
257/** Reports an error status and throws an exception object in case of failure
258 *
259 * @note This implementation is used when exceptions are enabled during compilation
260 *
261 * @param[in] status Status to report
262 * @param[in] msg Explanatory error messaged
263 *
264 * @return Status code
265 */
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000266static inline void report_status(StatusCode status, const std::string &msg)
Georgios Pinitas8a5146f2021-01-12 15:51:07 +0000267{
268 if(status != StatusCode::Success)
269 {
270 throw Status(status, msg);
271 }
Georgios Pinitas8a5146f2021-01-12 15:51:07 +0000272}
273#else /* defined(ARM_COMPUTE_EXCEPTIONS_ENABLED) */
274/** Reports a status code
275 *
276 * @note This implementation is used when exceptions are disabled during compilation
277 * @note Message is surpressed and not reported in this case
278 *
279 * @param[in] status Status to report
280 * @param[in] msg Explanatory error messaged
281 *
282 * @return Status code
283 */
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000284static inline void report_status(StatusCode status, const std::string &msg)
Georgios Pinitas8a5146f2021-01-12 15:51:07 +0000285{
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000286 ARM_COMPUTE_IGNORE_UNUSED(status);
Georgios Pinitas8a5146f2021-01-12 15:51:07 +0000287 ARM_COMPUTE_IGNORE_UNUSED(msg);
Georgios Pinitas8a5146f2021-01-12 15:51:07 +0000288}
289#endif /* defined(ARM_COMPUTE_EXCEPTIONS_ENABLED) */
290
291/**< Target enum */
292enum class Target
293{
294 Cpu = AclCpu, /**< Cpu target that leverages SIMD */
295 GpuOcl = AclGpuOcl /**< Gpu target that leverages OpenCL */
296};
297
298/**< Available execution modes */
299enum class ExecutionMode
300{
301 FastRerun = AclPreferFastRerun, /**< Prefer minimum latency in consecutive runs, might introduce higher startup times */
302 FastStart = AclPreferFastStart, /**< Prefer minimizing startup time */
303};
304
305/** Context class
306 *
307 * Context acts as a central aggregate service for further objects created from it.
308 * It provides, internally, common facilities in order to avoid the use of global
309 * statically initialized objects that can lead to important side-effect under
310 * specific execution contexts.
311 *
312 * For example context contains allocators for object creation, for further backing memory allocation,
313 * any serialization interfaces and other modules that affect the construction of objects,
314 * like program caches for OpenCL.
315 */
316class Context : public detail::ObjectBase<AclContext_>
317{
318public:
319 /**< Context options */
320 struct Options
321 {
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000322 static constexpr int32_t num_threads_auto = -1; /**< Allow runtime to specify number of threads */
323
Georgios Pinitas8a5146f2021-01-12 15:51:07 +0000324 /** Default Constructor
325 *
326 * @note By default no precision loss is enabled for operators
327 * @note By default the preferred execution mode is to favor multiple consecutive reruns of an operator
328 */
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000329 Options()
330 : Options(ExecutionMode::FastRerun /* mode */,
331 AclCpuCapabilitiesAuto /* caps */,
332 false /* enable_fast_math */,
333 nullptr /* kernel_config */,
334 num_threads_auto /* max_compute_units */,
335 nullptr /* allocator */)
336 {
337 }
Georgios Pinitas8a5146f2021-01-12 15:51:07 +0000338 /** Constructor
339 *
340 * @param[in] mode Execution mode to be used
341 * @param[in] caps Capabilities to be used
342 * @param[in] enable_fast_math Allow precision loss in favor of performance
343 * @param[in] kernel_config Kernel configuration file containing construction tuning meta-data
344 * @param[in] max_compute_units Max compute units that are expected to used
345 * @param[in] allocator Allocator to be used for internal memory allocation
346 */
347 Options(ExecutionMode mode,
348 AclTargetCapabilities caps,
349 bool enable_fast_math,
350 const char *kernel_config,
351 int32_t max_compute_units,
352 AclAllocator *allocator)
353 {
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000354 copts.mode = detail::as_cenum<AclExecutionMode>(mode);
355 copts.capabilities = caps;
356 copts.enable_fast_math = enable_fast_math;
357 copts.kernel_config_file = kernel_config;
358 copts.max_compute_units = max_compute_units;
359 copts.allocator = allocator;
Georgios Pinitas8a5146f2021-01-12 15:51:07 +0000360 }
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000361
362 AclContextOptions copts{};
Georgios Pinitas8a5146f2021-01-12 15:51:07 +0000363 };
364
365public:
366 /** Constructor
367 *
368 * @note Serves as a simpler delegate constructor
369 * @note As context options, default conservative options will be used
370 *
371 * @param[in] target Target to create context for
372 * @param[out] status Status information if requested
373 */
374 explicit Context(Target target, StatusCode *status = nullptr)
375 : Context(target, Options(), status)
376 {
377 }
378 /** Constructor
379 *
380 * @param[in] target Target to create context for
381 * @param[in] options Context construction options
382 * @param[out] status Status information if requested
383 */
384 Context(Target target, const Options &options, StatusCode *status = nullptr)
385 {
386 AclContext ctx;
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000387 const auto st = detail::as_enum<StatusCode>(AclCreateContext(&ctx, detail::as_cenum<AclTarget>(target), &options.copts));
Georgios Pinitas8a5146f2021-01-12 15:51:07 +0000388 reset(ctx);
Georgios Pinitasc3c352e2021-03-18 10:59:40 +0000389 report_status(st, "[Compute Library] Failed to create context");
Georgios Pinitas8a5146f2021-01-12 15:51:07 +0000390 if(status)
391 {
392 *status = st;
393 }
394 }
395};
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000396
Georgios Pinitasc3c352e2021-03-18 10:59:40 +0000397/**< Available tuning modes */
398enum class TuningMode
399{
400 Rapid = AclRapid,
401 Normal = AclNormal,
402 Exhaustive = AclExhaustive
403};
404
405/** Queue class
406 *
407 * Queue is responsible for the execution related aspects, with main responsibilities those of
408 * scheduling and tuning operators.
409 *
410 * Multiple queues can be created from the same context, and the same operator can be scheduled on each concurrently.
411 *
412 * @note An operator might depend on the maximum possible compute units that are provided in the context,
413 * thus in cases where the number of the scheduling units of the queue are greater might lead to errors.
414 */
415class Queue : public detail::ObjectBase<AclQueue_>
416{
417public:
418 /**< Queue options */
419 struct Options
420 {
421 /** Default Constructor
422 *
423 * As default options, no tuning will be performed, and the number of scheduling units will
424 * depends on internal device discovery functionality
425 */
426 Options()
427 : opts{ AclTuningModeNone, 0 } {};
428 /** Constructor
429 *
430 * @param[in] mode Tuning mode to be used
431 * @param[in] compute_units Number of scheduling units to be used
432 */
433 Options(TuningMode mode, int32_t compute_units)
434 : opts{ detail::as_cenum<AclTuningMode>(mode), compute_units }
435 {
436 }
437
438 AclQueueOptions opts;
439 };
440
441public:
442 /** Constructor
443 *
444 * @note Serves as a simpler delegate constructor
445 * @note As queue options, default conservative options will be used
446 *
447 * @param[in] ctx Context to create queue for
448 * @param[out] status Status information if requested
449 */
450 explicit Queue(Context &ctx, StatusCode *status = nullptr)
451 : Queue(ctx, Options(), status)
452 {
453 }
454 /** Constructor
455 *
456 * @note As queue options, default conservative options will be used
457 *
458 * @param[in] ctx Context from where the queue will be created from
459 * @param[in] options Queue options to be used
460 * @param[out] status Status information if requested
461 */
462 explicit Queue(Context &ctx, const Options &options = Options(), StatusCode *status = nullptr)
463 {
464 AclQueue queue;
465 const auto st = detail::as_enum<StatusCode>(AclCreateQueue(&queue, ctx.get(), &options.opts));
466 reset(queue);
467 report_status(st, "[Compute Library] Failed to create queue!");
468 if(status)
469 {
470 *status = st;
471 }
472 }
473 /** Block until all the tasks of the queue have been marked as finished
474 *
475 * @return Status code
476 */
477 StatusCode finish()
478 {
479 return detail::as_enum<StatusCode>(AclQueueFinish(_object.get()));
480 }
481};
482
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000483/**< Data type enumeration */
484enum class DataType
485{
486 Unknown = AclDataTypeUnknown,
487 UInt8 = AclUInt8,
488 Int8 = AclInt8,
489 UInt16 = AclUInt16,
490 Int16 = AclInt16,
491 UInt32 = AclUint32,
492 Int32 = AclInt32,
493 Float16 = AclFloat16,
494 BFloat16 = AclBFloat16,
495 Float32 = AclFloat32,
496};
497
498/** Tensor Descriptor class
499 *
500 * Structure that contains all the required meta-data to represent a tensor
501 */
502class TensorDescriptor
503{
504public:
505 /** Constructor
506 *
507 * @param[in] shape Shape of the tensor
508 * @param[in] data_type Data type of the tensor
509 */
510 TensorDescriptor(const std::vector<int32_t> &shape, DataType data_type)
511 : _shape(shape), _data_type(data_type)
512 {
513 _cdesc.ndims = _shape.size();
514 _cdesc.shape = _shape.data();
515 _cdesc.data_type = detail::as_cenum<AclDataType>(_data_type);
516 _cdesc.strides = nullptr;
517 _cdesc.boffset = 0;
518 }
Sang-Hoon Parkc6fcfb42021-03-31 15:18:16 +0100519 /** Constructor
520 *
521 * @param[in] desc C-type descriptor
522 */
523 explicit TensorDescriptor(const AclTensorDescriptor &desc)
524 {
525 _cdesc = desc;
526 _data_type = detail::as_enum<DataType>(desc.data_type);
527 _shape.reserve(desc.ndims);
528 for(int32_t d = 0; d < desc.ndims; ++d)
529 {
530 _shape.emplace_back(desc.shape[d]);
531 }
532 }
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000533 /** Get underlying C tensor descriptor
534 *
535 * @return Underlying structure
536 */
537 const AclTensorDescriptor *get() const
538 {
539 return &_cdesc;
540 }
Sang-Hoon Parkc6fcfb42021-03-31 15:18:16 +0100541 /** Operator to compare two TensorDescriptor
542 *
543 * @param[in] other The instance to compare against
544 *
545 * @return True if two instances have the same shape and data type
546 */
547 bool operator==(const TensorDescriptor &other)
548 {
549 bool is_same = true;
550
551 is_same &= _data_type == other._data_type;
552 is_same &= _shape.size() == other._shape.size();
553
554 if(is_same)
555 {
556 for(uint32_t d = 0; d < _shape.size(); ++d)
557 {
558 is_same &= _shape[d] == other._shape[d];
559 }
560 }
561
562 return is_same;
563 }
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000564
565private:
566 std::vector<int32_t> _shape{};
567 DataType _data_type{};
568 AclTensorDescriptor _cdesc{};
569};
570
571/** Import memory types */
572enum class ImportType
573{
574 Host = AclImportMemoryType::AclHostPtr
575};
576
577/** Tensor class
578 *
579 * Tensor is an mathematical construct that can represent an N-Dimensional space.
580 *
581 * @note Maximum dimensionality support is 6 internally at the moment
582 */
583class Tensor : public detail::ObjectBase<AclTensor_>
584{
585public:
586 /** Constructor
587 *
588 * @note Tensor memory is allocated
589 *
590 * @param[in] ctx Context from where the tensor will be created from
591 * @param[in] desc Tensor descriptor to be used
592 * @param[out] status Status information if requested
593 */
594 Tensor(Context &ctx, const TensorDescriptor &desc, StatusCode *status = nullptr)
595 : Tensor(ctx, desc, true, status)
596 {
597 }
598 /** Constructor
599 *
600 * @param[in] ctx Context from where the tensor will be created from
601 * @param[in] desc Tensor descriptor to be used
602 * @param[in] allocate Flag to indicate if the tensor needs to be allocated
603 * @param[out] status Status information if requested
604 */
605 Tensor(Context &ctx, const TensorDescriptor &desc, bool allocate, StatusCode *status)
606 {
607 AclTensor tensor;
608 const auto st = detail::as_enum<StatusCode>(AclCreateTensor(&tensor, ctx.get(), desc.get(), allocate));
609 reset(tensor);
Georgios Pinitasc3c352e2021-03-18 10:59:40 +0000610 report_status(st, "[Compute Library] Failed to create tensor!");
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000611 if(status)
612 {
613 *status = st;
614 }
615 }
616 /** Maps the backing memory of a given tensor that can be used by the host to access any contents
617 *
618 * @return A valid non-zero pointer in case of success else nullptr
619 */
620 void *map()
621 {
622 void *handle = nullptr;
623 const auto st = detail::as_enum<StatusCode>(AclMapTensor(_object.get(), &handle));
Georgios Pinitasc3c352e2021-03-18 10:59:40 +0000624 report_status(st, "[Compute Library] Failed to map the tensor and extract the tensor's backing memory!");
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000625 return handle;
626 }
627 /** Unmaps tensor's memory
628 *
629 * @param[in] handle Handle to unmap
630 *
631 * @return Status code
632 */
633 StatusCode unmap(void *handle)
634 {
635 const auto st = detail::as_enum<StatusCode>(AclUnmapTensor(_object.get(), handle));
Georgios Pinitasc3c352e2021-03-18 10:59:40 +0000636 report_status(st, "[Compute Library] Failed to unmap the tensor!");
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000637 return st;
638 }
639 /** Import external memory to a given tensor object
640 *
641 * @param[in] handle External memory handle
642 * @param[in] type Type of memory to be imported
643 *
644 * @return Status code
645 */
646 StatusCode import(void *handle, ImportType type)
647 {
648 const auto st = detail::as_enum<StatusCode>(AclTensorImport(_object.get(), handle, detail::as_cenum<AclImportMemoryType>(type)));
Georgios Pinitasc3c352e2021-03-18 10:59:40 +0000649 report_status(st, "[Compute Library] Failed to import external memory to tensor!");
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000650 return st;
651 }
Sang-Hoon Parkc6fcfb42021-03-31 15:18:16 +0100652 /** Get the size of the tensor in byte
653 *
654 * @note The size isn't based on allocated memory, but based on information in its descriptor (dimensions, data type, etc.).
655 *
656 * @return The size of the tensor in byte
657 */
658 uint64_t get_size()
659 {
660 uint64_t size{ 0 };
661 const auto st = detail::as_enum<StatusCode>(AclGetTensorSize(_object.get(), &size));
Georgios Pinitasc3c352e2021-03-18 10:59:40 +0000662 report_status(st, "[Compute Library] Failed to get the size of the tensor");
Sang-Hoon Parkc6fcfb42021-03-31 15:18:16 +0100663 return size;
664 }
665 /** Get the descriptor of this tensor
666 *
667 * @return The descriptor describing the characteristics of this tensor
668 */
669 TensorDescriptor get_descriptor()
670 {
671 AclTensorDescriptor desc;
672 const auto st = detail::as_enum<StatusCode>(AclGetTensorDescriptor(_object.get(), &desc));
Georgios Pinitasc3c352e2021-03-18 10:59:40 +0000673 report_status(st, "[Compute Library] Failed to get the descriptor of the tensor");
Sang-Hoon Parkc6fcfb42021-03-31 15:18:16 +0100674 return TensorDescriptor(desc);
675 }
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000676};
677
678/** Tensor pack class
679 *
680 * Pack is a utility construct that is used to create a collection of tensors that can then
681 * be passed into operator as inputs.
682 */
683class TensorPack : public detail::ObjectBase<AclTensorPack_>
684{
685public:
686 /** Pack pair construct */
687 struct PackPair
688 {
689 /** Constructor
690 *
691 * @param[in] tensor_ Tensor to pack
692 * @param[in] slot_id_ Slot identification of the tensor in respect with the operator
693 */
694 PackPair(Tensor *tensor_, int32_t slot_id_)
695 : tensor(tensor_), slot_id(slot_id_)
696 {
697 }
698
699 Tensor *tensor{ nullptr }; /**< Tensor object */
700 int32_t slot_id{ AclSlotUnknown }; /**< Slot id in respect with the operator */
701 };
702
703public:
704 /** Constructor
705 *
706 * @param[in] ctx Context from where the tensor pack will be created from
707 * @param[out] status Status information if requested
708 */
709 explicit TensorPack(Context &ctx, StatusCode *status = nullptr)
710 {
711 AclTensorPack pack;
712 const auto st = detail::as_enum<StatusCode>(AclCreateTensorPack(&pack, ctx.get()));
713 reset(pack);
Georgios Pinitasc3c352e2021-03-18 10:59:40 +0000714 report_status(st, "[Compute Library] Failure during tensor pack creation");
Georgios Pinitas3f26ef42021-02-23 10:01:33 +0000715 if(status)
716 {
717 *status = st;
718 }
719 }
720 /** Add tensor to tensor pack
721 *
722 * @param[in] slot_id Slot id of the tensor in respect with the operator
723 * @param[in] tensor Tensor to be added in the pack
724 *
725 * @return Status code
726 */
727 StatusCode add(Tensor &tensor, int32_t slot_id)
728 {
729 return detail::as_enum<StatusCode>(AclPackTensor(_object.get(), tensor.get(), slot_id));
730 }
731 /** Add a list of tensors to a tensor pack
732 *
733 * @param[in] packed Pair packs to be added
734 *
735 * @return Status code
736 */
737 StatusCode add(std::initializer_list<PackPair> packed)
738 {
739 const size_t size = packed.size();
740 std::vector<int32_t> slots(size);
741 std::vector<AclTensor> tensors(size);
742 int i = 0;
743 for(auto &p : packed)
744 {
745 slots[i] = p.slot_id;
746 tensors[i] = AclTensor(p.tensor);
747 ++i;
748 }
749 return detail::as_enum<StatusCode>(AclPackTensors(_object.get(), tensors.data(), slots.data(), size));
750 }
751};
Georgios Pinitas06ac6e42021-07-05 08:08:52 +0100752
753/** Operator class
754 *
755 * Operators are the basic algorithmic blocks responsible for performing distinct operations
756 */
757class Operator : public detail::ObjectBase<AclOperator_>
758{
759public:
760 /** Run an operator on a given input list
761 *
762 * @param[in,out] queue Queue to scheduler the operator on
763 * @param pack Tensor list to be used as input
764 *
765 * @return Status Code
766 */
767 StatusCode run(Queue &queue, TensorPack &pack)
768 {
769 return detail::as_cenum<StatusCode>(AclRunOperator(_object.get(), queue.get(), pack.get()));
770 }
771
772protected:
773 /** Constructor */
774 Operator() = default;
775};
Georgios Pinitas8a5146f2021-01-12 15:51:07 +0000776} // namespace acl
777#undef ARM_COMPUTE_IGNORE_UNUSED
778#endif /* ARM_COMPUTE_ACL_HPP_ */