Re: hipe_mfait_lock
Louis-Philippe Gauthier <[email protected]>
| Newsgroups | gmane.comp.lang.erlang.bugs |
|---|---|
| Message-ID | <CAGvQrRjZ22=f3XM19X-PV8zAN0stEh=WY7s9jYxr6auAMbvMmw@mail.gmail.com> |
Hi Mikael, Awesome work, I'll give the patch a try this week. Thanks, LP On Mon, Feb 23, 2015 at 6:30 AM, Mikael Pettersson <[email protected]> wrote: > Louis-Philippe Gauthier writes: > > Hi Sverker, > > That's not a bad idea, I'll try that approach! > > > > Thanks, > > LP > > > > On Thu, Jan 15, 2015 at 12:27 AM, Sverker Eriksson < > > [email protected]> wrote: > > > > > One quite simple improvement is to change the hipe_mfait_lock to be a > > > read-write mutex (erts_smp_rwmtx_t). > > > And then do read-lock at lookup and exclusive write-lock only when > > > inserting a new entry in the table. > > > > > > I don't think that requires much knowledge about the VM to pull off > ;-) . > > > > > > /Sverker, Erlang/OTP > > > > > > > > > > > > > > > On 01/14/2015 12:34 AM, Louis-Philippe Gauthier wrote: > > > > > > Hi erlang-bugs, > > > I couple of months ago I tried running our full application using > HiPE. I > > > ran into several issues, some manageable, some not... The most > problematic > > > issue was due to locking, specifically, the hipe_mfait_lock (you can > see > > > the lock counter output in the gist bellow). > > > https://gist.github.com/lpgauth/2b3220f4bceeed6f62d0 > > > > > > Looking at the code it's obvious that this is a known problem... the > > > following comment was added when the lock was added in 2010. > > > > > > "XXX: Redesign apply et al to avoid those updates." > https://github.com/erlang/otp/blob/maint/erts/emulator/hipe/hipe_bif0.c#L1218 > > > > > > Unfortunately, I'm don't know the runtime enough to start patching > it... so > > > instead I'm reporting it. > > Please try the attached patch (against 17.4, should apply to older > versions too by I haven't checked), and let me know if it makes a > noticeable improvement to your use case. > > Run-time apply:s now do their lookups using a shared read-lock, and > only if their lookups fail do they re-lock with an exclusive write-lock > in order to insert new data. Module loading functions always take > exclusive locks, which matches the current behaviour. > > /Mikael > > > --- otp_src_17.4/erts/emulator/hipe/hipe_bif0.c.~1~ 2014-12-09 > 21:11:07.000000000 +0100 > +++ otp_src_17.4/erts/emulator/hipe/hipe_bif0.c 2015-02-22 > 21:32:55.361884741 +0100 > @@ -1217,22 +1217,32 @@ static struct { > * they create a new stub for the mfa, which forces locking. > * XXX: Redesign apply et al to avoid those updates. > */ > - erts_smp_mtx_t lock; > + erts_smp_rwmtx_t lock; > } hipe_mfa_info_table; > > static inline void hipe_mfa_info_table_init_lock(void) > { > - erts_smp_mtx_init(&hipe_mfa_info_table.lock, "hipe_mfait_lock"); > + erts_smp_rwmtx_init(&hipe_mfa_info_table.lock, "hipe_mfait_lock"); > } > > -static inline void hipe_mfa_info_table_lock(void) > +static inline void hipe_mfa_info_table_rlock(void) > { > - erts_smp_mtx_lock(&hipe_mfa_info_table.lock); > + erts_smp_rwmtx_rlock(&hipe_mfa_info_table.lock); > } > > -static inline void hipe_mfa_info_table_unlock(void) > +static inline void hipe_mfa_info_table_runlock(void) > { > - erts_smp_mtx_unlock(&hipe_mfa_info_table.lock); > + erts_smp_rwmtx_runlock(&hipe_mfa_info_table.lock); > +} > + > +static inline void hipe_mfa_info_table_rwlock(void) > +{ > + erts_smp_rwmtx_rwlock(&hipe_mfa_info_table.lock); > +} > + > +static inline void hipe_mfa_info_table_rwunlock(void) > +{ > + erts_smp_rwmtx_rwunlock(&hipe_mfa_info_table.lock); > } > > #define HIPE_MFA_HASH(M,F,A) ((M) * (F) + (A)) > @@ -1333,6 +1343,7 @@ void *hipe_mfa_find_na(Eterm m, Eterm f, > } > #endif > > +/* PRE: called with write lock held */ > static struct hipe_mfa_info *hipe_mfa_info_table_put_locked(Eterm m, > Eterm f, unsigned int arity) > { > unsigned long h; > @@ -1362,7 +1373,7 @@ static void hipe_mfa_set_na(Eterm m, Ete > { > struct hipe_mfa_info *p; > > - hipe_mfa_info_table_lock(); > + hipe_mfa_info_table_rwlock(); > p = hipe_mfa_info_table_put_locked(m, f, arity); > #ifdef DEBUG_LINKER > printf("%s: ", __FUNCTION__); > @@ -1372,7 +1383,7 @@ static void hipe_mfa_set_na(Eterm m, Ete > p->local_address = address; > if (is_exported) > p->remote_address = address; > - hipe_mfa_info_table_unlock(); > + hipe_mfa_info_table_rwunlock(); > } > > #if defined(__powerpc__) || defined(__ppc__) || defined(__powerpc64__) || > defined(__arm__) > @@ -1381,10 +1392,10 @@ void *hipe_mfa_get_trampoline(Eterm m, E > struct hipe_mfa_info *p; > void *trampoline; > > - hipe_mfa_info_table_lock(); > - p = hipe_mfa_info_table_put_locked(m, f, arity); > - trampoline = p->trampoline; > - hipe_mfa_info_table_unlock(); > + hipe_mfa_info_table_rlock(); > + p = hipe_mfa_info_table_get_locked(m, f, arity); > + trampoline = p ? p->trampoline : NULL; > + hipe_mfa_info_table_runlock(); > return trampoline; > } > > @@ -1392,10 +1403,10 @@ void hipe_mfa_set_trampoline(Eterm m, Et > { > struct hipe_mfa_info *p; > > - hipe_mfa_info_table_lock(); > + hipe_mfa_info_table_rwlock(); > p = hipe_mfa_info_table_put_locked(m, f, arity); > p->trampoline = trampoline; > - hipe_mfa_info_table_unlock(); > + hipe_mfa_info_table_rwunlock(); > } > #endif > > @@ -1426,7 +1437,7 @@ BIF_RETTYPE hipe_bifs_invalidate_funinfo > struct mfa mfa; > struct hipe_mfa_info *p; > > - hipe_mfa_info_table_lock(); > + hipe_mfa_info_table_rwlock(); > lst = BIF_ARG_1; > while (is_list(lst)) { > if (!term_to_mfa(CAR(list_val(lst)), &mfa)) > @@ -1455,7 +1466,7 @@ BIF_RETTYPE hipe_bifs_invalidate_funinfo > } > } > } > - hipe_mfa_info_table_unlock(); > + hipe_mfa_info_table_rwunlock(); > if (is_not_nil(lst)) > BIF_ERROR(BIF_P, BADARG); > BIF_RET(NIL); > @@ -1469,7 +1480,7 @@ void hipe_mfa_save_orig_beam_op(Eterm mo > orig_beam_op = pc[0]; > if (orig_beam_op != BeamOpCode(op_hipe_trap_call_closure) && > orig_beam_op != BeamOpCode(op_hipe_trap_call)) { > - hipe_mfa_info_table_lock(); > + hipe_mfa_info_table_rwlock(); > p = hipe_mfa_info_table_put_locked(mod, fun, ari); > #ifdef DEBUG_LINKER > printf("%s: ", __FUNCTION__); > @@ -1478,7 +1489,7 @@ void hipe_mfa_save_orig_beam_op(Eterm mo > #endif > p->beam_code = pc; > p->orig_beam_op = orig_beam_op; > - hipe_mfa_info_table_unlock(); > + hipe_mfa_info_table_rwunlock(); > } else { > #ifdef DEBUG_LINKER > printf("%s: ", __FUNCTION__); > @@ -1505,7 +1516,8 @@ static void *hipe_make_stub(Eterm m, Ete > return StubAddress; > } > > -static void *hipe_get_na_nofail_locked(Eterm m, Eterm f, unsigned int a, > int is_remote) > +/* PRE: called with read or write lock held */ > +static void *hipe_get_na_try_locked(Eterm m, Eterm f, unsigned int a, int > is_remote, struct hipe_mfa_info **pp) > { > struct hipe_mfa_info *p; > void *address; > @@ -1523,7 +1535,20 @@ static void *hipe_get_na_nofail_locked(E > address = p->remote_address; > if (address) > return address; > - } else > + } > + /* Caller must take the slow path with the write lock held, but allow > + it to avoid some work if it already holds the write lock. */ > + if (pp) > + *pp = p; > + return NULL; > +} > + > +/* PRE: called with write lock held */ > +static void *hipe_get_na_slow_locked(Eterm m, Eterm f, unsigned int a, > int is_remote, struct hipe_mfa_info *p) > +{ > + void *address; > + > + if (!p) > p = hipe_mfa_info_table_put_locked(m, f, a); > address = hipe_make_stub(m, f, a, is_remote); > /* XXX: how to tell if a BEAM MFA is exported or not? */ > @@ -1531,14 +1556,34 @@ static void *hipe_get_na_nofail_locked(E > return address; > } > > +/* PRE: called with write lock held */ > +static void *hipe_get_na_nofail_locked(Eterm m, Eterm f, unsigned int a, > int is_remote) > +{ > + struct hipe_mfa_info *p /*= NULL*/; > + void *address; > + > + address = hipe_get_na_try_locked(m, f, a, is_remote, &p); > + if (address) > + return address; > + > + address = hipe_get_na_slow_locked(m, f, a, is_remote, p); > + return address; > +} > + > static void *hipe_get_na_nofail(Eterm m, Eterm f, unsigned int a, int > is_remote) > { > - void *p; > + void *address; > > - hipe_mfa_info_table_lock(); > - p = hipe_get_na_nofail_locked(m, f, a, is_remote); > - hipe_mfa_info_table_unlock(); > - return p; > + hipe_mfa_info_table_rlock(); > + address = hipe_get_na_try_locked(m, f, a, is_remote, NULL); > + hipe_mfa_info_table_runlock(); > + if (address) > + return address; > + > + hipe_mfa_info_table_rwlock(); > + address = hipe_get_na_slow_locked(m, f, a, is_remote, NULL); > + hipe_mfa_info_table_rwunlock(); > + return address; > } > > /* used for apply/3 in hipe_mode_switch */ > @@ -1617,7 +1662,7 @@ int hipe_find_mfa_from_ra(const void *ra > /* Note about locking: the table is only updated from the > loader, which runs with the rest of the system suspended. */ > /* XXX: alas not true; see comment at hipe_mfa_info_table.lock */ > - hipe_mfa_info_table_lock(); > + hipe_mfa_info_table_rwlock(); > bucket = hipe_mfa_info_table.bucket; > nrbuckets = 1 << hipe_mfa_info_table.log2size; > mfa = NULL; > @@ -1638,7 +1683,7 @@ int hipe_find_mfa_from_ra(const void *ra > *f = mfa->f; > *a = mfa->a; > } > - hipe_mfa_info_table_unlock(); > + hipe_mfa_info_table_rwunlock(); > return mfa ? 1 : 0; > } > > @@ -1715,7 +1760,7 @@ BIF_RETTYPE hipe_bifs_add_ref_2(BIF_ALIS > default: > goto badarg; > } > - hipe_mfa_info_table_lock(); > + hipe_mfa_info_table_rwlock(); > callee_mfa = hipe_mfa_info_table_put_locked(callee.mod, callee.fun, > callee.ari); > caller_mfa = hipe_mfa_info_table_put_locked(caller.mod, caller.fun, > caller.ari); > > @@ -1731,7 +1776,7 @@ BIF_RETTYPE hipe_bifs_add_ref_2(BIF_ALIS > ref->flags = flags; > ref->next = callee_mfa->referred_from; > callee_mfa->referred_from = ref; > - hipe_mfa_info_table_unlock(); > + hipe_mfa_info_table_rwunlock(); > > BIF_RET(NIL); > > @@ -1751,12 +1796,12 @@ BIF_RETTYPE hipe_bifs_mark_referred_from > > if (!term_to_mfa(BIF_ARG_1, &mfa)) > BIF_ERROR(BIF_P, BADARG); > - hipe_mfa_info_table_lock(); > + hipe_mfa_info_table_rwlock(); > p = hipe_mfa_info_table_get_locked(mfa.mod, mfa.fun, mfa.ari); > if (p) > for (ref = p->referred_from; ref != NULL; ref = ref->next) > ref->flags |= REF_FLAG_PENDING_REDIRECT; > - hipe_mfa_info_table_unlock(); > + hipe_mfa_info_table_rwunlock(); > BIF_RET(NIL); > } > > @@ -1770,7 +1815,7 @@ static void hipe_purge_all_refs(void) > struct hipe_mfa_info **bucket; > unsigned int i, nrbuckets; > > - hipe_mfa_info_table_lock(); > + hipe_mfa_info_table_rwlock(); > > bucket = hipe_mfa_info_table.bucket; > nrbuckets = 1 << hipe_mfa_info_table.log2size; > @@ -1792,7 +1837,7 @@ static void hipe_purge_all_refs(void) > erts_free(ERTS_ALC_T_HIPE, mfa); > } > } > - hipe_mfa_info_table_unlock(); > + hipe_mfa_info_table_rwunlock(); > } > > BIF_RETTYPE hipe_bifs_remove_refs_from_1(BIF_ALIST_1) > @@ -1809,7 +1854,7 @@ BIF_RETTYPE hipe_bifs_remove_refs_from_1 > > if (!term_to_mfa(BIF_ARG_1, &mfa)) > BIF_ERROR(BIF_P, BADARG); > - hipe_mfa_info_table_lock(); > + hipe_mfa_info_table_rwlock(); > caller_mfa = hipe_mfa_info_table_get_locked(mfa.mod, mfa.fun, > mfa.ari); > if (caller_mfa) { > refers_to = caller_mfa->refers_to; > @@ -1840,7 +1885,7 @@ BIF_RETTYPE hipe_bifs_remove_refs_from_1 > } > caller_mfa->refers_to = NULL; > } > - hipe_mfa_info_table_unlock(); > + hipe_mfa_info_table_rwunlock(); > BIF_RET(am_ok); > } > > @@ -1859,7 +1904,7 @@ BIF_RETTYPE hipe_bifs_redirect_referred_ > > if (!term_to_mfa(BIF_ARG_1, &mfa)) > BIF_ERROR(BIF_P, BADARG); > - hipe_mfa_info_table_lock(); > + hipe_mfa_info_table_rwlock(); > p = hipe_mfa_info_table_get_locked(mfa.mod, mfa.fun, mfa.ari); > if (p) { > prev = &p->referred_from; > @@ -1890,7 +1935,7 @@ BIF_RETTYPE hipe_bifs_redirect_referred_ > } > } > } > - hipe_mfa_info_table_unlock(); > + hipe_mfa_info_table_rwunlock(); > BIF_RET(NIL); > } > > > _______________________________________________ erlang-bugs mailing list [email protected] http://erlang.org/mailman/listinfo/erlang-bugs