diff --git a/changes/6153_circuittime_accessor b/changes/6153_circuittime_accessor
new file mode 100644
index 0000000000000000000000000000000000000000..16f1f557d5a49a93cc13fbd501e3c4cfc99c7570
--- /dev/null
+++ b/changes/6153_circuittime_accessor
@@ -0,0 +1,4 @@
+  o Code simplification and refactoring:
+
+    - Add a set of accessor functions for the circuit timeout data
+      structure. Fixes ticket 6153; patch from "piet".
diff --git a/src/or/channel.c b/src/or/channel.c
index 48bbf7902a07d18160f95c5cc71d39f0ca0545f9..7f395490c9e209d9c725e40b00c5c03a2f2897fc 100644
--- a/src/or/channel.c
+++ b/src/or/channel.c
@@ -2361,7 +2361,7 @@ channel_do_open_actions(channel_t *chan)
   started_here = channel_is_outgoing(chan);
 
   if (started_here) {
-    circuit_build_times_network_is_live(&circ_times);
+    circuit_build_times_network_is_live(get_circuit_build_times_mutable());
     rep_hist_note_connect_succeeded(chan->identity_digest, now);
     if (entry_guard_register_connect_status(
           chan->identity_digest, 1, 0, now) < 0) {
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 21fc2aeda36f40aa151427df38b56c448001e690..a203ceeef1cc74c88239fa757603b3c8a2332d4c 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -772,20 +772,24 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
          * it off at, we probably had a suspend event along this codepath,
          * and we should discard the value.
          */
-        if (timediff < 0 || timediff > 2*circ_times.close_ms+1000) {
+        if (timediff < 0 ||
+            timediff > 2*get_circuit_build_close_time_ms()+1000) {
           log_notice(LD_CIRC, "Strange value for circuit build time: %ldmsec. "
                               "Assuming clock jump. Purpose %d (%s)", timediff,
                      circ->base_.purpose,
                      circuit_purpose_to_string(circ->base_.purpose));
         } else if (!circuit_build_times_disabled()) {
           /* Only count circuit times if the network is live */
-          if (circuit_build_times_network_check_live(&circ_times)) {
-            circuit_build_times_add_time(&circ_times, (build_time_t)timediff);
-            circuit_build_times_set_timeout(&circ_times);
+          if (circuit_build_times_network_check_live(
+              get_circuit_build_times())) {
+            circuit_build_times_add_time(get_circuit_build_times_mutable(),
+                (build_time_t)timediff);
+            circuit_build_times_set_timeout(get_circuit_build_times_mutable());
           }
 
           if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
-            circuit_build_times_network_circ_success(&circ_times);
+            circuit_build_times_network_circ_success(
+                get_circuit_build_times_mutable());
           }
         }
       }
@@ -2273,7 +2277,7 @@ pathbias_measure_use_rate(entry_guard_t *guard)
                  tor_lround(guard->unusable_circuits),
                  tor_lround(guard->collapsed_circuits),
                  tor_lround(guard->timeouts),
-                 tor_lround(circ_times.close_ms/1000));
+                 tor_lround(get_circuit_build_close_time_ms()/1000));
           guard->path_bias_disabled = 1;
           guard->bad_since = approx_time();
           entry_guards_changed();
@@ -2299,7 +2303,7 @@ pathbias_measure_use_rate(entry_guard_t *guard)
                  tor_lround(guard->unusable_circuits),
                  tor_lround(guard->collapsed_circuits),
                  tor_lround(guard->timeouts),
-                 tor_lround(circ_times.close_ms/1000));
+                 tor_lround(get_circuit_build_close_time_ms()/1000));
       }
     } else if (pathbias_get_use_success_count(guard)/guard->use_attempts
                < pathbias_get_notice_use_rate(options)) {
@@ -2323,7 +2327,7 @@ pathbias_measure_use_rate(entry_guard_t *guard)
                  tor_lround(guard->unusable_circuits),
                  tor_lround(guard->collapsed_circuits),
                  tor_lround(guard->timeouts),
-                 tor_lround(circ_times.close_ms/1000));
+                 tor_lround(get_circuit_build_close_time_ms()/1000));
       }
     }
   }
