uftrace在arm平台的交叉编译使用介绍

uftrace

概述

uftrace 工具可用来跟踪和分析用 C/C++ 编写的程序。它深受 Linux 内核的 ftrace 框架(尤其是函数图跟踪器)的启发,并支持用户空间程序。它支持各种命令和过滤器来帮助分析程序的执行和性能。它的特性如下:

  • 它能跟踪可执行文件中的每个函数并显示持续时间,它也可以跟踪外部库调用(入口和出口),通常也支持外部库嵌套的外部库或者内部函数调用。
  • 它可以在功能级别显示详细的执行流程,并报告哪个函数的开销最高,它还显示了与执行环境相关的各种信息。
  • 可以设置过滤器,以便在跟踪时排除或包含特定函数。此外,它还可以保存和显示函数参数和返回值。
  • 它支持多进程和多线程应用程序。
  • 如果内核有启用函数图跟踪器(CONFIG_FUNCTION_GRAPH_TRACER=y),那么它还可以跟踪内核函数(使用 -k 选项)。

实践

toolchain:gcc-9.1.0-2019.11-x86_64_arm-linux-gnueabihf

下code

git clone https://github.com/namhyung/uftrace.git

编译

./configure --prefix=$PWD/output --host=arm-linux-gnueabihf 
make -j5
make install

生成布局为:

uftrace在arm平台的交叉编译使用介绍_第1张图片

运行

环境准备

  1. 板子挂载共享目录
ifconfig  eth0  up
ifconfig eth0  xxx.xxx.xxx.xxx
mount -t nfs xxx.xxx.xxx.xxx:/xxx /mnt -o nolock
  1. 将生成的 output/* 拷贝到共享目录的对应位置,板子上布局如下:

image-20200709171208050

  1. 编译二进制程序要带上 -pg 或者 -finstrument-functions,本文全程以下面的程序为例子:
//multi_thread.c
#include 
#include 

void *thread_funcA(void *arg)
{
    printf("%s:%d\n", __FUNCTION__, __LINE__);
    sleep(5);
    printf("%s:%d\n", __FUNCTION__, __LINE__);

    return NULL;
}

void *thread_funcB(void *arg)
{
    printf("%s:%d\n", __FUNCTION__, __LINE__);
    sleep(10);
    printf("%s:%d\n", __FUNCTION__, __LINE__);

    return NULL;
}

int main(void)
{
    pthread_t thidA;
    pthread_t thidB;

    printf("%s:%d\n", __FUNCTION__, __LINE__);
    pthread_create(&thidA, NULL, thread_funcA, "funcA");
    printf("%s:%d\n", __FUNCTION__, __LINE__);
    pthread_create(&thidB, NULL, thread_funcB, "funcB");
    printf("%s:%d\n", __FUNCTION__, __LINE__);
    pthread_join(thidA, NULL);
    printf("%s:%d\n", __FUNCTION__, __LINE__);
    pthread_join(thidB, NULL);
    printf("%s:%d\n", __FUNCTION__, __LINE__);

    return 0;
}

编译如下:

arm-linux-gnueabihf-gcc -pg multi_thread.c -lpthread -o multi_thread
  1. 将生成的 multi_thread 放到共享目录里
  2. 需要注意的是,uftrace 会在当前目录创建 fifo/utrace.data,如果是在 windows 共享目录下,会提示如下出错:

image-20200709172720988

​ 建议切到板子上的 /tmp 目录: cd /tmp

  1. 最后再设置一下环境变量和动态库路径就可以愉快玩耍了:
export PATH=/mnt/uftrace/bin:$PATH
export LD_LIBRARY_PATH=/mnt/uftrace/lib:$LD_LIBRARY_PATH

basic

目标程序执行完后,uftrace就会输出每个函数的执行时间。

uftrace /mnt/multi_thread

输出如下:

uftrace在arm平台的交叉编译使用介绍_第2张图片

filters

  • -F FUNC, --filter=FUNC

将过滤器设置为仅跟踪所选函数。

 uftrace -F sleep -F printf /mnt/multi_thread 

输出如下:

uftrace在arm平台的交叉编译使用介绍_第3张图片

  • -C FUNC, --caller-filter=FUNC

只显示所选函数的调用路径。

uftrace -C sleep -C printf /mnt/multi_thread 

输出如下:

uftrace在arm平台的交叉编译使用介绍_第4张图片

  • -N FUNC, --notrace=FUNC

设置过滤器不跟踪所选函数

uftrace -N printf /mnt/multi_thread 

输出如下:

uftrace在arm平台的交叉编译使用介绍_第5张图片

  • -t TIME, --time-filter=TIME

不显示设定时间阈值以下的短小函数。

uftrace  -t 1ms /mnt/multi_thread

uftrace在arm平台的交叉编译使用介绍_第6张图片

Arguments Detection with Debug Info

使用 -a/--auto-args 去侦测带调试信息的二进制程序的函数参数和返回值。

uftrace -a /mnt/multi_thread 

输出如下:

uftrace在arm平台的交叉编译使用介绍_第7张图片

uftrace record

可以记录下 trace data,便于后续分析。

uftrace record /mnt/multi_thread

生成如下:

uftrace在arm平台的交叉编译使用介绍_第8张图片

uftrace replay

可以回放对应的trace data,默认是回放当前目录的 uftrace.data。

uftrace replay

uftrace report

打印 trace data 的统计信息和摘要,默认是打印当前目录的 uftrace.data。

  • basic
uftrace report

输出如下:

uftrace在arm平台的交叉编译使用介绍_第9张图片

  • -s

该选项可选择按 total time/self time/calls 进行降序排序,默认按 total 降序排序。

  1. 按 total time 降序排序
uftrace report -s total

输出如下:

uftrace在arm平台的交叉编译使用介绍_第10张图片

  1. 按 self time 降序排序
uftrace report -s self

uftrace在arm平台的交叉编译使用介绍_第11张图片

  1. 按 calls 降序排序
uftrace report -s call

uftrace在arm平台的交叉编译使用介绍_第12张图片

uftrace graph

显示函数调用图,默认是显示当前目录的 uftrace.data。

uftrace graph

输出如下:

uftrace在arm平台的交叉编译使用介绍_第13张图片

总结

uftrace还有很多强大的特性,比如通过 dump 命令生成相应 trace data,可拿到 chrome 浏览器可视化展示或者生成火焰图;如果 configure 包含了 python,还可以编写 python 脚本定义函数入口和出口的钩子函数;如果编译加上 -mnop-mcount,还可以实现运行时动态跟踪;如果 configure 包含了 capstone,那可以实现完全动态跟踪,而不用编译器支持。因此 uftrace 还是值得尝试一下。

参考

  1. github 主页
  2. 详细的官网 PPT
  3. 官网教程

你可能感兴趣的:(c,c++,linux)