Flow-IPC 3.0.0
Flow-IPC project: Full implementation reference.
channel_stats.hpp
Go to the documentation of this file.
1/* Flow-IPC: Structured Transport
2 * Copyright (c) 2023 Akamai Technologies, Inc.; and other contributors.
3 * Each commit is copyright by its respective author or author's employer.
4 *
5 * Licensed under the MIT License:
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE. */
24
25/// @file
26#pragma once
27
29#include <flow/util/stat/histo.hpp>
30#include <flow/util/stat/stat_set.hpp>
31#include <cstdint>
32#include <string>
33#include <vector>
34
36{
37
38// Types.
39
40/**
41 * Cumulative stats from a struc::sync_io::Channel, covering both send and receive directions as well as
42 * message-type breakdowns, segment/split details, expect infrastructure, and request-response correlation.
43 *
44 * A single bidirectional `struct` (not split at the top level) because struc::Channel is one bidirectional object.
45 * Sub-structs Snd and Rcv group the directional state; a shared inner struct Msg captures
46 * message-level counts identically applicable to either direction.
47 *
48 * @note The word *segment* in nearby documentation refers to capnp (Cap'n Proto) segments. Please see
49 * capnp docs (https://capnproto.org/encoding.html) for a refresher on how these work; and perhaps
50 * specifically `capnp::MallocMessageBuilder` for a refresher about exponential segment size growth
51 * and such. (Flow-IPC may use a different impl, but the idea is similar.)
52 *
53 * @note On the receive side, Msg::m_requests, Msg::m_requests_one_off, and
54 * Msg::m_request_responses are always zero. The wire protocol does not distinguish
55 * notifications from requests (that is sender-local knowledge via the presence of `on_rsp_func`).
56 * All non-response user messages are counted as Msg::m_notifications on receive.
57 * This asymmetry is intentional, reserved for future protocol enrichment.
58 *
59 * @note When applicable and unless stated otherwise, #m_rcv counts et al *do* count messages only cached for
60 * the time being (due to being unsolicited and without an expectation of that Channel::Msg_which_in) or
61 * thrown-out due to being unexpected responses. That is to say, an #m_rcv in-message need not be delivered
62 * to the user for it to count.
63 *
64 * @note Unless stated otherwise, stats apply only to the aspects of messages that are transmitted directly via
65 * an IPC channel. That is if SHM (or some other custom substrate) is involved, the parts stored therein
66 * are not copied; hence (e.g.) Msg::m_total_segments will be incremented by only 1 -- a (small) segment is
67 * always enough to transmit a SHM-handle -- even if the serialization in SHM comprises many megabytes
68 * and several exponentially capnp-segments arranged from small to large in exponential fashion.
69 * For SHM-backed messaging, there are additional stats available which are so marked.
70 */
72{
73 // Types.
74
75 /**
76 * Per-message stats shared between send and receive directions. An instance appears as
77 * `Snd::m_msg` and `Rcv::m_msg`. Sender counts at send time; receiver counts at receipt time.
78 * Segment/blob stats apply to all messages (internal + user) since both paths flow through
79 * `send_core()` / the receive pipeline.
80 */
81 struct Msg
82 {
83 // Constants.
84
85 /// Number of histogram buckets for #m_histo_split_blobs_per_seg. Covers 2, 3, 4, 5+ blobs per split segment.
86 static constexpr size_t S_HISTO_SPLIT_BLOBS_N_BUCKETS = 4;
87 /// Number of histogram buckets for #m_histo_msg_sz.
88 static constexpr size_t S_HISTO_MSG_SZ_N_BUCKETS = 33;
89 /// Bucket-0 width for #m_histo_msg_sz: matches the internal mdt header frame-prefix size.
91 /// Regular bucket width for #m_histo_msg_sz (bytes).
92 static constexpr size_t S_HISTO_MSG_SZ_BUCKET_SZ = 2048;
93
94 // Data.
95
96 /**
97 * Internal (out-of-band) messages. As of this writing there is 1 kind: unexpected-response notification.
98 *
99 * @note While a well designed user protocol, as of this writing, will result in few or no internal messages,
100 * please be aware that those stats that are *not* documented to be sub-counts of #m_user_msgs --
101 * or as specifically pertaining to *user* messages -- *will* be based on both user messages and internal
102 * messages. This includes at least: #m_single_segment_msgs, #m_total_segments, #m_total_low_lvl_blobs,
103 * #m_histo_msg_sz. Relevantly consider that an internal message always consists of exactly 1
104 * minimally-sized (mdt header only) blob/unstructured message bearing no native handle.
105 * (Informally speaking: it counts but not for much.)
106 */
107 uint64_t m_internal_msgs = 0;
108
109 /**
110 * All user structured messages.
111 * - Send-side: 1 per the act of Msg_out going through a send API.
112 * - Receive-side: 1 per Msg_in being prepared inside `Channel` so as to immediately or eventually pass it
113 * to user; or thrown out due to being a response to a message that is not registered to await a
114 * response (active request).
115 */
116 uint64_t m_user_msgs = 0;
117
118 /**
119 * Sub-count of #m_user_msgs: user notifications (Channel::send() yes, Channel::async_request() no).
120 * On receive: same as #m_user_msgs, because currently we do not communicate this info from sender to
121 * receiver. Accordingly #m_requests is always zero on receive. (It is reserved for the future when
122 * we might transmit this information and thus count requests versus notifications. See class doc header.)
123 */
124 uint64_t m_notifications = 0;
125
126 /**
127 * Sub-count of #m_notifications: notification that is itself a response
128 * (when sending: `originating_msg_or_null != nullptr`).
129 */
131
132 /**
133 * Sub-count of #m_user_msgs: user requests (Channel::async_request(), Channel::send() no).
134 * `m_notifications + m_requests == m_user_msgs`.
135 * On receive: always zero (reserved; see #m_notifications and/or class doc header).
136 */
137 uint64_t m_requests = 0;
138
139 /**
140 * Sub-count of #m_requests: user requests each made with one-off response expectation (auto-cancel on first match).
141 * Sticky requests (where responses are expected ad infinitum until specifically unregistered via API)
142 * equal: `m_requests - m_requests_one_off`.
143 * On receive: always zero (because so is #m_requests).
144 */
145 uint64_t m_requests_one_off = 0;
146
147 /**
148 * Sub-count of #m_requests: requests each of which is also a response (ping-pong pattern).
149 * Requests that (which is arguably more typical) not themselves responding: `m_requests - m_request_responses`.
150 * On receive: always zero (because so is #m_requests).
151 */
153
154 /// Messages whose serializations each comprised exactly 1 segment (typical case; if SHM-backed then universal).
156
157 /**
158 * Messages whose serializations each comprised 2+ segments. Generally
159 * `m_internal_msgs + m_user_msgs == m_single_segment_msgs + m_multi_segment_msgs`.
160 *
161 * 2+ segments are needed if the total space required to serialize the needed data exceeds the first segment's
162 * size (which is pre-configured/allocated before any mutation send-side).
163 */
165
166 /// Sum of pre-split/post-reassembly segment counts across all messages.
167 uint64_t m_total_segments = 0;
168
169 /**
170 * Messages for which at least 1 segment had to be split across 2+ low-level blobs. Atypical; if SHM-backed
171 * then impossible.
172 *
173 * A pre-send/post-receive segment split is required if:
174 * a single *leaf* (capnp-`List`, `Data`, `Text` -- these are not splittable in capnp) was so large that
175 * a segment had to be sized larger than regular growth suggested, just to be able to fit that leaf alone,
176 * *and* that leaf/segment exceeded the IPC transport's max unstructured message size.
177 */
179
180 /// Total low-level blobs (each segment of #m_total_segments maps to 1 blob unless split; in which case to 2+).
182
183 /// Sub-count of #m_user_msgs: user messages such that each included a native handle.
185
186 /**
187 * Per-segment histogram: when a segment needed pre-send splitting/post-receive reassembly, how many blobs it
188 * became between split and reassembly. Only split cases are recorded. Buckets: [2], [3], [4], [5+].
189 */
190 flow::util::stat::Histogram_counter m_histo_split_blobs_per_seg{S_HISTO_SPLIT_BLOBS_N_BUCKETS, 1, 1, 2};
191
192 /**
193 * Total serialization bytes per message (all segments summed, metadata-bearing header included).
194 * Bucket 0 width = header size (internal msgs, each of which is header-only, land here);
195 * subsequent buckets ~2Ki; overflow into last bucket.
196 *
197 * Reminder: A SHM-backed message counts, but only the non-SHM-stored aspects count here. In fact
198 * every SHM-backed message, at least for a given SHM-provider and process, will be of the same small size
199 * (not much larger than #S_HISTO_MSG_SZ_BUCKET0_SZ): header plus SHM-handle serialization.
200 */
201 flow::util::stat::Histogram_counter m_histo_msg_sz{S_HISTO_MSG_SZ_N_BUCKETS,
203 }; // struct Msg
204
205 /// Send-direction stats.
206 struct Snd
207 {
208 // Data.
209
210 /// Message-level stats for the send direction.
212
213 /**
214 * Internal (out-of-band) messages that could not be sent, because they would not fit the fixed-size buffer
215 * reserved for serializing them. If this is not zero, maintainers should look into it: the buffer is sized
216 * with a wide margin over any realistic contents, so a non-zero value indicates a Flow-IPC bug. (The affected
217 * best-effort internal message is simply not sent; the `Channel` otherwise continues operating normally.)
218 *
219 * @internal
220 *
221 * See calculation of `INTERNAL_MSG_MAX_SZ` in sync_io::Channel, where the buffer is sized (with the reasoning)
222 * and the serialization failure is caught.
223 */
225 };
226
227 /// Receive-direction stats.
228 struct Rcv
229 {
230 // Constants.
231
232 /**
233 * Bucket min-values for #m_histo_one_off_request_rtt_usec (default config): a log-scale-ish 1-2-5 ladder
234 * covering 10usec through 10sec. See #m_histo_one_off_request_rtt_usec doc header for rationale.
235 */
236 static inline const std::vector<flow::util::stat::Histogram_counter::value_t>
238 {0, 10, 20, 50, 100, 200, 500, 1'000, 2'000, 5'000, 10'000, 20'000, 50'000,
239 100'000, 200'000, 500'000, 1'000'000, 2'000'000, 5'000'000, 10'000'000};
240
241 /**
242 * Last-bucket width for #m_histo_one_off_request_rtt_usec (default config); values past it land in that
243 * bucket regardless.
244 */
245 static constexpr flow::util::stat::Histogram_counter::value_t S_HISTO_RTT_BUCKET_N_SZ_USEC = 10'000'000;
246
247 /// Number of histogram buckets for #m_histo_one_off_request_rtt_usec (default config).
248 static inline const size_t S_HISTO_RTT_N_BUCKETS = S_HISTO_RTT_BUCKET_VAL0S_USEC.size();
249
250 // Data.
251
252 /**
253 * Various stats for the receive direction, generally mirroring the opposing peer's Snd::m_msg.
254 * Be aware some values may not be quite equal between the two due to at least (1) time (naturally)
255 * and (2) in some cases slightly different semantics (always documented around here and kept to a minimum).
256 */
258
259 /**
260 * Sub-count of `m_msg.m_notification_responses`: response arrived but no matching expectation
261 * registered (user protocol error). Matched responses = `m_msg.m_notification_responses - m_unexpected_responses`.
262 */
264
265 /**
266 * Number of times and out-of-order arrival enqueued into the reassembly queue
267 * (possible only if Channel::S_HAS_2_PIPES for Channel::Owned_channel). Such an event is atypical.
268 * Also it never occurs with internal messages: only user messages.
269 *
270 * ### Background: reassembly queue in struc::Channel et al ###
271 * A 2-pipe config has one pipe for native-handle-bearing user messages and the other for all others.
272 * However, that means that if I send msgs A-B (and one has a handle, the other does not), they might arrive
273 * as B-A. Until A arrives, I cannot fully contemplate B, necessarily, because via internal sequence numbers
274 * I can see there is a gap. The user protocol might rely on the original order. So then I stick B into
275 * an internal reassembly queue, until any seq-num gap before it filled with more in-messages.
276 */
278
279 /// Reassembly queue depth; typically zero. See #m_reassembly_q_insertions for some background.
281
282 /// Max of #m_reassembly_q_depth observed so far.
284
285 /**
286 * Non-response (unsolicited) user in-messages delivered to a handler immediately (at receipt
287 * handler was already registered).
288 */
290
291 /**
292 * Non-response (unsolicited) user messages cached (no handler registered yet at receipt).
293 * High rate may signal late Channel::expect_msgs() et al.
294 */
296
297 /**
298 * Current count (gauge) of non-response (unsolicited) user messages received but not yet
299 * `expect_*()`-registered at time of receipt (gauge).
300 */
302
303 /// Max of #m_pending_msgs_depth observed so far.
305
306 /**
307 * Total valid one-shot (Channel::expect_msg() or equivalent) registrations so far.
308 * "Valid" means this discounts those calls that return `false` (called on on already-hosed channel/similar).
309 */
310 uint64_t m_expect_msg_count = 0;
311
312 /**
313 * Current count (gauge) of active one-shot (Channel::expect_msg() or equivalent) expectations.
314 *
315 * A one-shot expectation is auto-canceled on being satisfied (got message of the specified Channel::Msg_which_in)
316 * once. Zeroed when the `Channel` is hosed (all expectations are discarded then).
317 */
319
320 /// Cf #m_expect_msg_count: tracks sticky (Channel::expect_msgs() or equivalent: not one-off) registrations.
322
323 /**
324 * Cf #m_expect_msg_active: tracks sticky (Channel::expect_msgs() or equivalent: not one-off) registrations.
325 *
326 * A sticky expectation remains active until actively canceling via Channel::undo_expect_msgs() or equivalent.
327 * Zeroed when the `Channel` is hosed (all expectations are discarded then).
328 */
330
331 /**
332 * Times already-queued messages were popped on `expect_*()` registration (once per pop event, not per popped
333 * message). To be clear:
334 * - Channel::expect_msg() will (if 1+ messages are already available) pop 1 message.
335 * That counts for 1.
336 * - Channel::expect_msgs() will (if 1+ messages are already available) pop all 1+ messages.
337 * That counts for 1 [sic].
338 */
340
341 /**
342 * Current count (gauge) of active one-off response expectations (one-off pending requests). A request
343 * is specified to be one-off versus not-one-off via arg to Channel::async_request() or equivalent.
344 * Zeroed when the `Channel` is hosed (all expectations are discarded then).
345 *
346 * See also in Snd [sic!] Msg::m_requests and/or Msg::m_requests_one_off regarding counts of such things.
347 */
349
350 /**
351 * Current count (gauge) of active sticky response expectations (indefinitely pending requests). A request
352 * is specified to be one-off versus not-one-off via arg to Channel::async_request() or equivalent.
353 * The expectation in this case remains until Channel::undo_expect_responses().
354 * Zeroed when the `Channel` is hosed (all expectations are discarded then).
355 *
356 * See also in Snd [sic!] Msg::m_requests and/or Msg::m_requests_one_off regarding counts of such things.
357 */
359
360 /**
361 * Total valid Channel::remote_peer_process_liveness_check() invocations. "Valid" means this discounts
362 * those calls that return `false` (called on on already-hosed channel/similar).
363 *
364 * A direct sync_io::Channel user may use Channel::remote_peer_process_liveness_check(), though informally
365 * we do not expect this to be particularly common.
366 *
367 * A struc::Channel user may cause such liveness checks indirectly by issuing a long-lasting
368 * struc::Channel::sync_request(); at times an ungraceful exit/abort of the opposing process *might*
369 * only be detected by such a check.
370 */
371 uint64_t m_liveness_checks = 0;
372
373 /**
374 * One-off `async_request()` round-trip time histogram (real time passed from said call to response receipt),
375 * in microseconds.
376 *
377 * Only one-off requests; sticky excluded (latency grows monotonically, meaningless).
378 * Default buckets: a 1-2-5 log-scale ladder from 10us through 10s (values beyond overflow into the last
379 * bucket). This captures -- with resolution proportional to magnitude -- both promptly-answered requests
380 * (expect ~100us) and ones whose responses take the opposing side seconds to issue, including a mix of
381 * the two in one channel. (Non-uniform buckets mean each recording costs a short binary search instead
382 * of O(1) arithmetic; immaterial at per-request frequency.)
383 *
384 * @note User can override bucket config via
385 * Channel::stats_configure_rcv_one_off_request_rtt_histogram() before Channel::start_and_poll()
386 * (same and transport::Channel::start(), respectively, for async-I/O-pattern transport::Channel).
387 *
388 * @note If you are using a sync_io::Channel directly please recall that we can process any events, including
389 * in-traffic, only when you report events to the `Channel`. So, e.g., if you wait a second between
390 * detecting a requested event being active and informing the `Channel`, then this will be at least
391 * one second, regardless of how instantly the actual data arrived. (If you're using
392 * struc::Channel, then its background thread should get to it ASAP however. Then again struc::Channel
393 * ultimately simply mounts an event loop in a thread, much as you might.)
394 */
397 }; // struct Rcv
398
399 // Data.
400
401 /// Send-direction stats.
403
404 /// Receive-direction stats.
406}; // struct Channel_stats
407
408// Template implementations.
409
410template<typename Visitor>
411void declare_stats(const flow::util::stat::Stat_name& name_prefix,
412 const Channel_stats* src_stats, Channel_stats* target_stats,
413 Visitor&& visitor)
414{
415 // m_snd.m_msg:
416 FLOW_UTIL_STAT_DECLARE(m_snd.m_msg.m_internal_msgs, ACCUMULATOR);
417 FLOW_UTIL_STAT_DECLARE(m_snd.m_msg.m_user_msgs, ACCUMULATOR);
418 FLOW_UTIL_STAT_DECLARE(m_snd.m_msg.m_notifications, ACCUMULATOR);
419 FLOW_UTIL_STAT_DECLARE(m_snd.m_msg.m_notification_responses, ACCUMULATOR);
420 FLOW_UTIL_STAT_DECLARE(m_snd.m_msg.m_requests, ACCUMULATOR);
421 FLOW_UTIL_STAT_DECLARE(m_snd.m_msg.m_requests_one_off, ACCUMULATOR);
422 FLOW_UTIL_STAT_DECLARE(m_snd.m_msg.m_request_responses, ACCUMULATOR);
423 FLOW_UTIL_STAT_DECLARE(m_snd.m_msg.m_single_segment_msgs, ACCUMULATOR);
424 FLOW_UTIL_STAT_DECLARE(m_snd.m_msg.m_multi_segment_msgs, ACCUMULATOR);
425 FLOW_UTIL_STAT_DECLARE(m_snd.m_msg.m_total_segments, ACCUMULATOR);
426 FLOW_UTIL_STAT_DECLARE(m_snd.m_msg.m_msgs_with_split_segments, ACCUMULATOR);
427 FLOW_UTIL_STAT_DECLARE(m_snd.m_msg.m_total_low_lvl_blobs, ACCUMULATOR);
428 FLOW_UTIL_STAT_DECLARE(m_snd.m_msg.m_handle_bearing_msgs, ACCUMULATOR);
429 FLOW_UTIL_STAT_DECLARE(m_snd.m_msg.m_histo_split_blobs_per_seg, ACCUMULATOR);
430 FLOW_UTIL_STAT_DECLARE(m_snd.m_msg.m_histo_msg_sz, ACCUMULATOR);
431
432 // m_snd (rest):
433 FLOW_UTIL_STAT_DECLARE(m_snd.m_internal_msgs_unserializable, ACCUMULATOR);
434
435 // m_rcv.m_msg:
436 FLOW_UTIL_STAT_DECLARE(m_rcv.m_msg.m_internal_msgs, ACCUMULATOR);
437 FLOW_UTIL_STAT_DECLARE(m_rcv.m_msg.m_user_msgs, ACCUMULATOR);
438 FLOW_UTIL_STAT_DECLARE(m_rcv.m_msg.m_notifications, ACCUMULATOR);
439 FLOW_UTIL_STAT_DECLARE(m_rcv.m_msg.m_notification_responses, ACCUMULATOR);
440 FLOW_UTIL_STAT_DECLARE(m_rcv.m_msg.m_requests, ACCUMULATOR);
441 FLOW_UTIL_STAT_DECLARE(m_rcv.m_msg.m_requests_one_off, ACCUMULATOR);
442 FLOW_UTIL_STAT_DECLARE(m_rcv.m_msg.m_request_responses, ACCUMULATOR);
443 FLOW_UTIL_STAT_DECLARE(m_rcv.m_msg.m_single_segment_msgs, ACCUMULATOR);
444 FLOW_UTIL_STAT_DECLARE(m_rcv.m_msg.m_multi_segment_msgs, ACCUMULATOR);
445 FLOW_UTIL_STAT_DECLARE(m_rcv.m_msg.m_total_segments, ACCUMULATOR);
446 FLOW_UTIL_STAT_DECLARE(m_rcv.m_msg.m_msgs_with_split_segments, ACCUMULATOR);
447 FLOW_UTIL_STAT_DECLARE(m_rcv.m_msg.m_total_low_lvl_blobs, ACCUMULATOR);
448 FLOW_UTIL_STAT_DECLARE(m_rcv.m_msg.m_handle_bearing_msgs, ACCUMULATOR);
449 FLOW_UTIL_STAT_DECLARE(m_rcv.m_msg.m_histo_split_blobs_per_seg, ACCUMULATOR);
450 FLOW_UTIL_STAT_DECLARE(m_rcv.m_msg.m_histo_msg_sz, ACCUMULATOR);
451
452 // m_rcv receive-specific:
453 FLOW_UTIL_STAT_DECLARE(m_rcv.m_unexpected_responses, ACCUMULATOR);
454 FLOW_UTIL_STAT_DECLARE(m_rcv.m_reassembly_q_insertions, ACCUMULATOR);
455 FLOW_UTIL_STAT_DECLARE(m_rcv.m_reassembly_q_depth, GAUGE);
456 FLOW_UTIL_STAT_DECLARE_HI_WMARK(m_rcv.m_reassembly_q_hi_wmark, m_rcv.m_reassembly_q_depth);
457 FLOW_UTIL_STAT_DECLARE(m_rcv.m_unsolicited_msgs_routed, ACCUMULATOR);
458 FLOW_UTIL_STAT_DECLARE(m_rcv.m_unsolicited_msgs_cached, ACCUMULATOR);
459 FLOW_UTIL_STAT_DECLARE(m_rcv.m_pending_msgs_depth, GAUGE);
460 FLOW_UTIL_STAT_DECLARE_HI_WMARK(m_rcv.m_pending_msgs_hi_wmark, m_rcv.m_pending_msgs_depth);
461 FLOW_UTIL_STAT_DECLARE(m_rcv.m_expect_msg_count, ACCUMULATOR);
462 FLOW_UTIL_STAT_DECLARE(m_rcv.m_expect_msg_active, GAUGE);
463 FLOW_UTIL_STAT_DECLARE(m_rcv.m_expect_msgs_count, ACCUMULATOR);
464 FLOW_UTIL_STAT_DECLARE(m_rcv.m_expect_msgs_active, GAUGE);
465 FLOW_UTIL_STAT_DECLARE(m_rcv.m_expect_q_immediate_pops, ACCUMULATOR);
466 FLOW_UTIL_STAT_DECLARE(m_rcv.m_expect_response_one_off_active, GAUGE);
467 FLOW_UTIL_STAT_DECLARE(m_rcv.m_expect_response_sticky_active, GAUGE);
468 FLOW_UTIL_STAT_DECLARE(m_rcv.m_liveness_checks, ACCUMULATOR);
469 FLOW_UTIL_STAT_DECLARE(m_rcv.m_histo_one_off_request_rtt_usec, ACCUMULATOR);
470} // declare_stats(Channel_stats)
471
472} // namespace ipc::transport::struc::sync_io::stat
Stats-related sub-namespace, for ADL segregation and general organization.
Definition: struc_fwd.hpp:568
void declare_stats(const flow::util::stat::Stat_name &name_prefix, const Channel_stats *src_stats, Channel_stats *target_stats, Visitor &&visitor)
Declares the stats for Channel_stats.
static constexpr size_t BUILDER_CONFIG_FRAME_PREFIX_SZ_VIA_STRUC_CHANNEL
struc::Channel (and struc::sync_io::Channel) requires, for internal purposes, that any Msg_out transm...
Definition: struc_fwd.hpp:247
Per-message stats shared between send and receive directions.
uint64_t m_handle_bearing_msgs
Sub-count of m_user_msgs: user messages such that each included a native handle.
uint64_t m_total_segments
Sum of pre-split/post-reassembly segment counts across all messages.
uint64_t m_msgs_with_split_segments
Messages for which at least 1 segment had to be split across 2+ low-level blobs.
uint64_t m_multi_segment_msgs
Messages whose serializations each comprised 2+ segments.
uint64_t m_requests
Sub-count of m_user_msgs: user requests (Channel::async_request(), Channel::send() no).
static constexpr size_t S_HISTO_SPLIT_BLOBS_N_BUCKETS
Number of histogram buckets for m_histo_split_blobs_per_seg. Covers 2, 3, 4, 5+ blobs per split segme...
uint64_t m_notification_responses
Sub-count of m_notifications: notification that is itself a response (when sending: originating_msg_o...
uint64_t m_total_low_lvl_blobs
Total low-level blobs (each segment of m_total_segments maps to 1 blob unless split; in which case to...
static constexpr size_t S_HISTO_MSG_SZ_BUCKET_SZ
Regular bucket width for m_histo_msg_sz (bytes).
flow::util::stat::Histogram_counter m_histo_msg_sz
Total serialization bytes per message (all segments summed, metadata-bearing header included).
static constexpr size_t S_HISTO_MSG_SZ_BUCKET0_SZ
Bucket-0 width for m_histo_msg_sz: matches the internal mdt header frame-prefix size.
uint64_t m_requests_one_off
Sub-count of m_requests: user requests each made with one-off response expectation (auto-cancel on fi...
uint64_t m_single_segment_msgs
Messages whose serializations each comprised exactly 1 segment (typical case; if SHM-backed then univ...
uint64_t m_notifications
Sub-count of m_user_msgs: user notifications (Channel::send() yes, Channel::async_request() no).
uint64_t m_internal_msgs
Internal (out-of-band) messages.
flow::util::stat::Histogram_counter m_histo_split_blobs_per_seg
Per-segment histogram: when a segment needed pre-send splitting/post-receive reassembly,...
uint64_t m_request_responses
Sub-count of m_requests: requests each of which is also a response (ping-pong pattern).
static constexpr size_t S_HISTO_MSG_SZ_N_BUCKETS
Number of histogram buckets for m_histo_msg_sz.
uint64_t m_user_msgs
All user structured messages.
static const size_t S_HISTO_RTT_N_BUCKETS
Number of histogram buckets for m_histo_one_off_request_rtt_usec (default config).
size_t m_expect_msg_active
Current count (gauge) of active one-shot (Channel::expect_msg() or equivalent) expectations.
uint64_t m_unexpected_responses
Sub-count of m_msg.m_notification_responses: response arrived but no matching expectation registered ...
static constexpr flow::util::stat::Histogram_counter::value_t S_HISTO_RTT_BUCKET_N_SZ_USEC
Last-bucket width for m_histo_one_off_request_rtt_usec (default config); values past it land in that ...
static const std::vector< flow::util::stat::Histogram_counter::value_t > S_HISTO_RTT_BUCKET_VAL0S_USEC
Bucket min-values for m_histo_one_off_request_rtt_usec (default config): a log-scale-ish 1-2-5 ladder...
uint64_t m_expect_msgs_count
Cf m_expect_msg_count: tracks sticky (Channel::expect_msgs() or equivalent: not one-off) registration...
uint64_t m_reassembly_q_insertions
Number of times and out-of-order arrival enqueued into the reassembly queue (possible only if Channel...
flow::util::stat::Histogram_counter m_histo_one_off_request_rtt_usec
One-off async_request() round-trip time histogram (real time passed from said call to response receip...
size_t m_reassembly_q_hi_wmark
Max of m_reassembly_q_depth observed so far.
uint64_t m_expect_q_immediate_pops
Times already-queued messages were popped on expect_*() registration (once per pop event,...
Msg m_msg
Various stats for the receive direction, generally mirroring the opposing peer's Snd::m_msg.
size_t m_reassembly_q_depth
Reassembly queue depth; typically zero. See m_reassembly_q_insertions for some background.
uint64_t m_unsolicited_msgs_cached
Non-response (unsolicited) user messages cached (no handler registered yet at receipt).
uint64_t m_expect_msg_count
Total valid one-shot (Channel::expect_msg() or equivalent) registrations so far.
size_t m_expect_response_one_off_active
Current count (gauge) of active one-off response expectations (one-off pending requests).
size_t m_pending_msgs_hi_wmark
Max of m_pending_msgs_depth observed so far.
size_t m_pending_msgs_depth
Current count (gauge) of non-response (unsolicited) user messages received but not yet expect_*()-reg...
size_t m_expect_msgs_active
Cf m_expect_msg_active: tracks sticky (Channel::expect_msgs() or equivalent: not one-off) registratio...
uint64_t m_liveness_checks
Total valid Channel::remote_peer_process_liveness_check() invocations.
uint64_t m_unsolicited_msgs_routed
Non-response (unsolicited) user in-messages delivered to a handler immediately (at receipt handler wa...
size_t m_expect_response_sticky_active
Current count (gauge) of active sticky response expectations (indefinitely pending requests).
uint64_t m_internal_msgs_unserializable
Internal (out-of-band) messages that could not be sent, because they would not fit the fixed-size buf...
Msg m_msg
Message-level stats for the send direction.
Cumulative stats from a struc::sync_io::Channel, covering both send and receive directions as well as...