@@ -2,10 +2,12 @@
# Copyright (c) 2018, Mellanox Technologies. All rights reserved. See COPYING file
import unittest
import resource
+import random
+from pyverbs.pyverbs_error import PyverbsError, PyverbsRDMAError
+import pyverbs.tests.utils as u
import pyverbs.device as d
-
PAGE_SIZE = resource.getpagesize()
@@ -73,3 +75,146 @@ class device_test(unittest.TestCase):
with d.Context(name=dev.name.decode()) as ctx:
attr_ex = ctx.query_device_ex()
self.verify_device_attr(attr_ex.orig_attr)
+
+
+class dm_test(unittest.TestCase):
+ """
+ Test various functionalities of the DM class.
+ """
+ def test_create_dm(self):
+ """
+ test ibv_alloc_dm()
+ """
+ lst = d.get_device_list()
+ for dev in lst:
+ with d.Context(name=dev.name.decode()) as ctx:
+ attr = ctx.query_device_ex()
+ if attr.max_dm_size == 0:
+ return
+ dm_len = random.randrange(u.MIN_DM_SIZE, attr.max_dm_size,
+ u.DM_ALIGNMENT)
+ dm_attrs = u.get_dm_attrs(dm_len)
+ with d.DM(ctx, dm_attrs):
+ pass
+
+ def test_destroy_dm(self):
+ """
+ test ibv_free_dm()
+ """
+ lst = d.get_device_list()
+ for dev in lst:
+ with d.Context(name=dev.name.decode()) as ctx:
+ attr = ctx.query_device_ex()
+ if attr.max_dm_size == 0:
+ return
+ dm_len = random.randrange(u.MIN_DM_SIZE, attr.max_dm_size,
+ u.DM_ALIGNMENT)
+ dm_attrs = u.get_dm_attrs(dm_len)
+ dm = d.DM(ctx, dm_attrs)
+ dm.close()
+
+ def test_create_dm_bad_flow(self):
+ """
+ test ibv_alloc_dm() with an illegal size and comp mask
+ """
+ lst = d.get_device_list()
+ for dev in lst:
+ with d.Context(name=dev.name.decode()) as ctx:
+ attr = ctx.query_device_ex()
+ if attr.max_dm_size == 0:
+ return
+ dm_len = attr.max_dm_size + 1
+ dm_attrs = u.get_dm_attrs(dm_len)
+ try:
+ dm = d.DM(ctx, dm_attrs)
+ except PyverbsRDMAError as e:
+ assert 'Failed to allocate device memory of size' in e.args[0]
+ assert 'Max available size' in e.args[0]
+ else:
+ raise PyverbsError('Created a DM with size larger than max reported')
+ dm_attrs.comp_mask = random.randint(1, 100)
+ try:
+ dm = d.DM(ctx, dm_attrs)
+ except PyverbsRDMAError as e:
+ assert 'Failed to allocate device memory of size' in e.args[0]
+ else:
+ raise PyverbsError('Created a DM with illegal comp mask {c}'.\
+ format(c=dm_attrs.comp_mask))
+
+ def test_destroy_dm_bad_flow(self):
+ """
+ test calling ibv_free_dm() twice
+ """
+ lst = d.get_device_list()
+ for dev in lst:
+ with d.Context(name=dev.name.decode()) as ctx:
+ attr = ctx.query_device_ex()
+ if attr.max_dm_size == 0:
+ return
+ dm_len = random.randrange(u.MIN_DM_SIZE, attr.max_dm_size, u.DM_ALIGNMENT)
+ dm_attrs = u.get_dm_attrs(dm_len)
+ dm = d.DM(ctx, dm_attrs)
+ dm.close()
+ dm.close()
+
+ def test_dm_write(self):
+ """
+ Test writing to the device memory
+ """
+ lst = d.get_device_list()
+ for dev in lst:
+ with d.Context(name=dev.name.decode()) as ctx:
+ attr = ctx.query_device_ex()
+ if attr.max_dm_size == 0:
+ return
+ dm_len = random.randrange(u.MIN_DM_SIZE, attr.max_dm_size, u.DM_ALIGNMENT)
+ dm_attrs = u.get_dm_attrs(dm_len)
+ with d.DM(ctx, dm_attrs) as dm:
+ data_length = random.randrange(4, dm_len, u.DM_ALIGNMENT)
+ data_offset = random.randrange(0, dm_len - data_length, u.DM_ALIGNMENT)
+ data = u.get_data(data_length)
+ dm.copy_to_dm(data_offset, data.encode(), data_length)
+
+ def test_dm_write_bad_flow(self):
+ """
+ Test writing to the device memory with bad offset and length
+ """
+ lst = d.get_device_list()
+ for dev in lst:
+ with d.Context(name=dev.name.decode()) as ctx:
+ attr = ctx.query_device_ex()
+ if attr.max_dm_size == 0:
+ return
+ dm_len = random.randrange(u.MIN_DM_SIZE, attr.max_dm_size, u.DM_ALIGNMENT)
+ dm_attrs = u.get_dm_attrs(dm_len)
+ with d.DM(ctx, dm_attrs) as dm:
+ data_length = random.randrange(4, dm_len, u.DM_ALIGNMENT)
+ data_offset = random.randrange(0, dm_len - data_length, u.DM_ALIGNMENT)
+ data_offset += 1 # offset needs to be a multiple of 4
+ data = u.get_data(data_length)
+ try:
+ dm.copy_to_dm(data_offset, data.encode(), data_length)
+ except PyverbsRDMAError as e:
+ assert 'Failed to copy to dm' in e.args[0]
+ else:
+ raise PyverbsError('Wrote to device memory with a bad offset')
+
+ def test_dm_read(self):
+ """
+ Test reading from the device memory
+ """
+ lst = d.get_device_list()
+ for dev in lst:
+ with d.Context(name=dev.name.decode()) as ctx:
+ attr = ctx.query_device_ex()
+ if attr.max_dm_size == 0:
+ return
+ dm_len = random.randrange(u.MIN_DM_SIZE, attr.max_dm_size, u.DM_ALIGNMENT)
+ dm_attrs = u.get_dm_attrs(dm_len)
+ with d.DM(ctx, dm_attrs) as dm:
+ data_length = random.randrange(4, dm_len, u.DM_ALIGNMENT)
+ data_offset = random.randrange(0, dm_len - data_length, u.DM_ALIGNMENT)
+ data = u.get_data(data_length)
+ dm.copy_to_dm(data_offset, data.encode(), data_length)
+ read_str = dm.copy_from_dm(data_offset, data_length)
+ assert read_str.decode() == data
@@ -5,8 +5,8 @@ import random
from pyverbs.pyverbs_error import PyverbsRDMAError, PyverbsError
from pyverbs.base import PyverbsRDMAErrno
+from pyverbs.mr import MR, MW, DMMR
import pyverbs.tests.utils as u
-from pyverbs.mr import MR, MW
import pyverbs.device as d
from pyverbs.pd import PD
import pyverbs.enums as e
@@ -181,3 +181,49 @@ class mw_test(unittest.TestCase):
else:
raise PyverbsError('Created a MW with type {t}'.\
format(t=mw_type))
+
+
+class dm_mr_test(unittest.TestCase):
+ """
+ Test various functionalities of the DMMR class.
+ """
+ def test_create_dm_mr(self):
+ """
+ Test ibv_reg_dm_mr
+ """
+ lst = d.get_device_list()
+ for dev in lst:
+ with d.Context(name=dev.name.decode()) as ctx:
+ attr = ctx.query_device_ex()
+ if attr.max_dm_size == 0:
+ return
+ with PD(ctx) as pd:
+ dm_len = random.randrange(u.MIN_DM_SIZE, attr.max_dm_size,
+ u.DM_ALIGNMENT)
+ dm_attrs = u.get_dm_attrs(dm_len)
+ with d.DM(ctx, dm_attrs) as dm:
+ dm_mr_len = random.randint(1, dm_len)
+ dm_mr_offset = random.randint(0, (dm_len - dm_mr_len))
+ dm_mr = DMMR(pd, dm_mr_len, e.IBV_ACCESS_ZERO_BASED, dm=dm,
+ offset=dm_mr_offset)
+
+ def test_destroy_dm_mr(self):
+ """
+ Test freeing of dm_mr
+ """
+ lst = d.get_device_list()
+ for dev in lst:
+ with d.Context(name=dev.name.decode()) as ctx:
+ attr = ctx.query_device_ex()
+ if attr.max_dm_size == 0:
+ return
+ with PD(ctx) as pd:
+ dm_len = random.randrange(u.MIN_DM_SIZE, attr.max_dm_size,
+ u.DM_ALIGNMENT)
+ dm_attrs = u.get_dm_attrs(dm_len)
+ with d.DM(ctx, dm_attrs) as dm:
+ dm_mr_len = random.randint(1, dm_len)
+ dm_mr_offset = random.randint(0, (dm_len - dm_mr_len))
+ dm_mr = DMMR(pd, dm_mr_len, e.IBV_ACCESS_ZERO_BASED, dm=dm,
+ offset=dm_mr_offset)
+ dm_mr.close()
@@ -2,9 +2,19 @@
# Copyright (c) 2019, Mellanox Technologies. All rights reserved. See COPYING file
from string import ascii_lowercase as al
import random
+
+import pyverbs.device as d
import pyverbs.enums as e
MAX_MR_SIZE = 4194304
+# Some HWs limit DM address and length alignment to 4 for read and write
+# operations. Use a minimal length and alignment that respect that.
+# For creation purposes use random alignments. As this is log2 of address
+# alignment, no need for large numbers.
+MIN_DM_SIZE = 4
+DM_ALIGNMENT = 4
+MIN_DM_LOG_ALIGN = 0
+MAX_DM_LOG_ALIGN = 6
def get_mr_length():
# Allocating large buffers typically fails
@@ -26,3 +36,9 @@ def get_access_flags():
def get_data(length):
return ''.join(random.choice(al) for i in range(length))
+
+
+def get_dm_attrs(dm_len):
+ align = random.randint(MIN_DM_LOG_ALIGN, MAX_DM_LOG_ALIGN)
+ # Comp mask != 0 is not supported
+ return d.AllocDmAttr(dm_len, align, 0)
Add tests for direct memory creation as well as DMMR. Signed-off-by: Noa Osherovich <noaos@mellanox.com> --- pyverbs/tests/device.py | 147 +++++++++++++++++++++++++++++++++++++++- pyverbs/tests/mr.py | 48 ++++++++++++- pyverbs/tests/utils.py | 16 +++++ 3 files changed, 209 insertions(+), 2 deletions(-)