Skip to content

Commit a8f0992

Browse files
terminusacmel
authored andcommitted
perf bench mem: Add mmap() workloads
Add two mmap() workloads: one that eagerly populates a region and another that demand faults it in. The intent is to probe the memory subsytem performance incurred by mmap(). $ perf bench mem mmap -s 4gb -p 4kb -l 10 -f populate # Running 'mem/mmap' benchmark: # function 'populate' (Eagerly populated map()) # Copying 4gb bytes ... 1.811691 GB/sec $ perf bench mem mmap -s 4gb -p 2mb -l 10 -f populate # Running 'mem/mmap' benchmark: # function 'populate' (Eagerly populated mmap()) # Copying 4gb bytes ... 12.272017 GB/sec $ perf bench mem mmap -s 4gb -p 1gb -l 10 -f populate # Running 'mem/mmap' benchmark: # function 'populate' (Eagerly populated mmap()) # Copying 4gb bytes ... 17.085927 GB/sec Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andy Lutomirski <luto@kernel.org> Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: David Hildenbrand <david@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: Mateusz Guzik <mjguzik@gmail.com> Cc: Matthew Wilcox <willy@infradead.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Raghavendra K T <raghavendra.kt@amd.com> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent c3047f9 commit a8f0992

File tree

4 files changed

+132
-0
lines changed

4 files changed

+132
-0
lines changed

tools/perf/Documentation/perf-bench.txt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,40 @@ Repeat memset invocation this number of times.
240240
--cycles::
241241
Use perf's cpu-cycles event instead of gettimeofday syscall.
242242

243+
*mmap*::
244+
Suite for evaluating memory subsystem performance for mmap()'d memory.
245+
246+
Options of *mmap*
247+
^^^^^^^^^^^^^^^^^
248+
-s::
249+
--size::
250+
Specify size of memory to set (default: 1MB).
251+
Available units are B, KB, MB, GB and TB (case insensitive).
252+
253+
-p::
254+
--page::
255+
Specify page-size for mapping memory buffers (default: 4KB).
256+
Available values are 4KB, 2MB, 1GB (case insensitive).
257+
258+
-r::
259+
--randomize::
260+
Specify seed to randomize page access offset (default: 0, or not randomized).
261+
262+
-f::
263+
--function::
264+
Specify function to set (default: all).
265+
Available functions are 'demand' and 'populate', with the first
266+
demand faulting pages in the region and the second using an eager
267+
mapping.
268+
269+
-l::
270+
--nr_loops::
271+
Repeat mmap() invocation this number of times.
272+
273+
-c::
274+
--cycles::
275+
Use perf's cpu-cycles event instead of gettimeofday syscall.
276+
243277
SUITES FOR 'numa'
244278
~~~~~~~~~~~~~~~~~
245279
*mem*::

tools/perf/bench/bench.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ int bench_syscall_fork(int argc, const char **argv);
2828
int bench_syscall_execve(int argc, const char **argv);
2929
int bench_mem_memcpy(int argc, const char **argv);
3030
int bench_mem_memset(int argc, const char **argv);
31+
int bench_mem_mmap(int argc, const char **argv);
3132
int bench_mem_find_bit(int argc, const char **argv);
3233
int bench_futex_hash(int argc, const char **argv);
3334
int bench_futex_wake(int argc, const char **argv);

tools/perf/bench/mem-functions.c

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ static const char *chunk_size_str = "0";
4040
static unsigned int nr_loops = 1;
4141
static bool use_cycles;
4242
static int cycles_fd;
43+
static unsigned int seed;
4344

