1 /**
2  * Copyright (c) Glow Contributors. See CONTRIBUTORS file.
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 #ifndef GLOW_BACKENDS_BACKENDUTILS_H
17 #define GLOW_BACKENDS_BACKENDUTILS_H
18 
19 #include "glow/CodeGen/MemoryAllocator.h"
20 #include "glow/IR/IR.h"
21 
22 #include <map>
23 
24 namespace glow {
25 namespace runtime {
26 
27 /// An enum to indicate what type each symbol in the bundle is.
28 enum class SymbolCategory {
29   Activation,
30   Placeholder,
31   Constant,
32   PlaceholderTensorView,
33   ConstantTensorView
34 };
35 
36 /// Contains information for initialization and handling of symbol at runtime.
37 struct RuntimeSymbolInfo {
38   /// The size in bytes.
39   size_t size{0};
40   /// Offset in bytes from the base address.
41   size_t offset{0};
42   /// Type of symbol.
43   Type type;
44   /// Is the symbol an input for the function.
45   bool input{true};
46   /// Is the symbol an output for the function.
47   bool output{true};
48   /// Indicates what category the symbol is.
49   SymbolCategory symbolCategory;
50 };
51 
52 using SymbolTableTy = std::map<std::string, RuntimeSymbolInfo>;
53 
54 /// Contains the information needed to be passed forward from compile time to
55 /// runtime. In order to allocate and initialize memory.
56 class RuntimeBundle {
57   /// Map from symbol name to a RuntimeSymbolInfo.
58   SymbolTableTy symbolTable_;
59   /// Pointer to memory containing the weights for execution.
60   uint8_t *constants_{nullptr};
61   /// Amount of memory needed for weights.
62   size_t constantWeightVarsMemSize_{0};
63   /// Amount of memory needed for mutable vars.
64   size_t mutableWeightVarsMemSize_{0};
65   /// Amount of memory needed for activations.
66   size_t activationsMemSize_{0};
67   /// True if the RuntimeBundle is valid, false if not.
68   bool isValid_{false};
69 
70 public:
71   /// Get Constant Weights memory size.
getConstantWeightSize()72   size_t getConstantWeightSize() const { return constantWeightVarsMemSize_; }
73   /// Get Mutable Weights memory size.
getMutableWeightSize()74   size_t getMutableWeightSize() const { return mutableWeightVarsMemSize_; }
75   /// Get Activations Weights memory size.
getActivationsSize()76   size_t getActivationsSize() const { return activationsMemSize_; }
77   /// Get pointer to memory block of constants.
getConstants()78   uint8_t *getConstants() const { return constants_; }
79   /// Set pointer to memory block of constants.
setConstants(uint8_t * constants)80   void setConstants(uint8_t *constants) { constants_ = constants; }
81   /// Helper function, gets offset of \p v.
82   size_t getValueOffset(const Named *v) const;
83   /// Helper function, gets symbol info for \p v.
84   const RuntimeSymbolInfo &getSymbolInfo(const Named *v) const;
85   /// Get a const reference to the symbol table.
getSymbolTable()86   const SymbolTableTy &getSymbolTable() const { return symbolTable_; }
87   /// At compile time condense constants to a single block of memory.
88   /// This allows the graph to go away after compile time.
89   /// Allocates a block of memory of size \p constantMaxSize then walks the
90   /// given function \p F and and copies weights to their address as specified
91   /// by offsets contained in symbolTable_.
92   void collectConstants(const IRFunction *F);
93   void collectConstants(const Module *M);
94   /// Free constants.
95   void freeConstants();
96 
97   /// Sets the input and output flags for each symbol in the symbolBundle.
98   void setInputsandOutputs();
99 
100   /// Computes offsets and total allocation for Constants, Placeholders, and
101   /// Activations to build runtime symbol table. Returns RuntimeBundle.
102   static runtime::RuntimeBundle create(const IRFunction &F,
103                                        MemoryAllocator &constantAllocator,
104                                        MemoryAllocator &placeholderAllocator,
105                                        MemoryAllocator &activationsAllocator);
106 
107   /// Computes offsets and total allocation for Constants, Placeholders, and
108   /// Activations to build runtime symbol table. \returns RuntimeBundle.
109   /// Constants and Placeholders are taken from \p F, and all Activations
110   /// required by each function in \p funcs are placed into the same
111   /// RuntimeBundle.
112   static runtime::RuntimeBundle
113   create(const Function &F, const std::vector<const IRFunction *> &funcs);
114 
115   /// Computes offsets and total allocations for Constants, Placeholders, and
116   /// Activations to build runtime symbol table. \returns RuntimeBundle. Uses a
117   /// single allocator \p allocator and allocates all buffers contiguously in
118   /// the same block.
119   static runtime::RuntimeBundle create(const IRFunction &F,
120                                        MemoryAllocator &allocator);
121 
122   /// Build a runtime symbol table from a Function.  Computes Constant and
123   /// Placeholder sizes, but not Activations, since Functions are unserialized.
124   /// Only use this method to generate bundles for backends that do not use
125   /// Glow's IR.
126   static runtime::RuntimeBundle create(const Function &F);
127 
128   /// Deleted default constructor.  A properly constructed RuntimeBundle is
129   /// necessary for correct execution using the HostManager.
130   RuntimeBundle() = delete;
131 
132   // Constructor.
RuntimeBundle(SymbolTableTy & symbolTable,size_t constWeight,size_t mutableWeight,size_t activations)133   RuntimeBundle(SymbolTableTy &symbolTable, size_t constWeight,
134                 size_t mutableWeight, size_t activations)
135       : symbolTable_(std::move(symbolTable)), constants_(nullptr),
136         constantWeightVarsMemSize_(constWeight),
137         mutableWeightVarsMemSize_(mutableWeight),
138         activationsMemSize_(activations), isValid_(true) {}
139 
140   // Explicit copy constructor and deleted assignment operator. A RuntimeBundle
141   // should be moved. It should only be copied if absolutely necessary and never
142   // implicitly.
143   explicit RuntimeBundle(const RuntimeBundle &) = default;
144   RuntimeBundle &operator=(const RuntimeBundle &) = delete;
145 
146   // Move constructor and assignment operator.
147   RuntimeBundle(RuntimeBundle &&rhs);
148   RuntimeBundle &operator=(RuntimeBundle &&rhs);
149 };
150 } // namespace runtime
151 
152 /// Generates a struct named has_\p METHOD_NAME that looks for a method called
153 /// \p METHOD_NAME inside of ClassName with return type ReturnType.
154 #define CLASS_CONTAINS_METHOD(METHOD_NAME)                                     \
155   template <typename ClassName, typename ReturnType>                           \
156   struct has_##METHOD_NAME {                                                   \
157   private:                                                                     \
158     template <typename T>                                                      \
159     static constexpr auto check(T *) ->                                        \
160         typename std::is_same<decltype(std::declval<T>().METHOD_NAME()),       \
161                               ReturnType>::type;                               \
162     template <typename> static constexpr std::false_type check(...);           \
163     typedef decltype(check<ClassName>(0)) type;                                \
164                                                                                \
165   public:                                                                      \
166     static constexpr bool value = type::value;                                 \
167   };
168 
169 /// Use template meta-programming to check if typename ClassName contains
170 /// getFusedActivation() method. Below generates a struct named
171 /// has_getFusedActivation that looks for said method.
172 CLASS_CONTAINS_METHOD(getFusedActivation)
173 
174 /// If \p PH is an output placeholder in the IRFunction \p F,
175 /// \returns true.
176 /// This is determined by checking if the PH has weights which are referenced by
177 /// other Instructions as OperandKind::InOut or OperandKind::Out.
178 bool isOutput(const Placeholder *PH, const IRFunction &F);
179 
180 /// If \p PH is an input placeholder in the IRFunction \p F,
181 /// \returns true.
182 /// This is determined by checking if the PH is always used as an @in parameter
183 /// by the current function.
184 bool isInput(const Placeholder *PH, const IRFunction &F);
185 
186 /// If \p N does not have fused activation \returns true.
187 template <typename T,
188           std::enable_if_t<!has_getFusedActivation<T, FusedActivation>::value,
189                            int> = 0>
checkNoFusion(const T & N)190 bool checkNoFusion(const T &N) {
191   (void)N;
192   return true;
193 }
194 
195 /// If \p N does not have fused activation \returns true.
196 template <typename T,
197           std::enable_if_t<has_getFusedActivation<T, FusedActivation>::value,
198                            int> = 0>
checkNoFusion(const T & N)199 bool checkNoFusion(const T &N) {
200   if (N.getFusedActivation() != FusedActivation::NONE) {
201     report("Glow backend does not support fused Activations for: " +
202            std::string(N.getKindName()));
203     return false;
204   }
205   return true;
206 }
207 
208 /// If \p N does not have fused activation \returns true.
209 bool checkNoFusionForNode(const Node &N);
210 
211 /// If \p I does not have fused activation \returns true.
212 bool checkNoFusionForInstr(const Instruction &I);
213 
214 /// Contains information for placeholder during allocation.
215 struct PlaceholderInputOutputInfo {
216   /// The placeholder address.
217   const Placeholder *addr;
218   /// Is the placeholder an input for the function.
219   bool isInput;
220   /// Is the placeholder an onput for the function.
221   bool isOutput;
222 };
223 
224 using ContiguousPlaceholders = std::vector<PlaceholderInputOutputInfo>;
225 
226 /// Convert placeholders to be ordered as input|inputOutput|output|neither.
227 /// Packed into {Placeholder *, isInput, isOutput} as
228 /// PlaceholderInputOutputInfo. FUN could be Function or IRFunction. ARR could
229 /// be std::list<Placeholder *> or std::vector<const Placeholder *>
230 template <typename FUN, typename ARR>
231 ContiguousPlaceholders getContiguousPlaceHolder(const ARR &holders,
232                                                 const FUN &F);
233 
234 /// \returns true if \p V is capable of handling a partial tensor as input.
235 bool allowsPartialInput(const Placeholder *V, const Function *F);
236 
237 /// \returns true if \p V requires last-element padding
238 bool requiresPadding(const Placeholder *V, const Function *F);
239 
240 /// \returns true if \p V is used in \p F; false otherwise.
241 bool usedInFunction(const Placeholder *V, const Function *F);
242 
243 } // end namespace glow
244 #endif // GLOW_BACKENDS_BACKENDUTILS_H
245