mirror of
https://github.com/matrix-construct/construct
synced 2024-12-28 00:14:07 +01:00
ircd::prof: Reorg; deinline various; add comments.
This commit is contained in:
parent
e4acdbf772
commit
30b59f4736
4 changed files with 238 additions and 149 deletions
|
@ -66,6 +66,7 @@ namespace ircd::prof::vg
|
||||||
struct enable;
|
struct enable;
|
||||||
struct disable;
|
struct disable;
|
||||||
|
|
||||||
|
bool enabled();
|
||||||
void dump(const char *const reason = nullptr);
|
void dump(const char *const reason = nullptr);
|
||||||
void toggle();
|
void toggle();
|
||||||
void reset();
|
void reset();
|
||||||
|
@ -73,23 +74,50 @@ namespace ircd::prof::vg
|
||||||
void stop() noexcept;
|
void stop() noexcept;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exports to ircd::
|
||||||
namespace ircd
|
namespace ircd
|
||||||
{
|
{
|
||||||
using prof::cycles;
|
using prof::cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enable callgrind profiling for the scope
|
||||||
struct ircd::prof::vg::enable
|
struct ircd::prof::vg::enable
|
||||||
{
|
{
|
||||||
enable() noexcept { start(); }
|
enable() noexcept;
|
||||||
~enable() noexcept { stop(); }
|
~enable() noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Disable any enabled callgrind profiling for the scope; then restore.
|
||||||
struct ircd::prof::vg::disable
|
struct ircd::prof::vg::disable
|
||||||
{
|
{
|
||||||
disable() noexcept { stop(); }
|
disable() noexcept;
|
||||||
~disable() noexcept { start(); }
|
~disable() noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// This suite of devices is intended to figure out when a system call is
|
||||||
|
/// really slow or "blocking." The original use-case is for io_submit() in
|
||||||
|
/// fs::aio.
|
||||||
|
///
|
||||||
|
/// The sample is conducted with times(2) which is itself a system call
|
||||||
|
/// though reasonably fast, and the result has poor resolution meaning
|
||||||
|
/// the result of at() is generally 0 unless the system call was very slow.
|
||||||
|
///
|
||||||
|
/// It is started on construction. The user must later call sample()
|
||||||
|
/// which returns the value of at() as well.
|
||||||
|
struct ircd::prof::syscall_timer
|
||||||
|
{
|
||||||
|
uint64_t started, stopped;
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint64_t at() const;
|
||||||
|
uint64_t sample();
|
||||||
|
|
||||||
|
syscall_timer() noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Frontend to times(2). This has low resolution in practice, but it's
|
||||||
|
/// very cheap as far as syscalls go; x-platform implementation courtesy
|
||||||
|
/// of boost::chrono.
|
||||||
struct ircd::prof::times
|
struct ircd::prof::times
|
||||||
{
|
{
|
||||||
uint64_t real {0};
|
uint64_t real {0};
|
||||||
|
@ -100,35 +128,8 @@ struct ircd::prof::times
|
||||||
times() = default;
|
times() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This device intends to figure out when a system call is really slow
|
/// Frontend to getrusage(2). This has higher resolution than prof::times
|
||||||
/// or "blocking." The original use-case is for io_submit() in fs::aio.
|
/// in practice with slight added expense.
|
||||||
/// The sample is conducted with times(2) which is itself a system call,
|
|
||||||
/// and the result has poor resolution meaning the result of at() is
|
|
||||||
/// generally 0 unless the system call was actually slow.
|
|
||||||
struct ircd::prof::syscall_timer
|
|
||||||
{
|
|
||||||
uint64_t started
|
|
||||||
{
|
|
||||||
time_kern()
|
|
||||||
};
|
|
||||||
|
|
||||||
uint64_t stopped
|
|
||||||
{
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
uint64_t at() const
|
|
||||||
{
|
|
||||||
return stopped - started;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t stop()
|
|
||||||
{
|
|
||||||
stopped = time_kern();
|
|
||||||
return at();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ircd::prof::resource
|
struct ircd::prof::resource
|
||||||
:std::array<uint64_t, 9>
|
:std::array<uint64_t, 9>
|
||||||
{
|
{
|
||||||
|
@ -151,6 +152,7 @@ struct ircd::prof::resource
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Frontend to perf_event_open(2). This has the highest resolution.
|
||||||
struct ircd::prof::system
|
struct ircd::prof::system
|
||||||
:std::array<std::array<uint64_t, 2>, 7>
|
:std::array<std::array<uint64_t, 2>, 7>
|
||||||
{
|
{
|
||||||
|
@ -174,6 +176,10 @@ struct ircd::prof::system
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Type descriptor for prof events. This structure is used to aggregate
|
||||||
|
/// information that describes a profiling event type, including whether
|
||||||
|
/// the kernel or the user is being profiled (dpl), the principal counter
|
||||||
|
/// type being profiled (counter) and any other contextual attributes.
|
||||||
struct ircd::prof::type
|
struct ircd::prof::type
|
||||||
{
|
{
|
||||||
enum dpl dpl {0};
|
enum dpl dpl {0};
|
||||||
|
@ -189,8 +195,8 @@ struct ircd::prof::type
|
||||||
enum ircd::prof::dpl
|
enum ircd::prof::dpl
|
||||||
:std::underlying_type<ircd::prof::dpl>::type
|
:std::underlying_type<ircd::prof::dpl>::type
|
||||||
{
|
{
|
||||||
KERNEL,
|
KERNEL = 0,
|
||||||
USER
|
USER = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ircd::prof::counter
|
enum ircd::prof::counter
|
||||||
|
|
|
@ -877,7 +877,7 @@ noexcept
|
||||||
{
|
{
|
||||||
timer.stopped?
|
timer.stopped?
|
||||||
timer.at():
|
timer.at():
|
||||||
timer.stop()
|
timer.sample()
|
||||||
};
|
};
|
||||||
|
|
||||||
if(likely(!total))
|
if(likely(!total))
|
||||||
|
|
|
@ -896,7 +896,7 @@ try
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef RB_DEBUG
|
#ifdef RB_DEBUG
|
||||||
stats.stalls += warning.timer.stop() > 0;
|
stats.stalls += warning.timer.sample() > 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
assert(!qcount || ret > 0);
|
assert(!qcount || ret > 0);
|
||||||
|
|
307
ircd/prof.cc
307
ircd/prof.cc
|
@ -188,6 +188,201 @@ catch(const std::exception &e)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// prof::vg
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace ircd::prof::vg
|
||||||
|
{
|
||||||
|
static bool _enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// prof::vg::enable
|
||||||
|
//
|
||||||
|
|
||||||
|
ircd::prof::vg::enable::enable()
|
||||||
|
noexcept
|
||||||
|
{
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
ircd::prof::vg::enable::~enable()
|
||||||
|
noexcept
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// prof::vg::disable
|
||||||
|
//
|
||||||
|
|
||||||
|
ircd::prof::vg::disable::disable()
|
||||||
|
noexcept
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
ircd::prof::vg::disable::~disable()
|
||||||
|
noexcept
|
||||||
|
{
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// prof::vg util
|
||||||
|
//
|
||||||
|
|
||||||
|
void
|
||||||
|
ircd::prof::vg::stop()
|
||||||
|
noexcept
|
||||||
|
{
|
||||||
|
#ifdef HAVE_VALGRIND_CALLGRIND_H
|
||||||
|
CALLGRIND_STOP_INSTRUMENTATION;
|
||||||
|
assert(_enabled);
|
||||||
|
_enabled = false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ircd::prof::vg::start()
|
||||||
|
noexcept
|
||||||
|
{
|
||||||
|
#ifdef HAVE_VALGRIND_CALLGRIND_H
|
||||||
|
assert(!_enabled);
|
||||||
|
_enabled = true;
|
||||||
|
CALLGRIND_START_INSTRUMENTATION;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ircd::prof::vg::reset()
|
||||||
|
{
|
||||||
|
#ifdef HAVE_VALGRIND_CALLGRIND_H
|
||||||
|
CALLGRIND_ZERO_STATS;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ircd::prof::vg::toggle()
|
||||||
|
{
|
||||||
|
#ifdef HAVE_VALGRIND_CALLGRIND_H
|
||||||
|
CALLGRIND_TOGGLE_COLLECT;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ircd::prof::vg::dump(const char *const reason)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_VALGRIND_CALLGRIND_H
|
||||||
|
CALLGRIND_DUMP_STATS_AT(reason);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ircd::prof::vg::enabled()
|
||||||
|
{
|
||||||
|
return _enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// syscall_timer
|
||||||
|
//
|
||||||
|
|
||||||
|
ircd::prof::syscall_timer::syscall_timer()
|
||||||
|
noexcept
|
||||||
|
:started
|
||||||
|
{
|
||||||
|
time_kern()
|
||||||
|
}
|
||||||
|
,stopped
|
||||||
|
{
|
||||||
|
0UL
|
||||||
|
}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
ircd::prof::syscall_timer::sample()
|
||||||
|
{
|
||||||
|
stopped = time_kern();
|
||||||
|
return at();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
ircd::prof::syscall_timer::at()
|
||||||
|
const
|
||||||
|
{
|
||||||
|
return stopped - started;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// time_*() suite
|
||||||
|
//
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
ircd::prof::time_thrd()
|
||||||
|
{
|
||||||
|
struct ::timespec tv;
|
||||||
|
syscall(::clock_gettime, CLOCK_THREAD_CPUTIME_ID, &tv);
|
||||||
|
return ulong(tv.tv_sec) * 1000000000UL + tv.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
ircd::prof::time_proc()
|
||||||
|
{
|
||||||
|
struct ::timespec tv;
|
||||||
|
syscall(::clock_gettime, CLOCK_PROCESS_CPUTIME_ID, &tv);
|
||||||
|
return ulong(tv.tv_sec) * 1000000000UL + tv.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Interface (cross-platform)
|
||||||
|
//
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
ircd::prof::time_real()
|
||||||
|
{
|
||||||
|
return boost::chrono::process_real_cpu_clock::now().time_since_epoch().count();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
ircd::prof::time_kern()
|
||||||
|
{
|
||||||
|
return boost::chrono::process_system_cpu_clock::now().time_since_epoch().count();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
ircd::prof::time_user()
|
||||||
|
{
|
||||||
|
return boost::chrono::process_user_cpu_clock::now().time_since_epoch().count();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// times
|
||||||
|
//
|
||||||
|
|
||||||
|
ircd::prof::times::times(sample_t)
|
||||||
|
:real{}
|
||||||
|
,kern{}
|
||||||
|
,user{}
|
||||||
|
{
|
||||||
|
const auto tp
|
||||||
|
{
|
||||||
|
boost::chrono::process_cpu_clock::now()
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto d
|
||||||
|
{
|
||||||
|
tp.time_since_epoch()
|
||||||
|
};
|
||||||
|
|
||||||
|
this->real = d.count().real;
|
||||||
|
this->kern = d.count().system;
|
||||||
|
this->user = d.count().user;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// resource
|
// resource
|
||||||
//
|
//
|
||||||
|
@ -730,115 +925,3 @@ ircd::prof::debug(std::ostream &s,
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Interface
|
|
||||||
//
|
|
||||||
|
|
||||||
uint64_t
|
|
||||||
ircd::prof::time_thrd()
|
|
||||||
{
|
|
||||||
struct ::timespec tv;
|
|
||||||
syscall(::clock_gettime, CLOCK_THREAD_CPUTIME_ID, &tv);
|
|
||||||
return ulong(tv.tv_sec) * 1000000000UL + tv.tv_nsec;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t
|
|
||||||
ircd::prof::time_proc()
|
|
||||||
{
|
|
||||||
struct ::timespec tv;
|
|
||||||
syscall(::clock_gettime, CLOCK_PROCESS_CPUTIME_ID, &tv);
|
|
||||||
return ulong(tv.tv_sec) * 1000000000UL + tv.tv_nsec;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Interface (cross-platform)
|
|
||||||
//
|
|
||||||
|
|
||||||
uint64_t
|
|
||||||
ircd::prof::time_real()
|
|
||||||
{
|
|
||||||
return boost::chrono::process_real_cpu_clock::now().time_since_epoch().count();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t
|
|
||||||
ircd::prof::time_kern()
|
|
||||||
{
|
|
||||||
return boost::chrono::process_system_cpu_clock::now().time_since_epoch().count();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t
|
|
||||||
ircd::prof::time_user()
|
|
||||||
{
|
|
||||||
return boost::chrono::process_user_cpu_clock::now().time_since_epoch().count();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// prof::vg
|
|
||||||
//
|
|
||||||
|
|
||||||
void
|
|
||||||
ircd::prof::vg::stop()
|
|
||||||
noexcept
|
|
||||||
{
|
|
||||||
#ifdef HAVE_VALGRIND_CALLGRIND_H
|
|
||||||
CALLGRIND_STOP_INSTRUMENTATION;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ircd::prof::vg::start()
|
|
||||||
noexcept
|
|
||||||
{
|
|
||||||
#ifdef HAVE_VALGRIND_CALLGRIND_H
|
|
||||||
CALLGRIND_START_INSTRUMENTATION;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ircd::prof::vg::reset()
|
|
||||||
{
|
|
||||||
#ifdef HAVE_VALGRIND_CALLGRIND_H
|
|
||||||
CALLGRIND_ZERO_STATS;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ircd::prof::vg::toggle()
|
|
||||||
{
|
|
||||||
#ifdef HAVE_VALGRIND_CALLGRIND_H
|
|
||||||
CALLGRIND_TOGGLE_COLLECT;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ircd::prof::vg::dump(const char *const reason)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_VALGRIND_CALLGRIND_H
|
|
||||||
CALLGRIND_DUMP_STATS_AT(reason);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// times
|
|
||||||
//
|
|
||||||
|
|
||||||
ircd::prof::times::times(sample_t)
|
|
||||||
:real{}
|
|
||||||
,kern{}
|
|
||||||
,user{}
|
|
||||||
{
|
|
||||||
const auto tp
|
|
||||||
{
|
|
||||||
boost::chrono::process_cpu_clock::now()
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto d
|
|
||||||
{
|
|
||||||
tp.time_since_epoch()
|
|
||||||
};
|
|
||||||
|
|
||||||
this->real = d.count().real;
|
|
||||||
this->kern = d.count().system;
|
|
||||||
this->user = d.count().user;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue