1 | /******************************************************************************* |
2 | * Copyright 2022 Intel Corporation |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | *******************************************************************************/ |
16 | |
17 | #ifndef COMMON_RESOURCE_HPP |
18 | #define COMMON_RESOURCE_HPP |
19 | |
20 | #include <assert.h> |
21 | #include <unordered_map> |
22 | |
23 | #include "c_types_map.hpp" |
24 | #include "oneapi/dnnl/dnnl.h" |
25 | |
26 | namespace dnnl { |
27 | namespace impl { |
28 | |
29 | // The resource_t abstraction is a base class for all resource classes. |
30 | // Those are responsible for holding a part of a primitive implementation that |
31 | // cannot be stored in the primitive cache as part of the implementation. |
32 | // Currently, there are two such things: |
33 | // 1. Any memory (memory_t, memory_storage_t, etc...), because it contains |
34 | // an engine. |
35 | // 2. (for GPU only) compiled kernels, because they are context dependent. |
36 | // |
37 | // The idea is that each primitive implementation should be able to create |
38 | // a resource and put there everything it needs to run, which cannot be stored |
39 | // in the cache as part of the primitive implementation. To create the resource |
40 | // each primitive implementation can override a function `create_resource`. |
41 | // |
42 | // This abstraction takes ownership of all content it holds hence it should be |
43 | // responsible for destroying it as well. |
44 | struct resource_t : public c_compatible { |
45 | virtual ~resource_t() = default; |
46 | }; |
47 | |
48 | // The resource_mapper_t is an abstraction for holding resources for |
49 | // a particular primitive implementation and providing corresponding mapping. |
50 | // |
51 | // Interacting with the mapper happens in two steps: |
52 | // 1. Initialization. Each derived from impl::primitive_t class may define |
53 | // `create_resource` member function that is responsible for creating a |
54 | // certain derived from resource_t object and filling it with some content, |
55 | // e.g. memory for scales, OpenCL kernels etc... |
56 | // 2. Passing it to the execution function which extracts needed resources and |
57 | // uses them at execution time. The mapper is passed to the execution function |
58 | // with the execution context. |
59 | // |
60 | // The resource_mapper_t takes ownership of all resources hence it should be |
61 | // responsible for destroying them as well. |
62 | struct primitive_t; |
63 | struct resource_mapper_t { |
64 | using key_t = const primitive_t; |
65 | using mapped_t = std::unique_ptr<resource_t>; |
66 | |
67 | resource_mapper_t() = default; |
68 | |
69 | bool has_resource(const primitive_t *p) const { |
70 | return primitive_to_resource_.count(p); |
71 | } |
72 | |
73 | void add(key_t *p, mapped_t &&r) { |
74 | assert(primitive_to_resource_.count(p) == 0); |
75 | primitive_to_resource_.emplace(p, std::move(r)); |
76 | } |
77 | |
78 | template <typename T> |
79 | const T *get(key_t *p) const { |
80 | assert(primitive_to_resource_.count(p)); |
81 | return utils::downcast<T *>(primitive_to_resource_.at(p).get()); |
82 | } |
83 | |
84 | DNNL_DISALLOW_COPY_AND_ASSIGN(resource_mapper_t); |
85 | |
86 | private: |
87 | std::unordered_map<key_t *, mapped_t> primitive_to_resource_; |
88 | }; |
89 | |
90 | } // namespace impl |
91 | } // namespace dnnl |
92 | |
93 | #endif |
94 | |