diff options
Diffstat (limited to 'tools/perf/bench/mem-memcpy.c')
-rw-r--r-- | tools/perf/bench/mem-memcpy.c | 286 |
1 files changed, 202 insertions, 84 deletions
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c index 2465141b554b..6c14afe8c1b1 100644 --- a/tools/perf/bench/mem-memcpy.c +++ b/tools/perf/bench/mem-memcpy.c @@ -13,6 +13,7 @@ #include "../util/cloexec.h" #include "bench.h" #include "mem-memcpy-arch.h" +#include "mem-memset-arch.h" #include <stdio.h> #include <stdlib.h> @@ -48,20 +49,24 @@ static const struct option options[] = { }; typedef void *(*memcpy_t)(void *, const void *, size_t); +typedef void *(*memset_t)(void *, int, size_t); struct routine { const char *name; const char *desc; - memcpy_t fn; + union { + memcpy_t memcpy; + memset_t memset; + } fn; }; -struct routine routines[] = { - { "default", - "Default memcpy() provided by glibc", - memcpy }, +struct routine memcpy_routines[] = { + { .name = "default", + .desc = "Default memcpy() provided by glibc", + .fn.memcpy = memcpy }, #ifdef HAVE_ARCH_X86_64_SUPPORT -#define MEMCPY_FN(fn, name, desc) { name, desc, fn }, +#define MEMCPY_FN(_fn, _name, _desc) {.name = _name, .desc = _desc, .fn.memcpy = _fn}, #include "mem-memcpy-x86-64-asm-def.h" #undef MEMCPY_FN @@ -69,7 +74,7 @@ struct routine routines[] = { { NULL, NULL, - NULL } + {NULL} } }; static const char * const bench_mem_memcpy_usage[] = { @@ -110,63 +115,6 @@ static double timeval2double(struct timeval *ts) (double)ts->tv_usec / (double)1000000; } -static void alloc_mem(void **dst, void **src, size_t length) -{ - *dst = zalloc(length); - if (!*dst) - die("memory allocation failed - maybe length is too large?\n"); - - *src = zalloc(length); - if (!*src) - die("memory allocation failed - maybe length is too large?\n"); - /* Make sure to always replace the zero pages even if MMAP_THRESH is crossed */ - memset(*src, 0, length); -} - -static u64 do_memcpy_cycle(memcpy_t fn, size_t len, bool prefault) -{ - u64 cycle_start = 0ULL, cycle_end = 0ULL; - void *src = NULL, *dst = NULL; - int i; - - alloc_mem(&src, &dst, len); - - if (prefault) - fn(dst, src, len); - - cycle_start = get_cycle(); - for (i = 0; i < iterations; ++i) - fn(dst, src, len); - cycle_end = get_cycle(); - - free(src); - free(dst); - return cycle_end - cycle_start; -} - -static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault) -{ - struct timeval tv_start, tv_end, tv_diff; - void *src = NULL, *dst = NULL; - int i; - - alloc_mem(&src, &dst, len); - - if (prefault) - fn(dst, src, len); - - BUG_ON(gettimeofday(&tv_start, NULL)); - for (i = 0; i < iterations; ++i) - fn(dst, src, len); - BUG_ON(gettimeofday(&tv_end, NULL)); - - timersub(&tv_end, &tv_start, &tv_diff); - - free(src); - free(dst); - return (double)((double)len / timeval2double(&tv_diff)); -} - #define pf (no_prefault ? 0 : 1) #define print_bps(x) do { \ @@ -180,16 +128,25 @@ static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault) printf(" %14lf GB/Sec", x / K / K / K); \ } while (0) -int bench_mem_memcpy(int argc, const char **argv, - const char *prefix __maybe_unused) +struct bench_mem_info { + const struct routine *routines; + u64 (*do_cycle)(const struct routine *r, size_t len, bool prefault); + double (*do_gettimeofday)(const struct routine *r, size_t len, bool prefault); + const char *const *usage; +}; + +static int bench_mem_common(int argc, const char **argv, + const char *prefix __maybe_unused, + struct bench_mem_info *info) { int i; size_t len; + double totallen; double result_bps[2]; u64 result_cycle[2]; argc = parse_options(argc, argv, options, - bench_mem_memcpy_usage, 0); + info->usage, 0); if (no_prefault && only_prefault) { fprintf(stderr, "Invalid options: -o and -n are mutually exclusive\n"); @@ -200,6 +157,7 @@ int bench_mem_memcpy(int argc, const char **argv, init_cycle(); len = (size_t)perf_atoll((char *)length_str); + totallen = (double)len * iterations; result_cycle[0] = result_cycle[1] = 0ULL; result_bps[0] = result_bps[1] = 0.0; @@ -213,16 +171,16 @@ int bench_mem_memcpy(int argc, const char **argv, if (only_prefault && no_prefault) only_prefault = no_prefault = false; - for (i = 0; routines[i].name; i++) { - if (!strcmp(routines[i].name, routine)) + for (i = 0; info->routines[i].name; i++) { + if (!strcmp(info->routines[i].name, routine)) break; } - if (!routines[i].name) { + if (!info->routines[i].name) { printf("Unknown routine:%s\n", routine); printf("Available routines...\n"); - for (i = 0; routines[i].name; i++) { + for (i = 0; info->routines[i].name; i++) { printf("\t%s ... %s\n", - routines[i].name, routines[i].desc); + info->routines[i].name, info->routines[i].desc); } return 1; } @@ -234,25 +192,25 @@ int bench_mem_memcpy(int argc, const char **argv, /* show both of results */ if (use_cycle) { result_cycle[0] = - do_memcpy_cycle(routines[i].fn, len, false); + info->do_cycle(&info->routines[i], len, false); result_cycle[1] = - do_memcpy_cycle(routines[i].fn, len, true); + info->do_cycle(&info->routines[i], len, true); } else { result_bps[0] = - do_memcpy_gettimeofday(routines[i].fn, + info->do_gettimeofday(&info->routines[i], len, false); result_bps[1] = - do_memcpy_gettimeofday(routines[i].fn, + info->do_gettimeofday(&info->routines[i], len, true); } } else { if (use_cycle) { result_cycle[pf] = - do_memcpy_cycle(routines[i].fn, + info->do_cycle(&info->routines[i], len, only_prefault); } else { result_bps[pf] = - do_memcpy_gettimeofday(routines[i].fn, + info->do_gettimeofday(&info->routines[i], len, only_prefault); } } @@ -263,10 +221,10 @@ int bench_mem_memcpy(int argc, const char **argv, if (use_cycle) { printf(" %14lf Cycle/Byte\n", (double)result_cycle[0] - / (double)len); + / totallen); printf(" %14lf Cycle/Byte (with prefault)\n", (double)result_cycle[1] - / (double)len); + / totallen); } else { print_bps(result_bps[0]); printf("\n"); @@ -277,7 +235,7 @@ int bench_mem_memcpy(int argc, const char **argv, if (use_cycle) { printf(" %14lf Cycle/Byte", (double)result_cycle[pf] - / (double)len); + / totallen); } else print_bps(result_bps[pf]); @@ -288,8 +246,8 @@ int bench_mem_memcpy(int argc, const char **argv, if (!only_prefault && !no_prefault) { if (use_cycle) { printf("%lf %lf\n", - (double)result_cycle[0] / (double)len, - (double)result_cycle[1] / (double)len); + (double)result_cycle[0] / totallen, + (double)result_cycle[1] / totallen); } else { printf("%lf %lf\n", result_bps[0], result_bps[1]); @@ -297,7 +255,7 @@ int bench_mem_memcpy(int argc, const char **argv, } else { if (use_cycle) { printf("%lf\n", (double)result_cycle[pf] - / (double)len); + / totallen); } else printf("%lf\n", result_bps[pf]); } @@ -310,3 +268,163 @@ int bench_mem_memcpy(int argc, const char **argv, return 0; } + +static void memcpy_alloc_mem(void **dst, void **src, size_t length) +{ + *dst = zalloc(length); + if (!*dst) + die("memory allocation failed - maybe length is too large?\n"); + + *src = zalloc(length); + if (!*src) + die("memory allocation failed - maybe length is too large?\n"); + /* Make sure to always replace the zero pages even if MMAP_THRESH is crossed */ + memset(*src, 0, length); +} + +static u64 do_memcpy_cycle(const struct routine *r, size_t len, bool prefault) +{ + u64 cycle_start = 0ULL, cycle_end = 0ULL; + void *src = NULL, *dst = NULL; + memcpy_t fn = r->fn.memcpy; + int i; + + memcpy_alloc_mem(&src, &dst, len); + + if (prefault) + fn(dst, src, len); + + cycle_start = get_cycle(); + for (i = 0; i < iterations; ++i) + fn(dst, src, len); + cycle_end = get_cycle(); + + free(src); + free(dst); + return cycle_end - cycle_start; +} + +static double do_memcpy_gettimeofday(const struct routine *r, size_t len, + bool prefault) +{ + struct timeval tv_start, tv_end, tv_diff; + memcpy_t fn = r->fn.memcpy; + void *src = NULL, *dst = NULL; + int i; + + memcpy_alloc_mem(&src, &dst, len); + + if (prefault) + fn(dst, src, len); + + BUG_ON(gettimeofday(&tv_start, NULL)); + for (i = 0; i < iterations; ++i) + fn(dst, src, len); + BUG_ON(gettimeofday(&tv_end, NULL)); + + timersub(&tv_end, &tv_start, &tv_diff); + + free(src); + free(dst); + return (double)(((double)len * iterations) / timeval2double(&tv_diff)); +} + +int bench_mem_memcpy(int argc, const char **argv, + const char *prefix __maybe_unused) +{ + struct bench_mem_info info = { + .routines = memcpy_routines, + .do_cycle = do_memcpy_cycle, + .do_gettimeofday = do_memcpy_gettimeofday, + .usage = bench_mem_memcpy_usage, + }; + + return bench_mem_common(argc, argv, prefix, &info); +} + +static void memset_alloc_mem(void **dst, size_t length) +{ + *dst = zalloc(length); + if (!*dst) + die("memory allocation failed - maybe length is too large?\n"); +} + +static u64 do_memset_cycle(const struct routine *r, size_t len, bool prefault) +{ + u64 cycle_start = 0ULL, cycle_end = 0ULL; + memset_t fn = r->fn.memset; + void *dst = NULL; + int i; + + memset_alloc_mem(&dst, len); + + if (prefault) + fn(dst, -1, len); + + cycle_start = get_cycle(); + for (i = 0; i < iterations; ++i) + fn(dst, i, len); + cycle_end = get_cycle(); + + free(dst); + return cycle_end - cycle_start; +} + +static double do_memset_gettimeofday(const struct routine *r, size_t len, + bool prefault) +{ + struct timeval tv_start, tv_end, tv_diff; + memset_t fn = r->fn.memset; + void *dst = NULL; + int i; + + memset_alloc_mem(&dst, len); + + if (prefault) + fn(dst, -1, len); + + BUG_ON(gettimeofday(&tv_start, NULL)); + for (i = 0; i < iterations; ++i) + fn(dst, i, len); + BUG_ON(gettimeofday(&tv_end, NULL)); + + timersub(&tv_end, &tv_start, &tv_diff); + + free(dst); + return (double)(((double)len * iterations) / timeval2double(&tv_diff)); +} + +static const char * const bench_mem_memset_usage[] = { + "perf bench mem memset <options>", + NULL +}; + +static const struct routine memset_routines[] = { + { .name ="default", + .desc = "Default memset() provided by glibc", + .fn.memset = memset }, +#ifdef HAVE_ARCH_X86_64_SUPPORT + +#define MEMSET_FN(_fn, _name, _desc) { .name = _name, .desc = _desc, .fn.memset = _fn }, +#include "mem-memset-x86-64-asm-def.h" +#undef MEMSET_FN + +#endif + + { .name = NULL, + .desc = NULL, + .fn.memset = NULL } +}; + +int bench_mem_memset(int argc, const char **argv, + const char *prefix __maybe_unused) +{ + struct bench_mem_info info = { + .routines = memset_routines, + .do_cycle = do_memset_cycle, + .do_gettimeofday = do_memset_gettimeofday, + .usage = bench_mem_memset_usage, + }; + + return bench_mem_common(argc, argv, prefix, &info); +} |