uprobe试用小结

来源:互联网 发布:哪个cms好 编辑:程序博客网 时间:2024/05/01 14:14

项目上需要分析用户态程序的性能,开发人员一般的方式是在程序内部实现打点函数,记录当程序运行到该点的时间戳,通过比较两点之间的时间间隔来估计两点之间的时间消耗。这样一方面增加了开发的工作量,另外这些打点也会给业务带来额外性能消耗,是否有另外的方式来解决该问题呢?

前段时间在研究ftrace,发现其还有个uprobe特性,故名思意就是用户态的探针工具,今天尝试了下uprobe的使用,小结如下:


1.编写小测试程序如下:

#include <stdlib.h>
#include <stdio.h>

int count = 0;

void do_sth()
{
        printf("current count = %d\n", count);
        count++;
}

int main(int argc, char* argv[])
{
        while(1)
        {
                do_sth();
        }

        return 0;
}


2.运行测试程序并找到需要probe的函数符号偏移量

root@X200:/home/kernel_test# objdump -t loop_print | grep do_sth
000000000040052d g     F .text    000000000000002c              do_sth
root@X200:/home/kernel_test# ./loop_print 1>/dev/null &
[1] 28481
root@X200:/home/kernel_test# pgrep loop_print
28481
root@X200:/home/kernel_test# man pgrep
root@X200:/home/kernel_test# cat /proc/28481/maps | grep loop_print | grep r-xp
00400000-00401000 r-xp 00000000 08:01 2885775                            /home/kernel_test/loop_print

3.配置uprobe事件

echo 'p:do_sth /home/kernel_test/loop_print:0x52d %ip %ax' > /sys/kernel/debug/tracing/uprobe_events
echo 'r:do_sth_exit /home/kernel_test/loop_print:0x52d %ip %ax' >> /sys/kernel/debug/tracing/uprobe_events

uprobe的事件格式如下:
  p[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a uprobe
  r[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a return uprobe (uretprobe)
  -:[GRP/]EVENT                           : Clear uprobe or uretprobe event

  GRP           : Group name. If omitted, "uprobes" is the default value.
  EVENT         : Event name. If omitted, the event name is generated based
                  on PATH+OFFSET.
  PATH          : Path to an executable or a library.
  OFFSET        : Offset where the probe is inserted.

  FETCHARGS     : Arguments. Each probe can have up to 128 args.
   %REG         : Fetch register REG
   @ADDR        : Fetch memory at ADDR (ADDR should be in userspace)
   @+OFFSET     : Fetch memory at OFFSET (OFFSET from same file as PATH)
   $stackN      : Fetch Nth entry of stack (N >= 0)
   $stack       : Fetch stack address.
   $retval      : Fetch return value.(*)
   +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**)
   NAME=FETCHARG     : Set NAME as the argument name of FETCHARG.
   FETCHARG:TYPE     : Set TYPE as the type of FETCHARG. Currently, basic types
                       (u8/u16/u32/u64/s8/s16/s32/s64), "string" and bitfield
                       are supported.

  (*) only for return probe.
  (**) this is useful for fetching a field of data structures.
其中FETCHARGS是每次执行到probe点的时候需要抓取的数据,其输出格式在/sys/kernel/debug/tracing/events/uprobes/do_sth/format中定义。

4.启动用户态探针

echo 1 > /sys/kernel/debug/tracing/events/uprobes/enable

5.查询探针结果

cat /sys/kernel/debug/tracing/trace | less

# tracer: nop
#
# entries-in-buffer/entries-written: 72053/1766702004   #P:2
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
      loop_print-28481 [001] d...  5590.582582: do_sth: (0x40052d) arg1=0x40052d arg2=0x0
      loop_print-28481 [001] d...  5590.582585: do_sth_exit: (0x400572 <- 0x40052d) arg1=0x400572 arg2=0x4df27b17
      loop_print-28481 [001] d...  5590.582586: do_sth: (0x40052d) arg1=0x40052d arg2=0x0
      loop_print-28481 [001] d...  5590.582589: do_sth_exit: (0x400572 <- 0x40052d) arg1=0x400572 arg2=0x4df27b18
      loop_print-28481 [001] d...  5590.582590: do_sth: (0x40052d) arg1=0x40052d arg2=0x0
      loop_print-28481 [001] d...  5590.582593: do_sth_exit: (0x400572 <- 0x40052d) arg1=0x400572 arg2=0x4df27b19
      loop_print-28481 [001] d...  5590.582594: do_sth: (0x40052d) arg1=0x40052d arg2=0x0
      loop_print-28481 [001] d...  5590.582597: do_sth_exit: (0x400572 <- 0x40052d) arg1=0x400572 arg2=0x4df27b1a
      loop_print-28481 [001] d...  5590.582598: do_sth: (0x40052d) arg1=0x40052d arg2=0x0
      loop_print-28481 [001] d...  5590.582600: do_sth_exit: (0x400572 <- 0x40052d) arg1=0x400572 arg2=0x4df27b1b
      loop_print-28481 [001] d...  5590.582602: do_sth: (0x40052d) arg1=0x40052d arg2=0x0
      loop_print-28481 [001] d...  5590.582604: do_sth_exit: (0x400572 <- 0x40052d) arg1=0x400572 arg2=0x4df27b1c

从以上输出可以看出进入函数和退出函数的时间轨迹。另外可以通过修改用户探针命中时指定的行为FETCHARGS来获取更多信息,比如观测全局变量变化等。


后注:

尝试了下uprobe的事件是否能和内核事件同时启用,发现启用一个另一个会自动关闭,因此无法看到进程包含核心态及用户态整体运行时间轨迹。

0 0
原创粉丝点击