PageRenderTime 61ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/erts/emulator/beam/erl_alloc.c

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