@@ -2379,7 +2383,7 @@ pathbias_measure_close_rate(entry_guard_t *guard)
                  tor_lround(guard->unusable_circuits),
                  tor_lround(guard->collapsed_circuits),
                  tor_lround(guard->timeouts),
-                 tor_lround(circ_times.close_ms/1000));
+                 tor_lround(get_circuit_build_close_time_ms()/1000));
           guard->path_bias_disabled = 1;
           guard->bad_since = approx_time();
           entry_guards_changed();
@@ -2405,7 +2409,7 @@ pathbias_measure_close_rate(entry_guard_t *guard)
                  tor_lround(guard->unusable_circuits),
                  tor_lround(guard->collapsed_circuits),
                  tor_lround(guard->timeouts),
-                 tor_lround(circ_times.close_ms/1000));
+                 tor_lround(get_circuit_build_close_time_ms()/1000));
       }
     } else if (pathbias_get_close_success_count(guard)/guard->circ_attempts
                 < pathbias_get_warn_rate(options)) {
@@ -2430,7 +2434,7 @@ pathbias_measure_close_rate(entry_guard_t *guard)
                  tor_lround(guard->unusable_circuits),
                  tor_lround(guard->collapsed_circuits),
                  tor_lround(guard->timeouts),
-                 tor_lround(circ_times.close_ms/1000));
+                 tor_lround(get_circuit_build_close_time_ms()/1000));
       }
     } else if (pathbias_get_close_success_count(guard)/guard->circ_attempts
                < pathbias_get_notice_rate(options)) {
@@ -2453,7 +2457,7 @@ pathbias_measure_close_rate(entry_guard_t *guard)
                  tor_lround(guard->unusable_circuits),
                  tor_lround(guard->collapsed_circuits),
                  tor_lround(guard->timeouts),
-                 tor_lround(circ_times.close_ms/1000));
+                 tor_lround(get_circuit_build_close_time_ms()/1000));
       }
     }
   }
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 69c4c4b13996c0f78bbe0c11b12ce407c3f89bb5..bb74594ecdf6c8650c6106a3c4970afd5244314f 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -678,7 +678,7 @@ origin_circuit_new(void)
 
   init_circuit_base(TO_CIRCUIT(circ));
 
-  circ_times.last_circ_at = approx_time();
+  circuit_build_times_update_last_circ(get_circuit_build_times_mutable());
 
   return circ;
 }
diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c
index 95129f9a4379d49eb122d325b4f0f8595dafc1d7..8fdef58858ca3e4f13b74cba8a07206704b3e168 100644
--- a/src/or/circuitstats.c
+++ b/src/or/circuitstats.c
@@ -18,6 +18,10 @@
 #undef log
 #include <math.h>
 
+static void cbt_control_event_buildtimeout_set(
+                                  const circuit_build_times_t *cbt,
+                                  buildtimeout_set_event_t type);
+
 #define CBT_BIN_TO_MS(bin) ((bin)*CBT_BIN_WIDTH + (CBT_BIN_WIDTH/2))
 
 /** Global list of circuit build times */
@@ -26,8 +30,7 @@
 // vary in their own latency. The downside of this is that guards
 // can change frequently, so we'd be building a lot more circuits
 // most likely.
-/* XXXX024 Make this static; add accessor functions. */
-circuit_build_times_t circ_times;
+static circuit_build_times_t circ_times;
 
 #ifdef TOR_UNIT_TESTS
 /** If set, we're running the unit tests: we should avoid clobbering
@@ -37,6 +40,37 @@ static int unit_tests = 0;
 #define unit_tests 0
 #endif
 
+/** Return a pointer to the data structure describing our current circuit
+ * build time history and computations. */
+const circuit_build_times_t *
+get_circuit_build_times(void)
+{
+  return &circ_times;
+}
+
+/** As get_circuit_build_times, but return a mutable pointer. */
+circuit_build_times_t *
+get_circuit_build_times_mutable(void)
+{
+  return &circ_times;
+}
+
+/** Return the time to wait before actually closing an under-construction, in
+ * milliseconds. */
+double
+get_circuit_build_close_time_ms(void)
+{
+  return circ_times.close_ms;
+}
+
+/** Return the time to wait before giving up on an under-construction circuit,
+ * in milliseconds. */
+double
+get_circuit_build_timeout_ms(void)
+{
+  return circ_times.timeout_ms;
+}
+
 /**
  * This function decides if CBT learning should be disabled. It returns
  * true if one or more of the following four conditions are met:
@@ -158,7 +192,7 @@ circuit_build_times_min_circs_to_observe(void)
 /** Return true iff <b>cbt</b> has recorded enough build times that we
  * want to start acting on the timeout it implies. */
 int
-circuit_build_times_enough_to_compute(circuit_build_times_t *cbt)
+circuit_build_times_enough_to_compute(const circuit_build_times_t *cbt)
 {
   return cbt->total_build_times >= circuit_build_times_min_circs_to_observe();
 }
@@ -475,7 +509,7 @@ circuit_build_times_init(circuit_build_times_t *cbt)
     cbt->liveness.timeouts_after_firsthop = NULL;
   }
   cbt->close_ms = cbt->timeout_ms = circuit_build_times_get_initial_timeout();
-  control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
+  cbt_control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
 }
 
 /**
@@ -561,7 +595,7 @@ circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time)
  * Return maximum circuit build time
  */
 static build_time_t
-circuit_build_times_max(circuit_build_times_t *cbt)
+circuit_build_times_max(const circuit_build_times_t *cbt)
 {
   int i = 0;
   build_time_t max_build_time = 0;
@@ -602,7 +636,7 @@ circuit_build_times_min(circuit_build_times_t *cbt)
  * The return value must be freed by the caller.
  */
 static uint32_t *
-circuit_build_times_create_histogram(circuit_build_times_t *cbt,
+circuit_build_times_create_histogram(const circuit_build_times_t *cbt,
                                      build_time_t *nbins)
 {
   uint32_t *histogram;
@@ -692,7 +726,7 @@ circuit_build_times_get_xm(circuit_build_times_t *cbt)
  * the or_state_t state structure.
  */
 void
-circuit_build_times_update_state(circuit_build_times_t *cbt,
+circuit_build_times_update_state(const circuit_build_times_t *cbt,
                                  or_state_t *state)
 {
   uint32_t *histogram;
@@ -1129,7 +1163,7 @@ circuit_build_times_initial_alpha(circuit_build_times_t *cbt,
  * Returns true if we need circuits to be built
  */
 int
-circuit_build_times_needs_circuits(circuit_build_times_t *cbt)
+circuit_build_times_needs_circuits(const circuit_build_times_t *cbt)
 {
   /* Return true if < MIN_CIRCUITS_TO_OBSERVE */
   return !circuit_build_times_enough_to_compute(cbt);
@@ -1140,7 +1174,7 @@ circuit_build_times_needs_circuits(circuit_build_times_t *cbt)
  * right now.
  */
 int
-circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt)
+circuit_build_times_needs_circuits_now(const circuit_build_times_t *cbt)
 {
   return circuit_build_times_needs_circuits(cbt) &&
     approx_time()-cbt->last_circ_at > circuit_build_times_test_frequency();
@@ -1273,7 +1307,7 @@ circuit_build_times_network_close(circuit_build_times_t *cbt,
  * in the case of recent liveness changes.
  */
 int
-circuit_build_times_network_check_live(circuit_build_times_t *cbt)
+circuit_build_times_network_check_live(const circuit_build_times_t *cbt)
 {
   if (cbt->liveness.nonlive_timeouts > 0) {
     return 0;
@@ -1339,7 +1373,7 @@ circuit_build_times_network_check_changed(circuit_build_times_t *cbt)
                   = circuit_build_times_get_initial_timeout();
   }
 
-  control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
+  cbt_control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
 
   log_notice(LD_CIRC,
             "Your network connection speed appears to have changed. Resetting "
@@ -1521,7 +1555,7 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt)
     }
   }
 
-  control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_COMPUTED);
+  cbt_control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_COMPUTED);
 
   timeout_rate = circuit_build_times_timeout_rate(cbt);
 
@@ -1567,3 +1601,44 @@ circuitbuild_running_unit_tests(void)
 }
 #endif
 
+void
+circuit_build_times_update_last_circ(circuit_build_times_t *cbt)
+{
+  cbt->last_circ_at = approx_time();
+}
+
+static void
+cbt_control_event_buildtimeout_set(const circuit_build_times_t *cbt,
+                                   buildtimeout_set_event_t type)
+{
+  char *args = NULL;
+  double qnt;
+
+  switch(type) {
+    case BUILDTIMEOUT_SET_EVENT_RESET:
+    case BUILDTIMEOUT_SET_EVENT_SUSPENDED:
+    case BUILDTIMEOUT_SET_EVENT_DISCARD:
+      qnt = 1.0;
+      break;
+    case BUILDTIMEOUT_SET_EVENT_COMPUTED:
+    case BUILDTIMEOUT_SET_EVENT_RESUME:
+    default:
+      qnt = circuit_build_times_quantile_cutoff();
+      break;
+  }
+
+  tor_asprintf(&args, "TOTAL_TIMES=%lu "
+               "TIMEOUT_MS=%lu XM=%lu ALPHA=%f CUTOFF_QUANTILE=%f "
+               "TIMEOUT_RATE=%f CLOSE_MS=%lu CLOSE_RATE=%f",
+               (unsigned long)cbt->total_build_times,
+               (unsigned long)cbt->timeout_ms,
+               (unsigned long)cbt->Xm, cbt->alpha, qnt,
+               circuit_build_times_timeout_rate(cbt),
+               (unsigned long)cbt->close_ms,
+               circuit_build_times_close_rate(cbt));
+
+  control_event_buildtimeout_set(type, args);
+
+  tor_free(args);
+
+}
diff --git a/src/or/circuitstats.h b/src/or/circuitstats.h
index 53ba2b2d2e785340f3fa5e3cfecab7be435491c7..38a7e4efa86bfd5b9c789f77398bfa5ed2257423 100644
--- a/src/or/circuitstats.h
+++ b/src/or/circuitstats.h
@@ -12,11 +12,14 @@
 #ifndef TOR_CIRCUITSTATS_H
 #define TOR_CIRCUITSTATS_H
 
-extern circuit_build_times_t circ_times;
+const circuit_build_times_t *get_circuit_build_times(void);
+circuit_build_times_t *get_circuit_build_times_mutable(void);
+double get_circuit_build_close_time_ms(void);
+double get_circuit_build_timeout_ms(void);
 
 int circuit_build_times_disabled(void);
-int circuit_build_times_enough_to_compute(circuit_build_times_t *cbt);
-void circuit_build_times_update_state(circuit_build_times_t *cbt,
+int circuit_build_times_enough_to_compute(const circuit_build_times_t *cbt);
+void circuit_build_times_update_state(const circuit_build_times_t *cbt,
                                       or_state_t *state);
 int circuit_build_times_parse_state(circuit_build_times_t *cbt,
                                     or_state_t *state);
@@ -27,9 +30,9 @@ int circuit_build_times_count_close(circuit_build_times_t *cbt,
 void circuit_build_times_set_timeout(circuit_build_times_t *cbt);
 int circuit_build_times_add_time(circuit_build_times_t *cbt,
                                  build_time_t time);
-int circuit_build_times_needs_circuits(circuit_build_times_t *cbt);
+int circuit_build_times_needs_circuits(const circuit_build_times_t *cbt);
 
-int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt);
+int circuit_build_times_needs_circuits_now(const circuit_build_times_t *cbt);
 void circuit_build_times_init(circuit_build_times_t *cbt);
 void circuit_build_times_free_timeouts(circuit_build_times_t *cbt);
 void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
@@ -37,6 +40,8 @@ void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
 double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt);
 double circuit_build_times_close_rate(const circuit_build_times_t *cbt);
 
+void circuit_build_times_update_last_circ(circuit_build_times_t *cbt);
+
 #ifdef CIRCUITSTATS_PRIVATE
 STATIC double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
                                              double quantile);
@@ -59,8 +64,35 @@ void circuitbuild_running_unit_tests(void);
 
 /* Network liveness functions */
 void circuit_build_times_network_is_live(circuit_build_times_t *cbt);
-int circuit_build_times_network_check_live(circuit_build_times_t *cbt);
+int circuit_build_times_network_check_live(const circuit_build_times_t *cbt);
 void circuit_build_times_network_circ_success(circuit_build_times_t *cbt);
 
+#ifdef CIRCUITSTATS_PRIVATE
+/** Structure for circuit build times history */
+struct circuit_build_times_s{
+  /** The circular array of recorded build times in milliseconds */
+  build_time_t circuit_build_times[CBT_NCIRCUITS_TO_OBSERVE];
+  /** Current index in the circuit_build_times circular array */
+  int build_times_idx;
+  /** Total number of build times accumulated. Max CBT_NCIRCUITS_TO_OBSERVE */
+  int total_build_times;
+  /** Information about the state of our local network connection */
+  network_liveness_t liveness;
+  /** Last time we built a circuit. Used to decide to build new test circs */
+  time_t last_circ_at;
+  /** "Minimum" value of our pareto distribution (actually mode) */
+  build_time_t Xm;
+  /** alpha exponent for pareto dist. */
+  double alpha;
+  /** Have we computed a timeout? */
+  int have_computed_timeout;
+  /** The exact value for that timeout in milliseconds. Stored as a double
+   * to maintain precision from calculations to and from quantile value. */
+  double timeout_ms;
+  /** How long we wait before actually closing the circuit. */
+  double close_ms;
+};
+#endif
+
 #endif
 
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 7beaa4e49cf32885f2c64086d913728fe5900313..e3c0d0cbd88236495a07ac7d187130e8928c284e 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -442,12 +442,12 @@ circuit_expire_building(void)
    *   RTTs = 4a + 3b + 2c
    *   RTTs = 9h
    */
-  SET_CUTOFF(general_cutoff, circ_times.timeout_ms);
-  SET_CUTOFF(begindir_cutoff, circ_times.timeout_ms);
+  SET_CUTOFF(general_cutoff, get_circuit_build_timeout_ms());
+  SET_CUTOFF(begindir_cutoff, get_circuit_build_timeout_ms());
 
   /* > 3hop circs seem to have a 1.0 second delay on their cannibalized
    * 4th hop. */
-  SET_CUTOFF(fourhop_cutoff, circ_times.timeout_ms * (10/6.0) + 1000);
+  SET_CUTOFF(fourhop_cutoff, get_circuit_build_timeout_ms() * (10/6.0) + 1000);
 
   /* CIRCUIT_PURPOSE_C_ESTABLISH_REND behaves more like a RELAY cell.
    * Use the stream cutoff (more or less). */
@@ -456,20 +456,20 @@ circuit_expire_building(void)
   /* Be lenient with cannibalized circs. They already survived the official
    * CBT, and they're usually not performance-critical. */
   SET_CUTOFF(cannibalized_cutoff,
-             MAX(circ_times.close_ms*(4/6.0),
+             MAX(get_circuit_build_close_time_ms()*(4/6.0),
                  options->CircuitStreamTimeout * 1000) + 1000);
 
   /* Intro circs have an extra round trip (and are also 4 hops long) */
-  SET_CUTOFF(c_intro_cutoff, circ_times.timeout_ms * (14/6.0) + 1000);
+  SET_CUTOFF(c_intro_cutoff, get_circuit_build_timeout_ms() * (14/6.0) + 1000);
 
   /* Server intro circs have an extra round trip */
-  SET_CUTOFF(s_intro_cutoff, circ_times.timeout_ms * (9/6.0) + 1000);
+  SET_CUTOFF(s_intro_cutoff, get_circuit_build_timeout_ms() * (9/6.0) + 1000);
 
-  SET_CUTOFF(close_cutoff, circ_times.close_ms);
-  SET_CUTOFF(extremely_old_cutoff, circ_times.close_ms*2 + 1000);
+  SET_CUTOFF(close_cutoff, get_circuit_build_close_time_ms());
+  SET_CUTOFF(extremely_old_cutoff, get_circuit_build_close_time_ms()*2 + 1000);
 
   SET_CUTOFF(hs_extremely_old_cutoff,
-             MAX(circ_times.close_ms*2 + 1000,
+             MAX(get_circuit_build_close_time_ms()*2 + 1000,
                  options->SocksTimeout * 1000));
 
   TOR_LIST_FOREACH(next_circ, circuit_get_global_list(), head) {
@@ -545,12 +545,14 @@ circuit_expire_building(void)
            * was a timeout, and the timeout value needs to reset if we
            * see enough of them. Note this means we also need to avoid
            * double-counting below, too. */
-          circuit_build_times_count_timeout(&circ_times, first_hop_succeeded);
+          circuit_build_times_count_timeout(get_circuit_build_times_mutable(),
+              first_hop_succeeded);
           TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout = 1;
         }
         continue;
       } else {
         static ratelim_t relax_timeout_limit = RATELIM_INIT(3600);
+        const double build_close_ms = get_circuit_build_close_time_ms();
         log_fn_ratelim(&relax_timeout_limit, LOG_NOTICE, LD_CIRC,
                  "No circuits are opened. Relaxed timeout for circuit %d "
                  "(a %s %d-hop circuit in state %s with channel state %s) to "
@@ -561,7 +563,8 @@ circuit_expire_building(void)
                  TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len,
                  circuit_state_to_string(victim->state),
                  channel_state_to_string(victim->n_chan->state),
-                 (long)circ_times.close_ms, num_live_entry_guards(0));
+                 (long)build_close_ms,
+                 num_live_entry_guards(0));
       }
     }
 
@@ -641,7 +644,7 @@ circuit_expire_building(void)
       }
 
       if (circuit_timeout_want_to_count_circ(TO_ORIGIN_CIRCUIT(victim)) &&
-          circuit_build_times_enough_to_compute(&circ_times)) {
+          circuit_build_times_enough_to_compute(get_circuit_build_times())) {
         /* Circuits are allowed to last longer for measurement.
          * Switch their purpose and wait. */
         if (victim->purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
@@ -655,8 +658,9 @@ circuit_expire_building(void)
            * have a timeout. We also want to avoid double-counting
            * already "relaxed" circuits, which are counted above. */
           if (!TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout) {
-            circuit_build_times_count_timeout(&circ_times,
-                                              first_hop_succeeded);
+            circuit_build_times_count_timeout(
+                                         get_circuit_build_times_mutable(),
+                                         first_hop_succeeded);
           }
           continue;
         }
@@ -673,10 +677,11 @@ circuit_expire_building(void)
                      (long)(now.tv_sec - victim->timestamp_began.tv_sec),
                      victim->purpose,
                      circuit_purpose_to_string(victim->purpose));
-        } else if (circuit_build_times_count_close(&circ_times,
+        } else if (circuit_build_times_count_close(
+                                         get_circuit_build_times_mutable(),
                                          first_hop_succeeded,
                                          victim->timestamp_created.tv_sec)) {
-          circuit_build_times_set_timeout(&circ_times);
+          circuit_build_times_set_timeout(get_circuit_build_times_mutable());
         }
       }
     }
