Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / clDNN / api / CPP / program.hpp
1 /*
2 // Copyright (c) 2016 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 ///////////////////////////////////////////////////////////////////////////////////////////////////
18 #pragma once
19 #include "cldnn_defs.h"
20 #include "topology.hpp"
21 #include "engine.hpp"
22 #include <iostream>
23
24 #include <memory>
25
26 namespace cldnn
27 {
28
29 /// @addtogroup cpp_api C++ API
30 /// @{
31
32 /// @defgroup cpp_program Program compilation
33 /// @{
34
35 /// @brief Represents user-provided program build option type.
36 enum class build_option_type
37 {
38     /// @brief Allow primitives fusing during program build (default: false).
39     fusing = cldnn_build_option_fusing,
40
41     /// @brief Enable implicit reordering for user inputs (default: false).
42     optimize_data = cldnn_build_option_optimize_data,
43
44     /// @brief Enable running detection output layer always on gpu, regardless performance
45     detection_output_gpu = cldnn_build_option_detection_output_gpu,
46
47     /// @brief Enable debug mode (default: false).
48     /// @details This option enforce all program primitives to be accessible as outputs.
49     debug = cldnn_build_option_debug,
50
51     /// @brief User selected list of program outputs.
52     outputs = cldnn_build_option_outputs,
53
54         /// @brief User defined learning parameters.
55         learning_config = cldnn_build_option_learning_config,
56
57     /// @brief Tuning config (default: Tuning is disabled).
58     /// @details The tuner will automatically find the optimal kernel/config for each node in the graph,
59     /// by running multiple implementations and configurations per node and storing the optimal one in cache.
60     /// Expect long execution time in the first run. 
61     /// After the first run a cache with the tuning results will be created in the path provided.
62     /// This cache will be used in the next runs.
63     tuning_config = cldnn_build_option_tuning_config,
64
65     /// @brief Specifies a directory to which stages of network compilation should be dumped. (default: empty, i.e. no dumping)
66     graph_dumps_dir = cldnn_build_option_graph_dumps_dir,
67     /// @brief Name for serialization process
68     serialize_network = cldnn_build_option_serialization,
69     load_program = cldnn_build_option_load_program
70 };
71
72 /// @brief Tuning mode.
73 enum class tuning_mode
74 {
75     /// @brief Tuning is disabled.
76     tuning_disabled = cldnn_tuning_disabled,
77
78     /// @brief Tuning using the cached data (no on-line tuning for non-existing data).
79     tuning_use_cache = cldnn_tuning_use_cache,
80
81     /// @brief Tuning using the cached data if exist, tune and update cache otherwise.
82     tuning_tune_and_cache = cldnn_tuning_tune_and_cache
83 };
84
85 /// @brief Tuning configuration.
86 struct tuning_config_options
87 {
88     tuning_mode mode;
89     std::string cache_file_path;
90
91     tuning_config_options() :
92         mode(tuning_mode::tuning_disabled),
93         cache_file_path("")
94     {}
95 };
96
97 /// @brief Learning parameters.
98 struct learning_params
99 {
100         float momentum;
101         float weights_decay;
102
103         learning_params() :
104                 momentum(0.9f),
105                 weights_decay(0.0005f)
106         {}
107 };
108
109 /// @brief Represents user-provided program build option.
110 struct build_option
111 {
112     /// @brief Allow primitives fusing during program build (default: false).
113     static std::shared_ptr<const build_option> fusing(bool enable = false);
114
115     /// @brief Enable implicit reordering for user inputs (default: false).
116     static std::shared_ptr<const build_option> optimize_data(bool enable = false);
117
118     /// @brief Enable running detection output layer always on GPU, regardless performance (default: false).
119     static std::shared_ptr<const build_option> detection_output_gpu(bool enable = false);
120
121     /// @brief Enable debug mode (default: false).
122     /// @details This option enforce all program primitives to be accessible as outputs.
123     static std::shared_ptr<const build_option> debug(bool enable = false);
124
125     /// @brief User selected list of program outputs.
126     static std::shared_ptr<const build_option> outputs(const std::vector<primitive_id>& outs);
127
128     /// @brief Tuning configuration (default: false).
129     /// @details This option will automatically find the optimal kernel/config for each node in the graph,
130     /// by running multiple implementations and configurations per node and storing the optimal one in cache.
131     /// Expect long execution time in the first run (unless the cache only mode is enabled). 
132     /// After the first run a cache with the tuning results will be created in the path provided.
133     /// This cache will be used in the next runs.
134     static std::shared_ptr<const build_option> tuning_config(const tuning_config_options& config = tuning_config_options());
135
136     /// @brief Specifies a directory to which stages of network compilation should be dumped (default: empty, i.e. no dumping)
137     static std::shared_ptr<const build_option> graph_dumps_dir(const std::string& dir_path);
138
139     /// @brief Specifies a name for serialization process.
140     static std::shared_ptr<const build_option> serialize_network(const std::string& network_name);
141     /// @brief Specifies a name of load_program process.
142     static std::shared_ptr<const build_option> load_program(const std::string& network_name);
143
144     /// @brief User defined learning parameters.
145     static std::shared_ptr<const build_option> learning_config(const learning_params& params = learning_params());
146
147     virtual ~build_option() = default;
148
149 private:
150     /// @brief Returns option type represented by this object.
151     virtual build_option_type get_type() const = 0;
152
153     /// @brief Returns option @ref ::cldnn_build_option::data represented by this object.
154     virtual const void* get_data() const = 0;
155
156     friend class build_options;
157 };
158
159 /// @brief @ref build_option specialization for boolean options.
160 template<build_option_type OptType>
161 struct build_option_bool : build_option
162 {
163     /// @brief Constructs option.
164     /// @param value Is option enabled.
165     explicit build_option_bool(bool value) : _value(value ? 1 : 0) {}
166
167     /// @brief Constructs from C API @ref ::cldnn_build_option.
168     explicit build_option_bool(const cldnn_build_option& value)
169         : _value(reinterpret_cast<uintptr_t>(value.data))
170     {
171         assert(value.type == static_cast<int32_t>(OptType));
172     }
173
174     /// @brief Is option enabled.
175     bool enabled() const { return _value != 0; }
176 private:
177     build_option_type get_type() const override { return OptType; }
178     const void* get_data() const override { return reinterpret_cast<const void*>(_value); }
179     uintptr_t _value;
180 };
181
182 /// @brief @ref build_option specialization for program outputs list.
183 struct build_option_outputs : build_option
184 {
185     /// @brief The list of output ids (names)
186     const std::vector<primitive_id> outputs;
187
188     /// @brief Constructs option.
189     /// @param outs List of ouput ids (names)
190     explicit build_option_outputs(const std::vector<primitive_id>& outs)
191         : outputs(outs)
192         , _ref_store(to_refs(outputs))
193         , _outputs_ref({ _ref_store.data(), _ref_store.size() })
194     {}
195
196     /// @brief Constructs from C API @ref ::cldnn_build_option.
197     explicit build_option_outputs(const cldnn_build_option& value)
198         : build_option_outputs(make_outputs_from_ref(value))
199     {
200         assert(value.type == static_cast<int32_t>(cldnn_build_option_outputs));
201     }
202
203 private:
204     /// @brief Returns build_option_type::outputs.
205     build_option_type get_type() const override { return build_option_type::outputs; }
206     /// @brief Returns pointer to @ref cldnn_primitive_is_arr
207     const void* get_data() const override { return &_outputs_ref; }
208
209     build_option_outputs(const build_option_outputs& other) = delete;
210     build_option_outputs& operator=(const build_option_outputs& other) = delete;
211
212     const std::vector<cldnn_primitive_id> _ref_store;
213     const cldnn_primitive_id_arr _outputs_ref;
214
215     static std::vector<cldnn_primitive_id> to_refs(const std::vector<primitive_id>& stor)
216     {
217         std::vector<cldnn_primitive_id> result(stor.size());
218         for (size_t i = 0; i < stor.size(); i++)
219         {
220             result[i] = stor[i].c_str();
221         }
222         return result;
223     }
224
225     static std::vector<primitive_id> make_outputs_from_ref(const cldnn_build_option& value)
226     {
227         if (value.type != cldnn_build_option_outputs) throw std::invalid_argument("option type does not match: should be 'output'");
228         if (value.data == nullptr) throw std::invalid_argument("output data is empty");
229         auto refs = reinterpret_cast<const cldnn_primitive_id_arr*>(value.data);
230         std::vector<primitive_id> result;
231         result.reserve(refs->size);
232         for (decltype(refs->size) i = 0; i < refs->size; i++)
233         {
234             result.push_back(refs->data[i]);
235         }
236         return result;
237     }
238 };
239
240 /// @brief @ref build_option specialization for learning config.
241 struct build_option_learning_config : build_option
242 {
243         /// @brief Learning parameters.
244         const learning_params params;
245
246         /// @brief Constructs learning config build option.
247         /// @param learning_params Parameters for learning.
248         explicit build_option_learning_config(const learning_params& params) :
249                 params(params),
250                 params_ref({ params.momentum, params.weights_decay })
251         {}
252
253         /// @brief Constructs learning config build option from C API @ref ::cldnn_build_option.
254         explicit build_option_learning_config(const cldnn_build_option& value)
255                 : build_option_learning_config(make_config_from_ref(value))
256         {
257                 assert(value.type == static_cast<int32_t>(cldnn_build_option_learning_config));
258         }
259
260 private:
261         /// @brief Returns build_option_type::learning_config.
262         build_option_type get_type() const override { return build_option_type::learning_config; }
263         /// @brief Returns pointer to @ref cldnn_learning_params.
264         const void* get_data() const override { return &params_ref; }
265
266         build_option_learning_config(const build_option_learning_config& other) = delete;
267         build_option_learning_config& operator=(const build_option_learning_config& other) = delete;
268
269         const cldnn_learning_params params_ref;
270
271         static learning_params make_config_from_ref(const cldnn_build_option& value)
272         {
273                 if (value.type != cldnn_build_option_learning_config) throw std::invalid_argument("option type does not match: should be 'learning_config'");
274                 if (value.data == nullptr) throw std::invalid_argument("Learning params data is empty");
275                 auto refs = reinterpret_cast<const cldnn_learning_params*>(value.data);
276                 learning_params result;
277                 result.momentum = refs->momentum;
278                 result.weights_decay = refs->weights_decay;
279                 return result;
280         }
281 };
282
283 /// @brief @ref build_option specialization for tuning config.
284 struct build_option_tuning_config : build_option
285 {
286     /// @brief Tuning configuration
287     const tuning_config_options config;
288
289     /// @brief Constructs tuning config build option.
290     /// @param tuning_config Configuration for the tuning.
291     explicit build_option_tuning_config(const tuning_config_options& tuning_config) :
292         config(tuning_config),
293         config_ref({ static_cast<int32_t>(config.mode), config.cache_file_path.c_str() })
294     {}
295
296     /// @brief Constructs tuning config build option from C API @ref ::cldnn_build_option.
297     explicit build_option_tuning_config(const cldnn_build_option& value)
298         : build_option_tuning_config(make_config_from_ref(value))
299     {
300         assert(value.type == static_cast<int32_t>(cldnn_build_option_tuning_config));
301     }
302
303 private:
304     /// @brief Returns build_option_type::tuning_config.
305     build_option_type get_type() const override { return build_option_type::tuning_config; }
306     /// @brief Returns pointer to @ref cldnn_tuning_config
307     const void* get_data() const override { return &config_ref; }
308
309     build_option_tuning_config(const build_option_tuning_config& other) = delete;
310     build_option_tuning_config& operator=(const build_option_tuning_config& other) = delete;
311
312     const cldnn_tuning_config config_ref;
313
314     static tuning_config_options make_config_from_ref(const cldnn_build_option& value)
315     {
316         if (value.type != cldnn_build_option_tuning_config) throw std::invalid_argument("option type does not match: should be 'tuning_config'");
317         if (value.data == nullptr) throw std::invalid_argument("Tuning config data is empty");
318         auto refs = reinterpret_cast<const cldnn_tuning_config*>(value.data);
319         tuning_config_options result;
320         result.mode = tuning_mode(refs->mode);
321         result.cache_file_path = std::string(refs->cache_file_path);
322         return result;
323     }
324 };
325
326 /// @brief @ref build_option specialization for selecting a directory.
327 template<build_option_type OptType>
328 struct build_option_directory : build_option
329 {
330     const std::string directory_path;
331
332     /// @brief Constructs option.
333     /// @param outs List of ouput ids (names)
334     explicit build_option_directory(const std::string& dir_path)
335         : directory_path(dir_path)
336     {}
337
338     /// @brief Constructs from C API @ref ::cldnn_build_option.
339     explicit build_option_directory(const cldnn_build_option& value)
340         : directory_path(from_c_value(value))
341     {}
342
343 private:
344     /// @brief Returns build_option_type::graph_dumps_dir.
345     build_option_type get_type() const override { return build_option_type::graph_dumps_dir; }
346     /// @brief Returns null terminated C string.
347     const void* get_data() const override { return (directory_path.empty() ? nullptr : directory_path.c_str()); }
348
349     build_option_directory(const build_option_directory& other) = delete;
350     build_option_directory& operator=(const build_option_directory& other) = delete;
351
352     static std::string from_c_value(const cldnn_build_option& value)
353     {
354         if (value.type != static_cast<int32_t>(OptType))
355             throw std::invalid_argument("option type does not match");
356         if (value.data == nullptr)
357             return{};
358
359         return{ static_cast<const char*>(value.data) };
360     }
361 };
362
363 /// @brief @ref build_option specialization for serialization process.
364 template<build_option_type OptType>
365 struct build_option_serialization : build_option
366 {
367     const std::string serialization_network_name;
368
369
370     explicit build_option_serialization(const std::string& name)
371         : serialization_network_name(name)
372     {}
373
374
375     explicit build_option_serialization(const cldnn_build_option& value)
376         : serialization_network_name(from_c_value(value))
377     {}
378
379 private:
380
381     build_option_type get_type() const override { return build_option_type::serialize_network; }
382
383     const void* get_data() const override { return (serialization_network_name.empty() ? nullptr : serialization_network_name.c_str()); }
384
385     build_option_serialization(const build_option_serialization& other) = delete;
386     build_option_serialization& operator=(const build_option_serialization& other) = delete;
387
388     static std::string from_c_value(const cldnn_build_option& value)
389     {
390         if (value.type != static_cast<int32_t>(OptType))
391             throw std::invalid_argument("option type does not match");
392         if (value.data == nullptr)
393             return{};
394
395         return{ static_cast<const char*>(value.data) };
396     }
397 };
398
399
400 /// @brief @ref build_option specialization for load_program process.
401 template<build_option_type OptType>
402 struct build_option_load_program : build_option
403 {
404     const std::string load_program_name;
405
406
407     explicit build_option_load_program(const std::string& name)
408         : load_program_name(name)
409     {}
410
411
412     explicit build_option_load_program(const cldnn_build_option& value)
413         : load_program_name(from_c_value(value))
414     {}
415
416 private:
417
418     build_option_type get_type() const override { return build_option_type::load_program; }
419
420     const void* get_data() const override { return (load_program_name.empty() ? nullptr : load_program_name.c_str()); }
421
422     build_option_load_program(const build_option_load_program& other) = delete;
423     build_option_load_program& operator=(const build_option_load_program& other) = delete;
424
425     static std::string from_c_value(const cldnn_build_option& value)
426     {
427         if (value.type != static_cast<int32_t>(OptType))
428             throw std::invalid_argument("option type does not match");
429         if (value.data == nullptr)
430             return{};
431
432         return{ static_cast<const char*>(value.data) };
433     }
434 };
435
436 namespace detail
437 {
438     /// @brief Helper template to convert @ref build_option_type value to particular @ref build_option class.
439     template<build_option_type OptType>
440     struct build_option_traits
441     {
442         /// @brief @ref build_option object type which represents the particular @p OptType.
443         typedef build_option object_type;
444         /// @brief Make default @ref build_option corresponding @p OptType
445         static std::shared_ptr<const build_option> make_default();
446         /// @brief Make @ref build_option from C API @ref ::cldnn_build_option
447         static std::shared_ptr<const build_option> make_option(const cldnn_build_option& option);
448     };
449
450 #ifndef DOXYGEN_SHOULD_SKIP_THIS
451     template<> struct build_option_traits<build_option_type::fusing>
452     {
453         typedef build_option_bool<build_option_type::fusing> object_type;
454         static std::shared_ptr<const build_option> make_default() { return build_option::fusing(); }
455         static std::shared_ptr<const build_option> make_option(const cldnn_build_option& option)
456         {
457             assert(option.type == cldnn_build_option_fusing);
458             return std::make_shared<object_type>(option);
459         }
460     };
461     template<> struct build_option_traits<build_option_type::optimize_data>
462     {
463         typedef build_option_bool<build_option_type::optimize_data> object_type;
464         static std::shared_ptr<const build_option> make_default() { return build_option::optimize_data(); }
465         static std::shared_ptr<const build_option> make_option(const cldnn_build_option& option)
466         {
467             assert(option.type == cldnn_build_option_optimize_data);
468             return std::make_shared<object_type>(option);
469         }
470     };
471     template<> struct build_option_traits<build_option_type::detection_output_gpu>
472     {
473         typedef build_option_bool<build_option_type::detection_output_gpu> object_type;
474         static std::shared_ptr<const build_option> make_default() { return build_option::detection_output_gpu(); }
475         static std::shared_ptr<const build_option> make_option(const cldnn_build_option& option)
476         {
477             assert(option.type == cldnn_build_option_detection_output_gpu);
478             return std::make_shared<object_type>(option);
479         }
480     };
481     template<> struct build_option_traits<build_option_type::debug>
482     {
483         typedef build_option_bool<build_option_type::debug> object_type;
484         static std::shared_ptr<const build_option> make_default() { return build_option::debug(); }
485         static std::shared_ptr<const build_option> make_option(const cldnn_build_option& option)
486         {
487             assert(option.type == cldnn_build_option_debug);
488             return std::make_shared<object_type>(option);
489         }
490     };
491     template<> struct build_option_traits<build_option_type::outputs>
492     {
493         typedef build_option_outputs object_type;
494         static std::shared_ptr<const build_option> make_default() { return build_option::outputs({}); }
495         static std::shared_ptr<const build_option> make_option(const cldnn_build_option& option)
496         {
497             assert(option.type == cldnn_build_option_outputs);
498             return std::make_shared<object_type>(option);
499         }
500     };
501         template<> struct build_option_traits<build_option_type::learning_config>
502         {
503                 typedef build_option_learning_config object_type;
504                 static std::shared_ptr<const build_option> make_default() { return build_option::learning_config(); }
505                 static std::shared_ptr<const build_option> make_option(const cldnn_build_option& option)
506                 {
507                         assert(option.type == cldnn_build_option_learning_config);
508                         return std::make_shared<object_type>(option);
509                 }
510         };
511     template<> struct build_option_traits<build_option_type::tuning_config>
512     {
513         typedef build_option_tuning_config object_type;
514         static std::shared_ptr<const build_option> make_default() { return build_option::tuning_config(); }
515         static std::shared_ptr<const build_option> make_option(const cldnn_build_option& option)
516         {
517             assert(option.type == cldnn_build_option_tuning_config);
518             return std::make_shared<object_type>(option);
519         }
520     };
521     template<> struct build_option_traits<build_option_type::graph_dumps_dir>
522     {
523         typedef build_option_directory<build_option_type::graph_dumps_dir> object_type;
524         static std::shared_ptr<const build_option> make_default() { return build_option::graph_dumps_dir({}); }
525         static std::shared_ptr<const build_option> make_option(const cldnn_build_option& option)
526         {
527             assert(option.type == cldnn_build_option_graph_dumps_dir);
528             return std::make_shared<object_type>(option);
529         }
530     };
531     template<> struct build_option_traits<build_option_type::serialize_network>
532     {
533         typedef build_option_serialization<build_option_type::serialize_network> object_type;
534         static std::shared_ptr<const build_option> make_default() { return build_option::serialize_network({}); }
535         static std::shared_ptr<const build_option> make_option(const cldnn_build_option& option)
536         {
537             assert(option.type == cldnn_build_option_serialization);
538             return std::make_shared<object_type>(option);
539         }
540     };
541     template<> struct build_option_traits<build_option_type::load_program>
542     {
543         typedef build_option_load_program<build_option_type::load_program> object_type;
544         static std::shared_ptr<const build_option> make_default() { return build_option::load_program({}); }
545         static std::shared_ptr<const build_option> make_option(const cldnn_build_option& option)
546         {
547             assert(option.type == cldnn_build_option_load_program);
548             return std::make_shared<object_type>(option);
549         }
550     };
551
552 #endif
553 } // namespace detail
554
555 #ifndef DOXYGEN_SHOULD_SKIP_THIS
556 inline std::shared_ptr<const build_option> build_option::fusing(bool enable)
557 {
558     return std::make_shared<build_option_bool<build_option_type::fusing>>(enable);
559 }
560
561 inline std::shared_ptr<const build_option> build_option::optimize_data(bool enable)
562 {
563     return std::make_shared<build_option_bool<build_option_type::optimize_data>>(enable);
564 }
565
566 inline std::shared_ptr<const build_option> build_option::detection_output_gpu(bool enable)
567 {
568     return std::make_shared<build_option_bool<build_option_type::detection_output_gpu>>(enable);
569 }
570
571 inline std::shared_ptr<const build_option> build_option::debug(bool enable)
572 {
573     return std::make_shared<build_option_bool<build_option_type::debug>>(enable);
574 }
575
576 inline std::shared_ptr<const build_option> build_option::outputs(const std::vector<primitive_id>& outs)
577 {
578     return std::make_shared<build_option_outputs>(outs);
579 }
580
581 inline std::shared_ptr<const build_option> build_option::learning_config(const learning_params& params)
582 {
583         return std::make_shared<build_option_learning_config>(params);
584 }
585
586 inline std::shared_ptr<const build_option> build_option::tuning_config(const tuning_config_options& config)
587 {
588     return std::make_shared<build_option_tuning_config>(config);
589 }
590
591 inline std::shared_ptr<const build_option> build_option::graph_dumps_dir(const std::string& dir_path)
592 {
593     return std::make_shared<build_option_directory<build_option_type::graph_dumps_dir>>(dir_path);
594 }
595 inline std::shared_ptr<const build_option> build_option::serialize_network(const std::string& name)
596 {
597     return std::make_shared<build_option_serialization<build_option_type::serialize_network>>(name);
598 }
599 inline std::shared_ptr<const build_option> build_option::load_program(const std::string& name)
600 {
601     return std::make_shared<build_option_load_program<build_option_type::load_program>>(name);
602 }
603 #endif
604
605 /// @brief Represents program build options list.
606 class build_options
607 {
608 public:
609     /// @brief Adds or replace option to the options list
610     void set_option(std::shared_ptr<const build_option> opt)
611     {
612         add_or_replace_option(opt);
613     }
614
615     /// @brief Adds or replace options to the options list
616     template<typename ...Args>
617     void set_option(std::shared_ptr<const build_option> opt, Args... args)
618     {
619         add_or_replace_option(opt);
620         set_option(args...);
621     }
622
623     /// @brief Constructs build options list from its arguments.
624     template<typename ...Args>
625     build_options(Args... args)
626     {
627         set_option(args...);
628     }
629
630     /// @brief Constructs build options list from C API ::cldnn_build_options.
631     build_options(array_ref<cldnn_build_option> options)
632     {
633         for (auto& o : options)
634         {
635             _options.emplace_back(make_option(o));
636         }
637     }
638
639     /// @brief Returns program build option for @p OptType
640     template<build_option_type OptType>
641     std::shared_ptr<const typename detail::build_option_traits<OptType>::object_type>
642         get() const
643     {
644         using T = typename detail::build_option_traits<OptType>::object_type;
645         for (auto& option : _options)
646         {
647             if (option->get_type() == OptType)
648                 return std::static_pointer_cast<const T>(option);
649         }
650         return std::static_pointer_cast<const T>(detail::build_option_traits<OptType>::make_default());
651     }
652
653 private:
654     friend struct program;
655     std::vector<std::shared_ptr<const build_option>> _options;
656     void set_option(void) {}
657
658     /// @brief Returns C API compatible list of ::cldnn_build_option
659     std::vector<cldnn_build_option> get_refs() const
660     {
661         std::vector<cldnn_build_option> result;
662         for (auto& o : _options)
663         {
664             result.push_back({ static_cast<int32_t>(o->get_type()), o->get_data() });
665         }
666         return result;
667     }
668
669     void add_or_replace_option(std::shared_ptr<const build_option> opt)
670     {
671         for (auto& p : _options)
672         {
673             if (p->get_type() == opt->get_type())
674             {
675                 p = opt;
676                 return;
677             }
678         }
679         _options.push_back(opt);
680     }
681
682     static std::shared_ptr<const build_option> make_option(const cldnn_build_option& option)
683     {
684         switch (option.type)
685         {
686         case cldnn_build_option_fusing:
687             return detail::build_option_traits<build_option_type::fusing>::make_option(option);
688         case cldnn_build_option_learning_config:
689             return detail::build_option_traits<build_option_type::learning_config>::make_option(option);
690         case cldnn_build_option_optimize_data:
691             return detail::build_option_traits<build_option_type::optimize_data>::make_option(option);
692         case cldnn_build_option_detection_output_gpu:
693             return detail::build_option_traits<build_option_type::detection_output_gpu>::make_option(option);
694         case cldnn_build_option_debug:
695             return detail::build_option_traits<build_option_type::debug>::make_option(option);
696         case cldnn_build_option_outputs:
697             return detail::build_option_traits<build_option_type::outputs>::make_option(option);
698         case cldnn_build_option_tuning_config:
699             return detail::build_option_traits<build_option_type::tuning_config>::make_option(option);
700         case cldnn_build_option_graph_dumps_dir:
701             return detail::build_option_traits<build_option_type::graph_dumps_dir>::make_option(option);
702         case cldnn_build_option_serialization:
703             return detail::build_option_traits<build_option_type::serialize_network>::make_option(option);
704         case cldnn_build_option_load_program:
705             return detail::build_option_traits<build_option_type::load_program>::make_option(option);
706         default: throw std::out_of_range("unsupported build option type");
707         }
708     }
709 };
710
711 /// @brief Compiled program build from @ref topology by @ref engine
712 struct program
713 {
714     friend struct network;
715
716 public:
717     /// @brief Builds executable program based on user-defined @p topology by specified @p engine.
718     /// @param[in] engine The engine which will be used to build the program.
719     /// @param[in] topology The user-defined topology on which the network will be based.
720     /// @param[in] options Program build options. See @ref build_option and @ref build_options for details.
721     program(engine const& engine, topology const& topology, build_options const& options = build_options())
722         :_impl(check_status<cldnn_program>("program creation failed", [&](status_t* status)
723             {
724                 auto options_refs = options.get_refs();
725                 return cldnn_build_program(engine.get(), topology.get(), options_refs.data(), options_refs.size(), status);
726             }))
727     {}
728
729     /// @brief Retains the C API @ref cldnn_program handler stored in @p other.
730     program(program const& other)
731         :_impl(other._impl)
732     {
733         retain();
734     }
735
736     /// @brief Dereferences the counter of the underlying C API @ref cldnn_program handler.
737     ~program()
738     {
739         release();
740     }
741
742     /// @brief Assigns new value by releasing previously referenced C API @ref cldnn_program handler and retaining the one referenced by @p other.
743     program& operator=(const program& other)
744     {
745         if (_impl == other._impl) return *this;
746         release();
747         _impl = other._impl;
748         retain();
749         return *this;
750     }
751
752     /// @brief Checks whether @p lhs and @p rhs reference the same C API @ref cldnn_program handler
753     friend bool operator==(const program& lhs, const program& rhs) { return lhs._impl == rhs._impl; }
754     /// @brief Checks whether @p lhs and @p rhs reference different C API @ref cldnn_program handlers
755     friend bool operator!=(const program& lhs, const program& rhs) { return !(lhs == rhs); }
756
757     /// @brief Returns wrapped C API @ref cldnn_program handler.
758     ::cldnn_program get() const { return _impl; }
759
760 private:
761
762     ::cldnn_program _impl;
763
764     program(::cldnn_program impl) : _impl(impl)
765     {
766         if (_impl == nullptr)
767             throw std::invalid_argument("implementation pointer should not be null");
768     }
769
770     void retain()
771     {
772         check_status<void>("retain topology failed", [=](status_t* status) { cldnn_retain_program(_impl, status); });
773     }
774     void release()
775     {
776         check_status<void>("retain topology failed", [=](status_t* status) { cldnn_release_program(_impl, status); });
777     }
778 };
779 /// @}
780 /// @}
781 }