From b9240f72148c536b038c0d26b1ef83da7c951429 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 2 Mar 2017 19:58:04 +0100 Subject: erts: Improve reduction count during table cleanup --- erts/emulator/beam/erl_db.c | 76 ++++++++++++++++++++++------------------ erts/emulator/beam/erl_db_hash.c | 30 ++++++++-------- erts/emulator/beam/erl_db_hash.h | 2 +- erts/emulator/beam/erl_db_tree.c | 28 +++++++-------- erts/emulator/beam/erl_db_util.h | 2 +- 5 files changed, 73 insertions(+), 65 deletions(-) diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c index 9c597afabf..2f188b5391 100644 --- a/erts/emulator/beam/erl_db.c +++ b/erts/emulator/beam/erl_db.c @@ -356,9 +356,9 @@ static void fix_table_locked(Process* p, DbTable* tb); static void unfix_table_locked(Process* p, DbTable* tb, db_lock_kind_t* kind); static void set_heir(Process* me, DbTable* tb, Eterm heir, UWord heir_data); static void free_heir_data(DbTable*); -static void free_fixations_locked(Process* p, DbTable *tb); +static SWord free_fixations_locked(Process* p, DbTable *tb); -static int free_table_cont(Process *p, DbTable *tb); +static SWord free_table_continue(Process *p, DbTable *tb, SWord reds); static void print_table(fmtfn_t to, void *to_arg, int show, DbTable* tb); static BIF_RETTYPE ets_select_delete_1(BIF_ALIST_1); static BIF_RETTYPE ets_select_count_1(BIF_ALIST_1); @@ -393,8 +393,6 @@ free_dbtable(void *vtb) erts_smp_atomic_read_nob(&tb->common.memory_size)-sizeof(DbTable), tb->common.fixations); } - erts_fprintf(stderr, "ets: free_dbtable(%T) deleted!!!\r\n", - tb->common.id); #endif #ifdef ERTS_SMP erts_smp_rwmtx_destroy(&tb->common.rwlock); @@ -1904,7 +1902,8 @@ BIF_RETTYPE ets_lookup_element_3(BIF_ALIST_3) */ BIF_RETTYPE ets_delete_1(BIF_ALIST_1) { - int trap; + SWord initial_reds = ERTS_BIF_REDS_LEFT(BIF_P); + SWord reds = initial_reds; DbTable* tb; #ifdef HARDDEBUG @@ -1958,11 +1957,10 @@ BIF_RETTYPE ets_delete_1(BIF_ALIST_1) free_heir_data(tb); tb->common.heir = am_none; - free_fixations_locked(BIF_P, tb); + reds -= free_fixations_locked(BIF_P, tb); db_unlock(tb, LCK_WRITE); - trap = free_table_cont(BIF_P, tb); - if (trap) { + if (free_table_continue(BIF_P, tb, reds) < 0) { /* * Package the DbTable* pointer into a bignum so that it can be safely * passed through a trap. We used to pass the DbTable* pointer directly @@ -1972,9 +1970,11 @@ BIF_RETTYPE ets_delete_1(BIF_ALIST_1) Eterm *hp = HAlloc(BIF_P, 2); hp[0] = make_pos_bignum_header(1); hp[1] = (Eterm) tb; + BUMP_ALL_REDS(BIF_P); BIF_TRAP1(&ets_delete_continue_exp, BIF_P, make_big(hp)); } else { + BUMP_REDS(BIF_P, (initial_reds - reds)); BIF_RET(am_true); } } @@ -3471,9 +3471,10 @@ send_ets_transfer_message(Process *c_p, Process *proc, /* Auto-release fixation from exiting process */ -static void proc_cleanup_fixed_table(Process* p, DbFixation* fix) +static SWord proc_cleanup_fixed_table(Process* p, DbFixation* fix) { DbTable* tb = btid2tab(fix->tabs.btid); + SWord work = 0; ASSERT(fix->procs.p == p); (void)p; if (tb) { @@ -3496,7 +3497,7 @@ static void proc_cleanup_fixed_table(Process* p, DbFixation* fix) erts_smp_mtx_unlock(&tb->common.fixlock); #endif if (!IS_FIXED(tb) && IS_HASH_TABLE(tb->common.status)) { - db_unfix_table_hash(&(tb->hash)); + work += db_unfix_table_hash(&(tb->hash)); } ASSERT(sizeof(DbFixation) == ERTS_ALC_DBG_BLK_SZ(fix)); @@ -3516,6 +3517,9 @@ static void proc_cleanup_fixed_table(Process* p, DbFixation* fix) } erts_free(ERTS_ALC_T_DB_FIXATION, fix); ERTS_ETS_MISC_MEM_ADD(-sizeof(DbFixation)); + ++work; + + return work; } @@ -3543,6 +3547,8 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks) CleanupState *state = (CleanupState *) c_p->u.terminate; Eterm pid = c_p->common.id; CleanupState default_state; + SWord initial_reds = ERTS_BIF_REDS_LEFT(c_p); + SWord reds = initial_reds; if (!state) { state = &default_state; @@ -3588,17 +3594,17 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks) remove_named_tab(tb, 0); free_heir_data(tb); - free_fixations_locked(c_p, tb); + reds -= free_fixations_locked(c_p, tb); db_unlock(tb, LCK_WRITE); state->op = FREE_OWNED_TABLE; - /* fall through */ + break; } case FREE_OWNED_TABLE: - if (free_table_cont(c_p, state->tb)) + reds = free_table_continue(c_p, state->tb, reds); + if (reds < 0) goto yield; state->op = GET_OWNED_TABLE; - break; case UNFIX_TABLES: { @@ -3612,20 +3618,21 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks) if (state != &default_state) erts_free(ERTS_ALC_T_DB_PROC_CLEANUP, state); c_p->u.terminate = NULL; + + BUMP_REDS(c_p, (initial_reds - reds)); return 0; } fixed_tabs_delete(c_p, fix); - proc_cleanup_fixed_table(c_p, fix); + reds -= proc_cleanup_fixed_table(c_p, fix); - BUMP_REDS(c_p, 10); break; } default: ERTS_DB_INTERNAL_ERROR("Bad internal state"); } - } while (ERTS_BIF_REDS_LEFT(c_p) > 0); + } while (reds > 0); yield: @@ -3740,6 +3747,7 @@ struct free_fixations_ctx { Process* p; DbTable* tb; + SWord cnt; }; static void free_fixations_op(DbFixation* fix, void* vctx) @@ -3785,6 +3793,7 @@ static void free_fixations_op(DbFixation* fix, void* vctx) ctx->tb, (void *) fix, sizeof(DbFixation)); ERTS_ETS_MISC_MEM_ADD(-sizeof(DbFixation)); } + ctx->cnt++; } #ifdef ERTS_SMP @@ -3802,7 +3811,7 @@ int erts_db_execute_free_fixation(Process* p, DbFixation* fix) } #endif -static void free_fixations_locked(Process* p, DbTable *tb) +static SWord free_fixations_locked(Process* p, DbTable *tb) { struct free_fixations_ctx ctx; @@ -3810,9 +3819,11 @@ static void free_fixations_locked(Process* p, DbTable *tb) ctx.p = p; ctx.tb = tb; + ctx.cnt = 0; fixing_procs_rbt_foreach_destroy(&tb->common.fixing_procs, free_fixations_op, &ctx); tb->common.fixing_procs = NULL; + return ctx.cnt; } static void set_heir(Process* me, DbTable* tb, Eterm heir, UWord heir_data) @@ -3876,42 +3887,40 @@ static void free_heir_data(DbTable* tb) static BIF_RETTYPE ets_delete_trap(BIF_ALIST_1) { - Process *p = BIF_P; + SWord initial_reds = ERTS_BIF_REDS_LEFT(BIF_P); + SWord reds = initial_reds; Eterm cont = BIF_ARG_1; - int trap; Eterm* ptr = big_val(cont); DbTable *tb = *((DbTable **) (UWord) (ptr + 1)); ASSERT(*ptr == make_pos_bignum_header(1)); - trap = free_table_cont(p, tb); - - if (trap) { - BIF_TRAP1(&ets_delete_continue_exp, p, cont); + if (free_table_continue(BIF_P, tb, reds) < 0) { + BUMP_ALL_REDS(BIF_P); + BIF_TRAP1(&ets_delete_continue_exp, BIF_P, cont); } else { + BUMP_REDS(BIF_P, (initial_reds - reds)); BIF_RET(am_true); } } /* - * free_table_cont() returns 0 when done and !0 when more work is needed. + * free_table_continue() returns reductions left + * done if >= 0 + * yield if < 0 */ -static int free_table_cont(Process *p, DbTable *tb) +static SWord free_table_continue(Process *p, DbTable *tb, SWord reds) { - Eterm result; - - result = tb->common.meth->db_free_table_continue(tb); + reds = tb->common.meth->db_free_table_continue(tb, reds); - if (result == 0) { + if (reds < 0) { #ifdef HARDDEBUG erts_fprintf(stderr,"ets: free_table_cont %T (continue begin)\r\n", tb->common.id); #endif /* More work to be done. Let other processes work and call us again. */ - BUMP_ALL_REDS(p); - return !0; } else { #ifdef HARDDEBUG @@ -3921,9 +3930,8 @@ static int free_table_cont(Process *p, DbTable *tb) /* Completely done - we will not get called again. */ delete_owned_table(p, tb); table_dec_refc(tb, 0); - BUMP_REDS(p, 100); - return 0; } + return reds; } struct fixing_procs_info_ctx diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c index 781886a822..18405342da 100644 --- a/erts/emulator/beam/erl_db_hash.c +++ b/erts/emulator/beam/erl_db_hash.c @@ -418,7 +418,7 @@ static void db_print_hash(fmtfn_t to, DbTable *tbl); static int db_free_table_hash(DbTable *tbl); -static int db_free_table_continue_hash(DbTable *tbl); +static SWord db_free_table_continue_hash(DbTable *tbl, SWord reds); static void db_foreach_offheap_hash(DbTable *, @@ -576,9 +576,10 @@ static void restore_fixdel(DbTableHash* tb, FixedDeletion* fixdel) ** Table interface routines ie what's called by the bif's */ -void db_unfix_table_hash(DbTableHash *tb) +SWord db_unfix_table_hash(DbTableHash *tb) { FixedDeletion* fixdel; + SWord work = 0; ERTS_SMP_LC_ASSERT(erts_smp_lc_rwmtx_is_rwlocked(&tb->common.rwlock) || (erts_smp_lc_rwmtx_is_rlocked(&tb->common.rwlock) @@ -599,7 +600,7 @@ restart: if (!IS_FIXED(tb)) { goto restart; /* unfixed again! */ } - return; + return work; } if (ix < NACTIVE(tb)) { bp = &BUCKET(tb, ix); @@ -609,6 +610,7 @@ restart: if (b->hvalue == INVALID_HASH) { *bp = b->next; free_term(tb, b); + work++; b = *bp; } else { bp = &b->next; @@ -624,9 +626,12 @@ restart: (void *) fx, sizeof(FixedDeletion)); ERTS_ETS_MISC_MEM_ADD(-sizeof(FixedDeletion)); + work++; } /* ToDo: Maybe try grow/shrink the table as well */ + + return work; } int db_create_hash(Process *p, DbTable *tbl) @@ -2080,19 +2085,17 @@ static void db_print_hash(fmtfn_t to, void *to_arg, int show, DbTable *tbl) /* release all memory occupied by a single table */ static int db_free_table_hash(DbTable *tbl) { - while (!db_free_table_continue_hash(tbl)) + while (db_free_table_continue_hash(tbl, ERTS_SWORD_MAX) < 0) ; return 0; } -static int db_free_table_continue_hash(DbTable *tbl) +static SWord db_free_table_continue_hash(DbTable *tbl, SWord reds) { DbTableHash *tb = &tbl->hash; - int done; FixedDeletion* fixdel = (FixedDeletion*) erts_smp_atomic_read_acqb(&tb->fixdel); ERTS_SMP_LC_ASSERT(IS_TAB_WLOCKED(tb) || (tb->common.status & DB_DELETE)); - done = 0; while (fixdel != NULL) { FixedDeletion *fx = fixdel; @@ -2102,22 +2105,21 @@ static int db_free_table_continue_hash(DbTable *tbl) (void *) fx, sizeof(FixedDeletion)); ERTS_ETS_MISC_MEM_ADD(-sizeof(FixedDeletion)); - if (++done >= 2*DELETE_RECORD_LIMIT) { + if (--reds < 0) { erts_smp_atomic_set_relb(&tb->fixdel, (erts_aint_t)fixdel); - return 0; /* Not done */ + return reds; /* Not done */ } } erts_smp_atomic_set_relb(&tb->fixdel, (erts_aint_t)NULL); - done /= 2; while(tb->nslots != 0) { - done += 1 + EXT_SEGSZ/64 + free_seg(tb, 1); + reds -= EXT_SEGSZ/64 + free_seg(tb, 1); /* * If we have done enough work, get out here. */ - if (done >= DELETE_RECORD_LIMIT) { - return 0; /* Not done */ + if (reds < 0) { + return reds; /* Not done */ } } #ifdef ERTS_SMP @@ -2132,7 +2134,7 @@ static int db_free_table_continue_hash(DbTable *tbl) } #endif ASSERT(erts_smp_atomic_read_nob(&tb->common.memory_size) == sizeof(DbTable)); - return 1; /* Done */ + return reds; /* Done */ } diff --git a/erts/emulator/beam/erl_db_hash.h b/erts/emulator/beam/erl_db_hash.h index cd02418370..c340c72311 100644 --- a/erts/emulator/beam/erl_db_hash.h +++ b/erts/emulator/beam/erl_db_hash.h @@ -75,7 +75,7 @@ typedef struct db_table_hash { ** table types. The process is always an [in out] parameter. */ void db_initialize_hash(void); -void db_unfix_table_hash(DbTableHash *tb /* [in out] */); +SWord db_unfix_table_hash(DbTableHash *tb); Uint db_kept_items_hash(DbTableHash *tb); /* Interface for meta pid table */ diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c index 3dd06fd7bb..14a7451267 100644 --- a/erts/emulator/beam/erl_db_tree.c +++ b/erts/emulator/beam/erl_db_tree.c @@ -282,7 +282,7 @@ struct select_delete_context { static TreeDbTerm *linkout_tree(DbTableTree *tb, Eterm key); static TreeDbTerm *linkout_object_tree(DbTableTree *tb, Eterm object); -static int do_free_tree_cont(DbTableTree *tb, int num_left); +static SWord do_free_tree_continue(DbTableTree *tb, SWord reds); static void free_term(DbTableTree *tb, TreeDbTerm* p); static int balance_left(TreeDbTerm **this); static int balance_right(TreeDbTerm **this); @@ -388,7 +388,7 @@ static void db_print_tree(fmtfn_t to, void *to_arg, int show, DbTable *tbl); static int db_free_table_tree(DbTable *tbl); -static int db_free_table_continue_tree(DbTable *tbl); +static SWord db_free_table_continue_tree(DbTable *tbl, SWord); static void db_foreach_offheap_tree(DbTable *, void (*)(ErlOffHeap *, void *), @@ -1751,23 +1751,22 @@ static void db_print_tree(fmtfn_t to, void *to_arg, /* release all memory occupied by a single table */ static int db_free_table_tree(DbTable *tbl) { - while (!db_free_table_continue_tree(tbl)) + while (db_free_table_continue_tree(tbl, ERTS_SWORD_MAX) < 0) ; return 1; } -static int db_free_table_continue_tree(DbTable *tbl) +static SWord db_free_table_continue_tree(DbTable *tbl, SWord reds) { DbTableTree *tb = &tbl->tree; - int result; if (!tb->deletion) { tb->static_stack.pos = 0; tb->deletion = 1; PUSH_NODE(&tb->static_stack, tb->root); } - result = do_free_tree_cont(tb, DELETE_RECORD_LIMIT); - if (result) { /* Completely done. */ + reds = do_free_tree_continue(tb, reds); + if (reds >= 0) { /* Completely done. */ erts_db_free(ERTS_ALC_T_DB_STK, (DbTable *) tb, (void *) tb->static_stack.array, @@ -1775,7 +1774,7 @@ static int db_free_table_continue_tree(DbTable *tbl) ASSERT(erts_smp_atomic_read_nob(&tb->common.memory_size) == sizeof(DbTable)); } - return result; + return reds; } static int db_delete_all_objects_tree(Process* p, DbTable* tbl) @@ -2058,7 +2057,7 @@ static int analyze_pattern(DbTableTree *tb, Eterm pattern, return DB_ERROR_NONE; } -static int do_free_tree_cont(DbTableTree *tb, int num_left) +static SWord do_free_tree_continue(DbTableTree *tb, SWord reds) { TreeDbTerm *root; TreeDbTerm *p; @@ -2077,15 +2076,14 @@ static int do_free_tree_cont(DbTableTree *tb, int num_left) root = p; } else { free_term(tb, root); - if (--num_left > 0) { - break; - } else { - return 0; /* Done enough for now */ - } + if (--reds < 0) { + return reds; /* Done enough for now */ + } + break; } } } - return 1; + return reds; } /* diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h index 4fb285186e..72298842d7 100644 --- a/erts/emulator/beam/erl_db_util.h +++ b/erts/emulator/beam/erl_db_util.h @@ -175,7 +175,7 @@ typedef struct db_table_method DbTable* db /* [in out] */ ); int (*db_free_table)(DbTable* db /* [in out] */ ); - int (*db_free_table_continue)(DbTable* db); /* [in out] */ + SWord (*db_free_table_continue)(DbTable* db, SWord reds); void (*db_print)(fmtfn_t to, void* to_arg, -- cgit v1.2.3