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 的新增功能