proxygen
folly::Codel Class Reference

#include <Codel.h>

Public Member Functions

 Codel ()
 
bool overloaded (std::chrono::nanoseconds delay)
 
int getLoad ()
 
std::chrono::nanoseconds getMinDelay ()
 
std::chrono::milliseconds getInterval ()
 
std::chrono::milliseconds getTargetDelay ()
 
std::chrono::milliseconds getSloughTimeout ()
 

Private Attributes

std::atomic< uint64_tcodelMinDelayNs_
 
std::atomic< uint64_tcodelIntervalTimeNs_
 
std::atomic< bool > codelResetDelay_
 
std::atomic< bool > overloaded_
 

Detailed Description

CoDel (controlled delay) is an active queue management algorithm from networking for battling bufferbloat.

Services also have queues (of requests, not packets) and suffer from queueing delay when overloaded. This class adapts the codel algorithm for services.

Codel is discussed in depth on the web [1,2], but a basic sketch of the algorithm is this: if every request has experienced queueing delay greater than the target (5ms) during the past interval (100ms), then we shed load.

We have adapted the codel algorithm. TCP sheds load by changing windows in reaction to dropped packets. Codel in a network setting drops packets at increasingly shorter intervals (100 / sqrt(n)) to achieve a linear change in throughput. In our experience a different scheme works better for services: when overloaded slough off requests that we dequeue which have exceeded an alternate timeout (2 * target_delay).

So in summary, to use this class, calculate the time each request spent in the queue and feed that delay to overloaded(), which will tell you whether to expire this request.

You can also ask for an instantaneous load estimate and the minimum delay observed during this interval.

  1. http://queue.acm.org/detail.cfm?id=2209336
  2. https://en.wikipedia.org/wiki/CoDel

Definition at line 57 of file Codel.h.

Constructor & Destructor Documentation

folly::Codel::Codel ( )

Definition at line 29 of file Codel.cpp.

30  : codelMinDelayNs_(0),
32  duration_cast<nanoseconds>(steady_clock::now().time_since_epoch())
33  .count()),
34  codelResetDelay_(true),
35  overloaded_(false) {}
std::atomic< bool > overloaded_
Definition: Codel.h:90
std::chrono::steady_clock::time_point now()
std::atomic< uint64_t > codelIntervalTimeNs_
Definition: Codel.h:84
std::atomic< bool > codelResetDelay_
Definition: Codel.h:88
int * count
std::atomic< uint64_t > codelMinDelayNs_
Definition: Codel.h:83

Member Function Documentation

milliseconds folly::Codel::getInterval ( )

Definition at line 93 of file Codel.cpp.

Referenced by overloaded().

93  {
94  return milliseconds(FLAGS_codel_interval);
95 }
int folly::Codel::getLoad ( )

Get the queue load, as seen by the codel algorithm Gives a rough guess at how bad the queue delay is.

min(100%, min_delay / (2 * target_delay))

Return: 0 = no delay, 100 = At the queueing limit

Definition at line 83 of file Codel.cpp.

References getMinDelay(), and getSloughTimeout().

Referenced by TEST().

83  {
84  // it might be better to use the average delay instead of minDelay, but we'd
85  // have to track it. aspiring bootcamper?
86  return std::min<int>(100, 100 * getMinDelay() / getSloughTimeout());
87 }
std::chrono::nanoseconds getMinDelay()
Definition: Codel.cpp:89
std::chrono::milliseconds getSloughTimeout()
Definition: Codel.cpp:101
nanoseconds folly::Codel::getMinDelay ( )

Definition at line 89 of file Codel.cpp.

References codelMinDelayNs_.

Referenced by getLoad().

89  {
90  return nanoseconds(codelMinDelayNs_);
91 }
std::atomic< uint64_t > codelMinDelayNs_
Definition: Codel.h:83
milliseconds folly::Codel::getSloughTimeout ( )

Definition at line 101 of file Codel.cpp.

References getTargetDelay().

Referenced by getLoad(), and overloaded().

