基于eBPF的procstat软件追踪C++ STL容器扩容

news2024/9/21 0:46:21

在性能敏感的C++程序中,标准模板库(STL)容器的扩容操作往往是导致性能抖动的原因之一。扩容操作可能会引发内存重新分配和数据迁移,从而导致性能不稳定。然而,由于C++标准库的扩容函数通常被内联化,传统的方法难以捕获这些操作。本文将介绍一种使用基于eBPF(Extended Berkeley Packet Filter)的 procstat 软件来监控C++ STL容器扩容情况的监控方案。

背景

C++ STL提供了一组强大的数据结构,例如vector、unordered_map、和unordered_set等。这些容器在程序中被广泛使用,但是在大量数据操作过程中,容器扩容可能引发显著的性能抖动。一般来说,容器会在现有容量耗尽时自动扩容,从而满足新的存储需求。然而,由于标准库函数被内联化,无法直接通过eBPF等工具进行监控。

监控方案

在性能敏感的C++程序中,为了实时监控STL容器的扩容情况,本文设计了一套监控方案。该方案通过去内联化标准库扩容函数,并结合eBPF强大的内核监控能力,帮助开发者深入了解扩容操作带来的性能影响。以下是该监控方案的详细介绍。

1. 自研库 smart_stl

由于C++标准库的扩容函数通常被内联化,在编译好的二进制文件中找不到扩容函数的符号,导致难以捕获扩容操作。为了应对这一挑战,我开发了 smart_stl 库。该库的设计理念是保持与STL的接口兼容,同时对扩容相关的函数强制去内联,从而让这些函数能够被eBPF监控到。
smart_stl的github链接地址
特点与实现

  1. 接口兼容:smart_stl 库继承了STL的 unordered_map、unordered_set、vector 等容器,并保持接口完全一致。这意味着现有代码只需要少量修改即可迁移到 smart_stl,从而实现监控能力。
  2. 去内联化:smart_stl 库的核心在于将容器中的扩容函数标记为 noinline。通过这一处理,扩容函数不再被编译器内联化,允许eBPF等外部工具挂钩这些函数的执行。
  3. 轻量级:smart_stl 仅包含头文件,非常轻量化。此外,由于扩容函数在大部分场景中被较少调用,监控功能几乎不会影响程序的整体性能。

2. eBPF简介

eBPF(Extended Berkeley Packet Filter)是一种强大的内核技术,最初用于网络数据包过滤。如今,eBPF已经发展成为一种通用的内核编程平台,广泛应用于性能监控、安全审计、网络分析等领域。它的强大之处在于能够在内核中高效、灵活地运行用户定义的代码,同时对系统性能的影响极小。eBPF允许开发者编写自定义的代码,并将这些代码动态加载到内核中,以监控各种系统级和应用级事件。由于eBPF程序在内核中运行,因此它能够以极低的开销实时捕获事件并反馈给用户。

uprobe:用户态函数监控

uprobe 是eBPF提供的一种能力,专门用于监控用户态程序中的特定函数。通过设置 uprobe、uretprobe,开发者可以在目标程序的函数被调用或退出时,自动触发预先定义的eBPF程序,从而捕获该函数的执行情况。其特点有:

  1. 函数挂钩:uprobe 可以挂钩到任意用户态函数,无论是标准库函数还是用户自定义函数。当该函数被调用时,uprobe 会触发EBPF程序的执行。
  2. 精确捕获:uprobe 能够精确捕获函数的调用时间、参数、返回值等关键信息。这对性能分析和调试非常有帮助。
  3. 轻量级监控:与传统的调试工具相比,uprobe 和eBPF结合后的监控方案不会影响程序的功能,对性能影响也很小,尤其是监控不常运行到的异常分支,如本文介绍的STL的扩容,几乎不影响程序性能。

在本文的监控方案中,eBPF被用来捕获C++程序中特定的用户态函数调用,通过与 uprobe 结合,实现对C++ STL容器扩容操作的实时监控。

procstat软件简介

