mirror of
https://github.com/matrix-construct/construct
synced 2024-12-26 15:33:54 +01:00
ircd::ctx: Improve prof related; add full ticker of counters.
This commit is contained in:
parent
39d4f2fb83
commit
d5ffc6b0de
4 changed files with 134 additions and 74 deletions
|
@ -29,15 +29,22 @@
|
||||||
///
|
///
|
||||||
namespace ircd::ctx::prof
|
namespace ircd::ctx::prof
|
||||||
{
|
{
|
||||||
struct profile;
|
enum class event :uint8_t;
|
||||||
enum class event;
|
struct ticker;
|
||||||
|
|
||||||
// lowlevel
|
// util
|
||||||
ulong rdtsc();
|
ulong rdtsc();
|
||||||
|
string_view reflect(const event &);
|
||||||
|
|
||||||
// state accessors
|
// totals
|
||||||
const ulong &total_slice_cycles();
|
const ticker &get();
|
||||||
const ulong &total_slices();
|
const uint64_t &get(const event &);
|
||||||
|
|
||||||
|
// specific context
|
||||||
|
const ticker &get(const ctx &c);
|
||||||
|
const uint64_t &get(const ctx &c, const event &);
|
||||||
|
|
||||||
|
// current slice state
|
||||||
const ulong &cur_slice_start();
|
const ulong &cur_slice_start();
|
||||||
ulong cur_slice_cycles();
|
ulong cur_slice_cycles();
|
||||||
|
|
||||||
|
@ -52,22 +59,6 @@ namespace ircd::ctx::prof
|
||||||
void mark(const event &);
|
void mark(const event &);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Profiling events for marking. These are currently used internally at the
|
|
||||||
/// appropriate point to mark(): the user of ircd::ctx has no reason to mark()
|
|
||||||
/// these events; this interface is not quite developed for general use yet.
|
|
||||||
enum class ircd::ctx::prof::event
|
|
||||||
{
|
|
||||||
SPAWN, // Context spawn requested
|
|
||||||
JOIN, // Context join requested
|
|
||||||
JOINED, // Context join completed
|
|
||||||
CUR_ENTER, // Current context entered
|
|
||||||
CUR_LEAVE, // Current context leaving
|
|
||||||
CUR_YIELD, // Current context yielding
|
|
||||||
CUR_CONTINUE, // Current context continuing
|
|
||||||
CUR_INTERRUPT, // Current context detects interruption
|
|
||||||
CUR_TERMINATE, // Current context detects termination
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace ircd::ctx::prof::settings
|
namespace ircd::ctx::prof::settings
|
||||||
{
|
{
|
||||||
extern conf::item<double> stack_usage_warning; // percentage
|
extern conf::item<double> stack_usage_warning; // percentage
|
||||||
|
@ -78,9 +69,31 @@ namespace ircd::ctx::prof::settings
|
||||||
extern conf::item<ulong> slice_assertion; // abort() when exceeded (not a signal, must yield)
|
extern conf::item<ulong> slice_assertion; // abort() when exceeded (not a signal, must yield)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// structure aggregating any profiling related state for a ctx
|
/// Profiling events for marking. These are currently used internally at the
|
||||||
struct ircd::ctx::prof::profile
|
/// appropriate point to mark(): the user of ircd::ctx has no reason to mark()
|
||||||
|
/// these events; this interface is not quite developed for general use yet.
|
||||||
|
enum class ircd::ctx::prof::event
|
||||||
|
:uint8_t
|
||||||
{
|
{
|
||||||
ulong cycles {0}; // monotonic counter (rdtsc)
|
SPAWN, // Context spawn requested
|
||||||
uint64_t yields {0}; // monotonic counter
|
JOIN, // Context join requested
|
||||||
|
JOINED, // Context join completed
|
||||||
|
ENTER, // Current context entered
|
||||||
|
LEAVE, // Current context leaving
|
||||||
|
YIELD, // Current context yielding
|
||||||
|
CONTINUE, // Current context continuing
|
||||||
|
INTERRUPT, // Current context detects interruption
|
||||||
|
TERMINATE, // Current context detects termination
|
||||||
|
|
||||||
|
_NUM_
|
||||||
|
};
|
||||||
|
|
||||||
|
/// structure aggregating any profiling related state for a ctx
|
||||||
|
struct ircd::ctx::prof::ticker
|
||||||
|
{
|
||||||
|
// monotonic counter (rdtsc)
|
||||||
|
ulong cycles {0};
|
||||||
|
|
||||||
|
// monotonic counters for events
|
||||||
|
std::array<uint64_t, num_of<prof::event>()> event {{0}};
|
||||||
};
|
};
|
||||||
|
|
137
ircd/ctx.cc
137
ircd/ctx.cc
|
@ -85,10 +85,10 @@ noexcept try
|
||||||
this->yc = &yc;
|
this->yc = &yc;
|
||||||
notes = 1;
|
notes = 1;
|
||||||
stack.base = uintptr_t(__builtin_frame_address(0));
|
stack.base = uintptr_t(__builtin_frame_address(0));
|
||||||
mark(prof::event::CUR_ENTER);
|
mark(prof::event::ENTER);
|
||||||
const unwind atexit([this]
|
const unwind atexit([this]
|
||||||
{
|
{
|
||||||
mark(prof::event::CUR_LEAVE);
|
mark(prof::event::LEAVE);
|
||||||
adjoindre.notify_all();
|
adjoindre.notify_all();
|
||||||
this->yc = nullptr;
|
this->yc = nullptr;
|
||||||
ircd::ctx::current = nullptr;
|
ircd::ctx::current = nullptr;
|
||||||
|
@ -279,7 +279,7 @@ ircd::ctx::ctx::termination_point(std::nothrow_t)
|
||||||
{
|
{
|
||||||
assert(~flags & context::NOINTERRUPT);
|
assert(~flags & context::NOINTERRUPT);
|
||||||
flags |= context::NOINTERRUPT;
|
flags |= context::NOINTERRUPT;
|
||||||
mark(prof::event::CUR_TERMINATE);
|
mark(prof::event::TERMINATE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else return false;
|
else return false;
|
||||||
|
@ -294,7 +294,7 @@ ircd::ctx::ctx::interruption_point(std::nothrow_t)
|
||||||
{
|
{
|
||||||
assert(~flags & context::NOINTERRUPT);
|
assert(~flags & context::NOINTERRUPT);
|
||||||
flags &= ~context::INTERRUPTED;
|
flags &= ~context::INTERRUPTED;
|
||||||
mark(prof::event::CUR_INTERRUPT);
|
mark(prof::event::INTERRUPT);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else return false;
|
else return false;
|
||||||
|
@ -490,7 +490,7 @@ ircd::ctx::cycles(const ctx &ctx)
|
||||||
const uint64_t &
|
const uint64_t &
|
||||||
ircd::ctx::yields(const ctx &ctx)
|
ircd::ctx::yields(const ctx &ctx)
|
||||||
{
|
{
|
||||||
return ctx.profile.yields;
|
return prof::get(ctx, prof::event::YIELD);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the notification count for `ctx`
|
/// Returns the notification count for `ctx`
|
||||||
|
@ -962,7 +962,7 @@ ircd::ctx::continuation::continuation(const predicate &pred,
|
||||||
|
|
||||||
// Tell the profiler this is the point where the context has concluded
|
// Tell the profiler this is the point where the context has concluded
|
||||||
// its execution run and is now yielding.
|
// its execution run and is now yielding.
|
||||||
mark(prof::event::CUR_YIELD);
|
mark(prof::event::YIELD);
|
||||||
|
|
||||||
// Null the fundamental current context register as the last operation
|
// Null the fundamental current context register as the last operation
|
||||||
// during execution before yielding. When a context resumes it will
|
// during execution before yielding. When a context resumes it will
|
||||||
|
@ -980,7 +980,7 @@ noexcept(false)
|
||||||
|
|
||||||
// Tell the profiler this is the point where the context is now resuming.
|
// Tell the profiler this is the point where the context is now resuming.
|
||||||
// On some optimized builds this might lead nowhere.
|
// On some optimized builds this might lead nowhere.
|
||||||
mark(prof::event::CUR_CONTINUE);
|
mark(prof::event::CONTINUE);
|
||||||
|
|
||||||
// Unconditionally reset the notes counter to 1 because we're awake now.
|
// Unconditionally reset the notes counter to 1 because we're awake now.
|
||||||
self->notes = 1;
|
self->notes = 1;
|
||||||
|
@ -1377,20 +1377,21 @@ ircd::ctx::debug_stats(const pool &pool)
|
||||||
|
|
||||||
namespace ircd::ctx::prof
|
namespace ircd::ctx::prof
|
||||||
{
|
{
|
||||||
ulong _slice_start; // Current/last time slice started
|
ulong _slice_start; // Current/last time slice started
|
||||||
ulong _slice_stop; // Last time slice ended
|
ulong _slice_stop; // Last time slice ended
|
||||||
profile _total; // Totals counter for all contexts.
|
ticker _total; // Totals kept for all contexts.
|
||||||
|
|
||||||
void check_stack();
|
static void check_stack();
|
||||||
void check_slice();
|
static void check_slice();
|
||||||
|
static void slice_enter();
|
||||||
|
static void slice_leave();
|
||||||
|
|
||||||
void slice_enter();
|
static void handle_cur_continue();
|
||||||
void slice_leave();
|
static void handle_cur_yield();
|
||||||
|
static void handle_cur_leave();
|
||||||
|
static void handle_cur_enter();
|
||||||
|
|
||||||
void handle_cur_continue();
|
static void inc_ticker(const event &e);
|
||||||
void handle_cur_yield();
|
|
||||||
void handle_cur_leave();
|
|
||||||
void handle_cur_enter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// stack_usage_warning at 1/3 engineering tolerance
|
// stack_usage_warning at 1/3 engineering tolerance
|
||||||
|
@ -1439,44 +1440,35 @@ ircd::ctx::prof::settings::slice_assertion
|
||||||
void
|
void
|
||||||
ircd::ctx::prof::mark(const event &e)
|
ircd::ctx::prof::mark(const event &e)
|
||||||
{
|
{
|
||||||
|
inc_ticker(e);
|
||||||
|
|
||||||
switch(e)
|
switch(e)
|
||||||
{
|
{
|
||||||
case event::CUR_ENTER: handle_cur_enter(); break;
|
case event::ENTER: handle_cur_enter(); break;
|
||||||
case event::CUR_LEAVE: handle_cur_leave(); break;
|
case event::LEAVE: handle_cur_leave(); break;
|
||||||
case event::CUR_YIELD: handle_cur_yield(); break;
|
case event::YIELD: handle_cur_yield(); break;
|
||||||
case event::CUR_CONTINUE: handle_cur_continue(); break;
|
case event::CONTINUE: handle_cur_continue(); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
void
|
void
|
||||||
ircd::ctx::prof::mark(const event &e)
|
ircd::ctx::prof::mark(const event &)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ulong
|
void
|
||||||
ircd::ctx::prof::cur_slice_cycles()
|
ircd::ctx::prof::inc_ticker(const event &e)
|
||||||
{
|
{
|
||||||
return rdtsc() - cur_slice_start();
|
assert(uint8_t(e) < num_of<event>());
|
||||||
}
|
|
||||||
|
|
||||||
const ulong &
|
// Increment the ticker for all contexts.
|
||||||
ircd::ctx::prof::cur_slice_start()
|
_total.event[uint8_t(e)]++;
|
||||||
{
|
|
||||||
return _slice_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ulong &
|
// Increment the ticker for the context's instance
|
||||||
ircd::ctx::prof::total_slice_cycles()
|
if(likely(current))
|
||||||
{
|
current->profile.event[uint8_t(e)]++;
|
||||||
return _total.cycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ulong &
|
|
||||||
ircd::ctx::prof::total_slices()
|
|
||||||
{
|
|
||||||
return _total.yields;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1522,9 +1514,7 @@ ircd::ctx::prof::slice_leave()
|
||||||
const auto last_slice(_slice_stop - _slice_start);
|
const auto last_slice(_slice_stop - _slice_start);
|
||||||
c.stack.at = stack_at_here();
|
c.stack.at = stack_at_here();
|
||||||
c.profile.cycles += last_slice;
|
c.profile.cycles += last_slice;
|
||||||
c.profile.yields++;
|
|
||||||
_total.cycles += last_slice;
|
_total.cycles += last_slice;
|
||||||
_total.yields++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1642,6 +1632,63 @@ ircd::ctx::prof::slice_exceeded_warning(const ulong &cycles)
|
||||||
return threshold > 0 && cycles >= threshold;
|
return threshold > 0 && cycles >= threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ulong
|
||||||
|
ircd::ctx::prof::cur_slice_cycles()
|
||||||
|
{
|
||||||
|
return rdtsc() - cur_slice_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ulong &
|
||||||
|
ircd::ctx::prof::cur_slice_start()
|
||||||
|
{
|
||||||
|
return _slice_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t &
|
||||||
|
ircd::ctx::prof::get(const ctx &c,
|
||||||
|
const event &e)
|
||||||
|
{
|
||||||
|
return get(c).event.at(uint8_t(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
const ircd::ctx::prof::ticker &
|
||||||
|
ircd::ctx::prof::get(const ctx &c)
|
||||||
|
{
|
||||||
|
return c.profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t &
|
||||||
|
ircd::ctx::prof::get(const event &e)
|
||||||
|
{
|
||||||
|
return get().event.at(uint8_t(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
const ircd::ctx::prof::ticker &
|
||||||
|
ircd::ctx::prof::get()
|
||||||
|
{
|
||||||
|
return _total;
|
||||||
|
}
|
||||||
|
|
||||||
|
ircd::string_view
|
||||||
|
ircd::ctx::prof::reflect(const event &e)
|
||||||
|
{
|
||||||
|
switch(e)
|
||||||
|
{
|
||||||
|
case event::SPAWN: return "SPAWN";
|
||||||
|
case event::JOIN: return "JOIN";
|
||||||
|
case event::JOINED: return "JOINED";
|
||||||
|
case event::ENTER: return "ENTER";
|
||||||
|
case event::LEAVE: return "LEAVE";
|
||||||
|
case event::YIELD: return "YIELD";
|
||||||
|
case event::CONTINUE: return "CONTINUE";
|
||||||
|
case event::INTERRUPT: return "INTERRUPT";
|
||||||
|
case event::TERMINATE: return "TERMINATE";
|
||||||
|
case event::_NUM_: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "?????";
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_X86INTRIN_H
|
#ifdef HAVE_X86INTRIN_H
|
||||||
ulong
|
ulong
|
||||||
ircd::ctx::prof::rdtsc()
|
ircd::ctx::prof::rdtsc()
|
||||||
|
|
|
@ -43,9 +43,9 @@ struct ircd::ctx::ctx
|
||||||
boost::asio::steady_timer alarm; // acting semaphore (64B)
|
boost::asio::steady_timer alarm; // acting semaphore (64B)
|
||||||
boost::asio::yield_context *yc {nullptr}; // boost interface
|
boost::asio::yield_context *yc {nullptr}; // boost interface
|
||||||
continuation *cont {nullptr}; // valid when asleep; invalid when awake
|
continuation *cont {nullptr}; // valid when asleep; invalid when awake
|
||||||
ircd::ctx::stack stack; // stack related structure
|
|
||||||
prof::profile profile; // prof related structure
|
|
||||||
list::node node; // node for ctx::list
|
list::node node; // node for ctx::list
|
||||||
|
ircd::ctx::stack stack; // stack related structure
|
||||||
|
prof::ticker profile; // prof related structure
|
||||||
dock adjoindre; // contexts waiting for this to join()
|
dock adjoindre; // contexts waiting for this to join()
|
||||||
|
|
||||||
bool started() const; // context was ever entered
|
bool started() const; // context was ever entered
|
||||||
|
|
|
@ -1345,7 +1345,7 @@ console_cmd__ctx__list(opt &out, const string_view &line)
|
||||||
<< std::setw(15) << std::right << cycles(ctx)
|
<< std::setw(15) << std::right << cycles(ctx)
|
||||||
<< " ";
|
<< " ";
|
||||||
|
|
||||||
const long double total_cyc(ctx::prof::total_slice_cycles());
|
const long double total_cyc(ctx::prof::get().cycles);
|
||||||
const auto tsc_pct
|
const auto tsc_pct
|
||||||
{
|
{
|
||||||
total_cyc > 0.0? (cycles(ctx) / total_cyc) : 0.0L
|
total_cyc > 0.0? (cycles(ctx) / total_cyc) : 0.0L
|
||||||
|
|
Loading…
Reference in a new issue