zoukankan      html  css  js  c++  java
  • tracepoint你真的了解吗?

    前言

    很惭愧,搞了这么久的linux开发,之前测试无论是用ftrace还是perf也好,都没有认真的去了解tracepoint的实现,这次正好

    开发的代码中需要设计一个tracepoint,便于后期调试使用,所以趁此机会,了解下tracepoint在内核里面的编写。

    你真的知道trace的原理吗?

    这里大致介绍下tracepoint的大致原理,和kprobe相比,tracepoint是一个安静的乖孩子,只有在内核里面编写好才能使用

    而kprobe不一样,可动可静,是一个活力十足的假小子,tracepoint实现是基于hooks的思想,function trace是利用gcc编译器初期

    在函数的入口就被放置一个probe点,也俗称打桩,这个probe点就会跟踪调用这个函数的各种信息,例如进程,地址,栈信息等,

    并将追踪的信息保存到一个环形队列中去,如果用户希望读取这些内核,就会通过debugfs形式来访问,所以有时候我在想是不是可以

    写一个程序,去专门监控trace环形队列占用的内存情况(有点跑偏了),下面从网上找的一张图介绍下这个trace的调用流程。

    去实现一个tracepoint

    实现一个tracepoint是很简单的事,尤其是有经验的内核开发同学,你只需要看下Documentation/trace/相关文档介绍,在看看

    内核里面任何一个tracepoint的实现patch, 基本就可以照葫芦画瓢去弄了,至少我在写tracepoint的时候就是这么弄的,很有意思。

    step1: 实现一个tracepoint的头文件

    我们需要定义一个tracepint的头文件,最好和你想要跟踪的function所在的目录或者相关头文件放在一起。

    例如我这里定义trace_myself.h文件

    // trace_myself.h
    #undef TRACE_SYSTEM #define TRACE_SYSTEM myself
    #if !defined(__TRACE_MYSELF_H__) || defined(TRACE_HEADER_MULTI_READ)

    #define __TRACE_MYSELF_H__#include <linux/tracepoint.h> // 此处是非常关键的地方,设计到你要追踪的函数的的相关内容作为参数// 为了方便,这里将参数设置为unsiged short形式TRACE_EVENT(myself_tp,
        TP_PROTO(unsigned short dest, unsigned short source),
        TP_ARGS(dest, source), // 定义两参数名称为dest和source
        TP_STRUCT__entry(  // 此处本人理解为打桩时候分配的环形队列时指定的作用域,说白了就是大小和attr。
            __field(unsigned short, dest)
            __field(unsigned short, source)
        ),
    TP_fast_assign(
        __entry->dest = dest;   //  将trace的函数的内容拷贝到环形队列中去
        __entry->source = source;
    ),
    
    TP_printk("dest:%d, source:%d", __entry->dest, __entry->source)  // 打印你所期望的内容
    );
    
    #endif // 此处定义完成后,仅仅是类型定义成功
    
    // 下一步我们需要指定头文件所在的目录,并且定义头文件的名称
    #undef TRACE_INCLUDE_PATH #define TRACE_INCLUDE_PATH . #define TRACE_INCLUDE_FILE trace_myself // 这就是该头文件的名字 #include <trace/define_trace.h>

    到这一步,只能算是你tracepoint function实现了,但是怎么编译和在代码中添加,又有很多规则需要注意

    step2: 加入到makefile中去

    ccflags-y += -I$(src)   # needed for trace events

    就是这么简短的一句,但是非加不可,如果不加,可定是不行的,gcc编译的时候会查找相关头文件,这告诉编译器,此处的头文件也要包含。

    step3: 在trace里的函数加入tracepoint


    //此处需要知道的是trace的函数所在的文件里必须包含CREATE_TRACE_POINTS
    //并且必须在头文件之前,虽然不理解,但是还是的遵守

    #define CREATE_TRACE_POINTS
    #include "test_tp.h"
    
    #include <net/protocol.h>
    #include <linux/ip.h>
    #include <linux/udp.h>
    
    int test(unsiged short dst, unsiged short src)
    {
        dst = src + 5;// 这里增加一个tracepoint点
        trace_myself(dst, src);
    return 0; } int init_module(void) { int ret = 0, dest = 5, src = 5;
    ret
    = test(dest, src); if (ret) { printk("failed "); return ret; } return 0; }
    void cleanup_module(void) {
      printk("failed
    ");
    } 

    int init_module(void); void cleanup_module(void); MODULE_LICENSE("GPLv2");
    是时候好好总结下自己走过的路。
  • 相关阅读:
    Manjaro中添加gitee的公钥部署
    另类的linux系统
    mac的快捷键flykey应用
    tidb总览
    raft算法
    tidb的tidb
    tidb的tikv
    tidb的pd
    切尔诺贝利事故
    血钻
  • 原文地址:https://www.cnblogs.com/haoxing990/p/14672590.html
Copyright © 2011-2022 走看看