src/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
0 / 1013
0.0%
Branches:
0 / 1755
0.0%
Functions:
0 / 47
0.0%

ps/rdma/petps_server.cc
Line Branch Exec Source
1 #include <folly/init/Init.h>
2
3 #include <boost/coroutine2/all.hpp>
4
5 #include <atomic>
6 #include <array>
7 #include <algorithm>
8 #include <chrono>
9 #include <condition_variable>
10 #include <csignal>
11 #include <deque>
12 #include <cstdint>
13 #include <cstdlib>
14 #include <cstring>
15 #include <fstream>
16 #include <iostream>
17 #include <limits>
18 #include <memory>
19 #include <mutex>
20 #include <stdexcept>
21 #include <string>
22 #include <thread>
23 #include <vector>
24
25 #include "base/bind_core.h"
26 #include "base/config.h"
27 #include "base/log.h"
28 #include "base/timer.h"
29 #include "memory/shm_file.h"
30 #include "ps/rdma/rdma_common.h"
31 #include "ps/rdma/rdma_deployment.h"
32 #include "ps/base/cache_ps_impl.h"
33 #include "ps/base/config.h"
34 #include "ps/rdma/control_plane.h"
35 #include "ps/rdma/rc_options.h"
36 #include "ps/rdma/rc_transport.h"
37 #include "ps/rdma/rdma_protocol.h"
38 #include "ps/rdma/rdma_status.h"
39
40 DEFINE_string(config_path, "", "config file path");
41 DEFINE_int32(thread_num, 1, "RC write poll thread count");
42 DECLARE_int32(global_id);
43 DECLARE_int32(num_server_processes);
44 DECLARE_int32(num_client_processes);
45 DEFINE_bool(use_dram, false, "unused compatibility flag");
46 DEFINE_int32(numa_id, 0, "NUMA node id for mmap and core binding");
47
48 namespace {
49
50 using petps::Exchange;
51 using petps::NamespaceToken;
52 using petps::NowNs;
53
54 constexpr std::size_t kMaxDirectSgesPerWr = 32;
55
56 ✗ bool ShouldTraceRdmaGet() {
57 ✗ static const bool enabled = [] {
58 ✗ const char* env = std::getenv("RECSTORE_RDMA_GET_TRACE");
59
0/14
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ return env != nullptr && std::string(env) != "0";
60
0/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ }();
61 ✗ return enabled;
62 }
63
64 ✗ std::uint64_t RdmaGetTraceInterval() {
65 ✗ static const std::uint64_t interval = [] {
66 ✗ const char* env = std::getenv("RECSTORE_RDMA_GET_TRACE_INTERVAL");
67
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (env == nullptr) {
68 ✗ return std::uint64_t{5000};
69 }
70 const auto parsed =
71 ✗ static_cast<std::uint64_t>(std::strtoull(env, nullptr, 10));
72
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ return parsed == 0 ? std::uint64_t{5000} : parsed;
73
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ }();
74 ✗ return interval;
75 }
76
77 ✗ std::string TimestampNow() {
78 ✗ const auto now = std::chrono::system_clock::now().time_since_epoch();
79 return std::to_string(
80
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ std::chrono::duration_cast<std::chrono::microseconds>(now).count());
81 }
82
83 ✗ int ResolveShardId(const nlohmann::json& config) {
84 ✗ const int default_shard = FLAGS_global_id;
85
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ if (!config.contains("cache_ps") || !config["cache_ps"].is_object()) {
86 ✗ return default_shard;
87 }
88
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const auto& cache_ps = config["cache_ps"];
89
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ if (cache_ps.contains("servers") && cache_ps["servers"].is_array()) {
90
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ for (const auto& server : cache_ps["servers"]) {
91
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ if (server.value("shard", -1) == FLAGS_global_id) {
92
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ return server.value("shard", default_shard);
93 }
94 }
95 }
96 ✗ return default_shard;
97 }
98
99 ✗ void NormalizeDramValuePath(nlohmann::json* base_kv_config) {
100
0/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ if (base_kv_config == nullptr || !base_kv_config->is_object()) {
101 ✗ return;
102 }
103
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ if (!base_kv_config->contains("value") ||
104
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ !(*base_kv_config)["value"].is_object()) {
105 ✗ return;
106 }
107
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ auto& value_cfg = (*base_kv_config)["value"];
108 const std::string value_type =
109
0/4
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ value_cfg.value("type", std::string("DRAM_VALUE_STORE"));
110
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (value_type != "DRAM_VALUE_STORE") {
111 ✗ return;
112 }
113
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ const std::string path = value_cfg.value("path", std::string());
114
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ if (path.empty() || path.rfind("/dev/shm", 0) == 0) {
115 ✗ return;
116 }
117
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ value_cfg["path"] = "/dev/shm/recstore_rdma_rc_" + TimestampNow() + "/value";
118
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ }
119
120 struct AlignedCharDeleter {
121 ✗ void operator()(char* ptr) const { std::free(ptr); }
122 };
123
124 class PetPSServer {
125 public:
126 ✗ PetPSServer(CachePS* cache_ps,
127 int thread_count,
128 int shard_id,
129 const std::string& namespace_token,
130 const petps::RdmaControlPlaneEndpoint& control_plane_endpoint,
131 const recstore::ResolvedRdmaDeployment& deployment,
132 const recstore::ResolvedRdmaFabric& fabric)
133 ✗ : cache_ps_(cache_ps),
134 ✗ thread_count_(thread_count),
135 ✗ shard_id_(shard_id),
136 ✗ deployment_(deployment),
137
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ fabric_(fabric),
138
0/6
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ control_plane_client_(control_plane_endpoint) {
139
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ petps::RcTransportConfig config;
140 ✗ config.node_id = FLAGS_global_id;
141 ✗ config.num_servers = deployment_.num_shards;
142 ✗ config.num_os_clients = deployment_.num_clients;
143 ✗ config.shard_id = shard_id_;
144 ✗ config.num_clients =
145 ✗ FLAGS_rdma_rc_num_logical_clients >= 0
146
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ ? FLAGS_rdma_rc_num_logical_clients
147 : FLAGS_num_client_processes;
148 ✗ config.qps_per_client_per_shard = FLAGS_rdma_rc_qps_per_client_per_shard;
149 ✗ config.slots_per_qp = FLAGS_rdma_rc_slots_per_qp;
150 ✗ config.request_slot_bytes =
151 ✗ static_cast<std::size_t>(FLAGS_rdma_rc_request_slot_bytes);
152 ✗ config.response_slot_bytes =
153 ✗ static_cast<std::size_t>(FLAGS_rdma_rc_response_slot_bytes);
154
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ config.control_plane_host = FLAGS_rdma_control_plane_host;
155 ✗ config.control_plane_port = FLAGS_rdma_control_plane_port;
156 ✗ config.control_plane_timeout_ms = FLAGS_rdma_control_plane_timeout_ms;
157
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ config.namespace_token = namespace_token;
158
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ config.deployment_id = deployment_.deployment_id;
159 ✗ config.deployment_epoch = deployment_.epoch;
160 ✗ config.protocol_version = deployment_.protocol_version;
161
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ config.configuration_digest = deployment_.configuration_digest;
162
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ config.fabric_digest = deployment_.fabric_digest;
163
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ config.fabric = fabric_;
164
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ transport_ = std::make_unique<petps::RcShardServerTransport>(config);
165
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const auto backing = cache_ps_->GetRDMABackingRegion();
166
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ if (backing.data != nullptr && backing.size > 0) {
167
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ transport_->RegisterLocalMemoryRegion(backing.data, backing.size);
168
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ LOG(INFO) << "component=rdma_rc_server event=value_region_registered"
169
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " bytes=" << backing.size;
170 } else {
171
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ LOG(INFO) << "component=rdma_rc_server event=value_region_unavailable";
172 }
173 // Registered read-only zero region used to serve absent keys on the
174 // direct_sg path. Written once here and never modified afterwards, so
175 // direct responses can reference it without any per-request memset.
176 const std::size_t direct_sg_zero_bytes =
177 ✗ transport_->config().response_slot_bytes;
178
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (direct_sg_zero_bytes > 0) {
179 ✗ void* zero_region = nullptr;
180
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (posix_memalign(&zero_region, 4096, direct_sg_zero_bytes) != 0) {
181
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw std::runtime_error("failed to allocate direct_sg zero region");
182 }
183 ✗ std::memset(zero_region, 0, direct_sg_zero_bytes);
184 ✗ direct_sg_zero_region_.reset(static_cast<char*>(zero_region));
185
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ transport_->RegisterLocalMemoryRegion(
186 ✗ direct_sg_zero_region_.get(), direct_sg_zero_bytes);
187
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ LOG(INFO) << "component=rdma_rc_server event=direct_sg_zero_region"
188
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " bytes=" << direct_sg_zero_bytes;
189 }
190 ✗ last_seq_.assign(
191
0/4
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ static_cast<std::size_t>(transport_->TotalSlots()), std::uint64_t{0});
192 ✗ inflight_seq_.assign(
193
0/4
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ static_cast<std::size_t>(transport_->TotalSlots()), std::uint64_t{0});
194 ✗ get_payload_worker_count_ = FLAGS_rdma_rc_server_get_workers;
195
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (get_payload_worker_count_ < 0) {
196
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ LOG(FATAL) << "--rdma_rc_server_get_workers must be non-negative";
197 }
198 ✗ poller_profiles_.reserve(
199
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ static_cast<std::size_t>(std::max(1, thread_count_)));
200
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ for (int i = 0; i < std::max(1, thread_count_); ++i) {
201
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ poller_profiles_.emplace_back(std::make_unique<PollerProfile>());
202 }
203 ✗ get_payload_completions_.resize(
204
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ static_cast<std::size_t>(std::max(1, thread_count_)));
205 ✗ next_rebuild_check_ns_.assign(
206
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ static_cast<std::size_t>(std::max(1, thread_count_)), 0);
207 ✗ rebuild_poll_backoff_ms_.assign(
208
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ static_cast<std::size_t>(std::max(1, thread_count_)), 0);
209 ✗ }
210
211 ✗ void Run() {
212 ✗ StartGetPayloadWorkers();
213
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ for (int i = 0; i < thread_count_; ++i) {
214
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ threads_.emplace_back(&PetPSServer::PollingThread, this, i);
215 }
216 // Observation-only shard heartbeat to the control plane.
217
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ heartbeat_thread_ = std::thread(&PetPSServer::HeartbeatThread, this);
218 ✗ }
219
220 // Graceful exit: stop every loop and join. Idempotent; the caller decides
221 // whether to tear the process down normally or short-circuit the (large)
222 // slab unmap.
223 //
224 // Deliberately no draining publication here: nothing consumes `draining`
225 // yet (the health snapshot reports liveness only), while a draining record
226 // permanently rejects READY for the same (deployment, epoch, shard), so a
227 // plain restart would never come back. Draining stays an explicit operator
228 // action until the re-ready rule is settled.
229 ✗ void Stop() {
230
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (stop_requested_.exchange(true, std::memory_order_relaxed)) {
231 ✗ return;
232 }
233 ✗ get_payload_cv_.notify_all();
234
0/2
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ for (std::thread& worker : get_payload_workers_) {
235
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (worker.joinable()) {
236
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ worker.join();
237 }
238 }
239
0/2
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ for (std::thread& thread : threads_) {
240
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (thread.joinable()) {
241
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ thread.join();
242 }
243 }
244
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (heartbeat_thread_.joinable()) {
245 ✗ heartbeat_thread_.join();
246 }
247
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ LOG(INFO) << "component=petps_server event=server_stopped"
248
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " server_id=" << FLAGS_global_id;
249 }
250
251 private:
252 struct GetPayloadTask {
253 int slot = -1;
254 int client_id = -1;
255 int qp_index = -1;
256 int slot_in_qp = -1;
257 int poll_thread_id = -1;
258 std::uint64_t seq = 0;
259 // Transport response epoch when the request was accepted; a later rebuild
260 // invalidates the slot this task would complete.
261 std::uint64_t response_epoch = 0;
262 petps::RequestDescriptor descriptor{};
263 const char* payload = nullptr;
264 petps::RcShardServerTransport::ResponseView response{};
265 };
266
267 struct GetPayloadCompletion {
268 int slot = -1;
269 int client_id = -1;
270 int qp_index = -1;
271 int slot_in_qp = -1;
272 int poll_thread_id = -1;
273 std::uint64_t seq = 0;
274 std::uint64_t response_epoch = 0;
275 petps::RcShardServerTransport::ResponseView response{};
276 bool payload_written_direct = false;
277 // The lane was rebuilt while the worker held this task, so its response
278 // must not be completed (the payload WRs were flushed or refused).
279 bool stale = false;
280 };
281
282 struct ProfileCounters {
283 std::atomic<std::uint64_t> scan_rounds{0};
284 std::atomic<std::uint64_t> scanned_slots{0};
285 std::atomic<std::uint64_t> ready_slots{0};
286 std::atomic<std::uint64_t> not_ready_slots{0};
287 std::atomic<std::uint64_t> zero_seq_ready{0};
288 std::atomic<std::uint64_t> duplicate_seq_ready{0};
289 std::atomic<std::uint64_t> inflight_seq_ready{0};
290 std::atomic<std::uint64_t> empty_scan_rounds{0};
291 std::atomic<std::uint64_t> max_ready_per_round{0};
292 std::atomic<std::uint64_t> handled_get{0};
293 std::atomic<std::uint64_t> handled_put{0};
294 std::atomic<std::uint64_t> handled_update{0};
295 std::atomic<std::uint64_t> handled_init{0};
296 std::atomic<std::uint64_t> invalid_descriptor{0};
297 std::atomic<std::uint64_t> wrong_shard{0};
298 std::atomic<std::uint64_t> handle_get_ns{0};
299 std::atomic<std::uint64_t> get_batch_get_ns{0};
300 std::atomic<std::uint64_t> get_index_lookup_ns{0};
301 std::atomic<std::uint64_t> get_zero_fill_ns{0};
302 std::atomic<std::uint64_t> get_row_copy_ns{0};
303 std::atomic<std::uint64_t> get_rows{0};
304 std::atomic<std::uint64_t> get_value_bytes{0};
305 std::atomic<std::uint64_t> get_missing_rows{0};
306 std::atomic<std::uint64_t> get_direct_sg{0};
307 std::atomic<std::uint64_t> get_direct_sg_fallback{0};
308 std::atomic<std::uint64_t> get_direct_sg_ns{0};
309 std::atomic<std::uint64_t> get_direct_sg_wr{0};
310 std::atomic<std::uint64_t> get_direct_sg_abort{0};
311 std::atomic<std::uint64_t> get_direct_sg_abort_ns{0};
312 std::atomic<std::uint64_t> handle_put_ns{0};
313 std::atomic<std::uint64_t> handle_update_ns{0};
314 std::atomic<std::uint64_t> handle_init_ns{0};
315 std::atomic<std::uint64_t> complete_response_ns{0};
316 std::atomic<std::uint64_t> poll_loop_ns{0};
317 std::atomic<std::uint64_t> next_report_ns{0};
318 };
319
320 struct PollerProfile {
321 std::atomic<std::uint64_t> scan_rounds{0};
322 std::atomic<std::uint64_t> scanned_slots{0};
323 std::atomic<std::uint64_t> ready_slots{0};
324 std::atomic<std::uint64_t> not_ready_slots{0};
325 std::atomic<std::uint64_t> duplicate_seq_ready{0};
326 std::atomic<std::uint64_t> inflight_seq_ready{0};
327 std::atomic<std::uint64_t> handled_get{0};
328 std::atomic<std::uint64_t> poll_loop_ns{0};
329 };
330
331 static void
332 ✗ UpdateMax(std::atomic<std::uint64_t>* value, std::uint64_t candidate) {
333 ✗ std::uint64_t current = value->load(std::memory_order_relaxed);
334
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ while (candidate > current &&
335
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ !value->compare_exchange_weak(
336 current, candidate, std::memory_order_relaxed)) {
337 }
338 ✗ }
339
340 ✗ void MaybeReportProfile(int thread_id) {
341
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ if (FLAGS_rdma_rc_profile_interval_ms <= 0 || thread_id != 0) {
342 ✗ return;
343 }
344
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const std::uint64_t now = NowNs();
345 ✗ const std::uint64_t interval =
346 ✗ static_cast<std::uint64_t>(FLAGS_rdma_rc_profile_interval_ms) * 1000000;
347 std::uint64_t expected =
348 ✗ profile_.next_report_ns.load(std::memory_order_relaxed);
349
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (expected == 0) {
350 ✗ profile_.next_report_ns.compare_exchange_strong(
351 expected, now + interval, std::memory_order_relaxed);
352 ✗ return;
353 }
354
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ if (now < expected ||
355
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ !profile_.next_report_ns.compare_exchange_strong(
356 expected, now + interval, std::memory_order_relaxed)) {
357 ✗ return;
358 }
359
360 ✗ const std::uint64_t scan_rounds = Exchange(&profile_.scan_rounds);
361 ✗ const std::uint64_t scanned_slots = Exchange(&profile_.scanned_slots);
362 ✗ const std::uint64_t ready_slots = Exchange(&profile_.ready_slots);
363 ✗ const std::uint64_t not_ready_slots = Exchange(&profile_.not_ready_slots);
364 ✗ const std::uint64_t zero_seq_ready = Exchange(&profile_.zero_seq_ready);
365 const std::uint64_t duplicate_seq_ready =
366 ✗ Exchange(&profile_.duplicate_seq_ready);
367 const std::uint64_t inflight_seq_ready =
368 ✗ Exchange(&profile_.inflight_seq_ready);
369 const std::uint64_t empty_scan_rounds =
370 ✗ Exchange(&profile_.empty_scan_rounds);
371 const std::uint64_t max_ready_per_round =
372 ✗ Exchange(&profile_.max_ready_per_round);
373 ✗ const std::uint64_t handled_get = Exchange(&profile_.handled_get);
374 ✗ const std::uint64_t handled_put = Exchange(&profile_.handled_put);
375 ✗ const std::uint64_t handled_update = Exchange(&profile_.handled_update);
376 ✗ const std::uint64_t handled_init = Exchange(&profile_.handled_init);
377 ✗ const std::uint64_t complete_count =
378 ✗ handled_get + handled_put + handled_update + handled_init;
379 ✗ const std::uint64_t handle_get_ns = Exchange(&profile_.handle_get_ns);
380 ✗ const std::uint64_t get_batch_get_ns = Exchange(&profile_.get_batch_get_ns);
381 const std::uint64_t get_index_lookup_ns =
382 ✗ Exchange(&profile_.get_index_lookup_ns);
383 ✗ const std::uint64_t get_zero_fill_ns = Exchange(&profile_.get_zero_fill_ns);
384 ✗ const std::uint64_t get_row_copy_ns = Exchange(&profile_.get_row_copy_ns);
385 ✗ const std::uint64_t get_rows = Exchange(&profile_.get_rows);
386 ✗ const std::uint64_t get_value_bytes = Exchange(&profile_.get_value_bytes);
387 ✗ const std::uint64_t get_missing_rows = Exchange(&profile_.get_missing_rows);
388 ✗ const std::uint64_t get_direct_sg = Exchange(&profile_.get_direct_sg);
389 ✗ const std::uint64_t get_direct_sg_ns = Exchange(&profile_.get_direct_sg_ns);
390 const std::uint64_t get_direct_sg_abort =
391 ✗ Exchange(&profile_.get_direct_sg_abort);
392 const std::uint64_t get_direct_sg_abort_ns =
393 ✗ Exchange(&profile_.get_direct_sg_abort_ns);
394 ✗ const std::uint64_t handle_put_ns = Exchange(&profile_.handle_put_ns);
395 ✗ const std::uint64_t handle_update_ns = Exchange(&profile_.handle_update_ns);
396 ✗ const std::uint64_t handle_init_ns = Exchange(&profile_.handle_init_ns);
397 const std::uint64_t complete_response_ns =
398 ✗ Exchange(&profile_.complete_response_ns);
399 ✗ const std::uint64_t poll_loop_ns = Exchange(&profile_.poll_loop_ns);
400 ✗ std::uint64_t poller_min_get = std::numeric_limits<std::uint64_t>::max();
401 ✗ std::uint64_t poller_max_get = 0;
402 ✗ int poller_min_get_thread = -1;
403 ✗ int poller_max_get_thread = -1;
404 ✗ std::uint64_t poller_total_get = 0;
405 ✗ std::uint64_t poller_active = 0;
406
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ for (std::size_t i = 0; i < poller_profiles_.size(); ++i) {
407 ✗ auto& poller = *poller_profiles_[i];
408 ✗ const std::uint64_t poller_get = Exchange(&poller.handled_get);
409 ✗ const std::uint64_t poller_scan_rounds = Exchange(&poller.scan_rounds);
410 const std::uint64_t poller_scanned_slots =
411 ✗ Exchange(&poller.scanned_slots);
412 ✗ const std::uint64_t poller_ready_slots = Exchange(&poller.ready_slots);
413 const std::uint64_t poller_not_ready_slots =
414 ✗ Exchange(&poller.not_ready_slots);
415 const std::uint64_t poller_duplicate_seq_ready =
416 ✗ Exchange(&poller.duplicate_seq_ready);
417 const std::uint64_t poller_inflight_seq_ready =
418 ✗ Exchange(&poller.inflight_seq_ready);
419 ✗ const std::uint64_t poller_poll_loop_ns = Exchange(&poller.poll_loop_ns);
420
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (poller_get > 0) {
421 ✗ ++poller_active;
422 }
423 ✗ poller_total_get += poller_get;
424
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (poller_get < poller_min_get) {
425 ✗ poller_min_get = poller_get;
426 ✗ poller_min_get_thread = static_cast<int>(i);
427 }
428
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (poller_get > poller_max_get) {
429 ✗ poller_max_get = poller_get;
430 ✗ poller_max_get_thread = static_cast<int>(i);
431 }
432 std::cout
433
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << "component=rdma_rc_server_poller_profile" << " shard=" << shard_id_
434
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ << " thread_id=" << i << " scan_rounds=" << poller_scan_rounds
435
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " scanned_slots=" << poller_scanned_slots
436
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " ready_slots=" << poller_ready_slots << " scan_hit_pct="
437 << (poller_scanned_slots == 0
438 ? 0.0
439 ✗ : 100.0 * static_cast<double>(poller_ready_slots) /
440
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ static_cast<double>(poller_scanned_slots))
441
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " not_ready_slots=" << poller_not_ready_slots
442
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " duplicate_seq_ready=" << poller_duplicate_seq_ready
443
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " inflight_seq_ready=" << poller_inflight_seq_ready
444
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " handled_get=" << poller_get << " poll_loop_avg_ns="
445 << (poller_scan_rounds == 0
446 ? 0
447
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ : poller_poll_loop_ns / poller_scan_rounds)
448
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << std::endl;
449 }
450
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (poller_min_get == std::numeric_limits<std::uint64_t>::max()) {
451 ✗ poller_min_get = 0;
452 }
453 std::cout
454
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << "component=rdma_rc_server_profile" << " shard=" << shard_id_
455
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ << " threads=" << thread_count_ << " scan_rounds=" << scan_rounds
456
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ << " scanned_slots=" << scanned_slots << " ready_slots=" << ready_slots
457
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " not_ready_slots=" << not_ready_slots << " zero_seq_ready="
458
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << zero_seq_ready << " duplicate_seq_ready=" << duplicate_seq_ready
459
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " inflight_seq_ready=" << inflight_seq_ready
460
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " empty_scan_rounds=" << empty_scan_rounds << " scan_hit_pct="
461 << (scanned_slots == 0 ? 0.0
462 ✗ : 100.0 * static_cast<double>(ready_slots) /
463
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ static_cast<double>(scanned_slots))
464
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " ready_round_pct="
465 << (scan_rounds == 0
466 ? 0.0
467 ✗ : 100.0 * static_cast<double>(scan_rounds - empty_scan_rounds) /
468
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ static_cast<double>(scan_rounds))
469
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " avg_ready_per_round="
470 << (scan_rounds == 0 ? 0.0
471 ✗ : static_cast<double>(ready_slots) /
472
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ static_cast<double>(scan_rounds))
473
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " max_ready_per_round=" << max_ready_per_round
474
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ << " handled_get=" << handled_get << " handled_put=" << handled_put
475
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " handled_update=" << handled_update
476
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " handled_init=" << handled_init
477
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ << " invalid_descriptor=" << Exchange(&profile_.invalid_descriptor)
478
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ << " wrong_shard=" << Exchange(&profile_.wrong_shard)
479
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " handle_get_avg_ns="
480
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ << (handled_get == 0 ? 0 : handle_get_ns / handled_get)
481
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " get_batch_get_avg_ns="
482
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ << (handled_get == 0 ? 0 : get_batch_get_ns / handled_get)
483
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " get_index_lookup_avg_ns="
484
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ << (handled_get == 0 ? 0 : get_index_lookup_ns / handled_get)
485
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " get_zero_fill_avg_ns="
486
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ << (handled_get == 0 ? 0 : get_zero_fill_ns / handled_get)
487
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " get_row_copy_avg_ns="
488
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ << (handled_get == 0 ? 0 : get_row_copy_ns / handled_get)
489
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ << " get_rows=" << get_rows << " get_value_bytes=" << get_value_bytes
490
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " get_missing_rows=" << get_missing_rows
491
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " get_direct_sg=" << get_direct_sg << " get_direct_sg_fallback="
492
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ << Exchange(&profile_.get_direct_sg_fallback)
493
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " get_direct_sg_avg_ns="
494
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ << (get_direct_sg == 0 ? 0 : get_direct_sg_ns / get_direct_sg)
495
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ << " get_direct_sg_wr=" << Exchange(&profile_.get_direct_sg_wr)
496
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " get_direct_sg_abort=" << get_direct_sg_abort
497
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " get_direct_sg_abort_avg_ns="
498 << (get_direct_sg_abort == 0
499 ? 0
500
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ : get_direct_sg_abort_ns / get_direct_sg_abort)
501
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " handle_put_avg_ns="
502
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ << (handled_put == 0 ? 0 : handle_put_ns / handled_put)
503
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " handle_update_avg_ns="
504
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ << (handled_update == 0 ? 0 : handle_update_ns / handled_update)
505
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " handle_init_avg_ns="
506
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ << (handled_init == 0 ? 0 : handle_init_ns / handled_init)
507
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " complete_response_avg_ns="
508
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ << (complete_count == 0 ? 0 : complete_response_ns / complete_count)
509
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " poll_loop_avg_ns="
510
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ << (scan_rounds == 0 ? 0 : poll_loop_ns / scan_rounds)
511
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " poller_active=" << poller_active << " poller_total_get="
512
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << poller_total_get << " poller_min_get=" << poller_min_get
513
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " poller_min_get_thread=" << poller_min_get_thread
514
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " poller_max_get=" << poller_max_get
515
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " poller_max_get_thread=" << poller_max_get_thread << std::endl;
516 }
517
518 // Periodically surfaces the two rebuild-fence counters so a test driver can
519 // assert the fence actually fired. Like MaybeReportProfile this is opt-in
520 // through an interval flag (0 = off), so it never writes to stderr in a
521 // production run; the counters can only move when lane rebuild is enabled.
522 ✗ void MaybeReportRebuildFenceStats() {
523
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (FLAGS_rdma_rc_server_fence_stats_interval_ms <= 0 ||
524
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ !FLAGS_rdma_lane_rebuild_enabled) {
525 ✗ return;
526 }
527 ✗ const std::uint64_t kIntervalNs =
528 ✗ static_cast<std::uint64_t>(
529 FLAGS_rdma_rc_server_fence_stats_interval_ms) *
530 1000000ull;
531
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const std::uint64_t now = NowNs();
532 std::uint64_t expected =
533 ✗ next_fence_report_ns_.load(std::memory_order_relaxed);
534
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (expected == 0) {
535 ✗ next_fence_report_ns_.compare_exchange_strong(
536 expected, now + kIntervalNs, std::memory_order_relaxed);
537 ✗ return;
538 }
539
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ if (now < expected ||
540
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ !next_fence_report_ns_.compare_exchange_strong(
541 expected, now + kIntervalNs, std::memory_order_relaxed)) {
542 ✗ return;
543 }
544 const std::uint64_t rejected =
545
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ transport_ == nullptr ? 0 : transport_->ResponseRejectedEpochCount();
546 const std::uint64_t dropped =
547 ✗ payload_completion_dropped_stale_.load(std::memory_order_relaxed);
548 // std::cerr, not LOG(INFO): the test driver captures the process pipe,
549 // while glog INFO lines only land in the per-process log files.
550 std::cerr << "component=rdma_rc_server event=rebuild_fence_stats"
551
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ << " shard=" << shard_id_ << " fence_rejected=" << rejected
552
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " dropped_stale=" << dropped
553
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " fence_events=" << (rejected + dropped) << std::endl;
554 }
555
556 ✗ bool GetPayloadOffloadEnabled() const {
557 ✗ return get_payload_worker_count_ > 0;
558 }
559
560 ✗ std::size_t MaxGetPayloadQueueDepth() const {
561 ✗ return static_cast<std::size_t>(std::max(1, transport_->TotalSlots()));
562 }
563
564 ✗ void StartGetPayloadWorkers() {
565
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (!GetPayloadOffloadEnabled()) {
566 ✗ return;
567 }
568
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ for (int worker_id = 0; worker_id < get_payload_worker_count_;
569 ++worker_id) {
570 ✗ get_payload_workers_.emplace_back(
571
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ &PetPSServer::GetPayloadWorkerLoop, this, worker_id);
572 }
573
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ LOG(INFO) << "component=rdma_rc_server event=get_payload_workers_started"
574
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " count=" << get_payload_worker_count_;
575 }
576
577 ✗ void BindServerCore(int core_index) {
578 ✗ base::bind_core_with_env_offset(core_index);
579 ✗ }
580
581 ✗ bool EnqueueGetPayloadTask(const GetPayloadTask& task) {
582
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ std::lock_guard<std::mutex> guard(get_payload_mu_);
583
0/4
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ if (get_payload_tasks_.size() >= MaxGetPayloadQueueDepth()) {
584 ✗ return false;
585 }
586
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ get_payload_tasks_.push_back(task);
587 ✗ get_payload_cv_.notify_one();
588 ✗ return true;
589 ✗ }
590
591 ✗ std::size_t PollThreadIndex(int poll_thread_id) const {
592 ✗ return static_cast<std::size_t>(poll_thread_id);
593 }
594
595 ✗ bool TryPopGetPayloadCompletion(int poll_thread_id,
596 GetPayloadCompletion* completion) {
597
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ std::lock_guard<std::mutex> guard(get_payload_mu_);
598 auto& completions =
599
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ get_payload_completions_.at(PollThreadIndex(poll_thread_id));
600
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (completions.empty()) {
601 ✗ return false;
602 }
603 ✗ *completion = completions.front();
604 ✗ completions.pop_front();
605 ✗ return true;
606 ✗ }
607
608 ✗ void PushGetPayloadCompletion(const GetPayloadCompletion& completion) {
609
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ std::lock_guard<std::mutex> guard(get_payload_mu_);
610
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ get_payload_completions_.at(PollThreadIndex(completion.poll_thread_id))
611
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ .push_back(completion);
612 ✗ }
613
614 ✗ void AccumulateFlatGetProfile(const CachePS::FlatGetProfile& get_profile) {
615 ✗ profile_.get_batch_get_ns.fetch_add(
616 ✗ get_profile.batch_get_ns, std::memory_order_relaxed);
617 ✗ profile_.get_index_lookup_ns.fetch_add(
618 ✗ get_profile.index_lookup_ns, std::memory_order_relaxed);
619 ✗ profile_.get_zero_fill_ns.fetch_add(
620 ✗ get_profile.zero_fill_ns, std::memory_order_relaxed);
621 ✗ profile_.get_row_copy_ns.fetch_add(
622 ✗ get_profile.row_copy_ns, std::memory_order_relaxed);
623 ✗ profile_.get_rows.fetch_add(get_profile.rows, std::memory_order_relaxed);
624 ✗ profile_.get_value_bytes.fetch_add(
625 ✗ get_profile.value_bytes, std::memory_order_relaxed);
626 ✗ profile_.get_missing_rows.fetch_add(
627 ✗ get_profile.missing_rows, std::memory_order_relaxed);
628 ✗ }
629
630 ✗ void GetPayloadWorkerLoop(int worker_id) {
631 ✗ BindServerCore(thread_count_ + worker_id);
632
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ LOG(INFO) << "component=rdma_rc_server event=get_payload_worker_ready"
633
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " worker_id=" << worker_id;
634 while (true) {
635 ✗ GetPayloadTask task;
636 {
637
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ std::unique_lock<std::mutex> lock(get_payload_mu_);
638 ✗ get_payload_cv_.wait(lock, [this] {
639
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ return !get_payload_tasks_.empty() ||
640 ✗ stop_requested_.load(std::memory_order_relaxed);
641 });
642
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (stop_requested_.load(std::memory_order_relaxed)) {
643 ✗ return;
644 }
645 ✗ task = get_payload_tasks_.front();
646 ✗ get_payload_tasks_.pop_front();
647
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ }
648
649 // Test-only: widen the enqueue-to-post window so a lane rebuild lands in
650 // the middle of this task's lifetime. That forces the response-epoch
651 // fence (RcLaneRebuiltDuringResponse / stale completion drop) to fire,
652 // which the tight loopback timing otherwise almost never does.
653
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (FLAGS_rdma_rc_server_get_worker_hold_us > 0) {
654
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ std::this_thread::sleep_for(
655 ✗ std::chrono::microseconds(FLAGS_rdma_rc_server_get_worker_hold_us));
656 }
657
658 ✗ const bool profile_enabled = FLAGS_rdma_rc_profile_interval_ms > 0;
659
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ const std::uint64_t handle_start_ns = profile_enabled ? NowNs() : 0;
660 ✗ bool payload_written_direct = false;
661 ✗ bool stale = false;
662 try {
663
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ payload_written_direct = HandleGet(
664 task.descriptor,
665 task.payload,
666 &task.response,
667 worker_id,
668 task.slot_in_qp,
669 task.response_epoch);
670
0/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ } catch (const petps::RcLaneRebuiltDuringResponse&) {
671 // A rebuild released this request's slot; completing it would overwrite
672 // the new generation's response.
673 ✗ stale = true;
674
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ } catch (const std::exception& error) {
675 // Never let a worker exception terminate the shard: the client will
676 // time out and retire the lane.
677
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ LOG(ERROR) << "component=rdma_rc_server event=get_payload_worker_error"
678
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ << " shard=" << shard_id_ << " worker_id=" << worker_id
679
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " slot=" << task.slot << " error=\"" << error.what()
680
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ << "\"";
681 ✗ stale = true;
682 ✗ }
683
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
684 ✗ profile_.handled_get.fetch_add(1, std::memory_order_relaxed);
685 ✗ profile_.handle_get_ns.fetch_add(
686
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ NowNs() - handle_start_ns, std::memory_order_relaxed);
687 }
688 const GetPayloadCompletion completion{
689 ✗ task.slot,
690 ✗ task.client_id,
691 ✗ task.qp_index,
692 ✗ task.slot_in_qp,
693 ✗ task.poll_thread_id,
694 ✗ task.seq,
695 ✗ task.response_epoch,
696 task.response,
697 payload_written_direct,
698 stale,
699 ✗ };
700
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ PushGetPayloadCompletion(completion);
701 ✗ }
702 }
703
704 ✗ void CompleteResponseForSlot(
705 int slot,
706 int client_id,
707 int qp_index,
708 int slot_in_qp,
709 const petps::RcShardServerTransport::ResponseView& response,
710 std::uint64_t seq,
711 bool profile_enabled) {
712 std::atomic_thread_fence(std::memory_order_release);
713
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ const std::uint64_t complete_start_ns = profile_enabled ? NowNs() : 0;
714 ✗ transport_->CompleteResponse(
715 client_id, qp_index, slot_in_qp, response, seq);
716
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
717 ✗ profile_.complete_response_ns.fetch_add(
718 ✗ NowNs() - complete_start_ns, std::memory_order_relaxed);
719 }
720
0/14
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ VLOG(1) << "component=rdma_rc_server event=complete shard=" << shard_id_
721
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ << " slot=" << slot << " client_id=" << client_id
722
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ << " qp=" << qp_index << " seq=" << seq
723
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " status=" << response.status->status
724
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " response_bytes=" << response.status->response_bytes;
725 ✗ last_seq_[static_cast<std::size_t>(slot)] = seq;
726
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (GetPayloadOffloadEnabled()) {
727 ✗ inflight_seq_[static_cast<std::size_t>(slot)] = 0;
728 }
729 ✗ }
730
731 ✗ void CompleteResponseStatusOnlyForSlot(
732 int slot,
733 int client_id,
734 int qp_index,
735 int slot_in_qp,
736 const petps::RcShardServerTransport::ResponseView& response,
737 std::uint64_t seq,
738 bool profile_enabled) {
739 std::atomic_thread_fence(std::memory_order_release);
740
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ const std::uint64_t complete_start_ns = profile_enabled ? NowNs() : 0;
741 ✗ transport_->CompleteResponseStatusOnly(
742 client_id, qp_index, slot_in_qp, response, seq);
743
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
744 ✗ profile_.complete_response_ns.fetch_add(
745 ✗ NowNs() - complete_start_ns, std::memory_order_relaxed);
746 }
747
0/14
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ VLOG(1) << "component=rdma_rc_server event=complete_direct shard="
748
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ << shard_id_ << " slot=" << slot << " client_id=" << client_id
749
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ << " qp=" << qp_index << " seq=" << seq
750
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << " status=" << response.status->status
751
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " response_bytes=" << response.status->response_bytes;
752 ✗ last_seq_[static_cast<std::size_t>(slot)] = seq;
753
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (GetPayloadOffloadEnabled()) {
754 ✗ inflight_seq_[static_cast<std::size_t>(slot)] = 0;
755 }
756 ✗ }
757
758 ✗ void DrainGetPayloadCompletions(int poll_thread_id, bool profile_enabled) {
759
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (!GetPayloadOffloadEnabled()) {
760
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ MaybeReportRebuildFenceStats();
761 ✗ return;
762 }
763 ✗ GetPayloadCompletion completion;
764
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ while (TryPopGetPayloadCompletion(poll_thread_id, &completion)) {
765
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ if (completion.stale ||
766 ✗ completion.response_epoch !=
767
0/4
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ transport_->ResponseEpoch(
768 completion.client_id, completion.qp_index)) {
769 // The lane was rebuilt after the request was accepted. Its payload WRs
770 // were flushed by the reset (or refused), so writing the status word
771 // now would report kOk for a response that never reached the client.
772 ✗ payload_completion_dropped_stale_.fetch_add(
773 1, std::memory_order_relaxed);
774
0/14
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ VLOG(1) << "component=rdma_rc_server event=get_payload_dropped_stale"
775
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ << " shard=" << shard_id_ << " client_id="
776
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << completion.client_id << " qp=" << completion.qp_index
777
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ << " slot=" << completion.slot << " seq=" << completion.seq;
778 ✗ continue;
779 ✗ }
780
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (completion.payload_written_direct) {
781
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ CompleteResponseStatusOnlyForSlot(
782 completion.slot,
783 completion.client_id,
784 completion.qp_index,
785 completion.slot_in_qp,
786 completion.response,
787 completion.seq,
788 profile_enabled);
789 } else {
790
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ CompleteResponseForSlot(
791 completion.slot,
792 completion.client_id,
793 completion.qp_index,
794 completion.slot_in_qp,
795 completion.response,
796 completion.seq,
797 profile_enabled);
798 }
799 }
800
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ MaybeReportRebuildFenceStats();
801 }
802
803 // Count a direct_sg batch that failed after the probe and record the probe
804 // time, so the fallback cost stays visible instead of being hidden by the
805 // early return (issue #257).
806 ✗ void RecordDirectSgAbort(std::uint64_t direct_start_ns) {
807
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (FLAGS_rdma_rc_profile_interval_ms <= 0) {
808 ✗ return;
809 }
810 ✗ profile_.get_direct_sg_abort.fetch_add(1, std::memory_order_relaxed);
811
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (direct_start_ns != 0) {
812 ✗ profile_.get_direct_sg_abort_ns.fetch_add(
813 ✗ NowNs() - direct_start_ns, std::memory_order_relaxed);
814 }
815 }
816
817 ✗ bool HandleGetDirectSg(
818 const petps::RequestDescriptor& descriptor,
819 base::ConstArray<std::uint64_t> keys,
820 petps::RcShardServerTransport::ResponseView* response,
821 int thread_id,
822 int slot_in_qp,
823 std::uint64_t response_epoch,
824 CachePS::FlatGetProfile* get_profile) {
825
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ if (descriptor.response_bytes == 0 || descriptor.embedding_dim == 0) {
826 ✗ return false;
827 }
828 ✗ const std::size_t row_bytes =
829 ✗ static_cast<std::size_t>(descriptor.embedding_dim) * sizeof(float);
830
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (row_bytes == 0 ||
831 ✗ descriptor.response_bytes !=
832
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ descriptor.key_count * static_cast<std::uint32_t>(row_bytes)) {
833 ✗ return false;
834 }
835
836
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ thread_local std::vector<CachePS::DirectFixedRow> rows;
837 ✗ rows.clear();
838 const std::uint64_t direct_start_ns =
839
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ FLAGS_rdma_rc_profile_interval_ms > 0 ? NowNs() : 0;
840 ✗ const bool ok = cache_ps_->GetParameterDirectFixedRows(
841 keys,
842 ✗ descriptor.key_count,
843 ✗ descriptor.embedding_dim,
844 thread_id,
845 &rows,
846 get_profile);
847
0/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ if (!ok || rows.size() != descriptor.key_count) {
848 ✗ RecordDirectSgAbort(direct_start_ns);
849 ✗ return false;
850 }
851 ✗ char* zero_base = direct_sg_zero_region_.get();
852 ✗ std::uint64_t response_offset = 0;
853 ✗ std::uint64_t wr_count = 0;
854 ✗ std::size_t zero_cursor = 0;
855
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ for (std::size_t row = 0; row < rows.size();) {
856 ✗ std::array<petps::RawVerbsSge, kMaxDirectSgesPerWr> sges{};
857 ✗ std::size_t sge_count = 0;
858 ✗ std::size_t row_count = 0;
859
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ for (; row < rows.size(); ++row) {
860 ✗ const auto& ref = rows[row];
861
0/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ if (!ref.missing && (ref.data == nullptr || ref.size != row_bytes)) {
862 // Key exists but is not directly addressable (SSD row or capacity
863 // mismatch). It must never be zero-filled, so fall back to the copy
864 // path for this whole batch.
865
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ RecordDirectSgAbort(direct_start_ns);
866 ✗ return false;
867 }
868 ✗ const char* src = ref.data;
869
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (ref.missing) {
870
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (zero_base == nullptr) {
871
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ RecordDirectSgAbort(direct_start_ns);
872 ✗ return false;
873 }
874 // Absent key: serve zeros from the registered zero region. The cursor
875 // advances one row per miss, so consecutive misses stay contiguous
876 // and coalesce into a single SGE.
877 ✗ src = zero_base + zero_cursor * row_bytes;
878 }
879
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (sge_count > 0) {
880 ✗ auto& last = sges[sge_count - 1];
881 ✗ const char* last_end =
882 ✗ static_cast<const char*>(last.data) + last.bytes;
883
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (last_end == src) {
884 ✗ last.bytes += row_bytes;
885 ✗ ++row_count;
886
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (ref.missing) {
887 ✗ ++zero_cursor;
888 }
889 ✗ continue;
890 }
891 }
892
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (sge_count == kMaxDirectSgesPerWr) {
893 ✗ break;
894 }
895 ✗ sges[sge_count++] = petps::RawVerbsSge{src, row_bytes};
896 ✗ ++row_count;
897
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (ref.missing) {
898 ✗ ++zero_cursor;
899 }
900 }
901 ✗ const std::uint64_t bytes =
902 static_cast<std::uint64_t>(row_count * row_bytes);
903 ✗ transport_->WriteResponsePayloadSg(
904 ✗ descriptor.client_id,
905
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ descriptor.qp_index,
906 slot_in_qp,
907 response_epoch,
908 base::ConstArray<petps::RawVerbsSge>(
909 ✗ sges.data(), static_cast<int>(sge_count)),
910 response_offset,
911 bytes);
912 ✗ response_offset += bytes;
913 ✗ ++wr_count;
914 }
915 ✗ response->status->status = static_cast<std::int32_t>(petps::RpcStatus::kOk);
916 ✗ response->status->response_bytes =
917 ✗ static_cast<std::uint32_t>(descriptor.response_bytes);
918
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (FLAGS_rdma_rc_profile_interval_ms > 0) {
919 ✗ profile_.get_direct_sg.fetch_add(1, std::memory_order_relaxed);
920 ✗ profile_.get_direct_sg_ns.fetch_add(
921 ✗ NowNs() - direct_start_ns, std::memory_order_relaxed);
922 ✗ profile_.get_direct_sg_wr.fetch_add(wr_count, std::memory_order_relaxed);
923
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (get_profile != nullptr) {
924 ✗ AccumulateFlatGetProfile(*get_profile);
925 }
926 }
927 ✗ return true;
928 }
929
930 ✗ bool HandleGet(const petps::RequestDescriptor& descriptor,
931 const char* payload,
932 petps::RcShardServerTransport::ResponseView* response,
933 int thread_id,
934 int slot_in_qp,
935 std::uint64_t response_epoch) {
936
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (FLAGS_rdma_rc_fake_get_mode == "throw") {
937 // Test-only fault injection for the ProcessSlot handler guard: proves a
938 // throwing handler cannot terminate the shard and still completes the
939 // request with kInternalError instead of leaving the client to time out.
940
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw std::runtime_error("injected handler failure");
941 }
942
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (FLAGS_rdma_rc_fake_get_mode == "status_only") {
943 ✗ response->status->status =
944 static_cast<std::int32_t>(petps::RpcStatus::kOk);
945 ✗ response->status->response_bytes = 0;
946 ✗ return false;
947 }
948
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (FLAGS_rdma_rc_fake_get_mode == "payload_memset") {
949 ✗ std::memset(response->payload, 0, descriptor.response_bytes);
950 ✗ response->status->status =
951 static_cast<std::int32_t>(petps::RpcStatus::kOk);
952 ✗ response->status->response_bytes =
953 ✗ static_cast<std::uint32_t>(descriptor.response_bytes);
954 ✗ return false;
955 }
956
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (FLAGS_rdma_rc_fake_get_mode == "index_only") {
957 base::ConstArray<std::uint64_t> keys(
958 reinterpret_cast<const std::uint64_t*>(payload),
959 ✗ descriptor.key_count);
960 ✗ CachePS::FlatGetProfile get_profile;
961 ✗ CachePS::FlatGetProfile* get_profile_ptr =
962
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ FLAGS_rdma_rc_profile_interval_ms > 0 ? &get_profile : nullptr;
963 const bool ok =
964
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ cache_ps_->ProbeParameterIndex(keys, thread_id, get_profile_ptr);
965
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (get_profile_ptr != nullptr) {
966 ✗ AccumulateFlatGetProfile(get_profile);
967 }
968
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ response->status->status = static_cast<std::int32_t>(
969 ok ? petps::RpcStatus::kOk : petps::RpcStatus::kValueSizeMismatch);
970 ✗ response->status->response_bytes = 0;
971 ✗ return false;
972 }
973
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ if (FLAGS_rdma_rc_fake_get_mode != "none" &&
974
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ !FLAGS_rdma_rc_fake_get_mode.empty()) {
975 ✗ response->status->status =
976 static_cast<std::int32_t>(petps::RpcStatus::kInvalidPayload);
977 ✗ response->status->response_bytes = 0;
978 ✗ return false;
979 }
980
981 base::ConstArray<std::uint64_t> keys(
982 ✗ reinterpret_cast<const std::uint64_t*>(payload), descriptor.key_count);
983 ✗ CachePS::FlatGetProfile get_profile;
984 ✗ CachePS::FlatGetProfile* get_profile_ptr =
985
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ FLAGS_rdma_rc_profile_interval_ms > 0 ? &get_profile : nullptr;
986
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if ((descriptor.flags & petps::kRcFlagGetDirectSg) != 0) {
987
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const bool direct_ok = HandleGetDirectSg(
988 descriptor,
989 keys,
990 response,
991 thread_id,
992 slot_in_qp,
993 response_epoch,
994 get_profile_ptr);
995
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (direct_ok) {
996 ✗ return true;
997 }
998
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (FLAGS_rdma_rc_profile_interval_ms > 0) {
999 ✗ profile_.get_direct_sg_fallback.fetch_add(1, std::memory_order_relaxed);
1000 }
1001
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if ((descriptor.flags & petps::kRcFlagGetAllowFallbackCopy) == 0) {
1002 ✗ response->status->status =
1003 static_cast<std::int32_t>(petps::RpcStatus::kInvalidPayload);
1004 ✗ response->status->response_bytes = 0;
1005 ✗ return false;
1006 }
1007 }
1008 ✗ const bool ok = cache_ps_->GetParameterFlat(
1009 keys,
1010 ✗ reinterpret_cast<float*>(response->payload),
1011 ✗ descriptor.key_count,
1012
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ descriptor.embedding_dim,
1013 thread_id,
1014 get_profile_ptr);
1015
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (get_profile_ptr != nullptr) {
1016 ✗ AccumulateFlatGetProfile(get_profile);
1017 }
1018
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ response->status->status = static_cast<std::int32_t>(
1019 ok ? petps::RpcStatus::kOk : petps::RpcStatus::kValueSizeMismatch);
1020 ✗ response->status->response_bytes =
1021 ✗ static_cast<std::uint32_t>(descriptor.response_bytes);
1022 ✗ return false;
1023 }
1024
1025 ✗ void HandlePut(const petps::RequestDescriptor& descriptor,
1026 const char* payload,
1027 petps::RcShardServerTransport::ResponseView* response,
1028 int thread_id) {
1029 ✗ const auto* reader =
1030 reinterpret_cast<const ParameterCompressReader*>(payload);
1031
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (!reader->Valid(static_cast<int>(descriptor.payload_bytes))) {
1032 ✗ response->status->status =
1033 static_cast<std::int32_t>(petps::RpcStatus::kInvalidPayload);
1034 ✗ response->status->response_bytes = 0;
1035 ✗ return;
1036 }
1037
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ for (int i = 0; i < reader->item_size(); ++i) {
1038 ✗ cache_ps_->PutSingleParameter(reader->item(i), thread_id);
1039 }
1040 ✗ response->status->status = static_cast<std::int32_t>(petps::RpcStatus::kOk);
1041 ✗ response->status->response_bytes = 0;
1042 }
1043
1044 ✗ void HandleUpdate(const petps::RequestDescriptor& descriptor,
1045 const char* payload,
1046 petps::RcShardServerTransport::ResponseView* response,
1047 int thread_id) {
1048
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const std::string_view table_name = petps::DescriptorTableName(descriptor);
1049
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (table_name.empty()) {
1050 ✗ response->status->status =
1051 static_cast<std::int32_t>(petps::RpcStatus::kInvalidPayload);
1052 ✗ response->status->response_bytes = 0;
1053 ✗ return;
1054 }
1055
1056 ✗ const auto* reader =
1057 reinterpret_cast<const ParameterCompressReader*>(payload);
1058
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ if (!reader->Valid(static_cast<int>(descriptor.payload_bytes))) {
1059 ✗ response->status->status =
1060 static_cast<std::int32_t>(petps::RpcStatus::kInvalidPayload);
1061 ✗ response->status->response_bytes = 0;
1062 ✗ return;
1063 }
1064
1065
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const bool ok = cache_ps_->UpdateParameter(
1066
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ std::string(table_name), reader, static_cast<unsigned>(thread_id));
1067
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ response->status->status = static_cast<std::int32_t>(
1068 ok ? petps::RpcStatus::kOk : petps::RpcStatus::kInvalidPayload);
1069 ✗ response->status->response_bytes = 0;
1070 }
1071
1072 ✗ void HandleUpdateFlat(const petps::RequestDescriptor& descriptor,
1073 const char* payload,
1074 petps::RcShardServerTransport::ResponseView* response,
1075 int thread_id) {
1076
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const std::string_view table_name = petps::DescriptorTableName(descriptor);
1077 ✗ const std::size_t expected_bytes = petps::FlatUpdatePayloadBytes(
1078 ✗ descriptor.key_count, descriptor.embedding_dim);
1079
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ if (table_name.empty() || descriptor.key_count == 0 ||
1080
0/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ expected_bytes == 0 || descriptor.payload_bytes != expected_bytes) {
1081 ✗ response->status->status =
1082 static_cast<std::int32_t>(petps::RpcStatus::kInvalidPayload);
1083 ✗ response->status->response_bytes = 0;
1084 ✗ return;
1085 }
1086
1087 ✗ const std::size_t key_bytes =
1088 ✗ static_cast<std::size_t>(descriptor.key_count) * sizeof(std::uint64_t);
1089 ✗ const auto* keys = reinterpret_cast<const std::uint64_t*>(payload);
1090 ✗ const auto* grads = reinterpret_cast<const float*>(payload + key_bytes);
1091
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const bool ok = cache_ps_->UpdateParameterFlat(
1092
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ std::string(table_name),
1093 ✗ base::ConstArray<std::uint64_t>(keys, descriptor.key_count),
1094 grads,
1095 ✗ descriptor.key_count,
1096 ✗ descriptor.embedding_dim,
1097 static_cast<unsigned>(thread_id));
1098
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ response->status->status = static_cast<std::int32_t>(
1099 ok ? petps::RpcStatus::kOk : petps::RpcStatus::kInvalidPayload);
1100 ✗ response->status->response_bytes = 0;
1101 }
1102
1103 ✗ void HandleInitTable(const petps::RequestDescriptor& descriptor,
1104 const char* payload,
1105 petps::RcShardServerTransport::ResponseView* response) {
1106
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const std::string_view table_name = petps::DescriptorTableName(descriptor);
1107
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ if (table_name.empty() ||
1108 ✗ descriptor.payload_bytes != petps::InitTablePayloadBytes()) {
1109 ✗ response->status->status =
1110 static_cast<std::int32_t>(petps::RpcStatus::kInvalidPayload);
1111 ✗ response->status->response_bytes = 0;
1112 ✗ return;
1113 }
1114
1115 ✗ std::uint64_t num_embeddings = 0;
1116 ✗ std::uint64_t embedding_dim = 0;
1117 ✗ std::uint64_t table_id = 0;
1118 ✗ std::memcpy(&num_embeddings, payload, sizeof(num_embeddings));
1119 ✗ std::memcpy(&embedding_dim,
1120 ✗ payload + sizeof(num_embeddings),
1121 sizeof(embedding_dim));
1122 ✗ std::memcpy(&table_id,
1123 ✗ payload + sizeof(num_embeddings) + sizeof(embedding_dim),
1124 sizeof(table_id));
1125
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const int tag = cache_ps_->InitTable(
1126
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ std::string(table_name), num_embeddings, embedding_dim, table_id);
1127
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ response->status->status = static_cast<std::int32_t>(
1128 tag >= 0 ? petps::RpcStatus::kOk : petps::RpcStatus::kInvalidPayload);
1129 ✗ response->status->reserved = tag >= 0 ? static_cast<std::uint32_t>(tag) : 0;
1130 ✗ response->status->response_bytes = 0;
1131 }
1132
1133 // Observation-only heartbeat loop. It never changes serving behavior: a
1134 // failed heartbeat is logged and retried, never propagated to the data path.
1135 ✗ void HeartbeatThread() {
1136 ✗ const int interval_ms = std::max(1, FLAGS_rdma_heartbeat_interval_ms);
1137
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ LOG(INFO) << "component=rdma_control_plane event=heartbeat_thread_ready"
1138
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " server_id=" << FLAGS_global_id
1139
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " interval_ms=" << interval_ms;
1140
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ while (!stop_requested_.load(std::memory_order_relaxed)) {
1141 try {
1142
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ control_plane_client_.SendHeartbeat(FLAGS_global_id);
1143
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ } catch (const std::exception& error) {
1144
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ LOG(WARNING) << "component=rdma_control_plane event=heartbeat_failed"
1145
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " server_id=" << FLAGS_global_id << " error=\""
1146
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ << error.what() << "\"";
1147 ✗ }
1148 // Bounded sleep: Stop() joins this thread after at most one interval.
1149
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ std::this_thread::sleep_for(std::chrono::milliseconds(interval_ms));
1150 }
1151 ✗ }
1152
1153 ✗ void MaybePublishServerReady() {
1154 const int started =
1155 ✗ started_threads_.fetch_add(1, std::memory_order_relaxed) + 1;
1156
0/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ if (started != thread_count_ ||
1157 ✗ ready_published_.exchange(true, std::memory_order_acq_rel)) {
1158 ✗ return;
1159 }
1160 ✗ control_plane_client_.PublishServerReady(FLAGS_global_id);
1161
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ LOG(INFO) << "component=rdma_control_plane event=server_ready_published"
1162
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " server_id=" << FLAGS_global_id
1163 << " host=" << FLAGS_rdma_control_plane_host
1164
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ << " port=" << FLAGS_rdma_control_plane_port;
1165 }
1166
1167 ✗ void PollingThread(int thread_id) {
1168 ✗ BindServerCore(thread_id);
1169
0/4
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ LOG(INFO) << "component=rdma_server event=polling_thread_ready thread_id="
1170
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << thread_id;
1171 ✗ MaybePublishServerReady();
1172 const int coroutines_per_thread =
1173 ✗ std::max(1, FLAGS_rdma_rc_server_coroutines_per_thread);
1174
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ LOG(INFO) << "component=rdma_rc_server event=polling_thread_mode"
1175
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " thread_id=" << thread_id
1176
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " coroutines_per_thread=" << coroutines_per_thread;
1177
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (coroutines_per_thread > 1) {
1178 ✗ RunCoroutinePollingThread(thread_id, coroutines_per_thread);
1179 ✗ return;
1180 }
1181
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ while (!stop_requested_.load(std::memory_order_relaxed)) {
1182 ✗ const bool profile_enabled = FLAGS_rdma_rc_profile_interval_ms > 0;
1183
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ const std::uint64_t poll_start_ns = profile_enabled ? NowNs() : 0;
1184 ✗ std::uint64_t scanned_slots = 0;
1185 ✗ std::uint64_t ready_slots = 0;
1186
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ DrainGetPayloadCompletions(thread_id, profile_enabled);
1187
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ ScanAssignedSlots(
1188 thread_id,
1189 /*worker_id=*/0,
1190 /*worker_count=*/1,
1191 profile_enabled,
1192 &scanned_slots,
1193 &ready_slots);
1194
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ DrainGetPayloadCompletions(thread_id, profile_enabled);
1195
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ MaybePollClientRebuilds(thread_id);
1196
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
1197 ✗ profile_.scan_rounds.fetch_add(1, std::memory_order_relaxed);
1198 ✗ profile_.scanned_slots.fetch_add(
1199 scanned_slots, std::memory_order_relaxed);
1200
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (ready_slots == 0) {
1201 ✗ profile_.empty_scan_rounds.fetch_add(1, std::memory_order_relaxed);
1202 }
1203 ✗ UpdateMax(&profile_.max_ready_per_round, ready_slots);
1204
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const std::uint64_t poll_loop_ns = NowNs() - poll_start_ns;
1205 ✗ profile_.poll_loop_ns.fetch_add(
1206 poll_loop_ns, std::memory_order_relaxed);
1207 auto& poller =
1208
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ *poller_profiles_.at(static_cast<std::size_t>(thread_id));
1209 ✗ poller.scan_rounds.fetch_add(1, std::memory_order_relaxed);
1210 ✗ poller.scanned_slots.fetch_add(
1211 scanned_slots, std::memory_order_relaxed);
1212 ✗ poller.ready_slots.fetch_add(ready_slots, std::memory_order_relaxed);
1213 ✗ poller.poll_loop_ns.fetch_add(poll_loop_ns, std::memory_order_relaxed);
1214
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ MaybeReportProfile(thread_id);
1215 }
1216 ✗ std::this_thread::yield();
1217 }
1218 }
1219
1220 ✗ bool ProcessSlot(int slot, int thread_id, bool profile_enabled) {
1221 ✗ int client_id = -1;
1222 ✗ int qp_index = -1;
1223 ✗ int slot_in_qp = -1;
1224
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ transport_->DecodeSlotIndex(slot, &client_id, &qp_index, &slot_in_qp);
1225
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ auto* commit = transport_->RequestCommitAt(slot);
1226
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (commit->state.load(std::memory_order_acquire) != petps::kRcSlotReady) {
1227
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
1228 ✗ profile_.not_ready_slots.fetch_add(1, std::memory_order_relaxed);
1229
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ poller_profiles_.at(static_cast<std::size_t>(thread_id))
1230 ✗ ->not_ready_slots.fetch_add(1, std::memory_order_relaxed);
1231 }
1232 ✗ return false;
1233 }
1234 ✗ const std::uint64_t seq = commit->seq.load(std::memory_order_acquire);
1235
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (seq == 0) {
1236
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
1237 ✗ profile_.zero_seq_ready.fetch_add(1, std::memory_order_relaxed);
1238 }
1239 ✗ return false;
1240 }
1241
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (seq == last_seq_[static_cast<std::size_t>(slot)]) {
1242
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
1243 ✗ profile_.duplicate_seq_ready.fetch_add(1, std::memory_order_relaxed);
1244
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ poller_profiles_.at(static_cast<std::size_t>(thread_id))
1245 ✗ ->duplicate_seq_ready.fetch_add(1, std::memory_order_relaxed);
1246 }
1247 ✗ return false;
1248 }
1249
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ if (GetPayloadOffloadEnabled() &&
1250
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ seq == inflight_seq_[static_cast<std::size_t>(slot)]) {
1251
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
1252 ✗ profile_.inflight_seq_ready.fetch_add(1, std::memory_order_relaxed);
1253
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ poller_profiles_.at(static_cast<std::size_t>(thread_id))
1254 ✗ ->inflight_seq_ready.fetch_add(1, std::memory_order_relaxed);
1255 }
1256 ✗ return false;
1257 }
1258
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
1259 ✗ profile_.ready_slots.fetch_add(1, std::memory_order_relaxed);
1260 }
1261
1262
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ auto* descriptor = transport_->RequestDescriptorAt(slot);
1263 ✗ std::string error;
1264
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (!petps::ValidateRequestDescriptor(
1265 *descriptor,
1266
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ transport_->config().request_slot_bytes,
1267 ✗ transport_->config().response_slot_bytes,
1268 &error)) {
1269
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ LOG(ERROR) << "component=rdma_rc_server event=invalid_descriptor"
1270
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ << " shard=" << shard_id_ << " slot=" << slot
1271
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ << " thread_id=" << thread_id << " seq=" << seq
1272
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " descriptor_seq=" << descriptor->seq
1273
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " client_id=" << descriptor->client_id
1274
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ << " qp=" << descriptor->qp_index << " op=" << descriptor->op
1275
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " key_count=" << descriptor->key_count
1276
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " payload_bytes=" << descriptor->payload_bytes
1277
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " response_bytes=" << descriptor->response_bytes
1278
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " error=\"" << error << "\"";
1279
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
1280 ✗ profile_.invalid_descriptor.fetch_add(1, std::memory_order_relaxed);
1281 }
1282 ✗ last_seq_[static_cast<std::size_t>(slot)] = seq;
1283 ✗ commit->state.store(0, std::memory_order_release);
1284 ✗ return true;
1285 }
1286
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (descriptor->client_id != static_cast<std::uint32_t>(client_id) ||
1287
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ descriptor->qp_index != static_cast<std::uint32_t>(qp_index)) {
1288
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ LOG(ERROR) << "component=rdma_rc_server event=slot_descriptor_mismatch"
1289
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ << " shard=" << shard_id_ << " slot=" << slot
1290
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " thread_id=" << thread_id
1291
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ << " slot_client_id=" << client_id << " slot_qp=" << qp_index
1292
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " descriptor_client_id=" << descriptor->client_id
1293
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ << " descriptor_qp=" << descriptor->qp_index << " seq=" << seq;
1294
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
1295 ✗ profile_.invalid_descriptor.fetch_add(1, std::memory_order_relaxed);
1296 }
1297 ✗ last_seq_[static_cast<std::size_t>(slot)] = seq;
1298 ✗ commit->state.store(0, std::memory_order_release);
1299 ✗ return true;
1300 }
1301
1302 auto response =
1303
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ transport_->OpenClientResponse(client_id, qp_index, slot_in_qp);
1304
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ const char* payload = transport_->RequestPayloadAt(slot);
1305
0/16
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ VLOG(1) << "component=rdma_rc_server event=consume shard=" << shard_id_
1306
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ << " slot=" << slot << " client_id=" << descriptor->client_id
1307
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ << " qp=" << descriptor->qp_index << " seq=" << seq << " op="
1308
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << descriptor->op << " key_count=" << descriptor->key_count
1309
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " payload_bytes=" << descriptor->payload_bytes
1310
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " response_bytes=" << descriptor->response_bytes;
1311 ✗ response.status->status =
1312 static_cast<std::int32_t>(petps::RpcStatus::kInvalidPayload);
1313 ✗ response.status->response_bytes = 0;
1314
1315 // A handler exception must not escape this thread: std::thread's entry
1316 // point terminates the process, so one malformed request would take the
1317 // whole shard down. The guard sits around the dispatch rather than around
1318 // the poll loop because the completion below also advances last_seq_; if
1319 // the slot were left unconsumed, the next scan would find the same ready
1320 // seq and throw again at polling rate.
1321 ✗ auto fail_request = [&](const char* what) {
1322
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ LOG(ERROR) << "component=rdma_rc_server event=handler_exception"
1323
0/12
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ << " shard=" << shard_id_ << " slot=" << slot << " client_id="
1324
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ << client_id << " qp=" << qp_index << " seq=" << seq
1325
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ << " op=" << descriptor->op << " error=\"" << what << "\"";
1326 ✗ response.status->status =
1327 static_cast<std::int32_t>(petps::RpcStatus::kInternalError);
1328 ✗ response.status->response_bytes = 0;
1329 ✗ };
1330 try {
1331
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (descriptor->shard_id != static_cast<std::uint32_t>(shard_id_)) {
1332
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ LOG(ERROR) << "component=rdma_rc_server event=wrong_shard"
1333
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << " expected_shard=" << shard_id_
1334
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " actual_shard=" << descriptor->shard_id
1335
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ << " slot=" << slot << " client_id=" << descriptor->client_id
1336
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ << " qp=" << descriptor->qp_index << " seq=" << seq << " op="
1337
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << descriptor->op << " key_count=" << descriptor->key_count;
1338
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
1339 ✗ profile_.wrong_shard.fetch_add(1, std::memory_order_relaxed);
1340 }
1341 ✗ response.status->status =
1342 static_cast<std::int32_t>(petps::RpcStatus::kWrongShard);
1343
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ } else if (descriptor->op ==
1344 static_cast<std::uint16_t>(petps::RcOp::kGet)) {
1345
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (GetPayloadOffloadEnabled()) {
1346 const GetPayloadTask task{
1347 slot,
1348 client_id,
1349 qp_index,
1350 slot_in_qp,
1351 thread_id,
1352 seq,
1353
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ transport_->ResponseEpoch(client_id, qp_index),
1354 *descriptor,
1355 payload,
1356 response,
1357 ✗ };
1358
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ if (!EnqueueGetPayloadTask(task)) {
1359 ✗ return false;
1360 }
1361 ✗ inflight_seq_[static_cast<std::size_t>(slot)] = seq;
1362 ✗ return true;
1363 } else {
1364
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ const std::uint64_t handle_start_ns = profile_enabled ? NowNs() : 0;
1365
0/4
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ const bool payload_written_direct = HandleGet(
1366 *descriptor,
1367 payload,
1368 &response,
1369 thread_id,
1370 slot_in_qp,
1371 transport_->ResponseEpoch(client_id, qp_index));
1372
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
1373 ✗ profile_.handled_get.fetch_add(1, std::memory_order_relaxed);
1374 ✗ profile_.handle_get_ns.fetch_add(
1375
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ NowNs() - handle_start_ns, std::memory_order_relaxed);
1376
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ poller_profiles_.at(static_cast<std::size_t>(thread_id))
1377 ✗ ->handled_get.fetch_add(1, std::memory_order_relaxed);
1378 }
1379
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (payload_written_direct) {
1380
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ CompleteResponseStatusOnlyForSlot(
1381 slot,
1382 client_id,
1383 qp_index,
1384 slot_in_qp,
1385 response,
1386 seq,
1387 profile_enabled);
1388 ✗ return true;
1389 }
1390 }
1391
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ } else if (descriptor->op ==
1392 static_cast<std::uint16_t>(petps::RcOp::kPut)) {
1393
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ const std::uint64_t handle_start_ns = profile_enabled ? NowNs() : 0;
1394
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ HandlePut(*descriptor, payload, &response, thread_id);
1395
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
1396 ✗ profile_.handled_put.fetch_add(1, std::memory_order_relaxed);
1397 ✗ profile_.handle_put_ns.fetch_add(
1398
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ NowNs() - handle_start_ns, std::memory_order_relaxed);
1399 }
1400
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ } else if (descriptor->op ==
1401 static_cast<std::uint16_t>(petps::RcOp::kUpdate)) {
1402
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ const std::uint64_t handle_start_ns = profile_enabled ? NowNs() : 0;
1403
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ HandleUpdate(*descriptor, payload, &response, thread_id);
1404
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
1405 ✗ profile_.handled_update.fetch_add(1, std::memory_order_relaxed);
1406 ✗ profile_.handle_update_ns.fetch_add(
1407
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ NowNs() - handle_start_ns, std::memory_order_relaxed);
1408 }
1409
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ } else if (descriptor->op ==
1410 static_cast<std::uint16_t>(petps::RcOp::kUpdateFlat)) {
1411
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ const std::uint64_t handle_start_ns = profile_enabled ? NowNs() : 0;
1412
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ HandleUpdateFlat(*descriptor, payload, &response, thread_id);
1413
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
1414 ✗ profile_.handled_update.fetch_add(1, std::memory_order_relaxed);
1415 ✗ profile_.handle_update_ns.fetch_add(
1416
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ NowNs() - handle_start_ns, std::memory_order_relaxed);
1417 }
1418
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ } else if (descriptor->op == static_cast<std::uint16_t>(
1419 petps::RcOp::kSparseGradientCommit)) {
1420
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (descriptor->response_bytes != sizeof(int64_t)) {
1421
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw std::invalid_argument("Invalid gradient commit response size");
1422 }
1423
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const int64_t committed = cache_ps_->SparseGradientCommit(
1424
0/4
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ std::string(petps::DescriptorTableName(*descriptor)),
1425
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ std::string(payload, descriptor->payload_bytes),
1426 ✗ thread_id);
1427 ✗ std::memcpy(response.payload, &committed, sizeof(committed));
1428 ✗ response.status->status = static_cast<int32_t>(petps::RpcStatus::kOk);
1429 ✗ response.status->response_bytes = sizeof(committed);
1430
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ } else if (descriptor->op ==
1431 static_cast<std::uint16_t>(petps::RcOp::kInitTable)) {
1432
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ const std::uint64_t handle_start_ns = profile_enabled ? NowNs() : 0;
1433
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ HandleInitTable(*descriptor, payload, &response);
1434
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
1435 ✗ profile_.handled_init.fetch_add(1, std::memory_order_relaxed);
1436 ✗ profile_.handle_init_ns.fetch_add(
1437
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ NowNs() - handle_start_ns, std::memory_order_relaxed);
1438 }
1439 }
1440
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ } catch (const std::exception& error) {
1441
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ fail_request(error.what());
1442 ✗ } catch (...) {
1443
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ fail_request("unknown exception");
1444
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ }
1445
1446
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ CompleteResponseForSlot(
1447 slot, client_id, qp_index, slot_in_qp, response, seq, profile_enabled);
1448 ✗ return true;
1449 ✗ }
1450
1451 // Throttled check for clients that rebuilt their lane QP. Runs on the polling
1452 // thread that owns the lanes, so it serializes with response writes without a
1453 // lock; disabled (and free) unless --rdma_lane_rebuild_enabled.
1454 ✗ void MaybePollClientRebuilds(int thread_id) {
1455
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (!FLAGS_rdma_lane_rebuild_enabled) {
1456 ✗ return;
1457 }
1458
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const std::uint64_t now = NowNs();
1459 std::uint64_t& next =
1460
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ next_rebuild_check_ns_.at(static_cast<std::size_t>(thread_id));
1461
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (now < next) {
1462 ✗ return;
1463 }
1464 ✗ const int base_ms = std::max(1, FLAGS_rdma_lane_rebuild_poll_ms);
1465 ✗ const int max_ms = std::max(base_ms, FLAGS_rdma_lane_rebuild_poll_max_ms);
1466 ✗ const int qp_count = transport_->config().qps_per_client_per_shard;
1467 ✗ int rebuilt_total = 0;
1468
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ for (int qp_index = thread_id; qp_index < qp_count;
1469 ✗ qp_index += thread_count_) {
1470 try {
1471
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ const int rebuilt = transport_->PollClientRebuildRequests(qp_index);
1472
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (rebuilt > 0) {
1473
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ LOG(WARNING)
1474 << "component=rdma_rc_server event=client_lane_rebuild_applied"
1475
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ << " shard=" << shard_id_ << " qp=" << qp_index
1476
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " count=" << rebuilt;
1477 }
1478 ✗ rebuilt_total += rebuilt;
1479
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ } catch (const std::exception& error) {
1480
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ LOG(WARNING)
1481 << "component=rdma_rc_server event=client_lane_rebuild_error"
1482
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ << " shard=" << shard_id_ << " qp=" << qp_index << " error=\""
1483
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ << error.what() << "\"";
1484 ✗ }
1485 }
1486 // Each quiet round doubles the next interval: an idle deployment should not
1487 // pay one GetMeta per client-lane every 50ms. A rebuild resets the backoff
1488 // so the next attempt is caught at the base interval.
1489 int& backoff_ms =
1490
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ rebuild_poll_backoff_ms_.at(static_cast<std::size_t>(thread_id));
1491
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (rebuilt_total > 0) {
1492 ✗ backoff_ms = 0;
1493 } else {
1494
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ const int current = backoff_ms > 0 ? backoff_ms : base_ms;
1495 ✗ backoff_ms = std::min(max_ms, current * 2);
1496 }
1497
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ const int next_ms = backoff_ms > 0 ? backoff_ms : base_ms;
1498 ✗ next = now + static_cast<std::uint64_t>(next_ms) * 1000000ULL;
1499 }
1500
1501 ✗ void ScanAssignedSlots(
1502 int thread_id,
1503 int worker_id,
1504 int worker_count,
1505 bool profile_enabled,
1506 std::uint64_t* scanned_slots,
1507 std::uint64_t* ready_slots) {
1508 ✗ const int qp_count = transport_->config().qps_per_client_per_shard;
1509 ✗ const int slots_per_qp = transport_->config().slots_per_qp;
1510 ✗ const int num_clients = transport_->config().num_clients;
1511 ✗ const int lane_slots = num_clients * slots_per_qp;
1512
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ for (int qp_index = thread_id; qp_index < qp_count;
1513 ✗ qp_index += thread_count_) {
1514
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ for (int lane_slot = worker_id; lane_slot < lane_slots;
1515 ✗ lane_slot += worker_count) {
1516 ✗ const int client_id = lane_slot / slots_per_qp;
1517 ✗ const int slot_in_qp = lane_slot % slots_per_qp;
1518 const int slot_index =
1519 ✗ transport_->SlotIndex(client_id, qp_index, slot_in_qp);
1520 ✗ ++(*scanned_slots);
1521
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (ProcessSlot(slot_index, thread_id, profile_enabled)) {
1522 ✗ ++(*ready_slots);
1523 }
1524 }
1525 }
1526 ✗ }
1527
1528 ✗ void CoroutineSlotScanner(
1529 boost::coroutines2::coroutine<void>::push_type& sink,
1530 int thread_id,
1531 int worker_id,
1532 int worker_count) {
1533
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ while (!stop_requested_.load(std::memory_order_relaxed)) {
1534 ✗ const bool profile_enabled = FLAGS_rdma_rc_profile_interval_ms > 0;
1535
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ const std::uint64_t poll_start_ns = profile_enabled ? NowNs() : 0;
1536 ✗ std::uint64_t scanned_slots = 0;
1537 ✗ std::uint64_t ready_slots = 0;
1538
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ DrainGetPayloadCompletions(thread_id, profile_enabled);
1539
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ ScanAssignedSlots(
1540 thread_id,
1541 worker_id,
1542 worker_count,
1543 profile_enabled,
1544 &scanned_slots,
1545 &ready_slots);
1546
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ DrainGetPayloadCompletions(thread_id, profile_enabled);
1547
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ MaybePollClientRebuilds(thread_id);
1548
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (profile_enabled) {
1549 ✗ profile_.scan_rounds.fetch_add(1, std::memory_order_relaxed);
1550 ✗ profile_.scanned_slots.fetch_add(
1551 scanned_slots, std::memory_order_relaxed);
1552
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (ready_slots == 0) {
1553 ✗ profile_.empty_scan_rounds.fetch_add(1, std::memory_order_relaxed);
1554 }
1555 ✗ UpdateMax(&profile_.max_ready_per_round, ready_slots);
1556
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const std::uint64_t poll_loop_ns = NowNs() - poll_start_ns;
1557 ✗ profile_.poll_loop_ns.fetch_add(
1558 poll_loop_ns, std::memory_order_relaxed);
1559 auto& poller =
1560
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ *poller_profiles_.at(static_cast<std::size_t>(thread_id));
1561 ✗ poller.scan_rounds.fetch_add(1, std::memory_order_relaxed);
1562 ✗ poller.scanned_slots.fetch_add(
1563 scanned_slots, std::memory_order_relaxed);
1564 ✗ poller.ready_slots.fetch_add(ready_slots, std::memory_order_relaxed);
1565 ✗ poller.poll_loop_ns.fetch_add(poll_loop_ns, std::memory_order_relaxed);
1566 }
1567
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ sink();
1568 }
1569 ✗ }
1570
1571 ✗ void RunCoroutinePollingThread(int thread_id, int coroutines_per_thread) {
1572 using Coroutine = boost::coroutines2::coroutine<void>;
1573 ✗ std::vector<std::unique_ptr<Coroutine::pull_type>> coroutines;
1574
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ coroutines.reserve(static_cast<std::size_t>(coroutines_per_thread));
1575
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ for (int coroutine_id = 0; coroutine_id < coroutines_per_thread;
1576 ++coroutine_id) {
1577
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ coroutines.emplace_back(std::make_unique<Coroutine::pull_type>(
1578 ✗ [this, thread_id, coroutine_id, coroutines_per_thread](
1579 ✗ Coroutine::push_type& sink) {
1580 ✗ CoroutineSlotScanner(
1581 sink, thread_id, coroutine_id, coroutines_per_thread);
1582 ✗ }));
1583 }
1584
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ while (!stop_requested_.load(std::memory_order_relaxed)) {
1585
0/2
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ for (auto& coroutine : coroutines) {
1586
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ (*coroutine)();
1587 }
1588
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ MaybeReportProfile(thread_id);
1589 ✗ std::this_thread::yield();
1590 }
1591 ✗ }
1592
1593 CachePS* cache_ps_ = nullptr;
1594 int thread_count_ = 1;
1595 int shard_id_ = 0;
1596 recstore::ResolvedRdmaDeployment deployment_;
1597 recstore::ResolvedRdmaFabric fabric_;
1598 std::unique_ptr<char, AlignedCharDeleter> direct_sg_zero_region_;
1599 std::unique_ptr<petps::RcShardServerTransport> transport_;
1600 petps::RdmaControlPlaneClient control_plane_client_;
1601 std::vector<std::thread> threads_;
1602 std::thread heartbeat_thread_;
1603 std::vector<std::uint64_t> last_seq_;
1604 std::vector<std::uint64_t> inflight_seq_;
1605 std::vector<std::unique_ptr<PollerProfile>> poller_profiles_;
1606 int get_payload_worker_count_ = 0;
1607 std::vector<std::thread> get_payload_workers_;
1608 std::vector<std::uint64_t> next_rebuild_check_ns_;
1609 std::vector<int> rebuild_poll_backoff_ms_;
1610 std::mutex get_payload_mu_;
1611 std::condition_variable get_payload_cv_;
1612 std::deque<GetPayloadTask> get_payload_tasks_;
1613 std::vector<std::deque<GetPayloadCompletion>> get_payload_completions_;
1614 std::atomic<int> started_threads_{0};
1615 std::atomic<bool> ready_published_{false};
1616 std::atomic<bool> stop_requested_{false};
1617 // Rebuild-fence observability: completions dropped because the response epoch
1618 // changed, and the next periodic fence-stats report deadline.
1619 std::atomic<std::uint64_t> payload_completion_dropped_stale_{0};
1620 std::atomic<std::uint64_t> next_fence_report_ns_{0};
1621 ProfileCounters profile_;
1622 };
1623
1624 std::atomic<bool> g_stop_requested{false};
1625
1626 ✗ void HandleStopSignal(int) { g_stop_requested.store(true); }
1627
1628 } // namespace
1629
1630 ✗ int main(int argc, char* argv[]) {
1631 // Keep crash dumps for real fatals; let SIGTERM/SIGINT exit cleanly.
1632 ✗ folly::InitOptions init_options;
1633 ✗ init_options.fatalSignals(
1634 (1UL << SIGSEGV) | (1UL << SIGILL) | (1UL << SIGFPE) | (1UL << SIGABRT) |
1635 (1UL << SIGBUS) | (1UL << SIGQUIT));
1636
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ folly::init(&argc, &argv, init_options);
1637 ✗ std::signal(SIGTERM, HandleStopSignal);
1638 ✗ std::signal(SIGINT, HandleStopSignal);
1639
1640 // petps_cluster_runner forwards the request sizing flags to both the server
1641 // and the client. The server derives these sizes from the JSON config and
1642 // per-request metadata, so accept the flags for compatibility only.
1643
0/16
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ VLOG(1) << "petps_server compatibility flags: value_size=" << FLAGS_value_size
1644
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << ", max_kv_num_per_request=" << FLAGS_max_kv_num_per_request;
1645
1646
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ if (ShouldTraceRdmaGet()) {
1647
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ std::cerr << "component=rdma_get_trace side=server event=enabled interval="
1648
0/4
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ << RdmaGetTraceInterval() << std::endl;
1649 }
1650
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ xmh::Reporter::StartReportThread();
1651
1652 ✗ base::PMMmapRegisterCenter::GetConfig().backend =
1653 ✗ base::PMMmapRegisterCenter::BackendFromUseDram(FLAGS_use_dram);
1654 ✗ base::PMMmapRegisterCenter::GetConfig().numa_id = FLAGS_numa_id;
1655
1656 ✗ base::global_socket_id = FLAGS_numa_id;
1657
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ LOG(INFO) << "set NUMA ID = " << FLAGS_numa_id;
1658
1659 const std::string config_path =
1660 ✗ FLAGS_config_path.empty()
1661
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ ? base::ResolveRecStoreConfigPath().string()
1662
0/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ : FLAGS_config_path;
1663
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ std::ifstream config_file(config_path);
1664
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ if (!config_file.is_open()) {
1665
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ LOG(FATAL) << "Cannot open config file: " << config_path;
1666 }
1667
1668 ✗ nlohmann::json config;
1669
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ config_file >> config;
1670
0/10
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ if (config.contains("cache_ps") && config["cache_ps"].is_object() &&
1671
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ config["cache_ps"].contains("base_kv_config")) {
1672
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ NormalizeDramValuePath(&config["cache_ps"]["base_kv_config"]);
1673 }
1674
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ if (config.contains("distributed_client") &&
1675
0/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ config["distributed_client"].is_object() &&
1676
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ config["distributed_client"].contains("base_kv_config")) {
1677
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ NormalizeDramValuePath(&config["distributed_client"]["base_kv_config"]);
1678 }
1679 ✗ std::unique_ptr<petps::RdmaControlPlaneServer> control_plane_server;
1680
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const auto deployment = recstore::ParseResolvedRdmaDeploymentConfig(config);
1681
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const auto& fabric = recstore::LocalRdmaFabric(deployment, FLAGS_global_id);
1682 ✗ petps::RdmaControlPlaneEndpoint control_plane_endpoint{
1683 FLAGS_rdma_control_plane_host,
1684 FLAGS_rdma_control_plane_port,
1685 FLAGS_rdma_control_plane_timeout_ms,
1686 deployment.deployment_id,
1687 ✗ deployment.epoch,
1688 ✗ deployment.protocol_version,
1689 deployment.configuration_digest,
1690 deployment.fabric_digest,
1691
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ deployment.num_shards};
1692 ✗ control_plane_endpoint.health_stale_ms =
1693 ✗ std::max(1, FLAGS_rdma_health_stale_ms);
1694 ✗ control_plane_endpoint.health_dead_ms = std::max(
1695 ✗ control_plane_endpoint.health_stale_ms + 1, FLAGS_rdma_health_dead_ms);
1696 ✗ if (FLAGS_rdma_heartbeat_interval_ms >=
1697
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ control_plane_endpoint.health_stale_ms) {
1698
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ LOG(WARNING) << "component=rdma_control_plane"
1699 << " event=heartbeat_interval_not_below_stale"
1700
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ << " heartbeat_interval_ms="
1701
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ << FLAGS_rdma_heartbeat_interval_ms << " health_stale_ms="
1702
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ << control_plane_endpoint.health_stale_ms;
1703 }
1704
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (FLAGS_global_id == 0) {
1705 control_plane_server =
1706
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ std::make_unique<petps::RdmaControlPlaneServer>(control_plane_endpoint);
1707
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ control_plane_server->Start();
1708
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ LOG(INFO) << "component=rdma_control_plane event=listening"
1709 << " server_id=0" << " host=" << FLAGS_rdma_control_plane_host
1710
0/12
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ << " port=" << FLAGS_rdma_control_plane_port;
1711 }
1712
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ auto cache_ps = std::make_unique<CachePS>(config["cache_ps"]);
1713
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const int shard_id = ResolveShardId(config);
1714 auto ps = std::make_unique<PetPSServer>(
1715 ✗ cache_ps.get(),
1716 FLAGS_thread_num,
1717 shard_id,
1718
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ NamespaceToken(),
1719 control_plane_endpoint,
1720 deployment,
1721
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ fabric);
1722
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ ps->Run();
1723
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ while (!g_stop_requested.load()) {
1724
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ std::this_thread::sleep_for(std::chrono::seconds(1));
1725 }
1726
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ LOG(INFO) << "component=petps_server event=shutdown";
1727
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ ps->Stop();
1728
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ if (control_plane_server != nullptr) {
1729
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ control_plane_server->Stop();
1730 }
1731 // Threads are joined; the process still exits without the global teardown,
1732 // which would unmap the multi-GB slab for no one.
1733 ✗ std::_Exit(0);
1734 ✗ }
1735