4445
static const struct option bench_common_options[] = {
4546
OPT_STRING('s', "size", &size_str, "1MB",
@@ -81,6 +82,7 @@ struct bench_params {
8182
size_t chunk_size;
8283
unsigned int nr_loops;
8384
unsigned int page_shift;
85+
unsigned int seed;
8486
};
8587

8688
struct bench_mem_info {
@@ -98,6 +100,7 @@ typedef void (*mem_fini_t)(struct bench_mem_info *, struct bench_params *,
98100
void **, void **);
99101
typedef void *(*memcpy_t)(void *, const void *, size_t);
100102
typedef void *(*memset_t)(void *, int, size_t);
103+
typedef void (*mmap_op_t)(void *, size_t, unsigned int, bool);
101104

102105
struct function {
103106
const char *name;
@@ -108,6 +111,7 @@ struct function {
108111
union {
109112
memcpy_t memcpy;
110113
memset_t memset;
114+
mmap_op_t mmap_op;
111115
};
112116
} fn;
113117
};
@@ -160,6 +164,14 @@ static union bench_clock clock_diff(union bench_clock *s, union bench_clock *e)
160164
return t;
161165
}
162166

167+
static void clock_accum(union bench_clock *a, union bench_clock *b)
168+
{
169+
if (use_cycles)
170+
a->cycles += b->cycles;
171+
else
172+
timeradd(&a->tv, &b->tv, &a->tv);
173+
}
174+
163175
static double timeval2double(struct timeval *ts)
164176
{
165177
return (double)ts->tv_sec + (double)ts->tv_usec / (double)USEC_PER_SEC;
@@ -271,6 +283,8 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info *
271283
}
272284
p.page_shift = ilog2(page_size);
273285

286+
p.seed = seed;
287+
274288
if (!strncmp(function_str, "all", 3)) {
275289
for (i = 0; info->functions[i].name; i++)
276290
__bench_mem_function(info, &p, i);
@@ -465,3 +479,85 @@ int bench_mem_memset(int argc, const char **argv)
465479

466480
return bench_mem_common(argc, argv, &info);
467481
}
482+
483+
static void mmap_page_touch(void *dst, size_t size, unsigned int page_shift, bool random)
484+
{
485+
unsigned long npages = size / (1 << page_shift);
486+
unsigned long offset = 0, r = 0;
487+
488+
for (unsigned long i = 0; i < npages; i++) {
489+
if (random)
490+
r = rand() % (1 << page_shift);
491+
492+
*((char *)dst + offset + r) = *(char *)(dst + offset + r) + i;
493+
offset += 1 << page_shift;
494+
}
495+
}
496+
497+
static int do_mmap(const struct function *r, struct bench_params *p,
498+
void *src __maybe_unused, void *dst __maybe_unused,
499+
union bench_clock *accum)
500+
{
501+
union bench_clock start, end, diff;
502+
mmap_op_t fn = r->fn.mmap_op;
503+
bool populate = strcmp(r->name, "populate") == 0;
504+
505+
if (p->seed)
506+
srand(p->seed);
507+
508+
for (unsigned int i = 0; i < p->nr_loops; i++) {
509+
clock_get(&start);
510+
dst = bench_mmap(p->size, populate, p->page_shift);
511+
if (!dst)
512+
goto out;
513+
514+
fn(dst, p->size, p->page_shift, p->seed);
515+
clock_get(&end);
516+
diff = clock_diff(&start, &end);
517+
clock_accum(accum, &diff);
518+
519+
bench_munmap(dst, p->size);
520+
}
521+
522+
return 0;
523+
out:
524+
printf("# Memory allocation failed - maybe size (%s) %s?\n", size_str,
525+
p->page_shift != PAGE_SHIFT_4KB ? "has insufficient hugepages" : "is too large");
526+
return -1;
527+
}
528+
529+
static const char * const bench_mem_mmap_usage[] = {
530+
"perf bench mem mmap <options>",
531+
NULL
532+
};
533+
534+
static const struct function mmap_functions[] = {
535+
{ .name = "demand",
536+
.desc = "Demand loaded mmap()",
537+
.fn.mmap_op = mmap_page_touch },
538+
539+
{ .name = "populate",
540+
.desc = "Eagerly populated mmap()",
541+
.fn.mmap_op = mmap_page_touch },
542+
543+
{ .name = NULL, }
544+
};
545+
546+
int bench_mem_mmap(int argc, const char **argv)
547+
{
548+
static const struct option bench_mmap_options[] = {
549+
OPT_UINTEGER('r', "randomize", &seed,
550+
"Seed to randomize page access offset."),
551+
OPT_PARENT(bench_common_options),
552+
OPT_END()
553+
};
554+
555+
struct bench_mem_info info = {
556+
.functions = mmap_functions,
557+
.do_op = do_mmap,
558+
.usage = bench_mem_mmap_usage,
559+
.options = bench_mmap_options,
560+
};
561+
562+
return bench_mem_common(argc, argv, &info);
563+
}

tools/perf/builtin-bench.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ static struct bench mem_benchmarks[] = {
6565
{ "memcpy", "Benchmark for memcpy() functions", bench_mem_memcpy },
6666
{ "memset", "Benchmark for memset() functions", bench_mem_memset },
6767
{ "find_bit", "Benchmark for find_bit() functions", bench_mem_find_bit },
68+
{ "mmap", "Benchmark for mmap() mappings", bench_mem_mmap },
6869
{ "all", "Run all memory access benchmarks", NULL },
6970
{ NULL, NULL, NULL }
7071
};

0 commit comments

Comments
 (0)