可可西

Android Studio Profiler(CPU : System Trace)

Android Studio 中 System Trace(系统跟踪)功能(注:为命令行工具systrace的GUI版本),是用于记录一段时间内的设备活动,用于提升App的性能。

不同于函数跟踪(如 Java Method 或 C/C++ Function Trace),System Trace 跟踪的是系统级的内容,如CPU各核心调度,SurfaceFlinger、VSync(垂直同步)、BufferQueue。

通过收集系统事件和App逻辑中插入的自定义事件的组合数据,在排查性能问题时 (例如UI卡顿或功耗过高)就会显得十分有用。

 

实时显示App及各线程上的CPU占用

 

自定义Trace System Calls设置

点击下拉菜单中的“Edit Configurations...”,查看Trace System Calls的设置

 

创建自定义的Trace System Calls

 

使用自定义的Trace System Calls来Record

 

录制一段System Trace Recording

 

点击保存按钮,可将当前记录数据保存到名为:cpu-perfetto-20220530T102357.trace的文件中

 

快捷键:

操作 键盘快捷键 鼠标快捷键
Zoom In(放大) W 按住Ctrl键,正向滚动鼠标
Zoom Out(缩小) S 按住Ctrl键,反向滚动鼠标
Pan Left(向左拖动) A 按住空格键,向右拖动鼠标
Pand Right(向右拖动) D 按住空格键,向左拖动鼠标

右上角工具栏说明:

:扩大CPU Usage轴上的选中范围

:缩小CPU Usage轴上的选中范围

:选择整个CPU Usage轴

当选中某个线程或event时,会出现“Clear thread/event selection”的点击按钮

 

Display和CPU cores

SurfaceFlinger:每个灰块表示OnMessageReceived的执行时长

VSYNC(垂直同步):0,1之间的切换

BufferQueue:0,1之间的切换

 

小米10共有8个CPU核心,Frequency(频率)分别如下:

CPU核心 Frequency(频率)
CPU0 1.8 GHz
CPU1
CPU2
CPU3
CPU4 2.4 GHz
CPU5
CPU6
CPU7 2.8 GHz

 

CPU核的轴线上各个色块表示不同进程的线程的执行时长和序列。除了当前Profile进程的线程外,还有其他进程的线程,如下:

其他进程 线程
/system/bin/traced_probes traced_probes
/system/bin/surfaceflinger surfaceflinger
/system/bin/surfaceflinger app
/vendor/bin/hw/vendor.qti.hardware.display.composer-server HwBinder:854_2
/system/bin/audioserver FastMixer

自定义事件

在App中使用Trace API来插入自定义事件进行埋点来形成的CallStack来详细跟进线程逻辑的执行过程。

 

UE自定义事件宏

