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.

cpu.cpp 74 kB

5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952
  1. // Tencent is pleased to support the open source community by making ncnn available.
  2. //
  3. // Copyright (C) 2017 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 "cpu.h"
  15. #include "platform.h"
  16. #include <limits.h>
  17. #ifndef __wasi__
  18. #include <setjmp.h>
  19. #include <signal.h>
  20. #endif // __wasi__
  21. #include <stdio.h>
  22. #include <string.h>
  23. #ifdef _OPENMP
  24. #if NCNN_SIMPLEOMP
  25. #include "simpleomp.h"
  26. #else
  27. #include <omp.h>
  28. #endif
  29. #endif
  30. #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  31. #ifdef _MSC_VER
  32. #include <intrin.h> // __cpuid()
  33. #include <immintrin.h> // _xgetbv()
  34. #endif
  35. #if defined(__clang__) || defined(__GNUC__)
  36. #include <cpuid.h> // __get_cpuid() and __cpuid_count()
  37. #endif
  38. #endif
  39. #ifdef __EMSCRIPTEN__
  40. #include <emscripten/threading.h>
  41. #endif
  42. #if defined _WIN32
  43. #define WIN32_LEAN_AND_MEAN
  44. #include <windows.h>
  45. #endif
  46. #if defined __ANDROID__ || defined __linux__
  47. #if defined __ANDROID__
  48. #if __ANDROID_API__ >= 18
  49. #include <sys/auxv.h> // getauxval()
  50. #endif
  51. #include <sys/system_properties.h> // __system_property_get()
  52. #include <dlfcn.h>
  53. #endif
  54. #include <ctype.h>
  55. #include <stdint.h>
  56. #include <fcntl.h>
  57. #include <sys/stat.h>
  58. #include <sys/syscall.h>
  59. #include <unistd.h>
  60. #endif
  61. #if __APPLE__
  62. #include <mach/mach.h>
  63. #include <mach/machine.h>
  64. #include <mach/thread_act.h>
  65. #include <sys/sysctl.h>
  66. #include <sys/types.h>
  67. #include <unistd.h>
  68. #include "TargetConditionals.h"
  69. #if TARGET_OS_IPHONE
  70. #define __IOS__ 1
  71. #endif
  72. // define missing cpu model for old sdk
  73. #ifndef CPUFAMILY_ARM_HURRICANE
  74. #define CPUFAMILY_ARM_HURRICANE 0x67ceee93
  75. #endif
  76. // A11
  77. #ifndef CPUFAMILY_ARM_MONSOON_MISTRAL
  78. #define CPUFAMILY_ARM_MONSOON_MISTRAL 0xe81e7ef6
  79. #endif
  80. // A12
  81. #ifndef CPUFAMILY_ARM_VORTEX_TEMPEST
  82. #define CPUFAMILY_ARM_VORTEX_TEMPEST 0x07d34b9f
  83. #endif
  84. // A13
  85. #ifndef CPUFAMILY_ARM_LIGHTNING_THUNDER
  86. #define CPUFAMILY_ARM_LIGHTNING_THUNDER 0x462504d2
  87. #endif
  88. // A14 / M1
  89. #ifndef CPUFAMILY_ARM_FIRESTORM_ICESTORM
  90. #define CPUFAMILY_ARM_FIRESTORM_ICESTORM 0x1b588bb3
  91. #endif
  92. // A15 / M2
  93. #ifndef CPUFAMILY_ARM_AVALANCHE_BLIZZARD
  94. #define CPUFAMILY_ARM_AVALANCHE_BLIZZARD 0xda33d83d
  95. #endif
  96. // A16
  97. #ifndef CPUFAMILY_ARM_EVEREST_SAWTOOTH
  98. #define CPUFAMILY_ARM_EVEREST_SAWTOOTH 0x8765edea
  99. #endif
  100. // A17
  101. #ifndef CPUFAMILY_ARM_COLL
  102. #define CPUFAMILY_ARM_COLL 0x2876f5b5
  103. #endif
  104. // M3
  105. #ifndef CPUFAMILY_ARM_IBIZA
  106. #define CPUFAMILY_ARM_IBIZA 0xfa33415e
  107. #endif
  108. // M3 Pro
  109. #ifndef CPUFAMILY_ARM_LOBOS
  110. #define CPUFAMILY_ARM_LOBOS 0x5f4dea93
  111. #endif
  112. // M3 Max
  113. #ifndef CPUFAMILY_ARM_PALMA
  114. #define CPUFAMILY_ARM_PALMA 0x72015832
  115. #endif
  116. #endif // __APPLE__
  117. #if defined(__SSE3__)
  118. #include <immintrin.h>
  119. #endif
  120. #if (defined _WIN32 && (__aarch64__ || __arm__))
  121. #define RUAPU_IMPLEMENTATION
  122. #include "ruapu.h"
  123. #endif
  124. // topology info
  125. static int g_cpucount;
  126. static int g_physical_cpucount;
  127. static int g_powersave;
  128. static ncnn::CpuSet g_cpu_affinity_mask_all;
  129. static ncnn::CpuSet g_cpu_affinity_mask_little;
  130. static ncnn::CpuSet g_cpu_affinity_mask_big;
  131. // isa info
  132. #if defined _WIN32
  133. #if __aarch64__
  134. static int g_cpu_support_arm_asimdhp;
  135. static int g_cpu_support_arm_cpuid;
  136. static int g_cpu_support_arm_asimddp;
  137. static int g_cpu_support_arm_asimdfhm;
  138. static int g_cpu_support_arm_bf16;
  139. static int g_cpu_support_arm_i8mm;
  140. static int g_cpu_support_arm_sve;
  141. static int g_cpu_support_arm_sve2;
  142. static int g_cpu_support_arm_svebf16;
  143. static int g_cpu_support_arm_svei8mm;
  144. static int g_cpu_support_arm_svef32mm;
  145. #elif __arm__
  146. static int g_cpu_support_arm_edsp;
  147. static int g_cpu_support_arm_neon;
  148. static int g_cpu_support_arm_vfpv4;
  149. #endif // __aarch64__ || __arm__
  150. #elif defined __ANDROID__ || defined __linux__
  151. static unsigned int g_hwcaps;
  152. static unsigned int g_hwcaps2;
  153. #elif __APPLE__
  154. static unsigned int g_hw_cpufamily;
  155. static cpu_type_t g_hw_cputype;
  156. static cpu_subtype_t g_hw_cpusubtype;
  157. #if __aarch64__
  158. static int g_hw_optional_arm_FEAT_FP16;
  159. static int g_hw_optional_arm_FEAT_DotProd;
  160. static int g_hw_optional_arm_FEAT_FHM;
  161. static int g_hw_optional_arm_FEAT_BF16;
  162. static int g_hw_optional_arm_FEAT_I8MM;
  163. #endif // __aarch64__
  164. #endif
  165. #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  166. static int g_cpu_support_x86_avx;
  167. static int g_cpu_support_x86_fma;
  168. static int g_cpu_support_x86_xop;
  169. static int g_cpu_support_x86_f16c;
  170. static int g_cpu_support_x86_avx2;
  171. static int g_cpu_support_x86_avx_vnni;
  172. static int g_cpu_support_x86_avx512;
  173. static int g_cpu_support_x86_avx512_vnni;
  174. static int g_cpu_support_x86_avx512_bf16;
  175. static int g_cpu_support_x86_avx512_fp16;
  176. #endif // defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  177. static int g_cpu_level2_cachesize;
  178. static int g_cpu_level3_cachesize;
  179. // misc info
  180. #if defined __ANDROID__ || defined __linux__
  181. #if __aarch64__
  182. static int g_cpu_is_arm_a53_a55;
  183. #endif // __aarch64__
  184. #endif // defined __ANDROID__ || defined __linux__
  185. static bool is_being_debugged()
  186. {
  187. #if defined _WIN32
  188. return IsDebuggerPresent();
  189. #elif defined __ANDROID__ || defined __linux__
  190. // https://stackoverflow.com/questions/3596781/how-to-detect-if-the-current-process-is-being-run-by-gdb
  191. int status_fd = open("/proc/self/status", O_RDONLY);
  192. if (status_fd == -1)
  193. return false;
  194. char buf[4096];
  195. ssize_t num_read = read(status_fd, buf, sizeof(buf) - 1);
  196. close(status_fd);
  197. if (num_read <= 0)
  198. return false;
  199. buf[num_read] = '\0';
  200. const char tracerPidString[] = "TracerPid:";
  201. const char* tracer_pid_ptr = strstr(buf, tracerPidString);
  202. if (!tracer_pid_ptr)
  203. return false;
  204. for (const char* ch = tracer_pid_ptr + sizeof(tracerPidString) - 1; ch <= buf + num_read; ++ch)
  205. {
  206. if (isspace(*ch))
  207. continue;
  208. return isdigit(*ch) != 0 && *ch != '0';
  209. }
  210. return false;
  211. #elif defined __APPLE__
  212. // https://stackoverflow.com/questions/2200277/detecting-debugger-on-mac-os-x
  213. struct kinfo_proc info;
  214. info.kp_proc.p_flag = 0;
  215. int mib[4];
  216. mib[0] = CTL_KERN;
  217. mib[1] = KERN_PROC;
  218. mib[2] = KERN_PROC_PID;
  219. mib[3] = getpid();
  220. size_t size = sizeof(info);
  221. sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
  222. return ((info.kp_proc.p_flag & P_TRACED) != 0);
  223. #else
  224. // unknown platform :(
  225. fprintf(stderr, "unknown platform!\n");
  226. return false;
  227. #endif
  228. }
  229. #if defined __ANDROID__ || defined __linux__
  230. #define AT_HWCAP 16
  231. #define AT_HWCAP2 26
  232. #if __aarch64__
  233. // from arch/arm64/include/uapi/asm/hwcap.h
  234. #define HWCAP_ASIMD (1 << 1)
  235. #define HWCAP_ASIMDHP (1 << 10)
  236. #define HWCAP_CPUID (1 << 11)
  237. #define HWCAP_ASIMDDP (1 << 20)
  238. #define HWCAP_SVE (1 << 22)
  239. #define HWCAP_ASIMDFHM (1 << 23)
  240. #define HWCAP2_SVE2 (1 << 1)
  241. #define HWCAP2_SVEI8MM (1 << 9)
  242. #define HWCAP2_SVEF32MM (1 << 10)
  243. #define HWCAP2_SVEBF16 (1 << 12)
  244. #define HWCAP2_I8MM (1 << 13)
  245. #define HWCAP2_BF16 (1 << 14)
  246. #else
  247. // from arch/arm/include/uapi/asm/hwcap.h
  248. #define HWCAP_EDSP (1 << 7)
  249. #define HWCAP_NEON (1 << 12)
  250. #define HWCAP_VFPv4 (1 << 16)
  251. #endif
  252. #if __mips__
  253. // from arch/mips/include/uapi/asm/hwcap.h
  254. #define HWCAP_MIPS_MSA (1 << 1)
  255. #define HWCAP_LOONGSON_MMI (1 << 11)
  256. #endif
  257. #if __loongarch64
  258. // from arch/loongarch/include/uapi/asm/hwcap.h
  259. #define HWCAP_LOONGARCH_LSX (1 << 4)
  260. #define HWCAP_LOONGARCH_LASX (1 << 5)
  261. #endif
  262. #if __riscv
  263. // from arch/riscv/include/uapi/asm/hwcap.h
  264. #define COMPAT_HWCAP_ISA_F (1 << ('F' - 'A'))
  265. #define COMPAT_HWCAP_ISA_V (1 << ('V' - 'A'))
  266. #endif
  267. #if defined __ANDROID__
  268. // Probe the system's C library for a 'getauxval' function and call it if
  269. // it exits, or return 0 for failure. This function is available since API
  270. // level 18.
  271. //
  272. // Note that getauxval() can't really be re-implemented here, because
  273. // its implementation does not parse /proc/self/auxv. Instead it depends
  274. // on values that are passed by the kernel at process-init time to the
  275. // C runtime initialization layer.
  276. static unsigned int get_elf_hwcap_from_getauxval(unsigned int type)
  277. {
  278. #if __ANDROID_API__ >= 18
  279. unsigned int hwcap = getauxval(type);
  280. if (hwcap)
  281. return hwcap;
  282. #endif
  283. typedef unsigned long getauxval_func_t(unsigned long);
  284. dlerror();
  285. void* libc_handle = dlopen("libc.so", RTLD_NOW);
  286. if (!libc_handle)
  287. {
  288. NCNN_LOGE("dlopen libc.so failed %s", dlerror());
  289. return 0;
  290. }
  291. unsigned int result = 0;
  292. getauxval_func_t* func = (getauxval_func_t*)dlsym(libc_handle, "getauxval");
  293. if (!func)
  294. {
  295. NCNN_LOGE("dlsym getauxval failed");
  296. }
  297. else
  298. {
  299. // Note: getauxval() returns 0 on failure. Doesn't touch errno.
  300. result = (unsigned int)(*func)(type);
  301. }
  302. dlclose(libc_handle);
  303. return result;
  304. }
  305. #endif // defined __ANDROID__
  306. // extract the ELF HW capabilities bitmap from /proc/self/auxv
  307. static unsigned int get_elf_hwcap_from_proc_self_auxv(unsigned int type)
  308. {
  309. FILE* fp = fopen("/proc/self/auxv", "rb");
  310. if (!fp)
  311. {
  312. NCNN_LOGE("fopen /proc/self/auxv failed");
  313. return 0;
  314. }
  315. #if __aarch64__ || __mips64 || __riscv_xlen == 64 || __loongarch64
  316. struct
  317. {
  318. uint64_t tag;
  319. uint64_t value;
  320. } entry;
  321. #else
  322. struct
  323. {
  324. unsigned int tag;
  325. unsigned int value;
  326. } entry;
  327. #endif
  328. unsigned int result = 0;
  329. while (!feof(fp))
  330. {
  331. int nread = fread((char*)&entry, sizeof(entry), 1, fp);
  332. if (nread != 1)
  333. break;
  334. if (entry.tag == 0 && entry.value == 0)
  335. break;
  336. if (entry.tag == type)
  337. {
  338. result = entry.value;
  339. break;
  340. }
  341. }
  342. fclose(fp);
  343. return result;
  344. }
  345. static unsigned int get_elf_hwcap(unsigned int type)
  346. {
  347. unsigned int hwcap = 0;
  348. #if defined __ANDROID__
  349. hwcap = get_elf_hwcap_from_getauxval(type);
  350. #endif
  351. if (!hwcap)
  352. hwcap = get_elf_hwcap_from_proc_self_auxv(type);
  353. #if defined __ANDROID__
  354. #if __aarch64__
  355. if (type == AT_HWCAP)
  356. {
  357. // samsung exynos9810 on android pre-9 incorrectly reports armv8.2
  358. // for little cores, but big cores only support armv8.0
  359. // drop all armv8.2 features used by ncnn for preventing SIGILLs
  360. // ref https://reviews.llvm.org/D114523
  361. char arch[PROP_VALUE_MAX];
  362. int len = __system_property_get("ro.arch", arch);
  363. if (len > 0 && strncmp(arch, "exynos9810", 10) == 0)
  364. {
  365. hwcap &= ~HWCAP_ASIMDHP;
  366. hwcap &= ~HWCAP_ASIMDDP;
  367. }
  368. }
  369. #endif // __aarch64__
  370. #endif // defined __ANDROID__
  371. return hwcap;
  372. }
  373. #endif // defined __ANDROID__ || defined __linux__
  374. #if __APPLE__
  375. static unsigned int get_hw_cpufamily()
  376. {
  377. unsigned int value = 0;
  378. size_t len = sizeof(value);
  379. sysctlbyname("hw.cpufamily", &value, &len, NULL, 0);
  380. return value;
  381. }
  382. static cpu_type_t get_hw_cputype()
  383. {
  384. cpu_type_t value = 0;
  385. size_t len = sizeof(value);
  386. sysctlbyname("hw.cputype", &value, &len, NULL, 0);
  387. return value;
  388. }
  389. static cpu_subtype_t get_hw_cpusubtype()
  390. {
  391. cpu_subtype_t value = 0;
  392. size_t len = sizeof(value);
  393. sysctlbyname("hw.cpusubtype", &value, &len, NULL, 0);
  394. return value;
  395. }
  396. static int get_hw_capability(const char* cap)
  397. {
  398. int64_t value = 0;
  399. size_t len = sizeof(value);
  400. sysctlbyname(cap, &value, &len, NULL, 0);
  401. return value;
  402. }
  403. #endif // __APPLE__
  404. #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  405. static inline void x86_cpuid(int level, unsigned int out[4])
  406. {
  407. #if defined(_MSC_VER) && !defined(__clang__)
  408. __cpuid((int*)out, level);
  409. #elif defined(__clang__) || defined(__GNUC__)
  410. __get_cpuid(level, out, out + 1, out + 2, out + 3);
  411. #else
  412. NCNN_LOGE("x86_cpuid is unknown for current compiler");
  413. out[0] = 0;
  414. out[1] = 0;
  415. out[2] = 0;
  416. out[3] = 0;
  417. #endif
  418. }
  419. static inline void x86_cpuid_sublevel(int level, int sublevel, unsigned int out[4])
  420. {
  421. #if defined(_MSC_VER)
  422. __cpuidex((int*)out, level, sublevel);
  423. #elif defined(__clang__) || defined(__GNUC__)
  424. __cpuid_count(level, sublevel, out[0], out[1], out[2], out[3]);
  425. #else
  426. NCNN_LOGE("x86_cpuid_sublevel is unknown for current compiler");
  427. out[0] = 0;
  428. out[1] = 0;
  429. out[2] = 0;
  430. out[3] = 0;
  431. #endif
  432. }
  433. static inline int x86_get_xcr0()
  434. {
  435. #if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 160040219)
  436. return _xgetbv(0);
  437. #elif defined(__i386__) || defined(__x86_64__)
  438. int xcr0 = 0;
  439. asm(".byte 0x0f, 0x01, 0xd0"
  440. : "=a"(xcr0)
  441. : "c"(0)
  442. : "%edx");
  443. return xcr0;
  444. #else
  445. NCNN_LOGE("x86_get_xcr0 is unknown for current compiler");
  446. return 0xffffffff; // assume it will work
  447. #endif
  448. }
  449. static int get_cpu_support_x86_avx()
  450. {
  451. unsigned int cpu_info[4] = {0};
  452. x86_cpuid(0, cpu_info);
  453. int nIds = cpu_info[0];
  454. if (nIds < 1)
  455. return 0;
  456. x86_cpuid(1, cpu_info);
  457. // check AVX XSAVE OSXSAVE
  458. if (!(cpu_info[2] & (1u << 28)) || !(cpu_info[2] & (1u << 26)) || !(cpu_info[2] & (1u << 27)))
  459. return 0;
  460. // check XSAVE enabled by kernel
  461. if ((x86_get_xcr0() & 6) != 6)
  462. return 0;
  463. return 1;
  464. }
  465. static int get_cpu_support_x86_fma()
  466. {
  467. unsigned int cpu_info[4] = {0};
  468. x86_cpuid(0, cpu_info);
  469. int nIds = cpu_info[0];
  470. if (nIds < 7)
  471. return 0;
  472. x86_cpuid(1, cpu_info);
  473. // check AVX XSAVE OSXSAVE
  474. if (!(cpu_info[2] & (1u << 28)) || !(cpu_info[2] & (1u << 26)) || !(cpu_info[2] & (1u << 27)))
  475. return 0;
  476. // check XSAVE enabled by kernel
  477. if ((x86_get_xcr0() & 6) != 6)
  478. return 0;
  479. return cpu_info[2] & (1u << 12);
  480. }
  481. static int get_cpu_support_x86_xop()
  482. {
  483. unsigned int cpu_info[4] = {0};
  484. x86_cpuid(0x80000000, cpu_info);
  485. if (cpu_info[0] < 0x80000001)
  486. return 0;
  487. x86_cpuid(0x80000001, cpu_info);
  488. return cpu_info[2] & (1u << 11);
  489. }
  490. static int get_cpu_support_x86_f16c()
  491. {
  492. unsigned int cpu_info[4] = {0};
  493. x86_cpuid(0, cpu_info);
  494. int nIds = cpu_info[0];
  495. if (nIds < 1)
  496. return 0;
  497. x86_cpuid(1, cpu_info);
  498. return cpu_info[2] & (1u << 29);
  499. }
  500. static int get_cpu_support_x86_avx2()
  501. {
  502. unsigned int cpu_info[4] = {0};
  503. x86_cpuid(0, cpu_info);
  504. int nIds = cpu_info[0];
  505. if (nIds < 7)
  506. return 0;
  507. x86_cpuid(1, cpu_info);
  508. // check AVX XSAVE OSXSAVE
  509. if (!(cpu_info[2] & (1u << 28)) || !(cpu_info[2] & (1u << 26)) || !(cpu_info[2] & (1u << 27)))
  510. return 0;
  511. // check XSAVE enabled by kernel
  512. if ((x86_get_xcr0() & 6) != 6)
  513. return 0;
  514. x86_cpuid_sublevel(7, 0, cpu_info);
  515. return cpu_info[1] & (1u << 5);
  516. }
  517. static int get_cpu_support_x86_avx_vnni()
  518. {
  519. unsigned int cpu_info[4] = {0};
  520. x86_cpuid(0, cpu_info);
  521. int nIds = cpu_info[0];
  522. if (nIds < 7)
  523. return 0;
  524. x86_cpuid(1, cpu_info);
  525. // check AVX XSAVE OSXSAVE
  526. if (!(cpu_info[2] & (1u << 28)) || !(cpu_info[2] & (1u << 26)) || !(cpu_info[2] & (1u << 27)))
  527. return 0;
  528. // check XSAVE enabled by kernel
  529. if ((x86_get_xcr0() & 6) != 6)
  530. return 0;
  531. x86_cpuid_sublevel(7, 1, cpu_info);
  532. return cpu_info[0] & (1u << 4);
  533. }
  534. static int get_cpu_support_x86_avx512()
  535. {
  536. #if __APPLE__
  537. return get_hw_capability("hw.optional.avx512f")
  538. && get_hw_capability("hw.optional.avx512bw")
  539. && get_hw_capability("hw.optional.avx512cd")
  540. && get_hw_capability("hw.optional.avx512dq")
  541. && get_hw_capability("hw.optional.avx512vl");
  542. #else
  543. unsigned int cpu_info[4] = {0};
  544. x86_cpuid(0, cpu_info);
  545. int nIds = cpu_info[0];
  546. if (nIds < 7)
  547. return 0;
  548. x86_cpuid(1, cpu_info);
  549. // check AVX XSAVE OSXSAVE
  550. if (!(cpu_info[2] & (1u << 28)) || !(cpu_info[2] & (1u << 26)) || !(cpu_info[2] & (1u << 27)))
  551. return 0;
  552. // check XSAVE enabled by kernel
  553. if ((x86_get_xcr0() & 6) != 6)
  554. return 0;
  555. // check avx512 XSAVE enabled by kernel
  556. if ((x86_get_xcr0() & 0xe0) != 0xe0)
  557. return 0;
  558. x86_cpuid_sublevel(7, 0, cpu_info);
  559. return (cpu_info[1] & (1u << 16)) && (cpu_info[1] & (1u << 17)) && (cpu_info[1] & (1u << 28)) && (cpu_info[1] & (1u << 30)) && (cpu_info[1] & (1u << 31));
  560. #endif
  561. }
  562. static int get_cpu_support_x86_avx512_vnni()
  563. {
  564. #if __APPLE__
  565. return get_hw_capability("hw.optional.avx512vnni");
  566. #else
  567. unsigned int cpu_info[4] = {0};
  568. x86_cpuid(0, cpu_info);
  569. int nIds = cpu_info[0];
  570. if (nIds < 7)
  571. return 0;
  572. x86_cpuid(1, cpu_info);
  573. // check AVX XSAVE OSXSAVE
  574. if (!(cpu_info[2] & (1u << 28)) || !(cpu_info[2] & (1u << 26)) || !(cpu_info[2] & (1u << 27)))
  575. return 0;
  576. // check XSAVE enabled by kernel
  577. if ((x86_get_xcr0() & 6) != 6)
  578. return 0;
  579. // check avx512 XSAVE enabled by kernel
  580. if ((x86_get_xcr0() & 0xe0) != 0xe0)
  581. return 0;
  582. x86_cpuid_sublevel(7, 0, cpu_info);
  583. return cpu_info[2] & (1u << 11);
  584. #endif
  585. }
  586. static int get_cpu_support_x86_avx512_bf16()
  587. {
  588. #if __APPLE__
  589. return get_hw_capability("hw.optional.avx512bf16");
  590. #else
  591. unsigned int cpu_info[4] = {0};
  592. x86_cpuid(0, cpu_info);
  593. int nIds = cpu_info[0];
  594. if (nIds < 7)
  595. return 0;
  596. x86_cpuid(1, cpu_info);
  597. // check AVX XSAVE OSXSAVE
  598. if (!(cpu_info[2] & (1u << 28)) || !(cpu_info[2] & (1u << 26)) || !(cpu_info[2] & (1u << 27)))
  599. return 0;
  600. // check XSAVE enabled by kernel
  601. if ((x86_get_xcr0() & 6) != 6)
  602. return 0;
  603. x86_cpuid_sublevel(7, 1, cpu_info);
  604. return cpu_info[0] & (1u << 5);
  605. #endif
  606. }
  607. static int get_cpu_support_x86_avx512_fp16()
  608. {
  609. #if __APPLE__
  610. return get_hw_capability("hw.optional.avx512fp16");
  611. #else
  612. unsigned int cpu_info[4] = {0};
  613. x86_cpuid(0, cpu_info);
  614. int nIds = cpu_info[0];
  615. if (nIds < 7)
  616. return 0;
  617. x86_cpuid(1, cpu_info);
  618. // check AVX XSAVE OSXSAVE
  619. if (!(cpu_info[2] & (1u << 28)) || !(cpu_info[2] & (1u << 26)) || !(cpu_info[2] & (1u << 27)))
  620. return 0;
  621. // check XSAVE enabled by kernel
  622. if ((x86_get_xcr0() & 6) != 6)
  623. return 0;
  624. // check avx512 XSAVE enabled by kernel
  625. if ((x86_get_xcr0() & 0xe0) != 0xe0)
  626. return 0;
  627. x86_cpuid_sublevel(7, 0, cpu_info);
  628. return cpu_info[3] & (1u << 23);
  629. #endif
  630. }
  631. #endif // defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  632. static int get_cpucount()
  633. {
  634. int count = 0;
  635. #ifdef __EMSCRIPTEN__
  636. if (emscripten_has_threading_support())
  637. count = emscripten_num_logical_cores();
  638. else
  639. count = 1;
  640. #elif defined _WIN32
  641. SYSTEM_INFO system_info;
  642. GetSystemInfo(&system_info);
  643. count = system_info.dwNumberOfProcessors;
  644. #elif defined __ANDROID__ || defined __linux__
  645. // get cpu count from /proc/cpuinfo
  646. FILE* fp = fopen("/proc/cpuinfo", "rb");
  647. if (!fp)
  648. return 1;
  649. char line[1024];
  650. while (!feof(fp))
  651. {
  652. char* s = fgets(line, 1024, fp);
  653. if (!s)
  654. break;
  655. if (memcmp(line, "processor", 9) == 0)
  656. {
  657. count++;
  658. }
  659. }
  660. fclose(fp);
  661. #elif __APPLE__
  662. size_t len = sizeof(count);
  663. sysctlbyname("hw.ncpu", &count, &len, NULL, 0);
  664. #else
  665. #ifdef _OPENMP
  666. count = omp_get_max_threads();
  667. #else
  668. count = 1;
  669. #endif // _OPENMP
  670. #endif
  671. if (count < 1)
  672. count = 1;
  673. return count;
  674. }
  675. #if defined __ANDROID__ || defined __linux__
  676. static int get_thread_siblings(int cpuid)
  677. {
  678. char path[256];
  679. sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings", cpuid);
  680. FILE* fp = fopen(path, "rb");
  681. if (!fp)
  682. return -1;
  683. int thread_siblings = -1;
  684. int nscan = fscanf(fp, "%x", &thread_siblings);
  685. if (nscan != 1)
  686. {
  687. // ignore
  688. }
  689. fclose(fp);
  690. return thread_siblings;
  691. }
  692. #endif // defined __ANDROID__ || defined __linux__
  693. static int get_physical_cpucount()
  694. {
  695. int count = 0;
  696. #if defined _WIN32
  697. typedef BOOL(WINAPI * LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
  698. LPFN_GLPI glpi = (LPFN_GLPI)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation");
  699. if (glpi == NULL)
  700. {
  701. NCNN_LOGE("GetLogicalProcessorInformation is not supported");
  702. return g_cpucount;
  703. }
  704. DWORD return_length = 0;
  705. glpi(NULL, &return_length);
  706. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(return_length);
  707. glpi(buffer, &return_length);
  708. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = buffer;
  709. DWORD byte_offset = 0;
  710. while (byte_offset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= return_length)
  711. {
  712. if (ptr->Relationship == RelationProcessorCore)
  713. {
  714. count++;
  715. }
  716. byte_offset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
  717. ptr++;
  718. }
  719. free(buffer);
  720. #elif defined __ANDROID__ || defined __linux__
  721. std::vector<int> thread_set;
  722. for (int i = 0; i < g_cpucount; i++)
  723. {
  724. int thread_siblings = get_thread_siblings(i);
  725. if (thread_siblings == -1)
  726. {
  727. // ignore malformed one
  728. continue;
  729. }
  730. bool thread_siblings_exists = false;
  731. for (size_t j = 0; j < thread_set.size(); j++)
  732. {
  733. if (thread_set[j] == thread_siblings)
  734. {
  735. thread_siblings_exists = true;
  736. break;
  737. }
  738. }
  739. if (!thread_siblings_exists)
  740. {
  741. thread_set.push_back(thread_siblings);
  742. count++;
  743. }
  744. }
  745. #elif __APPLE__
  746. size_t len = sizeof(count);
  747. sysctlbyname("hw.physicalcpu_max", &count, &len, NULL, 0);
  748. #else
  749. count = g_cpucount;
  750. #endif
  751. if (count > g_cpucount)
  752. count = g_cpucount;
  753. return count;
  754. }
  755. #if defined __ANDROID__ || defined __linux__
  756. static int get_data_cache_size(int cpuid, int level)
  757. {
  758. char path[256];
  759. // discover sysfs cache entry
  760. int indexid = -1;
  761. for (int i = 0;; i++)
  762. {
  763. // check level
  764. {
  765. sprintf(path, "/sys/devices/system/cpu/cpu%d/cache/index%d/level", cpuid, i);
  766. FILE* fp = fopen(path, "rb");
  767. if (!fp)
  768. break;
  769. int cache_level = -1;
  770. int nscan = fscanf(fp, "%d", &cache_level);
  771. fclose(fp);
  772. if (nscan != 1 || cache_level != level)
  773. continue;
  774. }
  775. // check type
  776. {
  777. sprintf(path, "/sys/devices/system/cpu/cpu%d/cache/index%d/type", cpuid, i);
  778. FILE* fp = fopen(path, "rb");
  779. if (!fp)
  780. break;
  781. char type[32];
  782. int nscan = fscanf(fp, "%31s", type);
  783. fclose(fp);
  784. if (nscan != 1 || (strcmp(type, "Data") != 0 && strcmp(type, "Unified") != 0))
  785. continue;
  786. }
  787. indexid = i;
  788. break;
  789. }
  790. if (indexid == -1)
  791. {
  792. // no sysfs entry
  793. return 0;
  794. }
  795. // get size
  796. int cache_size_K = 0;
  797. {
  798. sprintf(path, "/sys/devices/system/cpu/cpu%d/cache/index%d/size", cpuid, indexid);
  799. FILE* fp = fopen(path, "rb");
  800. if (!fp)
  801. return 0;
  802. int nscan = fscanf(fp, "%dK", &cache_size_K);
  803. fclose(fp);
  804. if (nscan != 1)
  805. {
  806. NCNN_LOGE("fscanf cache_size_K error %d", nscan);
  807. return 0;
  808. }
  809. }
  810. // parse shared_cpu_map mask
  811. ncnn::CpuSet shared_cpu_map;
  812. {
  813. sprintf(path, "/sys/devices/system/cpu/cpu%d/cache/index%d/shared_cpu_map", cpuid, indexid);
  814. FILE* fp = fopen(path, "rb");
  815. if (!fp)
  816. return 0;
  817. char shared_cpu_map_str[256];
  818. int nscan = fscanf(fp, "%255s", shared_cpu_map_str);
  819. fclose(fp);
  820. if (nscan != 1)
  821. {
  822. NCNN_LOGE("fscanf shared_cpu_map error %d", nscan);
  823. return 0;
  824. }
  825. int len = strlen(shared_cpu_map_str);
  826. if (shared_cpu_map_str[0] == '0' && shared_cpu_map_str[1] == 'x')
  827. {
  828. // skip leading 0x
  829. len -= 2;
  830. }
  831. int ci = 0;
  832. for (int i = len - 1; i >= 0; i--)
  833. {
  834. char x = shared_cpu_map_str[i];
  835. if (x & 1) shared_cpu_map.enable(ci + 0);
  836. if (x & 2) shared_cpu_map.enable(ci + 1);
  837. if (x & 4) shared_cpu_map.enable(ci + 2);
  838. if (x & 8) shared_cpu_map.enable(ci + 3);
  839. ci += 4;
  840. }
  841. }
  842. if (shared_cpu_map.num_enabled() == 1)
  843. return cache_size_K * 1024;
  844. // resolve physical cpu count in the shared_cpu_map
  845. int shared_physical_cpu_count = 0;
  846. {
  847. std::vector<int> thread_set;
  848. for (int i = 0; i < g_cpucount; i++)
  849. {
  850. if (!shared_cpu_map.is_enabled(i))
  851. continue;
  852. int thread_siblings = get_thread_siblings(i);
  853. if (thread_siblings == -1)
  854. {
  855. // ignore malformed one
  856. continue;
  857. }
  858. bool thread_siblings_exists = false;
  859. for (size_t j = 0; j < thread_set.size(); j++)
  860. {
  861. if (thread_set[j] == thread_siblings)
  862. {
  863. thread_siblings_exists = true;
  864. break;
  865. }
  866. }
  867. if (!thread_siblings_exists)
  868. {
  869. thread_set.push_back(thread_siblings);
  870. shared_physical_cpu_count++;
  871. }
  872. }
  873. }
  874. // return per-physical-core cache size with 4K aligned
  875. cache_size_K = (cache_size_K / shared_physical_cpu_count + 3) / 4 * 4;
  876. return cache_size_K * 1024;
  877. }
  878. static int get_big_cpu_data_cache_size(int level)
  879. {
  880. if (g_cpu_affinity_mask_big.num_enabled() == 0)
  881. {
  882. // smp cpu
  883. return get_data_cache_size(0, level);
  884. }
  885. for (int i = 0; i < g_cpucount; i++)
  886. {
  887. if (g_cpu_affinity_mask_big.is_enabled(i))
  888. {
  889. return get_data_cache_size(i, level);
  890. }
  891. }
  892. // should never reach here, fallback to cpu0
  893. return get_data_cache_size(0, level);
  894. }
  895. #endif // defined __ANDROID__ || defined __linux__
  896. static int get_cpu_level2_cachesize()
  897. {
  898. int size = 0;
  899. #if defined _WIN32
  900. typedef BOOL(WINAPI * LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
  901. LPFN_GLPI glpi = (LPFN_GLPI)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation");
  902. if (glpi != NULL)
  903. {
  904. DWORD return_length = 0;
  905. glpi(NULL, &return_length);
  906. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(return_length);
  907. glpi(buffer, &return_length);
  908. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = buffer;
  909. DWORD byte_offset = 0;
  910. while (byte_offset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= return_length)
  911. {
  912. if (ptr->Relationship == RelationCache)
  913. {
  914. PCACHE_DESCRIPTOR Cache = &ptr->Cache;
  915. if (Cache->Level == 2)
  916. {
  917. size = std::max(size, (int)Cache->Size);
  918. }
  919. }
  920. byte_offset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
  921. ptr++;
  922. }
  923. free(buffer);
  924. }
  925. #elif defined __ANDROID__ || defined __linux__
  926. size = get_big_cpu_data_cache_size(2);
  927. #if defined(_SC_LEVEL2_CACHE_SIZE)
  928. if (size <= 0)
  929. size = sysconf(_SC_LEVEL2_CACHE_SIZE);
  930. #endif
  931. #elif __APPLE__
  932. // perflevel 0 is the higher performance cluster
  933. int cpusperl2 = get_hw_capability("hw.perflevel0.cpusperl2");
  934. int l2cachesize = get_hw_capability("hw.perflevel0.l2cachesize");
  935. size = cpusperl2 > 1 ? l2cachesize / cpusperl2 : l2cachesize;
  936. #endif
  937. // fallback to a common value
  938. if (size <= 0)
  939. {
  940. #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  941. size = 64 * 1024;
  942. if (g_cpu_support_x86_avx)
  943. size = 128 * 1024;
  944. if (g_cpu_support_x86_avx2)
  945. size = 256 * 1024;
  946. if (g_cpu_support_x86_avx512)
  947. size = 1024 * 1024;
  948. #elif __aarch64__
  949. size = 256 * 1024;
  950. #elif __arm__
  951. size = 128 * 1024;
  952. #else
  953. // is 64k still too large here ?
  954. size = 64 * 1024;
  955. #endif
  956. }
  957. return size;
  958. }
  959. static int get_cpu_level3_cachesize()
  960. {
  961. int size = 0;
  962. #if defined _WIN32
  963. typedef BOOL(WINAPI * LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
  964. LPFN_GLPI glpi = (LPFN_GLPI)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation");
  965. if (glpi != NULL)
  966. {
  967. DWORD return_length = 0;
  968. glpi(NULL, &return_length);
  969. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(return_length);
  970. glpi(buffer, &return_length);
  971. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = buffer;
  972. DWORD byte_offset = 0;
  973. while (byte_offset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= return_length)
  974. {
  975. if (ptr->Relationship == RelationCache)
  976. {
  977. PCACHE_DESCRIPTOR Cache = &ptr->Cache;
  978. if (Cache->Level == 3)
  979. {
  980. size = std::max(size, (int)Cache->Size);
  981. }
  982. }
  983. byte_offset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
  984. ptr++;
  985. }
  986. free(buffer);
  987. }
  988. #elif defined __ANDROID__ || defined __linux__
  989. size = get_big_cpu_data_cache_size(3);
  990. #if defined(_SC_LEVEL3_CACHE_SIZE)
  991. if (size <= 0)
  992. size = sysconf(_SC_LEVEL3_CACHE_SIZE);
  993. #endif
  994. #elif __APPLE__
  995. // perflevel 0 is the higher performance cluster
  996. // get the size shared among all cpus
  997. size = get_hw_capability("hw.perflevel0.l3cachesize");
  998. #endif
  999. // l3 cache size can be zero
  1000. return size;
  1001. }
  1002. #if defined _WIN32
  1003. static ncnn::CpuSet get_smt_cpu_mask()
  1004. {
  1005. ncnn::CpuSet smt_cpu_mask;
  1006. typedef BOOL(WINAPI * LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
  1007. LPFN_GLPI glpi = (LPFN_GLPI)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation");
  1008. if (glpi == NULL)
  1009. {
  1010. NCNN_LOGE("GetLogicalProcessorInformation is not supported");
  1011. return smt_cpu_mask;
  1012. }
  1013. DWORD return_length = 0;
  1014. glpi(NULL, &return_length);
  1015. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(return_length);
  1016. glpi(buffer, &return_length);
  1017. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = buffer;
  1018. DWORD byte_offset = 0;
  1019. while (byte_offset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= return_length)
  1020. {
  1021. if (ptr->Relationship == RelationProcessorCore)
  1022. {
  1023. ncnn::CpuSet smt_set;
  1024. smt_set.mask = ptr->ProcessorMask;
  1025. if (smt_set.num_enabled() > 1)
  1026. {
  1027. // this core is smt
  1028. smt_cpu_mask.mask |= smt_set.mask;
  1029. }
  1030. }
  1031. byte_offset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
  1032. ptr++;
  1033. }
  1034. free(buffer);
  1035. return smt_cpu_mask;
  1036. }
  1037. static std::vector<int> get_max_freq_mhz()
  1038. {
  1039. typedef struct _PROCESSOR_POWER_INFORMATION
  1040. {
  1041. ULONG Number;
  1042. ULONG MaxMhz;
  1043. ULONG CurrentMhz;
  1044. ULONG MhzLimit;
  1045. ULONG MaxIdleState;
  1046. ULONG CurrentIdleState;
  1047. } PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
  1048. HMODULE powrprof = LoadLibrary(TEXT("powrprof.dll"));
  1049. typedef LONG(WINAPI * LPFN_CNPI)(POWER_INFORMATION_LEVEL, PVOID, ULONG, PVOID, ULONG);
  1050. LPFN_CNPI cnpi = (LPFN_CNPI)GetProcAddress(powrprof, "CallNtPowerInformation");
  1051. if (cnpi == NULL)
  1052. {
  1053. NCNN_LOGE("CallNtPowerInformation is not supported");
  1054. FreeLibrary(powrprof);
  1055. return std::vector<int>(g_cpucount, 0);
  1056. }
  1057. DWORD return_length = sizeof(PROCESSOR_POWER_INFORMATION) * g_cpucount;
  1058. PPROCESSOR_POWER_INFORMATION buffer = (PPROCESSOR_POWER_INFORMATION)malloc(return_length);
  1059. cnpi(ProcessorInformation, NULL, 0, buffer, return_length);
  1060. std::vector<int> ret;
  1061. for (int i = 0; i < g_cpucount; i++)
  1062. {
  1063. ULONG max_mhz = buffer[i].MaxMhz;
  1064. ret.push_back(max_mhz);
  1065. }
  1066. free(buffer);
  1067. FreeLibrary(powrprof);
  1068. return ret;
  1069. }
  1070. static int set_sched_affinity(const ncnn::CpuSet& thread_affinity_mask)
  1071. {
  1072. DWORD_PTR prev_mask = SetThreadAffinityMask(GetCurrentThread(), thread_affinity_mask.mask);
  1073. if (prev_mask == 0)
  1074. {
  1075. NCNN_LOGE("SetThreadAffinityMask failed %d", GetLastError());
  1076. return -1;
  1077. }
  1078. return 0;
  1079. }
  1080. #endif // defined _WIN32
  1081. #if defined __ANDROID__ || defined __linux__
  1082. static int get_max_freq_khz(int cpuid)
  1083. {
  1084. // first try, for all possible cpu
  1085. char path[256];
  1086. sprintf(path, "/sys/devices/system/cpu/cpufreq/stats/cpu%d/time_in_state", cpuid);
  1087. FILE* fp = fopen(path, "rb");
  1088. if (!fp)
  1089. {
  1090. // second try, for online cpu
  1091. sprintf(path, "/sys/devices/system/cpu/cpu%d/cpufreq/stats/time_in_state", cpuid);
  1092. fp = fopen(path, "rb");
  1093. if (fp)
  1094. {
  1095. int max_freq_khz = 0;
  1096. while (!feof(fp))
  1097. {
  1098. int freq_khz = 0;
  1099. int nscan = fscanf(fp, "%d %*d", &freq_khz);
  1100. if (nscan != 1)
  1101. break;
  1102. if (freq_khz > max_freq_khz)
  1103. max_freq_khz = freq_khz;
  1104. }
  1105. fclose(fp);
  1106. if (max_freq_khz != 0)
  1107. return max_freq_khz;
  1108. fp = NULL;
  1109. }
  1110. if (!fp)
  1111. {
  1112. // third try, for online cpu
  1113. sprintf(path, "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", cpuid);
  1114. fp = fopen(path, "rb");
  1115. if (!fp)
  1116. return -1;
  1117. int max_freq_khz = -1;
  1118. int nscan = fscanf(fp, "%d", &max_freq_khz);
  1119. if (nscan != 1)
  1120. {
  1121. NCNN_LOGE("fscanf cpuinfo_max_freq error %d", nscan);
  1122. }
  1123. fclose(fp);
  1124. return max_freq_khz;
  1125. }
  1126. }
  1127. int max_freq_khz = 0;
  1128. while (!feof(fp))
  1129. {
  1130. int freq_khz = 0;
  1131. int nscan = fscanf(fp, "%d %*d", &freq_khz);
  1132. if (nscan != 1)
  1133. break;
  1134. if (freq_khz > max_freq_khz)
  1135. max_freq_khz = freq_khz;
  1136. }
  1137. fclose(fp);
  1138. return max_freq_khz;
  1139. }
  1140. static bool is_smt_cpu(int cpuid)
  1141. {
  1142. // https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/stable/sysfs-devices-system-cpu#L68-72
  1143. char path[256];
  1144. sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/core_cpus_list", cpuid);
  1145. FILE* fp = fopen(path, "rb");
  1146. if (!fp)
  1147. {
  1148. sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpuid);
  1149. fp = fopen(path, "rb");
  1150. if (!fp)
  1151. return false;
  1152. }
  1153. bool is_smt = false;
  1154. while (!feof(fp))
  1155. {
  1156. char ch = fgetc(fp);
  1157. if (ch == ',' || ch == '-')
  1158. {
  1159. is_smt = true;
  1160. break;
  1161. }
  1162. }
  1163. fclose(fp);
  1164. return is_smt;
  1165. }
  1166. static int set_sched_affinity(const ncnn::CpuSet& thread_affinity_mask)
  1167. {
  1168. // set affinity for thread
  1169. #if defined(__BIONIC__) && !defined(__OHOS__)
  1170. pid_t pid = gettid();
  1171. #else
  1172. pid_t pid = syscall(SYS_gettid);
  1173. #endif
  1174. int syscallret = syscall(__NR_sched_setaffinity, pid, sizeof(cpu_set_t), &thread_affinity_mask.cpu_set);
  1175. if (syscallret)
  1176. {
  1177. NCNN_LOGE("syscall error %d", syscallret);
  1178. return -1;
  1179. }
  1180. return 0;
  1181. }
  1182. #endif // defined __ANDROID__ || defined __linux__
  1183. #if __APPLE__
  1184. static int set_sched_affinity(const ncnn::CpuSet& thread_affinity_mask)
  1185. {
  1186. // https://developer.apple.com/library/archive/releasenotes/Performance/RN-AffinityAPI/index.html
  1187. // http://www.hybridkernel.com/2015/01/18/binding_threads_to_cores_osx.html
  1188. // https://gist.github.com/Coneko/4234842
  1189. // This is a quite outdated document. Apple will not allow developers to set CPU affinity.
  1190. // In OS X 10.5 it worked, later it became a suggestion to OS X, then in 10.10 or so (as well in later ones), macOS will ignore any affinity settings.
  1191. // see https://github.com/Tencent/ncnn/pull/2335#discussion_r528233919 --- AmeAkio
  1192. int affinity_tag = THREAD_AFFINITY_TAG_NULL;
  1193. for (int i = 0; i < (int)sizeof(thread_affinity_mask.policy) * 8; i++)
  1194. {
  1195. if (thread_affinity_mask.is_enabled(i))
  1196. {
  1197. affinity_tag = i + 1;
  1198. break;
  1199. }
  1200. }
  1201. mach_port_t tid = pthread_mach_thread_np(pthread_self());
  1202. thread_affinity_policy_data_t policy_data;
  1203. policy_data.affinity_tag = affinity_tag;
  1204. int ret = thread_policy_set(tid, THREAD_AFFINITY_POLICY, (thread_policy_t)&policy_data, THREAD_AFFINITY_POLICY_COUNT);
  1205. if (ret && ret != KERN_NOT_SUPPORTED)
  1206. {
  1207. NCNN_LOGE("thread_policy_set error %d", ret);
  1208. return -1;
  1209. }
  1210. return 0;
  1211. }
  1212. #endif // __APPLE__
  1213. static void initialize_cpu_thread_affinity_mask(ncnn::CpuSet& mask_all, ncnn::CpuSet& mask_little, ncnn::CpuSet& mask_big)
  1214. {
  1215. mask_all.disable_all();
  1216. for (int i = 0; i < g_cpucount; i++)
  1217. {
  1218. mask_all.enable(i);
  1219. }
  1220. #if defined _WIN32
  1221. // get max freq mhz for all cores
  1222. int max_freq_mhz_min = INT_MAX;
  1223. int max_freq_mhz_max = 0;
  1224. std::vector<int> cpu_max_freq_mhz = get_max_freq_mhz();
  1225. for (int i = 0; i < g_cpucount; i++)
  1226. {
  1227. int max_freq_mhz = cpu_max_freq_mhz[i];
  1228. // NCNN_LOGE("%d max freq = %d khz", i, max_freq_mhz);
  1229. if (max_freq_mhz > max_freq_mhz_max)
  1230. max_freq_mhz_max = max_freq_mhz;
  1231. if (max_freq_mhz < max_freq_mhz_min)
  1232. max_freq_mhz_min = max_freq_mhz;
  1233. }
  1234. int max_freq_mhz_medium = (max_freq_mhz_min + max_freq_mhz_max) / 2;
  1235. if (max_freq_mhz_medium == max_freq_mhz_max)
  1236. {
  1237. mask_little.disable_all();
  1238. mask_big = mask_all;
  1239. return;
  1240. }
  1241. ncnn::CpuSet smt_cpu_mask = get_smt_cpu_mask();
  1242. for (int i = 0; i < g_cpucount; i++)
  1243. {
  1244. if (smt_cpu_mask.is_enabled(i))
  1245. {
  1246. // always treat smt core as big core
  1247. mask_big.enable(i);
  1248. continue;
  1249. }
  1250. if (cpu_max_freq_mhz[i] < max_freq_mhz_medium)
  1251. mask_little.enable(i);
  1252. else
  1253. mask_big.enable(i);
  1254. }
  1255. #elif defined __ANDROID__ || defined __linux__
  1256. int max_freq_khz_min = INT_MAX;
  1257. int max_freq_khz_max = 0;
  1258. std::vector<int> cpu_max_freq_khz(g_cpucount);
  1259. for (int i = 0; i < g_cpucount; i++)
  1260. {
  1261. int max_freq_khz = get_max_freq_khz(i);
  1262. // NCNN_LOGE("%d max freq = %d khz", i, max_freq_khz);
  1263. cpu_max_freq_khz[i] = max_freq_khz;
  1264. if (max_freq_khz > max_freq_khz_max)
  1265. max_freq_khz_max = max_freq_khz;
  1266. if (max_freq_khz < max_freq_khz_min)
  1267. max_freq_khz_min = max_freq_khz;
  1268. }
  1269. int max_freq_khz_medium = (max_freq_khz_min + max_freq_khz_max) / 2;
  1270. if (max_freq_khz_medium == max_freq_khz_max)
  1271. {
  1272. mask_little.disable_all();
  1273. mask_big = mask_all;
  1274. return;
  1275. }
  1276. for (int i = 0; i < g_cpucount; i++)
  1277. {
  1278. if (is_smt_cpu(i))
  1279. {
  1280. // always treat smt core as big core
  1281. mask_big.enable(i);
  1282. continue;
  1283. }
  1284. if (cpu_max_freq_khz[i] < max_freq_khz_medium)
  1285. mask_little.enable(i);
  1286. else
  1287. mask_big.enable(i);
  1288. }
  1289. #elif __APPLE__
  1290. int nperflevels = get_hw_capability("hw.nperflevels");
  1291. if (nperflevels == 1)
  1292. {
  1293. // smp models
  1294. mask_little.disable_all();
  1295. mask_big = mask_all;
  1296. }
  1297. else
  1298. {
  1299. // two or more clusters, level0 is the high-performance cluster
  1300. int perflevel0_logicalcpu = get_hw_capability("hw.perflevel0.logicalcpu_max");
  1301. for (int i = 0; i < perflevel0_logicalcpu; i++)
  1302. {
  1303. mask_big.enable(i);
  1304. }
  1305. for (int i = perflevel0_logicalcpu; i < g_cpucount; i++)
  1306. {
  1307. mask_little.enable(i);
  1308. }
  1309. }
  1310. #else
  1311. // TODO implement me for other platforms
  1312. mask_little.disable_all();
  1313. mask_big = mask_all;
  1314. #endif
  1315. }
  1316. #if defined __ANDROID__ || defined __linux__
  1317. #if __aarch64__
  1318. union midr_info_t
  1319. {
  1320. struct __attribute__((packed))
  1321. {
  1322. unsigned int revision : 4;
  1323. unsigned int part : 12;
  1324. unsigned int architecture : 4;
  1325. unsigned int variant : 4;
  1326. unsigned int implementer : 8;
  1327. };
  1328. unsigned int midr;
  1329. midr_info_t(unsigned int _midr)
  1330. : midr(_midr)
  1331. {
  1332. }
  1333. };
  1334. static unsigned int get_midr_from_sysfs(int cpuid)
  1335. {
  1336. char path[256];
  1337. sprintf(path, "/sys/devices/system/cpu/cpu%d/regs/identification/midr_el1", cpuid);
  1338. FILE* fp = fopen(path, "rb");
  1339. if (!fp)
  1340. return 0;
  1341. unsigned int midr_el1 = 0;
  1342. int nscan = fscanf(fp, "%x", &midr_el1);
  1343. if (nscan != 1)
  1344. {
  1345. // ignore
  1346. }
  1347. fclose(fp);
  1348. return midr_el1;
  1349. }
  1350. static int get_midr_from_proc_cpuinfo(std::vector<unsigned int>& midrs)
  1351. {
  1352. FILE* fp = fopen("/proc/cpuinfo", "rb");
  1353. if (!fp)
  1354. return -1;
  1355. midrs.resize(g_cpucount, 0);
  1356. int cpuid = -1;
  1357. midr_info_t midr_info(0);
  1358. char line[1024];
  1359. while (!feof(fp))
  1360. {
  1361. char* s = fgets(line, 1024, fp);
  1362. if (!s)
  1363. break;
  1364. if (memcmp(line, "processor", 9) == 0)
  1365. {
  1366. // processor : 4
  1367. int id = -1;
  1368. int nscan = sscanf(line, "%*[^:]: %d", &id);
  1369. if (nscan != 1)
  1370. continue;
  1371. if (cpuid >= 0 && cpuid < g_cpucount)
  1372. {
  1373. if (midr_info.midr == 0)
  1374. {
  1375. // shared midr
  1376. midrs[cpuid] = (unsigned int)-1;
  1377. }
  1378. else
  1379. {
  1380. // save midr and reset
  1381. midrs[cpuid] = midr_info.midr;
  1382. for (int i = 0; i < g_cpucount; i++)
  1383. {
  1384. if (midrs[i] == (unsigned int)-1)
  1385. midrs[i] = midr_info.midr;
  1386. }
  1387. }
  1388. midr_info.midr = 0;
  1389. }
  1390. cpuid = id;
  1391. }
  1392. if (cpuid == -1)
  1393. continue;
  1394. if (memcmp(line, "CPU implementer", 15) == 0)
  1395. {
  1396. // CPU implementer : 0x51
  1397. unsigned int id = 0;
  1398. int nscan = sscanf(line, "%*[^:]: %x", &id);
  1399. if (nscan != 1)
  1400. continue;
  1401. midr_info.implementer = id;
  1402. }
  1403. else if (memcmp(line, "CPU architecture", 16) == 0)
  1404. {
  1405. // CPU architecture: 8
  1406. int id = 0;
  1407. int nscan = sscanf(line, "%*[^:]: %d", &id);
  1408. if (nscan != 1)
  1409. continue;
  1410. midr_info.architecture = id;
  1411. }
  1412. else if (memcmp(line, "CPU variant", 11) == 0)
  1413. {
  1414. // CPU variant : 0xd
  1415. int id = 0;
  1416. int nscan = sscanf(line, "%*[^:]: %x", &id);
  1417. if (nscan != 1)
  1418. continue;
  1419. midr_info.variant = id;
  1420. }
  1421. else if (memcmp(line, "CPU part", 8) == 0)
  1422. {
  1423. // CPU part : 0x804
  1424. int id = 0;
  1425. int nscan = sscanf(line, "%*[^:]: %x", &id);
  1426. if (nscan != 1)
  1427. continue;
  1428. midr_info.part = id;
  1429. }
  1430. else if (memcmp(line, "CPU revision", 12) == 0)
  1431. {
  1432. // CPU revision : 14
  1433. int id = 0;
  1434. int nscan = sscanf(line, "%*[^:]: %d", &id);
  1435. if (nscan != 1)
  1436. continue;
  1437. midr_info.revision = id;
  1438. }
  1439. }
  1440. fclose(fp);
  1441. if (cpuid >= 0 && cpuid < g_cpucount)
  1442. {
  1443. if (midr_info.midr == 0)
  1444. {
  1445. // shared midr
  1446. midrs[cpuid] = (unsigned int)-1;
  1447. }
  1448. else
  1449. {
  1450. // save midr and reset
  1451. midrs[cpuid] = midr_info.midr;
  1452. for (int i = 0; i < g_cpucount; i++)
  1453. {
  1454. if (midrs[i] == (unsigned int)-1)
  1455. midrs[i] = midr_info.midr;
  1456. }
  1457. }
  1458. midr_info.midr = 0;
  1459. }
  1460. // /proc/cpuinfo may only report little/online cores on old kernel
  1461. if (g_cpu_affinity_mask_big.num_enabled() == g_cpucount)
  1462. {
  1463. // assign the remaining unknown midrs for smp cpu
  1464. for (int i = 0; i < g_cpucount; i++)
  1465. {
  1466. if (midrs[i] == 0)
  1467. midrs[i] = midr_info.midr;
  1468. }
  1469. }
  1470. else
  1471. {
  1472. // clear the big core midrs for hmp cpu if they are the same as little cores
  1473. unsigned int little_midr = 0;
  1474. for (int i = 0; i < g_cpucount; i++)
  1475. {
  1476. if (g_cpu_affinity_mask_little.is_enabled(i))
  1477. {
  1478. little_midr = midrs[i];
  1479. break;
  1480. }
  1481. }
  1482. for (int i = 0; i < g_cpucount; i++)
  1483. {
  1484. if (g_cpu_affinity_mask_big.is_enabled(i))
  1485. {
  1486. if (midrs[i] == little_midr)
  1487. {
  1488. midrs[i] = 0;
  1489. }
  1490. }
  1491. }
  1492. }
  1493. return 0;
  1494. }
  1495. // return midr for the current running core
  1496. static unsigned int get_midr_from_register()
  1497. {
  1498. uint64_t midr;
  1499. asm volatile("mrs %0, MIDR_EL1"
  1500. : "=r"(midr));
  1501. return (unsigned int)midr;
  1502. }
  1503. static int get_sched_affinity(ncnn::CpuSet& thread_affinity_mask)
  1504. {
  1505. // get affinity for thread
  1506. #if defined(__BIONIC__) && !defined(__OHOS__)
  1507. pid_t pid = gettid();
  1508. #else
  1509. pid_t pid = syscall(SYS_gettid);
  1510. #endif
  1511. thread_affinity_mask.disable_all();
  1512. int syscallret = syscall(__NR_sched_getaffinity, pid, sizeof(cpu_set_t), &thread_affinity_mask.cpu_set);
  1513. if (syscallret)
  1514. {
  1515. // handle get error silently
  1516. return -1;
  1517. }
  1518. return 0;
  1519. }
  1520. static int midr_is_a53_a55(unsigned int midr)
  1521. {
  1522. // 0x 41 ? f d03 ? = arm cortex-a53
  1523. // 0x 51 ? f 801 ? = qcom kryo200 a53
  1524. // 0x 41 ? f d04 ? = arm cortex-a35
  1525. // 0x 41 ? f d05 ? = arm cortex-a55
  1526. // 0x 51 ? f 803 ? = qcom kryo300 a55
  1527. // 0x 51 ? f 805 ? = qcom kryo400 a55
  1528. midr_info_t midr_info(midr);
  1529. return (midr_info.implementer == 0x41 && midr_info.part == 0xd03)
  1530. || (midr_info.implementer == 0x51 && midr_info.part == 0x801)
  1531. || (midr_info.implementer == 0x41 && midr_info.part == 0xd04)
  1532. || (midr_info.implementer == 0x41 && midr_info.part == 0xd05)
  1533. || (midr_info.implementer == 0x51 && midr_info.part == 0x803)
  1534. || (midr_info.implementer == 0x51 && midr_info.part == 0x805);
  1535. }
  1536. static int detect_cpu_is_arm_a53_a55()
  1537. {
  1538. int a53_a55_cpu_count = 0;
  1539. // first try, iterate /sys/devices/system/cpu/cpuX/regs/identification/midr_el1
  1540. bool sysfs_midr = true;
  1541. for (int i = 0; i < g_cpucount; i++)
  1542. {
  1543. unsigned int midr = 0;
  1544. // for kernel 4.7+
  1545. midr = get_midr_from_sysfs(i);
  1546. if (midr == 0)
  1547. {
  1548. sysfs_midr = false;
  1549. break;
  1550. }
  1551. if (midr_is_a53_a55(midr))
  1552. {
  1553. a53_a55_cpu_count++;
  1554. }
  1555. }
  1556. if (!sysfs_midr)
  1557. {
  1558. // second try, collect midr from /proc/cpuinfo
  1559. std::vector<unsigned int> midrs;
  1560. int ret = get_midr_from_proc_cpuinfo(midrs);
  1561. if (ret == 0 && (int)midrs.size() == g_cpucount)
  1562. {
  1563. for (int i = 0; i < g_cpucount; i++)
  1564. {
  1565. if (midr_is_a53_a55(midrs[i]))
  1566. {
  1567. a53_a55_cpu_count++;
  1568. }
  1569. }
  1570. }
  1571. else
  1572. {
  1573. // third try, assume all aarch64 little cores are a53/a55
  1574. a53_a55_cpu_count = g_cpu_affinity_mask_little.num_enabled();
  1575. }
  1576. }
  1577. if (a53_a55_cpu_count == 0)
  1578. return 0; // all non a53/a55
  1579. if (a53_a55_cpu_count == g_cpucount)
  1580. return 1; // all a53/a55
  1581. // little cores are a53/a55
  1582. return 2;
  1583. }
  1584. #endif // __aarch64__
  1585. #endif // defined __ANDROID__ || defined __linux__
  1586. // the initialization
  1587. static void initialize_global_cpu_info()
  1588. {
  1589. g_cpucount = get_cpucount();
  1590. g_physical_cpucount = get_physical_cpucount();
  1591. g_powersave = 0;
  1592. initialize_cpu_thread_affinity_mask(g_cpu_affinity_mask_all, g_cpu_affinity_mask_little, g_cpu_affinity_mask_big);
  1593. #if (defined _WIN32 && (__aarch64__ || __arm__))
  1594. if (!is_being_debugged())
  1595. {
  1596. ruapu_init();
  1597. }
  1598. #endif
  1599. #if defined _WIN32
  1600. #if __aarch64__
  1601. g_cpu_support_arm_cpuid = ruapu_supports("cpuid");
  1602. g_cpu_support_arm_asimdhp = ruapu_supports("asimdhp") || IsProcessorFeaturePresent(43); // dp implies hp
  1603. g_cpu_support_arm_asimddp = ruapu_supports("asimddp") || IsProcessorFeaturePresent(43); // 43 is PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE
  1604. g_cpu_support_arm_asimdfhm = ruapu_supports("asimdfhm");
  1605. g_cpu_support_arm_bf16 = ruapu_supports("bf16");
  1606. g_cpu_support_arm_i8mm = ruapu_supports("i8mm");
  1607. g_cpu_support_arm_sve = ruapu_supports("sve");
  1608. g_cpu_support_arm_sve2 = ruapu_supports("sve2");
  1609. g_cpu_support_arm_svebf16 = ruapu_supports("svebf16");
  1610. g_cpu_support_arm_svei8mm = ruapu_supports("svei8mm");
  1611. g_cpu_support_arm_svef32mm = ruapu_supports("svef32mm");
  1612. #elif __arm__
  1613. g_cpu_support_arm_edsp = ruapu_supports("edsp");
  1614. g_cpu_support_arm_neon = 1; // all modern windows arm devices have neon
  1615. g_cpu_support_arm_vfpv4 = ruapu_supports("vfpv4");
  1616. #endif // __aarch64__ || __arm__
  1617. #elif defined __ANDROID__ || defined __linux__
  1618. g_hwcaps = get_elf_hwcap(AT_HWCAP);
  1619. g_hwcaps2 = get_elf_hwcap(AT_HWCAP2);
  1620. #elif __APPLE__
  1621. g_hw_cpufamily = get_hw_cpufamily();
  1622. g_hw_cputype = get_hw_cputype();
  1623. g_hw_cpusubtype = get_hw_cpusubtype();
  1624. #if __aarch64__
  1625. g_hw_optional_arm_FEAT_FP16 = get_hw_capability("hw.optional.arm.FEAT_FP16");
  1626. g_hw_optional_arm_FEAT_DotProd = get_hw_capability("hw.optional.arm.FEAT_DotProd");
  1627. g_hw_optional_arm_FEAT_FHM = get_hw_capability("hw.optional.arm.FEAT_FHM");
  1628. g_hw_optional_arm_FEAT_BF16 = get_hw_capability("hw.optional.arm.FEAT_BF16");
  1629. g_hw_optional_arm_FEAT_I8MM = get_hw_capability("hw.optional.arm.FEAT_I8MM");
  1630. #endif // __aarch64__
  1631. #endif
  1632. #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  1633. g_cpu_support_x86_avx = get_cpu_support_x86_avx();
  1634. g_cpu_support_x86_fma = get_cpu_support_x86_fma();
  1635. g_cpu_support_x86_xop = get_cpu_support_x86_xop();
  1636. g_cpu_support_x86_f16c = get_cpu_support_x86_f16c();
  1637. g_cpu_support_x86_avx2 = get_cpu_support_x86_avx2();
  1638. g_cpu_support_x86_avx_vnni = get_cpu_support_x86_avx_vnni();
  1639. g_cpu_support_x86_avx512 = get_cpu_support_x86_avx512();
  1640. g_cpu_support_x86_avx512_vnni = get_cpu_support_x86_avx512_vnni();
  1641. g_cpu_support_x86_avx512_bf16 = get_cpu_support_x86_avx512_bf16();
  1642. g_cpu_support_x86_avx512_fp16 = get_cpu_support_x86_avx512_fp16();
  1643. #endif // defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  1644. g_cpu_level2_cachesize = get_cpu_level2_cachesize();
  1645. g_cpu_level3_cachesize = get_cpu_level3_cachesize();
  1646. #if defined __ANDROID__ || defined __linux__
  1647. #if __aarch64__
  1648. g_cpu_is_arm_a53_a55 = detect_cpu_is_arm_a53_a55();
  1649. #endif // __aarch64__
  1650. #endif // defined __ANDROID__ || defined __linux__
  1651. }
  1652. static int g_cpu_info_initialized = 0;
  1653. static inline void try_initialize_global_cpu_info()
  1654. {
  1655. if (!g_cpu_info_initialized)
  1656. {
  1657. initialize_global_cpu_info();
  1658. g_cpu_info_initialized = 1;
  1659. }
  1660. }
  1661. namespace ncnn {
  1662. #if defined _WIN32
  1663. CpuSet::CpuSet()
  1664. {
  1665. disable_all();
  1666. }
  1667. void CpuSet::enable(int cpu)
  1668. {
  1669. mask |= ((ULONG_PTR)1 << cpu);
  1670. }
  1671. void CpuSet::disable(int cpu)
  1672. {
  1673. mask &= ~((ULONG_PTR)1 << cpu);
  1674. }
  1675. void CpuSet::disable_all()
  1676. {
  1677. mask = 0;
  1678. }
  1679. bool CpuSet::is_enabled(int cpu) const
  1680. {
  1681. return mask & ((ULONG_PTR)1 << cpu);
  1682. }
  1683. int CpuSet::num_enabled() const
  1684. {
  1685. int num_enabled = 0;
  1686. for (int i = 0; i < (int)sizeof(mask) * 8; i++)
  1687. {
  1688. if (is_enabled(i))
  1689. num_enabled++;
  1690. }
  1691. return num_enabled;
  1692. }
  1693. #elif defined __ANDROID__ || defined __linux__
  1694. CpuSet::CpuSet()
  1695. {
  1696. disable_all();
  1697. }
  1698. void CpuSet::enable(int cpu)
  1699. {
  1700. CPU_SET(cpu, &cpu_set);
  1701. }
  1702. void CpuSet::disable(int cpu)
  1703. {
  1704. CPU_CLR(cpu, &cpu_set);
  1705. }
  1706. void CpuSet::disable_all()
  1707. {
  1708. CPU_ZERO(&cpu_set);
  1709. }
  1710. bool CpuSet::is_enabled(int cpu) const
  1711. {
  1712. return CPU_ISSET(cpu, &cpu_set);
  1713. }
  1714. int CpuSet::num_enabled() const
  1715. {
  1716. int num_enabled = 0;
  1717. for (int i = 0; i < (int)sizeof(cpu_set_t) * 8; i++)
  1718. {
  1719. if (is_enabled(i))
  1720. num_enabled++;
  1721. }
  1722. return num_enabled;
  1723. }
  1724. #elif __APPLE__
  1725. CpuSet::CpuSet()
  1726. {
  1727. disable_all();
  1728. }
  1729. void CpuSet::enable(int cpu)
  1730. {
  1731. policy |= ((unsigned int)1 << cpu);
  1732. }
  1733. void CpuSet::disable(int cpu)
  1734. {
  1735. policy &= ~((unsigned int)1 << cpu);
  1736. }
  1737. void CpuSet::disable_all()
  1738. {
  1739. policy = 0;
  1740. }
  1741. bool CpuSet::is_enabled(int cpu) const
  1742. {
  1743. return policy & ((unsigned int)1 << cpu);
  1744. }
  1745. int CpuSet::num_enabled() const
  1746. {
  1747. int num_enabled = 0;
  1748. for (int i = 0; i < (int)sizeof(policy) * 8; i++)
  1749. {
  1750. if (is_enabled(i))
  1751. num_enabled++;
  1752. }
  1753. return num_enabled;
  1754. }
  1755. #else
  1756. CpuSet::CpuSet()
  1757. {
  1758. }
  1759. void CpuSet::enable(int /* cpu */)
  1760. {
  1761. }
  1762. void CpuSet::disable(int /* cpu */)
  1763. {
  1764. }
  1765. void CpuSet::disable_all()
  1766. {
  1767. }
  1768. bool CpuSet::is_enabled(int /* cpu */) const
  1769. {
  1770. return true;
  1771. }
  1772. int CpuSet::num_enabled() const
  1773. {
  1774. return get_cpu_count();
  1775. }
  1776. #endif
  1777. int cpu_support_arm_edsp()
  1778. {
  1779. try_initialize_global_cpu_info();
  1780. #if __arm__ && !__aarch64__
  1781. #if defined _WIN32
  1782. return g_cpu_support_arm_edsp;
  1783. #elif defined __ANDROID__ || defined __linux__
  1784. return g_hwcaps & HWCAP_EDSP;
  1785. #elif __APPLE__
  1786. return g_hw_cputype == CPU_TYPE_ARM;
  1787. #else
  1788. return 0;
  1789. #endif
  1790. #else
  1791. return 0;
  1792. #endif
  1793. }
  1794. int cpu_support_arm_neon()
  1795. {
  1796. try_initialize_global_cpu_info();
  1797. #if __aarch64__
  1798. return 1;
  1799. #elif __arm__
  1800. #if defined _WIN32
  1801. return g_cpu_support_arm_neon;
  1802. #elif defined __ANDROID__ || defined __linux__
  1803. return g_hwcaps & HWCAP_NEON;
  1804. #elif __APPLE__
  1805. return g_hw_cputype == CPU_TYPE_ARM && g_hw_cpusubtype > CPU_SUBTYPE_ARM_V7;
  1806. #else
  1807. return 0;
  1808. #endif
  1809. #else
  1810. return 0;
  1811. #endif
  1812. }
  1813. int cpu_support_arm_vfpv4()
  1814. {
  1815. try_initialize_global_cpu_info();
  1816. #if __aarch64__
  1817. return 1;
  1818. #elif __arm__
  1819. #if defined _WIN32
  1820. return g_cpu_support_arm_vfpv4;
  1821. #elif defined __ANDROID__ || defined __linux__
  1822. return g_hwcaps & HWCAP_VFPv4;
  1823. #elif __APPLE__
  1824. return g_hw_cputype == CPU_TYPE_ARM && g_hw_cpusubtype > CPU_SUBTYPE_ARM_V7S;
  1825. #else
  1826. return 0;
  1827. #endif
  1828. #else
  1829. return 0;
  1830. #endif
  1831. }
  1832. int cpu_support_arm_asimdhp()
  1833. {
  1834. try_initialize_global_cpu_info();
  1835. #if __aarch64__
  1836. #if defined _WIN32
  1837. return g_cpu_support_arm_asimdhp;
  1838. #elif defined __ANDROID__ || defined __linux__
  1839. return g_hwcaps & HWCAP_ASIMDHP;
  1840. #elif __APPLE__
  1841. return g_hw_optional_arm_FEAT_FP16
  1842. || g_hw_cpufamily == CPUFAMILY_ARM_MONSOON_MISTRAL
  1843. || g_hw_cpufamily == CPUFAMILY_ARM_VORTEX_TEMPEST
  1844. || g_hw_cpufamily == CPUFAMILY_ARM_LIGHTNING_THUNDER
  1845. || g_hw_cpufamily == CPUFAMILY_ARM_FIRESTORM_ICESTORM
  1846. || g_hw_cpufamily == CPUFAMILY_ARM_AVALANCHE_BLIZZARD
  1847. || g_hw_cpufamily == CPUFAMILY_ARM_EVEREST_SAWTOOTH
  1848. || g_hw_cpufamily == CPUFAMILY_ARM_COLL
  1849. || g_hw_cpufamily == CPUFAMILY_ARM_IBIZA
  1850. || g_hw_cpufamily == CPUFAMILY_ARM_LOBOS
  1851. || g_hw_cpufamily == CPUFAMILY_ARM_PALMA;
  1852. #else
  1853. return 0;
  1854. #endif
  1855. #else
  1856. return 0;
  1857. #endif
  1858. }
  1859. int cpu_support_arm_cpuid()
  1860. {
  1861. try_initialize_global_cpu_info();
  1862. #if __aarch64__
  1863. #if defined _WIN32
  1864. return g_cpu_support_arm_cpuid;
  1865. #elif defined __ANDROID__ || defined __linux__
  1866. return g_hwcaps & HWCAP_CPUID;
  1867. #elif __APPLE__
  1868. return 0;
  1869. #else
  1870. return 0;
  1871. #endif
  1872. #else
  1873. return 0;
  1874. #endif
  1875. }
  1876. int cpu_support_arm_asimddp()
  1877. {
  1878. try_initialize_global_cpu_info();
  1879. #if __aarch64__
  1880. #if defined _WIN32
  1881. return g_cpu_support_arm_asimddp;
  1882. #elif defined __ANDROID__ || defined __linux__
  1883. return g_hwcaps & HWCAP_ASIMDDP;
  1884. #elif __APPLE__
  1885. return g_hw_optional_arm_FEAT_DotProd
  1886. || g_hw_cpufamily == CPUFAMILY_ARM_LIGHTNING_THUNDER
  1887. || g_hw_cpufamily == CPUFAMILY_ARM_FIRESTORM_ICESTORM
  1888. || g_hw_cpufamily == CPUFAMILY_ARM_AVALANCHE_BLIZZARD
  1889. || g_hw_cpufamily == CPUFAMILY_ARM_EVEREST_SAWTOOTH
  1890. || g_hw_cpufamily == CPUFAMILY_ARM_COLL
  1891. || g_hw_cpufamily == CPUFAMILY_ARM_IBIZA
  1892. || g_hw_cpufamily == CPUFAMILY_ARM_LOBOS
  1893. || g_hw_cpufamily == CPUFAMILY_ARM_PALMA;
  1894. #else
  1895. return 0;
  1896. #endif
  1897. #else
  1898. return 0;
  1899. #endif
  1900. }
  1901. int cpu_support_arm_asimdfhm()
  1902. {
  1903. try_initialize_global_cpu_info();
  1904. #if __aarch64__
  1905. #if defined _WIN32
  1906. return g_cpu_support_arm_asimdfhm;
  1907. #elif defined __ANDROID__ || defined __linux__
  1908. return g_hwcaps & HWCAP_ASIMDFHM;
  1909. #elif __APPLE__
  1910. return g_hw_optional_arm_FEAT_FHM
  1911. || g_hw_cpufamily == CPUFAMILY_ARM_LIGHTNING_THUNDER
  1912. || g_hw_cpufamily == CPUFAMILY_ARM_FIRESTORM_ICESTORM
  1913. || g_hw_cpufamily == CPUFAMILY_ARM_AVALANCHE_BLIZZARD
  1914. || g_hw_cpufamily == CPUFAMILY_ARM_EVEREST_SAWTOOTH
  1915. || g_hw_cpufamily == CPUFAMILY_ARM_COLL
  1916. || g_hw_cpufamily == CPUFAMILY_ARM_IBIZA
  1917. || g_hw_cpufamily == CPUFAMILY_ARM_LOBOS
  1918. || g_hw_cpufamily == CPUFAMILY_ARM_PALMA;
  1919. #else
  1920. return 0;
  1921. #endif
  1922. #else
  1923. return 0;
  1924. #endif
  1925. }
  1926. int cpu_support_arm_bf16()
  1927. {
  1928. try_initialize_global_cpu_info();
  1929. #if __aarch64__
  1930. #if defined _WIN32
  1931. return g_cpu_support_arm_bf16;
  1932. #elif defined __ANDROID__ || defined __linux__
  1933. return g_hwcaps2 & HWCAP2_BF16;
  1934. #elif __APPLE__
  1935. return g_hw_optional_arm_FEAT_BF16
  1936. || g_hw_cpufamily == CPUFAMILY_ARM_AVALANCHE_BLIZZARD
  1937. || g_hw_cpufamily == CPUFAMILY_ARM_EVEREST_SAWTOOTH
  1938. || g_hw_cpufamily == CPUFAMILY_ARM_COLL
  1939. || g_hw_cpufamily == CPUFAMILY_ARM_IBIZA
  1940. || g_hw_cpufamily == CPUFAMILY_ARM_LOBOS
  1941. || g_hw_cpufamily == CPUFAMILY_ARM_PALMA;
  1942. #else
  1943. return 0;
  1944. #endif
  1945. #else
  1946. return 0;
  1947. #endif
  1948. }
  1949. int cpu_support_arm_i8mm()
  1950. {
  1951. try_initialize_global_cpu_info();
  1952. #if __aarch64__
  1953. #if defined _WIN32
  1954. return g_cpu_support_arm_i8mm;
  1955. #elif defined __ANDROID__ || defined __linux__
  1956. return g_hwcaps2 & HWCAP2_I8MM;
  1957. #elif __APPLE__
  1958. return g_hw_optional_arm_FEAT_I8MM
  1959. || g_hw_cpufamily == CPUFAMILY_ARM_AVALANCHE_BLIZZARD
  1960. || g_hw_cpufamily == CPUFAMILY_ARM_EVEREST_SAWTOOTH
  1961. || g_hw_cpufamily == CPUFAMILY_ARM_COLL
  1962. || g_hw_cpufamily == CPUFAMILY_ARM_IBIZA
  1963. || g_hw_cpufamily == CPUFAMILY_ARM_LOBOS
  1964. || g_hw_cpufamily == CPUFAMILY_ARM_PALMA;
  1965. #else
  1966. return 0;
  1967. #endif
  1968. #else
  1969. return 0;
  1970. #endif
  1971. }
  1972. int cpu_support_arm_sve()
  1973. {
  1974. try_initialize_global_cpu_info();
  1975. #if __aarch64__
  1976. #if defined _WIN32
  1977. return g_cpu_support_arm_sve;
  1978. #elif defined __ANDROID__ || defined __linux__
  1979. return g_hwcaps & HWCAP_SVE;
  1980. #elif __APPLE__
  1981. return 0; // no known apple cpu support armv8.6 sve
  1982. #else
  1983. return 0;
  1984. #endif
  1985. #else
  1986. return 0;
  1987. #endif
  1988. }
  1989. int cpu_support_arm_sve2()
  1990. {
  1991. try_initialize_global_cpu_info();
  1992. #if __aarch64__
  1993. #if defined _WIN32
  1994. return g_cpu_support_arm_sve2;
  1995. #elif defined __ANDROID__ || defined __linux__
  1996. return g_hwcaps2 & HWCAP2_SVE2;
  1997. #elif __APPLE__
  1998. return 0; // no known apple cpu support armv8.6 sve2
  1999. #else
  2000. return 0;
  2001. #endif
  2002. #else
  2003. return 0;
  2004. #endif
  2005. }
  2006. int cpu_support_arm_svebf16()
  2007. {
  2008. try_initialize_global_cpu_info();
  2009. #if __aarch64__
  2010. #if defined _WIN32
  2011. return g_cpu_support_arm_svebf16;
  2012. #elif defined __ANDROID__ || defined __linux__
  2013. return g_hwcaps2 & HWCAP2_SVEBF16;
  2014. #elif __APPLE__
  2015. return 0; // no known apple cpu support armv8.6 svebf16
  2016. #else
  2017. return 0;
  2018. #endif
  2019. #else
  2020. return 0;
  2021. #endif
  2022. }
  2023. int cpu_support_arm_svei8mm()
  2024. {
  2025. try_initialize_global_cpu_info();
  2026. #if __aarch64__
  2027. #if defined _WIN32
  2028. return g_cpu_support_arm_svei8mm;
  2029. #elif defined __ANDROID__ || defined __linux__
  2030. return g_hwcaps2 & HWCAP2_SVEI8MM;
  2031. #elif __APPLE__
  2032. return 0; // no known apple cpu support armv8.6 svei8mm
  2033. #else
  2034. return 0;
  2035. #endif
  2036. #else
  2037. return 0;
  2038. #endif
  2039. }
  2040. int cpu_support_arm_svef32mm()
  2041. {
  2042. try_initialize_global_cpu_info();
  2043. #if __aarch64__
  2044. #if defined _WIN32
  2045. return g_cpu_support_arm_svef32mm;
  2046. #elif defined __ANDROID__ || defined __linux__
  2047. return g_hwcaps2 & HWCAP2_SVEF32MM;
  2048. #elif __APPLE__
  2049. return 0; // no known apple cpu support armv8.6 svef32mm
  2050. #else
  2051. return 0;
  2052. #endif
  2053. #else
  2054. return 0;
  2055. #endif
  2056. }
  2057. int cpu_support_x86_avx()
  2058. {
  2059. try_initialize_global_cpu_info();
  2060. #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  2061. return g_cpu_support_x86_avx;
  2062. #else
  2063. return 0;
  2064. #endif
  2065. }
  2066. int cpu_support_x86_fma()
  2067. {
  2068. try_initialize_global_cpu_info();
  2069. #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  2070. return g_cpu_support_x86_fma;
  2071. #else
  2072. return 0;
  2073. #endif
  2074. }
  2075. int cpu_support_x86_xop()
  2076. {
  2077. try_initialize_global_cpu_info();
  2078. #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  2079. return g_cpu_support_x86_xop;
  2080. #else
  2081. return 0;
  2082. #endif
  2083. }
  2084. int cpu_support_x86_f16c()
  2085. {
  2086. try_initialize_global_cpu_info();
  2087. #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  2088. return g_cpu_support_x86_f16c;
  2089. #else
  2090. return 0;
  2091. #endif
  2092. }
  2093. int cpu_support_x86_avx2()
  2094. {
  2095. try_initialize_global_cpu_info();
  2096. #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  2097. return g_cpu_support_x86_avx2;
  2098. #else
  2099. return 0;
  2100. #endif
  2101. }
  2102. int cpu_support_x86_avx_vnni()
  2103. {
  2104. try_initialize_global_cpu_info();
  2105. #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  2106. return g_cpu_support_x86_avx_vnni;
  2107. #else
  2108. return 0;
  2109. #endif
  2110. }
  2111. int cpu_support_x86_avx512()
  2112. {
  2113. try_initialize_global_cpu_info();
  2114. #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  2115. return g_cpu_support_x86_avx512;
  2116. #else
  2117. return 0;
  2118. #endif
  2119. }
  2120. int cpu_support_x86_avx512_vnni()
  2121. {
  2122. try_initialize_global_cpu_info();
  2123. #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  2124. return g_cpu_support_x86_avx512_vnni;
  2125. #else
  2126. return 0;
  2127. #endif
  2128. }
  2129. int cpu_support_x86_avx512_bf16()
  2130. {
  2131. try_initialize_global_cpu_info();
  2132. #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  2133. return g_cpu_support_x86_avx512_bf16;
  2134. #else
  2135. return 0;
  2136. #endif
  2137. }
  2138. int cpu_support_x86_avx512_fp16()
  2139. {
  2140. try_initialize_global_cpu_info();
  2141. #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
  2142. return g_cpu_support_x86_avx512_fp16;
  2143. #else
  2144. return 0;
  2145. #endif
  2146. }
  2147. int cpu_support_mips_msa()
  2148. {
  2149. try_initialize_global_cpu_info();
  2150. #if defined __ANDROID__ || defined __linux__
  2151. #if __mips__
  2152. return g_hwcaps & HWCAP_MIPS_MSA;
  2153. #else
  2154. return 0;
  2155. #endif
  2156. #else
  2157. return 0;
  2158. #endif
  2159. }
  2160. int cpu_support_loongarch_lsx()
  2161. {
  2162. try_initialize_global_cpu_info();
  2163. #if defined __ANDROID__ || defined __linux__
  2164. #if __loongarch64
  2165. return g_hwcaps & HWCAP_LOONGARCH_LSX;
  2166. #else
  2167. return 0;
  2168. #endif
  2169. #else
  2170. return 0;
  2171. #endif
  2172. }
  2173. int cpu_support_loongarch_lasx()
  2174. {
  2175. try_initialize_global_cpu_info();
  2176. #if defined __ANDROID__ || defined __linux__
  2177. #if __loongarch64
  2178. return g_hwcaps & HWCAP_LOONGARCH_LASX;
  2179. #else
  2180. return 0;
  2181. #endif
  2182. #else
  2183. return 0;
  2184. #endif
  2185. }
  2186. int cpu_support_loongson_mmi()
  2187. {
  2188. try_initialize_global_cpu_info();
  2189. #if defined __ANDROID__ || defined __linux__
  2190. #if __mips__
  2191. return g_hwcaps & HWCAP_LOONGSON_MMI;
  2192. #else
  2193. return 0;
  2194. #endif
  2195. #else
  2196. return 0;
  2197. #endif
  2198. }
  2199. int cpu_support_riscv_v()
  2200. {
  2201. try_initialize_global_cpu_info();
  2202. #if defined __ANDROID__ || defined __linux__
  2203. #if __riscv
  2204. return g_hwcaps & COMPAT_HWCAP_ISA_V;
  2205. #else
  2206. return 0;
  2207. #endif
  2208. #else
  2209. return 0;
  2210. #endif
  2211. }
  2212. int cpu_support_riscv_zfh()
  2213. {
  2214. try_initialize_global_cpu_info();
  2215. #if defined __ANDROID__ || defined __linux__
  2216. #if __riscv
  2217. // v + f does not imply zfh, but how to discover zfh properly ?
  2218. // upstream issue https://github.com/riscv/riscv-isa-manual/issues/414
  2219. return g_hwcaps & COMPAT_HWCAP_ISA_V && g_hwcaps & COMPAT_HWCAP_ISA_F;
  2220. #else
  2221. return 0;
  2222. #endif
  2223. #else
  2224. return 0;
  2225. #endif
  2226. }
  2227. int cpu_riscv_vlenb()
  2228. {
  2229. try_initialize_global_cpu_info();
  2230. #if __riscv
  2231. if (!cpu_support_riscv_v())
  2232. return 0;
  2233. int a = 0;
  2234. asm volatile(
  2235. ".word 0xc22026f3 \n" // csrr a3, vlenb
  2236. "mv %0, a3 \n"
  2237. : "=r"(a)
  2238. :
  2239. : "memory", "a3");
  2240. return a;
  2241. #else
  2242. return 0;
  2243. #endif
  2244. }
  2245. int get_cpu_count()
  2246. {
  2247. try_initialize_global_cpu_info();
  2248. return g_cpucount;
  2249. }
  2250. int get_little_cpu_count()
  2251. {
  2252. try_initialize_global_cpu_info();
  2253. return get_cpu_thread_affinity_mask(1).num_enabled();
  2254. }
  2255. int get_big_cpu_count()
  2256. {
  2257. try_initialize_global_cpu_info();
  2258. int big_cpu_count = get_cpu_thread_affinity_mask(2).num_enabled();
  2259. return big_cpu_count ? big_cpu_count : g_cpucount;
  2260. }
  2261. int get_physical_cpu_count()
  2262. {
  2263. try_initialize_global_cpu_info();
  2264. return g_physical_cpucount;
  2265. }
  2266. int get_physical_little_cpu_count()
  2267. {
  2268. try_initialize_global_cpu_info();
  2269. if (g_physical_cpucount == g_cpucount)
  2270. return get_little_cpu_count();
  2271. return g_physical_cpucount * 2 - g_cpucount;
  2272. }
  2273. int get_physical_big_cpu_count()
  2274. {
  2275. try_initialize_global_cpu_info();
  2276. if (g_physical_cpucount == g_cpucount)
  2277. return get_big_cpu_count();
  2278. return g_cpucount - g_physical_cpucount;
  2279. }
  2280. int get_cpu_level2_cache_size()
  2281. {
  2282. try_initialize_global_cpu_info();
  2283. return g_cpu_level2_cachesize;
  2284. }
  2285. int get_cpu_level3_cache_size()
  2286. {
  2287. try_initialize_global_cpu_info();
  2288. return g_cpu_level3_cachesize;
  2289. }
  2290. int get_cpu_powersave()
  2291. {
  2292. try_initialize_global_cpu_info();
  2293. return g_powersave;
  2294. }
  2295. int set_cpu_powersave(int powersave)
  2296. {
  2297. try_initialize_global_cpu_info();
  2298. if (powersave < 0 || powersave > 2)
  2299. {
  2300. NCNN_LOGE("powersave %d not supported", powersave);
  2301. return -1;
  2302. }
  2303. const CpuSet& thread_affinity_mask = get_cpu_thread_affinity_mask(powersave);
  2304. int ret = set_cpu_thread_affinity(thread_affinity_mask);
  2305. if (ret != 0)
  2306. return ret;
  2307. g_powersave = powersave;
  2308. return 0;
  2309. }
  2310. const CpuSet& get_cpu_thread_affinity_mask(int powersave)
  2311. {
  2312. try_initialize_global_cpu_info();
  2313. if (powersave == 0)
  2314. return g_cpu_affinity_mask_all;
  2315. if (powersave == 1)
  2316. return g_cpu_affinity_mask_little;
  2317. if (powersave == 2)
  2318. return g_cpu_affinity_mask_big;
  2319. NCNN_LOGE("powersave %d not supported", powersave);
  2320. // fallback to all cores anyway
  2321. return g_cpu_affinity_mask_all;
  2322. }
  2323. int set_cpu_thread_affinity(const CpuSet& thread_affinity_mask)
  2324. {
  2325. try_initialize_global_cpu_info();
  2326. #if defined __ANDROID__ || defined __linux__ || defined _WIN32
  2327. #ifdef _OPENMP
  2328. int num_threads = thread_affinity_mask.num_enabled();
  2329. // set affinity for each thread
  2330. set_omp_num_threads(num_threads);
  2331. std::vector<int> ssarets(num_threads, 0);
  2332. #pragma omp parallel for num_threads(num_threads)
  2333. for (int i = 0; i < num_threads; i++)
  2334. {
  2335. ssarets[i] = set_sched_affinity(thread_affinity_mask);
  2336. }
  2337. for (int i = 0; i < num_threads; i++)
  2338. {
  2339. if (ssarets[i] != 0)
  2340. return -1;
  2341. }
  2342. #else
  2343. int ssaret = set_sched_affinity(thread_affinity_mask);
  2344. if (ssaret != 0)
  2345. return -1;
  2346. #endif
  2347. return 0;
  2348. #elif __APPLE__
  2349. #ifdef _OPENMP
  2350. int num_threads = thread_affinity_mask.num_enabled();
  2351. // set affinity for each thread
  2352. set_omp_num_threads(num_threads);
  2353. std::vector<int> ssarets(num_threads, 0);
  2354. #pragma omp parallel for num_threads(num_threads)
  2355. for (int i = 0; i < num_threads; i++)
  2356. {
  2357. // assign one core for each thread
  2358. int core = -1 - i;
  2359. for (int j = 0; j < (int)sizeof(thread_affinity_mask.policy) * 8; j++)
  2360. {
  2361. if (thread_affinity_mask.is_enabled(j))
  2362. {
  2363. if (core == -1)
  2364. {
  2365. core = j;
  2366. break;
  2367. }
  2368. else
  2369. {
  2370. core++;
  2371. }
  2372. }
  2373. }
  2374. CpuSet this_thread_affinity_mask;
  2375. if (core != -1 - i)
  2376. {
  2377. this_thread_affinity_mask.enable(core);
  2378. }
  2379. ssarets[i] = set_sched_affinity(this_thread_affinity_mask);
  2380. }
  2381. for (int i = 0; i < num_threads; i++)
  2382. {
  2383. if (ssarets[i] != 0)
  2384. return -1;
  2385. }
  2386. #else
  2387. int ssaret = set_sched_affinity(thread_affinity_mask);
  2388. if (ssaret != 0)
  2389. return -1;
  2390. #endif
  2391. return 0;
  2392. #else
  2393. // TODO
  2394. (void)thread_affinity_mask;
  2395. return -1;
  2396. #endif
  2397. }
  2398. int is_current_thread_running_on_a53_a55()
  2399. {
  2400. try_initialize_global_cpu_info();
  2401. #if defined __ANDROID__ || defined __linux__
  2402. #if __aarch64__
  2403. if (g_cpu_is_arm_a53_a55 == 0)
  2404. return 0; // all non a53/a55
  2405. if (g_cpu_is_arm_a53_a55 == 1)
  2406. return 1; // all a53/a55
  2407. if (g_powersave == 2)
  2408. return 0; // big clusters
  2409. if (g_powersave == 1)
  2410. return 1; // little clusters
  2411. // little cores are a53/a55
  2412. // use cpuid for retrieving midr since kernel 4.7+
  2413. if (cpu_support_arm_cpuid())
  2414. {
  2415. unsigned int midr = get_midr_from_register();
  2416. if (midr)
  2417. return midr_is_a53_a55(midr);
  2418. }
  2419. // check if affinity cpuid is in the little ones
  2420. CpuSet thread_cs;
  2421. int ret = get_sched_affinity(thread_cs);
  2422. if (ret != 0)
  2423. {
  2424. // no affinity capability
  2425. return 0;
  2426. }
  2427. const CpuSet& little_cs = get_cpu_thread_affinity_mask(1);
  2428. for (int i = 0; i < g_cpucount; i++)
  2429. {
  2430. if (!thread_cs.is_enabled(i))
  2431. continue;
  2432. if (!little_cs.is_enabled(i))
  2433. return 0;
  2434. }
  2435. // all affinity cpuids are little core
  2436. return 1;
  2437. #else
  2438. return 0;
  2439. #endif // __aarch64__
  2440. #else
  2441. return 0;
  2442. #endif // defined __ANDROID__ || defined __linux__
  2443. }
  2444. int get_omp_num_threads()
  2445. {
  2446. #ifdef _OPENMP
  2447. return omp_get_num_threads();
  2448. #else
  2449. return 1;
  2450. #endif
  2451. }
  2452. void set_omp_num_threads(int num_threads)
  2453. {
  2454. #ifdef _OPENMP
  2455. omp_set_num_threads(num_threads);
  2456. #else
  2457. (void)num_threads;
  2458. #endif
  2459. }
  2460. int get_omp_dynamic()
  2461. {
  2462. #ifdef _OPENMP
  2463. return omp_get_dynamic();
  2464. #else
  2465. return 0;
  2466. #endif
  2467. }
  2468. void set_omp_dynamic(int dynamic)
  2469. {
  2470. #ifdef _OPENMP
  2471. omp_set_dynamic(dynamic);
  2472. #else
  2473. (void)dynamic;
  2474. #endif
  2475. }
  2476. int get_omp_thread_num()
  2477. {
  2478. #ifdef _OPENMP
  2479. return omp_get_thread_num();
  2480. #else
  2481. return 0;
  2482. #endif
  2483. }
  2484. int get_kmp_blocktime()
  2485. {
  2486. #if defined(_OPENMP) && (__clang__ || defined(_OPENMP_LLVM_RUNTIME))
  2487. return kmp_get_blocktime();
  2488. #else
  2489. return 0;
  2490. #endif
  2491. }
  2492. void set_kmp_blocktime(int time_ms)
  2493. {
  2494. #if defined(_OPENMP) && (__clang__ || defined(_OPENMP_LLVM_RUNTIME))
  2495. kmp_set_blocktime(time_ms);
  2496. #else
  2497. (void)time_ms;
  2498. #endif
  2499. }
  2500. static ncnn::ThreadLocalStorage tls_flush_denormals;
  2501. int get_flush_denormals()
  2502. {
  2503. #if defined(__SSE3__)
  2504. return (int)reinterpret_cast<size_t>(tls_flush_denormals.get());
  2505. #else
  2506. return 0;
  2507. #endif
  2508. }
  2509. int set_flush_denormals(int flush_denormals)
  2510. {
  2511. if (flush_denormals < 0 || flush_denormals > 3)
  2512. {
  2513. NCNN_LOGE("denormals_zero %d not supported", flush_denormals);
  2514. return -1;
  2515. }
  2516. #if defined(__SSE3__)
  2517. if (flush_denormals == 0)
  2518. {
  2519. _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF);
  2520. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
  2521. }
  2522. else if (flush_denormals == 1)
  2523. {
  2524. _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
  2525. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
  2526. }
  2527. else if (flush_denormals == 2)
  2528. {
  2529. _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF);
  2530. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
  2531. }
  2532. else if (flush_denormals == 3)
  2533. {
  2534. _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
  2535. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
  2536. }
  2537. tls_flush_denormals.set(reinterpret_cast<void*>((size_t)flush_denormals));
  2538. return 0;
  2539. #else
  2540. return 0;
  2541. #endif
  2542. }
  2543. } // namespace ncnn
  2544. #if defined __ANDROID__ && defined(_OPENMP) && __clang__
  2545. #ifdef __cplusplus
  2546. extern "C" {
  2547. #endif
  2548. void __wrap___kmp_affinity_determine_capable(const char* /*env_var*/)
  2549. {
  2550. // the internal affinity routines in llvm openmp call abort on __NR_sched_getaffinity / __NR_sched_setaffinity fails
  2551. // ref KMPNativeAffinity::get_system_affinity/set_system_affinity in openmp/runtime/src/kmp_affinity.h
  2552. // and cpu core goes offline in powersave mode on android, which triggers abort
  2553. // ATM there is no known api for controlling the abort behavior
  2554. // override __kmp_affinity_determine_capable with empty body to disable affinity regardless of KMP_AFFINITY env_var
  2555. // ugly hack works >.< --- nihui
  2556. }
  2557. #ifdef __cplusplus
  2558. } // extern "C"
  2559. #endif
  2560. #endif