Commit 85dacab1 authored by Juho Snellman's avatar Juho Snellman

Add more unit tests specifically probing the special nature of wheel slot 0

parent 35bfedfa
...@@ -4,7 +4,37 @@ ...@@ -4,7 +4,37 @@
#include "../timer-wheel.h" #include "../timer-wheel.h"
void test_single_timer_no_hierarchy() { #define TEST(fun) \
do { \
if (fun()) { \
printf("[OK] %s\n", #fun); \
} else { \
ok = false; \
printf("[FAILED] %s\n", #fun); \
} \
} while (0)
#define EXPECT(expr) \
do { \
if (!(expr)) { \
printf("%s:%d: Expect failed: %s\n", \
__FILE__, __LINE__, #expr); \
return false; \
} \
} while (0)
#define EXPECT_INTEQ(actual, expect) \
do { \
if (expect != actual) { \
printf("%s:%d: Expect failed, wanted %d" \
" got %d\n", \
__FILE__, __LINE__, \
expect, actual); \
return false; \
} \
} while (0)
bool test_single_timer_no_hierarchy() {
typedef std::function<void()> Callback; typedef std::function<void()> Callback;
HierarchicalTimerWheel<Callback> timers; HierarchicalTimerWheel<Callback> timers;
int count = 0; int count = 0;
...@@ -12,61 +42,107 @@ void test_single_timer_no_hierarchy() { ...@@ -12,61 +42,107 @@ void test_single_timer_no_hierarchy() {
&timers); &timers);
timers.advance(10); timers.advance(10);
assert(count == 0); EXPECT_INTEQ(count, 0);
assert(!timer.active()); EXPECT(!timer.active());
timers.schedule(&timer, 5); timers.schedule(&timer, 5);
assert(timer.active()); EXPECT(timer.active());
timers.advance(10); timers.advance(10);
assert(count == 1); EXPECT_INTEQ(count, 1);
timers.advance(10); timers.advance(10);
assert(count == 1); EXPECT_INTEQ(count, 1);
timers.schedule(&timer, 5); timers.schedule(&timer, 5);
timers.advance(10); timers.advance(10);
assert(count == 2); EXPECT_INTEQ(count, 2);
timers.schedule(&timer, 5); timers.schedule(&timer, 5);
timer.cancel(); timer.cancel();
assert(!timer.active()); EXPECT(!timer.active());
timers.advance(10); timers.advance(10);
assert(count == 2); EXPECT_INTEQ(count, 2);
// Test wraparound // Test wraparound
timers.advance(250); timers.advance(250);
timers.schedule(&timer, 5); timers.schedule(&timer, 5);
timers.advance(10); timers.advance(10);
assert(count == 3); EXPECT_INTEQ(count, 3);
return true;
} }
void test_single_timer_hierarchy() { bool test_single_timer_hierarchy() {
typedef std::function<void()> Callback; typedef std::function<void()> Callback;
HierarchicalTimerWheel<Callback> timers; HierarchicalTimerWheel<Callback> timers;
int count = 0; int count = 0;
TimerEvent<Callback> timer([&count] () { ++count; }, TimerEvent<Callback> timer([&count] () { ++count; },
&timers); &timers);
timers.advance(10); EXPECT_INTEQ(count, 0);
assert(count == 0);
// Schedule timer one layer up. // Schedule timer one layer up (make sure timer ends up in slot 0 once
timers.schedule(&timer, 261); // promoted to the innermost wheel, since that's a special case).
timers.advance(260); timers.schedule(&timer, 256);
assert(count == 0); timers.advance(255);
EXPECT_INTEQ(count, 0);
timers.advance(1); timers.advance(1);
assert(count == 1); EXPECT_INTEQ(count, 1);
timers.schedule(&timer, 256*4); // Then schedule one that ends up in some other slot
timers.advance(256*4 - 1); timers.schedule(&timer, 257);
assert(count == 1); timers.advance(256);
EXPECT_INTEQ(count, 1);
timers.advance(1); timers.advance(1);
assert(count == 2); EXPECT_INTEQ(count, 2);
// Schedule multiple rotations ahead in time, to slot 0.
timers.schedule(&timer, 256*4 - 1);
timers.advance(256*4 - 2);
EXPECT_INTEQ(count, 2);
timers.advance(1);
EXPECT_INTEQ(count, 3);
// Schedule multiple rotations ahead in time, to non-0 slot. (Do this
// twice, once starting from slot 0, once starting from slot 5);
for (int i = 0; i < 2; ++i) {
timers.schedule(&timer, 256*4 + 5);
timers.advance(256*4 + 4);
EXPECT_INTEQ(count, 3 + i);
timers.advance(1);
EXPECT_INTEQ(count, 4 + i);
}
return true;
}
bool test_single_timer_random() {
typedef std::function<void()> Callback;
HierarchicalTimerWheel<Callback> timers;
int count = 0;
TimerEvent<Callback> timer([&count] () { ++count; },
&timers);
for (int i = 0; i < 10000; ++i) {
int len = rand() % 20;
int r = 1 + rand() % ( 1 << len);
timers.schedule(&timer, r);
timers.advance(r - 1);
EXPECT_INTEQ(count, i);
timers.advance(1);
EXPECT_INTEQ(count, i + 1);
}
return true;
} }
int main(void) { int main(void) {
test_single_timer_no_hierarchy(); bool ok = true;
test_single_timer_hierarchy(); TEST(test_single_timer_no_hierarchy);
TEST(test_single_timer_hierarchy);
TEST(test_single_timer_random);
// Test canceling timer from within timer // Test canceling timer from within timer
// Test rescheduling timer from within timer // Test rescheduling timer from within timer
return ok ? 0 : 1;
} }
...@@ -131,12 +131,12 @@ public: ...@@ -131,12 +131,12 @@ public:
void advance(Timestamp delta) { void advance(Timestamp delta) {
while (delta--) { while (delta--) {
now_++; now_++;
size_t slot_index = now_ & (NUM_SLOTS - 1); size_t slot_index = now_ & MASK;
auto slot = &slots_[slot_index]; auto slot = &slots_[slot_index];
while (slot->events()) { while (slot->events()) {
auto event = slot->pop_event(); auto event = slot->pop_event();
if (down_) { if (down_) {
assert((down_->now_ & (NUM_SLOTS - 1)) == 0); assert((down_->now_ & MASK) == 0);
down_->schedule_absolute(event, event->scheduled_at()); down_->schedule_absolute(event, event->scheduled_at());
} else { } else {
event->execute(); event->execute();
...@@ -154,10 +154,10 @@ public: ...@@ -154,10 +154,10 @@ public:
} }
if (delta >= NUM_SLOTS) { if (delta >= NUM_SLOTS) {
return up_->schedule(event, delta >> WIDTH_BITS); return up_->schedule(event, (delta + (now_ & MASK)) >> WIDTH_BITS);
} }
size_t slot_index = (now_ + delta) & (NUM_SLOTS - 1); size_t slot_index = (now_ + delta) & MASK;
auto slot = &slots_[slot_index]; auto slot = &slots_[slot_index];
slot->push_event(event); slot->push_event(event);
} }
...@@ -177,7 +177,7 @@ private: ...@@ -177,7 +177,7 @@ private:
void schedule_absolute(TimerEvent<CBType>* event, Timestamp absolute) { void schedule_absolute(TimerEvent<CBType>* event, Timestamp absolute) {
Timestamp delta; Timestamp delta;
delta = absolute - now_; delta = absolute - now_;
assert(absolute > now_); assert(absolute >= now_);
assert(delta < NUM_SLOTS); assert(delta < NUM_SLOTS);
if (delta == 0) { if (delta == 0) {
if (!down_) { if (!down_) {
...@@ -195,6 +195,7 @@ private: ...@@ -195,6 +195,7 @@ private:
static const int WIDTH_BITS = 8; static const int WIDTH_BITS = 8;
static const int NUM_SLOTS = 1 << WIDTH_BITS; static const int NUM_SLOTS = 1 << WIDTH_BITS;
static const int MASK = (NUM_SLOTS - 1);
TimerWheelSlot<CBType> slots_[NUM_SLOTS]; TimerWheelSlot<CBType> slots_[NUM_SLOTS];
HierarchicalTimerWheel<CBType>* up_; HierarchicalTimerWheel<CBType>* up_;
HierarchicalTimerWheel<CBType>* down_; HierarchicalTimerWheel<CBType>* down_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment