Copilot commented on code in PR #14000:
URL: https://github.com/apache/trafficserver/pull/14000#discussion_r4474004226


##########
include/tsutil/Metrics.h:
##########
@@ -431,6 +431,78 @@ class Metrics
   std::shared_ptr<Storage> _storage;
 
 public:
+  /** Per-thread accumulation of counter increments.
+
+      Counters are summed by every thread that serves transactions, so 
incrementing the shared atomic
+      directly makes every thread write the same cache lines. A thread that 
owns a table adds into it
+      instead and periodically applies the sums with one atomic add per 
counter it touched. Readers
+      still read only the shared atomics, which lag by at most the owning 
thread's flush interval.
+
+      Gauges are not deferred: their current value is used for decisions, such 
as connection limits.
+   */
+  class ThreadDeferredCounters
+  {
+  public:
+    /// Adds @a val to @a metric's pending sum. Returns false if the table has 
no room for @a metric,
+    /// in which case the caller must apply the increment itself.
+    bool
+    add(AtomicType *metric, int64_t val)
+    {
+      size_t slot = (reinterpret_cast<uintptr_t>(metric) >> 3) * 
0x9E3779B97F4A7C15ULL >> (64 - SLOT_BITS);
+
+      for (size_t probe = 0; probe < MAX_PROBES; ++probe, slot = (slot + 1) & 
(SLOTS - 1)) {
+        Slot &s = _slots[slot];
+        if (s.metric == metric) {
+          s.delta += val;

Review Comment:
   This changes counter overflow from defined atomic wraparound to undefined 
signed arithmetic. `Counter::increment()` accepts a `uint64_t`, so deferring 
increments of `INT64_MAX` and then `1` for the same counter overflows `s.delta` 
before it is flushed, whereas the direct `fetch_add` path handles that sequence 
without undefined behavior. Please accumulate using unsigned arithmetic, 
preserving the direct path's wrapping semantics.



##########
src/iocore/eventsystem/UnixEThread.cc:
##########
@@ -264,6 +272,13 @@ EThread::execute_regular()
     EventStatistics statistics = fire_ready_events(loop_start_time);
     ink_hrtime      sleep_time = get_sleep_time(statistics.event_time, 
current_slice);
 
+    // Flush before a sleep that would outlast the interval too, so an idle 
thread's counters are current.
+    if (counter_flush_interval > 0 &&
+        (statistics.event_time - last_counter_flush >= counter_flush_interval 
|| sleep_time >= counter_flush_interval)) {

Review Comment:
   `sleep_time` is only an upper bound: `PollCont::do_poll()` forces a zero 
timeout when network ready/enable lists are nonempty, so this can flush every 
busy loop turn and defeat batching. Conversely, successive waits shorter than 
the interval can cross the flush deadline without publishing pending counters. 
Keep the elapsed-time check here, but move idle flushing to the actual 
blocking-wait boundaries, after pre-poll counter updates, so busy threads 
retain batching and sleeping threads publish their pending increments.



##########
src/iocore/eventsystem/UnixEThread.cc:
##########
@@ -264,6 +272,13 @@ EThread::execute_regular()
     EventStatistics statistics = fire_ready_events(loop_start_time);
     ink_hrtime      sleep_time = get_sleep_time(statistics.event_time, 
current_slice);
 
+    // Flush before a sleep that would outlast the interval too, so an idle 
thread's counters are current.
+    if (counter_flush_interval > 0 &&
+        (statistics.event_time - last_counter_flush >= counter_flush_interval 
|| sleep_time >= counter_flush_interval)) {
+      ts::Metrics::flush_thread_counters();

Review Comment:
   The flush deadline is checked only after `fire_ready_events()` finishes 
draining its queues. A chain of continuations using `schedule_imm_local()` can 
keep `process_queue()` draining beyond the configured interval, leaving their 
counter increments unpublished until the chain ends. Also check the deadline 
during event dispatch, and add a regression case that keeps the local queue 
busy longer than the interval.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to