Chromium源码阅读(9):了解事件跟踪TRACE_EVENT与第三方库Perfetto

Perfetto - System profiling, app tracing and trace analysis

Perfetto 是一个用于性能检测和跟踪分析的生产级开源堆栈。它提供用于记录系统级和应用级跟踪的服务和库、本机 + Java 堆分析、使用 SQL 分析跟踪的库以及用于可视化和探索多 GB 跟踪的基于 Web 的 UI。

See https://perfetto.dev/docs or the /docs/ directory for documentation.
在这里插入图片描述

Perfetto 的设计初衷是取代 chrome://tracing 基础设施的内部结构。Chromium 中的跟踪及其内部结构基于所有主要平台(Android、CrOS、Linux、MacOS、Windows)上的 Perfetto 代码库。系统范围跟踪采用相同的基于服务的架构,但内部使用的是 Chromium Mojo IPC 系统,而不是 Perfetto 自己的 UNIX 套接字。
在这里插入图片描述
使用chrome://tracing分析chromium性能:
在这里插入图片描述
性能记录的数据大部分通过TRACE_EVENT宏记录:在这里插入图片描述
在这里插入图片描述

TRACE_EVENT紧跟的数字表示arg的数量。

Perfetto库快速入门

步骤 1:定义事件类别

首先,在一个头文件中(例如 my_tracing.h),定义您要追踪的事件类别:

// File: my_tracing.h
#include "perfetto.h"
PERFETTO_DEFINE_CATEGORIES(perfetto::Category("base"),perfetto::Category("v8"),perfetto::Category("cc"));

步骤 2:初始化静态存储

然后,在一个 .cc 文件中(例如 my_tracing.cc),包含您的类别定义头文件,并初始化静态存储:

// File: my_tracing.cc#include "my_tracing.h"
PERFETTO_TRACK_EVENT_STATIC_STORAGE();

步骤 3:注册轨迹事件并记录事件

最后,在您的应用程序启动时注册轨迹事件。注册之后,您可以使用 TRACE_EVENT 宏记录事件:

// File: main.cc#include "my_tracing.h"int main() {perfetto::TrackEvent::Register();// 记录一个基本的轨迹事件,仅有事件名称。TRACE_EVENT("category", "MyEvent");// 记录一个带有调试注解的轨迹事件(最多两个)。TRACE_EVENT("category", "MyEvent", "parameter", 42);// 记录一个带有强类型参数的轨迹事件。TRACE_EVENT("category", "MyEvent", [](perfetto::EventContext ctx) {ctx.event()->set_foo(42);ctx.event()->set_bar(.5f);});return 0;
}

注意事项

  • 轨迹事件必须一致地嵌套。例如,不允许出现以下情况:

    TRACE_EVENT_BEGIN("a", "bar", ...);
    TRACE_EVENT_BEGIN("b", "foo", ...);
    TRACE_EVENT_END("a");  // 必须先结束 "foo" 事件,再结束 "bar" 事件。
    TRACE_EVENT_END("b");
    

多命名空间支持(高级用法)

如果您的程序使用多个轨迹事件命名空间,则需要为每个命名空间分别进行类别和轨迹事件的注册。使用宏 PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE 来实现一个程序中多个轨迹事件类别集的支持。

每个编译单元可以恰好在一个轨迹事件命名空间中。如果需要,这允许整个程序使用多个轨迹事件数据源和类别列表。

总体数据流:

