eBPF 入门开发实践教程十:在 eBPF 中使用 hardirqs 或 softirqs 捕获中断事件

这篇具有很好参考价值的文章主要介绍了eBPF 入门开发实践教程十:在 eBPF 中使用 hardirqs 或 softirqs 捕获中断事件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

eBPF (Extended Berkeley Packet Filter) 是 Linux 内核上的一个强大的网络和性能分析工具。它允许开发者在内核运行时动态加载、更新和运行用户定义的代码。

本文是 eBPF 入门开发实践教程的第十篇,在 eBPF 中使用 hardirqs 或 softirqs 捕获中断事件。
hardirqs 和 softirqs 是 Linux 内核中两种不同类型的中断处理程序。它们用于处理硬件设备产生的中断请求,以及内核中的异步事件。在 eBPF 中,我们可以使用同名的 eBPF 工具 hardirqs 和 softirqs 来捕获和分析内核中与中断处理相关的信息。

hardirqs 和 softirqs 是什么?

hardirqs 是硬件中断处理程序。当硬件设备产生一个中断请求时,内核会将该请求映射到一个特定的中断向量,然后执行与之关联的硬件中断处理程序。硬件中断处理程序通常用于处理设备驱动程序中的事件,例如设备数据传输完成或设备错误。

softirqs 是软件中断处理程序。它们是内核中的一种底层异步事件处理机制,用于处理内核中的高优先级任务。softirqs 通常用于处理网络协议栈、磁盘子系统和其他内核组件中的事件。与硬件中断处理程序相比,软件中断处理程序具有更高的灵活性和可配置性。

实现原理

在 eBPF 中,我们可以通过挂载特定的 kprobe 或者 tracepoint 来捕获和分析 hardirqs 和 softirqs。为了捕获 hardirqs 和 softirqs,需要在相关的内核函数上放置 eBPF 程序。这些函数包括:

  • 对于 hardirqs:irq_handler_entry 和 irq_handler_exit。
  • 对于 softirqs:softirq_entry 和 softirq_exit。

当内核处理 hardirqs 或 softirqs 时,这些 eBPF 程序会被执行,从而收集相关信息,如中断向量、中断处理程序的执行时间等。收集到的信息可以用于分析内核中的性能问题和其他与中断处理相关的问题。

为了捕获 hardirqs 和 softirqs,可以遵循以下步骤:

  1. 在 eBPF 程序中定义用于存储中断信息的数据结构和映射。
  2. 编写 eBPF 程序,将其挂载到相应的内核函数上,以捕获 hardirqs 或 softirqs。
  3. 在 eBPF 程序中,收集中断处理程序的相关信息,并将这些信息存储在映射中。
  4. 在用户空间应用程序中,读取映射中的数据以分析和展示中断处理信息。

通过上述方法,我们可以在 eBPF 中使用 hardirqs 和 softirqs 捕获和分析内核中的中断事件,以识别潜在的性能问题和与中断处理相关的问题。

hardirqs 代码实现

hardirqs 程序的主要目的是获取中断处理程序的名称、执行次数和执行时间,并以直方图的形式展示执行时间的分布。让我们一步步分析这段代码。

// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2020 Wenbo Zhang
#include <vmlinux.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include "hardirqs.h"
#include "bits.bpf.h"
#include "maps.bpf.h"

#define MAX_ENTRIES 256

const volatile bool filter_cg = false;
const volatile bool targ_dist = false;
const volatile bool targ_ns = false;
const volatile bool do_count = false;

struct {
 __uint(type, BPF_MAP_TYPE_CGROUP_ARRAY);
 __type(key, u32);
 __type(value, u32);
 __uint(max_entries, 1);
} cgroup_map SEC(".maps");

struct {
 __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
 __uint(max_entries, 1);
 __type(key, u32);
 __type(value, u64);
} start SEC(".maps");

struct {
 __uint(type, BPF_MAP_TYPE_HASH);
 __uint(max_entries, MAX_ENTRIES);
 __type(key, struct irq_key);
 __type(value, struct info);
} infos SEC(".maps");

