static LIST_HEAD(map_devs); // List of device maps
static int nfiles = 0; // Number of files to handle
static int no_stalls = 0; // Boolean: Disable pre-stalls
+static unsigned acc_factor = 1; // Int: Acceleration factor
static int find_records = 0; // Boolean: Find record files auto
/*
*/
static void get_ncpus(void)
{
- cpu_set_t cpus;
-
- if (sched_getaffinity(getpid(), sizeof(cpus), &cpus)) {
+#ifdef _SC_NPROCESSORS_ONLN
+ ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+ int nrcpus = 4096;
+ cpu_set_t * cpus;
+
+realloc:
+ cpus = CPU_ALLOC(nrcpus);
+ size = CPU_ALLOC_SIZE(nrcpus);
+ CPU_ZERO_S(size, cpus);
+
+ if (sched_getaffinity(getpid(), size, cpus)) {
+ if( errno == EINVAL && nrcpus < (4096<<4) ) {
+ CPU_FREE(cpus);
+ nrcpus <<= 1;
+ goto realloc;
+ }
fatal("sched_getaffinity", ERR_SYSCALL, "Can't get CPU info\n");
/*NOTREACHED*/
}
- /*
- * XXX This assumes (perhaps wrongly) that there are no /holes/
- * XXX in the mask.
- */
- for (ncpus = 0; ncpus < CPU_SETSIZE && CPU_ISSET(ncpus, &cpus); ncpus++)
- ;
+ ncpus = -1;
+ for (last_cpu = 0; last_cpu < CPU_SETSIZE && CPU_ISSET(last_cpu, &cpus); last_cpu++)
+ if (CPU_ISSET( last_cpu, &cpus) )
+ ncpus = last_cpu;
+ ncpus++;
+ CPU_FREE(cpus);
+#endif
if (ncpus == 0) {
fatal(NULL, ERR_SYSCALL, "Insufficient number of CPUs\n");
/*NOTREACHED*/
*/
static void pin_to_cpu(struct thr_info *tip)
{
- cpu_set_t cpus;
+ cpu_set_t *cpus;
+ size_t size;
+
+ cpus = CPU_ALLOC(ncpus);
+ size = CPU_ALLOC_SIZE(ncpus);
assert(0 <= tip->cpu && tip->cpu < ncpus);
- CPU_ZERO(&cpus);
- CPU_SET(tip->cpu, &cpus);
- if (sched_setaffinity(getpid(), sizeof(cpus), &cpus)) {
+ CPU_ZERO_S(size, cpus);
+ CPU_SET_S(tip->cpu, size, cpus);
+ if (sched_setaffinity(getpid(), size, cpus)) {
fatal("sched_setaffinity", ERR_SYSCALL, "Failed to pin CPU\n");
/*NOTREACHED*/
}
if (verbose > 1) {
int i;
- cpu_set_t now;
+ cpu_set_t *now = CPU_ALLOC(ncpus);
- (void)sched_getaffinity(getpid(), sizeof(now), &now);
+ (void)sched_getaffinity(getpid(), size, now);
fprintf(tip->vfp, "Pinned to CPU %02d ", tip->cpu);
for (i = 0; i < ncpus; i++)
- fprintf(tip->vfp, "%1d", CPU_ISSET(i, &now));
+ fprintf(tip->vfp, "%1d", CPU_ISSET_S(i, size, now));
fprintf(tip->vfp, "\n");
}
}
}
while ((ent = readdir(dir)) != NULL) {
- char *p, *dsf = malloc(256);
+ char *p, *dsf;
if (strstr(ent->d_name, ".replay.") == NULL)
continue;
static void read_map_devs(char *file_name)
{
FILE *fp;
- char *from_dev, *to_dev;
+ char from_dev[256], to_dev[256];
fp = fopen(file_name, "r");
if (!fp) {
/*NOTREACHED*/
}
- while (fscanf(fp, "%as %as", &from_dev, &to_dev) == 2) {
+ while (fscanf(fp, "%s %s", from_dev, to_dev) == 2) {
struct map_dev *mdp = malloc(sizeof(*mdp));
mdp->from_dev = from_dev;
struct timespec req;
long long dreal, tclock = gettime() - rgenesis;
+ oclock /= acc_factor;
+
if (verbose > 1)
fprintf(tip->vfp, " stall(%lld.%09lld, %lld.%09lld)\n",
du64_to_sec(oclock), du64_to_nsec(oclock),
*/
static void *replay_sub(void *arg)
{
+ unsigned int i;
+ char *mdev;
char path[MAXPATHLEN];
struct io_bunch bunch;
struct thr_info *tip = arg;
+ int oflags;
pin_to_cpu(tip);
- sprintf(path, "/dev/%s", map_dev(tip->devnm));
- tip->ofd = open(path, O_RDWR | O_DIRECT);
+ mdev = map_dev(tip->devnm);
+ sprintf(path, "/dev/%s", mdev);
+ /*
+ * convert underscores to slashes to
+ * restore device names that have larger paths
+ */
+ for (i = 0; i < strlen(mdev); i++)
+ if (path[strlen("/dev/") + i] == '_')
+ path[strlen("/dev/") + i] = '/';
+#ifdef O_NOATIME
+ oflags = O_NOATIME;
+#else
+ oflags = 0;
+#endif
+ tip->ofd = open(path, O_RDWR | O_DIRECT | oflags);
if (tip->ofd < 0) {
fatal(path, ERR_SYSCALL, "Failed device open\n");
/*NOTREACHED*/
set_replay_ready();
while (!is_send_done(tip) && tip->iterations--) {
wait_iter_start();
- if (verbose)
+ if (verbose > 1)
fprintf(tip->vfp, "\n=== %d ===\n", tip->iterations);
while (!is_send_done(tip) && next_bunch(tip, &bunch))
process_bunch(tip, &bunch);
*/
static char usage_str[] = \
- "\n" \
+ "\n" \
"\t[ -c <cpus> : --cpus=<cpus> ] Default: 1\n" \
"\t[ -d <dir> : --input-directory=<dir> ] Default: .\n" \
- "\t[ -F : --find-records ] Default: Off\n" \
+ "\t[ -F : --find-records ] Default: Off\n" \
"\t[ -h : --help ] Default: Off\n" \
"\t[ -i <base> : --input-base=<base> ] Default: replay\n" \
"\t[ -I <iters>: --iterations=<iters> ] Default: 1\n" \
"\t[ -M <file> : --map-devs=<file> ] Default: None\n" \
"\t[ -N : --no-stalls ] Default: Off\n" \
+ "\t[ -x : --acc-factor ] Default: 1\n" \
"\t[ -v : --verbose ] Default: Off\n" \
"\t[ -V : --version ] Default: Off\n" \
"\t[ -W : --write-enable ] Default: Off\n" \
"\t<dev...> Default: None\n" \
"\n";
-#define S_OPTS "c:d:Fhi:I:M:Nt:vVW"
+#define S_OPTS "c:d:Fhi:I:M:Nx:t:vVW"
static struct option l_opts[] = {
{
.name = "cpus",
.flag = NULL,
.val = 'N'
},
+ {
+ .name = "acc-factor",
+ .has_arg = required_argument,
+ .flag = NULL,
+ .val = 'x'
+ },
{
.name = "verbose",
.has_arg = no_argument,
static void handle_args(int argc, char *argv[])
{
int c;
+ int r;
while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) != -1) {
switch (c) {
no_stalls = 1;
break;
+ case 'x':
+ r = sscanf(optarg,"%u",&acc_factor);
+ if (r!=1) {
+ fprintf(stderr,
+ "Invalid acceleration factor\n");
+ exit(ERR_ARGS);
+ /*NOTREACHED*/
+ }
+ break;
+
case 'V':
fprintf(stderr, "btreplay -- version %s\n",
my_btversion);