一篇了解V8 CPU Profiler 的实现

网站建设3年前 (2022)发布
45 0 0

开始分析前,先来看一下对象的关系图(从左往右看),这个对后面的分析比较重要,因为他们的关系错综复杂。,下面开始分析。入口对象为 CpuProfiler。CpuProfiler 负责管理多个 CpuProfile,而我们进行一次 CPU Profile 时对应的就是一个 CpuProfile 对象。首先看一下 CpuProfiler 的构造函数。,构造函数的逻辑比较简单,只是进行一些初始化操作。然后看一下当开始采集时的逻辑。,首先调了 CpuProfilesCollection 对象的 StartProfiling。,StartProfiling 会新建一个 CpuProfile 来表示一次 CPU Profile 操作,从 CpuProfilesCollection 命名也可以看出,该对象用于管理多个 CPU Profile 对象。新建完后执行 StartProcessorIfNotStarted 开始 Profile。,接着看采集线程 SamplingEventsProcessor 的实现。,从继承关系可以看到创建 SamplingEventsProcessor 对象会创建一个线程对象,但是这个线程不会自动启动,需要主动调用 Start 函数,具体调用时机在 StartSynchronously 函数中,接下来看一下 SamplingEventsProcessor 的构造函数。,SamplingEventsProcessor 对象中新建了一个 CpuSampler 对象,这是非常核心的对象,它负责采集。来看一下 CpuSampler 的 Start 函数做了什么。,非 Windows 平台采用的是定时给主线程发送 SIGPROF 信号进行采样,所以需要先注册信号处理函数,看一下 IncreaseSamplerCount。,注册 SIGPROF 信号的处理函数是 HandleProfilerSignal,我们一会再分析。注册完信号把 Sampler 对象加入到 SamplerManager。SamplerManager 以线程 id 为键,值是一个 Sample 队列。注册完信号和初始化完 Sampler 后,就等待线程发送的定时信号。接下来看一下采集线程的逻辑。,发送完信号后看一下信号处理函数的逻辑。,看一下 FillRegisterState。,拿到当前执行上下文后调用 DoSample 开始采集。,DoSample 找出需要采集的 sampler,然后执行其 SampleStack 函数。,SampleStack 首先从循环队列里找到一个空闲的项,然后记录采集的信息在里面,接着看 sample->Init。,sample->Init 通过 GetStackSample 采集信息。,至此采集的逻辑就分析完了,数据保存在 SamplingEventsProcessor 对象的 ticks_buffer_ 字段中。在 Profile 线程中会进行处理,前面提到的 ProcessOneSample 函数。,我们只关注 SymbolizeAndAddToProfiles。,symbolizer_ 负责把底层的数据转成 JS 成的信息。,SymbolizeTickSample 的逻辑非常复杂,不过我们大概能看得出来它的作用。转换完之后需要通知所有的 profile 对象。,接着看 profile->AddPath。,Profile 数据就被记录到 samples_ 字段了。最后通过 Stop 停止采集时,就会返回这个 Profile 对象,从而拿到 Profile 的数据。

© 版权声明

相关文章