static struct info zero;

static int handle_entry(int irq, struct irqaction *action)
{
 if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
  return 0;

 if (do_count) {
  struct irq_key key = {};
  struct info *info;

  bpf_probe_read_kernel_str(&key.name, sizeof(key.name), BPF_CORE_READ(action, name));
  info = bpf_map_lookup_or_try_init(&infos, &key, &zero);
  if (!info)
   return 0;
  info->count += 1;
  return 0;
 } else {
  u64 ts = bpf_ktime_get_ns();
  u32 key = 0;

  if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
   return 0;

  bpf_map_update_elem(&start, &key, &ts, BPF_ANY);
  return 0;
 }
}

static int handle_exit(int irq, struct irqaction *action)
{
 struct irq_key ikey = {};
 struct info *info;
 u32 key = 0;
 u64 delta;
 u64 *tsp;

 if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
  return 0;

 tsp = bpf_map_lookup_elem(&start, &key);
 if (!tsp)
  return 0;

 delta = bpf_ktime_get_ns() - *tsp;
 if (!targ_ns)
  delta /= 1000U;

 bpf_probe_read_kernel_str(&ikey.name, sizeof(ikey.name), BPF_CORE_READ(action, name));
 info = bpf_map_lookup_or_try_init(&infos, &ikey, &zero);
 if (!info)
  return 0;

 if (!targ_dist) {
  info->count += delta;
 } else {
  u64 slot;

  slot = log2(delta);
  if (slot >= MAX_SLOTS)
   slot = MAX_SLOTS - 1;
  info->slots[slot]++;
 }

 return 0;
}

SEC("tp_btf/irq_handler_entry")
int BPF_PROG(irq_handler_entry_btf, int irq, struct irqaction *action)
{
 return handle_entry(irq, action);
}

SEC("tp_btf/irq_handler_exit")
int BPF_PROG(irq_handler_exit_btf, int irq, struct irqaction *action)
{
 return handle_exit(irq, action);
}

SEC("raw_tp/irq_handler_entry")
int BPF_PROG(irq_handler_entry, int irq, struct irqaction *action)
{
 return handle_entry(irq, action);
}

SEC("raw_tp/irq_handler_exit")
int BPF_PROG(irq_handler_exit, int irq, struct irqaction *action)
{
 return handle_exit(irq, action);
}

char LICENSE[] SEC("license") = "GPL";

这段代码是一个 eBPF 程序,用于捕获和分析内核中硬件中断处理程序(hardirqs)的执行信息。程序的主要目的是获取中断处理程序的名称、执行次数和执行时间,并以直方图的形式展示执行时间的分布。让我们一步步分析这段代码。

  1. 包含必要的头文件和定义数据结构:

    #include <vmlinux.h>
    #include <bpf/bpf_core_read.h>
    #include <bpf/bpf_helpers.h>
    #include <bpf/bpf_tracing.h>
    #include "hardirqs.h"
    #include "bits.bpf.h"
    #include "maps.bpf.h"
    

    该程序包含了 eBPF 开发所需的标准头文件,以及用于定义数据结构和映射的自定义头文件。

  2. 定义全局变量和映射:

    
    #define MAX_ENTRIES 256
    
    const volatile bool filter_cg = false;
    const volatile bool targ_dist = false;
    const volatile bool targ_ns = false;
    const volatile bool do_count = false;
    
    ...
    

    该程序定义了一些全局变量,用于配置程序的行为。例如,filter_cg 控制是否过滤 cgroup,targ_dist 控制是否显示执行时间的分布等。此外,程序还定义了三个映射,分别用于存储 cgroup 信息、开始时间戳和中断处理程序的信息。

  3. 定义两个辅助函数 handle_entryhandle_exit

    这两个函数分别在中断处理程序的入口和出口处被调用。handle_entry 记录开始时间戳或更新中断计数,handle_exit 计算中断处理程序的执行时间,并将结果存储到相应的信息映射中。

  4. 定义 eBPF 程序的入口点:

    
    SEC("tp_btf/irq_handler_entry")
    int BPF_PROG(irq_handler_entry_btf, int irq, struct irqaction *action)
    {
    return handle_entry(irq, action);
    }
    
    SEC("tp_btf/irq_handler_exit")
    int BPF_PROG(irq_handler_exit_btf, int irq, struct irqaction *action)
    {
    return handle_exit(irq, action);
    }
    
    SEC("raw_tp/irq_handler_entry")
    int BPF_PROG(irq_handler_entry, int irq, struct irqaction *action)
    {
    return handle_entry(irq, action);
    }
    
    SEC("raw_tp/irq_handler_exit")
    int BPF_PROG(irq_handler_exit, int irq, struct irqaction *action)
    {
    return handle_exit(irq, action);
    }
    

    这里定义了四个 eBPF 程序入口点,分别用于捕获中断处理程序的入口和出口事件。tp_btfraw_tp 分别代表使用 BPF Type Format(BTF)和原始 tracepoints 捕获事件。这样可以确保程序在不同内核版本上可以移植和运行。