@@ -939,7 +944,7 @@ circuit_predict_and_launch_new(void)
    * we can still build circuits preemptively as needed. */
   if (num < MAX_UNUSED_OPEN_CIRCUITS-2 &&
       get_options()->LearnCircuitBuildTimeout &&
-      circuit_build_times_needs_circuits_now(&circ_times)) {
+      circuit_build_times_needs_circuits_now(get_circuit_build_times())) {
     flags = CIRCLAUNCH_NEED_CAPACITY;
     log_info(LD_CIRC,
              "Have %d clean circs need another buildtime test circ.", num);
@@ -1075,7 +1080,7 @@ circuit_expire_old_circuits_clientside(void)
   cutoff = now;
 
   if (get_options()->LearnCircuitBuildTimeout &&
-      circuit_build_times_needs_circuits(&circ_times)) {
+      circuit_build_times_needs_circuits(get_circuit_build_times())) {
     /* Circuits should be shorter lived if we need more of them
      * for learning a good build timeout */
     cutoff.tv_sec -= IDLE_TIMEOUT_WHILE_LEARNING;
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 31fd6d673978e840e8a9c17481bdc3f80bd09077..7912bfb7fc4e6117e6fdabdbbab804a43f9d3098 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -1749,7 +1749,7 @@ connection_tls_finish_handshake(or_connection_t *conn)
                                               digest_rcvd) < 0)
     return -1;
 
