1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 36 #include "spdk/env.h" 37 #include "spdk/event.h" 38 #include "spdk/log.h" 39 #include "spdk/string.h" 40 41 static uint64_t g_tsc_rate; 42 static uint64_t g_tsc_end; 43 44 static int g_time_in_sec; 45 46 static uint64_t *call_count; 47 48 static bool g_app_stopped = false; 49 50 static void 51 submit_new_event(void *arg1, void *arg2) 52 { 53 struct spdk_event *event; 54 static __thread uint32_t next_lcore = UINT32_MAX; 55 56 if (spdk_get_ticks() > g_tsc_end) { 57 if (__sync_bool_compare_and_swap(&g_app_stopped, false, true)) { 58 spdk_app_stop(0); 59 } 60 return; 61 } 62 63 if (next_lcore == UINT32_MAX) { 64 next_lcore = spdk_env_get_next_core(spdk_env_get_current_core()); 65 if (next_lcore == UINT32_MAX) { 66 next_lcore = spdk_env_get_first_core(); 67 } 68 } 69 70 call_count[next_lcore]++; 71 event = spdk_event_allocate(next_lcore, submit_new_event, NULL, NULL); 72 spdk_event_call(event); 73 } 74 75 static void 76 event_work_fn(void *arg1, void *arg2) 77 { 78 79 submit_new_event(NULL, NULL); 80 submit_new_event(NULL, NULL); 81 submit_new_event(NULL, NULL); 82 submit_new_event(NULL, NULL); 83 } 84 85 static void 86 event_perf_start(void *arg1) 87 { 88 uint32_t i; 89 90 call_count = calloc(spdk_env_get_last_core() + 1, sizeof(*call_count)); 91 if (call_count == NULL) { 92 fprintf(stderr, "call_count allocation failed\n"); 93 spdk_app_stop(1); 94 return; 95 } 96 97 g_tsc_rate = spdk_get_ticks_hz(); 98 g_tsc_end = spdk_get_ticks() + g_time_in_sec * g_tsc_rate; 99 100 printf("Running I/O for %d seconds...", g_time_in_sec); 101 fflush(stdout); 102 103 SPDK_ENV_FOREACH_CORE(i) { 104 spdk_event_call(spdk_event_allocate(i, event_work_fn, 105 NULL, NULL)); 106 } 107 108 } 109 110 static void 111 usage(char *program_name) 112 { 113 printf("%s options\n", program_name); 114 printf("\t[-m core mask for distributing I/O submission/completion work\n"); 115 printf("\t\t(default: 0x1 - use core 0 only)]\n"); 116 printf("\t[-t time in seconds]\n"); 117 } 118 119 static void 120 performance_dump(int io_time) 121 { 122 uint32_t i; 123 124 if (call_count == NULL) { 125 return; 126 } 127 128 printf("\n"); 129 SPDK_ENV_FOREACH_CORE(i) { 130 printf("lcore %2d: %8ju\n", i, call_count[i] / g_time_in_sec); 131 } 132 133 fflush(stdout); 134 free(call_count); 135 } 136 137 int 138 main(int argc, char **argv) 139 { 140 struct spdk_app_opts opts = {}; 141 int op; 142 int rc = 0; 143 144 spdk_app_opts_init(&opts, sizeof(opts)); 145 opts.name = "event_perf"; 146 147 g_time_in_sec = 0; 148 149 while ((op = getopt(argc, argv, "m:t:")) != -1) { 150 switch (op) { 151 case 'm': 152 opts.reactor_mask = optarg; 153 break; 154 case 't': 155 g_time_in_sec = spdk_strtol(optarg, 10); 156 if (g_time_in_sec < 0) { 157 fprintf(stderr, "Invalid run time\n"); 158 return g_time_in_sec; 159 } 160 break; 161 default: 162 usage(argv[0]); 163 exit(1); 164 } 165 } 166 167 if (!g_time_in_sec) { 168 usage(argv[0]); 169 exit(1); 170 } 171 172 printf("Running I/O for %d seconds...", g_time_in_sec); 173 fflush(stdout); 174 175 rc = spdk_app_start(&opts, event_perf_start, NULL); 176 177 spdk_app_fini(); 178 performance_dump(g_time_in_sec); 179 180 printf("done.\n"); 181 return rc; 182 } 183