PageRenderTime 58ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/erts/emulator/beam/erl_alloc.c

https://github.com/mmullis/otp
C | 3460 lines | 2980 code | 393 blank | 87 comment | 491 complexity | fba2217479c0462b86ff92cd70d5f001 MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-2-Clause
  1. /*
  2. * %CopyrightBegin%
  3. *
  4. * Copyright Ericsson AB 2002-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: Management of memory allocators.
  21. *
  22. * Author: Rickard Green
  23. */
  24. #ifdef HAVE_CONFIG_H
  25. # include "config.h"
  26. #endif
  27. #define ERTS_ALLOC_C__
  28. #define ERTS_ALC_INTERNAL__
  29. #include "sys.h"
  30. #define ERL_THREADS_EMU_INTERNAL__
  31. #include "erl_threads.h"
  32. #include "global.h"
  33. #include "erl_db.h"
  34. #include "erl_binary.h"
  35. #include "erl_bits.h"
  36. #include "erl_instrument.h"
  37. #include "erl_mseg.h"
  38. #include "erl_monitors.h"
  39. #include "erl_bif_timer.h"
  40. #if defined(ERTS_ALC_T_DRV_SEL_D_STATE) || defined(ERTS_ALC_T_DRV_EV_D_STATE)
  41. #include "erl_check_io.h"
  42. #endif
  43. #define GET_ERL_GF_ALLOC_IMPL
  44. #include "erl_goodfit_alloc.h"
  45. #define GET_ERL_BF_ALLOC_IMPL
  46. #include "erl_bestfit_alloc.h"
  47. #define GET_ERL_AF_ALLOC_IMPL
  48. #include "erl_afit_alloc.h"
  49. #define ERTS_ALC_DEFAULT_MAX_THR_PREF 16
  50. #if defined(SMALL_MEMORY) || defined(PURIFY) || defined(VALGRIND)
  51. #define AU_ALLOC_DEFAULT_ENABLE(X) 0
  52. #else
  53. #define AU_ALLOC_DEFAULT_ENABLE(X) (X)
  54. #endif
  55. #ifdef DEBUG
  56. static Uint install_debug_functions(void);
  57. #if 0
  58. #define HARD_DEBUG
  59. #ifdef __GNUC__
  60. #warning "* * * * * * * * * * * * * *"
  61. #warning "* HARD DEBUG IS ENABLED! *"
  62. #warning "* * * * * * * * * * * * * *"
  63. #endif
  64. #endif
  65. #endif
  66. ErtsAllocatorFunctions_t erts_allctrs[ERTS_ALC_A_MAX+1];
  67. ErtsAllocatorInfo_t erts_allctrs_info[ERTS_ALC_A_MAX+1];
  68. ErtsAllocatorThrSpec_t erts_allctr_thr_spec[ERTS_ALC_A_MAX+1];
  69. #define ERTS_MIN(A, B) ((A) < (B) ? (A) : (B))
  70. #define ERTS_MAX(A, B) ((A) > (B) ? (A) : (B))
  71. typedef union {
  72. GFAllctr_t gfa;
  73. char align_gfa[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(GFAllctr_t))];
  74. BFAllctr_t bfa;
  75. char align_bfa[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(BFAllctr_t))];
  76. AFAllctr_t afa;
  77. char align_afa[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(AFAllctr_t))];
  78. } ErtsAllocatorState_t;
  79. static ErtsAllocatorState_t sl_alloc_state;
  80. static ErtsAllocatorState_t std_alloc_state;
  81. static ErtsAllocatorState_t ll_alloc_state;
  82. #if HALFWORD_HEAP
  83. static ErtsAllocatorState_t std_alloc_low_state;
  84. static ErtsAllocatorState_t ll_alloc_low_state;
  85. #endif
  86. static ErtsAllocatorState_t temp_alloc_state;
  87. static ErtsAllocatorState_t eheap_alloc_state;
  88. static ErtsAllocatorState_t binary_alloc_state;
  89. static ErtsAllocatorState_t ets_alloc_state;
  90. static ErtsAllocatorState_t driver_alloc_state;
  91. ErtsAlcType_t erts_fix_core_allocator_ix;
  92. #ifdef ERTS_ALC_N_MIN_A_FIXED_SIZE
  93. static void *(*fix_core_allocator)(ErtsAlcType_t, void *, Uint);
  94. static void *fix_core_extra;
  95. static void *fix_core_alloc(Uint size)
  96. {
  97. void *res;
  98. res = (*fix_core_allocator)(ERTS_ALC_T_UNDEF, fix_core_extra, size);
  99. if (erts_mtrace_enabled)
  100. erts_mtrace_crr_alloc(res,
  101. ERTS_ALC_A_FIXED_SIZE,
  102. erts_fix_core_allocator_ix,
  103. size);
  104. return res;
  105. }
  106. #endif
  107. enum allctr_type {
  108. GOODFIT,
  109. BESTFIT,
  110. AFIT
  111. };
  112. struct au_init {
  113. int enable;
  114. int thr_spec;
  115. enum allctr_type atype;
  116. struct {
  117. AllctrInit_t util;
  118. GFAllctrInit_t gf;
  119. BFAllctrInit_t bf;
  120. AFAllctrInit_t af;
  121. } init;
  122. struct {
  123. int mmbcs;
  124. int lmbcs;
  125. int smbcs;
  126. int mmmbc;
  127. } default_;
  128. };
  129. #define DEFAULT_ALLCTR_INIT { \
  130. ERTS_DEFAULT_ALLCTR_INIT, \
  131. ERTS_DEFAULT_GF_ALLCTR_INIT, \
  132. ERTS_DEFAULT_BF_ALLCTR_INIT, \
  133. ERTS_DEFAULT_AF_ALLCTR_INIT \
  134. }
  135. typedef struct {
  136. int erts_alloc_config;
  137. #if HAVE_ERTS_MSEG
  138. ErtsMsegInit_t mseg;
  139. #endif
  140. int trim_threshold;
  141. int top_pad;
  142. AlcUInit_t alloc_util;
  143. struct {
  144. int stat;
  145. int map;
  146. char *mtrace;
  147. char *nodename;
  148. } instr;
  149. struct au_init sl_alloc;
  150. struct au_init std_alloc;
  151. struct au_init ll_alloc;
  152. struct au_init temp_alloc;
  153. struct au_init eheap_alloc;
  154. struct au_init binary_alloc;
  155. struct au_init ets_alloc;
  156. struct au_init driver_alloc;
  157. #if HALFWORD_HEAP
  158. struct au_init std_alloc_low;
  159. struct au_init ll_alloc_low;
  160. #endif
  161. } erts_alc_hndl_args_init_t;
  162. #define ERTS_AU_INIT__ {0, 0, GOODFIT, DEFAULT_ALLCTR_INIT, {1,1,1,1}}
  163. #define SET_DEFAULT_ALLOC_OPTS(IP) \
  164. do { \
  165. struct au_init aui__ = ERTS_AU_INIT__; \
  166. sys_memcpy((void *) (IP), (void *) &aui__, sizeof(struct au_init)); \
  167. } while (0)
  168. static void
  169. set_default_sl_alloc_opts(struct au_init *ip)
  170. {
  171. SET_DEFAULT_ALLOC_OPTS(ip);
  172. ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
  173. ip->thr_spec = 1;
  174. ip->atype = GOODFIT;
  175. ip->init.util.name_prefix = "sl_";
  176. ip->init.util.mmmbc = 5;
  177. ip->init.util.alloc_no = ERTS_ALC_A_SHORT_LIVED;
  178. #ifndef SMALL_MEMORY
  179. ip->init.util.mmbcs = 128*1024; /* Main carrier size */
  180. #else
  181. ip->init.util.mmbcs = 32*1024; /* Main carrier size */
  182. #endif
  183. ip->init.util.ts = ERTS_ALC_MTA_SHORT_LIVED;
  184. ip->init.util.rsbcst = 80;
  185. #if HALFWORD_HEAP
  186. ip->init.util.low_mem = 1;
  187. #endif
  188. }
  189. static void
  190. set_default_std_alloc_opts(struct au_init *ip)
  191. {
  192. SET_DEFAULT_ALLOC_OPTS(ip);
  193. ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
  194. ip->thr_spec = 1;
  195. ip->atype = BESTFIT;
  196. ip->init.util.name_prefix = "std_";
  197. ip->init.util.mmmbc = 5;
  198. ip->init.util.alloc_no = ERTS_ALC_A_STANDARD;
  199. #ifndef SMALL_MEMORY
  200. ip->init.util.mmbcs = 128*1024; /* Main carrier size */
  201. #else
  202. ip->init.util.mmbcs = 32*1024; /* Main carrier size */
  203. #endif
  204. ip->init.util.ts = ERTS_ALC_MTA_STANDARD;
  205. }
  206. static void
  207. set_default_ll_alloc_opts(struct au_init *ip)
  208. {
  209. SET_DEFAULT_ALLOC_OPTS(ip);
  210. ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
  211. ip->thr_spec = 0;
  212. ip->atype = BESTFIT;
  213. ip->init.bf.ao = 1;
  214. ip->init.util.ramv = 0;
  215. ip->init.util.mmsbc = 0;
  216. ip->init.util.mmmbc = 0;
  217. ip->init.util.sbct = ~((UWord) 0);
  218. ip->init.util.name_prefix = "ll_";
  219. ip->init.util.alloc_no = ERTS_ALC_A_LONG_LIVED;
  220. #ifndef SMALL_MEMORY
  221. ip->init.util.mmbcs = 2*1024*1024; /* Main carrier size */
  222. #else
  223. ip->init.util.mmbcs = 1*1024*1024; /* Main carrier size */
  224. #endif
  225. ip->init.util.ts = ERTS_ALC_MTA_LONG_LIVED;
  226. ip->init.util.asbcst = 0;
  227. ip->init.util.rsbcst = 0;
  228. ip->init.util.rsbcmt = 0;
  229. ip->init.util.rmbcmt = 0;
  230. }
  231. static void
  232. set_default_temp_alloc_opts(struct au_init *ip)
  233. {
  234. SET_DEFAULT_ALLOC_OPTS(ip);
  235. ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
  236. ip->thr_spec = 1;
  237. ip->atype = AFIT;
  238. ip->init.util.name_prefix = "temp_";
  239. ip->init.util.alloc_no = ERTS_ALC_A_TEMPORARY;
  240. #ifndef SMALL_MEMORY
  241. ip->init.util.mmbcs = 128*1024; /* Main carrier size */
  242. #else
  243. ip->init.util.mmbcs = 32*1024; /* Main carrier size */
  244. #endif
  245. ip->init.util.ts = ERTS_ALC_MTA_TEMPORARY;
  246. ip->init.util.rsbcst = 90;
  247. ip->init.util.rmbcmt = 100;
  248. #if HALFWORD_HEAP
  249. ip->init.util.low_mem = 1;
  250. #endif
  251. }
  252. static void
  253. set_default_eheap_alloc_opts(struct au_init *ip)
  254. {
  255. SET_DEFAULT_ALLOC_OPTS(ip);
  256. ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
  257. ip->thr_spec = 1;
  258. ip->atype = GOODFIT;
  259. ip->init.util.mmmbc = 100;
  260. ip->init.util.name_prefix = "eheap_";
  261. ip->init.util.alloc_no = ERTS_ALC_A_EHEAP;
  262. #ifndef SMALL_MEMORY
  263. ip->init.util.mmbcs = 512*1024; /* Main carrier size */
  264. #else
  265. ip->init.util.mmbcs = 256*1024; /* Main carrier size */
  266. #endif
  267. ip->init.util.ts = ERTS_ALC_MTA_EHEAP;
  268. ip->init.util.rsbcst = 50;
  269. #if HALFWORD_HEAP
  270. ip->init.util.low_mem = 1;
  271. #endif
  272. }
  273. static void
  274. set_default_binary_alloc_opts(struct au_init *ip)
  275. {
  276. SET_DEFAULT_ALLOC_OPTS(ip);
  277. ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
  278. ip->thr_spec = 1;
  279. ip->atype = BESTFIT;
  280. ip->init.util.mmmbc = 50;
  281. ip->init.util.name_prefix = "binary_";
  282. ip->init.util.alloc_no = ERTS_ALC_A_BINARY;
  283. #ifndef SMALL_MEMORY
  284. ip->init.util.mmbcs = 128*1024; /* Main carrier size */
  285. #else
  286. ip->init.util.mmbcs = 32*1024; /* Main carrier size */
  287. #endif
  288. ip->init.util.ts = ERTS_ALC_MTA_BINARY;
  289. }
  290. static void
  291. set_default_ets_alloc_opts(struct au_init *ip)
  292. {
  293. SET_DEFAULT_ALLOC_OPTS(ip);
  294. ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
  295. ip->thr_spec = 1;
  296. ip->atype = BESTFIT;
  297. ip->init.util.mmmbc = 100;
  298. ip->init.util.name_prefix = "ets_";
  299. ip->init.util.alloc_no = ERTS_ALC_A_ETS;
  300. #ifndef SMALL_MEMORY
  301. ip->init.util.mmbcs = 128*1024; /* Main carrier size */
  302. #else
  303. ip->init.util.mmbcs = 32*1024; /* Main carrier size */
  304. #endif
  305. ip->init.util.ts = ERTS_ALC_MTA_ETS;
  306. }
  307. static void
  308. set_default_driver_alloc_opts(struct au_init *ip)
  309. {
  310. SET_DEFAULT_ALLOC_OPTS(ip);
  311. ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
  312. ip->thr_spec = 1;
  313. ip->atype = BESTFIT;
  314. ip->init.util.name_prefix = "driver_";
  315. ip->init.util.alloc_no = ERTS_ALC_A_DRIVER;
  316. #ifndef SMALL_MEMORY
  317. ip->init.util.mmbcs = 128*1024; /* Main carrier size */
  318. #else
  319. ip->init.util.mmbcs = 32*1024; /* Main carrier size */
  320. #endif
  321. ip->init.util.ts = ERTS_ALC_MTA_DRIVER;
  322. }
  323. #ifdef ERTS_SMP
  324. static void
  325. adjust_tpref(struct au_init *ip, int no_sched)
  326. {
  327. if (ip->thr_spec) {
  328. Uint allocs;
  329. if (ip->thr_spec < 0) {/* User specified amount */
  330. allocs = abs(ip->thr_spec);
  331. if (allocs > no_sched)
  332. allocs = no_sched;
  333. }
  334. else if (no_sched > ERTS_ALC_DEFAULT_MAX_THR_PREF)
  335. allocs = ERTS_ALC_DEFAULT_MAX_THR_PREF;
  336. else
  337. allocs = no_sched;
  338. if (allocs <= 1)
  339. ip->thr_spec = 0;
  340. else {
  341. ip->thr_spec = (int) allocs;
  342. ip->thr_spec *= -1; /* thread preferred */
  343. /* If default ... */
  344. /* ... shrink main multi-block carrier size */
  345. if (ip->default_.mmbcs)
  346. ip->init.util.mmbcs /= ERTS_MIN(4, allocs);
  347. /* ... shrink largest multi-block carrier size */
  348. if (ip->default_.lmbcs)
  349. ip->init.util.lmbcs /= ERTS_MIN(2, allocs);
  350. /* ... shrink smallest multi-block carrier size */
  351. if (ip->default_.smbcs)
  352. ip->init.util.smbcs /= ERTS_MIN(4, allocs);
  353. /* ... and more than three allocators shrink
  354. max mseg multi-block carriers */
  355. if (ip->default_.mmmbc && allocs > 2) {
  356. ip->init.util.mmmbc /= ERTS_MIN(4, allocs - 1);
  357. if (ip->init.util.mmmbc < 3)
  358. ip->init.util.mmmbc = 3;
  359. }
  360. }
  361. }
  362. }
  363. #endif
  364. static void handle_args(int *, char **, erts_alc_hndl_args_init_t *);
  365. static void
  366. set_au_allocator(ErtsAlcType_t alctr_n, struct au_init *init);
  367. static void
  368. start_au_allocator(ErtsAlcType_t alctr_n,
  369. struct au_init *init,
  370. ErtsAllocatorState_t *state);
  371. static void
  372. refuse_af_strategy(struct au_init *init)
  373. {
  374. if (init->atype == AFIT)
  375. init->atype = GOODFIT;
  376. }
  377. static void init_thr_ix(int static_ixs);
  378. #ifdef HARD_DEBUG
  379. static void hdbg_init(void);
  380. #endif
  381. void
  382. erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
  383. {
  384. UWord extra_block_size = 0;
  385. int i;
  386. erts_alc_hndl_args_init_t init = {
  387. 0,
  388. #if HAVE_ERTS_MSEG
  389. ERTS_MSEG_INIT_DEFAULT_INITIALIZER,
  390. #endif
  391. ERTS_DEFAULT_TRIM_THRESHOLD,
  392. ERTS_DEFAULT_TOP_PAD,
  393. ERTS_DEFAULT_ALCU_INIT
  394. };
  395. #ifdef HARD_DEBUG
  396. hdbg_init();
  397. #endif
  398. erts_sys_alloc_init();
  399. init_thr_ix(erts_no_schedulers);
  400. erts_init_utils_mem();
  401. set_default_sl_alloc_opts(&init.sl_alloc);
  402. set_default_std_alloc_opts(&init.std_alloc);
  403. set_default_ll_alloc_opts(&init.ll_alloc);
  404. set_default_temp_alloc_opts(&init.temp_alloc);
  405. set_default_eheap_alloc_opts(&init.eheap_alloc);
  406. set_default_binary_alloc_opts(&init.binary_alloc);
  407. set_default_ets_alloc_opts(&init.ets_alloc);
  408. set_default_driver_alloc_opts(&init.driver_alloc);
  409. if (argc && argv)
  410. handle_args(argc, argv, &init);
  411. if (erts_no_schedulers <= 1) {
  412. init.sl_alloc.thr_spec = 0;
  413. init.std_alloc.thr_spec = 0;
  414. init.ll_alloc.thr_spec = 0;
  415. init.eheap_alloc.thr_spec = 0;
  416. init.binary_alloc.thr_spec = 0;
  417. init.ets_alloc.thr_spec = 0;
  418. init.driver_alloc.thr_spec = 0;
  419. }
  420. if (init.erts_alloc_config) {
  421. /* Adjust flags that erts_alloc_config won't like */
  422. init.temp_alloc.thr_spec = 0;
  423. init.sl_alloc.thr_spec = 0;
  424. init.std_alloc.thr_spec = 0;
  425. init.ll_alloc.thr_spec = 0;
  426. init.eheap_alloc.thr_spec = 0;
  427. init.binary_alloc.thr_spec = 0;
  428. init.ets_alloc.thr_spec = 0;
  429. init.driver_alloc.thr_spec = 0;
  430. }
  431. #ifdef ERTS_SMP
  432. /* Only temp_alloc can use thread specific interface */
  433. if (init.temp_alloc.thr_spec)
  434. init.temp_alloc.thr_spec = erts_no_schedulers;
  435. /* Others must use thread preferred interface */
  436. adjust_tpref(&init.sl_alloc, erts_no_schedulers);
  437. adjust_tpref(&init.std_alloc, erts_no_schedulers);
  438. adjust_tpref(&init.ll_alloc, erts_no_schedulers);
  439. adjust_tpref(&init.eheap_alloc, erts_no_schedulers);
  440. adjust_tpref(&init.binary_alloc, erts_no_schedulers);
  441. adjust_tpref(&init.ets_alloc, erts_no_schedulers);
  442. adjust_tpref(&init.driver_alloc, erts_no_schedulers);
  443. #else
  444. /* No thread specific if not smp */
  445. init.temp_alloc.thr_spec = 0;
  446. #endif
  447. /*
  448. * The following allocators cannot be run with afit strategy.
  449. * Make sure they don't...
  450. */
  451. refuse_af_strategy(&init.sl_alloc);
  452. refuse_af_strategy(&init.std_alloc);
  453. refuse_af_strategy(&init.ll_alloc);
  454. refuse_af_strategy(&init.eheap_alloc);
  455. refuse_af_strategy(&init.binary_alloc);
  456. refuse_af_strategy(&init.ets_alloc);
  457. refuse_af_strategy(&init.driver_alloc);
  458. #ifdef ERTS_SMP
  459. if (!init.temp_alloc.thr_spec)
  460. refuse_af_strategy(&init.temp_alloc);
  461. #endif
  462. erts_mtrace_pre_init();
  463. #if HAVE_ERTS_MSEG
  464. erts_mseg_init(&init.mseg);
  465. #endif
  466. erts_alcu_init(&init.alloc_util);
  467. erts_afalc_init();
  468. erts_bfalc_init();
  469. erts_gfalc_init();
  470. for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) {
  471. erts_allctrs[i].alloc = NULL;
  472. erts_allctrs[i].realloc = NULL;
  473. erts_allctrs[i].free = NULL;
  474. erts_allctrs[i].extra = NULL;
  475. erts_allctrs_info[i].alloc_util = 0;
  476. erts_allctrs_info[i].enabled = 0;
  477. erts_allctrs_info[i].thr_spec = 0;
  478. erts_allctrs_info[i].extra = NULL;
  479. }
  480. #ifdef ERTS_ALC_N_MIN_A_FIXED_SIZE
  481. #if !defined(PURIFY) && !defined(VALGRIND)
  482. erts_allctrs[ERTS_ALC_A_FIXED_SIZE].alloc = erts_fix_alloc;
  483. erts_allctrs[ERTS_ALC_A_FIXED_SIZE].realloc = erts_fix_realloc;
  484. erts_allctrs[ERTS_ALC_A_FIXED_SIZE].free = erts_fix_free;
  485. erts_allctrs_info[ERTS_ALC_A_FIXED_SIZE].enabled = 1;
  486. #else
  487. erts_allctrs[ERTS_ALC_A_FIXED_SIZE].alloc = erts_sys_alloc;
  488. erts_allctrs[ERTS_ALC_A_FIXED_SIZE].realloc = erts_sys_realloc;
  489. erts_allctrs[ERTS_ALC_A_FIXED_SIZE].free = erts_sys_free;
  490. erts_allctrs_info[ERTS_ALC_A_FIXED_SIZE].enabled = 0;
  491. #endif
  492. #endif
  493. erts_allctrs[ERTS_ALC_A_SYSTEM].alloc = erts_sys_alloc;
  494. erts_allctrs[ERTS_ALC_A_SYSTEM].realloc = erts_sys_realloc;
  495. erts_allctrs[ERTS_ALC_A_SYSTEM].free = erts_sys_free;
  496. erts_allctrs_info[ERTS_ALC_A_SYSTEM].enabled = 1;
  497. #if HALFWORD_HEAP
  498. /* Init low memory variants by cloning */
  499. init.std_alloc_low = init.std_alloc;
  500. init.std_alloc_low.init.util.alloc_no = ERTS_ALC_A_STANDARD_LOW;
  501. init.std_alloc_low.init.util.low_mem = 1;
  502. init.ll_alloc_low = init.ll_alloc;
  503. init.ll_alloc_low.init.util.alloc_no = ERTS_ALC_A_LONG_LIVED_LOW;
  504. init.ll_alloc_low.init.util.low_mem = 1;
  505. set_au_allocator(ERTS_ALC_A_STANDARD_LOW, &init.std_alloc_low);
  506. set_au_allocator(ERTS_ALC_A_LONG_LIVED_LOW, &init.ll_alloc_low);
  507. #endif /* HALFWORD */
  508. set_au_allocator(ERTS_ALC_A_TEMPORARY, &init.temp_alloc);
  509. set_au_allocator(ERTS_ALC_A_SHORT_LIVED, &init.sl_alloc);
  510. set_au_allocator(ERTS_ALC_A_STANDARD, &init.std_alloc);
  511. set_au_allocator(ERTS_ALC_A_LONG_LIVED, &init.ll_alloc);
  512. set_au_allocator(ERTS_ALC_A_EHEAP, &init.eheap_alloc);
  513. set_au_allocator(ERTS_ALC_A_BINARY, &init.binary_alloc);
  514. set_au_allocator(ERTS_ALC_A_ETS, &init.ets_alloc);
  515. set_au_allocator(ERTS_ALC_A_DRIVER, &init.driver_alloc);
  516. for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) {
  517. if (!erts_allctrs[i].alloc)
  518. erl_exit(ERTS_ABORT_EXIT,
  519. "Missing alloc function for %s\n", ERTS_ALC_A2AD(i));
  520. if (!erts_allctrs[i].realloc)
  521. erl_exit(ERTS_ABORT_EXIT,
  522. "Missing realloc function for %s\n", ERTS_ALC_A2AD(i));
  523. if (!erts_allctrs[i].free)
  524. erl_exit(ERTS_ABORT_EXIT,
  525. "Missing free function for %s\n", ERTS_ALC_A2AD(i));
  526. }
  527. sys_alloc_opt(SYS_ALLOC_OPT_TRIM_THRESHOLD, init.trim_threshold);
  528. sys_alloc_opt(SYS_ALLOC_OPT_TOP_PAD, init.top_pad);
  529. if (erts_allctrs_info[ERTS_FIX_CORE_ALLOCATOR].enabled)
  530. erts_fix_core_allocator_ix = ERTS_FIX_CORE_ALLOCATOR;
  531. else
  532. erts_fix_core_allocator_ix = ERTS_ALC_A_SYSTEM;
  533. erts_mtrace_init(init.instr.mtrace, init.instr.nodename);
  534. start_au_allocator(ERTS_ALC_A_TEMPORARY,
  535. &init.temp_alloc,
  536. &temp_alloc_state);
  537. start_au_allocator(ERTS_ALC_A_SHORT_LIVED,
  538. &init.sl_alloc,
  539. &sl_alloc_state);
  540. start_au_allocator(ERTS_ALC_A_STANDARD,
  541. &init.std_alloc,
  542. &std_alloc_state);
  543. start_au_allocator(ERTS_ALC_A_LONG_LIVED,
  544. &init.ll_alloc,
  545. &ll_alloc_state);
  546. #if HALFWORD_HEAP
  547. start_au_allocator(ERTS_ALC_A_LONG_LIVED_LOW,
  548. &init.ll_alloc_low,
  549. &ll_alloc_low_state);
  550. start_au_allocator(ERTS_ALC_A_STANDARD_LOW,
  551. &init.std_alloc_low,
  552. &std_alloc_low_state);
  553. #endif
  554. start_au_allocator(ERTS_ALC_A_EHEAP,
  555. &init.eheap_alloc,
  556. &eheap_alloc_state);
  557. start_au_allocator(ERTS_ALC_A_BINARY,
  558. &init.binary_alloc,
  559. &binary_alloc_state);
  560. start_au_allocator(ERTS_ALC_A_ETS,
  561. &init.ets_alloc,
  562. &ets_alloc_state);
  563. start_au_allocator(ERTS_ALC_A_DRIVER,
  564. &init.driver_alloc,
  565. &driver_alloc_state);
  566. fix_core_allocator = erts_allctrs[erts_fix_core_allocator_ix].alloc;
  567. fix_core_extra = erts_allctrs[erts_fix_core_allocator_ix].extra;
  568. erts_mtrace_install_wrapper_functions();
  569. extra_block_size += erts_instr_init(init.instr.stat, init.instr.map);
  570. #ifdef DEBUG
  571. extra_block_size += install_debug_functions();
  572. #endif
  573. #ifdef ERTS_ALC_N_MIN_A_FIXED_SIZE
  574. erts_init_fix_alloc(extra_block_size, fix_core_alloc);
  575. #if !defined(PURIFY) && !defined(VALGRIND)
  576. erts_set_fix_size(ERTS_ALC_T_PROC, sizeof(Process));
  577. erts_set_fix_size(ERTS_ALC_T_DB_TABLE, sizeof(DbTable));
  578. erts_set_fix_size(ERTS_ALC_T_ATOM, sizeof(Atom));
  579. erts_set_fix_size(ERTS_ALC_T_MODULE, sizeof(Module));
  580. erts_set_fix_size(ERTS_ALC_T_REG_PROC, sizeof(RegProc));
  581. erts_set_fix_size(ERTS_ALC_T_FUN_ENTRY, sizeof(ErlFunEntry));
  582. #ifdef ERTS_ALC_T_DRV_EV_D_STATE
  583. erts_set_fix_size(ERTS_ALC_T_DRV_EV_D_STATE,
  584. sizeof(ErtsDrvEventDataState));
  585. #endif
  586. #ifdef ERTS_ALC_T_DRV_SEL_D_STATE
  587. erts_set_fix_size(ERTS_ALC_T_DRV_SEL_D_STATE,
  588. sizeof(ErtsDrvSelectDataState));
  589. #endif
  590. #if !HALFWORD_HEAP
  591. erts_set_fix_size(ERTS_ALC_T_EXPORT, sizeof(Export));
  592. erts_set_fix_size(ERTS_ALC_T_MONITOR_SH, ERTS_MONITOR_SH_SIZE*sizeof(Uint));
  593. erts_set_fix_size(ERTS_ALC_T_NLINK_SH, ERTS_LINK_SH_SIZE*sizeof(Uint));
  594. #endif
  595. #endif
  596. #endif
  597. }
  598. static void
  599. set_au_allocator(ErtsAlcType_t alctr_n, struct au_init *init)
  600. {
  601. ErtsAllocatorFunctions_t *af = &erts_allctrs[alctr_n];
  602. ErtsAllocatorInfo_t *ai = &erts_allctrs_info[alctr_n];
  603. ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[alctr_n];
  604. #if HALFWORD_HEAP
  605. /* If halfword heap, silently ignore any disabling of internal
  606. * allocators for low memory
  607. */
  608. if (init->init.util.low_mem) {
  609. init->enable = 1;
  610. }
  611. #endif
  612. if (!init->enable) {
  613. af->alloc = erts_sys_alloc;
  614. af->realloc = erts_sys_realloc;
  615. af->free = erts_sys_free;
  616. af->extra = NULL;
  617. ai->alloc_util = 0;
  618. ai->enabled = 0;
  619. ai->extra = NULL;
  620. return;
  621. }
  622. tspec->enabled = 0;
  623. tspec->all_thr_safe = 0;
  624. ai->thr_spec = 0;
  625. #ifdef USE_THREADS
  626. if (init->thr_spec) {
  627. if (init->thr_spec > 0) {
  628. af->alloc = erts_alcu_alloc_thr_spec;
  629. if (init->init.util.ramv)
  630. af->realloc = erts_alcu_realloc_mv_thr_spec;
  631. else
  632. af->realloc = erts_alcu_realloc_thr_spec;
  633. af->free = erts_alcu_free_thr_spec;
  634. }
  635. else {
  636. af->alloc = erts_alcu_alloc_thr_pref;
  637. if (init->init.util.ramv)
  638. af->realloc = erts_alcu_realloc_mv_thr_pref;
  639. else
  640. af->realloc = erts_alcu_realloc_thr_pref;
  641. af->free = erts_alcu_free_thr_pref;
  642. tspec->all_thr_safe = 1;
  643. }
  644. tspec->enabled = 1;
  645. tspec->size = abs(init->thr_spec) + 1;
  646. ai->thr_spec = tspec->size;
  647. }
  648. else if (init->init.util.ts) {
  649. af->alloc = erts_alcu_alloc_ts;
  650. if (init->init.util.ramv)
  651. af->realloc = erts_alcu_realloc_mv_ts;
  652. else
  653. af->realloc = erts_alcu_realloc_ts;
  654. af->free = erts_alcu_free_ts;
  655. }
  656. else
  657. #endif
  658. {
  659. af->alloc = erts_alcu_alloc;
  660. if (init->init.util.ramv)
  661. af->realloc = erts_alcu_realloc_mv;
  662. else
  663. af->realloc = erts_alcu_realloc;
  664. af->free = erts_alcu_free;
  665. }
  666. af->extra = NULL;
  667. ai->alloc_util = 1;
  668. ai->enabled = 1;
  669. }
  670. static void
  671. start_au_allocator(ErtsAlcType_t alctr_n,
  672. struct au_init *init,
  673. ErtsAllocatorState_t *state)
  674. {
  675. int i;
  676. int size = 1;
  677. void *as0;
  678. enum allctr_type atype;
  679. ErtsAllocatorFunctions_t *af = &erts_allctrs[alctr_n];
  680. ErtsAllocatorInfo_t *ai = &erts_allctrs_info[alctr_n];
  681. ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[alctr_n];
  682. if (!init->enable)
  683. return;
  684. if (init->thr_spec) {
  685. void *states = erts_sys_alloc(0,
  686. NULL,
  687. ((sizeof(Allctr_t *)
  688. * (tspec->size + 1))
  689. + (sizeof(ErtsAllocatorState_t)
  690. * tspec->size)
  691. + ERTS_CACHE_LINE_SIZE - 1));
  692. if (!states)
  693. erl_exit(ERTS_ABORT_EXIT,
  694. "Failed to allocate allocator states for %salloc\n",
  695. init->init.util.name_prefix);
  696. tspec->allctr = (Allctr_t **) states;
  697. states = ((char *) states) + sizeof(Allctr_t *) * (tspec->size + 1);
  698. states = ((((UWord) states) & ERTS_CACHE_LINE_MASK)
  699. ? (void *) ((((UWord) states) & ~ERTS_CACHE_LINE_MASK)
  700. + ERTS_CACHE_LINE_SIZE)
  701. : (void *) states);
  702. tspec->allctr[0] = init->thr_spec > 0 ? (Allctr_t *) state : (Allctr_t *) NULL;
  703. size = tspec->size;
  704. for (i = 1; i < size; i++)
  705. tspec->allctr[i] = (Allctr_t *)
  706. &((ErtsAllocatorState_t *) states)[i-1];
  707. }
  708. for (i = 0; i < size; i++) {
  709. void *as;
  710. atype = init->atype;
  711. if (!init->thr_spec)
  712. as0 = state;
  713. else {
  714. as0 = (void *) tspec->allctr[i];
  715. if (!as0)
  716. continue;
  717. if (i == 0) {
  718. if (atype == AFIT)
  719. atype = GOODFIT;
  720. init->init.util.ts = 1;
  721. }
  722. else {
  723. if (init->thr_spec < 0) {
  724. init->init.util.ts = 1;
  725. init->init.util.tspec = 0;
  726. init->init.util.tpref = -1*init->thr_spec;
  727. }
  728. else {
  729. init->init.util.ts = 0;
  730. init->init.util.tspec = init->thr_spec + 1;
  731. init->init.util.tpref = 0;
  732. }
  733. }
  734. }
  735. switch (atype) {
  736. case GOODFIT:
  737. as = (void *) erts_gfalc_start((GFAllctr_t *) as0,
  738. &init->init.gf,
  739. &init->init.util);
  740. break;
  741. case BESTFIT:
  742. as = (void *) erts_bfalc_start((BFAllctr_t *) as0,
  743. &init->init.bf,
  744. &init->init.util);
  745. break;
  746. case AFIT:
  747. as = (void *) erts_afalc_start((AFAllctr_t *) as0,
  748. &init->init.af,
  749. &init->init.util);
  750. break;
  751. default:
  752. as = NULL;
  753. ASSERT(0);
  754. }
  755. if (!as)
  756. erl_exit(ERTS_ABORT_EXIT,
  757. "Failed to start %salloc\n", init->init.util.name_prefix);
  758. ASSERT(as == (void *) as0);
  759. af->extra = as;
  760. }
  761. if (init->thr_spec) {
  762. af->extra = tspec;
  763. init->init.util.ts = 1;
  764. }
  765. ai->extra = af->extra;
  766. }
  767. static void bad_param(char *param_start, char *param_end)
  768. {
  769. size_t len = param_end - param_start;
  770. char param[100];
  771. if (len > 99)
  772. len = 99;
  773. sys_memcpy((void *) param, (void *) param_start, len);
  774. param[len] = '\0';
  775. erts_fprintf(stderr, "bad \"%s\" parameter\n", param);
  776. erts_usage();
  777. }
  778. static void bad_value(char *param_start, char *param_end, char *value)
  779. {
  780. size_t len = param_end - param_start;
  781. char param[100];
  782. if (len > 99)
  783. len = 99;
  784. sys_memcpy((void *) param, (void *) param_start, len);
  785. param[len] = '\0';
  786. erts_fprintf(stderr, "bad \"%s\" value: %s\n", param, value);
  787. erts_usage();
  788. }
  789. /* Get arg marks argument as handled by
  790. putting NULL in argv */
  791. static char *
  792. get_value(char* rest, char** argv, int* ip)
  793. {
  794. char *param = argv[*ip]+1;
  795. argv[*ip] = NULL;
  796. if (*rest == '\0') {
  797. char *next = argv[*ip + 1];
  798. if (next[0] == '-'
  799. && next[1] == '-'
  800. && next[2] == '\0') {
  801. bad_value(param, rest, "");
  802. }
  803. (*ip)++;
  804. argv[*ip] = NULL;
  805. return next;
  806. }
  807. return rest;
  808. }
  809. static ERTS_INLINE int
  810. has_prefix(const char *prefix, const char *string)
  811. {
  812. int i;
  813. for (i = 0; prefix[i]; i++)
  814. if (prefix[i] != string[i])
  815. return 0;
  816. return 1;
  817. }
  818. static int
  819. get_bool_value(char *param_end, char** argv, int* ip)
  820. {
  821. char *param = argv[*ip]+1;
  822. char *value = get_value(param_end, argv, ip);
  823. if (strcmp(value, "true") == 0)
  824. return 1;
  825. else if (strcmp(value, "false") == 0)
  826. return 0;
  827. else
  828. bad_value(param, param_end, value);
  829. return -1;
  830. }
  831. static Uint
  832. get_kb_value(char *param_end, char** argv, int* ip)
  833. {
  834. Sint tmp;
  835. Uint max = ((~((Uint) 0))/1024) + 1;
  836. char *rest;
  837. char *param = argv[*ip]+1;
  838. char *value = get_value(param_end, argv, ip);
  839. errno = 0;
  840. tmp = (Sint) strtol(value, &rest, 10);
  841. if (errno != 0 || rest == value || tmp < 0 || max < ((Uint) tmp))
  842. bad_value(param, param_end, value);
  843. if (max == (Uint) tmp)
  844. return ~((Uint) 0);
  845. else
  846. return ((Uint) tmp)*1024;
  847. }
  848. static Uint
  849. get_amount_value(char *param_end, char** argv, int* ip)
  850. {
  851. Sint tmp;
  852. char *rest;
  853. char *param = argv[*ip]+1;
  854. char *value = get_value(param_end, argv, ip);
  855. errno = 0;
  856. tmp = (Sint) strtol(value, &rest, 10);
  857. if (errno != 0 || rest == value || tmp < 0)
  858. bad_value(param, param_end, value);
  859. return (Uint) tmp;
  860. }
  861. static int
  862. get_bool_or_possitive_amount_value(int *bool, Uint *amount,
  863. char *param_end, char** argv, int* ip)
  864. {
  865. char *param = argv[*ip]+1;
  866. char *value = get_value(param_end, argv, ip);
  867. if (strcmp(value, "true") == 0) {
  868. *bool = 1;
  869. return 1;
  870. }
  871. else if (strcmp(value, "false") == 0) {
  872. *bool = 0;
  873. return 1;
  874. }
  875. else {
  876. Sint tmp;
  877. char *rest;
  878. errno = 0;
  879. tmp = (Sint) strtol(value, &rest, 10);
  880. if (errno != 0 || rest == value || tmp <= 0) {
  881. bad_value(param, param_end, value);
  882. return -1;
  883. }
  884. *amount = (Uint) tmp;
  885. return 0;
  886. }
  887. }
  888. static void
  889. handle_au_arg(struct au_init *auip,
  890. char* sub_param,
  891. char** argv,
  892. int* ip)
  893. {
  894. char *param = argv[*ip]+1;
  895. switch (sub_param[0]) {
  896. case 'a':
  897. if(has_prefix("asbcst", sub_param)) {
  898. auip->init.util.asbcst = get_kb_value(sub_param + 6, argv, ip);
  899. }
  900. else if(has_prefix("as", sub_param)) {
  901. char *alg = get_value(sub_param + 2, argv, ip);
  902. if (strcmp("bf", alg) == 0) {
  903. auip->atype = BESTFIT;
  904. auip->init.bf.ao = 0;
  905. }
  906. else if (strcmp("aobf", alg) == 0) {
  907. auip->atype = BESTFIT;
  908. auip->init.bf.ao = 1;
  909. }
  910. else if (strcmp("gf", alg) == 0) {
  911. auip->atype = GOODFIT;
  912. }
  913. else if (strcmp("af", alg) == 0) {
  914. auip->atype = AFIT;
  915. }
  916. else {
  917. bad_value(param, sub_param + 1, alg);
  918. }
  919. }
  920. else
  921. goto bad_switch;
  922. break;
  923. case 'e':
  924. auip->enable = get_bool_value(sub_param+1, argv, ip);
  925. break;
  926. case 'l':
  927. if (has_prefix("lmbcs", sub_param)) {
  928. auip->default_.lmbcs = 0;
  929. auip->init.util.lmbcs = get_kb_value(sub_param + 5, argv, ip);
  930. }
  931. else
  932. goto bad_switch;
  933. break;
  934. case 'm':
  935. if (has_prefix("mbcgs", sub_param)) {
  936. auip->init.util.mbcgs = get_amount_value(sub_param + 5, argv, ip);
  937. }
  938. else if (has_prefix("mbsd", sub_param)) {
  939. auip->init.gf.mbsd = get_amount_value(sub_param + 4, argv, ip);
  940. if (auip->init.gf.mbsd < 1)
  941. auip->init.gf.mbsd = 1;
  942. }
  943. else if (has_prefix("mmbcs", sub_param)) {
  944. auip->default_.mmbcs = 0;
  945. auip->init.util.mmbcs = get_kb_value(sub_param + 5, argv, ip);
  946. }
  947. else if (has_prefix("mmmbc", sub_param)) {
  948. auip->default_.mmmbc = 0;
  949. auip->init.util.mmmbc = get_amount_value(sub_param + 5, argv, ip);
  950. }
  951. else if (has_prefix("mmsbc", sub_param)) {
  952. auip->init.util.mmsbc = get_amount_value(sub_param + 5, argv, ip);
  953. }
  954. else
  955. goto bad_switch;
  956. break;
  957. case 'r':
  958. if(has_prefix("rsbcmt", sub_param)) {
  959. auip->init.util.rsbcmt = get_amount_value(sub_param + 6, argv, ip);
  960. if (auip->init.util.rsbcmt > 100)
  961. auip->init.util.rsbcmt = 100;
  962. }
  963. else if(has_prefix("rsbcst", sub_param)) {
  964. auip->init.util.rsbcst = get_amount_value(sub_param + 6, argv, ip);
  965. if (auip->init.util.rsbcst > 100)
  966. auip->init.util.rsbcst = 100;
  967. }
  968. else if (has_prefix("rmbcmt", sub_param)) {
  969. auip->init.util.rmbcmt = get_amount_value(sub_param + 6, argv, ip);
  970. if (auip->init.util.rmbcmt > 100)
  971. auip->init.util.rmbcmt = 100;
  972. }
  973. else if (has_prefix("ramv", sub_param)) {
  974. auip->init.util.ramv = get_bool_value(sub_param + 4, argv, ip);
  975. }
  976. else
  977. goto bad_switch;
  978. break;
  979. case 's':
  980. if(has_prefix("sbct", sub_param)) {
  981. auip->init.util.sbct = get_kb_value(sub_param + 4, argv, ip);
  982. }
  983. else if (has_prefix("smbcs", sub_param)) {
  984. auip->default_.smbcs = 0;
  985. auip->init.util.smbcs = get_kb_value(sub_param + 5, argv, ip);
  986. }
  987. else
  988. goto bad_switch;
  989. break;
  990. case 't': {
  991. Uint no;
  992. int enable;
  993. int res = get_bool_or_possitive_amount_value(&enable,
  994. &no,
  995. sub_param+1,
  996. argv,
  997. ip);
  998. if (res > 0)
  999. auip->thr_spec = enable ? 1 : 0;
  1000. else if (res == 0) {
  1001. int allocs = (int) no;
  1002. if (allocs < 0)
  1003. allocs = INT_MIN;
  1004. else {
  1005. allocs *= -1;
  1006. }
  1007. auip->thr_spec = allocs;
  1008. }
  1009. break;
  1010. }
  1011. default:
  1012. bad_switch:
  1013. bad_param(param, sub_param);
  1014. }
  1015. }
  1016. static void
  1017. handle_args(int *argc, char **argv, erts_alc_hndl_args_init_t *init)
  1018. {
  1019. struct au_init *aui[] = {
  1020. &init->binary_alloc,
  1021. &init->std_alloc,
  1022. &init->ets_alloc,
  1023. &init->eheap_alloc,
  1024. &init->ll_alloc,
  1025. &init->driver_alloc,
  1026. &init->sl_alloc,
  1027. &init->temp_alloc
  1028. };
  1029. int aui_sz = (int) sizeof(aui)/sizeof(aui[0]);
  1030. char *arg;
  1031. char *rest;
  1032. int i, j;
  1033. i = 1;
  1034. ASSERT(argc && argv && init);
  1035. while (i < *argc) {
  1036. if(argv[i][0] == '-') {
  1037. char *param = argv[i]+1;
  1038. switch (argv[i][1]) {
  1039. case 'M':
  1040. switch (argv[i][2]) {
  1041. case 'B':
  1042. handle_au_arg(&init->binary_alloc, &argv[i][3], argv, &i);
  1043. break;
  1044. case 'D':
  1045. handle_au_arg(&init->std_alloc, &argv[i][3], argv, &i);
  1046. break;
  1047. case 'E':
  1048. handle_au_arg(&init->ets_alloc, &argv[i][3], argv, &i);
  1049. break;
  1050. case 'F': /* fix_alloc */
  1051. if (has_prefix("e", param+2)) {
  1052. arg = get_value(param+3, argv, &i);
  1053. if (strcmp("true", arg) != 0)
  1054. bad_value(param, param+3, arg);
  1055. }
  1056. else
  1057. bad_param(param, param+2);
  1058. break;
  1059. case 'H':
  1060. handle_au_arg(&init->eheap_alloc, &argv[i][3], argv, &i);
  1061. break;
  1062. case 'L':
  1063. handle_au_arg(&init->ll_alloc, &argv[i][3], argv, &i);
  1064. break;
  1065. case 'M':
  1066. if (has_prefix("amcbf", argv[i]+3)) {
  1067. #if HAVE_ERTS_MSEG
  1068. init->mseg.amcbf =
  1069. #endif
  1070. get_kb_value(argv[i]+8, argv, &i);
  1071. }
  1072. else if (has_prefix("rmcbf", argv[i]+3)) {
  1073. #if HAVE_ERTS_MSEG
  1074. init->mseg.rmcbf =
  1075. #endif
  1076. get_amount_value(argv[i]+8, argv, &i);
  1077. }
  1078. else if (has_prefix("mcs", argv[i]+3)) {
  1079. #if HAVE_ERTS_MSEG
  1080. init->mseg.mcs =
  1081. #endif
  1082. get_amount_value(argv[i]+6, argv, &i);
  1083. }
  1084. else if (has_prefix("cci", argv[i]+3)) {
  1085. #if HAVE_ERTS_MSEG
  1086. init->mseg.cci =
  1087. #endif
  1088. get_amount_value(argv[i]+6, argv, &i);
  1089. }
  1090. else {
  1091. bad_param(param, param+2);
  1092. }
  1093. break;
  1094. case 'R':
  1095. handle_au_arg(&init->driver_alloc, &argv[i][3], argv, &i);
  1096. break;
  1097. case 'S':
  1098. handle_au_arg(&init->sl_alloc, &argv[i][3], argv, &i);
  1099. break;
  1100. case 'T':
  1101. handle_au_arg(&init->temp_alloc, &argv[i][3], argv, &i);
  1102. break;
  1103. case 'Y': { /* sys_alloc */
  1104. if (has_prefix("tt", param+2)) {
  1105. /* set trim threshold */
  1106. arg = get_value(param+4, argv, &i);
  1107. errno = 0;
  1108. init->trim_threshold = (int) strtol(arg, &rest, 10);
  1109. if (errno != 0
  1110. || rest == arg
  1111. || init->trim_threshold < 0
  1112. || (INT_MAX/1024) < init->trim_threshold) {
  1113. bad_value(param, param+4, arg);
  1114. }
  1115. VERBOSE(DEBUG_SYSTEM,
  1116. ("using trim threshold: %d\n",
  1117. init->trim_threshold));
  1118. init->trim_threshold *= 1024;
  1119. }
  1120. else if (has_prefix("tp", param+2)) {
  1121. /* set top pad */
  1122. arg = get_value(param+4, argv, &i);
  1123. errno = 0;
  1124. init->top_pad = (int) strtol(arg, &rest, 10);
  1125. if (errno != 0
  1126. || rest == arg
  1127. || init->top_pad < 0
  1128. || (INT_MAX/1024) < init->top_pad) {
  1129. bad_value(param, param+4, arg);
  1130. }
  1131. VERBOSE(DEBUG_SYSTEM,
  1132. ("using top pad: %d\n",init->top_pad));
  1133. init->top_pad *= 1024;
  1134. }
  1135. else if (has_prefix("m", param+2)) {
  1136. /* Has been handled by erlexec */
  1137. (void) get_value(param+3, argv, &i);
  1138. }
  1139. else if (has_prefix("e", param+2)) {
  1140. arg = get_value(param+3, argv, &i);
  1141. if (strcmp("true", arg) != 0)
  1142. bad_value(param, param+3, arg);
  1143. }
  1144. else
  1145. bad_param(param, param+2);
  1146. break;
  1147. }
  1148. case 'e':
  1149. switch (argv[i][3]) {
  1150. case 'a': {
  1151. int a;
  1152. arg = get_value(argv[i]+4, argv, &i);
  1153. if (strcmp("min", arg) == 0) {
  1154. for (a = 0; a < aui_sz; a++)
  1155. aui[a]->enable = 0;
  1156. }
  1157. else if (strcmp("max", arg) == 0) {
  1158. for (a = 0; a < aui_sz; a++)
  1159. aui[a]->enable = 1;
  1160. }
  1161. else if (strcmp("config", arg) == 0) {
  1162. init->erts_alloc_config = 1;
  1163. }
  1164. else if (strcmp("r9c", arg) == 0
  1165. || strcmp("r10b", arg) == 0
  1166. || strcmp("r11b", arg) == 0) {
  1167. set_default_sl_alloc_opts(&init->sl_alloc);
  1168. set_default_std_alloc_opts(&init->std_alloc);
  1169. set_default_ll_alloc_opts(&init->ll_alloc);
  1170. set_default_temp_alloc_opts(&init->temp_alloc);
  1171. set_default_eheap_alloc_opts(&init->eheap_alloc);
  1172. set_default_binary_alloc_opts(&init->binary_alloc);
  1173. set_default_ets_alloc_opts(&init->ets_alloc);
  1174. set_default_driver_alloc_opts(&init->driver_alloc);
  1175. init->driver_alloc.enable = 0;
  1176. if (strcmp("r9c", arg) == 0) {
  1177. init->sl_alloc.enable = 0;
  1178. init->std_alloc.enable = 0;
  1179. init->binary_alloc.enable = 0;
  1180. init->ets_alloc.enable = 0;
  1181. }
  1182. for (a = 0; a < aui_sz; a++) {
  1183. aui[a]->thr_spec = 0;
  1184. aui[a]->init.util.ramv = 0;
  1185. aui[a]->init.util.mmmbc = 10;
  1186. aui[a]->init.util.lmbcs = 5*1024*1024;
  1187. }
  1188. }
  1189. else {
  1190. bad_param(param, param+3);
  1191. }
  1192. break;
  1193. }
  1194. default:
  1195. bad_param(param, param+1);
  1196. }
  1197. break;
  1198. case 'i':
  1199. switch (argv[i][3]) {
  1200. case 's':
  1201. arg = get_value(argv[i]+4, argv, &i);
  1202. if (strcmp("true", arg) == 0)
  1203. init->instr.stat = 1;
  1204. else if (strcmp("false", arg) == 0)
  1205. init->instr.stat = 0;
  1206. else
  1207. bad_value(param, param+3, arg);
  1208. break;
  1209. case 'm':
  1210. arg = get_value(argv[i]+4, argv, &i);
  1211. if (strcmp("true", arg) == 0)
  1212. init->instr.map = 1;
  1213. else if (strcmp("false", arg) == 0)
  1214. init->instr.map = 0;
  1215. else
  1216. bad_value(param, param+3, arg);
  1217. break;
  1218. case 't':
  1219. init->instr.mtrace = get_value(argv[i]+4, argv, &i);
  1220. break;
  1221. default:
  1222. bad_param(param, param+2);
  1223. }
  1224. break;
  1225. case 'u':
  1226. if (has_prefix("ycs", argv[i]+3)) {
  1227. init->alloc_util.ycs
  1228. = get_kb_value(argv[i]+6, argv, &i);
  1229. }
  1230. else if (has_prefix("mmc", argv[i]+3)) {
  1231. init->alloc_util.mmc
  1232. = get_amount_value(argv[i]+6, argv, &i);
  1233. }
  1234. else {
  1235. int a;
  1236. int start = i;
  1237. char *param = argv[i];
  1238. char *val = i+1 < *argc ? argv[i+1] : NULL;
  1239. for (a = 0; a < aui_sz; a++) {
  1240. if (a > 0) {
  1241. ASSERT(i == start || i == start+1);
  1242. argv[start] = param;
  1243. if (i != start)
  1244. argv[start + 1] = val;
  1245. i = start;
  1246. }
  1247. handle_au_arg(aui[a], &argv[i][3], argv, &i);
  1248. }
  1249. }
  1250. break;
  1251. default:
  1252. bad_param(param, param+1);
  1253. }
  1254. break;
  1255. case '-':
  1256. if (argv[i][2] == '\0') {
  1257. /* End of system flags reached */
  1258. if (init->instr.mtrace
  1259. /* || init->instr.stat
  1260. || init->instr.map */) {
  1261. while (i < *argc) {
  1262. if(strcmp(argv[i], "-sname") == 0
  1263. || strcmp(argv[i], "-name") == 0) {
  1264. if (i + 1 <*argc) {
  1265. init->instr.nodename = argv[i+1];
  1266. break;
  1267. }
  1268. }
  1269. i++;
  1270. }
  1271. }
  1272. goto args_parsed;
  1273. }
  1274. break;
  1275. default:
  1276. break;
  1277. }
  1278. }
  1279. i++;
  1280. }
  1281. args_parsed:
  1282. /* Handled arguments have been marked with NULL. Slide arguments
  1283. not handled towards the beginning of argv. */
  1284. for (i = 0, j = 0; i < *argc; i++) {
  1285. if (argv[i])
  1286. argv[j++] = argv[i];
  1287. }
  1288. *argc = j;
  1289. }
  1290. static char *type_no_str(ErtsAlcType_t n)
  1291. {
  1292. #if ERTS_ALC_N_MIN != 0
  1293. if (n < ERTS_ALC_N_MIN)
  1294. return NULL;
  1295. #endif
  1296. if (n > ERTS_ALC_N_MAX)
  1297. return NULL;
  1298. return (char *) ERTS_ALC_N2TD(n);
  1299. }
  1300. #define type_str(T) type_no_str(ERTS_ALC_T2N((T)))
  1301. erts_tsd_key_t thr_ix_key;
  1302. erts_spinlock_t alloc_thr_ix_lock;
  1303. int last_thr_ix;
  1304. int first_dyn_thr_ix;
  1305. static void
  1306. init_thr_ix(int static_ixs)
  1307. {
  1308. erts_tsd_key_create(&thr_ix_key);
  1309. erts_spinlock_init(&alloc_thr_ix_lock, "alloc_thr_ix_lock");
  1310. last_thr_ix = -4711;
  1311. first_dyn_thr_ix = static_ixs+1;
  1312. }
  1313. int
  1314. erts_alc_get_thr_ix(void)
  1315. {
  1316. int ix = (int)(long) erts_tsd_get(thr_ix_key);
  1317. if (ix == 0) {
  1318. erts_spin_lock(&alloc_thr_ix_lock);
  1319. last_thr_ix++;
  1320. if (last_thr_ix < 0)
  1321. last_thr_ix = first_dyn_thr_ix;
  1322. ix = last_thr_ix;
  1323. erts_spin_unlock(&alloc_thr_ix_lock);
  1324. erts_tsd_set(thr_ix_key, (void *)(long) ix);
  1325. }
  1326. ASSERT(ix > 0);
  1327. return ix;
  1328. }
  1329. void erts_alloc_reg_scheduler_id(Uint id)
  1330. {
  1331. int ix = (int) id;
  1332. ASSERT(0 < ix && ix <= first_dyn_thr_ix);
  1333. ASSERT(0 == (int) (long) erts_tsd_get(thr_ix_key));
  1334. erts_tsd_set(thr_ix_key, (void *)(long) ix);
  1335. }
  1336. static void
  1337. no_verify(Allctr_t *allctr)
  1338. {
  1339. }
  1340. erts_alloc_verify_func_t
  1341. erts_alloc_get_verify_unused_temp_alloc(Allctr_t **allctr)
  1342. {
  1343. if (erts_allctrs_info[ERTS_ALC_A_TEMPORARY].alloc_util
  1344. && erts_allctrs_info[ERTS_ALC_A_TEMPORARY].thr_spec) {
  1345. ErtsAllocatorThrSpec_t *tspec;
  1346. tspec = &erts_allctr_thr_spec[ERTS_ALC_A_TEMPORARY];
  1347. if (!tspec->all_thr_safe) {
  1348. int ix = erts_alc_get_thr_ix();
  1349. if (ix < tspec->size) {
  1350. *allctr = tspec->allctr[ix];
  1351. return erts_alcu_verify_unused;
  1352. }
  1353. }
  1354. }
  1355. *allctr = NULL;
  1356. return no_verify;
  1357. }
  1358. __decl_noreturn void
  1359. erts_alc_fatal_error(int error, int func, ErtsAlcType_t n, ...)
  1360. {
  1361. char buf[10];
  1362. char *t_str;
  1363. char *allctr_str;
  1364. ASSERT(n >= ERTS_ALC_N_MIN);
  1365. ASSERT(n <= ERTS_ALC_N_MAX);
  1366. if (n < ERTS_ALC_N_MIN || ERTS_ALC_N_MAX < n)
  1367. allctr_str = "UNKNOWN";
  1368. else {
  1369. ErtsAlcType_t a = ERTS_ALC_T2A(ERTS_ALC_N2T(n));
  1370. if (erts_allctrs_info[a].enabled)
  1371. allctr_str = (char *) ERTS_ALC_A2AD(a);
  1372. else
  1373. allctr_str = (char *) ERTS_ALC_A2AD(ERTS_ALC_A_SYSTEM);
  1374. }
  1375. t_str = type_no_str(n);
  1376. if (!t_str) {
  1377. sprintf(buf, "%d", (int) n);
  1378. t_str = buf;
  1379. }
  1380. switch (error) {
  1381. case ERTS_ALC_E_NOTSUP: {
  1382. char *op_str;
  1383. switch (func) {
  1384. case ERTS_ALC_O_ALLOC: op_str = "alloc"; break;
  1385. case ERTS_ALC_O_REALLOC: op_str = "realloc"; break;
  1386. case ERTS_ALC_O_FREE: op_str = "free"; break;
  1387. default: op_str = "UNKNOWN"; break;
  1388. }
  1389. erl_exit(ERTS_ABORT_EXIT,
  1390. "%s: %s operation not supported (memory type: \"%s\")\n",
  1391. allctr_str, op_str, t_str);
  1392. break;
  1393. }
  1394. case ERTS_ALC_E_NOMEM: {
  1395. Uint size;
  1396. va_list argp;
  1397. char *op = func == ERTS_ALC_O_REALLOC ? "reallocate" : "allocate";
  1398. va_start(argp, n);
  1399. size = va_arg(argp, Uint);
  1400. va_end(argp);
  1401. erl_exit(1,
  1402. "%s: Cannot %s %lu bytes of memory (of type \"%s\").\n",
  1403. allctr_str, op, size, t_str);
  1404. break;
  1405. }
  1406. case ERTS_ALC_E_NOALLCTR:
  1407. erl_exit(ERTS_ABORT_EXIT,
  1408. "erts_alloc: Unknown allocator type: %d\n",
  1409. ERTS_ALC_T2A(ERTS_ALC_N2T(n)));
  1410. break;
  1411. default:
  1412. erl_exit(ERTS_ABORT_EXIT, "erts_alloc: Unknown error: %d\n", error);
  1413. break;
  1414. }
  1415. }
  1416. __decl_noreturn void
  1417. erts_alloc_enomem(ErtsAlcType_t type, Uint size)
  1418. {
  1419. erts_alloc_n_enomem(ERTS_ALC_T2N(type), size);
  1420. }
  1421. __decl_noreturn void
  1422. erts_alloc_n_enomem(ErtsAlcType_t n, Uint size)
  1423. {
  1424. erts_alc_fatal_error(ERTS_ALC_E_NOMEM, ERTS_ALC_O_ALLOC, n, size);
  1425. }
  1426. __decl_noreturn void
  1427. erts_realloc_enomem(ErtsAlcType_t type, void *ptr, Uint size)
  1428. {
  1429. erts_realloc_n_enomem(ERTS_ALC_T2N(type), ptr, size);
  1430. }
  1431. __decl_noreturn void
  1432. erts_realloc_n_enomem(ErtsAlcType_t n, void *ptr, Uint size)
  1433. {
  1434. erts_alc_fatal_error(ERTS_ALC_E_NOMEM, ERTS_ALC_O_REALLOC, n, size);
  1435. }
  1436. static ERTS_INLINE UWord
  1437. alcu_size(ErtsAlcType_t ai)
  1438. {
  1439. UWord res = 0;
  1440. ASSERT(erts_allctrs_info[ai].enabled);
  1441. ASSERT(erts_allctrs_info[ai].alloc_util);
  1442. if (!erts_allctrs_info[ai].thr_spec) {
  1443. Allctr_t *allctr = erts_allctrs_info[ai].extra;
  1444. AllctrSize_t asize;
  1445. erts_alcu_current_size(allctr, &asize);
  1446. res += asize.blocks;
  1447. }
  1448. else {
  1449. ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[ai];
  1450. int i;
  1451. ASSERT(tspec->all_thr_safe);
  1452. ASSERT(tspec->enabled);
  1453. for (i = tspec->size - 1; i >= 0; i--) {
  1454. Allctr_t *allctr = tspec->allctr[i];
  1455. AllctrSize_t asize;
  1456. if (allctr) {
  1457. erts_alcu_current_size(allctr, &asize);
  1458. res += asize.blocks;
  1459. }
  1460. }
  1461. }
  1462. return res;
  1463. }
  1464. #if HALFWORD_HEAP
  1465. static ERTS_INLINE int
  1466. alcu_is_low(ErtsAlcType_t ai)
  1467. {
  1468. int is_low = 0;
  1469. ASSERT(erts_allctrs_info[ai].enabled);
  1470. ASSERT(erts_allctrs_info[ai].alloc_util);
  1471. if (!erts_allctrs_info[ai].thr_spec) {
  1472. Allctr_t *allctr = erts_allctrs_info[ai].extra;
  1473. is_low = allctr->mseg_opt.low_mem;
  1474. }
  1475. else {
  1476. ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[ai];
  1477. int i;
  1478. # ifdef DEBUG
  1479. int found_one = 0;
  1480. # endif
  1481. ASSERT(tspec->all_thr_safe);
  1482. ASSERT(tspec->enabled);
  1483. for (i = tspec->size - 1; i >= 0; i--) {
  1484. Allctr_t *allctr = tspec->allctr[i];
  1485. if (allctr) {
  1486. # ifdef DEBUG
  1487. if (!found_one) {
  1488. is_low = allctr->mseg_opt.low_mem;
  1489. found_one = 1;
  1490. }
  1491. else ASSERT(is_low == allctr->mseg_opt.low_mem);
  1492. # else
  1493. is_low = allctr->mseg_opt.low_mem;
  1494. break;
  1495. # endif
  1496. }
  1497. }
  1498. ASSERT(found_one);
  1499. }
  1500. return is_low;
  1501. }
  1502. #endif /* HALFWORD */
  1503. Eterm
  1504. erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg)
  1505. {
  1506. #define ERTS_MEM_NEED_ALL_ALCU (!erts_instr_stat && want_tot_or_sys)
  1507. ErtsFixInfo efi;
  1508. struct {
  1509. int total;
  1510. int processes;
  1511. int processes_used;
  1512. int system;
  1513. int atom;
  1514. int atom_used;
  1515. int binary;
  1516. int code;
  1517. int ets;
  1518. int maximum;
  1519. #if HALFWORD_HEAP
  1520. int low;
  1521. #endif
  1522. } want = {0};
  1523. struct {
  1524. UWord total;
  1525. UWord processes;
  1526. UWord processes_used;
  1527. UWord system;
  1528. UWord atom;
  1529. UWord atom_used;
  1530. UWord binary;
  1531. UWord code;
  1532. UWord ets;
  1533. UWord maximum;
  1534. #if HALFWORD_HEAP
  1535. UWord low;
  1536. #endif
  1537. } size = {0};
  1538. Eterm atoms[sizeof(size)/sizeof(UWord)];
  1539. UWord *uintps[sizeof(size)/sizeof(UWord)];
  1540. Eterm euints[sizeof(size)/sizeof(UWord)];
  1541. int want_tot_or_sys;
  1542. int length;
  1543. Eterm res = THE_NON_VALUE;
  1544. ErtsAlcType_t ai;
  1545. int only_one_value = 0;
  1546. /* Figure out whats wanted... */
  1547. length = 0;
  1548. if (is_non_value(earg)) { /* i.e. wants all */
  1549. want.total = 1;
  1550. atoms[length] = am_total;
  1551. uintps[length++] = &size.total;
  1552. want.processes = 1;
  1553. atoms[length] = am_processes;
  1554. uintps[length++] = &size.processes;
  1555. want.processes_used = 1;
  1556. atoms[length] = am_processes_used;
  1557. uintps[length++] = &size.processes_used;
  1558. want.system = 1;
  1559. atoms[length] = am_system;
  1560. uintps[length++] = &size.system;
  1561. want.atom = 1;
  1562. atoms[length] = am_atom;
  1563. uintps[length++] = &size.atom;
  1564. want.atom_used = 1;
  1565. atoms[length] = am_atom_used;
  1566. uintps[length++] = &size.atom_used;
  1567. want.binary = 1;
  1568. atoms[length] = am_binary;
  1569. uintps[length++] = &size.binary;
  1570. want.code = 1;
  1571. atoms[length] = am_code;
  1572. uintps[length++] = &size.code;
  1573. want.ets = 1;
  1574. atoms[length] = am_ets;
  1575. uintps[length++] = &size.ets;
  1576. want.maximum = erts_instr_stat;
  1577. if (want.maximum) {
  1578. atoms[length] = am_maximum;
  1579. uintps[length++] = &size.maximum;
  1580. }
  1581. #if HALFWORD_HEAP
  1582. want.low = 1;
  1583. atoms[length] = am_low;
  1584. uintps[length++] = &size.low;
  1585. #endif
  1586. }
  1587. else {
  1588. DeclareTmpHeapNoproc(tmp_heap,2);
  1589. Eterm wanted_list;
  1590. if (is_nil(earg))
  1591. return NIL;
  1592. UseTmpHeapNoproc(2);
  1593. if (is_not_atom(earg))
  1594. wanted_list = earg;
  1595. else {
  1596. wanted_list = CONS(&tmp_heap[0], earg, NIL);
  1597. only_one_value = 1;
  1598. }
  1599. while (is_list(wanted_list)) {
  1600. switch (CAR(list_val(wanted_list))) {
  1601. case am_total:
  1602. if (!want.total) {
  1603. want.total = 1;
  1604. atoms[length] = am_total;
  1605. uintps[length++] = &size.total;
  1606. }
  1607. break;
  1608. case am_processes:
  1609. if (!want.processes) {
  1610. want.processes = 1;
  1611. atoms[length] = am_processes;
  1612. uintps[length++] = &size.processes;
  1613. }
  1614. break;
  1615. case am_processes_used:
  1616. if (!want.processes_used) {
  1617. want.processes_used = 1;
  1618. atoms[length] = am_processes_used;
  1619. uintps[length++] = &size.processes_used;
  1620. }
  1621. break;
  1622. case am_system:
  1623. if (!want.system) {
  1624. want.system = 1;
  1625. atoms[length] = am_system;
  1626. uintps[length++] = &size.system;
  1627. }
  1628. break;
  1629. case am_atom:
  1630. if (!want.atom) {
  1631. want.atom = 1;
  1632. atoms[length] = am_atom;
  1633. uintps[length++] = &size.atom;
  1634. }
  1635. break;
  1636. case am_atom_used:
  1637. if (!want.atom_used) {
  1638. want.atom_used = 1;
  1639. atoms[length] = am_atom_used;
  1640. uintps[length++] = &size.atom_used;
  1641. }
  1642. break;
  1643. case am_binary:
  1644. if (!want.binary) {
  1645. want.binary = 1;
  1646. atoms[length] = am_binary;
  1647. uintps[length++] = &size.binary;
  1648. }
  1649. break;
  1650. case am_code:
  1651. if (!want.code) {
  1652. want.code = 1;
  1653. atoms[length] = am_code;
  1654. uintps[length++] = &size.code;
  1655. }
  1656. break;
  1657. case am_ets:
  1658. if (!want.ets) {
  1659. want.ets = 1;
  1660. atoms[length] = am_ets;
  1661. uintps[length++] = &size.ets;
  1662. }
  1663. break;
  1664. case am_maximum:
  1665. if (erts_instr_stat) {
  1666. if (!want.maximum) {
  1667. want.maximum = 1;
  1668. atoms[length] = am_maximum;
  1669. uintps[length++] = &size.maximum;
  1670. }
  1671. } else {
  1672. UnUseTmpHeapNoproc(2);
  1673. return am_badarg;
  1674. }
  1675. break;
  1676. #if HALFWORD_HEAP
  1677. case am_low:
  1678. if (!want.low) {
  1679. want.low = 1;
  1680. atoms[length] = am_low;
  1681. uintps[length++] = &size.low;
  1682. }
  1683. break;
  1684. #endif
  1685. default:
  1686. UnUseTmpHeapNoproc(2);
  1687. return am_badarg;
  1688. }
  1689. wanted_list = CDR(list_val(wanted_list));
  1690. }
  1691. UnUseTmpHeapNoproc(2);
  1692. if (is_not_nil(wanted_list))
  1693. return am_badarg;
  1694. }
  1695. /* All alloc_util allocators *have* to be enabled */
  1696. for (ai = ERTS_ALC_A_MIN; ai <= ERTS_ALC_A_MAX; ai++) {
  1697. switch (ai) {
  1698. case ERTS_ALC_A_SYSTEM:
  1699. case ERTS_ALC_A_FIXED_SIZE:
  1700. break;
  1701. default:
  1702. if (!erts_allctrs_info[ai].enabled
  1703. || !erts_allctrs_info[ai].alloc_util) {
  1704. return am_notsup;
  1705. }
  1706. break;
  1707. }
  1708. }
  1709. ASSERT(length <= sizeof(atoms)/sizeof(Eterm));
  1710. ASSERT(length <= sizeof(euints)/sizeof(Eterm));
  1711. ASSERT(length <= sizeof(uintps)/sizeof(UWord));
  1712. if (proc) {
  1713. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN
  1714. == erts_proc_lc_my_proc_locks(proc));
  1715. /* We'll need locks early in the lock order */
  1716. erts_smp_proc_unlock(proc, ERTS_PROC_LOCK_MAIN);
  1717. }
  1718. /* Calculate values needed... */
  1719. want_tot_or_sys = want.total || want.system;
  1720. if (ERTS_MEM_NEED_ALL_ALCU) {
  1721. size.total = 0;
  1722. for (ai = ERTS_ALC_A_MIN; ai <= ERTS_ALC_A_MAX; ai++) {
  1723. if (erts_allctrs_info[ai].alloc_util) {
  1724. UWord *save;
  1725. UWord asz;
  1726. switch (ai) {
  1727. case ERTS_ALC_A_TEMPORARY:
  1728. /*
  1729. * Often not thread safe and usually never
  1730. * contain any allocated memory.
  1731. */
  1732. continue;
  1733. case ERTS_ALC_A_EHEAP:
  1734. save = &size.processes;
  1735. break;
  1736. case ERTS_ALC_A_ETS:
  1737. save = &size.ets;
  1738. break;
  1739. case ERTS_ALC_A_BINARY:
  1740. save = &size.binary;
  1741. break;
  1742. default:
  1743. save = NULL;
  1744. break;
  1745. }
  1746. asz = alcu_size(ai);
  1747. if (save)
  1748. *save = asz;
  1749. size.total += asz;
  1750. #if HALFWORD_HEAP
  1751. if (alcu_is_low(ai)) {
  1752. size.low += asz;
  1753. }
  1754. #endif
  1755. }
  1756. }
  1757. }
  1758. if (want_tot_or_sys || want.processes || want.processes_used) {
  1759. UWord tmp;
  1760. if (ERTS_MEM_NEED_ALL_ALCU)
  1761. tmp = size.processes;
  1762. else
  1763. tmp = alcu_size(ERTS_ALC_A_EHEAP);
  1764. tmp += erts_max_processes*sizeof(Process*);
  1765. #ifdef HYBRID
  1766. tmp += erts_max_processes*sizeof(Process*);
  1767. #endif
  1768. tmp += erts_bif_timer_memory_size();
  1769. tmp += erts_tot_link_lh_size();
  1770. size.processes = size.processes_used = tmp;
  1771. #if HALFWORD_HEAP
  1772. /* BUG: We ignore link and monitor memory */
  1773. #else
  1774. erts_fix_info(ERTS_ALC_T_NLINK_SH, &efi);
  1775. size.processes += efi.total;
  1776. size.processes_used += efi.used;
  1777. erts_fix_info(ERTS_ALC_T_MONITOR_SH, &efi);
  1778. size.processes += efi.total;
  1779. size.processes_used += efi.used;
  1780. #endif
  1781. erts_fix_info(ERTS_ALC_T_PROC, &efi);
  1782. size.processes += efi.total;
  1783. size.processes_used += efi.used;
  1784. erts_fix_info(ERTS_ALC_T_REG_PROC, &efi);
  1785. size.processes += efi.total;
  1786. size.processes_used += efi.used;
  1787. }
  1788. if (want.atom || want.atom_used) {
  1789. Uint reserved_atom_space, atom_space;
  1790. erts_atom_get_text_space_sizes(&reserved_atom_space, &atom_space);
  1791. size.atom = size.atom_used = atom_table_sz();
  1792. erts_fix_info(ERTS_ALC_T_ATOM, &efi);
  1793. if (want.atom) {
  1794. size.atom += reserved_atom_space;
  1795. size.atom += efi.total;
  1796. }
  1797. if (want.atom_used) {
  1798. size.atom_used += atom_space;
  1799. size.atom_used += efi.used;
  1800. }
  1801. }
  1802. if (!ERTS_MEM_NEED_ALL_ALCU && want.binary)
  1803. size.binary = alcu_size(ERTS_ALC_A_BINARY);
  1804. if (want.code) {
  1805. size.code = module_table_sz();
  1806. erts_fix_info(ERTS_ALC_T_MODULE, &efi);
  1807. size.code += efi.used;
  1808. size.code += export_table_sz();
  1809. #if HALFWORD_HEAP
  1810. size.code += export_list_size() * sizeof(Export);
  1811. #else
  1812. erts_fix_info(ERTS_ALC_T_EXPORT, &efi);
  1813. size.code += efi.used;
  1814. #endif
  1815. size.code += erts_fun_table_sz();
  1816. erts_fix_info(ERTS_ALC_T_FUN_ENTRY, &efi);
  1817. size.code += efi.used;
  1818. size.code += allocated_modules*sizeof(Range);
  1819. size.code += erts_total_code_size;
  1820. }
  1821. if (want.ets) {
  1822. if (!ERTS_MEM_NEED_ALL_ALCU)
  1823. size.ets = alcu_size(ERTS_ALC_A_ETS);
  1824. size.ets += erts_get_ets_misc_mem_size();
  1825. }
  1826. if (erts_instr_stat && (want_tot_or_sys || want.maximum)) {
  1827. if (want_tot_or_sys) {
  1828. size.total = erts_instr_get_total();
  1829. size.system = size.total - size.processes;
  1830. }
  1831. size.maximum = erts_instr_get_max_total();
  1832. }
  1833. else if (want_tot_or_sys) {
  1834. size.system = size.total - size.processes;
  1835. }
  1836. if (print_to_p) {
  1837. int i;
  1838. int to = *print_to_p;
  1839. void *arg = print_to_arg;
  1840. /* Print result... */
  1841. erts_print(to, arg, "=memory\n");
  1842. for (i = 0; i < length; i++)
  1843. erts_print(to, arg, "%T: %bpu\n", atoms[i], *uintps[i]);
  1844. }
  1845. if (proc) {
  1846. /* Build erlang term result... */
  1847. Uint *hp;
  1848. Uint hsz;
  1849. erts_smp_proc_lock(proc, ERTS_PROC_LOCK_MAIN);
  1850. if (only_one_value) {
  1851. ASSERT(length == 1);
  1852. hsz = 0;
  1853. erts_bld_uword(NULL, &hsz, *uintps[0]);
  1854. hp = hsz ? HAlloc((Process *) proc, hsz) : NULL;
  1855. res = erts_bld_uword(&hp, NULL, *uintps[0]);
  1856. }
  1857. else {
  1858. Uint **hpp = NULL;
  1859. Uint *hszp = &hsz;
  1860. hsz = 0;
  1861. while (1) {
  1862. int i;
  1863. for (i = 0; i < length; i++)
  1864. euints[i] = erts_bld_uword(hpp, hszp, *uintps[i]);
  1865. res = erts_bld_2tup_list(hpp, hszp, length, atoms, euints);
  1866. if (hpp)
  1867. break;
  1868. hp = HAlloc((Process *) proc, hsz);
  1869. hpp = &hp;
  1870. hszp = NULL;
  1871. }
  1872. }
  1873. }
  1874. return res;
  1875. #undef ERTS_MEM_NEED_ALL_ALCU
  1876. }
  1877. struct aa_values {
  1878. Uint arity;
  1879. const char *name;
  1880. Uint ui[2];
  1881. };
  1882. Eterm
  1883. erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc)
  1884. {
  1885. #define MAX_AA_VALUES \
  1886. (20 + (ERTS_ALC_N_MAX_A_FIXED_SIZE - ERTS_ALC_N_MIN_A_FIXED_SIZE + 1))
  1887. struct aa_values values[MAX_AA_VALUES];
  1888. Eterm res = THE_NON_VALUE;
  1889. int i, length;
  1890. ErtsFixInfo efi;
  1891. Uint reserved_atom_space, atom_space;
  1892. if (proc) {
  1893. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN
  1894. == erts_proc_lc_my_proc_locks(proc));
  1895. /* We'll need locks early in the lock order */
  1896. erts_smp_proc_unlock(proc, ERTS_PROC_LOCK_MAIN);
  1897. }
  1898. i = 0;
  1899. if (erts_instr_stat) {
  1900. values[i].arity = 2;
  1901. values[i].name = "total";
  1902. values[i].ui[0] = erts_instr_get_total();
  1903. i++;
  1904. values[i].arity = 2;
  1905. values[i].name = "maximum";
  1906. values[i].ui[0] = erts_instr_get_max_total();
  1907. i++;
  1908. }
  1909. values[i].arity = 2;
  1910. values[i].name = "sys_misc";
  1911. values[i].ui[0] = erts_sys_misc_mem_sz();
  1912. i++;
  1913. values[i].arity = 2;
  1914. values[i].name = "static";
  1915. values[i].ui[0] =
  1916. erts_max_ports*sizeof(Port) /* Port table */
  1917. + erts_timer_wheel_memory_size() /* Timer wheel */
  1918. #ifdef SYS_TMP_BUF_SIZE
  1919. + SYS_TMP_BUF_SIZE /* tmp_buf in sys on vxworks & ose */
  1920. #endif
  1921. ;
  1922. i++;
  1923. erts_atom_get_text_space_sizes(&reserved_atom_space, &atom_space);
  1924. values[i].arity = 3;
  1925. values[i].name = "atom_space";
  1926. values[i].ui[0] = reserved_atom_space;
  1927. values[i].ui[1] = atom_space;
  1928. i++;
  1929. values[i].arity = 2;
  1930. values[i].name = "atom_table";
  1931. values[i].ui[0] = atom_table_sz();
  1932. i++;
  1933. values[i].arity = 2;
  1934. values[i].name = "module_table";
  1935. values[i].ui[0] = module_table_sz();
  1936. i++;
  1937. values[i].arity = 2;
  1938. values[i].name = "export_table";
  1939. values[i].ui[0] = export_table_sz();
  1940. i++;
  1941. values[i].arity = 2;
  1942. values[i].name = "register_table";
  1943. values[i].ui[0] = process_reg_sz();
  1944. i++;
  1945. values[i].arity = 2;
  1946. values[i].name = "fun_table";
  1947. values[i].ui[0] = erts_fun_table_sz();
  1948. i++;
  1949. values[i].arity = 2;
  1950. values[i].name = "module_refs";
  1951. values[i].ui[0] = allocated_modules*sizeof(Range);
  1952. i++;
  1953. values[i].arity = 2;
  1954. values[i].name = "loaded_code";
  1955. values[i].ui[0] = erts_total_code_size;
  1956. i++;
  1957. values[i].arity = 2;
  1958. values[i].name = "dist_table";
  1959. values[i].ui[0] = erts_dist_table_size();
  1960. i++;
  1961. values[i].arity = 2;
  1962. values[i].name = "node_table";
  1963. values[i].ui[0] = erts_node_table_size();
  1964. i++;
  1965. values[i].arity = 2;
  1966. values[i].name = "bits_bufs_size";
  1967. values[i].ui[0] = erts_bits_bufs_size();
  1968. i++;
  1969. values[i].arity = 2;
  1970. values[i].name = "bif_timer";
  1971. values[i].ui[0] = erts_bif_timer_memory_size();
  1972. i++;
  1973. values[i].arity = 2;
  1974. values[i].name = "link_lh";
  1975. values[i].ui[0] = erts_tot_link_lh_size();
  1976. i++;
  1977. {
  1978. Uint n;
  1979. for (n = ERTS_ALC_N_MIN_A_FIXED_SIZE;
  1980. n <= ERTS_ALC_N_MAX_A_FIXED_SIZE;
  1981. n++) {
  1982. erts_fix_info(ERTS_ALC_N2T(n), &efi);
  1983. values[i].arity = 3;
  1984. values[i].name = ERTS_ALC_N2TD(n);
  1985. values[i].ui[0] = efi.total;
  1986. values[i].ui[1] = efi.used;
  1987. i++;
  1988. }
  1989. }
  1990. length = i;
  1991. ASSERT(length <= MAX_AA_VALUES);
  1992. if (print_to_p) {
  1993. /* Print result... */
  1994. int to = *print_to_p;
  1995. void *arg = print_to_arg;
  1996. erts_print(to, arg, "=allocated_areas\n");
  1997. for (i = 0; i < length; i++) {
  1998. switch (values[i].arity) {
  1999. case 2:
  2000. erts_print(to, arg, "%s: %beu\n",
  2001. values[i].name, values[i].ui[0]);
  2002. break;
  2003. case 3:
  2004. erts_print(to, arg, "%s: %beu %beu\n",
  2005. values[i].name, values[i].ui[0], values[i].ui[1]);
  2006. break;
  2007. default:
  2008. erts_print(to, arg, "ERROR: internal_error\n");
  2009. ASSERT(0);
  2010. return am_internal_error;
  2011. }
  2012. }
  2013. }
  2014. if (proc) {
  2015. /* Build erlang term result... */
  2016. Eterm tuples[MAX_AA_VALUES];
  2017. Uint *hp;
  2018. Uint **hpp;
  2019. Uint hsz;
  2020. Uint *hszp;
  2021. erts_smp_proc_lock(proc, ERTS_PROC_LOCK_MAIN);
  2022. hpp = NULL;
  2023. hsz = 0;
  2024. hszp = &hsz;
  2025. while (1) {
  2026. int i;
  2027. for (i = 0; i < length; i++) {
  2028. Eterm atom;
  2029. if (hpp)
  2030. atom = am_atom_put(values[i].name,
  2031. (int) strlen(values[i].name));
  2032. else
  2033. atom = am_true;
  2034. switch (values[i].arity) {
  2035. case 2:
  2036. tuples[i] = erts_bld_tuple(hpp, hszp, 2,
  2037. atom,
  2038. erts_bld_uint(hpp, hszp,
  2039. values[i].ui[0]));
  2040. break;
  2041. case 3:
  2042. tuples[i] = erts_bld_tuple(hpp, hszp, 3,
  2043. atom,
  2044. erts_bld_uint(hpp, hszp,
  2045. values[i].ui[0]),
  2046. erts_bld_uint(hpp, hszp,
  2047. values[i].ui[1]));
  2048. break;
  2049. default:
  2050. ASSERT(0);
  2051. return am_internal_error;
  2052. }
  2053. }
  2054. res = erts_bld_list(hpp, hszp, length, tuples);
  2055. if (hpp)
  2056. break;
  2057. hp = HAlloc((Process *) proc, hsz);
  2058. hpp = &hp;
  2059. hszp = NULL;
  2060. }
  2061. }
  2062. return res;
  2063. #undef MAX_AA_VALUES
  2064. }
  2065. Eterm
  2066. erts_alloc_util_allocators(void *proc)
  2067. {
  2068. Eterm res;
  2069. Uint *hp;
  2070. Uint sz;
  2071. int i;
  2072. /*
  2073. * Currently all allocators except sys_alloc and fix_alloc are
  2074. * alloc_util allocators.
  2075. */
  2076. sz = ((ERTS_ALC_A_MAX + 1 - ERTS_ALC_A_MIN) - 2)*2;
  2077. ASSERT(sz > 0);
  2078. hp = HAlloc((Process *) proc, sz);
  2079. res = NIL;
  2080. for (i = ERTS_ALC_A_MAX; i >= ERTS_ALC_A_MIN; i--) {
  2081. switch (i) {
  2082. case ERTS_ALC_A_SYSTEM:
  2083. case ERTS_ALC_A_FIXED_SIZE:
  2084. break;
  2085. default: {
  2086. char *alc_str = (char *) ERTS_ALC_A2AD(i);
  2087. Eterm alc = am_atom_put(alc_str, sys_strlen(alc_str));
  2088. res = CONS(hp, alc, res);
  2089. hp += 2;
  2090. break;
  2091. }
  2092. }
  2093. }
  2094. return res;
  2095. }
  2096. Eterm
  2097. erts_allocator_info_term(void *proc, Eterm which_alloc, int only_sz)
  2098. {
  2099. #define ERTS_AIT_RET(R) \
  2100. do { res = (R); goto done; } while (0)
  2101. #define ERTS_AIT_HALLOC(P, S) \
  2102. do { hp = HAlloc((P), (S)); hp_end = hp + (S); } while (0)
  2103. ErtsAlcType_t i;
  2104. Uint sz = 0;
  2105. Uint *hp = NULL;
  2106. Uint *hp_end = NULL;
  2107. Eterm res = am_undefined;
  2108. if (is_not_atom(which_alloc))
  2109. goto done;
  2110. for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) {
  2111. if (erts_is_atom_str((char *) ERTS_ALC_A2AD(i), which_alloc)) {
  2112. if (!erts_allctrs_info[i].enabled)
  2113. ERTS_AIT_RET(am_false);
  2114. else {
  2115. if (erts_allctrs_info[i].alloc_util) {
  2116. Eterm ires, tmp;
  2117. Eterm **hpp;
  2118. Uint *szp;
  2119. Eterm (*info_func)(Allctr_t *,
  2120. int,
  2121. int *,
  2122. void *,
  2123. Uint **,
  2124. Uint *);
  2125. info_func = (only_sz
  2126. ? erts_alcu_sz_info
  2127. : erts_alcu_info);
  2128. if (erts_allctrs_info[i].thr_spec) {
  2129. ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[i];
  2130. int j;
  2131. int block_system = !tspec->all_thr_safe;
  2132. if (block_system) {
  2133. erts_smp_proc_unlock(proc, ERTS_PROC_LOCK_MAIN);
  2134. erts_smp_block_system(0);
  2135. }
  2136. ASSERT(tspec->enabled);
  2137. szp = &sz;
  2138. hpp = NULL;
  2139. while (1) {
  2140. ires = NIL;
  2141. for (j = tspec->size - 1; j >= 0; j--) {
  2142. Allctr_t *allctr = tspec->allctr[j];
  2143. if (allctr) {
  2144. tmp = erts_bld_tuple(hpp,
  2145. szp,
  2146. 3,
  2147. erts_bld_atom(hpp,
  2148. szp,
  2149. "instance"),
  2150. make_small((Uint) j),
  2151. (*info_func)(allctr,
  2152. hpp != NULL,
  2153. NULL,
  2154. NULL,
  2155. hpp,
  2156. szp));
  2157. ires = erts_bld_cons(hpp, szp, tmp, ires);
  2158. }
  2159. }
  2160. if (hpp)
  2161. break;
  2162. ERTS_AIT_HALLOC((Process *) proc, sz);
  2163. hpp = &hp;
  2164. szp = NULL;
  2165. }
  2166. if (block_system) {
  2167. erts_smp_release_system();
  2168. erts_smp_proc_lock(proc, ERTS_PROC_LOCK_MAIN);
  2169. }
  2170. }
  2171. else {
  2172. Allctr_t *allctr = erts_allctrs_info[i].extra;
  2173. szp = &sz;
  2174. hpp = NULL;
  2175. while (1) {
  2176. ires = NIL;
  2177. tmp = erts_bld_tuple(hpp,
  2178. szp,
  2179. 3,
  2180. erts_bld_atom(hpp,
  2181. szp,
  2182. "instance"),
  2183. make_small((Uint) 0),
  2184. (*info_func)(allctr,
  2185. hpp != NULL,
  2186. NULL,
  2187. NULL,
  2188. hpp,
  2189. szp));
  2190. ires = erts_bld_cons(hpp, szp, tmp, ires);
  2191. if (hpp)
  2192. break;
  2193. ERTS_AIT_HALLOC((Process *) proc, sz);
  2194. hpp = &hp;
  2195. szp = NULL;
  2196. }
  2197. }
  2198. ERTS_AIT_RET(ires);
  2199. }
  2200. else {
  2201. Eterm *szp, **hpp;
  2202. switch (i) {
  2203. case ERTS_ALC_A_SYSTEM: {
  2204. SysAllocStat sas;
  2205. Eterm opts_am;
  2206. Eterm opts;
  2207. Eterm as[4]; /* Ok even if !HEAP_ON_C_STACK, not really heap data on stack */
  2208. Eterm ts[4]; /* Ok even if !HEAP_ON_C_STACK, not really heap data on stack */
  2209. int l;
  2210. if (only_sz)
  2211. ERTS_AIT_RET(NIL);
  2212. sys_alloc_stat(&sas);
  2213. opts_am = am_atom_put("options", 7);
  2214. szp = &sz;
  2215. hpp = NULL;
  2216. restart_sys_alloc:
  2217. l = 0;
  2218. as[l] = am_atom_put("e", 1);
  2219. ts[l++] = am_true;
  2220. as[l] = am_atom_put("m", 1);
  2221. ts[l++] = am_atom_put("libc", 4);
  2222. if(sas.trim_threshold >= 0) {
  2223. as[l] = am_atom_put("tt", 2);
  2224. ts[l++] = erts_bld_uint(hpp, szp,
  2225. (Uint) sas.trim_threshold);
  2226. }
  2227. if(sas.top_pad >= 0) {
  2228. as[l] = am_atom_put("tp", 2);
  2229. ts[l++] = erts_bld_uint(hpp, szp, (Uint) sas.top_pad);
  2230. }
  2231. opts = erts_bld_2tup_list(hpp, szp, l, as, ts);
  2232. res = erts_bld_2tup_list(hpp, szp, 1, &opts_am, &opts);
  2233. if (szp) {
  2234. ERTS_AIT_HALLOC((Process *) proc, sz);
  2235. szp = NULL;
  2236. hpp = &hp;
  2237. goto restart_sys_alloc;
  2238. }
  2239. ERTS_AIT_RET(res);
  2240. }
  2241. case ERTS_ALC_A_FIXED_SIZE: {
  2242. ErtsAlcType_t n;
  2243. Eterm as[2], vs[2];
  2244. if (only_sz)
  2245. ERTS_AIT_RET(NIL);
  2246. as[0] = am_atom_put("options", 7);
  2247. as[1] = am_atom_put("pools", 5);
  2248. szp = &sz;
  2249. hpp = NULL;
  2250. restart_fix_alloc:
  2251. vs[0] = erts_bld_cons(hpp, szp,
  2252. erts_bld_tuple(hpp, szp, 2,
  2253. am_atom_put("e",
  2254. 1),
  2255. am_true),
  2256. NIL);
  2257. vs[1] = NIL;
  2258. for (n = ERTS_ALC_N_MIN_A_FIXED_SIZE;
  2259. n <= ERTS_ALC_N_MAX_A_FIXED_SIZE;
  2260. n++) {
  2261. ErtsFixInfo efi;
  2262. erts_fix_info(ERTS_ALC_N2T(n), &efi);
  2263. vs[1] = erts_bld_cons(
  2264. hpp, szp,
  2265. erts_bld_tuple(
  2266. hpp, szp, 3,
  2267. am_atom_put((char *) ERTS_ALC_N2TD(n),
  2268. strlen(ERTS_ALC_N2TD(n))),
  2269. erts_bld_uint(hpp, szp, efi.total),
  2270. erts_bld_uint(hpp, szp, efi.used)),
  2271. vs[1]);
  2272. }
  2273. res = erts_bld_2tup_list(hpp, szp, 2, as, vs);
  2274. if (szp) {
  2275. ERTS_AIT_HALLOC((Process *) proc, sz);
  2276. szp = NULL;
  2277. hpp = &hp;
  2278. goto restart_fix_alloc;
  2279. }
  2280. ERTS_AIT_RET(res);
  2281. }
  2282. default:
  2283. ASSERT(0);
  2284. goto done;
  2285. }
  2286. }
  2287. }
  2288. }
  2289. }
  2290. if (ERTS_IS_ATOM_STR("mseg_alloc", which_alloc)) {
  2291. #if HAVE_ERTS_MSEG
  2292. if (only_sz)
  2293. ERTS_AIT_RET(NIL);
  2294. erts_mseg_info(NULL, NULL, 0, NULL, &sz);
  2295. if (sz)
  2296. ERTS_AIT_HALLOC((Process *) proc, sz);
  2297. ERTS_AIT_RET(erts_mseg_info(NULL, NULL, 1, &hp, NULL));
  2298. #else
  2299. ERTS_AIT_RET(am_false);
  2300. #endif
  2301. }
  2302. else if (ERTS_IS_ATOM_STR("alloc_util", which_alloc)) {
  2303. if (only_sz)
  2304. ERTS_AIT_RET(NIL);
  2305. erts_alcu_au_info_options(NULL, NULL, NULL, &sz);
  2306. if (sz)
  2307. ERTS_AIT_HALLOC((Process *) proc, sz);
  2308. ERTS_AIT_RET(erts_alcu_au_info_options(NULL, NULL, &hp, NULL));
  2309. }
  2310. done:
  2311. if (hp) {
  2312. ASSERT(hp_end >= hp);
  2313. HRelease((Process *) proc, hp_end, hp);
  2314. }
  2315. return res;
  2316. #undef ERTS_AIT_RET
  2317. #undef ERTS_AIT_HALLOC
  2318. }
  2319. void
  2320. erts_allocator_info(int to, void *arg)
  2321. {
  2322. ErtsAlcType_t a;
  2323. ERTS_SMP_LC_ASSERT(erts_smp_is_system_blocked(0)
  2324. || (ERTS_IS_CRASH_DUMPING
  2325. && erts_smp_is_system_blocked(ERTS_BS_FLG_ALLOW_GC)));
  2326. for (a = ERTS_ALC_A_MIN; a <= ERTS_ALC_A_MAX; a++) {
  2327. int ai;
  2328. for (ai = 0; ai == 0 || ai < erts_allctrs_info[a].thr_spec; ai++) {
  2329. if (erts_allctrs_info[a].thr_spec) {
  2330. if (!erts_allctr_thr_spec[a].allctr[ai])
  2331. continue;
  2332. erts_print(to, arg, "=allocator:%s[%d]\n",
  2333. ERTS_ALC_A2AD(a), ai);
  2334. }
  2335. else {
  2336. erts_print(to, arg, "=allocator:%s\n", ERTS_ALC_A2AD(a));
  2337. }
  2338. if (!erts_allctrs_info[a].enabled)
  2339. erts_print(to, arg, "option e: false\n");
  2340. else {
  2341. if (erts_allctrs_info[a].alloc_util) {
  2342. void *as;
  2343. if (!erts_allctrs_info[a].thr_spec)
  2344. as = erts_allctrs_info[a].extra;
  2345. else {
  2346. ASSERT(erts_allctr_thr_spec[a].enabled);
  2347. as = erts_allctr_thr_spec[a].allctr[ai];
  2348. }
  2349. /* Binary alloc has its own thread safety... */
  2350. erts_alcu_info(as, 0, &to, arg, NULL, NULL);
  2351. }
  2352. else {
  2353. switch (a) {
  2354. case ERTS_ALC_A_SYSTEM: {
  2355. SysAllocStat sas;
  2356. erts_print(to, arg, "option e: true\n");
  2357. erts_print(to, arg, "option m: libc\n");
  2358. sys_alloc_stat(&sas);
  2359. if(sas.trim_threshold >= 0)
  2360. erts_print(to, arg, "option tt: %d\n", sas.trim_threshold);
  2361. if(sas.top_pad >= 0)
  2362. erts_print(to, arg, "option tp: %d\n", sas.top_pad);
  2363. break;
  2364. }
  2365. case ERTS_ALC_A_FIXED_SIZE: {
  2366. ErtsAlcType_t n;
  2367. erts_print(to, arg, "option e: true\n");
  2368. for (n = ERTS_ALC_N_MIN_A_FIXED_SIZE;
  2369. n <= ERTS_ALC_N_MAX_A_FIXED_SIZE;
  2370. n++) {
  2371. ErtsFixInfo efi;
  2372. erts_fix_info(ERTS_ALC_N2T(n), &efi);
  2373. erts_print(to, arg, "%s: %lu %lu\n",
  2374. ERTS_ALC_N2TD(n),
  2375. efi.total,
  2376. efi.used);
  2377. }
  2378. break;
  2379. }
  2380. default:
  2381. ASSERT(0);
  2382. break;
  2383. }
  2384. }
  2385. }
  2386. }
  2387. }
  2388. #if HAVE_ERTS_MSEG
  2389. erts_print(to, arg, "=allocator:mseg_alloc\n");
  2390. erts_mseg_info(&to, arg, 0, NULL, NULL);
  2391. #endif
  2392. erts_print(to, arg, "=allocator:alloc_util\n");
  2393. erts_alcu_au_info_options(&to, arg, NULL, NULL);
  2394. erts_print(to, arg, "=allocator:instr\n");
  2395. erts_print(to, arg, "option m: %s\n",
  2396. erts_instr_memory_map ? "true" : "false");
  2397. erts_print(to, arg, "option s: %s\n",
  2398. erts_instr_stat ? "true" : "false");
  2399. erts_print(to, arg, "option t: %s\n",
  2400. erts_mtrace_enabled ? "true" : "false");
  2401. }
  2402. Eterm
  2403. erts_allocator_options(void *proc)
  2404. {
  2405. #if HAVE_ERTS_MSEG
  2406. int use_mseg = 0;
  2407. #endif
  2408. Uint sz, *szp, *hp, **hpp;
  2409. Eterm res, features, settings;
  2410. Eterm atoms[ERTS_ALC_A_MAX-ERTS_ALC_A_MIN+5];
  2411. Uint terms[ERTS_ALC_A_MAX-ERTS_ALC_A_MIN+5];
  2412. int a, length;
  2413. SysAllocStat sas;
  2414. Uint *endp = NULL;
  2415. sys_alloc_stat(&sas);
  2416. /* First find out the heap size needed ... */
  2417. hpp = NULL;
  2418. szp = &sz;
  2419. sz = 0;
  2420. bld_term:
  2421. length = 0;
  2422. features = NIL;
  2423. settings = NIL;
  2424. for (a = ERTS_ALC_A_MIN; a <= ERTS_ALC_A_MAX; a++) {
  2425. Eterm tmp = NIL;
  2426. atoms[length] = am_atom_put((char *) ERTS_ALC_A2AD(a),
  2427. strlen(ERTS_ALC_A2AD(a)));
  2428. if (erts_allctrs_info[a].enabled) {
  2429. if (erts_allctrs_info[a].alloc_util) {
  2430. Allctr_t *allctr;
  2431. #if HAVE_ERTS_MSEG
  2432. use_mseg++;
  2433. #endif
  2434. if (erts_allctr_thr_spec[a].enabled)
  2435. allctr = erts_allctr_thr_spec[a].allctr[1];
  2436. else
  2437. allctr = erts_allctrs_info[a].extra;
  2438. tmp = erts_alcu_info_options(allctr, NULL, NULL, hpp, szp);
  2439. }
  2440. else {
  2441. int l = 0;
  2442. Eterm as[4];
  2443. Eterm ts[4];
  2444. as[l] = am_atom_put("e", 1);
  2445. ts[l++] = am_true;
  2446. switch (a) {
  2447. case ERTS_ALC_A_SYSTEM:
  2448. as[l] = am_atom_put("m", 1);
  2449. ts[l++] = am_atom_put("libc", 4);
  2450. if(sas.trim_threshold >= 0) {
  2451. as[l] = am_atom_put("tt", 2);
  2452. ts[l++] = erts_bld_uint(hpp, szp,
  2453. (Uint) sas.trim_threshold);
  2454. }
  2455. if(sas.top_pad >= 0) {
  2456. as[l] = am_atom_put("tp", 2);
  2457. ts[l++] = erts_bld_uint(hpp, szp, (Uint) sas.top_pad);
  2458. }
  2459. break;
  2460. default:
  2461. break;
  2462. }
  2463. tmp = erts_bld_2tup_list(hpp, szp, l, as, ts);
  2464. }
  2465. }
  2466. else {
  2467. Eterm atom = am_atom_put("e", 1);
  2468. Eterm term = am_false;
  2469. tmp = erts_bld_2tup_list(hpp, szp, 1, &atom, &term);
  2470. }
  2471. terms[length++] = tmp;
  2472. }
  2473. #if HAVE_ERTS_MSEG
  2474. if (use_mseg) {
  2475. atoms[length] = am_atom_put("mseg_alloc", 10);
  2476. terms[length++] = erts_mseg_info_options(NULL, NULL, hpp, szp);
  2477. }
  2478. #endif
  2479. atoms[length] = am_atom_put("alloc_util", 10);
  2480. terms[length++] = erts_alcu_au_info_options(NULL, NULL, hpp, szp);
  2481. {
  2482. Eterm o[3], v[3];
  2483. o[0] = am_atom_put("m", 1);
  2484. v[0] = erts_instr_memory_map ? am_true : am_false;
  2485. o[1] = am_atom_put("s", 1);
  2486. v[1] = erts_instr_stat ? am_true : am_false;
  2487. o[2] = am_atom_put("t", 1);
  2488. v[2] = erts_mtrace_enabled ? am_true : am_false;
  2489. atoms[length] = am_atom_put("instr", 5);
  2490. terms[length++] = erts_bld_2tup_list(hpp, szp, 3, o, v);
  2491. }
  2492. settings = erts_bld_2tup_list(hpp, szp, length, atoms, terms);
  2493. length = 0;
  2494. for (a = ERTS_ALC_A_MIN; a <= ERTS_ALC_A_MAX; a++) {
  2495. if (erts_allctrs_info[a].enabled) {
  2496. terms[length++] = am_atom_put((char *) ERTS_ALC_A2AD(a),
  2497. strlen(ERTS_ALC_A2AD(a)));
  2498. }
  2499. }
  2500. #if HAVE_ERTS_MSEG
  2501. if (use_mseg)
  2502. terms[length++] = am_atom_put("mseg_alloc", 10);
  2503. #endif
  2504. features = length ? erts_bld_list(hpp, szp, length, terms) : NIL;
  2505. #if defined(__GLIBC__)
  2506. {
  2507. Eterm AM_glibc = am_atom_put("glibc", 5);
  2508. Eterm version;
  2509. version = erts_bld_cons(hpp,
  2510. szp,
  2511. make_small(__GLIBC__),
  2512. #ifdef __GLIBC_MINOR__
  2513. erts_bld_cons(hpp,
  2514. szp,
  2515. make_small(__GLIBC_MINOR__),
  2516. NIL)
  2517. #else
  2518. NIL
  2519. #endif
  2520. );
  2521. res = erts_bld_tuple(hpp, szp, 4,
  2522. AM_glibc, version, features, settings);
  2523. }
  2524. #else /* unknown allocator */
  2525. res = erts_bld_tuple(hpp, szp, 4,
  2526. am_undefined, NIL, features, settings);
  2527. #endif
  2528. if (szp) {
  2529. /* ... and then build the term */
  2530. hp = HAlloc((Process *) proc, sz);
  2531. endp = hp + sz;
  2532. hpp = &hp;
  2533. szp = NULL;
  2534. goto bld_term;
  2535. }
  2536. ASSERT(endp >= hp);
  2537. HRelease((Process *) proc, endp, hp);
  2538. return res;
  2539. }
  2540. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
  2541. * Deprecated functions *
  2542. * *
  2543. * These functions are still defined since "non-OTP linked in drivers" may *
  2544. * contain (illegal) calls to them. *
  2545. \* */
  2546. /* --- DO *NOT* USE THESE FUNCTIONS --- */
  2547. void *sys_alloc(Uint sz)
  2548. { return erts_alloc_fnf(ERTS_ALC_T_UNDEF, sz); }
  2549. void *sys_realloc(void *ptr, Uint sz)
  2550. { return erts_realloc_fnf(ERTS_ALC_T_UNDEF, ptr, sz); }
  2551. void sys_free(void *ptr)
  2552. { erts_free(ERTS_ALC_T_UNDEF, ptr); }
  2553. void *safe_alloc(Uint sz)
  2554. { return erts_alloc(ERTS_ALC_T_UNDEF, sz); }
  2555. void *safe_realloc(void *ptr, Uint sz)
  2556. { return erts_realloc(ERTS_ALC_T_UNDEF, ptr, sz); }
  2557. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
  2558. * NOTE: erts_alc_test() is only supposed to be used for testing. *
  2559. * *
  2560. * Keep alloc_SUITE_data/allocator_test.h updated if changes are made *
  2561. * to erts_alc_test() *
  2562. \* */
  2563. #define ERTS_ALC_TEST_ABORT erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n")
  2564. unsigned long erts_alc_test(unsigned long op,
  2565. unsigned long a1,
  2566. unsigned long a2,
  2567. unsigned long a3)
  2568. {
  2569. switch (op >> 8) {
  2570. case 0x0: return erts_alcu_test(op, a1, a2);
  2571. case 0x1: return erts_gfalc_test(op, a1, a2);
  2572. case 0x2: return erts_bfalc_test(op, a1, a2);
  2573. case 0x3: return erts_afalc_test(op, a1, a2);
  2574. case 0x4: return erts_mseg_test(op, a1, a2, a3);
  2575. case 0xf:
  2576. switch (op) {
  2577. case 0xf00:
  2578. #ifdef USE_THREADS
  2579. if (((Allctr_t *) a1)->thread_safe)
  2580. return (unsigned long) erts_alcu_alloc_ts(ERTS_ALC_T_UNDEF,
  2581. (void *) a1,
  2582. (Uint) a2);
  2583. else
  2584. #endif
  2585. return (unsigned long) erts_alcu_alloc(ERTS_ALC_T_UNDEF,
  2586. (void *) a1,
  2587. (Uint) a2);
  2588. case 0xf01:
  2589. #ifdef USE_THREADS
  2590. if (((Allctr_t *) a1)->thread_safe)
  2591. return (unsigned long) erts_alcu_realloc_ts(ERTS_ALC_T_UNDEF,
  2592. (void *) a1,
  2593. (void *) a2,
  2594. (Uint) a3);
  2595. else
  2596. #endif
  2597. return (unsigned long) erts_alcu_realloc(ERTS_ALC_T_UNDEF,
  2598. (void *) a1,
  2599. (void *) a2,
  2600. (Uint) a3);
  2601. case 0xf02:
  2602. #ifdef USE_THREADS
  2603. if (((Allctr_t *) a1)->thread_safe)
  2604. erts_alcu_free_ts(ERTS_ALC_T_UNDEF, (void *) a1, (void *) a2);
  2605. else
  2606. #endif
  2607. erts_alcu_free(ERTS_ALC_T_UNDEF, (void *) a1, (void *) a2);
  2608. return 0;
  2609. case 0xf03: {
  2610. Allctr_t *allctr;
  2611. struct au_init init;
  2612. SET_DEFAULT_ALLOC_OPTS(&init);
  2613. init.enable = 1;
  2614. init.atype = GOODFIT;
  2615. init.init.util.name_prefix = (char *) a1;
  2616. init.init.util.ts = a2 ? 1 : 0;
  2617. if ((char **) a3) {
  2618. char **argv = (char **) a3;
  2619. int i = 0;
  2620. while (argv[i]) {
  2621. if (argv[i][0] == '-' && argv[i][1] == 't')
  2622. handle_au_arg(&init, &argv[i][2], argv, &i);
  2623. else
  2624. return (unsigned long) NULL;
  2625. i++;
  2626. }
  2627. }
  2628. switch (init.atype) {
  2629. case GOODFIT:
  2630. allctr = erts_gfalc_start((GFAllctr_t *)
  2631. erts_alloc(ERTS_ALC_T_UNDEF,
  2632. sizeof(GFAllctr_t)),
  2633. &init.init.gf,
  2634. &init.init.util);
  2635. break;
  2636. case BESTFIT:
  2637. allctr = erts_bfalc_start((BFAllctr_t *)
  2638. erts_alloc(ERTS_ALC_T_UNDEF,
  2639. sizeof(BFAllctr_t)),
  2640. &init.init.bf,
  2641. &init.init.util);
  2642. break;
  2643. case AFIT:
  2644. allctr = erts_afalc_start((AFAllctr_t *)
  2645. erts_alloc(ERTS_ALC_T_UNDEF,
  2646. sizeof(AFAllctr_t)),
  2647. &init.init.af,
  2648. &init.init.util);
  2649. break;
  2650. default:
  2651. ASSERT(0);
  2652. allctr = NULL;
  2653. break;
  2654. }
  2655. return (unsigned long) allctr;
  2656. }
  2657. case 0xf04:
  2658. erts_alcu_stop((Allctr_t *) a1);
  2659. erts_free(ERTS_ALC_T_UNDEF, (void *) a1);
  2660. break;
  2661. #ifdef USE_THREADS
  2662. case 0xf05: return (unsigned long) 1;
  2663. case 0xf06: return (unsigned long) ((Allctr_t *) a1)->thread_safe;
  2664. #ifdef ETHR_NO_FORKSAFETY
  2665. case 0xf07: return (unsigned long) 0;
  2666. #else
  2667. case 0xf07: return (unsigned long) ((Allctr_t *) a1)->thread_safe;
  2668. #endif
  2669. case 0xf08: {
  2670. ethr_mutex *mtx = erts_alloc(ERTS_ALC_T_UNDEF, sizeof(ethr_mutex));
  2671. if (ethr_mutex_init(mtx) != 0)
  2672. ERTS_ALC_TEST_ABORT;
  2673. return (unsigned long) mtx;
  2674. }
  2675. case 0xf09: {
  2676. ethr_mutex *mtx = (ethr_mutex *) a1;
  2677. if (ethr_mutex_destroy(mtx) != 0)
  2678. ERTS_ALC_TEST_ABORT;
  2679. erts_free(ERTS_ALC_T_UNDEF, (void *) mtx);
  2680. break;
  2681. }
  2682. case 0xf0a:
  2683. ethr_mutex_lock((ethr_mutex *) a1);
  2684. break;
  2685. case 0xf0b:
  2686. ethr_mutex_unlock((ethr_mutex *) a1);
  2687. break;
  2688. case 0xf0c: {
  2689. ethr_cond *cnd = erts_alloc(ERTS_ALC_T_UNDEF, sizeof(ethr_cond));
  2690. if (ethr_cond_init(cnd) != 0)
  2691. ERTS_ALC_TEST_ABORT;
  2692. return (unsigned long) cnd;
  2693. }
  2694. case 0xf0d: {
  2695. ethr_cond *cnd = (ethr_cond *) a1;
  2696. if (ethr_cond_destroy(cnd) != 0)
  2697. ERTS_ALC_TEST_ABORT;
  2698. erts_free(ERTS_ALC_T_UNDEF, (void *) cnd);
  2699. break;
  2700. }
  2701. case 0xf0e:
  2702. ethr_cond_broadcast((ethr_cond *) a1);
  2703. break;
  2704. case 0xf0f: {
  2705. int res;
  2706. do {
  2707. res = ethr_cond_wait((ethr_cond *) a1, (ethr_mutex *) a2);
  2708. } while (res == EINTR);
  2709. break;
  2710. }
  2711. case 0xf10: {
  2712. ethr_tid *tid = erts_alloc(ERTS_ALC_T_UNDEF, sizeof(ethr_tid));
  2713. if (ethr_thr_create(tid,
  2714. (void * (*)(void *)) a1,
  2715. (void *) a2,
  2716. NULL) != 0)
  2717. ERTS_ALC_TEST_ABORT;
  2718. return (unsigned long) tid;
  2719. }
  2720. case 0xf11: {
  2721. ethr_tid *tid = (ethr_tid *) a1;
  2722. if (ethr_thr_join(*tid, NULL) != 0)
  2723. ERTS_ALC_TEST_ABORT;
  2724. erts_free(ERTS_ALC_T_UNDEF, (void *) tid);
  2725. break;
  2726. }
  2727. case 0xf12:
  2728. ethr_thr_exit((void *) a1);
  2729. ERTS_ALC_TEST_ABORT;
  2730. break;
  2731. #endif /* #ifdef USE_THREADS */
  2732. default:
  2733. break;
  2734. }
  2735. return (unsigned long) 0;
  2736. default:
  2737. break;
  2738. }
  2739. ASSERT(0);
  2740. return ~((unsigned long) 0);
  2741. }
  2742. #ifdef DEBUG
  2743. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
  2744. * Debug stuff *
  2745. \* */
  2746. #if 0
  2747. #define PRINT_OPS
  2748. #else
  2749. #undef PRINT_OPS
  2750. #endif
  2751. #ifdef HARD_DEBUG
  2752. #define FENCE_SZ (4*sizeof(UWord))
  2753. #else
  2754. #define FENCE_SZ (3*sizeof(UWord))
  2755. #endif
  2756. #if defined(ARCH_64)
  2757. #define FENCE_PATTERN 0xABCDEF97ABCDEF97
  2758. #else
  2759. #define FENCE_PATTERN 0xABCDEF97
  2760. #endif
  2761. #define TYPE_PATTERN_MASK ERTS_ALC_N_MASK
  2762. #define TYPE_PATTERN_SHIFT 16
  2763. #define FIXED_FENCE_PATTERN_MASK \
  2764. (~((UWord) (TYPE_PATTERN_MASK << TYPE_PATTERN_SHIFT)))
  2765. #define FIXED_FENCE_PATTERN \
  2766. (FENCE_PATTERN & FIXED_FENCE_PATTERN_MASK)
  2767. #define MK_PATTERN(T) \
  2768. (FIXED_FENCE_PATTERN | (((T) & TYPE_PATTERN_MASK) << TYPE_PATTERN_SHIFT))
  2769. #define GET_TYPE_OF_PATTERN(P) \
  2770. (((P) >> TYPE_PATTERN_SHIFT) & TYPE_PATTERN_MASK)
  2771. #ifdef HARD_DEBUG
  2772. #define ERL_ALC_HDBG_MAX_MBLK 100000
  2773. #define ERTS_ALC_O_CHECK -1
  2774. typedef struct hdbg_mblk_ hdbg_mblk;
  2775. struct hdbg_mblk_ {
  2776. hdbg_mblk *next;
  2777. hdbg_mblk *prev;
  2778. void *p;
  2779. Uint s;
  2780. ErtsAlcType_t n;
  2781. };
  2782. static hdbg_mblk hdbg_mblks[ERL_ALC_HDBG_MAX_MBLK];
  2783. static hdbg_mblk *free_hdbg_mblks;
  2784. static hdbg_mblk *used_hdbg_mblks;
  2785. static erts_mtx_t hdbg_mblk_mtx;
  2786. static void
  2787. hdbg_init(void)
  2788. {
  2789. int i;
  2790. for (i = 0; i < ERL_ALC_HDBG_MAX_MBLK-1; i++)
  2791. hdbg_mblks[i].next = &hdbg_mblks[i+1];
  2792. hdbg_mblks[ERL_ALC_HDBG_MAX_MBLK-1].next = NULL;
  2793. free_hdbg_mblks = &hdbg_mblks[0];
  2794. used_hdbg_mblks = NULL;
  2795. erts_mtx_init(&hdbg_mblk_mtx, "erts_alloc_hard_debug");
  2796. }
  2797. static void *check_memory_fence(void *ptr,
  2798. Uint *size,
  2799. ErtsAlcType_t n,
  2800. int func);
  2801. void erts_hdbg_chk_blks(void);
  2802. void
  2803. erts_hdbg_chk_blks(void)
  2804. {
  2805. hdbg_mblk *mblk;
  2806. erts_mtx_lock(&hdbg_mblk_mtx);
  2807. for (mblk = used_hdbg_mblks; mblk; mblk = mblk->next) {
  2808. Uint sz;
  2809. check_memory_fence(mblk->p, &sz, mblk->n, ERTS_ALC_O_CHECK);
  2810. ASSERT(sz == mblk->s);
  2811. }
  2812. erts_mtx_unlock(&hdbg_mblk_mtx);
  2813. }
  2814. static hdbg_mblk *
  2815. hdbg_alloc(void *p, Uint s, ErtsAlcType_t n)
  2816. {
  2817. hdbg_mblk *mblk;
  2818. erts_mtx_lock(&hdbg_mblk_mtx);
  2819. mblk = free_hdbg_mblks;
  2820. if (!mblk) {
  2821. erts_fprintf(stderr,
  2822. "Ran out of debug blocks; please increase "
  2823. "ERL_ALC_HDBG_MAX_MBLK=%d and recompile!\n",
  2824. ERL_ALC_HDBG_MAX_MBLK);
  2825. abort();
  2826. }
  2827. free_hdbg_mblks = mblk->next;
  2828. mblk->p = p;
  2829. mblk->s = s;
  2830. mblk->n = n;
  2831. mblk->next = used_hdbg_mblks;
  2832. mblk->prev = NULL;
  2833. if (used_hdbg_mblks)
  2834. used_hdbg_mblks->prev = mblk;
  2835. used_hdbg_mblks = mblk;
  2836. erts_mtx_unlock(&hdbg_mblk_mtx);
  2837. return (void *) mblk;
  2838. }
  2839. static void
  2840. hdbg_free(hdbg_mblk *mblk)
  2841. {
  2842. erts_mtx_lock(&hdbg_mblk_mtx);
  2843. if (mblk->next)
  2844. mblk->next->prev = mblk->prev;
  2845. if (mblk->prev)
  2846. mblk->prev->next = mblk->next;
  2847. else
  2848. used_hdbg_mblks = mblk->next;
  2849. mblk->next = free_hdbg_mblks;
  2850. free_hdbg_mblks = mblk;
  2851. erts_mtx_unlock(&hdbg_mblk_mtx);
  2852. }
  2853. #endif
  2854. #ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
  2855. static void *check_memory_fence(void *ptr, Uint *size, ErtsAlcType_t n, int func);
  2856. void check_allocated_block( Uint type, void *blk)
  2857. {
  2858. Uint dummy;
  2859. check_memory_fence(blk, &dummy, ERTS_ALC_T2N(type), ERTS_ALC_O_FREE);
  2860. }
  2861. void check_allocators(void)
  2862. {
  2863. int i;
  2864. if (!erts_initialized)
  2865. return;
  2866. for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; ++i) {
  2867. if (erts_allctrs_info[i].alloc_util) {
  2868. ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) erts_allctrs[i].extra;
  2869. Allctr_t *allctr = real_af->extra;
  2870. Carrier_t *ct;
  2871. #ifdef USE_THREADS
  2872. if (allctr->thread_safe)
  2873. erts_mtx_lock(&allctr->mutex);
  2874. #endif
  2875. if (allctr->check_mbc) {
  2876. for (ct = allctr->mbc_list.first; ct; ct = ct->next) {
  2877. fprintf(stderr,"Checking allocator %d\r\n",i);
  2878. allctr->check_mbc(allctr,ct);
  2879. }
  2880. }
  2881. #ifdef USE_THREADS
  2882. if (allctr->thread_safe)
  2883. erts_mtx_unlock(&allctr->mutex);
  2884. #endif
  2885. }
  2886. }
  2887. }
  2888. #endif
  2889. static void *
  2890. set_memory_fence(void *ptr, Uint sz, ErtsAlcType_t n)
  2891. {
  2892. UWord *ui_ptr;
  2893. UWord pattern;
  2894. #ifdef HARD_DEBUG
  2895. hdbg_mblk **mblkpp;
  2896. #endif
  2897. if (!ptr)
  2898. return NULL;
  2899. ui_ptr = (UWord *) ptr;
  2900. pattern = MK_PATTERN(n);
  2901. #ifdef HARD_DEBUG
  2902. mblkpp = (hdbg_mblk **) ui_ptr++;
  2903. #endif
  2904. *(ui_ptr++) = sz;
  2905. *(ui_ptr++) = pattern;
  2906. memcpy((void *) (((char *) ui_ptr)+sz), (void *) &pattern, sizeof(UWord));
  2907. #ifdef HARD_DEBUG
  2908. *mblkpp = hdbg_alloc((void *) ui_ptr, sz, n);
  2909. #endif
  2910. return (void *) ui_ptr;
  2911. }
  2912. static void *
  2913. check_memory_fence(void *ptr, Uint *size, ErtsAlcType_t n, int func)
  2914. {
  2915. Uint sz;
  2916. Uint found_type;
  2917. UWord pre_pattern;
  2918. UWord post_pattern;
  2919. UWord *ui_ptr;
  2920. #ifdef HARD_DEBUG
  2921. hdbg_mblk *mblk;
  2922. #endif
  2923. if (!ptr)
  2924. return NULL;
  2925. ui_ptr = (UWord *) ptr;
  2926. pre_pattern = *(--ui_ptr);
  2927. *size = sz = *(--ui_ptr);
  2928. #ifdef HARD_DEBUG
  2929. mblk = (hdbg_mblk *) *(--ui_ptr);
  2930. #endif
  2931. found_type = GET_TYPE_OF_PATTERN(pre_pattern);
  2932. if (pre_pattern != MK_PATTERN(n)) {
  2933. if ((FIXED_FENCE_PATTERN_MASK & pre_pattern) != FIXED_FENCE_PATTERN)
  2934. erl_exit(ERTS_ABORT_EXIT,
  2935. "ERROR: Fence at beginning of memory block (p=0x%u) "
  2936. "clobbered.\n",
  2937. (unsigned long) ptr);
  2938. }
  2939. memcpy((void *) &post_pattern, (void *) (((char *)ptr)+sz), sizeof(UWord));
  2940. if (post_pattern != MK_PATTERN(n)
  2941. || pre_pattern != post_pattern) {
  2942. char fbuf[10];
  2943. char obuf[10];
  2944. char *ftype;
  2945. char *otype;
  2946. char *op_str;
  2947. if ((FIXED_FENCE_PATTERN_MASK & post_pattern) != FIXED_FENCE_PATTERN)
  2948. erl_exit(ERTS_ABORT_EXIT,
  2949. "ERROR: Fence at end of memory block (p=0x%u, sz=%u) "
  2950. "clobbered.\n",
  2951. (unsigned long) ptr, (unsigned long) sz);
  2952. if (found_type != GET_TYPE_OF_PATTERN(post_pattern))
  2953. erl_exit(ERTS_ABORT_EXIT,
  2954. "ERROR: Fence around memory block (p=0x%u, sz=%u) "
  2955. "clobbered.\n",
  2956. (unsigned long) ptr, (unsigned long) sz);
  2957. ftype = type_no_str(found_type);
  2958. if (!ftype) {
  2959. sprintf(fbuf, "%d", (int) found_type);
  2960. ftype = fbuf;
  2961. }
  2962. otype = type_no_str(n);
  2963. if (!otype) {
  2964. sprintf(obuf, "%d", (int) n);
  2965. otype = obuf;
  2966. }
  2967. switch (func) {
  2968. case ERTS_ALC_O_ALLOC: op_str = "allocated"; break;
  2969. case ERTS_ALC_O_REALLOC: op_str = "reallocated"; break;
  2970. case ERTS_ALC_O_FREE: op_str = "freed"; break;
  2971. default: op_str = "???"; break;
  2972. }
  2973. erl_exit(ERTS_ABORT_EXIT,
  2974. "ERROR: Memory block (p=0x%u, sz=%u) allocated as type \"%s\","
  2975. " but %s as type \"%s\".\n",
  2976. (unsigned long) ptr, (unsigned long) sz, ftype, op_str, otype);
  2977. }
  2978. #ifdef HARD_DEBUG
  2979. switch (func) {
  2980. case ERTS_ALC_O_REALLOC:
  2981. case ERTS_ALC_O_FREE:
  2982. hdbg_free(mblk);
  2983. break;
  2984. default:
  2985. break;
  2986. }
  2987. #endif
  2988. return (void *) ui_ptr;
  2989. }
  2990. static ErtsAllocatorFunctions_t real_allctrs[ERTS_ALC_A_MAX+1];
  2991. static void *
  2992. debug_alloc(ErtsAlcType_t n, void *extra, Uint size)
  2993. {
  2994. ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
  2995. Uint dsize;
  2996. void *res;
  2997. #ifdef HARD_DEBUG
  2998. erts_hdbg_chk_blks();
  2999. #endif
  3000. ASSERT(ERTS_ALC_N_MIN <= n && n <= ERTS_ALC_N_MAX);
  3001. dsize = size + FENCE_SZ;
  3002. res = (*real_af->alloc)(n, real_af->extra, dsize);
  3003. res = set_memory_fence(res, size, n);
  3004. #ifdef PRINT_OPS
  3005. fprintf(stderr, "0x%lx = alloc(%s, %lu)\r\n",
  3006. (Uint) res, ERTS_ALC_N2TD(n), size);
  3007. #endif
  3008. return res;
  3009. }
  3010. static void *
  3011. debug_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size)
  3012. {
  3013. ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
  3014. Uint dsize;
  3015. Uint old_size;
  3016. void *dptr;
  3017. void *res;
  3018. ASSERT(ERTS_ALC_N_MIN <= n && n <= ERTS_ALC_N_MAX);
  3019. dsize = size + FENCE_SZ;
  3020. dptr = check_memory_fence(ptr, &old_size, n, ERTS_ALC_O_REALLOC);
  3021. #ifdef HARD_DEBUG
  3022. erts_hdbg_chk_blks();
  3023. #endif
  3024. if (old_size > size)
  3025. sys_memset((void *) (((char *) ptr) + size),
  3026. 0xf,
  3027. sizeof(Uint) + old_size - size);
  3028. res = (*real_af->realloc)(n, real_af->extra, dptr, dsize);
  3029. res = set_memory_fence(res, size, n);
  3030. #ifdef PRINT_OPS
  3031. fprintf(stderr, "0x%lx = realloc(%s, 0x%lx, %lu)\r\n",
  3032. (Uint) res, ERTS_ALC_N2TD(n), (Uint) ptr, size);
  3033. #endif
  3034. return res;
  3035. }
  3036. static void
  3037. debug_free(ErtsAlcType_t n, void *extra, void *ptr)
  3038. {
  3039. ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
  3040. void *dptr;
  3041. Uint size;
  3042. ASSERT(ERTS_ALC_N_MIN <= n && n <= ERTS_ALC_N_MAX);
  3043. dptr = check_memory_fence(ptr, &size, n, ERTS_ALC_O_FREE);
  3044. sys_memset((void *) dptr, n, size + FENCE_SZ);
  3045. (*real_af->free)(n, real_af->extra, dptr);
  3046. #ifdef PRINT_OPS
  3047. fprintf(stderr, "free(%s, 0x%lx)\r\n", ERTS_ALC_N2TD(n), (Uint) ptr);
  3048. #endif
  3049. #ifdef HARD_DEBUG
  3050. erts_hdbg_chk_blks();
  3051. #endif
  3052. }
  3053. static Uint
  3054. install_debug_functions(void)
  3055. {
  3056. int i;
  3057. ASSERT(sizeof(erts_allctrs) == sizeof(real_allctrs));
  3058. sys_memcpy((void *)real_allctrs,(void *)erts_allctrs,sizeof(erts_allctrs));
  3059. for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) {
  3060. erts_allctrs[i].alloc = debug_alloc;
  3061. erts_allctrs[i].realloc = debug_realloc;
  3062. erts_allctrs[i].free = debug_free;
  3063. erts_allctrs[i].extra = (void *) &real_allctrs[i];
  3064. }
  3065. return FENCE_SZ;
  3066. }
  3067. #endif /* #ifdef DEBUG */