Skip to content

Commit 0131356

Browse files
committed
Perftest: Add device memory with DMA-BUF export support
Introduce a new memory backend using ibv_alloc_dm() and ibv_dm_export_dmabuf_fd() to allocate and export device memory as DMA-BUF file descriptors for RDMA testing. Usage: --use_ib_dm_dmabuf=<ib_device> Also guard dmabuf registration prints behind verbosity level so --output=bandwidth produces clean output for all backends. Not supported with write latency tests. Signed-off-by: Shmuel Shaul <sshaul@nvidia.com>
1 parent 6a66a60 commit 0131356

File tree

9 files changed

+280
-13
lines changed

9 files changed

+280
-13
lines changed

Makefile.am

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ AUTOMAKE_OPTIONS= subdir-objects
3535

3636
noinst_LIBRARIES = libperftest.a
3737
libperftest_a_SOURCES = src/get_clock.c src/perftest_communication.c src/perftest_parameters.c src/perftest_resources.c src/perftest_counters.c src/host_memory.c src/mmap_memory.c
38-
noinst_HEADERS = src/get_clock.h src/perftest_communication.h src/perftest_parameters.h src/perftest_resources.h src/perftest_counters.h src/memory.h src/host_memory.h src/mmap_memory.h src/cuda_memory.h src/rocm_memory.h src/neuron_memory.h src/hl_memory.h src/mlu_memory.h
38+
noinst_HEADERS = src/get_clock.h src/perftest_communication.h src/perftest_parameters.h src/perftest_resources.h src/perftest_counters.h src/memory.h src/host_memory.h src/mmap_memory.h src/cuda_memory.h src/rocm_memory.h src/neuron_memory.h src/hl_memory.h src/mlu_memory.h src/dm_memory.h
3939

4040
if CUDA
4141
libperftest_a_SOURCES += src/cuda_memory.c src/cuda_loader.h src/cuda_loader.c
@@ -61,6 +61,10 @@ if OPENCL
6161
libperftest_a_SOURCES += src/opencl_memory.c
6262
endif
6363

64+
if IB_DM_DMABUF
65+
libperftest_a_SOURCES += src/dm_memory.c
66+
endif
67+
6468
bin_PROGRAMS = ib_send_bw ib_send_lat ib_write_lat ib_write_bw ib_read_lat ib_read_bw ib_atomic_lat ib_atomic_bw
6569
bin_SCRIPTS = run_perftest_loopback run_perftest_multi_devices
6670

configure.ac

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ if test $HAVE_REG_DMABUF_MR = yes; then
7777
AC_DEFINE([HAVE_REG_DMABUF_MR], [1], [Enable HAVE_REG_DMABUF_MR])
7878
fi
7979

