uprobe

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

前段时间在研究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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值