From daf8f46c46745ebb6fcdfb226252c7823264a410 Mon Sep 17 00:00:00 2001 From: Rick Reed Date: Fri, 16 Mar 2012 16:01:44 -0700 Subject: erts: Add lcnt port and suspend options * Add new suspend, location, and port_locks options to erts_debug:lock_counters. * Init and destroy lock counting for processes and ports as appropriate. Conflicts: erts/emulator/beam/erl_bif_info.c --- erts/emulator/beam/erl_bif_info.c | 83 +++++++++++++++++++---------------- erts/emulator/beam/erl_lock_count.c | 27 ++++++++++-- erts/emulator/beam/erl_lock_count.h | 3 ++ erts/emulator/beam/erl_process_lock.c | 31 ++++++++++++- erts/emulator/beam/io.c | 45 ++++++++++++++++++- 5 files changed, 144 insertions(+), 45 deletions(-) (limited to 'erts') diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index f889ccdb93..02a463002c 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -4051,6 +4051,11 @@ static Eterm lcnt_build_result_term(Eterm **hpp, Uint *szp, erts_lcnt_data_t *da } #endif +#ifdef ERTS_ENABLE_LOCK_COUNT +void enable_io_lock_count(int enable); +void enable_proc_lock_count(int enable); +#endif + BIF_RETTYPE erts_debug_lock_counters_1(BIF_ALIST_1) { #ifdef ERTS_ENABLE_LOCK_COUNT @@ -4110,48 +4115,50 @@ BIF_RETTYPE erts_debug_lock_counters_1(BIF_ALIST_1) Eterm* tp = tuple_val(BIF_ARG_1); switch (arityval(tp[0])) { - case 2: + case 2: { + int opt = 0; + int val = 0; if (ERTS_IS_ATOM_STR("copy_save", tp[1])) { - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); - if (tp[2] == am_true) { - - res = erts_lcnt_set_rt_opt(ERTS_LCNT_OPT_COPYSAVE) ? am_true : am_false; - - } else if (tp[2] == am_false) { - - res = erts_lcnt_clear_rt_opt(ERTS_LCNT_OPT_COPYSAVE) ? am_true : am_false; - - } else { - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - BIF_ERROR(BIF_P, BADARG); - } - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - BIF_RET(res); - + opt = ERTS_LCNT_OPT_COPYSAVE; } else if (ERTS_IS_ATOM_STR("process_locks", tp[1])) { - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); - if (tp[2] == am_true) { - - res = erts_lcnt_set_rt_opt(ERTS_LCNT_OPT_PROCLOCK) ? am_true : am_false; - - } else if (tp[2] == am_false) { - - res = erts_lcnt_set_rt_opt(ERTS_LCNT_OPT_PROCLOCK) ? am_true : am_false; + opt = ERTS_LCNT_OPT_PROCLOCK; + } else if (ERTS_IS_ATOM_STR("port_locks", tp[1])) { + opt = ERTS_LCNT_OPT_PORTLOCK; + } else if (ERTS_IS_ATOM_STR("suspend", tp[1])) { + opt = ERTS_LCNT_OPT_SUSPEND; + } else if (ERTS_IS_ATOM_STR("location", tp[1])) { + opt = ERTS_LCNT_OPT_LOCATION; + } else { + BIF_ERROR(BIF_P, BADARG); + } + if (tp[2] == am_true) { + val = 1; + } else if (tp[2] == am_false) { + val = 0; + } else { + BIF_ERROR(BIF_P, BADARG); + } - } else { - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - BIF_ERROR(BIF_P, BADARG); + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + + if (val) { + res = erts_lcnt_set_rt_opt(opt) ? am_true : am_false; + } else { + res = erts_lcnt_clear_rt_opt(opt) ? am_true : am_false; + } + if (res != tp[2]) { + if (opt == ERTS_LCNT_OPT_PORTLOCK) { + enable_io_lock_count(val); + } else if (opt == ERTS_LCNT_OPT_PROCLOCK) { + enable_proc_lock_count(val); } - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - BIF_RET(res); - } - break; + } + erts_smp_thr_progress_unblock(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + BIF_RET(res); + break; + } default: break; diff --git a/erts/emulator/beam/erl_lock_count.c b/erts/emulator/beam/erl_lock_count.c index 5518531bcd..741c0cb08e 100644 --- a/erts/emulator/beam/erl_lock_count.c +++ b/erts/emulator/beam/erl_lock_count.c @@ -240,7 +240,7 @@ void erts_lcnt_init() { lcnt_lock(); - erts_lcnt_rt_options = ERTS_LCNT_OPT_PROCLOCK; + erts_lcnt_rt_options = ERTS_LCNT_OPT_PROCLOCK | ERTS_LCNT_OPT_LOCATION; eltd = lcnt_thread_data_alloc(); @@ -312,7 +312,7 @@ void erts_lcnt_list_insert(erts_lcnt_lock_list_t *list, erts_lcnt_lock_t *lock) } void erts_lcnt_list_delete(erts_lcnt_lock_list_t *list, erts_lcnt_lock_t *lock) { - + if (lock->next) lock->next->prev = lock->prev; if (lock->prev) lock->prev->next = lock->next; if (list->head == lock) list->head = lock->next; @@ -334,6 +334,10 @@ void erts_lcnt_init_lock(erts_lcnt_lock_t *lock, char *name, Uint16 flag ) { } void erts_lcnt_init_lock_x(erts_lcnt_lock_t *lock, char *name, Uint16 flag, Eterm id) { int i; + if (!name) { + lock->flag = 0; + return; + } lcnt_lock(); lock->next = NULL; @@ -363,6 +367,8 @@ void erts_lcnt_init_lock_x(erts_lcnt_lock_t *lock, char *name, Uint16 flag, Eter void erts_lcnt_destroy_lock(erts_lcnt_lock_t *lock) { erts_lcnt_lock_t *deleted_lock; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; + lcnt_lock(); if (erts_lcnt_rt_options & ERTS_LCNT_OPT_COPYSAVE) { @@ -378,6 +384,7 @@ void erts_lcnt_destroy_lock(erts_lcnt_lock_t *lock) { } /* delete original */ erts_lcnt_list_delete(erts_lcnt_data->current_locks, lock); + lock->flag = 0; lcnt_unlock(); } @@ -389,6 +396,7 @@ void erts_lcnt_lock_opt(erts_lcnt_lock_t *lock, Uint16 option) { erts_lcnt_thread_data_t *eltd; if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; eltd = lcnt_get_thread_data(); @@ -422,6 +430,7 @@ void erts_lcnt_lock(erts_lcnt_lock_t *lock) { erts_lcnt_thread_data_t *eltd; if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; w_state = ethr_atomic_read(&lock->w_state); ethr_atomic_inc( &lock->w_state); @@ -452,6 +461,7 @@ void erts_lcnt_lock_unaquire(erts_lcnt_lock_t *lock) { /* should check if this thread was "waiting" */ if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; ethr_atomic_dec( &lock->w_state); } @@ -475,6 +485,7 @@ void erts_lcnt_lock_post_x(erts_lcnt_lock_t *lock, char *file, unsigned int line #endif if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; #ifdef DEBUG if (!(lock->flag & (ERTS_LCNT_LT_RWMUTEX | ERTS_LCNT_LT_RWSPINLOCK))) { @@ -489,9 +500,13 @@ void erts_lcnt_lock_post_x(erts_lcnt_lock_t *lock, char *file, unsigned int line ASSERT(eltd); /* if lock was in conflict, time it */ - - stats = lcnt_get_lock_stats(lock, file, line); + if (erts_lcnt_rt_options & ERTS_LCNT_OPT_LOCATION) { + stats = lcnt_get_lock_stats(lock, file, line); + } else { + stats = &lock->stats[0]; + } + if (eltd->timer_set) { lcnt_time(&timer); @@ -510,6 +525,7 @@ void erts_lcnt_lock_post_x(erts_lcnt_lock_t *lock, char *file, unsigned int line void erts_lcnt_unlock_opt(erts_lcnt_lock_t *lock, Uint16 option) { if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; if (option & ERTS_LCNT_LO_WRITE) ethr_atomic_dec(&lock->w_state); if (option & ERTS_LCNT_LO_READ ) ethr_atomic_dec(&lock->r_state); } @@ -520,6 +536,7 @@ void erts_lcnt_unlock(erts_lcnt_lock_t *lock) { erts_aint_t flowstate; #endif if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; #ifdef DEBUG /* flowstate */ flowstate = ethr_atomic_read(&lock->flowstate); @@ -537,6 +554,7 @@ void erts_lcnt_unlock(erts_lcnt_lock_t *lock) { void erts_lcnt_trylock_opt(erts_lcnt_lock_t *lock, int res, Uint16 option) { if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; /* Determine lock_state via res instead of state */ if (res != EBUSY) { if (option & ERTS_LCNT_LO_WRITE) ethr_atomic_inc(&lock->w_state); @@ -555,6 +573,7 @@ void erts_lcnt_trylock(erts_lcnt_lock_t *lock, int res) { erts_aint_t flowstate; #endif if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; + if (!ERTS_LCNT_LOCK_TYPE(lock)) return; if (res != EBUSY) { #ifdef DEBUG diff --git a/erts/emulator/beam/erl_lock_count.h b/erts/emulator/beam/erl_lock_count.h index 6306580ae4..690551c71f 100644 --- a/erts/emulator/beam/erl_lock_count.h +++ b/erts/emulator/beam/erl_lock_count.h @@ -89,6 +89,7 @@ #define ERTS_LCNT_OPT_LOCATION (((Uint16) 1) << 1) #define ERTS_LCNT_OPT_PROCLOCK (((Uint16) 1) << 2) #define ERTS_LCNT_OPT_COPYSAVE (((Uint16) 1) << 3) +#define ERTS_LCNT_OPT_PORTLOCK (((Uint16) 1) << 4) typedef struct { unsigned long s; @@ -201,5 +202,7 @@ void erts_lcnt_clear_counters(void); char *erts_lcnt_lock_type(Uint16 type); erts_lcnt_data_t *erts_lcnt_get_data(void); +#define ERTS_LCNT_LOCK_TYPE(lockp) ((lockp)->flag & ERTS_LCNT_LT_ALL) + #endif /* ifdef ERTS_ENABLE_LOCK_COUNT */ #endif /* ifndef ERTS_LOCK_COUNT_H__ */ diff --git a/erts/emulator/beam/erl_process_lock.c b/erts/emulator/beam/erl_process_lock.c index a5a753b798..4437d46ff9 100644 --- a/erts/emulator/beam/erl_process_lock.c +++ b/erts/emulator/beam/erl_process_lock.c @@ -1002,7 +1002,7 @@ erts_proc_lock_init(Process *p) #ifdef ERTS_ENABLE_LOCK_COUNT void erts_lcnt_proc_lock_init(Process *p) { - + if (erts_lcnt_rt_options & ERTS_LCNT_OPT_PROCLOCK) { if (p->id != ERTS_INVALID_PID) { erts_lcnt_init_lock_x(&(p->lock.lcnt_main), "proc_main", ERTS_LCNT_LT_PROCLOCK, p->id); erts_lcnt_init_lock_x(&(p->lock.lcnt_msgq), "proc_msgq", ERTS_LCNT_LT_PROCLOCK, p->id); @@ -1014,6 +1014,12 @@ void erts_lcnt_proc_lock_init(Process *p) { erts_lcnt_init_lock(&(p->lock.lcnt_link), "proc_link", ERTS_LCNT_LT_PROCLOCK); erts_lcnt_init_lock(&(p->lock.lcnt_status), "proc_status", ERTS_LCNT_LT_PROCLOCK); } + } else { + sys_memzero(&(p->lock.lcnt_main), sizeof(p->lock.lcnt_main)); + sys_memzero(&(p->lock.lcnt_msgq), sizeof(p->lock.lcnt_msgq)); + sys_memzero(&(p->lock.lcnt_link), sizeof(p->lock.lcnt_link)); + sys_memzero(&(p->lock.lcnt_status), sizeof(p->lock.lcnt_status)); + } } @@ -1108,6 +1114,29 @@ void erts_lcnt_proc_trylock(erts_proc_lock_t *lock, ErtsProcLocks locks, int res } } +void enable_proc_lock_count (int enable); + +void +enable_proc_lock_count (int enable) +{ + int i; + + for (i = 0; i < erts_max_processes; ++i) { + Process* p = process_tab[i]; + if (p) { + if (enable) { + if (!ERTS_LCNT_LOCK_TYPE(&(p->lock.lcnt_main))) { + erts_lcnt_proc_lock_init(p); + } + } else { + if (ERTS_LCNT_LOCK_TYPE(&(p->lock.lcnt_main))) { + erts_lcnt_proc_lock_destroy(p); + } + } + } + } +} + #endif /* ifdef ERTS_ENABLE_LOCK_COUNT */ diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 8a2a43bebd..e8f04ef68a 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -625,7 +625,11 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */ port->lock = erts_alloc(ERTS_ALC_T_PORT_LOCK, sizeof(erts_smp_mtx_t)); erts_smp_mtx_init_x(port->lock, +#ifdef ERTS_ENABLE_LOCK_COUNT + (erts_lcnt_rt_options & ERTS_LCNT_OPT_PORTLOCK) ? "port_lock" : NULL, +#else "port_lock", +#endif port->id); xstatus |= ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK; } @@ -783,7 +787,13 @@ driver_create_port(ErlDrvPort creator_port_ix, /* Creating port */ creator_port->xports = xplp; port->lock = erts_alloc(ERTS_ALC_T_PORT_LOCK, sizeof(erts_smp_mtx_t)); - erts_smp_mtx_init_locked_x(port->lock, "port_lock", port_id); + erts_smp_mtx_init_locked_x(port->lock, +#ifdef ERTS_ENABLE_LOCK_COUNT + (erts_lcnt_rt_options & ERTS_LCNT_OPT_PORTLOCK) ? "port_lock" : NULL, +#else + "port_lock", +#endif + port_id); xstatus |= ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK; } @@ -1347,7 +1357,13 @@ void init_io(void) erts_smp_atomic_init_nob(&erts_port[i].refc, 0); erts_port[i].lock = NULL; erts_port[i].xports = NULL; - erts_smp_spinlock_init_x(&erts_port[i].state_lck, "port_state", make_small(i)); + erts_smp_spinlock_init_x(&erts_port[i].state_lck, +#ifdef ERTS_ENABLE_LOCK_COUNT + (erts_lcnt_rt_options & ERTS_LCNT_OPT_PORTLOCK) ? "port_state" : NULL, +#else + "port_state", +#endif + 0); #endif erts_port[i].tracer_proc = NIL; erts_port[i].trace_flags = 0; @@ -1380,6 +1396,31 @@ void init_io(void) erts_smp_mtx_unlock(&erts_driver_list_lock); } +#ifdef ERTS_ENABLE_LOCK_COUNT +void enable_io_lock_count (int enable); + +void +enable_io_lock_count (int enable) +{ + int i; + + for (i = 0; i < erts_max_ports; i++) { + Port* p = &erts_port[i]; + if (enable) { + erts_lcnt_init_lock_x(&p->state_lck.lcnt, "port_state", ERTS_LCNT_LT_SPINLOCK, make_small(i)); + if (p->lock) { + erts_lcnt_init_lock_x(&p->lock->lcnt, "port_lock", ERTS_LCNT_LT_MUTEX, make_small(i)); + } + } else { + erts_lcnt_destroy_lock(&p->state_lck.lcnt); + if (p->lock) { + erts_lcnt_destroy_lock(&p->lock->lcnt); + } + } + } +} +#endif + /* * Buffering of data when using line oriented I/O on ports */ -- cgit v1.2.3