/* Try opening fi->domain_attr->cq_cnt number of completion queues * simultaneously using a size hint of 0 (indicating the provider should choose * the size) */ static int cq_open_close_simultaneous(void) { int ret; int opened; size_t count; int testret = FAIL; struct fid_cq **cq_array; count = fi->domain_attr->cq_cnt; FT_DEBUG("testing creation of up to %zu simultaneous CQs\n", count); cq_array = calloc(count, sizeof(*cq_array)); if (!cq_array) return -FI_ENOMEM; ret = 0; for (opened = 0; opened < count && !ret; opened++) { ret = create_cq(&cq_array[opened], 0, 0, FI_CQ_FORMAT_UNSPEC, FI_WAIT_UNSPEC); } if (ret) { FT_WARN("fi_cq_open failed after %d (cq_cnt: %zu): %s", opened, count, fi_strerror(-ret)); } testret = PASS; FT_CLOSEV_FID(cq_array, opened); free(cq_array); return TEST_RET_VAL(ret, testret); }
/* * Tests: * - test open and close of EQ over a range of sizes */ static int eq_open_close() { int i; int ret; int size; int testret; testret = FAIL; for (i = 0; i < 17; ++i) { size = 1 << i; ret = create_eq(size, 0, FI_WAIT_UNSPEC); if (ret != 0) { sprintf(err_buf, "fi_eq_open(%d, 0, FI_WAIT_UNSPEC) = %d, %s", size, ret, fi_strerror(-ret)); goto fail; } ret = fi_close(&eq->fid); if (ret != 0) { sprintf(err_buf, "close(eq) = %d, %s", ret, fi_strerror(-ret)); goto fail; } eq = NULL; } testret = PASS; fail: eq = NULL; return TEST_RET_VAL(ret, testret); }
/* Make sure the peeking works fine on normal read. */ static int eq_wait_read_peek(void) { int testret; int ret; testret = FAIL; ret = create_eq(32, FI_WRITE, FI_WAIT_NONE); if (ret) { sprintf(err_buf, "fi_eq_open ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } ret = insert_events(5); if (ret) goto fail; ret = read_events(5, FI_PEEK); if (ret) goto fail; ret = read_events(5, 0); if (ret) goto fail; testret = PASS; fail: FT_CLOSE_FID(eq); return TEST_RET_VAL(ret, testret); }
static int cq_signal() { struct fid_cq *cq; struct fi_cq_tagged_entry entry; int64_t elapsed; int testret; int ret; testret = FAIL; ret = create_cq(&cq, 1, 0, FI_CQ_FORMAT_UNSPEC, FI_WAIT_UNSPEC); if (ret) { sprintf(err_buf, "fi_cq_open(1, 0, FI_CQ_FORMAT_UNSPEC, " "FI_WAIT_UNSPEC) = %d, %s", ret, fi_strerror(-ret)); goto fail1; } ret = fi_cq_signal(cq); if (ret) { sprintf(err_buf, "fi_cq_signal = %d %s", ret, fi_strerror(-ret)); goto fail2; } ft_start(); ret = fi_cq_sread(cq, &entry, 1, NULL, 2000); ft_stop(); elapsed = get_elapsed(&start, &end, MILLI); if (ret != -FI_EAGAIN && ret != -FI_ECANCELED) { sprintf(err_buf, "fi_cq_sread = %d %s", ret, fi_strerror(-ret)); goto fail2; } if (elapsed > 1000) { sprintf(err_buf, "fi_cq_sread - signal ignored"); goto fail2; } ret = fi_close(&cq->fid); if (ret) { sprintf(err_buf, "close(cq) = %d, %s", ret, fi_strerror(-ret)); goto fail1; } cq = NULL; testret = PASS; fail2: FT_CLOSE_FID(cq); fail1: cq = NULL; return TEST_RET_VAL(ret, testret); }
static int mr_regattr() { int i, j, n; int ret = 0; int testret = FAIL; struct fid_mr *mr; struct iovec *iov; struct fi_mr_attr attr; char *base; attr.access = ft_info_to_mr_access(fi); attr.requested_key = FT_MR_KEY; attr.context = NULL; iov = calloc(fi->domain_attr->mr_iov_limit, sizeof(*iov)); if (!iov) { perror("calloc"); ret = -FI_ENOMEM; goto out; } for (i = 0; i < test_cnt && test_size[i].size <= fi->domain_attr->mr_iov_limit; i++) { n = test_size[i].size; base = buf; for (j = 0; j < n; j++) { iov[j].iov_base = base; iov[j].iov_len = test_size[test_cnt - 1].size / n; base += iov[j].iov_len; } attr.iov_count = n; attr.mr_iov = &iov[0]; ret = fi_mr_regattr(domain, &attr, 0, &mr); if (ret) { FT_UNIT_STRERR(err_buf, "fi_mr_regattr failed", ret); goto free; } ret = fi_close(&mr->fid); if (ret) { FT_UNIT_STRERR(err_buf, "fi_close failed", ret); goto free; } } testret = PASS; free: free(iov); out: return TEST_RET_VAL(ret, testret); }
/* Check that the peeking doesn't affect the waiting. If the peek invalidly * clears the FD, then this will fail. */ static int eq_wait_sread_peek(void) { int testret; int ret; testret = FAIL; ret = create_eq(32, FI_WRITE, FI_WAIT_FD); if (ret) { sprintf(err_buf, "fi_eq_open ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } /* Write an event */ ret = insert_events(1); if (ret) goto fail; /* Make sure we can read the event */ ret = sread_event(2000, 0); if (ret) goto fail; /* Write another event */ ret = insert_events(1); if (ret) goto fail; /* Peek at the event */ ret = sread_event(2000, FI_PEEK); if (ret) goto fail; /* Make sure the event is still available for reading */ ret = sread_event(2000, 0); if (ret) goto fail; testret = PASS; fail: FT_CLOSE_FID(eq); return TEST_RET_VAL(ret, testret); }
/* * Tests: */ static int mr_reg() { int i, j; int ret = 0; int testret = FAIL; struct fid_mr *mr; uint64_t access; uint64_t *access_combinations; int cnt; access = ft_info_to_mr_access(fi); ret = ft_alloc_bit_combo(0, access, &access_combinations, &cnt); if (ret) { FT_UNIT_STRERR(err_buf, "ft_alloc_bit_combo failed", ret); goto out; } for (i = 0; i < test_cnt; i++) { buf_size = test_size[i].size; for (j = 0; j < cnt; j++) { ret = fi_mr_reg(domain, buf, buf_size, access_combinations[j], 0, FT_MR_KEY, 0, &mr, NULL); if (ret) { FT_UNIT_STRERR(err_buf, "fi_mr_reg failed", ret); goto free; } ret = fi_close(&mr->fid); if (ret) { FT_UNIT_STRERR(err_buf, "fi_close failed", ret); goto free; } } } testret = PASS; free: ft_free_bit_combo(access_combinations); out: return TEST_RET_VAL(ret, testret); }
/* * Tests: * - write overflow */ static int eq_write_overflow() { struct fi_eq_entry entry; int testret; int ret; int i; testret = FAIL; ret = create_eq(32, FI_WRITE, FI_WAIT_NONE); if (ret != 0) { sprintf(err_buf, "fi_eq_open ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } /* Insert some events */ for (i = 0; i < 32; ++i) { entry.fid = &fabric->fid; entry.context = (void *)(uintptr_t)i; ret = fi_eq_write(eq, FI_NOTIFY, &entry, sizeof(entry), 0); if (ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_write ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } } ret = fi_eq_write(eq, FI_NOTIFY, &entry, sizeof(entry), 0); if (ret != -FI_EAGAIN && ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_write of full EQ returned %d", ret); goto fail; } testret = PASS; fail: FT_CLOSE_FID(eq); return TEST_RET_VAL(ret, testret); }
/* * Tests: * - sread with event pending * - sread with no event pending */ static int eq_wait_fd_sread() { struct fi_eq_entry entry; uint32_t event; int64_t elapsed; int testret; int ret; testret = FAIL; ret = create_eq(32, FI_WRITE, FI_WAIT_FD); if (ret != 0) { sprintf(err_buf, "fi_eq_open ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } /* timed sread on empty EQ, 2s timeout */ ft_start(); ret = fi_eq_sread(eq, &event, &entry, sizeof(entry), 2000, 0); if (ret != -FI_EAGAIN) { sprintf(err_buf, "fi_eq_read of empty EQ returned %d", ret); goto fail; } /* check timeout accuracy */ ft_stop(); elapsed = get_elapsed(&start, &end, MILLI); if (elapsed < 1500 || elapsed > 2500) { sprintf(err_buf, "fi_eq_sread slept %d ms, expected 2000", (int)elapsed); goto fail; } /* write an event */ entry.fid = &eq->fid; entry.context = eq; ret = fi_eq_write(eq, FI_NOTIFY, &entry, sizeof(entry), 0); if (ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_write ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } /* timed sread on EQ with event, 2s timeout */ ft_start(); event = ~0; memset(&entry, 0, sizeof(entry)); ret = fi_eq_sread(eq, &event, &entry, sizeof(entry), 2000, 0); if (ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_read ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } /* check that no undue waiting occurred */ ft_stop(); elapsed = get_elapsed(&start, &end, MILLI); if (elapsed > 5) { sprintf(err_buf, "fi_eq_sread slept %d ms, expected immediate return", (int)elapsed); goto fail; } if (event != FI_NOTIFY) { sprintf(err_buf, "fi_eq_sread: event = %d, should be %d\n", event, FI_NOTIFY); goto fail; } if (entry.fid != &eq->fid) { sprintf(err_buf, "fi_eq_sread: fid mismatch: %p should be %p\n", entry.fid, &eq->fid); goto fail; } if (entry.context != eq) { sprintf(err_buf, "fi_eq_sread: context mismatch: %p should be %p\n", entry.context, eq); goto fail; } testret = PASS; fail: FT_CLOSE_FID(eq); return TEST_RET_VAL(ret, testret); }
/* * Tests: * - extracting FD from EQ with FI_WAIT_FD * - wait on fd with nothing pending * - wait on fd with event pending */ static int eq_wait_fd_poll() { int fd; struct fi_eq_entry entry; struct pollfd pfd; struct fid *fids[1]; int testret; int ret; testret = FAIL; ret = create_eq(32, FI_WRITE, FI_WAIT_FD); if (ret != 0) { sprintf(err_buf, "fi_eq_open ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } ret = fi_control(&eq->fid, FI_GETWAIT, &fd); if (ret != 0) { sprintf(err_buf, "fi_control ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } fids[0] = &eq->fid; if (fi_trywait(fabric, fids, 1) != FI_SUCCESS) { sprintf(err_buf, "fi_trywait ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } pfd.fd = fd; pfd.events = POLLIN; ret = poll(&pfd, 1, 0); if (ret < 0) { sprintf(err_buf, "poll errno=%d, %s", errno, fi_strerror(-errno)); goto fail; } if (ret > 0) { sprintf(err_buf, "poll returned %d, should be 0", ret); goto fail; } /* write an event */ entry.fid = &eq->fid; entry.context = eq; ret = fi_eq_write(eq, FI_NOTIFY, &entry, sizeof(entry), 0); if (ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_write ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } pfd.fd = fd; pfd.events = POLLIN; ret = poll(&pfd, 1, 0); if (ret < 0) { sprintf(err_buf, "poll errno=%d, %s", errno, fi_strerror(-errno)); goto fail; } if (ret != 1) { sprintf(err_buf, "poll returned %d, should be 1", ret); goto fail; } testret = PASS; fail: FT_CLOSE_FID(eq); return TEST_RET_VAL(ret, testret); }
/* * Tests: * - writing to EQ * - reading from EQ with and without FI_PEEK * - underflow read */ static int eq_write_read_self() { struct fi_eq_entry entry; uint32_t event; int testret; int ret; int i; testret = FAIL; ret = create_eq(32, FI_WRITE, FI_WAIT_NONE); if (ret != 0) { sprintf(err_buf, "fi_eq_open ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } /* Insert some events */ for (i = 0; i < 5; ++i) { if (i & 1) { entry.fid = &fabric->fid; } else { entry.fid = &eq->fid; } entry.context = (void *)(uintptr_t)i; ret = fi_eq_write(eq, FI_NOTIFY, &entry, sizeof(entry), 0); if (ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_write ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } } /* Now read them back, peeking first at each one */ for (i = 0; i < 10; ++i) { event = ~0; memset(&entry, 0, sizeof(entry)); ret = fi_eq_read(eq, &event, &entry, sizeof(entry), (i & 1) ? 0 : FI_PEEK); if (ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_read ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } if (event != FI_NOTIFY) { sprintf(err_buf, "iter %d: event = %d, should be %d\n", i, event, FI_NOTIFY); goto fail; } if ((int)(uintptr_t)entry.context != i / 2) { sprintf(err_buf, "iter %d: context mismatch %d != %d", i, (int)(uintptr_t)entry.context, i / 2); goto fail; } if (entry.fid != ((i & 2) ? &fabric->fid : &eq->fid)) { sprintf(err_buf, "iter %d: fid mismatch %p != %p", i, entry.fid, ((i & 2) ? &fabric->fid : &eq->fid)); goto fail; } } /* queue is now empty */ ret = fi_eq_read(eq, &event, &entry, sizeof(entry), 0); if (ret != -FI_EAGAIN) { sprintf(err_buf, "fi_eq_read of empty EQ returned %d", ret); goto fail; } testret = PASS; fail: FT_CLOSE_FID(eq); return TEST_RET_VAL(ret, testret); }
static int cntr_loop() { size_t i, opened, cntr_cnt; uint64_t value, expected; struct timespec start, stop; int ret, testret = FAIL, timeout = 5000; cntr_cnt = MIN(fi->domain_attr->cntr_cnt, MAX_COUNTER_CHECK); struct fid_cntr **cntrs = calloc(cntr_cnt, sizeof(struct fid_cntr *)); if (!cntrs) { perror("calloc"); return -FI_ENOMEM; } for (opened = 0; opened < cntr_cnt; opened++) { ret = ft_cntr_open(&cntrs[opened]); if (ret) { FT_PRINTERR("fi_cntr_open", ret); goto close; } } for (i = 0; i < opened; i++) { ret = fi_cntr_set(cntrs[i], i); if (ret) { FT_PRINTERR("fi_cntr_set", ret); goto close; } ret = fi_cntr_seterr(cntrs[i], i << 1); if (ret) { FT_PRINTERR("fi_cntr_seterr", ret); goto close; } } for (i = 0; i < opened; i++) { ret = fi_cntr_add(cntrs[i], i); if (ret) { FT_PRINTERR("fi_cntr_add", ret); goto close; } ret = fi_cntr_adderr(cntrs[i], i); if (ret) { FT_PRINTERR("fi_cntr_adderr", ret); goto close; } } for (i = 0; i < opened; i++) { clock_gettime(CLOCK_MONOTONIC, &start); expected = i + i; do { value = fi_cntr_read(cntrs[i]); clock_gettime(CLOCK_MONOTONIC, &stop); sched_yield(); } while ((value != expected) && ((stop.tv_sec - start.tv_sec) > timeout)); if (value != expected) { FT_PRINTERR("fi_cntr_read", value); goto close; } clock_gettime(CLOCK_MONOTONIC, &start); expected = (i << 1) + i; do { value = fi_cntr_readerr(cntrs[i]); clock_gettime(CLOCK_MONOTONIC, &stop); sched_yield(); } while ((value != expected) && ((stop.tv_sec - start.tv_sec) > timeout)); if (value != expected) { FT_PRINTERR("fi_cntr_readerr", value); goto close; } } testret = PASS; close: for (i = 0; i < opened; i++) { ret = fi_close(&(cntrs[i])->fid); if (ret) { FT_PRINTERR("fi_cntr_close", ret); break; } } if (i < cntr_cnt) testret = FAIL; free(cntrs); return TEST_RET_VAL(ret, testret); }