Jonnie Disk IO Test
Program Documentation
Jonnie is a Disk IO test program written in Java. Its goal is to test the disk
sub-systems of computers. While it does produce performance numbers, the primary
goals of Jonnie are:
- Generate a heavy I/O Load
- Verify that data can be read and written correctly.
- Portability - Jonnie runs on any platform that supports JDK 1.5 or higher.
The tests performed by Jonnie are:
- File Creation Test
- Sequential I/O Test
- Random I/O Test
The most important thing to understand is that when read operations are
performed, the data is compared to the source data. This ensures that if
anything happened to corrupt the data (bad RAM, OS Bugs, firmware or driver bugs,
etc) those errors will be detected. Media or hardware errors in the disk devices
will be caught and reported by the OS.
To maximize the chance of data corruption being detected, each block of data is
filled with random data from a pseudo-random number generator (PRNG). On the
read cycle, the PRNG is re-seeded and used to generate the block data for
comparison.
System Requirements
- Java Runtime Engine JRE 1.5 or higher
- Test file system must support long file names.
- File system must support files at least as large as you specify for the
tests.
The command to run jonnie is:
java -server -jar jonnie.jar tests.xml
where tests.xml is the XML configuration file that describes how to perform the
tests.
It's important to use the -server JVM argument. Testing shows this can double
throughput on the Sequential Read test, and improve performance on other tests
by up to 25%.
Configuration of Jonnie is handled by editing an XML file. You can edit this
file, to remove specific tests, add your own custom tests, or configure tests.
Global Configuration Settings
Each test receives all global configuration settings plus all per-test settings.
If a test setting is present in both sections, then the per-test setting will
override the global configuration setting.
Note that count/size arguments can take power of 2 suffixes (i.e. K,M,G).
If you get ridiculously large throughput values from the tests, try increasing
the test file sizes.
- TestPath
-
This is the path where test files are created.
- ThreadCount (Global Configuration only)
-
If this value is not specified, one test thread is created. If you want, you can
have multiple test threads running at the same time. This can further stress
your computer's I/O sub-system by forcing seeks over a wider portion of the disk.
Keep in mind that if you specify a 16GB test file, and you run 5 threads, then
the total disk requirement for the test is 80GB.
- IterationCount (Global Configuration only)
-
This is the number of times that Jonnie should run the configured tests. If this
value is negative, then tests will run until the program is terminated.
If ThreadCount is greater than one, then each thread will execute IterationCount
tests.
- VerifyRead
-
If this value is true, then as the file is read, the data is compared with the
source data. If this value is false, then data will not be checked for accuracy
during the read cycle.We STRONGLY urge you to use the default setting of
true.
- TestCorruption
-
If this value is set to true, then each test will randomly corrupt the test file.
One byte in the test file will be modified. This is a diagnostic facility used to
test Jonnie itself to make sure that it can detect a corruption error. In normal
use, you would not turn this on.
Individual Test Configuration
com.mhsoftware.jonnie.FileCreationTest
The system creates the specified number of files. As each file is created, the
specified amount of data is written to the file, and it is then closed. After
all files have been created, each file is opened in turn, the data read and
verified, and then the file is deleted.
- TestPath
-
See Global Configuration
- FileCount
-
This is the number of files the File Creation Test should create. If you get
really high numbers, try increasing the count to larger values.
- FileSize
-
Rather than creating a 0 byte sized file, Jonnie writes actual data to the file.
This is the amount of data that should be written. Normal values would be 1k-16k.
- VerifyRead
-
See Global Configuration
com.mhsoftware.jonnie.SequentialIOTest
A new file is created, and filled with randomly generated data. The file is
closed, and then re-opened. The test then reads the file, verifying the data
blocks.
- TestPath
-
See Global Configuration Settings
- File Size
-
The size of the file to create for testing. This should be around 2-4 times the
size of the physical RAM on the test computer. Smaller values will yield totally
ridiculous numbers because of OS caching.
- BlockSize
-
This is the size of the block used for disk input/output. Where possible, a
direct I/O buffer is allocated. Normal values would be 32k-64k.
- VerifyRead
-
See Global Configuration - VerifyRead
com.mhsoftware.jonnie.RandomIOTest
A new file of the specified size is created, and filled with randomly generated
The program then does BlockCount random writes to the file, filling each block
with more randomly generated data.
After the write cycle has completed, the program does BlockCount random reads
from the file.
The location of the read/writes is calculated using the java.util.Random class.
Using a pseudo-random number generator will generally force a seek to a new
location in the file, and if the source file is large enough, disable the
operating systems cache of the file.
After the random read cycle is completed, the areas of the file not
written to during the random write cycle are verified to ensure the data has
not been overwritten.
This test mimics the behavior of a database that is being randomly
read/updated. Note that this is pretty much worst case scenario for a database.
Most database applications will have a few tables that are "hot" where
most reads and writes are made, so this test will report the worst possible
throughput.
- TestPath
-
See Global Configuration Settings
- File Size
-
The size of the file to use for testing. It should be 2-4 times the size of the
computer's physical RAM. If you get ridiculously large numbers, you should
increase this value.
- BlockSize
-
This is the size of the block of data to use for read-write operations. Normal
values would be 16k-64k.
- BlockCount
-
This is the number of blocks to read and write as part of the test.
- SyncOnWrite
-
Setting this argument will open the file with a setting to force data to be
flushed to the operating system on write. See the mode argument for java.io.RandomAccessFile's
constructor.
If you don't have this set, you can get artificially larger numbers because of
write caching by the OS. On the other hand, this setting this value to false can
demonstrate the effectiveness of the OS/driver write coalesce/elevator routines.
- VerifyRead
-
See Global Configuration - VerifyRead
- Why don't you just use bonnie or bonnie++
-
While these are fine programs, they lack one element that I consider essential.
They don't verify the integrity of the data read/write process.
I had a server that had a very funny bug in the disk sub-system/motherboard. The
file system on the computer would become corrupted. The more heavily used the
computer was, the faster it would corrupt. Initially, the corruption only
appeared every couple of weeks. Under heavy use the file system was getting
corrupted every day.
During the whole troubleshooting process, I repeatedly did system burn-in using
bonnie++ which never reported an error.
After a lot of trouble-shooting, the manufacturer replaced the motherboard with
an updated revision and the problem was solved.
The conclusion I finally came to was that if the disk I/O testing had done a
verification of the data it would have detected the data corruption issue. I
would never have placed the defective machine in production, and I would have
saved myself a TON of time.
- Why don't you just use badblocks with -wv?
-
Badblocks is designed to detect media defects. It sequentially writes then reads
set patterns to the disk.
- Sequential I/O does not generate the same sort of disk and power system
loading that a series of random read/write operations does. It's just not a
representative test.
In my case the data corruption issue was only evident when a heavy load was
present.
I have seen several other instances where hardware raid systems would fail under
heavy loads because of power supply inadequacies.
- Badblocks is rarely run using the actual production OS/drivers because it's
a destructive test. This means that when badblocks is run it's being done from a
live boot CD like Knoppix. This means you're using a different kernel/os/driver
version for performing your testing than you'll use in production.
- Badblocks is meaningless in a RAID environment.
In short, if you want to use badblocks to check the media for errors, that's
probably OK. For anything else it's a waste of time.
- Why are you using Java?
-
The reasons I use Java are:
- because I like it
- It is portable. I can use the software on the different operating systems I
support like MacOS, Linux, and Windows.
- It's dead easy to write multi-threaded code in.
- It's easy to localize. If there's interest, we'll provide a method to allow
easy translation of messages. Numeric output is already formatted according to
the locale of the machine.
- Isn't Java too slow to perform these kinds of tests?
-
I tested bonnie++ on a machine using a hardware RAID controller, and then I
tested jonnie. bonnie++ reported block level I/O rates of 79MB/ Second while
jonnie reported block level I/O rates of 75MB/Second. Setting the thread count
to 2 for testing yielded a combined I/O rate of 79MB/Second from Jonnie. So, it
appears that running single-threaded Jonnie is about 6% slower than bonnie++.
Running two threads brings the I/O rate to virtually the same value.
- Are there any drawbacks compared to bonnie/bonnie++?
-
The drawbacks that I see are:
- bonnie/bonnie++ produce CSV output that's easy to import into a charting
program.
- They produce CPU utilization numbers. Because Jonnie uses a
PRNG to fill each output block with randomly generated data,
you're not going to be able to get meaningful CPU
utilization/Disk IO numbers from it.
Again, Jonnie isn't so much focused on measuring performance as making sure that
the whole disk sub-system is working correctly.
- Can I write my own tests?
-
Yes. In a nutshell, you have to sub-class the com.mhsoftware.jonnie.JonnieTest
class, and implement the run() method. Your methods can use the JonnieTest.getProperty()
method to retrieve configuration values.
If you want to integrate testing your class into Jonnie, you should call the
testCorruption() method, and if it returns true introduce some corruption at
some point into your test file.
If your test detects corruption in the read data cycle, then you should call
reportException() with your Exception object.
Once you've created your class, and compiled it, you can add it to the test
cycle by putting it in the tests.xml file.
The only final thing to remember is that you'll have to add the class path for
your new test to the command line when you start Jonnie.
This program is licensed under the terms of the GNU GPL V3. Refer to the
accompanying LICENSE file, or the GNU web site for additional information.
Copyright 2008, MH Software, Inc. All Rights Reserved.