PageRenderTime 62ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/erts/emulator/beam/erl_alloc.c

https://github.com/shino/otp
C | 3588 lines | 3097 code | 401 blank | 90 comment | 504 complexity | 73ad32774dc3da957c335883375ed438 MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-2-Clause

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

  1. /*
  2. * %CopyrightBegin%
  3. *
  4. * Copyright Ericsson AB 2002-2011. All Rights Reserved.
  5. *
  6. * The contents of this file are subject to the Erlang Public License,
  7. * Version 1.1, (the "License"); you may not use this file except in
  8. * compliance with the License. You should have received a copy of the
  9. * Erlang Public License along with this software. If not, it can be
  10. * retrieved online at http://www.erlang.org/.
  11. *
  12. * Software distributed under the License is distributed on an "AS IS"
  13. * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  14. * the License for the specific language governing rights and limitations
  15. * under the License.
  16. *
  17. * %CopyrightEnd%
  18. */
  19. /*
  20. * Description: Management of memory allocators.
  21. *
  22. * Author: Rickard Green
  23. */
  24. #ifdef HAVE_CONFIG_H
  25. # include "config.h"
  26. #endif
  27. #define ERTS_ALLOC_C__
  28. #define ERTS_ALC_INTERNAL__
  29. #include "sys.h"
  30. #define ERL_THREADS_EMU_INTERNAL__
  31. #include "erl_threads.h"
  32. #include "global.h"
  33. #include "erl_db.h"
  34. #include "erl_binary.h"
  35. #include "erl_bits.h"
  36. #include "erl_instrument.h"
  37. #include "erl_mseg.h"
  38. #include "erl_monitors.h"
  39. #include "erl_bif_timer.h"
  40. #if defined(ERTS_ALC_T_DRV_SEL_D_STATE) || defined(ERTS_ALC_T_DRV_EV_D_STATE)
  41. #include "erl_check_io.h"
  42. #endif
  43. #define GET_ERL_GF_ALLOC_IMPL
  44. #include "erl_goodfit_alloc.h"
  45. #define GET_ERL_BF_ALLOC_IMPL
  46. #include "erl_bestfit_alloc.h"
  47. #define GET_ERL_AF_ALLOC_IMPL
  48. #include "erl_afit_alloc.h"
  49. #define GET_ERL_AOFF_ALLOC_IMPL
  50. #include "erl_ao_firstfit_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. #if 0
  60. #define HARD_DEBUG
  61. #ifdef __GNUC__
  62. #warning "* * * * * * * * * * * * * *"
  63. #warning "* HARD DEBUG IS ENABLED! *"
  64. #warning "* * * * * * * * * * * * * *"
  65. #endif
  66. #endif
  67. #endif
  68. ErtsAllocatorFunctions_t erts_allctrs[ERTS_ALC_A_MAX+1];
  69. ErtsAllocatorInfo_t erts_allctrs_info[ERTS_ALC_A_MAX+1];
  70. ErtsAllocatorThrSpec_t erts_allctr_thr_spec[ERTS_ALC_A_MAX+1];
  71. #define ERTS_MIN(A, B) ((A) < (B) ? (A) : (B))
  72. #define ERTS_MAX(A, B) ((A) > (B) ? (A) : (B))
  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. AOFFAllctr_t aoffa;
  81. char align_aoffa[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(AOFFAllctr_t))];
  82. } ErtsAllocatorState_t;
  83. static ErtsAllocatorState_t sbmbc_alloc_state;
  84. static ErtsAllocatorState_t std_alloc_state;
  85. static ErtsAllocatorState_t ll_alloc_state;
  86. #if HALFWORD_HEAP
  87. static ErtsAllocatorState_t sbmbc_low_alloc_state;
  88. static ErtsAllocatorState_t std_low_alloc_state;
  89. static ErtsAllocatorState_t ll_low_alloc_state;
  90. #endif
  91. static ErtsAllocatorState_t sl_alloc_state;
  92. static ErtsAllocatorState_t temp_alloc_state;
  93. static ErtsAllocatorState_t eheap_alloc_state;
  94. static ErtsAllocatorState_t binary_alloc_state;
  95. static ErtsAllocatorState_t ets_alloc_state;
  96. static ErtsAllocatorState_t driver_alloc_state;
  97. ErtsAlcType_t erts_fix_core_allocator_ix;
  98. #ifdef ERTS_ALC_N_MIN_A_FIXED_SIZE
  99. static void *(*fix_core_allocator)(ErtsAlcType_t, void *, Uint);
  100. static void *fix_core_extra;
  101. static void *fix_core_alloc(Uint size)
  102. {
  103. void *res;
  104. res = (*fix_core_allocator)(ERTS_ALC_T_UNDEF, fix_core_extra, size);
  105. if (erts_mtrace_enabled)
  106. erts_mtrace_crr_alloc(res,
  107. ERTS_ALC_A_FIXED_SIZE,
  108. erts_fix_core_allocator_ix,
  109. size);
  110. return res;
  111. }
  112. #endif
  113. enum allctr_type {
  114. GOODFIT,
  115. BESTFIT,
  116. AFIT,
  117. AOFIRSTFIT
  118. };
  119. struct au_init {
  120. int enable;
  121. int thr_spec;
  122. enum allctr_type atype;
  123. struct {
  124. AllctrInit_t util;
  125. GFAllctrInit_t gf;
  126. BFAllctrInit_t bf;
  127. AFAllctrInit_t af;
  128. AOFFAllctrInit_t aoff;
  129. } init;
  130. struct {
  131. int mmbcs;
  132. int lmbcs;
  133. int smbcs;
  134. int mmmbc;
  135. } default_;
  136. };
  137. #define DEFAULT_ALLCTR_INIT { \
  138. ERTS_DEFAULT_ALLCTR_INIT, \
  139. ERTS_DEFAULT_GF_ALLCTR_INIT, \
  140. ERTS_DEFAULT_BF_ALLCTR_INIT, \
  141. ERTS_DEFAULT_AF_ALLCTR_INIT, \
  142. ERTS_DEFAULT_AOFF_ALLCTR_INIT \
  143. }
  144. typedef struct {
  145. int erts_alloc_config;
  146. #if HAVE_ERTS_MSEG
  147. ErtsMsegInit_t mseg;
  148. #endif
  149. int trim_threshold;
  150. int top_pad;
  151. AlcUInit_t alloc_util;
  152. struct {
  153. int stat;
  154. int map;
  155. char *mtrace;
  156. char *nodename;
  157. } instr;
  158. struct au_init sbmbc_alloc;
  159. struct au_init sl_alloc;
  160. struct au_init std_alloc;
  161. struct au_init ll_alloc;
  162. struct au_init temp_alloc;
  163. struct au_init eheap_alloc;
  164. struct au_init binary_alloc;
  165. struct au_init ets_alloc;
  166. struct au_init driver_alloc;
  167. #if HALFWORD_HEAP
  168. struct au_init sbmbc_low_alloc;
  169. struct au_init std_low_alloc;
  170. struct au_init ll_low_alloc;
  171. #endif
  172. } erts_alc_hndl_args_init_t;
  173. #define ERTS_AU_INIT__ {0, 0, GOODFIT, DEFAULT_ALLCTR_INIT, {1,1,1,1}}
  174. #define SET_DEFAULT_ALLOC_OPTS(IP) \
  175. do { \
  176. struct au_init aui__ = ERTS_AU_INIT__; \
  177. sys_memcpy((void *) (IP), (void *) &aui__, sizeof(struct au_init)); \
  178. } while (0)
  179. static void
  180. set_default_sbmbc_alloc_opts(struct au_init *ip)
  181. {
  182. SET_DEFAULT_ALLOC_OPTS(ip);
  183. ip->enable = 0;
  184. ip->thr_spec = 0;
  185. ip->atype = BESTFIT;
  186. ip->init.bf.ao = 1;
  187. ip->init.util.ramv = 0;
  188. ip->init.util.mmsbc = 0;
  189. ip->init.util.mmmbc = 500;
  190. ip->init.util.sbct = ~((UWord) 0);
  191. ip->init.util.name_prefix = "sbmbc_";
  192. ip->init.util.alloc_no = ERTS_ALC_A_SBMBC;
  193. #ifndef SMALL_MEMORY
  194. ip->init.util.mmbcs = 2*1024*1024; /* Main carrier size */
  195. #else
  196. ip->init.util.mmbcs = 1*1024*1024; /* Main carrier size */
  197. #endif
  198. ip->init.util.ts = ERTS_ALC_MTA_SBMBC;
  199. ip->init.util.asbcst = 0;
  200. ip->init.util.rsbcst = 0;
  201. ip->init.util.rsbcmt = 0;
  202. ip->init.util.rmbcmt = 0;
  203. ip->init.util.sbmbct = 0;
  204. ip->init.util.sbmbcs = 0;
  205. }
  206. static void
  207. set_default_sl_alloc_opts(struct au_init *ip)
  208. {
  209. SET_DEFAULT_ALLOC_OPTS(ip);
  210. ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
  211. ip->thr_spec = 1;
  212. ip->atype = GOODFIT;
  213. ip->init.util.name_prefix = "sl_";
  214. ip->init.util.mmmbc = 5;
  215. ip->init.util.alloc_no = ERTS_ALC_A_SHORT_LIVED;
  216. #ifndef SMALL_MEMORY
  217. ip->init.util.mmbcs = 128*1024; /* Main carrier size */
  218. #else
  219. ip->init.util.mmbcs = 32*1024; /* Main carrier size */
  220. #endif
  221. ip->init.util.ts = ERTS_ALC_MTA_SHORT_LIVED;
  222. ip->init.util.rsbcst = 80;
  223. #if HALFWORD_HEAP
  224. ip->init.util.force = 1;
  225. ip->init.util.low_mem = 1;
  226. #endif
  227. }
  228. static void
  229. set_default_std_alloc_opts(struct au_init *ip)
  230. {
  231. SET_DEFAULT_ALLOC_OPTS(ip);
  232. ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
  233. ip->thr_spec = 1;
  234. ip->atype = BESTFIT;
  235. ip->init.util.name_prefix = "std_";
  236. ip->init.util.mmmbc = 5;
  237. ip->init.util.alloc_no = ERTS_ALC_A_STANDARD;
  238. #ifndef SMALL_MEMORY
  239. ip->init.util.mmbcs = 128*1024; /* Main carrier size */
  240. #else
  241. ip->init.util.mmbcs = 32*1024; /* Main carrier size */
  242. #endif
  243. ip->init.util.ts = ERTS_ALC_MTA_STANDARD;
  244. }
  245. static void
  246. set_default_ll_alloc_opts(struct au_init *ip)
  247. {
  248. SET_DEFAULT_ALLOC_OPTS(ip);
  249. ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
  250. ip->thr_spec = 0;
  251. ip->atype = BESTFIT;
  252. ip->init.bf.ao = 1;
  253. ip->init.util.ramv = 0;
  254. ip->init.util.mmsbc = 0;
  255. ip->init.util.mmmbc = 0;
  256. ip->init.util.sbct = ~((UWord) 0);
  257. ip->init.util.name_prefix = "ll_";
  258. ip->init.util.alloc_no = ERTS_ALC_A_LONG_LIVED;
  259. #ifndef SMALL_MEMORY
  260. ip->init.util.mmbcs = 2*1024*1024; /* Main carrier size */
  261. #else
  262. ip->init.util.mmbcs = 1*1024*1024; /* Main carrier size */
  263. #endif
  264. ip->init.util.ts = ERTS_ALC_MTA_LONG_LIVED;
  265. ip->init.util.asbcst = 0;
  266. ip->init.util.rsbcst = 0;
  267. ip->init.util.rsbcmt = 0;
  268. ip->init.util.rmbcmt = 0;
  269. ip->init.util.sbmbct = 0;
  270. ip->init.util.sbmbcs = 0;
  271. }
  272. static void
  273. set_default_temp_alloc_opts(struct au_init *ip)
  274. {
  275. SET_DEFAULT_ALLOC_OPTS(ip);
  276. ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
  277. ip->thr_spec = 1;
  278. ip->atype = AFIT;
  279. ip->init.util.name_prefix = "temp_";
  280. ip->init.util.alloc_no = ERTS_ALC_A_TEMPORARY;
  281. #ifndef SMALL_MEMORY
  282. ip->init.util.mmbcs = 128*1024; /* Main carrier size */
  283. #else
  284. ip->init.util.mmbcs = 32*1024; /* Main carrier size */
  285. #endif
  286. ip->init.util.ts = ERTS_ALC_MTA_TEMPORARY;
  287. ip->init.util.rsbcst = 90;
  288. ip->init.util.rmbcmt = 100;
  289. #if HALFWORD_HEAP
  290. ip->init.util.force = 1;
  291. ip->init.util.low_mem = 1;
  292. #endif
  293. }
  294. static void
  295. set_default_eheap_alloc_opts(struct au_init *ip)
  296. {
  297. SET_DEFAULT_ALLOC_OPTS(ip);
  298. ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
  299. ip->thr_spec = 1;
  300. ip->atype = GOODFIT;
  301. ip->init.util.mmmbc = 100;
  302. ip->init.util.name_prefix = "eheap_";
  303. ip->init.util.alloc_no = ERTS_ALC_A_EHEAP;
  304. #ifndef SMALL_MEMORY
  305. ip->init.util.mmbcs = 512*1024; /* Main carrier size */
  306. #else
  307. ip->init.util.mmbcs = 256*1024; /* Main carrier size */
  308. #endif
  309. ip->init.util.ts = ERTS_ALC_MTA_EHEAP;
  310. ip->init.util.rsbcst = 50;
  311. #if HALFWORD_HEAP
  312. ip->init.util.force = 1;
  313. ip->init.util.low_mem = 1;
  314. #endif
  315. }
  316. static void
  317. set_default_binary_alloc_opts(struct au_init *ip)
  318. {
  319. SET_DEFAULT_ALLOC_OPTS(ip);
  320. ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
  321. ip->thr_spec = 1;
  322. ip->atype = BESTFIT;
  323. ip->init.util.mmmbc = 50;
  324. ip->init.util.name_prefix = "binary_";
  325. ip->init.util.alloc_no = ERTS_ALC_A_BINARY;
  326. #ifndef SMALL_MEMORY
  327. ip->init.util.mmbcs = 128*1024; /* Main carrier size */
  328. #else
  329. ip->init.util.mmbcs = 32*1024; /* Main carrier size */
  330. #endif
  331. ip->init.util.ts = ERTS_ALC_MTA_BINARY;
  332. }
  333. static void
  334. set_default_ets_alloc_opts(struct au_init *ip)
  335. {
  336. SET_DEFAULT_ALLOC_OPTS(ip);
  337. ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
  338. ip->thr_spec = 1;
  339. ip->atype = BESTFIT;
  340. ip->init.util.mmmbc = 100;
  341. ip->init.util.name_prefix = "ets_";
  342. ip->init.util.alloc_no = ERTS_ALC_A_ETS;
  343. #ifndef SMALL_MEMORY
  344. ip->init.util.mmbcs = 128*1024; /* Main carrier size */
  345. #else
  346. ip->init.util.mmbcs = 32*1024; /* Main carrier size */
  347. #endif
  348. ip->init.util.ts = ERTS_ALC_MTA_ETS;
  349. }
  350. static void
  351. set_default_driver_alloc_opts(struct au_init *ip)
  352. {
  353. SET_DEFAULT_ALLOC_OPTS(ip);
  354. ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
  355. ip->thr_spec = 1;
  356. ip->atype = BESTFIT;
  357. ip->init.util.name_prefix = "driver_";
  358. ip->init.util.alloc_no = ERTS_ALC_A_DRIVER;
  359. #ifndef SMALL_MEMORY
  360. ip->init.util.mmbcs = 128*1024; /* Main carrier size */
  361. #else
  362. ip->init.util.mmbcs = 32*1024; /* Main carrier size */
  363. #endif
  364. ip->init.util.ts = ERTS_ALC_MTA_DRIVER;
  365. }
  366. #ifdef ERTS_SMP
  367. static void
  368. adjust_tpref(struct au_init *ip, int no_sched)
  369. {
  370. if (ip->thr_spec) {
  371. Uint allocs;
  372. if (ip->thr_spec < 0) {/* User specified amount */
  373. allocs = abs(ip->thr_spec);
  374. if (allocs > no_sched)
  375. allocs = no_sched;
  376. }
  377. else if (no_sched > ERTS_ALC_DEFAULT_MAX_THR_PREF)
  378. allocs = ERTS_ALC_DEFAULT_MAX_THR_PREF;
  379. else
  380. allocs = no_sched;
  381. if (allocs <= 1)
  382. ip->thr_spec = 0;
  383. else {
  384. ip->thr_spec = (int) allocs;
  385. ip->thr_spec *= -1; /* thread preferred */
  386. /* If default ... */
  387. /* ... shrink main multi-block carrier size */
  388. if (ip->default_.mmbcs)
  389. ip->init.util.mmbcs /= ERTS_MIN(4, allocs);
  390. /* ... shrink largest multi-block carrier size */
  391. if (ip->default_.lmbcs)
  392. ip->init.util.lmbcs /= ERTS_MIN(2, allocs);
  393. /* ... shrink smallest multi-block carrier size */
  394. if (ip->default_.smbcs)
  395. ip->init.util.smbcs /= ERTS_MIN(4, allocs);
  396. /* ... and more than three allocators shrink
  397. max mseg multi-block carriers */
  398. if (ip->default_.mmmbc && allocs > 2) {
  399. ip->init.util.mmmbc /= ERTS_MIN(4, allocs - 1);
  400. if (ip->init.util.mmmbc < 3)
  401. ip->init.util.mmmbc = 3;
  402. }
  403. }
  404. }
  405. }
  406. #endif
  407. static void handle_args(int *, char **, erts_alc_hndl_args_init_t *);
  408. static void
  409. set_au_allocator(ErtsAlcType_t alctr_n, struct au_init *init);
  410. static void
  411. start_au_allocator(ErtsAlcType_t alctr_n,
  412. struct au_init *init,
  413. ErtsAllocatorState_t *state);
  414. static void
  415. refuse_af_strategy(struct au_init *init)
  416. {
  417. if (init->atype == AFIT)
  418. init->atype = GOODFIT;
  419. }
  420. static void init_thr_ix(int static_ixs);
  421. #ifdef HARD_DEBUG
  422. static void hdbg_init(void);
  423. #endif
  424. void
  425. erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
  426. {
  427. UWord extra_block_size = 0;
  428. int i;
  429. erts_alc_hndl_args_init_t init = {
  430. 0,
  431. #if HAVE_ERTS_MSEG
  432. ERTS_MSEG_INIT_DEFAULT_INITIALIZER,
  433. #endif
  434. ERTS_DEFAULT_TRIM_THRESHOLD,
  435. ERTS_DEFAULT_TOP_PAD,
  436. ERTS_DEFAULT_ALCU_INIT
  437. };
  438. #ifdef HARD_DEBUG
  439. hdbg_init();
  440. #endif
  441. erts_have_sbmbc_alloc = 0;
  442. erts_sys_alloc_init();
  443. init_thr_ix(erts_no_schedulers);
  444. erts_init_utils_mem();
  445. set_default_sbmbc_alloc_opts(&init.sbmbc_alloc);
  446. set_default_sl_alloc_opts(&init.sl_alloc);
  447. set_default_std_alloc_opts(&init.std_alloc);
  448. set_default_ll_alloc_opts(&init.ll_alloc);
  449. set_default_temp_alloc_opts(&init.temp_alloc);
  450. set_default_eheap_alloc_opts(&init.eheap_alloc);
  451. set_default_binary_alloc_opts(&init.binary_alloc);
  452. set_default_ets_alloc_opts(&init.ets_alloc);
  453. set_default_driver_alloc_opts(&init.driver_alloc);
  454. if (argc && argv)
  455. handle_args(argc, argv, &init);
  456. if (erts_no_schedulers <= 1) {
  457. init.sbmbc_alloc.thr_spec = 0;
  458. init.sl_alloc.thr_spec = 0;
  459. init.std_alloc.thr_spec = 0;
  460. init.ll_alloc.thr_spec = 0;
  461. init.eheap_alloc.thr_spec = 0;
  462. init.binary_alloc.thr_spec = 0;
  463. init.ets_alloc.thr_spec = 0;
  464. init.driver_alloc.thr_spec = 0;
  465. }
  466. if (init.erts_alloc_config) {
  467. /* Adjust flags that erts_alloc_config won't like */
  468. init.sbmbc_alloc.thr_spec = 0;
  469. init.temp_alloc.thr_spec = 0;
  470. init.sl_alloc.thr_spec = 0;
  471. init.std_alloc.thr_spec = 0;
  472. init.ll_alloc.thr_spec = 0;
  473. init.eheap_alloc.thr_spec = 0;
  474. init.binary_alloc.thr_spec = 0;
  475. init.ets_alloc.thr_spec = 0;
  476. init.driver_alloc.thr_spec = 0;
  477. }
  478. #ifdef ERTS_SMP
  479. /* Only temp_alloc can use thread specific interface */
  480. if (init.temp_alloc.thr_spec)
  481. init.temp_alloc.thr_spec = erts_no_schedulers;
  482. /* Others must use thread preferred interface */
  483. adjust_tpref(&init.sbmbc_alloc, erts_no_schedulers);
  484. adjust_tpref(&init.sl_alloc, erts_no_schedulers);
  485. adjust_tpref(&init.std_alloc, erts_no_schedulers);
  486. adjust_tpref(&init.ll_alloc, erts_no_schedulers);
  487. adjust_tpref(&init.eheap_alloc, erts_no_schedulers);
  488. adjust_tpref(&init.binary_alloc, erts_no_schedulers);
  489. adjust_tpref(&init.ets_alloc, erts_no_schedulers);
  490. adjust_tpref(&init.driver_alloc, erts_no_schedulers);
  491. #else
  492. /* No thread specific if not smp */
  493. init.temp_alloc.thr_spec = 0;
  494. #endif
  495. /*
  496. * The following allocators cannot be run with afit strategy.
  497. * Make sure they don't...
  498. */
  499. refuse_af_strategy(&init.sbmbc_alloc);
  500. refuse_af_strategy(&init.sl_alloc);
  501. refuse_af_strategy(&init.std_alloc);
  502. refuse_af_strategy(&init.ll_alloc);
  503. refuse_af_strategy(&init.eheap_alloc);
  504. refuse_af_strategy(&init.binary_alloc);
  505. refuse_af_strategy(&init.ets_alloc);
  506. refuse_af_strategy(&init.driver_alloc);
  507. #ifdef ERTS_SMP
  508. if (!init.temp_alloc.thr_spec)
  509. refuse_af_strategy(&init.temp_alloc);
  510. #endif
  511. erts_mtrace_pre_init();
  512. #if HAVE_ERTS_MSEG
  513. erts_mseg_init(&init.mseg);
  514. #endif
  515. erts_alcu_init(&init.alloc_util);
  516. erts_afalc_init();
  517. erts_bfalc_init();
  518. erts_gfalc_init();
  519. erts_aoffalc_init();
  520. for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) {
  521. erts_allctrs[i].alloc = NULL;
  522. erts_allctrs[i].realloc = NULL;
  523. erts_allctrs[i].free = NULL;
  524. erts_allctrs[i].extra = NULL;
  525. erts_allctrs_info[i].alloc_util = 0;
  526. erts_allctrs_info[i].enabled = 0;
  527. erts_allctrs_info[i].thr_spec = 0;
  528. erts_allctrs_info[i].extra = NULL;
  529. }
  530. #ifdef ERTS_ALC_N_MIN_A_FIXED_SIZE
  531. #if !defined(PURIFY) && !defined(VALGRIND)
  532. erts_allctrs[ERTS_ALC_A_FIXED_SIZE].alloc = erts_fix_alloc;
  533. erts_allctrs[ERTS_ALC_A_FIXED_SIZE].realloc = erts_fix_realloc;
  534. erts_allctrs[ERTS_ALC_A_FIXED_SIZE].free = erts_fix_free;
  535. erts_allctrs_info[ERTS_ALC_A_FIXED_SIZE].enabled = 1;
  536. #else
  537. erts_allctrs[ERTS_ALC_A_FIXED_SIZE].alloc = erts_sys_alloc;
  538. erts_allctrs[ERTS_ALC_A_FIXED_SIZE].realloc = erts_sys_realloc;
  539. erts_allctrs[ERTS_ALC_A_FIXED_SIZE].free = erts_sys_free;
  540. erts_allctrs_info[ERTS_ALC_A_FIXED_SIZE].enabled = 0;
  541. #endif
  542. #endif
  543. erts_allctrs[ERTS_ALC_A_SYSTEM].alloc = erts_sys_alloc;
  544. erts_allctrs[ERTS_ALC_A_SYSTEM].realloc = erts_sys_realloc;
  545. erts_allctrs[ERTS_ALC_A_SYSTEM].free = erts_sys_free;
  546. erts_allctrs_info[ERTS_ALC_A_SYSTEM].enabled = 1;
  547. #if HALFWORD_HEAP
  548. /* Init low memory variants by cloning */
  549. init.sbmbc_low_alloc = init.sbmbc_alloc;
  550. init.sbmbc_low_alloc.init.util.name_prefix = "sbmbc_low_";
  551. init.sbmbc_low_alloc.init.util.alloc_no = ERTS_ALC_A_SBMBC_LOW;
  552. init.sbmbc_low_alloc.init.util.low_mem = 1;
  553. init.std_low_alloc = init.std_alloc;
  554. init.std_low_alloc.init.util.name_prefix = "std_low_";
  555. init.std_low_alloc.init.util.alloc_no = ERTS_ALC_A_STANDARD_LOW;
  556. init.std_low_alloc.init.util.force = 1;
  557. init.std_low_alloc.init.util.low_mem = 1;
  558. init.ll_low_alloc = init.ll_alloc;
  559. init.ll_low_alloc.init.util.name_prefix = "ll_low_";
  560. init.ll_low_alloc.init.util.alloc_no = ERTS_ALC_A_LONG_LIVED_LOW;
  561. init.ll_low_alloc.init.util.force = 1;
  562. init.ll_low_alloc.init.util.low_mem = 1;
  563. set_au_allocator(ERTS_ALC_A_SBMBC_LOW, &init.sbmbc_low_alloc);
  564. set_au_allocator(ERTS_ALC_A_STANDARD_LOW, &init.std_low_alloc);
  565. set_au_allocator(ERTS_ALC_A_LONG_LIVED_LOW, &init.ll_low_alloc);
  566. #endif /* HALFWORD */
  567. set_au_allocator(ERTS_ALC_A_TEMPORARY, &init.temp_alloc);
  568. set_au_allocator(ERTS_ALC_A_SBMBC, &init.sbmbc_alloc);
  569. set_au_allocator(ERTS_ALC_A_SHORT_LIVED, &init.sl_alloc);
  570. set_au_allocator(ERTS_ALC_A_STANDARD, &init.std_alloc);
  571. set_au_allocator(ERTS_ALC_A_LONG_LIVED, &init.ll_alloc);
  572. set_au_allocator(ERTS_ALC_A_EHEAP, &init.eheap_alloc);
  573. set_au_allocator(ERTS_ALC_A_BINARY, &init.binary_alloc);
  574. set_au_allocator(ERTS_ALC_A_ETS, &init.ets_alloc);
  575. set_au_allocator(ERTS_ALC_A_DRIVER, &init.driver_alloc);
  576. for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) {
  577. if (!erts_allctrs[i].alloc)
  578. erl_exit(ERTS_ABORT_EXIT,
  579. "Missing alloc function for %s\n", ERTS_ALC_A2AD(i));
  580. if (!erts_allctrs[i].realloc)
  581. erl_exit(ERTS_ABORT_EXIT,
  582. "Missing realloc function for %s\n", ERTS_ALC_A2AD(i));
  583. if (!erts_allctrs[i].free)
  584. erl_exit(ERTS_ABORT_EXIT,
  585. "Missing free function for %s\n", ERTS_ALC_A2AD(i));
  586. }
  587. sys_alloc_opt(SYS_ALLOC_OPT_TRIM_THRESHOLD, init.trim_threshold);
  588. sys_alloc_opt(SYS_ALLOC_OPT_TOP_PAD, init.top_pad);
  589. if (erts_allctrs_info[ERTS_FIX_CORE_ALLOCATOR].enabled)
  590. erts_fix_core_allocator_ix = ERTS_FIX_CORE_ALLOCATOR;
  591. else
  592. erts_fix_core_allocator_ix = ERTS_ALC_A_SYSTEM;
  593. erts_mtrace_init(init.instr.mtrace, init.instr.nodename);
  594. /* sbmbc_alloc() needs to be started first */
  595. start_au_allocator(ERTS_ALC_A_SBMBC,
  596. &init.sbmbc_alloc,
  597. &sbmbc_alloc_state);
  598. #if HALFWORD_HEAP
  599. start_au_allocator(ERTS_ALC_A_SBMBC_LOW,
  600. &init.sbmbc_low_alloc,
  601. &sbmbc_low_alloc_state);
  602. erts_have_sbmbc_alloc = (init.sbmbc_alloc.enable
  603. && init.sbmbc_low_alloc.enable);
  604. #else
  605. erts_have_sbmbc_alloc = init.sbmbc_alloc.enable;
  606. #endif
  607. start_au_allocator(ERTS_ALC_A_TEMPORARY,
  608. &init.temp_alloc,
  609. &temp_alloc_state);
  610. start_au_allocator(ERTS_ALC_A_SHORT_LIVED,
  611. &init.sl_alloc,
  612. &sl_alloc_state);
  613. start_au_allocator(ERTS_ALC_A_STANDARD,
  614. &init.std_alloc,
  615. &std_alloc_state);
  616. start_au_allocator(ERTS_ALC_A_LONG_LIVED,
  617. &init.ll_alloc,
  618. &ll_alloc_state);
  619. #if HALFWORD_HEAP
  620. start_au_allocator(ERTS_ALC_A_LONG_LIVED_LOW,
  621. &init.ll_low_alloc,
  622. &ll_low_alloc_state);
  623. start_au_allocator(ERTS_ALC_A_STANDARD_LOW,
  624. &init.std_low_alloc,
  625. &std_low_alloc_state);
  626. #endif
  627. start_au_allocator(ERTS_ALC_A_EHEAP,
  628. &init.eheap_alloc,
  629. &eheap_alloc_state);
  630. start_au_allocator(ERTS_ALC_A_BINARY,
  631. &init.binary_alloc,
  632. &binary_alloc_state);
  633. start_au_allocator(ERTS_ALC_A_ETS,
  634. &init.ets_alloc,
  635. &ets_alloc_state);
  636. start_au_allocator(ERTS_ALC_A_DRIVER,
  637. &init.driver_alloc,
  638. &driver_alloc_state);
  639. fix_core_allocator = erts_allctrs[erts_fix_core_allocator_ix].alloc;
  640. fix_core_extra = erts_allctrs[erts_fix_core_allocator_ix].extra;
  641. erts_mtrace_install_wrapper_functions();
  642. extra_block_size += erts_instr_init(init.instr.stat, init.instr.map);
  643. #ifdef DEBUG
  644. extra_block_size += install_debug_functions();
  645. #endif
  646. #ifdef ERTS_ALC_N_MIN_A_FIXED_SIZE
  647. erts_init_fix_alloc(extra_block_size, fix_core_alloc);
  648. #if !defined(PURIFY) && !defined(VALGRIND)
  649. erts_set_fix_size(ERTS_ALC_T_PROC, sizeof(Process));
  650. erts_set_fix_size(ERTS_ALC_T_DB_TABLE, sizeof(DbTable));
  651. erts_set_fix_size(ERTS_ALC_T_ATOM, sizeof(Atom));
  652. erts_set_fix_size(ERTS_ALC_T_MODULE, sizeof(Module));
  653. erts_set_fix_size(ERTS_ALC_T_REG_PROC, sizeof(RegProc));
  654. erts_set_fix_size(ERTS_ALC_T_FUN_ENTRY, sizeof(ErlFunEntry));
  655. #ifdef ERTS_ALC_T_DRV_EV_D_STATE
  656. erts_set_fix_size(ERTS_ALC_T_DRV_EV_D_STATE,
  657. sizeof(ErtsDrvEventDataState));
  658. #endif
  659. #ifdef ERTS_ALC_T_DRV_SEL_D_STATE
  660. erts_set_fix_size(ERTS_ALC_T_DRV_SEL_D_STATE,
  661. sizeof(ErtsDrvSelectDataState));
  662. #endif
  663. #if !HALFWORD_HEAP
  664. erts_set_fix_size(ERTS_ALC_T_EXPORT, sizeof(Export));
  665. erts_set_fix_size(ERTS_ALC_T_MONITOR_SH, ERTS_MONITOR_SH_SIZE*sizeof(Uint));
  666. erts_set_fix_size(ERTS_ALC_T_NLINK_SH, ERTS_LINK_SH_SIZE*sizeof(Uint));
  667. #endif
  668. #endif
  669. #endif
  670. }
  671. static void
  672. set_au_allocator(ErtsAlcType_t alctr_n, struct au_init *init)
  673. {
  674. ErtsAllocatorFunctions_t *af = &erts_allctrs[alctr_n];
  675. ErtsAllocatorInfo_t *ai = &erts_allctrs_info[alctr_n];
  676. ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[alctr_n];
  677. /*
  678. * Some allocators are forced on if halfword heap is used.
  679. */
  680. if (init->init.util.force)
  681. init->enable = 1;
  682. if (!init->enable) {
  683. af->alloc = erts_sys_alloc;
  684. af->realloc = erts_sys_realloc;
  685. af->free = erts_sys_free;
  686. af->extra = NULL;
  687. ai->alloc_util = 0;
  688. ai->enabled = 0;
  689. ai->extra = NULL;
  690. return;
  691. }
  692. tspec->enabled = 0;
  693. tspec->all_thr_safe = 0;
  694. ai->thr_spec = 0;
  695. #ifdef USE_THREADS
  696. if (init->thr_spec) {
  697. if (init->thr_spec > 0) {
  698. af->alloc = erts_alcu_alloc_thr_spec;
  699. if (init->init.util.ramv)
  700. af->realloc = erts_alcu_realloc_mv_thr_spec;
  701. else
  702. af->realloc = erts_alcu_realloc_thr_spec;
  703. af->free = erts_alcu_free_thr_spec;
  704. }
  705. else {
  706. af->alloc = erts_alcu_alloc_thr_pref;
  707. if (init->init.util.ramv)
  708. af->realloc = erts_alcu_realloc_mv_thr_pref;
  709. else
  710. af->realloc = erts_alcu_realloc_thr_pref;
  711. af->free = erts_alcu_free_thr_pref;
  712. tspec->all_thr_safe = 1;
  713. }
  714. tspec->enabled = 1;
  715. tspec->size = abs(init->thr_spec) + 1;
  716. ai->thr_spec = tspec->size;
  717. }
  718. else if (init->init.util.ts) {
  719. af->alloc = erts_alcu_alloc_ts;
  720. if (init->init.util.ramv)
  721. af->realloc = erts_alcu_realloc_mv_ts;
  722. else
  723. af->realloc = erts_alcu_realloc_ts;
  724. af->free = erts_alcu_free_ts;
  725. }
  726. else
  727. #endif
  728. {
  729. af->alloc = erts_alcu_alloc;
  730. if (init->init.util.ramv)
  731. af->realloc = erts_alcu_realloc_mv;
  732. else
  733. af->realloc = erts_alcu_realloc;
  734. af->free = erts_alcu_free;
  735. }
  736. af->extra = NULL;
  737. ai->alloc_util = 1;
  738. ai->enabled = 1;
  739. }
  740. static void
  741. start_au_allocator(ErtsAlcType_t alctr_n,
  742. struct au_init *init,
  743. ErtsAllocatorState_t *state)
  744. {
  745. int i;
  746. int size = 1;
  747. void *as0;
  748. enum allctr_type atype;
  749. ErtsAllocatorFunctions_t *af = &erts_allctrs[alctr_n];
  750. ErtsAllocatorInfo_t *ai = &erts_allctrs_info[alctr_n];
  751. ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[alctr_n];
  752. if (!init->enable)
  753. return;
  754. if (init->thr_spec) {
  755. void *states = erts_sys_alloc(0,
  756. NULL,
  757. ((sizeof(Allctr_t *)
  758. * (tspec->size + 1))
  759. + (sizeof(ErtsAllocatorState_t)
  760. * tspec->size)
  761. + ERTS_CACHE_LINE_SIZE - 1));
  762. if (!states)
  763. erl_exit(ERTS_ABORT_EXIT,
  764. "Failed to allocate allocator states for %salloc\n",
  765. init->init.util.name_prefix);
  766. tspec->allctr = (Allctr_t **) states;
  767. states = ((char *) states) + sizeof(Allctr_t *) * (tspec->size + 1);
  768. states = ((((UWord) states) & ERTS_CACHE_LINE_MASK)
  769. ? (void *) ((((UWord) states) & ~ERTS_CACHE_LINE_MASK)
  770. + ERTS_CACHE_LINE_SIZE)
  771. : (void *) states);
  772. tspec->allctr[0] = init->thr_spec > 0 ? (Allctr_t *) state : (Allctr_t *) NULL;
  773. size = tspec->size;
  774. for (i = 1; i < size; i++)
  775. tspec->allctr[i] = (Allctr_t *)
  776. &((ErtsAllocatorState_t *) states)[i-1];
  777. }
  778. for (i = 0; i < size; i++) {
  779. void *as;
  780. atype = init->atype;
  781. if (!init->thr_spec)
  782. as0 = state;
  783. else {
  784. as0 = (void *) tspec->allctr[i];
  785. if (!as0)
  786. continue;
  787. if (i == 0) {
  788. if (atype == AFIT)
  789. atype = GOODFIT;
  790. init->init.util.ts = 1;
  791. }
  792. else {
  793. if (init->thr_spec < 0) {
  794. init->init.util.ts = 1;
  795. init->init.util.tspec = 0;
  796. init->init.util.tpref = -1*init->thr_spec;
  797. }
  798. else {
  799. init->init.util.ts = 0;
  800. init->init.util.tspec = init->thr_spec + 1;
  801. init->init.util.tpref = 0;
  802. }
  803. }
  804. }
  805. switch (atype) {
  806. case GOODFIT:
  807. as = (void *) erts_gfalc_start((GFAllctr_t *) as0,
  808. &init->init.gf,
  809. &init->init.util);
  810. break;
  811. case BESTFIT:
  812. as = (void *) erts_bfalc_start((BFAllctr_t *) as0,
  813. &init->init.bf,
  814. &init->init.util);
  815. break;
  816. case AFIT:
  817. as = (void *) erts_afalc_start((AFAllctr_t *) as0,
  818. &init->init.af,
  819. &init->init.util);
  820. break;
  821. case AOFIRSTFIT:
  822. as = (void *) erts_aoffalc_start((AOFFAllctr_t *) as0,
  823. &init->init.aoff,
  824. &init->init.util);
  825. break;
  826. default:
  827. as = NULL;
  828. ASSERT(0);
  829. }
  830. if (!as)
  831. erl_exit(ERTS_ABORT_EXIT,
  832. "Failed to start %salloc\n", init->init.util.name_prefix);
  833. ASSERT(as == (void *) as0);
  834. af->extra = as;
  835. }
  836. if (init->thr_spec) {
  837. af->extra = tspec;
  838. init->init.util.ts = 1;
  839. }
  840. ai->extra = af->extra;
  841. }
  842. static void bad_param(char *param_start, char *param_end)
  843. {
  844. size_t len = param_end - param_start;
  845. char param[100];
  846. if (len > 99)
  847. len = 99;
  848. sys_memcpy((void *) param, (void *) param_start, len);
  849. param[len] = '\0';
  850. erts_fprintf(stderr, "bad \"%s\" parameter\n", param);
  851. erts_usage();
  852. }
  853. static void bad_value(char *param_start, char *param_end, char *value)
  854. {
  855. size_t len = param_end - param_start;
  856. char param[100];
  857. if (len > 99)
  858. len = 99;
  859. sys_memcpy((void *) param, (void *) param_start, len);
  860. param[len] = '\0';
  861. erts_fprintf(stderr, "bad \"%s\" value: %s\n", param, value);
  862. erts_usage();
  863. }
  864. /* Get arg marks argument as handled by
  865. putting NULL in argv */
  866. static char *
  867. get_value(char* rest, char** argv, int* ip)
  868. {
  869. char *param = argv[*ip]+1;
  870. argv[*ip] = NULL;
  871. if (*rest == '\0') {
  872. char *next = argv[*ip + 1];
  873. if (next[0] == '-'
  874. && next[1] == '-'
  875. && next[2] == '\0') {
  876. bad_value(param, rest, "");
  877. }
  878. (*ip)++;
  879. argv[*ip] = NULL;
  880. return next;
  881. }
  882. return rest;
  883. }
  884. static ERTS_INLINE int
  885. has_prefix(const char *prefix, const char *string)
  886. {
  887. int i;
  888. for (i = 0; prefix[i]; i++)
  889. if (prefix[i] != string[i])
  890. return 0;
  891. return 1;
  892. }
  893. static int
  894. get_bool_value(char *param_end, char** argv, int* ip)
  895. {
  896. char *param = argv[*ip]+1;
  897. char *value = get_value(param_end, argv, ip);
  898. if (strcmp(value, "true") == 0)
  899. return 1;
  900. else if (strcmp(value, "false") == 0)
  901. return 0;
  902. else
  903. bad_value(param, param_end, value);
  904. return -1;
  905. }
  906. static Uint
  907. get_kb_value(char *param_end, char** argv, int* ip)
  908. {
  909. Sint tmp;
  910. Uint max = ((~((Uint) 0))/1024) + 1;
  911. char *rest;
  912. char *param = argv[*ip]+1;
  913. char *value = get_value(param_end, argv, ip);
  914. errno = 0;
  915. tmp = (Sint) strtol(value, &rest, 10);
  916. if (errno != 0 || rest == value || tmp < 0 || max < ((Uint) tmp))
  917. bad_value(param, param_end, value);
  918. if (max == (Uint) tmp)
  919. return ~((Uint) 0);
  920. else
  921. return ((Uint) tmp)*1024;
  922. }
  923. static Uint
  924. get_byte_value(char *param_end, char** argv, int* ip)
  925. {
  926. Sint tmp;
  927. char *rest;
  928. char *param = argv[*ip]+1;
  929. char *value = get_value(param_end, argv, ip);
  930. errno = 0;
  931. tmp = (Sint) strtol(value, &rest, 10);
  932. if (errno != 0 || rest == value || tmp < 0)
  933. bad_value(param, param_end, value);
  934. return (Uint) tmp;
  935. }
  936. static Uint
  937. get_amount_value(char *param_end, char** argv, int* ip)
  938. {
  939. Sint tmp;
  940. char *rest;
  941. char *param = argv[*ip]+1;
  942. char *value = get_value(param_end, argv, ip);
  943. errno = 0;
  944. tmp = (Sint) strtol(value, &rest, 10);
  945. if (errno != 0 || rest == value || tmp < 0)
  946. bad_value(param, param_end, value);
  947. return (Uint) tmp;
  948. }
  949. static int
  950. get_bool_or_possitive_amount_value(int *bool, Uint *amount,
  951. char *param_end, char** argv, int* ip)
  952. {
  953. char *param = argv[*ip]+1;
  954. char *value = get_value(param_end, argv, ip);
  955. if (strcmp(value, "true") == 0) {
  956. *bool = 1;
  957. return 1;
  958. }
  959. else if (strcmp(value, "false") == 0) {
  960. *bool = 0;
  961. return 1;
  962. }
  963. else {
  964. Sint tmp;
  965. char *rest;
  966. errno = 0;
  967. tmp = (Sint) strtol(value, &rest, 10);
  968. if (errno != 0 || rest == value || tmp <= 0) {
  969. bad_value(param, param_end, value);
  970. return -1;
  971. }
  972. *amount = (Uint) tmp;
  973. return 0;
  974. }
  975. }
  976. static void
  977. handle_au_arg(struct au_init *auip,
  978. char* sub_param,
  979. char** argv,
  980. int* ip)
  981. {
  982. char *param = argv[*ip]+1;
  983. switch (sub_param[0]) {
  984. case 'a':
  985. if(has_prefix("asbcst", sub_param)) {
  986. auip->init.util.asbcst = get_kb_value(sub_param + 6, argv, ip);
  987. }
  988. else if(has_prefix("as", sub_param)) {
  989. char *alg = get_value(sub_param + 2, argv, ip);
  990. if (strcmp("bf", alg) == 0) {
  991. auip->atype = BESTFIT;
  992. auip->init.bf.ao = 0;
  993. }
  994. else if (strcmp("aobf", alg) == 0) {
  995. auip->atype = BESTFIT;
  996. auip->init.bf.ao = 1;
  997. }
  998. else if (strcmp("gf", alg) == 0) {
  999. auip->atype = GOODFIT;
  1000. }
  1001. else if (strcmp("af", alg) == 0) {
  1002. auip->atype = AFIT;
  1003. }
  1004. else if (strcmp("aoff", alg) == 0) {
  1005. auip->atype = AOFIRSTFIT;
  1006. }
  1007. else {
  1008. bad_value(param, sub_param + 1, alg);
  1009. }
  1010. }
  1011. else
  1012. goto bad_switch;
  1013. break;
  1014. case 'e':
  1015. auip->enable = get_bool_value(sub_param+1, argv, ip);
  1016. break;
  1017. case 'l':
  1018. if (has_prefix("lmbcs", sub_param)) {
  1019. auip->default_.lmbcs = 0;
  1020. auip->init.util.lmbcs = get_kb_value(sub_param + 5, argv, ip);
  1021. }
  1022. else
  1023. goto bad_switch;
  1024. break;
  1025. case 'm':
  1026. if (has_prefix("mbcgs", sub_param)) {
  1027. auip->init.util.mbcgs = get_amount_value(sub_param + 5, argv, ip);
  1028. }
  1029. else if (has_prefix("mbsd", sub_param)) {
  1030. auip->init.gf.mbsd = get_amount_value(sub_param + 4, argv, ip);
  1031. if (auip->init.gf.mbsd < 1)
  1032. auip->init.gf.mbsd = 1;
  1033. }
  1034. else if (has_prefix("mmbcs", sub_param)) {
  1035. auip->default_.mmbcs = 0;
  1036. auip->init.util.mmbcs = get_kb_value(sub_param + 5, argv, ip);
  1037. }
  1038. else if (has_prefix("mmmbc", sub_param)) {
  1039. auip->default_.mmmbc = 0;
  1040. auip->init.util.mmmbc = get_amount_value(sub_param + 5, argv, ip);
  1041. }
  1042. else if (has_prefix("mmsbc", sub_param)) {
  1043. auip->init.util.mmsbc = get_amount_value(sub_param + 5, argv, ip);
  1044. }
  1045. else
  1046. goto bad_switch;
  1047. break;
  1048. case 'r':
  1049. if(has_prefix("rsbcmt", sub_param)) {
  1050. auip->init.util.rsbcmt = get_amount_value(sub_param + 6, argv, ip);
  1051. if (auip->init.util.rsbcmt > 100)
  1052. auip->init.util.rsbcmt = 100;
  1053. }
  1054. else if(has_prefix("rsbcst", sub_param)) {
  1055. auip->init.util.rsbcst = get_amount_value(sub_param + 6, argv, ip);
  1056. if (auip->init.util.rsbcst > 100)
  1057. auip->init.util.rsbcst = 100;
  1058. }
  1059. else if (has_prefix("rmbcmt", sub_param)) {
  1060. auip->init.util.rmbcmt = get_amount_value(sub_param + 6, argv, ip);
  1061. if (auip->init.util.rmbcmt > 100)
  1062. auip->init.util.rmbcmt = 100;
  1063. }
  1064. else if (has_prefix("ramv", sub_param)) {
  1065. auip->init.util.ramv = get_bool_value(sub_param + 4, argv, ip);
  1066. }
  1067. else
  1068. goto bad_switch;
  1069. break;
  1070. case 's':
  1071. if(has_prefix("sbct", sub_param)) {
  1072. auip->init.util.sbct = get_kb_value(sub_param + 4, argv, ip);
  1073. }
  1074. else if (has_prefix("sbmbcs", sub_param)) {
  1075. auip->init.util.sbmbcs = get_byte_value(sub_param + 6, argv, ip);
  1076. }
  1077. else if (has_prefix("sbmbct", sub_param)) {
  1078. auip->init.util.sbmbct = get_byte_value(sub_param + 6, argv, ip);
  1079. }
  1080. else if (has_prefix("smbcs", sub_param)) {
  1081. auip->default_.smbcs = 0;
  1082. auip->init.util.smbcs = get_kb_value(sub_param + 5, argv, ip);
  1083. }
  1084. else
  1085. goto bad_switch;
  1086. break;
  1087. case 't': {
  1088. Uint no;
  1089. int enable;
  1090. int res = get_bool_or_possitive_amount_value(&enable,
  1091. &no,
  1092. sub_param+1,
  1093. argv,
  1094. ip);
  1095. if (res > 0)
  1096. auip->thr_spec = enable ? 1 : 0;
  1097. else if (res == 0) {
  1098. int allocs = (int) no;
  1099. if (allocs < 0)
  1100. allocs = INT_MIN;
  1101. else {
  1102. allocs *= -1;
  1103. }
  1104. auip->thr_spec = allocs;
  1105. }
  1106. break;
  1107. }
  1108. default:
  1109. bad_switch:
  1110. bad_param(param, sub_param);
  1111. }
  1112. }
  1113. static void
  1114. handle_args(int *argc, char **argv, erts_alc_hndl_args_init_t *init)
  1115. {
  1116. struct au_init *aui[] = {
  1117. &init->sbmbc_alloc,
  1118. &init->binary_alloc,
  1119. &init->std_alloc,
  1120. &init->ets_alloc,
  1121. &init->eheap_alloc,
  1122. &init->ll_alloc,
  1123. &init->driver_alloc,
  1124. &init->sl_alloc,
  1125. &init->temp_alloc
  1126. };
  1127. int aui_sz = (int) sizeof(aui)/sizeof(aui[0]);
  1128. char *arg;
  1129. char *rest;
  1130. int i, j;
  1131. i = 1;
  1132. ASSERT(argc && argv && init);
  1133. while (i < *argc) {
  1134. if(argv[i][0] == '-') {
  1135. char *param = argv[i]+1;
  1136. switch (argv[i][1]) {
  1137. case 'M':
  1138. switch (argv[i][2]) {
  1139. case 'B':
  1140. handle_au_arg(&init->binary_alloc, &argv[i][3], argv, &i);
  1141. break;
  1142. case 'C':
  1143. handle_au_arg(&init->sbmbc_alloc, &argv[i][3], argv, &i);
  1144. break;
  1145. case 'D':
  1146. handle_au_arg(&init->std_alloc, &argv[i][3], argv, &i);
  1147. break;
  1148. case 'E':
  1149. handle_au_arg(&init->ets_alloc, &argv[i][3], argv, &i);
  1150. break;
  1151. case 'F': /* fix_alloc */
  1152. if (has_prefix("e", param+2)) {
  1153. arg = get_value(param+3, argv, &i);
  1154. if (strcmp("true", arg) != 0)
  1155. bad_value(param, param+3, arg);
  1156. }
  1157. else
  1158. bad_param(param, param+2);
  1159. break;
  1160. case 'H':
  1161. handle_au_arg(&init->eheap_alloc, &argv[i][3], argv, &i);
  1162. break;
  1163. case 'L':
  1164. handle_au_arg(&init->ll_alloc, &argv[i][3], argv, &i);
  1165. break;
  1166. case 'M':
  1167. if (has_prefix("amcbf", argv[i]+3)) {
  1168. #if HAVE_ERTS_MSEG
  1169. init->mseg.amcbf =
  1170. #endif
  1171. get_kb_value(argv[i]+8, argv, &i);
  1172. }
  1173. else if (has_prefix("rmcbf", argv[i]+3)) {
  1174. #if HAVE_ERTS_MSEG
  1175. init->mseg.rmcbf =
  1176. #endif
  1177. get_amount_value(argv[i]+8, argv, &i);
  1178. }
  1179. else if (has_prefix("mcs", argv[i]+3)) {
  1180. #if HAVE_ERTS_MSEG
  1181. init->mseg.mcs =
  1182. #endif
  1183. get_amount_value(argv[i]+6, argv, &i);
  1184. }
  1185. else if (has_prefix("cci", argv[i]+3)) {
  1186. #if HAVE_ERTS_MSEG
  1187. init->mseg.cci =
  1188. #endif
  1189. get_amount_value(argv[i]+6, argv, &i);
  1190. }
  1191. else {
  1192. bad_param(param, param+2);
  1193. }
  1194. break;
  1195. case 'R':
  1196. handle_au_arg(&init->driver_alloc, &argv[i][3], argv, &i);
  1197. break;
  1198. case 'S':
  1199. handle_au_arg(&init->sl_alloc, &argv[i][3], argv, &i);
  1200. break;
  1201. case 'T':
  1202. handle_au_arg(&init->temp_alloc, &argv[i][3], argv, &i);
  1203. break;
  1204. case 'Y': { /* sys_alloc */
  1205. if (has_prefix("tt", param+2)) {
  1206. /* set trim threshold */
  1207. arg = get_value(param+4, argv, &i);
  1208. errno = 0;
  1209. init->trim_threshold = (int) strtol(arg, &rest, 10);
  1210. if (errno != 0
  1211. || rest == arg
  1212. || init->trim_threshold < 0
  1213. || (INT_MAX/1024) < init->trim_threshold) {
  1214. bad_value(param, param+4, arg);
  1215. }
  1216. VERBOSE(DEBUG_SYSTEM,
  1217. ("using trim threshold: %d\n",
  1218. init->trim_threshold));
  1219. init->trim_threshold *= 1024;
  1220. }
  1221. else if (has_prefix("tp", param+2)) {
  1222. /* set top pad */
  1223. arg = get_value(param+4, argv, &i);
  1224. errno = 0;
  1225. init->top_pad = (int) strtol(arg, &rest, 10);
  1226. if (errno != 0
  1227. || rest == arg
  1228. || init->top_pad < 0
  1229. || (INT_MAX/1024) < init->top_pad) {
  1230. bad_value(param, param+4, arg);
  1231. }
  1232. VERBOSE(DEBUG_SYSTEM,
  1233. ("using top pad: %d\n",init->top_pad));
  1234. init->top_pad *= 1024;
  1235. }
  1236. else if (has_prefix("m", param+2)) {
  1237. /* Has been handled by erlexec */
  1238. (void) get_value(param+3, argv, &i);
  1239. }
  1240. else if (has_prefix("e", param+2)) {
  1241. arg = get_value(param+3, argv, &i);
  1242. if (strcmp("true", arg) != 0)
  1243. bad_value(param, param+3, arg);
  1244. }
  1245. else
  1246. bad_param(param, param+2);
  1247. break;
  1248. }
  1249. case 'e':
  1250. switch (argv[i][3]) {
  1251. case 'a': {
  1252. int a;
  1253. arg = get_value(argv[i]+4, argv, &i);
  1254. if (strcmp("min", arg) == 0) {
  1255. for (a = 0; a < aui_sz; a++)
  1256. aui[a]->enable = 0;
  1257. }
  1258. else if (strcmp("max", arg) == 0) {
  1259. for (a = 0; a < aui_sz; a++)
  1260. aui[a]->enable = 1;
  1261. }
  1262. else if (strcmp("config", arg) == 0) {
  1263. init->erts_alloc_config = 1;
  1264. }
  1265. else if (strcmp("r9c", arg) == 0
  1266. || strcmp("r10b", arg) == 0
  1267. || strcmp("r11b", arg) == 0) {
  1268. set_default_sl_alloc_opts(&init->sl_alloc);
  1269. set_default_std_alloc_opts(&init->std_alloc);
  1270. set_default_ll_alloc_opts(&init->ll_alloc);
  1271. set_default_temp_alloc_opts(&init->temp_alloc);
  1272. set_default_eheap_alloc_opts(&init->eheap_alloc);
  1273. set_default_binary_alloc_opts(&init->binary_alloc);
  1274. set_default_ets_alloc_opts(&init->ets_alloc);
  1275. set_default_driver_alloc_opts(&init->driver_alloc);
  1276. init->driver_alloc.enable = 0;
  1277. if (strcmp("r9c", arg) == 0) {
  1278. init->sl_alloc.enable = 0;
  1279. init->std_alloc.enable = 0;
  1280. init->binary_alloc.enable = 0;
  1281. init->ets_alloc.enable = 0;
  1282. }
  1283. for (a = 0; a < aui_sz; a++) {
  1284. aui[a]->thr_spec = 0;
  1285. aui[a]->init.util.ramv = 0;
  1286. aui[a]->init.util.mmmbc = 10;
  1287. aui[a]->init.util.lmbcs = 5*1024*1024;
  1288. }
  1289. }
  1290. else {
  1291. bad_param(param, param+3);
  1292. }
  1293. break;
  1294. }
  1295. default:
  1296. bad_param(param, param+1);
  1297. }
  1298. break;
  1299. case 'i':
  1300. switch (argv[i][3]) {
  1301. case 's':
  1302. arg = get_value(argv[i]+4, argv, &i);
  1303. if (strcmp("true", arg) == 0)
  1304. init->instr.stat = 1;
  1305. else if (strcmp("false", arg) == 0)
  1306. init->instr.stat = 0;
  1307. else
  1308. bad_value(param, param+3, arg);
  1309. break;
  1310. case 'm':
  1311. arg = get_value(argv[i]+4, argv, &i);
  1312. if (strcmp("true", arg) == 0)
  1313. init->instr.map = 1;
  1314. else if (strcmp("false", arg) == 0)
  1315. init->instr.map = 0;
  1316. else
  1317. bad_value(param, param+3, arg);
  1318. break;
  1319. case 't':
  1320. init->instr.mtrace = get_value(argv[i]+4, argv, &i);
  1321. break;
  1322. default:
  1323. bad_param(param, param+2);
  1324. }
  1325. break;
  1326. case 'u':
  1327. if (has_prefix("ycs", argv[i]+3)) {
  1328. init->alloc_util.ycs
  1329. = get_kb_value(argv[i]+6, argv, &i);
  1330. }
  1331. else if (has_prefix("mmc", argv[i]+3)) {
  1332. init->alloc_util.mmc
  1333. = get_amount_value(argv[i]+6, argv, &i);
  1334. }
  1335. else {
  1336. int a;
  1337. int start = i;
  1338. char *param = argv[i];
  1339. char *val = i+1 < *argc ? argv[i+1] : NULL;
  1340. for (a = 0; a < aui_sz; a++) {
  1341. if (a > 0) {
  1342. ASSERT(i == start || i == start+1);
  1343. argv[start] = param;
  1344. if (i != start)
  1345. argv[start + 1] = val;
  1346. i = start;
  1347. }
  1348. handle_au_arg(aui[a], &argv[i][3], argv, &i);
  1349. }
  1350. }
  1351. break;
  1352. default:
  1353. bad_param(param, param+1);
  1354. }
  1355. break;
  1356. case '-':
  1357. if (argv[i][2] == '\0') {
  1358. /* End of system flags reached */
  1359. if (init->instr.mtrace
  1360. /* || init->instr.stat
  1361. || init->instr.map */) {
  1362. while (i < *argc) {
  1363. if(strcmp(argv[i], "-sname") == 0
  1364. || strcmp(argv[i], "-name") == 0) {
  1365. if (i + 1 <*argc) {
  1366. init->instr.nodename = argv[i+1];
  1367. break;
  1368. }
  1369. }
  1370. i++;
  1371. }
  1372. }
  1373. goto args_parsed;
  1374. }
  1375. break;
  1376. default:
  1377. break;
  1378. }
  1379. }
  1380. i++;
  1381. }
  1382. args_parsed:
  1383. /* Handled arguments have been marked with NULL. Slide arguments
  1384. not handled towards the beginning of argv. */
  1385. for (i = 0, j = 0; i < *argc; i++) {
  1386. if (argv[i])
  1387. argv[j++] = argv[i];
  1388. }
  1389. *argc = j;
  1390. }
  1391. static char *type_no_str(ErtsAlcType_t n)
  1392. {
  1393. #if ERTS_ALC_N_MIN != 0
  1394. if (n < ERTS_ALC_N_MIN)
  1395. return NULL;
  1396. #endif
  1397. if (n > ERTS_ALC_N_MAX)
  1398. return NULL;
  1399. return (char *) ERTS_ALC_N2TD(n);
  1400. }
  1401. #define type_str(T) type_no_str(ERTS_ALC_T2N((T)))
  1402. erts_tsd_key_t thr_ix_key;
  1403. erts_spinlock_t alloc_thr_ix_lock;
  1404. int last_thr_ix;
  1405. int first_dyn_thr_ix;
  1406. static void
  1407. init_thr_ix(int static_ixs)
  1408. {
  1409. erts_tsd_key_create(&thr_ix_key);
  1410. erts_spinlock_init(&alloc_thr_ix_lock, "alloc_thr_ix_lock");
  1411. last_thr_ix = -4711;
  1412. first_dyn_thr_ix = static_ixs+1;
  1413. }
  1414. int
  1415. erts_alc_get_thr_ix(void)
  1416. {
  1417. int ix = (int)(long) erts_tsd_get(thr_ix_key);
  1418. if (ix == 0) {
  1419. erts_spin_lock(&alloc_thr_ix_lock);
  1420. last_thr_ix++;
  1421. if (last_thr_ix < 0)
  1422. last_thr_ix = first_dyn_thr_ix;
  1423. ix = last_thr_ix;
  1424. erts_spin_unlock(&alloc_thr_ix_lock);
  1425. erts_tsd_set(thr_ix_key, (void *)(long) ix);
  1426. }
  1427. ASSERT(ix > 0);
  1428. return ix;
  1429. }
  1430. void erts_alloc_reg_scheduler_id(Uint id)
  1431. {
  1432. int ix = (int) id;
  1433. ASSERT(0 < ix && ix <= first_dyn_thr_ix);
  1434. ASSERT(0 == (int) (long) erts_tsd_get(thr_ix_key));
  1435. erts_tsd_set(thr_ix_key, (void *)(long) ix);
  1436. }
  1437. static void
  1438. no_verify(Allctr_t *allctr)
  1439. {
  1440. }
  1441. erts_alloc_verify_func_t
  1442. erts_alloc_get_verify_unused_temp_alloc(Allctr_t **allctr)
  1443. {
  1444. if (erts_allctrs_info[ERTS_ALC_A_TEMPORARY].alloc_util
  1445. && erts_allctrs_info[ERTS_ALC_A_TEMPORARY].thr_spec) {
  1446. ErtsAllocatorThrSpec_t *tspec;
  1447. tspec = &erts_allctr_thr_spec[ERTS_ALC_A_TEMPORARY];
  1448. if (!tspec->all_thr_safe) {
  1449. int ix = erts_alc_get_thr_ix();
  1450. if (ix < tspec->size) {
  1451. *allctr = tspec->allctr[ix];
  1452. return erts_alcu_verify_unused;
  1453. }
  1454. }
  1455. }
  1456. *allctr = NULL;
  1457. return no_verify;
  1458. }
  1459. __decl_noreturn void
  1460. erts_alc_fatal_error(int error, int func, ErtsAlcType_t n, ...)
  1461. {
  1462. char buf[10];
  1463. char *t_str;
  1464. char *allctr_str;
  1465. ASSERT(n >= ERTS_ALC_N_MIN);
  1466. ASSERT(n <= ERTS_ALC_N_MAX);
  1467. if (n < ERTS_ALC_N_MIN || ERTS_ALC_N_MAX < n)
  1468. allctr_str = "UNKNOWN";
  1469. else {
  1470. ErtsAlcType_t a = ERTS_ALC_T2A(ERTS_ALC_N2T(n));
  1471. if (erts_allctrs_info[a].enabled)
  1472. allctr_str = (char *) ERTS_ALC_A2AD(a);
  1473. else
  1474. allctr_str = (char *) ERTS_ALC_A2AD(ERTS_ALC_A_SYSTEM);
  1475. }
  1476. t_str = type_no_str(n);
  1477. if (!t_str) {
  1478. sprintf(buf, "%d", (int) n);
  1479. t_str = buf;
  1480. }
  1481. switch (error) {
  1482. case ERTS_ALC_E_NOTSUP: {
  1483. char *op_str;
  1484. switch (func) {
  1485. case ERTS_ALC_O_ALLOC: op_str = "alloc"; break;
  1486. case ERTS_ALC_O_REALLOC: op_str = "realloc"; break;
  1487. case ERTS_ALC_O_FREE: op_str = "free"; break;
  1488. default: op_str = "UNKNOWN"; break;
  1489. }
  1490. erl_exit(ERTS_ABORT_EXIT,
  1491. "%s: %s operation not supported (memory type: \"%s\")\n",
  1492. allctr_str, op_str, t_str);
  1493. break;
  1494. }
  1495. case ERTS_ALC_E_NOMEM: {
  1496. Uint size;
  1497. va_list argp;
  1498. char *op = func == ERTS_ALC_O_REALLOC ? "reallocate" : "allocate";
  1499. va_start(argp, n);
  1500. size = va_arg(argp, Uint);
  1501. va_end(argp);
  1502. erl_exit(1,
  1503. "%s: Cannot %s %lu bytes of memory (of type \"%s\").\n",
  1504. allctr_str, op, size, t_str);
  1505. break;
  1506. }
  1507. case ERTS_ALC_E_NOALLCTR:
  1508. erl_exit(ERTS_ABORT_EXIT,
  1509. "erts_alloc: Unknown allocator type: %d\n",
  1510. ERTS_ALC_T2A(ERTS_ALC_N2T(n)));
  1511. break;
  1512. default:
  1513. erl_exit(ERTS_ABORT_EXIT, "erts_alloc: Unknown error: %d\n", error);
  1514. break;
  1515. }
  1516. }
  1517. __decl_noreturn void
  1518. erts_alloc_enomem(ErtsAlcType_t type, Uint size)
  1519. {
  1520. erts_alloc_n_enomem(ERTS_ALC_T2N(type), size);
  1521. }
  1522. __decl_noreturn void
  1523. erts_alloc_n_enomem(ErtsAlcType_t n, Uint size)
  1524. {
  1525. erts_alc_fatal_error(ERTS_ALC_E_NOMEM, ERTS_ALC_O_ALLOC, n, size);
  1526. }
  1527. __decl_noreturn void
  1528. erts_realloc_enomem(ErtsAlcType_t type, void *ptr, Uint size)
  1529. {
  1530. erts_realloc_n_enomem(ERTS_ALC_T2N(type), ptr, size);
  1531. }
  1532. __decl_noreturn void
  1533. erts_realloc_n_enomem(ErtsAlcType_t n, void *ptr, Uint size)
  1534. {
  1535. erts_alc_fatal_error(ERTS_ALC_E_NOMEM, ERTS_ALC_O_REALLOC, n, size);
  1536. }
  1537. static ERTS_INLINE UWord
  1538. alcu_size(ErtsAlcType_t ai)
  1539. {
  1540. UWord res = 0;
  1541. ASSERT(erts_allctrs_info[ai].enabled);
  1542. ASSERT(erts_allctrs_info[ai].alloc_util);
  1543. if (!erts_allctrs_info[ai].thr_spec) {
  1544. Allctr_t *allctr = erts_allctrs_info[ai].extra;
  1545. AllctrSize_t asize;
  1546. erts_alcu_current_size(allctr, &asize);
  1547. res += asize.blocks;
  1548. }
  1549. else {
  1550. ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[ai];
  1551. int i;
  1552. ASSERT(tspec->all_thr_safe);
  1553. ASSERT(tspec->enabled);
  1554. for (i = tspec->size - 1; i >= 0; i--) {
  1555. Allctr_t *allctr = tspec->allctr[i];
  1556. AllctrSize_t asize;
  1557. if (allctr) {
  1558. erts_alcu_current_size(allctr, &asize);
  1559. res += asize.blocks;
  1560. }
  1561. }
  1562. }
  1563. return res;
  1564. }
  1565. #if HALFWORD_HEAP
  1566. static ERTS_INLINE int
  1567. alcu_is_low(ErtsAlcType_t ai)
  1568. {
  1569. int is_low = 0;
  1570. ASSERT(erts_allctrs_info[ai].enabled);
  1571. ASSERT(erts_allctrs_info[ai].alloc_util);
  1572. if (!erts_allctrs_info[ai].thr_spec) {
  1573. Allctr_t *allctr = erts_allctrs_info[ai].extra;
  1574. is_low = allctr->mseg_opt.low_mem;
  1575. }
  1576. else {
  1577. ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[ai];
  1578. int i;
  1579. # ifdef DEBUG
  1580. int found_one = 0;
  1581. # endif
  1582. ASSERT(tspec->all_thr_safe);
  1583. ASSERT(tspec->enabled);
  1584. for (i = tspec->size - 1; i >= 0; i--) {
  1585. Allctr_t *allctr = tspec->allctr[i];
  1586. if (allctr) {
  1587. # ifdef DEBUG
  1588. if (!found_one) {
  1589. is_low = allctr->mseg_opt.low_mem;
  1590. found_one = 1;
  1591. }
  1592. else ASSERT(is_low == allctr->mseg_opt.low_mem);
  1593. # else
  1594. is_low = allctr->mseg_opt.low_mem;
  1595. break;
  1596. # endif
  1597. }
  1598. }
  1599. ASSERT(found_one);
  1600. }
  1601. return is_low;
  1602. }
  1603. #endif /* HALFWORD */
  1604. Eterm
  1605. erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg)
  1606. {
  1607. #define ERTS_MEM_NEED_ALL_ALCU (!erts_instr_stat && want_tot_or_sys)
  1608. ErtsFixInfo efi;
  1609. struct {
  1610. int total;
  1611. int processes;
  1612. int processes_used;
  1613. int system;
  1614. int atom;
  1615. int atom_used;
  1616. int binary;
  1617. int code;
  1618. int ets;
  1619. int maximum;
  1620. #if HALFWORD_HEAP
  1621. int low;
  1622. #endif
  1623. } want = {0};
  1624. struct {
  1625. UWord total;
  1626. UWord processes;
  1627. UWord processes_used;
  1628. UWord system;
  1629. UWord atom;
  1630. UWord atom_used;
  1631. UWord binary;
  1632. UWord code;
  1633. UWord ets;
  1634. UWord maximum;
  1635. #if HALFWORD_HEAP
  1636. UWord low;
  1637. #endif
  1638. } size = {0};
  1639. Eterm atoms[sizeof(size)/sizeof(UWord)];
  1640. UWord *uintps[sizeof(size)/sizeof(UWord)];
  1641. Eterm euints[sizeof(size)/sizeof(UWord)];
  1642. int want_tot_or_sys;
  1643. int length;
  1644. Eterm res = THE_NON_VALUE;
  1645. ErtsAlcType_t ai;
  1646. int only_one_value = 0;
  1647. /* Figure out whats wanted... */
  1648. length = 0;
  1649. if (is_non_value(earg)) { /* i.e. wants all */
  1650. want.total = 1;
  1651. atoms[length] = am_total;
  1652. uintps[length++] = &size.total;
  1653. want.processes = 1;
  1654. atoms[length] = am_processes;
  1655. uintps[length++] = &size.processes;
  1656. want.processes_used = 1;
  1657. atoms[length] = am_processes_used;
  1658. uintps[length++] = &size.processes_used;
  1659. want.system = 1;
  1660. atoms[length] = am_system;
  1661. uintps[length++] = &size.system;
  1662. want.atom = 1;
  1663. atoms[length] = am_atom;
  1664. uintps[length++] = &size.atom;
  1665. want.atom_used = 1;
  1666. atoms[length] = am_atom_used;
  1667. uintps[length++] = &size.atom_used;
  1668. want.binary = 1;
  1669. atoms[length] = am_binary;
  1670. uintps[length++] = &size.binary;
  1671. want.code = 1;
  1672. atoms[length] = am_code;
  1673. uintps[length++] = &size.code;
  1674. want.ets = 1;
  1675. atoms[length] = am_ets;
  1676. uintps[length++] = &size.ets;
  1677. want.maximum = erts_instr_stat;
  1678. if (want.maximum) {
  1679. atoms[length] = am_maximum;
  1680. uintps[length++] = &size.maximum;
  1681. }
  1682. #if HALFWORD_HEAP
  1683. want.low = 1;
  1684. atoms[length] = am_low;
  1685. uintps[length++] = &size.low;
  1686. #endif
  1687. }
  1688. else {
  1689. DeclareTmpHeapNoproc(tmp_heap,2);
  1690. Eterm wanted_list;
  1691. if (is_nil(earg))
  1692. return NIL;
  1693. UseTmpHeapNoproc(2);
  1694. if (is_not_atom(earg))
  1695. wanted_list = earg;
  1696. else {
  1697. wanted_list = CONS(&tmp_heap[0], earg, NIL);
  1698. only_one_value = 1;
  1699. }
  1700. while (is_list(wanted_list)) {
  1701. switch (CAR(list_val(wanted_list))) {
  1702. case am_total:
  1703. if (!want.total) {
  1704. want.total = 1;
  1705. atoms[length] = am_total;
  1706. uintps[length++] = &size.total;
  1707. }
  1708. break;
  1709. case am_processes:
  1710. if (!want.processes) {
  1711. want.processes = 1;
  1712. atoms[length] = am_processes;
  1713. uintps[length++] = &size.processes;
  1714. }
  1715. break;
  1716. case am_processes_used:
  1717. if (!want.processes_used) {
  1718. want.processes_used = 1;
  1719. atoms[length] = am_processes_used;
  1720. uintps[length++] = &size.processes_used;
  1721. }
  1722. break;
  1723. case am_system:
  1724. if (!want.system) {
  1725. want.system = 1;
  1726. atoms[length] = am_system;
  1727. uintps[length++] = &size.system;
  1728. }
  1729. break;
  1730. case am_atom:
  1731. if (!want.atom) {
  1732. want.atom = 1;
  1733. atoms[length] = am_atom;
  1734. uintps[length++] = &size.atom;
  1735. }
  1736. break;
  1737. case am_atom_used:
  1738. if (!want.atom_used) {
  1739. want.atom_used = 1;
  1740. atoms[length] = am_atom_used;
  1741. uintps[length++] = &size.atom_used;
  1742. }
  1743. break;
  1744. case am_binary:
  1745. if (!want.binary) {
  1746. want.binary = 1;
  1747. atoms[length] = am_binary;
  1748. uintps[length++] = &size.binary;
  1749. }
  1750. break;
  1751. case am_code:
  1752. if (!want.code) {
  1753. want.code = 1;
  1754. atoms[length] = am_code;
  1755. uintps[length++] = &size.code;
  1756. }
  1757. break;
  1758. case am_ets:
  1759. if (!want.ets) {
  1760. want.ets = 1;
  1761. atoms[length] = am_ets;
  1762. uintps[length++] = &size.ets;
  1763. }
  1764. break;
  1765. case am_maximum:
  1766. if (erts_instr_stat) {
  1767. if (!want.maximum) {
  1768. want.maximum = 1;
  1769. atoms[length] =

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