Dr. Winston Prakash Ph.D. 

Personal Website

A simple idea to load test web application response

There are hundreds of sophisticated Web Testing tools available in the market, which you could use for Load testing your web site. Nevertheless, you might want to write some test code to quickly test the response time of your web application during its development time.

Here is a simple tip on how to do this. If you want to test your web application response time during various loads, first you need to simulate the load by simultaneously sending required number of requests for your web application pages to the web server. You could write your own concurrent programming to achieve this. But the easiest and simplest is to use the classes in java.util.concurrent package.

The following is a simple code to execute a Runnable task, specified number of times concurrently and then measure the total time elapsed. The idea behind the code logic is to use the utility Class called java.util.concurrent.CountDownLatch. Two latches are used in the code. A Start Latch with one count and an End Latch with count equals to the number of concurrent executions required. The main thread creates worker thread for each Runnable task. After the worker threads are started by the main thread, each one of them waits on the Start Latch. When all the worker threads are created, main thread counts down the Start Latch by one, which opens the gate for all worker threads to execute simultaneously. Before decreasing the count of Start Latch, the main thread marks the start time. When each worker thread finishes, it decreases the End Latch count by one. After starting all the worker threads and counting down the start latch for the worker threads to start executing, main thread waits on the End Latch. Since each worker thread counts down the End Latch by one at end of its execution, when all the tasks are completed, End Latch will be count down to 0, which causes its gate to open. Now the main thread, which was waiting on End Latch, notes the end time and returns the time elapsed time between the end time and the start time marked previously.

Public class ConcurrentTaskTester{  
    public long timeTasksConcurrently(int nThreads, final Runnable task) 
                          throws InterruptedException{
        final CountDownLatch startLatch = new CountDownLatch(1);
        final CountDownLatch endLatch = new CountDownLatch(nThreads);
        for (int i = 0; i < nThreads; i++){
            Thread workerThread = new Thread(){
                public void run(){
                    
                    try {
                        startLatch.await();
                        try {
                            task.run();
                        }finally {
                            endLatch.countDown();
                        }
                    } catch (Exception e) {
                        
                    }
                }
            };
            workerThread.start();
        }
        long start = System.currentTimeMillis();
        startLatch.countDown();
        endLatch.await();
        long end = System.currentTimeMillis();
        return end - start;
    }
    public void displayElapsedTime(String label, long milliSecs){
        long secs = milliSecs/1000;
        long elapsedHours = secs / (60 * 60);
        long elapsedMins = (secs - (elapsedHours * 60 * 60))/60;
        long elapsedSecs = secs - (elapsedHours * 60  - elapsedMins) * 60;
        long elapsedMilliSecs = milliSecs - ((elapsedHours * 60 - 
                             elapsedMins) * 60 * 1000) - (elapsedSecs * 1000);
        
        if("".equals(label)){
            System.out.println("Elapsed Time: " + elapsedHours + ":" + 
                  elapsedMins + ":" + elapsedSecs + "." + elapsedMilliSecs);
        }else{
            System.out.println(label + " " + elapsedHours + ":" + 
                  elapsedMins + ":" + elapsedSecs + "." + elapsedMilliSecs);
        }
    } 
}

Here is the code to use the above concurrent execution logic to test the web application response time. In the following sample code, the simple Runnable task is to get the header from the server for the particular web application and iterating over it. Not real testing though, but conveys the idea.

public class WebResponseTester {
    
    public static void main(String[] args) {      
        Runnable readHeaderTask = new Runnable(){
            public void run(){
                try {
                    // Create a URLConnection object for a URL
                    URL url = new URL("http://localhost:8084/WebApplication4/");
                    URLConnection conn = url.openConnection();
                    
                    //Iterate all the response headers from the server.
                    int headerCount = 0;
                    String headerName;
                    String headerValue;
                    do {
                        headerName = conn.getHeaderFieldKey(headerCount);
                        headerValue = conn.getHeaderField(headerCount);
                        headerCount++;
                    }while((headerName != null && headerValue != null));
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        };
        
        ConcurrentTaskTester concurrentTimingTester = new ConcurrentTaskTester();
        try {
            int numRuns = 20;
            long elapsedTime = concurrentTimingTester.timeTasksConcurrently(
          numRuns,
                              readHeaderTask);
            concurrentTimingTester.displayElapsedTime("Total Elapsed Time for " + 
                              numRuns + " concurrent runs: " , elapsedTime);
            double averageTime = (double) elapsedTime/((double)numRuns *
                              1000.); // Convert to secs
            System.out.println("Average Time per response for " + 
                              numRuns + " concurrent request: " + averageTime + 
                              " secs");
            numRuns = 200;
            elapsedTime = concurrentTimingTester.timeTasksConcurrently(numRuns, 
                              readHeaderTask);
            averageTime = (double) elapsedTime/((double)numRuns * 
                              1000.); // Convert to secs
            concurrentTimingTester.displayElapsedTime("Total Elapsed Time for " + 
                                numRuns + " concurrent runs: " , elapsedTime);
            System.out.println("Average Time per response for " + numRuns + 
                               " concurrent request: " + averageTime + " secs");
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}

In the code above, the Runnable task (fetching the header) is executed concurrently 20 & 200 times concurrently to measure the response time from the server. This is the result I got after running the above program

Total Elapsed Time for 20 concurrent runs:  0:0:0.661
Average Time per response for 20 concurrent request: 0.03305 secs
Total Elapsed Time for 200 concurrent runs:  0:0:28.932
Average Time per response for 200 concurrent request: 0.14466 secs