// The track event library consists of the following layers and components. The
// classes the internal namespace shouldn't be considered part of the public
// API.
//                    .--------------------------------.
//               .----|  TRACE_EVENT                   |----.
//      write   |     |   - App instrumentation point  |     |  write
//      event   |     '--------------------------------'     |  arguments
//              V                                            V
//  .----------------------------------.    .-----------------------------.
//  | TrackEvent                       |    | EventContext                |
//  |  - Registry of event categories  |    |  - One track event instance |
//  '----------------------------------'    '-----------------------------'
//              |                                            |
//              |                                            | look up
//              | is                                         | interning ids
//              V                                            V
//  .----------------------------------.    .-----------------------------.
//  | internal::TrackEventDataSource   |    | TrackEventInternedDataIndex |
//  | - Perfetto data source           |    | - Corresponds to a field in |
//  | - Has TrackEventIncrementalState |    |   in interned_data.proto    |
//  '----------------------------------'    '-----------------------------'
//              |                  |                         ^
//              |                  |       owns (1:many)     |
//              | write event      '-------------------------'
//              V
//  .----------------------------------.
//  | internal::TrackEventInternal     |
//  | - Outlined code to serialize     |
//  |   one track event                |
//  '----------------------------------'
//

Perfetto库中用到的有趣的C++技术

性能

一个事件记录库除了能强大的记录各种事件之外,其性能非常重要。

Perfetto 库通过多种方式来保证事件记录的性能:

  1. 条件记录:Perfetto 允许用户定义不同的事件类别,并且可以动态地控制哪些类别的事件是活跃的。通过这种方式,只有在特定类别被启用时才记录事件,这减少了不必要的性能开销。

  2. 编译时优化:通过使用宏(如 TRACE_EVENT)和内联函数,Perfetto 允许编译器在编译时进行优化。例如,如果一个事件类别未被激活,相关的代码(包括参数的计算)可能会被完全移除。

  3. 高效的参数处理:Perfetto 宏在记录事件之前会检查事件是否开启,从而避免在跟踪被禁用的情况下评估事件参数。这意味着参数的计算只有在事件实际记录的时候才会发生。

  4. 线程局部存储:Perfetto 通常使用线程局部存储(TLS)来减少在跨线程共享数据时所需的同步开销。

  5. 增量状态:Perfetto 的跟踪数据源可以维护一种增量状态,这样某些信息(如字符串)就不需要在每个事件中重复记录,而是仅在首次出现时记录,之后通过索引引用,从而减少数据量。

  6. 避免锁竞争:Perfetto 设计了一套避免锁竞争的机制,例如使用无锁队列和缓冲区来收集事件数据,从而最小化线程间同步的需要。

  7. 序列化性能:Perfetto 的内部序列化代码高度优化,确保将事件数据快速转换为可以写入磁盘的格式时的效率。

  8. 内存管理:Perfetto 通过精心设计的内存管理策略来避免不必要的内存分配和复制。例如,它可以使用环形缓冲区来重复使用内存,以及通过字符串和其他数据的内部化减少内存使用。

  9. 低开销的上下文切换:对于跟踪点的插入,Perfetto 努力确保上下文切换的开销最小,即使是在高度并发的环境中。

  10. 分层设计:Perfetto 的设计允许开发者在不同层次上使用其 API,以便他们可以选择最合适他们需要的性能和灵活性的平衡点。

举例来说,通过constexpr + 特例化模板,实现将事件在编译期进行分类:


// By default no statically defined categories are dynamic, but this can be
// overridden with PERFETTO_DEFINE_TEST_CATEGORY_PREFIXES.
template <typename... T>
constexpr bool IsDynamicCategory(const char*) {return false;
}// Explicitly dynamic categories are always dynamic.
constexpr bool IsDynamicCategory(const ::perfetto::DynamicCategory&) {return true;
}

通过编译期计算,将分类字符串转换为分类索引:

// At compile time, turns a category name represented by a static string into an
// index into the current category registry. A build error will be generated if
// the category hasn't been registered or added to the list of allowed dynamic
// categories. See PERFETTO_DEFINE_CATEGORIES.
#define PERFETTO_GET_CATEGORY_INDEX(category)                                \PERFETTO_TRACK_EVENT_NAMESPACE::internal::kConstExprCategoryRegistry.Find( \category,                                                              \::PERFETTO_TRACK_EVENT_NAMESPACE::internal::IsDynamicCategory(category))

