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 | |
17 | #include "benchmark/benchmark.h" |
18 | |
19 | #include "glow/Backends/DeviceManager.h" |
20 | #include "glow/Optimizer/GraphOptimizer/GraphOptimizer.h" |
21 | #include "glow/Runtime/Executor/ThreadPoolExecutor.h" |
22 | #include "glow/Runtime/HostManager/HostManager.h" |
23 | |
24 | #include "CPUBackend.h" |
25 | |
26 | #include <future> |
27 | |
28 | using namespace glow; |
29 | using namespace glow::runtime; |
30 | |
31 | //===--------------------------------------------------------------------===// |
32 | // Benchmark Declaration and Instantiation Macros // |
33 | //===--------------------------------------------------------------------===// |
34 | |
35 | /// Declare a subclass of ExecutorBenchmark and override its setUpModule and |
36 | /// setUpDAG methods with the given moduleCreator and dagCreator functions. |
37 | #define DECLARE_EXECUTOR_BENCHMARK(name, moduleCreator, dagCreator) \ |
38 | template <typename BackendTy> \ |
39 | class name##ExecutorBenchmark : public ExecutorBenchmark<BackendTy> { \ |
40 | protected: \ |
41 | void setUpModule(benchmark::State &state) override { \ |
42 | this->mod_ = moduleCreator(); \ |
43 | } \ |
44 | void setUpDAG(benchmark::State &state) override { \ |
45 | this->dag_ = dagCreator(this->deviceManagersFunctions_[0]); \ |
46 | this->dag_->root->module = this->mod_.get(); \ |
47 | } \ |
48 | }; |
49 | |
50 | /// Declare a subclass of an arbitrary Benchmark class and override its |
51 | /// setUpModule method with the given moduleCreator function. |
52 | #define DECLARE_RUNTIME_COMPONENT_BENCHMARK(name, moduleCreator, component) \ |
53 | template <typename BackendTy> \ |
54 | class name##component##Benchmark : public component##Benchmark<BackendTy> { \ |
55 | protected: \ |
56 | void setUpModule(benchmark::State &state) override { \ |
57 | this->mod_ = moduleCreator(); \ |
58 | } \ |
59 | }; |
60 | |
61 | /// Declare subclasses of all RuntimeBenchmark subclasses with appropriate |
62 | /// overrides. |
63 | #define DECLARE_RUNTIME_BENCHMARK(name, moduleCreator, dagCreator) \ |
64 | DECLARE_RUNTIME_COMPONENT_BENCHMARK(name, moduleCreator, HostManager) \ |
65 | DECLARE_EXECUTOR_BENCHMARK(name, moduleCreator, dagCreator) \ |
66 | DECLARE_RUNTIME_COMPONENT_BENCHMARK(name, moduleCreator, DeviceManager) |
67 | |
68 | /// Define a RuntimeBenchmark subclass declared using |
69 | /// DECLARE_XXX_BENCHMARK for a specific backend and component. This instance |
70 | /// calls RuntimeBenchmark::runBenchmark to run the benchmark. |
71 | #define INSTANTIATE_RUNTIME_COMPONENT_BENCHMARK(name, backend, component) \ |
72 | BENCHMARK_TEMPLATE_DEFINE_F(name##component##Benchmark, component##backend, \ |
73 | backend) \ |
74 | (benchmark::State & state) { runBenchmark(state); } \ |
75 | BENCHMARK_REGISTER_F(name##component##Benchmark, component##backend) \ |
76 | ->Unit(benchmark::kMicrosecond); |
77 | |
78 | /// Define RuntimeBenchmark subclasses for all runtime components. |
79 | #define INSTANTIATE_RUNTIME_BENCHMARK(name, backend) \ |
80 | INSTANTIATE_RUNTIME_COMPONENT_BENCHMARK(name, backend, HostManager) \ |
81 | INSTANTIATE_RUNTIME_COMPONENT_BENCHMARK(name, backend, Executor) \ |
82 | INSTANTIATE_RUNTIME_COMPONENT_BENCHMARK(name, backend, DeviceManager) |
83 | |
84 | //===--------------------------------------------------------------------===// |
85 | // Common Utility Functions // |
86 | //===--------------------------------------------------------------------===// |
87 | |
88 | /// Set up a DeviceManager instance by instantiating it, compiling all the |
89 | /// functions in \p mod using \p backend and adding them to the DeviceManager |
90 | /// instance. A reference to the configured DeviceManager instance is returned |
91 | /// in \p deviceManager, and all CompiledFunctions creating during compilation |
92 | /// are returned in \p deviceManagerFunctions. |
93 | void setUpDeviceManagerCommon( |
94 | benchmark::State &state, std::unique_ptr<Backend> &backend, |
95 | std::unique_ptr<Module> &mod, std::unique_ptr<DeviceManager> &deviceManager, |
96 | std::unordered_map<std::string, std::unique_ptr<CompiledFunction>> |
97 | &deviceManagerFunctions) { |
98 | |
99 | // Check that the backend is valid. |
100 | if (!backend) { |
101 | state.SkipWithError("Unable to set up DeviceManager - backend not set up!" ); |
102 | return; |
103 | } |
104 | |
105 | // Check that the module is valid. |
106 | if (!mod) { |
107 | state.SkipWithError("Unable to set up DeviceManager - module not set up!" ); |
108 | return; |
109 | } |
110 | |
111 | // Create and initialize the DeviceManager instance. |
112 | deviceManager = |
113 | std::unique_ptr<DeviceManager>(DeviceManager::createDeviceManager( |
114 | DeviceConfig(backend->getBackendName()))); |
115 | bool error = ERR_TO_BOOL(deviceManager->init()); |
116 | |
117 | if (error) { |
118 | state.SkipWithError("Unable to set up DeviceManager - failed to " |
119 | "initialize DeviceManager!" ); |
120 | return; |
121 | } |
122 | |
123 | FunctionMapTy funcs; |
124 | CompilationContext cctx; |
125 | |
126 | // Compile all functions in the module. |
127 | for (auto *function : mod->getFunctions()) { |
128 | EXIT_ON_ERR(::glow::optimizeFunction(function, *backend, cctx)); |
129 | std::unique_ptr<CompiledFunction> compiledFunction = |
130 | EXIT_ON_ERR(backend->compile(function)); |
131 | funcs.insert(std::make_pair(function->getName(), compiledFunction.get())); |
132 | deviceManagerFunctions.insert( |
133 | std::make_pair(function->getName(), std::move(compiledFunction))); |
134 | } |
135 | |
136 | // Add all compiled functions to the DeviceManager instance. |
137 | std::promise<bool> promise; |
138 | std::future<bool> future = promise.get_future(); |
139 | deviceManager->addNetwork(mod.get(), funcs, |
140 | [&promise](const Module * /*mod*/, Error err) { |
141 | promise.set_value(ERR_TO_BOOL(std::move(err))); |
142 | }); |
143 | future.wait(); |
144 | error = future.get(); |
145 | |
146 | if (error) { |
147 | state.SkipWithError( |
148 | "Unable to set up DeviceManager - failed to add functions!" ); |
149 | } |
150 | } |
151 | |
152 | /// Tear down a DeviceManager instance (\p deviceManager) by evicted all |
153 | /// functions added to it and shutting down the device. \p |
154 | /// deviceManagerFunctions contains the names of all resident functions. |
155 | void tearDownDeviceManagerCommon( |
156 | benchmark::State &state, std::unique_ptr<DeviceManager> &deviceManager, |
157 | std::unordered_map<std::string, std::unique_ptr<CompiledFunction>> |
158 | &deviceManagerFunctions) { |
159 | // Check that the DeviceManager is valid. |
160 | if (!deviceManager) { |
161 | state.SkipWithError( |
162 | "Unable to tear down DeviceManager - DeviceManager not set up!" ); |
163 | } |
164 | |
165 | // Evict all functions from the DeviceManager instance. |
166 | for (const auto &func : deviceManagerFunctions) { |
167 | std::promise<bool> promise; |
168 | std::future<bool> future = promise.get_future(); |
169 | deviceManager->evictNetwork( |
170 | func.first, [&promise](std::string /*name*/, Error err) { |
171 | promise.set_value(ERR_TO_BOOL(std::move(err))); |
172 | }); |
173 | future.wait(); |
174 | bool error = future.get(); |
175 | |
176 | if (error) { |
177 | state.SkipWithError("Unable to tear down DeviceManager - could not " |
178 | "evict all functions!" ); |
179 | } |
180 | } |
181 | |
182 | deviceManagerFunctions.clear(); |
183 | |
184 | // Stop the device. |
185 | bool error = ERR_TO_BOOL(deviceManager->stop()); |
186 | if (error) { |
187 | state.SkipWithError("Unable to tear down DeviceManager - failed to stop " |
188 | "DeviceManager!" ); |
189 | } |
190 | } |
191 | |
192 | //===--------------------------------------------------------------------===// |
193 | // Benchmark Template Fixture Classes // |
194 | //===--------------------------------------------------------------------===// |
195 | |
196 | /// Abstract base class for all runtime benchmarks. Other than definining the |
197 | /// benchmark interface, this class contains the Backend, Module and |
198 | /// ExecutionContext instances used by all benchmark types. |
199 | template <typename BackendTy> |
200 | class RuntimeBenchmark : public benchmark::Fixture { |
201 | public: |
202 | /// Set up to run the benchmark. |
203 | void SetUp(benchmark::State &state) override { |
204 | setUpBackend(state); |
205 | setUpModule(state); |
206 | setUpExecutionContext(state); |
207 | } |
208 | |
209 | /// Tear down after the benchmark has run. |
210 | void TearDown(benchmark::State &state) override { |
211 | tearDownExecutionContext(state); |
212 | tearDownModule(state); |
213 | tearDownBackend(state); |
214 | } |
215 | |
216 | protected: |
217 | std::unique_ptr<Backend> &getBackend() { return backend_; } |
218 | void setUpBackend(benchmark::State &state) { |
219 | backend_ = glow::make_unique<BackendTy>(); |
220 | } |
221 | virtual void tearDownBackend(benchmark::State &state) {} |
222 | |
223 | std::unique_ptr<Module> &getModule() { return mod_; } |
224 | /// Create the module that will be used for the benchmark. |
225 | virtual void setUpModule(benchmark::State &state) = 0; |
226 | virtual void tearDownModule(benchmark::State &state) {} |
227 | |
228 | std::unique_ptr<ExecutionContext> &getExecutionContext() { return ctx_; } |
229 | virtual void setUpExecutionContext(benchmark::State &state) { |
230 | // Check that the module is valid. |
231 | if (!mod_) { |
232 | state.SkipWithError( |
233 | "Unable to set up execution context - module not set up!" ); |
234 | return; |
235 | } |
236 | |
237 | // Allocate all Placeholders in mod_ and move the bindings into an |
238 | // ExecutionContext object. |
239 | auto bindings = glow::make_unique<PlaceholderBindings>(); |
240 | bindings->allocate(mod_->getPlaceholders()); |
241 | ctx_ = glow::make_unique<ExecutionContext>(std::move(bindings)); |
242 | } |
243 | virtual void tearDownExecutionContext(benchmark::State &state) {} |
244 | |
245 | virtual void runBenchmark(benchmark::State &state) = 0; |
246 | |
247 | /// An instance of the Backend the benchmark is running against. |
248 | std::unique_ptr<Backend> backend_; |
249 | /// The module to use for the benchmark. |
250 | std::unique_ptr<Module> mod_; |
251 | /// The execution context to use for the benchmark. |
252 | std::unique_ptr<ExecutionContext> ctx_; |
253 | }; |
254 | |
255 | /// RuntimeBenchmark subclass that benchmarks at the HostManager level (i.e. |
256 | /// HostManager + Executor + DeviceManager). |
257 | template <typename BackendTy> |
258 | class HostManagerBenchmark : public RuntimeBenchmark<BackendTy> { |
259 | public: |
260 | void SetUp(benchmark::State &state) override { |
261 | RuntimeBenchmark<BackendTy>::SetUp(state); |
262 | setUpHostManager(state); |
263 | } |
264 | |
265 | void TearDown(benchmark::State &state) override { |
266 | RuntimeBenchmark<BackendTy>::TearDown(state); |
267 | tearDownHostManager(state); |
268 | } |
269 | |
270 | protected: |
271 | virtual void setUpHostManager(benchmark::State &state) { |
272 | // Get references to the backend and module stored in the parent class. |
273 | // this->xxx() must be used since this is a template class (as is its |
274 | // superclass). |
275 | std::unique_ptr<Backend> &backend = this->getBackend(); |
276 | std::unique_ptr<Module> &mod = this->getModule(); |
277 | |
278 | // Check that the backend is valid. |
279 | if (!backend) { |
280 | state.SkipWithError( |
281 | "Unable to set up host manager - backend not set up!" ); |
282 | return; |
283 | } |
284 | |
285 | // Check that the module is valid. |
286 | if (!mod) { |
287 | state.SkipWithError("Unable to set up host manager - module not set up!" ); |
288 | return; |
289 | } |
290 | |
291 | // Create DeviceConfigs with which to initialize the HostManager |
292 | // instance. |
293 | std::vector<std::unique_ptr<DeviceConfig>> configs; |
294 | for (unsigned i = 0; i < numDeviceManagers_; ++i) { |
295 | configs.emplace_back( |
296 | glow::make_unique<DeviceConfig>(backend->getBackendName())); |
297 | } |
298 | |
299 | // Create and initialize the HostManager instance. |
300 | hostManager_ = glow::make_unique<HostManager>(std::move(configs)); |
301 | |
302 | // Remember the names of all functions in the module before passing |
303 | // ownership to the HostManager. |
304 | for (auto *function : mod->getFunctions()) { |
305 | functions_.emplace_back(function->getName()); |
306 | } |
307 | |
308 | // Add the module to the HostManager instance. |
309 | CompilationContext cctx; |
310 | bool error = ERR_TO_BOOL(hostManager_->addNetwork(std::move(mod), cctx)); |
311 | if (error) { |
312 | state.SkipWithError("Unable to set up host manager - failed to add " |
313 | "module!" ); |
314 | } |
315 | } |
316 | |
317 | virtual void tearDownHostManager(benchmark::State &state) { |
318 | // Check that the HostManager instance is valid. |
319 | if (!hostManager_) { |
320 | state.SkipWithError( |
321 | "Unable to tear down host manager - host manager not set up!" ); |
322 | return; |
323 | } |
324 | |
325 | // Clear all networks and stop all devices. |
326 | bool error = ERR_TO_BOOL(hostManager_->clearHost()); |
327 | if (error) { |
328 | state.SkipWithError( |
329 | "Unable to tear down host manager - failed to clear host!" ); |
330 | } |
331 | |
332 | functions_.clear(); |
333 | } |
334 | |
335 | void runBenchmark(benchmark::State &state) override { |
336 | // Get references to the context stored in the parent class. |
337 | // this->xxx() must be used since this is a template class (as is its |
338 | // superclass). |
339 | std::unique_ptr<ExecutionContext> &ctx = this->getExecutionContext(); |
340 | |
341 | for (auto _ : state) { |
342 | // Run all functions in the module synchronously. |
343 | for (const auto &function : functions_) { |
344 | std::promise<void> promise; |
345 | std::future<void> future = promise.get_future(); |
346 | hostManager_->runNetwork( |
347 | function, std::move(ctx), |
348 | [&promise, &ctx](runtime::RunIdentifierTy /*runId*/, Error err, |
349 | std::unique_ptr<ExecutionContext> result) { |
350 | // We don't care about the result but check the error to avoid |
351 | // uncheck error error. |
352 | ERR_TO_BOOL(std::move(err)); |
353 | ctx = std::move(result); |
354 | promise.set_value(); |
355 | }); |
356 | future.wait(); |
357 | } |
358 | } |
359 | } |
360 | |
361 | /// The HostManager instance being benchmarked. |
362 | std::unique_ptr<HostManager> hostManager_; |
363 | /// The number of DeviceManagers to use during the benchmark. |
364 | static constexpr unsigned numDeviceManagers_{1}; |
365 | /// List of functions in the module. |
366 | std::vector<std::string> functions_; |
367 | }; |
368 | |
369 | /// RuntimeBenchmark subclass that benchmarks at the Executor level (i.e. |
370 | /// Executor + DeviceManager). |
371 | template <typename BackendTy> |
372 | class ExecutorBenchmark : public RuntimeBenchmark<BackendTy> { |
373 | public: |
374 | void SetUp(benchmark::State &state) override { |
375 | RuntimeBenchmark<BackendTy>::SetUp(state); |
376 | setUpExecutor(state); |
377 | } |
378 | |
379 | void TearDown(benchmark::State &state) override { |
380 | RuntimeBenchmark<BackendTy>::TearDown(state); |
381 | tearDownExecutor(state); |
382 | } |
383 | |
384 | protected: |
385 | virtual void setUpDeviceManagers(benchmark::State &state) { |
386 | // Get references to the backend and module stored in the parent class. |
387 | // this->xxx() must be used since this is a template class (as is its |
388 | // superclass). |
389 | std::unique_ptr<Backend> &backend = this->getBackend(); |
390 | std::unique_ptr<Module> &module = this->getModule(); |
391 | |
392 | // Create numDeviceManagers_ DeviceManagers and store references to them as |
393 | // well as the CompiledFunctions loaded onto them. |
394 | for (unsigned i = 0; i < numDeviceManagers_; ++i) { |
395 | std::unique_ptr<DeviceManager> deviceManager; |
396 | std::unordered_map<std::string, std::unique_ptr<CompiledFunction>> |
397 | deviceManagerFunctions; |
398 | setUpDeviceManagerCommon(state, backend, module, deviceManager, |
399 | deviceManagerFunctions); |
400 | deviceManagers_.insert(std::make_pair(i, std::move(deviceManager))); |
401 | deviceManagersFunctions_.insert( |
402 | std::make_pair(i, std::move(deviceManagerFunctions))); |
403 | } |
404 | } |
405 | |
406 | virtual void tearDownDeviceManagers(benchmark::State &state) { |
407 | // Tear down the numDeviceManagers_ DeviceManagers used for the benchmark. |
408 | for (unsigned i = 0; i < numDeviceManagers_; ++i) { |
409 | tearDownDeviceManagerCommon(state, deviceManagers_[i], |
410 | deviceManagersFunctions_[i]); |
411 | deviceManagers_.erase(i); |
412 | deviceManagersFunctions_.erase(i); |
413 | } |
414 | } |
415 | |
416 | virtual void setUpExecutor(benchmark::State &state) { |
417 | setUpDeviceManagers(state); |
418 | executor_ = std::unique_ptr<ThreadPoolExecutor>( |
419 | new ThreadPoolExecutor(deviceManagers_)); |
420 | setUpDAG(state); |
421 | executor_->createPool(dag_->root.get(), 1, false, false); |
422 | } |
423 | |
424 | virtual void tearDownExecutor(benchmark::State &state) { |
425 | tearDownDeviceManagers(state); |
426 | |
427 | if (!executor_) { |
428 | state.SkipWithError( |
429 | "Unable to tear down executor - executor not set up!" ); |
430 | } |
431 | |
432 | executor_->shutdown(); |
433 | tearDownDAG(state); |
434 | } |
435 | |
436 | /// Set up the executor DAG that the Executor taken in as input to |
437 | /// Executor::run(). |
438 | virtual void setUpDAG(benchmark::State &state) = 0; |
439 | /// Tear down the executor DAG. |
440 | virtual void tearDownDAG(benchmark::State &state) {} |
441 | |
442 | virtual void runBenchmark(benchmark::State &state) override { |
443 | // Get a reference to the context stored in the parent class. |
444 | // this->xxx() must be used since this is a template class (as is its |
445 | // superclass). |
446 | std::unique_ptr<ExecutionContext> &ctx = this->getExecutionContext(); |
447 | for (auto _ : state) { |
448 | // Run the DAG synchronously. |
449 | std::promise<void> promise; |
450 | std::future<void> future = promise.get_future(); |
451 | executor_->run( |
452 | (dag_->root).get(), std::move(ctx), /*runId=*/0, |
453 | [&promise, &ctx](runtime::RunIdentifierTy /*runId*/, Error err, |
454 | std::unique_ptr<ExecutionContext> result) { |
455 | // We don't care about the result but check the error to avoid |
456 | // uncheck error error. |
457 | ERR_TO_BOOL(std::move(err)); |
458 | ctx = std::move(result); |
459 | promise.set_value(); |
460 | }); |
461 | future.wait(); |
462 | } |
463 | } |
464 | |
465 | /// The Executor instance being benchmarked. |
466 | std::unique_ptr<Executor> executor_; |
467 | /// The DAG needed by the Executor. |
468 | std::unique_ptr<DAG> dag_; |
469 | /// The number of DeviceManagers to create. |
470 | static constexpr unsigned numDeviceManagers_{1}; |
471 | /// The DeviceManagers used by the Executor during the benchmark (map from |
472 | /// DeviceID -> DeviceManager). |
473 | DeviceManagerMapTy deviceManagers_; |
474 | /// The CompiledFunctions loaded on the DeviceManagers used by the Executor |
475 | /// during the benchmark (map from DeviceID -> (map from string -> |
476 | /// CompiledFunction)). |
477 | std::unordered_map< |
478 | DeviceIDTy, |
479 | std::unordered_map<std::string, std::unique_ptr<CompiledFunction>>> |
480 | deviceManagersFunctions_; |
481 | }; |
482 | |
483 | /// RuntimeBenchmark subclass that benchmarks at the DeviceManager level. |
484 | template <typename BackendTy> |
485 | class DeviceManagerBenchmark : public RuntimeBenchmark<BackendTy> { |
486 | public: |
487 | void SetUp(benchmark::State &state) override { |
488 | RuntimeBenchmark<BackendTy>::SetUp(state); |
489 | setUpDeviceManager(state); |
490 | } |
491 | |
492 | void TearDown(benchmark::State &state) override { |
493 | tearDownDeviceManager(state); |
494 | RuntimeBenchmark<BackendTy>::TearDown(state); |
495 | } |
496 | |
497 | protected: |
498 | virtual void setUpDeviceManager(benchmark::State &state) { |
499 | setUpDeviceManagerCommon(state, this->getBackend(), this->getModule(), |
500 | deviceManager_, deviceManagerFunctions_); |
501 | } |
502 | |
503 | virtual void tearDownDeviceManager(benchmark::State &state) { |
504 | tearDownDeviceManagerCommon(state, deviceManager_, deviceManagerFunctions_); |
505 | } |
506 | |
507 | virtual void runBenchmark(benchmark::State &state) override { |
508 | // Get a reference to the context stored in the parent class. |
509 | // this->xxx() must be used since this is a template class (as is its |
510 | // superclass). |
511 | std::unique_ptr<ExecutionContext> &ctx = this->getExecutionContext(); |
512 | for (auto _ : state) { |
513 | // Run all functions added to the DeviceManager. |
514 | for (const auto &func : deviceManagerFunctions_) { |
515 | std::promise<void> promise; |
516 | std::future<void> future = promise.get_future(); |
517 | deviceManager_->runFunction( |
518 | func.first, std::move(ctx), |
519 | [&promise, &ctx](runtime::RunIdentifierTy /*runId*/, Error err, |
520 | std::unique_ptr<ExecutionContext> result) { |
521 | // We don't care about the result but check the error to avoid |
522 | // uncheck error error. |
523 | ERR_TO_BOOL(std::move(err)); |
524 | ctx = std::move(result); |
525 | promise.set_value(); |
526 | }); |
527 | future.wait(); |
528 | } |
529 | } |
530 | } |
531 | |
532 | /// The DeviceManager instance being benchmarked. |
533 | std::unique_ptr<DeviceManager> deviceManager_; |
534 | /// All of the CompiledFunctions added to the DeviceManager (they have to be |
535 | /// kept somewhere since the DeviceManager class does not own them). |
536 | std::unordered_map<std::string, std::unique_ptr<CompiledFunction>> |
537 | deviceManagerFunctions_; |
538 | }; |
539 | |
540 | //===--------------------------------------------------------------------===// |
541 | // Benchmark Module and DAG Creator Functions // |
542 | //===--------------------------------------------------------------------===// |
543 | |
544 | //----------------------------- Single Node --------------------------------// |
545 | /// Create a module consisting of a single FC operator. |
546 | std::unique_ptr<Module> createSingleNodeModule() { |
547 | auto mod = glow::make_unique<Module>(); |
548 | auto fn = mod->createFunction("singleNode" ); |
549 | PlaceholderBindings bindings; |
550 | |
551 | auto *input = |
552 | mod->createPlaceholder(ElemKind::FloatTy, {16, 32}, "input" , false); |
553 | auto *weights = |
554 | mod->createPlaceholder(ElemKind::FloatTy, {32, 32}, "weights1" , false); |
555 | auto *bias = mod->createPlaceholder(ElemKind::FloatTy, {32}, "bias" , false); |
556 | auto *output = |
557 | mod->createPlaceholder(ElemKind::FloatTy, {16, 32}, "output" , false); |
558 | |
559 | auto *fc = fn->createFullyConnected("fc" , input, weights, bias); |
560 | fn->createSave("save" , fc, output); |
561 | |
562 | bindings.allocate(weights)->getHandle().clear(0); |
563 | bindings.allocate(bias)->getHandle().clear(32); |
564 | |
565 | glow::convertPlaceholdersToConstants(fn, bindings, {input, output}); |
566 | |
567 | return mod; |
568 | } |
569 | |
570 | /// Create an Executor DAG consisting of just one node for the single FC |
571 | /// operator. |
572 | std::unique_ptr<DAG> createSingleNodeDAG( |
573 | std::unordered_map<std::string, std::unique_ptr<CompiledFunction>> |
574 | &compiledFunctions) { |
575 | // The DAG should have one root node and one actual node corresponding to the |
576 | // CompiledFunction obtained by compiling the singular function in the Module |
577 | // created by createSingleNodeModule. |
578 | auto root = glow::make_unique<DAGNode>(); |
579 | auto singleNode = glow::make_unique<DAGNode>(); |
580 | |
581 | root->children.emplace_back(singleNode.get()); |
582 | |
583 | singleNode->parents.emplace_back(root.get()); |
584 | singleNode->deviceRuntimeInfos[0] = DeviceRuntimeInfo(); |
585 | singleNode->name = "singleNode" ; |
586 | singleNode->runtimeBundle = glow::make_unique<RuntimeBundle>( |
587 | compiledFunctions["singleNode" ]->getRuntimeBundle()); |
588 | |
589 | std::vector<std::unique_ptr<DAGNode>> nodes; |
590 | nodes.emplace_back(std::move(singleNode)); |
591 | |
592 | auto dag = glow::make_unique<DAG>(); |
593 | dag->root = std::move(root); |
594 | dag->nodes = std::move(nodes); |
595 | |
596 | return dag; |
597 | } |
598 | //--------------------------------------------------------------------------// |
599 | |
600 | //===--------------------------------------------------------------------===// |
601 | // Benchmark Declarations and Instantiations // |
602 | //===--------------------------------------------------------------------===// |
603 | |
604 | // Declare a runtime benchmark named SingleNode that uses createSingleNodeModule |
605 | // to create the module and createSingleNodeDAG to create the Module and DAG for |
606 | // benchmarking. This declares appropriately named subclasses of |
607 | // HostManagerBenchmark, ExecutorBenchmark and DeviceManagerBenchmark. |
608 | DECLARE_RUNTIME_BENCHMARK(SingleNode, createSingleNodeModule, |
609 | createSingleNodeDAG); |
610 | |
611 | // Instantiate the SingleNode benchmark for the CPU backend. This creates |
612 | // instances of the HostManagerBenchmark, ExecutorBenchmark and |
613 | // DeviceManagerBenchmark subclasses declared by the macro above for the CPU |
614 | // backend. |
615 | INSTANTIATE_RUNTIME_BENCHMARK(SingleNode, CPUBackend); |
616 | |
617 | //===--------------------------------------------------------------------===// |
618 | // Benchmark Main // |
619 | //===--------------------------------------------------------------------===// |
620 | |
621 | // Benchmark main. |
622 | BENCHMARK_MAIN(); |
623 | |