1/* 2 * mem-memcpy.c 3 * 4 * memcpy: Simple memory copy in various ways 5 * 6 * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> 7 */ 8#include <ctype.h> 9 10#include "../perf.h" 11#include "../util/util.h" 12#include "../util/parse-options.h" 13#include "../util/header.h" 14#include "bench.h" 15 16#include <stdio.h> 17#include <stdlib.h> 18#include <string.h> 19#include <sys/time.h> 20#include <errno.h> 21 22#define K 1024 23 24static const char *length_str = "1MB"; 25static const char *routine = "default"; 26static bool use_clock = false; 27static int clock_fd; 28 29static const struct option options[] = { 30 OPT_STRING('l', "length", &length_str, "1MB", 31 "Specify length of memory to copy. " 32 "available unit: B, MB, GB (upper and lower)"), 33 OPT_STRING('r', "routine", &routine, "default", 34 "Specify routine to copy"), 35 OPT_BOOLEAN('c', "clock", &use_clock, 36 "Use CPU clock for measuring"), 37 OPT_END() 38}; 39 40struct routine { 41 const char *name; 42 const char *desc; 43 void * (*fn)(void *dst, const void *src, size_t len); 44}; 45 46struct routine routines[] = { 47 { "default", 48 "Default memcpy() provided by glibc", 49 memcpy }, 50 { NULL, 51 NULL, 52 NULL } 53}; 54 55static const char * const bench_mem_memcpy_usage[] = { 56 "perf bench mem memcpy <options>", 57 NULL 58}; 59 60static struct perf_event_attr clock_attr = { 61 .type = PERF_TYPE_HARDWARE, 62 .config = PERF_COUNT_HW_CPU_CYCLES 63}; 64 65static void init_clock(void) 66{ 67 clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0); 68 69 if (clock_fd < 0 && errno == ENOSYS) 70 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 71 else 72 BUG_ON(clock_fd < 0); 73} 74 75static u64 get_clock(void) 76{ 77 int ret; 78 u64 clk; 79 80 ret = read(clock_fd, &clk, sizeof(u64)); 81 BUG_ON(ret != sizeof(u64)); 82 83 return clk; 84} 85 86static double timeval2double(struct timeval *ts) 87{ 88 return (double)ts->tv_sec + 89 (double)ts->tv_usec / (double)1000000; 90} 91 92int bench_mem_memcpy(int argc, const char **argv, 93 const char *prefix __used) 94{ 95 int i; 96 void *dst, *src; 97 size_t length; 98 double bps = 0.0; 99 struct timeval tv_start, tv_end, tv_diff; 100 u64 clock_start, clock_end, clock_diff; 101 102 clock_start = clock_end = clock_diff = 0ULL; 103 argc = parse_options(argc, argv, options, 104 bench_mem_memcpy_usage, 0); 105 106 tv_diff.tv_sec = 0; 107 tv_diff.tv_usec = 0; 108 length = (size_t)perf_atoll((char *)length_str); 109 110 if ((s64)length <= 0) { 111 fprintf(stderr, "Invalid length:%s\n", length_str); 112 return 1; 113 } 114 115 for (i = 0; routines[i].name; i++) { 116 if (!strcmp(routines[i].name, routine)) 117 break; 118 } 119 if (!routines[i].name) { 120 printf("Unknown routine:%s\n", routine); 121 printf("Available routines...\n"); 122 for (i = 0; routines[i].name; i++) { 123 printf("\t%s ... %s\n", 124 routines[i].name, routines[i].desc); 125 } 126 return 1; 127 } 128 129 dst = zalloc(length); 130 if (!dst) 131 die("memory allocation failed - maybe length is too large?\n"); 132 133 src = zalloc(length); 134 if (!src) 135 die("memory allocation failed - maybe length is too large?\n"); 136 137 if (bench_format == BENCH_FORMAT_DEFAULT) { 138 printf("# Copying %s Bytes from %p to %p ...\n\n", 139 length_str, src, dst); 140 } 141 142 if (use_clock) { 143 init_clock(); 144 clock_start = get_clock(); 145 } else { 146 BUG_ON(gettimeofday(&tv_start, NULL)); 147 } 148 149 routines[i].fn(dst, src, length); 150 151 if (use_clock) { 152 clock_end = get_clock(); 153 clock_diff = clock_end - clock_start; 154 } else { 155 BUG_ON(gettimeofday(&tv_end, NULL)); 156 timersub(&tv_end, &tv_start, &tv_diff); 157 bps = (double)((double)length / timeval2double(&tv_diff)); 158 } 159 160 switch (bench_format) { 161 case BENCH_FORMAT_DEFAULT: 162 if (use_clock) { 163 printf(" %14lf Clock/Byte\n", 164 (double)clock_diff / (double)length); 165 } else { 166 if (bps < K) 167 printf(" %14lf B/Sec\n", bps); 168 else if (bps < K * K) 169 printf(" %14lfd KB/Sec\n", bps / 1024); 170 else if (bps < K * K * K) 171 printf(" %14lf MB/Sec\n", bps / 1024 / 1024); 172 else { 173 printf(" %14lf GB/Sec\n", 174 bps / 1024 / 1024 / 1024); 175 } 176 } 177 break; 178 case BENCH_FORMAT_SIMPLE: 179 if (use_clock) { 180 printf("%14lf\n", 181 (double)clock_diff / (double)length); 182 } else 183 printf("%lf\n", bps); 184 break; 185 default: 186 /* reaching this means there's some disaster: */ 187 die("unknown format: %d\n", bench_format); 188 break; 189 } 190 191 return 0; 192} 193