Here are some general profiling facts and tips you should be aware of
when profiling your applications:
Profiler calibration - results accuracy:
For each JDK used for profiling, the Profiler needs to perform an initial
calibration. The data obtained from the calibration is used to eliminate additional
profiling overhead from the collected results in order to deliver more accurate information
about execution times. The calibration data is tightly related to system
performance (CPU speed, memory & bus throughput etc.) and the JDK
version. Each time you change the JDK or make changes that could affect system performance, you should
rerun the calibration to ensure that the Profiler collects correct
results.
Runtime optimizations vs. instrumentation:
To get
methods call tree and timing, Profiler has to
perform instrumentation - this means that the original application's
bytecode is slightly modified. If the original code has already been
compiled by a JIT compiler to speedup execution, the code is switched back to
interpreted execution after instrumentation
and can run noticeably slower
for some time.
This does not necessarily mean that Profiler imposed such a large
overhead - if set up correctly, it allows the profiled application to
run at nearly full speed. Ideally, profiled code should be run
several times after instrumentation to allow the VM to apply runtime
optimizations (JIT) again. This ensures that profiling results
representing real application behavior in a production environment will
be collected.
Runtime optimizations - skipping simple methods:
Typically, there are many simple methods in an application that don't
take any real time when executing as they are compiled to native code
or inlined. Instrumenting such methods could lead to significant
profiling overhead without any useful results, so profiling
getters/setters and empty methods is disabled by default for Analyze
Performance - Entire Application profiling. This means that you won't
see these methods in call tree or hot spots views. You can change this
behavior by creating Custom Profiling Configuration and explicitly
enabling profiling getters/setters and empty methods.
Runtime optimizations - native routines:
Some mathematical
functions like Math.sin() are implemented
as Java methods calling native code, but you cannot see them in the
collected profiling results. They are not visible in the profiling results because of some execution
optimizations, which cause these functions to be executed directly
in native code, skipping their Java part. In this case, Profiler is
unable to detect that such methods have run and does not collect or
display the
appropriate calls. You should be aware of this when evaluating
profiling results. If you are running a 5.0-based JVM, specific functions that Profiler does not detect include Math.sin(),
Math.cos() and Math.sqrt(). In a 6.0-based JVM, the functions Math.tan(),
Math.abs(), Math.log() and Math.log10() are also not detected.
Compile time optimizations vs. real profiling
results: When
evaluating profiling results, you should be aware of
Java compiler optimizations, typically string
concatenation or constant expressions evaluation. For example, using System.out.println("Value
of a: " + a) results in creating and dealing with StringBuffer,
eventually
using some parsing/conversion functions to output the value of
float/double variable
'a' as a string. The Profiler is unable to
detect such optimizations and only reports real runtime flow/behavior of the application's
code.
Dynamic CPU frequency switching: If the
profiled
application runs on a machine with dynamic CPU frequency switching technologies
(like SpeedStep or PowerNow!), you should ensure that these
are disabled. In order to deliver profiling results that are as exact as
possible, the Profiler uses static calibration data describing
system performance. Changing CPU frequency during profiling would significantly
affect the accuracy of the results.