procstat是一款基于eBPF的监控工具软件,运行在Linux平台,主要用于跟踪目标程序的运行状态,并报告异常指标,是分析程序性能问题的一大利器。procstat软件结合前文提到的smart_stl库形成的方案能够用于追踪程序的STL容器扩容情况,实时捕捉STL扩容信息。当检测到扩容时间超过阈值的情况时,procstat会在日志中输出详细的信息,包括扩容时长、扩容次数、发生扩容的用户态堆栈等,帮助开发者快速定位问题根源。接下来我们将通过一个小实验来展示一下procstat软件是如何追踪STL扩容的。此软件可以在以下链接中下载到,并提供免费试用,后续还会有版本更新迭代,使用时需要能连互联网环境。
Github下载链接

STL扩容示例代码

我们通过一个简单的 C++ 程序来演示如何使用 procstat 追踪STL vector的扩容时间。以下是我们的示例程序:

#include <iostream>
#include <thread>
#include <vector>
#include <chrono>
#include "smart_vector.h"
using namespace std;

int main()
{
    while (true) {
        std::this_thread::sleep_for(std::chrono::seconds(5));
        smart_stl::vector<int> vec;
        smart_stl::vector<double> vec1;
        for (int i = 0; i < 10000; ++i) {
            vec.push_back(i);
            vec1.emplace_back(i);
        }
    }
    return 0;
}
//编译命令:g++ test.cpp -o test -g -std=c++11 -O2 -I/home/smart_stl

这个程序简单地在一个无限循环中每次创建2个vector,向其中插入10000个数据,这些插入数据操作会导致vector容器发生多次扩容行为。

使用procstat追踪vector扩容

编译并启动上述代码后,使用procstat软件来监控该程序并检测vector扩容行为。本实验中,编译后的程序名为test。首先,将procstat软件的配置中将vector扩容的阈值设置为0,单位是纳秒,意思是当进程发生vector扩容就会输出日志。
配置设置
配置文件位置在procstat目前下的conf目录中,名为config.json。

    "stl_realloc_stat": {
        "vector_realloc_symbol": "",
        "vector_realloc_duration": 0,
        "unordered_map_realloc_symbol": "",
        "unordered_map_realloc_duration": -1,
        "unordered_set_realloc_symbol": "",
        "unordered_set_realloc_duration": -1,
        "desc": "stl realloc stat"
    }

启动被监控的test小程序后,我们可以通过以下命令启动procstat进行监控:sh start.sh -p 进程号。其中,<进程号>是正在运行的test程序的进程ID。
运行程序

[root@VM-8-2-centos bin]# ./test &
[1] 2407420
[root@VM-8-2-centos bin]#
[root@VM-8-2-centos bin]# ps -ef | grep test
root     2407420 2406863  0 12:43 pts/2    00:00:00 ./test
root     2407447 2406863  0 12:44 pts/2    00:00:00 grep --color=auto test
[root@VM-8-2-centos bin]# sh start.sh -p 2407420
Start Loading...!
Start Stating...!

启动监控后(输出“Start Stating…!”后就已开始监控了),procstat会持续监控该程序的运行状态,并在日志中记录时间超过配置文件中设定的阈值的vector扩容操作(时长可配置)。

procstat软件日志

接下来我们查询procstat的日志信息,并搜索VECTOR REALLOC关键字。
在这里插入图片描述从上图的日志中可以看出已经成功地捕获到了test进程的vector扩容操作,我们对第26行日志分析一下:

  1. 扩容发生的时间是12:44:27.988465229,精确到纳秒级别;
  2. 发生扩容的进程名称是test,进程id是2407420,线程id是2407420;
  3. 发生扩容的vector对象的内存地址是0x7ffcd3d3a1c0和0x7ffcd3d3a1e0;
  4. 扩容前的容量是0;
  5. 捕获到了用户态堆栈,由于测试小程序比较简单,没有太深的堆栈,其中realloc_insert和realloc_emplace是smart_stl库中的vector扩容函数。

在这里插入图片描述在日志中grep一下VECTOR REALLOC关键字,如上图所示,我们发现test进程非常频繁地进行vector扩容操作,我们对结果分析一下:

  1. 第一行,包含[VECTOR REALLOC STAT]关键字,是一秒打印一次的统计信息,如果没有发生扩容则不打印,其中:
    (1) total_duration:是线程在这一秒内发生的扩容的总时长为484微秒,单位为纳秒;
    (2)avg_duration:是线程在这一秒内的平均扩容时长为16微秒,单位为纳秒;
    (3)max_duration:是线程在这一秒内的单次最大扩容时长为86微秒,单位为纳秒;
    (4)max_index:线程在这一秒内时长最长的那次扩容的第30次;
    (5)count:线程在这一秒内总共发生了30次扩容。
  2. 从第二行往后,包含[VECTOR REALLOC]关键字,代表发生扩容的时长超过阈值,字段含义在前一张图的分析中已解释。通过size_before_realloc字段的值可看出,vector的扩容规律是:0 -> 1 -> 2 -> 4 -> 8 ->16 ->32 ->64 -> … -> 8192,以当前的2倍作为目标容量进行扩容。

