確定性自動機插樁

由 dot2k 建立的 RV 監視器檔案,名為“$MODEL_NAME.c”,包含一個專門用於插樁的部分。

在 [1] 中建立的 wip.dot 監視器示例中,它將如下所示

/*
 * This is the instrumentation part of the monitor.
 *
 * This is the section where manual work is required. Here the kernel events
 * are translated into model's event.
 *
 */
static void handle_preempt_disable(void *data, /* XXX: fill header */)
{
      da_handle_event_wip(preempt_disable_wip);
}

static void handle_preempt_enable(void *data, /* XXX: fill header */)
{
      da_handle_event_wip(preempt_enable_wip);
}

static void handle_sched_waking(void *data, /* XXX: fill header */)
{
      da_handle_event_wip(sched_waking_wip);
}

static int enable_wip(void)
{
      int retval;

      retval = da_monitor_init_wip();
      if (retval)
              return retval;

      rv_attach_trace_probe("wip", /* XXX: tracepoint */, handle_preempt_disable);
      rv_attach_trace_probe("wip", /* XXX: tracepoint */, handle_preempt_enable);
      rv_attach_trace_probe("wip", /* XXX: tracepoint */, handle_sched_waking);

      return 0;
}

該部分的頂部註釋解釋了總體思想:插樁部分將核心事件轉換為模型事件。

追蹤回撥函式

前三個函式是 wip 模型中三個事件各自回撥處理函式的起點。開發者不一定需要使用它們:它們只是起點。

以…為例

void handle_preempt_disable(void *data, /* XXX: fill header */)
{
       da_handle_event_wip(preempt_disable_wip);
}

模型中的 preempt_disable 事件直接連線到 preemptirq:preempt_disable。preemptirq:preempt_disable 事件在 include/trace/events/preemptirq.h 中有以下簽名:

TP_PROTO(unsigned long ip, unsigned long parent_ip)

因此,handle_preempt_disable() 函式將如下所示

void handle_preempt_disable(void *data, unsigned long ip, unsigned long parent_ip)

在這種情況下,核心事件與自動機事件一一對應,確實,此函式不需要進行其他更改。

下一個處理函式 handle_preempt_enable() 具有與 handle_preempt_disable() 相同的引數列表。不同之處在於 preempt_enable 事件將用於將系統與模型同步。

最初,模型處於初始狀態。然而,系統可能處於也可能不處於初始狀態。監視器在得知系統已達到初始狀態之前無法開始處理事件。否則,監視器和系統可能會不同步。

檢視自動機定義,可以發現系統和模型在 preempt_enable 執行後預期會返回初始狀態。因此,它可以在監視部分初始化時用於同步系統和模型。

啟動透過一個特殊的處理函式通知,即“da_handle_start_event_$(MONITOR_NAME)(event)”,在本例中為

da_handle_start_event_wip(preempt_enable_wip);

因此,回撥函式將如下所示

void handle_preempt_enable(void *data, unsigned long ip, unsigned long parent_ip)
{
      da_handle_start_event_wip(preempt_enable_wip);
}

最後,“handle_sched_waking()”將如下所示

void handle_sched_waking(void *data, struct task_struct *task)
{
      da_handle_event_wip(sched_waking_wip);
}

解釋留給讀者作為練習。

啟用和停用函式

dot2k 自動建立兩個特殊函式

enable_$(MONITOR_NAME)()
disable_$(MONITOR_NAME)()

這些函式分別在監視器啟用和停用時被呼叫。

它們應該用於將插樁連線和分離到正在執行的系統。開發者必須在相關函式中新增所有需要將其監視器連線和分離到系統的操作。

對於 wip 情況,這些函式被命名為

enable_wip()
disable_wip()

但不需要更改,因為:預設情況下,這些函式會連線和分離 tracepoints_to_attach,這對於此情況已足夠。

插樁輔助函式

為了完成插樁,處理函式需要在監視啟用階段連線到核心事件。

RV 介面也方便了這一步驟。例如,宏“rv_attach_trace_probe()”用於將 wip 模型事件連線到相關的核心事件。dot2k 自動在啟用階段為每個模型事件新增“rv_attach_trace_probe()”函式呼叫,作為建議。

例如,來自 wip 示例模型

static int enable_wip(void)
{
      int retval;

      retval = da_monitor_init_wip();
      if (retval)
              return retval;

      rv_attach_trace_probe("wip", /* XXX: tracepoint */, handle_preempt_enable);
      rv_attach_trace_probe("wip", /* XXX: tracepoint */, handle_sched_waking);
      rv_attach_trace_probe("wip", /* XXX: tracepoint */, handle_preempt_disable);

      return 0;
}

探針需要在停用階段分離。

[1] wip 模型介紹於

Documentation/trace/rv/deterministic_automata.rst

wip 監視器介紹於

Documentation/trace/rv/da_monitor_synthesis.rst