diff --git a/src/timer-ns.cpp b/src/timer-ns.cpp index b467ce19..1f927f14 100644 --- a/src/timer-ns.cpp +++ b/src/timer-ns.cpp @@ -8,27 +8,61 @@ namespace floormat { -Debug& operator<<(Debug& dbg, const Ns& box) +Debug& operator<<(Debug& dbg, const Ns& val) { - const auto value = (float)((double)box.stamp * 1e-6); - const auto absval = Math::abs(value); + const char* unit; + double x = val.stamp; int precision; - if (absval < 2) - precision = 4; - else if (absval < 5) - precision = 2; - else if (absval < 100) + if (val >= 10*Second) + { + unit = "s"; + x *= 1e-9; precision = 1; + } +#if 0 + else if (val >= 1*Second) + { + unit = "ms"; + x *= 1e-6; + precision = 3; + + } +#endif + else if (val >= 100*Millisecond) + { + unit = "ms"; + x *= 1e-6; + precision = 3; + } + else if (val >= 50*Microsecond) + { + unit = "ms"; + x *= 1e-6; + precision = 4; + } + else if (val >= 1*Microsecond) + { + unit = "usec"; + x *= 1e-3; + precision = 3; + } + else if (val.stamp > 1000) + { + char buf[64]; + std::snprintf(buf, sizeof buf, "%llu_%llu ns", + val.stamp / 1000, val.stamp % 1000); + return dbg; + } else + { + unit = "ns"; precision = 0; - auto flags = dbg.flags(); - dbg << ""; - dbg.setFlags(flags | Debug::Flag::NoSpace); - //dbg << "{"; - dbg << fraction(value, precision); - dbg << " ms"; - //dbg << "}"; - dbg.setFlags(flags); + } + if (!precision) + dbg << (uint64_t)x << Debug::space << unit; + else + dbg << fraction((float)x, precision) << Debug::space << unit; + return dbg; } diff --git a/src/timer.hpp b/src/timer.hpp index 6e9bd651..36874e9e 100644 --- a/src/timer.hpp +++ b/src/timer.hpp @@ -60,18 +60,6 @@ struct Ns return Ns{(uint64_t)x}; } -#if 0 - template - requires (std::is_same_v) - static Ns from_nonzero(T seconds) - { - constexpr double max{uint64_t{1} << 53}; - fm_assert(seconds >= 0); - fm_assert(seconds <= max); - return Ns((uint64_t)seconds); - } -#endif - friend constexpr Ns operator+(const Ns& lhs, const Ns& rhs) { constexpr auto max = (uint64_t)-1; @@ -144,6 +132,19 @@ struct Ns return Ns{a / b}; } +#if 0 + template + requires std::is_floating_point_v + friend constexpr double operator/(const Ns& lhs, double b) + { + fm_assert(b != 0.); + auto x = double{lhs.stamp / b}; + constexpr auto max = double{uint64_t{1} << 53}; + fm_assert(x <= max); + return x; + } +#endif + friend constexpr uint64_t operator%(const Ns& lhs, const Ns& rhs) { auto a = lhs.stamp, b = rhs.stamp; diff --git a/test/critter.cpp b/test/critter.cpp index 9488d418..934ebe1d 100644 --- a/test/critter.cpp +++ b/test/critter.cpp @@ -52,13 +52,20 @@ struct Start { StringView name, instance; point pt; - float accel = 1; + double accel = 1; enum rotation rotation = N; - bool verbose = is_log_verbose(); -#if 0 +#if 1 + bool quiet = is_log_quiet() || is_log_standard(); + bool verbose = false; +#elif 0 + bool verbose = true; + bool quiet = false; +#elif 0 bool quiet = is_log_quiet(); + bool verbose = is_log_standard() || is_log_verbose(); #else - bool quiet = !is_log_verbose(); + bool quiet = is_log_quiet() || is_log_standard(); + bool verbose = is_log_verbose(); #endif }; @@ -70,33 +77,35 @@ struct Expected struct Grace { - Ns max_time = 600*Seconds; + Ns time = Ns{250}; uint32_t distance_L2 = 24; - uint32_t max_steps = 10'000; bool no_crash = false; }; -bool run(StringView subtest_name, world& w, const function_view& make_dt, +bool run(world& w, const function_view& make_dt, Start start, Expected expected, Grace grace = {}) { + constexpr auto max_time = 120*Second; + constexpr uint32_t max_steps = 10'000; + + fm_assert(grace.time != Ns{}); fm_assert(!start.quiet | !start.verbose); //validate_start(start); //validate_expected(expected); //validate_grace(grace); + fm_assert(start.accel > 1e-8); + fm_assert(start.accel <= 50); fm_assert(start.name); fm_assert(start.instance); fm_assert(start.rotation < rotation_COUNT); - fm_assert(expected.time <= grace.max_time); - fm_assert(grace.max_time <= 10*Minutes); - fm_assert(grace.max_time > Ns{}); + expected.time.stamp = uint64_t(expected.time.stamp / start.accel); + fm_assert(expected.time <= max_time); fm_assert(grace.distance_L2 <= (uint32_t)Vector2((iTILE_SIZE2 * TILE_MAX_DIM)).length()); - fm_assert(grace.max_steps > 0); - fm_assert(grace.max_steps <= 1000'00); mark_all_modified(w); object_id id = 0; - auto npc_ = w.ensure_player_character(id, make_proto(start.accel)).ptr; + auto npc_ = w.ensure_player_character(id, make_proto((float)start.accel)).ptr; auto& npc = *npc_; auto index = npc.index(); @@ -107,12 +116,7 @@ bool run(StringView subtest_name, world& w, const function_view& mak uint32_t i; if (!start.quiet) [[unlikely]] - { - if (subtest_name) - Debug{} << "**" << start.name << "->" << start.instance << Debug::nospace << subtest_name << colon(); - else - Debug{} << "**" << start.name << subtest_name << colon(); - } + Debug{} << "**" << start.name << start.instance << colon(); constexpr auto print_pos = [](StringView prefix, point start, point pos, Ns time, Ns dt) { DBG_nospace << prefix @@ -122,7 +126,7 @@ bool run(StringView subtest_name, world& w, const function_view& mak << " dist:" << point::distance_l2(pos, start); }; - for (i = 0; i <= grace.max_steps; i++) + for (i = 0; true; i++) { const auto dt = Ns{make_dt()}; if (dt == Ns{}) [[unlikely]] @@ -148,31 +152,32 @@ bool run(StringView subtest_name, world& w, const function_view& mak { print_pos("->", expected.pt, pos, time, dt); DBG_nospace << "===>" - << " iters" << colon(',') - << " time" << time + << " iters," + << " time:" << time + << " distance:" << point::distance_l2(last_pos, expected.pt) << " px" << Debug::newline; } if (i == 0) [[unlikely]] // todo! check for very small dt before dying { { auto dbg = Error{standard_error(), Debug::Flag::NoSpace}; - dbg << "!!! fatal: took zero iterations"; + dbg << "!!! fatal: stopped after zero iterations"; dbg << " dt=" << dt << " accel=" << npc.speed; } fm_assert(false); } break; } - if (time > grace.max_time) [[unlikely]] + if (time > max_time) [[unlikely]] { if (!start.quiet) [[unlikely]] print_pos("*", start.pt, last_pos, time, dt); - Error{standard_error()} << "!!! fatal: timeout" << grace.max_time << "reached!"; + Error{standard_error()} << "!!! fatal: timeout" << max_time << "reached!"; if (grace.no_crash) return false; else fm_assert(false); } - if (i > grace.max_steps) [[unlikely]] + if (i > max_steps) [[unlikely]] { print_pos("*", start.pt, last_pos, time, dt); Error{standard_error()} << "!!! fatal: position doesn't converge after" << i << "iterations!"; @@ -198,9 +203,13 @@ bool run(StringView subtest_name, world& w, const function_view& mak if (expected.time != Ns{}) { const auto time_diff = Ns{Math::abs((int64_t)expected.time.stamp - (int64_t)time.stamp)}; - if (time_diff > expected.time) + if (time_diff > grace.time) { - Error{standard_error()} << "!!! fatal: time" << time_diff << "over tolerance of" << grace.max_time; + Error{ standard_error(), Debug::Flag::NoSpace } + << "!!! fatal: wrong time " << time + << " expected:" << expected.time + << " diff:" << grace.time + << " for " << start.name << "/" << start.instance; if (grace.no_crash) return false; else @@ -219,7 +228,7 @@ void test1(StringView instance_name, const Function& make_dt, float accel) w[{{0,0,0}, {8,9}}].t.wall_north() = W; w[{{0,1,0}, {8,0}}].t.wall_north() = W; - bool ret = run("test1", w, make_dt, + bool ret = run(w, make_dt, Start{ .name = "test1"_s, .instance = instance_name, @@ -229,9 +238,11 @@ void test1(StringView instance_name, const Function& make_dt, float accel) }, Expected{ .pt = {{0,0,0}, {8, 9}, {-6,-15}}, // distance_L2 == 3 - .time = Millisecond*6950, + .time = 6950*Millisecond, }, - Grace{}); + Grace{ + .time = 300*Millisecond, + }); fm_assert(ret); } @@ -245,19 +256,22 @@ void test2(StringView instance_name, const Function& make_dt, float accel) w[{{1,1,0}, {4,5}}].t.wall_north() = W; w[{{1,1,0}, {5,4}}].t.wall_west() = W; - bool ret = run("test1", w, make_dt, + bool ret = run(w, make_dt, Start{ - .name = "test1"_s, + .name = "test2"_s, .instance = instance_name, - .pt = {{1,1,0}, {4,4}, {-29, 8}}, + .pt = {{-1,-1,0}, {13,14}, {-15,-29}}, .accel = accel, - .rotation = NW, + .rotation = SE, }, Expected{ - .pt = {{-1,-1,0}, {13, 13}, {-16,-16}}, // distance_L2 == 3 - .time = accel == 1 ? Ns{Millisecond*6900} : Ns{}, + .pt = {{1,1,0}, {4, 4}, {8,8}}, + .time = 35'000*Millisecond, }, - Grace{}); + Grace{ + .time = 250*Millisecond, + .distance_L2 = 8, + }); fm_assert(ret); } @@ -270,18 +284,35 @@ void test_app::test_critter() // [2K // \n - const bool is_noisy = Start{}.verbose; - + const bool is_noisy = !Start{}.quiet; if (is_noisy) DBG_nospace << ""; - test1("dt=1000 accel=1", constantly(Millisecond * 1000 ), 1); - test1("dt=1000 accel=5", constantly(Millisecond * 1000 ), 5); - test1("dt=100 accel=5", constantly(Millisecond * 100 ), 5); - test1("dt=50 accel=5", constantly(Millisecond * 50 ), 5); - test1("dt=16.667 accel=10", constantly(Millisecond * 16.667), 10); - test1("dt=16.667 accel=1", constantly(Millisecond * 16.667), 1); - //test1("dt=16.5 ms accel=1", constantly(Millisecond * 16.5), 1); // todo! fix this! - test2("dt=16.667 accel=5", constantly(Millisecond * 16.667), 5); + + test1("dt=16.667 accel=1", constantly(Millisecond * 16.667), 1); + test1("dt=16.667 accel=2", constantly(Millisecond * 16.667), 2); + test1("dt=16.667 accel=5", constantly(Millisecond * 16.667), 5); + test1("dt=33.337 accel=1", constantly(Millisecond * 33.337), 1); + test1("dt=33.337 accel=2", constantly(Millisecond * 33.337), 2); + test1("dt=33.337 accel=5", constantly(Millisecond * 33.337), 5); + test1("dt=16.667 accel=1", constantly(Millisecond * 50.000), 1); + test1("dt=16.667 accel=2", constantly(Millisecond * 50.000), 2); + test1("dt=16.667 accel=5", constantly(Millisecond * 50.000), 5); + test1("dt=200 accel=1", constantly(Millisecond * 200.0 ), 1); + test1("dt=100 accel=2", constantly(Millisecond * 100.0 ), 2); + // test1("dt=16.667 accel=0.5", constantly(Millisecond * 16.667),0.5); todo! fix this! + test1("dt=100 accel=0.5", constantly(Millisecond * 100.0), 0.5); + + //test1("dt=16.667 ms accel=1", constantly(Millisecond * 16.667), 1); // todo! fix this! + test2("dt=33.334 accel=1", constantly(Millisecond * 33.334), 1); + test2("dt=33.334 accel=2", constantly(Millisecond * 33.334), 2); + test2("dt=33.334 accel=5", constantly(Millisecond * 33.334), 5); + test2("dt=33.334 accel=10", constantly(Millisecond * 33.334), 10); + test2("dt=50.000 accel=1", constantly(Millisecond * 50.000), 1); + test2("dt=50.000 accel=2", constantly(Millisecond * 50.000), 2); + test2("dt=100.00 accel=1", constantly(Millisecond * 100.00), 1); + test2("dt=100.00 accel=2", constantly(Millisecond * 100.00), 2); + test2("dt=100.00 accel=0.5", constantly(Millisecond * 100.00), 0.5); + if (is_noisy) { std::fputc('\t', stdout);