c055564217
Parsing an option from the command line with OPT_BOOLEAN on a bool data type would not work on a big-endian machine due to the manner in which the boolean was being cast into an int and incremented. For example, running 'perf probe --list' on a PowerPC machine would fail to properly set the list_events bool and would therefore print out the usage information and terminate. This patch makes OPT_BOOLEAN work as expected with a bool datatype. For cases where the original OPT_BOOLEAN was intentionally being used to increment an int each time it was passed in on the command line, this patch introduces OPT_INCR with the old behaviour of OPT_BOOLEAN (the verbose variable is currently the only such example of this). I have reviewed every use of OPT_BOOLEAN to verify that a true C99 bool was passed. Where integers were used, I verified that they were only being used for boolean logic and changed them to bools to ensure that they would not be mistakenly used as ints. The major exception was the verbose variable which now uses OPT_INCR instead of OPT_BOOLEAN. Signed-off-by: Ian Munsie <imunsie@au.ibm.com> Acked-by: David S. Miller <davem@davemloft.net> Cc: <stable@kernel.org> # NOTE: wont apply to .3[34].x cleanly, please backport Cc: Git development list <git@vger.kernel.org> Cc: Ian Munsie <imunsie@au1.ibm.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Eric B Munson <ebmunson@us.ibm.com> Cc: Valdis.Kletnieks@vt.edu Cc: WANG Cong <amwang@redhat.com> Cc: Thiago Farina <tfransosi@gmail.com> Cc: Masami Hiramatsu <mhiramat@redhat.com> Cc: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> Cc: Jaswinder Singh Rajput <jaswinderrajput@gmail.com> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> Cc: Mike Galbraith <efault@gmx.de> Cc: Tom Zanussi <tzanussi@gmail.com> Cc: Anton Blanchard <anton@samba.org> Cc: John Kacur <jkacur@redhat.com> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Steven Rostedt <rostedt@goodmis.org> LKML-Reference: <1271147857-11604-1-git-send-email-imunsie@au.ibm.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
192 lines
4.1 KiB
C
192 lines
4.1 KiB
C
/*
|
|
* mem-memcpy.c
|
|
*
|
|
* memcpy: Simple memory copy in various ways
|
|
*
|
|
* Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
|
|
*/
|
|
#include <ctype.h>
|
|
|
|
#include "../perf.h"
|
|
#include "../util/util.h"
|
|
#include "../util/parse-options.h"
|
|
#include "../util/header.h"
|
|
#include "bench.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/time.h>
|
|
#include <errno.h>
|
|
|
|
#define K 1024
|
|
|
|
static const char *length_str = "1MB";
|
|
static const char *routine = "default";
|
|
static bool use_clock = false;
|
|
static int clock_fd;
|
|
|
|
static const struct option options[] = {
|
|
OPT_STRING('l', "length", &length_str, "1MB",
|
|
"Specify length of memory to copy. "
|
|
"available unit: B, MB, GB (upper and lower)"),
|
|
OPT_STRING('r', "routine", &routine, "default",
|
|
"Specify routine to copy"),
|
|
OPT_BOOLEAN('c', "clock", &use_clock,
|
|
"Use CPU clock for measuring"),
|
|
OPT_END()
|
|
};
|
|
|
|
struct routine {
|
|
const char *name;
|
|
const char *desc;
|
|
void * (*fn)(void *dst, const void *src, size_t len);
|
|
};
|
|
|
|
struct routine routines[] = {
|
|
{ "default",
|
|
"Default memcpy() provided by glibc",
|
|
memcpy },
|
|
{ NULL,
|
|
NULL,
|
|
NULL }
|
|
};
|
|
|
|
static const char * const bench_mem_memcpy_usage[] = {
|
|
"perf bench mem memcpy <options>",
|
|
NULL
|
|
};
|
|
|
|
static struct perf_event_attr clock_attr = {
|
|
.type = PERF_TYPE_HARDWARE,
|
|
.config = PERF_COUNT_HW_CPU_CYCLES
|
|
};
|
|
|
|
static void init_clock(void)
|
|
{
|
|
clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0);
|
|
|
|
if (clock_fd < 0 && errno == ENOSYS)
|
|
die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
|
|
else
|
|
BUG_ON(clock_fd < 0);
|
|
}
|
|
|
|
static u64 get_clock(void)
|
|
{
|
|
int ret;
|
|
u64 clk;
|
|
|
|
ret = read(clock_fd, &clk, sizeof(u64));
|
|
BUG_ON(ret != sizeof(u64));
|
|
|
|
return clk;
|
|
}
|
|
|
|
static double timeval2double(struct timeval *ts)
|
|
{
|
|
return (double)ts->tv_sec +
|
|
(double)ts->tv_usec / (double)1000000;
|
|
}
|
|
|
|
int bench_mem_memcpy(int argc, const char **argv,
|
|
const char *prefix __used)
|
|
{
|
|
int i;
|
|
void *dst, *src;
|
|
size_t length;
|
|
double bps = 0.0;
|
|
struct timeval tv_start, tv_end, tv_diff;
|
|
u64 clock_start, clock_end, clock_diff;
|
|
|
|
clock_start = clock_end = clock_diff = 0ULL;
|
|
argc = parse_options(argc, argv, options,
|
|
bench_mem_memcpy_usage, 0);
|
|
|
|
tv_diff.tv_sec = 0;
|
|
tv_diff.tv_usec = 0;
|
|
length = (size_t)perf_atoll((char *)length_str);
|
|
|
|
if ((s64)length <= 0) {
|
|
fprintf(stderr, "Invalid length:%s\n", length_str);
|
|
return 1;
|
|
}
|
|
|
|
for (i = 0; routines[i].name; i++) {
|
|
if (!strcmp(routines[i].name, routine))
|
|
break;
|
|
}
|
|
if (!routines[i].name) {
|
|
printf("Unknown routine:%s\n", routine);
|
|
printf("Available routines...\n");
|
|
for (i = 0; routines[i].name; i++) {
|
|
printf("\t%s ... %s\n",
|
|
routines[i].name, routines[i].desc);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
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");
|
|
|
|
if (bench_format == BENCH_FORMAT_DEFAULT) {
|
|
printf("# Copying %s Bytes from %p to %p ...\n\n",
|
|
length_str, src, dst);
|
|
}
|
|
|
|
if (use_clock) {
|
|
init_clock();
|
|
clock_start = get_clock();
|
|
} else {
|
|
BUG_ON(gettimeofday(&tv_start, NULL));
|
|
}
|
|
|
|
routines[i].fn(dst, src, length);
|
|
|
|
if (use_clock) {
|
|
clock_end = get_clock();
|
|
clock_diff = clock_end - clock_start;
|
|
} else {
|
|
BUG_ON(gettimeofday(&tv_end, NULL));
|
|
timersub(&tv_end, &tv_start, &tv_diff);
|
|
bps = (double)((double)length / timeval2double(&tv_diff));
|
|
}
|
|
|
|
switch (bench_format) {
|
|
case BENCH_FORMAT_DEFAULT:
|
|
if (use_clock) {
|
|
printf(" %14lf Clock/Byte\n",
|
|
(double)clock_diff / (double)length);
|
|
} else {
|
|
if (bps < K)
|
|
printf(" %14lf B/Sec\n", bps);
|
|
else if (bps < K * K)
|
|
printf(" %14lfd KB/Sec\n", bps / 1024);
|
|
else if (bps < K * K * K)
|
|
printf(" %14lf MB/Sec\n", bps / 1024 / 1024);
|
|
else {
|
|
printf(" %14lf GB/Sec\n",
|
|
bps / 1024 / 1024 / 1024);
|
|
}
|
|
}
|
|
break;
|
|
case BENCH_FORMAT_SIMPLE:
|
|
if (use_clock) {
|
|
printf("%14lf\n",
|
|
(double)clock_diff / (double)length);
|
|
} else
|
|
printf("%lf\n", bps);
|
|
break;
|
|
default:
|
|
/* reaching this means there's some disaster: */
|
|
die("unknown format: %d\n", bench_format);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|