80+
AC_CHECK_LIB([ibverbs], [ibv_dm_export_dmabuf_fd], [HAVE_IB_DM_DMABUF=yes], [HAVE_IB_DM_DMABUF=no])
81+
AM_CONDITIONAL([IB_DM_DMABUF], [test "x$HAVE_IB_DM_DMABUF" = "xyes"])
82+
if test "x$HAVE_IB_DM_DMABUF" = "xyes"; then
83+
AC_DEFINE([HAVE_IB_DM_DMABUF], [1], [Enable IB DM DMABUF export])
84+
fi
85+
8086
AC_TRY_LINK([#include <infiniband/verbs.h>],
8187
[struct ibv_flow *t = ibv_create_flow(NULL,NULL);],[HAVE_RAW_ETH_REG=yes], [HAVE_RAW_ETH_REG=no])
8288

man/perftest.1

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,13 @@ many different options and modes.
402402
Use MLU DMA-BUF for HW accelerator direct RDMA testing.
403403
System support required.
404404
.TP
405+
.B --use_ib_dm_dmabuf=<ib_device>
406+
Use IB device memory (allocated via ibv_alloc_dm) with DMA-BUF export
407+
(via ibv_dm_export_dmabuf_fd) for RDMA testing. The <ib_device> argument
408+
specifies the IB device name (e.g. mlx5_0). The requested message size
409+
must fit within the device's max_dm_size.
410+
System support required (rdma-core with ibv_dm_export_dmabuf_fd).
411+
.TP
405412
.B --use_opencl=<opencl device id>
406413
Use OpenCl specific device for GPUDirect RDMA testing
407414
Not relevant for raw_ethernet_fs_rate.

src/dm_memory.c

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include <errno.h>
5+
#include <unistd.h>
6+
#include <infiniband/verbs.h>
7+
#include "dm_memory.h"
8+
#include "perftest_parameters.h"
9+
10+
struct dm_memory_ctx {
11+
struct memory_ctx base;
12+
char *ib_devname;
13+
struct ibv_context *ib_ctx;
14+
struct ibv_dm *dm;
15+
uint64_t dm_size;
16+
bool use_dmabuf;
17+
enum verbosity_level output;
18+
};
19+
20+
static int dm_memory_init(struct memory_ctx *ctx)
21+
{
22+
struct dm_memory_ctx *dm_ctx = container_of(ctx, struct dm_memory_ctx, base);
23+
struct ibv_device **dev_list;
24+
struct ibv_device *ib_dev = NULL;
25+
int num_devices;
26+
int i;
27+
28+
dev_list = ibv_get_device_list(&num_devices);
29+
if (!dev_list) {
30+
fprintf(stderr, "Failed to get IB devices list\n");
31+
return FAILURE;
32+
}
33+
34+
for (i = 0; i < num_devices; i++) {
35+
if (!strcmp(ibv_get_device_name(dev_list[i]), dm_ctx->ib_devname)) {
36+
ib_dev = dev_list[i];
37+
break;
38+
}
39+
}
40+
41+
if (!ib_dev) {
42+
fprintf(stderr, "IB device %s not found\n", dm_ctx->ib_devname);
43+
ibv_free_device_list(dev_list);
44+
return FAILURE;
45+
}
46+
47+
dm_ctx->ib_ctx = ibv_open_device(ib_dev);
48+
ibv_free_device_list(dev_list);
49+
50+
if (!dm_ctx->ib_ctx) {
51+
fprintf(stderr, "Couldn't open IB device %s\n", dm_ctx->ib_devname);
52+
return FAILURE;
53+
}
54+
55+
if (dm_ctx->output == FULL_VERBOSITY)
56+
printf("Opened IB device %s for device memory\n", dm_ctx->ib_devname);
57+
return SUCCESS;
58+
}
59+
60+
static int dm_memory_destroy(struct memory_ctx *ctx)
61+
{
62+
struct dm_memory_ctx *dm_ctx = container_of(ctx, struct dm_memory_ctx, base);
63+
64+
if (dm_ctx->ib_ctx)
65+
ibv_close_device(dm_ctx->ib_ctx);
66+
67+
free(dm_ctx);
68+
return SUCCESS;
69+
}
70+
71+
static int dm_memory_allocate_buffer(struct memory_ctx *ctx, int alignment,
72+
uint64_t size, int *dmabuf_fd,
73+
uint64_t *dmabuf_offset, void **addr,
74+
bool *can_init)
75+
{
76+
struct dm_memory_ctx *dm_ctx = container_of(ctx, struct dm_memory_ctx, base);
77+
struct ibv_alloc_dm_attr dm_attr = {};
78+
struct ibv_device_attr_ex dev_attr = {};
79+
int ret;
80+
81+
ret = ibv_query_device_ex(dm_ctx->ib_ctx, NULL, &dev_attr);
82+
if (ret) {
83+
fprintf(stderr, "Failed to query device attributes: %d\n", ret);
84+
return FAILURE;
85+
}
86+
87+
if (size > dev_attr.max_dm_size) {
88+
fprintf(stderr, "Requested DM size %lu exceeds device max %lu\n",
89+
(unsigned long)size, (unsigned long)dev_attr.max_dm_size);
90+
return FAILURE;
91+
}
92+
93+
dm_attr.length = size;
94+
95+
dm_ctx->dm = ibv_alloc_dm(dm_ctx->ib_ctx, &dm_attr);
96+
if (!dm_ctx->dm) {
97+
fprintf(stderr, "Failed to allocate device memory of size %lu: %s\n",
98+
(unsigned long)size, strerror(errno));
99+
return FAILURE;
100+
}
101+
102+
dm_ctx->dm_size = size;
103+
*addr = NULL;
104+
*can_init = false;
105+
106+
if (dm_ctx->output == FULL_VERBOSITY)
107+
printf("Allocated %lu bytes of device memory\n", (unsigned long)size);
108+
109+
if (dm_ctx->use_dmabuf) {
110+
int fd = ibv_dm_export_dmabuf_fd(dm_ctx->dm);
111+
if (fd < 0) {
112+
fprintf(stderr, "Failed to export DM as dmabuf fd: %s\n",
113+
strerror(errno));
114+
ibv_free_dm(dm_ctx->dm);
115+
dm_ctx->dm = NULL;
116+
return FAILURE;
117+
}
118+
119+
*dmabuf_fd = fd;
120+
*dmabuf_offset = 0;
121+
if (dm_ctx->output == FULL_VERBOSITY)
122+
printf("Exported DM as dmabuf fd %d\n", fd);
123+
}
124+
125+
return SUCCESS;
126+
}
127+
128+
static int dm_memory_free_buffer(struct memory_ctx *ctx, int dmabuf_fd,
129+
void *addr, uint64_t size)
130+
{
131+
struct dm_memory_ctx *dm_ctx = container_of(ctx, struct dm_memory_ctx, base);
132+
133+
if (dm_ctx->dm) {
134+
ibv_free_dm(dm_ctx->dm);
135+
dm_ctx->dm = NULL;
136+
}
137+
138+
return SUCCESS;
139+
}
140+
141+
static void *dm_memory_copy_host_to_buffer(void *dest, const void *src, size_t size)
142+
{
143+
/*
144+
* DM buffers don't have a direct host address. The actual data path
145+
* goes through RDMA operations, so host-side copy is a no-op.
146+
*/
147+
return dest;
148+
}
149+
150+
static void *dm_memory_copy_buffer_to_host(void *dest, const void *src, size_t size)
151+
{
152+
return dest;
153+
}
154+
155+
static void *dm_memory_copy_buffer_to_buffer(void *dest, const void *src, size_t size)
156+
{
157+
return dest;
158+
}
159+
160+
bool dm_memory_dmabuf_supported()
161+
{
162+
return true;
163+
}
164+
165+
struct memory_ctx *dm_memory_create(struct perftest_parameters *params)
166+
{
167+
struct dm_memory_ctx *ctx;
168+
169+
ALLOCATE(ctx, struct dm_memory_ctx, 1);
170+
ctx->base.init = dm_memory_init;
171+
ctx->base.destroy = dm_memory_destroy;
172+
ctx->base.allocate_buffer = dm_memory_allocate_buffer;
173+
ctx->base.free_buffer = dm_memory_free_buffer;
174+
ctx->base.copy_host_to_buffer = dm_memory_copy_host_to_buffer;
175+
ctx->base.copy_buffer_to_host = dm_memory_copy_buffer_to_host;
176+
ctx->base.copy_buffer_to_buffer = dm_memory_copy_buffer_to_buffer;
177+
ctx->ib_devname = params->dm_ib_devname;
178+
ctx->use_dmabuf = params->use_ib_dm_dmabuf;
179+
ctx->output = params->output;
180+
ctx->dm = NULL;
181+
ctx->ib_ctx = NULL;
182+
183+
return &ctx->base;
184+
}

src/dm_memory.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#ifndef DM_MEMORY_H
2+
#define DM_MEMORY_H
3+
4+
#include "memory.h"
5+
#include "config.h"
6+
7+
8+
struct perftest_parameters;
9+
10+
bool dm_memory_dmabuf_supported();
11+
12+
struct memory_ctx *dm_memory_create(struct perftest_parameters *params);
13+
14+
15+
#ifndef HAVE_IB_DM_DMABUF
16+
17+
inline bool dm_memory_dmabuf_supported() {
18+
return false;
19+
}
20+
21+
inline struct memory_ctx *dm_memory_create(struct perftest_parameters *params) {
22+
return NULL;
23+
}
24+
25+
#endif
26+
27+
#endif /* DM_MEMORY_H */

src/perftest_communication.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1033,7 +1033,8 @@ int negotiate_params(struct pingpong_context *ctx,
10331033
};
10341034
#undef COMPARE
10351035

1036-
for (int i = 0; i < sizeof(compare_functions)/sizeof(compare_functions[0]); i++) {
1036+
int i;
1037+
for (i = 0; i < sizeof(compare_functions)/sizeof(compare_functions[0]); i++) {
10371038
if (compare_functions[i].compare_func(compare_functions[i].name,
10381039
compare_functions[i].local_value,
10391040
compare_functions[i].remote_value,

src/perftest_parameters.c

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "hl_memory.h"
2121
#include "mlu_memory.h"
2222
#include "opencl_memory.h"
23+
#include "dm_memory.h"
2324
#include<math.h>
2425
#ifdef HAVE_RO
2526
#include <stdbool.h>
@@ -700,6 +701,11 @@ static void usage(const char *argv0, VerbType verb, TestType tst, int connection
700701
printf(" Use OpenCl specific platform ID\n");
701702
}
702703

704+
if (dm_memory_dmabuf_supported()) {
705+
printf(" --use_ib_dm_dmabuf=<ib_device>");
706+
printf(" Use device memory with DMA-BUF export for RDMA testing\n");
707+
}
708+
703709
if (cuda_memory_supported() ||
704710
opencl_memory_supported()) {
705711
printf(" --gpu_touch=<once\\infinite> ");
@@ -947,6 +953,8 @@ static void init_perftest_params(struct perftest_parameters *user_param)
947953
user_param->use_mlu_dmabuf = 0;
948954
user_param->opencl_platform_id = 0;
949955
user_param->opencl_device_id = 0;
956+
user_param->dm_ib_devname = NULL;
957+
user_param->use_ib_dm_dmabuf = 0;
950958
user_param->gpu_touch = GPU_NO_TOUCH;
951959
user_param->mmap_file = NULL;
952960
user_param->mmap_offset = 0;
@@ -1987,9 +1995,10 @@ static void force_dependecies(struct perftest_parameters *user_param)
19871995
exit(1);
19881996
}
19891997

1990-
if (user_param->memory_type == MEMORY_CUDA && user_param->verb == SEND && (user_param->size <= 64 || user_param->test_method == RUN_ALL)) {
1998+
if ((user_param->memory_type == MEMORY_CUDA || user_param->memory_type == MEMORY_DM) &&
1999+
user_param->verb == SEND && (user_param->size <= 64 || user_param->test_method == RUN_ALL)) {
19912000
printf(RESULT_LINE);
1992-
printf("Scatter2CQE (size <= 64) is not supported with GPUDirect send tests: setting MLX5_SCATTER_TO_CQE=0\n");
2001+
printf("Scatter2CQE (size <= 64) is not supported with device memory send tests: setting MLX5_SCATTER_TO_CQE=0\n");
19932002
if (disable_mlx5_scatter_to_cqe())
19942003
exit(1);
19952004
}
@@ -2012,6 +2021,12 @@ static void force_dependecies(struct perftest_parameters *user_param)
20122021
exit(1);
20132022
}
20142023

2024+
if (user_param->memory_type == MEMORY_DM && user_param->tst == LAT && (user_param->verb == WRITE || user_param->verb == WRITE_IMM)) {
2025+
printf(RESULT_LINE);
2026+
fprintf(stderr,"Perftest doesn't support device memory latency test with write verb\n");
2027+
exit(1);
2028+
}
2029+
20152030
if (user_param->use_data_direct) {
20162031
user_param->use_cuda_pcie_mapping = 1;
20172032
}
@@ -2517,6 +2532,11 @@ static void ctx_set_max_inline(struct ibv_context *context,struct perftest_param
25172532
return;
25182533
}
25192534

2535+
if (user_param->memory_type == MEMORY_DM){
2536+
user_param->inline_size = 0;
2537+
return;
2538+
}
2539+
25202540
if (user_param->tst == LAT) {
25212541
switch(user_param->verb) {
25222542
case WRITE_IMM:
@@ -2633,6 +2653,7 @@ int parser(struct perftest_parameters *user_param,char *argv[], int argc)
26332653
static int use_mlu_dmabuf_flag = 0;
26342654
static int use_opencl_flag = 0;
26352655
static int opencl_platform_id_flag = 0;
2656+
static int use_ib_dm_dmabuf_flag = 0;
26362657
static int gpu_touch_flag = 0;
26372658
static int disable_pcir_flag = 0;
26382659
static int mmap_file_flag = 0;
@@ -2825,6 +2846,7 @@ int parser(struct perftest_parameters *user_param,char *argv[], int argc)
28252846
{ .name = "use_mlu_dmabuf", .has_arg = 0, .flag = &use_mlu_dmabuf_flag, .val = 1},
28262847
{ .name = "use_opencl", .has_arg = 1, .flag = &use_opencl_flag, .val = 1},
28272848
{ .name = "opencl_platform_id", .has_arg = 1, .flag = &opencl_platform_id_flag, .val = 1},
2849+
{ .name = "use_ib_dm_dmabuf", .has_arg = 1, .flag = &use_ib_dm_dmabuf_flag, .val = 1},
28282850
{ .name = "gpu_touch", .has_arg = 1, .flag = &gpu_touch_flag, .val = 1},
28292851
{ .name = "mmap", .has_arg = 1, .flag = &mmap_file_flag, .val = 1},
28302852
{ .name = "mmap-offset", .has_arg = 1, .flag = &mmap_offset_flag, .val = 1},
@@ -3278,7 +3300,8 @@ int parser(struct perftest_parameters *user_param,char *argv[], int argc)
32783300
(use_hl_flag && !hl_memory_supported()) ||
32793301
(use_mlu_flag && !mlu_memory_supported()) ||
32803302
(use_mlu_dmabuf_flag && !mlu_memory_dmabuf_supported()) ||
3281-
(use_opencl_flag && !opencl_memory_supported())) {
3303+
(use_opencl_flag && !opencl_memory_supported()) ||
3304+
(use_ib_dm_dmabuf_flag && !dm_memory_dmabuf_supported())) {
32823305
printf(" Unsupported memory type\n");
32833306
return FAILURE;
32843307
}
@@ -3289,6 +3312,7 @@ int parser(struct perftest_parameters *user_param,char *argv[], int argc)
32893312
/* Memory types are mutually exclucive, make sure we were not already asked to use a different memory type. */
32903313
if (user_param->memory_type != MEMORY_HOST &&
32913314
(mmap_file_flag || use_mlu_flag || use_neuron_flag || use_hl_flag ||
3315+
use_ib_dm_dmabuf_flag ||
32923316
(use_rocm_flag && user_param->memory_type != MEMORY_ROCM) ||
32933317
((use_cuda_flag || use_cuda_bus_id_flag) && user_param->memory_type != MEMORY_CUDA))) {
32943318
fprintf(stderr, " Can't use multiple memory types\n");
@@ -3422,6 +3446,13 @@ int parser(struct perftest_parameters *user_param,char *argv[], int argc)
34223446
}
34233447
opencl_platform_id_flag = 0;
34243448
}
3449+
if (use_ib_dm_dmabuf_flag) {
3450+
user_param->dm_ib_devname = strdup(optarg);
3451+
user_param->use_ib_dm_dmabuf = 1;
3452+
user_param->memory_type = MEMORY_DM;
3453+
user_param->memory_create = dm_memory_create;
3454+
use_ib_dm_dmabuf_flag = 0;
3455+
}
34253456
if (gpu_touch_flag) {
34263457
if (!cuda_gpu_touch_supported()) {
34273458
fprintf(stderr, "GPU touch is not supported\n");

0 commit comments

Comments
 (0)