1 /*
2 * Copyright (c) 2019 Intel Corporation. All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * BSD license below:
9 *
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 */
32
33 #include <inttypes.h>
34
35 #include "ofi.h"
36 #include "ofi_prov.h"
37 #include "ofi_hook.h"
38 #include "hook_prov.h"
39 #include "ofi_enosys.h"
40
41 #include "hook_debug.h"
42
43 struct hook_prov_ctx hook_debug_prov_ctx;
44
45 struct hook_debug_config config = {
46 .trace_exit = 1,
47 .trace_cq_entry = 1,
48 .track_sends = 1,
49 /* Disable for now: debug hang */
50 .track_recvs = 0,
51 };
52
53 static struct hook_debug_txrx_entry *
hook_debug_get_tx_entry(struct hook_debug_ep * myep,void * context,uint64_t flags)54 hook_debug_get_tx_entry(struct hook_debug_ep *myep, void *context,
55 uint64_t flags)
56 {
57 struct hook_debug_txrx_entry *tx_entry;
58
59 tx_entry = ofi_buf_alloc(myep->tx_pool);
60 assert(tx_entry);
61 assert(tx_entry->magic == OFI_MAGIC_64);
62
63 tx_entry->op_flags = myep->tx_op_flags | flags;
64 tx_entry->context = context;
65 return tx_entry;
66 }
67
68 static struct hook_debug_txrx_entry *
hook_debug_get_rx_entry(struct hook_debug_ep * myep,void * context,uint64_t flags)69 hook_debug_get_rx_entry(struct hook_debug_ep *myep, void *context,
70 uint64_t flags)
71 {
72 struct hook_debug_txrx_entry *rx_entry;
73
74 rx_entry = ofi_buf_alloc(myep->rx_pool);
75 assert(rx_entry);
76 assert(rx_entry->magic == OFI_MAGIC_64);
77
78 rx_entry->op_flags = myep->rx_op_flags | flags;
79 rx_entry->context = context;
80 return rx_entry;
81 }
82
hook_debug_trace_exit(struct fid * fid,struct fid * hfid,enum fi_log_subsys subsys,const char * fn,ssize_t ret,size_t * eagain_count)83 static void hook_debug_trace_exit(struct fid *fid, struct fid *hfid,
84 enum fi_log_subsys subsys, const char *fn,
85 ssize_t ret, size_t *eagain_count)
86 {
87 if (!config.trace_exit)
88 return;
89
90 if (ret > 0) {
91 FI_TRACE(hook_to_hprov(fid), subsys, "%s (fid: %p) returned: "
92 "%zd\n", fn, hfid, ret);
93 goto out;
94 }
95
96 if (ret != -FI_EAGAIN || !eagain_count ||
97 !((*eagain_count)++ % HOOK_DEBUG_EAGAIN_LOG))
98 FI_TRACE(hook_to_hprov(fid), subsys, "%s (fid: %p) returned: "
99 "%zd (%s)\n", fn, hfid, ret, fi_strerror(-ret));
100 out:
101 if (eagain_count && ret != -FI_EAGAIN)
102 *eagain_count = 0;
103 }
104
105 static void
hook_debug_trace_exit_eq(struct hook_debug_eq * eq,const char * fn,ssize_t ret)106 hook_debug_trace_exit_eq(struct hook_debug_eq *eq, const char *fn, ssize_t ret)
107 {
108 return hook_debug_trace_exit(&eq->hook_eq.eq.fid, &eq->hook_eq.heq->fid,
109 FI_LOG_EQ, fn, ret, &eq->eagain_count);
110 }
111
112 static void
hook_debug_trace_exit_cq(struct hook_debug_cq * cq,const char * fn,ssize_t ret)113 hook_debug_trace_exit_cq(struct hook_debug_cq *cq, const char *fn, ssize_t ret)
114 {
115 hook_debug_trace_exit(&cq->hook_cq.cq.fid, &cq->hook_cq.hcq->fid,
116 FI_LOG_CQ, fn, ret, &cq->eagain_count);
117 }
118
119 static void
hook_debug_trace_exit_cntr(struct hook_cntr * cntr,const char * fn,ssize_t ret)120 hook_debug_trace_exit_cntr(struct hook_cntr *cntr, const char *fn, ssize_t ret)
121 {
122 hook_debug_trace_exit(&cntr->cntr.fid, &cntr->hcntr->fid,
123 FI_LOG_CNTR, fn, ret, NULL);
124 }
125
126 static void
hook_debug_trace_exit_ep(struct hook_debug_ep * ep,const char * fn,ssize_t ret,size_t * eagain_count)127 hook_debug_trace_exit_ep(struct hook_debug_ep *ep, const char *fn, ssize_t ret,
128 size_t *eagain_count)
129 {
130 hook_debug_trace_exit(&ep->hook_ep.ep.fid, &ep->hook_ep.hep->fid,
131 FI_LOG_EP_DATA, fn, ret, eagain_count);
132 }
133
hook_debug_rx_end(struct hook_debug_ep * ep,char * fn,ssize_t ret,void * mycontext)134 static void hook_debug_rx_end(struct hook_debug_ep *ep, char *fn,
135 ssize_t ret, void *mycontext)
136 {
137 struct hook_debug_txrx_entry *rx_entry;
138
139 hook_debug_trace_exit_ep(ep, fn, ret, &ep->rx_eagain_count);
140
141 if (config.track_recvs) {
142 if (!ret) {
143 ep->rx_outs++;
144 FI_TRACE(hook_to_hprov(&ep->hook_ep.ep.fid),
145 FI_LOG_EP_DATA, "ep: %p rx_outs: %zu\n",
146 ep->hook_ep.hep, ep->rx_outs);
147 } else {
148 rx_entry = mycontext;
149 ofi_buf_free(rx_entry);
150 }
151 }
152 }
153
hook_debug_rx_start(struct hook_debug_ep * ep,void * context,uint64_t flags,void ** mycontext)154 static int hook_debug_rx_start(struct hook_debug_ep *ep, void *context,
155 uint64_t flags, void **mycontext)
156 {
157 struct hook_debug_txrx_entry *rx_entry;
158
159 if (config.track_recvs) {
160 if (flags & ~(FI_MULTI_RECV | FI_COMPLETION)) {
161 FI_TRACE(&hook_debug_prov_ctx.prov, FI_LOG_EP_DATA,
162 "unsupported flags: %s\n",
163 fi_tostr(&flags, FI_TYPE_OP_FLAGS));
164 return -FI_EINVAL;
165 }
166
167 rx_entry = hook_debug_get_rx_entry(ep, context, flags);
168 *mycontext = rx_entry;
169 } else {
170 *mycontext = context;
171 }
172 return 0;
173 }
174
175 static ssize_t
hook_debug_recv(struct fid_ep * ep,void * buf,size_t len,void * desc,fi_addr_t src_addr,void * context)176 hook_debug_recv(struct fid_ep *ep, void *buf, size_t len, void *desc,
177 fi_addr_t src_addr, void *context)
178 {
179 struct hook_debug_ep *myep = container_of(ep, struct hook_debug_ep,
180 hook_ep.ep);
181 void *mycontext;
182 ssize_t ret;
183
184 ret = hook_debug_rx_start(myep, context, 0, &mycontext);
185 if (ret)
186 return ret;
187
188 ret = fi_recv(myep->hook_ep.hep, buf, len, desc, src_addr, mycontext);
189 hook_debug_rx_end(myep, "fi_recv", ret, mycontext);
190 return ret;
191 }
192
193 static ssize_t
hook_debug_recvmsg(struct fid_ep * ep,const struct fi_msg * msg,uint64_t flags)194 hook_debug_recvmsg(struct fid_ep *ep, const struct fi_msg *msg, uint64_t flags)
195 {
196 struct hook_debug_ep *myep = container_of(ep, struct hook_debug_ep, hook_ep.ep);
197 struct fi_msg mymsg = *msg;
198 ssize_t ret;
199
200 ret = hook_debug_rx_start(myep, msg->context, flags, &mymsg.context);
201 if (ret)
202 return ret;
203
204 ret = fi_recvmsg(myep->hook_ep.hep, &mymsg, flags);
205 hook_debug_rx_end(myep, "fi_recvmsg", ret, mymsg.context);
206 return ret;
207 }
208
209 static ssize_t
hook_debug_trecv(struct fid_ep * ep,void * buf,size_t len,void * desc,fi_addr_t src_addr,uint64_t tag,uint64_t ignore,void * context)210 hook_debug_trecv(struct fid_ep *ep, void *buf, size_t len, void *desc,
211 fi_addr_t src_addr, uint64_t tag, uint64_t ignore,
212 void *context)
213 {
214 struct hook_debug_ep *myep = container_of(ep, struct hook_debug_ep, hook_ep.ep);
215 void *mycontext;
216 ssize_t ret;
217
218 ret = hook_debug_rx_start(myep, context, 0, &mycontext);
219 if (ret)
220 return ret;
221
222 ret = fi_trecv(myep->hook_ep.hep, buf, len, desc, src_addr,
223 tag, ignore, mycontext);
224
225 hook_debug_rx_end(myep, "fi_trecv", ret, mycontext);
226 return ret;
227 }
228
hook_debug_tx_end(struct hook_debug_ep * ep,char * fn,ssize_t ret,void * mycontext)229 static void hook_debug_tx_end(struct hook_debug_ep *ep, char *fn,
230 ssize_t ret, void *mycontext)
231 {
232 struct hook_debug_txrx_entry *tx_entry;
233
234 hook_debug_trace_exit_ep(ep, fn, ret, &ep->tx_eagain_count);
235
236 if (mycontext && config.track_sends) {
237 if (!ret) {
238 ep->tx_outs++;
239 FI_TRACE(hook_to_hprov(&ep->hook_ep.ep.fid),
240 FI_LOG_EP_DATA, "ep: %p tx_outs: %zu\n",
241 ep->hook_ep.hep, ep->tx_outs);
242 } else {
243 tx_entry = mycontext;
244 ofi_buf_free(tx_entry);
245 }
246 }
247 }
248
hook_debug_tx_start(struct hook_debug_ep * ep,void * context,uint64_t flags,void ** mycontext)249 static int hook_debug_tx_start(struct hook_debug_ep *ep, void *context,
250 uint64_t flags, void **mycontext)
251 {
252 struct hook_debug_txrx_entry *tx_entry;
253
254 if (mycontext) {
255 if (config.track_sends) {
256 tx_entry = hook_debug_get_tx_entry(ep, context, flags);
257 *mycontext = tx_entry;
258 } else {
259 *mycontext = context;
260 }
261 }
262 return 0;
263 }
264
265 static ssize_t
hook_debug_send(struct fid_ep * ep,const void * buf,size_t len,void * desc,fi_addr_t dest_addr,void * context)266 hook_debug_send(struct fid_ep *ep, const void *buf, size_t len, void *desc,
267 fi_addr_t dest_addr, void *context)
268 {
269 struct hook_debug_ep *myep = container_of(ep, struct hook_debug_ep, hook_ep.ep);
270 void *mycontext;
271 ssize_t ret;
272
273 ret = hook_debug_tx_start(myep, context, 0, &mycontext);
274 if (ret)
275 return ret;
276
277 ret = fi_send(myep->hook_ep.hep, buf, len, desc, dest_addr, mycontext);
278
279 hook_debug_tx_end(myep, "fi_send", ret, mycontext);
280 return ret;
281 }
282
283 static ssize_t
hook_debug_sendv(struct fid_ep * ep,const struct iovec * iov,void ** desc,size_t count,fi_addr_t dest_addr,void * context)284 hook_debug_sendv(struct fid_ep *ep, const struct iovec *iov, void **desc,
285 size_t count, fi_addr_t dest_addr, void *context)
286 {
287 struct hook_debug_ep *myep = container_of(ep, struct hook_debug_ep, hook_ep.ep);
288 void *mycontext;
289 ssize_t ret;
290
291 ret = hook_debug_tx_start(myep, context, 0, &mycontext);
292 if (ret)
293 return ret;
294
295 ret = fi_sendv(myep->hook_ep.hep, iov, desc, count, dest_addr, mycontext);
296
297 hook_debug_tx_end(myep, "fi_sendv", ret, mycontext);
298 return ret;
299 }
300
301 static ssize_t
hook_debug_sendmsg(struct fid_ep * ep,const struct fi_msg * msg,uint64_t flags)302 hook_debug_sendmsg(struct fid_ep *ep, const struct fi_msg *msg, uint64_t flags)
303 {
304 struct hook_debug_ep *myep = container_of(ep, struct hook_debug_ep, hook_ep.ep);
305 struct fi_msg mymsg = *msg;
306 ssize_t ret;
307
308 ret = hook_debug_tx_start(myep, msg->context, flags, &mymsg.context);
309 if (ret)
310 return ret;
311
312 ret = fi_sendmsg(myep->hook_ep.hep, &mymsg, flags);
313 hook_debug_tx_end(myep, "fi_sendmsg", ret, mymsg.context);
314 return ret;
315 }
316
317 static ssize_t
hook_debug_inject(struct fid_ep * ep,const void * buf,size_t len,fi_addr_t dest_addr)318 hook_debug_inject(struct fid_ep *ep, const void *buf, size_t len,
319 fi_addr_t dest_addr)
320 {
321 struct hook_debug_ep *myep = container_of(ep, struct hook_debug_ep, hook_ep.ep);
322 ssize_t ret;
323
324 ret = hook_debug_tx_start(myep, NULL, 0, NULL);
325 if (ret)
326 return ret;
327
328 ret = fi_inject(myep->hook_ep.hep, buf, len, dest_addr);
329
330 hook_debug_tx_end(myep, "fi_inject", ret, NULL);
331 return ret;
332 }
333
334 static ssize_t
hook_debug_senddata(struct fid_ep * ep,const void * buf,size_t len,void * desc,uint64_t data,fi_addr_t dest_addr,void * context)335 hook_debug_senddata(struct fid_ep *ep, const void *buf, size_t len, void *desc,
336 uint64_t data, fi_addr_t dest_addr, void *context)
337 {
338 struct hook_debug_ep *myep = container_of(ep, struct hook_debug_ep, hook_ep.ep);
339 void *mycontext;
340 ssize_t ret;
341
342 ret = hook_debug_tx_start(myep, context, 0, &mycontext);
343 if (ret)
344 return ret;
345
346 ret = fi_senddata(myep->hook_ep.hep, buf, len, desc, data, dest_addr, mycontext);
347 hook_debug_tx_end(myep, "fi_senddata", ret, mycontext);
348 return ret;
349 }
350
351 static ssize_t
hook_debug_injectdata(struct fid_ep * ep,const void * buf,size_t len,uint64_t data,fi_addr_t dest_addr)352 hook_debug_injectdata(struct fid_ep *ep, const void *buf, size_t len,
353 uint64_t data, fi_addr_t dest_addr)
354 {
355 struct hook_debug_ep *myep = container_of(ep, struct hook_debug_ep, hook_ep.ep);
356 ssize_t ret;
357
358 ret = hook_debug_tx_start(myep, NULL, 0, NULL);
359 if (ret)
360 return ret;
361
362 ret = fi_injectdata(myep->hook_ep.hep, buf, len, data, dest_addr);
363
364 hook_debug_tx_end(myep, "fi_injectdata", ret, NULL);
365 return ret;
366 }
367
368 static ssize_t
hook_debug_tsend(struct fid_ep * ep,const void * buf,size_t len,void * desc,fi_addr_t dest_addr,uint64_t tag,void * context)369 hook_debug_tsend(struct fid_ep *ep, const void *buf, size_t len, void *desc,
370 fi_addr_t dest_addr, uint64_t tag, void *context)
371 {
372 struct hook_debug_ep *myep = container_of(ep, struct hook_debug_ep, hook_ep.ep);
373 void *mycontext;
374 ssize_t ret;
375
376 ret = hook_debug_tx_start(myep, context, 0, &mycontext);
377 if (ret)
378 return ret;
379
380 ret = fi_tsend(myep->hook_ep.hep, buf, len, desc, dest_addr, tag, mycontext);
381 hook_debug_tx_end(myep, "fi_tsend", ret, mycontext);
382 return ret;
383 }
384
385 static ssize_t
hook_debug_tsendv(struct fid_ep * ep,const struct iovec * iov,void ** desc,size_t count,fi_addr_t dest_addr,uint64_t tag,void * context)386 hook_debug_tsendv(struct fid_ep *ep, const struct iovec *iov, void **desc,
387 size_t count, fi_addr_t dest_addr, uint64_t tag, void *context)
388 {
389 struct hook_debug_ep *myep = container_of(ep, struct hook_debug_ep, hook_ep.ep);
390 void *mycontext;
391 ssize_t ret;
392
393 ret = hook_debug_tx_start(myep, context, 0, &mycontext);
394 if (ret)
395 return ret;
396
397 ret = fi_tsendv(myep->hook_ep.hep, iov, desc, count,
398 dest_addr, tag, mycontext);
399
400 hook_debug_tx_end(myep, "fi_tsendv", ret, mycontext);
401 return ret;
402 }
403
404 static ssize_t
hook_debug_tsendmsg(struct fid_ep * ep,const struct fi_msg_tagged * msg,uint64_t flags)405 hook_debug_tsendmsg(struct fid_ep *ep, const struct fi_msg_tagged *msg,
406 uint64_t flags)
407 {
408 struct hook_debug_ep *myep = container_of(ep, struct hook_debug_ep, hook_ep.ep);
409 struct fi_msg_tagged mymsg = *msg;
410 ssize_t ret;
411
412 ret = hook_debug_tx_start(myep, msg->context, flags, &mymsg.context);
413 if (ret)
414 return ret;
415
416 ret = fi_tsendmsg(myep->hook_ep.hep, &mymsg, flags);
417 hook_debug_tx_end(myep, "fi_tsendmsg", ret, mymsg.context);
418 return ret;
419 }
420
421 static ssize_t
hook_debug_tinject(struct fid_ep * ep,const void * buf,size_t len,fi_addr_t dest_addr,uint64_t tag)422 hook_debug_tinject(struct fid_ep *ep, const void *buf, size_t len,
423 fi_addr_t dest_addr, uint64_t tag)
424 {
425 struct hook_debug_ep *myep = container_of(ep, struct hook_debug_ep, hook_ep.ep);
426 ssize_t ret;
427
428 ret = hook_debug_tx_start(myep, NULL, 0, NULL);
429 if (ret)
430 return ret;
431
432 ret = fi_tinject(myep->hook_ep.hep, buf, len, dest_addr, tag);
433
434 hook_debug_tx_end(myep, "fi_tinject", ret, NULL);
435 return ret;
436 }
437
438 static ssize_t
hook_debug_tsenddata(struct fid_ep * ep,const void * buf,size_t len,void * desc,uint64_t data,fi_addr_t dest_addr,uint64_t tag,void * context)439 hook_debug_tsenddata(struct fid_ep *ep, const void *buf, size_t len, void *desc,
440 uint64_t data, fi_addr_t dest_addr, uint64_t tag,
441 void *context)
442 {
443 struct hook_debug_ep *myep = container_of(ep, struct hook_debug_ep, hook_ep.ep);
444 void *mycontext;
445 ssize_t ret;
446
447 ret = hook_debug_tx_start(myep, context, 0, &mycontext);
448 if (ret)
449 return ret;
450
451 ret = fi_tsenddata(myep->hook_ep.hep, buf, len, desc, data,
452 dest_addr, tag, mycontext);
453 hook_debug_tx_end(myep, "fi_tsenddata", ret, mycontext);
454 return ret;
455 }
456
457 static ssize_t
hook_debug_tinjectdata(struct fid_ep * ep,const void * buf,size_t len,uint64_t data,fi_addr_t dest_addr,uint64_t tag)458 hook_debug_tinjectdata(struct fid_ep *ep, const void *buf, size_t len,
459 uint64_t data, fi_addr_t dest_addr, uint64_t tag)
460 {
461 struct hook_debug_ep *myep = container_of(ep, struct hook_debug_ep, hook_ep.ep);
462 ssize_t ret;
463
464 ret = hook_debug_tx_start(myep, NULL, 0, NULL);
465 if (ret)
466 return ret;
467
468 ret = fi_tinjectdata(myep->hook_ep.hep, buf, len, data, dest_addr, tag);
469
470 hook_debug_tx_end(myep, "fi_tinjectdata", ret, NULL);
471 return ret;
472 }
473
474 #define HOOK_DEBUG_TRACE(fabric, subsys, ...) \
475 FI_TRACE(hook_fabric_to_hprov(fabric), subsys, __VA_ARGS__)
476
477 #define HOOK_DEBUG_CQ_TRACE(cq, ...) \
478 HOOK_DEBUG_TRACE(cq->hook_cq.domain->fabric, FI_LOG_CQ, __VA_ARGS__)
479
hook_debug_cq_entry_log(struct hook_debug_cq * cq,struct fi_cq_tagged_entry * entry)480 static void hook_debug_cq_entry_log(struct hook_debug_cq *cq,
481 struct fi_cq_tagged_entry *entry)
482 {
483 if (!config.trace_cq_entry)
484 return;
485
486 HOOK_DEBUG_CQ_TRACE(cq, "cq_entry:\n");
487 HOOK_DEBUG_CQ_TRACE(cq, "\top_context: %p\n", entry->op_context);
488
489 if (cq->format > FI_CQ_FORMAT_CONTEXT) {
490 HOOK_DEBUG_CQ_TRACE(cq, "\tflags: %s\n",
491 fi_tostr(&entry->flags, FI_TYPE_CAPS));
492
493 if (entry->flags & FI_RECV)
494 HOOK_DEBUG_CQ_TRACE(cq, "\tlen: %zu\n", entry->len);
495
496 if (cq->format == FI_CQ_FORMAT_TAGGED)
497 HOOK_DEBUG_CQ_TRACE(cq, "\ttag: %" PRIx64 "\n", entry->tag);
498 }
499 }
500
hook_debug_cq_process_entry(struct hook_debug_cq * mycq,const char * fn,ssize_t ret,char * buf)501 static void hook_debug_cq_process_entry(struct hook_debug_cq *mycq,
502 const char *fn, ssize_t ret, char *buf)
503 {
504 struct hook_debug_txrx_entry *rx_entry, *tx_entry;
505 struct fi_cq_tagged_entry *cq_entry;
506 int i;
507
508 hook_debug_trace_exit_cq(mycq, fn, ret);
509
510 for (i = 0; i < ret; i++, buf += mycq->entry_size) {
511 cq_entry = (struct fi_cq_tagged_entry *)buf;
512 hook_debug_cq_entry_log(mycq, cq_entry);
513
514 if (config.track_recvs && (cq_entry->flags & FI_RECV)) {
515 rx_entry = cq_entry->op_context;
516 assert(rx_entry->magic == OFI_MAGIC_64);
517
518 cq_entry->op_context = rx_entry->context;
519
520 if (!(rx_entry->op_flags & FI_MULTI_RECV) ||
521 cq_entry->flags & FI_MULTI_RECV) {
522 rx_entry->ep->rx_outs--;
523 FI_TRACE(hook_to_hprov(&mycq->hook_cq.cq.fid),
524 FI_LOG_CQ, "ep: %p rx_outs: %zu\n",
525 rx_entry->ep->hook_ep.hep,
526 rx_entry->ep->rx_outs);
527 ofi_buf_free(rx_entry);
528 }
529 } else if (config.track_sends && (cq_entry->flags & FI_SEND)) {
530 tx_entry = cq_entry->op_context;
531 assert(tx_entry->magic == OFI_MAGIC_64);
532
533 cq_entry->op_context = tx_entry->context;
534
535 tx_entry->ep->tx_outs--;
536 FI_TRACE(hook_to_hprov(&mycq->hook_cq.cq.fid),
537 FI_LOG_CQ, "ep: %p tx_outs: %zu\n",
538 tx_entry->ep->hook_ep.hep,
539 tx_entry->ep->tx_outs);
540 ofi_buf_free(tx_entry);
541 }
542 }
543 }
544
hook_debug_cq_read(struct fid_cq * cq,void * buf,size_t count)545 static ssize_t hook_debug_cq_read(struct fid_cq *cq, void *buf, size_t count)
546 {
547 struct hook_debug_cq *mycq = container_of(cq, struct hook_debug_cq,
548 hook_cq.cq);
549 ssize_t ret;
550
551 ret = fi_cq_read(mycq->hook_cq.hcq, buf, count);
552 hook_debug_cq_process_entry(mycq, "fi_cq_read", ret, buf);
553 return ret;
554 }
555
hook_debug_cq_readfrom(struct fid_cq * cq,void * buf,size_t count,fi_addr_t * src_addr)556 static ssize_t hook_debug_cq_readfrom(struct fid_cq *cq, void *buf, size_t count,
557 fi_addr_t *src_addr)
558 {
559 struct hook_debug_cq *mycq = container_of(cq, struct hook_debug_cq,
560 hook_cq.cq);
561 ssize_t ret;
562
563 ret = fi_cq_readfrom(mycq->hook_cq.hcq, buf, count, src_addr);
564 hook_debug_cq_process_entry(mycq, "fi_cq_readfrom", ret, buf);
565 return ret;
566 }
567
hook_debug_cq_close(struct fid * fid)568 int hook_debug_cq_close(struct fid *fid)
569 {
570 struct hook_debug_cq *mycq =
571 container_of(fid, struct hook_debug_cq, hook_cq.cq.fid);
572 int ret = 0;
573
574 if (mycq->hook_cq.hcq)
575 ret = fi_close(&mycq->hook_cq.hcq->fid);
576 if (!ret)
577 free(mycq);
578 return ret;
579 }
580
581 // TODO move to common code
582 static size_t cq_entry_size[] = {
583 [FI_CQ_FORMAT_UNSPEC] = 0,
584 [FI_CQ_FORMAT_CONTEXT] = sizeof(struct fi_cq_entry),
585 [FI_CQ_FORMAT_MSG] = sizeof(struct fi_cq_msg_entry),
586 [FI_CQ_FORMAT_DATA] = sizeof(struct fi_cq_data_entry),
587 [FI_CQ_FORMAT_TAGGED] = sizeof(struct fi_cq_tagged_entry)
588 };
589
590 struct fi_ops hook_debug_cq_fid_ops;
591 struct fi_ops_cq hook_debug_cq_ops;
592
hook_debug_cq_attr_log(struct hook_domain * dom,struct fi_cq_attr * attr)593 static void hook_debug_cq_attr_log(struct hook_domain *dom,
594 struct fi_cq_attr *attr)
595 {
596 HOOK_DEBUG_TRACE(dom->fabric, FI_LOG_CQ, "fi_cq_attr:\n");
597 HOOK_DEBUG_TRACE(dom->fabric, FI_LOG_CQ, "\tsize: %zu\n", attr->size);
598 HOOK_DEBUG_TRACE(dom->fabric, FI_LOG_CQ, "\tflags: %s\n", "TBD");
599 HOOK_DEBUG_TRACE(dom->fabric, FI_LOG_CQ, "\tformat: %s\n", "TBD");
600 HOOK_DEBUG_TRACE(dom->fabric, FI_LOG_CQ, "\twait_obj: %s\n", "TBD");
601 HOOK_DEBUG_TRACE(dom->fabric, FI_LOG_CQ, "\tsignaling_vector: %d\n",
602 attr->signaling_vector);
603 HOOK_DEBUG_TRACE(dom->fabric, FI_LOG_CQ, "\twait_cond: %s\n", "TBD");
604 HOOK_DEBUG_TRACE(dom->fabric, FI_LOG_CQ, "\twait_set: %p\n", attr->wait_set);
605 }
606
hook_debug_cq_open(struct fid_domain * domain_fid,struct fi_cq_attr * attr,struct fid_cq ** cq,void * context)607 int hook_debug_cq_open(struct fid_domain *domain_fid, struct fi_cq_attr *attr,
608 struct fid_cq **cq, void *context)
609 {
610 struct hook_domain *domain = container_of(domain_fid, struct hook_domain,
611 domain);
612 struct hook_debug_cq *mycq;
613 int ret;
614
615 assert(!attr->flags);
616
617 hook_debug_cq_attr_log(domain, attr);
618
619 if ((config.track_sends || config.track_recvs) &&
620 (attr->format < FI_CQ_FORMAT_MSG)) {
621 FI_WARN(&hook_debug_prov_ctx.prov, FI_LOG_CQ,
622 "need FI_CQ_FORMAT_MSG or higher for tracking sends "
623 "and(or) recvs\n");
624 return -FI_EINVAL;
625 }
626
627 mycq = calloc(1, sizeof *mycq);
628 if (!mycq)
629 return -FI_EAGAIN;
630
631 ret = hook_cq_init(domain_fid, attr, cq, context, &mycq->hook_cq);
632 if (ret)
633 goto err;
634
635 FI_TRACE(hook_fabric_to_hprov(mycq->hook_cq.domain->fabric), FI_LOG_CQ,
636 "cq opened, fid: %p\n", &mycq->hook_cq.hcq->fid);
637
638 mycq->hook_cq.cq.fid.ops = &hook_debug_cq_fid_ops;
639 mycq->hook_cq.cq.ops = &hook_debug_cq_ops;
640 mycq->format = attr->format;
641 mycq->entry_size = cq_entry_size[attr->format];
642
643 assert(mycq->entry_size);
644
645 return 0;
646 err:
647 hook_debug_cq_close(&mycq->hook_cq.cq.fid);
648 return ret;
649 }
650
hook_debug_ep_close(struct fid * fid)651 static int hook_debug_ep_close(struct fid *fid)
652 {
653 struct hook_debug_ep *myep =
654 container_of(fid, struct hook_debug_ep, hook_ep.ep.fid);
655 int ret = 0;
656
657 if (myep->tx_pool)
658 ofi_bufpool_destroy(myep->tx_pool);
659
660 if (myep->rx_pool)
661 ofi_bufpool_destroy(myep->rx_pool);
662
663 if (myep->hook_ep.hep)
664 ret = fi_close(&myep->hook_ep.hep->fid);
665 if (!ret)
666 free(myep);
667 return ret;
668 }
669
hook_debug_ep_bind(struct fid * fid,struct fid * bfid,uint64_t flags)670 int hook_debug_ep_bind(struct fid *fid, struct fid *bfid, uint64_t flags)
671 {
672 struct fid *hfid, *hbfid;
673 struct hook_cntr *cntr;
674 struct hook_cq *cq;
675
676 hfid = hook_to_hfid(fid);
677 hbfid = hook_to_hfid(bfid);
678 if (!hfid || !hbfid)
679 return -FI_EINVAL;
680
681 switch (bfid->fclass) {
682 case FI_CLASS_CQ:
683 cq = container_of(bfid, struct hook_cq, cq.fid);
684 HOOK_DEBUG_TRACE(cq->domain->fabric, FI_LOG_EP_CTRL,
685 "cq: %p bind flags: %s\n", cq->hcq,
686 fi_tostr(&flags, FI_TYPE_CAPS));
687 break;
688 case FI_CLASS_CNTR:
689 cntr = container_of(bfid, struct hook_cntr, cntr.fid);
690 HOOK_DEBUG_TRACE(cntr->domain->fabric, FI_LOG_EP_CTRL,
691 "cntr: %p bind flags: %s\n", cntr->hcntr,
692 fi_tostr(&flags, FI_TYPE_CAPS));
693 break;
694 }
695 return hfid->ops->bind(hfid, hbfid, flags);
696 }
697
hook_debug_txrx_entry_init(struct ofi_bufpool_region * region,void * buf)698 static void hook_debug_txrx_entry_init(struct ofi_bufpool_region *region,
699 void *buf)
700 {
701 struct hook_debug_txrx_entry *entry = buf;
702 entry->magic = OFI_MAGIC_64;
703 entry->ep = region->pool->attr.context;
704 }
705
706 struct fi_ops hook_debug_ep_fid_ops;
707 static struct fi_ops_msg hook_debug_msg_ops = {
708 .size = sizeof(struct fi_ops_msg),
709 .recv = hook_debug_recv,
710 .recvv = fi_no_msg_recvv,
711 .recvmsg = hook_debug_recvmsg,
712 .send = hook_debug_send,
713 .senddata = hook_debug_senddata,
714 .sendv = hook_debug_sendv,
715 .sendmsg = hook_debug_sendmsg,
716 .inject = hook_debug_inject,
717 .injectdata = hook_debug_injectdata,
718 };
719
720 struct fi_ops_tagged hook_debug_tagged_ops = {
721 .recv = hook_debug_trecv,
722 .recvv = fi_no_tagged_recvv,
723 .recvmsg = fi_no_tagged_recvmsg,
724 .send = hook_debug_tsend,
725 .senddata = hook_debug_tsenddata,
726 .sendv = hook_debug_tsendv,
727 .sendmsg = hook_debug_tsendmsg,
728 .inject = hook_debug_tinject,
729 .injectdata = hook_debug_tinjectdata,
730 };
731
hook_debug_endpoint(struct fid_domain * domain,struct fi_info * info,struct fid_ep ** ep,void * context)732 int hook_debug_endpoint(struct fid_domain *domain, struct fi_info *info,
733 struct fid_ep **ep, void *context)
734 {
735 struct hook_debug_ep *myep;
736 struct ofi_bufpool_attr bufpool_attr = {
737 .size = sizeof(struct hook_debug_txrx_entry),
738 .alignment = 16,
739 .max_cnt = 0,
740 .init_fn = hook_debug_txrx_entry_init,
741 };
742
743 int ret = -FI_ENOMEM;
744
745 if (info->domain_attr->threading != FI_THREAD_DOMAIN) {
746 FI_WARN(&hook_debug_prov_ctx.prov, FI_LOG_CQ,
747 "debug hooking provider doesn't support thread safety"
748 "at this time\n");
749 return -FI_EINVAL;
750 }
751
752 FI_TRACE(hook_to_hprov(&domain->fid), FI_LOG_EP_CTRL,
753 "tx_attr->size: %zu\n", info->tx_attr->size);
754 FI_TRACE(hook_to_hprov(&domain->fid), FI_LOG_EP_CTRL,
755 "rx_attr->size: %zu\n", info->rx_attr->size);
756
757 myep = calloc(1, sizeof *myep);
758 if (!myep)
759 return ret;
760
761 bufpool_attr.context = myep;
762
763 if (config.track_sends) {
764 bufpool_attr.chunk_cnt = info->tx_attr->size;
765 ret = ofi_bufpool_create_attr(&bufpool_attr, &myep->tx_pool);
766 if (ret)
767 goto err;
768 }
769
770 if (config.track_recvs) {
771 bufpool_attr.chunk_cnt = info->rx_attr->size;
772 ret = ofi_bufpool_create_attr(&bufpool_attr, &myep->rx_pool);
773 if (ret)
774 goto err;
775 }
776
777 ret = hook_endpoint_init(domain, info, ep, context, &myep->hook_ep);
778 if (ret)
779 goto err;
780
781 FI_TRACE(hook_to_hprov(&myep->hook_ep.ep.fid), FI_LOG_EP_CTRL,
782 "endpoint opened, fid: %p\n", &myep->hook_ep.hep->fid);
783
784 myep->hook_ep.ep.fid.ops = &hook_debug_ep_fid_ops;
785 myep->hook_ep.ep.msg = &hook_debug_msg_ops;
786 myep->hook_ep.ep.tagged = &hook_debug_tagged_ops;
787 myep->tx_op_flags = info->tx_attr->op_flags;
788 myep->rx_op_flags = info->rx_attr->op_flags;
789
790 return 0;
791 err:
792 hook_debug_ep_close(&myep->hook_ep.ep.fid);
793 return ret;
794 }
795
796 /*
797 * EQ
798 */
799
hook_debug_eq_read(struct fid_eq * eq,uint32_t * event,void * buf,size_t len,uint64_t flags)800 static ssize_t hook_debug_eq_read(struct fid_eq *eq, uint32_t *event,
801 void *buf, size_t len, uint64_t flags)
802 {
803 struct hook_debug_eq *myeq = container_of(eq, struct hook_debug_eq,
804 hook_eq.eq);
805 ssize_t ret;
806
807 ret = hook_eq_read(eq, event, buf, len, flags);
808 if (ret > 0)
809 ofi_atomic_inc64(&myeq->event_cntr[*event]);
810
811 hook_debug_trace_exit_eq(myeq, "fi_eq_read", (ssize_t)ret);
812 return ret;
813 }
814
hook_debug_eq_sread(struct fid_eq * eq,uint32_t * event,void * buf,size_t len,int timeout,uint64_t flags)815 static ssize_t hook_debug_eq_sread(struct fid_eq *eq, uint32_t *event,
816 void *buf, size_t len, int timeout,
817 uint64_t flags)
818 {
819 struct hook_debug_eq *myeq = container_of(eq, struct hook_debug_eq,
820 hook_eq.eq);
821 ssize_t ret;
822
823 ret = hook_eq_sread(eq, event, buf, len, timeout, flags);
824 if (ret > 0)
825 ofi_atomic_inc64(&myeq->event_cntr[*event]);
826
827 hook_debug_trace_exit_eq(myeq, "fi_eq_sread", (ssize_t)ret);
828 return ret;
829 }
830
hook_debug_eq_close(struct fid * fid)831 static int hook_debug_eq_close(struct fid *fid)
832 {
833 struct hook_debug_eq *myeq = container_of(fid, struct hook_debug_eq,
834 hook_eq.eq.fid);
835 int i, ret;
836
837 HOOK_DEBUG_TRACE(myeq->hook_eq.fabric, FI_LOG_EQ, "EQ events:\n");
838
839 for (i = 0; i < HOOK_DEBUG_EQ_EVENT_MAX; i++)
840 HOOK_DEBUG_TRACE(myeq->hook_eq.fabric, FI_LOG_EQ,
841 "%-20s: %" PRIu64 "\n",
842 fi_tostr(&i, FI_TYPE_EQ_EVENT),
843 ofi_atomic_get64(&myeq->event_cntr[i]));
844
845 ret = fi_close(&myeq->hook_eq.heq->fid);
846 if (!ret)
847 free(myeq);
848
849 return ret;
850 }
851
852 static struct fi_ops_eq hook_debug_eq_ops;
853 static struct fi_ops hook_debug_eq_fid_ops;
854
hook_debug_eq_open(struct fid_fabric * fabric,struct fi_eq_attr * attr,struct fid_eq ** eq,void * context)855 int hook_debug_eq_open(struct fid_fabric *fabric, struct fi_eq_attr *attr,
856 struct fid_eq **eq, void *context)
857 {
858 struct hook_debug_eq *myeq;
859 int i, ret;
860
861 myeq = calloc(1, sizeof *myeq);
862 if (!myeq)
863 return -FI_ENOMEM;
864
865 ret = hook_eq_init(fabric, attr, eq, context, &myeq->hook_eq);
866 if (ret)
867 free(myeq);
868
869 myeq->hook_eq.eq.ops = &hook_debug_eq_ops;
870 myeq->hook_eq.eq.fid.ops = &hook_debug_eq_fid_ops;
871
872 for (i = 0; i < HOOK_DEBUG_EQ_EVENT_MAX; i++)
873 ofi_atomic_initialize64(&myeq->event_cntr[i], 0);
874
875 return 0;
876 }
877
878 /*
879 * Fabric
880 */
881
882 struct fi_ops hook_debug_fabric_fid_ops;
883 static struct fi_ops_fabric hook_debug_fabric_ops;
884
hook_debug_fabric(struct fi_fabric_attr * attr,struct fid_fabric ** fabric,void * context)885 static int hook_debug_fabric(struct fi_fabric_attr *attr,
886 struct fid_fabric **fabric, void *context)
887 {
888 struct fi_provider *hprov = context;
889 struct hook_fabric *fab;
890
891 FI_TRACE(hprov, FI_LOG_FABRIC, "Installing debug hook\n");
892 fab = calloc(1, sizeof *fab);
893 if (!fab)
894 return -FI_ENOMEM;
895
896 hook_fabric_init(fab, HOOK_DEBUG, attr->fabric, hprov,
897 &hook_debug_fabric_fid_ops, &hook_debug_prov_ctx);
898 *fabric = &fab->fabric;
899 fab->fabric.ops = &hook_debug_fabric_ops;
900 return 0;
901 }
902
903 struct hook_prov_ctx hook_debug_prov_ctx = {
904 .prov = {
905 .version = OFI_VERSION_DEF_PROV,
906 /* We're a pass-through provider, so the fi_version is always the latest */
907 .fi_version = OFI_VERSION_LATEST,
908 .name = "ofi_hook_debug",
909 .getinfo = NULL,
910 .fabric = hook_debug_fabric,
911 .cleanup = NULL,
912 },
913 };
914
hook_debug_cntr_read(struct fid_cntr * cntr)915 static uint64_t hook_debug_cntr_read(struct fid_cntr *cntr)
916 {
917 struct hook_cntr *mycntr = container_of(cntr, struct hook_cntr, cntr);
918 uint64_t ret;
919
920 ret = fi_cntr_read(mycntr->hcntr);
921 hook_debug_trace_exit_cntr(mycntr, "fi_cntr_read", (ssize_t)ret);
922 return ret;
923 }
924
925
hook_debug_cntr_wait(struct fid_cntr * cntr,uint64_t threshold,int timeout)926 static int hook_debug_cntr_wait(struct fid_cntr *cntr, uint64_t threshold, int timeout)
927 {
928 struct hook_cntr *mycntr = container_of(cntr, struct hook_cntr, cntr);
929 int ret;
930
931 HOOK_DEBUG_TRACE(mycntr->domain->fabric, FI_LOG_CNTR,
932 "cntr: %p, threshold: %" PRIu64 ", timeout: %d\n",
933 mycntr->hcntr, threshold, timeout);
934
935 ret = fi_cntr_wait(mycntr->hcntr, threshold, timeout);
936
937 hook_debug_trace_exit_cntr(mycntr, "fi_cntr_wait", (ssize_t)ret);
938 return ret;
939 }
940
941 static struct fi_ops_cntr hook_debug_cntr_ops;
942
hook_debug_cntr_init(struct fid * fid)943 int hook_debug_cntr_init(struct fid *fid)
944 {
945 struct hook_cntr *mycntr = container_of(fid, struct hook_cntr, cntr.fid);
946 HOOK_DEBUG_TRACE(mycntr->domain->fabric, FI_LOG_CNTR,
947 "fi_cntr_open: %p\n", mycntr->hcntr);
948 mycntr->cntr.ops = &hook_debug_cntr_ops;
949 return 0;
950 }
951
952 static struct fi_ops_domain hook_debug_domain_ops;
953
hook_debug_domain_init(struct fid * fid)954 int hook_debug_domain_init(struct fid *fid)
955 {
956 struct fid_domain *domain = container_of(fid, struct fid_domain, fid);
957 domain->ops = &hook_debug_domain_ops;
958 return 0;
959 }
960
961 HOOK_DEBUG_INI
962 {
963 // TODO explore adding a common hook_ini function that can initialize
964 // the ops to common ones. Then override here.
965 hook_debug_fabric_fid_ops = hook_fid_ops;
966 hook_debug_fabric_ops = hook_fabric_ops;
967 hook_debug_fabric_ops.eq_open = hook_debug_eq_open;
968
969 hook_debug_eq_fid_ops = hook_fid_ops;
970 hook_debug_eq_fid_ops.close = hook_debug_eq_close;
971 hook_debug_eq_ops = hook_eq_ops;
972 hook_debug_eq_ops.read = hook_debug_eq_read;
973 hook_debug_eq_ops.sread = hook_debug_eq_sread;
974
975 hook_debug_domain_ops = hook_domain_ops;
976 hook_debug_domain_ops.cq_open = hook_debug_cq_open;
977 hook_debug_domain_ops.endpoint = hook_debug_endpoint;
978
979 hook_debug_cq_fid_ops = hook_fid_ops;
980 hook_debug_cq_fid_ops.close = hook_debug_cq_close;
981
982 hook_debug_cq_ops = hook_cq_ops;
983 hook_debug_cq_ops.read = hook_debug_cq_read;
984 hook_debug_cq_ops.readfrom = hook_debug_cq_readfrom;
985 hook_debug_cq_ops.sread = fi_no_cq_sread;
986 hook_debug_cq_ops.sreadfrom = fi_no_cq_sreadfrom;
987
988 hook_debug_cntr_ops = hook_cntr_ops;
989 hook_debug_cntr_ops.read = hook_debug_cntr_read;
990 hook_debug_cntr_ops.add = fi_no_cntr_add;
991 hook_debug_cntr_ops.set = fi_no_cntr_set;
992 hook_debug_cntr_ops.wait = hook_debug_cntr_wait;
993
994 hook_debug_ep_fid_ops = hook_fid_ops;
995 hook_debug_ep_fid_ops.bind = hook_debug_ep_bind;
996 hook_debug_ep_fid_ops.close = hook_debug_ep_close;
997
998 hook_debug_prov_ctx.ini_fid[FI_CLASS_DOMAIN] = hook_debug_domain_init;
999 hook_debug_prov_ctx.ini_fid[FI_CLASS_CNTR] = hook_debug_cntr_init;
1000 return &hook_debug_prov_ctx.prov;
1001 }
1002