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.

simpleomp.cpp 29 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  1. // Copyright 2020 Tencent
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. #include "platform.h"
  4. #if NCNN_SIMPLEOMP
  5. #include "simpleomp.h"
  6. #include "cpu.h" // ncnn::get_cpu_count()
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <stdint.h>
  11. #include <stdarg.h>
  12. #if __clang__
  13. extern "C" typedef void (*kmpc_micro)(int32_t* gtid, int32_t* tid, ...);
  14. extern "C" typedef void (*kmpc_micro_0)(int32_t* gtid, int32_t* tid);
  15. extern "C" typedef void (*kmpc_micro_1)(int32_t* gtid, int32_t* tid, void*);
  16. extern "C" typedef void (*kmpc_micro_2)(int32_t* gtid, int32_t* tid, void*, void*);
  17. extern "C" typedef void (*kmpc_micro_3)(int32_t* gtid, int32_t* tid, void*, void*, void*);
  18. extern "C" typedef void (*kmpc_micro_4)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*);
  19. extern "C" typedef void (*kmpc_micro_5)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*);
  20. extern "C" typedef void (*kmpc_micro_6)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*);
  21. extern "C" typedef void (*kmpc_micro_7)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*);
  22. extern "C" typedef void (*kmpc_micro_8)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*);
  23. extern "C" typedef void (*kmpc_micro_9)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  24. extern "C" typedef void (*kmpc_micro_10)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  25. extern "C" typedef void (*kmpc_micro_11)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  26. extern "C" typedef void (*kmpc_micro_12)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  27. extern "C" typedef void (*kmpc_micro_13)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  28. extern "C" typedef void (*kmpc_micro_14)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  29. extern "C" typedef void (*kmpc_micro_15)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  30. extern "C" typedef void (*kmpc_micro_16)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  31. extern "C" typedef void (*kmpc_micro_17)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  32. extern "C" typedef void (*kmpc_micro_18)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  33. extern "C" typedef void (*kmpc_micro_19)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  34. extern "C" typedef void (*kmpc_micro_20)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  35. extern "C" typedef void (*kmpc_micro_21)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  36. extern "C" typedef void (*kmpc_micro_22)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  37. extern "C" typedef void (*kmpc_micro_23)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  38. extern "C" typedef void (*kmpc_micro_24)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  39. extern "C" typedef void (*kmpc_micro_25)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  40. extern "C" typedef void (*kmpc_micro_26)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  41. extern "C" typedef void (*kmpc_micro_27)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  42. extern "C" typedef void (*kmpc_micro_28)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  43. extern "C" typedef void (*kmpc_micro_29)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  44. extern "C" typedef void (*kmpc_micro_30)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  45. extern "C" typedef void (*kmpc_micro_31)(int32_t* gtid, int32_t* tid, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*);
  46. #endif // __clang__
  47. #ifdef __cplusplus
  48. extern "C" {
  49. #endif
  50. static void init_g_kmp_global();
  51. static void* kmp_threadfunc(void* args);
  52. #ifdef __cplusplus
  53. } // extern "C"
  54. #endif
  55. namespace ncnn {
  56. class KMPTask
  57. {
  58. public:
  59. // per-team
  60. #if __clang__
  61. // libomp abi
  62. kmpc_micro fn;
  63. int argc;
  64. void** argv;
  65. #else
  66. // libgomp abi
  67. void (*fn)(void*);
  68. void* data;
  69. #endif
  70. int num_threads;
  71. // per-task
  72. int thread_num;
  73. // finish status
  74. int* num_threads_to_wait;
  75. Mutex* finish_lock;
  76. ConditionVariable* finish_condition;
  77. };
  78. class KMPTaskQueue
  79. {
  80. public:
  81. KMPTaskQueue(int _max_size)
  82. {
  83. max_size = _max_size;
  84. tasks = new KMPTask*[max_size];
  85. size = 0;
  86. front = 0;
  87. back = 0;
  88. }
  89. ~KMPTaskQueue()
  90. {
  91. delete[] tasks;
  92. }
  93. void dispatch(KMPTask* v, int n)
  94. {
  95. lock.lock();
  96. if (size + n > max_size)
  97. {
  98. lock.unlock();
  99. for (int i = 0; i < n; i++)
  100. {
  101. put(&v[i]);
  102. }
  103. return;
  104. }
  105. for (int i = 0; i < n; i++)
  106. {
  107. tasks[back] = &v[i];
  108. back++;
  109. if (back == max_size)
  110. back = 0;
  111. }
  112. size += n;
  113. lock.unlock();
  114. condition.signal();
  115. }
  116. void put(KMPTask* v)
  117. {
  118. lock.lock();
  119. while (size >= max_size)
  120. {
  121. condition.wait(lock);
  122. }
  123. tasks[back] = v;
  124. back++;
  125. if (back == max_size)
  126. back = 0;
  127. size++;
  128. lock.unlock();
  129. condition.signal();
  130. }
  131. void get(KMPTask*& v)
  132. {
  133. lock.lock();
  134. while (size == 0)
  135. {
  136. condition.wait(lock);
  137. }
  138. v = tasks[front];
  139. front++;
  140. if (front == max_size)
  141. front = 0;
  142. size--;
  143. lock.unlock();
  144. condition.signal();
  145. }
  146. private:
  147. Mutex lock;
  148. ConditionVariable condition;
  149. // ring buffer queue
  150. int max_size;
  151. KMPTask** tasks;
  152. int size;
  153. int front;
  154. int back;
  155. };
  156. class KMPGlobal
  157. {
  158. public:
  159. KMPGlobal()
  160. {
  161. kmp_max_threads = 0;
  162. kmp_threads = 0;
  163. kmp_threads_tid = 0;
  164. kmp_task_queue = 0;
  165. }
  166. ~KMPGlobal()
  167. {
  168. deinit();
  169. }
  170. void try_init()
  171. {
  172. pthread_once(&is_initialized, init_g_kmp_global);
  173. }
  174. public:
  175. static pthread_once_t is_initialized;
  176. void init()
  177. {
  178. // NCNN_LOGE("KMPGlobal init");
  179. kmp_max_threads = ncnn::get_cpu_count();
  180. kmp_task_queue = new ncnn::KMPTaskQueue(std::max(kmp_max_threads * 4, 16));
  181. if (kmp_max_threads > 1)
  182. {
  183. kmp_threads = new ncnn::Thread*[kmp_max_threads - 1];
  184. kmp_threads_tid = new int[kmp_max_threads - 1];
  185. for (int i = 0; i < kmp_max_threads - 1; i++)
  186. {
  187. kmp_threads_tid[i] = i + 1;
  188. kmp_threads[i] = new ncnn::Thread(kmp_threadfunc, (void*)&kmp_threads_tid[i]);
  189. }
  190. }
  191. }
  192. void deinit()
  193. {
  194. // NCNN_LOGE("KMPGlobal deinit");
  195. if (kmp_max_threads > 1)
  196. {
  197. // TODO portable stack allocation
  198. ncnn::KMPTask* tasks = (ncnn::KMPTask*)alloca((kmp_max_threads - 1) * sizeof(ncnn::KMPTask));
  199. for (int i = 0; i < kmp_max_threads - 1; i++)
  200. {
  201. #if __clang__
  202. tasks[i].fn = 0;
  203. tasks[i].argc = 0;
  204. tasks[i].argv = (void**)0;
  205. #else
  206. tasks[i].fn = 0;
  207. tasks[i].data = 0;
  208. #endif
  209. tasks[i].num_threads = kmp_max_threads;
  210. tasks[i].thread_num = i + 1;
  211. tasks[i].num_threads_to_wait = 0;
  212. tasks[i].finish_lock = 0;
  213. tasks[i].finish_condition = 0;
  214. }
  215. // dispatch 1 ~ kmp_max_threads
  216. kmp_task_queue->dispatch(tasks, kmp_max_threads - 1);
  217. for (int i = 0; i < kmp_max_threads - 1; i++)
  218. {
  219. #ifndef __EMSCRIPTEN__
  220. // FIXME emscripten complains
  221. // pthread_join attempted on thread 12345678,
  222. // which does not point to a valid thread, or does not exist anymore!
  223. kmp_threads[i]->join();
  224. #endif
  225. delete kmp_threads[i];
  226. }
  227. delete[] kmp_threads;
  228. delete[] kmp_threads_tid;
  229. }
  230. delete kmp_task_queue;
  231. }
  232. public:
  233. int kmp_max_threads;
  234. ncnn::Thread** kmp_threads;
  235. int* kmp_threads_tid;
  236. ncnn::KMPTaskQueue* kmp_task_queue;
  237. };
  238. } // namespace ncnn
  239. pthread_once_t ncnn::KMPGlobal::is_initialized = PTHREAD_ONCE_INIT;
  240. static ncnn::KMPGlobal g_kmp_global;
  241. static ncnn::ThreadLocalStorage tls_num_threads;
  242. static ncnn::ThreadLocalStorage tls_thread_num;
  243. static void init_g_kmp_global()
  244. {
  245. g_kmp_global.init();
  246. }
  247. #ifdef __cplusplus
  248. extern "C" {
  249. #endif
  250. int omp_get_max_threads()
  251. {
  252. return ncnn::get_cpu_count();
  253. }
  254. int omp_get_dynamic()
  255. {
  256. return 1;
  257. }
  258. void omp_set_dynamic(int /*dynamic*/)
  259. {
  260. // always dynamic, ignore
  261. }
  262. void omp_set_num_threads(int num_threads)
  263. {
  264. tls_num_threads.set(reinterpret_cast<void*>((size_t)std::max(num_threads, 1)));
  265. }
  266. int omp_get_num_threads()
  267. {
  268. return std::max((int)reinterpret_cast<size_t>(tls_num_threads.get()), 1);
  269. }
  270. int omp_get_thread_num()
  271. {
  272. return (int)reinterpret_cast<size_t>(tls_thread_num.get());
  273. }
  274. #if __clang__
  275. int kmp_get_blocktime()
  276. {
  277. return 0;
  278. }
  279. void kmp_set_blocktime(int /*blocktime*/)
  280. {
  281. // always passive, ignore
  282. }
  283. static int kmp_invoke_microtask(kmpc_micro fn, int gtid, int tid, int argc, void** argv)
  284. {
  285. // fprintf(stderr, "__kmp_invoke_microtask %d %d %d\n", gtid, tid, argc);
  286. switch (argc)
  287. {
  288. case 0:
  289. (*(kmpc_micro_0)fn)(&gtid, &tid);
  290. break;
  291. case 1:
  292. (*(kmpc_micro_1)fn)(&gtid, &tid, argv[0]);
  293. break;
  294. case 2:
  295. (*(kmpc_micro_2)fn)(&gtid, &tid, argv[0], argv[1]);
  296. break;
  297. case 3:
  298. (*(kmpc_micro_3)fn)(&gtid, &tid, argv[0], argv[1], argv[2]);
  299. break;
  300. case 4:
  301. (*(kmpc_micro_4)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3]);
  302. break;
  303. case 5:
  304. (*(kmpc_micro_5)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4]);
  305. break;
  306. case 6:
  307. (*(kmpc_micro_6)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
  308. break;
  309. case 7:
  310. (*(kmpc_micro_7)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
  311. break;
  312. case 8:
  313. (*(kmpc_micro_8)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
  314. break;
  315. case 9:
  316. (*(kmpc_micro_9)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
  317. break;
  318. case 10:
  319. (*(kmpc_micro_10)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
  320. break;
  321. case 11:
  322. (*(kmpc_micro_11)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
  323. break;
  324. case 12:
  325. (*(kmpc_micro_12)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]);
  326. break;
  327. case 13:
  328. (*(kmpc_micro_13)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12]);
  329. break;
  330. case 14:
  331. (*(kmpc_micro_14)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13]);
  332. break;
  333. case 15:
  334. (*(kmpc_micro_15)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14]);
  335. break;
  336. case 16:
  337. (*(kmpc_micro_16)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15]);
  338. break;
  339. case 17:
  340. (*(kmpc_micro_17)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16]);
  341. break;
  342. case 18:
  343. (*(kmpc_micro_18)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17]);
  344. break;
  345. case 19:
  346. (*(kmpc_micro_19)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18]);
  347. break;
  348. case 20:
  349. (*(kmpc_micro_20)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], argv[19]);
  350. break;
  351. case 21:
  352. (*(kmpc_micro_21)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], argv[19], argv[20]);
  353. break;
  354. case 22:
  355. (*(kmpc_micro_22)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], argv[19], argv[20], argv[21]);
  356. break;
  357. case 23:
  358. (*(kmpc_micro_23)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], argv[19], argv[20], argv[21], argv[22]);
  359. break;
  360. case 24:
  361. (*(kmpc_micro_24)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], argv[19], argv[20], argv[21], argv[22], argv[23]);
  362. break;
  363. case 25:
  364. (*(kmpc_micro_25)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], argv[19], argv[20], argv[21], argv[22], argv[23], argv[24]);
  365. break;
  366. case 26:
  367. (*(kmpc_micro_26)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], argv[19], argv[20], argv[21], argv[22], argv[23], argv[24], argv[25]);
  368. break;
  369. case 27:
  370. (*(kmpc_micro_27)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], argv[19], argv[20], argv[21], argv[22], argv[23], argv[24], argv[25], argv[26]);
  371. break;
  372. case 28:
  373. (*(kmpc_micro_28)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], argv[19], argv[20], argv[21], argv[22], argv[23], argv[24], argv[25], argv[26], argv[27]);
  374. break;
  375. case 29:
  376. (*(kmpc_micro_29)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], argv[19], argv[20], argv[21], argv[22], argv[23], argv[24], argv[25], argv[26], argv[27], argv[28]);
  377. break;
  378. case 30:
  379. (*(kmpc_micro_30)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], argv[19], argv[20], argv[21], argv[22], argv[23], argv[24], argv[25], argv[26], argv[27], argv[28], argv[29]);
  380. break;
  381. case 31:
  382. (*(kmpc_micro_31)fn)(&gtid, &tid, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], argv[19], argv[20], argv[21], argv[22], argv[23], argv[24], argv[25], argv[26], argv[27], argv[28], argv[29], argv[30]);
  383. break;
  384. default:
  385. // assert never reach here
  386. break;
  387. }
  388. return 0;
  389. }
  390. #endif // __clang__
  391. static void* kmp_threadfunc(void* args)
  392. {
  393. #if __clang__
  394. int tid = *(int*)args;
  395. #else
  396. (void)args;
  397. #endif
  398. for (;;)
  399. {
  400. ncnn::KMPTask* task;
  401. g_kmp_global.kmp_task_queue->get(task);
  402. // fprintf(stderr, "get %d\n", tid);
  403. if (!task->fn)
  404. break;
  405. tls_num_threads.set(reinterpret_cast<void*>((size_t)task->num_threads));
  406. tls_thread_num.set(reinterpret_cast<void*>((size_t)task->thread_num));
  407. #if __clang__
  408. kmp_invoke_microtask(task->fn, task->thread_num, tid, task->argc, task->argv);
  409. #else
  410. task->fn(task->data);
  411. #endif
  412. // update finished
  413. {
  414. task->finish_lock->lock();
  415. *task->num_threads_to_wait = *task->num_threads_to_wait - 1;
  416. if (*task->num_threads_to_wait == 0)
  417. {
  418. task->finish_condition->signal();
  419. }
  420. task->finish_lock->unlock();
  421. }
  422. }
  423. // fprintf(stderr, "exit\n");
  424. return 0;
  425. }
  426. #if __clang__
  427. int32_t __kmpc_global_thread_num(void* /*loc*/)
  428. {
  429. // NCNN_LOGE("__kmpc_global_thread_num");
  430. return 0;
  431. }
  432. void __kmpc_push_num_threads(void* /*loc*/, int32_t /*gtid*/, int32_t num_threads)
  433. {
  434. // NCNN_LOGE("__kmpc_push_num_threads %d", num_threads);
  435. omp_set_num_threads(num_threads);
  436. }
  437. void __kmpc_fork_call(void* /*loc*/, int32_t argc, kmpc_micro fn, ...)
  438. {
  439. g_kmp_global.try_init();
  440. // NCNN_LOGE("__kmpc_fork_call %d", argc);
  441. int num_threads = omp_get_num_threads();
  442. // build argv
  443. void* argv[32];
  444. {
  445. va_list ap;
  446. va_start(ap, fn);
  447. for (int i = 0; i < argc; i++)
  448. argv[i] = va_arg(ap, void*);
  449. va_end(ap);
  450. }
  451. if (g_kmp_global.kmp_max_threads == 1 || num_threads == 1)
  452. {
  453. for (int i = 0; i < num_threads; i++)
  454. {
  455. tls_thread_num.set(reinterpret_cast<void*>((size_t)i));
  456. kmp_invoke_microtask(fn, 0, 0, argc, argv);
  457. }
  458. return;
  459. }
  460. int num_threads_to_wait = num_threads - 1;
  461. ncnn::Mutex finish_lock;
  462. ncnn::ConditionVariable finish_condition;
  463. // TODO portable stack allocation
  464. ncnn::KMPTask* tasks = (ncnn::KMPTask*)alloca((num_threads - 1) * sizeof(ncnn::KMPTask));
  465. for (int i = 0; i < num_threads - 1; i++)
  466. {
  467. tasks[i].fn = fn;
  468. tasks[i].argc = argc;
  469. tasks[i].argv = (void**)argv;
  470. tasks[i].num_threads = num_threads;
  471. tasks[i].thread_num = i + 1;
  472. tasks[i].num_threads_to_wait = &num_threads_to_wait;
  473. tasks[i].finish_lock = &finish_lock;
  474. tasks[i].finish_condition = &finish_condition;
  475. }
  476. // dispatch 1 ~ num_threads
  477. g_kmp_global.kmp_task_queue->dispatch(tasks, num_threads - 1);
  478. // dispatch 0
  479. {
  480. tls_num_threads.set(reinterpret_cast<void*>((size_t)num_threads));
  481. tls_thread_num.set(reinterpret_cast<void*>((size_t)0));
  482. kmp_invoke_microtask(fn, 0, 0, argc, argv);
  483. }
  484. // wait for finished
  485. {
  486. finish_lock.lock();
  487. if (num_threads_to_wait != 0)
  488. {
  489. finish_condition.wait(finish_lock);
  490. }
  491. finish_lock.unlock();
  492. }
  493. }
  494. void __kmpc_for_static_init_4(void* /*loc*/, int32_t gtid, int32_t /*sched*/, int32_t* last, int32_t* lower, int32_t* upper, int32_t* /*stride*/, int32_t /*incr*/, int32_t /*chunk*/)
  495. {
  496. // NCNN_LOGE("__kmpc_for_static_init_4");
  497. int num_threads = omp_get_num_threads();
  498. // TODO only support i++
  499. int32_t count = *upper - *lower + 1;
  500. int32_t threads = std::min(count, (int32_t)num_threads);
  501. int32_t count_per_thread = count / threads;
  502. int32_t remain = count % threads;
  503. *last = gtid == (int32_t)(threads - 1);
  504. *lower = gtid * count_per_thread + std::min(remain, gtid);
  505. *upper = std::min((gtid + 1) * count_per_thread + std::min(remain, gtid + 1) - 1, *upper);
  506. }
  507. void __kmpc_for_static_init_4u(void* /*loc*/, int32_t gtid, int32_t /*sched*/, int32_t* last, uint32_t* lower, uint32_t* upper, int32_t* /*stride*/, int32_t /*incr*/, int32_t /*chunk*/)
  508. {
  509. // NCNN_LOGE("__kmpc_for_static_init_4u");
  510. int num_threads = omp_get_num_threads();
  511. // TODO only support i++
  512. uint32_t count = *upper - *lower + 1;
  513. uint32_t threads = std::min(count, (uint32_t)num_threads);
  514. uint32_t count_per_thread = count / threads;
  515. uint32_t remain = count % threads;
  516. *last = gtid == (int32_t)(threads - 1);
  517. *lower = gtid * count_per_thread + std::min(remain, (uint32_t)gtid);
  518. *upper = std::min((gtid + 1) * count_per_thread + std::min(remain, (uint32_t)gtid + 1) - 1, *upper);
  519. }
  520. void __kmpc_for_static_init_8(void* /*loc*/, int32_t gtid, int32_t /*sched*/, int32_t* last, int64_t* lower, int64_t* upper, int64_t* /*stride*/, int64_t /*incr*/, int64_t /*chunk*/)
  521. {
  522. // NCNN_LOGE("__kmpc_for_static_init_8");
  523. int num_threads = omp_get_num_threads();
  524. // TODO only support i++
  525. int64_t count = *upper - *lower + 1;
  526. int64_t threads = std::min(count, (int64_t)num_threads);
  527. int64_t count_per_thread = count / threads;
  528. int64_t remain = count % threads;
  529. *last = gtid == (int64_t)(threads - 1);
  530. *lower = gtid * count_per_thread + std::min(remain, (int64_t)gtid);
  531. *upper = std::min((gtid + 1) * count_per_thread + std::min(remain, (int64_t)gtid + 1) - 1, *upper);
  532. }
  533. void __kmpc_for_static_init_8u(void* /*loc*/, int32_t gtid, int32_t /*sched*/, int32_t* last, uint64_t* lower, uint64_t* upper, int64_t* /*stride*/, int64_t /*incr*/, int64_t /*chunk*/)
  534. {
  535. // NCNN_LOGE("__kmpc_for_static_init_8u");
  536. int num_threads = omp_get_num_threads();
  537. // TODO only support i++
  538. uint64_t count = *upper - *lower + 1;
  539. uint64_t threads = std::min(count, (uint64_t)num_threads);
  540. uint64_t count_per_thread = count / threads;
  541. uint64_t remain = count % threads;
  542. *last = gtid == (int64_t)(threads - 1);
  543. *lower = gtid * count_per_thread + std::min(remain, (uint64_t)gtid);
  544. *upper = std::min((gtid + 1) * count_per_thread + std::min(remain, (uint64_t)gtid + 1) - 1, *upper);
  545. }
  546. void __kmpc_for_static_fini(void* /*loc*/, int32_t gtid)
  547. {
  548. // NCNN_LOGE("__kmpc_for_static_fini");
  549. (void)gtid;
  550. }
  551. #else // __clang__
  552. static ncnn::ThreadLocalStorage tls_parallel_context;
  553. struct parallel_context
  554. {
  555. int num_threads_to_wait;
  556. ncnn::Mutex finish_lock;
  557. ncnn::ConditionVariable finish_condition;
  558. ncnn::KMPTask* tasks;
  559. };
  560. void GOMP_parallel_start(void (*fn)(void*), void* data, unsigned num_threads)
  561. {
  562. g_kmp_global.try_init();
  563. // NCNN_LOGE("GOMP_parallel_start %p %p %u", fn, data, num_threads);
  564. if (num_threads == 0)
  565. {
  566. num_threads = omp_get_max_threads();
  567. }
  568. if (g_kmp_global.kmp_max_threads == 1 || num_threads == 1)
  569. {
  570. for (unsigned i = 0; i < num_threads; i++)
  571. {
  572. tls_num_threads.set(reinterpret_cast<void*>((size_t)num_threads));
  573. tls_thread_num.set(reinterpret_cast<void*>((size_t)i));
  574. fn(data);
  575. }
  576. return;
  577. }
  578. parallel_context* pc = new parallel_context;
  579. tls_parallel_context.set(pc);
  580. pc->num_threads_to_wait = num_threads - 1;
  581. pc->tasks = new ncnn::KMPTask[num_threads - 1];
  582. for (unsigned i = 0; i < num_threads - 1; i++)
  583. {
  584. pc->tasks[i].fn = fn;
  585. pc->tasks[i].data = data;
  586. pc->tasks[i].num_threads = num_threads;
  587. pc->tasks[i].thread_num = i + 1;
  588. pc->tasks[i].num_threads_to_wait = &pc->num_threads_to_wait;
  589. pc->tasks[i].finish_lock = &pc->finish_lock;
  590. pc->tasks[i].finish_condition = &pc->finish_condition;
  591. }
  592. // dispatch 1 ~ num_threads
  593. g_kmp_global.kmp_task_queue->dispatch(pc->tasks, num_threads - 1);
  594. // dispatch 0
  595. {
  596. tls_num_threads.set(reinterpret_cast<void*>((size_t)num_threads));
  597. tls_thread_num.set(reinterpret_cast<void*>((size_t)0));
  598. }
  599. }
  600. void GOMP_parallel_end()
  601. {
  602. // NCNN_LOGE("GOMP_parallel_end");
  603. parallel_context* pc = (parallel_context*)tls_parallel_context.get();
  604. tls_parallel_context.set(0);
  605. // wait for finished
  606. {
  607. pc->finish_lock.lock();
  608. if (pc->num_threads_to_wait != 0)
  609. {
  610. pc->finish_condition.wait(pc->finish_lock);
  611. }
  612. pc->finish_lock.unlock();
  613. }
  614. delete[] pc->tasks;
  615. delete pc;
  616. }
  617. void GOMP_parallel(void (*fn)(void*), void* data, unsigned num_threads, unsigned int /*flags*/)
  618. {
  619. g_kmp_global.try_init();
  620. // NCNN_LOGE("GOMP_parallel %p %p %u", fn, data, num_threads);
  621. if (num_threads == 0)
  622. {
  623. num_threads = omp_get_max_threads();
  624. }
  625. if (g_kmp_global.kmp_max_threads == 1 || num_threads == 1)
  626. {
  627. for (unsigned i = 0; i < num_threads; i++)
  628. {
  629. tls_num_threads.set(reinterpret_cast<void*>((size_t)num_threads));
  630. tls_thread_num.set(reinterpret_cast<void*>((size_t)i));
  631. fn(data);
  632. }
  633. return;
  634. }
  635. int num_threads_to_wait = num_threads - 1;
  636. ncnn::Mutex finish_lock;
  637. ncnn::ConditionVariable finish_condition;
  638. // TODO portable stack allocation
  639. ncnn::KMPTask* tasks = (ncnn::KMPTask*)alloca((num_threads - 1) * sizeof(ncnn::KMPTask));
  640. for (unsigned i = 0; i < num_threads - 1; i++)
  641. {
  642. tasks[i].fn = fn;
  643. tasks[i].data = data;
  644. tasks[i].num_threads = num_threads;
  645. tasks[i].thread_num = i + 1;
  646. tasks[i].num_threads_to_wait = &num_threads_to_wait;
  647. tasks[i].finish_lock = &finish_lock;
  648. tasks[i].finish_condition = &finish_condition;
  649. }
  650. // dispatch 1 ~ num_threads
  651. g_kmp_global.kmp_task_queue->dispatch(tasks, num_threads - 1);
  652. // dispatch 0
  653. {
  654. tls_num_threads.set(reinterpret_cast<void*>((size_t)num_threads));
  655. tls_thread_num.set(reinterpret_cast<void*>((size_t)0));
  656. fn(data);
  657. }
  658. // wait for finished
  659. {
  660. finish_lock.lock();
  661. if (num_threads_to_wait != 0)
  662. {
  663. finish_condition.wait(finish_lock);
  664. }
  665. finish_lock.unlock();
  666. }
  667. }
  668. #endif // __clang__
  669. #ifdef __cplusplus
  670. } // extern "C"
  671. #endif
  672. #endif // NCNN_SIMPLEOMP