1/* $NetBSD: perftest.c,v 1.5 2018/04/18 10:11:44 nonaka Exp $ */ 2 3/*- 4 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 5 * 6 * Copyright (C) 2012-2013 Intel Corporation 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#include <sys/cdefs.h> 32#ifndef lint 33__RCSID("$NetBSD: perftest.c,v 1.5 2018/04/18 10:11:44 nonaka Exp $"); 34#if 0 35__FBSDID("$FreeBSD: head/sbin/nvmecontrol/perftest.c 329824 2018-02-22 13:32:31Z wma $"); 36#endif 37#endif 38 39#include <sys/param.h> 40#include <sys/ioccom.h> 41 42#include <ctype.h> 43#include <err.h> 44#include <fcntl.h> 45#include <inttypes.h> 46#include <stdbool.h> 47#include <stddef.h> 48#include <stdio.h> 49#include <stdlib.h> 50#include <string.h> 51#include <unistd.h> 52 53#include "nvmectl.h" 54 55#ifdef PERFTEST_USAGE 56static void 57print_perftest(struct nvme_io_test *io_test, bool perthread) 58{ 59 uint64_t io_completed = 0, iops, mbps; 60 uint32_t i; 61 62 for (i = 0; i < io_test->num_threads; i++) 63 io_completed += io_test->io_completed[i]; 64 65 iops = io_completed/io_test->time; 66 mbps = iops * io_test->size / (1024*1024); 67 68 printf("Threads: %2d Size: %6d %5s Time: %3d IO/s: %7ju MB/s: %4ju\n", 69 io_test->num_threads, io_test->size, 70 io_test->opc == NVME_OPC_READ ? "READ" : "WRITE", 71 io_test->time, (uintmax_t)iops, (uintmax_t)mbps); 72 73 if (perthread) 74 for (i = 0; i < io_test->num_threads; i++) 75 printf("\t%3d: %8ju IO/s\n", i, 76 (uintmax_t)io_test->io_completed[i]/io_test->time); 77} 78 79static void 80perftest_usage(void) 81{ 82 fprintf(stderr, "usage:\n"); 83 fprintf(stderr, "\t%s" PERFTEST_USAGE, getprogname()); 84 exit(1); 85} 86 87void 88perftest(int argc, char *argv[]) 89{ 90 struct nvme_io_test io_test; 91 int fd; 92 int ch; 93 char *p; 94 u_long ioctl_cmd = NVME_IO_TEST; 95 bool nflag, oflag, sflag, tflag; 96 int perthread = 0; 97 98 nflag = oflag = sflag = tflag = false; 99 100 memset(&io_test, 0, sizeof(io_test)); 101 102 while ((ch = getopt(argc, argv, "f:i:n:o:ps:t:")) != -1) { 103 switch (ch) { 104 case 'f': 105 if (!strcmp(optarg, "refthread")) 106 io_test.flags |= NVME_TEST_FLAG_REFTHREAD; 107 break; 108 case 'i': 109 if (!strcmp(optarg, "bio") || 110 !strcmp(optarg, "wait")) 111 ioctl_cmd = NVME_BIO_TEST; 112 else if (!strcmp(optarg, "io") || 113 !strcmp(optarg, "intr")) 114 ioctl_cmd = NVME_IO_TEST; 115 break; 116 case 'n': 117 nflag = true; 118 io_test.num_threads = strtoul(optarg, &p, 0); 119 if (p != NULL && *p != '\0') { 120 fprintf(stderr, 121 "\"%s\" not valid number of threads.\n", 122 optarg); 123 perftest_usage(); 124 } else if (io_test.num_threads == 0 || 125 io_test.num_threads > 128) { 126 fprintf(stderr, 127 "\"%s\" not valid number of threads.\n", 128 optarg); 129 perftest_usage(); 130 } 131 break; 132 case 'o': 133 oflag = true; 134 if (!strcmp(optarg, "read") || !strcmp(optarg, "READ")) 135 io_test.opc = NVME_OPC_READ; 136 else if (!strcmp(optarg, "write") || 137 !strcmp(optarg, "WRITE")) 138 io_test.opc = NVME_OPC_WRITE; 139 else { 140 fprintf(stderr, "\"%s\" not valid opcode.\n", 141 optarg); 142 perftest_usage(); 143 } 144 break; 145 case 'p': 146 perthread = 1; 147 break; 148 case 's': 149 sflag = true; 150 io_test.size = strtoul(optarg, &p, 0); 151 if (p == NULL || *p == '\0' || toupper(*p) == 'B') { 152 // do nothing 153 } else if (toupper(*p) == 'K') { 154 io_test.size *= 1024; 155 } else if (toupper(*p) == 'M') { 156 io_test.size *= 1024 * 1024; 157 } else { 158 fprintf(stderr, "\"%s\" not valid size.\n", 159 optarg); 160 perftest_usage(); 161 } 162 break; 163 case 't': 164 tflag = true; 165 io_test.time = strtoul(optarg, &p, 0); 166 if (p != NULL && *p != '\0') { 167 fprintf(stderr, 168 "\"%s\" not valid time duration.\n", 169 optarg); 170 perftest_usage(); 171 } 172 break; 173 } 174 } 175 176 if (!nflag || !oflag || !sflag || !tflag || optind >= argc) 177 perftest_usage(); 178 179 open_dev(argv[optind], &fd, 1, 1); 180 if (ioctl(fd, ioctl_cmd, &io_test) < 0) 181 err(1, "ioctl NVME_IO_TEST failed"); 182 183 close(fd); 184 print_perftest(&io_test, perthread); 185 exit(0); 186} 187#endif 188