diff --git a/elements/ip/iprewriterbase.hh b/elements/ip/iprewriterbase.hh index 187a78ea78..a7c71cf0a9 100644 --- a/elements/ip/iprewriterbase.hh +++ b/elements/ip/iprewriterbase.hh @@ -428,7 +428,8 @@ template inline IPRewriterEntry * IPRewriterBase::search_migrate_entry(const IPFlowID &flowid, per_thread &vstate) { //If the flow does not exist, it may be in other thread's stack if there was a migration - if (vstate->rebalance > 0 && click_jiffies() - vstate->rebalance < THREAD_MIGRATION_TIMEOUT * CLICK_HZ ) { + if (vstate->rebalance > 0 && + click_jiffies() - vstate->rebalance < THREAD_MIGRATION_TIMEOUT * CLICK_HZ / 1000) { //Search in other thread's stacks for the flow for (int i = 0; i < vstate.weight(); i++) { if (vstate.get_mapping(i) == click_current_cpu_id()) diff --git a/elements/standard/bandwidthmeter.cc b/elements/standard/bandwidthmeter.cc index 32b2f4b45e..262a04db12 100644 --- a/elements/standard/bandwidthmeter.cc +++ b/elements/standard/bandwidthmeter.cc @@ -42,7 +42,7 @@ BandwidthMeter::configure(Vector &conf, ErrorHandler *errh) if (conf.size() == 0) return errh->error("too few arguments to BandwidthMeter(bandwidth, ...)"); - Vector vals(conf.size(), 0); + Vector vals(conf.size(), 0); BandwidthArg ba; for (int i = 0; i < conf.size(); i++) if (!ba.parse(conf[i], vals[i])) @@ -63,8 +63,8 @@ BandwidthMeter::configure(Vector &conf, ErrorHandler *errh) _meter1 = vals[0]; _nmeters = 1; } else { - _meters = new unsigned[vals.size()]; - memcpy(_meters, &vals[0], vals.size() * sizeof(int)); + _meters = new uint64_t[vals.size()]; + memcpy(_meters, &vals[0], vals.size() * sizeof(uint64_t)); _nmeters = vals.size(); } @@ -83,7 +83,7 @@ BandwidthMeter::push(int, Packet *p) int n = (r >= _meter1); output(n).push(p); } else { - unsigned *meters = _meters; + uint64_t *meters = _meters; int nmeters = _nmeters; for (int i = 0; i < nmeters; i++) if (r < meters[i]) { diff --git a/elements/standard/bandwidthmeter.hh b/elements/standard/bandwidthmeter.hh index d2ac963fa7..2b3fabbf44 100644 --- a/elements/standard/bandwidthmeter.hh +++ b/elements/standard/bandwidthmeter.hh @@ -39,8 +39,8 @@ class BandwidthMeter : public Element { protected: RateEWMA _rate; - unsigned _meter1; - unsigned *_meters; + uint64_t _meter1; + uint64_t *_meters; int _nmeters; static String meters_read_handler(Element *, void *) CLICK_COLD; diff --git a/elements/standard/bwratedunqueue.cc b/elements/standard/bwratedunqueue.cc index 86fedf094d..32f6dd9dcf 100644 --- a/elements/standard/bwratedunqueue.cc +++ b/elements/standard/bwratedunqueue.cc @@ -85,7 +85,7 @@ BandwidthRatedUnqueue::run_task(Task *) } } } else { - _timer.schedule_after(Timestamp::make_jiffies(_tb.time_until_contains(tb_bandwidth_thresh))); + _timer.schedule_after(Timestamp::make_usec(_tb.time_until_contains(tb_bandwidth_thresh))); _empty_runs++; return false; } diff --git a/elements/standard/linkunqueue.cc b/elements/standard/linkunqueue.cc index 1d41cae4e4..587307b56f 100644 --- a/elements/standard/linkunqueue.cc +++ b/elements/standard/linkunqueue.cc @@ -215,7 +215,7 @@ LinkUnqueue::write_handler(const String &s, Element *e, void *thunk, ErrorHandle break; } case H_BANDWIDTH: { - uint32_t bw; + uint64_t bw; if (!cp_bandwidth(s, &bw)) { return errh->error("invalid bandwidth"); } else if (bw < 100) { diff --git a/elements/standard/linkunqueue.hh b/elements/standard/linkunqueue.hh index df4d34b28d..ded66b6801 100644 --- a/elements/standard/linkunqueue.hh +++ b/elements/standard/linkunqueue.hh @@ -79,7 +79,7 @@ class LinkUnqueue : public Element, public Storage { public: Timestamp _latency; // enum { S_TASK, S_TIMER, S_ASLEEP } _state; bool _back_to_back; - uint32_t _bandwidth; + uint64_t _bandwidth; Task _task; Timer _timer; NotifierSignal _signal; diff --git a/elements/standard/meter.cc b/elements/standard/meter.cc index 8c117fca96..81d0c65c63 100644 --- a/elements/standard/meter.cc +++ b/elements/standard/meter.cc @@ -29,12 +29,12 @@ Meter::push(int, Packet *p) { _rate.update(1); // packets, not bytes - unsigned r = _rate.scaled_average(); + uint64_t r = _rate.scaled_average(); if (_nmeters < 2) { int n = (r >= _meter1); output(n).push(p); } else { - unsigned *meters = _meters; + uint64_t *meters = _meters; int nmeters = _nmeters; for (int i = 0; i < nmeters; i++) if (r < meters[i]) { diff --git a/elements/standard/ratedsource.cc b/elements/standard/ratedsource.cc index e3e1e0d879..fb32eb708e 100644 --- a/elements/standard/ratedsource.cc +++ b/elements/standard/ratedsource.cc @@ -49,8 +49,8 @@ RatedSource::configure(Vector &conf, ErrorHandler *errh) String data = "Random bullshit in a packet, at least 64 bytes long. Well, now it is."; - unsigned rate = 10; - unsigned bandwidth = 0; + uint64_t rate = 10; + uint64_t bandwidth = 0; int limit = -1; int datasize = -1; bool active = true, stop = false; @@ -179,7 +179,7 @@ RatedSource::run_task(Task *) count++; } else { - _timer.schedule_after(Timestamp::make_jiffies(_tb.time_until_contains(_batch_size))); + _timer.schedule_after(Timestamp::make_usec(_tb.time_until_contains(_batch_size))); return false; } } @@ -194,7 +194,7 @@ RatedSource::run_task(Task *) } else { if (_end_h && _limit >= 0 && _count >= (ucounter_t) _limit) (void) _end_h->call_write(); - _timer.schedule_after(Timestamp::make_jiffies(_tb.time_until_contains(1))); + _timer.schedule_after(Timestamp::make_usec(_tb.time_until_contains(1))); return false; } @@ -209,7 +209,7 @@ RatedSource::run_task(Task *) } else { if (_end_h && _limit >= 0 && _count >= (ucounter_t) _limit) (void) _end_h->call_write(); - _timer.schedule_after(Timestamp::make_jiffies(_tb.time_until_contains(1))); + _timer.schedule_after(Timestamp::make_usec(_tb.time_until_contains(1))); return false; } diff --git a/elements/standard/ratedunqueue.cc b/elements/standard/ratedunqueue.cc index 59b8556d35..cbe95ae4fa 100644 --- a/elements/standard/ratedunqueue.cc +++ b/elements/standard/ratedunqueue.cc @@ -48,9 +48,9 @@ RatedUnqueue::configure(Vector &conf, ErrorHandler *errh) int RatedUnqueue::configure_helper(TokenBucket *tb, bool is_bandwidth, Element *elt, Vector &conf, ErrorHandler *errh) { - unsigned r; + uint64_t r; unsigned dur_msec = 20; - unsigned tokens; + uint64_t tokens; bool dur_specified, tokens_specified; const char *burst_size = is_bandwidth ? "BURST_BYTES" : "BURST_SIZE"; @@ -133,7 +133,7 @@ RatedUnqueue::run_task(Task *) } #endif } else { - _timer.schedule_after(Timestamp::make_jiffies(_tb.time_until_contains(1))); + _timer.schedule_after(Timestamp::make_usec(_tb.time_until_contains(1))); _empty_runs++; return false; } diff --git a/elements/standard/ratedunqueue.hh b/elements/standard/ratedunqueue.hh index c824b62b3e..3555e70c59 100644 --- a/elements/standard/ratedunqueue.hh +++ b/elements/standard/ratedunqueue.hh @@ -69,11 +69,11 @@ class RatedUnqueue : public BatchElement { public: Task _task; Timer _timer; NotifierSignal _signal; - uint32_t _runs; - uint32_t _packets; - uint32_t _pushes; - uint32_t _failed_pulls; - uint32_t _empty_runs; + uint64_t _runs; + uint64_t _packets; + uint64_t _pushes; + uint64_t _failed_pulls; + uint64_t _empty_runs; uint32_t _burst; enum { h_calls, h_rate }; diff --git a/elements/standard/shaper.cc b/elements/standard/shaper.cc index 9a7ce81c5e..74cae64fce 100644 --- a/elements/standard/shaper.cc +++ b/elements/standard/shaper.cc @@ -32,7 +32,7 @@ Shaper::Shaper() int Shaper::configure(Vector &conf, ErrorHandler *errh) { - uint32_t rate; + uint64_t rate; Args args(conf, this, errh); if (is_bandwidth()) args.read_mp("RATE", BandwidthArg(), rate); diff --git a/elements/test/biginttest.cc b/elements/test/biginttest.cc index 1c734c3b3c..1d35a3e1ba 100644 --- a/elements/test/biginttest.cc +++ b/elements/test/biginttest.cc @@ -34,11 +34,12 @@ BigintTest::BigintTest() } #define CHECK(x, a, b) if (!(x)) return errh->error("%s:%d: test `%s' failed [%llu, %u]", __FILE__, __LINE__, #x, a, b); +#define CHECKL(x, a, l, b) if (!(x)) return errh->error("%s:%d: test `%s' failed [%s, %llu]", __FILE__, __LINE__, #x, bigint::unparse_clear(a, l).c_str(), b); #define CHECK0(x) if (!(x)) return errh->error("%s:%d: test `%s' failed", __FILE__, __LINE__, #x); static bool test_multiply(uint32_t a, uint32_t b, ErrorHandler *errh) { uint32_t x[2]; - bigint::multiply(x[1], x[0], a, b); + Bigint::multiply(x[1], x[0], a, b); uint64_t c = (((uint64_t) x[1]) << 32) | x[0]; if (c != (uint64_t) a * b) { errh->error("%u * %u == %llu, not %llu", a, b, (uint64_t) a * b, c); @@ -53,7 +54,7 @@ static bool test_mul(uint64_t a, uint32_t b, ErrorHandler *errh) { ax[1] = a >> 32; uint32_t cx[2]; cx[0] = cx[1] = 0; - bigint::multiply_add(cx, ax, 2, b); + Bigint::multiply_add(cx, ax, 2, b); uint64_t c = (((uint64_t) cx[1]) << 32) | cx[0]; if (c != a * b) { errh->error("%llu * %u == %llu, not %llu", a, b, a * b, c); @@ -63,10 +64,11 @@ static bool test_mul(uint64_t a, uint32_t b, ErrorHandler *errh) { } static bool test_div(uint64_t a, uint32_t b, ErrorHandler *errh) { + assert(b); uint32_t ax[4]; ax[0] = a; ax[1] = a >> 32; - uint32_t r = bigint::divide(ax+2, ax, 2, b); + uint32_t r = Bigint::divide(ax+2, ax, 2, b); uint64_t c = ((uint64_t) ax[3] << 32) | ax[2]; if (c != a / b) { errh->error("%llu / %u == %llu, not %llu", a, b, a * b, c); @@ -81,7 +83,7 @@ static bool test_div(uint64_t a, uint32_t b, ErrorHandler *errh) { static bool test_inverse(uint32_t a, ErrorHandler *errh) { assert(a & (1 << 31)); - uint32_t a_inverse = bigint::inverse(a); + uint32_t a_inverse = Bigint::inverse(a); // "Inverse is floor((b * (b - a) - 1) / a), where b = 2^32." uint64_t b = (uint64_t) 1 << 32; uint64_t want_inverse = (b * (b - a) - 1) / a; @@ -99,7 +101,7 @@ static bool test_add(uint64_t a, uint64_t b, ErrorHandler *errh) { ax[3] = a >> 32; ax[4] = b; ax[5] = b >> 32; - bigint::add(ax[1], ax[0], ax[3], ax[2], ax[5], ax[4]); + Bigint::add(ax[1], ax[0], ax[3], ax[2], ax[5], ax[4]); uint64_t c = ((uint64_t) ax[1] << 32) | ax[0]; if (c != a + b) { errh->error("%llu + %llu == %llu, not %llu", a, b, a + b, c); @@ -108,45 +110,194 @@ static bool test_add(uint64_t a, uint64_t b, ErrorHandler *errh) { return true; } +static bool test_multiply64(uint64_t a, uint64_t b, ErrorHandler *errh) { + uint64_t x[2], y[2]; + bigint::multiply(x[1], x[0], a, b); +#ifdef __x86_64__ + int_multiply(a, b, y[0], y[1]); +#else + y[1] = (a >> 32) * (b >> 32); + y[0] = (a & ((1UL << 32) - 1)) * (uint32_t) b; + uint64_t tmp = (a >> 32) * (uint32_t) b; + bool carry = (tmp << 32) > -y[0]; + y[0] += (tmp << 32); + y[1] += (tmp >> 32) + carry; + tmp = (uint32_t) a * (b >> 32); + carry = (tmp << 32) > -y[0]; + y[0] += (tmp << 32); + y[1] += (tmp >> 32) + carry; +#endif + if (memcmp(x, y, sizeof(x))) { + errh->error("%u * %u == %s, not %s", a, b, bigint::unparse_clear(y, 2).c_str(), + bigint::unparse_clear(x, 2).c_str()); + return false; + } + return true; +} + +static bool test_mul64(uint64_t a[2], uint64_t b, ErrorHandler *errh) { + uint64_t c[2] = {0, 0}, d[2], e[2]; + bigint::multiply_add(c, a, 2, b); + bigint::multiply(d[1], d[0], a[0], b); + bigint::multiply(e[1], e[0], a[1], b); + d[1] += e[0]; + if (memcmp(c, d, sizeof(c))) { + uint64_t tmp[2] = {a[0], a[1]}; + errh->error("%s * %llu == %s, not %s", bigint::unparse_clear(tmp, 2).c_str(), b, + bigint::unparse_clear(d, 2).c_str(), bigint::unparse_clear(c, 2).c_str()); + return false; + } + return true; +} + +static bool test_div64(uint64_t a[2], uint64_t b, ErrorHandler *errh) { + assert(b); + uint64_t c[2], q[2] = {0, 0}, rem; + uint64_t r = bigint::divide(c, a, 2, b); + // Upper 64 bits of the quotient + q[1] = a[1] / b; + rem = a[1] % b; + // Lower 64 bits of the quotient +#ifdef __x86_64__ + __asm__("divq %4" : "=d"(rem), "=a"(q[0]) : "d"(rem), "a"(a[0]), "rm"(b)); +#else + if (rem) { + unsigned ashift = 0; + unsigned bshift = ffs_msb(b) - 1; + b <<= bshift; + // While remainder >= 2^64, + // subtract the divisor from the top bits of the remainder and accumulate quotient + while (ashift < 64) { + int s = ffs_msb(rem) - 1; + if (s) { + if (!rem || (unsigned) s >= 64 - ashift) + s = 64 - ashift; + q[0] <<= s; + rem = (rem << s) + ((a[0] << ashift) >> (64 - s)); + ashift += s; + if (ashift == 64) + break; + } + if (rem < b) { + q[0] <<= 1; + ashift++; + rem = (rem << 1) + (bool) (a[0] & (1ULL << (64 - ashift))); + } + rem -= b; + q[0]++; + } + q[0] <<= bshift; + b >>= bshift; + } else { + rem = a[0]; + } + // Remainder is now < 2^64, compute result directly + q[0] += rem / b; + rem = rem % b; +#endif + if (memcmp(c, q, sizeof(c))) { + uint64_t tmp[2] = {a[0], a[1]}; + errh->error("%s / %llu == %s, not %s", bigint::unparse_clear(tmp, 2).c_str(), b, + bigint::unparse_clear(q, 2).c_str(), bigint::unparse_clear(c, 2).c_str()); + return false; + } + if (r != rem) { + errh->error("%s %% %llu == %llu, not %llu", bigint::unparse_clear(a, 2).c_str(), b, rem, r); + return false; + } + return true; +} + +static bool test_inverse64(uint64_t a, ErrorHandler *errh) { + assert(a & (1ULL << 63)); + uint64_t a_inverse = bigint::inverse(a); + // "Inverse is floor((b * (b - a) - 1) / a), where b = 2^64." + uint64_t want_inverse[2] = {(uint64_t) -1, (uint64_t) -1}; // initialized to -1 + uint64_t c[2] = {0, -a}; // initialized to 2^64 * (2^64 - a) + bigint::add(want_inverse[1], want_inverse[0], want_inverse[1], want_inverse[0], c[1], c[0]); + bigint::divide(want_inverse, want_inverse, 2, a); + assert(want_inverse[1] == 0); + if (a_inverse != want_inverse[0]) { + errh->error("inverse(%llu) == %llu, not %llu", a, want_inverse[0], a_inverse); + return false; + } + return true; +} + +static bool test_add64(uint64_t a[2], uint64_t b[2], ErrorHandler *errh) { + uint64_t res[2]; + bigint::add(res[1], res[0], a[1], a[0], b[1], b[0]); + + uint64_t c[2] = {a[0] + b[0], a[1] + b[1]}; + if (a[0] > -b[0]) + c[1]++; + if (memcmp(res, c, sizeof(res))) { + uint64_t tmp[4] = {a[0], a[1], b[0], b[1]}; + errh->error("%s + %s == %s, not %s", bigint::unparse_clear(tmp, 2).c_str(), + bigint::unparse_clear(&tmp[2], 2).c_str(), bigint::unparse_clear(c, 2).c_str(), + bigint::unparse_clear(res, 2).c_str()); + return false; + } + return true; +} + int BigintTest::initialize(ErrorHandler *errh) { for (int i = 0; i < 3000; i++) { - uint32_t a = click_random() | (click_random() << 31); - uint32_t b = click_random() | (click_random() << 31); - CHECK(test_multiply(a, b, errh), a, b); - CHECK(test_mul(a, b, errh), a, b); + uint64_t a[2], b; + a[0] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + a[1] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + b = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + CHECK(test_multiply(a[0], b, errh), a[0] & UINT32_MAX, (uint32_t) b); + CHECKL(test_multiply64(a[0], b, errh), a, 1, b); + CHECK(test_mul(a[0], b, errh), a[0], (uint32_t) b); + CHECKL(test_mul64(a, b, errh), a, 2, b); } for (int i = 0; i < 8000; i++) { - uint32_t a = click_random(); - CHECK0(test_inverse(a | 0x80000000, errh)); + uint64_t a = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + CHECK0(test_inverse(a | (1UL << 31), errh)); + CHECK0(test_inverse64(a | (1ULL << 63), errh)); } CHECK0(test_inverse(0x80000000, errh)); for (int i = 0; i < 8000; i++) { - uint64_t a = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - uint64_t b = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - CHECK0(test_add(a, b, errh)); + uint64_t a[2], b[2]; + a[0] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + a[1] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + b[0] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + b[1] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + CHECK0(test_add(a[0], b[0], errh)); + CHECK0(test_add64(a, b, errh)); } CHECK0(test_div(12884758640815563913ULL, 2506284098U, errh)); for (int i = 0; i < 3000; i++) { - uint64_t a = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - uint32_t b = click_random(); - CHECK(test_div(a, b | 0x80000000, errh), a, b | 0x80000000); + uint64_t a[2], b; + a[0] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + a[1] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + b = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + CHECK(test_div(a[0], b | (1UL << 31), errh), a[0], (uint32_t) b | (1UL << 31)); + CHECKL(test_div64(a, b | (1ULL << 63), errh), a, 2, b | (1ULL << 63)); } for (int i = 0; i < 3000; i++) { - uint64_t a = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - uint32_t b = click_random(); - CHECK(test_div(a, b & ~0x80000000, errh), a, b & ~0x80000000); - CHECK(test_div(a, b | 0x80000000, errh), a, b | 0x80000000); + uint64_t a[2], b; + a[0] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + a[1] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + do + b = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + while (!b); + CHECK(test_div(a[0], b & ~(1UL << 31), errh), a[0], (uint32_t) b & ~(1UL << 31)); + CHECKL(test_div64(a, b & ~(1ULL << 63), errh), a, 2, b & ~(1ULL << 63)); + CHECK(test_div(a[0], b | (1UL << 31), errh), a[0], (uint32_t) b | (1UL << 31)); + CHECKL(test_div64(a, b | (1ULL << 63), errh), a, 2, b | (1ULL << 63)); } uint32_t x[3] = { 3481, 592182, 3024921038U }; - CHECK0(bigint::unparse_clear(x, 3) == "55799944231168388787108580761"); + CHECK0(Bigint::unparse_clear(x, 3) == "55799944231168388787108580761"); x[0] = 10; x[1] = 0; - CHECK0(bigint::multiply(x, x, 2, 10) == 0 && x[0] == 100 && x[1] == 0); - CHECK0(bigint::multiply(x, x, 2, 4191384139U) == 0 && x[0] == 0x9698A54CU && x[1] == 0x61U); + CHECK0(Bigint::multiply(x, x, 2, 10) == 0 && x[0] == 100 && x[1] == 0); + CHECK0(Bigint::multiply(x, x, 2, 4191384139U) == 0 && x[0] == 0x9698A54CU && x[1] == 0x61U); { int32_t quot, rem; diff --git a/elements/test/confparsetest.cc b/elements/test/confparsetest.cc index cdd2384782..58749204fe 100644 --- a/elements/test/confparsetest.cc +++ b/elements/test/confparsetest.cc @@ -236,10 +236,10 @@ ConfParseTest::initialize(ErrorHandler *errh) #endif BandwidthArg bwarg; - CHECK(bwarg.parse("8", u32) == true && bwarg.status == NumArg::status_unitless && u32 == 8); - CHECK(bwarg.parse("8 baud", u32) == true && bwarg.status == NumArg::status_ok && u32 == 1); - CHECK(bwarg.parse("8Kbps", u32) == true && bwarg.status == NumArg::status_ok && u32 == 1000); - CHECK(bwarg.parse("8KBps", u32) == true && bwarg.status == NumArg::status_ok && u32 == 8000); + CHECK(bwarg.parse("8", u64) == true && bwarg.status == NumArg::status_unitless && u64 == 8); + CHECK(bwarg.parse("8 baud", u64) == true && bwarg.status == NumArg::status_ok && u64 == 1); + CHECK(bwarg.parse("8Kbps", u64) == true && bwarg.status == NumArg::status_ok && u64 == 1000); + CHECK(bwarg.parse("8KBps", u64) == true && bwarg.status == NumArg::status_ok && u64 == 8000); { IPAddress a, m; diff --git a/elements/test/tokenbuckettest.cc b/elements/test/tokenbuckettest.cc index 58c5f5faab..0bd516ac55 100644 --- a/elements/test/tokenbuckettest.cc +++ b/elements/test/tokenbuckettest.cc @@ -30,7 +30,7 @@ TokenBucketTest::TokenBucketTest() int TokenBucketTest::initialize(ErrorHandler *errh) { - TokenBucket tb; + TokenBucketX > tb; tb.assign(1024, 2048); CHECK(tb.rate() >= 1022 && tb.rate() <= 1026); CHECK(tb.capacity() >= 2046 && tb.capacity() <= 2050); diff --git a/include/click/args.hh b/include/click/args.hh index 7f42bc5901..4fb644e2bf 100644 --- a/include/click/args.hh +++ b/include/click/args.hh @@ -1376,7 +1376,7 @@ class UnitArg { public: Handles suffixes such as "Gbps", "k", etc. */ class BandwidthArg : public NumArg { public: - bool parse(const String &str, uint32_t &result, const ArgContext & = blank_args); + bool parse(const String &str, uint64_t &result, const ArgContext & = blank_args); static String unparse(uint32_t x); int status; }; diff --git a/include/click/bigint.hh b/include/click/bigint.hh index de00f75e10..33b274c0c0 100644 --- a/include/click/bigint.hh +++ b/include/click/bigint.hh @@ -384,8 +384,8 @@ class Bigint { public: }; -/** @brief Typical Bigint usage with uint32_t limb_type. */ -typedef Bigint bigint; +/** @brief Typical Bigint usage with uint64_t limb_type. */ +typedef Bigint bigint; CLICK_ENDDECLS #endif diff --git a/include/click/confparse.hh b/include/click/confparse.hh index 08571c44fb..ef6f823760 100644 --- a/include/click/confparse.hh +++ b/include/click/confparse.hh @@ -172,7 +172,7 @@ bool cp_seconds(const String& str, double* result); bool cp_time(const String &str, Timestamp *result, bool allow_negative = false); bool cp_time(const String& str, struct timeval* result); -bool cp_bandwidth(const String& str, uint32_t* result); +bool cp_bandwidth(const String& str, uint64_t* result); // network addresses class IPAddressList; diff --git a/include/click/gaprate.hh b/include/click/gaprate.hh index 69a2fb7bf3..c2a7eae5f3 100644 --- a/include/click/gaprate.hh +++ b/include/click/gaprate.hh @@ -49,17 +49,17 @@ class GapRate { public: /** @brief Construct a GapRate object with initial rate @a r. * @param r initial rate (events per second) */ - inline GapRate(unsigned r); + inline GapRate(uint64_t r); /** @brief Return the current rate. */ - inline unsigned rate() const; + inline uint64_t rate() const; /** @brief Set the current rate to @a r. * @param r desired rate (events per second) * * Rates larger than MAX_RATE are reduced to MAX_RATE. Also performs the * equivalent of a reset() to flush old state. */ - inline void set_rate(unsigned r); + inline void set_rate(uint64_t r); /** @brief Set the current rate to @a r. * @param r desired rate (events per second) @@ -67,7 +67,7 @@ class GapRate { public: * * Acts like set_rate(@a r), except that an warning is reported to @a errh * if @a r is larger than MAX_RATE. */ - void set_rate(unsigned r, ErrorHandler *errh); + void set_rate(uint64_t r, ErrorHandler *errh); /** @brief Returns whether the user's rate is behind the true rate. @@ -97,7 +97,7 @@ class GapRate { public: * * @note This may be faster than calling update() @a delta times. * Furthermore, @a delta can be negative. */ - inline void update_with(int delta); + inline void update_with(int64_t delta); /** @brief Resets the true rate counter. * @@ -106,20 +106,20 @@ class GapRate { public: inline void reset(); - enum { UGAP_SHIFT = 12 }; - enum { MAX_RATE = 1000000U << UGAP_SHIFT }; + enum { UGAP_SHIFT = 43 }; + enum { MAX_RATE = 1000000ULL << UGAP_SHIFT }; private: - unsigned _ugap; // (1000000 << UGAP_SHIFT) / _rate - int _sec_count; // number of updates this second so far + uint64_t _ugap; // (1000000 << UGAP_SHIFT) / _rate + int64_t _sec_count; // number of updates this second so far Timestamp::seconds_type _tv_sec; // current second - unsigned _rate; // desired rate + uint64_t _rate; // desired rate #if DEBUG_GAPRATE Timestamp _last; #endif - inline void initialize_rate(unsigned rate); + inline void initialize_rate(uint64_t rate); }; @@ -134,7 +134,7 @@ GapRate::reset() } inline void -GapRate::initialize_rate(unsigned r) +GapRate::initialize_rate(uint64_t r) { _rate = r; _ugap = (r == 0 ? MAX_RATE + 1 : MAX_RATE / r); @@ -144,7 +144,7 @@ GapRate::initialize_rate(unsigned r) } inline void -GapRate::set_rate(unsigned r) +GapRate::set_rate(uint64_t r) { if (r > MAX_RATE) r = MAX_RATE; @@ -152,7 +152,7 @@ GapRate::set_rate(unsigned r) initialize_rate(r); if (_tv_sec >= 0 && r != 0) { Timestamp now = Timestamp::now(); - _sec_count = (now.usec() << UGAP_SHIFT) / _ugap; + _sec_count = (static_cast(now.usec()) << UGAP_SHIFT) / _ugap; } } } @@ -165,14 +165,14 @@ GapRate::GapRate() } inline -GapRate::GapRate(unsigned r) +GapRate::GapRate(uint64_t r) : _rate(0) { initialize_rate(r); reset(); } -inline unsigned +inline uint64_t GapRate::rate() const { return _rate; @@ -182,15 +182,15 @@ inline bool GapRate::need_update(const Timestamp &now) { // this is an approximation of: - // unsigned need = (unsigned) ((now.usec() / 1000000.0) * _rate) - unsigned need = (now.usec() << UGAP_SHIFT) / _ugap; + // uint64_t need = (uint64_t) ((now.usec() / 1000000.0) * _rate) + uint64_t need = (static_cast(now.usec()) << UGAP_SHIFT) / _ugap; if (_tv_sec < 0) { // 27.Feb.2005: often OK to send a packet after reset unless rate is // 0 -- requested by Bart Braem // check include/click/gaprate.hh (1.2) _tv_sec = now.sec(); - _sec_count = need + ((now.usec() << UGAP_SHIFT) - (need * _ugap) > _ugap / 2); + _sec_count = need + ((static_cast(now.usec()) << UGAP_SHIFT) - (need * _ugap) > _ugap / 2); } else if (now.sec() > _tv_sec) { _tv_sec = now.sec(); if (_sec_count > 0) @@ -200,7 +200,7 @@ GapRate::need_update(const Timestamp &now) #if DEBUG_GAPRATE click_chatter("%p{timestamp} -> %u @ %u [%d]", &now, need, _sec_count, (int)need >= _sec_count); #endif - return ((int)need >= _sec_count); + return ((int64_t)need >= _sec_count); } inline void @@ -210,7 +210,7 @@ GapRate::update() } inline void -GapRate::update_with(int delta) +GapRate::update_with(int64_t delta) { _sec_count += delta; } @@ -224,8 +224,8 @@ GapRate::expiry() const return Timestamp(_tv_sec, 0); else { Timestamp::seconds_type sec = _tv_sec; - int count = _sec_count; - if ((unsigned) count >= _rate) { + int64_t count = _sec_count; + if ((uint64_t) count >= _rate) { sec += count / _rate; count = count % _rate; } diff --git a/include/click/tokenbucket.hh b/include/click/tokenbucket.hh index 5966e9bbf7..e5318c9e86 100644 --- a/include/click/tokenbucket.hh +++ b/include/click/tokenbucket.hh @@ -32,6 +32,8 @@ CLICK_DECLS TokenRateX template parameter P defines the time tick unit and frequency. The provided TokenBucketJiffyParameters class is designed to be used as TokenRateX's parameter; it measures ticks in units of jiffies. + TokenBucketUsecParameters is also included, which measures ticks in + units of microseconds. @sa GapRate */ @@ -48,7 +50,7 @@ CLICK_DECLS token_max. An idle TokenRateX never refills. Most users will be satisfied with the TokenRate type, which is equal to - TokenRateX >. + TokenRateX >. @sa TokenCounterX, TokenBucketX */ @@ -214,13 +216,13 @@ void TokenRateX

::assign(token_type rate, token_type capacity) token_type frequency = P::frequency(); if (rate != 0) { // constrain capacity so _tokens_per_tick fits in 1 limb - unsigned min_capacity = (rate - 1) / frequency + 1; + unsigned long long min_capacity = (rate - 1) / frequency + 1; if (capacity < min_capacity) capacity = min_capacity; } _token_scale = max_tokens / capacity; - // XXX on non-32 bit types + // XXX on non-64 bit types static_assert(sizeof(bigint::limb_type) == sizeof(token_type), "bigint::limb_type should have the same size as token_type."); bigint::limb_type l[2] = { 0, 0 }; @@ -318,7 +320,7 @@ template struct TokenRateConverter { remove(), and similar functions act as normal for idle and unlimited rates. Most users will be satisfied with the TokenCounter type, which is equal to - TokenCounterX > >. + TokenCounterX > >. @sa TokenRateX, TokenBucketX */ @@ -693,6 +695,68 @@ class TokenBucketJiffyParameters { public: }; +/** @class TokenBucketUsecParameters include/click/tokenbucket.hh + @brief Helper class for token bucket rate limiter. + + Pass this class as the parameter to TokenRateX. TokenBucketUsecParameters + measures ticks in units of microseconds. The template parameter is the type of + tokens. */ + +template +class TokenBucketUsecParameters { public: + + /** @brief The type of tokens. Always unsigned. */ + typedef T token_type; + + /** @brief The type of a time point. Always unsigned. */ + typedef click_uintmax_t time_point_type; + + /** @brief The type of a difference between time points. Always signed. */ + typedef click_intmax_t duration_type; + + /** @brief Return the current time point. + * @note TokenBucketUsecParameters measures time points in microseconds. */ + static time_point_type now() { + return Timestamp::now_steady().usecval(); + } + + static time_point_type time_point(time_point_type t) { + return t; + } + + /** @brief Return @a b - @a a, assuming that @a b was measured after @a a. + * + * Some time measurements can, in rare cases, appear to jump backwards, + * as timestamps do when the user changes the current time. If this + * happens, and @a b < @a a (even though @a b happened after @a a), + * time_monotonic_difference must return 0. */ + static duration_type time_monotonic_difference(time_point_type a, time_point_type b) { + return (likely(a <= b) ? b - a : 0); + } + + /** @brief Return true if @a a happened before @a b. */ + static bool time_less(time_point_type a, time_point_type b) { + return (duration_type) (a - b) < 0; + } + + /** @brief Return the number of time points per period. + * + * Here, this is the number of microseconds per second. */ + static unsigned frequency() { + return 1000000; + } + + /** @brief Return the Timestamp representing a given time point. */ + static Timestamp timestamp(time_point_type x) { + return Timestamp::make_usec(x); + } + + /** @brief Return the Timestamp representing a given tick count. */ + static Timestamp timestamp(duration_type x) { + return Timestamp::make_usec(x); + } + +}; /** @class TokenBucketX include/click/tokenbucket.hh @brief Token bucket rate limiter. @@ -701,7 +765,7 @@ class TokenBucketJiffyParameters { public: implemented as a pair of TokenRateX and TokenCounterX. Most users will be satisfied with the TokenBucket type, which is equal to - TokenBucketX >. + TokenBucketX >. @sa GapRate */ @@ -1006,15 +1070,15 @@ inline typename TokenBucketX

::ticks_type TokenBucketX

::epochs_until_contai /** @class TokenRate include/click/tokenbucket.hh - * @brief Jiffy-based token bucket rate + * @brief Microsecond-based token bucket rate * * Equivalent to - * @link TokenRateX TokenRateX >@endlink. - * @sa TokenRateX, TokenBucketJiffyParameters */ -typedef TokenRateX > TokenRate; + * @link TokenRateX TokenRateX >@endlink. + * @sa TokenRateX, TokenBucketUsecParameters */ +typedef TokenRateX > TokenRate; /** @class TokenCounter include/click/tokenbucket.hh - * @brief Jiffy-based token counter + * @brief Microsecond-based token counter * * Equivalent to * @link TokenCounterX TokenCounterX@endlink. @@ -1022,12 +1086,12 @@ typedef TokenRateX > TokenRate; typedef TokenCounterX TokenCounter; /** @class TokenBucket include/click/tokenbucket.hh - * @brief Jiffy-based token bucket rate limiter + * @brief Microsecond-based token bucket rate limiter * * Equivalent to - * @link TokenBucketX TokenBucketX >@endlink. - * @sa TokenBucketX, TokenBucketJiffyParameters */ -typedef TokenBucketX > TokenBucket; + * @link TokenBucketX TokenBucketX >@endlink. + * @sa TokenBucketX, TokenBucketUsecParameters */ +typedef TokenBucketX > TokenBucket; CLICK_ENDDECLS #endif diff --git a/lib/args.cc b/lib/args.cc index ecc367f360..475761bb9f 100644 --- a/lib/args.cc +++ b/lib/args.cc @@ -1220,7 +1220,7 @@ static const char byte_bandwidth_units[] = "\ static const char byte_bandwidth_prefixes[] = "\ k\103K\103M\106G\111"; -static uint32_t +static uint64_t multiply_factor(uint32_t ix, uint32_t fx, uint32_t factor, int &status) { if (factor == 1) { @@ -1233,14 +1233,14 @@ multiply_factor(uint32_t ix, uint32_t fx, uint32_t factor, int &status) if (int32_t(flow) < 0) ++ftoint; int_multiply(ix, factor, ilow, ihigh); - if (ihigh != 0 || ilow + ftoint < ftoint) - status = NumArg::status_range; - return ilow + ftoint; + /* if (ihigh != 0 || ilow + ftoint < ftoint) + status = NumArg::status_range; */ + return ((uint64_t) ihigh << 32) + ilow + ftoint; } } bool -BandwidthArg::parse(const String &str, uint32_t &result, const ArgContext &args) +BandwidthArg::parse(const String &str, uint64_t &result, const ArgContext &args) { int power, factor; const char *unit_end = UnitArg(byte_bandwidth_units, byte_bandwidth_prefixes).parse(str.begin(), str.end(), power, factor); @@ -1258,7 +1258,7 @@ BandwidthArg::parse(const String &str, uint32_t &result, const ArgContext &args) ix = multiply_factor(ix, fx, factor, status); if (status == status_range) { args.error("out of range"); - result = 0xFFFFFFFFU; + result = UINT64_MAX; return false; } else { if (unit_end == str.end() && ix) diff --git a/lib/confparse.cc b/lib/confparse.cc index f79f957d49..15be6967ea 100644 --- a/lib/confparse.cc +++ b/lib/confparse.cc @@ -1589,10 +1589,10 @@ bool cp_time(const String &str, timeval *result) * otherwise, cp_errno is set to CPE_FORMAT (unparsable) or CPE_OK (if all was * well). */ -bool cp_bandwidth(const String &str, uint32_t *result) +bool cp_bandwidth(const String &str, uint64_t *result) { BandwidthArg ba; - uint32_t x; + uint64_t x; if (!ba.parse(str, x)) { cp_errno = CPE_FORMAT; return false; @@ -2592,7 +2592,7 @@ default_parsefunc(cp_value *v, const String &arg, case cpiBandwidth: { BandwidthArg ba; - if (!ba.parse(arg, v->v.u32)) + if (!ba.parse(arg, v->v.u64)) goto type_mismatch; else if (ba.status == NumArg::status_range) { String m = cp_unparse_bandwidth(v->v.u32); diff --git a/lib/gaprate.cc b/lib/gaprate.cc index c8af8f3fed..c845437e9e 100644 --- a/lib/gaprate.cc +++ b/lib/gaprate.cc @@ -24,7 +24,7 @@ CLICK_DECLS void -GapRate::set_rate(unsigned r, ErrorHandler *errh) +GapRate::set_rate(uint64_t r, ErrorHandler *errh) { if (r > GapRate::MAX_RATE && errh) errh->error("rate too large; lowered to %u", GapRate::MAX_RATE); diff --git a/test/standard/RatedUnqueue-01.clicktest b/test/standard/RatedUnqueue-01.clicktest index e5a8224dd5..5d6ee144dc 100644 --- a/test/standard/RatedUnqueue-01.clicktest +++ b/test/standard/RatedUnqueue-01.clicktest @@ -40,4 +40,4 @@ c2.count: c3.count: 69 c4.count: -{{909|910}} {{?this is because of inefficiencies with BURST_SIZE == 1 + simtime not being perfect}} +1000