Real world performance metrics: java.io vs. java.nio

A before and after comparison of my application’s FLV indexing performance between java.io streams and java.nio file channels.

In my application at xtendx AG, there is some code that indexes uploaded FLV (Flash video) files to determine the byte mark of each key-frame which are spaced out every second or so by our encoding process.  The index allows client players to request an flash video at an arbitrary second position with in the FLV. This indexing needs to be done, for the sake of simplicity, once and only once before a file is streamed to an end user.  Therefor, the first attempt to view a file incurs a non-trivial delay as the server indexes the file.  It needs to be fast!  OK, that is the “why”.

The indexing process is very straight forward:

  1. Open the file, validate the header, read in meta data
  2. Read in key frame meta data (type, temporal position, frame size)
  3. Take note of temporal position and absolute position of start byte of key frame
  4. Skip ahead to start of next key frame
  5. Jump to step 2 until end of file
  6. Save temporal position / byte position map

As one can guess, the file access is not exactly serial nor is it exactly random in nature.  Because of the relatively large distance between key frames (up to thousands of bytes), I am thinking that the file access would be more appropriately categorized as random despite always moving forward.

Before changing the code, I whipped up some quick just-read-every-byte-in-file-quickly micro-benchmarks on my old MacBook to see what I could expect, and understand how to use FileChannels correctly.  Every looked good.

In the latest release of Simplex Media Server, v2.3, the indexing code was refactored to use java.nio’s FileChannels.  A little bit of strategic logging in both the new and old versions captured some performance metrics from one of our production systems.  Real world numbers rock!

It is probably worth documenting the relevant hardware and software involved:

Make & Model HP DL380 G5
CPU (1) 1.86GHz Xeon Quad-core
Memory  4GB
Operating System  RHEL4 (64-bit)
File System  SAS RAID-10 w/ (4) 10K RPM HDD
Java Version   Sun JDK 1.5.12 (64-bit)
Relevant JVM Options -Xms768m -Xmx768m -Xincgc

 

Raw Data
java.io results
 File Size (MB)  Speed (MBps)
4.8 31.9
6.9 61.5
8.6 11.8
9.2 15.6
10.8 102.3
11.5 40.1
11.5 36.9
13.7 10.6
15.5 17.4
25.9 31.3
30.0 15.2
50.0 13.9
101.2 38.8
107.3 40.2
113.5 38.8
114.1 32.9
116.6 38.4
134.8 37.1
148.6 41.0
161.3 38.5
222.5 40.9
java.nio results
 File Size (MB)  Speed (MBps)
5.9 90.8
6.8 110.7
6.9 42.2
8.5 111.2
9.4 93.4
10.6 79.6
10.9 70.9
11.6 87.6
12.5 91.7
15.7 63.9
15.8 71.1
18.5 97.6
19.0 132.6
26.4 89.8
68.4 69.5
80.7 77.5
81.0 117.0
86.0 44.6
99.1 65.0
119.7 72.6
282.6 96.7

 

x-axis = file size in MB
y-axis = indexing rate in MBps
Interpretations:

  1. I had graphed the results file size vs. index rate with the expectation of seeing slow rates for smaller files sizes due to the overhead of setting up the i/o.  That cost probably is only apparent with very small files relative to what we are working with here.
  2. As a consequence of the above, both trend lines are relatively flat, with java.io performing ~37MBps and java.nio at ~80MBps.  My refactoring has doubled the speed!
  3. It would be nice to have a larger data set, especially for file sizes larger than 50MB.  That would make me comfortable about the general accuracy of y-axis rate values
  4. The minimum/maximum range for the indexing rate is larger than I expected, even for a production system under load.   I suspect it was a mistake to ignore the video characteristics of the media files themselves, namely the bit rate.  (A higher bit rates mean larger gaps between key frames.)  A follow up post comparing the above values with number of index points on a z-axis would be interesting.