Skip to content

Commit

Permalink
f3probe: add option --time-ops
Browse files Browse the repository at this point in the history
In order to reduce probing time, one needs to time
reads, writes, and resets to evaluate how to change
the probing algorithm.
This patch adds these measurements.

A good 256MB drive produced the following measurements:
Probe time: 47.57 seconds
Probe read op: count=2014, total time=1.72s, avg op time=0.85ms
Probe write op: count=2003, total time=45.32s, avg op time=22.62ms
Probe reset op: count=3, total time=0.53s, avg op time=175.66ms
  • Loading branch information
AltraMayor committed Sep 25, 2014
1 parent a952fb7 commit 46a7f24
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 2 deletions.
47 changes: 45 additions & 2 deletions f3probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ static struct argp_option options[] = {
"Trade speed for less use of memory", 0},
{"manual-reset", 'm', NULL, 0,
"Ask user to manually reset the drive", 0},
{"time-ops", 't', NULL, 0,
"Time reads, writes, and resets", 0},
{ 0 }
};

Expand All @@ -62,7 +64,8 @@ struct args {
bool save;
bool min_mem;
bool manual_reset;
/* 2 free bytes. */
bool time_ops;
/* 1 free bytes. */

/* Geometry. */
uint64_t real_size_byte;
Expand Down Expand Up @@ -150,6 +153,10 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
args->manual_reset = true;
break;

case 't':
args->time_ops = true;
break;

case ARGP_KEY_INIT:
args->filename = NULL;
break;
Expand Down Expand Up @@ -294,14 +301,24 @@ static void report_order(const char *prefix, int order)
printf("%s %.2f %s (2^%i Byte)\n", prefix, f, unit, order);
}

static void report_ops(const char *op, uint64_t count, uint64_t time_us)
{
printf("Probe %s op: count=%" PRIu64
", total time=%.2fs, avg op time=%.2fms\n",
op, count, time_us / 1e6, (time_us / count) / 1e3);
}

