远程追踪

作者:

Vincent Donnefort <vdonnefort@google.com>

概述

固件和虚拟机管理程序对于内核而言是黑盒。能够查看它们的运行状态对于调试两者都很有用。这就是远程追踪缓冲区发挥作用的地方。远程追踪缓冲区是一个由固件或虚拟机管理程序在内存中执行的环形缓冲区,该内存被映射到主机内核。这类似于用户空间内存映射内核环形缓冲区的方式,但在本例中,内核充当用户空间的角色,而固件或虚拟机管理程序充当“内核”侧。通过远程追踪环形缓冲区,固件和虚拟机管理程序可以记录主机内核可以看到并暴露给用户空间的事件。

注册远程端

远程端必须提供一组回调函数 struct trace_remote_callbacks,其描述见下文。这些回调允许 Tracefs 启用和禁用追踪及事件,加载和卸载追踪缓冲区(一组环形缓冲区),以及交换读取页与头部页,这使得读取操作成为可能。

struct trace_remote_callbacks

Tracefs 用于控制远程端的回调函数

定义:

struct trace_remote_callbacks {
    int (*init)(struct dentry *d, void *priv);
    struct trace_buffer_desc *(*load_trace_buffer)(unsigned long size, void *priv);
    void (*unload_trace_buffer)(struct trace_buffer_desc *desc, void *priv);
    int (*enable_tracing)(bool enable, void *priv);
    int (*swap_reader_page)(unsigned int cpu, void *priv);
    int (*reset)(unsigned int cpu, void *priv);
    int (*enable_event)(unsigned short id, bool enable, void *priv);
};

成员

init

在远程端注册后调用。允许调用者扩展 Tracefs 远程目录

load_trace_buffer

在 Tracefs 首次访问追踪缓冲区之前调用。必须返回一个 trace_buffer_desc(很可能是通过 trace_remote_alloc_buffer() 填充)

unload_trace_buffer

当 Tracefs 不再使用追踪缓冲区时调用(很可能是调用 trace_remote_free_buffer()

enable_tracing

在 Tracefs 的 tracing_on 上调用。预期远程端允许写入。

swap_reader_page

当 Tracefs 从环形缓冲区消耗一个新页面时调用。预期远程端隔离出一个

reset

echo 0 > trace 时调用。预期远程端重置所有环形缓冲区页面。从 cpu 环形缓冲区获取新的读取页。

enable_event

在 events/event_name/enable 上调用。预期远程端允许写入事件 id

一旦注册,此远程端将出现在 Tracefs 目录 remotes/ 下的实例中。随后可以使用常规的 Tracefs 文件 trace_pipetrace 来读取缓冲区。

声明远程事件

提供了一些宏来简化远程事件的声明,类似于内核内部事件。声明必须提供一个 ID、事件参数的描述以及如何打印事件

REMOTE_EVENT(foo, EVENT_FOO_ID,
        RE_STRUCT(
                re_field(u64, bar)
        ),
        RE_PRINTK("bar=%lld", __entry->bar)
);

然后必须在 C 文件中通过以下方式声明这些事件

#define REMOTE_EVENT_INCLUDE_FILE foo_events.h
#include <trace/define_remote_events.h>

这将提供一个 struct remote_event remote_event_foo,可以将其提供给 trace_remote_register

注册的事件会出现在远程目录下的 events/ 中。

简单的环形缓冲区

可以在 kernel/trace/simple_ring_buffer.c 中找到环形缓冲区写入器的简单实现。