-  circuit_build_times_network_is_live(&circ_times);
+  circuit_build_times_network_is_live(get_circuit_build_times_mutable());
 
   if (tor_tls_used_v1_handshake(conn->tls)) {
     conn->link_proto = 1;
@@ -1783,7 +1783,7 @@ connection_or_launch_v3_or_handshake(or_connection_t *conn)
   tor_assert(connection_or_nonopen_was_started_here(conn));
   tor_assert(tor_tls_received_v3_certificate(conn->tls));
 
-  circuit_build_times_network_is_live(&circ_times);
+  circuit_build_times_network_is_live(get_circuit_build_times_mutable());
 
   connection_or_change_state(conn, OR_CONN_STATE_OR_HANDSHAKING_V3);
   if (connection_init_or_handshake_state(conn, 1) < 0)
@@ -2016,7 +2016,7 @@ connection_or_process_cells_from_inbuf(or_connection_t *conn)
       if (conn->chan)
         channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan));
 
-      circuit_build_times_network_is_live(&circ_times);
+      circuit_build_times_network_is_live(get_circuit_build_times_mutable());
       channel_tls_handle_var_cell(var_cell, conn);
       var_cell_free(var_cell);
     } else {
@@ -2032,7 +2032,7 @@ connection_or_process_cells_from_inbuf(or_connection_t *conn)
       if (conn->chan)
         channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan));
 
