Performance measurement of some aspects of Zth. On a MacBook Pro (2010), running the release build, it gives the following output:
#include <cmath>
void testEmpty() {}
void testNow()
{
}
void context2entry(void* )
{
while(true)
}
void testContextInit()
{
int res = 0;
}
void testContext()
{
}
void testContextCleanup()
{
}
void testYield1()
{
}
void testYield1Always()
{
}
void testYieldFiber()
{
while(true)
}
void testYieldInit()
{
}
void testYield()
{
}
void testYieldCleanup()
{
if(!testYieldFiberPtr)
testYieldFiberPtr->
kill();
}
void testFiberCreateEntry() {}
void testFiberCreate()
{
testFiberCreateEntry_future f =
async testFiberCreateEntry();
f->wait();
}
void testCurrentFiber()
{
}
void testNap0()
{
}
void testNap100ms()
{
}
{
if(s != s)
return "NaN";
if(s - s != s - s)
return s < 0 ? "-Inf" : "Inf";
if(s < 0)
res += "-";
else
res += " ";
double intpart = 0;
s = modf(fabs(s), &intpart);
for(int i = 0; i < 4; i++) {
if(i)
res += "'";
s = modf(s * 1000.0, &intpart);
}
res += " s";
return res;
}
namespace fsm {
class TestFsm : public Fsm {
public:
TestFsm(
zth::cow_string description,
void (*test)(),
double calibrationOffset = 0)
: m_description{std::move(description)}
, m_test{test}
, m_singleResult{calibrationOffset}
{}
size_t iterations() const
{
return (size_t)1U << m_calibration;
}
bool maxIterations() const
{
return iterations() > std::numeric_limits<size_t>::max() / 4U;
}
void calibrate()
{
for(size_t i = iterations() / 2U; i > 0; i--)
m_test();
m_calibration++;
}
void measure()
{
for(size_t i = iterations(); i > 0; i--)
m_test();
m_duration = dt();
}
void done()
{
m_singleResult += m_duration.s() / (double)iterations();
printf("%-50s: %s (2^%2u iterations, total %s)\n", m_description.c_str(),
preciseTime(m_singleResult).c_str(), (unsigned)m_calibration,
m_duration.str().c_str());
}
double result() const
{
return m_singleResult;
}
private:
void (*m_test)();
double m_singleResult;
size_t m_calibration{};
};
static constexpr
auto maxIterations =
guard(&TestFsm::maxIterations);
static constexpr
auto calibrate =
action(&TestFsm::calibrate);
static constexpr
auto measure =
action(&TestFsm::measure);
static constexpr
auto done =
action(&TestFsm::done);
static constexpr
auto transitions =
compile(
"calibrate" + timeout_ms<500> >>= "measure",
+ maxIterations >>= "measure",
calibrate ,
"measure" / measure >>= "done",
"done" / done
);
}
static void runTest(char const* set, char const* name, void (*test)(), bool calibrationRun = false)
{
static double calibration = 0;
if(calibrationRun)
calibration = 0;
fsm::TestFsm fsm{
zth::format(
"[%-10s] %s", set, name), test, calibration};
fsm::transitions.init(fsm);
fsm.run();
if(calibrationRun)
calibration = -fsm.result();
}
static void run_testset(char const* testset)
{
bool all = strcmp("all", testset) == 0;
char const* set = nullptr;
set = "now";
if(all || strcmp(set, testset) == 0) {
runTest(set, "Timestamp::now()", &testNow);
}
set = "context";
if(all || strcmp(set, testset) == 0) {
testContextInit();
runTest(set, "2 context_switch()s", &testContext);
testContextCleanup();
}
set = "yield";
if(all || strcmp(set, testset) == 0) {
runTest(set, "single-fiber yield()", &testYield1);
runTest(set, "single-fiber yield() always", &testYield1Always);
testYieldInit();
runTest(set, "yield() to fiber and back", &testYield);
testYieldCleanup();
}
set = "fiber";
if(all || strcmp(set, testset) == 0) {
runTest(set, "currentFiber()", &testCurrentFiber);
runTest(set, "create and cleanup fiber", &testFiberCreate);
}
set = "nap";
if(all || strcmp(set, testset) == 0) {
runTest(set, "nap(0)", &testNap0);
runTest(set, "nap(100 ms)", &testNap100ms);
}
}
{
runTest("calib", "calibration", &testEmpty, true);
runTest("calib", "empty test", &testEmpty);
if(argc <= 1)
run_testset("all");
else
for(int i = 1; i < argc; i++)
run_testset(argv[i]);
return 0;
}
Context * context() const noexcept
Convenient wrapper around struct timespec that contains a time interval.
Convenient wrapper around struct timespec that contains an absolute timestamp.
int main_fiber(int argc, char **argv)
void zth_logv(char const *fmt, va_list arg)
Prints the given printf()-like formatted string to stdout.
void nap(Timestamp const &sleepUntil)
Sleep until the given time stamp.
#define zth_fiber(...)
Prepare every given function to become a fiber by async.
void yield(Fiber *preferFiber=nullptr, bool alwaysYield=false, Timestamp const &now=Timestamp::now())
Allow a context switch.
Fiber & currentFiber() noexcept
Return the currently executing fiber.
#define async
Run a function as a new fiber.
constexpr auto guard(T &&g, char const *name=nullptr)
Create a guard from a function.
constexpr auto action(T &&a, char const *name=nullptr)
Create an action from a function.
constexpr auto stop
Action to return from Fsm::run().
constexpr auto compile(T &&... t)
Compile a transition description.
void abort(char const *fmt,...) noexcept
Aborts the process after printing the given printf() formatted message.
std::basic_string< char, std::char_traits< char >, Config::Allocator< char >::type > string
std::string type using Config::Allocator::type.
char const * banner() noexcept
Prints a banner line with version and configuration information.
void context_switch(Context *from, Context *to) noexcept
Perform context switch.
void context_destroy(Context *context) noexcept
Destroy and cleanup a context.
string err(int e)
Return a string like strerror() does, but as a zth::string.
int context_create(Context *&context, ContextAttr const &attr) noexcept
Create a context.
string format(char const *fmt,...)
Format like sprintf(), but save the result in an zth::string.