ircd::ios: Split headers into directory; minor reorg.

ircd::ios: Move profile constexprs into namespace.
This commit is contained in:
Jason Volk 2020-12-12 16:07:42 -08:00
parent befe5ac750
commit 9ca664d231
9 changed files with 507 additions and 447 deletions

View File

@ -351,7 +351,7 @@ noexcept try
{
ios.run_one();
if constexpr(ircd::ios::profile_logging)
if constexpr(ircd::ios::profile::logging)
ircd::log::logf
{
ircd::ios::log, ircd::log::DEBUG,

View File

@ -1,390 +0,0 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#pragma once
#define HAVE_IRCD_IOS_H
// Boost headers are not exposed to our users unless explicitly included by a
// definition file. Other libircd headers may extend this namespace with more
// forward declarations.
/// Forward declarations for boost::asio because it is not included here.
namespace boost::asio
{
struct executor;
struct io_context;
template<class function>
void asio_handler_invoke(function&, ...);
}
namespace ircd
{
namespace asio = boost::asio; ///< Alias so that asio:: can be used.
extern const info::versions boost_version_api, boost_version_abi;
}
namespace ircd::ios
{
struct handler;
struct descriptor;
template<class function> struct handle;
IRCD_OVERLOAD(synchronous)
struct dispatch;
struct defer;
struct post;
constexpr bool profile_history {false};
constexpr bool profile_logging {false};
extern log::log log;
extern std::thread::id main_thread_id;
extern asio::executor user;
extern asio::executor main;
const string_view &name(const descriptor &);
const string_view &name(const handler &);
bool available() noexcept;
const uint64_t &epoch() noexcept;
void forked_parent();
void forked_child();
void forking();
void init(asio::executor &&);
}
namespace ircd
{
using ios::dispatch;
using ios::defer;
using ios::post;
}
struct ircd::ios::dispatch
{
dispatch(descriptor &, std::function<void ()>);
dispatch(descriptor &, synchronous_t, const std::function<void ()> &);
dispatch(descriptor &, synchronous_t);
dispatch(std::function<void ()>);
dispatch(synchronous_t, const std::function<void ()> &);
};
struct ircd::ios::defer
{
defer(descriptor &, std::function<void ()>);
defer(descriptor &, synchronous_t, const std::function<void ()> &);
defer(descriptor &, synchronous_t);
defer(std::function<void ()>);
defer(synchronous_t, const std::function<void ()> &);
};
struct ircd::ios::post
{
post(descriptor &, std::function<void ()>);
post(descriptor &, synchronous_t, const std::function<void ()> &);
post(descriptor &, synchronous_t);
post(std::function<void ()>);
post(synchronous_t, const std::function<void ()> &);
};
struct ircd::ios::descriptor
:instance_list<descriptor>
{
struct stats;
static uint64_t ids;
static void *default_allocator(handler &, const size_t &);
static void default_deallocator(handler &, void *const &, const size_t &) noexcept;
string_view name;
uint64_t id {++ids};
std::unique_ptr<struct stats> stats;
void *(*allocator)(handler &, const size_t &);
void (*deallocator)(handler &, void *const &, const size_t &);
std::vector<std::array<uint64_t, 2>> history; // epoch, cycles
uint8_t history_pos {0};
bool continuation {false};
descriptor(const string_view &name,
const decltype(allocator) & = default_allocator,
const decltype(deallocator) & = default_deallocator,
const bool &continuation = false) noexcept;
descriptor(descriptor &&) = delete;
descriptor(const descriptor &) = delete;
~descriptor() noexcept;
};
struct ircd::ios::descriptor::stats
{
uint64_t queued {0};
uint64_t calls {0};
uint64_t faults {0};
uint64_t allocs {0};
uint64_t alloc_bytes{0};
uint64_t frees {0};
uint64_t free_bytes{0};
uint64_t slice_total {0};
uint64_t slice_last {0};
uint64_t latency_total {0};
uint64_t latency_last {0};
stats &operator+=(const stats &) &;
stats();
~stats() noexcept;
};
struct ircd::ios::handler
{
static thread_local handler *current;
static thread_local uint64_t epoch;
static void enqueue(handler *const &) noexcept;
static void *allocate(handler *const &, const size_t &);
static void deallocate(handler *const &, void *const &, const size_t &) noexcept;
static bool continuation(handler *const &) noexcept;
static void enter(handler *const &) noexcept;
static void leave(handler *const &) noexcept;
static bool fault(handler *const &) noexcept;
ios::descriptor *descriptor {nullptr};
uint64_t ts {0}; // last tsc sample; for profiling each phase
};
template<class function>
struct ircd::ios::handle
:handler
{
function f;
template<class... args>
void operator()(args&&... a) const;
handle(ios::descriptor &, function) noexcept;
};
// boost handlers
namespace ircd::ios
{
template<class function>
void asio_handler_deallocate(void *, size_t, handle<function> *);
template<class function>
void *asio_handler_allocate(size_t, handle<function> *);
template<class function>
bool asio_handler_is_continuation(handle<function> *);
template<class callable,
class function>
void asio_handler_invoke(callable &f, handle<function> *);
}
template<class callable,
class function>
inline void
ircd::ios::asio_handler_invoke(callable &f,
handle<function> *const h)
try
{
handler::enter(h);
boost::asio::asio_handler_invoke(f, &h);
handler::leave(h);
}
catch(...)
{
if(handler::fault(h))
handler::leave(h);
else
throw;
}
template<class function>
inline bool
ircd::ios::asio_handler_is_continuation(handle<function> *const h)
{
return handler::continuation(h);
}
template<class function>
inline void *
__attribute__((malloc, returns_nonnull, warn_unused_result, alloc_size(1)))
ircd::ios::asio_handler_allocate(size_t size,
handle<function> *const h)
{
return handler::allocate(h, size);
}
template<class function>
inline void
ircd::ios::asio_handler_deallocate(void *const ptr,
size_t size,
handle<function> *const h)
{
handler::deallocate(h, ptr, size);
}
//
// ircd::ios::handle
//
template<class function>
inline
ircd::ios::handle<function>::handle(ios::descriptor &d,
function f)
noexcept
:handler{&d, prof::cycles()}
,f(std::move(f))
{
handler::enqueue(this);
}
template<class function>
template<class... args>
inline void
ircd::ios::handle<function>::operator()(args&&... a)
const
{
assert(descriptor && descriptor->stats);
assert(descriptor->stats->queued > 0);
descriptor->stats->queued--;
f(std::forward<args>(a)...);
}
//
// ircd::ios::handler
//
[[gnu::hot]]
inline void
ircd::ios::handler::deallocate(handler *const &handler,
void *const &ptr,
const size_t &size)
noexcept
{
assert(handler && handler->descriptor);
auto &descriptor(*handler->descriptor);
assert(descriptor.deallocator);
descriptor.deallocator(*handler, ptr, size);
assert(descriptor.stats);
auto &stats(*descriptor.stats);
stats.free_bytes += size;
++stats.frees;
}
[[gnu::hot]]
inline void *
ircd::ios::handler::allocate(handler *const &handler,
const size_t &size)
{
assert(handler && handler->descriptor);
auto &descriptor(*handler->descriptor);
assert(descriptor.stats);
auto &stats(*descriptor.stats);
stats.alloc_bytes += size;
++stats.allocs;
assert(descriptor.allocator);
return descriptor.allocator(*handler, size);
}
[[gnu::hot]]
inline void
ircd::ios::handler::enqueue(handler *const &handler)
noexcept
{
assert(handler && handler->descriptor);
auto &descriptor(*handler->descriptor);
assert(descriptor.stats);
auto &stats(*descriptor.stats);
++stats.queued;
if constexpr(profile_logging)
log::logf
{
log, log::level::DEBUG,
"QUEUE %5u %-30s [%11lu] ------[%9lu] q:%-4lu",
descriptor.id,
trunc(descriptor.name, 30),
stats.calls,
0UL,
stats.queued,
};
}
[[gnu::hot]]
inline bool
ircd::ios::handler::continuation(handler *const &handler)
noexcept
{
assert(handler && handler->descriptor);
auto &descriptor(*handler->descriptor);
return descriptor.continuation;
}
//
// ios::descriptor
//
[[gnu::hot]]
inline void
ircd::ios::descriptor::default_deallocator(handler &handler,
void *const &ptr,
const size_t &size)
noexcept
{
#ifdef __clang__
::operator delete(ptr);
#else
::operator delete(ptr, size);
#endif
}
[[gnu::hot]]
inline void *
ircd::ios::descriptor::default_allocator(handler &handler,
const size_t &size)
{
return ::operator new(size);
}
//
// ircd::ios
//
inline const ircd::string_view &
ircd::ios::name(const handler &handler)
{
assert(handler.descriptor);
return name(*handler.descriptor);
}
inline const ircd::string_view &
ircd::ios::name(const descriptor &descriptor)
{
return descriptor.name;
}
inline const uint64_t &
__attribute__((always_inline))
ircd::ios::epoch()
noexcept
{
return handler::epoch;
}

81
include/ircd/ios/asio.h Normal file
View File

@ -0,0 +1,81 @@
// The Construct
//
// Copyright (C) The Construct Developers, Authors & Contributors
// Copyright (C) 2016-2020 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#pragma once
#define HAVE_IRCD_IOS_ASIO_H
/// Forward declarations for boost::asio because it is not included here.
namespace boost::asio
{
struct io_context;
template<class function>
void asio_handler_invoke(function&, ...);
}
namespace ircd::ios
{
template<class function>
void asio_handler_deallocate(void *, size_t, handle<function> *);
template<class function>
void *asio_handler_allocate(size_t, handle<function> *);
template<class function>
bool asio_handler_is_continuation(handle<function> *);
template<class callable,
class function>
void asio_handler_invoke(callable &f, handle<function> *);
}
template<class callable,
class function>
inline void
ircd::ios::asio_handler_invoke(callable &f,
handle<function> *const h)
try
{
handler::enter(h);
boost::asio::asio_handler_invoke(f, &h);
handler::leave(h);
}
catch(...)
{
if(handler::fault(h))
handler::leave(h);
else
throw;
}
template<class function>
inline bool
ircd::ios::asio_handler_is_continuation(handle<function> *const h)
{
return handler::continuation(h);
}
template<class function>
inline void *
__attribute__((malloc, returns_nonnull, warn_unused_result, alloc_size(1)))
ircd::ios::asio_handler_allocate(size_t size,
handle<function> *const h)
{
return handler::allocate(h, size);
}
template<class function>
inline void
ircd::ios::asio_handler_deallocate(void *const ptr,
size_t size,
handle<function> *const h)
{
handler::deallocate(h, ptr, size);
}

View File

@ -0,0 +1,97 @@
// The Construct
//
// Copyright (C) The Construct Developers, Authors & Contributors
// Copyright (C) 2016-2020 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#pragma once
#define HAVE_IRCD_IOS_DESCRIPTOR_H
namespace ircd::ios
{
struct handler;
struct descriptor;
const string_view &name(const descriptor &);
}
struct ircd::ios::descriptor
:instance_list<descriptor>
{
struct stats;
static uint64_t ids;
static void *default_allocator(handler &, const size_t &);
static void default_deallocator(handler &, void *const &, const size_t &) noexcept;
string_view name;
uint64_t id {++ids};
std::unique_ptr<struct stats> stats;
void *(*allocator)(handler &, const size_t &);
void (*deallocator)(handler &, void *const &, const size_t &);
std::vector<std::array<uint64_t, 2>> history; // epoch, cycles
uint8_t history_pos {0};
bool continuation {false};
descriptor(const string_view &name,
const decltype(allocator) & = default_allocator,
const decltype(deallocator) & = default_deallocator,
const bool &continuation = false) noexcept;
descriptor(descriptor &&) = delete;
descriptor(const descriptor &) = delete;
~descriptor() noexcept;
};
struct ircd::ios::descriptor::stats
{
uint64_t queued {0};
uint64_t calls {0};
uint64_t faults {0};
uint64_t allocs {0};
uint64_t alloc_bytes{0};
uint64_t frees {0};
uint64_t free_bytes{0};
uint64_t slice_total {0};
uint64_t slice_last {0};
uint64_t latency_total {0};
uint64_t latency_last {0};
stats &operator+=(const stats &) &;
stats();
~stats() noexcept;
};
[[gnu::hot]]
inline void
ircd::ios::descriptor::default_deallocator(handler &handler,
void *const &ptr,
const size_t &size)
noexcept
{
#ifdef __clang__
::operator delete(ptr);
#else
::operator delete(ptr, size);
#endif
}
[[gnu::hot]]
inline void *
ircd::ios::descriptor::default_allocator(handler &handler,
const size_t &size)
{
return ::operator new(size);
}
inline const ircd::string_view &
ircd::ios::name(const descriptor &descriptor)
{
return descriptor.name;
}

View File

@ -0,0 +1,55 @@
// The Construct
//
// Copyright (C) The Construct Developers, Authors & Contributors
// Copyright (C) 2016-2020 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#pragma once
#define HAVE_IRCD_IOS_DISPATCH_H
namespace ircd::ios
{
IRCD_OVERLOAD(synchronous)
struct dispatch;
struct defer;
struct post;
}
namespace ircd
{
using ios::dispatch;
using ios::defer;
using ios::post;
}
struct ircd::ios::dispatch
{
dispatch(descriptor &, std::function<void ()>);
dispatch(descriptor &, synchronous_t, const std::function<void ()> &);
dispatch(descriptor &, synchronous_t);
dispatch(std::function<void ()>);
dispatch(synchronous_t, const std::function<void ()> &);
};
struct ircd::ios::defer
{
defer(descriptor &, std::function<void ()>);
defer(descriptor &, synchronous_t, const std::function<void ()> &);
defer(descriptor &, synchronous_t);
defer(std::function<void ()>);
defer(synchronous_t, const std::function<void ()> &);
};
struct ircd::ios::post
{
post(descriptor &, std::function<void ()>);
post(descriptor &, synchronous_t, const std::function<void ()> &);
post(descriptor &, synchronous_t);
post(std::function<void ()>);
post(synchronous_t, const std::function<void ()> &);
};

160
include/ircd/ios/handler.h Normal file
View File

@ -0,0 +1,160 @@
// The Construct
//
// Copyright (C) The Construct Developers, Authors & Contributors
// Copyright (C) 2016-2020 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#pragma once
#define HAVE_IRCD_IOS_HANDLER_H
namespace ircd::ios
{
struct handler;
template<class function>
struct handle;
const string_view &name(const handler &);
}
struct ircd::ios::handler
{
static thread_local handler *current;
static thread_local uint64_t epoch;
static void enqueue(handler *const &) noexcept;
static void *allocate(handler *const &, const size_t &);
static void deallocate(handler *const &, void *const &, const size_t &) noexcept;
static bool continuation(handler *const &) noexcept;
static void enter(handler *const &) noexcept;
static void leave(handler *const &) noexcept;
static bool fault(handler *const &) noexcept;
ios::descriptor *descriptor {nullptr};
uint64_t ts {0}; // last tsc sample; for profiling each phase
};
template<class function>
struct ircd::ios::handle
:handler
{
function f;
template<class... args>
void operator()(args&&... a) const;
handle(ios::descriptor &, function) noexcept;
};
//
// ircd::ios::handle
//
template<class function>
inline
ircd::ios::handle<function>::handle(ios::descriptor &d,
function f)
noexcept
:handler{&d, prof::cycles()}
,f(std::move(f))
{
handler::enqueue(this);
}
template<class function>
template<class... args>
inline void
ircd::ios::handle<function>::operator()(args&&... a)
const
{
assert(descriptor && descriptor->stats);
assert(descriptor->stats->queued > 0);
descriptor->stats->queued--;
f(std::forward<args>(a)...);
}
//
// ircd::ios::handler
//
[[gnu::hot]]
inline void
ircd::ios::handler::deallocate(handler *const &handler,
void *const &ptr,
const size_t &size)
noexcept
{
assert(handler && handler->descriptor);
auto &descriptor(*handler->descriptor);
assert(descriptor.deallocator);
descriptor.deallocator(*handler, ptr, size);
assert(descriptor.stats);
auto &stats(*descriptor.stats);
stats.free_bytes += size;
++stats.frees;
}
[[gnu::hot]]
inline void *
ircd::ios::handler::allocate(handler *const &handler,
const size_t &size)
{
assert(handler && handler->descriptor);
auto &descriptor(*handler->descriptor);
assert(descriptor.stats);
auto &stats(*descriptor.stats);
stats.alloc_bytes += size;
++stats.allocs;
assert(descriptor.allocator);
return descriptor.allocator(*handler, size);
}
[[gnu::hot]]
inline void
ircd::ios::handler::enqueue(handler *const &handler)
noexcept
{
assert(handler && handler->descriptor);
auto &descriptor(*handler->descriptor);
assert(descriptor.stats);
auto &stats(*descriptor.stats);
++stats.queued;
if constexpr(profile::logging)
log::logf
{
log, log::level::DEBUG,
"QUEUE %5u %-30s [%11lu] ------[%9lu] q:%-4lu",
descriptor.id,
trunc(descriptor.name, 30),
stats.calls,
0UL,
stats.queued,
};
}
[[gnu::hot]]
inline bool
ircd::ios::handler::continuation(handler *const &handler)
noexcept
{
assert(handler && handler->descriptor);
auto &descriptor(*handler->descriptor);
return descriptor.continuation;
}
inline const ircd::string_view &
ircd::ios::name(const handler &handler)
{
assert(handler.descriptor);
return name(*handler.descriptor);
}

60
include/ircd/ios/ios.h Normal file
View File

@ -0,0 +1,60 @@
// The Construct
//
// Copyright (C) The Construct Developers, Authors & Contributors
// Copyright (C) 2016-2020 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#pragma once
#define HAVE_IRCD_IOS_IOS_H
/// Forward declarations for boost::asio because it is not included here.
namespace boost::asio
{
struct executor;
}
namespace ircd
{
namespace asio = boost::asio; ///< Alias so that asio:: can be used.
extern const info::versions boost_version_api, boost_version_abi;
}
namespace ircd::ios
{
extern log::log log;
extern asio::executor user, main;
extern std::thread::id main_thread_id;
bool available() noexcept;
const uint64_t &epoch() noexcept;
void forked_parent();
void forked_child();
void forking();
void init(asio::executor &&);
}
namespace ircd::ios::profile
{
constexpr bool history {false};
constexpr bool logging {false};
}
#include "descriptor.h"
#include "handler.h"
#include "asio.h"
#include "dispatch.h"
inline const uint64_t &
__attribute__((always_inline))
ircd::ios::epoch()
noexcept
{
return handler::epoch;
}

View File

@ -93,7 +93,7 @@
#include "stats.h"
#include "prof/prof.h"
#include "fs/fs.h"
#include "ios.h"
#include "ios/ios.h"
#include "ctx/ctx.h"
#include "exec.h"
#include "db/db.h"

View File

@ -44,10 +44,6 @@ ircd::boost_version_abi
"boost", info::versions::ABI //TODO: get this
};
//
// init
//
void
ircd::ios::init(asio::executor &&user)
{
@ -64,6 +60,43 @@ ircd::ios::init(asio::executor &&user)
ios::main = ios::user;
}
void
ircd::ios::forking()
{
#if BOOST_VERSION >= 107000
get().context().notify_fork(asio::execution_context::fork_prepare);
#else
get().notify_fork(asio::execution_context::fork_prepare);
#endif
}
void
ircd::ios::forked_child()
{
#if BOOST_VERSION >= 107000
get().context().notify_fork(asio::execution_context::fork_child);
#else
get().notify_fork(asio::execution_context::fork_child);
#endif
}
void
ircd::ios::forked_parent()
{
#if BOOST_VERSION >= 107000
get().context().notify_fork(asio::execution_context::fork_parent);
#else
get().notify_fork(asio::execution_context::fork_parent);
#endif
}
bool
ircd::ios::available()
noexcept
{
return bool(main);
}
//
// descriptor
//
@ -191,7 +224,7 @@ noexcept
false
};
if constexpr(profile_logging)
if constexpr(profile::logging)
log::logf
{
log, log::level::DEBUG,
@ -233,7 +266,7 @@ noexcept
stats.slice_last = handler->ts - slice_start;
stats.slice_total += stats.slice_last;
if constexpr(profile_history)
if constexpr(profile::history)
{
assert(descriptor.history_pos < descriptor.history.size());
descriptor.history[descriptor.history_pos][0] = handler::epoch;
@ -241,7 +274,7 @@ noexcept
++descriptor.history_pos;
}
if constexpr(profile_logging)
if constexpr(profile::logging)
log::logf
{
log, log::level::DEBUG,
@ -281,7 +314,7 @@ noexcept
stats.latency_last = handler->ts - last_ts;
stats.latency_total += stats.latency_last;
if constexpr(profile_logging)
if constexpr(profile::logging)
log::logf
{
log, log::level::DEBUG,
@ -295,50 +328,14 @@ noexcept
}
//
// ios.h
// dispatch
//
namespace ircd::ios
{
extern descriptor post_desc;
extern descriptor defer_desc;
extern descriptor dispatch_desc;
}
void
ircd::ios::forking()
{
#if BOOST_VERSION >= 107000
get().context().notify_fork(asio::execution_context::fork_prepare);
#else
get().notify_fork(asio::execution_context::fork_prepare);
#endif
}
void
ircd::ios::forked_child()
{
#if BOOST_VERSION >= 107000
get().context().notify_fork(asio::execution_context::fork_child);
#else
get().notify_fork(asio::execution_context::fork_child);
#endif
}
void
ircd::ios::forked_parent()
{
#if BOOST_VERSION >= 107000
get().context().notify_fork(asio::execution_context::fork_parent);
#else
get().notify_fork(asio::execution_context::fork_parent);
#endif
}
//
// dispatch
//
decltype(ircd::ios::dispatch_desc)
ircd::ios::dispatch_desc
{
@ -405,13 +402,15 @@ ircd::ios::dispatch::dispatch(descriptor &descriptor,
// defer
//
namespace ircd::ios
{
extern descriptor defer_desc;
}
decltype(ircd::ios::defer_desc)
ircd::ios::defer_desc
{
"ircd::ios defer",
descriptor::default_allocator,
descriptor::default_deallocator,
true, // continuation
};
[[gnu::hot]]
@ -474,6 +473,11 @@ ircd::ios::defer::defer(descriptor &descriptor,
// post
//
namespace ircd::ios
{
extern descriptor post_desc;
}
decltype(ircd::ios::post_desc)
ircd::ios::post_desc
{
@ -535,10 +539,3 @@ ircd::ios::post::post(descriptor &descriptor,
{
boost::asio::post(get(), handle(descriptor, std::move(function)));
}
bool
ircd::ios::available()
noexcept
{
return bool(main);
}