1 /* * Copyright (c) 2012-2021, 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 CIRCUITMUX_EWMA_PRIVATE
37 #include "core/or/or.h"
38 #include "core/or/circuitmux.h"
39 #include "core/or/circuitmux_ewma.h"
40 #include "lib/crypt_ops/crypto_rand.h"
41 #include "lib/crypt_ops/crypto_util.h"
42 #include "feature/nodelist/networkstatus.h"
43 #include "app/config/or_options_st.h"
45 /*** EWMA parameter #defines ***/
47 /** How long does a tick last (seconds)? */
48 #define EWMA_TICK_LEN_DEFAULT 10
49 #define EWMA_TICK_LEN_MIN 1
50 #define EWMA_TICK_LEN_MAX 600
51 static int ewma_tick_len
= EWMA_TICK_LEN_DEFAULT
;
53 /** The default per-tick scale factor, if it hasn't been overridden by a
54 * consensus or a configuration setting. zero means "disabled". */
55 #define EWMA_DEFAULT_HALFLIFE 0.0
57 /*** Some useful constant #defines ***/
59 /** Any halflife smaller than this number of seconds is considered to be
61 #define EPSILON 0.00001
62 /** The natural logarithm of 0.5. */
63 #define LOG_ONEHALF -0.69314718055994529
65 /*** Static declarations for circuitmux_ewma.c ***/
67 static void add_cell_ewma(ewma_policy_data_t
*pol
, cell_ewma_t
*ewma
);
68 static int compare_cell_ewma_counts(const void *p1
, const void *p2
);
69 static circuit_t
* cell_ewma_to_circuit(cell_ewma_t
*ewma
);
70 static inline double get_scale_factor(unsigned from_tick
, unsigned to_tick
);
71 static cell_ewma_t
* pop_first_cell_ewma(ewma_policy_data_t
*pol
);
72 static void remove_cell_ewma(ewma_policy_data_t
*pol
, cell_ewma_t
*ewma
);
73 static void scale_single_cell_ewma(cell_ewma_t
*ewma
, unsigned cur_tick
);
74 static void scale_active_circuits(ewma_policy_data_t
*pol
,
77 /*** Circuitmux policy methods ***/
79 static circuitmux_policy_data_t
* ewma_alloc_cmux_data(circuitmux_t
*cmux
);
80 static void ewma_free_cmux_data(circuitmux_t
*cmux
,
81 circuitmux_policy_data_t
*pol_data
);
82 static circuitmux_policy_circ_data_t
*
83 ewma_alloc_circ_data(circuitmux_t
*cmux
, circuitmux_policy_data_t
*pol_data
,
84 circuit_t
*circ
, cell_direction_t direction
,
85 unsigned int cell_count
);
87 ewma_free_circ_data(circuitmux_t
*cmux
,
88 circuitmux_policy_data_t
*pol_data
,
90 circuitmux_policy_circ_data_t
*pol_circ_data
);
92 ewma_notify_circ_active(circuitmux_t
*cmux
,
93 circuitmux_policy_data_t
*pol_data
,
95 circuitmux_policy_circ_data_t
*pol_circ_data
);
97 ewma_notify_circ_inactive(circuitmux_t
*cmux
,
98 circuitmux_policy_data_t
*pol_data
,
100 circuitmux_policy_circ_data_t
*pol_circ_data
);
102 ewma_notify_xmit_cells(circuitmux_t
*cmux
,
103 circuitmux_policy_data_t
*pol_data
,
105 circuitmux_policy_circ_data_t
*pol_circ_data
,
106 unsigned int n_cells
);
108 ewma_pick_active_circuit(circuitmux_t
*cmux
,
109 circuitmux_policy_data_t
*pol_data
);
111 ewma_cmp_cmux(circuitmux_t
*cmux_1
, circuitmux_policy_data_t
*pol_data_1
,
112 circuitmux_t
*cmux_2
, circuitmux_policy_data_t
*pol_data_2
);
114 /*** EWMA global variables ***/
116 /** The per-tick scale factor to be used when computing cell-count EWMA
117 * values. (A cell sent N ticks before the start of the current tick
118 * has value ewma_scale_factor ** N.)
120 static double ewma_scale_factor
= 0.1;
122 /*** EWMA circuitmux_policy_t method table ***/
124 circuitmux_policy_t ewma_policy
= {
125 /*.alloc_cmux_data =*/ ewma_alloc_cmux_data
,
126 /*.free_cmux_data =*/ ewma_free_cmux_data
,
127 /*.alloc_circ_data =*/ ewma_alloc_circ_data
,
128 /*.free_circ_data =*/ ewma_free_circ_data
,
129 /*.notify_circ_active =*/ ewma_notify_circ_active
,
130 /*.notify_circ_inactive =*/ ewma_notify_circ_inactive
,
131 /*.notify_set_n_cells =*/ NULL
, /* EWMA doesn't need this */
132 /*.notify_xmit_cells =*/ ewma_notify_xmit_cells
,
133 /*.pick_active_circuit =*/ ewma_pick_active_circuit
,
134 /*.cmp_cmux =*/ ewma_cmp_cmux
137 /** Have we initialized the ewma tick-counting logic? */
138 static int ewma_ticks_initialized
= 0;
139 /** At what monotime_coarse_t did the current tick begin? */
140 static monotime_coarse_t start_of_current_tick
;
141 /** What is the number of the current tick? */
142 static unsigned current_tick_num
;
144 /*** EWMA method implementations using the below EWMA helper functions ***/
146 /** Compute and return the current cell_ewma tick. */
147 static inline unsigned int
148 cell_ewma_get_tick(void)
150 monotime_coarse_t now
;
151 monotime_coarse_get(&now
);
152 int32_t msec_diff
= monotime_coarse_diff_msec32(&start_of_current_tick
,
154 return current_tick_num
+ msec_diff
/ (1000*ewma_tick_len
);
158 * Allocate an ewma_policy_data_t and upcast it to a circuitmux_policy_data_t;
159 * this is called when setting the policy on a circuitmux_t to ewma_policy.
162 static circuitmux_policy_data_t
*
163 ewma_alloc_cmux_data(circuitmux_t
*cmux
)
165 ewma_policy_data_t
*pol
= NULL
;
169 pol
= tor_malloc_zero(sizeof(*pol
));
170 pol
->base_
.magic
= EWMA_POL_DATA_MAGIC
;
171 pol
->active_circuit_pqueue
= smartlist_new();
172 pol
->active_circuit_pqueue_last_recalibrated
= cell_ewma_get_tick();
174 return TO_CMUX_POL_DATA(pol
);
178 * Free an ewma_policy_data_t allocated with ewma_alloc_cmux_data()
182 ewma_free_cmux_data(circuitmux_t
*cmux
,
183 circuitmux_policy_data_t
*pol_data
)
185 ewma_policy_data_t
*pol
= NULL
;
188 if (!pol_data
) return;
190 pol
= TO_EWMA_POL_DATA(pol_data
);
192 smartlist_free(pol
->active_circuit_pqueue
);
193 memwipe(pol
, 0xda, sizeof(ewma_policy_data_t
));
198 * Allocate an ewma_policy_circ_data_t and upcast it to a
199 * circuitmux_policy_data_t; this is called when attaching a circuit to a
200 * circuitmux_t with ewma_policy.
203 static circuitmux_policy_circ_data_t
*
204 ewma_alloc_circ_data(circuitmux_t
*cmux
,
205 circuitmux_policy_data_t
*pol_data
,
207 cell_direction_t direction
,
208 unsigned int cell_count
)
210 ewma_policy_circ_data_t
*cdata
= NULL
;
213 tor_assert(pol_data
);
215 tor_assert(direction
== CELL_DIRECTION_OUT
||
216 direction
== CELL_DIRECTION_IN
);
217 /* Shut the compiler up without triggering -Wtautological-compare */
220 cdata
= tor_malloc_zero(sizeof(*cdata
));
221 cdata
->base_
.magic
= EWMA_POL_CIRC_DATA_MAGIC
;
225 * Initialize the cell_ewma_t structure (formerly in
226 * init_circuit_base())
228 cdata
->cell_ewma
.last_adjusted_tick
= cell_ewma_get_tick();
229 cdata
->cell_ewma
.cell_count
= 0.0;
230 cdata
->cell_ewma
.heap_index
= -1;
231 if (direction
== CELL_DIRECTION_IN
) {
232 cdata
->cell_ewma
.is_for_p_chan
= 1;
234 cdata
->cell_ewma
.is_for_p_chan
= 0;
237 return TO_CMUX_POL_CIRC_DATA(cdata
);
241 * Free an ewma_policy_circ_data_t allocated with ewma_alloc_circ_data()
245 ewma_free_circ_data(circuitmux_t
*cmux
,
246 circuitmux_policy_data_t
*pol_data
,
248 circuitmux_policy_circ_data_t
*pol_circ_data
)
251 ewma_policy_circ_data_t
*cdata
= NULL
;
255 tor_assert(pol_data
);
257 if (!pol_circ_data
) return;
259 cdata
= TO_EWMA_POL_CIRC_DATA(pol_circ_data
);
260 memwipe(cdata
, 0xdc, sizeof(ewma_policy_circ_data_t
));
265 * Handle circuit activation; this inserts the circuit's cell_ewma into
266 * the active_circuits_pqueue.
270 ewma_notify_circ_active(circuitmux_t
*cmux
,
271 circuitmux_policy_data_t
*pol_data
,
273 circuitmux_policy_circ_data_t
*pol_circ_data
)
275 ewma_policy_data_t
*pol
= NULL
;
276 ewma_policy_circ_data_t
*cdata
= NULL
;
279 tor_assert(pol_data
);
281 tor_assert(pol_circ_data
);
283 pol
= TO_EWMA_POL_DATA(pol_data
);
284 cdata
= TO_EWMA_POL_CIRC_DATA(pol_circ_data
);
286 add_cell_ewma(pol
, &(cdata
->cell_ewma
));
290 * Handle circuit deactivation; this removes the circuit's cell_ewma from
291 * the active_circuits_pqueue.
295 ewma_notify_circ_inactive(circuitmux_t
*cmux
,
296 circuitmux_policy_data_t
*pol_data
,
298 circuitmux_policy_circ_data_t
*pol_circ_data
)
300 ewma_policy_data_t
*pol
= NULL
;
301 ewma_policy_circ_data_t
*cdata
= NULL
;
304 tor_assert(pol_data
);
306 tor_assert(pol_circ_data
);
308 pol
= TO_EWMA_POL_DATA(pol_data
);
309 cdata
= TO_EWMA_POL_CIRC_DATA(pol_circ_data
);
311 remove_cell_ewma(pol
, &(cdata
->cell_ewma
));
315 * Update cell_ewma for this circuit after we've sent some cells, and
316 * remove/reinsert it in the queue. This used to be done (brokenly,
317 * see bug 6816) in channel_flush_from_first_active_circuit().
321 ewma_notify_xmit_cells(circuitmux_t
*cmux
,
322 circuitmux_policy_data_t
*pol_data
,
324 circuitmux_policy_circ_data_t
*pol_circ_data
,
325 unsigned int n_cells
)
327 ewma_policy_data_t
*pol
= NULL
;
328 ewma_policy_circ_data_t
*cdata
= NULL
;
330 double fractional_tick
, ewma_increment
;
331 cell_ewma_t
*cell_ewma
, *tmp
;
334 tor_assert(pol_data
);
336 tor_assert(pol_circ_data
);
337 tor_assert(n_cells
> 0);
339 pol
= TO_EWMA_POL_DATA(pol_data
);
340 cdata
= TO_EWMA_POL_CIRC_DATA(pol_circ_data
);
342 /* Rescale the EWMAs if needed */
343 tick
= cell_ewma_get_current_tick_and_fraction(&fractional_tick
);
345 if (tick
!= pol
->active_circuit_pqueue_last_recalibrated
) {
346 scale_active_circuits(pol
, tick
);
349 /* How much do we adjust the cell count in cell_ewma by? */
351 ((double)(n_cells
)) * pow(ewma_scale_factor
, -fractional_tick
);
353 /* Do the adjustment */
354 cell_ewma
= &(cdata
->cell_ewma
);
355 cell_ewma
->cell_count
+= ewma_increment
;
358 * Since we just sent on this circuit, it should be at the head of
359 * the queue. Pop the head, assert that it matches, then re-add.
361 tmp
= pop_first_cell_ewma(pol
);
362 tor_assert(tmp
== cell_ewma
);
363 add_cell_ewma(pol
, cell_ewma
);
367 * Pick the preferred circuit to send from; this will be the one with
368 * the lowest EWMA value in the priority queue. This used to be done
369 * in channel_flush_from_first_active_circuit().
373 ewma_pick_active_circuit(circuitmux_t
*cmux
,
374 circuitmux_policy_data_t
*pol_data
)
376 ewma_policy_data_t
*pol
= NULL
;
377 circuit_t
*circ
= NULL
;
378 cell_ewma_t
*cell_ewma
= NULL
;
381 tor_assert(pol_data
);
383 pol
= TO_EWMA_POL_DATA(pol_data
);
385 if (smartlist_len(pol
->active_circuit_pqueue
) > 0) {
386 /* Get the head of the queue */
387 cell_ewma
= smartlist_get(pol
->active_circuit_pqueue
, 0);
388 circ
= cell_ewma_to_circuit(cell_ewma
);
395 * Compare two EWMA cmuxes, and return -1, 0 or 1 to indicate which should
396 * be more preferred - see circuitmux_compare_muxes() of circuitmux.c.
400 ewma_cmp_cmux(circuitmux_t
*cmux_1
, circuitmux_policy_data_t
*pol_data_1
,
401 circuitmux_t
*cmux_2
, circuitmux_policy_data_t
*pol_data_2
)
403 ewma_policy_data_t
*p1
= NULL
, *p2
= NULL
;
404 cell_ewma_t
*ce1
= NULL
, *ce2
= NULL
;
407 tor_assert(pol_data_1
);
409 tor_assert(pol_data_2
);
411 p1
= TO_EWMA_POL_DATA(pol_data_1
);
412 p2
= TO_EWMA_POL_DATA(pol_data_2
);
415 /* Get the head cell_ewma_t from each queue */
416 if (smartlist_len(p1
->active_circuit_pqueue
) > 0) {
417 ce1
= smartlist_get(p1
->active_circuit_pqueue
, 0);
420 if (smartlist_len(p2
->active_circuit_pqueue
) > 0) {
421 ce2
= smartlist_get(p2
->active_circuit_pqueue
, 0);
424 /* Got both of them? */
425 if (ce1
!= NULL
&& ce2
!= NULL
) {
426 /* Pick whichever one has the better best circuit */
427 return compare_cell_ewma_counts(ce1
, ce2
);
430 /* We only have a circuit on cmux_1, so prefer it */
432 } else if (ce2
!= NULL
) {
433 /* We only have a circuit on cmux_2, so prefer it */
436 /* No circuits at all; no preference */
441 /* We got identical params */
446 /** Helper for sorting cell_ewma_t values in their priority queue. */
448 compare_cell_ewma_counts(const void *p1
, const void *p2
)
450 const cell_ewma_t
*e1
= p1
, *e2
= p2
;
452 if (e1
->cell_count
< e2
->cell_count
)
454 else if (e1
->cell_count
> e2
->cell_count
)
460 /** Given a cell_ewma_t, return a pointer to the circuit containing it. */
462 cell_ewma_to_circuit(cell_ewma_t
*ewma
)
464 ewma_policy_circ_data_t
*cdata
= NULL
;
467 cdata
= SUBTYPE_P(ewma
, ewma_policy_circ_data_t
, cell_ewma
);
473 /* ==== Functions for scaling cell_ewma_t ====
475 When choosing which cells to relay first, we favor circuits that have been
476 quiet recently. This gives better latency on connections that aren't
477 pushing lots of data, and makes the network feel more interactive.
479 Conceptually, we take an exponentially weighted mean average of the number
480 of cells a circuit has sent, and allow active circuits (those with cells to
481 relay) to send cells in reverse order of their exponentially-weighted mean
482 average (EWMA) cell count. [That is, a cell sent N seconds ago 'counts'
483 F^N times as much as a cell sent now, for 0<F<1.0, and we favor the
484 circuit that has sent the fewest cells]
486 If 'double' had infinite precision, we could do this simply by counting a
487 cell sent at startup as having weight 1.0, and a cell sent N seconds later
488 as having weight F^-N. This way, we would never need to re-scale
489 any already-sent cells.
491 To prevent double from overflowing, we could count a cell sent now as
492 having weight 1.0 and a cell sent N seconds ago as having weight F^N.
493 This, however, would mean we'd need to re-scale *ALL* old circuits every
494 time we wanted to send a cell.
496 So as a compromise, we divide time into 'ticks' (currently, 10-second
497 increments) and say that a cell sent at the start of a current tick is
498 worth 1.0, a cell sent N seconds before the start of the current tick is
499 worth F^N, and a cell sent N seconds after the start of the current tick is
500 worth F^-N. This way we don't overflow, and we don't need to constantly
505 * Initialize the system that tells which ewma tick we are in.
508 cell_ewma_initialize_ticks(void)
510 if (ewma_ticks_initialized
)
512 monotime_coarse_get(&start_of_current_tick
);
513 crypto_rand((char*)¤t_tick_num
, sizeof(current_tick_num
));
514 ewma_ticks_initialized
= 1;
517 /** Compute the current cell_ewma tick and the fraction of the tick that has
518 * elapsed between the start of the tick and the current time. Return the
519 * former and store the latter in *<b>remainder_out</b>.
521 * These tick values are not meant to be shared between Tor instances, or used
522 * for other purposes. */
524 cell_ewma_get_current_tick_and_fraction(double *remainder_out
)
526 if (BUG(!ewma_ticks_initialized
)) {
527 cell_ewma_initialize_ticks(); // LCOV_EXCL_LINE
529 monotime_coarse_t now
;
530 monotime_coarse_get(&now
);
531 int32_t msec_diff
= monotime_coarse_diff_msec32(&start_of_current_tick
,
533 if (msec_diff
> (1000*ewma_tick_len
)) {
534 unsigned ticks_difference
= msec_diff
/ (1000*ewma_tick_len
);
535 monotime_coarse_add_msec(&start_of_current_tick
,
536 &start_of_current_tick
,
537 ticks_difference
* 1000 * ewma_tick_len
);
538 current_tick_num
+= ticks_difference
;
539 msec_diff
%= 1000*ewma_tick_len
;
541 *remainder_out
= ((double)msec_diff
) / (1.0e3
* ewma_tick_len
);
542 return current_tick_num
;
545 /* Default value for the CircuitPriorityHalflifeMsec consensus parameter in
547 #define CMUX_PRIORITY_HALFLIFE_MSEC_DEFAULT 30000
548 /* Minimum and maximum value for the CircuitPriorityHalflifeMsec consensus
550 #define CMUX_PRIORITY_HALFLIFE_MSEC_MIN 1
551 #define CMUX_PRIORITY_HALFLIFE_MSEC_MAX INT32_MAX
553 /* Return the value of the circuit priority halflife from the options if
554 * available or else from the consensus (in that order). If none can be found,
555 * a default value is returned.
557 * The source_msg points to a string describing from where the value was
558 * picked so it can be used for logging. */
560 get_circuit_priority_halflife(const or_options_t
*options
,
561 const networkstatus_t
*consensus
,
562 const char **source_msg
)
566 /* Compute the default value now. We might need it. */
567 double halflife_default
=
568 ((double) CMUX_PRIORITY_HALFLIFE_MSEC_DEFAULT
) / 1000.0;
570 /* Try to get it from configuration file first. */
571 if (options
&& options
->CircuitPriorityHalflife
>= -EPSILON
) {
572 halflife
= options
->CircuitPriorityHalflife
;
573 *source_msg
= "CircuitPriorityHalflife in configuration";
577 /* Try to get the msec value from the consensus. */
578 halflife_ms
= networkstatus_get_param(consensus
,
579 "CircuitPriorityHalflifeMsec",
580 CMUX_PRIORITY_HALFLIFE_MSEC_DEFAULT
,
581 CMUX_PRIORITY_HALFLIFE_MSEC_MIN
,
582 CMUX_PRIORITY_HALFLIFE_MSEC_MAX
);
583 halflife
= ((double) halflife_ms
) / 1000.0;
584 *source_msg
= "CircuitPriorityHalflifeMsec in consensus";
587 /* We should never go below the EPSILON else we would consider it disabled
588 * and we can't have that. */
589 if (halflife
< EPSILON
) {
590 log_warn(LD_CONFIG
, "CircuitPriorityHalflife is too small (%f). "
591 "Adjusting to the smallest value allowed: %f.",
592 halflife
, halflife_default
);
593 halflife
= halflife_default
;
598 /** Adjust the global cell scale factor based on <b>options</b> */
600 cmux_ewma_set_options(const or_options_t
*options
,
601 const networkstatus_t
*consensus
)
606 cell_ewma_initialize_ticks();
608 /* Both options and consensus can be NULL. This assures us to either get a
609 * valid configured value or the default one. */
610 halflife
= get_circuit_priority_halflife(options
, consensus
, &source
);
611 ewma_tick_len
= networkstatus_get_param(consensus
,
612 "CircuitPriorityTickSecs",
613 EWMA_TICK_LEN_DEFAULT
,
617 /* convert halflife into halflife-per-tick. */
618 halflife
/= ewma_tick_len
;
619 /* compute per-tick scale factor. */
620 ewma_scale_factor
= exp(LOG_ONEHALF
/ halflife
);
622 "Enabled cell_ewma algorithm because of value in %s; "
623 "scale factor is %f per %d seconds",
624 source
, ewma_scale_factor
, ewma_tick_len
);
627 /** Return the multiplier necessary to convert the value of a cell sent in
628 * 'from_tick' to one sent in 'to_tick'. */
630 get_scale_factor(unsigned from_tick
, unsigned to_tick
)
632 /* This math can wrap around, but that's okay: unsigned overflow is
634 int diff
= (int)(to_tick
- from_tick
);
635 return pow(ewma_scale_factor
, diff
);
638 /** Adjust the cell count of <b>ewma</b> so that it is scaled with respect to
641 scale_single_cell_ewma(cell_ewma_t
*ewma
, unsigned cur_tick
)
643 double factor
= get_scale_factor(ewma
->last_adjusted_tick
, cur_tick
);
644 ewma
->cell_count
*= factor
;
645 ewma
->last_adjusted_tick
= cur_tick
;
648 /** Adjust the cell count of every active circuit on <b>chan</b> so
649 * that they are scaled with respect to <b>cur_tick</b> */
651 scale_active_circuits(ewma_policy_data_t
*pol
, unsigned cur_tick
)
656 tor_assert(pol
->active_circuit_pqueue
);
660 pol
->active_circuit_pqueue_last_recalibrated
,
662 /** Ordinarily it isn't okay to change the value of an element in a heap,
663 * but it's okay here, since we are preserving the order. */
664 SMARTLIST_FOREACH_BEGIN(
665 pol
->active_circuit_pqueue
,
667 tor_assert(e
->last_adjusted_tick
==
668 pol
->active_circuit_pqueue_last_recalibrated
);
669 e
->cell_count
*= factor
;
670 e
->last_adjusted_tick
= cur_tick
;
671 } SMARTLIST_FOREACH_END(e
);
672 pol
->active_circuit_pqueue_last_recalibrated
= cur_tick
;
675 /** Rescale <b>ewma</b> to the same scale as <b>pol</b>, and add it to
676 * <b>pol</b>'s priority queue of active circuits */
678 add_cell_ewma(ewma_policy_data_t
*pol
, cell_ewma_t
*ewma
)
681 tor_assert(pol
->active_circuit_pqueue
);
683 tor_assert(ewma
->heap_index
== -1);
685 scale_single_cell_ewma(
687 pol
->active_circuit_pqueue_last_recalibrated
);
689 smartlist_pqueue_add(pol
->active_circuit_pqueue
,
690 compare_cell_ewma_counts
,
691 offsetof(cell_ewma_t
, heap_index
),
695 /** Remove <b>ewma</b> from <b>pol</b>'s priority queue of active circuits */
697 remove_cell_ewma(ewma_policy_data_t
*pol
, cell_ewma_t
*ewma
)
700 tor_assert(pol
->active_circuit_pqueue
);
702 tor_assert(ewma
->heap_index
!= -1);
704 smartlist_pqueue_remove(pol
->active_circuit_pqueue
,
705 compare_cell_ewma_counts
,
706 offsetof(cell_ewma_t
, heap_index
),
710 /** Remove and return the first cell_ewma_t from pol's priority queue of
711 * active circuits. Requires that the priority queue is nonempty. */
713 pop_first_cell_ewma(ewma_policy_data_t
*pol
)
716 tor_assert(pol
->active_circuit_pqueue
);
718 return smartlist_pqueue_pop(pol
->active_circuit_pqueue
,
719 compare_cell_ewma_counts
,
720 offsetof(cell_ewma_t
, heap_index
));
724 * Drop all resources held by circuitmux_ewma.c, and deinitialize the
727 circuitmux_ewma_free_all(void)
729 ewma_ticks_initialized
= 0;