/* * %CopyrightBegin% * * Copyright Ericsson AB 2014-2018. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * %CopyrightEnd% */ #ifndef ERL_MSACC_H__ #define ERL_MSACC_H__ /* Can be enabled/disabled via configure */ #if defined(ERTS_ENABLE_MSACC) && ERTS_ENABLE_MSACC == 2 #define ERTS_MSACC_EXTENDED_STATES 1 #endif /* Uncomment this to also count the number of transitions to a state. This will add a count to the counter map. */ /* #define ERTS_MSACC_STATE_COUNTERS 1 */ /* Uncomment this to make msacc to always be on, this reduces overhead a little bit when profiling */ /* #define ERTS_MSACC_ALWAYS_ON 1 */ /* Uncomment this to keep individual stats for all of the bifs when extended states is enabled */ /* #define ERTS_MSACC_EXTENDED_BIFS 1 */ #define ERTS_MSACC_DISABLE 0 #define ERTS_MSACC_ENABLE 1 #define ERTS_MSACC_RESET 2 #define ERTS_MSACC_GATHER 3 /* * When adding a new state, you have to: * * Add it here * * Increment ERTS_MSACC_STATE_COUNT * * Add string value to erts_msacc_states * * Have to be in alphabetical order! * * Only add states to the non-extended section after * careful benchmarking to make sure the overhead * when disabled is minimal. */ #ifndef ERTS_MSACC_EXTENDED_STATES #define ERTS_MSACC_STATE_AUX 0 #define ERTS_MSACC_STATE_CHECK_IO 1 #define ERTS_MSACC_STATE_EMULATOR 2 #define ERTS_MSACC_STATE_GC 3 #define ERTS_MSACC_STATE_OTHER 4 #define ERTS_MSACC_STATE_PORT 5 #define ERTS_MSACC_STATE_SLEEP 6 #define ERTS_MSACC_STATE_COUNT 7 #if defined(ERTS_MSACC_STATE_STRINGS) && defined(ERTS_ENABLE_MSACC) static char *erts_msacc_states[] = { "aux", "check_io", "emulator", "gc", "other", "port", "sleep" }; #endif #else #define ERTS_MSACC_STATE_ALLOC 0 #define ERTS_MSACC_STATE_AUX 1 #define ERTS_MSACC_STATE_BIF 2 #define ERTS_MSACC_STATE_BUSY_WAIT 3 #define ERTS_MSACC_STATE_CHECK_IO 4 #define ERTS_MSACC_STATE_EMULATOR 5 #define ERTS_MSACC_STATE_ETS 6 #define ERTS_MSACC_STATE_GC 7 #define ERTS_MSACC_STATE_GC_FULL 8 #define ERTS_MSACC_STATE_NIF 9 #define ERTS_MSACC_STATE_OTHER 10 #define ERTS_MSACC_STATE_PORT 11 #define ERTS_MSACC_STATE_SEND 12 #define ERTS_MSACC_STATE_SLEEP 13 #define ERTS_MSACC_STATE_TIMERS 14 #define ERTS_MSACC_STATIC_STATE_COUNT 15 #ifdef ERTS_MSACC_EXTENDED_BIFS #define ERTS_MSACC_STATE_COUNT (ERTS_MSACC_STATIC_STATE_COUNT + BIF_SIZE) #else #define ERTS_MSACC_STATE_COUNT ERTS_MSACC_STATIC_STATE_COUNT #endif #ifdef ERTS_MSACC_STATE_STRINGS static char *erts_msacc_states[] = { "alloc", "aux", "bif", "busy_wait", "check_io", "emulator", "ets", "gc", "gc_full", "nif", "other", "port", "send", "sleep", "timers" #ifdef ERTS_MSACC_EXTENDED_BIFS #define BIF_LIST(Mod,Func,Arity,BifFuncAddr,FuncAddr,Num) \ ,"bif_" #Mod "_" #Func "_" #Arity #include "erl_bif_list.h" #undef BIF_LIST #endif }; #endif #endif typedef struct erl_msacc_t_ ErtsMsAcc; typedef struct erl_msacc_p_cnt_t_ { ErtsSysPerfCounter pc; #ifdef ERTS_MSACC_STATE_COUNTERS Uint64 sc; #endif } ErtsMsAccPerfCntr; struct erl_msacc_t_ { /* protected by msacc_mutex in erl_msacc.c, and should be constant */ int unmanaged; erts_mtx_t mtx; ErtsMsAcc *next; erts_tid_t tid; Eterm id; char *type; /* the the values below are protected by mtx iff unmanaged = 1 */ ErtsSysPerfCounter perf_counter; Uint state; ErtsMsAccPerfCntr counters[]; }; #ifdef ERTS_ENABLE_MSACC extern erts_tsd_key_t ERTS_WRITE_UNLIKELY(erts_msacc_key); #ifdef ERTS_MSACC_ALWAYS_ON #define erts_msacc_enabled 1 #else extern int ERTS_WRITE_UNLIKELY(erts_msacc_enabled); #endif #define ERTS_MSACC_TSD_GET() erts_tsd_get(erts_msacc_key) #define ERTS_MSACC_TSD_SET(tsd) erts_tsd_set(erts_msacc_key,tsd) void erts_msacc_early_init(void); void erts_msacc_init(void); void erts_msacc_init_thread(char *type, int id, int liberty); /* The defines below are used to instrument the vm code * with different state changes. There are two variants * of each define. One that has a cached ErtsMsAcc * * that it can use, and one that does not. * The cached values are necessary to have in order to get * low enough overhead when running without msacc enabled. * * The two most common patterns to use the function with are: * * ERTS_MSACC_PUSH_AND_SET_STATE(ERTS_MSACC_STATE_NEWSTATE); * ... call other function in new state ... * ERTS_MSACC_POP_STATE(); * * Note that the erts_msacc_push* function declare new variables, so * to conform with C89 we have to call it in the beginning of a function. * We might not want to change state it the beginning though, so we use this: * * ERTS_MSACC_PUSH_STATE(); * ... some other code ... * ERTS_MSACC_SET_STATE_CACHED(ERTS_MSACC_STATE_NEWSTATE); * ... call other function in new state ... * ERTS_MSACC_POP_STATE(); * * Notice that we used the cached version of set_state as push_state already * read the erts_msacc_enabled to the cache. * * Most macros also have other variants with the suffix _m which means that * they are known to only be called in managed threads, or with the _x suffix * which means that it should only be used in an emulator compiled with * extended states. * * Here is a listing of the entire api: * * void ERTS_MSACC_DECLARE_CACHE() * void ERTS_MSACC_UPDATE_CACHE() * void ERTS_MSACC_IS_ENABLED() * void ERTS_MSACC_IS_ENABLED_CACHED() * * void ERTS_MSACC_PUSH_STATE() * void ERTS_MSACC_SET_STATE(int state) * void ERTS_MSACC_PUSH_AND_SET_STATE(int state) * * void ERTS_MSACC_PUSH_STATE_CACHED() * void ERTS_MSACC_SET_STATE_CACHED(int state) * void ERTS_MSACC_PUSH_AND_SET_STATE_CACHED(int state) * void ERTS_MSACC_POP_STATE() * * void ERTS_MSACC_PUSH_STATE_M() * void ERTS_MSACC_PUSH_STATE_CACHED_M() * void ERTS_MSACC_SET_STATE_CACHED_M(int state) * void ERTS_MSACC_SET_STATE_M(int state) * void ERTS_MSACC_POP_STATE_M() * void ERTS_MSACC_PUSH_AND_SET_STATE_M(int state) * * Most functions are also available with an _x suffix that are only enabled * when using the extra states. If they are not, just add them to the end * of this file. */ /* cache handling functions */ #define ERTS_MSACC_IS_ENABLED() ERTS_UNLIKELY(erts_msacc_enabled) #define ERTS_MSACC_DECLARE_CACHE() \ ErtsMsAcc *ERTS_MSACC_UPDATE_CACHE(); \ ERTS_DECLARE_DUMMY(Uint __erts_msacc_state) = ERTS_MSACC_STATE_OTHER; #define ERTS_MSACC_IS_ENABLED_CACHED() ERTS_UNLIKELY(__erts_msacc_cache != NULL) #define ERTS_MSACC_UPDATE_CACHE() \ __erts_msacc_cache = erts_msacc_enabled ? ERTS_MSACC_TSD_GET() : NULL /* The defines below implicitly declare and load a new cache */ #define ERTS_MSACC_PUSH_STATE() \ ERTS_MSACC_DECLARE_CACHE(); \ ERTS_MSACC_PUSH_STATE_CACHED() #define ERTS_MSACC_SET_STATE(state) \ ERTS_MSACC_DECLARE_CACHE(); \ ERTS_MSACC_SET_STATE_CACHED(state) #define ERTS_MSACC_PUSH_AND_SET_STATE(state) \ ERTS_MSACC_PUSH_STATE(); ERTS_MSACC_SET_STATE_CACHED(state) /* The defines below need an already declared cache to work */ #define ERTS_MSACC_PUSH_STATE_CACHED() \ __erts_msacc_state = ERTS_MSACC_IS_ENABLED_CACHED() ? \ erts_msacc_get_state_um__(__erts_msacc_cache) : ERTS_MSACC_STATE_OTHER #define ERTS_MSACC_SET_STATE_CACHED(state) \ if (ERTS_MSACC_IS_ENABLED_CACHED()) \ erts_msacc_set_state_um__(__erts_msacc_cache, state, 1) #define ERTS_MSACC_PUSH_AND_SET_STATE_CACHED(state) \ ERTS_MSACC_PUSH_STATE_CACHED(); ERTS_MSACC_SET_STATE_CACHED(state) #define ERTS_MSACC_POP_STATE() \ if (ERTS_MSACC_IS_ENABLED_CACHED()) \ erts_msacc_set_state_um__(__erts_msacc_cache, __erts_msacc_state, 0) /* Only use these defines when we know that we have in a managed thread */ #define ERTS_MSACC_PUSH_STATE_M() \ ERTS_MSACC_DECLARE_CACHE(); \ ERTS_MSACC_PUSH_STATE_CACHED_M() #define ERTS_MSACC_PUSH_STATE_CACHED_M() \ do { \ if (ERTS_MSACC_IS_ENABLED_CACHED()) { \ ASSERT(!__erts_msacc_cache->unmanaged); \ __erts_msacc_state = erts_msacc_get_state_m__(__erts_msacc_cache); \ } else { \ __erts_msacc_state = ERTS_MSACC_STATE_OTHER; \ } \ } while(0) #define ERTS_MSACC_SET_STATE_M(state) \ ERTS_MSACC_DECLARE_CACHE(); \ ERTS_MSACC_SET_STATE_CACHED_M(state) #define ERTS_MSACC_SET_STATE_CACHED_M(state) \ do { \ if (ERTS_MSACC_IS_ENABLED_CACHED()) { \ ASSERT(!__erts_msacc_cache->unmanaged); \ erts_msacc_set_state_m__(__erts_msacc_cache, state, 1); \ } \ } while(0) #define ERTS_MSACC_POP_STATE_M() \ do { \ if (ERTS_MSACC_IS_ENABLED_CACHED()) { \ ASSERT(!__erts_msacc_cache->unmanaged); \ erts_msacc_set_state_m__(__erts_msacc_cache, __erts_msacc_state, 0); \ } \ } while(0) #define ERTS_MSACC_PUSH_AND_SET_STATE_M(state) \ ERTS_MSACC_PUSH_STATE_M(); ERTS_MSACC_SET_STATE_CACHED_M(state) ERTS_GLB_INLINE void erts_msacc_set_state_um__(ErtsMsAcc *msacc,Uint state,int increment); ERTS_GLB_INLINE void erts_msacc_set_state_m__(ErtsMsAcc *msacc,Uint state,int increment); ERTS_GLB_INLINE Uint erts_msacc_get_state_um__(ErtsMsAcc *msacc); ERTS_GLB_INLINE Uint erts_msacc_get_state_m__(ErtsMsAcc *msacc); #if ERTS_GLB_INLINE_INCL_FUNC_DEF ERTS_GLB_INLINE Uint erts_msacc_get_state_um__(ErtsMsAcc *msacc) { Uint state; if (msacc->unmanaged) erts_mtx_lock(&msacc->mtx); state = msacc->state; if (msacc->unmanaged) erts_mtx_unlock(&msacc->mtx); return state; } ERTS_GLB_INLINE Uint erts_msacc_get_state_m__(ErtsMsAcc *msacc) { return msacc->state; } ERTS_GLB_INLINE void erts_msacc_set_state_um__(ErtsMsAcc *msacc, Uint new_state, int increment) { if (ERTS_UNLIKELY(msacc->unmanaged)) { erts_mtx_lock(&msacc->mtx); if (ERTS_LIKELY(!msacc->perf_counter)) { msacc->state = new_state; erts_mtx_unlock(&msacc->mtx); return; } } erts_msacc_set_state_m__(msacc,new_state,increment); if (ERTS_UNLIKELY(msacc->unmanaged)) erts_mtx_unlock(&msacc->mtx); } ERTS_GLB_INLINE void erts_msacc_set_state_m__(ErtsMsAcc *msacc, Uint new_state, int increment) { ErtsSysPerfCounter prev_perf_counter; Sint64 diff; if (new_state == msacc->state) return; prev_perf_counter = msacc->perf_counter; msacc->perf_counter = erts_sys_perf_counter(); diff = msacc->perf_counter - prev_perf_counter; ASSERT(diff >= 0); msacc->counters[msacc->state].pc += diff; #ifdef ERTS_MSACC_STATE_COUNTERS msacc->counters[new_state].sc += increment; #endif msacc->state = new_state; } #endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ #else #define ERTS_MSACC_IS_ENABLED() 0 #define erts_msacc_early_init() #define erts_msacc_init() #define erts_msacc_init_thread(type, id, liberty) #define ERTS_MSACC_PUSH_STATE() #define ERTS_MSACC_PUSH_STATE_CACHED() #define ERTS_MSACC_POP_STATE() #define ERTS_MSACC_SET_STATE(state) #define ERTS_MSACC_SET_STATE_CACHED(state) #define ERTS_MSACC_PUSH_AND_SET_STATE(state) #define ERTS_MSACC_PUSH_AND_SET_STATE_CACHED(state) #define ERTS_MSACC_UPDATE_CACHE() #define ERTS_MSACC_IS_ENABLED_CACHED() #define ERTS_MSACC_DECLARE_CACHE() #define ERTS_MSACC_PUSH_STATE_M() #define ERTS_MSACC_PUSH_STATE_CACHED_M() #define ERTS_MSACC_SET_STATE_CACHED_M(state) #define ERTS_MSACC_POP_STATE_M() #define ERTS_MSACC_PUSH_AND_SET_STATE_M(state) #define ERTS_MSACC_SET_BIF_STATE_CACHED_X(Mod,Addr) #endif /* ERTS_ENABLE_MSACC */ #ifndef ERTS_MSACC_EXTENDED_STATES #define ERTS_MSACC_PUSH_STATE_X() #define ERTS_MSACC_POP_STATE_X() #define ERTS_MSACC_SET_STATE_X(state) #define ERTS_MSACC_SET_STATE_M_X(state) #define ERTS_MSACC_SET_STATE_CACHED_X(state) #define ERTS_MSACC_PUSH_AND_SET_STATE_X(state) #define ERTS_MSACC_PUSH_AND_SET_STATE_CACHED_X(state) #define ERTS_MSACC_UPDATE_CACHE_X() #define ERTS_MSACC_IS_ENABLED_CACHED_X() 0 #define ERTS_MSACC_DECLARE_CACHE_X() #define ERTS_MSACC_PUSH_STATE_M_X() #define ERTS_MSACC_PUSH_STATE_CACHED_M_X() #define ERTS_MSACC_SET_STATE_CACHED_M_X(state) #define ERTS_MSACC_POP_STATE_M_X() #define ERTS_MSACC_PUSH_AND_SET_STATE_M_X(state) #define ERTS_MSACC_PUSH_AND_SET_STATE_CACHED_M_X(state) #define ERTS_MSACC_SET_BIF_STATE_CACHED_X(Mod,Addr) #else void erts_msacc_set_bif_state(ErtsMsAcc *msacc, Eterm mod, void *addr); #define ERTS_MSACC_PUSH_STATE_X() ERTS_MSACC_PUSH_STATE() #define ERTS_MSACC_POP_STATE_X() ERTS_MSACC_POP_STATE() #define ERTS_MSACC_SET_STATE_X(state) ERTS_MSACC_SET_STATE(state) #define ERTS_MSACC_SET_STATE_M_X(state) ERTS_MSACC_SET_STATE_M(state) #define ERTS_MSACC_SET_STATE_CACHED_X(state) ERTS_MSACC_SET_STATE_CACHED(state) #define ERTS_MSACC_PUSH_AND_SET_STATE_X(state) ERTS_MSACC_PUSH_AND_SET_STATE(state) #define ERTS_MSACC_PUSH_AND_SET_STATE_CACHED_X(state) ERTS_MSACC_PUSH_AND_SET_STATE_CACHED(state) #define ERTS_MSACC_UPDATE_CACHE_X() ERTS_MSACC_UPDATE_CACHE() #define ERTS_MSACC_IS_ENABLED_CACHED_X() ERTS_MSACC_IS_ENABLED_CACHED() #define ERTS_MSACC_DECLARE_CACHE_X() ERTS_MSACC_DECLARE_CACHE() #define ERTS_MSACC_PUSH_STATE_M_X() ERTS_MSACC_PUSH_STATE_M() #define ERTS_MSACC_PUSH_STATE_CACHED_M_X() ERTS_MSACC_PUSH_STATE_CACHED_M() #define ERTS_MSACC_SET_STATE_CACHED_M_X(state) ERTS_MSACC_SET_STATE_CACHED_M(state) #define ERTS_MSACC_POP_STATE_M_X() ERTS_MSACC_POP_STATE_M() #define ERTS_MSACC_PUSH_AND_SET_STATE_M_X(state) ERTS_MSACC_PUSH_AND_SET_STATE_M(state) #define ERTS_MSACC_SET_BIF_STATE_CACHED_X(Mod,Addr) \ if (ERTS_MSACC_IS_ENABLED_CACHED_X()) \ erts_msacc_set_bif_state(__erts_msacc_cache, Mod, Addr) #endif /* !ERTS_MSACC_EXTENDED_STATES */ #endif /* ERL_MSACC_H__ */