PageRenderTime 77ms CodeModel.GetById 37ms RepoModel.GetById 0ms app.codeStats 1ms

/erts/emulator/beam/erl_alloc.c

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