与命令行相比,来自 C 的 Dtrace 不会产生相同的分析结果

Posted

技术标签:

【中文标题】与命令行相比,来自 C 的 Dtrace 不会产生相同的分析结果【英文标题】:Dtrace from C does not yield same profiling result compared to command line 【发布时间】:2016-05-04 16:26:44 【问题描述】:

我想以编程方式从 C 跟踪 Node.js 的堆栈(JS 地址除外)。

以下命令为我提供了带有已解析 c++ 符号的堆栈。

sudo dtrace -C -n 'profile-101 /pid == 13221/  ustack() '

以下 C 代码仅返回 Node 的 C/C++ 代码的地址。什么是等价的?

#include <dtrace.h>
#include <signal.h>
#include <stdio.h>

struct ps_prochandle *g_pr;
static dtrace_hdl_t* g_dtp;

static int chewrec (const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg) 
   // A NULL rec indicates that we've processed the last record.
   if (rec == NULL) 
      return (DTRACE_CONSUME_NEXT);
   
   return (DTRACE_CONSUME_THIS);


static const char* g_prog =
  "#pragma D option switchrate=1000hz\n"
  "profile-1ms /pid == 13221/ \n"
    "ustack();\n"
  "";

static int g_intr;
static int g_exited;

static void intr (int signo) 
   g_intr = 1;



int main (int argc, char** argv) 
   int err;

   if ((g_dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) 
      fprintf(stderr, "failed to initialize dtrace: %s\n", dtrace_errmsg(NULL, err));
      return -1;
   
   printf("Dtrace initialized\n");

   (void) dtrace_setopt(g_dtp, "bufsize", "4m");
   (void) dtrace_setopt(g_dtp, "aggsize", "4m");

   printf("dtrace options set\n");

   dtrace_prog_t* prog;
   if ((prog = dtrace_program_strcompile(g_dtp, g_prog, DTRACE_PROBESPEC_NAME, DTRACE_C_CPP, 0, NULL)) == NULL) 
      fprintf(stderr, "failed to compile dtrace program\n");
      return -1;
    else 
      printf("dtrace program compiled\n");
   

   dtrace_proginfo_t info;
   if (dtrace_program_exec(g_dtp, prog, &info) == -1) 
      fprintf(stderr, "failed to enable dtrace probes\n");
      return -1;
    else 
      printf("dtrace probes enabled\n");
   

   struct sigaction act;
   (void) sigemptyset(&act.sa_mask);
   act.sa_flags = 0;
   act.sa_handler = intr;
   (void) sigaction(SIGINT, &act, NULL);
   (void) sigaction(SIGTERM, &act, NULL);

   if (dtrace_go(g_dtp) != 0) 
      fprintf(stderr, "could not start instrumentation\n");
      return -1;
    else 
      printf("instrumentation started ..\n");
   

   int done = 0;
   do 
      if (!g_intr && !done) 
         dtrace_sleep(g_dtp);
      

      if (done || g_intr || g_exited) 
         done = 1;
         if (dtrace_stop(g_dtp) == -1) 
            fprintf(stderr, "could not stop tracing\n");
            return -1;
         
      

      switch (dtrace_work(g_dtp, stdout, NULL, chewrec, NULL)) 
         case DTRACE_WORKSTATUS_DONE:
            done = 1;
            break;
         case DTRACE_WORKSTATUS_OKAY:
            break;
         default:
            fprintf(stderr, "processing aborted");
            return -1;
      
    while (!done);

   printf("closing dtrace\n");
   dtrace_close(g_dtp);

   return 0;

【问题讨论】:

有一个叫做ustack helpers的东西可以帮助你完成任务,但是你必须从你的代码中调用jstack()而不是ustack() @myaut 比这复杂一点,但无论如何感谢。不久前,我将其发布到 dtrace 邮件列表中,并附有以下答案,其中也包含您的组件 【参考方案1】:

来自 dtrace 邮件列表,Robert Mustacchi:

TL;DR在用户空间中自己解析符号。

“所以,所有的符号解析处理总是在用户空间完成。在 换句话说,内核中的 DTrace 只收集像 您正在查看使用 ustack 而不是 ustack 的情况 通过 jstack() 操作处理程序(jstack() 也只返回符号 非本地帧)。请注意,如果您想查看特定于 javascript 的 除了本地符号之外,您还需要使用 jstack() 在您的示例中,而不是 ustack()。

您可以执行这些映射的方式会有所不同,具体取决于 你在什么系统上。如果您查看 DTrace 在 illumos 上的作用 打印 ustack() 的结果 (http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libdtrace/common/dt_consume.c#1320), 然后你会看到它使用了 libproc 和 Plookup_by_addr() 函数 执行翻译。虽然值得指出的是 是稳定的接口,尽管它们很少改变。”

【讨论】:

以上是关于与命令行相比,来自 C 的 Dtrace 不会产生相同的分析结果的主要内容,如果未能解决你的问题,请参考以下文章

运维(21)- shell Linux核心命令

pthread_self() 中的 Pthread id 与 dtrace 脚本中的数据不匹配

DTrace `pid` 提供程序不会触发一些 `return` 探测

在 Oracle Linux 上使用 DTrace

在简单的逐行计算任务中,为啥犰狳与 C 风格的数组相比如此缓慢

C程序获取命令行参数