0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-27 07:54:05 +01:00

ircd::ctx: Improve prof related; add full ticker of counters.

This commit is contained in:
Jason Volk 2018-12-22 14:53:23 -08:00
parent 39d4f2fb83
commit d5ffc6b0de
4 changed files with 134 additions and 74 deletions

View file

@ -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}};
}; };

View file

@ -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()

View file

@ -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

View file

@ -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