kConstExprCategoryRegistry.Find的实现如下:

 // --------------------------------------------------------------------------// Trace point support// --------------------------------------------------------------------------//// (The following methods are used by the track event trace point// implementation and typically don't need to be called by other code.)// At compile time, turn a category name into an index into the registry.// Returns kInvalidCategoryIndex if the category was not found, or// kDynamicCategoryIndex if |is_dynamic| is true or a DynamicCategory was// passed in.static constexpr size_t kInvalidCategoryIndex = static_cast<size_t>(-1);static constexpr size_t kDynamicCategoryIndex = static_cast<size_t>(-2);constexpr size_t Find(const char* name, bool is_dynamic) const {return CheckIsValidCategoryIndex(FindImpl(name, is_dynamic));}constexpr size_t Find(const DynamicCategory&, bool) const {return kDynamicCategoryIndex;}constexpr bool ValidateCategories(size_t index = 0) const {return (index == category_count_)? true: IsValidCategoryName(categories_[index].name)? ValidateCategories(index + 1): false;}private:// TODO(skyostil): Make the compile-time routines nicer with C++14.constexpr size_t FindImpl(const char* name,bool is_dynamic,size_t index = 0) const {return is_dynamic ? kDynamicCategoryIndex: (index == category_count_)? kInvalidCategoryIndex: StringEq(categories_[index].name, name)? index: FindImpl(name, false, index + 1);}

可见全都是constexpr。

减少模板实例化数量:

这个技术来自这段代码的DecayEventNameType:

#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, ...) \PERFETTO_INTERNAL_SCOPED_TRACK_EVENT(                      \category, ::perfetto::internal::DecayEventNameType(name), ##__VA_ARGS__)// Convert all static strings of different length to StaticString to avoid
// unnecessary template instantiations.
inline ::perfetto::StaticString DecayEventNameType(const char* name) {return ::perfetto::StaticString{name};
}

代码解释如下:

  • 函数体非常简单,仅包含一个返回语句。它创建了一个 perfetto::StaticString 类型的临时对象,并使用传入的 name 参数初始化该对象。花括号 {name} 是列表初始化的一种形式,在这里等同于使用传统的构造函数语法 perfetto::StaticString(name)

  • inline 关键字表示这个函数应当被内联。内联函数的作用是告诉编译器在编译期间尽可能地将函数调用替换为函数体本身,这样可以消除函数调用的开销,但会增加编译后程序的大小。内联主要用于小型且频繁调用的函数。

  • 注释说明了函数的目的:将不同长度的静态字符串转换为 StaticString 类型,以避免在模板实例化时产生不必要的开销。在模板编程中,如果模板函数或类针对每一个不同的字符串长度都实例化一个版本,将会导致代码膨胀。通过使用 StaticString 类型统一接口,可以减少这种类型的模板实例化,从而减少编译后的代码量和可能的运行时开销。

这段代码通过减少模板实例化来提高程序的效率。

结语

默认情况下,Perfetto在 Chromium 中以进程内模式工作,仅记录 Chromium 进程发出的数据。在 Android 上(以及在 Linux 上,如果停用 Chromium 沙盒),跟踪可以在混合进程内+系统模式下工作,将特定于 Chrome 的跟踪事件与 Perfetto 系统事件相结合。

Perfetto给chromium开发者一个性能分析的利器。另外利用查看Trace的事件,也是分析Chromium工作原理和主要流程的利器!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3246561.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

基础动态规划题目基础动态规划题目

目录 题目1&#xff1a; P1216 [USACO1.5] [IOI1994]数字三角形 Number Triangles 代码示例&#xff1a; 题目2&#xff1a; Common Subsequence 代码示例 题目3 &#xff1a;最长上升子序列 最长不下降子序列 最长上升子序列oj答案 题目1&#xff1a; P1216 [USACO1.5]…

