@@ -40,6 +40,7 @@ static const char *chunk_size_str = "0";
4040static unsigned int nr_loops = 1 ;
4141static bool use_cycles ;
4242static int cycles_fd ;
43+ static unsigned int seed ;
4344
4445static 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
8688struct bench_mem_info {
@@ -98,6 +100,7 @@ typedef void (*mem_fini_t)(struct bench_mem_info *, struct bench_params *,
98100 void * * , void * * );
99101typedef void * (* memcpy_t )(void * , const void * , size_t );
100102typedef void * (* memset_t )(void * , int , size_t );
103+ typedef void (* mmap_op_t )(void * , size_t , unsigned int , bool );
101104
102105struct 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+
163175static 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+ }
0 commit comments