Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / clDNN / src / gpu / engine_info.cpp
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 #include "engine_info.h"
17 #include "ocl_toolkit.h"
18 #include <unordered_map>
19 #include <string>
20 #include <cassert>
21 #include <time.h>
22 #include <limits>
23 #include <chrono>
24 #include "istreamwrapper.h"
25
26 #ifdef _WIN32
27 #define WIN32_LEAN_AND_MEAN
28 #include <windows.h>
29 #include <SetupAPI.h>
30 #include <devguid.h>
31 #include <cstring>
32 #else
33 #include <unistd.h>
34 #include <limits.h>
35 #include <link.h>
36 #include <dlfcn.h>
37 #endif
38
39 #include <fstream>
40 #include <iostream>
41 #include <utility>
42
43
44 namespace cldnn { namespace gpu{
45
46 namespace {
47
48 const char* device_info_failed_msg = "Device lookup failed";
49
50 int get_gpu_device_id()
51 {
52     int result = 0;
53
54 #ifdef _WIN32
55     {
56         HDEVINFO device_info_set = SetupDiGetClassDevsA(&GUID_DEVCLASS_DISPLAY, NULL, NULL, DIGCF_PRESENT);
57         if (device_info_set == INVALID_HANDLE_VALUE)
58             return 0;
59
60         SP_DEVINFO_DATA devinfo_data;
61         std::memset(&devinfo_data, 0, sizeof(devinfo_data));
62         devinfo_data.cbSize = sizeof(devinfo_data);
63
64         for (DWORD dev_idx = 0; SetupDiEnumDeviceInfo(device_info_set, dev_idx, &devinfo_data); dev_idx++)
65         {
66             const size_t buf_size = 512;
67             char buf[buf_size];
68             if (!SetupDiGetDeviceInstanceIdA(device_info_set, &devinfo_data, buf, buf_size, NULL))
69             {
70                 continue;
71             }
72
73             char* vendor_pos = std::strstr(buf, "VEN_");
74             if (vendor_pos != NULL && std::stoi(vendor_pos + 4, NULL, 16) == 0x8086)
75             {
76                 char* device_pos = strstr(vendor_pos, "DEV_");
77                 if (device_pos != NULL)
78                 {
79                     result = std::stoi(device_pos + 4, NULL, 16);
80                     break;
81                 }
82             }
83         }
84
85         if (device_info_set)
86         {
87             SetupDiDestroyDeviceInfoList(device_info_set);
88         }
89     }
90 #elif defined(__linux__)
91     {
92         std::string dev_base{ "/sys/devices/pci0000:00/0000:00:02.0/" };
93         std::ifstream ifs(dev_base + "vendor");
94         if (ifs.good())
95         {
96             int ven_id;
97             ifs >> std::hex >> ven_id;
98             ifs.close();
99             if (ven_id == 0x8086)
100             {
101                 ifs.open(dev_base + "device");
102                 if (ifs.good())
103                 {
104                     ifs >> std::hex >> result;
105                 }
106             }
107         }
108     }
109 #endif
110
111     return result;
112 }
113
114 std::string to_string_hex(int val)
115 {
116     auto tmp = static_cast<unsigned int>(val);
117     if (tmp == 0) return "0x0";
118
119     const char* hex_chars = "0123456789ABCDEF";
120
121     // 64bit max
122     char buf[] = "0000000000000000";
123     size_t i = sizeof(buf) / sizeof(buf[0]) - 1;
124     while (i > 0 && tmp > 0)
125     {
126         buf[--i] = hex_chars[tmp & 0xF];
127         tmp >>= 4;
128     }
129     assert(tmp == 0);
130     return std::string("0x") + &buf[i];
131 }
132
133 #include "mode.inc"
134
135 std::shared_ptr<rapidjson::Document> get_cache_from_file(uint32_t compute_units_count, const gpu_toolkit& context) {
136     std::string tuning_cache_path = context.get_configuration().tuning_cache_path;
137     if (tuning_cache_path.compare("cache.json") == 0)
138     {
139 #ifdef _WIN32
140         char path[MAX_PATH];
141         HMODULE hm = NULL;
142         GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
143                           GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
144                           (LPCSTR)&get_cache_from_file, &hm);
145         GetModuleFileName(hm, path, sizeof(path));
146         std::string bin_path(path);
147         tuning_cache_path = bin_path.substr(0, bin_path.find_last_of("\\")) + "\\cache.json";
148 #else
149         Dl_info dl_info;
150         dladdr((void*)device_info_failed_msg, &dl_info);
151         std::string bin_path(dl_info.dli_fname);
152         tuning_cache_path = bin_path.substr(0, bin_path.find_last_of("/")) + "/cache.json";
153 #endif
154     }
155     rapidjson::Document cacheFile;
156     rapidjson::Document cacheDeviceData;
157     auto computeUnits = std::to_string(compute_units_count);
158     std::ifstream f(tuning_cache_path);
159     if (f.good())
160     {
161         rapidjson::IStreamWrapper isw{ f };
162         cacheFile.ParseStream(isw);
163         auto errorCode = cacheFile.GetParseError();
164         if (!cacheFile.HasMember(computeUnits.c_str()) && errorCode == 0)
165         {
166             computeUnits = "24";
167         }
168         if (cacheFile.HasMember(computeUnits.c_str()) && errorCode == 0)
169         {
170             cacheDeviceData.CopyFrom(cacheFile[computeUnits.c_str()], cacheDeviceData.GetAllocator());
171         }
172         else
173         {
174             cacheDeviceData.Parse("{}");
175         }
176     }
177     else
178     {
179         cacheDeviceData.Parse("{}");
180     }
181     return std::make_shared < rapidjson::Document>(std::move(cacheDeviceData));
182 }
183
184 } // namespace <anonymous>
185
186 engine_info_internal::engine_info_internal(const gpu_toolkit& context)
187 {
188     auto device_id = get_gpu_device_id();
189     if (0 == device_id) throw std::runtime_error(device_info_failed_msg);
190     dev_id = to_string_hex(device_id);
191     driver_version = context.device().getInfo<CL_DRIVER_VERSION>();
192
193     compute_units_count = context.device().getInfo<CL_DEVICE_MAX_COMPUTE_UNITS>();
194     try {
195         device_cache = get_cache_from_file(compute_units_count, context);
196     }
197     catch (...){
198         std::cout << "[WARNING] error during parsing cache file, tuning data won't be used" << std::endl;
199         device_cache->Parse("{}");
200     }
201     cores_count = static_cast<uint32_t>(context.device().getInfo<CL_DEVICE_MAX_COMPUTE_UNITS>());
202     core_frequency = static_cast<uint32_t>(context.device().getInfo<CL_DEVICE_MAX_CLOCK_FREQUENCY>());
203
204     max_work_group_size = static_cast<uint64_t>(context.device().getInfo<CL_DEVICE_MAX_WORK_GROUP_SIZE>());
205
206         if (max_work_group_size > 256)
207                 max_work_group_size = 256;
208
209     max_local_mem_size = static_cast<uint64_t>(context.device().getInfo<CL_DEVICE_LOCAL_MEM_SIZE>());
210     max_global_mem_size = static_cast<uint64_t>(context.device().getInfo<CL_DEVICE_GLOBAL_MEM_SIZE>());
211     max_alloc_mem_size = static_cast<uint64_t>(context.device().getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>());
212
213     supports_image = static_cast<uint8_t>(context.device().getInfo<CL_DEVICE_IMAGE_SUPPORT>());
214     max_image2d_width = static_cast<uint64_t>(context.device().getInfo<CL_DEVICE_IMAGE2D_MAX_WIDTH>());
215     max_image2d_height = static_cast<uint64_t>(context.device().getInfo<CL_DEVICE_IMAGE2D_MAX_HEIGHT>());
216
217     // Check for supported features.
218     auto extensions = context.device().getInfo<CL_DEVICE_EXTENSIONS>();
219     extensions.push_back(' '); // Add trailing space to ease searching (search with keyword with trailing space).
220
221     supports_fp16 = extensions.find("cl_khr_fp16 ") != std::string::npos;
222     supports_fp16_denorms = supports_fp16 && (context.device().getInfo<CL_DEVICE_HALF_FP_CONFIG>() & CL_FP_DENORM) != 0;
223
224     supports_subgroups_short = extensions.find("cl_intel_subgroups_short") != std::string::npos;
225
226     supports_imad = is_imad_supported(device_id);
227     supports_immad = is_immad_supported(device_id);
228 }
229 }}