Softirq 代码也类似,这里就不再赘述了。

运行代码

eunomia-bpf 是一个结合 Wasm 的开源 eBPF 动态加载运行时和开发工具链,它的目的是简化 eBPF 程序的开发、构建、分发、运行。可以参考 https://github.com/eunomia-bpf/eunomia-bpf 下载和安装 ecc 编译工具链和 ecli 运行时。我们使用 eunomia-bpf 编译运行这个例子。

要编译这个程序,请使用 ecc 工具:

$ ecc hardirqs.bpf.c
Compiling bpf object...
Packing ebpf object and config into package.json...

然后运行:

sudo ecli run ./package.json

总结

在本章节(eBPF 入门开发实践教程十:在 eBPF 中使用 hardirqs 或 softirqs 捕获中断事件)中,我们学习了如何使用 eBPF 程序捕获和分析内核中硬件中断处理程序(hardirqs)的执行信息。我们详细讲解了示例代码,包括如何定义数据结构、映射以及 eBPF 程序入口点,以及如何在中断处理程序的入口和出口处调用辅助函数来记录执行信息。

通过学习本章节内容,您应该已经掌握了如何在 eBPF 中使用 hardirqs 或 softirqs 捕获中断事件的方法,以及如何分析这些事件以识别内核中的性能问题和其他与中断处理相关的问题。这些技能对于分析和优化 Linux 内核的性能至关重要。

为了更好地理解和实践 eBPF 编程,我们建议您阅读 eunomia-bpf 的官方文档:https://github.com/eunomia-bpf/eunomia-bpf 。此外,我们还为您提供了完整的教程和源代码,您可以在 https://github.com/eunomia-bpf/bpf-developer-tutorial 中查看和学习。希望本教程能够帮助您顺利入门 eBPF 开发,并为您的进一步学习和实践提供有益的参考。文章来源地址https://www.toymoban.com/news/detail-470389.html