-      circuit_build_times_network_is_live(&circ_times);
+      circuit_build_times_network_is_live(get_circuit_build_times_mutable());
       connection_fetch_from_buf(buf, cell_network_size, TO_CONN(conn));
 
       /* retrieve cell info from buf (create the host-order struct from the
diff --git a/src/or/control.c b/src/or/control.c
index 81df00cf9287a0a8b288f2ad11184f12a9a20dfc..fc4809b3997df6df6bd3ba5b0c972e9c4e26b387 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -4163,32 +4163,26 @@ control_event_newconsensus(const networkstatus_t *consensus)
 
 /** Called when we compute a new circuitbuildtimeout */
 int
-control_event_buildtimeout_set(const circuit_build_times_t *cbt,
-                        buildtimeout_set_event_t type)
+control_event_buildtimeout_set(buildtimeout_set_event_t type,
+                               const char *args)
 {
   const char *type_string = NULL;
-  double qnt;
 
   if (!control_event_is_interesting(EVENT_BUILDTIMEOUT_SET))
     return 0;
 
-  qnt = circuit_build_times_quantile_cutoff();
-
   switch (type) {
     case BUILDTIMEOUT_SET_EVENT_COMPUTED:
       type_string = "COMPUTED";
       break;
     case BUILDTIMEOUT_SET_EVENT_RESET:
       type_string = "RESET";
-      qnt = 1.0;
       break;
     case BUILDTIMEOUT_SET_EVENT_SUSPENDED:
       type_string = "SUSPENDED";
-      qnt = 1.0;
       break;
     case BUILDTIMEOUT_SET_EVENT_DISCARD:
       type_string = "DISCARD";
-      qnt = 1.0;
       break;
     case BUILDTIMEOUT_SET_EVENT_RESUME:
       type_string = "RESUME";
@@ -4199,15 +4193,8 @@ control_event_buildtimeout_set(const circuit_build_times_t *cbt,
   }
 
   send_control_event(EVENT_BUILDTIMEOUT_SET, ALL_FORMATS,
-                     "650 BUILDTIMEOUT_SET %s TOTAL_TIMES=%lu "
-                     "TIMEOUT_MS=%lu XM=%lu ALPHA=%f CUTOFF_QUANTILE=%f "
-                     "TIMEOUT_RATE=%f CLOSE_MS=%lu CLOSE_RATE=%f\r\n",
-                     type_string, (unsigned long)cbt->total_build_times,
-                     (unsigned long)cbt->timeout_ms,
-                     (unsigned long)cbt->Xm, cbt->alpha, qnt,
-                     circuit_build_times_timeout_rate(cbt),
-                     (unsigned long)cbt->close_ms,
-                     circuit_build_times_close_rate(cbt));
+                     "650 BUILDTIMEOUT_SET %s %s\r\n",
+                     type_string, args);
 
   return 0;
 }
