Computer Science 251
Computer Organization and Architecture

Dickinson College
Fall Semester 2004
Grant Braught

Project #1 - Measuring Java's Method Call Overhead

Introduction:

There are many different ways to write a program to perform a given task. For example, in Java there are at least three fundamentally different ways to write a program: Unstructured, Procedural and Object Oriented. In an unstructured program, all of the code would be placed in the main method and no method calls would be used. For example, the following unstructured program sums up all of the numbers from 1 to 1000:

Another approach would be to use a procedural programming approach and break the program into subroutines implemented as static methods. Using a procedural programming approach the program for summing the numbers from 1 to 1000 might appear as:

The third approach would be to use an object oriented approach, identifying the objects and instance methods necessary to complete the program. With an object oriented approach our example program might appear as:

These increasingly complex programming paradigms (unstructured, procedural and object oriented) bring with them the ability to deal effectively with larger and larger programs. However, along with this increased effectiveness for large programs comes increased overhead that can decrease performance. In fact, you have probably been told that method calls incur additional overhead that makes them slower than including the same code in-line. For example, the statement x=y*y; will execute more quickly than x=Math.pow(y,2.0); because the overhead associated with the method call can be eliminated. Similarly, the AllInMain program above will execute more quickly than the StaticMethod program.

In this project you will measure and compare the time required to call static and instance methods in Java (i.e. Java's method call overhead).

Getting Started:

To get started you will need a tool that allows you measure how much time each part of a program takes to execute. You will then be able to use this tool, and some calculations, to determine how much overhead is incurred when calling methods in Java. Fortunately, the Java Virtual Machine (JVM) provides a profiler which is just such a tool. The profiler in the JVM will keep track of the total time it takes a program to execute and what percentage of that total time is spent in each method in the program.

As an example of how to use the JVM profiler we'll use the following variant of the AllInMain program from above:

The MainTest program still computes the sum of all of the numbers from 1 to 1000. However, it repeats this operation 100,000 times. The reason that it is repeated 100,000 times is so that the time used by the main method represents a significant portion of the total time required for the program to execute. If the sum were only performed once then other operations such as initializing the JVM and loading the class take more time than the code in which we are interested. By ensuring that the code in which we are interested dominates the total execution time we will obtain more accurate results.

To use the JVM profiler, you compile the program normally and use a command line argument to the JVM to ask it to perform profiling. For example, to profile the MainTest program you would use the command:

This command will run the MainTest program and record the profiling data in a file named java.hprof.txt. Note, that you may see several lines of output that say "HPROF ERROR". These are due to glitches in the profiler and will not affect your results and can safely be ignored. The java.hprof.txt file contains a lot of information. The information that you will be interested in for this project appears near the end of the file and will look similar to the following:

In the first line above, total = 12400 indicates that the MainTest program took a total of 12400 milliseconds (i.e. 12.400 seconds) to execute. The following lines provided profiling information about each method called (directly or indirectly) by the MainTest program. The rank column indicates which methods used the most time, with lower ranks indicating the methods that used the most time. In the table above, the main method in the MainTest class has rank 1, indicating that it used the most time. The self column indicates the percentage of the total time that was used by each method. For example, the main method used 98.31% of the total time, while the charAt method in the java.lang.String class used 0.08% of the total time. The accum column maintains a running total of the percentage of total time used by all of the methods with lower rank. For example, the last line in the table above indicates that the methods with rank 1 through 7 used 98.79% of the total time.

Collecting the Data:

You should begin by collecting data on the amount of time the MainTest program spends in the main method. However, to ensure accurate results you should adjust the number of iterations in the for (int j=0...) loop so that the main method uses at least 90% of the total time before collection your data. Also, be sure to use good experimental technique by collecting and averaging the data from at least 20 trials.

After collecting data for MainTest you will need to conduct additional experiments to collect data that will allow you to calculate the overhead of static and instance method calls. Specifically, you need to find the time it takes to make a single static method call and the time it takes to make a single instance method call. The examples in the introduction should give you some good ideas on how to get started.

IMPORTANT: As you begin to design the programs, experiments and calculations that you will use the single most important thing you need to do is to ensure that you are isolating the method call overhead. In other words, make sure that the values you are finding represent only the time required for the method calls and nothing else.

The Write ups:

There will be three written documents associated with this project. The first will be a project proposal written collectively by each group. The second and third documents will be a rough draft and final draft of a scientific paper describing the project. The rough and final drafts must be written individually.

Bonus:

In addition to working with static and instance methods, also analyze final instance methods. This will require that you expand your background section to discuss the meaning and effect of the final modifier. Your conclusions will also have to thoroughly explain the results in light of the use of the final modifier. If you complete the bonus your score on the final draft will be increased by up to 10% depending on the quality of your work on the bonus material.