static int test_device(struct args *args)
{
struct timeval t1, t2;
double time_s;
struct device *dev;
struct device *dev, *pdev;
enum fake_type fake_type;
uint64_t real_size_byte, announced_size_byte;
int wrap, block_order;
uint64_t read_count, read_time_us;
uint64_t write_count, write_time_us;
uint64_t reset_count, reset_time_us;

dev = args->debug
? create_file_device(args->filename, args->real_size_byte,
Expand All @@ -310,6 +327,14 @@ static int test_device(struct args *args)
: create_block_device(args->filename, args->manual_reset);
assert(dev);

if (args->time_ops) {
pdev = create_perf_device(dev);
assert(pdev);
dev = pdev;
} else {
pdev = NULL;
}

if (args->save) {
dev = create_safe_device(dev, probe_device_max_blocks(dev),
args->min_mem);
Expand All @@ -333,7 +358,18 @@ static int test_device(struct args *args)
* make sure that the written blocks are recovered when
* @args->save is true.
*/
if (args->time_ops)
perf_device_sample(pdev,
&read_count, &read_time_us,
&write_count, &write_time_us,
&reset_count, &reset_time_us);
if (args->save) {
printf("Probe finished, recovering blocks...");
fflush(stdout);
}
free_device(dev);
if (args->save)
printf(" Done\n\n");

fake_type = dev_param_to_type(real_size_byte, announced_size_byte,
wrap, block_order);
Expand Down Expand Up @@ -363,6 +399,12 @@ static int test_device(struct args *args)
report_order("\t Module:", wrap);
report_order("\t Block size:", block_order);
printf("\nProbe time: %.2f seconds\n", time_s);

if (args->time_ops) {
report_ops("read", read_count, read_time_us);
report_ops("write", write_count, write_time_us);
report_ops("reset", reset_count, reset_time_us);
}
return 0;
}

Expand All @@ -376,6 +418,7 @@ int main(int argc, char **argv)
.save = true,
.min_mem = false,
.manual_reset = false,
.time_ops = false,
.real_size_byte = 1ULL << 31,
.fake_size_byte = 1ULL << 34,
.wrap = 31,
Expand Down
128 changes: 128 additions & 0 deletions libprobe.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
Expand Down Expand Up @@ -536,6 +537,133 @@ struct device *create_block_device(const char *filename, int manual_reset)
return NULL;
}

struct perf_device {
/* This must be the first field. See dev_pdev() for details. */
struct device dev;

struct device *shadow_dev;

uint64_t read_count;
uint64_t read_time_us;
uint64_t write_count;
uint64_t write_time_us;
uint64_t reset_count;
uint64_t reset_time_us;
};

static inline struct perf_device *dev_pdev(struct device *dev)
{
return (struct perf_device *)dev;
}

static inline uint64_t diff_timeval_us(const struct timeval *t1,
const struct timeval *t2)
{
return (t2->tv_sec - t1->tv_sec) * 1000000ULL +
t2->tv_usec - t1->tv_usec;
}

static int pdev_read_block(struct device *dev, char *buf, int length,
uint64_t offset)
{
struct perf_device *pdev = dev_pdev(dev);
struct timeval t1, t2;
int rc;

assert(!gettimeofday(&t1, NULL));
rc = pdev->shadow_dev->read_block(pdev->shadow_dev, buf,
length, offset);
assert(!gettimeofday(&t2, NULL));
pdev->read_count++;
pdev->read_time_us += diff_timeval_us(&t1, &t2);
return rc;
}

static int pdev_write_block(struct device *dev, const char *buf, int length,
uint64_t offset)
{
struct perf_device *pdev = dev_pdev(dev);
struct timeval t1, t2;
int rc;

assert(!gettimeofday(&t1, NULL));
rc = pdev->shadow_dev->write_block(pdev->shadow_dev, buf,
length, offset);
assert(!gettimeofday(&t2, NULL));
pdev->write_count++;
pdev->write_time_us += diff_timeval_us(&t1, &t2);
return rc;
}

static int pdev_reset(struct device *dev)
{
struct perf_device *pdev = dev_pdev(dev);
struct timeval t1, t2;
int rc;

assert(!gettimeofday(&t1, NULL));
rc = dev_reset(pdev->shadow_dev);
assert(!gettimeofday(&t2, NULL));
pdev->reset_count++;
pdev->reset_time_us += diff_timeval_us(&t1, &t2);
return rc;
}

static void pdev_free(struct device *dev)
{
struct perf_device *pdev = dev_pdev(dev);
free_device(pdev->shadow_dev);
}

struct device *create_perf_device(struct device *dev)
{
struct perf_device *pdev;

pdev = malloc(sizeof(*pdev));
if (!pdev)
return NULL;

pdev->shadow_dev = dev;
pdev->read_count = 0;
pdev->read_time_us = 0;
pdev->write_count = 0;
pdev->write_time_us = 0;
pdev->reset_count = 0;
pdev->reset_time_us = 0;

pdev->dev.size_byte = dev->size_byte;
pdev->dev.block_order = dev->block_order;
pdev->dev.read_block = pdev_read_block;
pdev->dev.write_block = pdev_write_block;
pdev->dev.reset = pdev_reset;
pdev->dev.free = pdev_free;

return &pdev->dev;
}

void perf_device_sample(struct device *dev,
uint64_t *pread_count, uint64_t *pread_time_us,
uint64_t *pwrite_count, uint64_t *pwrite_time_us,
uint64_t *preset_count, uint64_t *preset_time_us)
{
struct perf_device *pdev = dev_pdev(dev);

if (pread_count)
*pread_count = pdev->read_count;
if (pread_time_us)
*pread_time_us = pdev->read_time_us;

if (pwrite_count)
*pwrite_count = pdev->write_count;
if (pwrite_time_us)
*pwrite_time_us = pdev->write_time_us;

if (preset_count)
*preset_count = pdev->reset_count;
if (preset_time_us)
*preset_time_us = pdev->reset_time_us;
}

#define SDEV_BITMAP_WORD long
#define SDEV_BITMAP_BITS_PER_WORD (8*sizeof(SDEV_BITMAP_WORD))
struct safe_device {
Expand Down
6 changes: 6 additions & 0 deletions libprobe.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ struct device *create_file_device(const char *filename,

struct device *create_block_device(const char *filename, int manual_reset);

struct device *create_perf_device(struct device *dev);
void perf_device_sample(struct device *dev,
uint64_t *pread_count, uint64_t *pread_time_us,
uint64_t *pwrite_count, uint64_t *pwrite_time_us,
uint64_t *preset_count, uint64_t *preset_time_us);

struct device *create_safe_device(struct device *dev, int max_blocks,
int min_memory);

Expand Down

0 comments on commit 46a7f24

Please sign in to comment.