|
Comments
Did you read today's front page stories & breaking news?
SYS-CON.TV
|
General Java Java Performance I/O Tuning
Java Performance I/O Tuning
By: Engineering Sun
Nov. 1, 1997 12:00 AM
Many Java programs that utilize I/O are excellent candidates for performance tuning. One of the more common problems in Java applications is inefficient I/O. A profile of Java applications and applets that handle significant volumes of data will show significant time spent in I/O routines, implying substantial gains can be had from I/O performance tuning. In fact, the I/O performance issues usually overshadow all other performance issues, making them the first area to concentrate on when tuning performance. Therefore, I/O efficiency should be a high priority for developers looking to optimally increase performance. Unfortunately, optimal reading and writing can be challenging in Java. Once an application's reliance upon I/O is established and I/O is determined to account for a substantial slice of the applications execution time, performance tuning can be undertaken. The best method for determining the distribution of execution time among methods is to use a profiler. Sunª Javaª WorkShopª software provides an excellent profiler that offers detailed call counts and execution times for each method. System method call statistics can be tabulated as an option. Stream chaining and custom I/O class methods of performance tuning are discussed. An example program is provided that allows the progressive measurement of the progress of the tuning effort. Using the example program that is provided, JavaIOTest.java, and utilizing the techniques described, substantial performance improvements of an order of magnitude can be achieved. Simple stream chaining provides approximately a 91% decrease in execution time from 28,198 milliseconds to 2,510 milliseconds, while a custom BufferedFileReader class cuts performance time by another 75%, over 97% total, to 630 milliseconds for a 250 kilobyte text file on The Sun™ Solaris™ 2.6 operating environment. Introduction Because Java is a relatively new language, optimizing compiler features are less sophisticated than those available for C and C++, leaving room for more "hand-crafting". The "hand" optimization of key sections identified by profilers, such as the profiler available in Sun's Java WorkShop 2.0, can reap substantial benefits. One of the more common problems in Java applications is inefficient I/O. A profile of Java applications and applets that handle significant volumes of data will show significant time spent in I/O routines, implying substantial gains can be had from I/O performance tuning. In fact, the I/O performance issues usually overshadow all other performance issues, making them the first area to concentrate on when tuning performance. Therefore, I/O efficiency should be a high priority for developers looking to optimally increase performance. Unfortunately, optimal reading and writing can be challenging in Java. Streamlining the use of I/O often results in greater performance gains than all other possible optimizations combined. It is not uncommon to see a speed improvement of at least an order of magnitude using efficient I/O techniques, as this paper and the example program will demonstrate. This article focuses on the improvement gains possible through careful use of both the existing Java I/O classes and the introduction of a custom file reader, BufferedFileReader. BufferedFileReader is responsible for some of the performance increase of Java WorkShop version 2.0 over version 1.0. An example application is used to read three different file sizes, ranging from 100 kilobytes to 500 kilobytes and the results are compared for various optimizations. Performance Tuning Through Stream Chaining Basic IO: DataInputStream The results of using the default, basic I/O scheme are as follows. The first section of the example program, JavaIOTest, showed run times of 28,198 milliseconds reading a 250 kilobyte file.* An Improvement: BufferedInputStream The resulting performance increase for the medium sized file (250 kilobytes) was 91%, from 28,198 milliseconds to 2,510 -- over an order of magnitude with just a simple change.* The New JDK 1.1 Classes Unfortunately, the scheme to provide for Unicode character localization consists of invoking a locale-dependent converter on the raw bytes to convert them to Java characters, causing an extra copy operation per character. This penalty is offset by other efficiencies in the code. The code change is shown in Listing 3. The resulting performance increase for the medium file size was 57%, >from 2,510 to 1,092 milliseconds.* Buffer Size Effects Depending upon the file's size and platform used for testing, the larger buffer size provided performance improvements ranging from 3 to 13 percent. The use of a large buffer size will improve performance significantly and should be considered unless local memory is restricted. Summary Tuning with Custom I/O Classes The BufferedFileReader class is being used in Java WorkShop (package sun.jws.util). The documentation comment in Listing 6 describes the efficiencies added. Without having to chain together several different classes, as with the standard JDK classes, the example provides a single, efficient class through which a file may be read. It is also more efficient (typically faster) than the fastest JDK classes. Specific optimizations include: This class (see Listing 6) contains a self-benchmarking test in its main() method that can be used to measure the exact speedup on a particular system. Further Tuning First, if we look at the first line of the while loop, we see that a new String object is being created for every line of the file being read: while ((line = in.readLine()) != null) {
This means, for example, that for a 100,000 line file 100,000 String objects would be created. Creating a large number of objects incurs costs in three ways: 1. Time and memory to allocate the space for the objects The problem here is that the I/O buffer is private; the user cannot access it directly. Therefore, BufferedFileReader must create a new String object in order to return the data to the user. Although this follows the conventional assertion that class structures should largely be private in order to control data access, the performance penalty is too high an insurance premium for this case. To get around this problem, the user must manage the buffer directly without using the BufferedReader or BufferedFileReader convenience classes. This will enable the user to reuse buffers rather than creating a new object each time to hold the data. Second, strings are inherently less efficient than arrays based upon char. This is because the user must call a method to access each character of a String, whereas the characters can be accessed directly in a char array. Hence, our code example can be made more efficient by avoiding Strings entirely, and using char arrays directly. Listing 7 shows the code which implements the two optimizations above. It is substantially more lines of code than the previous examples, but tests show it performs as much as 3 times faster than the example in Listing 5. Performance Tuning Results *Full test results are available at: http://www.sun.com/workshop/java/wp-javaio. See Appendix One. This article was provided by Engineering, Sun's Authoring and Development Tools Group. Reader Feedback: Page 1 of 1
Latest Cloud Developer Stories
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
|
SYS-CON Featured Whitepapers
Most Read This Week
Breaking Cloud Computing News
|
|||||||||||||||||||||||||||||||||||||||||||||||||