mirror of
https://github.com/AltraMayor/f3.git
synced 2025-09-09 23:27:52 -04:00
f3probe: add option --time-ops
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
This commit is contained in:
parent
a952fb7244
commit
46a7f24638
47
f3probe.c
47
f3probe.c
@ -47,6 +47,8 @@ static struct argp_option options[] = {
|
|||||||
"Trade speed for less use of memory", 0},
|
"Trade speed for less use of memory", 0},
|
||||||
{"manual-reset", 'm', NULL, 0,
|
{"manual-reset", 'm', NULL, 0,
|
||||||
"Ask user to manually reset the drive", 0},
|
"Ask user to manually reset the drive", 0},
|
||||||
|
{"time-ops", 't', NULL, 0,
|
||||||
|
"Time reads, writes, and resets", 0},
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -62,7 +64,8 @@ struct args {
|
|||||||
bool save;
|
bool save;
|
||||||
bool min_mem;
|
bool min_mem;
|
||||||
bool manual_reset;
|
bool manual_reset;
|
||||||
/* 2 free bytes. */
|
bool time_ops;
|
||||||
|
/* 1 free bytes. */
|
||||||
|
|
||||||
/* Geometry. */
|
/* Geometry. */
|
||||||
uint64_t real_size_byte;
|
uint64_t real_size_byte;
|
||||||
@ -150,6 +153,10 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
|||||||
args->manual_reset = true;
|
args->manual_reset = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
args->time_ops = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case ARGP_KEY_INIT:
|
case ARGP_KEY_INIT:
|
||||||
args->filename = NULL;
|
args->filename = NULL;
|
||||||
break;
|
break;
|
||||||
@ -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);
|
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)
|
static int test_device(struct args *args)
|
||||||
{
|
{
|
||||||
struct timeval t1, t2;
|
struct timeval t1, t2;
|
||||||
double time_s;
|
double time_s;
|
||||||
struct device *dev;
|
struct device *dev, *pdev;
|
||||||
enum fake_type fake_type;
|
enum fake_type fake_type;
|
||||||
uint64_t real_size_byte, announced_size_byte;
|
uint64_t real_size_byte, announced_size_byte;
|
||||||
int wrap, block_order;
|
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
|
dev = args->debug
|
||||||
? create_file_device(args->filename, args->real_size_byte,
|
? create_file_device(args->filename, args->real_size_byte,
|
||||||
@ -310,6 +327,14 @@ static int test_device(struct args *args)
|
|||||||
: create_block_device(args->filename, args->manual_reset);
|
: create_block_device(args->filename, args->manual_reset);
|
||||||
assert(dev);
|
assert(dev);
|
||||||
|
|
||||||
|
if (args->time_ops) {
|
||||||
|
pdev = create_perf_device(dev);
|
||||||
|
assert(pdev);
|
||||||
|
dev = pdev;
|
||||||
|
} else {
|
||||||
|
pdev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (args->save) {
|
if (args->save) {
|
||||||
dev = create_safe_device(dev, probe_device_max_blocks(dev),
|
dev = create_safe_device(dev, probe_device_max_blocks(dev),
|
||||||
args->min_mem);
|
args->min_mem);
|
||||||
@ -333,7 +358,18 @@ static int test_device(struct args *args)
|
|||||||
* make sure that the written blocks are recovered when
|
* make sure that the written blocks are recovered when
|
||||||
* @args->save is true.
|
* @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);
|
free_device(dev);
|
||||||
|
if (args->save)
|
||||||
|
printf(" Done\n\n");
|
||||||
|
|
||||||
fake_type = dev_param_to_type(real_size_byte, announced_size_byte,
|
fake_type = dev_param_to_type(real_size_byte, announced_size_byte,
|
||||||
wrap, block_order);
|
wrap, block_order);
|
||||||
@ -363,6 +399,12 @@ static int test_device(struct args *args)
|
|||||||
report_order("\t Module:", wrap);
|
report_order("\t Module:", wrap);
|
||||||
report_order("\t Block size:", block_order);
|
report_order("\t Block size:", block_order);
|
||||||
printf("\nProbe time: %.2f seconds\n", time_s);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,6 +418,7 @@ int main(int argc, char **argv)
|
|||||||
.save = true,
|
.save = true,
|
||||||
.min_mem = false,
|
.min_mem = false,
|
||||||
.manual_reset = false,
|
.manual_reset = false,
|
||||||
|
.time_ops = false,
|
||||||
.real_size_byte = 1ULL << 31,
|
.real_size_byte = 1ULL << 31,
|
||||||
.fake_size_byte = 1ULL << 34,
|
.fake_size_byte = 1ULL << 34,
|
||||||
.wrap = 31,
|
.wrap = 31,
|
||||||
|
128
libprobe.c
128
libprobe.c
@ -10,6 +10,7 @@
|
|||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/time.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -536,6 +537,133 @@ error:
|
|||||||
return NULL;
|
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_WORD long
|
||||||
#define SDEV_BITMAP_BITS_PER_WORD (8*sizeof(SDEV_BITMAP_WORD))
|
#define SDEV_BITMAP_BITS_PER_WORD (8*sizeof(SDEV_BITMAP_WORD))
|
||||||
struct safe_device {
|
struct safe_device {
|
||||||
|
@ -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_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,
|
struct device *create_safe_device(struct device *dev, int max_blocks,
|
||||||
int min_memory);
|
int min_memory);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user