Commit 5649866e authored by Bas Zoetekouw's avatar Bas Zoetekouw Committed by Dmitry Smirnov

Imported Debian snapshot 0.99.3+git-20071207142532-1

parent a716ce6e
......@@ -5,20 +5,26 @@ PROGS = blkparse blktrace verify_blkparse blkrawverify
LIBS = -lpthread
SCRIPTS = btrace
ALL = $(PROGS) $(SCRIPTS) btt/btt
ALL = $(PROGS) $(SCRIPTS) btt/btt btreplay/btrecord btreplay/btreplay
all: $(ALL)
btt/btt:
$(MAKE) -C btt
btreplay/btrecord:
$(MAKE) -C btreplay
btreplay/btreplay:
$(MAKE) -C btreplay
%.o: %.c
$(CC) -o $*.o -c $(ALL_CFLAGS) $<
blkparse: blkparse.o blkparse_fmt.o rbtree.o act_mask.o
$(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^)
blktrace: blktrace.o act_mask.o $(LIBS)
blktrace: blktrace.o act_mask.o
$(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^) $(LIBS)
verify_blkparse: verify_blkparse.o
......@@ -32,10 +38,12 @@ $(PROGS): | depend
docs:
$(MAKE) -C doc all
$(MAKE) -C btt docs
$(MAKE) -C btreplay docs
docsclean:
$(MAKE) -C doc clean
$(MAKE) -C btt clean
$(MAKE) -C btreplay clean
depend:
@$(CC) -MM $(ALL_CFLAGS) *.c 1> .depend
......@@ -63,6 +71,7 @@ rpm: dist
clean: docsclean
-rm -f *.o $(PROGS) .depend btrace-1.0.tar.bz2
$(MAKE) -C btt clean
$(MAKE) -C btreplay clean
install: all
$(INSTALL) -m 755 -d $(DESTDIR)$(bindir)
......
......@@ -17,7 +17,7 @@
#define store_barrier() asm volatile("":::"memory")
#elif defined(__sparc__)
#define store_barrier() asm volatile("":::"memory")
#elif defined(__m68000__)
#elif defined(__m68000__) || defined(__m68k__) || defined(mc68000) || defined(_M_M68K)
#define store_barrier() asm volatile("":::"memory")
#elif defined(__mips__) /* also mipsel */
#define store_barrier() do { } while(0)
......
......@@ -1224,6 +1224,7 @@ static int start_devices(void)
fprintf(stderr, "Out of memory, threads (%d)\n", size * ndevs);
return 1;
}
memset(thread_information, 0, size * ndevs);
for_each_dip(dip, i) {
if (start_trace(dip)) {
......
#
# OCFLAGS:
# COUNT_IOS - Counts struct io's left at end
# DEBUG - Various and sundy debug asserts
# NDEBUG - Defined: no asserts, Undefined: asserts
#
CC = gcc
CFLAGS = -Wall -W -O2 -g
INCS = -I. -I.. -I../btt
OCFLAGS = -UCOUNT_IOS -UDEBUG -DNDEBUG
XCFLAGS = -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
override CFLAGS += $(INCS) $(XCFLAGS) $(OCFLAGS)
PROGS = btrecord btreplay
LIBS = -laio -lrt
all: depend $(PROGS)
$(PROGS): | depend
docs:
$(MAKE) -C doc all
docsclean:
$(MAKE) -C doc clean
clean: docsclean
-rm -f *.o $(PROGS) .depend
%.o: %.c
$(CC) $(CFLAGS) -c -o $*.o $<
btrecord: btrecord.o
$(CC) $(CFLAGS) -o $@ $(filter %.o,$^) $(LIBS)
btreplay: btreplay.o
$(CC) $(CFLAGS) -o $@ $(filter %.o,$^) $(LIBS)
depend:
@$(CC) -MM $(CFLAGS) *.c 1> .depend
ifneq ($(wildcard .depend),)
include .depend
endif
This diff is collapsed.
/*
* Blktrace record utility - Convert binary trace data into bunches of IOs
*
* Copyright (C) 2007 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
*/
#if !defined(__BTRECORD_H__)
#define __BTRECORD_H__
#include <asm/types.h>
#define BT_MAX_PKTS 512
/*
* Header for each bunch
*
* @nkts: Number of IO packets to process
* @time_stamp: Time stamp for this bunch of IOs
*/
struct io_bunch_hdr {
__u64 npkts;
__u64 time_stamp;
};
/*
* IO specifer
*
* @sector: Sector number of IO
* @nbytes: Number of bytes to process
* @rw: IO direction: 0 = write, 1 = read
*/
struct io_pkt {
__u64 sector;
__u64 nbytes;
__u32 rw;
};
/*
* Shorthand notion of a bunch of IOs
*
* @hdr: Header describing stall and how many IO packets follow
* @pkts: Individual IOs are described here
*/
struct io_bunch {
struct io_bunch_hdr hdr;
struct io_pkt pkts[BT_MAX_PKTS];
};
/*
* Header for each recorded file
*
* @version: Version information
* @genesis: Time stamp for earliest bunch
* @nbunches: Number of bunches put into the file
* @total_pkts: Number of packets to be processed
*/
struct io_file_hdr {
__u64 version;
__u64 genesis;
__u64 nbunches;
__u64 total_pkts;
};
static inline __u64 mk_btversion(int mjr, int mnr, int sub)
{
return ((mjr & 0xff) << 16) | ((mnr & 0xff) << 8) | (sub & 0xff);
}
static inline void get_btversion(__u64 version, int *mjr, int *mnr, int *sub)
{
*mjr = (int)((version >> 16) & 0xff);
*mnr = (int)((version >> 8) & 0xff);
*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;
#endif
This diff is collapsed.
DOCTMP = btreplay.log btreplay.aux btreplay.dvi btreplay.toc
all: btreplay.dvi btreplay.pdf
btreplay.tex:
@touch btreplay.tex
btreplay.dvi: btreplay.tex abstract.tex
@latex btreplay.tex
@latex btreplay.tex
btreplay.pdf: btreplay.dvi
@dvipdfm -p letter btreplay
clean:
-rm -f $(DOCTMP)
-rm -f *.bak *.ps *.pdf
@rm -rf btreplay
%
% Copyright (C) 2007 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
%
% vi :set textwidth=75
%
The \texttt{btrecord} and \texttt{btreplay} tools provide the ability to
record and replay IOs captured by the \texttt{blktrace} utility. Attempts
are made to maintain ordering, CPU mappings and time-separation of IOs. The
general workflow is expected to be:
\begin{enumerate}
\item Initiate \texttt{blktrace} to capture traces
\item Generate traces\ldots
\item Stop \texttt{blktrace}
\item Run \texttt{btrecord} to convert traces into IO records
\item Utilize \texttt{btreplay} to replay IOs
\end{enumerate}
This document will discuss the operating characteristics of
\texttt{btreplay} and provide detailed command line option descriptions.
This diff is collapsed.
......@@ -17,7 +17,7 @@ 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
../rbtree.o mmap.o trace_plug.o bno_dump.o unplug_hist.o q2d.o
all: depend $(PROGS)
......
......@@ -131,6 +131,8 @@ void dip_exit(void)
seeki_exit(dip->q2q_handle);
bno_dump_exit(dip->bno_dump_handle);
unplug_hist_exit(dip->unplug_hist_handle);
if (output_all_data)
q2d_release(dip->q2d_priv);
free(dip);
}
}
......@@ -167,6 +169,8 @@ struct d_info *dip_add(__u32 device, struct io *iop)
list_add_tail(&dip->all_head, &all_devs);
dip->start_time = BIT_TIME(iop->t.time);
dip->pre_culling = 1;
if (output_all_data)
dip->q2d_priv = q2d_init();
n_devs++;
}
......
......@@ -22,7 +22,7 @@
\title{\texttt{btt} User Guide}
\author{Alan D. Brunelle (Alan.Brunelle@hp.com)}
\date{16 April 2007}
\date{13 November 2007}
\begin{document}
\maketitle
......@@ -56,7 +56,7 @@ easier.
\bigskip
This document refers to the output formats generated by \texttt{btt}
version 0.99.1. However, the descriptions are general enough to cover
version 2.00. However, the descriptions are general enough to cover
output formats prior to that.
\newpage\tableofcontents
......@@ -251,6 +251,32 @@ Q2C 0.000207665 0.125405263 1.830917198 2262311
The total number of unplugs is equal to the number of plugs less the
ones due to timer unplugs.
\item[Active Requests At Q Information]
An important consideration when analyzing block IO schedulers is to
know how many requests the scheduler has to work with. The metric
provided in this section details how many requests (on average) were
being held by the IO scheduler when an incoming IO request was being
handled. To determine this, \texttt{btt} keeps track of how many Q
requests came in, and subtacts requests that have been issued (D).
Here is a sample output of this sections:
\begin{verbatim}
==================== Active Requests At Q Information ====================
DEV | Avg Reqs @ Q
---------- | -------------
( 65, 80) | 12.0
( 65,240) | 16.9
...
( 66,112) | 44.2
---------- | -------------
Overall | Avgs Reqs @ Q
Average | 17.4
\end{verbatim}
\end{description}
\newpage
......@@ -310,6 +336,27 @@ pdflush 0.000000790 0.000006752 0.247231307 179791
\item[Per Device Averages] The average columns from the above charts,
are also presented in their own chart.
\item[Q2D Histogram] A display of histogram buckets for the Q to D times
-- basically, from where an IO enters the block IO layer for a given
device, and when it is dispatched. The buckets are arranged via the
time in seconds, as in:
\begin{verbatim}
==================== Q2D Histogram ====================
DEV | <.005 <.010 <.025 <.050 <.075 <.100 <.250 <.500 < 1.0 >=1.0
--------- | ===== ===== ===== ===== ===== ===== ===== ===== ===== =====
( 66, 80) | 61.2 7.9 12.1 7.9 3.0 1.4 1.5 0.2 0.0 4.6
( 65,192) | 42.3 5.0 8.7 30.0 8.9 3.0 1.8 0.1 0.0 0.1
( 65,128) | 34.3 5.3 8.9 32.0 9.7 3.7 5.3 0.6 0.0 0.1
...
( 65, 64) | 59.9 4.2 6.0 24.6 4.2 0.8 0.1 0.0 0.0 0.1
( 66, 64) | 62.6 8.1 12.7 7.9 2.4 0.6 0.1 0.0 0.0 5.4
========== | ===== ===== ===== ===== ===== ===== ===== ===== ===== =====
AVG | 52.9 6.2 10.0 20.1 5.3 1.7 1.4 0.2 0.0 2.1
\end{verbatim}
\end{description}
\newpage\section{\label{sec:data-files}Data Files Output}
......@@ -646,7 +693,7 @@ Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s
\newpage\section{\label{sec:cmd-line}Command Line}
\begin{verbatim}
Usage: \texttt{btt} 0.99.1
Usage: btt 2.00
[ -a | --seek-absolute ]
[ -A | --all-data ]
[ -B <output name> | --dump-blocknos=<output name> ]
......
......@@ -159,10 +159,12 @@ struct d_info {
struct region_info regions;
struct devmap *map;
void *q2q_handle, *seek_handle, *bno_dump_handle, *unplug_hist_handle;
void *q2d_priv;
FILE *d2c_ofp, *q2c_ofp;
struct avgs_info avgs;
struct stats stats, all_stats;
__u64 last_q, n_ds;
__u64 last_q, n_qs, n_ds;
__u64 n_act_q, t_act_q; /* # currently active when Q comes in */
__u32 device;
int pre_culling;
......@@ -295,6 +297,16 @@ void bno_dump_exit(void *param);
void bno_dump_add(void *handle, struct io *iop);
void bno_dump_clean(void);
/* q2d.c */
void q2d_histo_add(void *priv, __u64 q2d);
void *q2d_init(void);
void q2d_release(void *priv);
void q2d_display_header(FILE *fp);
void q2d_display_dashes(FILE *fp);
void q2d_display(FILE *fp, void *priv);
int q2d_ok(void *priv);
void q2d_acc(void *a1, void *a2);
/* seek.c */
void *seeki_init(char *str);
void seeki_exit(void *param);
......
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
#include <stdio.h>
#ifndef offsetof
/**
* Get offset of a member
*/
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#ifndef container_of
/**
* Casts a member of a structure out to the containing structure
* @param ptr the pointer to the member.
* @param type the type of the container struct this is embedded in.
* @param member the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#endif
/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
......@@ -166,4 +188,29 @@ static inline void list_move_tail(struct list_head *list,
list_add_tail(list, head);
}
static inline void __list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
/**
* * list_splice - join two lists
* * @list: the new list to add.
* * @head: the place to add it in the first list.
* */
static inline void list_splice(struct list_head *list, struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head);
}
#endif
......@@ -133,6 +133,49 @@ void output_dip_avg(FILE *ofp, char *hdr, ai_dip_t (*func)(struct d_info *))
fprintf(ofp, "\n");
}
struct __q2d {
FILE *ofp;
void *q2d_all;
int n;
};
void __output_q2d_histo(struct d_info *dip, void *arg)
{
struct __q2d *q2dp = arg;
if (q2d_ok(dip->q2d_priv)) {
char scratch[15];
FILE *ofp = q2dp->ofp;
fprintf(q2dp->ofp, "%10s | ", make_dev_hdr(scratch, 15, dip));
q2d_display(ofp, dip->q2d_priv);
q2d_acc(q2dp->q2d_all, dip->q2d_priv);
q2dp->n++;
}
}
void output_q2d_histo(FILE *ofp)
{
struct __q2d __q2d = {
.ofp = ofp,
.q2d_all = q2d_init(),
.n = 0
};
fprintf(ofp, "%10s | ", "DEV");
q2d_display_header(ofp);
fprintf(ofp, "--------- | ");
q2d_display_dashes(ofp);
dip_foreach_out(__output_q2d_histo, &__q2d);
if (__q2d.n) {
fprintf(ofp, "========== | ");
q2d_display_dashes(ofp);
fprintf(ofp, "%10s | ", "AVG");
q2d_display(ofp, __q2d.q2d_all);
fprintf(ofp, "\n");
}
}
int n_merges = 0;
struct {
unsigned long long nq, nd, blkmin, blkmax, total;
......@@ -141,15 +184,25 @@ void __output_dip_merge_ratio(struct d_info *dip, void *arg)
{
double blks_avg;
char scratch[15];
double ratio, q2c_n = dip->avgs.q2c.n, d2c_n = dip->n_ds;
double ratio, q2c_n, d2c_n;
if (dip->n_qs == 0 || dip->n_ds == 0)
return;
else if (dip->n_qs < dip->n_ds)
dip->n_qs = dip->n_ds;
q2c_n = dip->n_qs;
d2c_n = dip->n_ds;
if (q2c_n > 0.0 && d2c_n > 0.0) {
ratio = q2c_n / d2c_n;
if (q2c_n < d2c_n)
ratio = 1.0;
else
ratio = q2c_n / d2c_n;
blks_avg = (double)dip->avgs.blks.total / d2c_n;
fprintf((FILE *)arg,
"%10s | %8llu %8llu %7.1lf | %8llu %8llu %8llu %8llu\n",
make_dev_hdr(scratch, 15, dip),
(unsigned long long)dip->avgs.q2c.n,
(unsigned long long)dip->n_qs,
(unsigned long long)dip->n_ds,
ratio,
(unsigned long long)dip->avgs.blks.min,
......@@ -162,7 +215,7 @@ void __output_dip_merge_ratio(struct d_info *dip, void *arg)
merge_data.blkmax = dip->avgs.blks.max;
}
merge_data.nq += dip->avgs.q2c.n;
merge_data.nq += dip->n_qs;
merge_data.nd += dip->n_ds;
merge_data.total += dip->avgs.blks.total;
if (dip->avgs.blks.min < merge_data.blkmin)
......@@ -500,6 +553,45 @@ void output_plug_info(FILE *ofp)
fprintf(ofp, "\n");
}
int n_actQs;
struct actQ_info {
__u64 t_qs;
__u64 t_act_qs;
} actQ_info;
void __dip_output_actQ(struct d_info *dip, void *arg)
{
if (dip->n_qs > 0 && !remapper_dev(dip->device)) {
char dev_info[15];
double a_actQs = (double)dip->t_act_q / (double)dip->n_qs;
fprintf((FILE *)arg, "%10s | %13.1lf\n",
make_dev_hdr(dev_info, 15, dip), a_actQs);
n_actQs++;
actQ_info.t_qs += dip->n_qs;
actQ_info.t_act_qs += dip->t_act_q;
}
}
void __dip_output_actQ_all(FILE *ofp, struct actQ_info *p)
{
fprintf(ofp, "---------- | -------------\n");
fprintf(ofp, "%10s | %13s\n", "Overall", "Avgs Reqs @ Q");
fprintf(ofp, "%10s | %13.1lf\n", "Average",
(double)p->t_act_qs / (double)p->t_qs);
}
void output_actQ_info(FILE *ofp)
{
fprintf(ofp, "%10s | %13s\n", "DEV", "Avg Reqs @ Q");
fprintf(ofp, "---------- | -------------\n");
dip_foreach_out(__dip_output_actQ, ofp);
if (n_actQs > 1)
__dip_output_actQ_all(ofp, &actQ_info);
fprintf(ofp, "\n");
}
void output_histos(void)
{
int i;
......@@ -594,8 +686,16 @@ int output_avgs(FILE *ofp)
output_section_hdr(ofp, "Plug Information");
output_plug_info(ofp);
output_section_hdr(ofp, "Active Requests At Q Information");
output_actQ_info(ofp);
output_histos();
if (output_all_data) {
output_section_hdr(ofp, "Q2D Histogram");
output_q2d_histo(ofp);
}
return 0;
}
......
/*
* blktrace output analysis: generate a timeline & gather statistics
*
* (C) Copyright 2007 Hewlett-Packard Development Company, L.P.
*
* 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"
#define Q2D_MAX_HISTO 9
struct q2d_info {
unsigned long nhistos;
unsigned long histos[Q2D_MAX_HISTO + 1];
};
void q2d_histo_add(void *priv, __u64 q2d_in)
{
int index;
struct q2d_info *q2dp = priv;
double q2d = BIT_TIME(q2d_in);
long msec = (long)(q2d / 0.001);
switch (msec) {
default: index = 9; break;
case 500 ... 999: index = 8; break;
case 250 ... 499: index = 7; break;
case 100 ... 249: index = 6; break;
case 75 ... 99: index = 5; break;
case 50 ... 74: index = 4; break;
case 25 ... 49: index = 3; break;
case 10 ... 24: index = 2; break;
case 5 ... 9: index = 1; break;
case 0 ... 4: index = 0; break;
}
q2dp->histos[index]++;
q2dp->nhistos++;
}
void *q2d_init(void)
{
struct q2d_info *q2dp = malloc(sizeof(*q2dp));
return memset(q2dp, 0, sizeof(*q2dp));
}
void q2d_release(void *priv)
{
free(priv);
}
void q2d_display_header(FILE *fp)
{
fprintf(fp, "%5s ", "<.005");
fprintf(fp, "%5s ", "<.010");
fprintf(fp, "%5s ", "<.025");
fprintf(fp, "%5s ", "<.050");
fprintf(fp, "%5s ", "<.075");
fprintf(fp, "%5s ", "<.100");
fprintf(fp, "%5s ", "<.250");
fprintf(fp, "%5s ", "<.500");
fprintf(fp, "%5s ", "< 1.0");
fprintf(fp, "%5s ", ">=1.0\n");
}
void q2d_display_dashes(FILE *fp)
{
int i;
for (i = 0; i <= Q2D_MAX_HISTO; i++)
fprintf(fp, "===== ");
fprintf(fp, "\n");
}
void q2d_display(FILE *fp, void *priv)
{
int i;
struct q2d_info *q2dp = priv;
double nh = (double)q2dp->nhistos;
for (i = 0; i <= Q2D_MAX_HISTO; i++) {
double p = 100.0 * (double)q2dp->histos[i] / nh;
fprintf(fp, "%5.1lf ", p);
}
fprintf(fp, "\n");
}
int q2d_ok(void *priv)
{
struct q2d_info *q2dp = priv;
return q2dp && q2dp->nhistos > 0;
}
void q2d_acc(void *a1, void *a2)
{
int i;
struct q2d_info *ap = a1;
struct q2d_info *tp = a2;
for (i = 0; i <= Q2D_MAX_HISTO; i++)
ap->histos[i] += tp->histos[i];
ap->nhistos += tp->nhistos;
}
......@@ -25,6 +25,9 @@ static void handle_issue(struct io *d_iop)
LIST_HEAD(head);
struct list_head *p, *q;