101  {
102  return getTargetDelay() * 2;
103 }
std::chrono::milliseconds getTargetDelay()
Definition: Codel.cpp:97
milliseconds folly::Codel::getTargetDelay ( )

Definition at line 97 of file Codel.cpp.

Referenced by getSloughTimeout(), and overloaded().

97  {
98  return milliseconds(FLAGS_codel_target_delay);
99 }
bool folly::Codel::overloaded ( std::chrono::nanoseconds  delay)

Returns true if this request should be expired to reduce overload. In detail, this returns true if min_delay > target_delay for the interval, and this delay > 2 * target_delay.

As you may guess, we observe the clock so this is time sensitive. Call it promptly after calculating queueing delay.

Definition at line 37 of file Codel.cpp.

References codelIntervalTimeNs_, codelMinDelayNs_, codelResetDelay_, count, getInterval(), getSloughTimeout(), getTargetDelay(), now(), and overloaded_.

Referenced by TEST().

37  {
38  bool ret = false;
39  auto now = steady_clock::now();
40 
41  // Avoid another thread updating the value at the same time we are using it
42  // to calculate the overloaded state
43  auto minDelay = nanoseconds(codelMinDelayNs_);
44 
45  if (now > steady_clock::time_point(nanoseconds(codelIntervalTimeNs_)) &&
46  // testing before exchanging is more cacheline-friendly
47  (!codelResetDelay_.load(std::memory_order_acquire) &&
48  !codelResetDelay_.exchange(true))) {
50  duration_cast<nanoseconds>((now + getInterval()).time_since_epoch())
51  .count();
52 
53  if (minDelay > getTargetDelay()) {
54  overloaded_ = true;
55  } else {
56  overloaded_ = false;
57  }
58  }
59  // Care must be taken that only a single thread resets codelMinDelay_,
60  // and that it happens after the interval reset above
61  if (codelResetDelay_.load(std::memory_order_acquire) &&
62  codelResetDelay_.exchange(false)) {
63  codelMinDelayNs_ = delay.count();
64  // More than one request must come in during an interval before codel
65  // starts dropping requests
66  return false;
67  } else if (delay < nanoseconds(codelMinDelayNs_)) {
68  codelMinDelayNs_ = delay.count();
69  }
70 
71  // Here is where we apply different logic than codel proper. Instead of
72  // adapting the interval until the next drop, we slough off requests with
73  // queueing delay > 2*target_delay while in the overloaded regime. This
74  // empirically works better for our services than the codel approach of
75  // increasingly often dropping packets.
76  if (overloaded_ && delay > getSloughTimeout()) {
77  ret = true;
78  }
79 
80  return ret;
81 }
std::atomic< bool > overloaded_
Definition: Codel.h:90
std::chrono::milliseconds getTargetDelay()
Definition: Codel.cpp:97
std::chrono::steady_clock::time_point now()
std::atomic< uint64_t > codelIntervalTimeNs_
Definition: Codel.h:84
std::atomic< bool > codelResetDelay_
Definition: Codel.h:88
std::chrono::milliseconds getInterval()
Definition: Codel.cpp:93
int * count
std::atomic< uint64_t > codelMinDelayNs_
Definition: Codel.h:83
std::chrono::milliseconds getSloughTimeout()
Definition: Codel.cpp:101

Member Data Documentation

std::atomic<uint64_t> folly::Codel::codelIntervalTimeNs_
private

Definition at line 84 of file Codel.h.

Referenced by overloaded().

std::atomic<uint64_t> folly::Codel::codelMinDelayNs_
private

Definition at line 83 of file Codel.h.

Referenced by getMinDelay(), and overloaded().

std::atomic<bool> folly::Codel::codelResetDelay_
private

Definition at line 88 of file Codel.h.

Referenced by overloaded().

std::atomic<bool> folly::Codel::overloaded_
private

Definition at line 90 of file Codel.h.

Referenced by overloaded().


The documentation for this class was generated from the following files: