blob: 75fc3e65fb2a8025e29d426f2d6b368b7882e577 [file] [log] [blame]
Jan Beulichbe3de802012-01-24 10:03:22 -02001/*
2 * mem-memset.c
3 *
4 * memset: Simple memory set in various ways
5 *
6 * Trivial clone of mem-memcpy.c.
7 */
Jan Beulichbe3de802012-01-24 10:03:22 -02008
9#include "../perf.h"
10#include "../util/util.h"
11#include "../util/parse-options.h"
12#include "../util/header.h"
Yann Droneaud57480d22014-06-30 22:28:47 +020013#include "../util/cloexec.h"
Jan Beulichbe3de802012-01-24 10:03:22 -020014#include "bench.h"
15#include "mem-memset-arch.h"
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/time.h>
21#include <errno.h>
22
23#define K 1024
24
25static const char *length_str = "1MB";
26static const char *routine = "default";
Jan Beuliche3e877e2012-01-18 13:29:59 +000027static int iterations = 1;
Hitoshi Mitake17d7a112012-07-02 22:46:17 +090028static bool use_cycle;
29static int cycle_fd;
Jan Beulichbe3de802012-01-24 10:03:22 -020030static bool only_prefault;
31static bool no_prefault;
32
33static const struct option options[] = {
34 OPT_STRING('l', "length", &length_str, "1MB",
Namhyung Kim08942f62012-06-20 15:08:06 +090035 "Specify length of memory to set. "
36 "Available units: B, KB, MB, GB and TB (upper and lower)"),
Jan Beulichbe3de802012-01-24 10:03:22 -020037 OPT_STRING('r', "routine", &routine, "default",
Namhyung Kim08942f62012-06-20 15:08:06 +090038 "Specify routine to set"),
Jan Beuliche3e877e2012-01-18 13:29:59 +000039 OPT_INTEGER('i', "iterations", &iterations,
40 "repeat memset() invocation this number of times"),
Hitoshi Mitake17d7a112012-07-02 22:46:17 +090041 OPT_BOOLEAN('c', "cycle", &use_cycle,
Namhyung Kim08942f62012-06-20 15:08:06 +090042 "Use cycles event instead of gettimeofday() for measuring"),
Jan Beulichbe3de802012-01-24 10:03:22 -020043 OPT_BOOLEAN('o', "only-prefault", &only_prefault,
44 "Show only the result with page faults before memset()"),
45 OPT_BOOLEAN('n', "no-prefault", &no_prefault,
46 "Show only the result without page faults before memset()"),
47 OPT_END()
48};
49
50typedef void *(*memset_t)(void *, int, size_t);
51
52struct routine {
53 const char *name;
54 const char *desc;
55 memset_t fn;
56};
57
58static const struct routine routines[] = {
59 { "default",
60 "Default memset() provided by glibc",
61 memset },
Ingo Molnar89fe8082013-09-30 12:07:11 +020062#ifdef HAVE_ARCH_X86_64_SUPPORT
Jan Beulichbe3de802012-01-24 10:03:22 -020063
64#define MEMSET_FN(fn, name, desc) { name, desc, fn },
65#include "mem-memset-x86-64-asm-def.h"
66#undef MEMSET_FN
67
68#endif
69
70 { NULL,
71 NULL,
72 NULL }
73};
74
75static const char * const bench_mem_memset_usage[] = {
76 "perf bench mem memset <options>",
77 NULL
78};
79
Hitoshi Mitake17d7a112012-07-02 22:46:17 +090080static struct perf_event_attr cycle_attr = {
Jan Beulichbe3de802012-01-24 10:03:22 -020081 .type = PERF_TYPE_HARDWARE,
82 .config = PERF_COUNT_HW_CPU_CYCLES
83};
84
Hitoshi Mitake17d7a112012-07-02 22:46:17 +090085static void init_cycle(void)
Jan Beulichbe3de802012-01-24 10:03:22 -020086{
Yann Droneaud57480d22014-06-30 22:28:47 +020087 cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1,
88 perf_event_open_cloexec_flag());
Jan Beulichbe3de802012-01-24 10:03:22 -020089
Hitoshi Mitake17d7a112012-07-02 22:46:17 +090090 if (cycle_fd < 0 && errno == ENOSYS)
Jan Beulichbe3de802012-01-24 10:03:22 -020091 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
92 else
Hitoshi Mitake17d7a112012-07-02 22:46:17 +090093 BUG_ON(cycle_fd < 0);
Jan Beulichbe3de802012-01-24 10:03:22 -020094}
95
Hitoshi Mitake17d7a112012-07-02 22:46:17 +090096static u64 get_cycle(void)
Jan Beulichbe3de802012-01-24 10:03:22 -020097{
98 int ret;
99 u64 clk;
100
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900101 ret = read(cycle_fd, &clk, sizeof(u64));
Jan Beulichbe3de802012-01-24 10:03:22 -0200102 BUG_ON(ret != sizeof(u64));
103
104 return clk;
105}
106
107static double timeval2double(struct timeval *ts)
108{
109 return (double)ts->tv_sec +
110 (double)ts->tv_usec / (double)1000000;
111}
112
113static void alloc_mem(void **dst, size_t length)
114{
115 *dst = zalloc(length);
Kirill A. Shutemov13966722013-06-06 14:35:03 +0300116 if (!*dst)
Jan Beulichbe3de802012-01-24 10:03:22 -0200117 die("memory allocation failed - maybe length is too large?\n");
118}
119
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900120static u64 do_memset_cycle(memset_t fn, size_t len, bool prefault)
Jan Beulichbe3de802012-01-24 10:03:22 -0200121{
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900122 u64 cycle_start = 0ULL, cycle_end = 0ULL;
Jan Beulichbe3de802012-01-24 10:03:22 -0200123 void *dst = NULL;
Jan Beuliche3e877e2012-01-18 13:29:59 +0000124 int i;
Jan Beulichbe3de802012-01-24 10:03:22 -0200125
126 alloc_mem(&dst, len);
127
128 if (prefault)
129 fn(dst, -1, len);
130
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900131 cycle_start = get_cycle();
Jan Beuliche3e877e2012-01-18 13:29:59 +0000132 for (i = 0; i < iterations; ++i)
133 fn(dst, i, len);
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900134 cycle_end = get_cycle();
Jan Beulichbe3de802012-01-24 10:03:22 -0200135
136 free(dst);
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900137 return cycle_end - cycle_start;
Jan Beulichbe3de802012-01-24 10:03:22 -0200138}
139
140static double do_memset_gettimeofday(memset_t fn, size_t len, bool prefault)
141{
142 struct timeval tv_start, tv_end, tv_diff;
143 void *dst = NULL;
Jan Beuliche3e877e2012-01-18 13:29:59 +0000144 int i;
Jan Beulichbe3de802012-01-24 10:03:22 -0200145
146 alloc_mem(&dst, len);
147
148 if (prefault)
149 fn(dst, -1, len);
150
151 BUG_ON(gettimeofday(&tv_start, NULL));
Jan Beuliche3e877e2012-01-18 13:29:59 +0000152 for (i = 0; i < iterations; ++i)
153 fn(dst, i, len);
Jan Beulichbe3de802012-01-24 10:03:22 -0200154 BUG_ON(gettimeofday(&tv_end, NULL));
155
156 timersub(&tv_end, &tv_start, &tv_diff);
157
158 free(dst);
159 return (double)((double)len / timeval2double(&tv_diff));
160}
161
162#define pf (no_prefault ? 0 : 1)
163
164#define print_bps(x) do { \
165 if (x < K) \
166 printf(" %14lf B/Sec", x); \
167 else if (x < K * K) \
168 printf(" %14lfd KB/Sec", x / K); \
169 else if (x < K * K * K) \
170 printf(" %14lf MB/Sec", x / K / K); \
171 else \
172 printf(" %14lf GB/Sec", x / K / K / K); \
173 } while (0)
174
175int bench_mem_memset(int argc, const char **argv,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300176 const char *prefix __maybe_unused)
Jan Beulichbe3de802012-01-24 10:03:22 -0200177{
178 int i;
179 size_t len;
180 double result_bps[2];
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900181 u64 result_cycle[2];
Jan Beulichbe3de802012-01-24 10:03:22 -0200182
183 argc = parse_options(argc, argv, options,
184 bench_mem_memset_usage, 0);
185
Davidlohr Bueso424e9632014-06-16 11:14:25 -0700186 if (no_prefault && only_prefault) {
187 fprintf(stderr, "Invalid options: -o and -n are mutually exclusive\n");
188 return 1;
189 }
190
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900191 if (use_cycle)
192 init_cycle();
Jan Beulichbe3de802012-01-24 10:03:22 -0200193
194 len = (size_t)perf_atoll((char *)length_str);
195
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900196 result_cycle[0] = result_cycle[1] = 0ULL;
Jan Beulichbe3de802012-01-24 10:03:22 -0200197 result_bps[0] = result_bps[1] = 0.0;
198
199 if ((s64)len <= 0) {
200 fprintf(stderr, "Invalid length:%s\n", length_str);
201 return 1;
202 }
203
204 /* same to without specifying either of prefault and no-prefault */
205 if (only_prefault && no_prefault)
206 only_prefault = no_prefault = false;
207
208 for (i = 0; routines[i].name; i++) {
209 if (!strcmp(routines[i].name, routine))
210 break;
211 }
212 if (!routines[i].name) {
213 printf("Unknown routine:%s\n", routine);
214 printf("Available routines...\n");
215 for (i = 0; routines[i].name; i++) {
216 printf("\t%s ... %s\n",
217 routines[i].name, routines[i].desc);
218 }
219 return 1;
220 }
221
222 if (bench_format == BENCH_FORMAT_DEFAULT)
223 printf("# Copying %s Bytes ...\n\n", length_str);
224
225 if (!only_prefault && !no_prefault) {
226 /* show both of results */
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900227 if (use_cycle) {
228 result_cycle[0] =
229 do_memset_cycle(routines[i].fn, len, false);
230 result_cycle[1] =
231 do_memset_cycle(routines[i].fn, len, true);
Jan Beulichbe3de802012-01-24 10:03:22 -0200232 } else {
233 result_bps[0] =
234 do_memset_gettimeofday(routines[i].fn,
235 len, false);
236 result_bps[1] =
237 do_memset_gettimeofday(routines[i].fn,
238 len, true);
239 }
240 } else {
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900241 if (use_cycle) {
242 result_cycle[pf] =
243 do_memset_cycle(routines[i].fn,
Jan Beulichbe3de802012-01-24 10:03:22 -0200244 len, only_prefault);
245 } else {
246 result_bps[pf] =
247 do_memset_gettimeofday(routines[i].fn,
248 len, only_prefault);
249 }
250 }
251
252 switch (bench_format) {
253 case BENCH_FORMAT_DEFAULT:
254 if (!only_prefault && !no_prefault) {
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900255 if (use_cycle) {
256 printf(" %14lf Cycle/Byte\n",
257 (double)result_cycle[0]
Jan Beulichbe3de802012-01-24 10:03:22 -0200258 / (double)len);
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900259 printf(" %14lf Cycle/Byte (with prefault)\n ",
260 (double)result_cycle[1]
Jan Beulichbe3de802012-01-24 10:03:22 -0200261 / (double)len);
262 } else {
263 print_bps(result_bps[0]);
264 printf("\n");
265 print_bps(result_bps[1]);
266 printf(" (with prefault)\n");
267 }
268 } else {
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900269 if (use_cycle) {
270 printf(" %14lf Cycle/Byte",
271 (double)result_cycle[pf]
Jan Beulichbe3de802012-01-24 10:03:22 -0200272 / (double)len);
273 } else
274 print_bps(result_bps[pf]);
275
276 printf("%s\n", only_prefault ? " (with prefault)" : "");
277 }
278 break;
279 case BENCH_FORMAT_SIMPLE:
280 if (!only_prefault && !no_prefault) {
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900281 if (use_cycle) {
Jan Beulichbe3de802012-01-24 10:03:22 -0200282 printf("%lf %lf\n",
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900283 (double)result_cycle[0] / (double)len,
284 (double)result_cycle[1] / (double)len);
Jan Beulichbe3de802012-01-24 10:03:22 -0200285 } else {
286 printf("%lf %lf\n",
287 result_bps[0], result_bps[1]);
288 }
289 } else {
Hitoshi Mitake17d7a112012-07-02 22:46:17 +0900290 if (use_cycle) {
291 printf("%lf\n", (double)result_cycle[pf]
Jan Beulichbe3de802012-01-24 10:03:22 -0200292 / (double)len);
293 } else
294 printf("%lf\n", result_bps[pf]);
295 }
296 break;
297 default:
298 /* reaching this means there's some disaster: */
299 die("unknown format: %d\n", bench_format);
300 break;
301 }
302
303 return 0;
304}