Added mutex stats.
This commit is contained in:
parent
e80dc97d6d
commit
e4757031a2
5 changed files with 184 additions and 5 deletions
|
@ -38,6 +38,7 @@ static void do_async_stat(void* arg);
|
|||
static void do_async_lock_stat(void* arg);
|
||||
static void do_async_log_stat(void* arg);
|
||||
static void do_async_memp_stat(void* arg);
|
||||
static void do_async_mutex_stat(void* arg);
|
||||
|
||||
static int add_dbref(PortData* data, int dbref);
|
||||
static int del_dbref(PortData* data, int dbref);
|
||||
|
@ -966,6 +967,45 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd,
|
|||
int rc = G_DB_ENV->memp_stat_print(G_DB_ENV, flags);
|
||||
RETURN_INT(rc, outbuf);
|
||||
}
|
||||
case CMD_MUTEX_STAT:
|
||||
{
|
||||
FAIL_IF_ASYNC_PENDING(d, outbuf);
|
||||
|
||||
// Inbuf is <<Flags:32 >>
|
||||
// If the working buffer is large enough, copy the data to put/get into it. Otherwise, realloc
|
||||
// until it is large enough
|
||||
if (d->work_buffer_sz < inbuf_sz)
|
||||
{
|
||||
d->work_buffer = driver_realloc(d->work_buffer, inbuf_sz);
|
||||
d->work_buffer_sz = inbuf_sz;
|
||||
}
|
||||
|
||||
// Copy the payload into place
|
||||
memcpy(d->work_buffer, inbuf, inbuf_sz);
|
||||
d->work_buffer_offset = inbuf_sz;
|
||||
|
||||
// Mark the port as busy and then schedule the appropriate async operation
|
||||
d->async_op = cmd;
|
||||
d->async_pool = G_TPOOL_GENERAL;
|
||||
bdberl_tpool_run(d->async_pool, &do_async_mutex_stat, d, 0, &d->async_job);
|
||||
|
||||
// Let caller know that the operation is in progress
|
||||
// Outbuf is: <<0:32>>
|
||||
RETURN_INT(0, outbuf);
|
||||
}
|
||||
case CMD_MUTEX_STAT_PRINT:
|
||||
{
|
||||
FAIL_IF_ASYNC_PENDING(d, outbuf);
|
||||
|
||||
// Inbuf is << Flags:32 >>
|
||||
unsigned int flags = UNPACK_INT(inbuf, 0);
|
||||
|
||||
// Outbuf is <<Rc:32>>
|
||||
// Run the command on the VM thread - this is for debugging only,
|
||||
// any real monitoring will use the async lock_stat
|
||||
int rc = G_DB_ENV->mutex_stat_print(G_DB_ENV, flags);
|
||||
RETURN_INT(rc, outbuf);
|
||||
}
|
||||
}
|
||||
*outbuf = 0;
|
||||
return 0;
|
||||
|
@ -1640,6 +1680,37 @@ static void async_cleanup_and_send_memp_stats(PortData* d, DB_MPOOL_STAT *gsp,
|
|||
}
|
||||
|
||||
|
||||
static void async_cleanup_and_send_mutex_stats(PortData* d, DB_MUTEX_STAT *msp)
|
||||
{
|
||||
// Save the port and pid references -- we need copies independent from the PortData
|
||||
// structure. Once we release the port_lock after clearing the cmd, it's possible that
|
||||
// the port could go away without waiting on us to finish. This is acceptable, but we need
|
||||
// to be certain that there is no overlap of data between the two threads. driver_send_term
|
||||
// is safe to use from a thread, even if the port you're sending from has already expired.
|
||||
ErlDrvPort port = d->port;
|
||||
ErlDrvTermData pid = d->port_owner;
|
||||
async_cleanup(d);
|
||||
|
||||
ErlDrvTermData response[] = {
|
||||
ERL_DRV_ATOM, driver_mk_atom("ok"),
|
||||
// Start of list
|
||||
ST_STATS_TUPLE(msp, mutex_align), /* Mutex alignment */
|
||||
ST_STATS_TUPLE(msp, mutex_tas_spins), /* Mutex test-and-set spins */
|
||||
ST_STATS_TUPLE(msp, mutex_cnt), /* Mutex count */
|
||||
ST_STATS_TUPLE(msp, mutex_free), /* Available mutexes */
|
||||
ST_STATS_TUPLE(msp, mutex_inuse), /* Mutexes in use */
|
||||
ST_STATS_TUPLE(msp, mutex_inuse_max), /* Maximum mutexes ever in use */
|
||||
ST_STATS_TUPLE(msp, region_wait), /* Region lock granted after wait. */
|
||||
ST_STATS_TUPLE(msp, region_nowait), /* Region lock granted without wait. */
|
||||
ST_STATS_TUPLE(msp, regsize), /* Region size. */
|
||||
// End of list
|
||||
ERL_DRV_NIL,
|
||||
ERL_DRV_LIST, 9+1,
|
||||
ERL_DRV_TUPLE, 2
|
||||
};
|
||||
driver_send_term(port, pid, response, sizeof(response) / sizeof(response[0]));
|
||||
}
|
||||
|
||||
|
||||
static void do_async_put(void* arg)
|
||||
{
|
||||
|
@ -1955,7 +2026,7 @@ static void do_async_log_stat(void* arg)
|
|||
async_cleanup_and_send_log_stats(d, lsp);
|
||||
}
|
||||
|
||||
// Finally, clean up lock stats
|
||||
// Finally, clean up stats
|
||||
if (NULL != lsp)
|
||||
{
|
||||
free(lsp);
|
||||
|
@ -1982,7 +2053,7 @@ static void do_async_memp_stat(void* arg)
|
|||
async_cleanup_and_send_memp_stats(d, gsp, fsp);
|
||||
}
|
||||
|
||||
// Finally, clean up lock stats
|
||||
// Finally, clean up stats
|
||||
if (NULL != gsp)
|
||||
{
|
||||
free(gsp);
|
||||
|
@ -1993,6 +2064,31 @@ static void do_async_memp_stat(void* arg)
|
|||
}
|
||||
}
|
||||
|
||||
static void do_async_mutex_stat(void* arg)
|
||||
{
|
||||
// Payload is: <<Flags:32 >>
|
||||
PortData* d = (PortData*)arg;
|
||||
|
||||
// Extract operation flags
|
||||
unsigned flags = UNPACK_INT(d->work_buffer, 0);
|
||||
|
||||
DB_MUTEX_STAT *msp = NULL;
|
||||
int rc = G_DB_ENV->mutex_stat(G_DB_ENV, &msp, flags);
|
||||
if (rc != 0 || msp == NULL)
|
||||
{
|
||||
async_cleanup_and_send_rc(d, rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
async_cleanup_and_send_mutex_stats(d, msp);
|
||||
}
|
||||
|
||||
// Finally, clean up stats
|
||||
if (NULL != msp)
|
||||
{
|
||||
free(msp);
|
||||
}
|
||||
}
|
||||
|
||||
static void* zalloc(unsigned int size)
|
||||
{
|
||||
|
|
|
@ -55,6 +55,8 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd,
|
|||
#define CMD_LOG_STAT_PRINT 24
|
||||
#define CMD_MEMP_STAT 25
|
||||
#define CMD_MEMP_STAT_PRINT 26
|
||||
#define CMD_MUTEX_STAT 27
|
||||
#define CMD_MUTEX_STAT_PRINT 28
|
||||
|
||||
/**
|
||||
* Command status values
|
||||
|
|
|
@ -30,8 +30,10 @@
|
|||
-define(CMD_LOCK_STAT_PRINT, 22).
|
||||
-define(CMD_LOG_STAT, 23).
|
||||
-define(CMD_LOG_STAT_PRINT, 24).
|
||||
-define(CMD_MEMP_STAT, 25).
|
||||
-define(CMD_MEMP_STAT_PRINT,26).
|
||||
-define(CMD_MEMP_STAT, 25).
|
||||
-define(CMD_MEMP_STAT_PRINT, 26).
|
||||
-define(CMD_MUTEX_STAT, 27).
|
||||
-define(CMD_MUTEX_STAT_PRINT,28).
|
||||
|
||||
-define(DB_TYPE_BTREE, 1).
|
||||
-define(DB_TYPE_HASH, 2).
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
log_stat_print/1,
|
||||
memp_stat/1,
|
||||
memp_stat_print/1,
|
||||
mutex_stat/1,
|
||||
mutex_stat_print/1,
|
||||
env_stat_print/1,
|
||||
transaction/1, transaction/2, transaction/3,
|
||||
put/3, put/4,
|
||||
|
@ -1613,6 +1615,78 @@ memp_stat_print(Opts) ->
|
|||
Error -> {error, Error}
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc
|
||||
%% Retrieve mutex stats
|
||||
%%
|
||||
%% This function retrieves mutex statistics
|
||||
%%
|
||||
%% === Options ===
|
||||
%%
|
||||
%% <dl>
|
||||
%% <dt>stat_clear</dt>
|
||||
%% <dd>Reset statistics after returning their values</dd>
|
||||
%% </dl>
|
||||
%%
|
||||
%% @spec mutex_stat(Opts) -> {ok, [{atom(), number()}]} | {error, Error}
|
||||
%% where
|
||||
%% Opts = [atom()]
|
||||
%%
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
-spec mutex_stat(Opts :: db_flags()) ->
|
||||
{ok, [{atom(), number()}]} | db_error().
|
||||
|
||||
mutex_stat(Opts) ->
|
||||
Flags = process_flags(Opts),
|
||||
Cmd = <<Flags:32/native>>,
|
||||
<<Result:32/signed-native>> = erlang:port_control(get_port(), ?CMD_MUTEX_STAT, Cmd),
|
||||
case decode_rc(Result) of
|
||||
ok ->
|
||||
receive
|
||||
{error, Reason} ->
|
||||
{error, decode_rc(Reason)};
|
||||
{ok, Stats} ->
|
||||
{ok, Stats}
|
||||
end;
|
||||
Error ->
|
||||
{error, Error}
|
||||
end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc
|
||||
%% Print mutex stats
|
||||
%%
|
||||
%% This function prints mutex statistics to wherever
|
||||
%% BDB messages are being sent
|
||||
%%
|
||||
%% === Options ===
|
||||
%%
|
||||
%% <dl>
|
||||
%% <dt>stat_all</dt>
|
||||
%% <dd>Display all available information.</dd>
|
||||
%% <dt>stat_clear</dt>
|
||||
%% <dd>Reset statistics after displaying their values.</dd>
|
||||
%% </dl>
|
||||
%%
|
||||
%% @spec mutex_stat_print(Opts) -> ok | {error, Error}
|
||||
%% where
|
||||
%% Opts = [atom()]
|
||||
%%
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
-spec mutex_stat_print(Opts :: db_flags()) ->
|
||||
ok | db_error().
|
||||
mutex_stat_print(Opts) ->
|
||||
Flags = process_flags(Opts),
|
||||
Cmd = <<Flags:32/native>>,
|
||||
<<Result:32/signed-native>> = erlang:port_control(get_port(), ?CMD_MUTEX_STAT_PRINT, Cmd),
|
||||
case decode_rc(Result) of
|
||||
ok -> ok;
|
||||
Error -> {error, Error}
|
||||
end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc
|
||||
|
|
|
@ -37,7 +37,8 @@ all() ->
|
|||
stat_should_fail_on_bad_dbref,
|
||||
lock_stat_should_report_on_success,
|
||||
log_stat_should_report_on_success,
|
||||
memp_stat_should_report_on_success].
|
||||
memp_stat_should_report_on_success,
|
||||
mutex_stat_should_report_on_success].
|
||||
|
||||
|
||||
dbconfig(Config) ->
|
||||
|
@ -298,3 +299,7 @@ memp_stat_should_report_on_success(_Config) ->
|
|||
true = is_list(Fstat),
|
||||
true = is_list(Gstat),
|
||||
done.
|
||||
|
||||
mutex_stat_should_report_on_success(_Config) ->
|
||||
{ok, _Stat} = bdberl:mutex_stat([]),
|
||||
done.
|
||||
|
|
Loading…
Reference in a new issue