/erts/emulator/beam/erl_alloc.c
C | 3460 lines | 2980 code | 393 blank | 87 comment | 491 complexity | fba2217479c0462b86ff92cd70d5f001 MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-2-Clause
Large files files are truncated, but you can click here to view the full file
- /*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2002-2011. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
- /*
- * Description: Management of memory allocators.
- *
- * Author: Rickard Green
- */
- #ifdef HAVE_CONFIG_H
- # include "config.h"
- #endif
- #define ERTS_ALLOC_C__
- #define ERTS_ALC_INTERNAL__
- #include "sys.h"
- #define ERL_THREADS_EMU_INTERNAL__
- #include "erl_threads.h"
- #include "global.h"
- #include "erl_db.h"
- #include "erl_binary.h"
- #include "erl_bits.h"
- #include "erl_instrument.h"
- #include "erl_mseg.h"
- #include "erl_monitors.h"
- #include "erl_bif_timer.h"
- #if defined(ERTS_ALC_T_DRV_SEL_D_STATE) || defined(ERTS_ALC_T_DRV_EV_D_STATE)
- #include "erl_check_io.h"
- #endif
- #define GET_ERL_GF_ALLOC_IMPL
- #include "erl_goodfit_alloc.h"
- #define GET_ERL_BF_ALLOC_IMPL
- #include "erl_bestfit_alloc.h"
- #define GET_ERL_AF_ALLOC_IMPL
- #include "erl_afit_alloc.h"
- #define ERTS_ALC_DEFAULT_MAX_THR_PREF 16
- #if defined(SMALL_MEMORY) || defined(PURIFY) || defined(VALGRIND)
- #define AU_ALLOC_DEFAULT_ENABLE(X) 0
- #else
- #define AU_ALLOC_DEFAULT_ENABLE(X) (X)
- #endif
- #ifdef DEBUG
- static Uint install_debug_functions(void);
- #if 0
- #define HARD_DEBUG
- #ifdef __GNUC__
- #warning "* * * * * * * * * * * * * *"
- #warning "* HARD DEBUG IS ENABLED! *"
- #warning "* * * * * * * * * * * * * *"
- #endif
- #endif
- #endif
- ErtsAllocatorFunctions_t erts_allctrs[ERTS_ALC_A_MAX+1];
- ErtsAllocatorInfo_t erts_allctrs_info[ERTS_ALC_A_MAX+1];
- ErtsAllocatorThrSpec_t erts_allctr_thr_spec[ERTS_ALC_A_MAX+1];
- #define ERTS_MIN(A, B) ((A) < (B) ? (A) : (B))
- #define ERTS_MAX(A, B) ((A) > (B) ? (A) : (B))
- typedef union {
- GFAllctr_t gfa;
- char align_gfa[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(GFAllctr_t))];
- BFAllctr_t bfa;
- char align_bfa[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(BFAllctr_t))];
- AFAllctr_t afa;
- char align_afa[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(AFAllctr_t))];
- } ErtsAllocatorState_t;
- static ErtsAllocatorState_t sl_alloc_state;
- static ErtsAllocatorState_t std_alloc_state;
- static ErtsAllocatorState_t ll_alloc_state;
- #if HALFWORD_HEAP
- static ErtsAllocatorState_t std_alloc_low_state;
- static ErtsAllocatorState_t ll_alloc_low_state;
- #endif
- static ErtsAllocatorState_t temp_alloc_state;
- static ErtsAllocatorState_t eheap_alloc_state;
- static ErtsAllocatorState_t binary_alloc_state;
- static ErtsAllocatorState_t ets_alloc_state;
- static ErtsAllocatorState_t driver_alloc_state;
- ErtsAlcType_t erts_fix_core_allocator_ix;
- #ifdef ERTS_ALC_N_MIN_A_FIXED_SIZE
- static void *(*fix_core_allocator)(ErtsAlcType_t, void *, Uint);
- static void *fix_core_extra;
- static void *fix_core_alloc(Uint size)
- {
- void *res;
- res = (*fix_core_allocator)(ERTS_ALC_T_UNDEF, fix_core_extra, size);
- if (erts_mtrace_enabled)
- erts_mtrace_crr_alloc(res,
- ERTS_ALC_A_FIXED_SIZE,
- erts_fix_core_allocator_ix,
- size);
- return res;
- }
- #endif
- enum allctr_type {
- GOODFIT,
- BESTFIT,
- AFIT
- };
- struct au_init {
- int enable;
- int thr_spec;
- enum allctr_type atype;
- struct {
- AllctrInit_t util;
- GFAllctrInit_t gf;
- BFAllctrInit_t bf;
- AFAllctrInit_t af;
- } init;
- struct {
- int mmbcs;
- int lmbcs;
- int smbcs;
- int mmmbc;
- } default_;
- };
- #define DEFAULT_ALLCTR_INIT { \
- ERTS_DEFAULT_ALLCTR_INIT, \
- ERTS_DEFAULT_GF_ALLCTR_INIT, \
- ERTS_DEFAULT_BF_ALLCTR_INIT, \
- ERTS_DEFAULT_AF_ALLCTR_INIT \
- }
- typedef struct {
- int erts_alloc_config;
- #if HAVE_ERTS_MSEG
- ErtsMsegInit_t mseg;
- #endif
- int trim_threshold;
- int top_pad;
- AlcUInit_t alloc_util;
- struct {
- int stat;
- int map;
- char *mtrace;
- char *nodename;
- } instr;
- struct au_init sl_alloc;
- struct au_init std_alloc;
- struct au_init ll_alloc;
- struct au_init temp_alloc;
- struct au_init eheap_alloc;
- struct au_init binary_alloc;
- struct au_init ets_alloc;
- struct au_init driver_alloc;
- #if HALFWORD_HEAP
- struct au_init std_alloc_low;
- struct au_init ll_alloc_low;
- #endif
- } erts_alc_hndl_args_init_t;
- #define ERTS_AU_INIT__ {0, 0, GOODFIT, DEFAULT_ALLCTR_INIT, {1,1,1,1}}
- #define SET_DEFAULT_ALLOC_OPTS(IP) \
- do { \
- struct au_init aui__ = ERTS_AU_INIT__; \
- sys_memcpy((void *) (IP), (void *) &aui__, sizeof(struct au_init)); \
- } while (0)
- static void
- set_default_sl_alloc_opts(struct au_init *ip)
- {
- SET_DEFAULT_ALLOC_OPTS(ip);
- ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
- ip->thr_spec = 1;
- ip->atype = GOODFIT;
- ip->init.util.name_prefix = "sl_";
- ip->init.util.mmmbc = 5;
- ip->init.util.alloc_no = ERTS_ALC_A_SHORT_LIVED;
- #ifndef SMALL_MEMORY
- ip->init.util.mmbcs = 128*1024; /* Main carrier size */
- #else
- ip->init.util.mmbcs = 32*1024; /* Main carrier size */
- #endif
- ip->init.util.ts = ERTS_ALC_MTA_SHORT_LIVED;
- ip->init.util.rsbcst = 80;
- #if HALFWORD_HEAP
- ip->init.util.low_mem = 1;
- #endif
- }
- static void
- set_default_std_alloc_opts(struct au_init *ip)
- {
- SET_DEFAULT_ALLOC_OPTS(ip);
- ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
- ip->thr_spec = 1;
- ip->atype = BESTFIT;
- ip->init.util.name_prefix = "std_";
- ip->init.util.mmmbc = 5;
- ip->init.util.alloc_no = ERTS_ALC_A_STANDARD;
- #ifndef SMALL_MEMORY
- ip->init.util.mmbcs = 128*1024; /* Main carrier size */
- #else
- ip->init.util.mmbcs = 32*1024; /* Main carrier size */
- #endif
- ip->init.util.ts = ERTS_ALC_MTA_STANDARD;
- }
- static void
- set_default_ll_alloc_opts(struct au_init *ip)
- {
- SET_DEFAULT_ALLOC_OPTS(ip);
- ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
- ip->thr_spec = 0;
- ip->atype = BESTFIT;
- ip->init.bf.ao = 1;
- ip->init.util.ramv = 0;
- ip->init.util.mmsbc = 0;
- ip->init.util.mmmbc = 0;
- ip->init.util.sbct = ~((UWord) 0);
- ip->init.util.name_prefix = "ll_";
- ip->init.util.alloc_no = ERTS_ALC_A_LONG_LIVED;
- #ifndef SMALL_MEMORY
- ip->init.util.mmbcs = 2*1024*1024; /* Main carrier size */
- #else
- ip->init.util.mmbcs = 1*1024*1024; /* Main carrier size */
- #endif
- ip->init.util.ts = ERTS_ALC_MTA_LONG_LIVED;
- ip->init.util.asbcst = 0;
- ip->init.util.rsbcst = 0;
- ip->init.util.rsbcmt = 0;
- ip->init.util.rmbcmt = 0;
- }
- static void
- set_default_temp_alloc_opts(struct au_init *ip)
- {
- SET_DEFAULT_ALLOC_OPTS(ip);
- ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
- ip->thr_spec = 1;
- ip->atype = AFIT;
- ip->init.util.name_prefix = "temp_";
- ip->init.util.alloc_no = ERTS_ALC_A_TEMPORARY;
- #ifndef SMALL_MEMORY
- ip->init.util.mmbcs = 128*1024; /* Main carrier size */
- #else
- ip->init.util.mmbcs = 32*1024; /* Main carrier size */
- #endif
- ip->init.util.ts = ERTS_ALC_MTA_TEMPORARY;
- ip->init.util.rsbcst = 90;
- ip->init.util.rmbcmt = 100;
- #if HALFWORD_HEAP
- ip->init.util.low_mem = 1;
- #endif
- }
- static void
- set_default_eheap_alloc_opts(struct au_init *ip)
- {
- SET_DEFAULT_ALLOC_OPTS(ip);
- ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
- ip->thr_spec = 1;
- ip->atype = GOODFIT;
- ip->init.util.mmmbc = 100;
- ip->init.util.name_prefix = "eheap_";
- ip->init.util.alloc_no = ERTS_ALC_A_EHEAP;
- #ifndef SMALL_MEMORY
- ip->init.util.mmbcs = 512*1024; /* Main carrier size */
- #else
- ip->init.util.mmbcs = 256*1024; /* Main carrier size */
- #endif
- ip->init.util.ts = ERTS_ALC_MTA_EHEAP;
- ip->init.util.rsbcst = 50;
- #if HALFWORD_HEAP
- ip->init.util.low_mem = 1;
- #endif
- }
- static void
- set_default_binary_alloc_opts(struct au_init *ip)
- {
- SET_DEFAULT_ALLOC_OPTS(ip);
- ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
- ip->thr_spec = 1;
- ip->atype = BESTFIT;
- ip->init.util.mmmbc = 50;
- ip->init.util.name_prefix = "binary_";
- ip->init.util.alloc_no = ERTS_ALC_A_BINARY;
- #ifndef SMALL_MEMORY
- ip->init.util.mmbcs = 128*1024; /* Main carrier size */
- #else
- ip->init.util.mmbcs = 32*1024; /* Main carrier size */
- #endif
- ip->init.util.ts = ERTS_ALC_MTA_BINARY;
- }
- static void
- set_default_ets_alloc_opts(struct au_init *ip)
- {
- SET_DEFAULT_ALLOC_OPTS(ip);
- ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
- ip->thr_spec = 1;
- ip->atype = BESTFIT;
- ip->init.util.mmmbc = 100;
- ip->init.util.name_prefix = "ets_";
- ip->init.util.alloc_no = ERTS_ALC_A_ETS;
- #ifndef SMALL_MEMORY
- ip->init.util.mmbcs = 128*1024; /* Main carrier size */
- #else
- ip->init.util.mmbcs = 32*1024; /* Main carrier size */
- #endif
- ip->init.util.ts = ERTS_ALC_MTA_ETS;
- }
- static void
- set_default_driver_alloc_opts(struct au_init *ip)
- {
- SET_DEFAULT_ALLOC_OPTS(ip);
- ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
- ip->thr_spec = 1;
- ip->atype = BESTFIT;
- ip->init.util.name_prefix = "driver_";
- ip->init.util.alloc_no = ERTS_ALC_A_DRIVER;
- #ifndef SMALL_MEMORY
- ip->init.util.mmbcs = 128*1024; /* Main carrier size */
- #else
- ip->init.util.mmbcs = 32*1024; /* Main carrier size */
- #endif
- ip->init.util.ts = ERTS_ALC_MTA_DRIVER;
- }
- #ifdef ERTS_SMP
- static void
- adjust_tpref(struct au_init *ip, int no_sched)
- {
- if (ip->thr_spec) {
- Uint allocs;
- if (ip->thr_spec < 0) {/* User specified amount */
- allocs = abs(ip->thr_spec);
- if (allocs > no_sched)
- allocs = no_sched;
- }
- else if (no_sched > ERTS_ALC_DEFAULT_MAX_THR_PREF)
- allocs = ERTS_ALC_DEFAULT_MAX_THR_PREF;
- else
- allocs = no_sched;
- if (allocs <= 1)
- ip->thr_spec = 0;
- else {
- ip->thr_spec = (int) allocs;
- ip->thr_spec *= -1; /* thread preferred */
- /* If default ... */
- /* ... shrink main multi-block carrier size */
- if (ip->default_.mmbcs)
- ip->init.util.mmbcs /= ERTS_MIN(4, allocs);
- /* ... shrink largest multi-block carrier size */
- if (ip->default_.lmbcs)
- ip->init.util.lmbcs /= ERTS_MIN(2, allocs);
- /* ... shrink smallest multi-block carrier size */
- if (ip->default_.smbcs)
- ip->init.util.smbcs /= ERTS_MIN(4, allocs);
- /* ... and more than three allocators shrink
- max mseg multi-block carriers */
- if (ip->default_.mmmbc && allocs > 2) {
- ip->init.util.mmmbc /= ERTS_MIN(4, allocs - 1);
- if (ip->init.util.mmmbc < 3)
- ip->init.util.mmmbc = 3;
- }
- }
- }
- }
- #endif
- static void handle_args(int *, char **, erts_alc_hndl_args_init_t *);
- static void
- set_au_allocator(ErtsAlcType_t alctr_n, struct au_init *init);
- static void
- start_au_allocator(ErtsAlcType_t alctr_n,
- struct au_init *init,
- ErtsAllocatorState_t *state);
- static void
- refuse_af_strategy(struct au_init *init)
- {
- if (init->atype == AFIT)
- init->atype = GOODFIT;
- }
- static void init_thr_ix(int static_ixs);
- #ifdef HARD_DEBUG
- static void hdbg_init(void);
- #endif
- void
- erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
- {
- UWord extra_block_size = 0;
- int i;
- erts_alc_hndl_args_init_t init = {
- 0,
- #if HAVE_ERTS_MSEG
- ERTS_MSEG_INIT_DEFAULT_INITIALIZER,
- #endif
- ERTS_DEFAULT_TRIM_THRESHOLD,
- ERTS_DEFAULT_TOP_PAD,
- ERTS_DEFAULT_ALCU_INIT
- };
- #ifdef HARD_DEBUG
- hdbg_init();
- #endif
- erts_sys_alloc_init();
- init_thr_ix(erts_no_schedulers);
- erts_init_utils_mem();
- set_default_sl_alloc_opts(&init.sl_alloc);
- set_default_std_alloc_opts(&init.std_alloc);
- set_default_ll_alloc_opts(&init.ll_alloc);
- set_default_temp_alloc_opts(&init.temp_alloc);
- set_default_eheap_alloc_opts(&init.eheap_alloc);
- set_default_binary_alloc_opts(&init.binary_alloc);
- set_default_ets_alloc_opts(&init.ets_alloc);
- set_default_driver_alloc_opts(&init.driver_alloc);
- if (argc && argv)
- handle_args(argc, argv, &init);
- if (erts_no_schedulers <= 1) {
- init.sl_alloc.thr_spec = 0;
- init.std_alloc.thr_spec = 0;
- init.ll_alloc.thr_spec = 0;
- init.eheap_alloc.thr_spec = 0;
- init.binary_alloc.thr_spec = 0;
- init.ets_alloc.thr_spec = 0;
- init.driver_alloc.thr_spec = 0;
- }
- if (init.erts_alloc_config) {
- /* Adjust flags that erts_alloc_config won't like */
- init.temp_alloc.thr_spec = 0;
- init.sl_alloc.thr_spec = 0;
- init.std_alloc.thr_spec = 0;
- init.ll_alloc.thr_spec = 0;
- init.eheap_alloc.thr_spec = 0;
- init.binary_alloc.thr_spec = 0;
- init.ets_alloc.thr_spec = 0;
- init.driver_alloc.thr_spec = 0;
- }
- #ifdef ERTS_SMP
- /* Only temp_alloc can use thread specific interface */
- if (init.temp_alloc.thr_spec)
- init.temp_alloc.thr_spec = erts_no_schedulers;
- /* Others must use thread preferred interface */
- adjust_tpref(&init.sl_alloc, erts_no_schedulers);
- adjust_tpref(&init.std_alloc, erts_no_schedulers);
- adjust_tpref(&init.ll_alloc, erts_no_schedulers);
- adjust_tpref(&init.eheap_alloc, erts_no_schedulers);
- adjust_tpref(&init.binary_alloc, erts_no_schedulers);
- adjust_tpref(&init.ets_alloc, erts_no_schedulers);
- adjust_tpref(&init.driver_alloc, erts_no_schedulers);
- #else
- /* No thread specific if not smp */
- init.temp_alloc.thr_spec = 0;
- #endif
- /*
- * The following allocators cannot be run with afit strategy.
- * Make sure they don't...
- */
- refuse_af_strategy(&init.sl_alloc);
- refuse_af_strategy(&init.std_alloc);
- refuse_af_strategy(&init.ll_alloc);
- refuse_af_strategy(&init.eheap_alloc);
- refuse_af_strategy(&init.binary_alloc);
- refuse_af_strategy(&init.ets_alloc);
- refuse_af_strategy(&init.driver_alloc);
- #ifdef ERTS_SMP
- if (!init.temp_alloc.thr_spec)
- refuse_af_strategy(&init.temp_alloc);
- #endif
- erts_mtrace_pre_init();
- #if HAVE_ERTS_MSEG
- erts_mseg_init(&init.mseg);
- #endif
- erts_alcu_init(&init.alloc_util);
- erts_afalc_init();
- erts_bfalc_init();
- erts_gfalc_init();
- for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) {
- erts_allctrs[i].alloc = NULL;
- erts_allctrs[i].realloc = NULL;
- erts_allctrs[i].free = NULL;
- erts_allctrs[i].extra = NULL;
- erts_allctrs_info[i].alloc_util = 0;
- erts_allctrs_info[i].enabled = 0;
- erts_allctrs_info[i].thr_spec = 0;
- erts_allctrs_info[i].extra = NULL;
- }
- #ifdef ERTS_ALC_N_MIN_A_FIXED_SIZE
- #if !defined(PURIFY) && !defined(VALGRIND)
- erts_allctrs[ERTS_ALC_A_FIXED_SIZE].alloc = erts_fix_alloc;
- erts_allctrs[ERTS_ALC_A_FIXED_SIZE].realloc = erts_fix_realloc;
- erts_allctrs[ERTS_ALC_A_FIXED_SIZE].free = erts_fix_free;
- erts_allctrs_info[ERTS_ALC_A_FIXED_SIZE].enabled = 1;
- #else
- erts_allctrs[ERTS_ALC_A_FIXED_SIZE].alloc = erts_sys_alloc;
- erts_allctrs[ERTS_ALC_A_FIXED_SIZE].realloc = erts_sys_realloc;
- erts_allctrs[ERTS_ALC_A_FIXED_SIZE].free = erts_sys_free;
- erts_allctrs_info[ERTS_ALC_A_FIXED_SIZE].enabled = 0;
- #endif
- #endif
- erts_allctrs[ERTS_ALC_A_SYSTEM].alloc = erts_sys_alloc;
- erts_allctrs[ERTS_ALC_A_SYSTEM].realloc = erts_sys_realloc;
- erts_allctrs[ERTS_ALC_A_SYSTEM].free = erts_sys_free;
- erts_allctrs_info[ERTS_ALC_A_SYSTEM].enabled = 1;
- #if HALFWORD_HEAP
- /* Init low memory variants by cloning */
- init.std_alloc_low = init.std_alloc;
- init.std_alloc_low.init.util.alloc_no = ERTS_ALC_A_STANDARD_LOW;
- init.std_alloc_low.init.util.low_mem = 1;
- init.ll_alloc_low = init.ll_alloc;
- init.ll_alloc_low.init.util.alloc_no = ERTS_ALC_A_LONG_LIVED_LOW;
- init.ll_alloc_low.init.util.low_mem = 1;
- set_au_allocator(ERTS_ALC_A_STANDARD_LOW, &init.std_alloc_low);
- set_au_allocator(ERTS_ALC_A_LONG_LIVED_LOW, &init.ll_alloc_low);
- #endif /* HALFWORD */
- set_au_allocator(ERTS_ALC_A_TEMPORARY, &init.temp_alloc);
- set_au_allocator(ERTS_ALC_A_SHORT_LIVED, &init.sl_alloc);
- set_au_allocator(ERTS_ALC_A_STANDARD, &init.std_alloc);
- set_au_allocator(ERTS_ALC_A_LONG_LIVED, &init.ll_alloc);
- set_au_allocator(ERTS_ALC_A_EHEAP, &init.eheap_alloc);
- set_au_allocator(ERTS_ALC_A_BINARY, &init.binary_alloc);
- set_au_allocator(ERTS_ALC_A_ETS, &init.ets_alloc);
- set_au_allocator(ERTS_ALC_A_DRIVER, &init.driver_alloc);
- for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) {
- if (!erts_allctrs[i].alloc)
- erl_exit(ERTS_ABORT_EXIT,
- "Missing alloc function for %s\n", ERTS_ALC_A2AD(i));
- if (!erts_allctrs[i].realloc)
- erl_exit(ERTS_ABORT_EXIT,
- "Missing realloc function for %s\n", ERTS_ALC_A2AD(i));
- if (!erts_allctrs[i].free)
- erl_exit(ERTS_ABORT_EXIT,
- "Missing free function for %s\n", ERTS_ALC_A2AD(i));
- }
- sys_alloc_opt(SYS_ALLOC_OPT_TRIM_THRESHOLD, init.trim_threshold);
- sys_alloc_opt(SYS_ALLOC_OPT_TOP_PAD, init.top_pad);
- if (erts_allctrs_info[ERTS_FIX_CORE_ALLOCATOR].enabled)
- erts_fix_core_allocator_ix = ERTS_FIX_CORE_ALLOCATOR;
- else
- erts_fix_core_allocator_ix = ERTS_ALC_A_SYSTEM;
- erts_mtrace_init(init.instr.mtrace, init.instr.nodename);
- start_au_allocator(ERTS_ALC_A_TEMPORARY,
- &init.temp_alloc,
- &temp_alloc_state);
- start_au_allocator(ERTS_ALC_A_SHORT_LIVED,
- &init.sl_alloc,
- &sl_alloc_state);
- start_au_allocator(ERTS_ALC_A_STANDARD,
- &init.std_alloc,
- &std_alloc_state);
- start_au_allocator(ERTS_ALC_A_LONG_LIVED,
- &init.ll_alloc,
- &ll_alloc_state);
- #if HALFWORD_HEAP
- start_au_allocator(ERTS_ALC_A_LONG_LIVED_LOW,
- &init.ll_alloc_low,
- &ll_alloc_low_state);
- start_au_allocator(ERTS_ALC_A_STANDARD_LOW,
- &init.std_alloc_low,
- &std_alloc_low_state);
- #endif
- start_au_allocator(ERTS_ALC_A_EHEAP,
- &init.eheap_alloc,
- &eheap_alloc_state);
- start_au_allocator(ERTS_ALC_A_BINARY,
- &init.binary_alloc,
- &binary_alloc_state);
- start_au_allocator(ERTS_ALC_A_ETS,
- &init.ets_alloc,
- &ets_alloc_state);
- start_au_allocator(ERTS_ALC_A_DRIVER,
- &init.driver_alloc,
- &driver_alloc_state);
- fix_core_allocator = erts_allctrs[erts_fix_core_allocator_ix].alloc;
- fix_core_extra = erts_allctrs[erts_fix_core_allocator_ix].extra;
- erts_mtrace_install_wrapper_functions();
- extra_block_size += erts_instr_init(init.instr.stat, init.instr.map);
- #ifdef DEBUG
- extra_block_size += install_debug_functions();
- #endif
- #ifdef ERTS_ALC_N_MIN_A_FIXED_SIZE
- erts_init_fix_alloc(extra_block_size, fix_core_alloc);
- #if !defined(PURIFY) && !defined(VALGRIND)
- erts_set_fix_size(ERTS_ALC_T_PROC, sizeof(Process));
- erts_set_fix_size(ERTS_ALC_T_DB_TABLE, sizeof(DbTable));
- erts_set_fix_size(ERTS_ALC_T_ATOM, sizeof(Atom));
- erts_set_fix_size(ERTS_ALC_T_MODULE, sizeof(Module));
- erts_set_fix_size(ERTS_ALC_T_REG_PROC, sizeof(RegProc));
- erts_set_fix_size(ERTS_ALC_T_FUN_ENTRY, sizeof(ErlFunEntry));
- #ifdef ERTS_ALC_T_DRV_EV_D_STATE
- erts_set_fix_size(ERTS_ALC_T_DRV_EV_D_STATE,
- sizeof(ErtsDrvEventDataState));
- #endif
- #ifdef ERTS_ALC_T_DRV_SEL_D_STATE
- erts_set_fix_size(ERTS_ALC_T_DRV_SEL_D_STATE,
- sizeof(ErtsDrvSelectDataState));
- #endif
- #if !HALFWORD_HEAP
- erts_set_fix_size(ERTS_ALC_T_EXPORT, sizeof(Export));
- erts_set_fix_size(ERTS_ALC_T_MONITOR_SH, ERTS_MONITOR_SH_SIZE*sizeof(Uint));
- erts_set_fix_size(ERTS_ALC_T_NLINK_SH, ERTS_LINK_SH_SIZE*sizeof(Uint));
- #endif
- #endif
- #endif
- }
- static void
- set_au_allocator(ErtsAlcType_t alctr_n, struct au_init *init)
- {
- ErtsAllocatorFunctions_t *af = &erts_allctrs[alctr_n];
- ErtsAllocatorInfo_t *ai = &erts_allctrs_info[alctr_n];
- ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[alctr_n];
- #if HALFWORD_HEAP
- /* If halfword heap, silently ignore any disabling of internal
- * allocators for low memory
- */
- if (init->init.util.low_mem) {
- init->enable = 1;
- }
- #endif
- if (!init->enable) {
- af->alloc = erts_sys_alloc;
- af->realloc = erts_sys_realloc;
- af->free = erts_sys_free;
- af->extra = NULL;
- ai->alloc_util = 0;
- ai->enabled = 0;
- ai->extra = NULL;
- return;
- }
- tspec->enabled = 0;
- tspec->all_thr_safe = 0;
- ai->thr_spec = 0;
- #ifdef USE_THREADS
- if (init->thr_spec) {
- if (init->thr_spec > 0) {
- af->alloc = erts_alcu_alloc_thr_spec;
- if (init->init.util.ramv)
- af->realloc = erts_alcu_realloc_mv_thr_spec;
- else
- af->realloc = erts_alcu_realloc_thr_spec;
- af->free = erts_alcu_free_thr_spec;
- }
- else {
- af->alloc = erts_alcu_alloc_thr_pref;
- if (init->init.util.ramv)
- af->realloc = erts_alcu_realloc_mv_thr_pref;
- else
- af->realloc = erts_alcu_realloc_thr_pref;
- af->free = erts_alcu_free_thr_pref;
- tspec->all_thr_safe = 1;
- }
- tspec->enabled = 1;
- tspec->size = abs(init->thr_spec) + 1;
- ai->thr_spec = tspec->size;
- }
- else if (init->init.util.ts) {
- af->alloc = erts_alcu_alloc_ts;
- if (init->init.util.ramv)
- af->realloc = erts_alcu_realloc_mv_ts;
- else
- af->realloc = erts_alcu_realloc_ts;
- af->free = erts_alcu_free_ts;
- }
- else
- #endif
- {
- af->alloc = erts_alcu_alloc;
- if (init->init.util.ramv)
- af->realloc = erts_alcu_realloc_mv;
- else
- af->realloc = erts_alcu_realloc;
- af->free = erts_alcu_free;
- }
- af->extra = NULL;
- ai->alloc_util = 1;
- ai->enabled = 1;
- }
- static void
- start_au_allocator(ErtsAlcType_t alctr_n,
- struct au_init *init,
- ErtsAllocatorState_t *state)
- {
- int i;
- int size = 1;
- void *as0;
- enum allctr_type atype;
- ErtsAllocatorFunctions_t *af = &erts_allctrs[alctr_n];
- ErtsAllocatorInfo_t *ai = &erts_allctrs_info[alctr_n];
- ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[alctr_n];
- if (!init->enable)
- return;
- if (init->thr_spec) {
- void *states = erts_sys_alloc(0,
- NULL,
- ((sizeof(Allctr_t *)
- * (tspec->size + 1))
- + (sizeof(ErtsAllocatorState_t)
- * tspec->size)
- + ERTS_CACHE_LINE_SIZE - 1));
- if (!states)
- erl_exit(ERTS_ABORT_EXIT,
- "Failed to allocate allocator states for %salloc\n",
- init->init.util.name_prefix);
- tspec->allctr = (Allctr_t **) states;
- states = ((char *) states) + sizeof(Allctr_t *) * (tspec->size + 1);
- states = ((((UWord) states) & ERTS_CACHE_LINE_MASK)
- ? (void *) ((((UWord) states) & ~ERTS_CACHE_LINE_MASK)
- + ERTS_CACHE_LINE_SIZE)
- : (void *) states);
- tspec->allctr[0] = init->thr_spec > 0 ? (Allctr_t *) state : (Allctr_t *) NULL;
- size = tspec->size;
- for (i = 1; i < size; i++)
- tspec->allctr[i] = (Allctr_t *)
- &((ErtsAllocatorState_t *) states)[i-1];
- }
- for (i = 0; i < size; i++) {
- void *as;
- atype = init->atype;
- if (!init->thr_spec)
- as0 = state;
- else {
- as0 = (void *) tspec->allctr[i];
- if (!as0)
- continue;
- if (i == 0) {
- if (atype == AFIT)
- atype = GOODFIT;
- init->init.util.ts = 1;
- }
- else {
- if (init->thr_spec < 0) {
- init->init.util.ts = 1;
- init->init.util.tspec = 0;
- init->init.util.tpref = -1*init->thr_spec;
- }
- else {
- init->init.util.ts = 0;
- init->init.util.tspec = init->thr_spec + 1;
- init->init.util.tpref = 0;
- }
- }
- }
- switch (atype) {
- case GOODFIT:
- as = (void *) erts_gfalc_start((GFAllctr_t *) as0,
- &init->init.gf,
- &init->init.util);
- break;
- case BESTFIT:
- as = (void *) erts_bfalc_start((BFAllctr_t *) as0,
- &init->init.bf,
- &init->init.util);
- break;
- case AFIT:
- as = (void *) erts_afalc_start((AFAllctr_t *) as0,
- &init->init.af,
- &init->init.util);
- break;
- default:
- as = NULL;
- ASSERT(0);
- }
- if (!as)
- erl_exit(ERTS_ABORT_EXIT,
- "Failed to start %salloc\n", init->init.util.name_prefix);
- ASSERT(as == (void *) as0);
- af->extra = as;
- }
- if (init->thr_spec) {
- af->extra = tspec;
- init->init.util.ts = 1;
- }
- ai->extra = af->extra;
- }
- static void bad_param(char *param_start, char *param_end)
- {
- size_t len = param_end - param_start;
- char param[100];
- if (len > 99)
- len = 99;
- sys_memcpy((void *) param, (void *) param_start, len);
- param[len] = '\0';
- erts_fprintf(stderr, "bad \"%s\" parameter\n", param);
- erts_usage();
- }
- static void bad_value(char *param_start, char *param_end, char *value)
- {
- size_t len = param_end - param_start;
- char param[100];
- if (len > 99)
- len = 99;
- sys_memcpy((void *) param, (void *) param_start, len);
- param[len] = '\0';
- erts_fprintf(stderr, "bad \"%s\" value: %s\n", param, value);
- erts_usage();
- }
- /* Get arg marks argument as handled by
- putting NULL in argv */
- static char *
- get_value(char* rest, char** argv, int* ip)
- {
- char *param = argv[*ip]+1;
- argv[*ip] = NULL;
- if (*rest == '\0') {
- char *next = argv[*ip + 1];
- if (next[0] == '-'
- && next[1] == '-'
- && next[2] == '\0') {
- bad_value(param, rest, "");
- }
- (*ip)++;
- argv[*ip] = NULL;
- return next;
- }
- return rest;
- }
- static ERTS_INLINE int
- has_prefix(const char *prefix, const char *string)
- {
- int i;
- for (i = 0; prefix[i]; i++)
- if (prefix[i] != string[i])
- return 0;
- return 1;
- }
- static int
- get_bool_value(char *param_end, char** argv, int* ip)
- {
- char *param = argv[*ip]+1;
- char *value = get_value(param_end, argv, ip);
- if (strcmp(value, "true") == 0)
- return 1;
- else if (strcmp(value, "false") == 0)
- return 0;
- else
- bad_value(param, param_end, value);
- return -1;
- }
- static Uint
- get_kb_value(char *param_end, char** argv, int* ip)
- {
- Sint tmp;
- Uint max = ((~((Uint) 0))/1024) + 1;
- char *rest;
- char *param = argv[*ip]+1;
- char *value = get_value(param_end, argv, ip);
- errno = 0;
- tmp = (Sint) strtol(value, &rest, 10);
- if (errno != 0 || rest == value || tmp < 0 || max < ((Uint) tmp))
- bad_value(param, param_end, value);
- if (max == (Uint) tmp)
- return ~((Uint) 0);
- else
- return ((Uint) tmp)*1024;
- }
- static Uint
- get_amount_value(char *param_end, char** argv, int* ip)
- {
- Sint tmp;
- char *rest;
- char *param = argv[*ip]+1;
- char *value = get_value(param_end, argv, ip);
- errno = 0;
- tmp = (Sint) strtol(value, &rest, 10);
- if (errno != 0 || rest == value || tmp < 0)
- bad_value(param, param_end, value);
- return (Uint) tmp;
- }
- static int
- get_bool_or_possitive_amount_value(int *bool, Uint *amount,
- char *param_end, char** argv, int* ip)
- {
- char *param = argv[*ip]+1;
- char *value = get_value(param_end, argv, ip);
- if (strcmp(value, "true") == 0) {
- *bool = 1;
- return 1;
- }
- else if (strcmp(value, "false") == 0) {
- *bool = 0;
- return 1;
- }
- else {
- Sint tmp;
- char *rest;
- errno = 0;
- tmp = (Sint) strtol(value, &rest, 10);
- if (errno != 0 || rest == value || tmp <= 0) {
- bad_value(param, param_end, value);
- return -1;
- }
- *amount = (Uint) tmp;
- return 0;
- }
- }
- static void
- handle_au_arg(struct au_init *auip,
- char* sub_param,
- char** argv,
- int* ip)
- {
- char *param = argv[*ip]+1;
- switch (sub_param[0]) {
- case 'a':
- if(has_prefix("asbcst", sub_param)) {
- auip->init.util.asbcst = get_kb_value(sub_param + 6, argv, ip);
- }
- else if(has_prefix("as", sub_param)) {
- char *alg = get_value(sub_param + 2, argv, ip);
- if (strcmp("bf", alg) == 0) {
- auip->atype = BESTFIT;
- auip->init.bf.ao = 0;
- }
- else if (strcmp("aobf", alg) == 0) {
- auip->atype = BESTFIT;
- auip->init.bf.ao = 1;
- }
- else if (strcmp("gf", alg) == 0) {
- auip->atype = GOODFIT;
- }
- else if (strcmp("af", alg) == 0) {
- auip->atype = AFIT;
- }
- else {
- bad_value(param, sub_param + 1, alg);
- }
- }
- else
- goto bad_switch;
- break;
- case 'e':
- auip->enable = get_bool_value(sub_param+1, argv, ip);
- break;
- case 'l':
- if (has_prefix("lmbcs", sub_param)) {
- auip->default_.lmbcs = 0;
- auip->init.util.lmbcs = get_kb_value(sub_param + 5, argv, ip);
- }
- else
- goto bad_switch;
- break;
- case 'm':
- if (has_prefix("mbcgs", sub_param)) {
- auip->init.util.mbcgs = get_amount_value(sub_param + 5, argv, ip);
- }
- else if (has_prefix("mbsd", sub_param)) {
- auip->init.gf.mbsd = get_amount_value(sub_param + 4, argv, ip);
- if (auip->init.gf.mbsd < 1)
- auip->init.gf.mbsd = 1;
- }
- else if (has_prefix("mmbcs", sub_param)) {
- auip->default_.mmbcs = 0;
- auip->init.util.mmbcs = get_kb_value(sub_param + 5, argv, ip);
- }
- else if (has_prefix("mmmbc", sub_param)) {
- auip->default_.mmmbc = 0;
- auip->init.util.mmmbc = get_amount_value(sub_param + 5, argv, ip);
- }
- else if (has_prefix("mmsbc", sub_param)) {
- auip->init.util.mmsbc = get_amount_value(sub_param + 5, argv, ip);
- }
- else
- goto bad_switch;
- break;
- case 'r':
- if(has_prefix("rsbcmt", sub_param)) {
- auip->init.util.rsbcmt = get_amount_value(sub_param + 6, argv, ip);
- if (auip->init.util.rsbcmt > 100)
- auip->init.util.rsbcmt = 100;
- }
- else if(has_prefix("rsbcst", sub_param)) {
- auip->init.util.rsbcst = get_amount_value(sub_param + 6, argv, ip);
- if (auip->init.util.rsbcst > 100)
- auip->init.util.rsbcst = 100;
- }
- else if (has_prefix("rmbcmt", sub_param)) {
- auip->init.util.rmbcmt = get_amount_value(sub_param + 6, argv, ip);
- if (auip->init.util.rmbcmt > 100)
- auip->init.util.rmbcmt = 100;
- }
- else if (has_prefix("ramv", sub_param)) {
- auip->init.util.ramv = get_bool_value(sub_param + 4, argv, ip);
- }
- else
- goto bad_switch;
- break;
- case 's':
- if(has_prefix("sbct", sub_param)) {
- auip->init.util.sbct = get_kb_value(sub_param + 4, argv, ip);
- }
- else if (has_prefix("smbcs", sub_param)) {
- auip->default_.smbcs = 0;
- auip->init.util.smbcs = get_kb_value(sub_param + 5, argv, ip);
- }
- else
- goto bad_switch;
- break;
- case 't': {
- Uint no;
- int enable;
- int res = get_bool_or_possitive_amount_value(&enable,
- &no,
- sub_param+1,
- argv,
- ip);
- if (res > 0)
- auip->thr_spec = enable ? 1 : 0;
- else if (res == 0) {
- int allocs = (int) no;
- if (allocs < 0)
- allocs = INT_MIN;
- else {
- allocs *= -1;
- }
- auip->thr_spec = allocs;
- }
- break;
- }
- default:
- bad_switch:
- bad_param(param, sub_param);
- }
- }
- static void
- handle_args(int *argc, char **argv, erts_alc_hndl_args_init_t *init)
- {
- struct au_init *aui[] = {
- &init->binary_alloc,
- &init->std_alloc,
- &init->ets_alloc,
- &init->eheap_alloc,
- &init->ll_alloc,
- &init->driver_alloc,
- &init->sl_alloc,
- &init->temp_alloc
- };
- int aui_sz = (int) sizeof(aui)/sizeof(aui[0]);
- char *arg;
- char *rest;
- int i, j;
- i = 1;
- ASSERT(argc && argv && init);
- while (i < *argc) {
- if(argv[i][0] == '-') {
- char *param = argv[i]+1;
- switch (argv[i][1]) {
- case 'M':
- switch (argv[i][2]) {
- case 'B':
- handle_au_arg(&init->binary_alloc, &argv[i][3], argv, &i);
- break;
- case 'D':
- handle_au_arg(&init->std_alloc, &argv[i][3], argv, &i);
- break;
- case 'E':
- handle_au_arg(&init->ets_alloc, &argv[i][3], argv, &i);
- break;
- case 'F': /* fix_alloc */
- if (has_prefix("e", param+2)) {
- arg = get_value(param+3, argv, &i);
- if (strcmp("true", arg) != 0)
- bad_value(param, param+3, arg);
- }
- else
- bad_param(param, param+2);
- break;
- case 'H':
- handle_au_arg(&init->eheap_alloc, &argv[i][3], argv, &i);
- break;
- case 'L':
- handle_au_arg(&init->ll_alloc, &argv[i][3], argv, &i);
- break;
- case 'M':
- if (has_prefix("amcbf", argv[i]+3)) {
- #if HAVE_ERTS_MSEG
- init->mseg.amcbf =
- #endif
- get_kb_value(argv[i]+8, argv, &i);
- }
- else if (has_prefix("rmcbf", argv[i]+3)) {
- #if HAVE_ERTS_MSEG
- init->mseg.rmcbf =
- #endif
- get_amount_value(argv[i]+8, argv, &i);
- }
- else if (has_prefix("mcs", argv[i]+3)) {
- #if HAVE_ERTS_MSEG
- init->mseg.mcs =
- #endif
- get_amount_value(argv[i]+6, argv, &i);
- }
- else if (has_prefix("cci", argv[i]+3)) {
- #if HAVE_ERTS_MSEG
- init->mseg.cci =
- #endif
- get_amount_value(argv[i]+6, argv, &i);
- }
- else {
- bad_param(param, param+2);
- }
- break;
- case 'R':
- handle_au_arg(&init->driver_alloc, &argv[i][3], argv, &i);
- break;
- case 'S':
- handle_au_arg(&init->sl_alloc, &argv[i][3], argv, &i);
- break;
- case 'T':
- handle_au_arg(&init->temp_alloc, &argv[i][3], argv, &i);
- break;
- case 'Y': { /* sys_alloc */
- if (has_prefix("tt", param+2)) {
- /* set trim threshold */
- arg = get_value(param+4, argv, &i);
- errno = 0;
- init->trim_threshold = (int) strtol(arg, &rest, 10);
- if (errno != 0
- || rest == arg
- || init->trim_threshold < 0
- || (INT_MAX/1024) < init->trim_threshold) {
- bad_value(param, param+4, arg);
- }
- VERBOSE(DEBUG_SYSTEM,
- ("using trim threshold: %d\n",
- init->trim_threshold));
- init->trim_threshold *= 1024;
- }
- else if (has_prefix("tp", param+2)) {
- /* set top pad */
- arg = get_value(param+4, argv, &i);
- errno = 0;
- init->top_pad = (int) strtol(arg, &rest, 10);
- if (errno != 0
- || rest == arg
- || init->top_pad < 0
- || (INT_MAX/1024) < init->top_pad) {
- bad_value(param, param+4, arg);
- }
- VERBOSE(DEBUG_SYSTEM,
- ("using top pad: %d\n",init->top_pad));
- init->top_pad *= 1024;
- }
- else if (has_prefix("m", param+2)) {
- /* Has been handled by erlexec */
- (void) get_value(param+3, argv, &i);
- }
- else if (has_prefix("e", param+2)) {
- arg = get_value(param+3, argv, &i);
- if (strcmp("true", arg) != 0)
- bad_value(param, param+3, arg);
- }
- else
- bad_param(param, param+2);
- break;
- }
- case 'e':
- switch (argv[i][3]) {
- case 'a': {
- int a;
- arg = get_value(argv[i]+4, argv, &i);
- if (strcmp("min", arg) == 0) {
- for (a = 0; a < aui_sz; a++)
- aui[a]->enable = 0;
- }
- else if (strcmp("max", arg) == 0) {
- for (a = 0; a < aui_sz; a++)
- aui[a]->enable = 1;
- }
- else if (strcmp("config", arg) == 0) {
- init->erts_alloc_config = 1;
- }
- else if (strcmp("r9c", arg) == 0
- || strcmp("r10b", arg) == 0
- || strcmp("r11b", arg) == 0) {
- set_default_sl_alloc_opts(&init->sl_alloc);
- set_default_std_alloc_opts(&init->std_alloc);
- set_default_ll_alloc_opts(&init->ll_alloc);
- set_default_temp_alloc_opts(&init->temp_alloc);
- set_default_eheap_alloc_opts(&init->eheap_alloc);
- set_default_binary_alloc_opts(&init->binary_alloc);
- set_default_ets_alloc_opts(&init->ets_alloc);
- set_default_driver_alloc_opts(&init->driver_alloc);
- init->driver_alloc.enable = 0;
- if (strcmp("r9c", arg) == 0) {
- init->sl_alloc.enable = 0;
- init->std_alloc.enable = 0;
- init->binary_alloc.enable = 0;
- init->ets_alloc.enable = 0;
- }
- for (a = 0; a < aui_sz; a++) {
- aui[a]->thr_spec = 0;
- aui[a]->init.util.ramv = 0;
- aui[a]->init.util.mmmbc = 10;
- aui[a]->init.util.lmbcs = 5*1024*1024;
- }
- }
- else {
- bad_param(param, param+3);
- }
- break;
- }
- default:
- bad_param(param, param+1);
- }
- break;
- case 'i':
- switch (argv[i][3]) {
- case 's':
- arg = get_value(argv[i]+4, argv, &i);
- if (strcmp("true", arg) == 0)
- init->instr.stat = 1;
- else if (strcmp("false", arg) == 0)
- init->instr.stat = 0;
- else
- bad_value(param, param+3, arg);
- break;
- case 'm':
- arg = get_value(argv[i]+4, argv, &i);
- if (strcmp("true", arg) == 0)
- init->instr.map = 1;
- else if (strcmp("false", arg) == 0)
- init->instr.map = 0;
- else
- bad_value(param, param+3, arg);
- break;
- case 't':
- init->instr.mtrace = get_value(argv[i]+4, argv, &i);
- break;
- default:
- bad_param(param, param+2);
- }
- break;
- case 'u':
- if (has_prefix("ycs", argv[i]+3)) {
- init->alloc_util.ycs
- = get_kb_value(argv[i]+6, argv, &i);
- }
- else if (has_prefix("mmc", argv[i]+3)) {
- init->alloc_util.mmc
- = get_amount_value(argv[i]+6, argv, &i);
- }
- else {
- int a;
- int start = i;
- char *param = argv[i];
- char *val = i+1 < *argc ? argv[i+1] : NULL;
- for (a = 0; a < aui_sz; a++) {
- if (a > 0) {
- ASSERT(i == start || i == start+1);
- argv[start] = param;
- if (i != start)
- argv[start + 1] = val;
- i = start;
- }
- handle_au_arg(aui[a], &argv[i][3], argv, &i);
- }
- }
- break;
- default:
- bad_param(param, param+1);
- }
- break;
- case '-':
- if (argv[i][2] == '\0') {
- /* End of system flags reached */
- if (init->instr.mtrace
- /* || init->instr.stat
- || init->instr.map */) {
- while (i < *argc) {
- if(strcmp(argv[i], "-sname") == 0
- || strcmp(argv[i], "-name") == 0) {
- if (i + 1 <*argc) {
- init->instr.nodename = argv[i+1];
- break;
- }
- }
- i++;
- }
- }
- goto args_parsed;
- }
- break;
- default:
- break;
- }
- }
- i++;
- }
- args_parsed:
- /* Handled arguments have been marked with NULL. Slide arguments
- not handled towards the beginning of argv. */
- for (i = 0, j = 0; i < *argc; i++) {
- if (argv[i])
- argv[j++] = argv[i];
- }
- *argc = j;
- }
- static char *type_no_str(ErtsAlcType_t n)
- {
- #if ERTS_ALC_N_MIN != 0
- if (n < ERTS_ALC_N_MIN)
- return NULL;
- #endif
- if (n > ERTS_ALC_N_MAX)
- return NULL;
- return (char *) ERTS_ALC_N2TD(n);
- }
- #define type_str(T) type_no_str(ERTS_ALC_T2N((T)))
- erts_tsd_key_t thr_ix_key;
- erts_spinlock_t alloc_thr_ix_lock;
- int last_thr_ix;
- int first_dyn_thr_ix;
- static void
- init_thr_ix(int static_ixs)
- {
- erts_tsd_key_create(&thr_ix_key);
- erts_spinlock_init(&alloc_thr_ix_lock, "alloc_thr_ix_lock");
- last_thr_ix = -4711;
- first_dyn_thr_ix = static_ixs+1;
- }
- int
- erts_alc_get_thr_ix(void)
- {
- int ix = (int)(long) erts_tsd_get(thr_ix_key);
- if (ix == 0) {
- erts_spin_lock(&alloc_thr_ix_lock);
- last_thr_ix++;
- if (last_thr_ix < 0)
- last_thr_ix = first_dyn_thr_ix;
- ix = last_thr_ix;
- erts_spin_unlock(&alloc_thr_ix_lock);
- erts_tsd_set(thr_ix_key, (void *)(long) ix);
- }
- ASSERT(ix > 0);
- return ix;
- }
- void erts_alloc_reg_scheduler_id(Uint id)
- {
- int ix = (int) id;
- ASSERT(0 < ix && ix <= first_dyn_thr_ix);
- ASSERT(0 == (int) (long) erts_tsd_get(thr_ix_key));
- erts_tsd_set(thr_ix_key, (void *)(long) ix);
- }
- static void
- no_verify(Allctr_t *allctr)
- {
- }
- erts_alloc_verify_func_t
- erts_alloc_get_verify_unused_temp_alloc(Allctr_t **allctr)
- {
- if (erts_allctrs_info[ERTS_ALC_A_TEMPORARY].alloc_util
- && erts_allctrs_info[ERTS_ALC_A_TEMPORARY].thr_spec) {
- ErtsAllocatorThrSpec_t *tspec;
- tspec = &erts_allctr_thr_spec[ERTS_ALC_A_TEMPORARY];
- if (!tspec->all_thr_safe) {
- int ix = erts_alc_get_thr_ix();
- if (ix < tspec->size) {
- *allctr = tspec->allctr[ix];
- return erts_alcu_verify_unused;
- }
- }
- }
- *allctr = NULL;
- return no_verify;
- }
- __decl_noreturn void
- erts_alc_fatal_error(int error, int func, ErtsAlcType_t n, ...)
- {
- char buf[10];
- char *t_str;
- char *allctr_str;
- ASSERT(n >= ERTS_ALC_N_MIN);
- ASSERT(n <= ERTS_ALC_N_MAX);
- if (n < ERTS_ALC_N_MIN || ERTS_ALC_N_MAX < n)
- allctr_str = "UNKNOWN";
- else {
- ErtsAlcType_t a = ERTS_ALC_T2A(ERTS_ALC_N2T(n));
- if (erts_allctrs_info[a].enabled)
- allctr_str = (char *) ERTS_ALC_A2AD(a);
- else
- allctr_str = (char *) ERTS_ALC_A2AD(ERTS_ALC_A_SYSTEM);
- }
- t_str = type_no_str(n);
- if (!t_str) {
- sprintf(buf, "%d", (int) n);
- t_str = buf;
- }
- switch (error) {
- case ERTS_ALC_E_NOTSUP: {
- char *op_str;
- switch (func) {
- case ERTS_ALC_O_ALLOC: op_str = "alloc"; break;
- case ERTS_ALC_O_REALLOC: op_str = "realloc"; break;
- case ERTS_ALC_O_FREE: op_str = "free"; break;
- default: op_str = "UNKNOWN"; break;
- }
- erl_exit(ERTS_ABORT_EXIT,
- "%s: %s operation not supported (memory type: \"%s\")\n",
- allctr_str, op_str, t_str);
- break;
- }
- case ERTS_ALC_E_NOMEM: {
- Uint size;
- va_list argp;
- char *op = func == ERTS_ALC_O_REALLOC ? "reallocate" : "allocate";
-
- va_start(argp, n);
- size = va_arg(argp, Uint);
- va_end(argp);
- erl_exit(1,
- "%s: Cannot %s %lu bytes of memory (of type \"%s\").\n",
- allctr_str, op, size, t_str);
- break;
- }
- case ERTS_ALC_E_NOALLCTR:
- erl_exit(ERTS_ABORT_EXIT,
- "erts_alloc: Unknown allocator type: %d\n",
- ERTS_ALC_T2A(ERTS_ALC_N2T(n)));
- break;
- default:
- erl_exit(ERTS_ABORT_EXIT, "erts_alloc: Unknown error: %d\n", error);
- break;
- }
- }
- __decl_noreturn void
- erts_alloc_enomem(ErtsAlcType_t type, Uint size)
- {
- erts_alloc_n_enomem(ERTS_ALC_T2N(type), size);
- }
- __decl_noreturn void
- erts_alloc_n_enomem(ErtsAlcType_t n, Uint size)
- {
- erts_alc_fatal_error(ERTS_ALC_E_NOMEM, ERTS_ALC_O_ALLOC, n, size);
- }
- __decl_noreturn void
- erts_realloc_enomem(ErtsAlcType_t type, void *ptr, Uint size)
- {
- erts_realloc_n_enomem(ERTS_ALC_T2N(type), ptr, size);
- }
- __decl_noreturn void
- erts_realloc_n_enomem(ErtsAlcType_t n, void *ptr, Uint size)
- {
- erts_alc_fatal_error(ERTS_ALC_E_NOMEM, ERTS_ALC_O_REALLOC, n, size);
- }
- static ERTS_INLINE UWord
- alcu_size(ErtsAlcType_t ai)
- {
- UWord res = 0;
- ASSERT(erts_allctrs_info[ai].enabled);
- ASSERT(erts_allctrs_info[ai].alloc_util);
- if (!erts_allctrs_info[ai].thr_spec) {
- Allctr_t *allctr = erts_allctrs_info[ai].extra;
- AllctrSize_t asize;
- erts_alcu_current_size(allctr, &asize);
- res += asize.blocks;
- }
- else {
- ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[ai];
- int i;
- ASSERT(tspec->all_thr_safe);
- ASSERT(tspec->enabled);
- for (i = tspec->size - 1; i >= 0; i--) {
- Allctr_t *allctr = tspec->allctr[i];
- AllctrSize_t asize;
- if (allctr) {
- erts_alcu_current_size(allctr, &asize);
- res += asize.blocks;
- }
- }
- }
- return res;
- }
- #if HALFWORD_HEAP
- static ERTS_INLINE int
- alcu_is_low(ErtsAlcType_t ai)
- {
- int is_low = 0;
- ASSERT(erts_allctrs_info[ai].enabled);
- ASSERT(erts_allctrs_info[ai].alloc_util);
- if (!erts_allctrs_info[ai].thr_spec) {
- Allctr_t *allctr = erts_allctrs_info[ai].extra;
- is_low = allctr->mseg_opt.low_mem;
- }
- else {
- ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[ai];
- int i;
- # ifdef DEBUG
- int found_one = 0;
- # endif
- ASSERT(tspec->all_thr_safe);
- ASSERT(tspec->enabled);
- for (i = tspec->size - 1; i >= 0; i--) {
- Allctr_t *allctr = tspec->allctr[i];
- if (allctr) {
- # ifdef DEBUG
- if (!found_one) {
- is_low = allctr->mseg_opt.low_mem;
- found_one = 1;
- }
- else ASSERT(is_low == allctr->mseg_opt.low_mem);
- # else
- is_low = allctr->mseg_opt.low_mem;
- break;
- # endif
- }
- }
- ASSERT(found_one);
- }
- return is_low;
- }
- #endif /* HALFWORD */
- Eterm
- erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg)
- {
- #define ERTS_MEM_NEED_ALL_ALCU (!erts_instr_stat && want_tot_or_sys)
- ErtsFixInfo efi;
- struct {
- int total;
- int processes;
- int processes_used;
- int system;
- int atom;
- int atom_used;
- int binary;
- int code;
- int ets;
- int maximum;
- #if HALFWORD_HEAP
- int low;
- #endif
- } want = {0};
- struct {
- UWord total;
- UWord processes;
- UWord processes_used;
- UWord system;
- UWord atom;
- UWord atom_used;
- UWord binary;
- UWord code;
- UWord ets;
- UWord maximum;
- #if HALFWORD_HEAP
- UWord low;
- #endif
- } size = {0};
- Eterm atoms[sizeof(size)/sizeof(UWord)];
- UWord *uintps[sizeof(size)/sizeof(UWord)];
- Eterm euints[sizeof(size)/sizeof(UWord)];
- int want_tot_or_sys;
- int length;
- Eterm res = THE_NON_VALUE;
- ErtsAlcType_t ai;
- int only_one_value = 0;
- /* Figure out whats wanted... */
- length = 0;
- if (is_non_value(earg)) { /* i.e. wants all */
- want.total = 1;
- atoms[length] = am_total;
- uintps[length++] = &size.total;
- want.processes = 1;
- atoms[length] = am_processes;
- uintps[length++] = &size.processes;
- want.processes_used = 1;
- atoms[length] = am_processes_used;
- uintps[length++] = &size.processes_used;
- want.system = 1;
- atoms[length] = am_system;
- uintps[length++] = &size.system;
- want.atom = 1;
- atoms[length] = am_atom;
- uintps[length++] = &size.atom;
- want.atom_used = 1;
- atoms[length] = am_atom_used;
- uintps[length++] = &size.atom_used;
- want.binary = 1;
- atoms[length] = am_binary;
- uintps[length++] = &size.binary;
- want.code = 1;
- atoms[length] = am_code;
- uintps[length++] = &size.code;
- want.ets = 1;
- atoms[length] = am_ets;
- uintps[length++] = &size.ets;
- want.maximum = erts_instr_stat;
- if (want.maximum) {
- atoms[length] = am_maximum;
- uintps[length++] = &size.maximum;
- }
- #if HALFWORD_HEAP
- want.low = 1;
- atoms[length] = am_low;
- uintps[length++] = &size.low;
- #endif
- }
- else {
- DeclareTmpHeapNoproc(tmp_heap,2);
- Eterm wanted_list;
- if (is_nil(earg))
- return NIL;
- UseTmpHeapNoproc(2);
- if (is_not_atom(earg))
- wanted_list = earg;
- else {
- wanted_list = CONS(&tmp_heap[0], earg, NIL);
- only_one_value = 1;
- }
-
- while (is_list(wanted_list)) {
- switch (CAR(list_val(wanted_list))) {
- case am_total:
- if (!want.total) {
- want.total = 1;
- atoms[length] = am_total;
- uintps[length++] = &size.total;
- }
- break;
- case am_processes:
- if (!want.processes) {
- want.processes = 1;
- atoms[length] = am_processes;
- uintps[length++] = &size.processes;
- }
- break;
- case am_processes_used:
- if (!want.processes_used) {
- want.processes_used = 1;
- atoms[length] = am_processes_used;
- uintps[length++] = &size.processes_used;
- }
- break;
- case am_system:
- if (!want.system) {
- want.system = 1;
- atoms[length] = am_system;
- uintps[length++] = &size.system;
- }
- break;
- case am_atom:
- if (!want.atom) {
- want.atom = 1;
- atoms[length] = am_atom;
- uintps[length++] = &size.atom;
- }
- break;
- case am_atom_used:
- if (!want.atom_used) {
- want.atom_used = 1;
- atoms[length] = am_atom_used;
- uintps[length++] = &size.atom_used;
- }
- break;
- case am_binary:
- if (!want.binary) {
- want.binary = 1;
- atoms[length] = am_binary;
- uintps[length++] = &size.binary;
- }
- break;
- case am_code:
- if (!want.code) {
- want.code = 1;
- atoms[length] = am_code;
- uintps[length++] = &size.code;
- }
- break;
- case am_ets:
- if (!want.ets) {
- want.ets = 1;
- atoms[length] = am_ets;
- uintps[length++] = &size.ets;
- }
- break;
- case am_maximum:
- if (erts_instr_stat) {
- if (!want.maximum) {
- want.maximum = 1;
- atoms[length] = am_maximum;
- uintps[length++] = &size.maximum;
- }
- } else {
- UnUseTmpHeapNoproc(2);
- return am_badarg;
- }
- break;
- #if HALFWORD_HEAP
- case am_low:
- if (!want.low) {
- want.low = 1;
- atoms[length] = am_low;
- uintps[length++] = &size.low;
- }
- break;
- #endif
- default:
- UnUseTmpHeapNoproc(2);
- return am_badarg;
- }
- wanted_list = CDR(list_val(wanted_list));
- }
- UnUseTmpHeapNoproc(2);
- if (is_not_nil(wanted_list))
- return am_badarg;
- }
- /* All alloc_util allocators *have* to be enabled */
-
- for (ai = ERTS_ALC_A_MIN; ai <= ERTS_ALC_A_MAX; ai++) {
- switch (ai) {
- case ERTS_ALC_A_SYSTEM:
- case ERTS_ALC_A_FIXED_SIZE:
- break;
- default:
- if (!erts_allctrs_info[ai].enabled
- || !erts_allctrs_info[ai].alloc_util) {
- return am_notsup;
- }
- break;
- }
- }
- ASSERT(length <= sizeof(atoms)/sizeof(Eterm));
- ASSERT(length <= sizeof(euints)/sizeof(Eterm));
- ASSERT(length <= sizeof(uintps)/sizeof(UWord));
- if (proc) {
- ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN
- == erts_proc_lc_my_proc_locks(proc));
- /* We'll need locks early in the lock order */
- erts_smp_proc_unlock(proc, ERTS_PROC_LOCK_MAIN);
- }
- /* Calculate values needed... */
- want_tot_or_sys = want.total || want.system;
- if (ERTS_MEM_NEED_ALL_ALCU) {
- size.total = 0;
- for (ai = ERTS_ALC_A_MIN; ai <= ERTS_ALC_A_MAX; ai++) {
- if (erts_allctrs_info[ai].alloc_util) {
- UWord *save;
- UWord asz;
- switch (ai) {
- case ERTS_ALC_A_TEMPORARY:
- /*
- * Often not thread safe and usually never
- * contain any allocated memory.
- */
- continue;
- case ERTS_ALC_A_EHEAP:
- save = &size.processes;
- break;
- case ERTS_ALC_A_ETS:
- save = &size.ets;
- break;
- case ERTS_ALC_A_BINARY:
- save = &size.binary;
- break;
- default:
- save = NULL;
- break;
- }
- asz = alcu_size(ai);
- if (save)
- *save = asz;
- size.total += asz;
- #if HALFWORD_HEAP
- if (alcu_is_low(ai)) {
- size.low += asz;
- }
- #endif
- }
- }
- }
- if (want_tot_or_sys || want.processes || want.processes_used) {
- UWord tmp;
- if (ERTS_MEM_NEED_ALL_ALCU)
- tmp = size.processes;
- else
- tmp = alcu_size(ERTS_ALC_A_EHEAP);
- tmp += erts_max_processes*sizeof(Process*);
- #ifdef HYBRID
- tmp += erts_max_processes*sizeof(Process*);
- #endif
- tmp += erts_bif_timer_memory_size();
- tmp += erts_tot_link_lh_size();
- size.processes = size.processes_used = tmp;
- #if HALFWORD_HEAP
- /* BUG: We ignore link and monitor memory */
- #else
- erts_fix_info(ERTS_ALC_T_NLINK_SH, &efi);
- size.processes += efi.total;
- size.processes_used += efi.used;
- erts_fix_info(ERTS_ALC_T_MONITOR_SH, &efi);
- size.processes += efi.total;
- size.processes_used += efi.used;
- #endif
- erts_fix_info(ERTS_ALC_T_PROC, &efi);
- size.processes += efi.total;
- size.processes_used += efi.used;
- erts_fix_info(ERTS_ALC_T_REG_PROC, &efi);
- size.processes += efi.total;
- size.processes_used += efi.used;
- }
- if (want.atom || want.atom_used) {
- Uint reserved_atom_space, atom_space;
- erts_atom_get_text_space_sizes(&reserved_atom_space, &atom_space);
- size.atom = size.atom_used = atom_table_sz();
- erts_fix_info(ERTS_ALC_T_ATOM, &efi);
- if (want.atom) {
- size.atom += reserved_atom_space;
- size.atom += efi.total;
- }
- if (want.atom_used) {
- size.atom_used += atom_space;
- size.atom_used += efi.used;
- }
- }
- if (!ERTS_MEM_NEED_ALL_ALCU && want.binary)
- size.binary = alcu_size(ERTS_ALC_A_BINARY);
- if (want.co…
Large files files are truncated, but you can click here to view the full file