PageRenderTime 66ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/erts/emulator/beam/erl_cpu_topology.c

https://github.com/Bwooce/otp
C | 2361 lines | 2004 code | 316 blank | 41 comment | 591 complexity | 33c9cf41f5c948f75153a14a492d897a MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-2-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * %CopyrightBegin%
  3. *
  4. * Copyright Ericsson AB 2010-2011. All Rights Reserved.
  5. *
  6. * The contents of this file are subject to the Erlang Public License,
  7. * Version 1.1, (the "License"); you may not use this file except in
  8. * compliance with the License. You should have received a copy of the
  9. * Erlang Public License along with this software. If not, it can be
  10. * retrieved online at http://www.erlang.org/.
  11. *
  12. * Software distributed under the License is distributed on an "AS IS"
  13. * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  14. * the License for the specific language governing rights and limitations
  15. * under the License.
  16. *
  17. * %CopyrightEnd%
  18. */
  19. /*
  20. * Description: CPU topology and related functionality
  21. *
  22. * Author: Rickard Green
  23. */
  24. #ifdef HAVE_CONFIG_H
  25. # include "config.h"
  26. #endif
  27. #include <ctype.h>
  28. #include "global.h"
  29. #include "error.h"
  30. #include "bif.h"
  31. #include "erl_cpu_topology.h"
  32. #define ERTS_MAX_READER_GROUPS 8
  33. /*
  34. * Cpu topology hierarchy.
  35. */
  36. #define ERTS_TOPOLOGY_NODE 0
  37. #define ERTS_TOPOLOGY_PROCESSOR 1
  38. #define ERTS_TOPOLOGY_PROCESSOR_NODE 2
  39. #define ERTS_TOPOLOGY_CORE 3
  40. #define ERTS_TOPOLOGY_THREAD 4
  41. #define ERTS_TOPOLOGY_LOGICAL 5
  42. #define ERTS_TOPOLOGY_MAX_DEPTH 6
  43. typedef struct {
  44. int bind_id;
  45. int bound_id;
  46. } ErtsCpuBindData;
  47. static erts_cpu_info_t *cpuinfo;
  48. static int max_main_threads;
  49. static int reader_groups;
  50. static ErtsCpuBindData *scheduler2cpu_map;
  51. static erts_smp_rwmtx_t cpuinfo_rwmtx;
  52. typedef enum {
  53. ERTS_CPU_BIND_UNDEFINED,
  54. ERTS_CPU_BIND_SPREAD,
  55. ERTS_CPU_BIND_PROCESSOR_SPREAD,
  56. ERTS_CPU_BIND_THREAD_SPREAD,
  57. ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD,
  58. ERTS_CPU_BIND_NO_NODE_PROCESSOR_SPREAD,
  59. ERTS_CPU_BIND_NO_NODE_THREAD_SPREAD,
  60. ERTS_CPU_BIND_NO_SPREAD,
  61. ERTS_CPU_BIND_NONE
  62. } ErtsCpuBindOrder;
  63. #define ERTS_CPU_BIND_DEFAULT_BIND \
  64. ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD
  65. static int no_cpu_groups_callbacks;
  66. static ErtsCpuBindOrder cpu_bind_order;
  67. static erts_cpu_topology_t *user_cpudata;
  68. static int user_cpudata_size;
  69. static erts_cpu_topology_t *system_cpudata;
  70. static int system_cpudata_size;
  71. typedef struct {
  72. int level[ERTS_TOPOLOGY_MAX_DEPTH+1];
  73. } erts_avail_cput;
  74. typedef struct {
  75. int id;
  76. int sub_levels;
  77. int cpu_groups;
  78. } erts_cpu_groups_count_t;
  79. typedef struct {
  80. int logical;
  81. int cpu_group;
  82. } erts_cpu_groups_map_array_t;
  83. typedef struct erts_cpu_groups_callback_list_t_ erts_cpu_groups_callback_list_t;
  84. struct erts_cpu_groups_callback_list_t_ {
  85. erts_cpu_groups_callback_list_t *next;
  86. erts_cpu_groups_callback_t callback;
  87. void *arg;
  88. };
  89. typedef struct erts_cpu_groups_map_t_ erts_cpu_groups_map_t;
  90. struct erts_cpu_groups_map_t_ {
  91. erts_cpu_groups_map_t *next;
  92. int groups;
  93. erts_cpu_groups_map_array_t *array;
  94. int size;
  95. int logical_processors;
  96. erts_cpu_groups_callback_list_t *callback_list;
  97. };
  98. typedef struct {
  99. erts_cpu_groups_callback_t callback;
  100. int ix;
  101. void *arg;
  102. } erts_cpu_groups_callback_call_t;
  103. static erts_cpu_groups_map_t *cpu_groups_maps;
  104. static erts_cpu_groups_map_t *reader_groups_map;
  105. #define ERTS_TOPOLOGY_CG ERTS_TOPOLOGY_MAX_DEPTH
  106. #define ERTS_MAX_CPU_TOPOLOGY_ID ((int) 0xffff)
  107. #ifdef ERTS_SMP
  108. static void cpu_bind_order_sort(erts_cpu_topology_t *cpudata,
  109. int size,
  110. ErtsCpuBindOrder bind_order,
  111. int mk_seq);
  112. static void write_schedulers_bind_change(erts_cpu_topology_t *cpudata, int size);
  113. #endif
  114. static void reader_groups_callback(int, ErtsSchedulerData *, int, void *);
  115. static erts_cpu_groups_map_t *add_cpu_groups(int groups,
  116. erts_cpu_groups_callback_t callback,
  117. void *arg);
  118. static void update_cpu_groups_maps(void);
  119. static void make_cpu_groups_map(erts_cpu_groups_map_t *map, int test);
  120. static int cpu_groups_lookup(erts_cpu_groups_map_t *map,
  121. ErtsSchedulerData *esdp);
  122. static void create_tmp_cpu_topology_copy(erts_cpu_topology_t **cpudata,
  123. int *cpudata_size);
  124. static void destroy_tmp_cpu_topology_copy(erts_cpu_topology_t *cpudata);
  125. static int
  126. int_cmp(const void *vx, const void *vy)
  127. {
  128. return *((int *) vx) - *((int *) vy);
  129. }
  130. static int
  131. cpu_spread_order_cmp(const void *vx, const void *vy)
  132. {
  133. erts_cpu_topology_t *x = (erts_cpu_topology_t *) vx;
  134. erts_cpu_topology_t *y = (erts_cpu_topology_t *) vy;
  135. if (x->thread != y->thread)
  136. return x->thread - y->thread;
  137. if (x->core != y->core)
  138. return x->core - y->core;
  139. if (x->processor_node != y->processor_node)
  140. return x->processor_node - y->processor_node;
  141. if (x->processor != y->processor)
  142. return x->processor - y->processor;
  143. if (x->node != y->node)
  144. return x->node - y->node;
  145. return 0;
  146. }
  147. static int
  148. cpu_processor_spread_order_cmp(const void *vx, const void *vy)
  149. {
  150. erts_cpu_topology_t *x = (erts_cpu_topology_t *) vx;
  151. erts_cpu_topology_t *y = (erts_cpu_topology_t *) vy;
  152. if (x->thread != y->thread)
  153. return x->thread - y->thread;
  154. if (x->processor_node != y->processor_node)
  155. return x->processor_node - y->processor_node;
  156. if (x->core != y->core)
  157. return x->core - y->core;
  158. if (x->node != y->node)
  159. return x->node - y->node;
  160. if (x->processor != y->processor)
  161. return x->processor - y->processor;
  162. return 0;
  163. }
  164. static int
  165. cpu_thread_spread_order_cmp(const void *vx, const void *vy)
  166. {
  167. erts_cpu_topology_t *x = (erts_cpu_topology_t *) vx;
  168. erts_cpu_topology_t *y = (erts_cpu_topology_t *) vy;
  169. if (x->thread != y->thread)
  170. return x->thread - y->thread;
  171. if (x->node != y->node)
  172. return x->node - y->node;
  173. if (x->processor != y->processor)
  174. return x->processor - y->processor;
  175. if (x->processor_node != y->processor_node)
  176. return x->processor_node - y->processor_node;
  177. if (x->core != y->core)
  178. return x->core - y->core;
  179. return 0;
  180. }
  181. static int
  182. cpu_thread_no_node_processor_spread_order_cmp(const void *vx, const void *vy)
  183. {
  184. erts_cpu_topology_t *x = (erts_cpu_topology_t *) vx;
  185. erts_cpu_topology_t *y = (erts_cpu_topology_t *) vy;
  186. if (x->thread != y->thread)
  187. return x->thread - y->thread;
  188. if (x->node != y->node)
  189. return x->node - y->node;
  190. if (x->core != y->core)
  191. return x->core - y->core;
  192. if (x->processor != y->processor)
  193. return x->processor - y->processor;
  194. return 0;
  195. }
  196. static int
  197. cpu_no_node_processor_spread_order_cmp(const void *vx, const void *vy)
  198. {
  199. erts_cpu_topology_t *x = (erts_cpu_topology_t *) vx;
  200. erts_cpu_topology_t *y = (erts_cpu_topology_t *) vy;
  201. if (x->node != y->node)
  202. return x->node - y->node;
  203. if (x->thread != y->thread)
  204. return x->thread - y->thread;
  205. if (x->core != y->core)
  206. return x->core - y->core;
  207. if (x->processor != y->processor)
  208. return x->processor - y->processor;
  209. return 0;
  210. }
  211. static int
  212. cpu_no_node_thread_spread_order_cmp(const void *vx, const void *vy)
  213. {
  214. erts_cpu_topology_t *x = (erts_cpu_topology_t *) vx;
  215. erts_cpu_topology_t *y = (erts_cpu_topology_t *) vy;
  216. if (x->node != y->node)
  217. return x->node - y->node;
  218. if (x->thread != y->thread)
  219. return x->thread - y->thread;
  220. if (x->processor != y->processor)
  221. return x->processor - y->processor;
  222. if (x->core != y->core)
  223. return x->core - y->core;
  224. return 0;
  225. }
  226. static int
  227. cpu_no_spread_order_cmp(const void *vx, const void *vy)
  228. {
  229. erts_cpu_topology_t *x = (erts_cpu_topology_t *) vx;
  230. erts_cpu_topology_t *y = (erts_cpu_topology_t *) vy;
  231. if (x->node != y->node)
  232. return x->node - y->node;
  233. if (x->processor != y->processor)
  234. return x->processor - y->processor;
  235. if (x->processor_node != y->processor_node)
  236. return x->processor_node - y->processor_node;
  237. if (x->core != y->core)
  238. return x->core - y->core;
  239. if (x->thread != y->thread)
  240. return x->thread - y->thread;
  241. return 0;
  242. }
  243. static ERTS_INLINE void
  244. make_cpudata_id_seq(erts_cpu_topology_t *cpudata, int size, int no_node)
  245. {
  246. int ix;
  247. int node = -1;
  248. int processor = -1;
  249. int processor_node = -1;
  250. int processor_node_node = -1;
  251. int core = -1;
  252. int thread = -1;
  253. int old_node = -1;
  254. int old_processor = -1;
  255. int old_processor_node = -1;
  256. int old_core = -1;
  257. int old_thread = -1;
  258. for (ix = 0; ix < size; ix++) {
  259. if (!no_node || cpudata[ix].node >= 0) {
  260. if (old_node == cpudata[ix].node)
  261. cpudata[ix].node = node;
  262. else {
  263. old_node = cpudata[ix].node;
  264. old_processor = processor = -1;
  265. if (!no_node)
  266. old_processor_node = processor_node = -1;
  267. old_core = core = -1;
  268. old_thread = thread = -1;
  269. if (no_node || cpudata[ix].node >= 0)
  270. cpudata[ix].node = ++node;
  271. }
  272. }
  273. if (old_processor == cpudata[ix].processor)
  274. cpudata[ix].processor = processor;
  275. else {
  276. old_processor = cpudata[ix].processor;
  277. if (!no_node)
  278. processor_node_node = old_processor_node = processor_node = -1;
  279. old_core = core = -1;
  280. old_thread = thread = -1;
  281. cpudata[ix].processor = ++processor;
  282. }
  283. if (no_node && cpudata[ix].processor_node < 0)
  284. old_processor_node = -1;
  285. else {
  286. if (old_processor_node == cpudata[ix].processor_node) {
  287. if (no_node)
  288. cpudata[ix].node = cpudata[ix].processor_node = node;
  289. else {
  290. if (processor_node_node >= 0)
  291. cpudata[ix].node = processor_node_node;
  292. cpudata[ix].processor_node = processor_node;
  293. }
  294. }
  295. else {
  296. old_processor_node = cpudata[ix].processor_node;
  297. old_core = core = -1;
  298. old_thread = thread = -1;
  299. if (no_node)
  300. cpudata[ix].node = cpudata[ix].processor_node = ++node;
  301. else {
  302. cpudata[ix].node = processor_node_node = ++node;
  303. cpudata[ix].processor_node = ++processor_node;
  304. }
  305. }
  306. }
  307. if (!no_node && cpudata[ix].processor_node < 0)
  308. cpudata[ix].processor_node = 0;
  309. if (old_core == cpudata[ix].core)
  310. cpudata[ix].core = core;
  311. else {
  312. old_core = cpudata[ix].core;
  313. old_thread = thread = -1;
  314. cpudata[ix].core = ++core;
  315. }
  316. if (old_thread == cpudata[ix].thread)
  317. cpudata[ix].thread = thread;
  318. else
  319. old_thread = cpudata[ix].thread = ++thread;
  320. }
  321. }
  322. static void
  323. cpu_bind_order_sort(erts_cpu_topology_t *cpudata,
  324. int size,
  325. ErtsCpuBindOrder bind_order,
  326. int mk_seq)
  327. {
  328. if (size > 1) {
  329. int no_node = 0;
  330. int (*cmp_func)(const void *, const void *);
  331. switch (bind_order) {
  332. case ERTS_CPU_BIND_SPREAD:
  333. cmp_func = cpu_spread_order_cmp;
  334. break;
  335. case ERTS_CPU_BIND_PROCESSOR_SPREAD:
  336. cmp_func = cpu_processor_spread_order_cmp;
  337. break;
  338. case ERTS_CPU_BIND_THREAD_SPREAD:
  339. cmp_func = cpu_thread_spread_order_cmp;
  340. break;
  341. case ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD:
  342. no_node = 1;
  343. cmp_func = cpu_thread_no_node_processor_spread_order_cmp;
  344. break;
  345. case ERTS_CPU_BIND_NO_NODE_PROCESSOR_SPREAD:
  346. no_node = 1;
  347. cmp_func = cpu_no_node_processor_spread_order_cmp;
  348. break;
  349. case ERTS_CPU_BIND_NO_NODE_THREAD_SPREAD:
  350. no_node = 1;
  351. cmp_func = cpu_no_node_thread_spread_order_cmp;
  352. break;
  353. case ERTS_CPU_BIND_NO_SPREAD:
  354. cmp_func = cpu_no_spread_order_cmp;
  355. break;
  356. default:
  357. cmp_func = NULL;
  358. erl_exit(ERTS_ABORT_EXIT,
  359. "Bad cpu bind type: %d\n",
  360. (int) cpu_bind_order);
  361. break;
  362. }
  363. if (mk_seq)
  364. make_cpudata_id_seq(cpudata, size, no_node);
  365. qsort(cpudata, size, sizeof(erts_cpu_topology_t), cmp_func);
  366. }
  367. }
  368. static int
  369. processor_order_cmp(const void *vx, const void *vy)
  370. {
  371. erts_cpu_topology_t *x = (erts_cpu_topology_t *) vx;
  372. erts_cpu_topology_t *y = (erts_cpu_topology_t *) vy;
  373. if (x->processor != y->processor)
  374. return x->processor - y->processor;
  375. if (x->node != y->node)
  376. return x->node - y->node;
  377. if (x->processor_node != y->processor_node)
  378. return x->processor_node - y->processor_node;
  379. if (x->core != y->core)
  380. return x->core - y->core;
  381. if (x->thread != y->thread)
  382. return x->thread - y->thread;
  383. return 0;
  384. }
  385. #ifdef ERTS_SMP
  386. void
  387. erts_sched_check_cpu_bind_prep_suspend(ErtsSchedulerData *esdp)
  388. {
  389. erts_cpu_groups_map_t *cgm;
  390. erts_cpu_groups_callback_list_t *cgcl;
  391. erts_cpu_groups_callback_call_t *cgcc;
  392. int cgcc_ix;
  393. /* Unbind from cpu */
  394. erts_smp_rwmtx_rwlock(&cpuinfo_rwmtx);
  395. if (scheduler2cpu_map[esdp->no].bound_id >= 0
  396. && erts_unbind_from_cpu(cpuinfo) == 0) {
  397. esdp->cpu_id = scheduler2cpu_map[esdp->no].bound_id = -1;
  398. }
  399. cgcc = erts_alloc(ERTS_ALC_T_TMP,
  400. (no_cpu_groups_callbacks
  401. * sizeof(erts_cpu_groups_callback_call_t)));
  402. cgcc_ix = 0;
  403. for (cgm = cpu_groups_maps; cgm; cgm = cgm->next) {
  404. for (cgcl = cgm->callback_list; cgcl; cgcl = cgcl->next) {
  405. cgcc[cgcc_ix].callback = cgcl->callback;
  406. cgcc[cgcc_ix].ix = cpu_groups_lookup(cgm, esdp);
  407. cgcc[cgcc_ix].arg = cgcl->arg;
  408. cgcc_ix++;
  409. }
  410. }
  411. ASSERT(no_cpu_groups_callbacks == cgcc_ix);
  412. erts_smp_rwmtx_rwunlock(&cpuinfo_rwmtx);
  413. for (cgcc_ix = 0; cgcc_ix < no_cpu_groups_callbacks; cgcc_ix++)
  414. cgcc[cgcc_ix].callback(1,
  415. esdp,
  416. cgcc[cgcc_ix].ix,
  417. cgcc[cgcc_ix].arg);
  418. erts_free(ERTS_ALC_T_TMP, cgcc);
  419. if (esdp->no <= max_main_threads)
  420. erts_thr_set_main_status(0, 0);
  421. }
  422. void
  423. erts_sched_check_cpu_bind_post_suspend(ErtsSchedulerData *esdp)
  424. {
  425. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(esdp->run_queue));
  426. if (esdp->no <= max_main_threads)
  427. erts_thr_set_main_status(1, (int) esdp->no);
  428. /* Make sure we check if we should bind to a cpu or not... */
  429. if (esdp->run_queue->flags & ERTS_RUNQ_FLG_SHARED_RUNQ)
  430. erts_smp_atomic32_set(&esdp->chk_cpu_bind, 1);
  431. else
  432. esdp->run_queue->flags |= ERTS_RUNQ_FLG_CHK_CPU_BIND;
  433. }
  434. #endif
  435. void
  436. erts_sched_check_cpu_bind(ErtsSchedulerData *esdp)
  437. {
  438. int res, cpu_id, cgcc_ix;
  439. erts_cpu_groups_map_t *cgm;
  440. erts_cpu_groups_callback_list_t *cgcl;
  441. erts_cpu_groups_callback_call_t *cgcc;
  442. #ifdef ERTS_SMP
  443. if (erts_common_run_queue)
  444. erts_smp_atomic32_set(&esdp->chk_cpu_bind, 0);
  445. else {
  446. esdp->run_queue->flags &= ~ERTS_RUNQ_FLG_CHK_CPU_BIND;
  447. }
  448. #endif
  449. erts_smp_runq_unlock(esdp->run_queue);
  450. erts_smp_rwmtx_rwlock(&cpuinfo_rwmtx);
  451. cpu_id = scheduler2cpu_map[esdp->no].bind_id;
  452. if (cpu_id >= 0 && cpu_id != scheduler2cpu_map[esdp->no].bound_id) {
  453. res = erts_bind_to_cpu(cpuinfo, cpu_id);
  454. if (res == 0)
  455. esdp->cpu_id = scheduler2cpu_map[esdp->no].bound_id = cpu_id;
  456. else {
  457. erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
  458. erts_dsprintf(dsbufp, "Scheduler %d failed to bind to cpu %d: %s\n",
  459. (int) esdp->no, cpu_id, erl_errno_id(-res));
  460. erts_send_error_to_logger_nogl(dsbufp);
  461. if (scheduler2cpu_map[esdp->no].bound_id >= 0)
  462. goto unbind;
  463. }
  464. }
  465. else if (cpu_id < 0) {
  466. unbind:
  467. /* Get rid of old binding */
  468. res = erts_unbind_from_cpu(cpuinfo);
  469. if (res == 0)
  470. esdp->cpu_id = scheduler2cpu_map[esdp->no].bound_id = -1;
  471. else if (res != -ENOTSUP) {
  472. erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
  473. erts_dsprintf(dsbufp, "Scheduler %d failed to unbind from cpu %d: %s\n",
  474. (int) esdp->no, cpu_id, erl_errno_id(-res));
  475. erts_send_error_to_logger_nogl(dsbufp);
  476. }
  477. }
  478. cgcc = erts_alloc(ERTS_ALC_T_TMP,
  479. (no_cpu_groups_callbacks
  480. * sizeof(erts_cpu_groups_callback_call_t)));
  481. cgcc_ix = 0;
  482. for (cgm = cpu_groups_maps; cgm; cgm = cgm->next) {
  483. for (cgcl = cgm->callback_list; cgcl; cgcl = cgcl->next) {
  484. cgcc[cgcc_ix].callback = cgcl->callback;
  485. cgcc[cgcc_ix].ix = cpu_groups_lookup(cgm, esdp);
  486. cgcc[cgcc_ix].arg = cgcl->arg;
  487. cgcc_ix++;
  488. }
  489. }
  490. ASSERT(no_cpu_groups_callbacks == cgcc_ix);
  491. erts_smp_rwmtx_rwunlock(&cpuinfo_rwmtx);
  492. for (cgcc_ix = 0; cgcc_ix < no_cpu_groups_callbacks; cgcc_ix++)
  493. cgcc[cgcc_ix].callback(0,
  494. esdp,
  495. cgcc[cgcc_ix].ix,
  496. cgcc[cgcc_ix].arg);
  497. erts_free(ERTS_ALC_T_TMP, cgcc);
  498. erts_smp_runq_lock(esdp->run_queue);
  499. }
  500. #ifdef ERTS_SMP
  501. void
  502. erts_sched_init_check_cpu_bind(ErtsSchedulerData *esdp)
  503. {
  504. int cgcc_ix;
  505. erts_cpu_groups_map_t *cgm;
  506. erts_cpu_groups_callback_list_t *cgcl;
  507. erts_cpu_groups_callback_call_t *cgcc;
  508. erts_smp_rwmtx_rlock(&cpuinfo_rwmtx);
  509. cgcc = erts_alloc(ERTS_ALC_T_TMP,
  510. (no_cpu_groups_callbacks
  511. * sizeof(erts_cpu_groups_callback_call_t)));
  512. cgcc_ix = 0;
  513. for (cgm = cpu_groups_maps; cgm; cgm = cgm->next) {
  514. for (cgcl = cgm->callback_list; cgcl; cgcl = cgcl->next) {
  515. cgcc[cgcc_ix].callback = cgcl->callback;
  516. cgcc[cgcc_ix].ix = cpu_groups_lookup(cgm, esdp);
  517. cgcc[cgcc_ix].arg = cgcl->arg;
  518. cgcc_ix++;
  519. }
  520. }
  521. ASSERT(no_cpu_groups_callbacks == cgcc_ix);
  522. erts_smp_rwmtx_runlock(&cpuinfo_rwmtx);
  523. for (cgcc_ix = 0; cgcc_ix < no_cpu_groups_callbacks; cgcc_ix++)
  524. cgcc[cgcc_ix].callback(0,
  525. esdp,
  526. cgcc[cgcc_ix].ix,
  527. cgcc[cgcc_ix].arg);
  528. erts_free(ERTS_ALC_T_TMP, cgcc);
  529. if (esdp->no <= max_main_threads)
  530. erts_thr_set_main_status(1, (int) esdp->no);
  531. }
  532. #endif
  533. static void
  534. write_schedulers_bind_change(erts_cpu_topology_t *cpudata, int size)
  535. {
  536. int s_ix = 1;
  537. int cpu_ix;
  538. ERTS_SMP_LC_ASSERT(erts_lc_rwmtx_is_rwlocked(&cpuinfo_rwmtx));
  539. if (cpu_bind_order != ERTS_CPU_BIND_NONE && size) {
  540. cpu_bind_order_sort(cpudata, size, cpu_bind_order, 1);
  541. for (cpu_ix = 0; cpu_ix < size && cpu_ix < erts_no_schedulers; cpu_ix++)
  542. if (erts_is_cpu_available(cpuinfo, cpudata[cpu_ix].logical))
  543. scheduler2cpu_map[s_ix++].bind_id = cpudata[cpu_ix].logical;
  544. }
  545. if (s_ix <= erts_no_schedulers)
  546. for (; s_ix <= erts_no_schedulers; s_ix++)
  547. scheduler2cpu_map[s_ix].bind_id = -1;
  548. }
  549. int
  550. erts_init_scheduler_bind_type_string(char *how)
  551. {
  552. if (sys_strcmp(how, "u") == 0)
  553. cpu_bind_order = ERTS_CPU_BIND_NONE;
  554. else if (erts_bind_to_cpu(cpuinfo, -1) == -ENOTSUP)
  555. return ERTS_INIT_SCHED_BIND_TYPE_NOT_SUPPORTED;
  556. else if (!system_cpudata && !user_cpudata)
  557. return ERTS_INIT_SCHED_BIND_TYPE_ERROR_NO_CPU_TOPOLOGY;
  558. else if (sys_strcmp(how, "db") == 0)
  559. cpu_bind_order = ERTS_CPU_BIND_DEFAULT_BIND;
  560. else if (sys_strcmp(how, "s") == 0)
  561. cpu_bind_order = ERTS_CPU_BIND_SPREAD;
  562. else if (sys_strcmp(how, "ps") == 0)
  563. cpu_bind_order = ERTS_CPU_BIND_PROCESSOR_SPREAD;
  564. else if (sys_strcmp(how, "ts") == 0)
  565. cpu_bind_order = ERTS_CPU_BIND_THREAD_SPREAD;
  566. else if (sys_strcmp(how, "tnnps") == 0)
  567. cpu_bind_order = ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD;
  568. else if (sys_strcmp(how, "nnps") == 0)
  569. cpu_bind_order = ERTS_CPU_BIND_NO_NODE_PROCESSOR_SPREAD;
  570. else if (sys_strcmp(how, "nnts") == 0)
  571. cpu_bind_order = ERTS_CPU_BIND_NO_NODE_THREAD_SPREAD;
  572. else if (sys_strcmp(how, "ns") == 0)
  573. cpu_bind_order = ERTS_CPU_BIND_NO_SPREAD;
  574. else
  575. return ERTS_INIT_SCHED_BIND_TYPE_ERROR_NO_BAD_TYPE;
  576. return ERTS_INIT_SCHED_BIND_TYPE_SUCCESS;
  577. }
  578. static Eterm
  579. bound_schedulers_term(ErtsCpuBindOrder order)
  580. {
  581. switch (order) {
  582. case ERTS_CPU_BIND_SPREAD: {
  583. ERTS_DECL_AM(spread);
  584. return AM_spread;
  585. }
  586. case ERTS_CPU_BIND_PROCESSOR_SPREAD: {
  587. ERTS_DECL_AM(processor_spread);
  588. return AM_processor_spread;
  589. }
  590. case ERTS_CPU_BIND_THREAD_SPREAD: {
  591. ERTS_DECL_AM(thread_spread);
  592. return AM_thread_spread;
  593. }
  594. case ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD: {
  595. ERTS_DECL_AM(thread_no_node_processor_spread);
  596. return AM_thread_no_node_processor_spread;
  597. }
  598. case ERTS_CPU_BIND_NO_NODE_PROCESSOR_SPREAD: {
  599. ERTS_DECL_AM(no_node_processor_spread);
  600. return AM_no_node_processor_spread;
  601. }
  602. case ERTS_CPU_BIND_NO_NODE_THREAD_SPREAD: {
  603. ERTS_DECL_AM(no_node_thread_spread);
  604. return AM_no_node_thread_spread;
  605. }
  606. case ERTS_CPU_BIND_NO_SPREAD: {
  607. ERTS_DECL_AM(no_spread);
  608. return AM_no_spread;
  609. }
  610. case ERTS_CPU_BIND_NONE: {
  611. ERTS_DECL_AM(unbound);
  612. return AM_unbound;
  613. }
  614. default:
  615. ASSERT(0);
  616. return THE_NON_VALUE;
  617. }
  618. }
  619. Eterm
  620. erts_bound_schedulers_term(Process *c_p)
  621. {
  622. ErtsCpuBindOrder order;
  623. erts_smp_rwmtx_rlock(&cpuinfo_rwmtx);
  624. order = cpu_bind_order;
  625. erts_smp_rwmtx_runlock(&cpuinfo_rwmtx);
  626. return bound_schedulers_term(order);
  627. }
  628. Eterm
  629. erts_bind_schedulers(Process *c_p, Eterm how)
  630. {
  631. int notify = 0;
  632. Eterm res;
  633. erts_cpu_topology_t *cpudata;
  634. int cpudata_size;
  635. ErtsCpuBindOrder old_cpu_bind_order;
  636. erts_smp_rwmtx_rwlock(&cpuinfo_rwmtx);
  637. if (erts_bind_to_cpu(cpuinfo, -1) == -ENOTSUP) {
  638. if (cpu_bind_order == ERTS_CPU_BIND_NONE
  639. && ERTS_IS_ATOM_STR("unbound", how)) {
  640. res = bound_schedulers_term(ERTS_CPU_BIND_NONE);
  641. goto done;
  642. }
  643. ERTS_BIF_PREP_ERROR(res, c_p, EXC_NOTSUP);
  644. }
  645. else {
  646. old_cpu_bind_order = cpu_bind_order;
  647. if (ERTS_IS_ATOM_STR("default_bind", how))
  648. cpu_bind_order = ERTS_CPU_BIND_DEFAULT_BIND;
  649. else if (ERTS_IS_ATOM_STR("spread", how))
  650. cpu_bind_order = ERTS_CPU_BIND_SPREAD;
  651. else if (ERTS_IS_ATOM_STR("processor_spread", how))
  652. cpu_bind_order = ERTS_CPU_BIND_PROCESSOR_SPREAD;
  653. else if (ERTS_IS_ATOM_STR("thread_spread", how))
  654. cpu_bind_order = ERTS_CPU_BIND_THREAD_SPREAD;
  655. else if (ERTS_IS_ATOM_STR("thread_no_node_processor_spread", how))
  656. cpu_bind_order = ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD;
  657. else if (ERTS_IS_ATOM_STR("no_node_processor_spread", how))
  658. cpu_bind_order = ERTS_CPU_BIND_NO_NODE_PROCESSOR_SPREAD;
  659. else if (ERTS_IS_ATOM_STR("no_node_thread_spread", how))
  660. cpu_bind_order = ERTS_CPU_BIND_NO_NODE_THREAD_SPREAD;
  661. else if (ERTS_IS_ATOM_STR("no_spread", how))
  662. cpu_bind_order = ERTS_CPU_BIND_NO_SPREAD;
  663. else if (ERTS_IS_ATOM_STR("unbound", how))
  664. cpu_bind_order = ERTS_CPU_BIND_NONE;
  665. else {
  666. cpu_bind_order = old_cpu_bind_order;
  667. ERTS_BIF_PREP_ERROR(res, c_p, BADARG);
  668. goto done;
  669. }
  670. create_tmp_cpu_topology_copy(&cpudata, &cpudata_size);
  671. if (!cpudata) {
  672. cpu_bind_order = old_cpu_bind_order;
  673. ERTS_BIF_PREP_ERROR(res, c_p, BADARG);
  674. goto done;
  675. }
  676. write_schedulers_bind_change(cpudata, cpudata_size);
  677. notify = 1;
  678. destroy_tmp_cpu_topology_copy(cpudata);
  679. res = bound_schedulers_term(old_cpu_bind_order);
  680. }
  681. done:
  682. erts_smp_rwmtx_rwunlock(&cpuinfo_rwmtx);
  683. if (notify)
  684. erts_sched_notify_check_cpu_bind();
  685. return res;
  686. }
  687. int
  688. erts_sched_bind_atthrcreate_prepare(void)
  689. {
  690. ErtsSchedulerData *esdp = erts_get_scheduler_data();
  691. return esdp != NULL && erts_is_scheduler_bound(esdp);
  692. }
  693. int
  694. erts_sched_bind_atthrcreate_child(int unbind)
  695. {
  696. int res = 0;
  697. if (unbind) {
  698. erts_smp_rwmtx_rlock(&cpuinfo_rwmtx);
  699. res = erts_unbind_from_cpu(cpuinfo);
  700. erts_smp_rwmtx_runlock(&cpuinfo_rwmtx);
  701. }
  702. return res;
  703. }
  704. void
  705. erts_sched_bind_atthrcreate_parent(int unbind)
  706. {
  707. }
  708. int
  709. erts_sched_bind_atfork_prepare(void)
  710. {
  711. ErtsSchedulerData *esdp = erts_get_scheduler_data();
  712. int unbind = esdp != NULL && erts_is_scheduler_bound(esdp);
  713. if (unbind)
  714. erts_smp_rwmtx_rlock(&cpuinfo_rwmtx);
  715. return unbind;
  716. }
  717. int
  718. erts_sched_bind_atfork_child(int unbind)
  719. {
  720. if (unbind) {
  721. ERTS_SMP_LC_ASSERT(erts_lc_rwmtx_is_rlocked(&cpuinfo_rwmtx)
  722. || erts_lc_rwmtx_is_rwlocked(&cpuinfo_rwmtx));
  723. return erts_unbind_from_cpu(cpuinfo);
  724. }
  725. return 0;
  726. }
  727. char *
  728. erts_sched_bind_atvfork_child(int unbind)
  729. {
  730. if (unbind) {
  731. ERTS_SMP_LC_ASSERT(erts_lc_rwmtx_is_rlocked(&cpuinfo_rwmtx)
  732. || erts_lc_rwmtx_is_rwlocked(&cpuinfo_rwmtx));
  733. return erts_get_unbind_from_cpu_str(cpuinfo);
  734. }
  735. return "false";
  736. }
  737. void
  738. erts_sched_bind_atfork_parent(int unbind)
  739. {
  740. if (unbind)
  741. erts_smp_rwmtx_runlock(&cpuinfo_rwmtx);
  742. }
  743. Eterm
  744. erts_fake_scheduler_bindings(Process *p, Eterm how)
  745. {
  746. ErtsCpuBindOrder fake_cpu_bind_order;
  747. erts_cpu_topology_t *cpudata;
  748. int cpudata_size;
  749. Eterm res;
  750. if (ERTS_IS_ATOM_STR("default_bind", how))
  751. fake_cpu_bind_order = ERTS_CPU_BIND_DEFAULT_BIND;
  752. else if (ERTS_IS_ATOM_STR("spread", how))
  753. fake_cpu_bind_order = ERTS_CPU_BIND_SPREAD;
  754. else if (ERTS_IS_ATOM_STR("processor_spread", how))
  755. fake_cpu_bind_order = ERTS_CPU_BIND_PROCESSOR_SPREAD;
  756. else if (ERTS_IS_ATOM_STR("thread_spread", how))
  757. fake_cpu_bind_order = ERTS_CPU_BIND_THREAD_SPREAD;
  758. else if (ERTS_IS_ATOM_STR("thread_no_node_processor_spread", how))
  759. fake_cpu_bind_order = ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD;
  760. else if (ERTS_IS_ATOM_STR("no_node_processor_spread", how))
  761. fake_cpu_bind_order = ERTS_CPU_BIND_NO_NODE_PROCESSOR_SPREAD;
  762. else if (ERTS_IS_ATOM_STR("no_node_thread_spread", how))
  763. fake_cpu_bind_order = ERTS_CPU_BIND_NO_NODE_THREAD_SPREAD;
  764. else if (ERTS_IS_ATOM_STR("no_spread", how))
  765. fake_cpu_bind_order = ERTS_CPU_BIND_NO_SPREAD;
  766. else if (ERTS_IS_ATOM_STR("unbound", how))
  767. fake_cpu_bind_order = ERTS_CPU_BIND_NONE;
  768. else {
  769. ERTS_BIF_PREP_ERROR(res, p, BADARG);
  770. return res;
  771. }
  772. erts_smp_rwmtx_rlock(&cpuinfo_rwmtx);
  773. create_tmp_cpu_topology_copy(&cpudata, &cpudata_size);
  774. erts_smp_rwmtx_runlock(&cpuinfo_rwmtx);
  775. if (!cpudata || fake_cpu_bind_order == ERTS_CPU_BIND_NONE)
  776. ERTS_BIF_PREP_RET(res, am_false);
  777. else {
  778. int i;
  779. Eterm *hp;
  780. cpu_bind_order_sort(cpudata, cpudata_size, fake_cpu_bind_order, 1);
  781. #ifdef ERTS_FAKE_SCHED_BIND_PRINT_SORTED_CPU_DATA
  782. erts_fprintf(stderr, "node: ");
  783. for (i = 0; i < cpudata_size; i++)
  784. erts_fprintf(stderr, " %2d", cpudata[i].node);
  785. erts_fprintf(stderr, "\n");
  786. erts_fprintf(stderr, "processor: ");
  787. for (i = 0; i < cpudata_size; i++)
  788. erts_fprintf(stderr, " %2d", cpudata[i].processor);
  789. erts_fprintf(stderr, "\n");
  790. if (fake_cpu_bind_order != ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD
  791. && fake_cpu_bind_order != ERTS_CPU_BIND_NO_NODE_PROCESSOR_SPREAD
  792. && fake_cpu_bind_order != ERTS_CPU_BIND_NO_NODE_THREAD_SPREAD) {
  793. erts_fprintf(stderr, "processor_node:");
  794. for (i = 0; i < cpudata_size; i++)
  795. erts_fprintf(stderr, " %2d", cpudata[i].processor_node);
  796. erts_fprintf(stderr, "\n");
  797. }
  798. erts_fprintf(stderr, "core: ");
  799. for (i = 0; i < cpudata_size; i++)
  800. erts_fprintf(stderr, " %2d", cpudata[i].core);
  801. erts_fprintf(stderr, "\n");
  802. erts_fprintf(stderr, "thread: ");
  803. for (i = 0; i < cpudata_size; i++)
  804. erts_fprintf(stderr, " %2d", cpudata[i].thread);
  805. erts_fprintf(stderr, "\n");
  806. erts_fprintf(stderr, "logical: ");
  807. for (i = 0; i < cpudata_size; i++)
  808. erts_fprintf(stderr, " %2d", cpudata[i].logical);
  809. erts_fprintf(stderr, "\n");
  810. #endif
  811. hp = HAlloc(p, cpudata_size+1);
  812. ERTS_BIF_PREP_RET(res, make_tuple(hp));
  813. *hp++ = make_arityval((Uint) cpudata_size);
  814. for (i = 0; i < cpudata_size; i++)
  815. *hp++ = make_small((Uint) cpudata[i].logical);
  816. }
  817. destroy_tmp_cpu_topology_copy(cpudata);
  818. return res;
  819. }
  820. Eterm
  821. erts_get_schedulers_binds(Process *c_p)
  822. {
  823. int ix;
  824. ERTS_DECL_AM(unbound);
  825. Eterm *hp = HAlloc(c_p, erts_no_schedulers+1);
  826. Eterm res = make_tuple(hp);
  827. *(hp++) = make_arityval(erts_no_schedulers);
  828. erts_smp_rwmtx_rlock(&cpuinfo_rwmtx);
  829. for (ix = 1; ix <= erts_no_schedulers; ix++)
  830. *(hp++) = (scheduler2cpu_map[ix].bound_id >= 0
  831. ? make_small(scheduler2cpu_map[ix].bound_id)
  832. : AM_unbound);
  833. erts_smp_rwmtx_runlock(&cpuinfo_rwmtx);
  834. return res;
  835. }
  836. /*
  837. * CPU topology
  838. */
  839. typedef struct {
  840. int *id;
  841. int used;
  842. int size;
  843. } ErtsCpuTopIdSeq;
  844. typedef struct {
  845. ErtsCpuTopIdSeq logical;
  846. ErtsCpuTopIdSeq thread;
  847. ErtsCpuTopIdSeq core;
  848. ErtsCpuTopIdSeq processor_node;
  849. ErtsCpuTopIdSeq processor;
  850. ErtsCpuTopIdSeq node;
  851. } ErtsCpuTopEntry;
  852. static void
  853. init_cpu_top_entry(ErtsCpuTopEntry *cte)
  854. {
  855. int size = 10;
  856. cte->logical.id = erts_alloc(ERTS_ALC_T_TMP_CPU_IDS,
  857. sizeof(int)*size);
  858. cte->logical.size = size;
  859. cte->thread.id = erts_alloc(ERTS_ALC_T_TMP_CPU_IDS,
  860. sizeof(int)*size);
  861. cte->thread.size = size;
  862. cte->core.id = erts_alloc(ERTS_ALC_T_TMP_CPU_IDS,
  863. sizeof(int)*size);
  864. cte->core.size = size;
  865. cte->processor_node.id = erts_alloc(ERTS_ALC_T_TMP_CPU_IDS,
  866. sizeof(int)*size);
  867. cte->processor_node.size = size;
  868. cte->processor.id = erts_alloc(ERTS_ALC_T_TMP_CPU_IDS,
  869. sizeof(int)*size);
  870. cte->processor.size = size;
  871. cte->node.id = erts_alloc(ERTS_ALC_T_TMP_CPU_IDS,
  872. sizeof(int)*size);
  873. cte->node.size = size;
  874. }
  875. static void
  876. destroy_cpu_top_entry(ErtsCpuTopEntry *cte)
  877. {
  878. erts_free(ERTS_ALC_T_TMP_CPU_IDS, cte->logical.id);
  879. erts_free(ERTS_ALC_T_TMP_CPU_IDS, cte->thread.id);
  880. erts_free(ERTS_ALC_T_TMP_CPU_IDS, cte->core.id);
  881. erts_free(ERTS_ALC_T_TMP_CPU_IDS, cte->processor_node.id);
  882. erts_free(ERTS_ALC_T_TMP_CPU_IDS, cte->processor.id);
  883. erts_free(ERTS_ALC_T_TMP_CPU_IDS, cte->node.id);
  884. }
  885. static int
  886. get_cput_value_or_range(int *v, int *vr, char **str)
  887. {
  888. long l;
  889. char *c = *str;
  890. errno = 0;
  891. if (!isdigit((unsigned char)*c))
  892. return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID;
  893. l = strtol(c, &c, 10);
  894. if (errno != 0 || l < 0 || ERTS_MAX_CPU_TOPOLOGY_ID < l)
  895. return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID;
  896. *v = (int) l;
  897. if (*c == '-') {
  898. c++;
  899. if (!isdigit((unsigned char)*c))
  900. return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE;
  901. l = strtol(c, &c, 10);
  902. if (errno != 0 || l < 0 || ERTS_MAX_CPU_TOPOLOGY_ID < l)
  903. return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE;
  904. *vr = (int) l;
  905. }
  906. *str = c;
  907. return ERTS_INIT_CPU_TOPOLOGY_OK;
  908. }
  909. static int
  910. get_cput_id_seq(ErtsCpuTopIdSeq *idseq, char **str)
  911. {
  912. int ix = 0;
  913. int need_size = 0;
  914. char *c = *str;
  915. while (1) {
  916. int res;
  917. int val;
  918. int nids;
  919. int val_range = -1;
  920. res = get_cput_value_or_range(&val, &val_range, &c);
  921. if (res != ERTS_INIT_CPU_TOPOLOGY_OK)
  922. return res;
  923. if (val_range < 0 || val_range == val)
  924. nids = 1;
  925. else {
  926. if (val_range > val)
  927. nids = val_range - val + 1;
  928. else
  929. nids = val - val_range + 1;
  930. }
  931. need_size += nids;
  932. if (need_size > idseq->size) {
  933. idseq->size = need_size + 10;
  934. idseq->id = erts_realloc(ERTS_ALC_T_TMP_CPU_IDS,
  935. idseq->id,
  936. sizeof(int)*idseq->size);
  937. }
  938. if (nids == 1)
  939. idseq->id[ix++] = val;
  940. else if (val_range > val) {
  941. for (; val <= val_range; val++)
  942. idseq->id[ix++] = val;
  943. }
  944. else {
  945. for (; val >= val_range; val--)
  946. idseq->id[ix++] = val;
  947. }
  948. if (*c != ',')
  949. break;
  950. c++;
  951. }
  952. *str = c;
  953. idseq->used = ix;
  954. return ERTS_INIT_CPU_TOPOLOGY_OK;
  955. }
  956. static int
  957. get_cput_entry(ErtsCpuTopEntry *cput, char **str)
  958. {
  959. int h;
  960. char *c = *str;
  961. cput->logical.used = 0;
  962. cput->thread.id[0] = 0;
  963. cput->thread.used = 1;
  964. cput->core.id[0] = 0;
  965. cput->core.used = 1;
  966. cput->processor_node.id[0] = -1;
  967. cput->processor_node.used = 1;
  968. cput->processor.id[0] = 0;
  969. cput->processor.used = 1;
  970. cput->node.id[0] = -1;
  971. cput->node.used = 1;
  972. h = ERTS_TOPOLOGY_MAX_DEPTH;
  973. while (*c != ':' && *c != '\0') {
  974. int res;
  975. ErtsCpuTopIdSeq *idseqp;
  976. switch (*c++) {
  977. case 'L':
  978. if (h <= ERTS_TOPOLOGY_LOGICAL)
  979. return ERTS_INIT_CPU_TOPOLOGY_INVALID_HIERARCHY;
  980. idseqp = &cput->logical;
  981. h = ERTS_TOPOLOGY_LOGICAL;
  982. break;
  983. case 't':
  984. case 'T':
  985. if (h <= ERTS_TOPOLOGY_THREAD)
  986. return ERTS_INIT_CPU_TOPOLOGY_INVALID_HIERARCHY;
  987. idseqp = &cput->thread;
  988. h = ERTS_TOPOLOGY_THREAD;
  989. break;
  990. case 'c':
  991. case 'C':
  992. if (h <= ERTS_TOPOLOGY_CORE)
  993. return ERTS_INIT_CPU_TOPOLOGY_INVALID_HIERARCHY;
  994. idseqp = &cput->core;
  995. h = ERTS_TOPOLOGY_CORE;
  996. break;
  997. case 'p':
  998. case 'P':
  999. if (h <= ERTS_TOPOLOGY_PROCESSOR)
  1000. return ERTS_INIT_CPU_TOPOLOGY_INVALID_HIERARCHY;
  1001. idseqp = &cput->processor;
  1002. h = ERTS_TOPOLOGY_PROCESSOR;
  1003. break;
  1004. case 'n':
  1005. case 'N':
  1006. if (h <= ERTS_TOPOLOGY_PROCESSOR) {
  1007. do_node:
  1008. if (h <= ERTS_TOPOLOGY_NODE)
  1009. return ERTS_INIT_CPU_TOPOLOGY_INVALID_HIERARCHY;
  1010. idseqp = &cput->node;
  1011. h = ERTS_TOPOLOGY_NODE;
  1012. }
  1013. else {
  1014. int p_node = 0;
  1015. char *p_chk = c;
  1016. while (*p_chk != '\0' && *p_chk != ':') {
  1017. if (*p_chk == 'p' || *p_chk == 'P') {
  1018. p_node = 1;
  1019. break;
  1020. }
  1021. p_chk++;
  1022. }
  1023. if (!p_node)
  1024. goto do_node;
  1025. if (h <= ERTS_TOPOLOGY_PROCESSOR_NODE)
  1026. return ERTS_INIT_CPU_TOPOLOGY_INVALID_HIERARCHY;
  1027. idseqp = &cput->processor_node;
  1028. h = ERTS_TOPOLOGY_PROCESSOR_NODE;
  1029. }
  1030. break;
  1031. default:
  1032. return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_TYPE;
  1033. }
  1034. res = get_cput_id_seq(idseqp, &c);
  1035. if (res != ERTS_INIT_CPU_TOPOLOGY_OK)
  1036. return res;
  1037. }
  1038. if (cput->logical.used < 1)
  1039. return ERTS_INIT_CPU_TOPOLOGY_MISSING_LID;
  1040. if (*c == ':') {
  1041. c++;
  1042. }
  1043. if (cput->thread.used != 1
  1044. && cput->thread.used != cput->logical.used)
  1045. return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE;
  1046. if (cput->core.used != 1
  1047. && cput->core.used != cput->logical.used)
  1048. return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE;
  1049. if (cput->processor_node.used != 1
  1050. && cput->processor_node.used != cput->logical.used)
  1051. return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE;
  1052. if (cput->processor.used != 1
  1053. && cput->processor.used != cput->logical.used)
  1054. return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE;
  1055. if (cput->node.used != 1
  1056. && cput->node.used != cput->logical.used)
  1057. return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE;
  1058. *str = c;
  1059. return ERTS_INIT_CPU_TOPOLOGY_OK;
  1060. }
  1061. static int
  1062. verify_topology(erts_cpu_topology_t *cpudata, int size)
  1063. {
  1064. if (size > 0) {
  1065. int *logical;
  1066. int node, processor, no_nodes, i;
  1067. /* Verify logical ids */
  1068. logical = erts_alloc(ERTS_ALC_T_TMP, sizeof(int)*size);
  1069. for (i = 0; i < size; i++)
  1070. logical[i] = cpudata[i].logical;
  1071. qsort(logical, size, sizeof(int), int_cmp);
  1072. for (i = 0; i < size-1; i++) {
  1073. if (logical[i] == logical[i+1]) {
  1074. erts_free(ERTS_ALC_T_TMP, logical);
  1075. return ERTS_INIT_CPU_TOPOLOGY_NOT_UNIQUE_LIDS;
  1076. }
  1077. }
  1078. erts_free(ERTS_ALC_T_TMP, logical);
  1079. qsort(cpudata, size, sizeof(erts_cpu_topology_t), processor_order_cmp);
  1080. /* Verify unique entities */
  1081. for (i = 1; i < size; i++) {
  1082. if (cpudata[i-1].processor == cpudata[i].processor
  1083. && cpudata[i-1].node == cpudata[i].node
  1084. && (cpudata[i-1].processor_node
  1085. == cpudata[i].processor_node)
  1086. && cpudata[i-1].core == cpudata[i].core
  1087. && cpudata[i-1].thread == cpudata[i].thread) {
  1088. return ERTS_INIT_CPU_TOPOLOGY_NOT_UNIQUE_ENTITIES;
  1089. }
  1090. }
  1091. /* Verify numa nodes */
  1092. node = cpudata[0].node;
  1093. processor = cpudata[0].processor;
  1094. no_nodes = cpudata[0].node < 0 && cpudata[0].processor_node < 0;
  1095. for (i = 1; i < size; i++) {
  1096. if (no_nodes) {
  1097. if (cpudata[i].node >= 0 || cpudata[i].processor_node >= 0)
  1098. return ERTS_INIT_CPU_TOPOLOGY_INVALID_NODES;
  1099. }
  1100. else {
  1101. if (cpudata[i].processor == processor && cpudata[i].node != node)
  1102. return ERTS_INIT_CPU_TOPOLOGY_INVALID_NODES;
  1103. node = cpudata[i].node;
  1104. processor = cpudata[i].processor;
  1105. if (node >= 0 && cpudata[i].processor_node >= 0)
  1106. return ERTS_INIT_CPU_TOPOLOGY_INVALID_NODES;
  1107. if (node < 0 && cpudata[i].processor_node < 0)
  1108. return ERTS_INIT_CPU_TOPOLOGY_INVALID_NODES;
  1109. }
  1110. }
  1111. }
  1112. return ERTS_INIT_CPU_TOPOLOGY_OK;
  1113. }
  1114. int
  1115. erts_init_cpu_topology_string(char *topology_str)
  1116. {
  1117. ErtsCpuTopEntry cput;
  1118. int need_size;
  1119. char *c;
  1120. int ix;
  1121. int error = ERTS_INIT_CPU_TOPOLOGY_OK;
  1122. if (user_cpudata)
  1123. erts_free(ERTS_ALC_T_CPUDATA, user_cpudata);
  1124. user_cpudata_size = 10;
  1125. user_cpudata = erts_alloc(ERTS_ALC_T_CPUDATA,
  1126. (sizeof(erts_cpu_topology_t)
  1127. * user_cpudata_size));
  1128. init_cpu_top_entry(&cput);
  1129. ix = 0;
  1130. need_size = 0;
  1131. c = topology_str;
  1132. if (*c == '\0') {
  1133. error = ERTS_INIT_CPU_TOPOLOGY_MISSING;
  1134. goto fail;
  1135. }
  1136. do {
  1137. int r;
  1138. error = get_cput_entry(&cput, &c);
  1139. if (error != ERTS_INIT_CPU_TOPOLOGY_OK)
  1140. goto fail;
  1141. need_size += cput.logical.used;
  1142. if (user_cpudata_size < need_size) {
  1143. user_cpudata_size = need_size + 10;
  1144. user_cpudata = erts_realloc(ERTS_ALC_T_CPUDATA,
  1145. user_cpudata,
  1146. (sizeof(erts_cpu_topology_t)
  1147. * user_cpudata_size));
  1148. }
  1149. ASSERT(cput.thread.used == 1
  1150. || cput.thread.used == cput.logical.used);
  1151. ASSERT(cput.core.used == 1
  1152. || cput.core.used == cput.logical.used);
  1153. ASSERT(cput.processor_node.used == 1
  1154. || cput.processor_node.used == cput.logical.used);
  1155. ASSERT(cput.processor.used == 1
  1156. || cput.processor.used == cput.logical.used);
  1157. ASSERT(cput.node.used == 1
  1158. || cput.node.used == cput.logical.used);
  1159. for (r = 0; r < cput.logical.used; r++) {
  1160. user_cpudata[ix].logical = cput.logical.id[r];
  1161. user_cpudata[ix].thread =
  1162. cput.thread.id[cput.thread.used == 1 ? 0 : r];
  1163. user_cpudata[ix].core =
  1164. cput.core.id[cput.core.used == 1 ? 0 : r];
  1165. user_cpudata[ix].processor_node =
  1166. cput.processor_node.id[cput.processor_node.used == 1 ? 0 : r];
  1167. user_cpudata[ix].processor =
  1168. cput.processor.id[cput.processor.used == 1 ? 0 : r];
  1169. user_cpudata[ix].node =
  1170. cput.node.id[cput.node.used == 1 ? 0 : r];
  1171. ix++;
  1172. }
  1173. } while (*c != '\0');
  1174. if (user_cpudata_size != ix) {
  1175. user_cpudata_size = ix;
  1176. user_cpudata = erts_realloc(ERTS_ALC_T_CPUDATA,
  1177. user_cpudata,
  1178. (sizeof(erts_cpu_topology_t)
  1179. * user_cpudata_size));
  1180. }
  1181. error = verify_topology(user_cpudata, user_cpudata_size);
  1182. if (error == ERTS_INIT_CPU_TOPOLOGY_OK) {
  1183. destroy_cpu_top_entry(&cput);
  1184. return ERTS_INIT_CPU_TOPOLOGY_OK;
  1185. }
  1186. fail:
  1187. if (user_cpudata)
  1188. erts_free(ERTS_ALC_T_CPUDATA, user_cpudata);
  1189. user_cpudata_size = 0;
  1190. destroy_cpu_top_entry(&cput);
  1191. return error;
  1192. }
  1193. #define ERTS_GET_CPU_TOPOLOGY_ERROR -1
  1194. #define ERTS_GET_USED_CPU_TOPOLOGY 0
  1195. #define ERTS_GET_DETECTED_CPU_TOPOLOGY 1
  1196. #define ERTS_GET_DEFINED_CPU_TOPOLOGY 2
  1197. static Eterm get_cpu_topology_term(Process *c_p, int type);
  1198. Eterm
  1199. erts_set_cpu_topology(Process *c_p, Eterm term)
  1200. {
  1201. erts_cpu_topology_t *cpudata = NULL;
  1202. int cpudata_size = 0;
  1203. Eterm res;
  1204. erts_smp_rwmtx_rwlock(&cpuinfo_rwmtx);
  1205. res = get_cpu_topology_term(c_p, ERTS_GET_USED_CPU_TOPOLOGY);
  1206. if (term == am_undefined) {
  1207. if (user_cpudata)
  1208. erts_free(ERTS_ALC_T_CPUDATA, user_cpudata);
  1209. user_cpudata = NULL;
  1210. user_cpudata_size = 0;
  1211. if (cpu_bind_order != ERTS_CPU_BIND_NONE && system_cpudata) {
  1212. cpudata_size = system_cpudata_size;
  1213. cpudata = erts_alloc(ERTS_ALC_T_TMP,
  1214. (sizeof(erts_cpu_topology_t)
  1215. * cpudata_size));
  1216. sys_memcpy((void *) cpudata,
  1217. (void *) system_cpudata,
  1218. sizeof(erts_cpu_topology_t)*cpudata_size);
  1219. }
  1220. }
  1221. else if (is_not_list(term)) {
  1222. error:
  1223. erts_smp_rwmtx_rwunlock(&cpuinfo_rwmtx);
  1224. res = THE_NON_VALUE;
  1225. goto done;
  1226. }
  1227. else {
  1228. Eterm list = term;
  1229. int ix = 0;
  1230. cpudata_size = 100;
  1231. cpudata = erts_alloc(ERTS_ALC_T_TMP,
  1232. (sizeof(erts_cpu_topology_t)
  1233. * cpudata_size));
  1234. while (is_list(list)) {
  1235. Eterm *lp = list_val(list);
  1236. Eterm cpu = CAR(lp);
  1237. Eterm* tp;
  1238. Sint id;
  1239. if (is_not_tuple(cpu))
  1240. goto error;
  1241. tp = tuple_val(cpu);
  1242. if (arityval(tp[0]) != 7 || tp[1] != am_cpu)
  1243. goto error;
  1244. if (ix >= cpudata_size) {
  1245. cpudata_size += 100;
  1246. cpudata = erts_realloc(ERTS_ALC_T_TMP,
  1247. cpudata,
  1248. (sizeof(erts_cpu_topology_t)
  1249. * cpudata_size));
  1250. }
  1251. id = signed_val(tp[2]);
  1252. if (id < -1 || ERTS_MAX_CPU_TOPOLOGY_ID < id)
  1253. goto error;
  1254. cpudata[ix].node = (int) id;
  1255. id = signed_val(tp[3]);
  1256. if (id < -1 || ERTS_MAX_CPU_TOPOLOGY_ID < id)
  1257. goto error;
  1258. cpudata[ix].processor = (int) id;
  1259. id = signed_val(tp[4]);
  1260. if (id < -1 || ERTS_MAX_CPU_TOPOLOGY_ID < id)
  1261. goto error;
  1262. cpudata[ix].processor_node = (int) id;
  1263. id = signed_val(tp[5]);
  1264. if (id < -1 || ERTS_MAX_CPU_TOPOLOGY_ID < id)
  1265. goto error;
  1266. cpudata[ix].core = (int) id;
  1267. id = signed_val(tp[6]);
  1268. if (id < -1 || ERTS_MAX_CPU_TOPOLOGY_ID < id)
  1269. goto error;
  1270. cpudata[ix].thread = (int) id;
  1271. id = signed_val(tp[7]);
  1272. if (id < -1 || ERTS_MAX_CPU_TOPOLOGY_ID < id)
  1273. goto error;
  1274. cpudata[ix].logical = (int) id;
  1275. list = CDR(lp);
  1276. ix++;
  1277. }
  1278. if (is_not_nil(list))
  1279. goto error;
  1280. cpudata_size = ix;
  1281. if (ERTS_INIT_CPU_TOPOLOGY_OK != verify_topology(cpudata, cpudata_size))
  1282. goto error;
  1283. if (user_cpudata_size != cpudata_size) {
  1284. if (user_cpudata)
  1285. erts_free(ERTS_ALC_T_CPUDATA, user_cpudata);
  1286. user_cpudata = erts_alloc(ERTS_ALC_T_CPUDATA,
  1287. sizeof(erts_cpu_topology_t)*cpudata_size);
  1288. user_cpudata_size = cpudata_size;
  1289. }
  1290. sys_memcpy((void *) user_cpudata,
  1291. (void *) cpudata,
  1292. sizeof(erts_cpu_topology_t)*cpudata_size);
  1293. }
  1294. update_cpu_groups_maps();
  1295. write_schedulers_bind_change(cpudata, cpudata_size);
  1296. erts_smp_rwmtx_rwunlock(&cpuinfo_rwmtx);
  1297. erts_sched_notify_check_cpu_bind();
  1298. done:
  1299. if (cpudata)
  1300. erts_free(ERTS_ALC_T_TMP, cpudata);
  1301. return res;
  1302. }
  1303. static void
  1304. create_tmp_cpu_topology_copy(erts_cpu_topology_t **cpudata, int *cpudata_size)
  1305. {
  1306. if (user_cpudata) {
  1307. *cpudata_size = user_cpudata_size;
  1308. *cpudata = erts_alloc(ERTS_ALC_T_TMP,
  1309. (sizeof(erts_cpu_topology_t)
  1310. * (*cpudata_size)));
  1311. sys_memcpy((void *) *cpudata,
  1312. (void *) user_cpudata,
  1313. sizeof(erts_cpu_topology_t)*(*cpudata_size));
  1314. }
  1315. else if (system_cpudata) {
  1316. *cpudata_size = system_cpudata_size;
  1317. *cpudata = erts_alloc(ERTS_ALC_T_TMP,
  1318. (sizeof(erts_cpu_topology_t)
  1319. * (*cpudata_size)));
  1320. sys_memcpy((void *) *cpudata,
  1321. (void *) system_cpudata,
  1322. sizeof(erts_cpu_topology_t)*(*cpudata_size));
  1323. }
  1324. else {
  1325. *cpudata = NULL;
  1326. *cpudata_size = 0;
  1327. }
  1328. }
  1329. static void
  1330. destroy_tmp_cpu_topology_copy(erts_cpu_topology_t *cpudata)
  1331. {
  1332. if (cpudata)
  1333. erts_free(ERTS_ALC_T_TMP, cpudata);
  1334. }
  1335. static Eterm
  1336. bld_topology_term(Eterm **hpp,
  1337. Uint *hszp,
  1338. erts_cpu_topology_t *cpudata,
  1339. int size)
  1340. {
  1341. Eterm res = NIL;
  1342. int i;
  1343. if (size == 0)
  1344. return am_undefined;
  1345. for (i = size-1; i >= 0; i--) {
  1346. res = erts_bld_cons(hpp,
  1347. hszp,
  1348. erts_bld_tuple(hpp,
  1349. hszp,
  1350. 7,
  1351. am_cpu,
  1352. make_small(cpudata[i].node),
  1353. make_small(cpudata[i].processor),
  1354. make_small(cpudata[i].processor_node),
  1355. make_small(cpudata[i].core),
  1356. make_small(cpudata[i].thread),
  1357. make_small(cpudata[i].logical)),
  1358. res);
  1359. }
  1360. return res;
  1361. }
  1362. static Eterm
  1363. get_cpu_topology_term(Process *c_p, int type)
  1364. {
  1365. #ifdef DEBUG
  1366. Eterm *hp_end;
  1367. #endif
  1368. Eterm *hp;
  1369. Uint hsz;
  1370. Eterm res = THE_NON_VALUE;
  1371. erts_cpu_topology_t *cpudata = NULL;
  1372. int size = 0;
  1373. switch (type) {
  1374. case ERTS_GET_USED_CPU_TOPOLOGY:
  1375. if (user_cpudata)
  1376. goto defined;
  1377. else
  1378. goto detected;
  1379. case ERTS_GET_DETECTED_CPU_TOPOLOGY:
  1380. detected:
  1381. if (!system_cpudata)
  1382. res = am_undefined;
  1383. else {
  1384. size = system_cpudata_size;
  1385. cpudata = erts_alloc(ERTS_ALC_T_TMP,
  1386. (sizeof(erts_cpu_topology_t)
  1387. * size));
  1388. sys_memcpy((void *) cpudata,
  1389. (void *) system_cpudata,
  1390. sizeof(erts_cpu_topology_t)*size);
  1391. }
  1392. break;
  1393. case ERTS_GET_DEFINED_CPU_TOPOLOGY:
  1394. defined:
  1395. if (!user_cpudata)
  1396. res = am_undefined;
  1397. else {
  1398. size = user_cpudata_size;
  1399. cpudata = user_cpudata;
  1400. }
  1401. break;
  1402. default:
  1403. erl_exit(ERTS_ABORT_EXIT, "Bad cpu topology type: %d\n", type);
  1404. break;
  1405. }
  1406. if (res == am_undefined) {
  1407. ASSERT(!cpudata);
  1408. return res;
  1409. }
  1410. hsz = 0;
  1411. bld_topology_term(NULL, &hsz,
  1412. cpudata, size);
  1413. hp = HAlloc(c_p, hsz);
  1414. #ifdef DEBUG
  1415. hp_end = hp + hsz;
  1416. #endif
  1417. res = bld_topology_term(&hp, NULL,
  1418. cpudata, size);
  1419. ASSERT(hp_end == hp);
  1420. if (cpudata && cpudata != system_cpudata && cpudata != user_cpudata)
  1421. erts_free(ERTS_ALC_T_TMP, cpudata);
  1422. return res;
  1423. }
  1424. Eterm
  1425. erts_get_cpu_topology_term(Process *c_p, Eterm which)
  1426. {
  1427. Eterm res;
  1428. int type;
  1429. erts_smp_rwmtx_rlock(&cpuinfo_rwmtx);
  1430. if (ERTS_IS_ATOM_STR("used", which))
  1431. type = ERTS_GET_USED_CPU_TOPOLOGY;
  1432. else if (ERTS_IS_ATOM_STR("detected", which))
  1433. type = ERTS_GET_DETECTED_CPU_TOPOLOGY;
  1434. else if (ERTS_IS_ATOM_STR("defined", which))
  1435. type = ERTS_GET_DEFINED_CPU_TOPOLOGY;
  1436. else
  1437. type = ERTS_GET_CPU_TOPOLOGY_ERROR;
  1438. if (type == ERTS_GET_CPU_TOPOLOGY_ERROR)
  1439. res = THE_NON_VALUE;
  1440. else
  1441. res = get_cpu_topology_term(c_p, type);
  1442. erts_smp_rwmtx_runlock(&cpuinfo_rwmtx);
  1443. return res;
  1444. }
  1445. static void
  1446. get_logical_processors(int *conf, int *onln, int *avail)
  1447. {
  1448. if (conf)
  1449. *conf = erts_get_cpu_configured(cpuinfo);
  1450. if (onln)
  1451. *onln = erts_get_cpu_online(cpuinfo);
  1452. if (avail)
  1453. *avail = erts_get_cpu_available(cpuinfo);
  1454. }
  1455. void
  1456. erts_get_logical_processors(int *conf, int *onln, int *avail)
  1457. {
  1458. erts_smp_rwmtx_rlock(&cpuinfo_rwmtx);
  1459. get_logical_processors(conf, onln, avail);
  1460. erts_smp_rwmtx_runlock(&cpuinfo_rwmtx);
  1461. }
  1462. void
  1463. erts_pre_early_init_cpu_topology(int *max_rg_p,
  1464. int *conf_p,
  1465. int *onln_p,
  1466. int *avail_p)
  1467. {
  1468. cpu_groups_maps = NULL;
  1469. no_cpu_groups_callbacks = 0;
  1470. *max_rg_p = ERTS_MAX_READER_GROUPS;
  1471. cpuinfo = erts_cpu_info_create();
  1472. get_logical_processors(conf_p, onln_p, avail_p);
  1473. }
  1474. void
  1475. erts_early_init_cpu_topology(int no_schedulers,
  1476. int *max_main_threads_p,
  1477. int max_reader_groups,
  1478. int *reader_groups_p)
  1479. {
  1480. user_cpudata = NULL;
  1481. user_cpudata_size = 0;
  1482. system_cpudata_size = erts_get_cpu_topology_size(cpuinfo);
  1483. system_cpudata = erts_alloc(ERTS_ALC_T_CPUDATA,
  1484. (sizeof(erts_cpu_topology_t)
  1485. * system_cpudata_size));
  1486. cpu_bind_order = ERTS_CPU_BIND_UNDEFINED;
  1487. if (!erts_get_cpu_topology(cpuinfo, system_cpudata)
  1488. || ERTS_INIT_CPU_TOPOLOGY_OK != verify_topology(system_cpudata,
  1489. system_cpudata_size)) {
  1490. erts_free(ERTS_ALC_T_CPUDATA, system_cpudata);
  1491. system_cpudata = NULL;
  1492. system_cpudata_size = 0;
  1493. }
  1494. max_main_threads = erts_get_cpu_configured(cpuinfo);
  1495. if (max_main_threads > no_schedulers)
  1496. max_main_threads = no_schedulers;
  1497. *max_main_threads_p = max_main_threads;
  1498. reader_groups = max_main_threads;
  1499. if (reader_groups <= 1 || max_reader_groups <= 1)
  1500. reader_groups = 0;
  1501. if (reader_groups > max_reader_groups)
  1502. reader_groups = max_reader_groups;
  1503. *reader_groups_p = reader_groups;
  1504. }
  1505. void
  1506. erts_init_cpu_topology(void)
  1507. {
  1508. int ix;
  1509. erts_smp_rwmtx_init(&cpuinfo_rwmtx, "cpu_info");
  1510. erts_smp_rwmtx_rwlock(&cpuinfo_rwmtx);
  1511. scheduler2cpu_map = erts_alloc(ERTS_ALC_T_CPUDATA,
  1512. (sizeof(ErtsCpuBindData)
  1513. * (erts_no_schedulers+1)));
  1514. for (ix = 1; ix <= erts_no_schedulers; ix++) {
  1515. scheduler2cpu_map[ix].bind_id = -1;
  1516. scheduler2cpu_map[ix].bound_id = -1;
  1517. }
  1518. if (cpu_bind_order == ERTS_CPU_BIND_UNDEFINED) {
  1519. int ncpus = erts_get_cpu_configured(cpuinfo);
  1520. if (ncpus < 1 || erts_no_schedulers < ncpus)
  1521. cpu_bind_order = ERTS_CPU_BIND_NONE;
  1522. else
  1523. cpu_bind_order = ((system_cpudata || user_cpudata)
  1524. && (erts_bind_to_cpu(cpuinfo, -1) != -ENOTSUP)
  1525. ? ERTS_CPU_BIND_DEFAULT_BIND
  1526. : ERTS_CPU_BIND_NONE);
  1527. }
  1528. reader_groups_map = add_cpu_groups(reader_groups,
  1529. reader_groups_callback,
  1530. NULL);
  1531. if (cpu_bind_order == ERTS_CPU_BIND_NONE)
  1532. erts_smp_rwmtx_rwunlock(&cpuinfo_rwmtx);
  1533. else {
  1534. erts_cpu_topology_t *cpudata;
  1535. int cpudata_size;
  1536. create_tmp_cpu_topology_copy(&cpudata, &cpudata_size);
  1537. write_schedulers_bind_change(cpudata, cpudata_size);
  1538. erts_smp_rwmtx_rwunlock(&cpuinfo_rwmtx);
  1539. erts_sched_notify_check_cpu_bind();
  1540. destroy_tmp_cpu_topology_copy(cpudata);
  1541. }
  1542. }
  1543. int
  1544. erts_update_cpu_info(void)
  1545. {
  1546. int changed;
  1547. erts_smp_rwmtx_rwlock(&cpuinfo_rwmtx);
  1548. changed = erts_cpu_info_update(cpuinfo);
  1549. if (changed) {
  1550. erts_cpu_topology_t *cpudata;
  1551. int cpudata_size;
  1552. if (system_cpudata)
  1553. erts_free(ERTS_ALC_T_CPUDATA, system_cpudata);
  1554. system_cpudata_size = erts_get_cpu_topology_size(cpuinfo);
  1555. if (!system_cpudata_size)
  1556. system_cpudata = NULL;
  1557. else {
  1558. system_cpudata = erts_alloc(ERTS_ALC_T_CPUDATA,
  1559. (sizeof(erts_cpu_topology_t)
  1560. * system_cpudata_size));
  1561. if (!erts_get_cpu_topology(cpuinfo, system_cpudata)
  1562. || (ERTS_INIT_CPU_TOPOLOGY_OK
  1563. != verify_topology(system_cpudata,
  1564. system_cpudata_size))) {
  1565. erts_free(ERTS_ALC_T_CPUDATA, system_cpudata);
  1566. system_cpudata = NULL;
  1567. system_cpudata_size = 0;
  1568. }
  1569. }
  1570. update_cpu_groups_maps();
  1571. create_tmp_cpu_topology_copy(&cpudata, &cpudata_size);
  1572. write_schedulers_bind_change(cpudata, cpudata_size);
  1573. destroy_tmp_cpu_topology_copy(cpudata);
  1574. }
  1575. erts_smp_rwmtx_rwunlock(&cpuinfo_rwmtx);
  1576. if (changed)
  1577. erts_sched_notify_check_cpu_bind();
  1578. return changed;
  1579. }
  1580. /*
  1581. * reader groups map
  1582. */
  1583. void
  1584. reader_groups_callback(int suspending,
  1585. ErtsSchedulerData *esdp,
  1586. int group,
  1587. void *unused)
  1588. {
  1589. if (reader_groups && esdp->no <= max_main_threads)
  1590. erts_smp_rwmtx_set_reader_group(suspending ? 0 : group+1);
  1591. }
  1592. static Eterm get_cpu_groups_map(Process *c_p,
  1593. erts_cpu_groups_map_t *map,
  1594. int offset);
  1595. Eterm
  1596. erts_debug_reader_groups_map(Process *c_p, int groups)
  1597. {
  1598. Eterm res;
  1599. erts_cpu_groups_map_t test;
  1600. test.array = NULL;
  1601. test.groups = groups;
  1602. make_cpu_groups_map(&test, 1);
  1603. if (!test.array)
  1604. res = NIL;
  1605. else {
  1606. res = get_cpu_groups_map(c_p, &test, 1);
  1607. erts_free(ERTS_ALC_T_TMP, test.array);
  1608. }
  1609. return res;
  1610. }
  1611. Eterm
  1612. erts_get_reader_groups_map(Process *c_p)
  1613. {
  1614. Eterm res;
  1615. erts_smp_rwmtx_rlock(&cpuinfo_rwmtx);
  1616. res = get_cpu_groups_map(c_p, reader_groups_map, 1);
  1617. erts_smp_rwmtx_runlock(&cpuinfo_rwmtx);
  1618. return res;
  1619. }
  1620. /*
  1621. * CPU groups
  1622. */
  1623. static Eterm
  1624. get_cpu_groups_map(Process *c_p,
  1625. erts_cpu_groups_map_t *map,
  1626. int offset)
  1627. {
  1628. #ifdef DEBUG
  1629. Eterm *endp;
  1630. #endif
  1631. Eterm res = NIL, tuple;
  1632. Eterm *hp;
  1633. int i;
  1634. hp = HAlloc(c_p, map->logical_processors*(2+3));
  1635. #ifdef DEBUG
  1636. endp = hp + map->logical_processors*(2+3);
  1637. #endif
  1638. for (i = map->size - 1; i >= 0; i--) {
  1639. if (map->array[i].logical >= 0) {
  1640. tuple = TUPLE2(hp,
  1641. make_small(map->array[i].logical),
  1642. make_small(map->array[i].cpu_group + offset));
  1643. hp += 3;
  1644. res = CONS(hp, tuple, res);
  1645. hp += 2;
  1646. }
  1647. }
  1648. ASSERT(hp == endp);
  1649. return res;
  1650. }
  1651. static void
  1652. make_available_cpu_topology(erts_avail_cput *no,
  1653. erts_avail_cput *avail,
  1654. erts_cpu_topology_t *cpudata,
  1655. int *size,
  1656. int test)
  1657. {
  1658. int len = *size;
  1659. erts_cpu_topology_t last;
  1660. int a, i, j;
  1661. no->level[ERTS_TOPOLOGY_NODE] = -1;
  1662. no->level[ERTS_TOPOLOGY_PROCESSOR] = -1;
  1663. no->

Large files files are truncated, but you can click here to view the full file