xref: /spdk/test/thread/poller_perf/poller_perf.c (revision 9efad7468f30e1c5f7442823f5a8b17acd1e6a9b)
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/string.h"
39 #include "spdk/thread.h"
40 #include "spdk/util.h"
41 
42 #define MAX_NUM_POLLERS	1000
43 
44 static int g_time_in_sec;
45 static int g_period_in_usec;
46 static int g_num_pollers;
47 
48 static struct spdk_poller *g_timer;
49 static struct spdk_poller *g_pollers[MAX_NUM_POLLERS];
50 static uint64_t g_run_count;
51 
52 static struct spdk_thread_stats g_start_stats;
53 
54 static int
55 poller_run(void *arg)
56 {
57 	g_run_count++;
58 
59 	return SPDK_POLLER_BUSY;
60 }
61 
62 static void
63 _poller_perf_end(void)
64 {
65 	struct spdk_thread_stats end_stats;
66 	uint64_t tsc_hz, busy_cyc, poller_cost_cyc, poller_cost_nsec;
67 	int i;
68 
69 	spdk_thread_get_stats(&end_stats);
70 	busy_cyc = end_stats.busy_tsc - g_start_stats.busy_tsc;
71 
72 	tsc_hz = spdk_get_ticks_hz();
73 
74 	printf("\r ======================================\n");
75 
76 	printf("\r busy:%" PRIu64 " (cyc)\n", busy_cyc);
77 	printf("\r total_run_count: %" PRIu64 "\n", g_run_count);
78 	printf("\r tsc_hz: %" PRIu64 " (cyc)\n", tsc_hz);
79 
80 	printf("\r ======================================\n");
81 
82 	poller_cost_cyc = busy_cyc / g_run_count;
83 	poller_cost_nsec = (poller_cost_cyc * SPDK_SEC_TO_NSEC) / tsc_hz;
84 
85 	printf("\r poller_cost: %" PRIu64 " (cyc), %" PRIu64 " (nsec)\n",
86 	       poller_cost_cyc, poller_cost_nsec);
87 
88 	spdk_poller_unregister(&g_timer);
89 
90 	for (i = 0; i < g_num_pollers; i++) {
91 		spdk_poller_unregister(&g_pollers[i]);
92 	}
93 
94 	spdk_app_stop(0);
95 }
96 
97 static int
98 poller_perf_end(void *arg)
99 {
100 	_poller_perf_end();
101 
102 	return SPDK_POLLER_BUSY;
103 }
104 
105 static void
106 poller_perf_start(void *arg1)
107 {
108 	int i;
109 
110 	printf("Running %d pollers for %d seconds with %d microseconds period.\n",
111 	       g_num_pollers, g_time_in_sec, g_period_in_usec);
112 	fflush(stdout);
113 
114 	for (i = 0; i < g_num_pollers; i++) {
115 		g_pollers[i] = SPDK_POLLER_REGISTER(poller_run, NULL, g_period_in_usec);
116 	}
117 
118 	spdk_thread_get_stats(&g_start_stats);
119 
120 	g_timer = SPDK_POLLER_REGISTER(poller_perf_end, NULL, g_time_in_sec * SPDK_SEC_TO_USEC);
121 }
122 
123 static void
124 poller_perf_shutdown_cb(void)
125 {
126 	_poller_perf_end();
127 }
128 
129 static int
130 poller_perf_parse_arg(int ch, char *arg)
131 {
132 	int tmp;
133 
134 	tmp = spdk_strtol(optarg, 10);
135 	if (tmp < 0) {
136 		fprintf(stderr, "Parse failed for the option %c.\n", ch);
137 		return tmp;
138 	}
139 
140 	switch (ch) {
141 	case 'b':
142 		g_num_pollers = tmp;
143 		break;
144 	case 'l':
145 		g_period_in_usec = tmp;
146 		break;
147 	case 't':
148 		g_time_in_sec = tmp;
149 		break;
150 	default:
151 		return -EINVAL;
152 	}
153 
154 	return 0;
155 }
156 
157 static void
158 poller_perf_usage(void)
159 {
160 	printf(" -b <number>            number of pollers\n");
161 	printf(" -l <period>            poller period in usec\n");
162 	printf(" -t <time>              run time in seconds\n");
163 }
164 
165 static int
166 poller_perf_verify_params(void)
167 {
168 	if (g_num_pollers <= 0 || g_num_pollers > MAX_NUM_POLLERS) {
169 		fprintf(stderr, "number of pollers must not be more than %d\n", MAX_NUM_POLLERS);
170 		return -EINVAL;
171 	}
172 
173 	if (g_period_in_usec < 0) {
174 		fprintf(stderr, "period of poller cannot be negative\n");
175 		return -EINVAL;
176 	}
177 
178 	if (g_time_in_sec <= 0) {
179 		fprintf(stderr, "run time must be positive\n");
180 		return -EINVAL;
181 	}
182 
183 	return 0;
184 }
185 
186 int
187 main(int argc, char **argv)
188 {
189 	struct spdk_app_opts opts;
190 	int rc;
191 
192 	spdk_app_opts_init(&opts, sizeof(opts));
193 	opts.name = "poller_perf";
194 	opts.shutdown_cb = poller_perf_shutdown_cb;
195 
196 	rc = spdk_app_parse_args(argc, argv, &opts, "b:l:t:", NULL,
197 				 poller_perf_parse_arg, poller_perf_usage);
198 	if (rc != SPDK_APP_PARSE_ARGS_SUCCESS) {
199 		return rc;
200 	}
201 
202 	rc = poller_perf_verify_params();
203 	if (rc != 0) {
204 		return rc;
205 	}
206 
207 	rc = spdk_app_start(&opts, poller_perf_start, NULL);
208 
209 	spdk_app_fini();
210 
211 	return rc;
212 }
213