【ffmpeg命令基础】过滤处理

文章目录 前言过滤处理的介绍两种过滤类型简单滤波图简单滤波图是什么简单滤波示例 复杂滤波图复杂滤波是什么区别示例 总结 前言 FFmpeg是一款功能强大的开源音视频处理工具&#xff0c;广泛应用于音视频的采集、编解码、转码、流化、过滤和播放等领域。1本文将重点介绍FFmpe…

软件确认测试报告包括的内容和作用简析,专业软件测试公司推荐

软件确认测试是指验证软件是否符合特定需求和规范的过程。它是软件开发生命周期中的一个关键环节&#xff0c;旨在确保软件的功能、性能、稳定性和安全性达到预期的标准&#xff0c;确认测试报告则是整个确认测试过程的总结和归纳&#xff0c;是对软件质量和稳定性的全面评估。…

5分钟教会你夸克网盘批量转存分享,夸克网盘批量保存,付详细图文

大家好&#xff0c;我是徐师兄&#xff0c;今天为大家带来的是夸克网盘批量转存分享&#xff0c;夸克网盘批量保存&#xff0c;付详细图文教程。 前言 夸克网盘批量保存工具下载 前段日子折腾夸克网盘的时候&#xff0c;找来了好多的资源&#xff0c;但这些资源链接非常多&a…

Transformer超详细解读

论文&#xff1a;Attention Is All You Need 作者&#xff1a;Ashish Vaswani, Noam Shazeer, Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N. Gomez, Lukasz Kaiser, Illia Polosukhin 机构&#xff1a;Google Brain 链接&#xff1a;https://arxiv.org/abs/1706.03762…

SQL Server Query Store Settings (查询存储设置)

参考&#xff1a;Query Store Settings - Erin Stellato 在 SQL Server 2017 中&#xff0c;有九 (9) 个设置与查询存储相关。虽然这些设置记录在sys.database_query_store_options中&#xff0c;但我经常被问到每个设置的值“应该”是多少。我在下面列出了每个设置&am…

EXCEL VBA工程密码破解 工作表保护破解

这里写目录标题 破解Excel宏工程加密方法一 新建破解宏文件方法二 修改二进制文件 破解工作表保护引用 破解Excel宏工程加密 如图所示 白料数据处理已工程被加密。 方法一 新建破解宏文件 1 创建一个XLSM文件&#xff0c;查看代码 ALTF11 2 新建一个模块&#xff0c;“插…

夏日狂欢水上漂流的爆笑奇遇记

【夏日狂欢&#xff0c;水上漂流的爆笑奇遇记 —— 月亮姐姐的“睫毛漂流记”】在这个炎炎夏日&#xff0c;当烈日炙烤着大地&#xff0c;每一寸空气弥漫着对清凉的渴望时&#xff0c;一场别开生面的“暑期嘉年华”正悄然掀起一场水上狂欢的浪潮。而在这场盛宴中&#xff0c;月…

【论文】(2024.6) KAN: Kolmogorov–Arnold Networks 阅读笔记 | KAN周边扩展

KAN的优势声称是能以更少的参数量实现更高的精度。KANs在数学上是可靠的、准确的和可解释的。 一 KAN 论文题目&#xff1a;KAN: Kolmogorov–Arnold Networks 论文地址&#xff1a;https://arxiv.org/pdf/2404.19756 代码地址&#xff1a;https://github.com/KindXiaoming/…

如何打造一个专属网盘?可道云teamOS这些个性化设置了解一下

在这个数字化时代&#xff0c;企业对于云端存储和协作工具的需求日益增长。而网盘作为企业协作的重要工具之一&#xff0c;其个性化、定制化的需求也日益凸显。 今天&#xff0c;我要为大家介绍的是一款高度个性化的企业网盘——可道云teamOS。 满足个性化需求的企业网盘 可…

防火墙NAT地址转换和智能选举综合实验

