CN106227671B - 程序运行性能分析方法及装置 - Google Patents
程序运行性能分析方法及装置 Download PDFInfo
- Publication number
- CN106227671B CN106227671B CN201610644861.2A CN201610644861A CN106227671B CN 106227671 B CN106227671 B CN 106227671B CN 201610644861 A CN201610644861 A CN 201610644861A CN 106227671 B CN106227671 B CN 106227671B
- Authority
- CN
- China
- Prior art keywords
- function
- thread
- run
- stack frame
- current stack
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Active
Links
Classifications
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F11/00—Error detection; Error correction; Monitoring
- G06F11/36—Preventing errors by testing or debugging software
- G06F11/3604—Software analysis for verifying properties of programs
- G06F11/3612—Software analysis for verifying properties of programs by runtime analysis
Landscapes
- Engineering & Computer Science (AREA)
- Theoretical Computer Science (AREA)
- Software Systems (AREA)
- Computer Hardware Design (AREA)
- Quality & Reliability (AREA)
- Physics & Mathematics (AREA)
- General Engineering & Computer Science (AREA)
- General Physics & Mathematics (AREA)
- Debugging And Monitoring (AREA)
Abstract
本公开是关于一种程序运行性能分析方法及装置。该程序运行性能分析方法包括:步骤1、将运行程序中的待分析进程中处于运行态的线程中断;步骤2、当所述线程当前处于函数调用中,获取当前栈帧所运行的函数的函数名;步骤3、根据所述函数的函数名判断该当前栈帧所运行的函数是否为第一虚拟机入口函数;步骤4、当该当前栈帧所运行的函数为所述第一虚拟机入口函数时,记录该运行程序中的所述当前栈帧所运行的第一类函数调用信息。本公开可以实现对运行的程序的性能分析。
Description
技术领域
本公开涉及计算机技术领域,具体而言,涉及一种程序运行性能分析方法及装置。
背景技术
在Linux环境下,对于运行的项目程序,监测其性能是非常重要的,因为程序的性能直接影响了产品的用户体验。但是究竟是程序中哪些函数消耗掉了大部分执行时间,通常不是非常容易看出来的,需要借助性能分析工具。性能分析工具主要是用来分析程序的主要消耗点和热点在哪里,测试出程序的性能及瓶颈所在,为程序的优化提供基础。针对性能分析结果,可以对程序进行有效的针对性优化,使其提高运行效率,直接提高用户的使用体验。
以常见的编程语言C/C++和Python为例,常见的C/C++性能分析工具包括perf,gprof,oprofile等,常见的Python性能分析工具包括cProfile,hotshot等。以下简单阐述目前常用的性能分析工具及其原理。
perf是内置于Linux内核源码树中的性能剖析工具,常用于发现性能瓶颈和定位热点代码。它的原理是基于事件采样,以采集性能事件为基础。它支持针对处理器相关性能指标与操作***相关性能指标的性能剖析。
gprof也是用于为Linux平台上的程序精确分析性能瓶颈,它可以准确地给出函数被调用的时间和次数,以及给出函数调用关系。通过在编译和链接程序的时候加入相应的选项,Gcc(GNU C Com piler,一种编译器)在程序中的每个函数中都加入了一个特定的函数。当调用程序里的函数的时候,都会调用这个特定的函数,从而保存了所有与函数相关的调用时间,调用次数等等的有用信息。
oProfile是Linux内核支持的一种性能分析机制,它在时钟中断处理入口处建立监测点,记录被中断的上下文现场。
cProfile是Isprof的用C语言实现的扩展应用,运行开销比较合理,适合分析运行时间较长的程序。它只能分析Python代码,并且需要嵌入代码,以及需要额外的工具查看详细的结果。
hotshot同样是用于分析Python代码的,其大部分都是用C实现的,减少了性能分析时的运行开销,但是会产生巨大的运行记录,分析也比较慢。hotshot不支持多线程的程序。
尚无工具可以同时分析C/C++和Python的性能,并给出详细的分析结果。且目前的性能分析工具一般需要通过指定编译参数,或者在启动前加入相关参数,或者修改代码嵌入相关的语句,以实现在程序运行时进行性能监督。
需要说明的是,在上述背景技术部分公开的信息仅用于加强对本公开的背景的理解,因此可以包括不构成对本领域普通技术人员已知的现有技术的信息。
发明内容
针对现有技术中的部分问题或者全部问题,本公开提供一种程序运行性能分析方法及装置,用于实现运行程序性能的监测和分析。
根据本公开的一个方面,提供一种程序运行性能分析方法,包括:步骤1、将运行程序中的待分析进程中处于运行态的线程中断;步骤2、当所述线程当前处于函数调用中,获取当前栈帧所运行的函数的函数名;步骤3、根据所述函数的函数名判断所述当前栈帧所运行的函数是否为第一虚拟机入口函数;步骤4、当所述当前栈帧所运行的函数为所述第一虚拟机入口函数时,记录该运行程序中的所述当前栈帧所运行的第一类函数调用信息。
在本公开的一种示例性实施例中,还包括:步骤5、当所述当前栈帧所运行的函数不是所述第一虚拟机入口函数时,记录该运行程序中的所述当前栈帧所运行的第二类函数调用信息。
在本公开的一种示例性实施例中,还包括:步骤6、从所述当前栈帧切换到上一栈帧,根据所述步骤2-5遍历该线程的所有栈帧,根据所述步骤4和5中记录的第一类和第二类函数调用信息统计该运行程序中的第一类和第二类函数调用信息。
在本公开的一种示例性实施例中,在所述步骤1之后还包括:判断所述线程当前是否处于***调用中;当所述线程处于***调用中,记录为***调用;间隔预设时间后,回到所述步骤1中断该待分析进程中的下一个运行态的线程。
在本公开的一种示例性实施例中,所述步骤1包括:根据进程ID,获取所述待分析进程所包含的线程;利用第一***调用函数中的第一参数,跟踪所述线程;根据所述线程ID中的状态字段获得所述线程的状态,并对运行态的线程进行标记;利用所述第一***调用函数中的第二参数,中断运行态的线程。
在本公开的一种示例性实施例中,还包括:对中断成功的线程,利用第一库中的第一函数进行栈帧分析的初始化。
在本公开的一种示例性实施例中,所述步骤2包括:利用第一库中的第二函数,获取所述当前栈帧所运行的函数的改编函数名;利用第一命名空间下的第三函数对所述改编函数名进行译解获得所述函数的函数名。
在本公开的一种示例性实施例中,所述步骤4包括:当所述当前栈帧所运行的函数为所述第一虚拟机入口函数时,利用第一库中的第四函数,获取所述当前栈帧的第一指针;根据所述第一指针定位到所述当前栈帧的第一对象位置;根据所述第一对象位置从内存中读取第一对象;根据读取到的所述第一对象获得所述当前栈帧对应的第一类函数名以及具体执行到的行数。
在本公开的一种示例性实施例中,所述步骤6中第一类函数调用信息的统计包括两种模式:第一模式,其用于统计每个第一类函数自身的调用信息;第二模块,其用于统计每个第一类函数包含自身在内以及所有子函数的调用信息。
在本公开的一种示例性实施例中,所述第一类和第二类函数调用信息包括函数调用次数和/或函数调用频率和/或函数调用关系。
在本公开的一种示例性实施例中,还包括:设置调节参数,所述调节参数用于设置采样频率和/或数据刷新频次和/或针对所述待分析进程中的指定线程进行分析。
根据本公开的一个方面,提供一种程序运行性能分析装置,包括:中断模块,其用于将运行程序中的待分析进程中处于运行态的线程中断;函数名获取模块,其用于当所述线程当前处于函数调用中,获取当前栈帧所运行的函数的函数名;第一判断模块,其用于根据所述函数的函数名判断所述当前栈帧所运行的函数是否为第一虚拟机入口函数;第一记录模块,其用于当所述当前栈帧所运行的函数为所述第一虚拟机入口函数时,记录该运行程序中的所述当前栈帧所运行的第一类函数调用信息。
在本公开的一种示例性实施例中,还包括:第二记录模块,其用于当所述当前栈帧所运行的函数不是所述第一虚拟机入口函数时,记录该运行程序中的所述当前栈帧所运行的第二类函数调用信息。
在本公开的一种示例性实施例中,还包括:统计模块,其用于从所述当前栈帧切换到上一栈帧,调用所述函数名获取模块、所述第一判断模块、所述第一记录模块及所述第二记录模块遍历该线程的所有栈帧,根据所述第一记录模块和所述第二记录模块记录的第一类和第二类函数调用信息统计该运行程序中的第一类和第二类函数调用信息。
在本公开的一种示例性实施例中,还包括:第二判断模块,其用于判断所述线程当前是否处于***调用中;第三记录模块,其用于当所述线程处于***调用中,记录为***调用;调用模块,其用于间隔预设时间后,调用所述中断模块中断该待分析进程中的下一个运行态的线程。
本公开的一种实施例中的程序运行性能分析方法及装置中,利用第一***调用函数中的参数和第一库中的函数,可以同时分析运行时程序的C/C++栈帧和Python栈帧。
应当理解的是,以上的一般描述和后文的细节描述仅是示例性和解释性的,并不能限制本公开。
附图说明
此处的附图被并入说明书中并构成本说明书的一部分,示出了符合本公开的实施例,并与说明书一起用于解释本公开的原理。显而易见地,下面描述中的附图仅仅是本公开的一些实施例,对于本领域普通技术人员来讲,在不付出创造性劳动的前提下,还可以根据这些附图获得其他的附图。
图1示意性示出本公开示例性实施例中一种程序运行性能分析方法的流程图。
图2示意性示出32位***的函数调用过程形成的栈帧布局的示意图。
图3示意性示出本公开示例性实施例中程序运行性能分析方法步骤S11的一种流程图。
图4示意性示出本公开示例性实施例中程序运行性能分析方法步骤S14的一种流程图。
图5示意性示出本公开示例性实施例中另一种程序运行性能分析方法的流程图。
图6示意性示出本公开示例性实施例中程序运行性能分析方法的C/C++函数调用信息的统计图。
图7示意性示出本公开示例性实施例中程序运行性能分析方法的Python函数的内部模式的统计图。
图8示意性示出本公开示例性实施例中程序运行性能分析方法的Python函数的累积模式的统计图。
图9示意性示出本公开示例性实施例中程序运行性能分析方法的Python函数调用关系的统计图。
图10示意性示出本公开示例性实施例中一种程序运行性能分析装置的方框图。
具体实施方式
现在将参考附图更全面地描述示例实施方式。然而,示例实施方式能够以多种形式实施,且不应被理解为限于在此阐述的范例;相反,提供这些实施方式使得本公开将更加全面和完整,并将示例实施方式的构思全面地传达给本领域的技术人员。所描述的特征、结构或特性可以以任何合适的方式结合在一个或更多实施方式中。在下面的描述中,提供许多具体细节从而给出对本公开的实施方式的充分理解。然而,本领域技术人员将意识到,可以实践本公开的技术方案而省略所述特定细节中的一个或更多,或者可以采用其它的方法、组元、装置、步骤等。在其它情况下,不详细示出或描述公知技术方案以避免喧宾夺主而使得本公开的各方面变得模糊。
此外,附图仅为本公开的示意性图解,并非一定是按比例绘制。图中相同的附图标记表示相同或类似的部分,因而将省略对它们的重复描述。附图中所示的一些方框图是功能实体,不一定必须与物理或逻辑上独立的实体相对应。可以采用软件形式来实现这些功能实体,或在一个或多个硬件模块或集成电路中实现这些功能实体,或在不同网络和/或处理器装置和/或微控制器装置中实现这些功能实体。
综合考虑图1至图4。图1示意性示出本公开示例性实施例中一种程序运行性能分析方法的流程图。
本发明实施例开发了一个全新的程序运行性能分析工具,解决了目前无工具可以同时分析C/C++和Python性能的问题。如图1所示,在步骤S11中,将运行程序中的待分析进程中处于运行态的线程中断。
图3示意性示出所述步骤S11的一种流程图。如图3所示,在步骤S111中,根据进程ID(Process Identification,进程识别号,也就是进程标识符,操作***里每打开一个程序都会创建一个进程ID,简称为PID),获取该待分析进程所包含的线程。
例如,用户提供进程ID,首先从/proc/PID/task下获得该进程所包含的所有线程(本发明实施例中默认分析进程的所有线程,在其它实施例中,也可以仅分析指定的某一个或某几个线程)。
在步骤S112中,利用第一***调用函数中的第一参数,跟踪所述线程。
在示例性实施例中,针对Linux操作***和其他遵循System V AMD64ABI调用约定的操作***,以下均以Linux***为例进行说明。所述第一***调用函数为ptrace***调用函数,所述第一参数为所述ptrace***调用函数中的PTRACE_SEIZE参数,即利用ptrace***调用函数中的PTRACE_SEIZE参数,挂载(attach)到所有线程上,此时并不会停止线程的运行,并且跟踪所有线程。如果将该程序运行性能分析方法应用于其他操作***,则所述第一***调用函数及其第一参数也可以是能够实现类似跟踪线程功能的其他***调用函数及其参数,在此不对本发明的发明目的构成限制。
在步骤S113中,根据所述线程ID(thread ID,简称为TID)中的状态字段获得所述线程的状态,并对运行态的线程进行标记。
在示例性实施例中,所述状态字段为state字段。
例如,对所有线程ID进行分析,根据/proc/PID/task/TID/status中的State字段获得当前线程的状态,如果线程是运行(running)状态(休眠状态对应字段是State:S(sleeping),运行态是State:R(running)),则进行相应的标记。
其中,所述对运行态的线程进行标记可以是将其标记为第1个运行态的线程,第2个运行态的线程,直至第n个运行态的线程。当存在多个(两个或者两个以上)运行态的线程时,可以设置按顺序分析该待分析进程中包含的所有运行态的线程,也可以指定分析该待分析进程中的某一个或某几个运行态的线程。在一个实施例中,设置默认的是分析该待分析进程中包含的所有运行态的线程。在另一个实施例中,可以设置一调节参数,用于指定该待分析进程中的某一特定运行态的线程进行分析。
在示例性实施例中,由于被监控进程和本发明示例的程序运行性能分析工具是两个不同的进程,因此在分析前,需要利用libunwind库中的_UPT_access_mem函数,把相关数据从被监控进程中按字节拷贝到程序运行性能分析工具进程中,然后再进行分析。
在步骤S114中,利用所述第一***调用函数中的第二参数,中断该运行态的线程。
在示例性实施例中,所述第二参数为所述ptrace***调用函数中的PTRACE_INTERRUPT参数,用于中断running态的线程。
其中,采样过程中可以随时暂停或者终止。终止就是正常退出监测进程即可。暂停就是增加一个bool变量,用Stop来表示是否处于暂停状态,在上述采样步骤中的S113中判断,如果Stop是true,则直接休眠一段时间(默认为10ms,可以根据实际需要自主设置,可以是采样频率的倒数)。
在示例性实施例中,在所述步骤S11之后还包括:对中断成功的线程,利用第一库中的第一函数进行栈帧分析的初始化。
例如,所述栈帧分析的初始化可以包括:开辟出相应的内存空间,以便之后把相应内存数据从被监测的进程中拷贝到profile进程中的操作。
在示例性实施例中,所述第一库为libunwind库,所述第一函数为所述libunwind库中的unw_init_remote函数。类似地,如果将该程序运行性能分析方法应用于其他操作***,则所述第一库及其第一函数也可以是能够实现类似栈帧分析初始化功能的其他库及其函数,在此不对本发明的发明目的构成限制。
在示例性实施例中,在所述步骤S11之后还包括:判断所述线程当前是否处于***调用中;当所述线程处于***调用中,记录为***调用;间隔预设时间后,回到所述步骤S11中断该待分析进程中的下一个运行态的线程。
例如,根据/proc/PID/task/TID/syscall下的信息,可以知道该线程当前是否处于***调用中,如果是,则在统计数据中直接记录为***调用,并且直接休眠一段时间;如果否,则继续进行下面的步骤。***调用和一般函数调用/过程调用都是比较常见的。***调用是用户程序和内核交互的接口。***调用时,CPU(Central Processing Unit,中央处理器)通过软中断切换到内核态开始执行内核***调用函数,这个时候就不需要分析在用户态上的那些栈帧函数调用链。
在步骤S12中,当所述线程当前处于函数调用中,获取当前栈帧(stack frame)所运行的函数的函数名。
这里简要阐述栈帧的概念和原理。本发明是基于采样的栈帧分析的。栈是相对整个***而言的,而栈帧则是相对某个函数而言的。栈帧也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构。在当今多数计算机体系架构中,函数的参数传递、局部变量的分配和释放都是通过操作栈来实现的,栈还用来存储返回值信息,保存寄存器以供恢复调用前的状态。每个函数的调用过程,都会为该次调用的函数分配栈空间,为单个函数分配的那部分栈空间就叫做栈帧。
这个栈帧中维持着函数调用过程所需要的信息,如函数入参、出参、返回地址和上一个栈帧的栈底指针等信息,还保存了函数内部的自动变量。因此栈作用就是用来保持栈帧的活动记录(即函数调用)。
图2示意性示出32位***的函数调用过程形成的栈帧布局的示意图。
如图2所示,对于一个栈来说,ebp(extended base pointer,基址指针寄存器)和esp(extended stack pointer,栈指针寄存器)分别指向***栈最上面一个栈帧的底部和栈帧的栈顶。假设参数1,…,参数n为被调用函数的入参,图2的栈表示的是从上到下压栈的,就是参数n先压栈,然后是参数n-1,…,最后是参数1。例如,假设有一个函数fun(参数1,参数2,…,参数n),则是将参数1至n从右到左压到栈中的。当被调用函数结束后,根据栈中被保存的返回地址和保存的ebp,可以恢复到调用者原来的栈帧状态。这里的返回地址可以理解为:父函数在调用某一子函数时,将该父函数中所述子函数所在代码的下一条代码的地址作为返回地址。
在基于ebp构造的栈中,每一次函数调用都产生一个栈帧,栈帧中保存着该次函数调用对应参数、返回地址以及该函数在运行过程中产生的数据。各个栈帧通过ebp连通,形如单向链表,链表表头由当前ebp寄存器指定。例如,假设包含三个函数栈帧A、B和C,所示函数调用顺序为函数C调用函数B,函数B调用函数A,***当前正在运行函数A中的代码。当前ebp寄存器保存着栈帧A中的[ebp]所在地址([ebp]表示压入栈中的ebp寄存器),A.[ebp]则记录着B.[ebp]所在地址,B.[ebp]中保存着C.[ebp]所在栈中的地址,形成如
ebp->A.[ebp]->B.[ebp]->C.[ebp]
的单向ebp链。函数A对应栈帧为***中的最新栈帧,函数A中的代码便可通过上述关系去遍历当前***中的所有栈帧,继而读取各个栈帧的内容。
而x86框架下的64位***版本的栈帧布局则和32位***版本的栈帧布局有所不同,首先,32位下只有8个通用寄存器供使用(eax,ebx,edx,ebp,esp,esi,edi),而64位则将寄存器扩展为64位(前缀由“e”变更为“r”),并且新增了8个寄存器(r8,r9,r10,r11,r12,r13,r14,r15)。其次,参数传递的方式也会有所不同,函数开始的6个整数或指针类型的参数将通过寄存器传递,第一个参数保存在rdi中,第二个保存在rsi中,接下来依次保存在rdx,rcx,r8,r9中,从第7个参数开始,接下来的所有参数都将通过栈传递。
在示例性实施例中,所述步骤S12包括:利用第一库中的第二函数,获取当前栈帧运行的函数的改编函数名;利用第一命名空间下的第三函数对所述改编函数名进行译解获得该函数的函数名。
在示例性实施例中,所述第二函数为所述libunwind库中的unw_get_proc_name函数,所述第一命名空间为abi命名空间,所述第三函数为所述abi命名空间下的__cxa_demangle函数。利用libunwind库中的unw_get_proc_name函数,可以获取当前栈帧运行的函数的名称,但此时函数名称是改编过的(为允许重载,编译器将描述函数参数类型的信息合并到函数的原始名称中,从而为重载函数生成唯一的函数名称),所以需要利用abi命名空间下的__cxa_demangle函数对函数名进行译解获得该函数的真实的函数名。
在步骤S13中,根据所述函数的函数名判断所述当前栈帧所运行的函数是否为第一虚拟机入口函数。
在示例性实施例中,所述第一虚拟机入口函数为Python虚拟机入口函数。当然,所述第一虚拟机入口函数还可以是其它虚拟机入口函数,例如脚本语言lua,本发明对此不作限定。下面以Python虚拟机为例进行详细说明。当该当前运行的函数的函数名为PyEval_EvalFrameEx时,即判断该当前运行的函数为所述Python虚拟机入口函数。
下面简要阐述Python虚拟机的概念及其执行原理。Python运行相关数据结构主要由PyCodeObject和PyFrameObject构成。其中PyCodeObject是Python字节码的存储结构,Python程序文件在执行前需要编译成PyCodeObject对象,每一个Code Block都会是一个PyCodeObject对象。编译后的pyc文件就是以PyCodeObject结构序列后存储的,运行时加载并反序列化为PyCodeObject对象。Python虚拟机会从编译得到的PyCodeObject对象中依次读入每一条字节码指令,并在当前的上下文环境中执行这条字节码指令。Python虚拟机实际上是在模拟操作中执行文件的过程。Python程序的字节码指令以及一些静态信息比如常量等都存储在PyCodeObject中,但是运行时有很多内容是运行时动态改变的,因而PyFrameObject也就是栈帧对象是必需的。
PyFrameObject是对栈帧的模拟,当进入到一个新的函数时,都会有PyFrameObject对象用于模拟栈帧操作。每一个PyFrameObject对象都维护了一个PyCodeObject对象,这表明每一个PyFrameObject中的动态内存空间对象都和源代码中的一段代码(code)相对应。通过分析PyFrameObject对象,我们可以获取和当前Python函数相关的信息,如Python函数的名称、具体的行数及所属文件等等。
在步骤S14中,当所述当前栈帧所运行的函数为所述第一虚拟机入口函数时,记录该运行程序中的所述当前栈帧所运行的第一类函数调用信息。
例如,所述第一类函数为该运行程序中的Python函数。
图4示意性示出所述步骤S14的一种流程图。如图4所示,在步骤S141中,当所述当前栈帧所运行的函数为所述第一虚拟机入口函数时,利用第一库中的第四函数,获取所述当前栈帧的第一指针。
在示例性实施例中,针对32位***,所述第四函数为所述libunwind库中的unw_get_reg函数,所述第一指针为esp指针,利用libunwind库中的unw_get_reg函数,获取当前栈帧的esp指针。在另一实施例中,针对64位***,所述第一指针为rsp指针。需要说明的是,这里的esp和rsp均为举例说明,实际可以根据程序运行的***平台不同而相应调整的,在此不做限定。下面均以32位***为例进行说明。
在步骤S142中,根据所述第一指针定位到该当前栈帧的第一对象位置。
在示例性实施例中,所述第一对象为PyFrameObject。根据所述esp指针定位到该当前栈帧的PyFrameObject位置。这里利用esp来寻找PyEval_EvalFrameEx函数的第一个参数PyFrameObject*在内存中的位置,这个寻找的思路需要基于前面分析的函数调用时的栈帧的原理。
在步骤S143中,根据所述第一对象位置从内存中读取第一对象。
例如,根据所述PyFrameObject位置从内存中读取PyFrameObject。
在步骤S144中,根据读取到的所述第一对象获得该当前栈帧对应的第一类函数名以及具体执行到的行数。
例如,根据读取到的PyFrameObject获得该当前栈帧对应的Python函数名以及具体执行到的行数,并进行相关的记录。
在示例性实施例中,所述方法还包括:步骤S15、当该当前栈帧所运行的函数不是所述第一虚拟机入口函数时,记录该运行程序中的该当前栈帧所运行的第二类函数调用信息。
例如,所述第二类函数为C/C++函数。
在一实施例中,C/C++函数的调用频率采用以下方法统计:在对第一个栈帧,也就是函数调用链上的最后一个函数分析时,根据上述流程中的步骤S144得到函数的真实的函数名后,可以对该函数的出现次数加一;遍历整个线程的所有栈帧后,即可统计得到该函数的调用频次。在另一实施例中,还包括:将上述得到的函数的调用频次除以根据总共采样的次数,可以求得每个函数的调用频率。
在示例性实施例中,所述方法还包括:步骤S16、从当前栈帧切换到上一栈帧,根据所述步骤S12-S15遍历该线程的所有栈帧,根据所述步骤S14和S15中记录的第一类和第二类函数调用信息统计该运行程序中的第一类和第二类函数调用信息。
例如,可以利用libunwind库中的unw_step函数,把状态从当前栈帧切换到上一个栈帧,以该上一个栈帧作为新的当前栈帧,然后可以利用所述步骤S12-S15遍历该线程的所有栈帧,并统计相关信息,直到unw_step函数失败为止,则这次的中断线程采样分析的过程结束。
在示例性实施例中,所述步骤S16中第一类函数调用信息的统计包括两种模式:第一模式,其用于统计每个第一类函数自身的调用信息;第二模块,其用于统计每个第一类函数包含自身在内以及所有子函数的调用信息。
例如,所述第一模式为内部模式(internal模式),其用于统计每个Python函数自身的调用信息;所述第二模式为累积模式(cumulative模式),其用于统计每个Python函数包含自身在内以及所有子函数的调用信息。
其中,Python的内部模式是指:该模式统计的是每个函数自己本身的调用频率和/或调用频次,不包括子函数的调用频率和/或调用频次,因而在具体分析Python函数的时候,采取上述和C/C++函数类似的统计方法,对函数调用链上第一个出现的Python虚拟机栈帧的函数进行频次的加一。
其中,Python的累积模式是指:该模式统计的是包含每个函数自己在内,以及所有子函数的调用频率和/或调用频次之和,所以在整个Python函数调用链中,除了最后一个栈帧对应的Python函数名称需要频次加一外,其余调用链上的Python函数都需要同时加一。
例如,Python函数调用链:A->B->C->D,即A函数调用B函数,B函数调用C函数,C函数调用D函数,A函数是B函数的父函数,而B函数是A函数的子函数,同时B函数还是C函数的父函数,类似的,C函数是B函数的子函数,同时,C函数还是D函数的父函数,以及D函数是C函数的子函数。在Python的internal模式下,只需要把D函数的频次加一即可;而Python的cumulative模式下,则需要把A,B,C,D四个函数的频次都加一。
具体来说,在函数调用关系中,父函数和子函数是相对而言的。对于***在调用函数时往栈中压入被调用的该函数的父函数栈帧的起始地址的情况,当父函数调用一个函数时,***首先会向栈中压入一个返回地址,然后会压入父函数的栈帧起始地址,通过***压入栈中的栈帧起始地址可以直接计算出父函数执行时所使用的栈帧长度,这样就能够比较准确地推算出任务的函数调用关系。找到了一个确定的函数调用关系,并将返回地址对应的函数的函数名记录下来(例如,记录在一个记录表中);继续查找栈中的下一个返回地址,同样根据当前查找到的返回地址确定引起该当前查找到的返回地址入栈的、表示函数调用的操作码,若操作码的寻址类型为间接寻址,则根据操作码确定被调用的函数,若上述记录表中记录有被调用的函数的函数名,则将上述记录表中记录的被调用的该函数的父函数的函数名删除,并将返回地址对应的函数的函数名记录在上述记录表中,依此对栈内返回地址进行遍历直至栈顶。
具体来说,记录表用来存放可能存在调用关系的函数的函数名,其可以是任意可用来存放数据的数据结构,例如可以是链表,本发明并不以此为限制。
在示例性实施例中,该方法还可以统计Python的函数调用关系,根据调用关系记录相邻的两个函数,最后统计即可。
例如,还是以上面的Python函数调用链:A->B->C->D为例进行说明,则对相邻的函数调用(A,B),(B,C),(C,D)分别进行频次加一。
在示例性实施例中,所述第一类和第二类函数调用信息包括函数调用次数和/或函数调用频率和/或函数调用关系。
在示例性实施例中,还包括:设置调节参数,所述调节参数用于设置采样频率和/或数据刷新频次和/或针对该待分析进程中的指定线程进行分析。
例如,./本发明示例的程序运行性能分析工具名称-help会显示如下提示:
Options:
--help Produce help message//输出帮助信息
--sample_interval arg Sample interval.Default 10ms.//设置采样频率,默认10毫秒。
--preserve_times arg Use the lastest preserve_times data forstatistics.
Default 30000.//设置数据刷新频次,默认保留最新的30000次采样结果作统计。
--profile_thread arg Profile the specified thread.//设置针对进程中指定的线程作统计分析。
实际运行时,只需要./本发明示例的程序运行性能分析工具名称PID即可对指定的进程进行采样分析。
本发明实施方式提供的一种程序运行性能分析方法,利用ptrace***调用函数和libunwind库,可同时分析运行时程序的C/C++栈帧和Python栈帧,可以同时分析C/C++和Python性能。该方法还提供了简单方便的调用方式,采用挂载的方式,只需提供进程PID即可进行实时分析,无需指定编译参数或者修改代码,并且同时支持32位和64位***。在一些实施例中,可以深入分析运行时程序的Python虚拟机,统计出函数之间的详细调用关系。在另一些实施例中,还提供可调参数支持数据的刷新机制以及采样频率。采样过程中可以随时暂停或者终止。在一些实施例中,默认对进程中的所有线程进行采样分析,同时支持对进程中的单一线程进行性能分析。
图5示意性示出本公开示例性实施例中另一种程序运行性能分析方法的流程图。
如图5所示,以遍历待分析进程中所有运行态的线程为例进行说明。
在步骤S21中,将运行程序中的待分析进程中处于运行态的线程进行标记,中断第i个运行态的线程。这里i=1,2,3…,n,n为正整数,其中n为该待分析进程中包含的所有运行态的线程的个数,当然,也可以仅仅是指定的某一个或某几个线程。
在步骤S22中,判断该线程是否中断成功,当该线程中断成功时,则进入下一步S23;反之,则调回到步骤S21。
在步骤S23中,利用第一库中的第一函数进行栈帧分析的初始化。
在步骤S24中,判断该线程当前处于***调用中,当该线程当前处于***调用中,则跳转到步骤S211;反之,则进入下一步S25。
在步骤S25中,获取当前栈帧所运行的函数的函数名。
在步骤S26中,判断该当前栈帧所运行的函数是否为第一虚拟机入口函数,当该当前栈帧所运行的函数为所述第一虚拟机入口函数时,则进入下一步S27;当该当前栈帧所运行的函数不为所述第一虚拟机入口函数时,则跳转到步骤S28。
在步骤S27中,记录该运行程序中的该当前栈帧所运行的第一类函数调用信息。
在步骤S28中,记录该运行程序中的该当前栈帧所运行的第二类函数调用信息。
在步骤S29中,从该当前栈帧切换到上一栈帧,以该上一栈帧作为新的当前栈帧。
在步骤S210中,判断是否已经遍历该线程的所有栈帧,如果已经遍历完该线程的所有栈帧,则跳转到步骤S212;反之,跳回到步骤S25,按照上述步骤S25-S29遍历该线程的所有栈帧为止。
在步骤S211中,记录为***调用。
在步骤S212中,休眠预设时间。
例如,该预设时间默认设置为10毫秒。当然,可以根据具体需要进行设置。
在步骤S213中,判断是否遍历完该进程的所有运行态的线程,如果没有,则跳回到步骤S21继续分析该进程中的下一个运行态的线程,直至遍历该进程的所有运行态的线程。
在步骤S214中,结束。
本发明实施方式提供的一种程序运行性能分析方法,主要的实现原理是基于采样的栈帧分析,利用ptrace***调用函数,可以对待分析的进程里面包含的所有线程进行锁定,然后间隔特定的时间(一般设置为10毫秒,和设定的采样频率相关)对线程进行中断,接着对线程的栈帧进行逐帧的分析和统计,对于Python虚拟机入口的栈帧即函数名为“PyEval_EvalFrameEx”,会进一步深入Python虚拟机,从内存中获取相关的信息如函数名、函数入口行数等进行统计和分析。
在示例性实施例中,本发明提供的程序运行性能分析方法支持实时的数据可视化分析界面。例如,采用libncurses库绘制。在另一实施例中,对于Python的统计提供cumulative模式和internal模式的切换。
因为本方法是基于采样的,因而采样次数越多,越接近真实的调用频率。以下图6-9是实际对某个工程项目采用本发明示例的程序运行性能分析工具分析的结果。
图6示意性示出本公开示例性实施例中程序运行性能分析方法的C/C++函数调用信息的统计图。
如图6所示,第一列为调用频率,第二列[s]表示为***调用,[+]表示可展开的Python函数性能统计,[.]为普通函数。这里的普通函数是指除了Python虚拟机入口函数以外的一般函数。需要说明的是,在图6-9的测试设计中,只有***调用([s])和一般函数调用,一般函数调用中又单独分出了Python虚拟机入口的函数,而如果本方法应用于其他程序性能测试,可以根据代码的不同或所包含的函数不同,进行适应性修改,统计其他类型函数的调用频次和/或调用频率和/或调用关系,在此不作限定。
图7示意性示出本公开示例性实施例中程序运行性能分析方法的Python函数的内部模式的统计图。
如图7所示,第一列为调用频率,第二列如果为[+]表示可以选择展开,得到该函数的调用图,第三列是文件名,第四列为函数名。
图8示意性示出本公开示例性实施例中程序运行性能分析方法的Python函数的累积模式的统计图。
如图8所示,第一列为频率,第二列如果为[+]表示可以选择展开,得到该函数的调用图,第三列是文件名,第四列为函数名。
图9示意性示出本公开示例性实施例中程序运行性能分析方法的Python函数调用关系的统计图。
如图9所示,Python的函数调用统计,采用自底向上的展示方式,用缩进表示调用的层次顺序。
分别利用perf,gprof,cProfile等工具对程序进行C/C++和Python的性能分析,然后汇总,虽然可以得到相近的结果,但是需要加入编译链接相关参数或者嵌入代码,并且cProfile无法对Python程序进行持续的实时分析,只能对某一段时间的性能进行分析,而且当程序处于卡死状态时,cProfile的分析可能会失败。
图10示意性示出本公开示例性实施例中一种程序运行性能分析装置的方框图。
如图10所示,该程序运行性能分析装置11包括:中断模块111,其用于将运行程序中的待分析进程中处于运行态的线程中断;函数名获取模块112,其用于当所述线程当前处于函数调用中,获取当前栈帧所运行的函数的函数名;第一判断模块113,其用于根据所述函数的函数名判断该当前栈帧所运行的函数是否为第一虚拟机入口函数;第一记录模块114,其用于当该当前栈帧所运行的函数为所述第一虚拟机入口函数时,记录该运行程序中的该当前栈帧所运行的第一类函数调用信息。
在示例性实施例中,该程序运行性能分析装置11还包括:第二记录模块,其用于当该当前栈帧所运行的函数不是所述第一虚拟机入口函数时,记录该运行程序中的该当前栈帧所运行的第二类函数调用信息。
在示例性实施例中,该程序运行性能分析装置11还包括:统计模块,其用于从该当前栈帧切换到上一栈帧,调用所述函数名获取模块、所述第一判断模块、所述第一记录模块及所述第二记录模块遍历该线程的所有栈帧,根据所述第一记录模块和所述第二记录模块记录的第一类和第二类函数调用信息统计该运行程序中的第一类和第二类函数调用信息。
在示例性实施例中,该程序运行性能分析装置11还包括:第二判断模块,其用于判断所述线程当前是否处于***调用中;第三记录模块,其用于当所述线程处于***调用中,记录为***调用;调用模块,其用于间隔预设时间后,调用所述中断模块中断该待分析进程中的下一个运行态的线程。
由于本发明实施方式的程序运行性能分析装置的各个功能模块与上述方法发明实施方式中相同,因此在此不再赘述。
应当注意,尽管在上文详细描述中提及了程序运行性能分析装置的若干模块或者单元,但是这种划分并非强制性的。实际上,根据本公开的实施方式,上文描述的两个或更多模块或者单元的特征和功能可以在一个模块或者单元中具体化。反之,上文描述的一个模块或者单元的特征和功能可以进一步划分为由多个模块或者单元来具体化。
此外,尽管在附图中以特定顺序描述了本公开中方法的各个步骤,但是,这并非要求或者暗示必须按照该特定顺序来执行这些步骤,或是必须执行全部所示的步骤才能实现期望的结果。附加的或备选的,可以省略某些步骤,将多个步骤合并为一个步骤执行,以及/或者将一个步骤分解为多个步骤执行等。
通过以上的实施方式的描述,本领域的技术人员易于理解,这里描述的示例实施方式可以通过软件实现,也可以通过软件结合必要的硬件的方式来实现。因此,根据本公开实施方式的技术方案可以以软件产品的形式体现出来,该软件产品可以存储在一个非易失性存储介质(可以是CD-ROM,U盘,移动硬盘等)中或网络上,包括若干指令以使得一台计算设备(可以是个人计算机、服务器、触控终端、或者网络设备等)执行根据本公开实施方式的方法。
本领域技术人员在考虑说明书及实践这里公开的发明后,将容易想到本公开的其它实施方案。本申请旨在涵盖本公开的任何变型、用途或者适应性变化,这些变型、用途或者适应性变化遵循本公开的一般性原理并包括本公开未公开的本技术领域中的公知常识或惯用技术手段。说明书和实施例仅被视为示例性的,本公开的真正范围和精神由下面的权利要求指出。
应当理解的是,本公开并不局限于上面已经描述并在附图中示出的精确结构,并且可以在不脱离其范围进行各种修改和改变。本公开的范围仅由所附的权利要求来限制。
Claims (13)
1.一种程序运行性能分析方法,包括:
步骤1、将运行程序中的待分析进程中处于运行态的线程中断;
步骤2、当所述线程当前处于函数调用中,获取当前栈帧所运行的函数的函数名;
步骤3、根据所述函数的函数名判断所述当前栈帧所运行的函数是否为第一虚拟机入口函数;
步骤4、当所述当前栈帧所运行的函数为所述第一虚拟机入口函数时,记录该运行程序中的所述当前栈帧所运行的第一类函数调用信息;
所述步骤1包括:
根据进程ID,获取所述待分析进程所包含的线程;
利用第一***调用函数中的第一参数,跟踪所述线程;
根据线程ID中的状态字段获得所述线程的状态,并对运行态的线程进行标记;
利用所述第一***调用函数中的第二参数,中断运行态的线程;
对中断成功的线程,利用第一库中的第一函数进行栈帧分析的初始化。
2.根据权利要求1所述的程序运行性能分析方法,其特征在于,还包括:
步骤5、当所述当前栈帧所运行的函数不是所述第一虚拟机入口函数时,记录该运行程序中的所述当前栈帧所运行的第二类函数调用信息。
3.根据权利要求2所述的程序运行性能分析方法,其特征在于,还包括:
步骤6、从所述当前栈帧切换到上一栈帧,根据所述步骤2-5遍历该线程的所有栈帧,根据所述步骤4和5中记录的第一类和第二类函数调用信息统计该运行程序中的第一类和第二类函数调用信息。
4.根据权利要求3所述的程序运行性能分析方法,其特征在于,在所述步骤1之后还包括:
判断所述线程当前是否处于***调用中;
当所述线程处于***调用中,记录为***调用;
间隔预设时间后,回到所述步骤1中断该待分析进程中的下一个运行态的线程。
5.根据权利要求1所述的程序运行性能分析方法,其特征在于,所述步骤2包括:
利用第一库中的第二函数,获取所述当前栈帧所运行的函数的改编函数名;
利用第一命名空间下的第三函数对所述改编函数名进行译解获得所述函数的函数名。
6.根据权利要求1所述的程序运行性能分析方法,其特征在于,所述步骤4包括:
当所述当前栈帧所运行的函数为所述第一虚拟机入口函数时,利用第一库中的第四函数,获取所述当前栈帧的第一指针;
根据所述第一指针定位到所述当前栈帧的第一对象位置;
根据所述第一对象位置从内存中读取第一对象;
根据读取到的所述第一对象获得所述当前栈帧对应的第一类函数名以及具体执行到的行数。
7.根据权利要求3所述的程序运行性能分析方法,其特征在于,所述步骤6中第一类函数调用信息的统计包括两种模式:
第一模式,其用于统计每个第一类函数自身的调用信息;
第二模块,其用于统计每个第一类函数包含自身在内以及所有子函数的调用信息。
8.根据权利要求3所述的程序运行性能分析方法,其特征在于,所述第一类和第二类函数调用信息包括函数调用次数和/或函数调用频率和/或函数调用关系。
9.根据权利要求1所述的程序运行性能分析方法,其特征在于,还包括:
设置调节参数,所述调节参数用于设置采样频率和/或数据刷新频次和/或针对所述待分析进程中的指定线程进行分析。
10.一种程序运行性能分析装置,其特征在于,包括:
中断模块,其用于将运行程序中的待分析进程中处于运行态的线程中断;
函数名获取模块,其用于当所述线程当前处于函数调用中,获取当前栈帧所运行的函数的函数名;
第一判断模块,其用于根据所述函数的函数名判断所述当前栈帧所运行的函数是否为第一虚拟机入口函数;
第一记录模块,其用于当所述当前栈帧所运行的函数为所述第一虚拟机入口函数时,记录该运行程序中的所述当前栈帧所运行的第一类函数调用信息;
所述中断模块还用于根据进程ID,获取所述待分析进程所包含的线程;利用第一***调用函数中的第一参数,跟踪所述线程;根据线程ID中的状态字段获得所述线程的状态,并对运行态的线程进行标记;利用所述第一***调用函数中的第二参数,中断运行态的线程;对中断成功的线程,利用第一库中的第一函数进行栈帧分析的初始化。
11.根据权利要求10所述的程序运行性能分析装置,其特征在于,还包括:
第二记录模块,其用于当所述当前栈帧所运行的函数不是所述第一虚拟机入口函数时,记录该运行程序中的所述当前栈帧所运行的第二类函数调用信息。
12.根据权利要求11所述的程序运行性能分析装置,其特征在于,还包括:
统计模块,其用于从所述当前栈帧切换到上一栈帧,调用所述函数名获取模块、所述第一判断模块、所述第一记录模块及所述第二记录模块遍历该线程的所有栈帧,根据所述第一记录模块和所述第二记录模块记录的第一类和第二类函数调用信息统计该运行程序中的第一类和第二类函数调用信息。
13.根据权利要求12所述的程序运行性能分析装置,其特征在于,还包括:
第二判断模块,其用于判断所述线程当前是否处于***调用中;
第三记录模块,其用于当所述线程处于***调用中,记录为***调用;
调用模块,其用于间隔预设时间后,调用所述中断模块中断该待分析进程中的下一个运行态的线程。
Priority Applications (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN201610644861.2A CN106227671B (zh) | 2016-08-05 | 2016-08-05 | 程序运行性能分析方法及装置 |
Applications Claiming Priority (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN201610644861.2A CN106227671B (zh) | 2016-08-05 | 2016-08-05 | 程序运行性能分析方法及装置 |
Publications (2)
Publication Number | Publication Date |
---|---|
CN106227671A CN106227671A (zh) | 2016-12-14 |
CN106227671B true CN106227671B (zh) | 2018-10-26 |
Family
ID=57548252
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN201610644861.2A Active CN106227671B (zh) | 2016-08-05 | 2016-08-05 | 程序运行性能分析方法及装置 |
Country Status (1)
Country | Link |
---|---|
CN (1) | CN106227671B (zh) |
Families Citing this family (14)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
TWI633432B (zh) * | 2016-12-29 | 2018-08-21 | 宏碁股份有限公司 | 檔案統計方法 |
CN107135128B (zh) * | 2017-06-28 | 2021-07-23 | 努比亚技术有限公司 | 调用链数据采集方法、移动终端及计算机可读存储介质 |
CN109753414A (zh) * | 2017-11-01 | 2019-05-14 | 阿里巴巴集团控股有限公司 | 性能数据的采集方法、展示方法、电子设备和客户端 |
TWI682323B (zh) * | 2017-11-24 | 2020-01-11 | 財團法人工業技術研究院 | 伺服器及其設定方法 |
CN108363911B (zh) * | 2018-02-11 | 2021-10-29 | 西安四叶草信息技术有限公司 | 一种Python脚本混淆、水印的方法及装置 |
CN110737465B (zh) * | 2018-07-20 | 2023-09-22 | 深圳市大梦龙途网络科技有限公司 | 一种函数调用路径获取的方法和相关装置 |
CN109542793B (zh) * | 2018-11-30 | 2022-06-14 | 北京小马智行科技有限公司 | 一种程序性能分析方法及装置 |
CN109992511B (zh) * | 2019-03-25 | 2022-11-22 | 口碑(上海)信息技术有限公司 | 获取代码测试覆盖率的装置及方法 |
CN111090466B (zh) * | 2019-12-20 | 2022-03-18 | 北京字节跳动网络技术有限公司 | 调用指令的优化方法、装置、设备和存储介质 |
CN113760338B (zh) * | 2020-06-05 | 2023-07-18 | 北京字跳网络技术有限公司 | 切换应用程序二进制接口abi的方法、装置及电子设备 |
CN112052073A (zh) * | 2020-09-18 | 2020-12-08 | 网易(杭州)网络有限公司 | 脚本性能分析方法及装置、可读存储介质及电子设备 |
CN112882695B (zh) * | 2021-03-02 | 2023-11-28 | 百果园技术(新加坡)有限公司 | 传参方法、装置、计算机设备及存储介质 |
CN113703879B (zh) * | 2021-08-31 | 2023-10-20 | 康键信息技术(深圳)有限公司 | 对象重载方法、装置、设备及存储介质 |
CN113886251B (zh) * | 2021-09-30 | 2023-04-11 | 四川大学 | 基于热力图的热点函数确定方法 |
Citations (1)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN102346708A (zh) * | 2010-08-03 | 2012-02-08 | 中兴通讯股份有限公司 | 一种调试器及其调试方法 |
Family Cites Families (2)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
US7017153B2 (en) * | 2001-12-13 | 2006-03-21 | Hewlett-Packard Development Company, L.P. | Uninstrumenting in-line code instrumentation via stack unwinding and cleanup |
US9361102B2 (en) * | 2014-06-09 | 2016-06-07 | Lehigh University | Methods for enforcing control flow of a computer program |
-
2016
- 2016-08-05 CN CN201610644861.2A patent/CN106227671B/zh active Active
Patent Citations (1)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN102346708A (zh) * | 2010-08-03 | 2012-02-08 | 中兴通讯股份有限公司 | 一种调试器及其调试方法 |
Non-Patent Citations (1)
Title |
---|
"Produce stack traces in output with libunwind";eb1b3f4;《https://github.com/pgbovine/strace-plus/blob/master/strace.c》;20130423;第1-30页 * |
Also Published As
Publication number | Publication date |
---|---|
CN106227671A (zh) | 2016-12-14 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
CN106227671B (zh) | 程序运行性能分析方法及装置 | |
Bhansali et al. | Framework for instruction-level tracing and analysis of program executions | |
US8423982B2 (en) | Speculative compilation | |
US10802946B2 (en) | Presenting differences between code entity invocations | |
US7210127B1 (en) | Methods and apparatus for executing instructions in parallel | |
US7475394B2 (en) | System and method of analyzing interpreted programs | |
KR100750834B1 (ko) | 자바 바이트 코드의 데이터 모니터링 시 모니터링된 데이터의 호출관계 규명 방법 및 이 방법을 이용한 알고리즘을 통해 자바 어플리케이션의 각종 성능 데이터를 추출하기 위한 컴퓨터 판독 가능한 기록 매체 | |
CN107766130B (zh) | 虚拟机向容器迁移的方法和装置 | |
CN102222023A (zh) | 异步工作流 | |
CN107015841B (zh) | 一种程序编译的预处理方法及程序编译设备 | |
ES2882177T3 (es) | Reproducción especulativa de código ejecutable | |
KR102013582B1 (ko) | 혼합 모드 프로그램의 소스 코드 오류 위치 검출 장치 및 방법 | |
CN103559123A (zh) | 基于VxWorks操作***的函数调用栈分析方法及装置 | |
CN112099800A (zh) | 代码数据的处理方法、装置和服务器 | |
Kähkönen et al. | Unfolding based automated testing of multithreaded programs | |
CN105550575B (zh) | 一种未导出的函数地址和数据结构偏移的获取方法及装置 | |
KR20110080073A (ko) | 멀티쓰레드 환경을 테스트하는 커버리지 장치 및 방법 | |
Vasilakis et al. | Ignis: Scaling distribution-oblivious systems with light-touch distribution | |
Kallas et al. | Practically correct,{Just-in-Time} shell script parallelization | |
Hirt et al. | Oracle JRockit: The Definitive Guide | |
US20090265156A1 (en) | Dynamically varying simulation precision | |
JP2018502390A (ja) | 負荷テスト | |
US20050257096A1 (en) | Modification of array access checking in AIX | |
Lång et al. | Parallel graph-based stateless model checking | |
US7774763B1 (en) | Techniques for forming a multi-tasking executable program and using the same |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
C06 | Publication | ||
PB01 | Publication | ||
SE01 | Entry into force of request for substantive examination | ||
SE01 | Entry into force of request for substantive examination | ||
GR01 | Patent grant | ||
GR01 | Patent grant |