summaryrefslogtreecommitdiff
path: root/erts/emulator/beam/erl_alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/erl_alloc.c')
-rw-r--r--erts/emulator/beam/erl_alloc.c196
1 files changed, 138 insertions, 58 deletions
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index 2cea68a817..125a5a240e 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -148,6 +148,9 @@ ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(aireq,
ERTS_ALC_T_AINFO_REQ)
ErtsAlcType_t erts_fix_core_allocator_ix;
+erts_tsd_key_t erts_thr_alloc_data_key;
+
+Uint ERTS_WRITE_UNLIKELY(erts_no_dirty_alloc_instances);
struct au_init {
int enable;
@@ -186,6 +189,7 @@ typedef struct {
#endif
int trim_threshold;
int top_pad;
+ int dirty_alloc_insts;
AlcUInit_t alloc_util;
struct {
char *mtrace;
@@ -461,7 +465,7 @@ set_default_test_alloc_opts(struct au_init *ip)
{
SET_DEFAULT_ALLOC_OPTS(ip);
ip->enable = 0; /* Disabled by default */
- ip->thr_spec = -1 * erts_no_schedulers;
+ ip->thr_spec = -1;
ip->astrat = ERTS_ALC_S_FIRSTFIT;
ip->init.aoff.crr_order = FF_AOFF;
ip->init.aoff.blk_order = FF_BF;
@@ -488,10 +492,10 @@ set_default_test_alloc_opts(struct au_init *ip)
static void
-adjust_tpref(struct au_init *ip, int no_sched)
+adjust_tpref(struct au_init *ip, int no_sched, int no_dirty_inst)
{
if (ip->thr_spec) {
- ip->thr_spec = no_sched;
+ ip->thr_spec = no_sched + no_dirty_inst;
ip->thr_spec *= -1; /* thread preferred */
/* If default ... */
@@ -607,6 +611,7 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
#endif
ERTS_DEFAULT_TRIM_THRESHOLD,
ERTS_DEFAULT_TOP_PAD,
+ 0, /* Default dirty alloc instances */
ERTS_DEFAULT_ALCU_INIT,
};
size_t fix_type_sizes[ERTS_ALC_NO_FIXED_SIZES] = {0};
@@ -644,6 +649,8 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
hdbg_init();
#endif
+ erts_tsd_key_create(&erts_thr_alloc_data_key, "erts_alc_data_key");
+
lock_all_physical_memory = 0;
ncpu = eaiop->ncpu;
@@ -686,6 +693,7 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
#endif
}
+ erts_no_dirty_alloc_instances = init.dirty_alloc_insts;
/* Make adjustments for carrier migration support */
init.temp_alloc.init.util.acul = 0;
@@ -729,18 +737,19 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
/* Only temp_alloc can use thread specific interface */
if (init.temp_alloc.thr_spec)
- init.temp_alloc.thr_spec = erts_no_schedulers;
+ init.temp_alloc.thr_spec = erts_no_schedulers + init.dirty_alloc_insts;
/* 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);
- adjust_tpref(&init.fix_alloc, erts_no_schedulers);
- adjust_tpref(&init.literal_alloc, erts_no_schedulers);
+ adjust_tpref(&init.sl_alloc, erts_no_schedulers, init.dirty_alloc_insts);
+ adjust_tpref(&init.std_alloc, erts_no_schedulers, init.dirty_alloc_insts);
+ adjust_tpref(&init.ll_alloc, erts_no_schedulers, init.dirty_alloc_insts);
+ adjust_tpref(&init.eheap_alloc, erts_no_schedulers, init.dirty_alloc_insts);
+ adjust_tpref(&init.binary_alloc, erts_no_schedulers, init.dirty_alloc_insts);
+ adjust_tpref(&init.ets_alloc, erts_no_schedulers, init.dirty_alloc_insts);
+ adjust_tpref(&init.driver_alloc, erts_no_schedulers, init.dirty_alloc_insts);
+ adjust_tpref(&init.fix_alloc, erts_no_schedulers, init.dirty_alloc_insts);
+ adjust_tpref(&init.literal_alloc, erts_no_schedulers, init.dirty_alloc_insts);
+ adjust_tpref(&init.test_alloc, erts_no_schedulers, init.dirty_alloc_insts);
/*
@@ -756,6 +765,7 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
refuse_af_strategy(&init.driver_alloc);
refuse_af_strategy(&init.fix_alloc);
refuse_af_strategy(&init.literal_alloc);
+ refuse_af_strategy(&init.test_alloc);
if (!init.temp_alloc.thr_spec)
refuse_af_strategy(&init.temp_alloc);
@@ -763,6 +773,7 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
erts_mtrace_pre_init();
#if HAVE_ERTS_MSEG
init.mseg.nos = erts_no_schedulers;
+ init.mseg.ndai = init.dirty_alloc_insts;
erts_mseg_init(&init.mseg);
#endif
@@ -1038,12 +1049,12 @@ start_au_allocator(ErtsAlcType_t alctr_n,
if (!as0)
continue;
if (init->thr_spec < 0) {
- init->init.util.ts = i == 0;
+ init->init.util.ts = (i == 0 || erts_no_schedulers < i);
init->init.util.tspec = 0;
init->init.util.tpref = -1*init->thr_spec + 1;
}
else {
- if (i != 0)
+ if (0 < i && i <= erts_no_schedulers)
init->init.util.ts = 0;
else {
if (astrat == ERTS_ALC_S_AFIT)
@@ -1749,6 +1760,24 @@ handle_args(int *argc, char **argv, erts_alc_hndl_args_init_t *init)
}
bad_param(param, param+2);
break;
+ case 'd':
+ if (has_prefix("ai", param+2)) {
+ arg = get_value(argv[i]+5, argv, &i);
+ if (sys_strcmp("max", arg) == 0)
+ init->dirty_alloc_insts = (int) erts_no_dirty_cpu_schedulers;
+ else {
+ Sint tmp;
+ char *rest;
+ errno = 0;
+ tmp = (Sint) ErtsStrToSint(arg, &rest, 10);
+ if (errno != 0 || rest == arg || tmp < 0)
+ bad_value(param, param+4, arg);
+ init->dirty_alloc_insts = (int) tmp;
+ }
+ break;
+ }
+ bad_param(param, param+2);
+ break;
case 'u':
if (has_prefix("ycs", argv[i]+3)) {
init->alloc_util.ycs
@@ -1817,6 +1846,10 @@ handle_args(int *argc, char **argv, erts_alc_hndl_args_init_t *init)
argv[j++] = argv[i];
}
*argc = j;
+
+ if (init->dirty_alloc_insts > erts_no_dirty_cpu_schedulers)
+ init->dirty_alloc_insts = (int) erts_no_dirty_cpu_schedulers;
+
}
static char *type_no_str(ErtsAlcType_t n)
@@ -1837,46 +1870,92 @@ void
erts_alloc_register_scheduler(void *vesdp)
{
ErtsSchedulerData *esdp = (ErtsSchedulerData *) vesdp;
- int ix = (int) esdp->no;
+ int ix;
int aix;
+ int normal_sched;
- ASSERT(!ERTS_SCHEDULER_IS_DIRTY(esdp));
+ ASSERT(esdp == erts_get_scheduler_data());
+
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) {
+ ix = (int) esdp->no;
+ ASSERT(0 < ix && ix <= erts_no_schedulers);
+ normal_sched = !0;
+ }
+ else if (!erts_no_dirty_alloc_instances) {
+ ix = 0;
+ normal_sched = 0;
+ }
+ else {
+ ix = (int) esdp->dirty_no;
+ ASSERT(ix > 0);
+ ix = ((ix - 1) % erts_no_dirty_alloc_instances) + 1;
+ ix += erts_no_schedulers;
+ ASSERT(erts_no_schedulers < ix
+ && ix <= (erts_no_schedulers
+ + erts_no_dirty_alloc_instances));
+ normal_sched = 0;
+ }
+
+ esdp->aux_work_data.alloc_data.delayed_dealloc_handler = normal_sched;
+ esdp->aux_work_data.alloc_data.alc_ix = ix;
for (aix = ERTS_ALC_A_MIN; aix <= ERTS_ALC_A_MAX; aix++) {
ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[aix];
- esdp->alloc_data.deallctr[aix] = NULL;
- esdp->alloc_data.pref_ix[aix] = -1;
- if (tspec->enabled) {
- if (!tspec->dd)
- esdp->alloc_data.pref_ix[aix] = ix;
- else {
- Allctr_t *allctr = tspec->allctr[ix];
- ASSERT(allctr);
- esdp->alloc_data.deallctr[aix] = allctr;
- esdp->alloc_data.pref_ix[aix] = ix;
- }
- }
+ esdp->aux_work_data.alloc_data.deallctr[aix] = NULL;
+ if (!normal_sched)
+ continue;
+ /*
+ * Delayed dealloc is handled by normal schedulers,
+ * but not by dirty schedulers...
+ */
+ if (tspec->enabled && tspec->dd) {
+ Allctr_t *allctr = tspec->allctr[ix];
+ ASSERT(allctr);
+ esdp->aux_work_data.alloc_data.deallctr[aix] = allctr;
+ }
}
+ erts_tsd_set(erts_thr_alloc_data_key, (void *) &esdp->aux_work_data.alloc_data);
}
void
-erts_alloc_scheduler_handle_delayed_dealloc(void *vesdp,
- int *need_thr_progress,
- ErtsThrPrgrVal *thr_prgr_p,
- int *more_work)
+erts_alloc_register_delayed_dealloc_handler_thread(ErtsThrAllocData *tadp, int ix)
{
- ErtsSchedulerData *esdp = (ErtsSchedulerData *) vesdp;
int aix;
+
+ /*
+ * Should not be a scheduler of any kind and should not
+ * handle an 'ix' reserved for normal schedulers...
+ */
+ ASSERT(!erts_get_scheduler_data());
+ ASSERT(0 == ix /* Aux thread... */
+ || /* Handler thread for dirty scheds instances... */
+ (erts_no_schedulers < ix
+ && ix <= (erts_no_schedulers
+ + erts_no_dirty_alloc_instances)));
+
+ tadp->delayed_dealloc_handler = !0;
+ tadp->alc_ix = ix;
for (aix = ERTS_ALC_A_MIN; aix <= ERTS_ALC_A_MAX; aix++) {
- Allctr_t *allctr;
- if (esdp)
- allctr = esdp->alloc_data.deallctr[aix];
- else {
- ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[aix];
- if (tspec->enabled && tspec->dd)
- allctr = tspec->allctr[0];
- else
- allctr = NULL;
- }
+ ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[aix];
+ tadp->deallctr[aix] = NULL;
+ if (tspec->enabled && tspec->dd) {
+ Allctr_t *allctr = tspec->allctr[ix];
+ ASSERT(allctr);
+ tadp->deallctr[aix] = allctr;
+ }
+ }
+ erts_tsd_set(erts_thr_alloc_data_key, (void *) tadp);
+}
+
+void
+erts_alloc_handle_delayed_dealloc(ErtsThrAllocData *thr_alloc_data,
+ int *need_thr_progress,
+ ErtsThrPrgrVal *thr_prgr_p,
+ int *more_work)
+{
+ int aix;
+ ASSERT(thr_alloc_data);
+ for (aix = ERTS_ALC_A_MIN; aix <= ERTS_ALC_A_MAX; aix++) {
+ Allctr_t *allctr = thr_alloc_data->deallctr[aix];
if (allctr) {
erts_alcu_check_delayed_dealloc(allctr,
1,
@@ -1912,7 +1991,7 @@ 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;
- int ix = ERTS_ALC_GET_THR_IX();
+ int ix = erts_get_thr_alloc_ix();
tspec = &erts_allctr_thr_spec[ERTS_ALC_A_TEMPORARY];
if (ix < tspec->size) {
@@ -3001,8 +3080,8 @@ static void
reply_alloc_info(void *vair)
{
ErtsAllocInfoReq *air = (ErtsAllocInfoReq *) vair;
- Uint sched_id = erts_get_scheduler_id();
- int global_instances = air->req_sched == sched_id;
+ int tix = erts_get_thr_alloc_ix();
+ int global_instances = air->req_sched == tix;
ErtsProcLocks rp_locks;
Process *rp = air->proc;
Eterm ref_copy = NIL, ai_list, msg = NIL;
@@ -3028,7 +3107,7 @@ reply_alloc_info(void *vair)
? erts_alcu_sz_info
: erts_alcu_info);
- rp_locks = air->req_sched == sched_id ? ERTS_PROC_LOCK_MAIN : 0;
+ rp_locks = air->req_sched == tix ? ERTS_PROC_LOCK_MAIN : 0;
sz = 0;
hpp = NULL;
@@ -3196,11 +3275,11 @@ reply_alloc_info(void *vair)
case ERTS_ALC_INFO_A_MSEG_ALLOC:
#if HAVE_ERTS_MSEG
alloc_atom = erts_bld_atom(hpp, szp, "mseg_alloc");
- ainfo = erts_mseg_info(sched_id, NULL, NULL,
+ ainfo = erts_mseg_info(tix, NULL, NULL,
hpp != NULL, air->only_sz, hpp, szp);
ainfo = erts_bld_tuple(hpp, szp, 3,
alloc_atom,
- make_small(sched_id),
+ make_small(tix),
ainfo);
ai_list = erts_bld_cons(hpp, szp, ainfo, ai_list);
#endif
@@ -3209,7 +3288,7 @@ reply_alloc_info(void *vair)
if (erts_allctrs_info[ai].thr_spec) {
alloc_atom = erts_bld_atom(hpp, szp,
(char *) ERTS_ALC_A2AD(ai));
- allctr = erts_allctr_thr_spec[ai].allctr[sched_id];
+ allctr = erts_allctr_thr_spec[ai].allctr[tix];
ainfo = info_func(allctr, air->internal, hpp != NULL, NULL,
NULL, hpp, szp);
ai_list = erts_bld_cons(hpp, szp,
@@ -3217,7 +3296,7 @@ reply_alloc_info(void *vair)
hpp, szp,
3,
alloc_atom,
- make_small(sched_id),
+ make_small(tix),
ainfo),
ai_list);
}
@@ -3226,7 +3305,7 @@ reply_alloc_info(void *vair)
msg = erts_bld_tuple(hpp, szp,
3,
ref_copy,
- make_small(sched_id),
+ make_small(tix),
ai_list);
}
@@ -3245,7 +3324,7 @@ reply_alloc_info(void *vair)
erts_queue_message(rp, rp_locks, mp, msg, am_system);
- if (air->req_sched == sched_id)
+ if (air->req_sched == tix)
rp_locks &= ~ERTS_PROC_LOCK_MAIN;
erts_proc_unlock(rp, rp_locks);
@@ -3325,13 +3404,14 @@ erts_request_alloc_info(struct process *c_p,
air->allocs[airix] = ERTS_ALC_A_INVALID;
erts_atomic32_init_nob(&air->refc,
- (erts_aint32_t) erts_no_schedulers);
+ (erts_aint32_t) erts_no_aux_work_threads-1);
- erts_proc_add_refc(c_p, (Sint) erts_no_schedulers);
+ erts_proc_add_refc(c_p, (Sint) erts_no_aux_work_threads-1);
- if (erts_no_schedulers > 1)
+ if (erts_no_aux_work_threads > 2)
erts_schedule_multi_misc_aux_work(1,
- erts_no_schedulers,
+ 1,
+ erts_no_aux_work_threads-1,
reply_alloc_info,
(void *) air);