NAME
tha - GUI for analyzing a Thread Analyzer experiment
SYNOPSIS
tha [ options ] [ thread-analyzer-experiment ]
DESCRIPTION
The tha(1) command invokes a GUI for analyzing the various
Thread Analyzer experiments collected by the Collector using
the collect(1) command. The GUI is a version of the Perfor-
mance Analyzer customized for examining Thread Analyzer
experiments.
The Collector gathers thread analysis information to create
a Thread Analyzer experiment during the execution of a pro-
cess. The tha command reads in such an experiment and
displays any errors detected. The current Thread Analyzer
supports data race detection and deadlock detection. For
further information on those, see the sections "DATA RACE
DETECTION" and "DEADLOCK DETECTION" below.
A command-line version of the tha command is available as
the er_print(1) utility.
To start tha, type the following on the command line:
tha [thread-analyzer-experiment]
Both the tha command and the analyzer(1) command can be used
to read a Thread Analyzer experiment. The tha command has
the same functionality and features as the analyzer command,
but shows a simplified set of default tabs that pertain to
Thread Analyzer experiments.
OPTIONS
Option Meaning
-j | --jdkhome jvmpath
Specify the path to the Java[TM] virtual machine
(JVM) software for running the analyzer. The
default path is taken first by examining environ-
ment variables for a path to the JVM, in the order
JDK_HOME, and then JAVA_PATH. If neither environ-
ment variable is set, the default path is where
the Java[TM] 2 Platform, Standard Edition technol-
ogy was installed with the Oracle Solaris Studio
release, and if it was not installed, as set in
the user's PATH. (The terms "Java virtual
machine" and "JVM" mean a virtual machine for the
Java(TM) platform.)
-J jvm-option
Specify JVM(TM) software options.
-f | --fontsize size
Specify the font size to be used in the analyzer.
-v | --verbose
Print version information and Java runtime argu-
ments before starting.
-V | --version
Print version information and exit.
-? | -h| --help
Print usage information and exit.
THA WINDOW -- LEFT HAND TABS
The tha window has a menu bar, a tool bar, and a split pane
that contains tabs for the various displays.
The left-hand pane contains tabs for the principal displays.
The tabs that are actually present in the pane are con-
trolled by a rtabs directive in a .er.rc file. The Experi-
ments tab is always shown. The Races tab will be shown if
data race data is in one or more of the loaded experiments.
The Deadlocks tab will be shown if deadlock data is in one
or more of the loaded experiments. The Dual Source tab will
be shown if either the Races or Deadlocks tabs are shown.
By default, the Races tab is selected, if available. If it
is not available, the Deadlocks tab is selected, if it is
available. If neither is available, only the Experiments
tab will be visible.
The Races Tab
The Races tab is shown if data for data races is in one
or more of the experiments loaded. The tab presents the
list of data races detected in the application. By
default, the first data race in the list of data races
is selected.
For each data race, the following information is shown:
o A unique id that identifies the data race
o One or more virtual addresses (Vaddr) associated
with the data race. If the data race occurs on mul-
tiple virtual addresses, then "(Multiple Addresses)"
is shown instead of a single address.
o The two accesses by two different threads that con-
stitute the data race. For each access, the type of
the access (Read or Write) is shown, as well as the
function, offset, and line number in the source code
where the access occurred.
o The total number of traces associated with the data
race. The individual traces can be displayed by
clicking on the button to the left of the "Total
Traces" label.
Each trace refers to the pair of thread callstacks
at the time the two data race accesses occurred.
When a trace is selected, the two callstacks will be
displayed in the Race Details tab in the right-hand
pane of the tha window (see below). The frame at the
top of the callstack for the first access is
selected by default.
The Deadlocks Tab
The Deadlocks tab is shown if deadlock data is in one
or more of the experiments loaded. The tab presents the
list of deadlocks detected in the application. By
default the first deadlock in the list of deadlocks is
selected.
For each deadlock, the following information is shown:
o A unique id that identifies the deadlock
o The type of the deadlock (potential or actual)
o The total number of threads involved in the
deadlock.
The context of each thread can be displayed by clicking
on the button to the left of the "Total Threads" label.
Each thread context shows the two operations
corresponding to holding a first lock and deadlocking
attempting to acquire a second lock.
When a thread context is selected, the two callstacks
where the lock hold and lock request took place will be
displayed in the Deadlock Details tab in the right-hand
pane of the tha window (see below).
The Dual Source Tab
The Dual Source tab is shown if either data race or
deadlock data is in one or more of the experiments
loaded. The Dual Source tab shows the two source loca-
tions pertaining to the selected data race or deadlock.
For a selected data race, the Dual Source tab shows the
source locations for the two accesses of the data race
selected, as shown in the Race Details tab. For a
selected deadlock, the Dual Source tab shows the two
operations corresponding to holding a first lock and
deadlocking attempting to acquire a second lock by the
thread selected, as shown in the Deadlock Details tab.
The source line where the access occurred will appear
highlighted. If the source code was compiled with -g,
then compiler commentary may appear interleaved in the
source code.
To the left of each source line, metrics that relate to
that source line are shown. For data races, the default
metric shown is the Exclusive Race Accesses metric;
this metric gives a count of the number of times a data
race access was reported on that line. For deadlocks,
the default metric shown is the Exclusive Deadlocks
metric; this metric gives a count of the number of
times a lock hold or lock request operation, which was
involved in a deadlock, was reported on that line.
Exclusive metrics relate to the source line at which
they appear only. Inclusive metrics relate to the
source line at which they appear and to any functions
that have been called from that source line. Count
metrics are shown as an integer count. Percentages are
shown to a precision of 0.01%. Because of rounding,
percentages may not sum to exactly 100%.
The metrics that are shown can be changed using the Set
Data Presentation dialog box (see "Selecting the Data
Presentation Options" below).
To reorder the columns of metrics in the source
display, drag the column header to the place you want
it to appear.
The Experiments Tab
The Experiments tab is divided into two panels. The top
panel shows a tree that contains nodes for the load
objects in the experiment loaded. The bottom panel
lists error and warning messages from the tha session.
For more information about the Experiments tab, refer
to the analyzer(1) man page.
THA WINDOW -- RIGHT HAND TABS
The right-hand pane of the tha window contains tabs for
displaying additional information about a data race. The
Summary tab is always shown. The Race Details tab is shown
if the Races tab is shown; the Deadlock Details tab is shown
if the Deadlocks tab is shown.
The Summary Tab
The Summary tab shows summary information about a data
race selected from the Races tab. This information
includes the object file name, source file name, and PC
(program counter) address.
The Race Details Tab
The Race Details tab is selected whenever the Races tab
is raised, and a selection made from the Races tab. It
shows detailed information about a data race or trace
selected from the Races tab.
The Race Details tab is divided into two panes. The
upper pane shows information about the first access of
a selected data race or trace (Access 1). The lower
pane shows information about the second access of a
selected data race or trace (Access 2).
When a data race or a trace is selected from the Races
tab, the Race Details tab shows the following:
o The data race or trace id
o The virtual address (Vaddr) associated with the data
race. If the data race occurs on multiple virtual
addresses, then "(Multiple Addresses)" is shown
instead of a single address.
In addition, for each of the two accesses, the Race
Details tab shows the following:
o Whether the data race access is read or write
o If a data race from the Races tab is selected, then
the Race Details tab shows the leaf PC of the thread
when the data race access occurred. If, on the other
hand, a trace from the Races tab is selected, then
the Race Details tab shows the callstack of the
thread when the data race access occurred. By
default, the frame at the top of the callstack is
selected.
The Deadlock Details Tab
The Deadlock Details tab is selected whenever the
Deadlocks tab is raised, and a selection made from the
Deadlocks Tab. It shows detailed information about a
thread context selected from the Deadlocks tab.
For each thread context selected, the deadlock id,
deadlock type, and thread id are shown. In addition,
for each of the two lock operations involved, the type
of lock operation (lock being held or lock being
requested) and the callstacks of the thread are shown.
By default, the frame at the top of each callstack is
selected.
DATA RACE DETECTION
A data race occurs when two or more threads in a single pro-
cess access the same memory location concurrently, at least
one of the accesses is for writing, and the threads are not
using any exclusive locks to control their accesses to that
memory. In such situations, the order of accesses is non-
deterministic, and the computation may give different
results depending on that order. Some data races may be
benign (for example, when the memory access is used for a
busy-wait), but many data races are bugs in the program.
Data-race-detection experiments record data races that are
detected during the execution of a multithreaded process.
Data race detection works on multithreaded applications
written using POSIX thread APIs, Solaris thread APIs,
OpenMP, or a mix of the above.
There are three steps involved in detecting data races:
Step 1: Instrument the code
To enable data race detection in an application, the
code must first be instrumented to monitor memory
accesses at runtime. The instrumentation can be done at
the application source-level or binary-level.
If doing source-level instrumentation, the source code
of the application should be compiled with the special
compiler option:
-xinstrument=datarace
With this compiler option, the code generated by the
compiler will be instrumented for data race detection.
If doing binary-level instrumentation, the application
binary should be instrumented using the Discover tool
which is invoked by the discover(1) command. If the
binary is named a.out, then an instrumented binary
a.outi can be generated by executing:
discover -i datarace -o a.outi a.out
The Discover tool automatically instruments all shared
libraries as they are opened, whether they are stati-
cally linked in the program or opened dynamically by
dlopen(). You can use the discover command line option
-N to ignore certain libraries, or use the discover
command line option -T to ignore all libraries.
To use the Discover tool, the input binary must be com-
piled with optimization flag -O[n] (n>=0) using Solaris
Studio 12 Update 1 compilers or later versions, on a
machine with Oracle Solaris 10 update 5 or higher, or
Oracle Solaris 11. On older Solaris versions, try the
-xbinopt=prepare compiler option (SPARC only).
For both source-level and binary-level instrumentation,
it is recommended that the -g compiler option be used
when building application binaries. This will allow tha
to display source code and line number information when
reporting data races.
Step 2: Create a data-race-detection experiment
Use the collect command with the -r race flag to run
the application and create a data-race-detection exper-
iment during the execution of the process.
Data-race-detection data collected consists of pairs of
data-accesses that constitute a race. Data-race-
detection data is converted into the "Race Accesses"
metric.
See collect(1) man page for more information.
Step 3: Examine the data-race-detection experiment
A data-race-detection experiment can be examined with
either the tha or analyzer command (GUI), or with the
er_print utility (command-line).
Both the tha and the analyzer commands present a GUI
interface; the former presents a simplified set of
default tabs, but is otherwise identical to the
analyzer. The er_print utility, on the other hand,
presents a command-line interface.
Note: The Thread Analyzer may report false positive data
races if it does not recognize user-defined synchronizations
in the application. The Thread Analyzer runtime library,
libtha.so, provides an API that can be used to notify the
Thread Analyzer about user-defined synchronizations and
reduce the number of false positives reported. See libtha(3)
man page for more information.
DEADLOCK DETECTION
Deadlock describes a condition where two or more threads are
blocked (hung) forever, waiting for each other. There are
many causes of deadlocks; these include erroneous program
logic, inappropriate use of synchronizations and barriers,
and so on.
The Thread Analyzer detects deadlocks that are caused by
inappropriate use of mutual exclusion locks. This kind of
deadlock is commonly encountered in multi-threaded applica-
tions. Suppose we have a process with two or more threads.
A deadlock caused by inappropriate use of mutual exclusion
locks occurs when the following three conditions hold:
(1) Threads already holding locks request new locks,
(2) The requests are made concurrently, and
(3) Two or more threads form a circular chain where each
thread waits for a lock that the next thread in the chain
holds.
Here is an example of a deadlock condition:
Thread 1: holds lock A, requests lock B
Thread 2: holds lock B, requests lock A
A deadlock in a particular run of the program can be a
potential deadlock or an actual deadlock. A potential
deadlock is a deadlock that did not actually occur in the
run of the program, but can occur in other runs of the pro-
gram, depending on the scheduling of threads and the timings
of requests for locks by the threads. An actual deadlock is
a deadlock that actually occurred in the run of the program.
An actual deadlock causes the threads involved to hang, but
may or may not cause the whole process to hang.
Deadlock-detection experiments record both potential and
actual deadlocks that are detected during the execution of a
multi-threaded process. Deadlock detection works on multi-
threaded applications written using POSIX thread APIs,
Solaris thread APIs, OpenMP, or a mix of the above.
There are two steps involved in detecting deadlocks:
Step 1: Create a deadlock-detection experiment
Use the collect command with the -r deadlock flag to
run the application and create a deadlock-detection
experiment during the execution of the process.
Deadlock-detection data collected consists of lock
holds and lock requests that form a circular chain.
Deadlock-detection data is converted into the
"Deadlocks" metric.
See collect(1) man page for more information.
Step 2: Examine the deadlock-detection experiment
A deadlock-detection experiment can be examined with
either the tha or analyzer command (GUI), or with the
er_print utility (command-line).
Both the tha and the analyzer commands present a GUI
interface; the former presents a simplified set of
default tabs, but is otherwise identical to the
analyzer. The er_print utility, on the other hand,
presents a command-line interface.
It is recommended that the -g compiler option be used when
building application binaries. This will allow tha to
display source code and line number information when report-
ing deadlocks.
SELECTING DATA PRESENTATION OPTIONS
You can control the presentation of data from the Set Data
Presentation dialog box. To open this dialog box, click on
the Set Data Presentation button in the tool bar, or choose
Set Data Presentation from the View menu.
The Set Data Presentation dialog box has a tabbed pane with
seven tabs. Refer to the analyzer(1) man page for more
information.
DEFAULTS
The Thread Analyzer processes directives from a .er.rc file
in the current directory, if present; from a .er.rc file in
the user's home directory, if present; and from a system
er.rc file installed with the product.
These .er.rc files can contain default settings for which
tabs are visible (rtabs), when the Thread Analyzer is
brought up. The tabs are named by the er_print command for
the corresponding report, except for the Experiments Tab,
named headers, the Timeline Tab, named timeline, the Dual
Source Tab, named dsrc, and the Source/Disassembly tab,
named srcdis.
The .er.rc files can also contain default settings for
metrics, sorting, and for specifying compiler commentary
options and highlighting thresholds for source and disassem-
bly output. The files also specify a path for C++ name
demangling for other compilers, as well as default settings
for the Timeline tab, and for name formatting, and setting
View Mode (viewmode).
The .er.rc files can also contain a setting, en_desc
{on|off} to control whether or not descendant experiments
are selected and read when the founder experiment is read.
The .er.rc files can also contain directives to control the
search path for source and object files. In the Thread
Analyzer, an .er.rc file can be saved by clicking on the
Save button in the Set Data Presentation dialog box, which
you can open from the View menu. Saving an .er.rc file from
the Set Data Presentation dialog box not only affects subse-
quent invocations of the Thread Analyzer, but also the
er_print utility and er_src utility. See the description of
these directives and files, and their processing, in the
er_print(1) man page.
The Thread Analyzer puts a message into its Errors/Warning
logs areas naming the user .er.rc files it processed,
including any processing message generated when any tab is
loaded.
SEE ALSO
analyzer(1), collect(1), discover(1), er_archive(1),
er_cp(1), er_export(1), er_mv(1), er_print(1), er_rm(1),
er_src(1), libtha(3), tha(1), the Thread Analyzer User's
Guide, and the Performance Analyzer manual.