/** UnrealEngine\Engine\Source\Runtime\Core\Public\HAL\PlatformMisc.h **/
#define SCOPED_NAMED_EVENT(Name, Color)\
    FScopedNamedEventStatic ANONYMOUS_VARIABLE(NamedEvent_##Name##_)(Color, NAMED_EVENT_STR(#Name));\
    TRACE_CPUPROFILER_EVENT_SCOPE(Name);

#define SCOPED_NAMED_EVENT_FSTRING(Text, Color)\
    FScopedNamedEvent ANONYMOUS_VARIABLE(NamedEvent_)(Color, *Text);\
    TRACE_CPUPROFILER_EVENT_SCOPE_TEXT(*Text);

#define SCOPED_NAMED_EVENT_TCHAR(Text, Color)\
    FScopedNamedEvent ANONYMOUS_VARIABLE(NamedEvent_)(Color, Text);\
    TRACE_CPUPROFILER_EVENT_SCOPE_TEXT(Text);

#define SCOPED_NAMED_EVENT_TEXT(Text, Color)\
    FScopedNamedEventStatic ANONYMOUS_VARIABLE(NamedEvent_)(Color, NAMED_EVENT_STR(Text));\
    TRACE_CPUPROFILER_EVENT_SCOPE_STR(Text);

#define SCOPED_NAMED_EVENT_F(Format, Color, ...)\
    FScopedNamedEvent ANONYMOUS_VARIABLE(NamedEvent_)(Color, *FString::Printf(Format, __VA_ARGS__));\
    TRACE_CPUPROFILER_EVENT_SCOPE_TEXT(*FString::Printf(Format, __VA_ARGS__));

 

UE中插入的自定义事件

/** UnrealEngine\Engine\Source\Runtime\Launch\Private\LaunchEngineLoop.cpp **/
void FEngineLoop::Tick() 
{
    // ... ...
    #if ENABLE_NAMED_EVENTS
    TCHAR IndexedFrameString[32] = { 0 };
    const TCHAR* FrameString = nullptr;
    if (UE_TRACE_CHANNELEXPR_IS_ENABLED(CpuChannel))
    {
        FrameString = TEXT("FEngineLoop");
    }
    else
    {
#if PLATFORM_LIMIT_PROFILER_UNIQUE_NAMED_EVENTS
        FrameString = TEXT("FEngineLoop");
#else
        FCString::Snprintf(IndexedFrameString, 32, TEXT("Frame %d"), CurrentFrameCounter);
        FrameString = IndexedFrameString;
#endif
    }
    SCOPED_NAMED_EVENT_TCHAR(FrameString, FColor::Red);
#endif
    // ... ...
}

/** UnrealEngine\Engine\Source\Runtime\Launch\Private\LaunchEngineLoop.cpp **/
static inline void BeginFrameRenderThread(FRHICommandListImmediate& RHICmdList, uint64 CurrentFrameCounter)
{
    // ... ...
    FString FrameString = FString::Printf(TEXT("Frame %d"), CurrentFrameCounter);
#if ENABLE_NAMED_EVENTS
#if PLATFORM_LIMIT_PROFILER_UNIQUE_NAMED_EVENTS
    FPlatformMisc::BeginNamedEvent(FColor::Yellow, TEXT("Frame"));
#else
    FPlatformMisc::BeginNamedEvent(FColor::Yellow, *FrameString);
#endif
#endif // ENABLE_NAMED_EVENTS
    // ... ...
}

/** UnrealEngine\Engine\Source\Runtime\Core\Private\GenericPlatform\GenericPlatformProcess.cpp **/
bool FPThreadEvent::Wait(uint32 WaitTime, const bool bIgnoreThreadIdleStats /*= false*/)
{
    // ... ...
    SCOPED_NAMED_EVENT(EventWait, FColor::Red);
    // ... ...
}

/** UnrealEngine\Engine\Source\Runtime\Core\Private\Async\TaskGraph.cpp **/
class FTaskGraphImplementation : public FTaskGraphInterface
{
    virtual void WaitUntilTasksComplete(const FGraphEventArray& Tasks, ENamedThreads::Type CurrentThreadIfKnown = ENamedThreads::AnyThread) final override
    {
        // ... ...
        SCOPED_NAMED_EVENT(WaitUntilTasksComplete, FColor::Red);
        // ... ...
    }
};
    
/** UnrealEngine\Engine\Source\Runtime\Engine\Private\LevelTick.cpp **/
void UWorld::Tick( ELevelTick TickType, float DeltaSeconds )
{
    // ... ...
    SCOPED_NAMED_EVENT(UWorld_Tick, FColor::Orange);
    // ... ...
}
    
/** UnrealEngine\Engine\Source\Runtime\Slate\Private\Framework\Application\SlateApplication.cpp **/
void FSlateApplication::DrawWindows()
{
    SCOPED_NAMED_EVENT_TEXT("Slate::DrawWindows", FColor::Magenta);
    PrivateDrawWindows();
}

/** UnrealEngine\Engine\Source\Runtime\RHI\Private\RHICommandList.cpp **/
class FExecuteRHIThreadTask
{
    void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
    {
        // ... ...
        SCOPED_NAMED_EVENT(RHIThreadExecute, FColor::Red);
        // ... ...
    }
};

 

线程上的CPU状态和自定义事件CallStack

 

注1:最上面的轴线上,灰色块为线程的Sleep状态,黄色块为线程的Waiting状态,绿色块为线程的Running状态

注2:下方则为线程内部自定义事件CallStack

 

RenderThread

 

RHIThread

 

选中线程

选中线程的选中区域的Summary

 

选中线程的选中区域的Top Down

 

选中线程的选中区域的Flame Chart

注:Flame Chart即火焰图,会对同名的栈帧进行合并显示

 

选中线程的选中区域的Bottom Up

 

选中线程的Events

 

All threads

所有线程的选中区域的Summary

 

所有线程的选中区域的Top Down

 

所有线程的选中区域的Flame Chart

注:Flame Chart即火焰图,会对同名的栈帧进行合并显示

 

所有线程的选中区域的Bottom Up

 

参考

Android Studio 中 System Trace 的新增功能

Android SystemTrace实战

 

posted on 2022-06-02 01:07  可可西  阅读(3414)  评论(0编辑  收藏  举报

导航