Commit cda3a55c authored by Bas Zoetekouw's avatar Bas Zoetekouw Committed by Dmitry Smirnov

Imported Debian snapshot 1.0.1-1

parent a9e4ac1f
CC = gcc
CFLAGS = -Wall -O2 -g -W
ALL_CFLAGS = $(CFLAGS) -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
PROGS = blkparse blktrace verify_blkparse blkrawverify
PROGS = blkparse blktrace verify_blkparse blkrawverify blkiomon
LIBS = -lpthread
SCRIPTS = btrace
......@@ -34,6 +34,9 @@ verify_blkparse: verify_blkparse.o
blkrawverify: blkrawverify.o
$(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^)
blkiomon: blkiomon.o rbtree.o
$(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^) $(LIBS) -lrt
$(PROGS): | depend
docs:
......
......@@ -23,8 +23,11 @@ static struct mask_map mask_maps[] = {
DECLARE_MASK_MAP(COMPLETE),
DECLARE_MASK_MAP(FS),
DECLARE_MASK_MAP(PC),
DECLARE_MASK_MAP(NOTIFY),
DECLARE_MASK_MAP(AHEAD),
DECLARE_MASK_MAP(META),
DECLARE_MASK_MAP(DISCARD),
DECLARE_MASK_MAP(DRV_DATA),
};
int find_mask_map(char *string)
......
This diff is collapsed.
/*
* I/O monitor based on block queue trace data
*
* Copyright IBM Corp. 2008
*
* Author(s): Martin Peschke <mp3@de.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef BLKIOMON_H
#define BLKIOMON_H
#include <string.h>
#include "stats.h"
#include "blktrace.h"
#define BLKIOMON_SIZE_BUCKETS 16
#define BLKIOMON_D2C_BUCKETS 25
struct blkiomon_stat {
__u64 time;
__u32 size_hist[BLKIOMON_SIZE_BUCKETS];
__u32 d2c_hist[BLKIOMON_D2C_BUCKETS];
__u32 device;
struct minmax size_r;
struct minmax size_w;
struct minmax d2c_r;
struct minmax d2c_w;
struct minmax thrput_r;
struct minmax thrput_w;
__u64 bidir;
};
static struct histlog2 size_hist = {
.first = 0,
.delta = 1024,
.num = BLKIOMON_SIZE_BUCKETS
};
static struct histlog2 d2c_hist = {
.first = 0,
.delta = 8,
.num = BLKIOMON_D2C_BUCKETS
};
static inline void blkiomon_stat_init(struct blkiomon_stat *bstat)
{
memset(bstat, 0, sizeof(*bstat));
minmax_init(&bstat->size_r);
minmax_init(&bstat->size_w);
minmax_init(&bstat->d2c_r);
minmax_init(&bstat->d2c_w);
minmax_init(&bstat->thrput_r);
minmax_init(&bstat->thrput_w);
}
static inline void blkiomon_stat_to_be(struct blkiomon_stat *bstat)
{
histlog2_to_be(bstat->size_hist, &size_hist);
histlog2_to_be(bstat->d2c_hist, &d2c_hist);
minmax_to_be(&bstat->size_r);
minmax_to_be(&bstat->size_w);
minmax_to_be(&bstat->d2c_r);
minmax_to_be(&bstat->d2c_w);
minmax_to_be(&bstat->thrput_r);
minmax_to_be(&bstat->thrput_w);
bstat->bidir = cpu_to_be64(bstat->bidir);
bstat->time = cpu_to_be64(bstat->time);
bstat->device = cpu_to_be32(bstat->device);
}
static inline void blkiomon_stat_merge(struct blkiomon_stat *dst,
struct blkiomon_stat *src)
{
histlog2_merge(&size_hist, dst->size_hist, src->size_hist);
histlog2_merge(&d2c_hist, dst->d2c_hist, src->d2c_hist);
minmax_merge(&dst->size_r, &src->size_r);
minmax_merge(&dst->size_w, &src->size_w);
minmax_merge(&dst->d2c_r, &src->d2c_r);
minmax_merge(&dst->d2c_w, &src->d2c_w);
minmax_merge(&dst->thrput_r, &src->thrput_r);
minmax_merge(&dst->thrput_w, &src->thrput_w);
dst->bidir += src->bidir;
}
static inline void blkiomon_stat_print(FILE *fp, struct blkiomon_stat *p)
{
if (!fp)
return;
fprintf(fp, "\ntime: %s", ctime((void *)&p->time));
fprintf(fp, "device: %d,%d\n", MAJOR(p->device), MINOR(p->device));
minmax_print(fp, "sizes read (bytes)", &p->size_r);
minmax_print(fp, "sizes write (bytes)", &p->size_w);
minmax_print(fp, "d2c read (usec)", &p->d2c_r);
minmax_print(fp, "d2c write (usec)", &p->d2c_w);
minmax_print(fp, "throughput read (bytes/msec)", &p->thrput_r);
minmax_print(fp, "throughput write (bytes/msec)", &p->thrput_w);
histlog2_print(fp, "sizes histogram (bytes)", p->size_hist, &size_hist);
histlog2_print(fp, "d2c histogram (usec)", p->d2c_hist, &d2c_hist);
fprintf(fp, "bidirectional requests: %ld\n", (unsigned long)p->bidir);
}
#endif
This diff is collapsed.
......@@ -44,10 +44,6 @@ int add_format_spec(char *option)
return 1;
}
option += 2;
if (*option == '\0') {
fprintf(stderr,"Bad format specifier - need fmt %s\n", option);
return 1;
}
override_format[spec] = strdup(option);
......@@ -61,9 +57,12 @@ static inline void fill_rwbs(char *rwbs, struct blk_io_trace *t)
int b = t->action & BLK_TC_ACT(BLK_TC_BARRIER);
int s = t->action & BLK_TC_ACT(BLK_TC_SYNC);
int m = t->action & BLK_TC_ACT(BLK_TC_META);
int d = t->action & BLK_TC_ACT(BLK_TC_DISCARD);
int i = 0;
if (w)
if (d)
rwbs[i++] = 'D';
else if (w)
rwbs[i++] = 'W';
else if (t->bytes)
rwbs[i++] = 'R';
......@@ -153,11 +152,11 @@ static unsigned int get_pdu_int(struct blk_io_trace *t)
static void get_pdu_remap(struct blk_io_trace *t, struct blk_io_trace_remap *r)
{
struct blk_io_trace_remap *__r = pdu_start(t);
__u64 sector = __r->sector;
__u64 sector_from = __r->sector_from;
r->device = be32_to_cpu(__r->device);
r->device_from = be32_to_cpu(__r->device_from);
r->sector = be64_to_cpu(sector);
r->device_to = be32_to_cpu(__r->device_to);
r->sector_from = be64_to_cpu(sector_from);
}
static void print_field(char *act, struct per_cpu_info *pci,
......@@ -285,20 +284,24 @@ static void process_default(char *act, struct per_cpu_info *pci,
struct blk_io_trace *t, unsigned long long elapsed,
int pdu_len, unsigned char *pdu_buf)
{
struct blk_io_trace_remap r = { .device = 0, };
struct blk_io_trace_remap r = { .device_from = 0, };
char rwbs[6];
char *name;
fill_rwbs(rwbs, t);
/*
* For remaps we have to modify the device using the remap structure
* passed up.
*/
if (act[0] == 'A') {
get_pdu_remap(t, &r);
t->device = r.device_to;
}
/*
* The header is always the same
*/
if (act[0] == 'A') { /* Remap */
get_pdu_remap(t, &r);
t->device = r.device_from;
}
fprintf(ofp, "%3d,%-3d %2d %8d %5d.%09lu %5u %2s %3s ",
MAJOR(t->device), MINOR(t->device), pci->cpu, t->sequence,
(int) SECONDS(t->time), (unsigned long) NANO_SECONDS(t->time),
......@@ -389,17 +392,22 @@ static void process_default(char *act, struct per_cpu_info *pci,
break;
case 'A': /* remap */
get_pdu_remap(t, &r);
fprintf(ofp, "%llu + %u <- (%d,%d) %llu\n",
(unsigned long long) t->sector, t_sec(t),
MAJOR(r.device), MINOR(r.device),
(unsigned long long) r.sector);
MAJOR(r.device_from), MINOR(r.device_from),
(unsigned long long) r.sector_from);
break;
case 'X': /* Split */
fprintf(ofp, "%llu / %u [%s]\n", (unsigned long long) t->sector,
get_pdu_int(t), name);
break;
case 'm': /* Message */
fprintf(ofp, "%*s\n", pdu_len, pdu_buf);
break;
default:
fprintf(stderr, "Unknown action %c\n", act[0]);
break;
......
......@@ -49,6 +49,7 @@ static struct trace_info traces[] = {
TRACE_TO_STRING( BLK_TC_PC ),
TRACE_TO_STRING( BLK_TC_AHEAD ),
TRACE_TO_STRING( BLK_TC_META ),
TRACE_TO_STRING( BLK_TC_DISCARD ),
};
#define N_TRACES (sizeof(traces) / sizeof(struct trace_info))
......@@ -295,8 +296,14 @@ int main(int argc, char *argv[])
printf("Verifying %s\n", devname); fflush(stdout);
for (cpu = 0; ; cpu++) {
sprintf(fname, "%s.blktrace.%d", devname, cpu);
if (stat(fname, &st) < 0)
if (stat(fname, &st) < 0) {
if (cpu == 0) {
fprintf(stderr, "No tracefiles found for %s\n",
devname);
rval = 1;
}
break;
}
printf(" CPU %d ", cpu); fflush(stdout);
nbad = process(&ofp, devname, fname, cpu);
if (nbad) {
......
This diff is collapsed.
......@@ -32,6 +32,9 @@ struct io_stats {
unsigned long long qread_kb, qwrite_kb, cread_kb, cwrite_kb;
unsigned long long iread_kb, iwrite_kb;
unsigned long long mread_kb, mwrite_kb;
unsigned long qreads_pc, qwrites_pc, ireads_pc, iwrites_pc;
unsigned long rrqueue_pc, wrqueue_pc, creads_pc, cwrites_pc;
unsigned long long qread_kb_pc, qwrite_kb_pc, iread_kb_pc, iwrite_kb_pc;
unsigned long io_unplugs, timer_unplugs;
};
......
......@@ -20,6 +20,8 @@ enum {
BLK_TC_NOTIFY = 1 << 10, /* special message */
BLK_TC_AHEAD = 1 << 11, /* readahead */
BLK_TC_META = 1 << 12, /* metadata */
BLK_TC_DISCARD = 1 << 13, /* discard requests */
BLK_TC_DRV_DATA = 1 << 14, /* binary driver data */
BLK_TC_END = 1 << 15, /* only 16-bits, reminder */
};
......@@ -46,6 +48,8 @@ enum {
__BLK_TA_SPLIT, /* bio was split */
__BLK_TA_BOUNCE, /* bio was bounced */
__BLK_TA_REMAP, /* bio was remapped */
__BLK_TA_ABORT, /* request aborted */
__BLK_TA_DRV_DATA, /* binary driver data */
};
/*
......@@ -54,6 +58,7 @@ enum {
enum blktrace_notify {
__BLK_TN_PROCESS = 0, /* establish pid/name mapping */
__BLK_TN_TIMESTAMP, /* include system clock */
__BLK_TN_MESSAGE, /* Character string message */
};
/*
......@@ -74,9 +79,12 @@ enum blktrace_notify {
#define BLK_TA_SPLIT (__BLK_TA_SPLIT)
#define BLK_TA_BOUNCE (__BLK_TA_BOUNCE)
#define BLK_TA_REMAP (__BLK_TA_REMAP | BLK_TC_ACT(BLK_TC_QUEUE))
#define BLK_TA_ABORT (__BLK_TA_ABORT | BLK_TC_ACT(BLK_TC_QUEUE))
#define BLK_TA_DRV_DATA (__BLK_TA_DRV_DATA | BLK_TC_ACT(BLK_TC_DRV_DATA))
#define BLK_TN_PROCESS (__BLK_TN_PROCESS | BLK_TC_ACT(BLK_TC_NOTIFY))
#define BLK_TN_TIMESTAMP (__BLK_TN_TIMESTAMP | BLK_TC_ACT(BLK_TC_NOTIFY))
#define BLK_TN_MESSAGE (__BLK_TN_MESSAGE | BLK_TC_ACT(BLK_TC_NOTIFY))
#define BLK_IO_TRACE_MAGIC 0x65617400
#define BLK_IO_TRACE_VERSION 0x07
......@@ -102,9 +110,9 @@ struct blk_io_trace {
* The remap event
*/
struct blk_io_trace_remap {
__u32 device;
__u32 device_from;
__u64 sector;
__u32 device_to;
__u64 sector_from;
};
/*
......
......@@ -8,11 +8,10 @@
TRACEOPTS=""
PARSEOPTS="-b100000"
SUMMARIZE=""
USAGE="Usage: btrace [-s] [-t] [-S] [-w N] [-a <trace>...] [-r <dbg mnt]<dev>..."
USAGE="Usage: btrace [-s] [-t] [-w N] [-n N] [-b N] [-a <trace>...] [-r <dbg mnt>] <dev>..."
DIRNAME=`dirname $0`
while getopts "a:r:stSw:hv" c
while getopts "a:w:n:b:r:sthv" c
do
case $c in
a) TRACEOPTS=$TRACEOPTS" -a "$OPTARG" ";;
......@@ -24,13 +23,11 @@ do
t) PARSEOPTS=$PARSEOPTS" -t";;
h) PARSEOPTS=$PARSEOPTS" -h";;
v) PARSEOPTS=$PARSEOPTS" -v";;
S) SUMMARIZE="";;
\?) echo $USAGE 1>&2
exit 2
;;
esac
done
PARSEOPTS="${PARSEOPTS} ${SUMMARIZE}"
shift `expr $OPTIND - 1`
if [ $# -eq 0 ]; then
......
......@@ -48,6 +48,7 @@ rm -rf $RPM_BUILD_ROOT
%defattr(-,root,root)
%doc README doc/blktrace.pdf
/usr/bin/*
/usr/man/*
%changelog -n btrace
* Mon Oct 10 2005 - axboe@suse.de
......
......@@ -32,7 +32,7 @@ clean: docsclean
$(CC) $(CFLAGS) -c -o $*.o $<
btrecord: btrecord.o
$(CC) $(CFLAGS) -o $@ $(filter %.o,$^) $(LIBS)
$(CC) $(CFLAGS) -o $@ $(filter %.o,$^)
btreplay: btreplay.o
$(CC) $(CFLAGS) -o $@ $(filter %.o,$^) $(LIBS)
......
......@@ -152,7 +152,7 @@ static struct option l_opts[] = {
.val = 'm'
},
{
.name = "max_pkts",
.name = "max-pkts",
.has_arg = required_argument,
.flag = NULL,
.val = 'M'
......
......@@ -87,9 +87,9 @@ static inline void get_btversion(__u64 version, int *mjr, int *mnr, int *sub)
*sub = (int)((version >> 0) & 0xff);
}
static char my_btversion[] = "0.9.3";
static int btver_mjr = 0;
static int btver_mnr = 9;
static int btver_sub = 3;
static char my_btversion[] = "1.0.0";
static int btver_mjr = 1;
static int btver_mnr = 0;
static int btver_sub = 0;
#endif
......@@ -154,6 +154,7 @@ static LIST_HEAD(input_files); // List of input files to handle
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
/*
......@@ -1175,6 +1176,8 @@ static void stall(struct thr_info *tip, long long oclock)
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),
......@@ -1314,11 +1317,18 @@ static void *replay_sub(void *arg)
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 | O_NOATIME);
#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*/
......@@ -1347,22 +1357,23 @@ static void *replay_sub(void *arg)
*/
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",
......@@ -1412,6 +1423,12 @@ static struct option l_opts[] = {
.flag = NULL,
.val = 'N'
},
{
.name = "acc-factor",
.has_arg = required_argument,
.flag = NULL,
.val = 'x'
},
{
.name = "verbose",
.has_arg = no_argument,
......@@ -1445,6 +1462,7 @@ static struct option l_opts[] = {
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) {
......@@ -1499,6 +1517,16 @@ static void handle_args(int argc, char *argv[])
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);
......
......@@ -80,7 +80,7 @@ The basic operating work-flow to replay IOs would be something like:
\item You extract the pertinent IO information from the traces saved by
\texttt{blktrace} using the \texttt{btrecord} utility. This will parse
each trace file created by \texttt{blktrace}, and crafty IO descriptions
each trace file created by \texttt{blktrace}, and craft IO descriptions
to be used in the next phase of the workload processing.
\item Once \texttt{btrecord} has successfully created a series of data
......@@ -157,15 +157,15 @@ Each input data file (one per device per CPU) results in a new record
data file (again, one per device per CPU) which contains information
about \emph{bunches} of IOs to be replayed. \texttt{btreplay} operates on
these record data files by spawning a new pair of threads per file. One
thread managed the submitting of AIOs per bunch in the record data file,
thread manages the submitting of AIOs per bunch in the record data file,
while the other thread manages reclaiming AIOs completed\footnote{We
have found that having the same thread do both results in a further
reduction in replay timing accuracty.}.
reduction in replay timing accuracy.}.
Each submitting thread simply reads the input file of \emph{bunches}
recorded by \texttt{btrecord}, and attempts to faithfully reproduce the
ordering and timing of IOs seen during the sample workload. The reclaiming
thread simply wait for AIO completions, freeing up resources for the
thread simply waits for AIO completions, freeing up resources for the
submitting thread to utilize to submit new AIOs.
The number of CPUs being used on the replay system can be different from
......@@ -206,7 +206,7 @@ included as well.
\begin{quote}
\emph{The user has \emph{some} control over this (via the
\texttt{--max-pkts} option). One \emph{could} simply specify
\texttt{-max-pkts=1} and then each IO would be treated individualy. Of
\texttt{-max-pkts=1} and then each IO would be treated individually. Of
course, this would probably then run into the problem of excessive
inter-IO times.}
\end{quote}
......@@ -306,7 +306,7 @@ amount of time (in nanoseconds) to include in any one bunch of IOs that
are to be processed. The smaller the value, the smaller the number of
IOs processed at one time -- perhaps yielding in more realistic replay.
However, after a certain point the amount of overhead per bunch may result
in additonal real replay time, thus yielding less accurate replay times.
in additional real replay time, thus yielding less accurate replay times.
The default value is 10,000,000 nanoseconds (10 milliseconds).
......@@ -360,7 +360,7 @@ sdab:3: 474773 pkts (tot), 117849 pkts (replay), 69572 bunches, 1.7 pkts/bunch
\begin{figure}[h!]
\begin{description}
\item[Field 1] The first field contains the device name and CPU
identrifer. Thus: \texttt{sdab:0:} means the device \texttt{sdab} and
identifier. Thus: \texttt{sdab:0:} means the device \texttt{sdab} and
traces on CPU 0.
\item[Field 2] The second field contains the total number of packets
......@@ -386,12 +386,13 @@ Usage: btreplay -- version 0.9.3
[ -c <cpus> : --cpus=<cpus> ] Default: 1
[ -d <dir> : --input-directory=<dir> ] Default: .
[ -F : --find-records ] Default: Off
[ -F : --find-records ] Default: Off
[ -h : --help ] Default: Off
[ -i <base> : --input-base=<base> ] Default: replay
[ -I <iters>: --iterations=<iters> ] Default: 1
[ -M <file> : --map-devs=<file> ] Default: None
[ -N : --no-stalls ] Default: Off
[ -x <int> : --acc-factor=<int> ] Default: 1
[ -v : --verbose ] Default: Off
[ -V : --version ] Default: Off
[ -W : --write-enable ] Default: Off
......@@ -462,8 +463,8 @@ to run through the input files. The default value is 1.
\subsubsection{\label{sec:p-o-M}\texttt{-M} or \texttt{map-devs}\\
Specify Device Mappings}
This option requires a single paramter which specifies the name of a
file contain device mappings. The file must be very simply managed, with
This option requires a single parameter which specifies the name of a
file containing device mappings. The file must be very simply managed, with
just two pieces of data per line:
\begin{enumerate}
......@@ -496,6 +497,16 @@ Pre-bunch Stalls}
When specified on the command line, all pre-bunch stall indicators will be
ignored. IOs will be replayed without inter-bunch delays.
\subsubsection{\label{sec:o-x}\texttt{-x} or \texttt{--acc-factor}\\Acceleration
Factor}
While the \texttt{--no-stalls} option allows the traces to be replayed
with no waiting time, this option specifies some acceleration factor
to be used. If the value of two is used, then the stall time is
divided by half resulting in a reduction of the execution time by
this factor. Note that if this number is too high, the results will
be equivalent of not having stall.
\subsubsection{\label{sec:p-o-v}\texttt{-v} or
\texttt{--verbose}\\Select Verbose Output}
......
......@@ -16,7 +16,8 @@ LIBS = $(PLIBS) $(ELIBS)
OBJS = args.o bt_timeline.o devmap.o devs.o dip_rb.o iostat.o latency.o \
misc.o output.o proc.o seek.o trace.o trace_complete.o trace_im.o \
trace_issue.o trace_queue.o trace_remap.o trace_requeue.o \
../rbtree.o mmap.o trace_plug.o bno_dump.o unplug_hist.o q2d.o
../rbtree.o mmap.o trace_plug.o bno_dump.o unplug_hist.o q2d.o \
aqd.o plat.o
all: depend $(PROGS)
......
/*
* blktrace output analysis: generate a timeline & gather statistics
*
* Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "globals.h"
struct aqd_info {
FILE *fp;
int na; /* # active */
};
void *aqd_alloc(char *str)
{
char *oname;
struct aqd_info *ap;
if (aqd_name == NULL) return NULL;
ap = malloc(sizeof(*ap));
ap->na = 0;
oname = malloc(strlen(aqd_name) + strlen(str) + 32);
sprintf(oname, "%s_%s.dat", aqd_name, str);
if ((ap->fp = my_fopen(oname, "w")) == NULL) {
perror(oname);
return NULL;
}
add_file(ap->fp, oname);
return ap;
}
void aqd_free(void *info)
{
free(info);
}
void aqd_issue(void *info, double ts)
{
if (info) {
struct aqd_info *ap = info;
fprintf(ap->fp, "%lf %d\n%lf %d\n", ts, ap->na, ts, ap->na + 1);
ap->na += 1;
}
}
void aqd_complete(void *info, double ts)
{
if (info) {
struct aqd_info *ap = info;
if (ap->na > 0) {
fprintf(ap->fp, "%lf %d\n%lf %d\n",
ts, ap->na, ts, ap->na - 1);
ap->na -= 1;
}
}
}
......@@ -29,7 +29,7 @@
#define SETBUFFER_SIZE (64 * 1024)
#define S_OPTS "aAB:d:D:e:hi:I:l:M:o:p:q:s:S:t:T:u:Vv"
#define S_OPTS "aAB:d:D:e:hi:I:l:L:m:M:o:p:P:q:Q:rs:S:t:T:u:VvXz:"
static struct option l_opts[] = {
{
.name = "seek-absolute",
......@@ -91,6 +91,18 @@ static struct option l_opts[] = {
.flag = NULL,
.val = 'l'
},
{
.name = "periodic-latencies",
.has_arg = required_argument,
.flag = NULL,
.val = 'L'
},
{
.name = "seeks-per-second",
.has_arg = required_argument,
.flag = NULL,
.val = 'm'
},
{
.name = "dev-maps",
.has_arg = required_argument,
......@@ -109,12 +121,30 @@ static struct option l_opts[] = {
.flag = NULL,
.val = 'p'
},
{
.name = "per-io-trees",
.has_arg = required_argument,
.flag = NULL,
.val = 'P'
},
{
.name = "q2c-latencies",