add ffsb (Flexible File System Benchmark) to the build (gcc4 only).

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38803 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval
2010-09-23 17:55:34 +00:00
parent c6789116b7
commit 23395e2082
61 changed files with 22531 additions and 0 deletions
@@ -3,6 +3,7 @@ SubDir HAIKU_TOP src tests add-ons kernel file_systems ;
HaikuSubInclude bfs ;
HaikuSubInclude cdda ;
HaikuSubInclude consistency_check ;
HaikuSubInclude ffsb ;
HaikuSubInclude fs_shell ;
HaikuSubInclude fragmenter ;
HaikuSubInclude iso9660 ;
@@ -0,0 +1,7 @@
Dominique Heger ([email protected])
Josh Jacobs ([email protected])
-> up to Version 3.0 of FFSB
Sonny Rao ([email protected])
versions 3.1 and beyond
@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
@@ -0,0 +1,182 @@
Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, a file
`config.cache' that saves the results of its tests to speed up
reconfiguring, and a file `config.log' containing compiler output
(useful mainly for debugging `configure').
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If at some point `config.cache'
contains results you don't want to keep, you may remove or edit it.
The file `configure.in' is used to create `configure' by a program
called `autoconf'. You only need `configure.in' if you want to change
it or regenerate `configure' using a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. You can give `configure'
initial values for variables by setting them in the environment. Using
a Bourne-compatible shell, you can do that on the command line like
this:
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
Or on systems that have the `env' program, you can do it like this:
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not supports the `VPATH'
variable, you have to compile the package for one architecture at a time
in the source code directory. After you have installed the package for
one architecture, use `make distclean' before reconfiguring for another
architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' can not figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
a message saying it can not guess the host type, give it the
`--host=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the host type.
If you are building compiler tools for cross-compiling, you can also
use the `--target=TYPE' option to select the type of system they will
produce code for and the `--build=TYPE' option to select the type of
system on which you are compiling the package.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Operation Controls
==================
`configure' recognizes the following options to control how it
operates.
`--cache-file=FILE'
Use and save the results of the tests in FILE instead of
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
debugging `configure'.
`--help'
Print a summary of the options to `configure', and exit.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--version'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`configure' also accepts some other, not widely useful, options.
@@ -0,0 +1,6 @@
SubDir HAIKU_TOP src tests add-ons kernel file_systems ffsb ;
SimpleTest ffsb :
cirlist.c ffsb_fs.c ffsb_stats.c ffsb_thread.c filelist.c list.c metaops.c rand.c rwlock.c
ffsb_fc.c ffsb_op.c ffsb_tg.c fh.c fileops.c main.c parser.c rbt.c util.c
;
@@ -0,0 +1,347 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
The Free Software Foundation has exempted Bash from the requirement of
Paragraph 2c of the General Public License. This is to say, there is
no requirement for Bash to print a notice when it is started
interactively in the usual way. We made this exception because users
and standards expect shells not to print such messages. This
exception applies to any program that serves as a shell and that is
based primarily on Bash as opposed to other GNU software.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
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
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
@@ -0,0 +1,46 @@
bin_PROGRAMS = ffsb #ffsb_test
ffsb_SOURCES = \
fileops.c \
rand.c \
config.h \
fileops.h \
ffsb.h \
rand.h \
main.c \
fh.h \
fh.c \
filelist.c \
filelist.h \
metaops.c \
metaops.h \
rwlock.h \
rwlock.c \
cirlist.c \
cirlist.h \
rbt.c \
rbt.h \
ffsb_tg.h \
ffsb_tg.c \
ffsb_fs.h \
ffsb_fs.c \
ffsb_thread.c \
ffsb_thread.h \
ffsb_op.h \
ffsb_op.c \
util.h \
util.c \
parser.c \
parser.h \
ffsb_fc.c \
ffsb_stats.c \
list.c
#ffsb_test_SOURCES = config.h fileops.h ffsb.h rand.h fh.h filelist.h metaops.h rwlock.h cirlist.h rbt.h ffsb_tg.h ffsb_fs.h ffsb_thread.h ffsb_op.h util.h parser.c parser.h ffsb_test.c
EXTRA_DIST = *.txt *.tex
AM_CFLAGS = -D_GNU_SOURCE
#CFLAGS += -Wall -Werror -g -Wconversion -ansi
#LDFLAGS += -lefence
@@ -0,0 +1,628 @@
# Makefile.in generated by automake 1.10.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
bin_PROGRAMS = ffsb$(EXEEXT)
subdir = .
DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in $(srcdir)/config.h.in \
$(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \
config.guess config.sub depcomp install-sh missing \
mkinstalldirs
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.in
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno config.status.lineno
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES =
am__installdirs = "$(DESTDIR)$(bindir)"
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(bin_PROGRAMS)
am_ffsb_OBJECTS = fileops.$(OBJEXT) rand.$(OBJEXT) main.$(OBJEXT) \
fh.$(OBJEXT) filelist.$(OBJEXT) metaops.$(OBJEXT) \
rwlock.$(OBJEXT) cirlist.$(OBJEXT) rbt.$(OBJEXT) \
ffsb_tg.$(OBJEXT) ffsb_fs.$(OBJEXT) ffsb_thread.$(OBJEXT) \
ffsb_op.$(OBJEXT) util.$(OBJEXT) parser.$(OBJEXT) \
ffsb_fc.$(OBJEXT) ffsb_stats.$(OBJEXT) list.$(OBJEXT)
ffsb_OBJECTS = $(am_ffsb_OBJECTS)
ffsb_LDADD = $(LDADD)
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(ffsb_SOURCES)
DIST_SOURCES = $(ffsb_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
am__remove_distdir = \
{ test ! -d $(distdir) \
|| { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
&& rm -fr $(distdir); }; }
DIST_ARCHIVES = $(distdir).tar.gz
GZIP_ENV = --best
distuninstallcheck_listfiles = find . -type f -print
distcleancheck_listfiles = find . -type f -print
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LTLIBOBJS = @LTLIBOBJS@
MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_CC = @ac_ct_CC@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
ffsb_SOURCES = \
fileops.c \
rand.c \
config.h \
fileops.h \
ffsb.h \
rand.h \
main.c \
fh.h \
fh.c \
filelist.c \
filelist.h \
metaops.c \
metaops.h \
rwlock.h \
rwlock.c \
cirlist.c \
cirlist.h \
rbt.c \
rbt.h \
ffsb_tg.h \
ffsb_tg.c \
ffsb_fs.h \
ffsb_fs.c \
ffsb_thread.c \
ffsb_thread.h \
ffsb_op.h \
ffsb_op.c \
util.h \
util.c \
parser.c \
parser.h \
ffsb_fc.c \
ffsb_stats.c \
list.c
#ffsb_test_SOURCES = config.h fileops.h ffsb.h rand.h fh.h filelist.h metaops.h rwlock.h cirlist.h rbt.h ffsb_tg.h ffsb_fs.h ffsb_thread.h ffsb_op.h util.h parser.c parser.h ffsb_test.c
EXTRA_DIST = *.txt *.tex
AM_CFLAGS = -D_GNU_SOURCE
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-am
.SUFFIXES:
.SUFFIXES: .c .o .obj
am--refresh:
@:
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \
cd $(srcdir) && $(AUTOMAKE) --gnu \
&& exit 0; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
cd $(top_srcdir) && \
$(AUTOMAKE) --gnu Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
echo ' $(SHELL) ./config.status'; \
$(SHELL) ./config.status;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
$(SHELL) ./config.status --recheck
$(top_srcdir)/configure: $(am__configure_deps)
cd $(srcdir) && $(AUTOCONF)
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
config.h: stamp-h1
@if test ! -f $@; then \
rm -f stamp-h1; \
$(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
else :; fi
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
@rm -f stamp-h1
cd $(top_builddir) && $(SHELL) ./config.status config.h
$(srcdir)/config.h.in: $(am__configure_deps)
cd $(top_srcdir) && $(AUTOHEADER)
rm -f stamp-h1
touch $@
distclean-hdr:
-rm -f config.h stamp-h1
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
@list='$(bin_PROGRAMS)'; for p in $$list; do \
p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
if test -f $$p \
; then \
f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
$(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
else :; fi; \
done
uninstall-binPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(bin_PROGRAMS)'; for p in $$list; do \
f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
rm -f "$(DESTDIR)$(bindir)/$$f"; \
done
clean-binPROGRAMS:
-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
ffsb$(EXEEXT): $(ffsb_OBJECTS) $(ffsb_DEPENDENCIES)
@rm -f ffsb$(EXEEXT)
$(LINK) $(ffsb_OBJECTS) $(ffsb_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cirlist.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ffsb_fc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ffsb_fs.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ffsb_op.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ffsb_stats.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ffsb_tg.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ffsb_thread.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fh.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filelist.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileops.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metaops.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rand.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rbt.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rwlock.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c $<
.c.obj:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$tags $$unique; \
fi
ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$tags $$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& cd $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) $$here
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
$(am__remove_distdir)
test -d $(distdir) || mkdir $(distdir)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
fi; \
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
else \
test -f $(distdir)/$$file \
|| cp -p $$d/$$file $(distdir)/$$file \
|| exit 1; \
fi; \
done
-find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|| chmod -R a+r $(distdir)
dist-gzip: distdir
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
$(am__remove_distdir)
dist-bzip2: distdir
tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
$(am__remove_distdir)
dist-lzma: distdir
tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
$(am__remove_distdir)
dist-tarZ: distdir
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
$(am__remove_distdir)
dist-shar: distdir
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
$(am__remove_distdir)
dist-zip: distdir
-rm -f $(distdir).zip
zip -rq $(distdir).zip $(distdir)
$(am__remove_distdir)
dist dist-all: distdir
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
$(am__remove_distdir)
# This target untars the dist file and tries a VPATH configuration. Then
# it guarantees that the distribution is self-contained by making another
# tarfile.
distcheck: dist
case '$(DIST_ARCHIVES)' in \
*.tar.gz*) \
GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
*.tar.bz2*) \
bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
*.tar.lzma*) \
unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\
*.tar.Z*) \
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
*.shar.gz*) \
GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
*.zip*) \
unzip $(distdir).zip ;;\
esac
chmod -R a-w $(distdir); chmod a+w $(distdir)
mkdir $(distdir)/_build
mkdir $(distdir)/_inst
chmod a-w $(distdir)
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
&& cd $(distdir)/_build \
&& ../configure --srcdir=.. --prefix="$$dc_install_base" \
$(DISTCHECK_CONFIGURE_FLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
&& $(MAKE) $(AM_MAKEFLAGS) check \
&& $(MAKE) $(AM_MAKEFLAGS) install \
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
&& $(MAKE) $(AM_MAKEFLAGS) uninstall \
&& $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
distuninstallcheck \
&& chmod -R a-w "$$dc_install_base" \
&& ({ \
(cd ../.. && umask 077 && mkdir "$$dc_destdir") \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
} || { rm -rf "$$dc_destdir"; exit 1; }) \
&& rm -rf "$$dc_destdir" \
&& $(MAKE) $(AM_MAKEFLAGS) dist \
&& rm -rf $(DIST_ARCHIVES) \
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck
$(am__remove_distdir)
@(echo "$(distdir) archives ready for distribution: "; \
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
distuninstallcheck:
@cd $(distuninstallcheck_dir) \
&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
|| { echo "ERROR: files left after uninstall:" ; \
if test -n "$(DESTDIR)"; then \
echo " (check DESTDIR support)"; \
fi ; \
$(distuninstallcheck_listfiles) ; \
exit 1; } >&2
distcleancheck: distclean
@if test '$(srcdir)' = . ; then \
echo "ERROR: distcleancheck can only run from a VPATH build" ; \
exit 1 ; \
fi
@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
|| { echo "ERROR: files left in build directory after distclean:" ; \
$(distcleancheck_listfiles) ; \
exit 1; } >&2
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS) config.h
installdirs:
for dir in "$(DESTDIR)$(bindir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
distclean: distclean-am
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-hdr distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-exec-am: install-binPROGRAMS
install-html: install-html-am
install-info: install-info-am
install-man:
install-pdf: install-pdf-am
install-ps: install-ps-am
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -rf $(top_srcdir)/autom4te.cache
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-binPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \
clean-binPROGRAMS clean-generic ctags dist dist-all dist-bzip2 \
dist-gzip dist-lzma dist-shar dist-tarZ dist-zip distcheck \
distclean distclean-compile distclean-generic distclean-hdr \
distclean-tags distcleancheck distdir distuninstallcheck dvi \
dvi-am html html-am info info-am install install-am \
install-binPROGRAMS install-data install-data-am install-dvi \
install-dvi-am install-exec install-exec-am install-html \
install-html-am install-info install-info-am install-man \
install-pdf install-pdf-am install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
tags uninstall uninstall-am uninstall-binPROGRAMS
#CFLAGS += -Wall -Werror -g -Wconversion -ansi
#LDFLAGS += -lefence
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
@@ -0,0 +1,413 @@
Introduction:
The Flexible Filesystem Benchmark (FFSB) is a filesystem performance
measurement tool. It is a multi-threaded application (using
pthreads), written entirely in C with cross-platform portability in
mind. It differs from other filesystem benchmarks in that the user
may supply a profile to create custom workloads, while most other
filesystem benchmarks use a fixed set of workloads.
As of version 5.1, it supports seven different basic operations, support
for multiple groups of threads with different operation mixtures,
support for operation across multiple filesystems, and support for
filesystem aging prior to benchmarking.
Differences from version 4.0 and older:
Version 5.0 and above represent almost a total re-write and many
things have changed. In version 5.0 and above FFSB moved to a
time-regulated run versus doing a set number of different operations
and timing the whole thing. This is primarily to better deal with the
use of multiple threadgroups which would otherwise not be synchronized
at termination time.
Additionally, the FFSB configuration file format has changed in
version 5.0, although we do support old-style configuration files
along with a run-time passed on the command line. In this mode,
version 5.0 and above ignores the iterations parameter, and simply
uses the time specified on the command line.
Behaviorally, most of the old operations are the same -- sequential
reads and sequential writes work as they did before. One change in
version 5.0 is the skip-read behavior of reading then seeking forward
a fixed amount then reading again is removed, we now support fully
randomized reads and writes from random offsets within the file.
Version 4.0 didn't support overwrites (only appends) so we interpret
writes in old config files to be append operations.
On Linux, CPU utilization information will only be accurate for
systems using NPTL, older Linuxthreads systems will probably only see
zeros for CPU utilization because Linuxthreads is non-compliant to
POSIX. Version 4.0 and older could be recompiled to work on
Linuxthreads, but in 5.0 and later we no longer support this.
We no longer support the "outputfile" on the command line.
One should simply use tee or similar to capture the output. FFSB
unbuffers standard out for this purpose, and errors are sent on
standard error.
Global options:
There are eight valid global options placed at the beginning of the
profile. Three of them are required: num_filesystems (number of
filesystems), num_threadgroups (number of threadgroups), and time
(running time of the benchmark). The other five options are:
directio - each call to open will be made using O_DIRECT
alignio - aligns all block operations for random reads and writes
on 4k boundaries.
bufferedio - currently ignorred: it is intended to use libc
fread,rwrite, instead of just unix read and write calls
verbose - currently ignored
callout - calls and external command and waits for its termination
before FFSB begins the benchmark phase.
This is useful for synchronizing distributed clients,
starting profilers, etc.
They must be specified in the above order (num_filesystems,
num_threadgroups, time, directio, alignio, bufferedio, verbose,
callout).
Filesystems:
Filesystems are specified to FFSB in the form of a directory. FFSB
assumes that the filesystem is mounted at this directory and will not
do any verification of this fact beyond ensuring it can read/write to
the location. So be careful to ensure something with enough space to
handle the dataset is in fact mounted at the specified location.
In the filesystem clause of the profile, one may set the starting
number of files and directories as well as a minimum and maximum
filesize for the filesystem. One may also specify the blocksize
used for creating the files separately in the filesystem clause.
Also, if a filesystem is to be aged, a special threadgroup clause may
be embedded in a filesystem clause to specify the operation mixture
and number of threads used to age the filesystem. This threadgroup is
run until filesystem utilization reaches the specified amount.
Inheritance -- if you are using multiple filesystems, all attributes
except the location should be inherited from the previous filesystem.
This is done to make it easier to add groups of similar filesystems.
In this case, only the location is required in the filesystem clause.
As of version 5.1, filesystem re-use is supported if a given
filesystem hasn't been modified beyond it's orginal specifications
(number of files and directories is correct, and file sizes are within
specifications). This can be a huge time saver if one wishes to do
multiple runs on the same data-set without altering it during a run,
because the fileset doesn't need to be recreated before each run.
To do this, specify "reuse=1" in the filesystem clause, and FFSB will
verify the fileset first, and if it checks out it will use it.
Otherwise, it will remove everything and re-create the filesets for
that filesystem.
Threadgroups:
An arbitrary number of threadgroups with differing numbers of threads
and operation mixes can be specified. The operations are specified
using a weighting for each operation, if an operation isn't specified
it's weighting is assumed to be zero (not used).
"Think-time" for a threadgroup may also be specified in millisecond
amounts using the "op_delay" parameter, where every thread will wait
for the specified amount between each operation.
Operations:
All operations begin by randomly selecting a filesystem from the list
of filesystems specified in the profile. The distribution aims to be
uniform across all filesystems.
The seven operations are:
reads - read() calls with an overall amount and a blocksize
operates on existing files. Care must be taken to ensure
that the read amount is smaller than the size of any possible
file.
If random_read is specified, then the each individual blocks
will be read starting from a random point with the file, and
this will continune until the entire amount specifed has been
read. This offset of each random block will be totally
random to the byte level, unless the "alignio" global parameter
is on, and then the reads will be 4096 byte aligned. This is
generally recommended.
readall - Very similar to read above, except it doesn't take an
amount; it simply reads the entire file sequentially using the
read_blocksize. This is useful for situations where
different filesystems have differently sized files, and sequential
read patterns across all filesystems are desired.
writes - write() calls with an overall amount and blocksize
this is an overwrite operation and will not enlarge an existing
file, again one must be careful not to specify a write amount
that is larger than any possible file in the data set.
If random_write is specified, then the each individual blocks
will be written starting from a random point with the file, and
this will continune until the entire amount specifed has been
written out. This offset of each random block will be totally
random to the byte level, unless the "alignio" global parameter
is on, and then the writes will be 4096 byte aligned. This
is generally recommended.
If the fsync_flag parameter for the threadgroup is non-zero,
then after all of the write calls are finished, fsync() will
be called on the file descriptor before the file is closed.
creates - creates a file using open() call and determines the size
randomly between on the constraints (min_filesize and
max_filesize) for the selected filesystem. Write operations will
be done using the same blocksize as is specified for the
write operation.
deletes - calls unlink() on a filename and removes it from the
internal data-structures. One must be careful to ensure
there are enough files to delete at all times or else the benchmark
will terminate.
appends - calls write() using the append flag with an overall amount
and a blocksize to be appended onto a randomly chosen file.
metas - this is actually a mix of several different directory
operations. Each "meta" operation consists of two directory
creates, one directory remove, and a directory rename.
These operations are all carried out separately from the
other 5 operations.
Operation accounting:
Each operation which uses a blocksize counts each read/write of a
blocksize as an operation (reads,writes,creates, and appends) whereas
deletes and metas are considered single operations.
Running the benchmark:
There are three phases to running the benchmark, aging, fileset
creates, and the benchmark phase.
The create phase is carried out across all filesystems simultanously
with one dedicated thread per filesystem.
After the create phase, sync() is called to ensure all dirty data gets
written out before the benchmark phase begins, and sync() is again
called at the end of the benchmark phase. The time in sync() at the
end of the benchmark phase is counted as part of the benchmark phase.
Caveats/Holes/Bugs:
Aging and aging across multiple filesystems simultaneously hasn't been tested
very much.
If *any* i/o operation or system call/libc call fails, the benchmark
will terminate immediately.
The parser doesn't handle mal-formed or incorrect profiles very well
(or at all).
The parser doesn't check to make sure all of the appropriate options
have been specified. For example, if writes are specified in a
threadgroup but write_blocksize isn't specified, the parse won't catch
it, but the benchmark run will fail later on.
Configuration Files (new style):
New Style Configuration allows for arbitrary newlines between lines,
and comments using '#' at the start of a line. Also it allows tabs,
whitespace before and after configuration parameters.
The new style configuration file is broken up into three main parts:
global parameters, filesystems, and threadgroups
The sections must be in the above order.
Global parameters:
Global Paramters are described above, the first three are always
required. Example:
----------
num_filesystems=1
num_threadgroups=1
time=30 # time is in seconds
directio=0 # don't use direct io
alignio=1 # align random IOs to 4k
bufferedio=0 # this does nothing right now
verbose=0 # this does nothing right now
# calls and external command and waits
# everything until the newline is taken
# so you can have abritrary parmeters
callout=synchronize.sh myhostname
---------
All of these must appear in this order, though you can leave out the
optional ones.
Filesystems:
Filesystems describe differnt logical sets of files residing in
different directorys. There is no strict requirement that they
actually be on different filesystems, only that the directory
specified already exists.
Filesystems are specified by a clause with a filesystem number like
this:
[filesystem0]
location=/mnt/testing/
num_files=10
num_dirs=1
max_filesize=4096
min_filesize=4096
[end0]
The clause must always begin with [filesystemX] and end with [endX]
where X is the number of that filesystem.
You should start wiht X = 0, and increment by one for each following
filesystem. If they are out of order, things will likely break.
The required information for each filesystem is: location, num_files,
num_dirs, max_filesize, and min_filesize. Beyond those the following
four options are supported:
reuse=1 # check the filesystem to see if it is reusable
# filesystem aging, three components required
# takes agefs=1 to turn it on
# then a valid threadgroup specification
# then a desired utilization percentage
agefs=1 # age the filesystem according to the following threadgroup
[threadgroup0]
num_threads=10
write_size=40960
write_blocksize=4096
create_weight=10
append_weight=10
delete_weight=1
[end0]
desired_util=0.20 # In this case, age until the fs is 20% full
create_blocksize=4096 # specify the blocksize to write()
# for creating the fileset, defaults to 4096
age_blocksize=4096 # specify the blocksize to write() for aging
Also, to allow lazy people to use lots of filesystems, we support
filesystem inheritance, which simply copies all options but the
location from the previous filesystem clause if nothing is specified.
Obviously, this doesn't work for filesystem0. (May not work for aging
either?)
Full blown filesystem clause example:
----
[filesystem0]
# required parts
location=/home/sonny/tmp
num_files=100
num_dirs=100
max_filesize=65536
min_filesize=4096
# aging part
agefs=0
[threadgroup0]
num_threads=10
write_size=40960
write_blocksize=4096
create_weight=10
append_weight=10
delete_weight=1
[end0]
desired_util=0.02 # age until 2% full
# other optional commands
create_blocksize=1024 # use a small create blocksize
age_blocksize=1024 # and smaller age create blocksize
reuse=0 # don't reuse it
[end0]
--
Threadgroups:
Threadgropus are very similar to filesystems in that any number of
them can be specified in clauses, and they must be in order starting
with threadgroup0.
Example:
---
[threadgroup0]
num_threads=32
read_weight=4
append_weight=1
write_size=4096
write_blocksize=4096
read_size=4096
read_blocksize=4096
[end0]
---
In a threadgroup clause, num_threads is required and must be at least
1. Then, at least one operation must be given a weight greater than 0
to be a valid threadgroup. Operations can be given a weighting of 0,
and in this case they are ignored.
Certain operations will also require other commands, for example, if
read_weight is greater than zero, then one must also include a
read_size and a read_blocksize. Here's the table of requirements and
options:
Operation Requirements Options
-- -- --
read_weight read_size, read_blocksize read_random
readall_weight read_blocksize none
write_weight write_size, write_blocksize write_random,fsync_file
create_weight write_blocksize or create_blocksize none
append_weight write_blocksize, write_size none
delete_weight none none
meta_weight none none
Other threadgroup options:
op_delay=10 # specify a wait between operations in milli-seconds
bindfs=3 # This allows you to restrict a threadgroup's operation
# to a specific filesystem number. Currently only
# binding to one specific filesystem is supported
+880
View File
@@ -0,0 +1,880 @@
# generated automatically by aclocal 1.10.1 -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
# 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
m4_if(AC_AUTOCONF_VERSION, [2.61],,
[m4_warning([this file was generated for autoconf 2.61.
You have another version of autoconf. It may work, but is not guaranteed to.
If you have problems, you may need to regenerate the build system entirely.
To do so, use the procedure documented by the package, typically `autoreconf'.])])
# Copyright (C) 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_AUTOMAKE_VERSION(VERSION)
# ----------------------------
# Automake X.Y traces this macro to ensure aclocal.m4 has been
# generated from the m4 files accompanying Automake X.Y.
# (This private macro should not be called outside this file.)
AC_DEFUN([AM_AUTOMAKE_VERSION],
[am__api_version='1.10'
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
dnl require some minimum version. Point them to the right macro.
m4_if([$1], [1.10.1], [],
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
])
# _AM_AUTOCONF_VERSION(VERSION)
# -----------------------------
# aclocal traces this macro to find the Autoconf version.
# This is a private macro too. Using m4_define simplifies
# the logic in aclocal, which can simply ignore this definition.
m4_define([_AM_AUTOCONF_VERSION], [])
# AM_SET_CURRENT_AUTOMAKE_VERSION
# -------------------------------
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
[AM_AUTOMAKE_VERSION([1.10.1])dnl
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
_AM_AUTOCONF_VERSION(AC_AUTOCONF_VERSION)])
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
#
# Of course, Automake must honor this variable whenever it calls a
# tool from the auxiliary directory. The problem is that $srcdir (and
# therefore $ac_aux_dir as well) can be either absolute or relative,
# depending on how configure is run. This is pretty annoying, since
# it makes $ac_aux_dir quite unusable in subdirectories: in the top
# source directory, any form will work fine, but in subdirectories a
# relative path needs to be adjusted first.
#
# $ac_aux_dir/missing
# fails when called from a subdirectory if $ac_aux_dir is relative
# $top_srcdir/$ac_aux_dir/missing
# fails if $ac_aux_dir is absolute,
# fails when called from a subdirectory in a VPATH build with
# a relative $ac_aux_dir
#
# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
# are both prefixed by $srcdir. In an in-source build this is usually
# harmless because $srcdir is `.', but things will broke when you
# start a VPATH build or use an absolute $srcdir.
#
# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
# and then we would define $MISSING as
# MISSING="\${SHELL} $am_aux_dir/missing"
# This will work as long as MISSING is not called from configure, because
# unfortunately $(top_srcdir) has no meaning in configure.
# However there are other variables, like CC, which are often used in
# configure, and could therefore not use this "fixed" $ac_aux_dir.
#
# Another solution, used here, is to always expand $ac_aux_dir to an
# absolute PATH. The drawback is that using absolute paths prevent a
# configured tree to be moved without reconfiguration.
AC_DEFUN([AM_AUX_DIR_EXPAND],
[dnl Rely on autoconf to set up CDPATH properly.
AC_PREREQ([2.50])dnl
# expand $ac_aux_dir to an absolute path
am_aux_dir=`cd $ac_aux_dir && pwd`
])
# AM_CONDITIONAL -*- Autoconf -*-
# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 8
# AM_CONDITIONAL(NAME, SHELL-CONDITION)
# -------------------------------------
# Define a conditional.
AC_DEFUN([AM_CONDITIONAL],
[AC_PREREQ(2.52)dnl
ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
AC_SUBST([$1_TRUE])dnl
AC_SUBST([$1_FALSE])dnl
_AM_SUBST_NOTMAKE([$1_TRUE])dnl
_AM_SUBST_NOTMAKE([$1_FALSE])dnl
if $2; then
$1_TRUE=
$1_FALSE='#'
else
$1_TRUE='#'
$1_FALSE=
fi
AC_CONFIG_COMMANDS_PRE(
[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
AC_MSG_ERROR([[conditional "$1" was never defined.
Usually this means the macro was only invoked conditionally.]])
fi])])
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 9
# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
# written in clear, in which case automake, when reading aclocal.m4,
# will think it sees a *use*, and therefore will trigger all it's
# C support machinery. Also note that it means that autoscan, seeing
# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
# _AM_DEPENDENCIES(NAME)
# ----------------------
# See how the compiler implements dependency checking.
# NAME is "CC", "CXX", "GCJ", or "OBJC".
# We try a few techniques and use that to set a single cache variable.
#
# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
# dependency, and given that the user is not expected to run this macro,
# just rely on AC_PROG_CC.
AC_DEFUN([_AM_DEPENDENCIES],
[AC_REQUIRE([AM_SET_DEPDIR])dnl
AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
AC_REQUIRE([AM_MAKE_INCLUDE])dnl
AC_REQUIRE([AM_DEP_TRACK])dnl
ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
[$1], CXX, [depcc="$CXX" am_compiler_list=],
[$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
[$1], UPC, [depcc="$UPC" am_compiler_list=],
[$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
[depcc="$$1" am_compiler_list=])
AC_CACHE_CHECK([dependency style of $depcc],
[am_cv_$1_dependencies_compiler_type],
[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
# We make a subdir and do the tests there. Otherwise we can end up
# making bogus files that we don't know about and never remove. For
# instance it was reported that on HP-UX the gcc test will end up
# making a dummy file named `D' -- because `-MD' means `put the output
# in D'.
mkdir conftest.dir
# Copy depcomp to subdir because otherwise we won't find it if we're
# using a relative directory.
cp "$am_depcomp" conftest.dir
cd conftest.dir
# We will build objects and dependencies in a subdirectory because
# it helps to detect inapplicable dependency modes. For instance
# both Tru64's cc and ICC support -MD to output dependencies as a
# side effect of compilation, but ICC will put the dependencies in
# the current directory while Tru64 will put them in the object
# directory.
mkdir sub
am_cv_$1_dependencies_compiler_type=none
if test "$am_compiler_list" = ""; then
am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
fi
for depmode in $am_compiler_list; do
# Setup a source with many dependencies, because some compilers
# like to wrap large dependency lists on column 80 (with \), and
# we should not choose a depcomp mode which is confused by this.
#
# We need to recreate these files for each test, as the compiler may
# overwrite some of them when testing with obscure command lines.
# This happens at least with the AIX C compiler.
: > sub/conftest.c
for i in 1 2 3 4 5 6; do
echo '#include "conftst'$i'.h"' >> sub/conftest.c
# Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
# Solaris 8's {/usr,}/bin/sh.
touch sub/conftst$i.h
done
echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
case $depmode in
nosideeffect)
# after this tag, mechanisms are not by side-effect, so they'll
# only be used when explicitly requested
if test "x$enable_dependency_tracking" = xyes; then
continue
else
break
fi
;;
none) break ;;
esac
# We check with `-c' and `-o' for the sake of the "dashmstdout"
# mode. It turns out that the SunPro C++ compiler does not properly
# handle `-M -o', and we need to detect this.
if depmode=$depmode \
source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
$SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
>/dev/null 2>conftest.err &&
grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
${MAKE-make} -s -f confmf > /dev/null 2>&1; then
# icc doesn't choke on unknown options, it will just issue warnings
# or remarks (even with -Werror). So we grep stderr for any message
# that says an option was ignored or not supported.
# When given -MP, icc 7.0 and 7.1 complain thusly:
# icc: Command line warning: ignoring option '-M'; no argument required
# The diagnosis changed in icc 8.0:
# icc: Command line remark: option '-MP' not supported
if (grep 'ignoring option' conftest.err ||
grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
am_cv_$1_dependencies_compiler_type=$depmode
break
fi
fi
done
cd ..
rm -rf conftest.dir
else
am_cv_$1_dependencies_compiler_type=none
fi
])
AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
AM_CONDITIONAL([am__fastdep$1], [
test "x$enable_dependency_tracking" != xno \
&& test "$am_cv_$1_dependencies_compiler_type" = gcc3])
])
# AM_SET_DEPDIR
# -------------
# Choose a directory name for dependency files.
# This macro is AC_REQUIREd in _AM_DEPENDENCIES
AC_DEFUN([AM_SET_DEPDIR],
[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
])
# AM_DEP_TRACK
# ------------
AC_DEFUN([AM_DEP_TRACK],
[AC_ARG_ENABLE(dependency-tracking,
[ --disable-dependency-tracking speeds up one-time build
--enable-dependency-tracking do not reject slow dependency extractors])
if test "x$enable_dependency_tracking" != xno; then
am_depcomp="$ac_aux_dir/depcomp"
AMDEPBACKSLASH='\'
fi
AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
AC_SUBST([AMDEPBACKSLASH])dnl
_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
])
# Generate code to set up dependency tracking. -*- Autoconf -*-
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
#serial 3
# _AM_OUTPUT_DEPENDENCY_COMMANDS
# ------------------------------
AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
[for mf in $CONFIG_FILES; do
# Strip MF so we end up with the name of the file.
mf=`echo "$mf" | sed -e 's/:.*$//'`
# Check whether this is an Automake generated Makefile or not.
# We used to match only the files named `Makefile.in', but
# some people rename them; so instead we look at the file content.
# Grep'ing the first line is not enough: some people post-process
# each Makefile.in and add a new line on top of each file to say so.
# Grep'ing the whole file is not good either: AIX grep has a line
# limit of 2048, but all sed's we know have understand at least 4000.
if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
dirpart=`AS_DIRNAME("$mf")`
else
continue
fi
# Extract the definition of DEPDIR, am__include, and am__quote
# from the Makefile without running `make'.
DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
test -z "$DEPDIR" && continue
am__include=`sed -n 's/^am__include = //p' < "$mf"`
test -z "am__include" && continue
am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
# When using ansi2knr, U may be empty or an underscore; expand it
U=`sed -n 's/^U = //p' < "$mf"`
# Find all dependency output files, they are included files with
# $(DEPDIR) in their names. We invoke sed twice because it is the
# simplest approach to changing $(DEPDIR) to its actual value in the
# expansion.
for file in `sed -n "
s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
# Make sure the directory exists.
test -f "$dirpart/$file" && continue
fdir=`AS_DIRNAME(["$file"])`
AS_MKDIR_P([$dirpart/$fdir])
# echo "creating $dirpart/$file"
echo '# dummy' > "$dirpart/$file"
done
done
])# _AM_OUTPUT_DEPENDENCY_COMMANDS
# AM_OUTPUT_DEPENDENCY_COMMANDS
# -----------------------------
# This macro should only be invoked once -- use via AC_REQUIRE.
#
# This code is only required when automatic dependency tracking
# is enabled. FIXME. This creates each `.P' file that we will
# need in order to bootstrap the dependency handling code.
AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
[AC_CONFIG_COMMANDS([depfiles],
[test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
[AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
])
# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 8
# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS.
AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)])
# Do all the work for Automake. -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
# 2005, 2006, 2008 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 13
# This macro actually does too much. Some checks are only needed if
# your package does certain things. But this isn't really a big deal.
# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
# AM_INIT_AUTOMAKE([OPTIONS])
# -----------------------------------------------
# The call with PACKAGE and VERSION arguments is the old style
# call (pre autoconf-2.50), which is being phased out. PACKAGE
# and VERSION should now be passed to AC_INIT and removed from
# the call to AM_INIT_AUTOMAKE.
# We support both call styles for the transition. After
# the next Automake release, Autoconf can make the AC_INIT
# arguments mandatory, and then we can depend on a new Autoconf
# release and drop the old call support.
AC_DEFUN([AM_INIT_AUTOMAKE],
[AC_PREREQ([2.60])dnl
dnl Autoconf wants to disallow AM_ names. We explicitly allow
dnl the ones we care about.
m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
AC_REQUIRE([AC_PROG_INSTALL])dnl
if test "`cd $srcdir && pwd`" != "`pwd`"; then
# Use -I$(srcdir) only when $(srcdir) != ., so that make's output
# is not polluted with repeated "-I."
AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
# test to see if srcdir already configured
if test -f $srcdir/config.status; then
AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
fi
fi
# test whether we have cygpath
if test -z "$CYGPATH_W"; then
if (cygpath --version) >/dev/null 2>/dev/null; then
CYGPATH_W='cygpath -w'
else
CYGPATH_W=echo
fi
fi
AC_SUBST([CYGPATH_W])
# Define the identity of the package.
dnl Distinguish between old-style and new-style calls.
m4_ifval([$2],
[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
AC_SUBST([PACKAGE], [$1])dnl
AC_SUBST([VERSION], [$2])],
[_AM_SET_OPTIONS([$1])dnl
dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
[m4_fatal([AC_INIT should be called with package and version arguments])])dnl
AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
_AM_IF_OPTION([no-define],,
[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
# Some tools Automake needs.
AC_REQUIRE([AM_SANITY_CHECK])dnl
AC_REQUIRE([AC_ARG_PROGRAM])dnl
AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
AM_MISSING_PROG(AUTOCONF, autoconf)
AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
AM_MISSING_PROG(AUTOHEADER, autoheader)
AM_MISSING_PROG(MAKEINFO, makeinfo)
AM_PROG_INSTALL_SH
AM_PROG_INSTALL_STRIP
AC_REQUIRE([AM_PROG_MKDIR_P])dnl
# We need awk for the "check" target. The system "awk" is bad on
# some platforms.
AC_REQUIRE([AC_PROG_AWK])dnl
AC_REQUIRE([AC_PROG_MAKE_SET])dnl
AC_REQUIRE([AM_SET_LEADING_DOT])dnl
_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
[_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
[_AM_PROG_TAR([v7])])])
_AM_IF_OPTION([no-dependencies],,
[AC_PROVIDE_IFELSE([AC_PROG_CC],
[_AM_DEPENDENCIES(CC)],
[define([AC_PROG_CC],
defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
AC_PROVIDE_IFELSE([AC_PROG_CXX],
[_AM_DEPENDENCIES(CXX)],
[define([AC_PROG_CXX],
defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
AC_PROVIDE_IFELSE([AC_PROG_OBJC],
[_AM_DEPENDENCIES(OBJC)],
[define([AC_PROG_OBJC],
defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
])
])
# When config.status generates a header, we must update the stamp-h file.
# This file resides in the same directory as the config header
# that is generated. The stamp files are numbered to have different names.
# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
# loop where config.status creates the headers, so we can generate
# our stamp files there.
AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
[# Compute $1's index in $config_headers.
_am_arg=$1
_am_stamp_count=1
for _am_header in $config_headers :; do
case $_am_header in
$_am_arg | $_am_arg:* )
break ;;
* )
_am_stamp_count=`expr $_am_stamp_count + 1` ;;
esac
done
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_PROG_INSTALL_SH
# ------------------
# Define $install_sh.
AC_DEFUN([AM_PROG_INSTALL_SH],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"}
AC_SUBST(install_sh)])
# Copyright (C) 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 2
# Check whether the underlying file-system supports filenames
# with a leading dot. For instance MS-DOS doesn't.
AC_DEFUN([AM_SET_LEADING_DOT],
[rm -rf .tst 2>/dev/null
mkdir .tst 2>/dev/null
if test -d .tst; then
am__leading_dot=.
else
am__leading_dot=_
fi
rmdir .tst 2>/dev/null
AC_SUBST([am__leading_dot])])
# Check to see how 'make' treats includes. -*- Autoconf -*-
# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 3
# AM_MAKE_INCLUDE()
# -----------------
# Check to see how make treats includes.
AC_DEFUN([AM_MAKE_INCLUDE],
[am_make=${MAKE-make}
cat > confinc << 'END'
am__doit:
@echo done
.PHONY: am__doit
END
# If we don't find an include directive, just comment out the code.
AC_MSG_CHECKING([for style of include used by $am_make])
am__include="#"
am__quote=
_am_result=none
# First try GNU make style include.
echo "include confinc" > confmf
# We grep out `Entering directory' and `Leaving directory'
# messages which can occur if `w' ends up in MAKEFLAGS.
# In particular we don't look at `^make:' because GNU make might
# be invoked under some other name (usually "gmake"), in which
# case it prints its new name instead of `make'.
if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
am__include=include
am__quote=
_am_result=GNU
fi
# Now try BSD make style include.
if test "$am__include" = "#"; then
echo '.include "confinc"' > confmf
if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
am__include=.include
am__quote="\""
_am_result=BSD
fi
fi
AC_SUBST([am__include])
AC_SUBST([am__quote])
AC_MSG_RESULT([$_am_result])
rm -f confinc confmf
])
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 5
# AM_MISSING_PROG(NAME, PROGRAM)
# ------------------------------
AC_DEFUN([AM_MISSING_PROG],
[AC_REQUIRE([AM_MISSING_HAS_RUN])
$1=${$1-"${am_missing_run}$2"}
AC_SUBST($1)])
# AM_MISSING_HAS_RUN
# ------------------
# Define MISSING if not defined so far and test if it supports --run.
# If it does, set am_missing_run to use it, otherwise, to nothing.
AC_DEFUN([AM_MISSING_HAS_RUN],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
AC_REQUIRE_AUX_FILE([missing])dnl
test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
# Use eval to expand $SHELL
if eval "$MISSING --run true"; then
am_missing_run="$MISSING --run "
else
am_missing_run=
AC_MSG_WARN([`missing' script is too old or missing])
fi
])
# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_PROG_MKDIR_P
# ---------------
# Check for `mkdir -p'.
AC_DEFUN([AM_PROG_MKDIR_P],
[AC_PREREQ([2.60])dnl
AC_REQUIRE([AC_PROG_MKDIR_P])dnl
dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P,
dnl while keeping a definition of mkdir_p for backward compatibility.
dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
dnl Makefile.ins that do not define MKDIR_P, so we do our own
dnl adjustment using top_builddir (which is defined more often than
dnl MKDIR_P).
AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
case $mkdir_p in
[[\\/$]]* | ?:[[\\/]]*) ;;
*/*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
esac
])
# Helper functions for option handling. -*- Autoconf -*-
# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 3
# _AM_MANGLE_OPTION(NAME)
# -----------------------
AC_DEFUN([_AM_MANGLE_OPTION],
[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
# _AM_SET_OPTION(NAME)
# ------------------------------
# Set option NAME. Presently that only means defining a flag for this option.
AC_DEFUN([_AM_SET_OPTION],
[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
# _AM_SET_OPTIONS(OPTIONS)
# ----------------------------------
# OPTIONS is a space-separated list of Automake options.
AC_DEFUN([_AM_SET_OPTIONS],
[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
# -------------------------------------------
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
AC_DEFUN([_AM_IF_OPTION],
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
# Check to make sure that the build environment is sane. -*- Autoconf -*-
# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
# Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 4
# AM_SANITY_CHECK
# ---------------
AC_DEFUN([AM_SANITY_CHECK],
[AC_MSG_CHECKING([whether build environment is sane])
# Just in case
sleep 1
echo timestamp > conftest.file
# Do `set' in a subshell so we don't clobber the current shell's
# arguments. Must try -L first in case configure is actually a
# symlink; some systems play weird games with the mod time of symlinks
# (eg FreeBSD returns the mod time of the symlink's containing
# directory).
if (
set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
if test "$[*]" = "X"; then
# -L didn't work.
set X `ls -t $srcdir/configure conftest.file`
fi
rm -f conftest.file
if test "$[*]" != "X $srcdir/configure conftest.file" \
&& test "$[*]" != "X conftest.file $srcdir/configure"; then
# If neither matched, then we have a broken ls. This can happen
# if, for instance, CONFIG_SHELL is bash and it inherits a
# broken ls alias from the environment. This has actually
# happened. Such a system could not be considered "sane".
AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
alias in your environment])
fi
test "$[2]" = conftest.file
)
then
# Ok.
:
else
AC_MSG_ERROR([newly created file is older than distributed files!
Check your system clock])
fi
AC_MSG_RESULT(yes)])
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_PROG_INSTALL_STRIP
# ---------------------
# One issue with vendor `install' (even GNU) is that you can't
# specify the program used to strip binaries. This is especially
# annoying in cross-compiling environments, where the build's strip
# is unlikely to handle the host's binaries.
# Fortunately install-sh will honor a STRIPPROG variable, so we
# always use install-sh in `make install-strip', and initialize
# STRIPPROG with the value of the STRIP variable (set by the user).
AC_DEFUN([AM_PROG_INSTALL_STRIP],
[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
# Installed binaries are usually stripped using `strip' when the user
# run `make install-strip'. However `strip' might not be the right
# tool to use in cross-compilation environments, therefore Automake
# will honor the `STRIP' environment variable to overrule this program.
dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
if test "$cross_compiling" != no; then
AC_CHECK_TOOL([STRIP], [strip], :)
fi
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
AC_SUBST([INSTALL_STRIP_PROGRAM])])
# Copyright (C) 2006 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# _AM_SUBST_NOTMAKE(VARIABLE)
# ---------------------------
# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
# This macro is traced by Automake.
AC_DEFUN([_AM_SUBST_NOTMAKE])
# Check how to create a tarball. -*- Autoconf -*-
# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 2
# _AM_PROG_TAR(FORMAT)
# --------------------
# Check how to create a tarball in format FORMAT.
# FORMAT should be one of `v7', `ustar', or `pax'.
#
# Substitute a variable $(am__tar) that is a command
# writing to stdout a FORMAT-tarball containing the directory
# $tardir.
# tardir=directory && $(am__tar) > result.tar
#
# Substitute a variable $(am__untar) that extract such
# a tarball read from stdin.
# $(am__untar) < result.tar
AC_DEFUN([_AM_PROG_TAR],
[# Always define AMTAR for backward compatibility.
AM_MISSING_PROG([AMTAR], [tar])
m4_if([$1], [v7],
[am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
[m4_case([$1], [ustar],, [pax],,
[m4_fatal([Unknown tar format])])
AC_MSG_CHECKING([how to create a $1 tar archive])
# Loop over all known methods to create a tar archive until one works.
_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
_am_tools=${am_cv_prog_tar_$1-$_am_tools}
# Do not fold the above two line into one, because Tru64 sh and
# Solaris sh will not grok spaces in the rhs of `-'.
for _am_tool in $_am_tools
do
case $_am_tool in
gnutar)
for _am_tar in tar gnutar gtar;
do
AM_RUN_LOG([$_am_tar --version]) && break
done
am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
am__untar="$_am_tar -xf -"
;;
plaintar)
# Must skip GNU tar: if it does not support --format= it doesn't create
# ustar tarball either.
(tar --version) >/dev/null 2>&1 && continue
am__tar='tar chf - "$$tardir"'
am__tar_='tar chf - "$tardir"'
am__untar='tar xf -'
;;
pax)
am__tar='pax -L -x $1 -w "$$tardir"'
am__tar_='pax -L -x $1 -w "$tardir"'
am__untar='pax -r'
;;
cpio)
am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
am__untar='cpio -i -H $1 -d'
;;
none)
am__tar=false
am__tar_=false
am__untar=false
;;
esac
# If the value was cached, stop now. We just wanted to have am__tar
# and am__untar set.
test -n "${am_cv_prog_tar_$1}" && break
# tar/untar a dummy directory, and stop if the command works
rm -rf conftest.dir
mkdir conftest.dir
echo GrepMe > conftest.dir/file
AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
rm -rf conftest.dir
if test -s conftest.tar; then
AM_RUN_LOG([$am__untar <conftest.tar])
grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
fi
done
rm -rf conftest.dir
AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
AC_MSG_RESULT([$am_cv_prog_tar_$1])])
AC_SUBST([am__tar])
AC_SUBST([am__untar])
]) # _AM_PROG_TAR
@@ -0,0 +1,107 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 <stdlib.h>
#include <assert.h>
#include "cirlist.h"
#include "util.h"
void init_cirlist(struct cirlist *cl)
{
cl->count = 0;
cl->head = NULL;
}
int cl_empty(struct cirlist *cl)
{
return !(cl->count);
}
void cl_insert_tail(struct cirlist *cl , cldatatype object)
{
struct cnode *new = ffsb_malloc(sizeof(struct cnode));
new->obj = object;
if (cl->count == 0) {
assert(cl->head == NULL);
cl->head = new;
cl->head->next = cl->head;
cl->head->prev = cl->head;
cl->count = 1;
} else {
if (cl->count == 1) {
assert(cl->head->next == cl->head);
assert(cl->head->prev == cl->head);
cl->head->next = new;
cl->head->prev = new;
new->next = cl->head;
new->prev = cl->head;
} else {
assert(cl->head->next != cl->head);
assert(cl->head->prev != cl->head);
new->next = cl->head;
new->prev = (cl->head)->prev;
cl->head->prev->next = new;
cl->head->prev = new;
}
cl->count++;
}
}
cldatatype cl_remove_head(struct cirlist *cl)
{
struct cnode *oldhead = NULL;
struct cnode *newhead = NULL;
cldatatype ret = NULL;
if (cl->count == 0) {
assert(cl->head == NULL);
return NULL;
}
if (cl->count == 1) {
assert(cl->head->next == cl->head);
assert(cl->head->prev == cl->head);
oldhead = cl->head;
cl->head = NULL;
cl->count = 0;
} else if (cl->count == 2) {
oldhead = cl->head;
newhead = oldhead->next;
newhead->next = newhead;
newhead->prev = newhead;
cl->head = newhead;
cl->count = 1;
} else {
assert(cl->head->next != cl->head);
assert(cl->head->prev != cl->head);
oldhead = cl->head;
newhead = oldhead->next;
newhead->prev = oldhead->prev;
newhead->prev->next = newhead;
cl->head = newhead;
cl->count--;
}
ret = oldhead->obj;
oldhead->obj = (void *)(-1);
oldhead->next = (void *)(-1);
oldhead->prev = (void *)(-1);
free(oldhead);
return ret;
}
@@ -0,0 +1,41 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 _CIRLIST_H
#define _CIRLIST_H
#include "filelist.h"
typedef struct ffsb_file *cldatatype;
struct cnode {
cldatatype obj;
struct cnode *next;
struct cnode *prev;
};
struct cirlist {
int count;
struct cnode *head;
};
void init_cirlist(struct cirlist *cl);
int cl_empty(struct cirlist *cl);
void cl_insert_tail(struct cirlist *cl , cldatatype object);
cldatatype cl_remove_head(struct cirlist *cl);
#endif /* _CIRLIST_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,131 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.in by autoheader. */
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the `fseeko64' function. */
/* #undef HAVE_FSEEKO64 */
/* Define to 1 if you have the `gettimeofday' function. */
#define HAVE_GETTIMEOFDAY 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `m' library (-lm). */
#define HAVE_LIBM 1
/* Define to 1 if you have the `pthread' library (-lpthread). */
#define HAVE_LIBPTHREAD 1
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if you have the `lrand48_r' function. */
#define HAVE_LRAND48_R 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `mkdir' function. */
#define HAVE_MKDIR 1
/* Define to 1 if you have the `open64' function. */
/* #undef HAVE_OPEN64 */
/* Define to 1 if you have the <pthread.h> header file. */
#define HAVE_PTHREAD_H 1
/* Define to 1 if you have the `srand48_r' function. */
#define HAVE_SRAND48_R 1
/* Define to 1 if you have the `stat64' function. */
/* #undef HAVE_STAT64 */
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `system' function. */
#define HAVE_SYSTEM 1
/* Define to 1 if you have the <sys/limits.h> header file. */
/* #undef HAVE_SYS_LIMITS_H */
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <sys/vfs.h> header file. */
/* #undef HAVE_SYS_VFS_H */
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
#define HAVE_SYS_WAIT_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Name of package */
#define PACKAGE "ffsb"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME ""
/* Define to the full name and version of this package. */
#define PACKAGE_STRING ""
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME ""
/* Define to the version of this package. */
#define PACKAGE_VERSION ""
/* Define to 1 if the C compiler supports function prototypes. */
#define PROTOTYPES 1
/* Define to 1 if the `setvbuf' function takes the buffering type as its
second argument and the buffer pointer as the third, as on System V before
release 3. */
/* #undef SETVBUF_REVERSED */
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#define TIME_WITH_SYS_TIME 1
/* Version number of package */
#define VERSION "6.0-RC2"
/* Define to 1 if on AIX 3.
System headers sometimes define this.
We just want to avoid a redefinition error message. */
#ifndef _ALL_SOURCE
/* # undef _ALL_SOURCE */
#endif
/* Define like PROTOTYPES; this can be used by system headers. */
#define __PROTOTYPES 1
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
@@ -0,0 +1,130 @@
/* config.h.in. Generated from configure.in by autoheader. */
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the `fseeko64' function. */
#undef HAVE_FSEEKO64
/* Define to 1 if you have the `gettimeofday' function. */
#undef HAVE_GETTIMEOFDAY
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the `m' library (-lm). */
#undef HAVE_LIBM
/* Define to 1 if you have the `pthread' library (-lpthread). */
#undef HAVE_LIBPTHREAD
/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define to 1 if you have the `lrand48_r' function. */
#undef HAVE_LRAND48_R
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `mkdir' function. */
#undef HAVE_MKDIR
/* Define to 1 if you have the `open64' function. */
#undef HAVE_OPEN64
/* Define to 1 if you have the <pthread.h> header file. */
#undef HAVE_PTHREAD_H
/* Define to 1 if you have the `srand48_r' function. */
#undef HAVE_SRAND48_R
/* Define to 1 if you have the `stat64' function. */
#undef HAVE_STAT64
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the `strerror' function. */
#undef HAVE_STRERROR
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `system' function. */
#undef HAVE_SYSTEM
/* Define to 1 if you have the <sys/limits.h> header file. */
#undef HAVE_SYS_LIMITS_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/vfs.h> header file. */
#undef HAVE_SYS_VFS_H
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
#undef HAVE_SYS_WAIT_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to 1 if the C compiler supports function prototypes. */
#undef PROTOTYPES
/* Define to 1 if the `setvbuf' function takes the buffering type as its
second argument and the buffer pointer as the third, as on System V before
release 3. */
#undef SETVBUF_REVERSED
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
/* Version number of package */
#undef VERSION
/* Define to 1 if on AIX 3.
System headers sometimes define this.
We just want to avoid a redefinition error message. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
/* Define like PROTOTYPES; this can be used by system headers. */
#undef __PROTOTYPES
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,49 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(main.c)
AM_INIT_AUTOMAKE(ffsb, 6.0-RC2)
AM_CONFIG_HEADER(config.h)
AC_CANONICAL_HOST
dnl need to define _ALL_SOURCE and _THREAD_SAFE on AIX
AC_AIX
case "${host}" in
*aix*)
CFLAGS="${CFLAGS} -D_THREAD_SAFE"
;;
*linux*)
CFLAGS="${CFLAGS} -D_REENTRANT"
;;
*)
echo "detected unknown platform : ${host} : compiles may fail"
CFLAGS="${CFLAGS} -D_REENTRANT"
;;
esac
dnl Checks for programs.
AC_PROG_CC
dnl Checks for libraries.
dnl Replace `main' with a function in -lm:
AC_CHECK_LIB(m, main)
dnl Replace `main' with a function in -lpthread:
AC_CHECK_LIB(pthread, main)
dnl Checks for header files.
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(pthread.h fcntl.h limits.h stdint.h sys/time.h unistd.h sys/vfs.h sys/limits.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_HEADER_TIME
dnl Checks for library functions.
AC_FUNC_SETVBUF_REVERSED
AC_CHECK_FUNCS(system gettimeofday mkdir strerror open64 stat64 fseeko64 lrand48_r srand48_r)
AC_SUBST(CFLAGS)
AC_SUBST(CC)
AC_OUTPUT(Makefile, echo timestamp > stamp-h)
+472
View File
@@ -0,0 +1,472 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
# Copyright 1999, 2000 Free Software Foundation, Inc.
# 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, 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.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva <[email protected]>.
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# `libtool' can also be set to `yes' or `no'.
if test -z "$depfile"; then
base=`echo "$object" | sed -e 's,^.*/,,' -e 's,\.\([^.]*\)$,.P\1,'`
dir=`echo "$object" | sed 's,/.*$,/,'`
if test "$dir" = "$object"; then
dir=
fi
# FIXME: should be _deps on DOS.
depfile="$dir.deps/$base"
fi
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
"$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say).
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
## The second -e expression handles DOS-style file names with drive letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the `deleted header file' problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
tr ' ' '
' < "$tmpdepfile" |
## Some versions of gcc put a space before the `:'. On the theory
## that the space means something, we add a space to the output as
## well.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like `#:fec' to the end of the
# dependency line.
tr ' ' '
' < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
tr '
' ' ' >> $depfile
echo >> $depfile
# The second pass generates a dummy entry for each header file.
tr ' ' '
' < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> $depfile
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. This file always lives in the current directory.
# Also, the AIX compiler puts `$object:' at the start of each line;
# $object doesn't have directory information.
stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'`
tmpdepfile="$stripped.u"
outname="$stripped.o"
if test "$libtool" = yes; then
"$@" -Wc,-M
else
"$@" -M
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
if test -f "$tmpdepfile"; then
# Each line is of the form `foo.o: dependent.h'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
icc)
# Intel's C compiler understands `-MD -MF file'. However on
# icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
# ICC 7.0 will fill foo.d with something like
# foo.o: sub/foo.c
# foo.o: sub/foo.h
# which is wrong. We want:
# sub/foo.o: sub/foo.c
# sub/foo.o: sub/foo.h
# sub/foo.c:
# sub/foo.h:
# ICC 7.1 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using \ :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in `foo.d' instead, so we check for that too.
# Subdirectories are respected.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
tmpdepfile1="$dir.libs/$base.lo.d"
tmpdepfile2="$dir.libs/$base.d"
"$@" -Wc,-MD
else
tmpdepfile1="$dir$base.o.d"
tmpdepfile2="$dir$base.d"
"$@" -MD
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
if test -f "$tmpdepfile1"; then
tmpdepfile="$tmpdepfile1"
else
tmpdepfile="$tmpdepfile2"
fi
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
# That's a space and a tab in the [].
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the proprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test $1 != '--mode=compile'; do
shift
done
shift
fi
# Remove `-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for `:'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
"$@" $dashmflag |
sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
tr ' ' '
' < "$tmpdepfile" | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test $1 != '--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no
for arg in "$@"; do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix="`echo $object | sed 's/^.*\././'`"
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
sed '1,2d' "$tmpdepfile" | tr ' ' '
' | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the proprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test $1 != '--mode=compile'; do
shift
done
shift
fi
# Remove `-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E |
sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the proprocessed file to stdout, regardless of -o,
# because we must use -o when running libtool.
"$@" || exit $?
IFS=" "
for arg
do
case "$arg" in
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
echo " " >> "$depfile"
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
@@ -0,0 +1,119 @@
directio = 0
time = 10
[filesystem]
location = /mnt/test1
num_dirs = 100
size_weight 4k 33
size_weight 8k 21
size_weight 16k 13
size_weight 32k 10
size_weight 64k 8
size_weight 128k 5
size_weight 256k 4
size_weight 512k 3
size_weight 8m 2
size_weight 32m 1
# size_weight 1g 1
# min_filesize = 4k
# max_filesize = 10m
# num_files = 0
init_size = 100m
# init_size = 6GB
# init_size = 1gb
# init_util = 0.002
agefs = 0
[threadgroup]
num_threads = 10
write_size = 400
write_blocksize = 1024
create_weight = 10
append_weight = 10
delete_weight = 1
[end]
desired_util = 0.005
[end]
#[filesystem]
# location = /mnt/test1
# clone = /mnt/test2
#[end]
[threadgroup]
num_threads = 4
# bindfs = /mnt/test1
append_weight = 1
append_fsync_weight = 1
stat_weight = 1
# write_weight = 1
# write_fsync_weight = 1
# read_weight = 1
create_weight = 1
create_fsync_weight = 1
delete_weight = 1
readall_weight = 1
writeall_weight = 1
writeall_fsync_weight = 1
open_close_weight = 1
read_random = 0
write_random = 0
write_size = 40k
write_blocksize = 4k
read_size = 40k
read_blocksize = 4k
op_delay = 0
[stats]
enable_stats = 1
enable_range = 0
# ignore = close
# ignore = open
# ignore = lseek
# ignore = write
# ignore = read
msec_range 0.00 0.01
msec_range 0.01 0.02
msec_range 0.02 0.03
msec_range 0.03 0.04
msec_range 0.04 0.05
msec_range 0.05 0.1
msec_range 0.1 0.2
msec_range 0.2 0.5
msec_range 0.5 1.0
msec_range 1.0 2.0
msec_range 2.0 3.0
msec_range 3.0 4.0
msec_range 4.0 5.0
msec_range 5.0 10.0
msec_range 10.0 10000.0
[end]
[end]
#[threadgroup]
# num_threads = 1
#
# readall_weight = 0
# writeall_weight = 0
# createdir_weight = 0
#
# write_size = 4096
# write_blocksize = 4096
# read_size = 4096
# read_blocksize = 4096
#
# op_delay = 12
#[end]
@@ -0,0 +1,105 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 _FFSB_H_
#define _FFSB_H_
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include "config.h"
#include "ffsb_op.h"
#include "ffsb_tg.h"
#include "ffsb_fs.h"
/*
* The main thread wakes up once in so many seconds to check elapsed
* time this is a tunable for that sleep interval in seconds
*/
#define FFSB_TG_WAIT_TIME (1)
#define MARK printf("MARK FUNC: %s() @ %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
struct results {
struct rusage before;
struct rusage after;
double runtime;
double cputime;
double cpu_before;
double cpu_after;
double cpu_total;
};
struct ffsb_tg;
struct ffsb_fs;
typedef struct profile_config {
struct config_options *global;
struct container *fs_container;
struct container *tg_container;
} profile_config_t;
typedef struct ffsb_config {
unsigned time;
unsigned num_filesys;
unsigned num_threadgroups;
int num_totalthreads; /* gets calculated after init() */
struct ffsb_tg *groups;
struct ffsb_fs *filesystems;
struct profile_config *profile_conf;
char *callout; /* we will try and exec this */
struct results results;
} ffsb_config_t;
void init_ffsb_config(ffsb_config_t *fc, unsigned num_fs, unsigned num_tg);
/*
* this is kind of like a special case "constructor" which is only
* used by fs-aging code to build a fake config for the aging tg
*/
void init_ffsb_config_1fs(ffsb_config_t *fc, struct ffsb_fs *fs,
struct ffsb_tg *tg);
void destroy_ffsb_config(ffsb_config_t *fc);
/* getters/setters, parser only should use setters */
void fc_set_time(ffsb_config_t *fc, unsigned time);
void fc_set_num_totalthreads(ffsb_config_t *fc, int num);
/* num is zero-based */
/* get a particular threadgroup object */
struct ffsb_tg *fc_get_tg(ffsb_config_t *fc, unsigned num);
/* get a particular filesystem object */
struct ffsb_fs *fc_get_fs(ffsb_config_t *fc, unsigned num);
void fc_set_callout(ffsb_config_t *fc, char *callout);
char *fc_get_callout(ffsb_config_t *fc);
#endif
@@ -0,0 +1,112 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 <pthread.h>
#include <sys/time.h>
#include <sys/times.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>
#include "config.h"
#include "ffsb.h"
#include "util.h"
#include "parser.h"
void init_ffsb_config(ffsb_config_t *fc, unsigned num_fs, unsigned num_tg)
{
memset(fc, 0, sizeof(ffsb_config_t));
fc->num_totalthreads = -1;
fc->num_threadgroups = num_tg;
fc->num_filesys = num_fs;
fc->groups = ffsb_malloc(sizeof(ffsb_tg_t) * num_tg);
fc->filesystems = ffsb_malloc(sizeof(ffsb_fs_t) * num_fs);
}
void init_ffsb_config_1fs(ffsb_config_t *fc, ffsb_fs_t *fs, ffsb_tg_t *tg)
{
memset(fc, 0, sizeof(*fc));
fc->num_totalthreads = tg_get_numthreads(tg);
fc->num_threadgroups = 1;
fc->num_filesys = 1;
fc->groups = tg;
fc->filesystems = fs;
}
void destroy_ffsb_config(ffsb_config_t *fc)
{
int i;
for (i = 0; i < fc->num_filesys; i++)
destroy_ffsb_fs(&fc->filesystems[i]);
for (i = 0; i < fc->num_threadgroups; i++)
destroy_ffsb_tg(&fc->groups[i]);
free(fc->groups);
free(fc->filesystems);
}
void fc_set_time(ffsb_config_t *fc, unsigned time)
{
fc->time = time;
}
unsigned fc_get_num_filesys(ffsb_config_t *fc)
{
return fc->num_filesys;
}
struct ffsb_tg *fc_get_tg(ffsb_config_t *fc, unsigned num)
{
assert(num < fc->num_threadgroups);
return &fc->groups[num];
}
struct ffsb_fs *fc_get_fs(ffsb_config_t *fc, unsigned num)
{
assert(num < fc->num_filesys);
return &fc->filesystems[num];
}
void fc_set_num_totalthreads(ffsb_config_t *fc, int num)
{
assert(num > 0);
fc->num_totalthreads = num;
}
void fc_set_callout(ffsb_config_t *fc, char *callout)
{
if (fc->callout)
free(fc->callout);
fc->callout = ffsb_strdup(callout);
}
char *fc_get_callout(ffsb_config_t *fc)
{
return fc->callout;
}
@@ -0,0 +1,634 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include "ffsb_fs.h"
#include "util.h"
#include "fh.h"
/* First zero out struct, set num_dirs, and strdups basedir */
void init_ffsb_fs(ffsb_fs_t *fs, char *basedir, uint32_t num_data_dirs,
uint32_t numstartfiles, unsigned flags)
{
memset(fs, 0, sizeof(ffsb_fs_t));
fs->basedir = ffsb_strdup(basedir);
fs->num_dirs = num_data_dirs;
fs->num_start_files = numstartfiles;
fs->flags = flags;
fs->create_blocksize = FFSB_FS_DEFAULT_CREATE_BLOCKSIZE;
fs->age_blocksize = FFSB_FS_DEFAULT_AGE_BLOCKSIZE;
fs->age_fs = 0;
}
/*
* Does not remove files/dirs on disk, only frees up data
* structures
*/
void destroy_ffsb_fs(ffsb_fs_t *fs)
{
free(fs->basedir);
destroy_filelist(&fs->files);
destroy_filelist(&fs->fill);
destroy_filelist(&fs->meta);
}
void clone_ffsb_fs(ffsb_fs_t *target, ffsb_fs_t *orig)
{
target->basedir = orig->basedir;
target->flags = orig->flags;
/* !!!! hackish, write a filelist_clone() function later */
memcpy(&target->files, &orig->files, sizeof(orig->files));
memcpy(&target->fill, &orig->fill, sizeof(orig->fill));
memcpy(&target->meta, &orig->meta, sizeof(orig->meta));
target->num_dirs = orig->num_dirs;
target->num_start_files = orig->num_start_files;
target->minfilesize = orig->minfilesize;
target->maxfilesize = orig->maxfilesize;
target->start_fsutil = orig->start_fsutil;
target->desired_fsutil = orig->desired_fsutil;
target->age_fs = orig->age_fs;
target->num_age_dirs = orig->num_age_dirs;
target->aging_tg = orig->aging_tg;
target->create_blocksize = orig->create_blocksize;
target->age_blocksize = orig->age_blocksize;
memcpy(target->op_data, orig->op_data, sizeof(void *) * FFSB_NUMOPS);
}
static void add_files(ffsb_fs_t *fs, struct benchfiles *bf, int num,
uint64_t minsize, uint64_t maxsize, unsigned blocksize)
{
struct ffsb_file *cur;
int i, fd, condition = 0, has_directio = 0;
randdata_t rd;
char *buf = ffsb_malloc(blocksize);
uint64_t initial_free = getfsutil_size(fs->basedir);
if (fs_get_directio(fs)) {
has_directio = 1;
fs_set_directio(fs, 0);
}
assert(blocksize);
init_random(&rd, 0);
if (num)
condition = num;
else if (fs->init_size) {
if (getfsutil(fs->basedir) != initial_free ||
fs->init_size > (getfsutil_size(fs->basedir) -
initial_free))
condition = 1;
else
condition = 0;
}
else if (fs->init_fsutil) {
if (fs->init_fsutil > getfsutil(fs->basedir))
condition = 1;
else
condition = 0;
}
while (condition) {
uint64_t size;
if (fs->num_weights) {
int num = 1 + getrandom(&rd, fs->sum_weights);
int curop = 0;
while (fs->size_weights[curop].weight < num) {
num -= fs->size_weights[curop].weight;
curop++;
}
size = fs->size_weights[curop].size;
}
else
size = minsize + getllrandom(&rd, maxsize - minsize);
cur = add_file(bf, size, &rd);
fd = fhopencreate(cur->name, NULL, fs);
writefile_helper(fd, size, blocksize, buf, NULL, fs);
fhclose(fd, NULL, fs);
unlock_file_writer(cur);
if (num)
condition--;
else if (fs->init_size) {
if (fs->init_size > getfsutil_size(fs->basedir) -
initial_free)
condition = 1;
else
condition = 0;
}
else if (fs->init_fsutil) {
if (fs->init_fsutil > getfsutil(fs->basedir))
condition = 1;
else
condition = 0;
}
}
free(buf);
if (has_directio)
fs_set_directio(fs, 1);
}
static void age_fs(ffsb_fs_t *fs, double utilization);
static ffsb_fs_t *construct_new_fileset(ffsb_fs_t *fs);
static ffsb_fs_t *check_existing_fileset(ffsb_fs_t *fs);
void *construct_ffsb_fs(void *data)
{
ffsb_fs_t *fs = (ffsb_fs_t *)data;
ffsb_fs_t *ret = NULL;
if (fs_get_reuse_fs(fs)) {
printf("checking existing fs: %s\n", fs->basedir);
ret = check_existing_fileset(fs);
if (ret == NULL) {
printf("recreating new fileset\n");
ret = construct_new_fileset(fs);
}
} else {
printf("creating new fileset %s\n", fs->basedir);
ret = construct_new_fileset(fs);
}
if (ret == NULL) {
printf("fs setup on %s failed\n", fs->basedir);
exit(1);
}
return ret;
}
static int verify_file(struct benchfiles *bf, char *fname, void *fs_ptr)
{
ffsb_fs_t *fs = (ffsb_fs_t *)fs_ptr;
uint64_t minsize = fs->minfilesize;
uint64_t maxsize = fs->maxfilesize;
uint64_t filesize = 0;
int fd = 0;
DIR *dirptr = NULL;
/* If it is a directory and it passed the name verification we
* don't need to do anything here
*/
dirptr = opendir(fname);
if (dirptr) {
closedir(dirptr);
return 0;
}
fd = open(fname, O_RDONLY);
/* If we can't open it for read we're done */
if (fd < 0) {
printf("verify_file: error opening %s for readonly\n", fname);
perror(fname);
return 1;
}
close(fd);
filesize = ffsb_get_filesize(fname);
if (filesize < minsize || filesize > maxsize) {
printf("size %llu bytes for file %s is invalid\n",
filesize, fname);
return 1;
}
return 0;
}
/* Record the number of files and directorys there are supposed to be
* grab (check and build the structures) the regular data fileset then
* check to make sure the number of directories and files in that
* filelist matches up. Then grab the meta filelist and verify that
* the meta filelist is empty. Set up the filelist for fill (aging)
* and setup the ops for the benchmark.
*/
static ffsb_fs_t *check_existing_fileset(ffsb_fs_t *fs)
{
char buf[FILENAME_MAX * 3];
int retval = 0;
uint32_t num_dirs = fs->num_dirs;
uint32_t num_files = fs->num_start_files;
if (fs->age_fs) {
printf("Aging and reusing the fileset are mutually "
"exclusive\n");
printf("aborting\n");
return NULL;
}
/* Set up bench/age dir */
if (FILENAME_MAX <=
snprintf(buf, FILENAME_MAX, "%s/%s", fs->basedir, FILES_BASE)) {
printf("pathname \"%s\" is too long, aborting\n", buf);
return NULL;
}
/* Make a "dummy" filelist that has numsubdirs set to 0 and
* numstartfiles set to 0
*/
init_filelist(&fs->files, buf, FILES_BASE, 0, 0);
retval = grab_old_fileset(&fs->files, buf, verify_file, fs);
if (retval)
return NULL;
if ((get_listsize(&fs->files) != num_files) ||
(get_numsubdirs(&fs->files) != num_dirs)) {
printf("check_existing_fileset: number of files (%u)"
" or directorys (%u) don't match up\n",
get_listsize(&fs->files), get_numsubdirs(&fs->files));
destroy_filelist(&fs->files);
return NULL;
}
if (FILENAME_MAX <=
snprintf(buf, FILENAME_MAX, "%s/%s", fs->basedir, META_BASE)) {
printf("pathname \"%s\" is too long, aborting\n", buf);
return NULL;
}
init_filelist(&fs->meta, buf, META_BASE, 0, 1);
retval = grab_old_fileset(&fs->meta, buf, verify_file, fs);
if (retval) {
destroy_filelist(&fs->files);
return NULL;
}
if ((get_listsize(&fs->meta) != 0) ||
(get_numsubdirs(&fs->meta) != 0)) {
printf("check_existing_fileset: meta directory isn't empty\n"
"aborting\n");
destroy_filelist(&fs->files);
destroy_filelist(&fs->meta);
return NULL;
}
/* Even though we won't use it, we still need to be consistent
* here.
*/
init_filelist(&fs->fill, buf, AGE_BASE, 0, 0);
/* Have to do this or everything else could break. */
ops_setup_bench(fs);
return fs;
}
/*
* clean up fs, "rm -rf data meta"
* record utilization
* set up the dirs: files, meta
* age filesystem
* have ffsb_ops setup their data
* create starting files in files
*/
static ffsb_fs_t *construct_new_fileset(ffsb_fs_t *fs)
{
char buf[FILENAME_MAX * 3];
/* TODO: Convert this quick and dirty rm -rf to a "real"
* programmatic version, that doesn't rely on the rm command.
*/
if (FILENAME_MAX * 3 <= snprintf(buf, FILENAME_MAX * 3,
"rm -rf %s/data %s/meta",
fs->basedir, fs->basedir)) {
printf("pathname too long for command \"%s\"\n", buf);
return NULL;
}
if (ffsb_system(buf) < 0) {
perror(buf);
return NULL;
}
fs->start_fsutil = getfsutil(fs->basedir);
/* Set up bench/age dir */
if (FILENAME_MAX <=
snprintf(buf, FILENAME_MAX, "%s/%s", fs->basedir, FILES_BASE)) {
printf("pathname \"%s\" is too long, aborting\n", buf);
return NULL;
}
ffsb_mkdir(buf);
/* Regular files and aging share this directory */
init_filelist(&fs->files, buf, FILES_BASE, fs->num_dirs, 1);
init_filelist(&fs->fill, buf, AGE_BASE, fs->num_age_dirs, 1);
/* Set up meta dir */
snprintf(buf, FILENAME_MAX, "%s/%s", fs->basedir, META_BASE);
ffsb_mkdir(buf);
init_filelist(&fs->meta, buf, META_BASE, 0, 1);
/* Do aging */
if (fs->age_fs)
age_fs(fs, fs->desired_fsutil);
/* Call back into ops, set for benchmark */
ops_setup_bench(fs);
/* Create initial fileset */
add_files(fs, &fs->files, fs->num_start_files, fs->minfilesize,
fs->maxfilesize, fs->create_blocksize);
return fs;
}
struct poll_data {
ffsb_fs_t *fs;
double util;
};
static int fs_get_util(void *data)
{
struct poll_data *pd = (struct poll_data *) data;
double fsutil = getfsutil(pd->fs->basedir);
if (fsutil >= pd->util)
return 1;
return 0;
}
static void age_fs(ffsb_fs_t *fs, double utilization)
{
ffsb_barrier_t barrier;
pthread_t thread;
struct poll_data pdata;
ffsb_tg_t *tg = fs_get_aging_tg(fs);
tg_run_params_t params;
ffsb_config_t fc;
printf("aging fs %s from %.2lf to %.2lf\n", fs->basedir,
fs->start_fsutil, utilization);
ffsb_barrier_init(&barrier, tg_get_numthreads(tg));
init_ffsb_config_1fs(&fc, fs, tg);
pdata.fs = fs;
pdata.util = utilization;
params.tg = tg;
params.poll_fn = fs_get_util;
params.poll_data = &pdata;
params.wait_time = 1;
params.fc = &fc;
params.tg_barrier = NULL;
params.thread_barrier = &barrier;
/* Call back into ops, setup for aging */
ops_setup_age(fs);
/* Throw in some files to start off, so there's something */
add_files(fs, &fs->fill, 10, 0, 0, fs->age_blocksize);
pthread_create(&thread, NULL, tg_run, &params);
pthread_join(thread, NULL);
}
void fs_set_create_blocksize(ffsb_fs_t *fs, uint32_t blocksize)
{
fs->create_blocksize = blocksize;
}
void fs_set_age_blocksize(ffsb_fs_t *fs, uint32_t blocksize)
{
fs->age_blocksize = blocksize;
}
uint32_t fs_get_create_blocksize(ffsb_fs_t *fs)
{
return fs->create_blocksize;
}
uint32_t fs_get_age_blocksize(ffsb_fs_t *fs)
{
return fs->age_blocksize;
}
char *fs_get_basedir(ffsb_fs_t *fs)
{
return fs->basedir;
}
uint32_t fs_get_numstartfiles(ffsb_fs_t *fs)
{
return fs->num_start_files;
}
uint32_t fs_get_numdirs(ffsb_fs_t *fs)
{
return fs->num_dirs;
}
int fs_get_libcio(ffsb_fs_t *fs)
{
return fs->flags & FFSB_FS_LIBCIO;
}
void fs_set_libcio(ffsb_fs_t *fs, int lio)
{
if (lio)
fs->flags |= FFSB_FS_LIBCIO;
else
fs->flags &= ~0 & ~FFSB_FS_LIBCIO;
}
int fs_get_directio(ffsb_fs_t *fs)
{
return fs->flags & FFSB_FS_DIRECTIO;
}
void fs_set_directio(ffsb_fs_t *fs, int dio)
{
if (dio)
fs->flags |= FFSB_FS_DIRECTIO;
else
fs->flags &= ~0 & ~FFSB_FS_DIRECTIO;
}
int fs_get_alignio(ffsb_fs_t *fs)
{
return fs->flags & FFSB_FS_ALIGNIO4K;
}
void fs_set_alignio(ffsb_fs_t *fs, int aio)
{
if (aio)
fs->flags |= FFSB_FS_ALIGNIO4K;
else
fs->flags &= ~0 & ~FFSB_FS_ALIGNIO4K;
}
int fs_get_reuse_fs(ffsb_fs_t *fs)
{
return fs->flags & FFSB_FS_REUSE_FS;
}
void fs_set_reuse_fs(ffsb_fs_t *fs, int rfs)
{
if (rfs)
fs->flags |= FFSB_FS_REUSE_FS;
else
fs->flags &= ~0 & ~FFSB_FS_REUSE_FS;
}
struct benchfiles *fs_get_datafiles(ffsb_fs_t *fs)
{
return &fs->files;
}
struct benchfiles *fs_get_metafiles(ffsb_fs_t *fs)
{
return &fs->meta;
}
struct benchfiles *fs_get_agefiles(ffsb_fs_t *fs)
{
return &fs->fill;
}
void fs_set_aging_tg(ffsb_fs_t *fs, struct ffsb_tg *tg, double util)
{
fs->aging_tg = tg;
fs->age_fs = 1;
fs->desired_fsutil = util;
}
struct ffsb_tg *fs_get_aging_tg(ffsb_fs_t *fs)
{
return fs->aging_tg;
}
int fs_get_agefs(ffsb_fs_t *fs)
{
return fs->age_fs;
}
/* TODO: Implement this!!!*/
void fs_set_num_age_dirs(ffsb_fs_t *fs, uint32_t numdirs)
{
fs->num_age_dirs = numdirs;
}
void fs_set_opdata(ffsb_fs_t *fs, void *data, unsigned opnum)
{
fs->op_data[opnum] = data;
}
void *fs_get_opdata(ffsb_fs_t *fs, unsigned opnum)
{
return fs->op_data[opnum];
}
void fs_set_min_filesize(ffsb_fs_t *fs, uint64_t size)
{
fs->minfilesize = size;
}
void fs_set_max_filesize(ffsb_fs_t *fs, uint64_t size)
{
fs->maxfilesize = size;
}
uint64_t fs_get_min_filesize(ffsb_fs_t *fs)
{
return fs->minfilesize;
}
uint64_t fs_get_max_filesize(ffsb_fs_t *fs)
{
return fs->maxfilesize;
}
double fs_get_desired_fsutil(ffsb_fs_t *fs)
{
return fs->desired_fsutil;
}
void fs_print_config(ffsb_fs_t *fs)
{
char buf[256];
printf("FileSystem %s\n", fs->basedir);
printf("==========\n");
printf("\t num_dirs = %u\n", fs->num_dirs);
printf("\t starting files = %u\n", fs->num_start_files);
printf("\t\n");
if (fs->num_weights) {
int i;
printf("\t Fileset weight:\n");
for (i = 0; i < fs->num_weights; i++)
printf("\t\t %12llu (%6s) -> %u (%.2f\%)\n",
fs->size_weights[i].size,
ffsb_printsize(buf, fs->size_weights[i].size, 256),
fs->size_weights[i].weight,
((float)fs->size_weights[i].weight /
(float)fs->sum_weights) * 100);
}
else {
printf("\t min file size = %llu\t(%s)\n", fs->minfilesize,
ffsb_printsize(buf, fs->minfilesize, 256));
printf("\t max file size = %llu\t(%s)\n", fs->maxfilesize,
ffsb_printsize(buf, fs->maxfilesize, 256));
}
printf("\t directio = %s\n", (fs->flags & FFSB_FS_DIRECTIO) ?
"on" : "off");
printf("\t alignedio = %s\n", (fs->flags & FFSB_FS_ALIGNIO4K) ?
"on" : "off");
printf("\t bufferedio = %s\n", (fs->flags & FFSB_FS_LIBCIO) ?
"on" : "off");
printf("\t\n");
printf("\t aging is %s\n", (fs->age_fs) ? "on" : "off");
printf("\t current utilization = %.2f\%\n", getfsutil(fs->basedir)*100);
if (fs->age_fs) {
printf("\t desired utilization = %.2lf%\n", fs->desired_fsutil * 100);
printf("\t \n");
tg_print_config_aging(fs->aging_tg, fs->basedir);
}
printf("\t\n");
}
int fs_needs_stats(ffsb_fs_t *fs, syscall_t sys)
{
return (fs != NULL) ? (int)fs->fsd.config : 0;
}
void fs_add_stat(ffsb_fs_t *fs, syscall_t sys, uint32_t val)
{
if (fs)
ffsb_add_data(&fs->fsd, sys, val);
}
@@ -0,0 +1,184 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 _FFSB_FS_H_
#define _FFSB_FS_H_
#include "filelist.h"
#include "ffsb_op.h"
#include "ffsb_tg.h"
#include "ffsb_stats.h"
/* These are the base names for the different file types on a
* filesystem.
*/
#define FILES_BASE "data"
#define META_BASE "meta"
#define AGE_BASE "fill"
struct ffsb_tg;
typedef struct size_weight {
uint64_t size;
int weight;
} size_weight_t;
/* A filesystem object
* --
* represents a filesystem on disk, and maintains access to the different
* directories within it. Currently there are two directories created in
* each filesystem: data and meta
* "data" contains the aging files and the working set files
* "meta" only contains directories for use in the metadata operation
*
* Aging
* This object contains methods for aging the filesystem if needed
* a properly set up threadgroup is supplied by the parser which is run
* until the filesystem reaches the desired utilization
*
* Operations
* The semantics of a ffsb operation are always such that they occur on
* a filesystem, so the filesystem also hold operation specific data as
* an opaque type
* One example of how this is useful is the aging process, where a different
* set of files is operated upon than in the regular benchmark and the
* op_data is pointing to the "fill" set rather than the "files" set
*/
typedef struct ffsb_fs {
char *basedir;
struct benchfiles files;
struct benchfiles meta;
struct benchfiles fill;
int flags;
#define FFSB_FS_DIRECTIO (1 << 0)
#define FFSB_FS_ALIGNIO4K (1 << 1)
#define FFSB_FS_LIBCIO (1 << 2)
#define FFSB_FS_REUSE_FS (1 << 3)
/* These pararmeters pertain to files in the files and fill
* dirs. Meta dir only contains directories, starting with 0.
*/
uint32_t num_dirs;
uint32_t num_start_files;
uint64_t minfilesize, maxfilesize;
double init_fsutil;
uint64_t init_size;
/* These two parameters specify the blocksize to use for
* writes when creating and aging the fs.
*/
uint32_t create_blocksize, age_blocksize;
#define FFSB_FS_DEFAULT_CREATE_BLOCKSIZE 4096
#define FFSB_FS_DEFAULT_AGE_BLOCKSIZE 4096
double start_fsutil;
/* Aging data/parameters */
double desired_fsutil;
int age_fs;
uint32_t num_age_dirs;
/* Use an ffsb thread group to do the aging work */
struct ffsb_tg *aging_tg;
/* If a particular operation wants to maintain fs-specific
* data, it should use this array. Naturally, the ops must
* synchonize access to the data for now, they are all just
* putting pointers to a particular benchfiles struct here,
* which is already sync'ed
*/
void *op_data[FFSB_NUMOPS];
/* per-fs stats */
ffsb_statsc_t fsc;
ffsb_statsd_t fsd;
size_weight_t *size_weights;
unsigned num_weights;
unsigned sum_weights;
} ffsb_fs_t;
/* Set up the structure, zeros everything out and dups the basedir
* string
*/
void init_ffsb_fs(ffsb_fs_t *fs, char *basedir, uint32_t num_data_dirs,
uint32_t num_start_files, unsigned flags);
/* Does not remove files/dirs on disk, only frees up data
* structures
*/
void destroy_ffsb_fs(ffsb_fs_t *fs);
/* Set up the files and such on the disk including aging if requested.
* Should call back into each op, which initialize its op_data[]
* entry. Aging is done by starting the aging_tg thread group, and
* waiting until the desired utilization is achieved. It can (and is)
* be used with pthread_create(). Parameter should be a ffsb_fs_t * ,
* and it will return the same type
*/
void *construct_ffsb_fs(void *ffsb_fs_ptr);
/* Shallow clone, original should simply be discarded (not destroyed).
* Generally should only be used by parser to write into the config
* object
*/
void clone_ffsb_fs(ffsb_fs_t *target, ffsb_fs_t *original);
void fs_print_config(ffsb_fs_t *fs);
char *fs_get_basedir(ffsb_fs_t *fs);
int fs_get_directio(ffsb_fs_t *fs);
void fs_set_directio(ffsb_fs_t *fs, int dio);
int fs_get_alignio(ffsb_fs_t *fs);
void fs_set_alignio(ffsb_fs_t *fs, int aio);
int fs_get_libcio(ffsb_fs_t *fs);
void fs_set_libcio(ffsb_fs_t *fs, int lio);
int fs_get_reuse_fs(ffsb_fs_t *fs);
void fs_set_reuse_fs(ffsb_fs_t *fs, int rfs);
struct benchfiles *fs_get_datafiles(ffsb_fs_t *fs);
struct benchfiles *fs_get_metafiles(ffsb_fs_t *fs);
struct benchfiles *fs_get_agefiles(ffsb_fs_t *fs);
void fs_set_aging_tg(ffsb_fs_t *fs, struct ffsb_tg *, double util);
struct ffsb_tg *fs_get_aging_tg(ffsb_fs_t *fs);
int fs_get_agefs(ffsb_fs_t *fs);
void fs_set_opdata(ffsb_fs_t *fs, void *data, unsigned opnum);
void *fs_get_opdata(ffsb_fs_t *fs, unsigned opnum);
void fs_set_min_filesize(ffsb_fs_t *fs, uint64_t size);
void fs_set_max_filesize(ffsb_fs_t *fs, uint64_t size);
void fs_set_create_blocksize(ffsb_fs_t *fs, uint32_t blocksize);
void fs_set_age_blocksize(ffsb_fs_t *fs, uint32_t blocksize);
uint32_t fs_get_create_blocksize(ffsb_fs_t *fs);
uint32_t fs_get_age_blocksize(ffsb_fs_t *fs);
uint64_t fs_get_min_filesize(ffsb_fs_t *fs);
uint64_t fs_get_max_filesize(ffsb_fs_t *fs);
uint32_t fs_get_numstartfiles(ffsb_fs_t *fs);
uint32_t fs_get_numdirs(ffsb_fs_t *fs);
double fs_get_desired_fsutil(ffsb_fs_t *fs);
/* For these two, fs == NULL is OK */
int fs_needs_stats(ffsb_fs_t *fs, syscall_t s);
void fs_add_stat(ffsb_fs_t *fs, syscall_t sys, uint32_t val);
#endif /* _FFSB_FS_H_ */
@@ -0,0 +1,178 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "ffsb_op.h"
#include "fileops.h"
#include "metaops.h"
ffsb_op_t ffsb_op_list[] =
{{0, "read", ffsb_readfile, READ, fop_bench, NULL},
{1, "readall", ffsb_readall, READ, fop_bench, NULL},
{2, "write", ffsb_writefile, WRITE, fop_bench, NULL},
{3, "create", ffsb_createfile, WRITE, fop_bench, fop_age},
{4, "append", ffsb_appendfile, WRITE, fop_bench, fop_age},
{5, "delete", ffsb_deletefile, NA, fop_bench, fop_age},
{6, "metaop", ffsb_metaops, NA, metaops_metadir, NULL},
{7, "createdir", ffsb_createdir, NA, fop_bench, NULL},
{8, "stat", ffsb_stat, NA, fop_bench, NULL},
{9, "writeall", ffsb_writeall, WRITE, fop_bench, NULL},
{10, "writeall_fsync", ffsb_writeall_fsync, WRITE, fop_bench, NULL},
{11, "open_close", ffsb_open_close, NA, fop_bench, NULL},
{12, "write_fsync", ffsb_writefile_fsync, WRITE, fop_bench, NULL},
{13, "create_fsync", ffsb_createfile_fsync, WRITE, fop_bench, fop_age},
{14, "append_fsync", ffsb_appendfile_fsync, WRITE, fop_bench, fop_age},
};
void init_ffsb_op_results(ffsb_op_results_t *results)
{
memset(results, 0, sizeof(ffsb_op_results_t));
}
static int exclusive_op(ffsb_op_results_t *results, unsigned int op_num)
{
int i;
int ret = 0;
for (i = 0; i < FFSB_NUMOPS ; i++) {
if (i == op_num)
continue;
ret += results->ops[i];
}
if (ret)
return 0;
return 1;
}
static void generic_op_print(char *name, unsigned num, double op_pcnt,
double weigth_pcnt, double runtime, char *tput)
{
printf("%20s : %12u\t%10.2lf\t%6.3lf%%\t\t%6.3lf%%\t %11s\n",
name, num, num/runtime, op_pcnt, weigth_pcnt, tput);
}
static void print_op_results(unsigned int op_num, ffsb_op_results_t *results,
double runtime, unsigned total_ops,
unsigned total_weight)
{
char buf[256];
double op_pcnt = 100 * (double)results->ops[op_num] /
(double)total_ops;
double weight_pcnt = 100 * (double)results->op_weight[op_num] /
(double)total_weight;
if (ffsb_op_list[op_num].throughput) {
ffsb_printsize (buf, results->bytes[op_num] / runtime, 256);
sprintf(buf, "%s/sec\0", buf);
}
else
sprintf(buf, "NA\0");
generic_op_print(ffsb_op_list[op_num].op_name, results->ops[op_num],
op_pcnt, weight_pcnt, runtime, buf);
}
#if 0
static void print_op_throughput(unsigned int op_num, ffsb_op_results_t *results,
double runtime)
{
if (ffsb_op_list[op_num].op_exl_print_fn != NULL)
ffsb_op_list[op_num].op_exl_print_fn(results, runtime, op_num);
}
#endif
void print_results(struct ffsb_op_results *results, double runtime)
{
int i;
uint64_t total_ops = 0;
uint64_t total_weight = 0;
char buf[256];
for (i = 0; i < FFSB_NUMOPS ; i++) {
total_ops += results->ops[i];
total_weight += results->op_weight[i];
}
printf(" Op Name Transactions\t Trans/sec\t% Trans\t % Op Weight\t Throughput\n");
printf(" ======= ============\t =========\t=======\t ===========\t ==========\n");
for (i = 0; i < FFSB_NUMOPS ; i++)
if (results->ops[i] != 0)
print_op_results(i, results, runtime, total_ops,
total_weight);
printf("-\n%.2lf Transactions per Second\n\n", (double)total_ops / runtime);
if (results->write_bytes || results->read_bytes)
printf("Throughput Results\n===================\n");
if (results->read_bytes) {
ffsb_printsize(buf, results->read_bytes / runtime, 256);
printf("Read Throughput: %s/sec\n", buf);
}
if (results->write_bytes) {
ffsb_printsize(buf, results->write_bytes / runtime, 256);
printf("Write Throughput: %s/sec\n", buf);
}
}
char *op_get_name(int opnum)
{
return ffsb_op_list[opnum].op_name;
}
void ops_setup_bench(ffsb_fs_t *fs)
{
int i;
for (i = 0; i < FFSB_NUMOPS; i++)
ffsb_op_list[i].op_bench(fs, i);
}
void ops_setup_age(ffsb_fs_t *fs)
{
int i;
for (i = 0; i < FFSB_NUMOPS; i++)
if (ffsb_op_list[i].op_age)
ffsb_op_list[i].op_age(fs, i);
}
int ops_find_op(char *opname)
{
int i;
for (i = 0; i < FFSB_NUMOPS; i++)
if (!strcmp(opname, ffsb_op_list[i].op_name))
return i;
return -1;
}
void add_results(struct ffsb_op_results *target, struct ffsb_op_results *src)
{
int i;
target->read_bytes += src->read_bytes;
target->write_bytes += src->write_bytes;
for (i = 0; i < FFSB_NUMOPS; i++) {
target->ops[i] += src->ops[i];
target->op_weight[i] += src->op_weight[i];
target->bytes[i] += src->bytes[i];
}
}
void do_op(struct ffsb_thread *ft, struct ffsb_fs *fs, unsigned op_num)
{
ffsb_op_list[op_num].op_fn(ft, fs, op_num);
}
@@ -0,0 +1,102 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 _FFSB_OP_H_
#define _FFSB_OP_H_
#include <stdlib.h>
#include <sys/types.h>
#include <inttypes.h>
struct ffsb_op_results;
struct ffsb_thread;
struct ffsb_fs;
#define NA 0x00
#define READ 0x01
#define WRITE 0x02
/* This file handles all of the operations FFSB supports. It has
* tight interactions with the filesystem objects, but is otherwise
* pretty abstract.
*/
/* The op callback */
typedef void (*ffsb_op_fn)(struct ffsb_thread *, struct ffsb_fs *,
unsigned op_num);
/* Operation results printing function */
typedef void (*ffsb_op_print_fn)(struct ffsb_op_results *, double secs,
unsigned int op_num);
/* Operation specific initialization for a filesystem */
typedef void (*ffsb_op_fs_fn)(struct ffsb_fs *, unsigned opnum);
typedef struct ffsb_op {
unsigned int op_id;
char *op_name;
ffsb_op_fn op_fn;
unsigned int throughput;
/* The point of these two fields is to determine which set of
* files are being worked on. Currently either data, meta, or
* aging. Data and meta are mutually exclusive, so we only
* need two funcs.
*/
ffsb_op_fs_fn op_bench;
ffsb_op_fs_fn op_age;
} ffsb_op_t;
/* List of all operations, located in ffsb_op.c */
extern ffsb_op_t ffsb_op_list[];
/* This *must* be updated when a new operation is added or one is
* removed several other structures use it for statically sized arrays
*/
#define FFSB_NUMOPS (15)
/* Returns index of an op.
* Returns -1 if opname isn't found, and its case sensitive :)
*/
int ops_find_op(char *opname);
typedef struct ffsb_op_results {
/* Count of how many times each op was run */
unsigned int ops[FFSB_NUMOPS];
unsigned int op_weight[FFSB_NUMOPS];
uint64_t bytes[FFSB_NUMOPS];
uint64_t read_bytes;
uint64_t write_bytes;
} ffsb_op_results_t;
void init_ffsb_op_results(struct ffsb_op_results *);
void print_results(struct ffsb_op_results *results, double runtime);
char *op_get_name(int opnum);
/* Setup the ops for the benchmark */
void ops_setup_bench(struct ffsb_fs *fs);
/* setup the ops for aging the filesystem */
void ops_setup_age(struct ffsb_fs *fs);
void add_results(struct ffsb_op_results *target, struct ffsb_op_results *src);
/* Run this op, using this thread state, on this filesystem */
void do_op(struct ffsb_thread *ft, struct ffsb_fs *fs, unsigned op_num);
#endif /* _FFSB_OP_H_ */
@@ -0,0 +1,241 @@
#include <stdio.h>
#include <assert.h>
#include <limits.h>
#include "ffsb_stats.h"
#include "util.h"
char *syscall_names[] = {
"open",
"read",
"write",
"create",
"lseek",
"unlink",
"close",
"stat",
};
/* yuck, just for the parser anyway.. */
int ffsb_stats_str2syscall(char *str, syscall_t *sys)
{
int i;
int ret;
for (i = 0; i < FFSB_NUM_SYSCALLS; i++) {
ret = strncasecmp(syscall_names[i], str,
strlen(syscall_names[i]));
/* printf("%s = syscall_names[%d] vs %str ret = %d\n",
* syscall_names[i],i,str,ret);
*/
if (0 == ret) {
*sys = (syscall_t)i; /* ewww */
/* printf("matched syscall %s\n",syscall_names[i]); */
return 1;
}
}
printf("warning: failed to get match for syscall %s\n", str);
return 0;
}
void ffsb_statsc_init(ffsb_statsc_t *fsc)
{
fsc->num_buckets = 0;
fsc->buckets = NULL;
fsc->ignore_stats = 0;
}
void ffsb_statsc_addbucket(ffsb_statsc_t *fsc, uint32_t min, uint32_t max)
{
struct stat_bucket *temp;
fsc->num_buckets++;
/* printf("ffsb_realloc(): fsc_buckets = %d\n",fsc->num_buckets); */
temp = ffsb_realloc(fsc->buckets, sizeof(struct stat_bucket) *
fsc->num_buckets);
fsc->buckets = temp;
/* Convert to micro-secs from milli-secs */
fsc->buckets[fsc->num_buckets-1].min = min ;
fsc->buckets[fsc->num_buckets-1].max = max ;
}
void ffsb_statsc_destroy(ffsb_statsc_t *fsc)
{
free(fsc->buckets);
}
void ffsb_statsc_ignore_sys(ffsb_statsc_t *fsc, syscall_t s)
{
/* printf("fsis: oring 0x%x with 0x%x\n",
* fsc->ignore_stats,
* (1 << s ) );
*/
fsc->ignore_stats |= (1 << s);
}
int fsc_ignore_sys(ffsb_statsc_t *fsc, syscall_t s)
{
return fsc->ignore_stats & (1 << s);
}
void ffsb_statsd_init(ffsb_statsd_t *fsd, ffsb_statsc_t *fsc)
{
int i;
memset(fsd, 0, sizeof(*fsd));
for (i = 0; i < FFSB_NUM_SYSCALLS; i++) {
fsd->totals[i] = 0;
fsd->mins[i] = UINT_MAX;
fsd->maxs[i] = 0;
fsd->buckets[i] = ffsb_malloc(sizeof(uint32_t) *
fsc->num_buckets);
assert(fsd->buckets[i] != NULL);
memset(fsd->buckets[i], 0, sizeof(uint32_t) *
fsc->num_buckets);
}
fsd->config = fsc;
}
void ffsb_statsd_destroy(ffsb_statsd_t *fsd)
{
int i ;
for (i = 0 ; i < FFSB_NUM_SYSCALLS; i++)
free(fsd->buckets[i]);
}
void ffsb_add_data(ffsb_statsd_t *fsd, syscall_t s, uint32_t value)
{
unsigned num_buckets, i;
struct stat_bucket *bucket_defs;
if (!fsd || fsc_ignore_sys(fsd->config, s))
return;
if (value < fsd->mins[s])
fsd->mins[s] = value;
if (value > fsd->maxs[s])
fsd->maxs[s] = value;
fsd->counts[s]++;
fsd->totals[s] += value;
if (fsd->config->num_buckets == 0)
return;
num_buckets = fsd->config->num_buckets;
bucket_defs = fsd->config->buckets;
for (i = 0; i < num_buckets; i++) {
struct stat_bucket *b = &bucket_defs[i];
if (value <= b->max && value >= b->min) {
fsd->buckets[s][i]++;
break;
}
}
}
void ffsb_statsc_copy(ffsb_statsc_t *dest, ffsb_statsc_t *src)
{
memcpy(dest, src, sizeof(*src));
}
void ffsb_statsd_add(ffsb_statsd_t *dest, ffsb_statsd_t *src)
{
int i, j;
unsigned num_buckets;
if (dest->config != src->config)
printf("ffsb_statsd_add: warning configs do not"
"match for data being collected\n");
num_buckets = dest->config->num_buckets;
for (i = 0; i < FFSB_NUM_SYSCALLS; i++) {
dest->counts[i] += src->counts[i];
dest->totals[i] += src->totals[i];
if (src->mins[i] < dest->mins[i])
dest->mins[i] = src->mins[i];
if (src->maxs[i] > dest->maxs[i])
dest->maxs[i] = src->maxs[i];
for (j = 0; j < num_buckets; j++)
dest->buckets[i][j] += src->buckets[i][j];
}
}
static void print_buckets_helper(ffsb_statsc_t *fsc, uint32_t *buckets)
{
int i;
if (fsc->num_buckets == 0) {
printf(" -\n");
return;
}
for (i = 0; i < fsc->num_buckets; i++) {
struct stat_bucket *sb = &fsc->buckets[i];
printf("\t\t msec_range[%d]\t%f - %f : %8u\n",
i, (double)sb->min/1000.0f, (double)sb->max/1000.0f,
buckets[i]);
}
printf("\n");
}
void ffsb_statsd_print(ffsb_statsd_t *fsd)
{
int i;
printf("\nSystem Call Latency statistics in millisecs\n" "=====\n");
printf("\t\tMin\t\tAvg\t\tMax\t\tTotal Calls\n");
printf("\t\t========\t========\t========\t============\n");
for (i = 0; i < FFSB_NUM_SYSCALLS; i++)
if (fsd->counts[i]) {
printf("[%7s]\t%05f\t%05lf\t%05f\t%12u\n",
syscall_names[i], (float)fsd->mins[i] / 1000.0f,
(fsd->totals[i] / (1000.0f *
(double)fsd->counts[i])),
(float)fsd->maxs[i] / 1000.0f, fsd->counts[i]);
print_buckets_helper(fsd->config, fsd->buckets[i]);
}
}
#if 0 /* Testing */
void *ffsb_malloc(size_t s)
{
void *p = malloc(s);
assert(p != NULL);
return p;
}
int main(int arc, char *argv[])
{
ffsb_statsc_t fsc;
ffsb_statsd_t fsd;
int i ;
printf("init\n");
ffsb_statsc_init(&fsc, 10);
ffsb_statsc_setbucket(&fsc, 0, 0.0f, 50.0f);
ffsb_statsc_setbucket(&fsc, 1, 50.0f, 10000.0f);
ffsb_statsc_setbucket(&fsc, 2, 0.1f, 0.2f);
ffsb_statsc_setbucket(&fsc, 3, 0.0f, 50.0f);
ffsb_statsc_setbucket(&fsc, 4, 50.0f, 10000.0f);
ffsb_statsc_setbucket(&fsc, 5, 0.1f, 0.2f);
ffsb_statsc_setbucket(&fsc, 6, 0.0f, 50.0f);
ffsb_statsc_setbucket(&fsc, 7, 50.0f, 10000.0f);
ffsb_statsc_setbucket(&fsc, 8, 0.1f, 0.2f);
ffsb_statsc_setbucket(&fsc, 9, 50.0f, 10000.0f);
ffsb_statsd_init(&fsd, &fsc);
printf("test\n");
for (i = 0; i < 50000000; i++)
ffsb_add_data(&fsd, SYS_READ, (float)i);
printf("cleanup\n");
ffsb_statsd_destroy(&fsd);
ffsb_statsc_destroy(&fsc);
return 0;
}
#endif /* Testing */
@@ -0,0 +1,109 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2007
*
* 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 _FFSB_STATS_H_
#define _FFSB_STATS_H_
#include <inttypes.h>
/* Latency statistics collection extension.
*
* For now, we are going to collect latency info on each (most)
* syscalls using gettimeofday. Unfortunately, it is the
* responsibility of each operation to collect this timing info. We
* try to make this easier by providing a function that does the
* timing for supported syscalls.
*
* We want the ability to collect the average latency for a particular
* call, and also to collect latency info for user specified intervals
* -- called "buckets"
*/
struct stat_bucket {
uint32_t min;
uint32_t max;
/* max = 0 indicates uninitialized bucket */
};
/* These are all the syscalls we currently support */
typedef enum { SYS_OPEN = 0,
SYS_READ,
SYS_WRITE,
SYS_CREATE,
SYS_LSEEK,
SYS_UNLINK,
SYS_CLOSE,
SYS_STAT
} syscall_t;
/* ASCII versions of the syscall names */
extern char *syscall_names[];
/* Return 1 on success, 0 on error */
int ffsb_stats_str2syscall(char *, syscall_t *);
/* Keep it in sync with syscall_t */
#define FFSB_NUM_SYSCALLS (8UL)
/* What stats to collect, shared among all threads */
typedef struct ffsb_stats_config {
unsigned num_buckets;
struct stat_bucket *buckets;
/* Ignore stats collection for some syscalls.
* Each bit corresponds to one syscall.
*/
uint32_t ignore_stats;
} ffsb_statsc_t;
void ffsb_statsc_init(ffsb_statsc_t *);
void ffsb_statsc_addbucket(ffsb_statsc_t *, uint32_t min, uint32_t max);
void ffsb_statsc_ignore_sys(ffsb_statsc_t *, syscall_t s);
void ffsb_statsc_destroy(ffsb_statsc_t *);
/* If we are collecting stats, then the config field is non-NULL */
typedef struct ffsb_stats_data {
ffsb_statsc_t *config;
uint32_t counts[FFSB_NUM_SYSCALLS];
uint64_t totals[FFSB_NUM_SYSCALLS]; /* cumulative sums */
uint64_t mins[FFSB_NUM_SYSCALLS];
uint64_t maxs[FFSB_NUM_SYSCALLS];
uint32_t *buckets[FFSB_NUM_SYSCALLS]; /* bucket counters */
} ffsb_statsd_t ;
/* constructor/destructor */
void ffsb_statsd_init(ffsb_statsd_t *, ffsb_statsc_t *);
void ffsb_statsd_destroy(ffsb_statsd_t *);
/* Add data to a stats data struct. Value should be in microsecs
* _NOT_ milli-secs
*/
void ffsb_add_data(ffsb_statsd_t *, syscall_t, uint32_t);
/* Make a copy of a stats config */
void ffsb_statsc_copy(ffsb_statsc_t *, ffsb_statsc_t *);
/* Add two statsd structs together */
void ffsb_statsd_add(ffsb_statsd_t *, ffsb_statsd_t *);
/* Print out statsd structure */
void ffsb_statsd_print(ffsb_statsd_t *fsd);
/* Do we want stats for the specified syscall */
int fsc_ignore_sys(ffsb_statsc_t *fsc, syscall_t s);
#endif /* _FFSB_STATS_H_ */
@@ -0,0 +1,369 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 <string.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h>
#include "ffsb_tg.h"
#include "util.h"
void init_ffsb_tg(ffsb_tg_t *tg, unsigned num_threads, unsigned tg_num)
{
int i;
memset(tg, 0, sizeof(ffsb_tg_t));
tg->threads = ffsb_malloc(sizeof(ffsb_thread_t) * num_threads);
tg->tg_num = tg_num;
tg->num_threads = num_threads;
tg->bindfs = -1; /* default is not bound */
tg->thread_bufsize = 0;
for (i = 0 ; i < num_threads ; i++)
init_ffsb_thread(tg->threads + i, tg, 0, tg_num, i);
}
void destroy_ffsb_tg(ffsb_tg_t *tg)
{
int i;
for (i = 0; i < tg->num_threads; i++)
destroy_ffsb_thread(tg->threads + i);
free(tg->threads);
if (tg_needs_stats(tg))
ffsb_statsc_destroy(&tg->fsc);
}
void *tg_run(void *data)
{
tg_run_params_t *params = (tg_run_params_t *)data;
ffsb_tg_t *tg = params->tg;
int i;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
tg->start_barrier = params->thread_barrier;
/* Sum up the weights for use later by tg_get_op() */
tg->sum_weights = 0;
for (i = 0; i < FFSB_NUMOPS; i++)
tg->sum_weights += tg->op_weights[i];
tg->fc = params->fc;
tg->flagval = -1;
tg->stopval = 1;
/* spawn threads */
for (i = 0; i < tg->num_threads; i++) {
ffsb_thread_t *ft = &tg->threads[i];
pthread_create(&ft->ptid, &attr, ft_run, ft);
}
if (params->tg_barrier)
ffsb_barrier_wait(params->tg_barrier);
/* wait for termination condition to be true */
do {
ffsb_sleep(params->wait_time);
} while (params->poll_fn(params->poll_data) == 0);
/* set flag value */
tg->flagval = tg->stopval;
/* wait on theads to finish */
for (i = 0; i < tg->num_threads; i++)
pthread_join(tg->threads[i].ptid, NULL);
return NULL;
}
/* Needs to set params->opnum and params->fs */
void tg_get_op(ffsb_tg_t *tg, randdata_t *rd, tg_op_params_t *params)
{
unsigned curop;
int num;
int fsnum;
num = 1 + getrandom(rd, tg->sum_weights);
curop = 0;
while (tg->op_weights[curop] < num) {
num -= tg->op_weights[curop];
curop++;
}
params->opnum = curop;
/* If we're bound to a particular filesystem, use that,
* otherwise, pick one at random.
*/
fsnum = tg->bindfs;
if (fsnum < 0)
fsnum = getrandom(rd, tg->fc->num_filesys);
params->fs = fc_get_fs(tg->fc, fsnum);
}
void tg_set_op_weight(ffsb_tg_t *tg, char *opname, unsigned weight)
{
int opnum = ops_find_op(opname);
assert(opnum >= 0);
tg->op_weights[opnum] = weight;
}
unsigned tg_get_op_weight(ffsb_tg_t *tg, char *opname)
{
int opnum = ops_find_op(opname);
assert(opnum >= 0);
return tg->op_weights[opnum];
}
void tg_set_bindfs(ffsb_tg_t *tg, int fsnum)
{
tg->bindfs = fsnum;
}
int tg_get_bindfs(ffsb_tg_t *tg)
{
return tg->bindfs;
}
unsigned tg_get_numthreads(ffsb_tg_t *tg)
{
return tg->num_threads;
}
static void update_bufsize(ffsb_tg_t *tg)
{
int i;
uint32_t newmax = max(tg->read_blocksize, tg->write_blocksize);
if (newmax == max(newmax, tg->thread_bufsize))
for (i = 0; i < tg->num_threads ; i++)
ft_alter_bufsize(tg->threads + i, newmax);
}
void tg_set_read_random(ffsb_tg_t *tg, int rr)
{
tg->read_random = rr;
}
void tg_set_write_random(ffsb_tg_t *tg, int wr)
{
tg->write_random = wr;
}
void tg_set_fsync_file(ffsb_tg_t *tg, int fsync)
{
tg->fsync_file = fsync;
}
void tg_set_read_size(ffsb_tg_t *tg, uint64_t rs)
{
tg->read_size = rs;
}
void tg_set_read_blocksize(ffsb_tg_t *tg, uint32_t rs)
{
tg->read_blocksize = rs;
update_bufsize(tg);
}
void tg_set_read_skip(ffsb_tg_t *tg, int rs)
{
tg->read_skip = rs;
}
void tg_set_read_skipsize(ffsb_tg_t *tg, uint32_t rs)
{
tg->read_skipsize = rs;
}
void tg_set_write_size(ffsb_tg_t *tg, uint64_t ws)
{
tg->write_size = ws;
}
void tg_set_write_blocksize(ffsb_tg_t *tg, uint32_t ws)
{
tg->write_blocksize = ws;
update_bufsize(tg);
}
int tg_get_read_random(ffsb_tg_t *tg)
{
return tg->read_random;
}
int tg_get_write_random(ffsb_tg_t *tg)
{
return tg->write_random;
}
int tg_get_fsync_file(ffsb_tg_t *tg)
{
return tg->fsync_file;
}
uint64_t tg_get_read_size(ffsb_tg_t *tg)
{
return tg->read_size;
}
uint32_t tg_get_read_blocksize(ffsb_tg_t *tg)
{
return tg->read_blocksize;
}
int tg_get_read_skip(ffsb_tg_t *tg)
{
return tg->read_skip;
}
uint32_t tg_get_read_skipsize(ffsb_tg_t *tg)
{
return tg->read_skipsize;
}
uint64_t tg_get_write_size(ffsb_tg_t *tg)
{
return tg->write_size;
}
uint32_t tg_get_write_blocksize(ffsb_tg_t *tg)
{
return tg->write_blocksize;
}
int tg_get_stopval(ffsb_tg_t *tg)
{
return tg->stopval;
}
ffsb_barrier_t *tg_get_start_barrier(ffsb_tg_t *tg)
{
return tg->start_barrier;
}
static void tg_print_config_helper(ffsb_tg_t *tg)
{
int i;
int sumweights = 0;
char buf[256];
printf("\t num_threads = %d\n", tg->num_threads);
printf("\t\n");
printf("\t read_random = %s\n", (tg->read_random) ? "on" : "off");
printf("\t read_size = %llu\t(%s)\n", tg->read_size,
ffsb_printsize(buf, tg->read_size, 256));
printf("\t read_blocksize = %u\t(%s)\n", tg->read_blocksize,
ffsb_printsize(buf, tg->read_blocksize, 256));
printf("\t read_skip = %s\n", (tg->read_skip) ? "on" : "off");
printf("\t read_skipsize = %u\t(%s)\n", tg->read_skipsize,
ffsb_printsize(buf, tg->read_skipsize, 256));
printf("\t\n");
printf("\t write_random = %s\n", (tg->write_random) ? "on" : "off");
printf("\t write_size = %llu\t(%s)\n", tg->write_size,
ffsb_printsize(buf, tg->write_size, 256));
printf("\t fsync_file = %d\n", tg->fsync_file);
printf("\t write_blocksize = %u\t(%s)\n", tg->write_blocksize,
ffsb_printsize(buf, tg->write_blocksize, 256));
printf("\t wait time = %u\n", tg->wait_time);
if (tg->bindfs >= 0) {
printf("\t\n");
printf("\t bound to fs %d\n", tg->bindfs);
}
printf("\t\n");
printf("\t op weights\n");
for (i = 0; i < FFSB_NUMOPS; i++)
sumweights += tg->op_weights[i];
for (i = 0; i < FFSB_NUMOPS; i++)
printf("\t %20s = %d (%.2f%%)\n", op_get_name(i),
tg->op_weights[i], 100 * (float)tg->op_weights[i] /
(float)sumweights);
printf("\t\n");
}
void tg_print_config(ffsb_tg_t *tg)
{
printf("ThreadGroup %d\n", tg->tg_num);
printf("================\n");
tg_print_config_helper(tg);
}
void tg_print_config_aging(ffsb_tg_t *tg, char *fsname)
{
printf("\t Aging ThreadGroup for fs %s\n", fsname);
printf("\t ================\n");
tg_print_config_helper(tg);
}
void tg_collect_results(ffsb_tg_t *tg, ffsb_op_results_t *r)
{
int i;
for (i = 0; i < tg_get_numthreads(tg); i++)
add_results(r, ft_get_results(tg->threads + i));
}
void tg_set_waittime(ffsb_tg_t *tg, unsigned time)
{
tg->wait_time = time;
}
unsigned tg_get_waittime(ffsb_tg_t *tg)
{
return tg->wait_time;
}
int tg_get_flagval(ffsb_tg_t *tg)
{
return tg->flagval;
}
void tg_set_statsc(ffsb_tg_t *tg, ffsb_statsc_t *fsc)
{
if (fsc) {
int i;
tg->need_stats = 1;
ffsb_statsc_copy(&tg->fsc, fsc);
for (i = 0; i < tg->num_threads; i++)
ft_set_statsc(tg->threads + i, &tg->fsc);
}
}
void tg_collect_stats(ffsb_tg_t *tg, ffsb_statsd_t *fsd)
{
int i;
assert(tg->need_stats);
ffsb_statsd_init(fsd, &tg->fsc);
for (i = 0; i < tg_get_numthreads(tg); i++)
ffsb_statsd_add(fsd, ft_get_stats_data(tg->threads+i));
}
int tg_needs_stats(ffsb_tg_t *tg)
{
return tg->need_stats;
}
@@ -0,0 +1,206 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 _FFSB_TG_H_
#define _FFSB_TG_H_
#include <inttypes.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pthread.h>
#include "ffsb.h"
#include "ffsb_op.h"
#include "ffsb_thread.h"
#include "ffsb_fs.h"
#include "ffsb_stats.h"
#include "util.h" /* for barrier obj */
/* "Thread Group" object defs.
*
* A thread group contains configuration information and can run its
* "gang" of threads performing a particular mix of operations.
*
* The thread group is responsible for creating the ffsb_thread
* objects which must ask the thread group object to select an
* operation and a filesystem to run that operation on. The thread
* objects don't contain any of the configuration information.
*
* Thread groups are also abstracted so they can be "run" arbitrarily
* which is useful because we can reuse them for aging. The running
* is a bit complex, the thread group has to have a callback function
* which is runs at a specified interval to determine when to
* terminate.
*
* To synchronize starting across many thread groups there are two
* barriers used, the first one "tg_barrier" in the run_params is to
* synchronize multiple thread-groups being ready to start, meaning
* that all their threads have been spawned The second one
* "thread_barrier" synchronizes all threads across multiple thread
* groups, so that they all start at once.
*/
struct ffsb_thread;
struct ffsb_config;
typedef struct ffsb_tg {
unsigned tg_num;
unsigned num_threads;
unsigned op_weights[FFSB_NUMOPS];
struct ffsb_thread *threads;
/* A threadgroup can be bound to just one filesystem.
* A value * < 0 , means we aren't bound to any.
*/
int bindfs;
int read_random; /* boolean */
uint64_t read_size;
uint32_t read_blocksize;
int read_skip; /* boolean */
uint32_t read_skipsize;
int write_random; /* boolean */
uint64_t write_size;
uint32_t write_blocksize;
int fsync_file; /* boolean */
/* Should be max(write_blocksize, read_blocksize) */
uint32_t thread_bufsize;
/* these fields are calculated/set by tg_run() */
unsigned sum_weights;
struct ffsb_config *fc;
ffsb_barrier_t *start_barrier;
/* Used for stopping the threads */
int flagval;
int stopval;
/* Delay between every operation, in milliseconds*/
unsigned wait_time;
/* stats configuration */
int need_stats;
ffsb_statsc_t fsc;
} ffsb_tg_t;
/* Init should be the very first thing called on the tg. After that,
* the user can call the set methods and finally run.
*/
void init_ffsb_tg(ffsb_tg_t *tg, unsigned num_threads, unsigned tg_num);
void destroy_ffsb_tg(ffsb_tg_t *tg);
/* Parameters needed to fire off a thread group. The main thread will
* evaluate poll_fn(poll_data) until it gets a nonzero return value.
* It will sleep for wait_time secs between calls The ffsb_config
* struct is needed for fs selection. Barriers are to synchronize
* multiple tgs and all threads pt is for pthread_create()
*/
typedef struct tg_run_params {
ffsb_tg_t *tg;
int (*poll_fn)(void *);
void *poll_data;
unsigned wait_time; /* in sec */
struct ffsb_config *fc;
ffsb_barrier_t *tg_barrier;
/* Should be initialized by caller to tg_run() */
ffsb_barrier_t *thread_barrier;
pthread_t pt;
} tg_run_params_t;
/* This function is meant to be called as a parameter to
* pthread_create()
*/
void *tg_run(void *);
void tg_print_config(ffsb_tg_t *tg);
void tg_print_config_aging(ffsb_tg_t *tg, char *fsname);
/* Adds all of this tg's results to res */
void tg_collect_results(ffsb_tg_t *tg, ffsb_op_results_t *res);
/* Adds up all this tg's stats to totals */
void tg_collect_stats(ffsb_tg_t *tg, ffsb_statsd_t *totals);
/* getters/setters, setters should not be called after a run has begun */
void tg_set_statsc(ffsb_tg_t *tg, ffsb_statsc_t *fsc);
void tg_set_bindfs(ffsb_tg_t *tg, int fsnum);
int tg_get_bindfs(ffsb_tg_t *tg);
unsigned tg_get_numthreads(ffsb_tg_t *tg);
void tg_set_op_weight(ffsb_tg_t *tg, char *opname, unsigned weight);
unsigned tg_get_op_weight(ffsb_tg_t *tg, char *opname);
void tg_set_read_random(ffsb_tg_t *tg, int rr);
void tg_set_write_random(ffsb_tg_t *tg, int wr);
void tg_set_fsync_file(ffsb_tg_t *tg, int fsync);
int tg_get_read_random(ffsb_tg_t *tg);
int tg_get_write_random(ffsb_tg_t *tg);
int tg_get_fsync_file(ffsb_tg_t *tg);
void tg_set_read_size(ffsb_tg_t *tg, uint64_t rs);
void tg_set_read_blocksize(ffsb_tg_t *tg, uint32_t rs);
void tg_set_read_skipsize(ffsb_tg_t *tg, uint32_t rs);
void tg_set_read_skip(ffsb_tg_t *tg, int rs);
void tg_set_write_size(ffsb_tg_t *tg, uint64_t ws);
void tg_set_write_blocksize(ffsb_tg_t *tg, uint32_t ws);
uint64_t tg_get_read_size(ffsb_tg_t *tg);
uint32_t tg_get_read_blocksize(ffsb_tg_t *tg);
int tg_get_read_skip(ffsb_tg_t *tg);
uint32_t tg_get_read_skipsize(ffsb_tg_t *tg);
uint64_t tg_get_write_size(ffsb_tg_t *tg);
uint32_t tg_get_write_blocksize(ffsb_tg_t *tg);
void tg_set_waittime(ffsb_tg_t *tg, unsigned time);
unsigned tg_get_waittime(ffsb_tg_t *tg);
/* The threads in the tg should be the only ones using these (below)
* funcs.
*/
ffsb_barrier_t *tg_get_start_barrier(ffsb_tg_t *tg);
int tg_get_stopval(ffsb_tg_t *tg);
int tg_get_flagval(ffsb_tg_t *tg);
/* The threads in this tg will use this function to get an op to run,
* so all configuration specific information is kept in this object.
*/
typedef struct tg_op_params {
struct ffsb_fs *fs; /* out parameter */
unsigned opnum; /* out parameter */
} tg_op_params_t;
/* tg and rd and in parameters, everything in params is out */
void tg_get_op(ffsb_tg_t *tg, randdata_t *rd, tg_op_params_t *params);
/* want stats for this tg ? */
int tg_needs_stats(ffsb_tg_t *tg);
#endif /* _FFSB_TG_H_ */
@@ -0,0 +1,171 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 "ffsb_tg.h"
#include "ffsb_thread.h"
#include "ffsb_op.h"
#include "util.h"
void init_ffsb_thread(ffsb_thread_t *ft, struct ffsb_tg *tg, unsigned bufsize,
unsigned tg_num, unsigned thread_num)
{
memset(ft, 0, sizeof(ffsb_thread_t));
ft->tg = tg;
ft->tg_num = tg_num;
ft->thread_num = thread_num;
if (bufsize)
ft_alter_bufsize(ft, bufsize);
init_random(&ft->rd, MAX_RANDBUF_SIZE);
}
void destroy_ffsb_thread(ffsb_thread_t *ft)
{
free(ft->mallocbuf);
destroy_random(&ft->rd);
if (ft->fsd.config)
ffsb_statsd_destroy(&ft->fsd);
}
void ft_set_statsc(ffsb_thread_t *ft, ffsb_statsc_t *fsc)
{
ffsb_statsd_init(&ft->fsd, fsc);
}
void *ft_run(void *data)
{
ffsb_thread_t *ft = (ffsb_thread_t *)data;
tg_op_params_t params;
unsigned wait_time = tg_get_waittime(ft->tg);
int stopval = tg_get_stopval(ft->tg);
ffsb_barrier_wait(tg_get_start_barrier(ft->tg));
while (tg_get_flagval(ft->tg) != stopval) {
tg_get_op(ft->tg, &ft->rd, &params);
do_op(ft, params.fs, params.opnum);
ffsb_milli_sleep(wait_time);
}
return NULL;
}
void ft_alter_bufsize(ffsb_thread_t *ft, unsigned bufsize)
{
if (ft->mallocbuf != NULL)
free(ft->mallocbuf);
ft->mallocbuf = ffsb_malloc(bufsize + 4096);
ft->alignedbuf = ffsb_align_4k(ft->mallocbuf + (4096 - 1));
}
char *ft_getbuf(ffsb_thread_t *ft)
{
return ft->alignedbuf;
}
int ft_get_read_random(ffsb_thread_t *ft)
{
return tg_get_read_random(ft->tg);
}
uint32_t ft_get_read_size(ffsb_thread_t *ft)
{
return tg_get_read_size(ft->tg);
}
uint32_t ft_get_read_blocksize(ffsb_thread_t *ft)
{
return tg_get_read_blocksize(ft->tg);
}
int ft_get_write_random(ffsb_thread_t *ft)
{
return tg_get_write_random(ft->tg);
}
uint32_t ft_get_write_size(ffsb_thread_t *ft)
{
return tg_get_write_size(ft->tg);
}
uint32_t ft_get_write_blocksize(ffsb_thread_t *ft)
{
return tg_get_write_blocksize(ft->tg);
}
int ft_get_fsync_file(ffsb_thread_t *ft)
{
return tg_get_fsync_file(ft->tg);
}
randdata_t *ft_get_randdata(ffsb_thread_t *ft)
{
return &ft->rd;
}
void ft_incr_op(ffsb_thread_t *ft, unsigned opnum, unsigned increment, uint64_t bytes)
{
ft->results.ops[opnum] += increment;
ft->results.op_weight[opnum]++;
ft->results.bytes[opnum] += bytes;
}
void ft_add_readbytes(ffsb_thread_t *ft, uint32_t bytes)
{
ft->results.read_bytes += bytes;
}
void ft_add_writebytes(ffsb_thread_t *ft, uint32_t bytes)
{
ft->results.write_bytes += bytes;
}
ffsb_op_results_t *ft_get_results(ffsb_thread_t *ft)
{
return &ft->results;
}
int ft_get_read_skip(ffsb_thread_t *ft)
{
return tg_get_read_skip(ft->tg);
}
uint32_t ft_get_read_skipsize(ffsb_thread_t *ft)
{
return tg_get_read_skipsize(ft->tg);
}
int ft_needs_stats(ffsb_thread_t *ft, syscall_t sys)
{
int ret = 0;
if (ft && ft->fsd.config && !fsc_ignore_sys(ft->fsd.config, sys))
ret = 1;
return ret;
}
void ft_add_stat(ffsb_thread_t *ft, syscall_t sys, uint32_t val)
{
if (ft)
ffsb_add_data(&ft->fsd, sys, val);
}
ffsb_statsd_t *ft_get_stats_data(ffsb_thread_t *ft)
{
return &ft->fsd;
}
@@ -0,0 +1,108 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 _FFSB_THREAD_H_
#define _FFSB_THREAD_H_
#include <pthread.h>
#include <inttypes.h>
#include "rand.h"
#include "ffsb_op.h"
#include "ffsb_tg.h"
#include "ffsb_stats.h"
#include "util.h" /* for barrier stuff */
struct ffsb_tg;
struct ffsb_op_results;
/* FFSB thread object
*
* The thread object doesn't store any configuration information, it
* mostly just holds per-thread state information such as the random
* data store and the per-thread buffer to copy data to/from disk
*/
typedef struct ffsb_thread {
unsigned thread_num;
unsigned tg_num;
pthread_t ptid;
struct randdata rd;
struct ffsb_tg *tg; /* owning thread group */
/* If we are using Direct IO, then we must only use a 4k
* aligned buffer so, alignedbuf_4k is a pointer into
* "mallocbuf" which is what malloc gave us.
*/
char *alignedbuf;
char *mallocbuf;
struct ffsb_op_results results;
/* stats */
ffsb_statsd_t fsd;
} ffsb_thread_t ;
void init_ffsb_thread(ffsb_thread_t *, struct ffsb_tg *, unsigned,
unsigned, unsigned);
void destroy_ffsb_thread(ffsb_thread_t *);
/* Owning thread group will start thread with this, thread runs until
* *ft->checkval == ft->stopval. Yes this is not strictly
* synchronized, but that is okay for our purposes, and it limits (IMO
* expensive) bus-locking.
*
* pthread_create() is called by tg with this function as a parameter
* data is a (ffsb_thread_t*)
*/
void *ft_run(void *);
void ft_alter_bufsize(ffsb_thread_t *, unsigned);
char *ft_getbuf(ffsb_thread_t *);
int ft_get_read_random(ffsb_thread_t *);
uint32_t ft_get_read_size(ffsb_thread_t *);
uint32_t ft_get_read_blocksize(ffsb_thread_t *);
int ft_get_write_random(ffsb_thread_t *);
uint32_t ft_get_write_size(ffsb_thread_t *);
uint32_t ft_get_write_blocksize(ffsb_thread_t *);
int ft_get_fsync_file(ffsb_thread_t *);
randdata_t *ft_get_randdata(ffsb_thread_t *);
void ft_incr_op(ffsb_thread_t *ft, unsigned opnum, unsigned increment, uint64_t bytes);
void ft_add_readbytes(ffsb_thread_t *, uint32_t);
void ft_add_writebytes(ffsb_thread_t *, uint32_t);
int ft_get_read_skip(ffsb_thread_t *);
uint32_t ft_get_read_skipsize(ffsb_thread_t *);
ffsb_op_results_t *ft_get_results(ffsb_thread_t *);
void ft_set_statsc(ffsb_thread_t *, ffsb_statsc_t *);
/* for these two, ft == NULL is OK */
int ft_needs_stats(ffsb_thread_t *, syscall_t);
void ft_add_stat(ffsb_thread_t *, syscall_t, uint32_t);
ffsb_statsd_t *ft_get_stats_data(ffsb_thread_t *);
#endif /* _FFSB_THREAD_H_ */
@@ -0,0 +1,280 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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
*/
#define FILE_OFFSET_BITS 64
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <inttypes.h>
#include <assert.h>
#include "ffsb.h"
#include "fh.h"
#include "config.h"
/* !!! ugly */
#ifndef HAVE_OPEN64
#define open64 open
#endif
#ifndef HAVE_FSEEKO64
#define lseek64 lseek
#endif
/* All these functions read the global mainconfig->bufferedio variable
* to determine if they are to do buffered i/o or normal.
*
* ha, well, they're supposed to anyway...!!! TODO -SR 2006/05/14
*/
static void do_stats(struct timeval *start, struct timeval *end,
ffsb_thread_t *ft, ffsb_fs_t *fs, syscall_t sys)
{
struct timeval diff;
uint32_t value = 0;
if (!ft && !fs)
return;
timersub(end, start, &diff);
value = 1000000 * diff.tv_sec + diff.tv_usec;
if (ft && ft_needs_stats(ft, sys))
ft_add_stat(ft, sys, value);
if (fs && fs_needs_stats(fs, sys))
fs_add_stat(fs, sys, value);
}
static int fhopenhelper(char *filename, char *bufflags, int flags,
ffsb_thread_t *ft, ffsb_fs_t *fs)
{
int fd = 0;
struct timeval start, end;
int need_stats = ft_needs_stats(ft, SYS_OPEN) ||
fs_needs_stats(fs, SYS_OPEN);
#ifndef __HAIKU__
flags |= O_LARGEFILE;
#endif
if (need_stats)
gettimeofday(&start, NULL);
fd = open64(filename, flags, S_IRWXU);
if (fd < 0) {
perror(filename);
exit(0);
}
if (need_stats) {
gettimeofday(&end, NULL);
do_stats(&start, &end, ft, fs, SYS_OPEN);
}
return fd;
}
int fhopenread(char *filename, ffsb_thread_t *ft, ffsb_fs_t *fs)
{
int flags = O_RDONLY;
int directio = fs_get_directio(fs);
if (directio)
flags |= O_DIRECT;
return fhopenhelper(filename, "r", flags, ft, fs);
}
int fhopenappend(char *filename, ffsb_thread_t *ft, ffsb_fs_t *fs)
{
int flags = O_APPEND | O_WRONLY;
int directio = fs_get_directio(fs);
if (directio)
flags |= O_DIRECT;
return fhopenhelper(filename, "a", flags, ft, fs);
}
int fhopenwrite(char *filename, ffsb_thread_t *ft, ffsb_fs_t *fs)
{
int flags = O_WRONLY;
int directio = fs_get_directio(fs);
if (directio)
flags |= O_DIRECT;
return fhopenhelper(filename, "w", flags, ft, fs);
}
int fhopencreate(char *filename, ffsb_thread_t *ft, ffsb_fs_t *fs)
{
int flags = O_CREAT | O_RDWR | O_TRUNC;
int directio = fs_get_directio(fs);
if (directio)
flags |= O_DIRECT;
return fhopenhelper(filename, "rw", flags, ft, fs);
}
void fhread(int fd, void *buf, uint64_t size, ffsb_thread_t *ft, ffsb_fs_t *fs)
{
ssize_t realsize;
struct timeval start, end;
int need_stats = ft_needs_stats(ft, SYS_READ) ||
fs_needs_stats(fs, SYS_READ);
assert(size <= SIZE_MAX);
if (need_stats)
gettimeofday(&start, NULL);
realsize = read(fd, buf, size);
if (need_stats) {
gettimeofday(&end, NULL);
do_stats(&start, &end, ft, fs, SYS_READ);
}
if (realsize != size) {
printf("Read %lld instead of %llu bytes.\n",
(unsigned long long)realsize, (unsigned long long)size);
perror("read");
exit(1);
}
}
void fhwrite(int fd, void *buf, uint32_t size, ffsb_thread_t *ft, ffsb_fs_t *fs)
{
ssize_t realsize;
struct timeval start, end;
int need_stats = ft_needs_stats(ft, SYS_WRITE) ||
fs_needs_stats(fs, SYS_WRITE);
assert(size <= SIZE_MAX);
if (need_stats)
gettimeofday(&start, NULL);
realsize = write(fd, buf, size);
if (need_stats) {
gettimeofday(&end, NULL);
do_stats(&start, &end, ft, fs, SYS_WRITE);
}
if (realsize != size) {
printf("Wrote %d instead of %d bytes.\n"
"Probably out of disk space\n", realsize, size);
perror("write");
exit(1);
}
}
void fhseek(int fd, uint64_t offset, int whence, ffsb_thread_t *ft,
ffsb_fs_t *fs)
{
uint64_t res;
struct timeval start, end;
int need_stats = ft_needs_stats(ft, SYS_LSEEK) ||
fs_needs_stats(fs, SYS_LSEEK);
if ((whence == SEEK_CUR) && (offset == 0))
return;
if (need_stats)
gettimeofday(&start, NULL);
res = lseek64(fd, offset, whence);
if (need_stats) {
gettimeofday(&end, NULL);
do_stats(&start, &end, ft, fs, SYS_LSEEK);
}
if ((whence == SEEK_SET) && (res != offset))
perror("seek");
if (res == -1) {
if (whence == SEEK_SET)
fprintf(stderr, "tried to seek to %lld\n", offset);
else
fprintf(stderr, "tried to seek from current "
"position to %lld\n", offset);
perror("seek");
exit(1);
}
}
void fhclose(int fd, ffsb_thread_t *ft, ffsb_fs_t *fs)
{
struct timeval start, end;
int need_stats = ft_needs_stats(ft, SYS_CLOSE) ||
fs_needs_stats(fs, SYS_CLOSE);
if (need_stats)
gettimeofday(&start, NULL);
close(fd);
if (need_stats) {
gettimeofday(&end, NULL);
do_stats(&start, &end, ft, fs, SYS_CLOSE);
}
}
void fhstat(char *name, ffsb_thread_t *ft, ffsb_fs_t *fs)
{
struct timeval start, end;
struct stat tmp_stat;
int need_stats = ft_needs_stats(ft, SYS_STAT) ||
fs_needs_stats(fs, SYS_CLOSE);
if (need_stats)
gettimeofday(&start, NULL);
if (stat(name, &tmp_stat)) {
fprintf (stderr, "stat call failed for file %s\n", name);
exit(1);
}
if (need_stats) {
gettimeofday(&end, NULL);
do_stats(&start, &end, ft, fs, SYS_STAT);
}
}
int writefile_helper(int fd, uint64_t size, uint32_t blocksize, char *buf,
struct ffsb_thread *ft, struct ffsb_fs *fs)
{
uint64_t iterations, a;
uint64_t last;
iterations = size / blocksize;
last = size % blocksize;
for (a = 0; a < iterations; a++)
fhwrite(fd, buf, blocksize, ft, fs);
if (last) {
a++;
fhwrite(fd, buf, last, ft, fs);
}
return a;
}
@@ -0,0 +1,41 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 _FH_H_
#define _FH_H_
#include <inttypes.h>
struct ffsb_thread;
struct ffsb_fs;
int fhopenread(char *, struct ffsb_thread *, struct ffsb_fs *);
int fhopenwrite(char *, struct ffsb_thread *, struct ffsb_fs *);
int fhopencreate(char *, struct ffsb_thread *, struct ffsb_fs *);
int fhopenappend(char *, struct ffsb_thread *, struct ffsb_fs *);
void fhread(int, void *, uint64_t, struct ffsb_thread *, struct ffsb_fs *);
/* can only write up to size_t bytes at a time, so size is a uint32_t */
void fhwrite(int, void *, uint32_t, struct ffsb_thread *, struct ffsb_fs *);
void fhseek(int, uint64_t, int, struct ffsb_thread *, struct ffsb_fs *);
void fhclose(int, struct ffsb_thread *, struct ffsb_fs *);
int writefile_helper(int, uint64_t, uint32_t, char *, struct ffsb_thread *,
struct ffsb_fs *);
#endif /* _FH_H_ */
@@ -0,0 +1,503 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "rand.h"
#include "filelist.h"
#include "util.h"
#include "rwlock.h"
#include "rbt.h"
#include "cirlist.h"
#if 0
static
void print_cl(struct cirlist *cl)
{
struct cnode *cur = cl->head;
printf("curlist: ");
if (cur == NULL) {
printf("\n");
return;
}
do {
printf("%d ", cur->obj->num);
cur = cur->next;
} while (cur != cl->head);
printf("\n");
}
#endif
#if 0
static
int node_cmp(struct ffsb_file *a, struct ffsb_file *b)
{
return a->num - b->num;
}
#endif
static
void build_dirs(struct benchfiles *bf)
{
char buf[FILENAME_MAX];
int i;
if (mkdir(bf->basedir, S_IRWXU) < 0)
if (errno != EEXIST) {
perror(bf->basedir);
exit(1);
}
for (i = 0; i < bf->numsubdirs; i++) {
snprintf(buf, FILENAME_MAX, "%s/%s%s%d",
bf->basedir, bf->basename,
SUBDIRNAME_BASE, i);
if (mkdir(buf, S_IRWXU) == -1)
if (errno != EEXIST) {
perror(buf);
exit(1);
}
}
}
void init_filelist(struct benchfiles *b, char *basedir, char *basename,
uint32_t numsubdirs, int builddirs)
{
memset(b, 0, sizeof(struct benchfiles));
b->basedir = ffsb_strdup(basedir);
b->basename = ffsb_strdup(basename);
b->numsubdirs = numsubdirs;
init_rwlock(&b->fileslock);
b->files = rbtree_construct();
b->dirs = rbtree_construct();
b->holes = ffsb_malloc(sizeof(struct cirlist));
b->dholes = ffsb_malloc(sizeof(struct cirlist));
init_cirlist(b->holes);
init_cirlist(b->dholes);
if (builddirs)
build_dirs(b);
}
static void file_destructor(struct ffsb_file *file)
{
free(file->name);
free(file);
}
void destroy_filelist(struct benchfiles *bf)
{
free(bf->basedir);
free(bf->basename);
while (!cl_empty(bf->holes)) {
struct ffsb_file *cur = cl_remove_head(bf->holes);
file_destructor(cur);
}
free(bf->holes);
rbtree_clean(bf->files, file_destructor);
free(bf->files);
}
struct ffsb_file *add_file(struct benchfiles *b, uint64_t size, randdata_t *rd)
{
struct ffsb_file *newfile, *oldfile = NULL;
int filenum = 0;
/* We pre-allocate here, because I don't want to spend time
* malloc'ing while the list is locked we free it later if
* necessary
*/
newfile = ffsb_malloc(sizeof(struct ffsb_file));
newfile->size = size;
init_rwlock(&(newfile->lock));
/* Write lock the filelist, begin critical section */
rw_lock_write(&b->fileslock);
/* First check "holes" for a file */
if (!cl_empty(b->holes)) {
oldfile = cl_remove_head(b->holes);
rbtree_insert(b->files, oldfile);
rw_lock_write(&oldfile->lock);
} else {
filenum = b->listsize;
b->listsize++;
newfile->num = filenum;
rbtree_insert(b->files, newfile);
rw_lock_write(&newfile->lock);
}
/* unlock filelist */
rw_unlock_write(&b->fileslock);
if (oldfile == NULL) {
char buf[FILENAME_MAX];
int randdir = getrandom(rd, b->numsubdirs+1);
int namesize = 0;
if (randdir == 0)
namesize = snprintf(buf, FILENAME_MAX, "%s/%s%s%d",
b->basedir, b->basename,
FILENAME_BASE, filenum);
else
namesize = snprintf(buf, FILENAME_MAX,
"%s/%s%s%d/%s%s%d", b->basedir,
b->basename, SUBDIRNAME_BASE,
randdir - 1, b->basename,
FILENAME_BASE, filenum);
if (namesize >= FILENAME_MAX)
/* !!! do something about this ? */
printf("warning: filename \"%s\" too long\n", buf);
newfile->name = ffsb_strdup(buf);
return newfile;
} else {
free(newfile);
return oldfile;
}
}
struct ffsb_file *add_dir(struct benchfiles *b, uint64_t size, randdata_t *rd)
{
struct ffsb_file *newdir, *olddir = NULL;
int dirnum = 0;
newdir = ffsb_malloc(sizeof(struct ffsb_file));
init_rwlock(&newdir->lock);
/* write lock the filelist, beging critical section */
rw_lock_write(&b->fileslock);
/* First check "holes" for a file */
if (!cl_empty(b->dholes)) {
olddir = cl_remove_head(b->dholes);
rbtree_insert(b->files, olddir);
rw_lock_write(&olddir->lock);
} else {
dirnum = b->numsubdirs;
b->numsubdirs++;
printf("dirnum: %d\n", dirnum);
newdir->num = dirnum;
rbtree_insert(b->dirs, newdir);
rw_lock_write(&newdir->lock);
}
/* unlock filelist */
rw_unlock_write(&b->fileslock);
if (olddir == NULL) {
char buf[FILENAME_MAX];
int namesize = 0;
namesize = snprintf(buf, FILENAME_MAX, "%s/%s%s%d",
b->basedir, b->basename,
SUBDIRNAME_BASE, dirnum);
if (namesize >= FILENAME_MAX)
printf("warning: filename \"%s\" too long\n", buf);
/* TODO: take action here... */
newdir->name = ffsb_strdup(buf);
return newdir;
} else {
free(newdir);
return olddir;
}
}
/* Private version of above function used only for reusing a
* fileset.
*/
static struct ffsb_file *add_file_named(struct benchfiles *b, uint64_t size,
char *name)
{
struct ffsb_file *newfile = NULL;
newfile = ffsb_malloc(sizeof(struct ffsb_file));
memset(newfile, 0, sizeof(struct ffsb_file));
newfile->name = ffsb_strdup(name);
newfile->size = size;
init_rwlock(&newfile->lock);
/* Write lock the filelist, begin critical section */
rw_lock_write(&b->fileslock);
newfile->num = b->listsize;
b->listsize++;
/* Add a new file to the rbtree */
rbtree_insert(b->files, newfile);
rw_lock_write(&newfile->lock);
/* Unlock filelist */
rw_unlock_write(&b->fileslock);
return newfile;
}
#if 0
static void print_rb_helper(rb_node *cur)
{
if (cur != NULL) {
print_rb_helper(cur->left);
printf("%d ", cur->object->num);
print_rb_helper(cur->right);
}
}
static void print_rb(rb_tree *tree)
{
print_rb_helper(tree->root);
}
#endif
void remove_file(struct benchfiles *b, struct ffsb_file *entry)
{
rw_lock_write(&b->fileslock);
rbtree_remove(b->files, entry, NULL);
/* add node to the cir. list of "holes" */
cl_insert_tail(b->holes, entry);
rw_unlock_write(&b->fileslock);
}
static struct ffsb_file *choose_file(struct benchfiles *b, randdata_t *rd)
{
rb_node *cur = NULL;
int chosen = 0;
struct ffsb_file temp;
temp.num = chosen;
if (b->listsize == 0) {
fprintf(stderr, "No more files to operate on,"
" try making more initial files "
"or fewer delete operations\n");
exit(0);
}
while (cur == NULL) {
chosen = getrandom(rd, b->listsize);
temp.num = chosen;
cur = rbtree_find(b->files, &temp);
}
return cur->object;
}
struct ffsb_file *choose_file_reader(struct benchfiles *bf, randdata_t *rd)
{
struct ffsb_file *ret;
rw_lock_read(&bf->fileslock);
/* If b->holes->count == bf->listsize, all files have been
* deleted!
*/
assert(bf->holes->count != bf->listsize);
ret = choose_file(bf, rd);
if (rw_trylock_read(&ret->lock)) {
rw_unlock_read(&bf->fileslock);
return choose_file_reader(bf, rd);
}
rw_unlock_read(&bf->fileslock);
return ret;
}
struct ffsb_file *choose_file_writer(struct benchfiles *bf, randdata_t *rd)
{
struct ffsb_file *ret ;
rw_lock_read(&bf->fileslock);
assert(bf->holes->count != bf->listsize);
ret = choose_file(bf, rd);
if (rw_trylock_write(&ret->lock)) {
rw_unlock_read(&bf->fileslock);
return choose_file_writer(bf, rd);
}
rw_unlock_read(&bf->fileslock);
return ret;
}
void unlock_file_reader(struct ffsb_file *file)
{
rw_unlock_read(&file->lock) ;
}
void unlock_file_writer(struct ffsb_file *file)
{
rw_unlock_write(&file->lock) ;
}
void rename_file(struct ffsb_file *file)
{
char *newname = malloc(strlen(file->name) + 2);
sprintf(newname, "%sa", file->name);
file->name = newname;
}
int validate_filename(struct benchfiles *bf, char *name)
{
int retval = -1;
char fmt_str[FILENAME_MAX];
if (FILENAME_MAX <= snprintf(fmt_str, FILENAME_MAX,
"%s%s%%d", bf->basename, FILENAME_BASE)) {
printf("filename is too long declaring it invalid\n");
return -1;
}
sscanf(name, fmt_str, &retval);
return retval;
}
int validate_dirname(struct benchfiles *bf, char *name)
{
int retval = -1;
char fmt_str[FILENAME_MAX];
if (FILENAME_MAX <= snprintf(fmt_str, FILENAME_MAX, "%s%s%%d",
bf->basename, SUBDIRNAME_BASE)) {
printf("dirname is too long declaring it invalid\n");
return -1;
}
sscanf(name, fmt_str, &retval);
return retval;
}
/* Do all the dirty work of recursing through a directory structure
* check everything for validitiy and update everything properly.
* Note it does not check filesizes !!!, it doesn't know anything
* about them
*/
static int add_dir_to_filelist(struct benchfiles *bf, DIR *subdir,
char *subdir_path, fl_validation_func_t vfunc,
void *vf_data)
{
int retval = 0;
struct dirent *d_ent = NULL;
while ((d_ent = readdir(subdir)) != NULL) {
DIR *tmp = NULL;
char filename_buf[FILENAME_MAX*2];
if (FILENAME_MAX < snprintf(filename_buf, FILENAME_MAX, "%s/%s",
subdir_path, d_ent->d_name)) {
printf("filename \"%s\" too long aborting\n",
filename_buf);
return -1;
}
tmp = opendir(filename_buf);
if (tmp == NULL) {
struct ffsb_file *ffsb_file = NULL;
if (validate_filename(bf, d_ent->d_name) < 0) {
printf("filename \"%s\" is invalid aborting\n",
d_ent->d_name);
return -1;
}
/* Verify size/other attributes via callback */
if (vfunc(bf, filename_buf, vf_data)) {
printf("filename \"%s\" didn't pass "
"validation\n", d_ent->d_name);
return -1;
}
/* Add file to data structure */
ffsb_file = add_file_named(bf, ffsb_get_filesize(filename_buf),
filename_buf);
unlock_file_writer(ffsb_file);
} else {
/* Check for the usual suspects and skip them */
if ((0 == strcmp(".", d_ent->d_name)) ||
(0 == strcmp("..", d_ent->d_name))) {
closedir(tmp);
continue;
}
if (validate_dirname(bf, d_ent->d_name) < 0) {
printf("dirname \"%s\" is invalid aborting\n",
d_ent->d_name);
closedir(tmp);
return -1;
}
if (vfunc(bf, filename_buf, vf_data)) {
printf("dir \"%s\" didn't pass validation\n",
d_ent->d_name);
closedir(tmp);
return -1;
}
/* Update filelist */
bf->numsubdirs++;
/* recurse */
retval += add_dir_to_filelist(bf, tmp, filename_buf,
vfunc, vf_data);
/* clean up */
closedir(tmp);
}
}
return retval;
}
int grab_old_fileset(struct benchfiles *bf, char *basename,
fl_validation_func_t vfunc, void *vfunc_data)
{
int retval = 0;
char buf[FILENAME_MAX*2];
DIR *lc_dir = NULL;
if (FILENAME_MAX < snprintf(buf, FILENAME_MAX, "%s",
bf->basedir)) {
printf("filename \"%s\" is too long aborting\n", buf);
return -1;
}
lc_dir = opendir(buf);
if (lc_dir == NULL) {
perror("opendir");
return -1;
}
retval = add_dir_to_filelist(bf, lc_dir, buf, vfunc, vfunc_data);
closedir(lc_dir);
return retval ;
}
/* Get the number of files */
uint32_t get_listsize(struct benchfiles *bf)
{
return bf->listsize;
}
/* Get the number of subdirectories */
uint32_t get_numsubdirs(struct benchfiles *bf)
{
return bf->numsubdirs;
}
@@ -0,0 +1,145 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 _FILELIST_H_
#define _FILELIST_H_
#include <pthread.h>
#include "rand.h"
#include "rwlock.h"
#include "cirlist.h"
#include "rbt.h"
#define SUBDIRNAME_BASE "dir"
#define FILENAME_BASE "file"
struct ffsb_file {
char *name;
uint64_t size;
struct rwlock lock;
uint32_t num;
};
struct cirlist;
/* Tree of ffsb_file structs and associated state info struct must be
* locked during use.
*/
struct benchfiles {
/* The base directory in which all subdirs and files are
* created
*/
char *basedir;
/* The name to prepend to all directory and file names */
char *basename;
uint32_t numsubdirs;
/* Files which currently exist on the filesystem */
struct red_black_tree *files;
/* Directories which currently exist on the filesystem */
struct red_black_tree *dirs;
/* Files which have been deleted, and whose numbers should be
* reused
*/
struct cirlist *holes;
struct cirlist *dholes;
/* This lock must be held while manipulating the structure */
struct rwlock fileslock;
uint32_t listsize; /* Sum size of nodes in files and holes */
};
/* Initializes the list, user must call this before anything else it
* will create the basedir and subdirs on the filesystem automatically
* if the builddirs arg. is nonzero
*/
void init_filelist(struct benchfiles *, char *, char *, uint32_t, int);
void destroy_filelist(struct benchfiles *);
/* Allocates a new file, adds to list, (write) locks it, and returns
* it. This function also randomly selects a filename + path to
* assign to the new file.
*
* It first checks the "holes" list for any available filenames.
* Caller must ensure file is actually created on disk
*/
struct ffsb_file *add_file(struct benchfiles *b, uint64_t size, randdata_t *rd);
struct ffsb_file *add_dir(struct benchfiles *, uint64_t, randdata_t *);
/* Removes file from list, decrements listsize.
*
* File should be writer-locked before calling this function.
*
* This function does not unlock file after removal from list.
*
* Caller must ensure file is actually removed on disk.
*
* Caller must NOT free file->name and file, since oldfiles are being
* put into holes list.
*/
void remove_file(struct benchfiles *, struct ffsb_file *);
/* Picks a file at random, locks it for reading and returns it
* locked
*/
struct ffsb_file *choose_file_reader(struct benchfiles *, randdata_t *);
/* Picks a file at random, locks it for writing and returns it
* locked
*/
struct ffsb_file *choose_file_writer(struct benchfiles *, randdata_t *);
/* changes the file->name of a file, file must be write locked
* it does not free the old file->name, so caller must keep a ref to it
* and free after the call
*/
void rename_file(struct ffsb_file *);
void unlock_file_reader(struct ffsb_file *);
void unlock_file_writer(struct ffsb_file *);
/* Uses SUBDIRNAME_BASE/FILENAME_BASE + bf->basename to validate a
* name returns a negative on invalid names, and the actual file
* number if valid
*/
int validate_filename(struct benchfiles *, char *);
int validate_dirname(struct benchfiles *, char *);
/* Function type which, does some validation of existing files
* currently only used by ffsb_fs stuff, returns 0 on success
*/
typedef int (*fl_validation_func_t)(struct benchfiles *, char *, void *);
/* Provided for re-use of filesets. Also runs the validation callback
* on each file/dir that is found, after verifying the name is
* conformant. The fileset should be initialized with init_fileset()
* beforehand.
* Returns 0 on success
*/
int grab_old_fileset(struct benchfiles *, char *, fl_validation_func_t,
void *);
/* Get the number of files */
uint32_t get_listsize(struct benchfiles *);
/* Get the number of subdirectories */
uint32_t get_numsubdirs(struct benchfiles *);
#endif /* _FILELIST_H_ */
@@ -0,0 +1,547 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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
*/
#define _LARGEFILE64_SOURCE
#include <sys/stat.h>
#include <sys/types.h>
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include "fh.h"
#include "util.h"
#include "ffsb.h"
#include "fileops.h"
#include "ffsb_op.h"
static void do_stats(struct timeval *start, struct timeval *end,
ffsb_thread_t *ft, ffsb_fs_t *fs, syscall_t sys)
{
struct timeval diff;
uint32_t value = 0;
if (!ft && !fs)
return;
timersub(end, start, &diff);
value = 1000000 * diff.tv_sec + diff.tv_usec;
if (ft && ft_needs_stats(ft, sys))
ft_add_stat(ft, sys, value);
if (fs && fs_needs_stats(fs, sys))
fs_add_stat(fs, sys, value);
}
void fop_bench(ffsb_fs_t *fs, unsigned opnum)
{
fs_set_opdata(fs, fs_get_datafiles(fs), opnum);
}
void fop_age(ffsb_fs_t *fs, unsigned opnum)
{
fs_set_opdata(fs, fs_get_agefiles(fs), opnum);
}
static unsigned readfile_helper(int fd, uint64_t size, uint32_t blocksize,
char *buf, ffsb_thread_t *ft, ffsb_fs_t *fs)
{
int iterations, a;
int last;
iterations = size / blocksize;
last = size % blocksize;
for (a = 0; a < iterations; a++)
fhread(fd, buf, blocksize, ft, fs);
if (last)
fhread(fd, buf, last, ft, fs);
return iterations;
}
static uint64_t get_random_offset(randdata_t *rd, uint64_t filesize,
int aligned)
{
if (!aligned)
return getllrandom(rd, filesize);
filesize /= 4096;
return getllrandom(rd, filesize) * 4096;
}
void ffsb_readfile(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum)
{
struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
struct ffsb_file *curfile = NULL;
int fd;
uint64_t filesize;
char *buf = ft_getbuf(ft);
int read_random = ft_get_read_random(ft);
uint64_t read_size = ft_get_read_size(ft);
uint32_t read_blocksize = ft_get_read_blocksize(ft);
uint32_t read_skipsize = ft_get_read_skipsize(ft);
int skip_reads = ft_get_read_skip(ft);
struct randdata *rd = ft_get_randdata(ft);
uint64_t iterations = 0;
curfile = choose_file_reader(bf, rd);
fd = fhopenread(curfile->name, ft, fs);
filesize = ffsb_get_filesize(curfile->name);
assert(filesize >= read_size);
/* Sequential read, starting at a random point */
if (!read_random) {
uint64_t range = filesize - read_size;
uint64_t offset = 0;
/* Skip or "stride" reads option */
if (skip_reads) {
unsigned i, last;
uint64_t minfilesize;
iterations = read_size / read_blocksize;
last = read_size % read_blocksize;
/* Double check that the user hasn't specified
* a read_size that is too large when combined
* with the seeks
*/
if (last)
minfilesize = last + iterations *
(read_blocksize + read_skipsize);
else
minfilesize = read_blocksize + iterations - 1 *
(read_blocksize + read_skipsize);
if (minfilesize > filesize) {
printf("Error: read size %llu bytes too big "
"w/ skipsize %u and blocksize %u,"
" for file of size %llu bytes\n"
" aborting\n\n", read_size,
read_skipsize, read_blocksize,
filesize);
printf("minimum file size must be at least "
" %llu bytes\n", minfilesize);
exit(1);
}
for (i = 0; i < iterations; i++) {
fhread(fd, buf, read_blocksize, ft, fs);
fhseek(fd, (uint64_t)read_skipsize, SEEK_CUR,
ft, fs);
}
if (last) {
fhread(fd, buf, (uint64_t)last, ft, fs);
iterations++;
}
} else {
/* Regular sequential reads */
if (range) {
offset = get_random_offset(rd, range,
fs_get_alignio(fs));
fhseek(fd, offset, SEEK_SET, ft, fs);
}
iterations = readfile_helper(fd, read_size,
read_blocksize, buf,
ft, fs);
}
} else {
/* Randomized read */
uint64_t range = filesize - read_blocksize;
int i;
iterations = read_size / read_blocksize;
for (i = 0; i < iterations; i++) {
uint64_t offset = get_random_offset(rd, range,
fs_get_alignio(fs));
fhseek(fd, offset, SEEK_SET, ft, fs);
fhread(fd, buf, read_blocksize, ft, fs);
}
}
unlock_file_reader(curfile);
fhclose(fd, ft, fs);
ft_incr_op(ft, opnum, iterations, read_size);
ft_add_readbytes(ft, read_size);
}
/* Just like ffsb_readfile but we read the whole file from start to
* finish regardless of file size.
*/
void ffsb_readall(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum)
{
struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
struct ffsb_file *curfile = NULL;
int fd;
uint64_t filesize;
char *buf = ft_getbuf(ft);
uint32_t read_blocksize = ft_get_read_blocksize(ft);
struct randdata *rd = ft_get_randdata(ft);
unsigned iterations = 0;
curfile = choose_file_reader(bf, rd);
fd = fhopenread(curfile->name, ft, fs);
filesize = ffsb_get_filesize(curfile->name);
iterations = readfile_helper(fd, filesize, read_blocksize, buf, ft, fs);
unlock_file_reader(curfile);
fhclose(fd, ft, fs);
ft_incr_op(ft, opnum, iterations, filesize);
ft_add_readbytes(ft, filesize);
}
/* Shared core between ffsb_writefile and ffsb_writefile_fsync.*/
static unsigned ffsb_writefile_core(ffsb_thread_t *ft, ffsb_fs_t *fs,
unsigned opnum, uint64_t *filesize_ret,
int fsync_file)
{
struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
struct ffsb_file *curfile = NULL;
int fd;
uint64_t filesize;
char *buf = ft_getbuf(ft);
int write_random = ft_get_write_random(ft);
uint32_t write_size = ft_get_write_size(ft);
uint32_t write_blocksize = ft_get_write_blocksize(ft);
struct randdata *rd = ft_get_randdata(ft);
unsigned iterations = 0;
curfile = choose_file_reader(bf, rd);
fd = fhopenwrite(curfile->name, ft, fs);
filesize = ffsb_get_filesize(curfile->name);
assert(filesize >= write_size);
/* Sequential write, starting at a random point */
if (!write_random) {
uint64_t range = filesize - write_size;
uint64_t offset = 0;
if (range) {
offset = get_random_offset(rd, range,
fs_get_alignio(fs));
fhseek(fd, offset, SEEK_SET, ft, fs);
}
iterations = writefile_helper(fd, write_size, write_blocksize,
buf, ft, fs);
} else {
/* Randomized write */
uint64_t range = filesize - write_blocksize;
int i;
iterations = write_size / write_blocksize;
for (i = 0; i < iterations; i++) {
uint64_t offset = get_random_offset(rd, range,
fs_get_alignio(fs));
fhseek(fd, offset, SEEK_SET, ft, fs);
fhwrite(fd, buf, write_blocksize, ft, fs);
}
}
if (fsync_file) {
if (fsync(fd)) {
perror("fsync");
printf("aborting\n");
exit(1);
}
}
unlock_file_reader(curfile);
fhclose(fd, ft, fs);
*filesize_ret = filesize;
return iterations;
}
void ffsb_writefile(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum)
{
unsigned iterations;
uint64_t filesize;
iterations = ffsb_writefile_core(ft, fs, opnum, &filesize, 0);
ft_incr_op(ft, opnum, iterations, filesize);
ft_add_writebytes(ft, filesize);
}
void ffsb_writefile_fsync(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum)
{
unsigned iterations;
uint64_t filesize;
iterations = ffsb_writefile_core(ft, fs, opnum, &filesize, 1);
ft_incr_op(ft, opnum, iterations, filesize);
ft_add_writebytes(ft, filesize);
}
/* Shared core between ffsb_writeall and ffsb_writeall_fsync.*/
static unsigned ffsb_writeall_core(ffsb_thread_t *ft, ffsb_fs_t *fs,
unsigned opnum, uint64_t *filesize_ret,
int fsync_file)
{
struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
struct ffsb_file *curfile = NULL;
int fd;
uint64_t filesize;
char *buf = ft_getbuf(ft);
uint32_t write_blocksize = ft_get_write_blocksize(ft);
struct randdata *rd = ft_get_randdata(ft);
unsigned iterations = 0;
curfile = choose_file_reader(bf, rd);
fd = fhopenwrite(curfile->name, ft, fs);
filesize = ffsb_get_filesize(curfile->name);
iterations = writefile_helper(fd, filesize, write_blocksize, buf,
ft, fs);
if (fsync_file)
if (fsync(fd)) {
perror("fsync");
printf("aborting\n");
exit(1);
}
unlock_file_reader(curfile);
fhclose(fd, ft, fs);
*filesize_ret = filesize;
return iterations;
}
/* Just like ffsb_writefile but we write the whole file from start to
* finish regardless of file size
*/
void ffsb_writeall(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum)
{
unsigned iterations;
uint64_t filesize;
iterations = ffsb_writeall_core(ft, fs, opnum, &filesize, 0);
ft_incr_op(ft, opnum, iterations, filesize);
ft_add_writebytes(ft, filesize);
}
void ffsb_writeall_fsync(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum)
{
unsigned iterations;
uint64_t filesize;
iterations = ffsb_writeall_core(ft, fs, opnum, &filesize, 1);
ft_incr_op(ft, opnum, iterations, filesize);
ft_add_writebytes(ft, filesize);
}
static unsigned ffsb_appendfile_core(ffsb_thread_t *ft, ffsb_fs_t *fs,
unsigned opnum, uint64_t *filesize_ret,
int fsync_file)
{
struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
struct ffsb_file *curfile;
int fd;
char *buf = ft_getbuf(ft);
uint32_t write_size = ft_get_write_size(ft);
uint32_t write_blocksize = ft_get_write_blocksize(ft);
struct randdata *rd = ft_get_randdata(ft);
unsigned iterations = 0;
curfile = choose_file_reader(bf, rd);
fd = fhopenappend(curfile->name, ft, fs);
unlock_file_reader(curfile);
curfile->size += (uint64_t)write_size;
iterations = writefile_helper(fd, write_size, write_blocksize, buf,
ft, fs);
if (fsync_file)
if (fsync(fd)) {
perror("fsync");
printf("aborting\n");
exit(1);
}
fhclose(fd, ft, fs);
*filesize_ret = write_size;
return iterations;
}
void ffsb_appendfile(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum)
{
unsigned iterations;
uint64_t filesize;
iterations = ffsb_appendfile_core(ft, fs, opnum, &filesize, 0);
ft_incr_op(ft, opnum, iterations, filesize);
ft_add_writebytes(ft, filesize);
}
void ffsb_appendfile_fsync(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum)
{
unsigned iterations;
uint64_t filesize;
iterations = ffsb_appendfile_core(ft, fs, opnum, &filesize, 1);
ft_incr_op(ft, opnum, iterations, filesize);
ft_add_writebytes(ft, filesize);
}
static unsigned ffsb_createfile_core(ffsb_thread_t *ft, ffsb_fs_t *fs,
unsigned opnum, uint64_t *filesize_ret,
int fsync_file)
{
struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
struct ffsb_file *newfile = NULL;
int fd;
uint64_t size;
char *buf = ft_getbuf(ft);
uint32_t write_blocksize = ft_get_write_blocksize(ft);
struct randdata *rd = ft_get_randdata(ft);
unsigned iterations = 0;
if (fs->num_weights) {
int num = 1 + getrandom(rd, fs->sum_weights);
int curop = 0;
while (fs->size_weights[curop].weight < num) {
num -= fs->size_weights[curop].weight;
curop++;
}
size = fs->size_weights[curop].size;
}
else {
uint64_t range = fs_get_max_filesize(fs) - fs_get_min_filesize(fs);
size = fs_get_min_filesize(fs);
if (range != 0)
size += getllrandom(rd, range);
}
newfile = add_file(bf, size, rd);
fd = fhopencreate(newfile->name, ft, fs);
iterations = writefile_helper(fd, size, write_blocksize, buf, ft, fs);
if (fsync_file)
if (fsync(fd)) {
perror("fsync");
printf("aborting\n");
exit(1);
}
fhclose(fd, ft, fs);
unlock_file_writer(newfile);
*filesize_ret = size;
return iterations;
}
void ffsb_createfile(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum)
{
unsigned iterations;
uint64_t filesize;
iterations = ffsb_createfile_core(ft, fs, opnum, &filesize, 0);
ft_incr_op(ft, opnum, iterations, filesize);
ft_add_writebytes(ft, filesize);
}
void ffsb_createfile_fsync(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum)
{
unsigned iterations;
uint64_t filesize;
iterations = ffsb_createfile_core(ft, fs, opnum, &filesize, 1);
ft_incr_op(ft, opnum, iterations, filesize);
ft_add_writebytes(ft, filesize);
}
void ffsb_deletefile(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum)
{
struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
struct ffsb_file *curfile = NULL;
randdata_t *rd = ft_get_randdata(ft);
struct timeval start, end;
int need_stats = ft_needs_stats(ft, SYS_UNLINK) ||
fs_needs_stats(fs, SYS_UNLINK);
curfile = choose_file_writer(bf, rd);
remove_file(bf, curfile);
if (need_stats)
gettimeofday(&start, NULL);
if (unlink(curfile->name) == -1) {
printf("error deleting %s in deletefile\n", curfile->name);
perror("deletefile");
exit(0);
}
if (need_stats) {
gettimeofday(&end, NULL);
do_stats(&start, &end, ft, fs, SYS_UNLINK);
}
rw_unlock_write(&curfile->lock);
ft_incr_op(ft, opnum, 1, 0);
}
void ffsb_open_close(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum)
{
struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
struct ffsb_file *curfile = NULL;
randdata_t *rd = ft_get_randdata(ft);
int fd;
curfile = choose_file_reader(bf, rd);
fd = fhopenread(curfile->name, ft, fs);
fhclose(fd, ft, fs);
unlock_file_reader(curfile);
ft_incr_op(ft, opnum, 1, 0);
}
void ffsb_stat(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum)
{
struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
struct ffsb_file *curfile = NULL;
randdata_t *rd = ft_get_randdata(ft);
curfile = choose_file_reader(bf, rd);
fhstat(curfile->name, ft, fs);
unlock_file_reader(curfile);
ft_incr_op(ft, opnum, 1, 0);
}
@@ -0,0 +1,51 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 _FILEOPS_H_
#define _FILEOPS_H_
#include "ffsb_thread.h"
#include "ffsb.h"
#include "ffsb_op.h"
#include "ffsb_fs.h"
void ffsb_readfile(ffsb_thread_t *tconfig, ffsb_fs_t *, unsigned opnum);
void ffsb_readall(ffsb_thread_t *tconfig, ffsb_fs_t *, unsigned opnum);
void ffsb_writefile(ffsb_thread_t *tconfig, ffsb_fs_t *, unsigned opnum);
void ffsb_writefile_fsync(ffsb_thread_t *tconfig, ffsb_fs_t *, unsigned opnum);
void ffsb_writeall(ffsb_thread_t *tconfig, ffsb_fs_t *, unsigned opnum);
void ffsb_writeall_fsync(ffsb_thread_t *tconfig, ffsb_fs_t *, unsigned opnum);
void ffsb_createfile(ffsb_thread_t *tconfig, ffsb_fs_t *, unsigned opnum);
void ffsb_createfile_fsync(ffsb_thread_t *tconfig, ffsb_fs_t *, unsigned opnum);
void ffsb_deletefile(ffsb_thread_t *tconfig, ffsb_fs_t *, unsigned opnum);
void ffsb_appendfile(ffsb_thread_t *tconfig, ffsb_fs_t *, unsigned opnum);
void ffsb_appendfile_fsync(ffsb_thread_t *tconfig, ffsb_fs_t *, unsigned opnum);
void ffsb_stat(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum);
void ffsb_open_close(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum);
struct ffsb_op_results;
void ffsb_read_print_exl(struct ffsb_op_results *, double secs, unsigned op_num);
void ffsb_write_print_exl(struct ffsb_op_results *, double secs, unsigned op_num);
void ffsb_create_print_exl(struct ffsb_op_results *, double secs, unsigned op_num);
void ffsb_append_print_exl(struct ffsb_op_results *, double secs, unsigned op_num);
/* Set up ops for either aging or benchmarking */
void fop_bench(ffsb_fs_t *fs, unsigned opnum);
void fop_age(ffsb_fs_t *fs, unsigned opnum);
#endif /* _FILEOPS_H_ */
@@ -0,0 +1,251 @@
#!/bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5 (mit/util/scripts/install.sh).
#
# Copyright 1991 by the Massachusetts Institute of Technology
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch. It can only install one file at a time, a restriction
# shared with many OS's install programs.
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
transformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
true
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
chmodcmd=""
else
instcmd=mkdir
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src -o -d $src ]
then
true
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
true
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
true
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
true
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
true
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0
@@ -0,0 +1,55 @@
/*
* Simple list implementation mostly take from the Linux Kernel
*/
#include <stdlib.h>
#include "list.h"
void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = NULL;
entry->prev = NULL;
}
void list_replace(struct list_head *old,
struct list_head *new)
{
new->next = old->next;
new->next->prev = new;
new->prev = old->prev;
new->prev->next = new;
}
@@ -0,0 +1,53 @@
/*
* Simple list implementation mostly take from the Linux Kernel
*/
#ifndef _LIST_H_
#define _LIST_H_
struct list_head {
struct list_head *next, *prev;
};
void INIT_LIST_HEAD(struct list_head *list);
void __list_add(struct list_head *new, struct list_head *prev,
struct list_head *next);
void __list_del(struct list_head *prev, struct list_head *next);
void list_add(struct list_head *new, struct list_head *head);
void list_add_tail(struct list_head *new, struct list_head *head);
void list_del(struct list_head *entry);
void list_replace(struct list_head *old, struct list_head *new);
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
#define list_for_each(pos, head) \
for (pos = (head)->next; pos->next, pos != (head); pos = pos->next)
#define offsetof(type, member) ((int) &((type *)0)->member)
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) *__mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
pos->member.next, &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
#endif
@@ -0,0 +1,258 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 <pthread.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>
#include "config.h"
#include "ffsb.h"
#include "util.h"
#include "parser.h"
/* State information for the polling function below */
struct ffsb_time_poll {
struct timeval starttime;
int wait_time;
};
/* This is the polling function used by the threadgroups to check
* elapsed time, when it returns 1 they know it is time to stop
*/
static int ffsb_poll_fn(void *ptr)
{
struct ffsb_time_poll *data = (struct ffsb_time_poll *)ptr;
struct timeval curtime, difftime;
gettimeofday(&curtime, NULL);
timersub(&curtime, &data->starttime, &difftime);
if (difftime.tv_sec >= data->wait_time)
return 1;
return 0;
}
int main(int argc, char *argv[])
{
int i;
ffsb_config_t fc;
ffsb_barrier_t thread_barrier, tg_barrier;
tg_run_params_t *params;
struct ffsb_time_poll pdata;
struct timeval starttime, endtime, difftime;
pthread_attr_t attr;
ffsb_op_results_t total_results;
double totaltime = 0.0f, usertime = 0.0f, systime = 0.0f;
struct rusage before_self, before_children, after_self, after_children;
pthread_t *fs_pts; /* threads to do filesystem creates in parallel */
char *callout = NULL;
char ctime_start_buf[32];
char ctime_end_buf[32];
memset(&before_self, 0, sizeof(before_self));
memset(&before_children, 0, sizeof(before_children));
memset(&after_self, 0, sizeof(after_self));
memset(&after_children, 0, sizeof(after_children));
ffsb_unbuffer_stdout();
if (argc < 2) {
fprintf(stderr, "usage: %s <config file>\n",
argv[0]);
exit(1);
}
/* VERSION comes from config.h (which is autogenerated by autoconf) */
printf("FFSB version %s started\n\n", VERSION);
ffsb_parse_newconfig(&fc, argv[1]);
pdata.wait_time = fc.time;
if (fc.time)
printf("benchmark time = %u\n", fc.time);
else
printf("Only creating the fileset, not running benchmark.\n");
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
for (i = 0; i < fc.num_threadgroups; i++)
tg_print_config(&fc.groups[i]);
fs_pts = ffsb_malloc(sizeof(pthread_t) * fc.num_filesys);
gettimeofday(&starttime, NULL);
for (i = 0; i < fc.num_filesys; i++) {
fs_print_config(&fc.filesystems[i]);
pthread_create(fs_pts + i, &attr, construct_ffsb_fs,
&fc.filesystems[i]);
}
fflush(stdout);
for (i = 0; i < fc.num_filesys; i++)
pthread_join(fs_pts[i], NULL);
gettimeofday(&endtime, NULL);
timersub(&endtime, &starttime, &difftime);
printf("fs setup took %ld secs\n", difftime.tv_sec);
free(fs_pts);
if (fc.time == 0) {
printf("Setup complete, exiting\n");
return 0;
}
params = ffsb_malloc(sizeof(tg_run_params_t) * fc.num_threadgroups);
init_ffsb_op_results(&total_results);
ffsb_barrier_init(&thread_barrier, fc.num_totalthreads);
ffsb_barrier_init(&tg_barrier, fc.num_threadgroups + 1);
ffsb_sync();
/* Execute the callout if any and wait for it to return */
callout = fc_get_callout(&fc);
if (callout) {
printf("executing callout: \n %s\n", callout);
if (ffsb_system(callout) < 0) {
perror("system");
exit(1);
}
}
/* Spawn all of the threadgroup master threads */
for (i = 0; i < fc.num_threadgroups; i++) {
params[i].tg = &fc.groups[i];
params[i].fc = &fc;
params[i].poll_fn = ffsb_poll_fn;
params[i].poll_data = &pdata;
params[i].wait_time = FFSB_TG_WAIT_TIME;
params[i].tg_barrier = &tg_barrier;
params[i].thread_barrier = &thread_barrier;
pthread_create(&params[i].pt, &attr, tg_run, &params[i]);
}
ffsb_getrusage(&before_self, &before_children);
gettimeofday(&pdata.starttime, NULL);
ffsb_barrier_wait(&tg_barrier); /* sync with tg's to start*/
printf("Starting Actual Benchmark At: %s\n",
ctime_r(&pdata.starttime.tv_sec, ctime_start_buf));
fflush(stdout);
/* Wait for all of the threadgroup master threads to finish */
for (i = 0; i < fc.num_threadgroups; i++)
pthread_join(params[i].pt, NULL);
ffsb_sync();
gettimeofday(&endtime, NULL);
ffsb_getrusage(&after_self, &after_children);
printf("FFSB benchmark finished at: %s\n",
ctime_r(&endtime.tv_sec, ctime_end_buf));
printf("Results:\n");
fflush(stdout);
timersub(&endtime, &pdata.starttime, &difftime);
totaltime = tvtodouble(&difftime);
printf("Benchmark took %.2lf sec\n", totaltime);
printf("\n");
for (i = 0; i < fc.num_threadgroups; i++) {
struct ffsb_op_results tg_results;
ffsb_tg_t *tg = fc.groups + i;
init_ffsb_op_results(&tg_results);
/* Grab the individual tg results */
tg_collect_results(tg, &tg_results);
if (fc.num_threadgroups == 1)
printf("Total Results\n");
else
printf("ThreadGroup %d\n", i);
printf("===============\n");
print_results(&tg_results, totaltime);
if (tg_needs_stats(tg)) {
ffsb_statsd_t fsd;
tg_collect_stats(tg, &fsd);
ffsb_statsd_print(&fsd);
}
printf("\n");
/* Add the tg results to the total */
tg_collect_results(&fc.groups[i], &total_results);
}
if (fc.num_threadgroups > 1) {
printf("Total Results\n");
printf("===============\n");
print_results(&total_results, totaltime);
}
#define USEC_PER_SEC ((double)(1000000.0f))
/* sum up self and children after */
usertime = (after_self.ru_utime.tv_sec +
((after_self.ru_utime.tv_usec)/USEC_PER_SEC)) +
((after_children.ru_utime.tv_sec +
((after_children.ru_utime.tv_usec)/USEC_PER_SEC)));
/* subtract away the before */
usertime -= (before_self.ru_utime.tv_sec +
((before_self.ru_utime.tv_usec)/USEC_PER_SEC)) +
((before_children.ru_utime.tv_sec +
((before_children.ru_utime.tv_usec)/USEC_PER_SEC)));
/* sum up self and children after */
systime = (after_self.ru_stime.tv_sec +
((after_self.ru_stime.tv_usec)/USEC_PER_SEC)) +
((after_children.ru_stime.tv_sec +
((after_children.ru_stime.tv_usec)/USEC_PER_SEC)));
/* subtract away the before */
systime -= (before_self.ru_stime.tv_sec +
((before_self.ru_stime.tv_usec)/USEC_PER_SEC)) +
((before_children.ru_stime.tv_sec +
((before_children.ru_stime.tv_usec)/USEC_PER_SEC)));
printf("\n\n");
printf("%.1lf%% User Time\n", 100 * usertime / totaltime);
printf("%.1lf%% System Time\n", 100 * systime / totaltime);
printf("%.1f%% CPU Utilization\n", 100 * (usertime + systime) /
totaltime);
free(params);
destroy_ffsb_config(&fc);
return 0;
}
@@ -0,0 +1,112 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "ffsb.h"
#include "metaops.h"
#include "rand.h"
#include "filelist.h"
/* metaops:
* createdir
* removedir
* renamedir
* renamefile
*/
void metaops_metadir(ffsb_fs_t *fs, unsigned opnum)
{
fs_set_opdata(fs, fs_get_metafiles(fs), opnum);
}
static void createdir(struct benchfiles *dirs, randdata_t *rd)
{
struct ffsb_file *newdir;
newdir = add_file(dirs, 0, rd);
if (mkdir(newdir->name, S_IRWXU) < 0) {
perror("mkdir");
exit(1);
}
unlock_file_writer(newdir);
}
static void removedir(struct benchfiles *dirs, randdata_t *rd)
{
struct ffsb_file *deldir;
deldir = choose_file_writer(dirs, rd);
remove_file(dirs, deldir);
if (rmdir(deldir->name) < 0) {
perror("rmdir");
exit(1);
}
unlock_file_writer(deldir);
}
static void renamedir(struct benchfiles *dirs, randdata_t *rd)
{
struct ffsb_file *dir;
char *oldname;
dir = choose_file_writer(dirs, rd);
oldname = dir->name;
rename_file(dir);
if (rename(oldname, dir->name) < 0) {
perror("rename");
exit(1);
}
unlock_file_writer(dir);
free(oldname);
}
void ffsb_metaops(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum)
{
struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
randdata_t *rd = ft_get_randdata(ft);
createdir(bf, rd);
createdir(bf, rd);
removedir(bf, rd);
renamedir(bf, rd);
ft_incr_op(ft, opnum, 1, 0);
}
void ffsb_createdir(ffsb_thread_t *ft, ffsb_fs_t *fs, unsigned opnum)
{
struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
struct ffsb_file *newdir;
randdata_t *rd = ft_get_randdata(ft);
newdir = add_dir(bf, 0, rd);
if (mkdir(newdir->name, S_IRWXU) < 0) {
perror("mkdir");
exit(1);
}
unlock_file_writer(newdir);
ft_incr_op(ft, opnum, 1, 0);
}
@@ -0,0 +1,28 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 _METAOPS_H_
#define _METAOPS_H_
#include "ffsb.h"
#include "fileops.h"
void ffsb_metaops(struct ffsb_thread *, ffsb_fs_t *, unsigned);
void ffsb_createdir(struct ffsb_thread *, ffsb_fs_t *, unsigned);
void metaops_metadir(ffsb_fs_t *, unsigned);
#endif /* _METAOPS_H_ */
@@ -0,0 +1,336 @@
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
# Copyright (C) 1996, 1997, 1999, 2000, 2002 Free Software Foundation, Inc.
# Originally by Fran,cois Pinard <[email protected]>, 1996.
# 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, 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.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
fi
run=:
# In the cases where this matters, `missing' is being run in the
# srcdir already.
if test -f configure.ac; then
configure_ac=configure.ac
else
configure_ac=configure.in
fi
case "$1" in
--run)
# Try to run requested program, and just exit if it succeeds.
run=
shift
"$@" && exit 0
;;
esac
# If it does not exist, or fails to run (possibly an outdated version),
# try to emulate it.
case "$1" in
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
error status if there is no known handling for PROGRAM.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
--run try to run the given command, and emulate it if it fails
Supported PROGRAM values:
aclocal touch file \`aclocal.m4'
autoconf touch file \`configure'
autoheader touch file \`config.h.in'
automake touch all \`Makefile.in' files
bison create \`y.tab.[ch]', if possible, from existing .[ch]
flex create \`lex.yy.c', if possible, from existing .c
help2man touch the output file
lex create \`lex.yy.c', if possible, from existing .c
makeinfo touch the output file
tar try tar, gnutar, gtar, then tar without non-portable flags
yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing 0.4 - GNU automake"
;;
-*)
echo 1>&2 "$0: Unknown \`$1' option"
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
;;
aclocal*)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
to install the \`Automake' and \`Perl' packages. Grab them from
any GNU archive site."
touch aclocal.m4
;;
autoconf)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified \`${configure_ac}'. You might want to install the
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
archive site."
touch configure
;;
autoheader)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified \`acconfig.h' or \`${configure_ac}'. You might want
to install the \`Autoconf' and \`GNU m4' packages. Grab them
from any GNU archive site."
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
test -z "$files" && files="config.h"
touch_files=
for f in $files; do
case "$f" in
*:*) touch_files="$touch_files "`echo "$f" |
sed -e 's/^[^:]*://' -e 's/:.*//'`;;
*) touch_files="$touch_files $f.in";;
esac
done
touch $touch_files
;;
automake*)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
You might want to install the \`Automake' and \`Perl' packages.
Grab them from any GNU archive site."
find . -type f -name Makefile.am -print |
sed 's/\.am$/.in/' |
while read f; do touch "$f"; done
;;
autom4te)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is needed, and you do not seem to have it handy on your
system. You might have modified some files without having the
proper tools for further handling them.
You can get \`$1Help2man' as part of \`Autoconf' from any GNU
archive site."
file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
if test -f "$file"; then
touch $file
else
test -z "$file" || exec >$file
echo "#! /bin/sh"
echo "# Created by GNU Automake missing as a replacement of"
echo "# $ $@"
echo "exit 0"
chmod +x $file
exit 1
fi
;;
bison|yacc)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified a \`.y' file. You may need the \`Bison' package
in order for those modifications to take effect. You can get
\`Bison' from any GNU archive site."
rm -f y.tab.c y.tab.h
if [ $# -ne 1 ]; then
eval LASTARG="\${$#}"
case "$LASTARG" in
*.y)
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
if [ -f "$SRCFILE" ]; then
cp "$SRCFILE" y.tab.c
fi
SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
if [ -f "$SRCFILE" ]; then
cp "$SRCFILE" y.tab.h
fi
;;
esac
fi
if [ ! -f y.tab.h ]; then
echo >y.tab.h
fi
if [ ! -f y.tab.c ]; then
echo 'main() { return 0; }' >y.tab.c
fi
;;
lex|flex)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified a \`.l' file. You may need the \`Flex' package
in order for those modifications to take effect. You can get
\`Flex' from any GNU archive site."
rm -f lex.yy.c
if [ $# -ne 1 ]; then
eval LASTARG="\${$#}"
case "$LASTARG" in
*.l)
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
if [ -f "$SRCFILE" ]; then
cp "$SRCFILE" lex.yy.c
fi
;;
esac
fi
if [ ! -f lex.yy.c ]; then
echo 'main() { return 0; }' >lex.yy.c
fi
;;
help2man)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified a dependency of a manual page. You may need the
\`Help2man' package in order for those modifications to take
effect. You can get \`Help2man' from any GNU archive site."
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
if test -z "$file"; then
file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
fi
if [ -f "$file" ]; then
touch $file
else
test -z "$file" || exec >$file
echo ".ab help2man is required to generate this page"
exit 1
fi
;;
makeinfo)
if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then
# We have makeinfo, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified a \`.texi' or \`.texinfo' file, or any other file
indirectly affecting the aspect of the manual. The spurious
call might also be the consequence of using a buggy \`make' (AIX,
DU, IRIX). You might want to install the \`Texinfo' package or
the \`GNU make' package. Grab either from any GNU archive site."
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
if test -z "$file"; then
file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
fi
touch $file
;;
tar)
shift
if test -n "$run"; then
echo 1>&2 "ERROR: \`tar' requires --run"
exit 1
fi
# We have already tried tar in the generic part.
# Look for gnutar/gtar before invocation to avoid ugly error
# messages.
if (gnutar --version > /dev/null 2>&1); then
gnutar "$@" && exit 0
fi
if (gtar --version > /dev/null 2>&1); then
gtar "$@" && exit 0
fi
firstarg="$1"
if shift; then
case "$firstarg" in
*o*)
firstarg=`echo "$firstarg" | sed s/o//`
tar "$firstarg" "$@" && exit 0
;;
esac
case "$firstarg" in
*h*)
firstarg=`echo "$firstarg" | sed s/h//`
tar "$firstarg" "$@" && exit 0
;;
esac
fi
echo 1>&2 "\
WARNING: I can't seem to be able to run \`tar' with the given arguments.
You may want to install GNU tar or Free paxutils, or check the
command line arguments."
exit 1
;;
*)
echo 1>&2 "\
WARNING: \`$1' is needed, and you do not seem to have it handy on your
system. You might have modified some files without having the
proper tools for further handling them. Check the \`README' file,
it often tells you about the needed prerequirements for installing
this package. You may also peek at any GNU archive site, in case
some other package would contain this missing \`$1' program."
exit 1
;;
esac
exit 0
@@ -0,0 +1,40 @@
#! /bin/sh
# mkinstalldirs --- make directory hierarchy
# Author: Noah Friedman <[email protected]>
# Created: 1993-05-16
# Public domain
# $Id: mkinstalldirs,v 4.0 2004/03/31 17:52:41 sonnyrao Exp $
errstatus=0
for file
do
set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
shift
pathcomp=
for d
do
pathcomp="$pathcomp$d"
case "$pathcomp" in
-* ) pathcomp=./$pathcomp ;;
esac
if test ! -d "$pathcomp"; then
echo "mkdir $pathcomp"
mkdir "$pathcomp" || lasterr=$?
if test ! -d "$pathcomp"; then
errstatus=$lasterr
fi
fi
pathcomp="$pathcomp/"
done
done
exit $errstatus
# mkinstalldirs ends here
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,151 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 _PARSER_H_
#define _PARSER_H_
#include "ffsb.h"
#include "list.h"
#define COMMENT_CHAR '#'
#define STORE_SINGLE 0x0001
#define STORE_LIST 0x0002
#define TYPE_U32 0x0001
#define TYPE_U64 0x0002
#define TYPE_STRING 0x0004
#define TYPE_BOOLEAN 0x0008
#define TYPE_DOUBLE 0x0010
#define TYPE_RANGE 0x0020
#define TYPE_SIZEWEIGHT 0x0040
#define TYPE_DEPRECATED 0x0080
#define TYPE_WEIGHT 0x0100
#define TYPE_SIZE32 0x0200
#define TYPE_SIZE64 0x0400
#define ROOT 0x0001
#define THREAD_GROUP 0x0002
#define FILESYSTEM 0x0004
#define END 0x0008
#define STATS 0x0010
#define GLOBAL_OPTIONS { \
{"num_filesystems", NULL, TYPE_DEPRECATED, STORE_SINGLE}, \
{"num_threadgroups", NULL, TYPE_DEPRECATED, STORE_SINGLE}, \
{"verbose", NULL, TYPE_BOOLEAN, STORE_SINGLE}, \
{"time", NULL, TYPE_U32, STORE_SINGLE}, \
{"directio", NULL, TYPE_BOOLEAN, STORE_SINGLE}, \
{"bufferio", NULL, TYPE_BOOLEAN, STORE_SINGLE}, \
{"alignio", NULL, TYPE_BOOLEAN, STORE_SINGLE}, \
{"callout", NULL, TYPE_STRING, STORE_SINGLE}, \
{NULL, NULL, 0, 0} }
#define THREADGROUP_OPTIONS { \
{"bindfs", NULL, TYPE_STRING, STORE_SINGLE}, \
{"num_threads", NULL, TYPE_U32, STORE_SINGLE}, \
{"read_weight", NULL, TYPE_WEIGHT, STORE_SINGLE}, \
{"readall_weight", NULL, TYPE_WEIGHT, STORE_SINGLE}, \
{"read_random", NULL, TYPE_BOOLEAN, STORE_SINGLE}, \
{"read_skip", NULL, TYPE_U32, STORE_SINGLE}, \
{"read_size", NULL, TYPE_SIZE64, STORE_SINGLE}, \
{"read_blocksize", NULL, TYPE_SIZE32, STORE_SINGLE}, \
{"read_skipsize", NULL, TYPE_SIZE32, STORE_SINGLE}, \
{"write_weight", NULL, TYPE_WEIGHT, STORE_SINGLE}, \
{"write_fsync_weight", NULL, TYPE_WEIGHT, STORE_SINGLE}, \
{"write_random", NULL, TYPE_BOOLEAN, STORE_SINGLE}, \
{"fsync_file", NULL, TYPE_DEPRECATED, STORE_SINGLE}, \
{"write_size", NULL, TYPE_SIZE64, STORE_SINGLE}, \
{"write_blocksize", NULL, TYPE_SIZE32, STORE_SINGLE}, \
{"create_weight", NULL, TYPE_WEIGHT, STORE_SINGLE}, \
{"create_fsync_weight", NULL, TYPE_WEIGHT, STORE_SINGLE}, \
{"delete_weight", NULL, TYPE_WEIGHT, STORE_SINGLE}, \
{"append_weight", NULL, TYPE_WEIGHT, STORE_SINGLE}, \
{"append_fsync_weight", NULL, TYPE_WEIGHT, STORE_SINGLE}, \
{"metaop_weight", NULL, TYPE_WEIGHT, STORE_SINGLE}, \
{"createdir_weight", NULL, TYPE_WEIGHT, STORE_SINGLE}, \
{"op_delay", NULL, TYPE_U32, STORE_SINGLE}, \
{"stat_weight", NULL, TYPE_WEIGHT, STORE_SINGLE}, \
{"writeall_weight", NULL, TYPE_WEIGHT, STORE_SINGLE}, \
{"writeall_fsync_weight", NULL, TYPE_WEIGHT, STORE_SINGLE}, \
{"open_close_weight", NULL, TYPE_WEIGHT, STORE_SINGLE}, \
{NULL, NULL, 0} }
#define FILESYSTEM_OPTIONS { \
{"location", NULL, TYPE_STRING, STORE_SINGLE}, \
{"num_files", NULL, TYPE_U32, STORE_SINGLE}, \
{"num_dirs", NULL, TYPE_U32, STORE_SINGLE}, \
{"reuse", NULL, TYPE_BOOLEAN, STORE_SINGLE}, \
{"min_filesize", NULL, TYPE_SIZE64, STORE_SINGLE}, \
{"max_filesize", NULL, TYPE_SIZE64, STORE_SINGLE}, \
{"create_blocksize", NULL, TYPE_SIZE32, STORE_SINGLE}, \
{"age_blocksize", NULL, TYPE_SIZE32, STORE_SINGLE}, \
{"desired_util", NULL, TYPE_DOUBLE, STORE_SINGLE}, \
{"agefs", NULL, TYPE_BOOLEAN, STORE_SINGLE}, \
{"size_weight", NULL, TYPE_SIZEWEIGHT, STORE_LIST}, \
{"init_util", NULL, TYPE_DOUBLE, STORE_SINGLE}, \
{"init_size", NULL, TYPE_SIZE64, STORE_SINGLE}, \
{"clone", NULL, TYPE_STRING, STORE_SINGLE}, \
{NULL, NULL, 0} }
#define STATS_OPTIONS { \
{"enable_stats", NULL, TYPE_BOOLEAN, STORE_SINGLE}, \
{"enable_range", NULL, TYPE_BOOLEAN, STORE_SINGLE}, \
{"ignore", NULL, TYPE_STRING, STORE_LIST}, \
{"msec_range", NULL, TYPE_RANGE, STORE_LIST}, \
{NULL, NULL, 0} }
#define CONTAINER_DESC { \
{"filesystem", FILESYSTEM, 10}, \
{"threadgroup", THREAD_GROUP, 11}, \
{"end", END, 3}, \
{"stats", STATS, 5}, \
{NULL, 0, 0} }
typedef struct container {
struct config_options *config;
uint32_t type;
struct container *child;
struct container *next;
} container_t;
typedef struct config_options {
char *name;
void *value;
int type;
int storage_type;
} config_options_t;
typedef struct container_desc {
char *name;
uint16_t type;
uint16_t size;
} container_desc_t;
typedef struct range {
double a;
double b;
} range_t;
typedef struct value_list {
void *value;
struct list_head list;
} value_list_t;
void ffsb_parse_newconfig(ffsb_config_t *fc, char *filename);
#endif
@@ -0,0 +1,4 @@
The Flexible Filesystem Benchmark (FFSB) is a filesystem performance
measurement tool. It uses customizable profiles to measure of different
workloads, and it supports multiple groups of threads across multiple
filesystems.
@@ -0,0 +1,188 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <inttypes.h>
#include <assert.h>
#include "config.h"
#include "rand.h"
#include "util.h"
#define RANDSRC "/dev/urandom"
static int randfd = -1;
/* close the file after we're done with the benchmark */
void randcleanup(void)
{
if (randfd > 0)
close(randfd);
}
/* We fill up the array with random bits from RANDSRC here and set index */
/* to 0 */
/* pre: state->size must be set and state->mt must be allocated! */
static void sgenrand(randdata_t *state)
{
int got = 0;
got = read(randfd, state->mt, state->size);
if (got != state->size) {
int i ;
/* fall back on lrand48 */
/* printf("fallback_rand\n"); */
for (i = got ; i < state->size ; i += 4) {
long int rand = 0;
#ifdef HAVE_LRAND48
lrand48_r(&(state->data), &rand);
#else
rand = random();
#endif
assert(rand != 0);
state->mt[i] = (rand >> 24) & (512 - 1);
state->mt[i+1] = (rand >> 16) & (512 - 1);
state->mt[i+2] = (rand >> 8) & (512 - 1);
state->mt[i+3] = (rand) & (512 - 1);
}
}
state->mti = 0;
}
/* returns 8 random bits */
static uint8_t genrand8(randdata_t *state)
{
unsigned long ret = 0;
if (state->mti >= state->size) {
/* sgenrand(state); */
state->mti = 0;
}
ret = state->mt[state->mti];
state->mti++;
return ret;
}
/* returns 32 random bits */
static uint32_t genrand32(randdata_t *state)
{
uint8_t bytes[4];
uint32_t ret = 0;
bytes[0] = genrand8(state);
bytes[1] = genrand8(state);
bytes[2] = genrand8(state);
bytes[3] = genrand8(state);
ret = *((uint32_t *)bytes); /* !!! hack */
return ret;
}
void init_random(randdata_t *state, uint32_t iter)
{
struct timeval time;
if (iter == 0)
state->size = MIN_RANDBUF_SIZE * AVG_ITR_RNDBTS;
else if (iter > MAX_RANDBUF_SIZE)
state->size = MAX_RANDBUF_SIZE * AVG_ITR_RNDBTS;
else
state->size = iter * AVG_ITR_RNDBTS;
state->mt = ffsb_malloc(state->size);
/* !!!! racy? add pthread_once stuff later */
if ((randfd < 0) && (randfd = open(RANDSRC, O_RDONLY)) < 0) {
perror("open " RANDSRC);
exit(1);
}
sgenrand(state);
gettimeofday(&time, NULL);
#ifdef HAVE_LRAND48
srand48_r(time.tv_sec, &state->data);
#endif
}
void destroy_random(randdata_t *rd)
{
free(rd->mt);
}
/*
* I've taken the liberty of slightly redesigning this stuff.
* Instead of simply getting the full word of random bits
* and throwing away most of it using the mod operator,
* we should only get byte-sized chunks of random bits and
* construct our random number that way with less wasteage - SR
*/
uint32_t getrandom(randdata_t *state, uint32_t mod)
{
uint8_t bytes[4] = { 0, 0, 0, 0 };
uint32_t ret;
int num_bytes = 4;
int i;
if ((mod == 0) || (mod == 1))
return 0;
if (!(mod >> 8))
num_bytes = 1;
else if (!(mod >> 16))
num_bytes = 2;
else if (!(mod >> 24))
num_bytes = 3;
for (i = 0; i < num_bytes; i++)
bytes[i] = genrand8(state);
ret = (bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0];
return ret % mod;
}
uint64_t getllrandom(randdata_t *state, uint64_t mod)
{
uint64_t result = 0;
uint64_t high = 0;
uint32_t low = 0;
if (mod == 0)
return 0;
/* ULONG_MAX comes from limits.h */
if (mod < ULONG_MAX)
return (uint64_t)getrandom(state, (uint32_t)mod);
high = genrand32(state);
low = genrand32(state);
result = high << 32;
result |= (uint64_t)low;
assert(result != 0);
assert(result > 0);
return result % mod;
}
@@ -0,0 +1,60 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 _MTINT_H_
#define _MTINT_H_
#include "config.h"
#include <stdlib.h>
#include <sys/types.h>
#include <inttypes.h>
/* A guess of how many random bytes (not bits) */
/* will be consumed per iteration */
/* This is multiplied by the iteration count */
/* to get the size of the array in init_random() */
#define AVG_ITR_RNDBTS 2
/* Set a cap on the size of the array, note this */
/* is multiplied by AVG_ITR_RNDBTS */
#define MAX_RANDBUF_SIZE (10 * 1024)
#define MIN_RANDBUF_SIZE 1024
typedef struct randdata {
int size;
uint8_t *mt; /* the array of random bits */
int mti; /* mti==N+1 means mt[N] is not initialized */
/* fallback random source, lrand48_r() */
#ifdef HAVE_LRAND48_R
struct drand48_data data;
#endif
} randdata_t;
uint32_t getrandom(randdata_t *rd, uint32_t mod);
uint64_t getllrandom(randdata_t *rd, uint64_t mod);
/* pass in thread-local state, and est. number of "uses" */
/* pass in 0 for size if size is unknown/not important */
void init_random(randdata_t *state, uint32_t size);
void destroy_random(randdata_t *rd);
void randcleanup(void);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,316 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 RED_BLACK_TREE_H
#define RED_BLACK_TREE_H
/*
* ***************************************************************************
*
* Container class for a red-black tree ......
*
* A binary tree that satisfies the following properties:
*
* 1. Every node is either red or black
* 2. The root node is black
* 3. Every leaf (NIL) is black
* 4. If a node is red, both its children are black
* 5. For each node, all paths from the node to descendant leaf nodes
* contain the same number of black nodes
*
* Due to points 4 & 5, the depth of a red-black tree containing n nodes
* is bounded by 2*log2(n+1) (WC).
*
*
* The rb_tree template requires two additional parmeters:
*
* - The contained TYPE class represents the objects stored in the tree.
* It has to support the copy constructor and the assignment operator (opr)
* - cmp is a functor used to define the order of objects of class TYPE:
* This class has to support an operator() that recieves two objects from
* the TYPE class and returns a negative, 0, or a positive integer,
* depending on the comparison result.
*
* Dominique Heger, S. Rao
*
* ***************************************************************************
*/
/* Color enumeration for nodes of red-black tree */
/* ********************************************* */
#include "filelist.h"
typedef struct ffsb_file *datatype;
#define COMP_NODES(a, b) ((a)->num - (b)->num)
typedef enum red_black_color {red, black} rb_color;
/*! Representation of a node in a red-black tree */
typedef struct red_black_node {
datatype object; /* the stored object */
rb_color color; /* the color of the node */
struct red_black_node *parent; /* points to the parent node */
struct red_black_node *right; /* points to the right child */
struct red_black_node *left; /* points to the left child */
} rb_node;
typedef int(cmp)(datatype, datatype);
typedef void(opr)(void *);
typedef void(destructor)(datatype);
/* Construct of a red-black tree node
* - The object stored in the node
* - The color of the node
*/
extern rb_node *rbnode_construct(datatype object, rb_color color);
/* Recursive destructor for the entire sub-tree */
/* ******************************************** */
extern void rbnode_destruct(rb_node *node, destructor d);
/* Calculate the depth of the sub-tree spanned by the given node
* - The sub-tree root
* - The sub-tree depth
*/
extern int rbnode_depth(rb_node *node);
/* Get the leftmost node in the sub-tree spanned by the given node
* - The sub-tree root
* - The sub-tree minimum
*/
extern rb_node *rbnode_minimum(rb_node *node);
/* Get the rightmost node in the sub-tree spanned by the given node
* - The sub-tree root
* - The sub-tree maximum
*/
extern rb_node *rbnode_maximum(rb_node *node);
/* Replace the object */
/* ****************** */
extern void rbnode_replace(rb_node *node, datatype object);
/* Get the next node in the tree (according to the tree order)
* - The current node
* - The successor node, or NULL if node is the tree maximum
*/
extern rb_node *rbnode_successor(rb_node *node);
/* Get the previous node in the tree (according to the tree order)
* - The current node
* - The predecessor node, or NULL if node is the tree minimum
*/
extern rb_node *rbnode_predecessor(rb_node *node);
/* Duplicate the entire sub-tree rooted at the given node
* - The sub-tree root
* - A pointer to the duplicated sub-tree root
*/
extern rb_node *rbnode_duplicate(rb_node *node);
/* Traverse a red-black sub-tree
* - The sub-tree root
* - The operation to perform on each object in the sub-tree
*/
extern void rbnode_traverse(rb_node *node, opr *op);
/* Representation of a red-black tree */
/* ********************************** */
typedef struct red_black_tree {
rb_node *root; /* pointer to the tree root */
int isize; /* number of objects stored */
/* cmp * comp; */ /* compare function */
} rb_tree;
/* Initialize a red-black tree with a comparision function
* - The tree
* - The comparision function
*/
void rbtree_init(rb_tree *tree);
/* Construct a red-black tree with a comparison object
* - A pointer to the comparison object to be used by the tree
* - The newly constructed tree
*/
rb_tree *rbtree_construct(void);
/* Clean a red-black tree [takes O(n) operations]
* - The tree
*/
extern void rbtree_clean(rb_tree *tree, destructor d);
/* Destruct a red-black tree
* - The tree
*/
extern void rbtree_destruct(rb_tree *tree, destructor d);
/* Get the size of the tree [takes O(1) operations]
* - The tree
* - The number of objects stored in the tree
*/
extern int rbtree_size(rb_tree *tree);
/* Get the depth of the tree [takes O(n) operations]
* - The tree
* - The length of the longest path from the root to a leaf node
*/
extern int rbtree_depth(rb_tree *tree);
/* Check whether the tree contains an object [takes O(log n) operations]
* - The tree
* - The query object
* - (true) if an equal object is found in the tree, otherwise (false)
*/
extern int rbtree_contains(rb_tree *tree, datatype object);
/* Insert an object to the tree [takes O(log n) operations]
* - The tree
* - The object to be inserted
* - Return the inserted object node
*/
extern rb_node *rbtree_insert(rb_tree *tree, datatype object);
/* Insert a new object to the tree as the a successor of a given node
* - The tree
* - The new node
*/
extern rb_node *insert_successor_at(rb_tree *tree, rb_node *at_node,
datatype object);
/* Insert a new object to the tree as the a predecessor of a given node
* - The tree
* - The new node
*/
extern rb_node *insert_predecessor_at(rb_tree *tree, rb_node *at_node,
datatype object);
/* Remove an object from the tree [takes O(log n) operations]
* - The tree
* - The object to be removed
* - The object should be contained in the tree
*/
extern void rbtree_remove(rb_tree *tree, datatype object, destructor d);
/* Get a handle to the tree minimum [takes O(log n) operations]
* - The tree
* - Return the minimal object in the tree, or a NULL if the tree is empty
*/
extern rb_node *rbtree_minimum(rb_tree *tree);
/* Get a handle to the tree maximum [takes O(log n) operations]
* - The tree
* - Return the maximal object in the tree, or a NULL if the tree is empty
*/
extern rb_node *rbtree_maximum(rb_tree *tree);
/* Get the next node in the tree (according to the tree order)
* - [takes O(log n) operations at worst-case, but only O(1) amortized]
* - The tree
* - The current object
* - The successor node, or a NULL, if we are at the tree maximum
*/
extern rb_node *rbtree_successor(rb_tree *tree, rb_node *node);
/* Get the previous node in the tree (according to the tree order)
* - [takes O(log n) operations at worst-case, but only O(1) amortized]
* - The tree
* - The current object
* - The predecessor node, or a NULL, if we are at the tree minimum
*/
extern rb_node *rbtree_predecessor(rb_tree *tree, rb_node *node);
/* Find a node that contains the given object
* - The tree
* - The desired object
* - Return a node that contains the given object, or NULL if no such object
* is found in the tree
*/
extern rb_node *rbtree_find(rb_tree *tree, datatype object);
/* Remove the object stored in the given tree node
* - The tree
* - The node storing the object to be removed from the tree
*/
extern void rbtree_remove_at(rb_tree *tree, rb_node *node, destructor d);
/* Left-rotate the sub-tree spanned by the given node
* - The tree
* - The sub-tree root
*/
extern void rbtree_rotate_left(rb_tree *tree, rb_node *node);
/* Right-rotate the sub-tree spanned by the given node
* - The tree
* - The sub-tree root
*/
extern void rbtree_rotate_right(rb_tree *tree, rb_node *node);
/*
* Fix the red-black tree properties after an insertion operation
* - The tree
* - The node that has just been inserted to the tree
* - The color of node must be red
*/
extern void rbtree_insert_fixup(rb_tree *tree, rb_node *node);
/* Fix the red-black tree properties after a removal operation
* - The tree
* - The child of the node that has just been removed from the tree
*/
extern void rbtree_remove_fixup(rb_tree *tree, rb_node *node);
/* Traverse a red-black tree
* - The tree
* - The operation to perform on every object of the tree (according to
* the tree order)
*/
extern void rbtree_traverse(rb_tree *tree, opr *op);
#endif
@@ -0,0 +1,7 @@
The Flexible Filesystem Benchmark (FFSB) is a filesystem performance measurement tool. It is a multi-threaded application (using pthreads), written entirely in C with cross-platform portability in mind. It differs from other filesystem benchmarks in that the user may supply a profile to create custom workloads, while most other filesystem benchmarks use a fixed set of workloads.
It is currently known to support Linux, AIX, and Solaris, although almost all development and testing has occurred on Linux. We intend to add support for HP-UX, IRIX, and possibly others in the near future.
FFSB is currently at version 5.0, and has been an internal tool at IBM for about four years. I has already been used to conduct a study of Linux Kernel 2.6 IO-schedulers, and a great deal of future filesystem performance work is planned with FFSB as the primary tool.
In version 5.0, it supports six different basic operations, support for multiple groups of threads with different operation mixtures, support for operation across multiple filesystems, and support for filesystem aging prior to benchmarking.
@@ -0,0 +1,109 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 <pthread.h>
#include <stdlib.h>
#include <stdio.h>
/* #define RWDEBUG 1 */
#include "config.h"
#include "rwlock.h"
void init_rwlock(struct rwlock *rw)
{
rw->n_readers = 0;
pthread_mutex_init(&rw->plock, NULL);
pthread_cond_init(&rw->pcond, NULL);
#ifdef RWDEBUG
rw->n_write_waiting = 0;
rw->n_read_waiting = 0;
rw->writer_tid = -1;
#endif
}
void rw_lock_read(struct rwlock *rw)
{
pthread_mutex_lock(&rw->plock);
#ifdef RWDEBUG
rw->n_read_waiting++;
#endif
while (rw->n_readers < 0)
pthread_cond_wait(&rw->pcond, &rw->plock);
rw->n_readers++;
#ifdef RWDEBUG
rw->n_read_waiting--;
#endif
pthread_mutex_unlock(&rw->plock);
}
void rw_lock_write(struct rwlock *rw)
{
pthread_mutex_lock(&rw->plock);
#ifdef RWDEBUG
rw->n_write_waiting++;
#endif
while (rw->n_readers != 0)
pthread_cond_wait(&rw->pcond, &rw->plock);
rw->n_readers = -1;
#ifdef RWDEBUG
rw->n_write_waiting--;
rw->writer_tid = (int)pthread_self();
#endif
pthread_mutex_unlock(&rw->plock);
}
void rw_unlock_read(struct rwlock *rw)
{
pthread_mutex_lock(&rw->plock);
rw->n_readers -= 1 ;
pthread_cond_signal(&rw->pcond);
pthread_mutex_unlock(&rw->plock);
}
void rw_unlock_write(struct rwlock *rw)
{
pthread_mutex_lock(&rw->plock);
rw->n_readers = 0 ;
pthread_cond_broadcast(&rw->pcond);
pthread_mutex_unlock(&rw->plock);
}
int rw_trylock_read(struct rwlock *rw)
{
int ret = 1;
pthread_mutex_lock(&rw->plock);
if (rw->n_readers >= 0) {
rw->n_readers++;
ret = 0;
}
pthread_mutex_unlock(&rw->plock);
return ret;
}
int rw_trylock_write(struct rwlock *rw)
{
int ret = 1;
pthread_mutex_lock(&rw->plock);
if (rw->n_readers == 0) {
ret = 0;
rw->n_readers = -1;
}
pthread_mutex_unlock(&rw->plock);
return ret;
}
@@ -0,0 +1,51 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 _RWLOCK_H
#define _RWLOCK_H
#include <pthread.h>
/* #define RWDEBUG 1 */
/* n_readers >= 0 means 0 or more readers */
/* n_readers < 0 means a writer */
struct rwlock {
pthread_mutex_t plock;
int n_readers;
pthread_cond_t pcond;
#ifdef RWDEBUG
int writer_tid;
int n_read_waiting;
int n_write_waiting;
#endif
};
void init_rwlock(struct rwlock *rw);
void rw_lock_read(struct rwlock *rw);
void rw_lock_write(struct rwlock *rw);
void rw_unlock_read(struct rwlock *rw);
void rw_unlock_write(struct rwlock *rw);
int rw_trylock_read(struct rwlock *rw);
int rw_trylock_write(struct rwlock *rw);
#endif
@@ -0,0 +1 @@
timestamp
@@ -0,0 +1,363 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2004
*
* 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 <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/select.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <pthread.h>
#include "config.h"
#include "fh.h"
#include "util.h"
uint64_t ffsb_get_filesize(char *name)
{
#ifndef HAVE_STAT64
#define STAT(a, b) do { stat((a), (b)); } while (0)
struct stat filestat;
#else
#define STAT(a, b) do { stat64((a), (b)); } while (0)
struct stat64 filestat;
#endif
STAT(name, &filestat);
return (uint64_t)filestat.st_size;
#undef STAT
}
void *ffsb_malloc(size_t size)
{
void *ptr = malloc((size));
assert(ptr != NULL);
memset(ptr, 0, size);
return ptr;
}
void *ffsb_realloc(void *ptr, size_t size)
{
void *tmp ;
/* printf("ffsb_realloc: ptr = %p size = %ld\n",ptr,size); */
if (ptr == NULL)
return ffsb_malloc(size);
tmp = realloc(ptr, size);
assert(ptr != NULL);
ptr = tmp;
return ptr;
}
void *ffsb_align_4k(void *ptr)
{
unsigned long mask = ~(0xfff); /* 12 zeros at the end */
void *ret = (void *)((unsigned long)ptr & mask);
/* printf("align_4k got %p returning %p\n",ptr,ret); */
return ret;
}
char *ffsb_strdup(const char *str)
{
int len = strlen(str);
char *dup = ffsb_malloc(len + 1);
/* !!! am I off by one here ?? */
strncpy(dup, str, len+1);
return dup;
}
size_t ffsb_strnlen(const char *str, size_t maxlen)
{
size_t index = 0;
while (index < maxlen) {
if (str[index] == '\0')
break;
index++;
}
return index;
}
/* not perfect, in case we are somehow interrupted it's borked */
void ffsb_sleep(unsigned secs)
{
struct timeval tv = { 0 , 0 };
tv.tv_sec = secs;
select(0, NULL, NULL, NULL, &tv);
}
char *ffsb_printsize(char *buf, double size, int bufsize)
{
if (size >= 1024 * 1024 * 1024)
snprintf(buf, bufsize, "%.3gGB", size / (1024 * 1024 * 1024));
else if (size >= 1024 * 1024)
snprintf(buf, bufsize, "%.3gMB", size / (1024 * 1024));
else if (size >= 1024)
snprintf(buf, bufsize, "%.3gKB", size/1024);
else
snprintf(buf, bufsize, "%.3gB", size);
return buf;
}
void ffsb_mkdir(char *dirname)
{
if (mkdir(dirname, S_IRWXU) < 0) {
fprintf(stderr, "Error creating %s\n", dirname);
perror("mkdir");
exit(1);
}
}
struct timeval tvsub(struct timeval t1, struct timeval t0)
{
struct timeval tdiff;
tdiff.tv_sec = t1.tv_sec - t0.tv_sec;
tdiff.tv_usec = t1.tv_usec - t0.tv_usec;
if (tdiff.tv_usec < 0)
tdiff.tv_sec--, tdiff.tv_usec += 1000000;
return tdiff;
}
struct timeval tvadd(struct timeval t1, struct timeval t0)
{
struct timeval tdiff;
tdiff.tv_sec = t1.tv_sec + t0.tv_sec;
tdiff.tv_usec = t1.tv_usec + t0.tv_usec;
if (tdiff.tv_usec > 1000000)
tdiff.tv_sec++, tdiff.tv_usec -= 1000000;
return tdiff;
}
double tvtodouble(struct timeval *t)
{
return ((double)t->tv_sec*(1000000.0f) + (double)t->tv_usec) /
1000000.0f;
}
double cpu_so_far(void)
{
struct rusage rusage;
getrusage(RUSAGE_SELF, &rusage);
return
((double) rusage.ru_utime.tv_sec) +
(((double) rusage.ru_utime.tv_usec) / 1000000.0) +
((double) rusage.ru_stime.tv_sec) +
(((double) rusage.ru_stime.tv_usec) / 1000000.0);
}
double cpu_so_far_children(void)
{
struct rusage rusage;
getrusage(RUSAGE_CHILDREN, &rusage);
return
((double) rusage.ru_utime.tv_sec) +
(((double) rusage.ru_utime.tv_usec) / 1000000.0) +
((double) rusage.ru_stime.tv_sec) +
(((double) rusage.ru_stime.tv_usec) / 1000000.0);
}
/* !!!! check portability */
float getfsutil(char *dirname)
{
#ifdef __HAIKU__
struct statvfs fsdata;
statvfs(dirname, &fsdata);
#else
struct statvfs64 fsdata;
statvfs64(dirname, &fsdata);
#endif
/* return (float)(fsdata.f_blocks-fsdata.f_bfree)/ */
/* (float)(fsdata.f_blocks-fsdata.f_bfree+fsdata.f_bavail); */
return (float) (((float)(fsdata.f_blocks - fsdata.f_bfree)) /
((float)fsdata.f_blocks));
}
uint64_t getfsutil_size(char *dirname)
{
#ifdef __HAIKU__
struct statvfs fsdata;
statvfs(dirname, &fsdata);
#else
struct statvfs64 fsdata;
statvfs64(dirname, &fsdata);
#endif
return (fsdata.f_blocks - fsdata.f_bfree) * fsdata.f_bsize;
}
int ffsb_system(char *command)
{
int pid=0, status;
extern char **environ;
if (command == NULL)
return 1;
pid = fork();
if (pid == -1)
return -1;
if (pid == 0) {
char *argv[4];
argv[0] = "sh";
argv[1] = "-c";
argv[2] = command;
argv[3] = 0;
execve("/bin/sh", argv, environ);
exit(127);
}
do {
if (waitpid(pid, &status, 0) == -1) {
if (errno != EINTR)
return -1;
}
else
return status;
} while (1);
}
void ffsb_sync()
{
struct timeval starttime, endtime, difftime;
printf("Syncing()...");
fflush(stdout);
gettimeofday(&starttime, NULL);
sync();
gettimeofday(&endtime, NULL);
timersub(&endtime, &starttime, &difftime);
printf("%ld sec\n", difftime.tv_sec);
}
void ffsb_getrusage(struct rusage *ru_self, struct rusage *ru_children)
{
int ret = 0;
/* printf("cpu_so_far is %lf\n",cpu_so_far()); */
/* printf("cpu_so_far_children is %lf\n",cpu_so_far_children()); */
ret = getrusage(RUSAGE_SELF, ru_self);
if (ret < 0)
perror("getrusage self");
/* printf("self returned %d\n",ret); */
ret = getrusage(RUSAGE_CHILDREN, ru_children);
if (ret < 0)
perror("getrusage children");
/* printf("children returned %d\n",ret); */
}
void ffsb_milli_sleep(unsigned time)
{
struct timeval tv = { 0 , 0 };
if (!time)
return;
tv.tv_usec = time * 1000;
select(0, NULL, NULL, NULL, &tv);
}
void ffsb_micro_sleep(unsigned time)
{
struct timeval tv = { 0 , 0 };
if (!time)
return;
tv.tv_usec = time ;
select(0, NULL, NULL, NULL, &tv);
}
void ffsb_barrier_init(ffsb_barrier_t *fb, unsigned count)
{
memset(fb, 0, sizeof(*fb));
pthread_mutex_init(&fb->plock, NULL);
pthread_cond_init(&fb->pcond, NULL);
fb->required_count = count;
}
void ffsb_barrier_wait(ffsb_barrier_t *fb)
{
pthread_mutex_lock(&fb->plock);
fb->current_count++;
if (fb->current_count == fb->required_count)
pthread_cond_broadcast(&fb->pcond);
else
while (fb->current_count != fb->required_count)
pthread_cond_wait(&fb->pcond, &fb->plock);
pthread_mutex_unlock(&fb->plock);
}
void ffsb_unbuffer_stdout(void)
{
#ifndef SETVBUF_REVERSED
setvbuf(stdout, NULL, _IONBF, 0);
#else
setvbuf(stdout, _IONBF, NULL, 0);
#endif
}
void ffsb_bench_gettimeofday(void)
{
unsigned long i = 0;
uint64_t total_usec;
uint64_t average = 0;
struct timeval starttime, endtime, junk, difftime;
gettimeofday(&starttime, NULL);
for (i = 0; i < 1000000; i++)
gettimeofday(&junk, NULL);
gettimeofday(&endtime, NULL);
timersub(&endtime, &starttime, &difftime);
total_usec = difftime.tv_sec * 1000000;
total_usec += difftime.tv_usec;
average = total_usec / 1000ull;
printf("average time for gettimeofday(): %llu nsec\n", average);
}
void ffsb_bench_getpid(void)
{
unsigned long i = 0;
uint64_t total_usec;
uint64_t average = 0;
struct timeval starttime, endtime, difftime;
gettimeofday(&starttime, NULL);
for (i = 0; i < 1000000; i++)
getpid();
gettimeofday(&endtime, NULL);
timersub(&endtime, &starttime, &difftime);
total_usec = difftime.tv_sec * 1000000;
total_usec += difftime.tv_usec;
average = total_usec / 1000ull;
printf("average time for getpid(): %llu nsec\n", average);
}
@@ -0,0 +1,94 @@
/*
* Copyright (c) International Business Machines Corp., 2001-2006
*
* 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 _UTIL_H_
#define _UTIL_H_
#include "config.h"
#include <sys/time.h>
#include <sys/resource.h>
#ifdef HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#include <sys/statvfs.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <pthread.h>
void ffsb_sleep(unsigned secs);
void *ffsb_malloc(size_t size);
void *ffsb_realloc(void *ptr, size_t size);
char *ffsb_strdup(const char *str);
size_t ffsb_strnlen(const char *str, size_t maxlen);
void ffsb_mkdir(char *dirname);
void ffsb_getrusage(struct rusage *ru_self, struct rusage *ru_children);
void ffsb_sync(void);
void *ffsb_align_4k(void *ptr);
char *ffsb_printsize(char *buf, double size, int bufsize);
int ffsb_system(char *command);
void ffsb_milli_sleep(unsigned time);
void ffsb_micro_sleep(unsigned time);
void ffsb_unbuffer_stdout(void);
void ffsb_bench_gettimeofday(void);
void ffsb_bench_getpid(void);
uint64_t ffsb_get_filesize(char *name);
typedef struct {
unsigned required_count;
unsigned current_count;
pthread_mutex_t plock;
pthread_cond_t pcond;
} ffsb_barrier_t ;
void ffsb_barrier_init(ffsb_barrier_t *fb, unsigned count);
void ffsb_barrier_wait(ffsb_barrier_t *fb);
double cpu_so_far(void);
double time_so_far(void);
double cpu_so_far_children(void);
float getfsutil(char *dirname);
uint64_t getfsutil_size(char *dirname);
struct timeval tvsub(struct timeval t1, struct timeval t0);
struct timeval tvadd(struct timeval t1, struct timeval t0);
double tvtodouble(struct timeval *t);
#define max(a, b) (((a) > (b)) ? (a) : (b))
#ifndef timersub
#define timersub(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
\
if ((result)->tv_usec < 0) { \
(result)->tv_sec--; \
(result)->tv_usec += 1000000; \
} \
} while (0)
#endif /* timersub */
#endif /* _UTIL_H_ */