tha [ options ] [ thread-analyzer-experiment ]
tha 命令可调用 GUI 来分析收集器使用 collect (1) 命令收集的各种线程分析器实验。GUI 是为了检查线程分析器实验而定制的性能分析器版本。
收集器在进程执行过程中收集线程分析信息以创建线程分析器实验。tha 命令读入此类实验,并显示检测到的任何错误。当前的线程分析器支持数据争用检测和死锁检测。有关这些内容的详细信息,请参见下文的“数据争用检测”和“死锁检测”两部分。
tha 命令的命令行版本作为 er_print(1) 实用程序提供。
要启动 tha,请在命令行上键入以下内容:
tha [thread-analyzer-experiment]
tha 命令和 analyzer(1) 命令均可用于读取线程分析器实验。tha 命令的功能和特性与 analyzer 命令相同,但是显示与线程分析器实验相关的一组简化的缺省标签。
指定用于运行 analyzer 的 Java[TM] 虚拟机 (Java Virtual Machine, JVM) 软件的路径。首先采用缺省路径,方法是在环境变量中检查 JVM 的路径(先检查 JDK_HOME,再检查 JAVA_PATH)。如果这两个环境变量均未设置,则缺省路径是在 Oracle Solaris Studio 发行版中安装 Java[TM] 2 平台标准版技术的位置,如果未安装该技术,则是在用户的 PATH 中设置的路径。(术语“Java 虚拟机”和 "JVM" 表示用于 Java(TM) 平台的虚拟机。)
指定 JVM(TM) 软件选项。
指定要在 analyzer 中使用的字体大小。
启动之前输出版本信息和 Java 运行时参数。
输出版本信息并退出。
输出用法信息并退出。
tha 窗口具有菜单栏、工具栏以及包含多个标签的拆分窗格(不同标签对应不同的显示)。
左侧窗格包含主要显示内容的标签。窗格中实际显示的标签由 .er.rc 文件中的 rtabs 指令控制。始终显示 "Experiments"(实验)标签。如果数据争用数据在一个或多个装入的实验中,将显示 "Races"(争用)标签。如果死锁数据在一个或多个装入的实验中,将显示 "Deadlocks"(死锁)标签。如果显示 "Races"(争用)标签或 "Deadlocks"(死锁)标签,将显示 "Dual Source"(双源)标签。
缺省情况下,"Races"(争用)标签(如果有)处于选中状态。如果没有该标签,"Deadlocks"(死锁)标签(如果有)将处于选中状态。如果这两个标签都没有,则只有 "Experiments"(实验)标签可见。
如果数据争用数据在一个或多个装入的实验中,将显示 "Races"(争用)标签。该标签显示在应用程序中检测到的数据争用的列表。缺省情况下,选择数据争用列表中的第一个数据争用。
对于每个数据争用,将显示以下信息:
标识数据争用的唯一 ID。
与数据争用关联的一个或多个虚拟地址 (Vaddr)。如果数据争用发生在多个虚拟地址上,将显示 "(Multiple Addresses)"(多个地址)而非单个地址。
造成数据争用的两个不同线程的两次访问。对于每个访问,将会显示访问的类型(读取或写入),以及源代码中发生访问的函数、偏移量和行号。
与数据争用相关联的跟踪总数。单击 "Total Traces"(跟踪总计)标签左侧的按钮可显示单个跟踪。
每个跟踪都引用发生两个数据争用访问时的一对线程调用堆栈。如果选择了一个跟踪,tha 窗口右侧窗格中的 "Race Details"(争用详细信息)标签中将显示两个调用堆栈(请参见下文)。缺省情况下,第一次访问的调用堆栈顶部的帧处于选中状态。
如果死锁数据在一个或多个装入的实验中,将显示 "Deadlocks"(死锁)标签。该标签显示应用程序中检测到的死锁的列表。缺省情况下,选择死锁列表中的第一个死锁。
对于每个死锁,将显示以下信息:
标识死锁的唯一 ID。
死锁的类型(潜在或实际)。
死锁中涉及的线程总数。
单击 "Total Threads"(线程合计)标签左侧的按钮可显示每个线程的上下文。每个线程上下文显示两项操作,对应于持有第一个锁和死锁尝试获取第二个锁。
如果选择了一个线程上下文,tha 窗口右侧窗格中的 "Deadlock Details"(死锁详细信息)标签中将显示发生锁持有和锁请求的两个调用堆栈(请参见下文)。
如果数据争用或死锁数据在一个或多个装入的实验中,将显示 "Dual Source"(双源)标签。"Dual Source"(双源)标签显示与所选数据争用或死锁相关的两个源位置。
对于所选的数据争用,"Dual Source"(双源)标签显示所选数据争用的两次访问所对应的源代码位置,如 "Race Detail"(争用详细信息)标签中所示。对于选定的死锁,"Dual Source"(双源)标签显示两项操作,它们对应于选定线程持有第一个锁和死锁尝试获取第二个锁,如 "Deadlock Details"(死锁详细信息)标签中所示。
发生访问的源代码行将突出显示。如果源代码是使用 -g 编译的,则编译器注释可能会在源代码中交错显示。
在每个源代码行左侧,显示了与该源代码行相关的度量。对于数据争用,显示的缺省度量是独占争用访问度量;该度量显示了该行上报告的数据争用访问次数。对于死锁,显示的缺省度量是独占死锁度量;该度量显示了该行上报告的死锁涉及的锁持有或锁请求操作的次数。
独占度量只与显示它们的源代码行相关。非独占度量与显示它们的源代码行以及从该源代码行调用的任何函数相关。计数度量显示为整数计数。显示的百分比精确到 .01%。由于进行了舍入,百分比总和可能不会恰好是 100%。
显示的度量可使用 "Set Data Presentation"(设置数据显示)对话框进行更改(请参见下文的“选择数据显示选项”)。
要对源代码显示中的度量列进行重新排序,请将列标题拖动到希望显示它的位置。
"Experiments"(实验)标签分为两个面板。顶部面板显示了一个树,树中包含装入的实验中装入对象的节点。底部的面板列出来自 tha 会话的错误消息和警告消息。
有关 "Experiments"(实验)标签的更多信息,请参阅 analyzer(1) 手册页。
tha 窗口的右侧窗格中包含用于显示有关数据争用附加信息的标签。始终显示 "Summary"(摘要)标签。如果显示了 "Races"(争用)标签,便会显示 "Race Details"(争用详细信息)标签;如果显示了 "Deadlocks"(死锁)标签,便会显示 "Deadlock Details"(死锁详细信息)标签。
"Summary"(摘要)标签,显示从 "Races"(争用)标签中选择的数据争用的摘要信息。该信息包括对象文件名、源文件名和 PC(program counter,程序计数器)地址。
每当出现 "Races"(争用)标签并从 "Races"(争用)标签中做出选择时,"Race Details"(争用详细信息)标签便会处于选中状态。该标签显示从 "Races"(争用)标签中选择的数据争用或跟踪的详细信息。
"Race Details"(争用详细信息)标签分为两个窗格。上面的窗格显示有关选定数据争用或跟踪的第一次访问(访问 1)的信息。下面的窗格显示有关选定数据争用或跟踪的第二次访问(访问 2)的信息。
从 "Races"(争用)标签中选择数据争用或跟踪后,"Race Details"(争用详细信息)标签将显示以下信息:
数据争用或跟踪 ID
与数据争用相关联的虚拟地址 (Vaddr)。如果数据争用发生在多个虚拟地址上,将显示“(多个地址)”而非单个地址。
此外,对于两次访问中的每一次,"Race Details"(争用详细信息)标签都将显示以下信息:
数据争用访问是读取还是写入
如果从 "Races"(争用)标签中选择了数据争用,则 "Race Details"(争用详细信息)标签将显示发生数据争用访问时线程的叶 PC。另一方面,如果从 "Races"(争用)标签中选择了跟踪,则 "Race Details"(争用详细信息)标签将显示发生数据争用访问时线程的调用堆栈。缺省情况下,调用堆栈顶部的帧处于选中状态。
每当出现 "Deadlocks"(死锁)标签并从 "Deadlocks"(死锁)标签中做出选择时,"Deadlock Details"(死锁详细信息)标签便会处于选中状态。该标签显示从 "Deadlocks"(死锁)标签中选择的线程上下文的详细信息。
对于选择的每个线程上下文,将显示死锁 ID、死锁类型和线程 ID。此外,对于涉及的两项锁操作中的每一项,都将显示锁操作的类型(持有锁或请求锁)和线程的调用堆栈。缺省情况下,各调用堆栈顶部的帧处于选中状态。
发生数据争用的情况如下:单个进程中的两个或多个线程同时访问相同的内存位置,至少一次访问为写访问,并且线程未使用任何独占锁定控制对该内存的访问。在这种情况下,访问的顺序是不确定的,计算结果可能因该顺序而异。有些数据争用可能是良性的(例如,内存访问用于忙等待时),但许多数据争用都属于程序中的错误。
数据争用检测实验记录在多线程进程执行期间检测到的数据争用。数据争用检测适用于使用 POSIX 线程 API、Solaris 线程 API、OpenMP 或混用这几者编写的多线程应用程序。
检测数据争用涉及三个步骤:
为了在应用程序中检测数据争用,必须首先对代码进行检测以监视运行时的内存访问。检测可以在应用程序源代码级或二进制文件级执行。
如果执行源代码级检测,应该使用特殊编译器选项编译应用程序的源代码:
-xinstrument=datarace
通过使用该编译器选项,将会对编译器生成的代码进行检测以便检测数据争用。
如果执行二进制文件级检测,应该使用由 discover(1) 命令调用的 Discover 工具检测应用程序二进制文件。如果二进制文件名为 a.out,可通过执行以下命令生成检测过的二进制文件 a.outi:
discover -i datarace -o a.outi a.out
Discover 工具在共享库打开时自动检测所有共享库,无论它们是静态链接到程序中的,还是通过 dlopen() 动态打开的。您可以使用 discover 命令行选项 -N 忽略某些库,也可以使用 discover 命令行选项 -T 忽略所有库。
要使用 Discover 工具,必须在运行 Oracle Solaris 10 Update 5 或更高版本或者 Oracle Solaris 11 的计算机上使用 Solaris Studio 12 Update 1 编译器或更高版本以优化标志 -O[n] (n>=0) 编译输入二进制文件。在早期 Solaris 版本上,请尝试使用 -xbinopt=prepare 编译器选项(仅限 SPARC)。
对于源代码级和二进制文件级检测,建议在生成应用程序二进制文件时使用 -g 编译器选项。这样,tha 便可以在报告数据争用时显示源代码和行号信息。
使用带有 -r race 标志的 collect 命令来运行应用程序并在进程执行期间创建数据争用检测实验。
收集的数据争用检测数据由造成争用的成对数据访问组成。数据争用检测数据将转换为“争用访问”度量。
有关更多信息,请参见 collect(1) 手册页。
数据争用检测实验可使用 tha 或 analyzer 命令 (GUI) 或者使用 er_print 实用程序(命令行)进行检查。
tha 和 analyzer 命令都能显示 GUI 界面;前者显示一组简化的缺省标签,但在其他方面与 analyzer 完全相同。另一方面,er_print 实用程序可显示命令行界面。
注意:如果线程分析器在应用程序中无法识别用户定义的同步,可能会误报数据争用。线程分析器运行时库 libtha.so 提供了一个 API,该 API 可用于通知线程分析器用户定义的同步并减少误报数量。有关更多信息,请参见 libtha(3) 手册页。
死锁描述的是两个或多个线程永远被阻塞(挂起)而相互等待的情况。导致死锁的原因有很多,其中包括程序逻辑错误以及不恰当使用同步和屏障等。
线程分析器可检测由于不恰当使用互斥锁而导致的死锁。此类死锁通常发生在多线程应用程序中。假设有一个包含两个或多个线程的进程。当以下三个条件成立时,将发生由于互斥锁使用不当而导致的死锁:
已持有锁的线程请求新锁,
同时发起请求,
两个或多个线程形成一个循环链,其中每个线程都在等待链中下一个线程持有的锁。
以下是一个死锁情况的示例:
Thread 1: holds lock A, requests lock B Thread 2: holds lock B, requests lock A
程序特定运行过程中发生的死锁可以是潜在死锁或实际死锁。潜在死锁实际上并未发生在程序的运行过程中,但可能发生在程序的其他运行过程中,具体取决于线程的调度情况以及线程进行锁请求的时间。实际死锁是实际发生在程序运行过程中的死锁。实际死锁会导致所涉及的线程挂起,但不一定会导致整个进程挂起。
死锁检测实验记录在多线程进程执行期间检测到的潜在死锁和实际死锁。死锁检测适用于使用 POSIX 线程 API、Solaris 线程 API、OpenMP 或混用这几者编写的多线程应用程序。
检测死锁包括两个步骤:
使用带有 -r deadlock 标志的 collect 命令来运行应用程序并在进程执行期间创建死锁检测实验。
收集的死锁检测数据由形成循环链的锁持有和锁请求构成。死锁检测数据将转换为“死锁”度量。
有关更多信息,请参见 collect(1) 手册页。
死锁检测实验可使用 tha 或 analyzer 命令 (GUI) 或者使用 er_print 实用程序(命令行)进行检查。
tha 和 analyzer 命令都能显示 GUI 界面;前者显示一组简化的缺省标签,但在其他方面与 analyzer 完全相同。另一方面,er_print 实用程序可显示命令行界面。
建议在生成应用程序二进制文件时使用 -g 编译器选项。这样,tha 便可以在报告死锁时显示源代码和行号信息。
您可以通过 "Set Data Presentation"(设置数据显示)对话框控制数据的显示。要打开该对话框,请单击工具栏中的 "Set Data Presentation"(设置数据显示)按钮或从 "View"(视图)菜单中选择 "Set Data Presentation"(设置数据显示)。
"Set Data Presentation"(设置数据显示)对话框具有一个包含七个标签的窗格。有关更多信息,请参阅 analyzer(1) 手册页。
线程分析器处理以下文件中的指令:当前目录中的 .er.rc 文件(如果有);用户起始目录中的 .er.rc 文件(如果有);随产品安装的系统 er.rc 文件。
这些 .er.rc 文件可以包含控制打开线程分析器时显示哪些标签的缺省设置 (rtabs)。标签由相应报告的 er_print 命令命名,以下标签除外:"Experiments"(实验)标签,名为 headers;"Timeline"(时间线)标签,名为 timeline;"Dual Source"(双源)标签,名为 dsrc;以及 "Source/Disassembly"(源代码/反汇编代码)标签,名为 srcdis。
.er.rc 文件还可以包含用于度量、排序、指定编译器注释选项和突出显示源代码和反汇编代码输出阈值的缺省设置。这些文件还为其他编译器的 C++ 名称取消改编指定路径,并指定用于 "Timeline"(时间线)标签、名称格式和设置 "View Mode"(查看模式)(viewmode) 的缺省设置。
.er.rc 文件还可以包含一项设置,即 en_desc {on|off},它用于控制读取创始实验后是否选择和读取子孙实验。
.er.rc 文件还可以包含用于控制源文件和对象文件搜索路径的指令。在线程分析器中,可以通过单击 "Set Data Presentation"(设置数据显示)对话框中的 "Save"(保存)按钮来保存 .er.rc 文件,该对话框可以通过 "View"(视图)菜单打开。从 "Set Data Presentation"(设置数据显示)对话框中保存 .er.rc 文件后,不仅影响线程分析器的后续调用,还影响 er_print 实用程序和 er_src 实用程序。请参见 er_print(1) 手册页中这些指令和文件的说明及其处理。
线程分析器将在错误/警告日志区域中写入一条消息,指出它处理的用户 .er.rc 文件,包括装入任何标签时生成的任何处理消息。
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) 、 tha (1) 、 libtha (3)
线程分析器用户指南
性能分析器手册