总结

procstat 是一个功能强大的工具,通过 eBPF 技术实现了对程序中STL容器扩容时间的全面追踪。通过本文的介绍和示例,相信你已经对 procstat 有了基本的了解。希望你能在实际工作中充分利用这个软件,提高程序的性能和稳定性。
procstat软件还可以监测很多的程序异常状态,随着eBPF技术的不断发展和procstat软件不断的迭代,希望能够帮助大家定位程序的性能问题和异常问题,进一步提升对软件和操作系统的监控能力,欢迎大家试用,有问题请私信我,共同学习、交流,共同进步!
推荐文章:
基于eBPF的procstat软件追踪程序Offcpu时间
基于eBPF的procstat软件追踪等待锁和持有锁的时间
基于eBPF的procstat软件定位软件死锁

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

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

相关文章

Geekbench AI 1.0正式发布:AI性能评估

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

STM32标准库学习笔记-4.定时器中断

参考教程&#xff1a;【STM32入门教程-2023版 细致讲解 中文字幕】 定时器简介 TIM&#xff08;Timer&#xff09;定时器。定时器可以对输入的时钟进行计数&#xff0c;并在计数值达到设定值时触发中断。16位计数器、预分频器、自动重装寄存器的时基单元&#xff0c;在72MHz计…

vue3响应式工具 toRefs() 和 toRef()

前言 直接解构响应式对象的属性进行赋值给新的变量&#xff0c;会导致新变量失去响应式。 当修改新变量的值时&#xff0c;不会触发原始响应式对象的更新&#xff0c;从而在模板中也不会有相应的视图更新。 示例&#xff1a; <template><div><p>姓名: {{ …

垂直行业数字化表现抢眼 亚信科技全年利润展望乐观

大数据产业创新服务媒体 ——聚焦数据 改变商业 2024年8月14日&#xff0c;亚信科技控股有限公司&#xff08;股票代码&#xff1a;01675.HK&#xff09;公布了公司截至2024年6月30日的中期业绩。 财报数据显示&#xff0c;2024年上半年&#xff0c;亚信科技的营业收入为人民币…

Java巅峰之路---进阶篇---面向对象(一)

static关键字 介绍 static表示静态&#xff0c;是java中的一个修饰符&#xff0c;可以修饰成员方法&#xff0c;成员变量。 其中&#xff0c;被static修饰的成员变量&#xff0c;叫做静态变量&#xff1b;被static修饰的成员方法&#xff0c;叫做静态方法。 静态变量 调用…

水凝胶和皮肤再生有关系?那它是什么玩意儿?

大家好&#xff0c;今天我们来聊聊皮肤再生与水凝胶的关系。这篇《Hydrogel-Based Skin Regeneration》是发表于《International Journal of Molecular Sciences》上的一篇文章。皮肤作为人体最大的器官&#xff0c;其伤口愈合至关重要&#xff0c;但传统治疗方法有局限性。组织…

数据结构(Java):揭开二叉搜索树删除机制的奥秘

目录 1、二叉搜索树 1.1 概念 2、代码模拟实现 2.1 插入操作 2.2 查找操作 2.3 &#x1f31f;删除操作&#x1f31f;&#xff08;难点&#xff09; 2.3.1 要删除节点的左子树为空 2.3.2 要删除节点的右子树为空 2.3.3 要删除节点的左右子树均不为空 2.3.4 删除操作代码…

认知杂谈17

今天分享 有人说的一段争议性的话 I I 男人撑起一片天&#xff0c;背后是默默的坚守与承担 说起生孩子这事儿啊&#xff0c;对大多数男同胞来讲&#xff0c;那真是又温馨又充满挑战。要当爸爸了&#xff0c;这意味着责任重大&#xff0c;心里期待满满&#xff0c;一方面得…

函数图像绘制小工具