diff --git a/src/or/control.h b/src/or/control.h
index be9476ea3f1439f3652fb3552c364644a818caf8..1a44768ceed7ce030a2366aa1b438013bd275129 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -73,8 +73,8 @@ int control_event_server_status(int severity, const char *format, ...)
 int control_event_guard(const char *nickname, const char *digest,
                         const char *status);
 int control_event_conf_changed(const smartlist_t *elements);
-int control_event_buildtimeout_set(const circuit_build_times_t *cbt,
-                                   buildtimeout_set_event_t type);
+int control_event_buildtimeout_set(buildtimeout_set_event_t type,
+                                   const char *args);
 int control_event_signal(uintptr_t signal);
 
 int init_control_cookie_authentication(int enabled);
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index cadc70ec7af8a8324106bccb7a78e82e6c274b20..b66cc2b0d84db2384f453295521a9b931ab06c23 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -2279,6 +2279,6 @@ entry_guards_free_all(void)
   clear_bridge_list();
   smartlist_free(bridge_list);
   bridge_list = NULL;
-  circuit_build_times_free_timeouts(&circ_times);
+  circuit_build_times_free_timeouts(get_circuit_build_times_mutable());
 }
 
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 3f995a9f6c933e0627fe44164798fe56054f4984..35a20b06cadc3f73273a72a38cf0bb2822dcdbe7 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -1822,7 +1822,8 @@ networkstatus_set_current_consensus(const char *consensus,
      * current consensus really alter our view of any OR's rate limits? */
     connection_or_update_token_buckets(get_connection_array(), options);
 
-    circuit_build_times_new_consensus_params(&circ_times, current_consensus);
+    circuit_build_times_new_consensus_params(get_circuit_build_times_mutable(),
+        current_consensus);
   }
 
   if (directory_caches_dir_info(options)) {
diff --git a/src/or/or.h b/src/or/or.h
index 2daf12b82d4ebb3db4901760c3fc50fa85823ba7..041421ed4292186b02d0030bf2165f96b9610910 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -4471,30 +4471,7 @@ typedef struct {
   int after_firsthop_idx;
 } network_liveness_t;
 
-/** Structure for circuit build times history */
-typedef struct {
-  /** The circular array of recorded build times in milliseconds */
-  build_time_t circuit_build_times[CBT_NCIRCUITS_TO_OBSERVE];
-  /** Current index in the circuit_build_times circular array */
-  int build_times_idx;
-  /** Total number of build times accumulated. Max CBT_NCIRCUITS_TO_OBSERVE */
-  int total_build_times;
-  /** Information about the state of our local network connection */
-  network_liveness_t liveness;
-  /** Last time we built a circuit. Used to decide to build new test circs */
-  time_t last_circ_at;
-  /** "Minimum" value of our pareto distribution (actually mode) */
-  build_time_t Xm;
-  /** alpha exponent for pareto dist. */
-  double alpha;
-  /** Have we computed a timeout? */
-  int have_computed_timeout;
-  /** The exact value for that timeout in milliseconds. Stored as a double
-   * to maintain precision from calculations to and from quantile value. */
-  double timeout_ms;
-  /** How long we wait before actually closing the circuit. */
-  double close_ms;
-} circuit_build_times_t;
+typedef struct circuit_build_times_s circuit_build_times_t;
 
 /********************************* config.c ***************************/
 
diff --git a/src/or/statefile.c b/src/or/statefile.c
index 8736c35a2d6e127440978857c7aa4cc33b38d508..db9091ca27806dadc673e61d2c62b80ad9b327ff 100644
--- a/src/or/statefile.c
+++ b/src/or/statefile.c
@@ -238,7 +238,8 @@ or_state_set(or_state_t *new_state)
     tor_free(err);
     ret = -1;
   }
-  if (circuit_build_times_parse_state(&circ_times, global_state) < 0) {
+  if (circuit_build_times_parse_state(
+      get_circuit_build_times_mutable(),global_state) < 0) {
     ret = -1;
   }
   return ret;
@@ -405,7 +406,7 @@ or_state_save(time_t now)
    * to avoid redundant writes. */
   entry_guards_update_state(global_state);
   rep_hist_update_state(global_state);
-  circuit_build_times_update_state(&circ_times, global_state);
+  circuit_build_times_update_state(get_circuit_build_times(), global_state);
   if (accounting_is_enabled(get_options()))
     accounting_run_housekeeping(now);