CN104636259A - 一种基于运行期动态跟踪的函数执行超时与死锁检测方法 - Google Patents
一种基于运行期动态跟踪的函数执行超时与死锁检测方法 Download PDFInfo
- Publication number
- CN104636259A CN104636259A CN201510118723.6A CN201510118723A CN104636259A CN 104636259 A CN104636259 A CN 104636259A CN 201510118723 A CN201510118723 A CN 201510118723A CN 104636259 A CN104636259 A CN 104636259A
- Authority
- CN
- China
- Prior art keywords
- function
- thread
- track record
- measured
- function call
- 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.)
- Granted
Links
Landscapes
- Debugging And Monitoring (AREA)
Abstract
本发明涉及计算机技术领域,一种基于运行期动态跟踪的函数执行超时与死锁检测的方法包括A、在待检测函数的运行入口插入一段跟踪代码,区分待检测函数当前运行所属线程,登记各个进入运行的待检测函数的特征信息,并返回此特征信息对象的引用数据给待测函数临时保存。B、在待测函数的运行出口也插入对应的跟踪代码,根据A中曾返回的特征信息对象的访问信息,将函数特征信息对象从当前运行所属线程的数据结构中取消登记。C、在进程中创建一独立监视线程,对于时间计数超过第一级时间计数阈值的待测函数,则表示其运行时间偏长,即超时,而对于时间计数超过第二级时间计数阈值的待测函数,则表示其运行时间过长,存在死锁可能。本发明能有效判断超时和死锁。
Description
技术领域
本发明涉及计算机技术领域,具体涉及一种基于运行期动态跟踪的函数执行超时与死锁检测的方法。
背景技术
所有计算机软件运行过程中,都会存在大量的函数调用,并且大部分函数一般设计为可在一个足够小时间(纳秒、毫秒级)内运行完毕。而在实际的计算机软件编制过程中,由于设计、开发上的缺陷或疏忽,有时函数运行可能发生极为严重的故障,例如运行死锁。这相对于函数运行时发生异常(异常一般可以被捕获)更加严重,因为此时软件将处于“呆滞”状态,已无法运行捕获错误信息,对软件系统的集成联试、运行造成极大的困扰。同时这样的故障也非常难于排查,因为在数万、数十万行代码中,在1秒成千上万个函数调用中准确定位到故障函数是非常困难的,特别是当问题以随机小概率发生的时候。
为了排除此类故障,一般普通的作法是针对疑点函数调用,在函数进入和退出的运行点进行日志打印跟踪输出,然后在发生函数调用死锁时,检查输出的日志,检索最后一次进入但是却无退出记录的函数调用来进行判断。从理论上而言该方法具备一定的可行性,但同时也存在很多困扰。首先,由于初始时不确认是哪一函数调用存在问题,因此,可能存在疑虑需要日志跟踪的函数调用有很多,在日志中检索时便存在大量正常函数的日志干扰,检索困难;其二,由于多线程的存在,各函数调用进入、退出的日志记录可呈交错态,进一步增加了判断有进入无退出的函数调用的困难;其三,高频度的函数调用将输出大量的跟踪日志,极为影响性能,可能会破坏死锁发生的性能条件,从而不能观测到死锁;其四,函数调用的退出和进入不同,可能存在多个分支退出点,这在编码开发上也是不方便的。
发明内容
有鉴于此,本发明的主要目的在于提供一种基于运行期动态跟踪的函数执行超时与死锁检测的方法及组件,能对C++编写的程序进行有效、方便的死锁检测,以降低人工分析死锁的工作量,提高分析效率。
为了达到上述目的,本发明所采用的技术方案是如下实现的,一种基于运行期动态跟踪的函数执行超时与死锁检测的方法,该方法主要包括三个部分:
A、在待检测函数的运行入口插入一段跟踪代码,区分待检测函数当前运行所属线程,分别为不同的线程建立相应的数据结构,登记各个进入运行的待检测函数的特征信息(如函数名、事先预分配的唯一标识符等),并返回此特征信息对象的引用数据(对象地址)给待测函数临时保存。对于存在嵌套调用关系的待测函数,则按进入运行的先后次序创建一个链表数据结构对多个待检测函数特征信息进行保存。
B、类似A,在待测函数的运行出口(可能有多个运行退出点)也插入对应的跟踪代码,根据A中曾返回的特征信息对象的访问信息,将函数特征信息对象从当前运行所属线程的数据结构中取消登记。
C、在进程中创建一独立监视线程,以一个足够短的单位时间周期(推荐值为1秒,避免对程序运行造成太多额外运行开销)内扫描各个线程中由于一个或多个待测函数进入运行产生的特征信息对象,并对其进行时间计数递增,对于时间计数超过第一级时间计数阈值(建议3秒以内,除非阻塞或高密度计算,否则大部分编程良好的函数不需要运行超出1秒以上的时间)的待测函数,则表示其运行时间偏长,即超时,而对于时间计数超过第二级时间计数阈值(足够大值,建议30秒左右,以排除部分计算负担较重、耗时较久的函数影响)的待测函数,则表示其运行时间过长,存在死锁可能。
为使上述技术方案的应用足够简便,本发明对其进行封装,封装为一个可复用的函数调用跟踪组件(在Windows系统中以DLL体现)。
该函数调用跟踪组件将实现上述A、B、C三部分的主要有效实现,其中主要包括:为多个线程各自独立维护、跟踪待测函数运行的数据结构,以及一个独立的监视线程。
对应地,为应用此发明的待检测程序提供函数调用跟踪组件包装对象、函数调用跟踪代理对象来运用函数调用跟踪组件。
上述函数调用跟踪组件包装对象定义为,控制函数调用跟踪组件在待测目标程序中进行加载、启动、调用、停止、释放活动的代理类对象,为待测目标程序使用函数调用跟踪组件提供对象级别的管理。
上述函数调用跟踪代理对象定义为,接收函数调用信息,通过函数调用跟踪组件的API接口将待测目标函数信息、进入和退出动作传递进函数调用跟踪组件中以供超时或死锁判断的代理类对象。
函数调用跟踪组件中为多个线程独立维护、跟踪待测函数运行的数据结构具体定义如下。
将上述A部分中提到的待检测函数特征信息对象,正式约定为“函数调用跟踪记录”,定义为记录所跟踪目标程序模块中某个待测函数调用信息、并缓存在函数调用跟踪组件中供监视线程检测超时或死锁的一个数据对象,其中主要记录了待测函数的进入时间点、已进入运行后的滞留时间长度、所属的程序模块信息(如模块名称)、特征信息(如函数名称)。
待检测函数之间完全存在嵌套调用的可能性,即,一个待测函数func1进入运行后、尚未退出前,另一个待测函数func2进入运行。对于此种情形,由于当前线程中func1的函数调用跟踪记录尚未被删除,就会面临被func2的函数跟踪记录覆写、从而丢失func1的函数调用跟踪记录的风险。为解决此问题,定义线程内函数调用跟踪记录链为线程中多个嵌套进行的待测函数调用所生成函数调用跟踪记录的一个链式数据结构,其中待测函数的函数调用跟踪记录在链表中的先后顺序与待测函数嵌套调用的先后顺序相同。每个可能运行到的线程均拥有一个线程内函数调用跟踪记录链。
上述各部件,函数调用跟踪组件包装对象和函数调用跟踪代理对象位于待测函数所属之待跟踪程序模块中。函数调用跟踪记录由线程内函数调用跟踪记录链对象的链式结构所管理,而线程内函数调用跟踪记录链对象又保存在函数调用跟踪组件为待测目标程序进程的各线程创建的一个线程内函数调用跟踪记录链对象集合中。
函数调用跟踪组件包装对象主要管理函数调用跟踪组件的加载、启动、调用、停止、释放,主要通过操作系统API、及函数调用跟踪组件本身输出的用户API对函数调用跟踪组件的运行进行控制管理,同时负责将函数调用跟踪组件输出的用户API调用信息(如函数指针方式)复制给函数调用跟踪代理对象进行静态化保存(静态化指保存数据不受单个函数调用跟踪代理对象创建和销毁的影响)。
函数调用跟踪代理对象则通过调用函数调用跟踪组件包装对象复制而来的API函数指针,将待测函数进入、退出调用动作传递到函数调用跟踪组件中,驱动函数调用跟踪组件查找当前线程对应的线程内函数调用跟踪记录链对象,并在其中建立函数调用跟踪记录。
进一步,函数调用跟踪组件加载初始化步骤如下:
Step11.待测目标程序模块在完成加载、初始化后,通过函数调用跟踪组件包装对象加载函数调用跟踪组件,并驱动其进行初始化启动。
Step12.函数调用跟踪组件在初始化过程中首先创建一个“线程内函数调用跟踪记录链对象的集合”数据结构。
Step13.函数调用跟踪组件在初始化过程的最后,创建一独立工作线程,用于对运行了待测函数的各个线程所对应的线程内函数调用跟踪记录链对象进行扫描检测。
进一步,待测函数进入跟踪步骤如下:
Step21.待测函数进入运行后,创建“函数调用跟踪代理对象”。
Step22.“函数调用跟踪代理对象”创建时自动调用构造函数,并在其中调用“函数调用跟踪组件”输出的记录待测函数进入动作的API函数,将待测函数进入动作和待测函数信息一并传递到函数调用跟踪组件中。
Step23.函数调用跟踪组件通过系统API获取当前运行线程的id标识符,并根据此id标示符,从“线程内函数调用跟踪记录链对象”的集合对象中检索出对应的“线程内函数调用跟踪记录链对象”。
Step24.为当前待测函数生成新的函数调用跟踪记录对象,同时在其中保存外部通过函数调用参数逐层传入的待测函数信息。
Step25.将新创建的函数调用跟踪记录对象,插入到对应的线程内函数调用跟踪记录链的头部,作为当前线程的最近一次函数调用跟踪记录。
Step26.最终,将新创建的函数调用跟踪记录对象的持有信息(如对象地址)逐层返回给“函数调用跟踪代理对象”保存,留待待测函数退出时使用。
进一步,待测函数退出跟踪步骤如下:
Step31.待测函数退出运行前,并无论在函数内部何处返回,受益于编程语言提供的特性,“函数调用跟踪代理对象”将被自动销毁,其析构函数自动发生调用,通过在其析构函数内执行“函数调用跟踪组件”输出的记录待测函数退出动作的API函数,将曾保存的函数调用跟踪记录对象的持有信息传递到函数调用跟踪组件中。
Step32.函数调用跟踪组件通过系统API获取当前运行线程的id标识符,并根据此id标识符,从“线程内函数调用跟踪记录链对象”的集合对象中检索出当前线程的“线程内函数调用跟踪记录链对象”。
Step33.验证当前线程内函数调用跟踪记录链的头部所保存函数调用跟踪记录对象,与外部传入函数调用跟踪记录对象是否匹配、相同。若不一致,则输出错误信息,直接转向Step35,否则继续。
Step34.移除“线程内函数调用跟踪记录链”头部引用的最近一次函数调用跟踪记录。
Step35.结束。
进一步,函数调用超时与死锁检测步骤如下:
Step41.将函数调用跟踪组件中所有的“线程内函数调用跟踪记录链对象”(可使用多种数据结构实现集合对象)的引用信息(如对象地址)转存为一个一维数组,以供遍历。
Step42.遍历该一维数组,设置当前数组访问下标为1,从第一个元素开始。
Step43.判断当前数组访问下标,若超出数组长度,则转向Step49,否则继续。
Step44.根据当前数组访问下标,取得一维数组中对应的“线程内函数调用跟踪记录链对象”。
Step45.对“线程内函数调用跟踪记录链对象”的已运行时间进行计数增加1,表示增加一个时间单位(可自定义单位时间大小,建议值为1秒,此时间单位对应前述独立监视线程的扫描时间周期)。
Step46.将“线程内函数调用跟踪记录链对象”的已运行时间与第一级时间计数阈值(建议3秒以内,除非阻塞或高密度计算,否则大部分编程良好的函数不需要运行超出1秒以上的时间)进行大小判断,也为超时判断,若超出,则输出函数运行超时日志信息进行提示。
Step47.将“线程内函数调用跟踪记录链对象”的已运行时间与第二级时间计数阈值(足够大值,建议30秒左右,以排除部分计算负担较重、耗时较久的函数影响)(死锁判断)进行大小判断,若超出,则输出函数运行死锁日志信息进行提示。
Step48.当前数组访问下标自增1,返回Step43。
Step49.结束循环。
以上发明中,涉及到同一数据结构被多个线程共享操作的,需参照公知技术,施以加锁操作进行多线程同步。
进一步地,由于待测函数进入跟踪步骤和待测函数退出跟踪步骤中,需要根据当前运行线程的id标识符,从“线程内函数调用跟踪记录链对象”的集合对象中检索出对应的“线程内函数调用跟踪记录链对象”。采用本领域公知常用的一些容器类来实现该集合对象,将会面临多线程同步、复杂或低效的查找算法带来的性能损失,对于将会内嵌到大量待测函数中运行的代码而言,将会显著影响整个程序的性能。
主流操作系统中线程id一般定义为4字节的整数,从检索性能和线程访问隔离的角度考虑,定义下标从0到0xFFFFFFFF对应线程id的一维简单数组来实现上述集合对象对于直接随机查找而言是性能最优的。但在实际中,这将会占用至少2G以上的内存空间,并且大部分空间不会被使用到,空间利用率极低,因此并不现实。
本发明采取组合方法解决此问题。由于线程id虽一般定义为4字节的整数,但实际运行的进程中,线程的数量并不多,大部分线程id一般表现为4位整数(即最高位为千位)。因此,“线程内函数调用跟踪记录链对象”的集合对象可以使用两级数据结构进行管理。对于4位整数以内的线程id对应的线程内函数调用跟踪记录链对象采用简单数组管理,对于4位整数以上的线程id对应的线程内函数调用跟踪记录链对象采用本领域公知常用的一些复杂容器类(一般为平衡二叉树、哈希表等映射类)管理。
本发明通过采用上述技术方案,与现有技术相比,具有如下优点:
(1)通过C++对象创建、销毁分别自动调用构造和析构函数的特性,简化建立函数调用跟踪机制所需的代码,对所需跟踪的函数只需一行代码即可获得跟踪特性的支持;
(2)采用的独立自主线程判断机制,不影响软件原有的运行逻辑,可在软件主线程和工作线程陷入死锁时,正常执行跟踪工作;
(3)在检测到函数死锁故障前不打印不必要的日志,可避免不必要的性能损失。
(4)采用此方法,通过增加设一个判断函数调用超时的时间阈值,还可以用于检测函数调用是否存在设计不希望的运行性能问题。
附图说明
图1是本发明的实施例的静态结构示意图。
图2是本发明的实施例中则当某线程运行至FunctionC时,其对应线程内函数调用跟踪记录链状态。
具体实施方式
现结合附图和具体实施方式对本发明进一步说明。
作为一个具体的实施例,如图1所示,本发明的一种基于运行期动态跟踪的函数执行超时与死锁检测的方法,该方法主要包括:
A、在待检测函数的运行入口插入一段跟踪代码,区分待检测函数当前运行所属线程,分别为不同的线程建立相应的数据结构,登记各个进入运行的待检测函数的特征信息,并返回此特征信息对象的引用数据给待测函数临时保存,对于存在嵌套调用关系的待测函数,则按进入运行的先后次序创建一个链表数据结构对多个待检测函数特征信息进行保存;
B、在待测函数的运行出口也插入对应的跟踪代码,根据A中曾返回的特征信息对象的访问信息,将函数特征信息对象从当前运行所属线程的数据结构中取消登记;
C、在进程中创建一独立监视线程,以一个单位时间周期(推荐值为1秒,避免对程序运行造成太多额外运行开销)内扫描各个线程中由于一个或多个待测函数进入运行产生的特征信息对象,并对其进行时间计数递增,对于时间计数超过第一级时间计数阈值(建议3秒以内,除非阻塞或高密度计算,否则大部分编程良好的函数不需要运行超出1秒以上的时间)的待测函数,则表示其运行时间偏长,即超时,而对于时间计数超过第二级时间计数阈值的待测函数,则表示其运行时间过长,存在死锁可能。
为使上述技术方案的应用足够简便,本发明对其进行封装,封装为一个可复用的函数调用跟踪组件(在Windows系统中以DLL体现)。
该函数调用跟踪组件将实现上述A、B、C三部分的主要有效实现,其中主要包括:为多个线程各自独立维护、跟踪待测函数运行的数据结构,以及一个独立的监视线程。
对应地,为应用此发明的待检测程序提供函数调用跟踪组件包装对象、函数调用跟踪代理对象来运用函数调用跟踪组件。
上述函数调用跟踪组件包装对象定义为,控制函数调用跟踪组件在待测目标程序中进行加载、启动、调用、停止、释放活动的代理类对象,为待测目标程序使用函数调用跟踪组件提供对象级别的管理。
将上述创建函数调用跟踪组件包装对象(以下用CRTErrTrackerDllWrapper指代,Wrapper class of dynamic link library runtime-error tracker)、函数调用跟踪代理对象(以下用CFunctionTracker指代)、函数调用跟踪记录(以下用CFuncInvokeRecord指代)、线程内函数调用跟踪记录链(以下CFuncInvokeRecordChain指代)、函数调用跟踪监视器模块(以下用CMonitor指代):
1、创建该函数调用跟踪组件包装对象(以下用CRTErrTrackerDllWrapper指代,Wrapper class of dynamic link library runtime-error tracker)
对于将要使用本发明中这一机制的程序模块,不论是EXE可执行程序还是DLL动态链接库,均可在程序模块中定义一个函数调用跟踪组件包装对象类型的全局变量,以方便对函数调用跟踪组件DLL模块的进行加载、初始化、启动、停止、释放等管理动作。
CRTErrTrackerDllWrapper的定义布局如下:
上述函数调用跟踪代理对象定义为,接收函数调用信息,通过函数调用跟踪组件的API接口将待测目标函数信息、进入和退出动作传递进函数调用跟踪组件中以供超时或死锁判断的代理类对象。
2、创建函数调用跟踪代理对象(以下用CFunctionTracker指代,Proxyclass of function-invoke tracker)
为了在目标程序模块中使用函数调用跟踪组件DLL来检测待测目标函数运行中可能存在的问题,需要按一定的顺序调用函数调用跟踪组件DLL导出的两个函数:EnterFunctionTracker、LeaveFunctionTracker。而CFunctionTracker则是为了使调用更加方便做出的封装。
该对象使用在待测函数刚进入运行时声明局部变量的方式创建,使用对象的构造、析构函数完成对函数调用跟踪组件DLL导出函数的调用。其创建伪代码如下:
CFunctionTracker的定义布局如下:
函数调用跟踪组件中为多个线程独立维护、跟踪待测函数运行的数据结构具体定义如下。
将上述A部分中提到的待检测函数特征信息对象,正式约定为“函数调用跟踪记录”,定义为记录所跟踪目标程序模块中某个待测函数调用信息、并缓存在函数调用跟踪组件中供监视线程检测超时或死锁的一个数据对象,其中主要记录了待测函数的进入时间点、已进入运行后的滞留时间长度、所属的程序模块信息(如模块名称)、特征信息(如函数名称)。
3、函数调用跟踪记录(以下用CFuncInvokeRecord指代)
CFuncInvokeRecord是函数调用跟踪组件DLL内部记录对待测函数调用动作的数据记录对象,主要保存待测函数的信息(如名称)、运行滞留时间。当函数调用跟踪组件DLL通过导出函数接收到待测函数进入运行的通知时创建,接收到待测函数退出运行的通知时销毁。其中的运行滞留时间,由函数调用跟踪监视器模块进行计数和超时判断。
CFuncInvokeRecord的定义布局如下:
其中,紧邻外层被测函数跟踪记录,指的是待测函数外部还存在其他嵌套调用的被测函数时,外层最近的一个被测函数对应生成的函数跟踪记录。
如上述伪代码所示,如果FunctionA和FunctionB均被CFunctionTracker对象进行跟踪时,FunctionB对应的函数跟踪记录中的“紧邻外层被测函数跟踪记录”即是FunctionA对应的函数跟踪记录。
而函数运行滞留时间,指的是待测函数在进入运行后、退出运行前,对应的函数跟踪记录所生存的时间。该时间变量由函数调用跟踪监视器模块CMonitor中的独立扫描线程进行计时累加。
待测程序模块名称和待测函数名称,则是函数调用跟踪监视器模块CMonitor在为待测函数建立对应的函数调用跟踪记录时,由待测模块通过函数调用跟踪代理对象的构造函数逐层传入保存的两个数据。其目的在于,当函数调用跟踪监视器模块CMonitor中的独立扫描线程检测到函数运行超时后,能具体地输出故障模块和故障函数的信息。
待检测函数之间完全存在嵌套调用的可能性,即,一个待测函数func1进入运行后、尚未退出前,另一个待测函数func2进入运行。对于此种情形,由于当前线程中func1的函数调用跟踪记录尚未被删除,就会面临被func2的函数跟踪记录覆写、从而丢失func1的函数调用跟踪记录的风险。为解决此问题,定义线程内函数调用跟踪记录链为线程中多个嵌套进行的待测函数调用所生成函数调用跟踪记录的一个链式数据结构,其中待测函数的函数调用跟踪记录在链表中的先后顺序与待测函数嵌套调用的先后顺序相同。每个可能运行到的线程均拥有一个线程内函数调用跟踪记录链。
4、线程内函数调用跟踪记录链
考虑到,多个待测函数间可能存在嵌套的调用,因此,函数调用跟踪记录CFuncInvokeRecord需要建立对应嵌套、链式的结构进行数据保存。又考虑到,任何一个待测函数均有可能被多个线程调用,因此,为了避免发生跟踪混乱,需要为每一个线程都维护一个链式结构,此数据结构定义为“线程内函数调用跟踪记录链”。
CFuncInvokeRecordChain的定义布局如下:
假设FunctionA、FunctionB、FunctionC有如下嵌套关系:
则当某线程运行至FunctionC时,其对应线程内函数调用跟踪记录链状态如图2所示。
上述各部件,函数调用跟踪组件包装对象和函数调用跟踪代理对象位于待测函数所属之待跟踪程序模块中。函数调用跟踪记录由线程内函数调用跟踪记录链的链式结构所管理,而线程内函数调用跟踪记录链对象又保存在函数调用跟踪组件为待测目标程序进程的各线程创建的一个线程内函数调用跟踪记录链对象集合中。
函数调用跟踪组件包装对象主要管理函数调用跟踪组件的加载、启动、调用、停止、释放,主要通过操作系统API、及函数调用跟踪组件本身输出的用户API对函数调用跟踪组件的运行进行控制管理,同时负责将函数调用跟踪组件输出的用户API调用信息(如函数指针方式)复制给函数调用跟踪代理对象进行静态化保存(静态化指保存数据不受单个函数调用跟踪代理对象创建和销毁的影响)。
函数调用跟踪代理对象则通过调用函数调用跟踪组件包装对象复制而来的API函数指针,将待测函数进入、退出调用动作传递到函数调用跟踪组件中,驱动函数调用跟踪组件查找当前线程对应的线程内函数调用跟踪记录链对象,并在其中建立函数调用跟踪记录。
5、函数调用跟踪监视器模块的定义以及组成部件
函数调用跟踪监视器模块是函数调用跟踪组件DLL中的核心控制类,主要完成对“线程内函数调用跟踪记录链”对象的创建、管理,以及一个扫描函数调用跟踪记录中函数运行滞留时间是否超时的独立线程的创建、管理。
CMonitor的定义布局如下:
其中,扫描线程函数ScanThreadFunc,主要完成以1秒钟为间隔的定时扫描,扫描作为参数传入的函数调用跟踪监视器模块CMonitor对象中各“线程内函数调用跟踪记录链”对象CFuncInvokeRecordChain的当前跟踪记录(CurRecord_Pointer所指向的函数调用跟踪记录)中的函数运行滞留时间StayTime,对于StayTime超出预设值(如5秒以上)的,将待测程序模块名称和待测函数名称输出为文件日志,不超出预设值的,对StayTime增加1,进行函数运行累加计时。
启动工作函数Init_Startup主要目的是通过将扫描线程函数作为参数传递给系统调用(此为公知技术),启动独立扫描线程。对应地,结束工作函数Stop_Release的设计目的是停止扫描线程。
线程内函数调用跟踪记录链对象数组FuncInvokeRecordChain_Array和线程内函数调用跟踪记录链对象映射FuncInvokeRecordChain_Map,设计用于对“线程内函数调用跟踪记录链对象”进行分级管理。
在操作系统中,由于线程Id标识符往往设计为4个字节的整数。线程内函数调用跟踪记录链对象数组FuncInvokeRecordChain_Array设计为用于访问进程中实际运行的、其线程Id标识符小于某个整数值MaxThreadId的线程所对应的线程内函数调用跟踪记录链对象的性能最优方法,线程Id标识符用作访问数组元素的下标值。
绝大部分情况下,进程中实际运行的线程,其线程Id标识符极少超出9999四位数字的表达范围,因此,本实施例中MaxThreadId取值20000。
对于特殊情况下,线程Id标识符超出20000的线程所对应的线程内函数调用跟踪记录链对象则在线程内函数调用跟踪记录链对象映射FuncInvokeRecordChain_Map中进行管理。此时,其根据线程Id标识符获取线程内函数调用跟踪记录链对象的访问性能低于上述数组查找方式。
(1)加载初始化该函数调用跟踪组件;其中,加载初始化该函数调用跟踪组件包括以下步骤:
Step11.待测目标程序模块在完成加载、初始化后,通过函数调用跟踪组件包装对象加载函数调用跟踪组件,并驱动其进行初始化启动。具体过程如下。
分步骤111:调用进程创建函数调用跟踪组件包装对象,调用其组件启动运行函数Load_Init_Startup;
分步骤112:在前述Load_Init_Startup函数中,函数调用跟踪组件包装对象CRTErrTrackerDllWrapper负责通过Windows API函数LoadLibrary,将函数调用跟踪组件DLL(后续可用RTErrTracker.dll指代)加载到待测目标进程中运行,并获得LoadLibary返回的函数调用跟踪组件模块句柄保存至DLLModule中。若同一进程中,前面已有其他程序模块通过函数调用跟踪组件包装对象执行过函数调用跟踪组件的加载,则转分步骤四(这一点可由系统调用LoadLibrary保证),相反,则继续分步骤113;
分步骤113:函数调用跟踪组件DLL首次加载到进程空间中后,通过声明一个函数调用跟踪监视器类型的全局变量的方式,创建函数调用跟踪监视器模块,其定义见前述表达,同时将函数调用跟踪监视器模块的初始化状态赋值为假(False),代表尚未初始化;
分步骤114:函数调用跟踪组件包装对象以之前返回的函数调用跟踪组件模块句柄DLLModule为参数,通过GetProcAddress系统调用(此处为公知技术),取得函数调用跟踪组件DLL导出函数的函数指针进行保存,分别是以下四个导出函数:函数调用跟踪组件DLL启动运行函数(以下用DLLInit_Startup指代)、函数调用跟踪组件DLL结束运行函数(以下用DLLStop_Release指代)、待测目标函数进入运行跟踪函数(以下用EnterFunctionTracker指代)、待测目标函数退出运行跟踪函数(以下用LeaveFunctionTracker指代)。将DLLInit_Startup、DLLStop_Release这两个导出函数的函数指针赋值保存至自身Init_Startup_FuncPointer、Stop_Release_FuncPointer这两个静态成员中。将EnterFunctionTracker、LeaveFunctionTracker这两个导出函数的函数指针赋值给函数调用跟踪代理对象CFunctionTracker的EnterFunctionTracker_FunctionPointer、LeaveFunctionTracker_FunctionPointer这两个静态成员保存。同时,将待测程序模块的名称字符串赋值给CFunctionTracker的静态成员ModuleName;
分步骤115:函数调用跟踪组件包装对象CRTErrTrackerDllWrapper通过前面赋值保存的函数指针Init_Startup_FuncPointer对函数调用跟踪组件DLL导出的DLLInit_Startup函数进行调用(通过函数指针调用函数是一项公知技术);
分步骤116:在函数调用跟踪组件DLL的启动运行函数DLLInit_Startup中,对函数调用跟踪监视器模块进行初始化,若其初始化状态为真(True),则结束,否则,继续下一步骤;
分步骤117:将函数调用跟踪组件DLL中函数调用跟踪监视器模块的初始化状态设置为真(True)。
Step12.函数跟踪组件在初始化过程中首先创建一个“线程内函数调用跟踪记录链对象的集合”数据结构。
进一步具体地,由函数调用跟踪监视器模块CMonitor负责创建线程内函数调用跟踪记录链对象数组FuncInvokeRecordChain_Array和线程内函数调用跟踪记录链对象映射FuncInvokeRecordChain_Map对线程内函数调用跟踪记录链对象按线程Id进行分级管理,以实现“线程内函数调用跟踪记录链对象的集合”这一数据结构。
进一步地,线程内函数调用跟踪记录链对象的分级管理规则为:线程内函数调用跟踪记录链对象数组FuncInvokeRecordChain_Array用于存储线程Id小于20000的线程所对应的线程内函数调用跟踪记录链对象,线程内函数调用跟踪记录链对象映射FuncInvokeRecordChain_Map用于存储线程Id大于20000的线程所对应的线程内函数调用跟踪记录链对象。
Step13.函数调用跟踪组件在初始化过程的最后,创建一独立工作线程,用于对运行了待测函数的各个线程所对应的线程内函数调用跟踪记录链对象进行扫描检测。
具体地,由函数调用跟踪监视器模块CMonitor负责启动其内部的主动扫描线程ScanThreadFunc(通过向系统调用_beginthreadex传入线程函数启动线程是一项公知技术);
(2)待测函数进入跟踪步骤
Step21.待测函数进入运行后,创建“函数调用跟踪代理对象”。
具体为,待测函数进入运行后,立即创建一个函数调用跟踪代理对象,并向其传递待测函数的基本信息,本实施例中仅传入待测函数的名称字符串,作为函数调用跟踪代理对象的构造函数的参数。此处的特殊作法是,用作参数的待测函数的函数名字符串是使用常量字符串的方式编译进待测程序模块(指操作系统中编译为可执行代码的程序模块,例如windows操作系统下的exe、dll文件)的静态存储区中。例如,形如CFunctionTrackertracker(“FunctionA”)的代码中,字符串“FunctionA”将被编译进静态存储区,当待测程序模块被加载后,该字符串常量将始终存在,有着固定的访问地址,可以直接复制字符串常量的首地址进行保存使用,如此可以避免在函数调用跟踪组件DLL内部的函数调用跟踪记录对象中重新分配内存进行字符串内容的拷贝复制,可以显著地提升性能;
Step22.“函数调用跟踪代理对象”创建时自动调用构造函数,并在其中调用“函数调用跟踪组件”输出的记录待测函数进入动作的API函数,将待测函数进入动作和待测函数信息一并传递到函数调用跟踪组件中。
具体为,函数调用跟踪代理对象在构造时(指编译器自动生成的代码调用对象的构造函数这一过程,为公知技术),通过函数调用跟踪代理对象的待测目标函数进入运行跟踪函数指针EnterFunctionTracker_FuncPointer,调用函数调用跟踪组件DLL的导出函数EnterFunctionTracker,调用时将函数调用跟踪代理对象在前面步骤中复制保存的待测程序模块名称ModuleName和构造函数传入的待测函数名称字符串FuncName作为参数传入;
Step23.函数调用跟踪组件通过系统API获取当前运行线程的id标识符,并根据此id标示符,从“线程内函数调用跟踪记录链对象”的集合对象中检索出对应的“线程内函数调用跟踪记录链对象”。具体过程如下。
分步骤231,函数调用跟踪组件DLL运行待测目标函数进入运行跟踪函数EnterFunctionTracker,获取当前执行线程的线程Id标识符。若线程Id标识符小于等于20000,则以线程Id标识符为下标,从函数调用跟踪监视器模块的线程内函数调用跟踪记录链对象数组中取出对应的线程内函数调用跟踪记录链对象,结束,否则,继续进入分步骤232;
分步骤232:对于线程Id标识符大于20000,从函数调用跟踪监视器模块的线程内函数调用跟踪记录链对象映射Map中查找取出对应的线程内函数调用跟踪记录链对象(基于Map的Key-value查找属公知技术,一般基于平衡二叉树或哈希表技术),若查找失败,则表示所需对象尚未创建,可新建一个线程内函数调用跟踪记录链对象加入函数调用跟踪监视器模块的线程内函数调用跟踪记录链对象映射Map对象中。
Step24.为当前待测函数生成新的函数调用跟踪记录对象,同时在其中保存外部通过函数调用参数逐层传入的待测函数信息。具体过程如下。
分步骤241:创建一个新的函数调用跟踪记录,其定义如前所述,将步骤二中传入的待测程序模块名称ModuleName和构造函数传入的待测函数名称字符串FuncName对应的字符串首指针分别分别复制到函数调用跟踪记录的待测程序模块名称ModuleName和待测函数名称FuncName这两个成员变量上进行保存。
分步骤242:将新创建的函数调用跟踪记录的函数运行滞留时间StayTime初始化赋值为0;
Step25.将新创建的函数调用跟踪记录对象,插入到对应的线程内函数调用跟踪记录链的头部,作为当前线程的最近一次函数调用跟踪记录。具体过程如下。
分步骤251:检查当前线程内函数调用跟踪记录链对象的当前跟踪记录指针引用CurRecord_Poniter,如为空(NULL),则直接转分步骤253,否则,继续下一步骤;
分步骤252:将当前线程内函数调用跟踪记录链对象的当前跟踪记录指针引用CurRecord_Poniter赋值复制给Step24中新创建的函数调用跟踪记录的紧邻外层被测函数跟踪记录PrevTracker_Pointer;
分步骤253:将步骤五中新创建的函数调用跟踪记录的指针引用赋值复制给当前线程内函数调用跟踪记录链对象的当前跟踪记录指针引用CurRecord_Poniter;
Step26.最终,将新创建的函数调用跟踪记录对象的持有信息(如对象地址)逐层返回给“函数调用跟踪代理对象”保存,留待待测函数退出时使用。
具体指,将新创建函数调用跟踪记录的指针引用,返回给Step21中的函数调用跟踪代理对象保存,具体保存在其内部跟踪记录对象指针InternalTracker_Pointer中。
(3)待测函数退出跟踪步骤:
Step31.待测函数退出运行前,并无论在函数内部何处返回,受益于编程语言提供的特性,“函数调用跟踪代理对象”将被自动销毁,其析构函数自动发生调用,通过在其析构函数内执行“函数调用跟踪组件”输出的记录待测函数退出动作的API函数,将曾保存的函数调用跟踪记录对象的持有信息传递到函数调用跟踪组件中。具体过程如下:
分步骤311:待测函数正常或异常退出后,函数调用跟踪代理对象将析构(指编译器自动生成的代码调用对象的析构函数这一过程,为公知技术)销毁;
分步骤312:函数调用跟踪代理对象在析构时,通过函数调用跟踪代理对象的待测目标函数退出运行跟踪函数指针LeaveFunctionTracker_FuncPointer,调用函数调用跟踪组件DLL的导出函数LeaveFunctionTracker,同时传递待测函数进入跟踪步骤十返回给函数调用跟踪代理对象的内部跟踪记录对象指针InternalTracker_Pointer保存的函数调用跟踪记录指针引用作为参数,调入函数调用跟踪组件中运行;
Step32.函数调用跟踪组件通过系统API获取当前运行线程的id标识符,并根据此id标识符,从“线程内函数调用跟踪记录链对象”的集合对象中检索出当前线程的“线程内函数调用跟踪记录链对象”。
进一步更佳的实现是,根据传入的函数调用跟踪记录的所属的线程内函数调用跟踪记录链对象指针引用Chain_Pointer,直接获取当前线程内函数调用跟踪记录链对象;
Step33.验证当前线程内函数调用跟踪记录链的头部所保存函数调用跟踪记录对象,与外部传入函数调用跟踪记录对象是否匹配、相同。若不一致,则输出错误信息,直接转向Step35,否则继续。
Step34.移除“线程内函数调用跟踪记录链”头部引用的最近一次函数调用跟踪记录。具体过程如下。
分步骤341:将当前线程内函数调用跟踪记录的紧邻外层被测函数跟踪记录PrevTracker_Pointer赋值复制给当前线程内函数调用跟踪记录链对象的当前跟踪记录指针引用CurRecord_Poniter,将传入的函数调用跟踪记录从当前线程内函数调用跟踪记录链上移除;
分步骤342:检查当前线程内函数调用跟踪记录链对象的当前跟踪记录指针引用CurRecord_Poniter目前是否为空(NULL),如为空,转分步骤344,否则继续下一步骤;
分步骤343:将传入移除的函数调用跟踪记录的函数运行滞留时间StayTime,累加到当前线程内函数调用跟踪记录链对象的当前跟踪记录指针引用CurRecord_Poniter所指向的函数调用跟踪记录的函数运行滞留时间StayTime上;
分步骤344:检查传入移除的函数调用跟踪记录的函数运行滞留时间StayTime,如超出预设值,则可输出运行超时日志用于分析;
分步骤345:从内存中销毁、删除传入移除的函数调用跟踪记录后,结束;
Step35.结束。
(4)函数调用超时与死锁检测步骤:
Step41.将函数调用跟踪组件中所有的“线程内函数调用跟踪记录链对象”(可使用多种数据结构实现集合对象)的引用信息(如对象地址)转存为一个一维数组,以供遍历。具体过程如下。
分步骤411:函数调用跟踪监视器模块的主动监视线程创建后进入运行,判断调用进程是否要求退出,如果要求退出,则转分步骤412,否则转分步骤413;
分步骤412:对所有的线程内函数调用跟踪记录链执行清理动作,释放资源后,退出主动监视线程,结束;
分步骤413:主动监视线程执行系统调用Sleep(1000),主动睡眠1秒钟,防止函数过度占用CPU资源;
分步骤414:主动监视线程睡眠时间到,由操作系统主动唤醒后,重新从ini配置文件中,读取函数运行超时、运行死锁判断的时间阈值,赋值给函数调用跟踪组件DLL模块中的全局整型变量timeout_max_value、deadlock_max_value,可起到配置刷新的效果,可支持运行时实时修改设置;
分步骤415:主动监视线程扫描所有函数调用跟踪监视器模块中通过数组和映射管理的所有线程内函数调用跟踪记录链对象,检查其中存储的当前跟踪记录指针引用CurRecord_Poniter是否为空(NULL),若非空,则将其输出到一个临时数组temp_chain_array中;
Step42.遍历该一维数组,设置当前数组访问下标为1,从第一个元素开始。
具体指,设置循环整型变量index为0,从一维数组temp_chain_array的第一个元素开始循环访问。
Step43.判断当前数组访问下标,若超出数组长度,则转向Step49,否则继续。
具体指,判断整型变量index小于临时数组temp_chain_array的元素个数count的表达式是否为真,若非真,则结束循环,直接结束,若为真,继续下一步骤;
Step44.根据当前数组访问下标,取得一维数组中对应的“线程内函数调用跟踪记录链对象”。
具体指,从临时数组temp_chain_array中获取下表为index的线程内函数调用跟踪记录链对象,通过CurRecord_Poniter字段取得当前跟踪记录。
Step45.对“线程内函数调用跟踪记录链对象”的已运行时间进行计数增加1,表示增加一个时间单位(可自定义单位时间大小,建议值为1秒,此时间单位对应前述独立监视线程的扫描时间周期)。
具体指,对当前跟踪记录的函数运行滞留时间StayTime递增1。
Step46.将“线程内函数调用跟踪记录链对象”的已运行时间与第一级时间计数阈值(建议3秒以内,除非阻塞或高密度计算,否则大部分编程良好的函数不需要运行超出1秒以上的时间)进行大小判断,也为超时判断,若超出,则输出函数运行超时日志信息进行提示。
具体指,判断StayTime小于函数调用跟踪组件DLL模块中的全局整型变量timeout_max_value的表达式是否为真,若非真,则输出当前跟踪记录的待测程序模块名称ModuleName和待测函数名称FuncName(同时附加“运行超时”字符串信息)到文件日志中。
Step47.将“线程内函数调用跟踪记录链对象”的已运行时间与第二级时间计数阈值(足够大值,建议30秒左右,以排除部分计算负担较重、耗时较久的函数影响)(死锁判断)进行大小判断,若超出,则输出函数运行死锁日志信息进行提示。
具体指,判断StayTime小于函数调用跟踪组件DLL模块中的全局整型变量deadlock_max_value的表达式是否为真,若非真,则输出当前跟踪记录的待测程序模块名称ModuleName和待测函数名称FuncName(同时附加“运行可能死锁”字符串信息)到文件日志中。
Step48.当前数组访问下标自增1,返回Step43。
具体指,整型变量index递增1,转向step43。
Step49.结束循环。
实施例中,主要给出了判断函数运行超时的方法,本发明又认为函数的足够长时间运行超时可视作存在死锁的可能。因此,本发明通过设定一个足够大的函数运行超时判断时间阈值(可定义为函数运行死锁判断时间阈值),结合超时判断方法来检测可能的死锁,而非通过严格的死锁逻辑条件来判断。
以上发明中,涉及到同一数据结构被多个线程共享操作的,需参照公知技术,施以加锁操作进行多线程同步。
但进一步地,由于步骤(2)和步骤(3)中,需要根据当前运行线程的id标识符,从“线程内函数调用跟踪记录链对象”的集合对象中检索出对应的“线程内函数调用跟踪记录链对象”。采用本领域公知常用的一些容器类来实现该集合对象,将会面临多线程同步、复杂或低效的查找算法带来的性能损失,对于将会内嵌到大量待测函数中运行的代码而言,将会显著影响整个程序的性能。
主流操作系统中线程id一般定义为4字节的整数,从检索性能和线程访问隔离的角度考虑,定义下标从0到0xFFFFFFFF对应线程id的一维简单数组来实现上述集合对象对于直接随机查找而言是性能最优的。但在实际中,这将会占用至少2G以上的内存空间,并且大部分空间不会被使用到,空间利用率极低,因此并不现实。
本发明采取组合方法解决此问题。由于线程id虽一般定义为4字节的整数,但实际运行的进程中,线程的数量并不多,大部分线程id一般表现为4位整数(即最高位为千位)。因此,“线程内函数调用跟踪记录链对象”的集合对象可以使用两级数据结构进行管理。对于4位整数以内的线程id对应的线程内函数调用跟踪记录链对象采用简单数组管理,对于4位整数以上的线程id对应的线程内函数调用跟踪记录链对象采用本领域公知常用的一些复杂容器类(一般为平衡二叉树、哈希表等映射类)管理。
尽管结合优选实施方案具体展示和介绍了本发明,但所属领域的技术人员应该明白,在不脱离所附权利要求书所限定的本发明的精神和范围内,在形式上和细节上可以对本发明做出各种变化,均为本发明的保护范围。
Claims (6)
1.一种基于运行期动态跟踪的函数执行超时与死锁检测方法,其特征在于:该方法主要包括三个部分:
A、在待检测函数的运行入口插入一段跟踪代码,区分待检测函数当前运行所属线程,分别为不同的线程建立相应的数据结构,登记各个进入运行的待检测函数的特征信息,并返回此特征信息对象的引用数据给待测函数临时保存。对于存在嵌套调用关系的待测函数,则按进入运行的先后次序创建一个链表数据结构对多个待检测函数特征信息进行保存,
B、在待测函数的运行出口插入对应的跟踪代码,根据A中曾返回的特征信息对象的访问信息,将函数特征信息对象从当前运行所属线程的数据结构中取消登记;
C、在进程中创建一独立监视线程,以一个单位时间周期内扫描各个线程中由于一个或多个待测函数进入运行产生的特征信息对象,并对其进行时间计数递增,对于时间计数超过第一级时间计数阈值的待测函数,则表示其运行时间偏长,即超时,而对于时间计数超过第二级时间计数阈值的待测函数,则表示其运行时间过长,存在死锁可能。
2.根据权利要求1所述的一种基于运行期动态跟踪的函数执行超时与死锁检测方法,其特征在于:封装一个可复用的函数调用跟踪组件,该函数调用跟踪组件实现上述A、B、C三部分,其主要包括:为多个线程各自独立维护、跟踪待测函数运行的数据结构,以及一个独立的监视线程,对应地,为应用此发明的待检测程序提供函数调用跟踪组件包装对象、函数调用跟踪代理对象来运用函数调用跟踪组件,
上述函数调用跟踪组件包装对象定义为,控制函数调用跟踪组件在待测目标程序中进行加载、启动、调用、停止、释放活动的代理类对象,为待测目标程序使用函数调用跟踪组件提供对象级别的管理;
上述函数调用跟踪代理对象定义为,接收函数调用信息,通过函数调用跟踪组件的API接口将待测目标函数信息、进入和退出动作传递进函数调用跟踪组件中以供超时或死锁判断的代理类对象;
函数调用跟踪组件中为多个线程独立维护、跟踪待测函数运行的数据结构具体定义如下:
将所述待检测函数特征信息对象定义为“函数调用跟踪记录”,其记录所跟踪目标程序模块中某个待测函数调用信息、并缓存在函数调用跟踪组件中供监视线程检测超时或死锁的一个数据对象,其中主要记录了待测函数的进入时间点、已进入运行后的滞留时间长度、所属的程序模块信息(如模块名称)、特征信息;
定义线程内函数调用跟踪记录链为线程中多个嵌套进行的待测函数调用所生成函数调用跟踪记录的一个链式数据结构,其中待测函数的函数调用跟踪记录在链表中的先后顺序与待测函数嵌套调用的先后顺序相同;每个可能运行到的线程均拥有一个线程内函数调用跟踪记录链;
函数调用跟踪组件包装对象和函数调用跟踪代理对象位于待测函数所属之待跟踪程序模块中,函数调用跟踪记录由线程内函数调用跟踪记录链的链式结构所管理,而线程内函数调用跟踪记录链对象又保存在函数调用跟踪组件为待测目标程序进程的各线程创建的一个线程内函数调用跟踪记录链对象集合中,
函数调用跟踪组件包装对象主要管理函数调用跟踪组件的加载、启动、调用、停止、释放,主要通过操作系统API、及函数调用跟踪组件本身输出的用户API对函数调用跟踪组件的运行进行控制管理,同时负责将函数调用跟踪组件输出的用户API调用信息复制给函数调用跟踪代理对象进行静态化保存;
函数调用跟踪代理对象则通过调用函数调用跟踪组件包装对象复制而来的API函数指针,将待测函数进入、退出调用动作传递到函数调用跟踪组件中,驱动函数调用跟踪组件查找当前线程对应的线程内函数调用跟踪记录链对象,并在其中建立函数调用跟踪记录。
3.根据权利要求2所述的一种基于运行期动态跟踪的函数执行超时与死锁检测方法,其特征在于:函数调用跟踪组件加载初始化步骤如下:
Step11.待测目标程序模块在完成加载、初始化后,通过函数调用跟踪组件包装对象加载函数调用跟踪组件,并驱动其进行初始化启动;
Step12.函数调用跟踪组件在初始化过程中首先创建一个“线程内函数调用跟踪记录链对象的集合”对象;
Step13.函数调用跟踪组件在初始化过程的最后,创建一独立工作线程,用于对运行了待测函数的各个线程所对应的线程内函数调用跟踪记录链对象进行扫描检测。
4.根据权利要求2所述的一种基于运行期动态跟踪的函数执行超时与死锁检测方法,其特征在于:待测函数进入跟踪步骤如下:
Step21.待测函数进入运行后,创建“函数调用跟踪代理对象”;
Step22.“函数调用跟踪代理对象”创建时自动调用构造函数,并在其中调用“函数调用跟踪组件”输出的记录待测函数进入动作的API函数,将待测函数进入动作和待测函数信息一并传递到函数调用跟踪组件中;
Step23.函数调用跟踪组件通过系统API获取当前运行线程的id标识符,并根据此id标示符,从“线程内函数调用跟踪记录链对象”的集合对象中检索出对应的“线程内函数调用跟踪记录链对象”;
Step24.为当前待测函数生成新的函数调用跟踪记录对象,同时在其中保存外部通过函数调用参数逐层传入的待测函数信息;
Step25.将新创建的函数调用跟踪记录对象,插入到对应的线程内函数调用跟踪记录链的头部,作为当前线程的最近一次函数调用跟踪记录;
Step26.最终,将新创建的函数调用跟踪记录对象的持有信息逐层返回给“函数调用跟踪代理对象”保存,留待待测函数退出时使用。
5.根据权利要求2所述的一种基于运行期动态跟踪的函数执行超时与死锁检测方法,其特征在于:待测函数退出跟踪步骤如下:
Step31.待测函数退出运行前,并无论在函数内部何处返回,“函数调用跟踪代理对象”将被自动销毁,其析构函数自动发生调用,通过在其析构函数内执行“函数调用跟踪组件”输出的记录待测函数退出动作的API函数,将曾保存的函数调用跟踪记录对象的持有信息传递到函数调用跟踪组件中;
Step32.函数调用跟踪组件通过系统API获取当前运行线程的id标识符,并根据此id标识符,从“线程内函数调用跟踪记录链对象”的集合对象中检索出当前线程的“线程内函数调用跟踪记录链对象”;
Step33.验证当前线程内函数调用跟踪记录链的头部所保存函数调用跟踪记录对象,与外部传入函数调用跟踪记录对象是否匹配、相同。若不一致,则输出错误信息,直接转向Step35,否则继续;
Step34.移除“线程内函数调用跟踪记录链”头部引用的最近一次函数调用跟踪记录;
Step35.结束。
6.根据权利要求2所述的一种基于运行期动态跟踪的函数执行超时与死锁检测方法,其特征在于:函数调用超时与死锁检测步骤如下:
Step41.将函数调用跟踪组件中所有的“线程内函数调用跟踪记录链对象”(可使用多种数据结构实现集合对象)的引用信息(如对象地址)转存为一个一维数组,以供遍历;
Step42.遍历该一维数组,设置当前数组访问下标为1,从第一个元素开始;
Step43.判断当前数组访问下标,若超出数组长度,则转向Step49,否则继续;
Step44.根据当前数组访问下标,取得一维数组中对应的“线程内函数调用跟踪记录链对象”;
Step45.对“线程内函数调用跟踪记录链对象”的已运行时间进行计数增加1,表示增加一个时间单位;
Step46.将“线程内函数调用跟踪记录链对象”的已运行时间与第一级时间计数阈值进行大小判断,若超出,则输出函数运行超时日志信息进行提示;
Step47.将“线程内函数调用跟踪记录链对象”的已运行时间与第二级时间计数阈值(死锁判断)进行大小判断,若超出,则输出函数运行死锁日志信息进行提示;
Step48.当前数组访问下标自增1,返回Step43;
Step49.结束循环。
Priority Applications (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN201510118723.6A CN104636259B (zh) | 2015-03-18 | 2015-03-18 | 一种基于运行期动态跟踪的函数执行超时与死锁检测方法 |
Applications Claiming Priority (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN201510118723.6A CN104636259B (zh) | 2015-03-18 | 2015-03-18 | 一种基于运行期动态跟踪的函数执行超时与死锁检测方法 |
Publications (2)
Publication Number | Publication Date |
---|---|
CN104636259A true CN104636259A (zh) | 2015-05-20 |
CN104636259B CN104636259B (zh) | 2020-05-22 |
Family
ID=53215043
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN201510118723.6A Active CN104636259B (zh) | 2015-03-18 | 2015-03-18 | 一种基于运行期动态跟踪的函数执行超时与死锁检测方法 |
Country Status (1)
Country | Link |
---|---|
CN (1) | CN104636259B (zh) |
Cited By (14)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN105260174A (zh) * | 2015-09-16 | 2016-01-20 | 北京航空航天大学 | 实时Java虚拟机中基于等价类的对象内存状态的记录跟踪方法 |
CN105740080A (zh) * | 2016-03-11 | 2016-07-06 | 深圳市茁壮网络股份有限公司 | 一种程序卡死检测方法及处理器 |
CN106506279A (zh) * | 2016-11-11 | 2017-03-15 | 盛科网络(苏州)有限公司 | 网络死锁状态检测方法及装置 |
CN107168807A (zh) * | 2016-03-08 | 2017-09-15 | 慧荣科技股份有限公司 | 函式分析方法与内存装置 |
CN107179975A (zh) * | 2016-03-09 | 2017-09-19 | 北京京东尚科信息技术有限公司 | 监控方法和装置 |
WO2017167062A1 (zh) * | 2016-03-30 | 2017-10-05 | 阿里巴巴集团控股有限公司 | 一种应用程序接口死锁监控方法和装置 |
CN107590015A (zh) * | 2017-09-11 | 2018-01-16 | 北京京东尚科信息技术有限公司 | 监测主线程的阻塞的方法和装置 |
CN108959069A (zh) * | 2018-06-11 | 2018-12-07 | 北京奇艺世纪科技有限公司 | 一种函数运行的追踪方法和装置 |
CN110069358A (zh) * | 2019-04-18 | 2019-07-30 | 彩讯科技股份有限公司 | 调用链跟踪分析方法、装置、电子设备及存储介质 |
CN110659195A (zh) * | 2018-06-28 | 2020-01-07 | 武汉斗鱼网络科技有限公司 | 一种安卓程序崩溃定位方法、存储介质、电子设备及系统 |
CN111538599A (zh) * | 2020-04-23 | 2020-08-14 | 杭州涂鸦信息技术有限公司 | 一种基于linux的多线程死锁问题定位方法及系统 |
CN112363779A (zh) * | 2020-11-25 | 2021-02-12 | 王志平 | 一种动态链接程序的安全控制方法 |
CN113032209A (zh) * | 2021-03-09 | 2021-06-25 | 北京百度网讯科技有限公司 | 运行监控方法、装置、服务器及介质 |
WO2022155937A1 (zh) * | 2021-01-23 | 2022-07-28 | 王志平 | 一种动态链接程序的安全控制方法 |
Citations (4)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN1605987A (zh) * | 2004-11-17 | 2005-04-13 | 中兴通讯股份有限公司 | 一种多线程系统中实现实时监控各线程状态的方法 |
CN1629821A (zh) * | 2003-12-19 | 2005-06-22 | 华为技术有限公司 | 一种多线程处理器线程死锁检测的方法及其系统 |
CN1811719A (zh) * | 2006-02-22 | 2006-08-02 | 福建师范大学 | 一种单线程微处理器的死锁检测与干预方法 |
US20120079483A1 (en) * | 2010-09-29 | 2012-03-29 | Nec Laboratories America, Inc. | Computer Implemented Automatic Lock Insertion in Concurrent Programs |
-
2015
- 2015-03-18 CN CN201510118723.6A patent/CN104636259B/zh active Active
Patent Citations (4)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN1629821A (zh) * | 2003-12-19 | 2005-06-22 | 华为技术有限公司 | 一种多线程处理器线程死锁检测的方法及其系统 |
CN1605987A (zh) * | 2004-11-17 | 2005-04-13 | 中兴通讯股份有限公司 | 一种多线程系统中实现实时监控各线程状态的方法 |
CN1811719A (zh) * | 2006-02-22 | 2006-08-02 | 福建师范大学 | 一种单线程微处理器的死锁检测与干预方法 |
US20120079483A1 (en) * | 2010-09-29 | 2012-03-29 | Nec Laboratories America, Inc. | Computer Implemented Automatic Lock Insertion in Concurrent Programs |
Cited By (20)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN105260174B (zh) * | 2015-09-16 | 2018-09-28 | 北京航空航天大学 | 实时Java虚拟机中基于等价类的对象内存状态的记录跟踪方法 |
CN105260174A (zh) * | 2015-09-16 | 2016-01-20 | 北京航空航天大学 | 实时Java虚拟机中基于等价类的对象内存状态的记录跟踪方法 |
CN107168807B (zh) * | 2016-03-08 | 2021-09-03 | 慧荣科技股份有限公司 | 函数分析方法与内存装置 |
CN107168807A (zh) * | 2016-03-08 | 2017-09-15 | 慧荣科技股份有限公司 | 函式分析方法与内存装置 |
CN107179975A (zh) * | 2016-03-09 | 2017-09-19 | 北京京东尚科信息技术有限公司 | 监控方法和装置 |
CN105740080B (zh) * | 2016-03-11 | 2019-02-22 | 深圳市茁壮网络股份有限公司 | 一种程序卡死检测方法及处理器 |
CN105740080A (zh) * | 2016-03-11 | 2016-07-06 | 深圳市茁壮网络股份有限公司 | 一种程序卡死检测方法及处理器 |
WO2017167062A1 (zh) * | 2016-03-30 | 2017-10-05 | 阿里巴巴集团控股有限公司 | 一种应用程序接口死锁监控方法和装置 |
TWI738722B (zh) * | 2016-03-30 | 2021-09-11 | 香港商阿里巴巴集團服務有限公司 | 應用程式介面死鎖監控方法和裝置 |
CN106506279A (zh) * | 2016-11-11 | 2017-03-15 | 盛科网络(苏州)有限公司 | 网络死锁状态检测方法及装置 |
CN106506279B (zh) * | 2016-11-11 | 2019-12-13 | 盛科网络(苏州)有限公司 | 网络死锁状态检测方法及装置 |
CN107590015A (zh) * | 2017-09-11 | 2018-01-16 | 北京京东尚科信息技术有限公司 | 监测主线程的阻塞的方法和装置 |
CN108959069A (zh) * | 2018-06-11 | 2018-12-07 | 北京奇艺世纪科技有限公司 | 一种函数运行的追踪方法和装置 |
CN110659195A (zh) * | 2018-06-28 | 2020-01-07 | 武汉斗鱼网络科技有限公司 | 一种安卓程序崩溃定位方法、存储介质、电子设备及系统 |
CN110069358A (zh) * | 2019-04-18 | 2019-07-30 | 彩讯科技股份有限公司 | 调用链跟踪分析方法、装置、电子设备及存储介质 |
CN111538599A (zh) * | 2020-04-23 | 2020-08-14 | 杭州涂鸦信息技术有限公司 | 一种基于linux的多线程死锁问题定位方法及系统 |
CN112363779A (zh) * | 2020-11-25 | 2021-02-12 | 王志平 | 一种动态链接程序的安全控制方法 |
WO2022155937A1 (zh) * | 2021-01-23 | 2022-07-28 | 王志平 | 一种动态链接程序的安全控制方法 |
CN113032209A (zh) * | 2021-03-09 | 2021-06-25 | 北京百度网讯科技有限公司 | 运行监控方法、装置、服务器及介质 |
CN113032209B (zh) * | 2021-03-09 | 2024-05-28 | 北京百度网讯科技有限公司 | 运行监控方法、装置、服务器及介质 |
Also Published As
Publication number | Publication date |
---|---|
CN104636259B (zh) | 2020-05-22 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
CN104636259A (zh) | 一种基于运行期动态跟踪的函数执行超时与死锁检测方法 | |
US8225291B2 (en) | Automated detection of application performance bottlenecks | |
KR101942518B1 (ko) | 2 패스 자동화된 애플리케이션 인스트루먼테이션 | |
US9129056B2 (en) | Tracing values of method parameters | |
CN103440457B (zh) | 基于进程模拟的二进制程序分析系统 | |
US10599652B2 (en) | Database query time estimator | |
Feitosa et al. | Investigating the effect of design patterns on energy consumption | |
US11029930B2 (en) | Code optimization conversations for connected managed runtime environments | |
Kunkel et al. | The SIOX architecture–coupling automatic monitoring and optimization of parallel I/O | |
Borzacchiello et al. | Memory models in symbolic execution: key ideas and new thoughts | |
US20160092174A1 (en) | Execution guards in dynamic programming | |
US8516448B2 (en) | Identifying interpreted programs through class loading sequences | |
CN105243023A (zh) | 并行运行时错误检测方法 | |
Singh et al. | Parallel chopped symbolic execution | |
Butrovich et al. | Tastes great! Less filling! High performance and accurate training data collection for self-driving database management systems | |
CN112130848B (zh) | 一种面向便笺式存储器的带宽感知循环分块优化方法、编译系统、设备及存储介质 | |
CN111259042A (zh) | 一种动态查询方法及系统 | |
Jibaja et al. | Deferred gratification: Engineering for high performance garbage collection from the get go | |
Chen et al. | Pattern-based circular reference detection in Python | |
Zimmerle et al. | Reactive-based complex event processing: An overview and energy consumption analysis of cep. js | |
Fuad et al. | Static Analysis, Code Transformation and Runtime Profiling for Self-healing. | |
KR20200095241A (ko) | 리소스 모니터링을 이용한 소프트웨어 리팩토링 방법 및 장치 | |
Katsaragakis et al. | A memory footprint optimization framework for Python applications targeting edge devices | |
US11947531B1 (en) | Copy avoidance via static analysis for DBMS querying | |
CN116775040B (zh) | 实现代码疫苗的插桩方法及基于代码疫苗的应用测试方法 |
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 |