JVM Performance
An application written using DataFlow is also a Java application. Therefore, tools for analyzing and profiling Java applications can also be used with DataFlow. Several tools are available on the market that can do this.
A useful tool that is delivered with the JDK is jvisualvm. Look for jvisualvm in the bin directory of a JDK installation; this tool is not available in JRE-only installations. jvisualvm supports extension through the installation of plugins. There are a number of useful plugins available, enhancing both the collection and display of information.
To use jvisualvm, start it within a windowed environment. A list of running JVMs on the local machine will display in a tree view. It also can be configured to monitor JVMs on remote hosts. Double-clicking on a listed JVM will connect to it, opening a new tab for the selected JVM.
Each connected JVM includes the following subtabs:
Overview
Contains JVM options and other general information.
Monitor
Time-based graphs of CPU, memory, class and thread usage.
Threads
Thread activity of each thread running in the JVM.
Sampler
Enables sampling run-time metrics of a running JVM.
Profiling
Enables profiling of a running JVM.
There are a number of different aspects of execution you can check at the JVM level. These topics are discussed in more detail below.
Garbage Collection and Memory Usage
The JVM provides a managed heap where programs do not explicitly need to release allocated memory. Instead, the process of garbage collection (GC) reclaims previously allocated space that is determined to be no longer in use.
While convenient for the writers of Java code, this feature does not come for free. Usually the cost of this collection represents only a small fraction of the overall execution time for a program. However, it can sometimes be the primary factor determining performance. If GC activity consumes a large portion of overall run time, it usually indicates a problem.
There are a few common ways to monitor GC activity:
• The -verbose:gc option to the JVM logs GC events to the console. Each time a collection is performed, a line of information summarizing the event is output. This data includes how long the collection took, how much was reclaimed, and the type of collection. There are a number of tools available you can use to distill accumulated statistics from this output, providing an aggregate view of GC for the lifetime of an application.
• jvisualvm provides a graph of memory usage over time on the Monitor tab for a selected JVM. VisualGC is a useful plugin, which adds an additional tab showing information about current memory usage and accumulated GC statistics. It is not installed by default, but is available from the default plugin discovery locations.
When trying to understand why garbage collection is occurring frequently, it is sometimes useful to know what is taking up space in the heap. You can then use this information can then be used to reduce peak memory usage, thereby relieving pressure on the garbage collector. Again, there are a number of tools available with an installation of the JDK that can be useful in doing this:
• jvisualvm can be used both to generate and analyze heap dumps. The right-click context menu for a selected JVM provides an option to produce a heap dump, which can then be opened for analysis.
If
OutOfMemoryError situations are occurring that cannot be accounted for or explained based on the settings of operator properties in a graph, it is possible to collect a heap dump automatically using the
–XX:+HeapDumpOnOutOfMemoryError option to the JVM.
Thread and Wait Monitoring
A dataflow graph can only be as fast as its slowest operator. The nature of dataflow dictates that faster nodes will have to wait for slower nodes to produce or consume data. By looking at thread-level activity information, it is sometimes possible to identify these bottlenecks in processing. Ideally, all threads would be equally busy for any given time slice. However, if operators must wait on producers upstream or consumers downstream, some threads may be idle in a wait state for noticeable stretches of time.
jvisualvm provides a visualization of per-thread activity over time on the Threads tab for a selected JVM. The relative activity (or inactivity) of threads can be compared in this view. Seeing activity in this way can sometimes make bottlenecks stand out.
Code Profiling
As previously mentioned, DataFlow applications are Java applications. They can be profiled the same as any other Java program. Profiling can reveal where, at the code level, the application spends most of its time. Some tools can also provide additional CPU-level statistics, such as cache misses and branch prediction failures, although this level of detail is not generally required.
The information provided by profiling can be used to discover opportunities to improve the implementation of operators.
Some things to keep in mind when profiling code:
• Profiling can show a skew, particularly in small, frequently called functions as profiling overhead rivals the actual cost of the call. Many of the common low-level methods in the DataFlow library—for example stepNext() on RecordInput—will be called very often during the execution of a graph.
• Profiling can have a large impact on the performance of an application. Profiling something that already takes a long time can end up making it run even longer. Reducing the size of the profiled problem will yield better results (the same technique as suggested in debugging,
Executing Locally).
• Profiling can generate a lot of fine-grain details that are difficult to map back to the dataflow graph. As a consequence, code profilers are best used to analyze the performance of a single operator, not the entire graph.
A number of tools are available for profiling Java programs. Two simple ways of profiling are available with most Java installations:
• The
-agentlib:hprof option to the JVM can be used to enable profiling by sampling (
cpu=sample) or by byte code instrumentation (
cpu=times). On exit, the JVM will generate a report with the profiling results. Refer to Java
documentation for options and more information about using this flag.
• jvisualvm supports profiling of the selected JVM. The Sampler and Profiler tabs present options for performing profiling by sampling or byte code instrumentation respectively. This profiling can be started and stopped at any time within the tool.