1252267Sjimharris/*- 2252267Sjimharris * Copyright (C) 2012-2013 Intel Corporation 3252267Sjimharris * All rights reserved. 4252267Sjimharris * 5252267Sjimharris * Redistribution and use in source and binary forms, with or without 6252267Sjimharris * modification, are permitted provided that the following conditions 7252267Sjimharris * are met: 8252267Sjimharris * 1. Redistributions of source code must retain the above copyright 9252267Sjimharris * notice, this list of conditions and the following disclaimer. 10252267Sjimharris * 2. Redistributions in binary form must reproduce the above copyright 11252267Sjimharris * notice, this list of conditions and the following disclaimer in the 12252267Sjimharris * documentation and/or other materials provided with the distribution. 13252267Sjimharris * 14252267Sjimharris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15252267Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16252267Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17252267Sjimharris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18252267Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19252267Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20252267Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21252267Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22252267Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23252267Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24252267Sjimharris * SUCH DAMAGE. 25252267Sjimharris */ 26252267Sjimharris 27252267Sjimharris#include <sys/cdefs.h> 28252267Sjimharris__FBSDID("$FreeBSD$"); 29252267Sjimharris 30252267Sjimharris#include <sys/param.h> 31252267Sjimharris#include <sys/ioccom.h> 32252267Sjimharris 33252267Sjimharris#include <ctype.h> 34253109Sjimharris#include <err.h> 35252267Sjimharris#include <fcntl.h> 36256152Sjimharris#include <inttypes.h> 37252267Sjimharris#include <stdbool.h> 38252267Sjimharris#include <stddef.h> 39252267Sjimharris#include <stdio.h> 40252267Sjimharris#include <stdlib.h> 41252267Sjimharris#include <string.h> 42252267Sjimharris#include <unistd.h> 43252267Sjimharris 44252267Sjimharris#include "nvmecontrol.h" 45252267Sjimharris 46252267Sjimharrisstatic void 47252267Sjimharrisprint_perftest(struct nvme_io_test *io_test, bool perthread) 48252267Sjimharris{ 49256152Sjimharris uint64_t io_completed = 0, iops, mbps; 50256152Sjimharris uint32_t i; 51252267Sjimharris 52252267Sjimharris for (i = 0; i < io_test->num_threads; i++) 53252267Sjimharris io_completed += io_test->io_completed[i]; 54252267Sjimharris 55252267Sjimharris iops = io_completed/io_test->time; 56252267Sjimharris mbps = iops * io_test->size / (1024*1024); 57252267Sjimharris 58256152Sjimharris printf("Threads: %2d Size: %6d %5s Time: %3d IO/s: %7ju MB/s: %4ju\n", 59252267Sjimharris io_test->num_threads, io_test->size, 60252267Sjimharris io_test->opc == NVME_OPC_READ ? "READ" : "WRITE", 61256152Sjimharris io_test->time, (uintmax_t)iops, (uintmax_t)mbps); 62252267Sjimharris 63252267Sjimharris if (perthread) 64252267Sjimharris for (i = 0; i < io_test->num_threads; i++) 65256152Sjimharris printf("\t%3d: %8ju IO/s\n", i, 66256152Sjimharris (uintmax_t)io_test->io_completed[i]/io_test->time); 67252267Sjimharris} 68252267Sjimharris 69252267Sjimharrisstatic void 70252267Sjimharrisperftest_usage(void) 71252267Sjimharris{ 72252267Sjimharris fprintf(stderr, "usage:\n"); 73252267Sjimharris fprintf(stderr, PERFTEST_USAGE); 74253109Sjimharris exit(1); 75252267Sjimharris} 76252267Sjimharris 77252267Sjimharrisvoid 78252267Sjimharrisperftest(int argc, char *argv[]) 79252267Sjimharris{ 80252267Sjimharris struct nvme_io_test io_test; 81252267Sjimharris int fd; 82252267Sjimharris char ch; 83252267Sjimharris char *p; 84252267Sjimharris u_long ioctl_cmd = NVME_IO_TEST; 85252267Sjimharris bool nflag, oflag, sflag, tflag; 86252267Sjimharris int perthread = 0; 87252267Sjimharris 88252267Sjimharris nflag = oflag = sflag = tflag = false; 89252267Sjimharris 90252267Sjimharris memset(&io_test, 0, sizeof(io_test)); 91252267Sjimharris 92252267Sjimharris while ((ch = getopt(argc, argv, "f:i:n:o:ps:t:")) != -1) { 93252267Sjimharris switch (ch) { 94252267Sjimharris case 'f': 95252267Sjimharris if (!strcmp(optarg, "refthread")) 96252267Sjimharris io_test.flags |= NVME_TEST_FLAG_REFTHREAD; 97252267Sjimharris break; 98252267Sjimharris case 'i': 99252267Sjimharris if (!strcmp(optarg, "bio") || 100252267Sjimharris !strcmp(optarg, "wait")) 101252267Sjimharris ioctl_cmd = NVME_BIO_TEST; 102252267Sjimharris else if (!strcmp(optarg, "io") || 103252267Sjimharris !strcmp(optarg, "intr")) 104252267Sjimharris ioctl_cmd = NVME_IO_TEST; 105252267Sjimharris break; 106252267Sjimharris case 'n': 107252267Sjimharris nflag = true; 108252267Sjimharris io_test.num_threads = strtoul(optarg, &p, 0); 109252267Sjimharris if (p != NULL && *p != '\0') { 110252267Sjimharris fprintf(stderr, 111252267Sjimharris "\"%s\" not valid number of threads.\n", 112252267Sjimharris optarg); 113252267Sjimharris perftest_usage(); 114252267Sjimharris } else if (io_test.num_threads == 0 || 115252267Sjimharris io_test.num_threads > 128) { 116252267Sjimharris fprintf(stderr, 117252267Sjimharris "\"%s\" not valid number of threads.\n", 118252267Sjimharris optarg); 119252267Sjimharris perftest_usage(); 120252267Sjimharris } 121252267Sjimharris break; 122252267Sjimharris case 'o': 123252267Sjimharris oflag = true; 124252267Sjimharris if (!strcmp(optarg, "read") || !strcmp(optarg, "READ")) 125252267Sjimharris io_test.opc = NVME_OPC_READ; 126252267Sjimharris else if (!strcmp(optarg, "write") || 127252267Sjimharris !strcmp(optarg, "WRITE")) 128252267Sjimharris io_test.opc = NVME_OPC_WRITE; 129252267Sjimharris else { 130252267Sjimharris fprintf(stderr, "\"%s\" not valid opcode.\n", 131252267Sjimharris optarg); 132252267Sjimharris perftest_usage(); 133252267Sjimharris } 134252267Sjimharris break; 135252267Sjimharris case 'p': 136252267Sjimharris perthread = 1; 137252267Sjimharris break; 138252267Sjimharris case 's': 139252267Sjimharris sflag = true; 140252267Sjimharris io_test.size = strtoul(optarg, &p, 0); 141252267Sjimharris if (p == NULL || *p == '\0' || toupper(*p) == 'B') { 142252267Sjimharris // do nothing 143252267Sjimharris } else if (toupper(*p) == 'K') { 144252267Sjimharris io_test.size *= 1024; 145252267Sjimharris } else if (toupper(*p) == 'M') { 146252267Sjimharris io_test.size *= 1024 * 1024; 147252267Sjimharris } else { 148252267Sjimharris fprintf(stderr, "\"%s\" not valid size.\n", 149252267Sjimharris optarg); 150252267Sjimharris perftest_usage(); 151252267Sjimharris } 152252267Sjimharris break; 153252267Sjimharris case 't': 154252267Sjimharris tflag = true; 155252267Sjimharris io_test.time = strtoul(optarg, &p, 0); 156252267Sjimharris if (p != NULL && *p != '\0') { 157252267Sjimharris fprintf(stderr, 158252267Sjimharris "\"%s\" not valid time duration.\n", 159252267Sjimharris optarg); 160252267Sjimharris perftest_usage(); 161252267Sjimharris } 162252267Sjimharris break; 163252267Sjimharris } 164252267Sjimharris } 165252267Sjimharris 166252267Sjimharris if (!nflag || !oflag || !sflag || !tflag || optind >= argc) 167252267Sjimharris perftest_usage(); 168252267Sjimharris 169252267Sjimharris open_dev(argv[optind], &fd, 1, 1); 170253109Sjimharris if (ioctl(fd, ioctl_cmd, &io_test) < 0) 171253109Sjimharris err(1, "ioctl NVME_IO_TEST failed"); 172252267Sjimharris 173252267Sjimharris close(fd); 174252267Sjimharris print_perftest(&io_test, perthread); 175253109Sjimharris exit(0); 176252267Sjimharris} 177