Skip to content

Commit

Permalink
SA: Initial drop.
Browse files Browse the repository at this point in the history
Initial drop of the sources and a basic README.

Signed-off-by: Andrei Warkentin <andrey.warkentin@gmail.com>
  • Loading branch information
andreiw committed Apr 15, 2011
1 parent 6d14b4f commit 83d5ec2
Show file tree
Hide file tree
Showing 6 changed files with 611 additions and 0 deletions.
14 changes: 14 additions & 0 deletions Android.mk
@@ -0,0 +1,14 @@

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := sa
LOCAL_MODULE_TAGS := eng

LOCAL_SRC_FILES := \
sa.c dev.c

#LOCAL_STATIC_LIBRARIES := libc
#LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
12 changes: 12 additions & 0 deletions Makefile
@@ -0,0 +1,12 @@
CC := gcc
CFLAGS := -O2 -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter -g2
LDFLAGS := -lrt -lm

all: sa

sa: sa.o dev.o
sa.o: sa.c dev.h
dev.o: dev.c dev.h

clean:
rm sa sa.o dev.o vm.o
58 changes: 58 additions & 0 deletions README
@@ -0,0 +1,58 @@
Superalign
==========

A tool to measure read/write performance for block devices.
It performs direct (unaffected by cache or filesystem) block transfers
(reads or writes) linearly or "randomly" (LFSR) while collecting timing
statistics on the transfers. You get min time/max time/avg time and standard
deviation, so you can perform better analysis of the received data. It has
tunable parameters such as aligning a transfer on a particular boundary,
adding an offset to that alignment, or doing a discard on the device
prior to transfers.

The tool originally started out as an addition to Arnd Bergmann's
excellent flashbench tool - git://git.linaro.org/people/arnd/flashbench.git

It's a bit rough, and hopefully I'll have the time to clean up the code a
bit soon.

Examples
========

Test 512-byte writes aligned to 4k.

sa -s 512 -a 4096 /dev/mmcblk0p15

Test 1024-byte writes straddling 8k boundary.

sa -s 1024 -a 8192 -o 7680 /dev/mmcblk0p15

Test 8k reads.

sa -s 8192 -d /dev/mmcblk0p15

Test maximum 1000 different 8k writes (as opposite to as many as can
fit in the device)

sa -s 8192 -c 1000 /dev/mmcblk0p15

Repeat above test five times, blk erasing the device before each repeat.

sa -s 8192 -c 1000 -r 5 -e /dev/mmcblk0p15

Use LFSR ("random") instead of sequential access.

sa -s 8192 -R /dev/mmcblk0p15

Print verbose info.

sa -v -s 8192 /dev/mmcblk0p15

Print really verbose info.

sa -v -v -s 8192 /dev/mmcblk0p15

Contact Info
============

Andrei Warkentin (andrey.warkentin@gmail.com, andreiw@motorola.com)
182 changes: 182 additions & 0 deletions dev.c
@@ -0,0 +1,182 @@
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <sched.h>
#include <string.h>
#include <getopt.h>
#include <stdbool.h>

#include <linux/fs.h>

#ifndef BLKDISCARD
#define BLKDISCARD _IO(0x12,119)
#endif

#include "dev.h"

#define MAX_BUFSIZE (64 * 1024 * 1024)

static inline long long time_to_ns(struct timespec *ts)
{
return ((long long) ts->tv_sec) * 1000 * 1000 * 1000 + ts->tv_nsec;
}

static long long get_ns(void)
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return time_to_ns(&ts);
}

#if !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
int posix_memalign(void **memptr, size_t alignment, size_t size)
{
void *ptr;

if (alignment % sizeof(void *))
return EINVAL;

ptr = memalign(alignment, size);
if (!ptr)
return ENOMEM;

*memptr = ptr;
return 0;
}
#endif


long long time_read(struct device *dev, off_t pos, size_t size)
{
long long now = get_ns();
ssize_t ret;

if (size > MAX_BUFSIZE)
return -ENOMEM;

do {
ret = pread(dev->fd, dev->readbuf, size, (unsigned long long) pos % dev->size);
if (ret > 0) {
size -= ret;
pos += ret;
}
} while (ret > 0 || errno == -EAGAIN);

if (ret) {
perror("time_read");
return 0;
}

return get_ns() - now;
}

long long time_write(struct device *dev, off_t pos, size_t size, enum writebuf which)
{
long long now = get_ns();
ssize_t ret;
unsigned long *p;

if (size > MAX_BUFSIZE)
return -ENOMEM;
p = dev->writebuf[which];

do {
ret = pwrite(dev->fd, p, size, (unsigned long long) pos % dev->size);
if (ret > 0) {
size -= ret;
pos += ret;
}
} while (ret > 0 || errno == -EAGAIN);

if (ret) {
perror("time_write");
return 0;
}

return get_ns() - now;
}

long long time_erase(struct device *dev, off_t pos, size_t size)
{
long long now = get_ns();
ssize_t ret;
unsigned long long args[2] = { size, pos % dev->size };

if (size > MAX_BUFSIZE)
return -ENOMEM;

ret = ioctl(dev->fd, BLKDISCARD, &args);

if (ret) {
perror("time_erase");
}

return get_ns() - now;
}

static void set_rtprio(void)
{
int ret;
struct sched_param p = {
.sched_priority = 10,
};
ret = sched_setscheduler(0, SCHED_FIFO, &p);
if (ret)
perror("sched_setscheduler");
}


int setup_dev(struct device *dev, const char *filename)
{
int err;
void *p;
set_rtprio();

dev->fd = open(filename, O_RDWR | O_DIRECT | O_SYNC | O_NOATIME);
if (dev->fd < 0) {
perror(filename);
return -errno;
}

dev->size = lseek(dev->fd, 0, SEEK_END);
if (dev->size < 0) {
perror("seek");
return -errno;
}

err = posix_memalign(&dev->readbuf, 4096, MAX_BUFSIZE);
if (err)
return -err;

err = posix_memalign(&p, 4096, MAX_BUFSIZE);
if (err)
return -err;
memset(p, 0, MAX_BUFSIZE);
dev->writebuf[WBUF_ZERO] = p;

err = posix_memalign(&p, 4096, MAX_BUFSIZE);
if (err)
return -err;
memset(p, 0xff, MAX_BUFSIZE);
dev->writebuf[WBUF_ONE] = p;

err = posix_memalign(&p , 4096, MAX_BUFSIZE);
if (err)
return -err;
memset(p, 0x5a, MAX_BUFSIZE);
dev->writebuf[WBUF_RAND] = p;

return 0;
}
27 changes: 27 additions & 0 deletions dev.h
@@ -0,0 +1,27 @@
#ifndef FLASHBENCH_DEV_H
#define FLASHBENCH_DEV_H

#include <unistd.h>

struct device {
void *readbuf;
void *writebuf[3];
int fd;
off_t size;
};

enum writebuf {
WBUF_ZERO,
WBUF_ONE,
WBUF_RAND,
};

extern int setup_dev(struct device *dev, const char *filename);

long long time_write(struct device *dev, off_t pos, size_t size, enum writebuf which);

long long time_read(struct device *dev, off_t pos, size_t size);

long long time_erase(struct device *dev, off_t pos, size_t size);

#endif /* FLASHBENCH_DEV_H */

0 comments on commit 83d5ec2

Please sign in to comment.