到了这里,关于eBPF 入门开发实践教程十:在 eBPF 中使用 hardirqs 或 softirqs 捕获中断事件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 微信小程序开发实践入门教程

    随着微信小程序的火爆,越来越多的人开始关注 微信小程序开发 并加入开发大军中,而很多人对于如何开发微信小程序,并没有很好的思路和方法。因此,为了方便大家在学习、实践和应用的过程中能够少走弯路,本文将通过一篇关于微信小程序开发实践入门教程来为大家

    2024年02月06日
    浏览(36)
  • 【项目实践】海康威视工业相机SDK开发小白版入门教程(VS2015+OpenCV4.5.1)

      由于学校要求暑期实习,于是找了一位学长开的公司,接了一个项目,是 对海康威视工业相机(MV_CE200_10GM)进行二次开发,读取其图像并做分析处理。 于是花了一点时间查找的相关资料并记录一些 入门要点 。   想先说说一些 “尝试授人与渔” 的话,也是自己的一

    2024年02月04日
    浏览(49)
  • 基于 eBPF 的 Kubernetes 可观测实践

    可观测是为了解决问题,所以在聊可观测之前,应先对问题排查的普适原则进行了解。 问题排查的原则 以排查系统问题为例,要理解系统,要先关注基础知识,理解编程语言基本的计算机科学知识,关注系统大图比如架构部署和重大流程,要关注运行细节,要对核心功能的

    2024年01月19日
    浏览(55)
  • VPN入门教程:基本概念、使用方法及思科模拟器实践

    数据来源         本文仅用于信息安全的学习,请遵守相关法律法规,严禁用于非法途径。若观众因此作出任何危害网络安全的行为,后果自负,与本人无关。 VPN可以实现在不安全的网络上,安全的传输数据,类似专网 VPN只是一个技术,使用PKI技术,来保证数据的安全三

    2024年02月08日
    浏览(86)
  • eBPF内核技术在滴滴云原生的落地实践

    将滴滴技术设为“ 星标⭐️ ” 第一时间收到文章更新 导读 eBPF是Linux内核革命性技术,能够安全高效地扩展内核能力,应用广泛,尤其是在云原生可观测性领域的应用已经成为行业热点。在滴滴云原生环境中,eBPF技术进行了业务实践和内源共建,HuaTuo eBPF 平台快速落地并取

    2024年02月12日
    浏览(40)
  • windows日志捕获工具-DebugView使用教程

    debugview 是一款捕获windows桌面系统程序中由TRACE(debug版本)和OutputDebugString输出的信息。 1、双击打开DebugView.exe工具,看到如下界面: 其中这里 Include代表过滤想要的,一般不会找自己想要的日志就设置成星号*,表示显示所有日志。 Exclude就是过滤掉不想要的

    2023年04月21日
    浏览(32)
  • eBPF系列之:DeepFlow 扩展协议解析实践(MongoDB协议与Kafka协议)

    原文:https://blog.mickeyzzc.tech/posts/ebpf/deepflow-agent-proto-dev MongoDB 目前使用广泛,但是缺乏有效的可观测能力。DeepFlow 在可观测能力上是很优秀的解决方案,但是却缺少了对 MongoDB 协议的支持。该文是为 DeepFlow 扩展了 MongoDB 协议解析,增强 MongoDB 生态的可观测能力,简要描述了从

    2024年01月21日
    浏览(44)
  • 嵌入式开发--CubeMX使用入门教程

    嵌入式开发–CubeMX使用入门教程 传统的单片机开发时,需要针对片上外设做各种初始化的工作,相当麻烦。 CubeMX是ST公司出品的一款图形化代码生成工具,通过图形化界面,可以非常直观的配置好各种片上外设,时钟,中断,DMA等等各种设备的参数,然后CubeMX可以直接生成初

    2024年04月12日
    浏览(59)
  • 【抓包工具】实战:WireShark 捕获过滤器的超全使用教程

    目录 一、应用场景 二、「捕获选项」弹框界面 (1)选项卡:Input ① 接口 ② 流量 ③ 链路层 ④ 混杂 ⑤ 捕获长度(B) ⑥ 缓冲区(MB) ⑦ 监控模式 ⑧ 捕获过滤器 (2)选项卡:输出 (3)选项卡:选项 三、捕获过滤表达式 (1)语法说明 (2)限定符 (3)运算符 (4)特

    2023年04月18日
    浏览(108)
  • 【eBPF-02】入门:基于 BCC 框架的程序进阶

    本文是 eBPF 系列的第二篇文章,我们来学习 eBPF BCC 框架的进阶用法,对上一篇文章中的代码进行升级,动态输出进程运行时的参数情况。 主要内容包括: 通过 kprobe 挂载内核事件的 eBPF 程序要如何编写? 通过 tracepoint 挂载内核事件的 eBPF 程序要如何编写? eBPF 的程序事件类

    2024年02月04日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包