You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

pipelinecache.cpp 14 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. // Tencent is pleased to support the open source community by making ncnn available.
  2. //
  3. // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
  4. //
  5. // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
  6. // in compliance with the License. You may obtain a copy of the License at
  7. //
  8. // https://opensource.org/licenses/BSD-3-Clause
  9. //
  10. // Unless required by applicable law or agreed to in writing, software distributed
  11. // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  12. // CONDITIONS OF ANY KIND, either express or implied. See the License for the
  13. // specific language governing permissions and limitations under the License.
  14. #include "pipelinecache.h"
  15. #include "gpu.h"
  16. namespace ncnn {
  17. #if NCNN_VULKAN
  18. // https://en.wikipedia.org/wiki/MurmurHash
  19. static uint32_t murmur3_32(const uint32_t* data, int size)
  20. {
  21. uint32_t h = 0;
  22. for (int i = 0; i < size; i++)
  23. {
  24. uint32_t k = *data++;
  25. k *= 0xcc9e2d51;
  26. k = (k << 15) | (k >> (32 - 15));
  27. k *= 0x1b873593;
  28. h ^= k;
  29. h = (h << 13) | (h >> (32 - 13));
  30. h = (h * 5) + 0xe6546b64;
  31. }
  32. h ^= size * 4;
  33. h ^= h >> 16;
  34. h *= 0x85ebca6b;
  35. h ^= h >> 13;
  36. h *= 0xc2b2ae35;
  37. h ^= h >> 16;
  38. return h;
  39. }
  40. // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash
  41. static uint32_t fnv1a_32(const uint8_t* data, int size)
  42. {
  43. uint32_t h = 0x811c9dc5;
  44. for (int i = 0; i < size; i++)
  45. {
  46. h ^= (uint32_t)*data++;
  47. h *= 0x01000193;
  48. }
  49. return h;
  50. }
  51. PipelineCache::pipeline_cache_digest::pipeline_cache_digest(const uint32_t* spv_data, size_t spv_data_size, const std::vector<vk_specialization_type>& specializations,
  52. uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z)
  53. {
  54. spv_data_murmur3 = murmur3_32(spv_data, spv_data_size / 4);
  55. // encode opt
  56. opt_local_size_bits[0] = 0;
  57. // encode local_size
  58. opt_local_size_bits[1] = local_size_x;
  59. opt_local_size_bits[2] = local_size_y;
  60. opt_local_size_bits[3] = local_size_z;
  61. // encode specializations
  62. const int specialization_count = specializations.size();
  63. specializations_murmur3 = murmur3_32((const uint32_t*)specializations.data(), specialization_count);
  64. specializations_fnv1a = fnv1a_32((const uint8_t*)specializations.data(), specialization_count * sizeof(vk_specialization_type));
  65. }
  66. PipelineCache::pipeline_cache_digest::pipeline_cache_digest(int _shader_type_index, const Option& opt, const std::vector<vk_specialization_type>& specializations,
  67. uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z)
  68. {
  69. shader_type_index = _shader_type_index;
  70. // encode opt
  71. opt_local_size_bits[0] = opt.use_image_storage << 7
  72. | opt.use_fp16_packed << 6
  73. | opt.use_fp16_storage << 5
  74. | opt.use_fp16_arithmetic << 4
  75. | opt.use_int8_storage << 3
  76. | opt.use_int8_arithmetic << 2;
  77. // encode local_size
  78. opt_local_size_bits[1] = local_size_x;
  79. opt_local_size_bits[2] = local_size_y;
  80. opt_local_size_bits[3] = local_size_z;
  81. // encode specializations
  82. const int specialization_count = specializations.size();
  83. specializations_murmur3 = murmur3_32((const uint32_t*)specializations.data(), specialization_count);
  84. specializations_fnv1a = fnv1a_32((const uint8_t*)specializations.data(), specialization_count * sizeof(vk_specialization_type));
  85. }
  86. PipelineCache::PipelineCache(const VulkanDevice* _vkdev)
  87. : vkdev(_vkdev)
  88. {
  89. }
  90. PipelineCache::~PipelineCache()
  91. {
  92. clear();
  93. }
  94. void PipelineCache::clear()
  95. {
  96. MutexLockGuard lock(cache_lock);
  97. for (size_t i = 0; i < cache_artifacts.size(); i++)
  98. {
  99. const pipeline_cache_artifact& cc = cache_artifacts[i];
  100. if (vkdev->info.support_VK_KHR_descriptor_update_template)
  101. {
  102. if (cc.descriptor_update_template)
  103. {
  104. vkdev->vkDestroyDescriptorUpdateTemplateKHR(vkdev->vkdevice(), cc.descriptor_update_template, 0);
  105. }
  106. }
  107. if (cc.pipeline)
  108. {
  109. vkDestroyPipeline(vkdev->vkdevice(), cc.pipeline, 0);
  110. }
  111. if (cc.pipeline_layout)
  112. {
  113. vkDestroyPipelineLayout(vkdev->vkdevice(), cc.pipeline_layout, 0);
  114. }
  115. if (cc.descriptorset_layout)
  116. {
  117. vkDestroyDescriptorSetLayout(vkdev->vkdevice(), cc.descriptorset_layout, 0);
  118. }
  119. if (cc.shader_module)
  120. {
  121. vkDestroyShaderModule(vkdev->vkdevice(), cc.shader_module, 0);
  122. }
  123. }
  124. cache_digests.clear();
  125. cache_artifacts.clear();
  126. }
  127. int PipelineCache::get_pipeline(const uint32_t* spv_data, size_t spv_data_size, const std::vector<vk_specialization_type>& specializations,
  128. uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z,
  129. VkShaderModule* _shader_module,
  130. VkDescriptorSetLayout* descriptorset_layout,
  131. VkPipelineLayout* pipeline_layout,
  132. VkPipeline* pipeline,
  133. VkDescriptorUpdateTemplateKHR* descriptor_update_template,
  134. ShaderInfo& shader_info) const
  135. {
  136. MutexLockGuard lock(cache_lock);
  137. pipeline_cache_digest key(spv_data, spv_data_size, specializations, local_size_x, local_size_y, local_size_z);
  138. if (!vkdev->info.bug_corrupted_online_pipeline_cache)
  139. {
  140. // find cache
  141. for (size_t i = 0; i < cache_digests.size(); i++)
  142. {
  143. if (cache_digests[i] != key)
  144. continue;
  145. // hit cache
  146. const pipeline_cache_artifact& cc = cache_artifacts[i];
  147. *_shader_module = cc.shader_module;
  148. *descriptorset_layout = cc.descriptorset_layout;
  149. *pipeline_layout = cc.pipeline_layout;
  150. *pipeline = cc.pipeline;
  151. *descriptor_update_template = cc.descriptor_update_template;
  152. shader_info = cc.shader_info;
  153. // NCNN_LOGE("get_pipeline hit %d", last_digest_index);
  154. return 0;
  155. }
  156. }
  157. int ret = 0;
  158. ret = resolve_shader_info(spv_data, spv_data_size, shader_info);
  159. if (ret != 0)
  160. {
  161. NCNN_LOGE("resolve_shader_info failed %d", ret);
  162. return -1;
  163. }
  164. VkShaderModule shader_module = vkdev->compile_shader_module(spv_data, spv_data_size, local_size_x, local_size_y, local_size_z);
  165. if (!shader_module)
  166. {
  167. NCNN_LOGE("create_shader_module failed");
  168. return -1;
  169. }
  170. ret = new_pipeline(shader_module, shader_info, specializations, descriptorset_layout, pipeline_layout, pipeline, descriptor_update_template);
  171. if (ret != 0)
  172. {
  173. NCNN_LOGE("new_pipeline failed");
  174. vkDestroyShaderModule(vkdev->vkdevice(), shader_module, 0);
  175. return -1;
  176. }
  177. *_shader_module = shader_module;
  178. // save to cache
  179. {
  180. pipeline_cache_artifact cc;
  181. cc.shader_module = *_shader_module;
  182. cc.descriptorset_layout = *descriptorset_layout;
  183. cc.pipeline_layout = *pipeline_layout;
  184. cc.pipeline = *pipeline;
  185. cc.descriptor_update_template = *descriptor_update_template;
  186. cc.shader_info = shader_info;
  187. cache_digests.push_back(key);
  188. cache_artifacts.push_back(cc);
  189. }
  190. // NCNN_LOGE("new_pipeline %d", last_digest_index);
  191. return 0;
  192. }
  193. int PipelineCache::get_pipeline(int shader_type_index, const Option& opt, const std::vector<vk_specialization_type>& specializations,
  194. uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z,
  195. VkShaderModule* _shader_module,
  196. VkDescriptorSetLayout* descriptorset_layout,
  197. VkPipelineLayout* pipeline_layout,
  198. VkPipeline* pipeline,
  199. VkDescriptorUpdateTemplateKHR* descriptor_update_template,
  200. ShaderInfo& shader_info) const
  201. {
  202. MutexLockGuard lock(cache_lock);
  203. pipeline_cache_digest key(shader_type_index, opt, specializations, local_size_x, local_size_y, local_size_z);
  204. if (!vkdev->info.bug_corrupted_online_pipeline_cache)
  205. {
  206. // find cache
  207. for (size_t i = 0; i < cache_digests.size(); i++)
  208. {
  209. if (cache_digests[i] != key)
  210. continue;
  211. // hit cache
  212. const pipeline_cache_artifact& cc = cache_artifacts[i];
  213. *_shader_module = cc.shader_module;
  214. *descriptorset_layout = cc.descriptorset_layout;
  215. *pipeline_layout = cc.pipeline_layout;
  216. *pipeline = cc.pipeline;
  217. *descriptor_update_template = cc.descriptor_update_template;
  218. shader_info = cc.shader_info;
  219. // NCNN_LOGE("get_pipeline hit %d", last_digest_index);
  220. return 0;
  221. }
  222. }
  223. int ret = 0;
  224. // create new pipeline
  225. VkShaderModule shader_module = 0;
  226. ret = create_shader_module(shader_type_index, opt, local_size_x, local_size_y, local_size_z, &shader_module, shader_info);
  227. if (ret != 0)
  228. {
  229. NCNN_LOGE("create_shader_module failed");
  230. return -1;
  231. }
  232. ret = new_pipeline(shader_module, shader_info, specializations, descriptorset_layout, pipeline_layout, pipeline, descriptor_update_template);
  233. if (ret != 0)
  234. {
  235. NCNN_LOGE("new_pipeline failed");
  236. vkDestroyShaderModule(vkdev->vkdevice(), shader_module, 0);
  237. return -1;
  238. }
  239. *_shader_module = shader_module;
  240. // save to cache
  241. {
  242. pipeline_cache_artifact cc;
  243. cc.shader_module = *_shader_module;
  244. cc.descriptorset_layout = *descriptorset_layout;
  245. cc.pipeline_layout = *pipeline_layout;
  246. cc.pipeline = *pipeline;
  247. cc.descriptor_update_template = *descriptor_update_template;
  248. cc.shader_info = shader_info;
  249. cache_digests.push_back(key);
  250. cache_artifacts.push_back(cc);
  251. }
  252. // NCNN_LOGE("new_pipeline %d", last_digest_index);
  253. return 0;
  254. }
  255. int PipelineCache::create_shader_module(int shader_type_index, const Option& opt, uint32_t local_size_x, uint32_t local_size_y, uint32_t local_size_z,
  256. VkShaderModule* _shader_module, ShaderInfo& si) const
  257. {
  258. std::vector<uint32_t> spirv;
  259. int retc = compile_spirv_module(shader_type_index, opt, spirv);
  260. if (retc != 0)
  261. {
  262. NCNN_LOGE("compile_spirv_module failed %d", retc);
  263. return -1;
  264. }
  265. const uint32_t* spv_data = spirv.data();
  266. size_t spv_data_size = spirv.size() * 4;
  267. int ret = resolve_shader_info(spv_data, spv_data_size, si);
  268. if (ret != 0)
  269. {
  270. NCNN_LOGE("resolve_shader_info failed %d", ret);
  271. return -1;
  272. }
  273. VkShaderModule shader_module = vkdev->compile_shader_module(spv_data, spv_data_size, local_size_x, local_size_y, local_size_z);
  274. if (!shader_module)
  275. {
  276. NCNN_LOGE("create_shader_module failed");
  277. return -1;
  278. }
  279. *_shader_module = shader_module;
  280. return 0;
  281. }
  282. int PipelineCache::new_pipeline(VkShaderModule shader_module, const ShaderInfo& shader_info, const std::vector<vk_specialization_type>& specializations,
  283. VkDescriptorSetLayout* _descriptorset_layout,
  284. VkPipelineLayout* _pipeline_layout,
  285. VkPipeline* _pipeline,
  286. VkDescriptorUpdateTemplateKHR* _descriptor_update_template) const
  287. {
  288. int ret = 0;
  289. VkDescriptorSetLayout descriptorset_layout = 0;
  290. VkPipelineLayout pipeline_layout = 0;
  291. VkPipeline pipeline = 0;
  292. VkDescriptorUpdateTemplateKHR descriptor_update_template = 0;
  293. // create new pipeline
  294. if ((int)specializations.size() != shader_info.specialization_count)
  295. {
  296. NCNN_LOGE("pipeline specialization count mismatch, expect %d but got %d", shader_info.specialization_count, (int)specializations.size());
  297. goto ERROR_PipelineCache;
  298. }
  299. ret = vkdev->create_descriptorset_layout(shader_info.binding_count, shader_info.binding_types, &descriptorset_layout);
  300. if (ret != 0)
  301. goto ERROR_PipelineCache;
  302. ret = vkdev->create_pipeline_layout(shader_info.push_constant_count, descriptorset_layout, &pipeline_layout);
  303. if (ret != 0)
  304. goto ERROR_PipelineCache;
  305. ret = vkdev->create_pipeline(shader_module, pipeline_layout, specializations, &pipeline);
  306. if (ret != 0)
  307. goto ERROR_PipelineCache;
  308. if (vkdev->info.support_VK_KHR_descriptor_update_template)
  309. {
  310. ret = vkdev->create_descriptor_update_template(shader_info.binding_count, shader_info.binding_types, descriptorset_layout, pipeline_layout, &descriptor_update_template);
  311. if (ret != 0)
  312. goto ERROR_PipelineCache;
  313. }
  314. *_descriptorset_layout = descriptorset_layout;
  315. *_pipeline_layout = pipeline_layout;
  316. *_pipeline = pipeline;
  317. *_descriptor_update_template = descriptor_update_template;
  318. return 0;
  319. ERROR_PipelineCache:
  320. if (vkdev->info.support_VK_KHR_descriptor_update_template)
  321. {
  322. if (descriptor_update_template)
  323. {
  324. vkdev->vkDestroyDescriptorUpdateTemplateKHR(vkdev->vkdevice(), descriptor_update_template, 0);
  325. }
  326. }
  327. if (pipeline)
  328. {
  329. vkDestroyPipeline(vkdev->vkdevice(), pipeline, 0);
  330. }
  331. if (pipeline_layout)
  332. {
  333. vkDestroyPipelineLayout(vkdev->vkdevice(), pipeline_layout, 0);
  334. }
  335. if (descriptorset_layout)
  336. {
  337. vkDestroyDescriptorSetLayout(vkdev->vkdevice(), descriptorset_layout, 0);
  338. }
  339. return -1;
  340. }
  341. #endif // NCNN_VULKAN
  342. } // namespace ncnn