函数图像绘制小工具 文章说明核心代码效果展示源码下载 文章说明 方便绘制一些数学的基础图象&#xff0c;制作该款小工具&#xff0c;不过尚为雏形阶段&#xff0c;等待后续逐步完善 核心代码 采用canvas绘图实现&#xff0c;核心代码如下 <script setup> import {onMou…

公开数据库汇总及下载(1)-TCGA

文章目录 1. 常用数据库2. TCGA数据下载2.1 TCGA介绍2.2 数据类型详解2.3 TCGA数据等级2.4 TCGA网页筛选页面介绍2.5 各文件每个字段的含义2.6 biospecimen IDs介绍(样本ID)2.7 下载代码 参考文件 本文的内容介绍、代码下载主要参考了网上多个文件汇总而成&#xff0c;本文仅作…

深度学习基础—Dropout正则化(随机失活正则化)

1.Dropout正则化 Dropout正则化&#xff1a;网络中每一个神经元节点都有一定概率保留或消除&#xff0c;从而下较小规模的网络。 假设上图网络存在过拟合&#xff0c;Dropout正则化的做法就是遍历每一个节点&#xff0c;对该节点以一定的概率保留或删除&#xff0c;从而简化网络…

C语言 | Leetcode C语言题解之第347题前K个高频元素

题目&#xff1a; 题解&#xff1a; struct hash_table {int key;int val;// 查看 https://troydhanson.github.io/uthash/ 了解更多UT_hash_handle hh; };typedef struct hash_table* hash_ptr;struct pair {int first;int second; };void swap(struct pair* a, struct pair*…

【C++】udp通信协议详解和示例

前言 UDP&#xff08;‌User Datagram Protocol&#xff0c;‌用户数据报协议&#xff09;‌是一种无连接的、‌不可靠的、‌面向数据报的传输层协议。‌它广泛应用于需要高实时性且对数据传输可靠性要求不高的场景&#xff0c;‌如实时音视频传输、‌在线游戏等。‌本文将详细…

Python做统计图之美

Python数据分析可视化 案例效果图 import pandas as pd import matplotlib.pyplot as plt import matplotlib# 数据 data {"房型": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],"住宅类型": ["普通宅", "普通宅", "普通宅", &q…

JUC6-共享模型之不可变

目录 日期转换的问题 问题提出 思路&#xff1a;同步锁 思路&#xff1a;不可变 不可变设计 final的使用 保护性拷贝 享元模式 概述 体现 包装类 String串池 BigDecimal BigInteger DIY 原理&#xff1a;final 无状态 日期转换的问题 问题提出 下面的代码在运…

python井字棋游戏设计与实现

python实现井字棋游戏 游戏规则&#xff0c;有三个井字棋盘&#xff0c;看谁连成的直线棋盘多谁就获胜 棋盘的展现形式为 棋盘号ABC和位置数字1-9 输入A1 代表在A棋盘1号位数下棋 效果图如下 部分源码如下&#xff1a; 卫星工纵浩 白龙码程序设计&#xff0c;点 代码获取 …

Stability AI发布了单目视频转4D模型的新AI模型:Stable Video 4D

开放生成式人工智能初创公司Stability AI在3月发布了Stable Video 3D&#xff0c;是一款可以根据图像中的物体生成出可旋转的3D模型视频工具。Stability AI在7月24日发布了新一代的Stable Video 4D&#xff0c;增添了赋予3D模移动作的功能。 Stable Video 4D能在约40秒内生成8…

DBAPI如何用SQL将多表关联查询出树状结构数据(嵌套JSON格式)

场景描述 假设数据库中有3张表如下&#xff1a; 客户信息表 订单表 订单详情表 一个客户有多个订单&#xff0c;一个订单包含多个产品信息&#xff0c;客户-订单-产品就构成了3级的树状结构&#xff0c;如何查询出如下树状结构数据呢&#xff1f; [{"customer_age"…

矩阵--旋转图像

给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例 &#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&a…

嵌入式Day33---Linux软件编程---网络编程

目录 一、TCP包头 1.1.源端口 1.2.目的端口 1.3.序号 1.4.确认号 1.5.数据偏移 1.6.保留 1.7.指令信号 1.SYN 2.ACK 3.FIN 4.RST 5.PSH 6.URG 1.8.窗口 1.9.校验和 1.10.紧急指针 二、TCP的过程 2.1三次握手 2.2.传输数据 ​编辑 2.3.四次挥手 ​编辑 …