1 /* * Copyright (c) 2012-2017, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
5 * \file circuitmux_ewma.c
6 * \brief EWMA circuit selection as a circuitmux_t policy
8 * The "EWMA" in this module stands for the "exponentially weighted moving
9 * average" of the number of cells sent on each circuit. The goal is to
10 * prioritize cells on circuits that have been quiet recently, by looking at
11 * those that have sent few cells over time, prioritizing recent times
12 * more than older ones.
14 * Specifically, a cell sent at time "now" has weight 1, but a time X ticks
15 * before now has weight ewma_scale_factor ^ X , where ewma_scale_factor is
16 * between 0.0 and 1.0.
18 * For efficiency, we do not re-scale these averages every time we send a
19 * cell: that would be horribly inefficient. Instead, we we keep the cell
20 * count on all circuits on the same circuitmux scaled relative to a single
21 * tick. When we add a new cell, we scale its weight depending on the time
22 * that has elapsed since the tick. We do re-scale the circuits on the
23 * circuitmux periodically, so that we don't overflow double.
26 * This module should be used through the interfaces in circuitmux.c, which it
31 #define TOR_CIRCUITMUX_EWMA_C_
38 #include "circuitmux.h"
39 #include "circuitmux_ewma.h"
40 #include "networkstatus.h"
42 /*** EWMA parameter #defines ***/
44 /** How long does a tick last (seconds)? */
45 #define EWMA_TICK_LEN 10
47 /** The default per-tick scale factor, if it hasn't been overridden by a
48 * consensus or a configuration setting. zero means "disabled". */
49 #define EWMA_DEFAULT_HALFLIFE 0.0
51 /*** Some useful constant #defines ***/
53 /** Any halflife smaller than this number of seconds is considered to be
55 #define EPSILON 0.00001
56 /** The natural logarithm of 0.5. */
57 #define LOG_ONEHALF -0.69314718055994529
59 /*** EWMA structures ***/
61 typedef struct cell_ewma_s cell_ewma_t
;
62 typedef struct ewma_policy_data_s ewma_policy_data_t
;
63 typedef struct ewma_policy_circ_data_s ewma_policy_circ_data_t
;
66 * The cell_ewma_t structure keeps track of how many cells a circuit has
67 * transferred recently. It keeps an EWMA (exponentially weighted moving
68 * average) of the number of cells flushed from the circuit queue onto a
69 * connection in channel_flush_from_first_active_circuit().
73 /** The last 'tick' at which we recalibrated cell_count.
75 * A cell sent at exactly the start of this tick has weight 1.0. Cells sent
76 * since the start of this tick have weight greater than 1.0; ones sent
77 * earlier have less weight. */
78 unsigned int last_adjusted_tick
;
79 /** The EWMA of the cell count. */
81 /** True iff this is the cell count for a circuit's previous
83 unsigned int is_for_p_chan
: 1;
84 /** The position of the circuit within the OR connection's priority
89 struct ewma_policy_data_s
{
90 circuitmux_policy_data_t base_
;
93 * Priority queue of cell_ewma_t for circuits with queued cells waiting
94 * for room to free up on the channel that owns this circuitmux. Kept
95 * in heap order according to EWMA. This was formerly in channel_t, and
96 * in or_connection_t before that.
98 smartlist_t
*active_circuit_pqueue
;
101 * The tick on which the cell_ewma_ts in active_circuit_pqueue last had
102 * their ewma values rescaled. This was formerly in channel_t, and in
103 * or_connection_t before that.
105 unsigned int active_circuit_pqueue_last_recalibrated
;
108 struct ewma_policy_circ_data_s
{
109 circuitmux_policy_circ_data_t base_
;
112 * The EWMA count for the number of cells flushed from this circuit
113 * onto this circuitmux. Used to determine which circuit to flush
114 * from next. This was formerly in circuit_t and or_circuit_t.
116 cell_ewma_t cell_ewma
;
119 * Pointer back to the circuit_t this is for; since we're separating
120 * out circuit selection policy like this, we can't attach cell_ewma_t
121 * to the circuit_t any more, so we can't use SUBTYPE_P directly to a
122 * circuit_t like before; instead get it here.
127 #define EWMA_POL_DATA_MAGIC 0x2fd8b16aU
128 #define EWMA_POL_CIRC_DATA_MAGIC 0x761e7747U
130 /*** Downcasts for the above types ***/
132 static ewma_policy_data_t
*
133 TO_EWMA_POL_DATA(circuitmux_policy_data_t
*);
135 static ewma_policy_circ_data_t
*
136 TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t
*);
139 * Downcast a circuitmux_policy_data_t to an ewma_policy_data_t and assert
140 * if the cast is impossible.
143 static inline ewma_policy_data_t
*
144 TO_EWMA_POL_DATA(circuitmux_policy_data_t
*pol
)
146 if (!pol
) return NULL
;
148 tor_assert(pol
->magic
== EWMA_POL_DATA_MAGIC
);
149 return DOWNCAST(ewma_policy_data_t
, pol
);
154 * Downcast a circuitmux_policy_circ_data_t to an ewma_policy_circ_data_t
155 * and assert if the cast is impossible.
158 static inline ewma_policy_circ_data_t
*
159 TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t
*pol
)
161 if (!pol
) return NULL
;
163 tor_assert(pol
->magic
== EWMA_POL_CIRC_DATA_MAGIC
);
164 return DOWNCAST(ewma_policy_circ_data_t
, pol
);
168 /*** Static declarations for circuitmux_ewma.c ***/
170 static void add_cell_ewma(ewma_policy_data_t
*pol
, cell_ewma_t
*ewma
);
171 static int compare_cell_ewma_counts(const void *p1
, const void *p2
);
172 static unsigned cell_ewma_tick_from_timeval(const struct timeval
*now
,
173 double *remainder_out
);
174 static circuit_t
* cell_ewma_to_circuit(cell_ewma_t
*ewma
);
175 static inline double get_scale_factor(unsigned from_tick
, unsigned to_tick
);
176 static cell_ewma_t
* pop_first_cell_ewma(ewma_policy_data_t
*pol
);
177 static void remove_cell_ewma(ewma_policy_data_t
*pol
, cell_ewma_t
*ewma
);
178 static void scale_single_cell_ewma(cell_ewma_t
*ewma
, unsigned cur_tick
);
179 static void scale_active_circuits(ewma_policy_data_t
*pol
,
182 /*** Circuitmux policy methods ***/
184 static circuitmux_policy_data_t
* ewma_alloc_cmux_data(circuitmux_t
*cmux
);
185 static void ewma_free_cmux_data(circuitmux_t
*cmux
,
186 circuitmux_policy_data_t
*pol_data
);
187 static circuitmux_policy_circ_data_t
*
188 ewma_alloc_circ_data(circuitmux_t
*cmux
, circuitmux_policy_data_t
*pol_data
,
189 circuit_t
*circ
, cell_direction_t direction
,
190 unsigned int cell_count
);
192 ewma_free_circ_data(circuitmux_t
*cmux
,
193 circuitmux_policy_data_t
*pol_data
,
195 circuitmux_policy_circ_data_t
*pol_circ_data
);
197 ewma_notify_circ_active(circuitmux_t
*cmux
,
198 circuitmux_policy_data_t
*pol_data
,
200 circuitmux_policy_circ_data_t
*pol_circ_data
);
202 ewma_notify_circ_inactive(circuitmux_t
*cmux
,
203 circuitmux_policy_data_t
*pol_data
,
205 circuitmux_policy_circ_data_t
*pol_circ_data
);
207 ewma_notify_xmit_cells(circuitmux_t
*cmux
,
208 circuitmux_policy_data_t
*pol_data
,
210 circuitmux_policy_circ_data_t
*pol_circ_data
,
211 unsigned int n_cells
);
213 ewma_pick_active_circuit(circuitmux_t
*cmux
,
214 circuitmux_policy_data_t
*pol_data
);
216 ewma_cmp_cmux(circuitmux_t
*cmux_1
, circuitmux_policy_data_t
*pol_data_1
,
217 circuitmux_t
*cmux_2
, circuitmux_policy_data_t
*pol_data_2
);
219 /*** EWMA global variables ***/
221 /** The per-tick scale factor to be used when computing cell-count EWMA
222 * values. (A cell sent N ticks before the start of the current tick
223 * has value ewma_scale_factor ** N.)
225 static double ewma_scale_factor
= 0.1;
226 /* DOCDOC ewma_enabled */
227 static int ewma_enabled
= 0;
229 /*** EWMA circuitmux_policy_t method table ***/
231 circuitmux_policy_t ewma_policy
= {
232 /*.alloc_cmux_data =*/ ewma_alloc_cmux_data
,
233 /*.free_cmux_data =*/ ewma_free_cmux_data
,
234 /*.alloc_circ_data =*/ ewma_alloc_circ_data
,
235 /*.free_circ_data =*/ ewma_free_circ_data
,
236 /*.notify_circ_active =*/ ewma_notify_circ_active
,
237 /*.notify_circ_inactive =*/ ewma_notify_circ_inactive
,
238 /*.notify_set_n_cells =*/ NULL
, /* EWMA doesn't need this */
239 /*.notify_xmit_cells =*/ ewma_notify_xmit_cells
,
240 /*.pick_active_circuit =*/ ewma_pick_active_circuit
,
241 /*.cmp_cmux =*/ ewma_cmp_cmux
244 /*** EWMA method implementations using the below EWMA helper functions ***/
247 * Allocate an ewma_policy_data_t and upcast it to a circuitmux_policy_data_t;
248 * this is called when setting the policy on a circuitmux_t to ewma_policy.
251 static circuitmux_policy_data_t
*
252 ewma_alloc_cmux_data(circuitmux_t
*cmux
)
254 ewma_policy_data_t
*pol
= NULL
;
258 pol
= tor_malloc_zero(sizeof(*pol
));
259 pol
->base_
.magic
= EWMA_POL_DATA_MAGIC
;
260 pol
->active_circuit_pqueue
= smartlist_new();
261 pol
->active_circuit_pqueue_last_recalibrated
= cell_ewma_get_tick();
263 return TO_CMUX_POL_DATA(pol
);
267 * Free an ewma_policy_data_t allocated with ewma_alloc_cmux_data()
271 ewma_free_cmux_data(circuitmux_t
*cmux
,
272 circuitmux_policy_data_t
*pol_data
)
274 ewma_policy_data_t
*pol
= NULL
;
277 if (!pol_data
) return;
279 pol
= TO_EWMA_POL_DATA(pol_data
);
281 smartlist_free(pol
->active_circuit_pqueue
);
286 * Allocate an ewma_policy_circ_data_t and upcast it to a
287 * circuitmux_policy_data_t; this is called when attaching a circuit to a
288 * circuitmux_t with ewma_policy.
291 static circuitmux_policy_circ_data_t
*
292 ewma_alloc_circ_data(circuitmux_t
*cmux
,
293 circuitmux_policy_data_t
*pol_data
,
295 cell_direction_t direction
,
296 unsigned int cell_count
)
298 ewma_policy_circ_data_t
*cdata
= NULL
;
301 tor_assert(pol_data
);
303 tor_assert(direction
== CELL_DIRECTION_OUT
||
304 direction
== CELL_DIRECTION_IN
);
305 /* Shut the compiler up without triggering -Wtautological-compare */
308 cdata
= tor_malloc_zero(sizeof(*cdata
));
309 cdata
->base_
.magic
= EWMA_POL_CIRC_DATA_MAGIC
;
313 * Initialize the cell_ewma_t structure (formerly in
314 * init_circuit_base())
316 cdata
->cell_ewma
.last_adjusted_tick
= cell_ewma_get_tick();
317 cdata
->cell_ewma
.cell_count
= 0.0;
318 cdata
->cell_ewma
.heap_index
= -1;
319 if (direction
== CELL_DIRECTION_IN
) {
320 cdata
->cell_ewma
.is_for_p_chan
= 1;
322 cdata
->cell_ewma
.is_for_p_chan
= 0;
325 return TO_CMUX_POL_CIRC_DATA(cdata
);
329 * Free an ewma_policy_circ_data_t allocated with ewma_alloc_circ_data()
333 ewma_free_circ_data(circuitmux_t
*cmux
,
334 circuitmux_policy_data_t
*pol_data
,
336 circuitmux_policy_circ_data_t
*pol_circ_data
)
339 ewma_policy_circ_data_t
*cdata
= NULL
;
343 tor_assert(pol_data
);
345 if (!pol_circ_data
) return;
347 cdata
= TO_EWMA_POL_CIRC_DATA(pol_circ_data
);
353 * Handle circuit activation; this inserts the circuit's cell_ewma into
354 * the active_circuits_pqueue.
358 ewma_notify_circ_active(circuitmux_t
*cmux
,
359 circuitmux_policy_data_t
*pol_data
,
361 circuitmux_policy_circ_data_t
*pol_circ_data
)
363 ewma_policy_data_t
*pol
= NULL
;
364 ewma_policy_circ_data_t
*cdata
= NULL
;
367 tor_assert(pol_data
);
369 tor_assert(pol_circ_data
);
371 pol
= TO_EWMA_POL_DATA(pol_data
);
372 cdata
= TO_EWMA_POL_CIRC_DATA(pol_circ_data
);
374 add_cell_ewma(pol
, &(cdata
->cell_ewma
));
378 * Handle circuit deactivation; this removes the circuit's cell_ewma from
379 * the active_circuits_pqueue.
383 ewma_notify_circ_inactive(circuitmux_t
*cmux
,
384 circuitmux_policy_data_t
*pol_data
,
386 circuitmux_policy_circ_data_t
*pol_circ_data
)
388 ewma_policy_data_t
*pol
= NULL
;
389 ewma_policy_circ_data_t
*cdata
= NULL
;
392 tor_assert(pol_data
);
394 tor_assert(pol_circ_data
);
396 pol
= TO_EWMA_POL_DATA(pol_data
);
397 cdata
= TO_EWMA_POL_CIRC_DATA(pol_circ_data
);
399 remove_cell_ewma(pol
, &(cdata
->cell_ewma
));
403 * Update cell_ewma for this circuit after we've sent some cells, and
404 * remove/reinsert it in the queue. This used to be done (brokenly,
405 * see bug 6816) in channel_flush_from_first_active_circuit().
409 ewma_notify_xmit_cells(circuitmux_t
*cmux
,
410 circuitmux_policy_data_t
*pol_data
,
412 circuitmux_policy_circ_data_t
*pol_circ_data
,
413 unsigned int n_cells
)
415 ewma_policy_data_t
*pol
= NULL
;
416 ewma_policy_circ_data_t
*cdata
= NULL
;
418 double fractional_tick
, ewma_increment
;
419 /* The current (hi-res) time */
420 struct timeval now_hires
;
421 cell_ewma_t
*cell_ewma
, *tmp
;
424 tor_assert(pol_data
);
426 tor_assert(pol_circ_data
);
427 tor_assert(n_cells
> 0);
429 pol
= TO_EWMA_POL_DATA(pol_data
);
430 cdata
= TO_EWMA_POL_CIRC_DATA(pol_circ_data
);
432 /* Rescale the EWMAs if needed */
433 tor_gettimeofday_cached(&now_hires
);
434 tick
= cell_ewma_tick_from_timeval(&now_hires
, &fractional_tick
);
436 if (tick
!= pol
->active_circuit_pqueue_last_recalibrated
) {
437 scale_active_circuits(pol
, tick
);
440 /* How much do we adjust the cell count in cell_ewma by? */
442 ((double)(n_cells
)) * pow(ewma_scale_factor
, -fractional_tick
);
444 /* Do the adjustment */
445 cell_ewma
= &(cdata
->cell_ewma
);
446 cell_ewma
->cell_count
+= ewma_increment
;
449 * Since we just sent on this circuit, it should be at the head of
450 * the queue. Pop the head, assert that it matches, then re-add.
452 tmp
= pop_first_cell_ewma(pol
);
453 tor_assert(tmp
== cell_ewma
);
454 add_cell_ewma(pol
, cell_ewma
);
458 * Pick the preferred circuit to send from; this will be the one with
459 * the lowest EWMA value in the priority queue. This used to be done
460 * in channel_flush_from_first_active_circuit().
464 ewma_pick_active_circuit(circuitmux_t
*cmux
,
465 circuitmux_policy_data_t
*pol_data
)
467 ewma_policy_data_t
*pol
= NULL
;
468 circuit_t
*circ
= NULL
;
469 cell_ewma_t
*cell_ewma
= NULL
;
472 tor_assert(pol_data
);
474 pol
= TO_EWMA_POL_DATA(pol_data
);
476 if (smartlist_len(pol
->active_circuit_pqueue
) > 0) {
477 /* Get the head of the queue */
478 cell_ewma
= smartlist_get(pol
->active_circuit_pqueue
, 0);
479 circ
= cell_ewma_to_circuit(cell_ewma
);
486 * Compare two EWMA cmuxes, and return -1, 0 or 1 to indicate which should
487 * be more preferred - see circuitmux_compare_muxes() of circuitmux.c.
491 ewma_cmp_cmux(circuitmux_t
*cmux_1
, circuitmux_policy_data_t
*pol_data_1
,
492 circuitmux_t
*cmux_2
, circuitmux_policy_data_t
*pol_data_2
)
494 ewma_policy_data_t
*p1
= NULL
, *p2
= NULL
;
495 cell_ewma_t
*ce1
= NULL
, *ce2
= NULL
;
498 tor_assert(pol_data_1
);
500 tor_assert(pol_data_2
);
502 p1
= TO_EWMA_POL_DATA(pol_data_1
);
503 p2
= TO_EWMA_POL_DATA(pol_data_2
);
506 /* Get the head cell_ewma_t from each queue */
507 if (smartlist_len(p1
->active_circuit_pqueue
) > 0) {
508 ce1
= smartlist_get(p1
->active_circuit_pqueue
, 0);
511 if (smartlist_len(p2
->active_circuit_pqueue
) > 0) {
512 ce2
= smartlist_get(p2
->active_circuit_pqueue
, 0);
515 /* Got both of them? */
516 if (ce1
!= NULL
&& ce2
!= NULL
) {
517 /* Pick whichever one has the better best circuit */
518 return compare_cell_ewma_counts(ce1
, ce2
);
521 /* We only have a circuit on cmux_1, so prefer it */
523 } else if (ce2
!= NULL
) {
524 /* We only have a circuit on cmux_2, so prefer it */
527 /* No circuits at all; no preference */
532 /* We got identical params */
537 /** Helper for sorting cell_ewma_t values in their priority queue. */
539 compare_cell_ewma_counts(const void *p1
, const void *p2
)
541 const cell_ewma_t
*e1
= p1
, *e2
= p2
;
543 if (e1
->cell_count
< e2
->cell_count
)
545 else if (e1
->cell_count
> e2
->cell_count
)
551 /** Given a cell_ewma_t, return a pointer to the circuit containing it. */
553 cell_ewma_to_circuit(cell_ewma_t
*ewma
)
555 ewma_policy_circ_data_t
*cdata
= NULL
;
558 cdata
= SUBTYPE_P(ewma
, ewma_policy_circ_data_t
, cell_ewma
);
564 /* ==== Functions for scaling cell_ewma_t ====
566 When choosing which cells to relay first, we favor circuits that have been
567 quiet recently. This gives better latency on connections that aren't
568 pushing lots of data, and makes the network feel more interactive.
570 Conceptually, we take an exponentially weighted mean average of the number
571 of cells a circuit has sent, and allow active circuits (those with cells to
572 relay) to send cells in reverse order of their exponentially-weighted mean
573 average (EWMA) cell count. [That is, a cell sent N seconds ago 'counts'
574 F^N times as much as a cell sent now, for 0<F<1.0, and we favor the
575 circuit that has sent the fewest cells]
577 If 'double' had infinite precision, we could do this simply by counting a
578 cell sent at startup as having weight 1.0, and a cell sent N seconds later
579 as having weight F^-N. This way, we would never need to re-scale
580 any already-sent cells.
582 To prevent double from overflowing, we could count a cell sent now as
583 having weight 1.0 and a cell sent N seconds ago as having weight F^N.
584 This, however, would mean we'd need to re-scale *ALL* old circuits every
585 time we wanted to send a cell.
587 So as a compromise, we divide time into 'ticks' (currently, 10-second
588 increments) and say that a cell sent at the start of a current tick is
589 worth 1.0, a cell sent N seconds before the start of the current tick is
590 worth F^N, and a cell sent N seconds after the start of the current tick is
591 worth F^-N. This way we don't overflow, and we don't need to constantly
595 /** Given a timeval <b>now</b>, compute the cell_ewma tick in which it occurs
596 * and the fraction of the tick that has elapsed between the start of the tick
597 * and <b>now</b>. Return the former and store the latter in
598 * *<b>remainder_out</b>.
600 * These tick values are not meant to be shared between Tor instances, or used
601 * for other purposes. */
604 cell_ewma_tick_from_timeval(const struct timeval
*now
,
605 double *remainder_out
)
607 unsigned res
= (unsigned) (now
->tv_sec
/ EWMA_TICK_LEN
);
609 double rem
= (now
->tv_sec
% EWMA_TICK_LEN
) +
610 ((double)(now
->tv_usec
)) / 1.0e6
;
611 *remainder_out
= rem
/ EWMA_TICK_LEN
;
615 /** Tell the caller whether ewma_enabled is set */
617 cell_ewma_enabled(void)
622 /** Compute and return the current cell_ewma tick. */
624 cell_ewma_get_tick(void)
626 return ((unsigned)approx_time() / EWMA_TICK_LEN
);
629 /** Adjust the global cell scale factor based on <b>options</b> */
631 cell_ewma_set_scale_factor(const or_options_t
*options
,
632 const networkstatus_t
*consensus
)
637 if (options
&& options
->CircuitPriorityHalflife
>= -EPSILON
) {
638 halflife
= options
->CircuitPriorityHalflife
;
639 source
= "CircuitPriorityHalflife in configuration";
640 } else if (consensus
&& (halflife_ms
= networkstatus_get_param(
641 consensus
, "CircuitPriorityHalflifeMsec",
642 -1, -1, INT32_MAX
)) >= 0) {
643 halflife
= ((double)halflife_ms
)/1000.0;
644 source
= "CircuitPriorityHalflifeMsec in consensus";
646 halflife
= EWMA_DEFAULT_HALFLIFE
;
647 source
= "Default value";
650 if (halflife
<= EPSILON
) {
651 /* The cell EWMA algorithm is disabled. */
652 ewma_scale_factor
= 0.1;
655 "Disabled cell_ewma algorithm because of value in %s",
658 /* convert halflife into halflife-per-tick. */
659 halflife
/= EWMA_TICK_LEN
;
660 /* compute per-tick scale factor. */
661 ewma_scale_factor
= exp( LOG_ONEHALF
/ halflife
);
664 "Enabled cell_ewma algorithm because of value in %s; "
665 "scale factor is %f per %d seconds",
666 source
, ewma_scale_factor
, EWMA_TICK_LEN
);
670 /** Return the multiplier necessary to convert the value of a cell sent in
671 * 'from_tick' to one sent in 'to_tick'. */
673 get_scale_factor(unsigned from_tick
, unsigned to_tick
)
675 /* This math can wrap around, but that's okay: unsigned overflow is
677 int diff
= (int)(to_tick
- from_tick
);
678 return pow(ewma_scale_factor
, diff
);
681 /** Adjust the cell count of <b>ewma</b> so that it is scaled with respect to
684 scale_single_cell_ewma(cell_ewma_t
*ewma
, unsigned cur_tick
)
686 double factor
= get_scale_factor(ewma
->last_adjusted_tick
, cur_tick
);
687 ewma
->cell_count
*= factor
;
688 ewma
->last_adjusted_tick
= cur_tick
;
691 /** Adjust the cell count of every active circuit on <b>chan</b> so
692 * that they are scaled with respect to <b>cur_tick</b> */
694 scale_active_circuits(ewma_policy_data_t
*pol
, unsigned cur_tick
)
699 tor_assert(pol
->active_circuit_pqueue
);
703 pol
->active_circuit_pqueue_last_recalibrated
,
705 /** Ordinarily it isn't okay to change the value of an element in a heap,
706 * but it's okay here, since we are preserving the order. */
707 SMARTLIST_FOREACH_BEGIN(
708 pol
->active_circuit_pqueue
,
710 tor_assert(e
->last_adjusted_tick
==
711 pol
->active_circuit_pqueue_last_recalibrated
);
712 e
->cell_count
*= factor
;
713 e
->last_adjusted_tick
= cur_tick
;
714 } SMARTLIST_FOREACH_END(e
);
715 pol
->active_circuit_pqueue_last_recalibrated
= cur_tick
;
718 /** Rescale <b>ewma</b> to the same scale as <b>pol</b>, and add it to
719 * <b>pol</b>'s priority queue of active circuits */
721 add_cell_ewma(ewma_policy_data_t
*pol
, cell_ewma_t
*ewma
)
724 tor_assert(pol
->active_circuit_pqueue
);
726 tor_assert(ewma
->heap_index
== -1);
728 scale_single_cell_ewma(
730 pol
->active_circuit_pqueue_last_recalibrated
);
732 smartlist_pqueue_add(pol
->active_circuit_pqueue
,
733 compare_cell_ewma_counts
,
734 offsetof(cell_ewma_t
, heap_index
),
738 /** Remove <b>ewma</b> from <b>pol</b>'s priority queue of active circuits */
740 remove_cell_ewma(ewma_policy_data_t
*pol
, cell_ewma_t
*ewma
)
743 tor_assert(pol
->active_circuit_pqueue
);
745 tor_assert(ewma
->heap_index
!= -1);
747 smartlist_pqueue_remove(pol
->active_circuit_pqueue
,
748 compare_cell_ewma_counts
,
749 offsetof(cell_ewma_t
, heap_index
),
753 /** Remove and return the first cell_ewma_t from pol's priority queue of
754 * active circuits. Requires that the priority queue is nonempty. */
756 pop_first_cell_ewma(ewma_policy_data_t
*pol
)
759 tor_assert(pol
->active_circuit_pqueue
);
761 return smartlist_pqueue_pop(pol
->active_circuit_pqueue
,
762 compare_cell_ewma_counts
,
763 offsetof(cell_ewma_t
, heap_index
));