Tuesday 29 January 2013

Monitoring the GC


GCHisto for Offline Analysis of Garbage Collection Data

GCHisto is a tool designed to do offline analysis, it’s free and it’s hosted on http://java.net/projects/gchisto.
To run it you need to download it, cd into gchisto folder and type:
sudo ant run
You can then load any gc log file and this tool will give you a visual view on the log.
The tab “GC Pause stats” will help you to identify the duration of the young and full GC action.
The overhead column is useful to identify how good your GC is tuned. Documentations says that a concurrent GC should be less than 10% overhead (ideal is 1% or less). If it’s above 10% it may required some tuning (increase the heap space can be one).


It will also provide useful graphs which are always better and less boring the raw data:


The GC Pause Distribution is used to analyse how many pauses occurs and how they are distributed:


a more detailed guide on all the gchisto features can be found here : http://sysadminsjourney.com/2008/09/15/profile-gc-with-gchisto/
—————————————————————-

Visual GC plugin + VisualVM for Live Analysis of Garbage Collection Data

In case you want to monitor what’s happening in the GC in real time you can use the visualVM that come together with your jdk.
To run it just type
jvisualvm
To add the viusualGC click on Tools–>Plugins–>Available plugins and select and install Visual GC
Restart visual VM.
With the basic VisualVM you can monitor memory usage, CPU consumption and how the Threads behave. The visual GC gives you a realtime view on the 3 heap memory spaces usage.

As you can see, a full and immediate vision on the Permanent, old and young space is given, helping a lot during analysis.
You can use this tool locally without any other required step, but it’s also possible to monitor remote VM (UAT,SYS,etc) using the jstatd deamon provided by java in sdk (same place where the jvisualvm is).
The jstatd daemon launches a Java RMI server application that watches for the creation and termination of HotSpot VMs and provides an interface to allow remote monitoring tools such as VisualVM to attach and monitor Java applications remotely, here is how to use it and configure it : http://docs.oracle.com/javase/6/docs/technotes/tools/share/jstatd.html
Hope this will help you a bit guys!

Monday 14 January 2013

ExecutorService VS CompletionService VS normal loop

This is to show the difference between handling jobs with a pure ExecutorService VS a CompletionService VS a normal loop.

The CompletionServiceTest class simply prints numbers at predefined intervals ( waittime = 200 that simulates a work done by the thread, for example reading or parsing a file or run calculations, etc).

We do the same job in 3 different ways and we print the result together with the total execution time.


import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CompletionServiceTest {

        private static final int waittime = 200;
        private static final int numberOfThreadsInThePool = 3;

        private final List<String> printRequests = Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                        "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                        "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                        "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                        "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                        "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                        "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                        "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                        "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                        "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                        "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                        "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                        "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                        "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"
                        );

        void normalLoop() {
                for (String image : printRequests) {
                        try {
                                Thread.sleep(waittime);
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
                        System.out.print(image);
                }
        }

        void normalExecutorService() {
                ExecutorService executor = Executors.newFixedThreadPool(numberOfThreadsInThePool);
                try {
                        Set<Future<String>> printTaskFutures = new HashSet<Future<String>>();
                        for (final String printRequest : printRequests) {
                                printTaskFutures.add(executor.submit(new Printer(printRequest)));
                        }
                        for (Future<String> future : printTaskFutures) {
                                System.out.print(future.get());

                        }
                } catch (Exception e) {
                        Thread.currentThread().interrupt();
                } finally {
                        if (executor != null) {
                                executor.shutdownNow();
                        }
                }
        }

        void completionService() {
                ExecutorService executor = Executors.newFixedThreadPool(numberOfThreadsInThePool);
                CompletionService<String> completionService = new ExecutorCompletionService<String>(executor);
                for (final String printRequest : printRequests) {
                        completionService.submit(new Printer(printRequest));
                }
                try {
                        for (int t = 0, n = printRequests.size(); t < n; t++) {
                                Future<String> f = completionService.take();
                                System.out.print(f.get());
                        }
                } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                } catch (ExecutionException e) {
                        Thread.currentThread().interrupt();
                } finally {
                        if (executor != null) {
                                executor.shutdownNow();
                        }
                }

        }

        private class Printer implements Callable<String> {

                private final String toPrint;

                public Printer(String toPrint) {
                        this.toPrint = toPrint;
                }

                public String call() {
                        try {
                                Thread.sleep(waittime);
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
                        return toPrint;
                }
        }

        public static void main(String[] args) {
                System.out.println("Normal Executor Service");
                long start = System.currentTimeMillis();
                new CompletionServiceTest().normalExecutorService();
                System.out.println();
                System.out.println("Execution time : " + (System.currentTimeMillis() - start));

                System.out.println("Completion Service");
                start = System.currentTimeMillis();
                new CompletionServiceTest().completionService();
                System.out.println();
                System.out.println("Execution time : " + (System.currentTimeMillis() - start));

                System.out.println("Normal Loop");
                start = System.currentTimeMillis();
                new CompletionServiceTest().normalLoop();
                System.out.println();
                System.out.println("Execution time : " + (System.currentTimeMillis() - start));

        }
}


The output :


Normal Executor Service
4865447106310711038976137104163378132553196955489824610105761329674254896133105110752911167871022184410147885282715959248479622229673310496981056331010958
Execution time : 9410
Completion Service
1234567891012345678910123456789101234567891012345678109123456789101234567891012345678910123456789101235647891012345678910123456789101234568791012435687109
Execution time : 9405
Normal Loop
1234567891012345678910123456789101234567891012345678910123456789101234567891012345678910123456789101234567891012345678910123456789101234567891012345678910
Execution time : 28013



As you can see the total execution time between Normal Executor Service and Completion Service is the same, while the normal loop was more than 3 times slower. This is easily explained by the fact that the normal loop was single threaded and the others 2 were run with 3 threads.

The difference between  Normal Executor Service and Completion Service is visible at runtime, Normal Executor Service always waits  for the next thread to finish the job before printing the number, the client needs to wait until a big bunch of threads return all together.
Completion Service is behaving differently, it follows a producer/consumer philosophy: as soon a thread is done, it puts the result into a non blocking queue so that the consumer can take it.

I hope this simple example will help you to better clarify the completion service as it did for me.




Thursday 3 January 2013

Fix for bad performance in Eclipse Juno SR1



Several major performance defects have been addressed in the Juno SR2 stream (4.2.2). Community members have confirmed that these fixes substantially address the performance problems with editor and view opening, closing, and switchingThese fixes will be widely available in the Juno Service Release 2 (February 2013) and Kepler (June 2013) releases. Meanwhile, a patch is available for those using Juno SR1 that provides early access to these fixes. To install this patch:
  1. Ensure you are already running on a package from the Juno SR1 release (September 2012)
  2. Invoke Help > Install New Software
  3. Select this repository: http://download.eclipse.org/eclipse/updates/4.2
  4. Expand Juno SR1 Patches and install Eclipse UI Juno SR1 Optimizations