Avoid crashing if we call num_usable_bridges() when bridges are not enabled
[tor/appveyor.git] / src / or / circuitmux_ewma.c
blobfde2d22a8934b2307e532c2f5fcf0c6cbe9f5c4b
1 /* * Copyright (c) 2012-2017, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 /**
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
27 * implements.
29 **/
31 #define TOR_CIRCUITMUX_EWMA_C_
33 #include "orconfig.h"
35 #include <math.h>
37 #include "or.h"
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
54 * "disabled". */
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;
65 /**
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().
72 struct cell_ewma_s {
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. */
80 double cell_count;
81 /** True iff this is the cell count for a circuit's previous
82 * channel. */
83 unsigned int is_for_p_chan : 1;
84 /** The position of the circuit within the OR connection's priority
85 * queue. */
86 int heap_index;
89 struct ewma_policy_data_s {
90 circuitmux_policy_data_t base_;
92 /**
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.
124 circuit_t *circ;
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;
147 else {
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;
162 else {
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,
180 unsigned cur_tick);
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);
191 static void
192 ewma_free_circ_data(circuitmux_t *cmux,
193 circuitmux_policy_data_t *pol_data,
194 circuit_t *circ,
195 circuitmux_policy_circ_data_t *pol_circ_data);
196 static void
197 ewma_notify_circ_active(circuitmux_t *cmux,
198 circuitmux_policy_data_t *pol_data,
199 circuit_t *circ,
200 circuitmux_policy_circ_data_t *pol_circ_data);
201 static void
202 ewma_notify_circ_inactive(circuitmux_t *cmux,
203 circuitmux_policy_data_t *pol_data,
204 circuit_t *circ,
205 circuitmux_policy_circ_data_t *pol_circ_data);
206 static void
207 ewma_notify_xmit_cells(circuitmux_t *cmux,
208 circuitmux_policy_data_t *pol_data,
209 circuit_t *circ,
210 circuitmux_policy_circ_data_t *pol_circ_data,
211 unsigned int n_cells);
212 static circuit_t *
213 ewma_pick_active_circuit(circuitmux_t *cmux,
214 circuitmux_policy_data_t *pol_data);
215 static int
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;
256 tor_assert(cmux);
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()
270 static void
271 ewma_free_cmux_data(circuitmux_t *cmux,
272 circuitmux_policy_data_t *pol_data)
274 ewma_policy_data_t *pol = NULL;
276 tor_assert(cmux);
277 if (!pol_data) return;
279 pol = TO_EWMA_POL_DATA(pol_data);
281 smartlist_free(pol->active_circuit_pqueue);
282 tor_free(pol);
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,
294 circuit_t *circ,
295 cell_direction_t direction,
296 unsigned int cell_count)
298 ewma_policy_circ_data_t *cdata = NULL;
300 tor_assert(cmux);
301 tor_assert(pol_data);
302 tor_assert(circ);
303 tor_assert(direction == CELL_DIRECTION_OUT ||
304 direction == CELL_DIRECTION_IN);
305 /* Shut the compiler up without triggering -Wtautological-compare */
306 (void)cell_count;
308 cdata = tor_malloc_zero(sizeof(*cdata));
309 cdata->base_.magic = EWMA_POL_CIRC_DATA_MAGIC;
310 cdata->circ = circ;
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;
321 } else {
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()
332 static void
333 ewma_free_circ_data(circuitmux_t *cmux,
334 circuitmux_policy_data_t *pol_data,
335 circuit_t *circ,
336 circuitmux_policy_circ_data_t *pol_circ_data)
339 ewma_policy_circ_data_t *cdata = NULL;
341 tor_assert(cmux);
342 tor_assert(circ);
343 tor_assert(pol_data);
345 if (!pol_circ_data) return;
347 cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data);
349 tor_free(cdata);
353 * Handle circuit activation; this inserts the circuit's cell_ewma into
354 * the active_circuits_pqueue.
357 static void
358 ewma_notify_circ_active(circuitmux_t *cmux,
359 circuitmux_policy_data_t *pol_data,
360 circuit_t *circ,
361 circuitmux_policy_circ_data_t *pol_circ_data)
363 ewma_policy_data_t *pol = NULL;
364 ewma_policy_circ_data_t *cdata = NULL;
366 tor_assert(cmux);
367 tor_assert(pol_data);
368 tor_assert(circ);
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.
382 static void
383 ewma_notify_circ_inactive(circuitmux_t *cmux,
384 circuitmux_policy_data_t *pol_data,
385 circuit_t *circ,
386 circuitmux_policy_circ_data_t *pol_circ_data)
388 ewma_policy_data_t *pol = NULL;
389 ewma_policy_circ_data_t *cdata = NULL;
391 tor_assert(cmux);
392 tor_assert(pol_data);
393 tor_assert(circ);
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().
408 static void
409 ewma_notify_xmit_cells(circuitmux_t *cmux,
410 circuitmux_policy_data_t *pol_data,
411 circuit_t *circ,
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;
417 unsigned int tick;
418 double fractional_tick, ewma_increment;
419 /* The current (hi-res) time */
420 struct timeval now_hires;
421 cell_ewma_t *cell_ewma, *tmp;
423 tor_assert(cmux);
424 tor_assert(pol_data);
425 tor_assert(circ);
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? */
441 ewma_increment =
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().
463 static circuit_t *
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;
471 tor_assert(cmux);
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);
482 return circ;
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.
490 static int
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;
497 tor_assert(cmux_1);
498 tor_assert(pol_data_1);
499 tor_assert(cmux_2);
500 tor_assert(pol_data_2);
502 p1 = TO_EWMA_POL_DATA(pol_data_1);
503 p2 = TO_EWMA_POL_DATA(pol_data_2);
505 if (p1 != p2) {
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);
519 } else {
520 if (ce1 != NULL ) {
521 /* We only have a circuit on cmux_1, so prefer it */
522 return -1;
523 } else if (ce2 != NULL) {
524 /* We only have a circuit on cmux_2, so prefer it */
525 return 1;
526 } else {
527 /* No circuits at all; no preference */
528 return 0;
531 } else {
532 /* We got identical params */
533 return 0;
537 /** Helper for sorting cell_ewma_t values in their priority queue. */
538 static int
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)
544 return -1;
545 else if (e1->cell_count > e2->cell_count)
546 return 1;
547 else
548 return 0;
551 /** Given a cell_ewma_t, return a pointer to the circuit containing it. */
552 static circuit_t *
553 cell_ewma_to_circuit(cell_ewma_t *ewma)
555 ewma_policy_circ_data_t *cdata = NULL;
557 tor_assert(ewma);
558 cdata = SUBTYPE_P(ewma, ewma_policy_circ_data_t, cell_ewma);
559 tor_assert(cdata);
561 return cdata->circ;
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
592 rescale.
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. */
603 static unsigned
604 cell_ewma_tick_from_timeval(const struct timeval *now,
605 double *remainder_out)
607 unsigned res = (unsigned) (now->tv_sec / EWMA_TICK_LEN);
608 /* rem */
609 double rem = (now->tv_sec % EWMA_TICK_LEN) +
610 ((double)(now->tv_usec)) / 1.0e6;
611 *remainder_out = rem / EWMA_TICK_LEN;
612 return res;
615 /** Tell the caller whether ewma_enabled is set */
617 cell_ewma_enabled(void)
619 return ewma_enabled;
622 /** Compute and return the current cell_ewma tick. */
623 unsigned int
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> */
630 void
631 cell_ewma_set_scale_factor(const or_options_t *options,
632 const networkstatus_t *consensus)
634 int32_t halflife_ms;
635 double halflife;
636 const char *source;
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";
645 } else {
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;
653 ewma_enabled = 0;
654 log_info(LD_OR,
655 "Disabled cell_ewma algorithm because of value in %s",
656 source);
657 } else {
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 );
662 ewma_enabled = 1;
663 log_info(LD_OR,
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'. */
672 static inline double
673 get_scale_factor(unsigned from_tick, unsigned to_tick)
675 /* This math can wrap around, but that's okay: unsigned overflow is
676 well-defined */
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
682 * <b>cur_tick</b> */
683 static void
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> */
693 static void
694 scale_active_circuits(ewma_policy_data_t *pol, unsigned cur_tick)
696 double factor;
698 tor_assert(pol);
699 tor_assert(pol->active_circuit_pqueue);
701 factor =
702 get_scale_factor(
703 pol->active_circuit_pqueue_last_recalibrated,
704 cur_tick);
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,
709 cell_ewma_t *, e) {
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 */
720 static void
721 add_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma)
723 tor_assert(pol);
724 tor_assert(pol->active_circuit_pqueue);
725 tor_assert(ewma);
726 tor_assert(ewma->heap_index == -1);
728 scale_single_cell_ewma(
729 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),
735 ewma);
738 /** Remove <b>ewma</b> from <b>pol</b>'s priority queue of active circuits */
739 static void
740 remove_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma)
742 tor_assert(pol);
743 tor_assert(pol->active_circuit_pqueue);
744 tor_assert(ewma);
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),
750 ewma);
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. */
755 static cell_ewma_t *
756 pop_first_cell_ewma(ewma_policy_data_t *pol)
758 tor_assert(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));