一、实验拓扑 目录 一、实验拓扑 二、实验要求&#xff08;接上一个实验要求后&#xff09; 三、实验步骤 3.1办公区设备可以通过电信链路和移动链路上网(多对多的NAT&#xff0c;并且需要保留一个公网IP不能用来转换) 3.2分公司设备可以通过总公司的移动链路和电信链路访…

【深度学习】PyTorch框架(4):初始网络、残差网络 和密集连接网络

1、引言 在本篇文章中&#xff0c;我们将深入探讨并实现一些现代卷积神经网络&#xff08;CNN&#xff09;架构的变体。近年来&#xff0c;学界提出了众多新颖的网络架构。其中一些最具影响力&#xff0c;并且至今仍然具有重要地位的架构包括&#xff1a;GoogleNet/Inception架…

Qt Style Sheets-使用样式表自定义 Qt 部件

使用样式表自定义 Qt 部件 在使用样式表时&#xff0c;每个小部件都被视为具有四个同心矩形的框&#xff1a;边距矩形、边框矩形、填充矩形和内容矩形。框模型对此进行了更详细的描述。 盒模型 以下是四个同心矩形在概念上的呈现方式&#xff1a; 边距超出边框。边框绘制在边…

自学 阿里巴巴Java开发手册最新版(嵩山版)

&#x1f534; 阿里巴巴Java开发手册最新版&#xff08;嵩山版&#xff09; 一、编程规约(一) 命名风格(二) 常量定义(三) 代码格式(四) OOP 规约(五) 日期时间(六) 集合处理(七) 并发处理(八) 控制语句(九) 注释规约(十) 前后端规范 二、异常日志(一) 错误码(二) 异常处理(三)…

mac环境下安装python3的图文教程

Python 是一种功能多样且强大的编程语言&#xff0c;在各个领域得到广泛应用。许多 Mac 用户都在其设备上安装和运行 Python&#xff0c;以运行特定的应用程序或创建、运行自己的 Python 脚本。 文章源自设计学徒自学网-http://www.sx1c.com/49441.html 虽然某些版本的 macOS…

沃尔玛,temu测评: 搭建稳定高效的自养号测评体系时需要考虑的关键点

​自养号测评是通过自己培养账号进行测评&#xff0c;‌将整个过程的主导权掌握在自己手中&#xff0c;‌可以有效控制测评过程&#xff0c;‌降低风险。建议还是自己精养一批账号&#xff0c;账号在自己手里比较安全可控&#xff0c;随时随地可以给自己送测&#xff0c;精准搜…

现场可重构CPLD芯片应用案例—蓝牙音箱

我司英尚微提供的高性能数模混合现场可重构IC、通用可配置的模数混合芯片内部集成丰富的模拟资源和数字资源&#xff0c;可轻松替代电路中的各种标准器件&#xff0c;并按照客户要求组合成最优小型ASIC&#xff0c;缩短开发周期&#xff0c;降低成本。下面介绍LS98002现场可重构…

openwrt安装netbird

官方版本安装后无法启动&#xff0c;有报错&#xff0c;请使用以下版本&#xff1a; https://github.com/tbc0309/openwrt-netbird 下载地址&#xff1a; https://github.com/tbc0309/openwrt-netbird/releases/ 平台架构根据自己的设备选择&#xff0c;可以通过以下方法获得…

【LeetCode:试题 16.06. 最小差 + 双指针 + 防止整型溢出】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

Visual Studio使用——在vs中给vb.net项目添加新的窗口:新建的方式、添加已有窗口的方式

目录 引出Visual Studio使用vb添加新的窗体自定义代码片段vs显示所有文件 总结Idea安装和使用0.Java下载 和 IDEA工具1.首次新建项目2.隐藏文件不必要显示文件3.目录层级设置4.Settings设置选择idea的场景提示代码不区分大小写 取消git的代码作者显示 引出 Visual Studio使用—…