| # SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) | |
| # Copyright (c) 2019 Mellanox Technologies, Inc. All rights reserved. See COPYING file | |
| # Copyright 2020 Amazon.com, Inc. or its affiliates. All rights reserved. | |
| """ | |
| Test module for pyverbs' cq module. | |
| """ | |
| import unittest | |
| import errno | |
| import time | |
| from tests.base import PyverbsAPITestCase, RDMATestCase, UDResources | |
| from pyverbs.pyverbs_error import PyverbsRDMAError | |
| from pyverbs.base import PyverbsRDMAErrno | |
| from pyverbs.cq import CompChannel, CQ | |
| import tests.irdma_base as irdma | |
| from pyverbs.qp import QPCap | |
| import pyverbs.device as d | |
| import tests.utils as u | |
| class CQUDResources(UDResources): | |
| def __init__(self, dev_name, ib_port, gid_index, cq_depth=None): | |
| self.cq_depth = cq_depth | |
| super().__init__(dev_name, ib_port, gid_index) | |
| def create_cq(self): | |
| """ | |
| Initializes self.cq with a CQ of depth <num_msgs> - defined by each | |
| test. | |
| :return: None | |
| """ | |
| cq_depth = self.cq_depth if self.cq_depth is not None else self.num_msgs | |
| self.cq = CQ(self.ctx, cq_depth, None, None, 0) | |
| def create_qp_cap(self): | |
| return QPCap(max_recv_wr=self.num_msgs, max_send_wr=10) | |
| class CQAPITest(PyverbsAPITestCase): | |
| """ | |
| Test the API of the CQ class. | |
| """ | |
| def setUp(self): | |
| super().setUp() | |
| def test_create_cq(self): | |
| for cq_size in [1, self.attr.max_cqe/2, self.attr.max_cqe]: | |
| for comp_vector in range(0, min(2, self.ctx.num_comp_vectors)): | |
| try: | |
| cq = CQ(self.ctx, cq_size, None, None, comp_vector) | |
| cq.close() | |
| except PyverbsRDMAError as ex: | |
| cq_attr = f'cq_size={cq_size}, comp_vector={comp_vector}' | |
| raise PyverbsRDMAErrno(f'Failed to create a CQ with {cq_attr}') | |
| # Create CQ with Max value of comp_vector. | |
| max_cqs_comp_vector = self.ctx.num_comp_vectors - 1 | |
| cq = CQ(self.ctx, self.ctx.num_comp_vectors, None, None, max_cqs_comp_vector) | |
| def test_create_cq_with_comp_channel(self): | |
| for cq_size in [1, self.attr.max_cqe/2, self.attr.max_cqe]: | |
| try: | |
| cc = CompChannel(self.ctx) | |
| CQ(self.ctx, cq_size, None, cc, 0) | |
| cc.close() | |
| except PyverbsRDMAError as ex: | |
| if ex.error_code == errno.EOPNOTSUPP: | |
| raise unittest.SkipTest(f'CQ with completion channel is not supported') | |
| def test_create_cq_bad_flow(self): | |
| """ | |
| Test ibv_create_cq() with wrong comp_vector / number of cqes | |
| """ | |
| with self.assertRaises(PyverbsRDMAError) as ex: | |
| CQ(self.ctx, self.attr.max_cqe + 1, None, None, 0) | |
| self.assertEqual(ex.exception.error_code, errno.EINVAL) | |
| with self.assertRaises(PyverbsRDMAError) as ex: | |
| CQ(self.ctx, 100, None, None, self.ctx.num_comp_vectors + 1) | |
| self.assertEqual(ex.exception.error_code, errno.EINVAL) | |
| class CQTest(RDMATestCase): | |
| """ | |
| Test various functionalities of the CQ class. | |
| """ | |
| def setUp(self): | |
| super().setUp() | |
| self.iters = 10 | |
| self.server = None | |
| self.client = None | |
| def test_resize_cq(self): | |
| """ | |
| Test resize CQ, start with specific value and then increase and decrease | |
| the CQ size. The test also check bad flow of decrease the CQ size when | |
| there are more completions on it than the new value. | |
| """ | |
| self.create_players(CQUDResources, cq_depth=3) | |
| # Decrease the CQ size. | |
| new_cq_size = 1 | |
| try: | |
| self.client.cq.resize(new_cq_size) | |
| except PyverbsRDMAError as ex: | |
| if ex.error_code == errno.EOPNOTSUPP: | |
| raise unittest.SkipTest('Resize CQ is not supported') | |
| raise ex | |
| self.assertTrue(self.client.cq.cqe >= new_cq_size, | |
| f'The actual CQ size ({self.client.cq.cqe}) is less ' | |
| 'than guaranteed ({new_cq_size})') | |
| # Increase the CQ size. | |
| new_cq_size = 7 | |
| post_send_num = new_cq_size - 1 | |
| self.client.cq.resize(new_cq_size) | |
| self.assertTrue(self.client.cq.cqe >= new_cq_size, | |
| f'The actual CQ size ({self.client.cq.cqe}) is less ' | |
| 'than guaranteed ({new_cq_size})') | |
| # Fill the CQ entries except one for avoid cq_overrun warnings. | |
| send_wr, _ = u.get_send_elements(self.client, False) | |
| ah_client = u.get_global_ah(self.client, self.gid_index, self.ib_port) | |
| for i in range(post_send_num): | |
| u.send(self.client, send_wr, ah=ah_client) | |
| # Give a chance for some sends to be processed completely. | |
| time.sleep(1) | |
| # Decrease the CQ size to less than the CQ unpolled entries. | |
| new_cq_size = 1 | |
| try: | |
| self.client.cq.resize(new_cq_size) | |
| except PyverbsRDMAError as ex: | |
| self.assertEqual(ex.error_code, errno.EINVAL) | |
| finally: | |
| for i in range(post_send_num): | |
| u.poll_cq(self.client.cq) |