使用perf测量到达main函数的时间?

Measure the time to reach the main function using perf?

我想通过测量到达主函数的时间来测量我的程序初始化时间,这样我就得到了"运行时初始化"的时间(例如,bss 部分设置为 0 并调用了全局构造函数) .

我如何使用 perf 来做到这一点?


将一些可以立即终止进程而很少或根本没有清理的东西,例如 exit_group,作为 main 中的第一件事,然后使用 perf stat(查看任务时钟)或简单地使用 time 来测量进程运行时间。

如果您不需要专门使用 perf,则一种非破坏性方法是使用 clock() 调用,它测量自进程启动以来的 CPU 时间以及对于大多数进程(不启动线程)或在 main 之前阻塞)如果您在 main 开始时发出它,则?等于在 main 之前花费的实际时间。

我经常使用 clock() 和 perf\\ 的 --delay 选项来将启动成本排除在测量之外。这实际上导致了第三种方法 - 在运行时使用和不使用排除启动的 --delay 参数时的统计数据差异。如果您想获取启动部分的时间以外的性能统计信息,这很有用。


首先,您必须考虑到 perf 并不真正测量时间 - 它记录事件。现在您可以进行一些分析并查看调用堆栈并得出一些有关初始化的信息,但是为了测量特定时间,我们需要记录开始和结束时间戳。

如果时间到达main函数,我们可以使用

1) main:

上的动态跟踪点

$ sudo perf probe -x ./gctor main Added new event:  probe_gctor:main (on main in ./gctor)perf record -e probe_gctor:main -aR sleepsudo perf record -e probe_gctor:main -e syscalls:sys_exit_execve ./gctor

         ^ this is what perf probe told you earlier# time of first sample : 77582.919313

# time of last sample : 77585.150377

# sample duration :  2231.064 ms

[....]

# ========

#

     gctor 238828 [007] 77582.919313: syscalls:sys_exit_execve: 0x0

     gctor 238828 [001] 77585.150377:     probe_gctor:main: (5600ea33414d)gdb ./gctor -ex 'b main' -ex 'python import time' -ex 'python ts=time.time()' -ex 'run' -ex 'python print(time.time()-ts)'[max@supernova:~/src/test] $ cat test.cc

#include <stdint.h>

#include <stdio.h>



extern uint64_t start_tsc;



int main() {

  uint64_t main_tsc = __builtin_ia32_rdtsc();

  printf("C/C++ run-time start took %lu cycles.\

", main_tsc - start_tsc);

}



[max@supernova:~/src/test] $ cat mystart.asm

    global mystart

    global start_tsc

    extern _start



    section .text

mystart:

    push rdx

    rdtsc

    shl rdx, 32

    or rax, rdx

    mov [rel start_tsc], rax

    pop rdx

    jmp _start



    section .data

start_tsc:

    dq 0



[max@supernova:~/src/test] $ make

g++ -o test.o -c -W{all,extra,error} -g -Og test.cc

nasm -felf64 -o mystart.o mystart.asm

g++ -o test -g -Wl,-emystart test.o mystart.o 



[max@supernova:~/src/test] $ ./test

C/C++ run-time start took 5314 cycles.

您现在可以在所有性能工具中使用它,例如:

$ sudo perf probe -x ./gctor main Added new event:  probe_gctor:main (on main in ./gctor)perf record -e probe_gctor:main -aR sleepsudo perf record -e probe_gctor:main -e syscalls:sys_exit_execve ./gctor

         ^ this is what perf probe told you earlier# time of first sample : 77582.919313

# time of last sample : 77585.150377

# sample duration :  2231.064 ms

[....]

# ========

#

     gctor 238828 [007] 77582.919313: syscalls:sys_exit_execve: 0x0

     gctor 238828 [001] 77585.150377:     probe_gctor:main: (5600ea33414d)gdb ./gctor -ex 'b main' -ex 'python import time' -ex 'python ts=time.time()' -ex 'run' -ex 'python print(time.time()-ts)'[max@supernova:~/src/test] $ cat test.cc

#include <stdint.h>

#include <stdio.h>



extern uint64_t start_tsc;



int main() {

  uint64_t main_tsc = __builtin_ia32_rdtsc();

  printf("C/C++ run-time start took %lu cycles.\

", main_tsc - start_tsc);

}



[max@supernova:~/src/test] $ cat mystart.asm

    global mystart

    global start_tsc

    extern _start



    section .text

mystart:

    push rdx

    rdtsc

    shl rdx, 32

    or rax, rdx

    mov [rel start_tsc], rax

    pop rdx

    jmp _start



    section .data

start_tsc:

    dq 0



[max@supernova:~/src/test] $ make

g++ -o test.o -c -W{all,extra,error} -g -Og test.cc

nasm -felf64 -o mystart.o mystart.asm

g++ -o test -g -Wl,-emystart test.o mystart.o 



[max@supernova:~/src/test] $ ./test

C/C++ run-time start took 5314 cycles.

这确实需要相当高的权限,我将在示例中使用 root。

2) 二进制文件的"开始"是一个明智的点。

我建议使用跟踪点 syscalls:sys_exit_execve。这基本上是在 perf record 开始执行您的二进制文件之后。这适用于我的版本(5.3.7) - 如果它不适合您,您可能需要修补。您当然可以只使用 -e cycles,但随后您会收到不想要的事件的垃圾邮件。

把它放在一起:

$ sudo perf probe -x ./gctor main Added new event:  probe_gctor:main (on main in ./gctor)perf record -e probe_gctor:main -aR sleepsudo perf record -e probe_gctor:main -e syscalls:sys_exit_execve ./gctor

         ^ this is what perf probe told you earlier# time of first sample : 77582.919313

# time of last sample : 77585.150377

# sample duration :  2231.064 ms

[....]

# ========

#

     gctor 238828 [007] 77582.919313: syscalls:sys_exit_execve: 0x0

     gctor 238828 [001] 77585.150377:     probe_gctor:main: (5600ea33414d)gdb ./gctor -ex 'b main' -ex 'python import time' -ex 'python ts=time.time()' -ex 'run' -ex 'python print(time.time()-ts)'[max@supernova:~/src/test] $ cat test.cc

#include <stdint.h>

#include <stdio.h>



extern uint64_t start_tsc;



int main() {

  uint64_t main_tsc = __builtin_ia32_rdtsc();

  printf("C/C++ run-time start took %lu cycles.\

", main_tsc - start_tsc);

}



[max@supernova:~/src/test] $ cat mystart.asm

    global mystart

    global start_tsc

    extern _start



    section .text

mystart:

    push rdx

    rdtsc

    shl rdx, 32

    or rax, rdx

    mov [rel start_tsc], rax

    pop rdx

    jmp _start



    section .data

start_tsc:

    dq 0



[max@supernova:~/src/test] $ make

g++ -o test.o -c -W{all,extra,error} -g -Og test.cc

nasm -felf64 -o mystart.o mystart.asm

g++ -o test -g -Wl,-emystart test.o mystart.o 



[max@supernova:~/src/test] $ ./test

C/C++ run-time start took 5314 cycles.

然后用perf script --header

查看

$ sudo perf probe -x ./gctor main Added new event:  probe_gctor:main (on main in ./gctor)perf record -e probe_gctor:main -aR sleepsudo perf record -e probe_gctor:main -e syscalls:sys_exit_execve ./gctor

         ^ this is what perf probe told you earlier# time of first sample : 77582.919313

# time of last sample : 77585.150377

# sample duration :  2231.064 ms

[....]

# ========

#

     gctor 238828 [007] 77582.919313: syscalls:sys_exit_execve: 0x0

     gctor 238828 [001] 77585.150377:     probe_gctor:main: (5600ea33414d)gdb ./gctor -ex 'b main' -ex 'python import time' -ex 'python ts=time.time()' -ex 'run' -ex 'python print(time.time()-ts)'[max@supernova:~/src/test] $ cat test.cc

#include <stdint.h>

#include <stdio.h>



extern uint64_t start_tsc;



int main() {

  uint64_t main_tsc = __builtin_ia32_rdtsc();

  printf("C/C++ run-time start took %lu cycles.\

", main_tsc - start_tsc);

}



[max@supernova:~/src/test] $ cat mystart.asm

    global mystart

    global start_tsc

    extern _start



    section .text

mystart:

    push rdx

    rdtsc

    shl rdx, 32

    or rax, rdx

    mov [rel start_tsc], rax

    pop rdx

    jmp _start



    section .data

start_tsc:

    dq 0



[max@supernova:~/src/test] $ make

g++ -o test.o -c -W{all,extra,error} -g -Og test.cc

nasm -felf64 -o mystart.o mystart.asm

g++ -o test -g -Wl,-emystart test.o mystart.o 



[max@supernova:~/src/test] $ ./test

C/C++ run-time start took 5314 cycles.

您可以从这两个样本中计算它,或者如果您的跟踪中确实只有两个样本,则使用 sample duration

为了完整性:这是一种使用 gdb:

的方法

$ sudo perf probe -x ./gctor main Added new event:  probe_gctor:main (on main in ./gctor)perf record -e probe_gctor:main -aR sleepsudo perf record -e probe_gctor:main -e syscalls:sys_exit_execve ./gctor

         ^ this is what perf probe told you earlier# time of first sample : 77582.919313

# time of last sample : 77585.150377

# sample duration :  2231.064 ms

[....]

# ========

#

     gctor 238828 [007] 77582.919313: syscalls:sys_exit_execve: 0x0

     gctor 238828 [001] 77585.150377:     probe_gctor:main: (5600ea33414d)gdb ./gctor -ex 'b main' -ex 'python import time' -ex 'python ts=time.time()' -ex 'run' -ex 'python print(time.time()-ts)'[max@supernova:~/src/test] $ cat test.cc

#include <stdint.h>

#include <stdio.h>



extern uint64_t start_tsc;



int main() {

  uint64_t main_tsc = __builtin_ia32_rdtsc();

  printf("C/C++ run-time start took %lu cycles.\

", main_tsc - start_tsc);

}



[max@supernova:~/src/test] $ cat mystart.asm

    global mystart

    global start_tsc

    extern _start



    section .text

mystart:

    push rdx

    rdtsc

    shl rdx, 32

    or rax, rdx

    mov [rel start_tsc], rax

    pop rdx

    jmp _start



    section .data

start_tsc:

    dq 0



[max@supernova:~/src/test] $ make

g++ -o test.o -c -W{all,extra,error} -g -Og test.cc

nasm -felf64 -o mystart.o mystart.asm

g++ -o test -g -Wl,-emystart test.o mystart.o 



[max@supernova:~/src/test] $ ./test

C/C++ run-time start took 5314 cycles.

这不太准确,在我的系统上大约有 100 毫秒的开销,但它不需要更高的权限。您当然可以通过在 C 中使用 fork/ptrace/exec 构建自己的跑步者来改进这一点。


另一种选择是提供您自己的可执行入口点,该入口点记录时间戳计数器,然后将控制权转移到标准入口点 _start。输入 main 后,您可以从现在减去它以获得 C 或 C 运行时启动的确切循环计数。

工作示例:

$ sudo perf probe -x ./gctor main Added new event:  probe_gctor:main (on main in ./gctor)perf record -e probe_gctor:main -aR sleepsudo perf record -e probe_gctor:main -e syscalls:sys_exit_execve ./gctor

         ^ this is what perf probe told you earlier# time of first sample : 77582.919313

# time of last sample : 77585.150377

# sample duration :  2231.064 ms

[....]

# ========

#

     gctor 238828 [007] 77582.919313: syscalls:sys_exit_execve: 0x0

     gctor 238828 [001] 77585.150377:     probe_gctor:main: (5600ea33414d)gdb ./gctor -ex 'b main' -ex 'python import time' -ex 'python ts=time.time()' -ex 'run' -ex 'python print(time.time()-ts)'[max@supernova:~/src/test] $ cat test.cc

#include <stdint.h>

#include <stdio.h>



extern uint64_t start_tsc;



int main() {

  uint64_t main_tsc = __builtin_ia32_rdtsc();

  printf("C/C++ run-time start took %lu cycles.\

", main_tsc - start_tsc);

}



[max@supernova:~/src/test] $ cat mystart.asm

    global mystart

    global start_tsc

    extern _start



    section .text

mystart:

    push rdx

    rdtsc

    shl rdx, 32

    or rax, rdx

    mov [rel start_tsc], rax

    pop rdx

    jmp _start



    section .data

start_tsc:

    dq 0



[max@supernova:~/src/test] $ make

g++ -o test.o -c -W{all,extra,error} -g -Og test.cc

nasm -felf64 -o mystart.o mystart.asm

g++ -o test -g -Wl,-emystart test.o mystart.o 



[max@supernova:~/src/test] $ ./test

C/C++ run-time start took 5314 cycles.

相关推荐

  • Spring部署设置openshift

    Springdeploymentsettingsopenshift我有一个问题让我抓狂了三天。我根据OpenShift帐户上的教程部署了spring-eap6-quickstart代码。我已配置调试选项,并且已将Eclipse工作区与OpehShift服务器同步-服务器上的一切工作正常,但在Eclipse中出现无法消除的错误。我有这个错误:cvc-complex-type.2.4.a:Invali…
    2025-04-161
  • 检查Java中正则表达式中模式的第n次出现

    CheckfornthoccurrenceofpatterninregularexpressioninJava本问题已经有最佳答案,请猛点这里访问。我想使用Java正则表达式检查输入字符串中特定模式的第n次出现。你能建议怎么做吗?这应该可以工作:MatchResultfindNthOccurance(intn,Patternp,CharSequencesrc){Matcherm=p.matcher…
    2025-04-161
  • 如何让 JTable 停留在已编辑的单元格上

    HowtohaveJTablestayingontheeditedcell如果有人编辑JTable的单元格内容并按Enter,则内容会被修改并且表格选择会移动到下一行。是否可以禁止JTable在单元格编辑后转到下一行?原因是我的程序使用ListSelectionListener在单元格选择上同步了其他一些小部件,并且我不想在编辑当前单元格后选择下一行。Enter的默认绑定是名为selectNext…
    2025-04-161
  • Weblogic 12c 部署

    Weblogic12cdeploy我正在尝试将我的应用程序从Tomcat迁移到Weblogic12.2.1.3.0。我能够毫无错误地部署应用程序,但我遇到了与持久性提供程序相关的运行时错误。这是堆栈跟踪:javax.validation.ValidationException:CalltoTraversableResolver.isReachable()threwanexceptionatorg.…
    2025-04-161
  • Resteasy Content-Type 默认值

    ResteasyContent-Typedefaults我正在使用Resteasy编写一个可以返回JSON和XML的应用程序,但可以选择默认为XML。这是我的方法:@GET@Path("/content")@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})publicStringcontentListRequestXm…
    2025-04-161
  • 代码不会停止运行,在 Java 中

    thecodedoesn'tstoprunning,inJava我正在用Java解决项目Euler中的问题10,即"Thesumoftheprimesbelow10is2+3+5+7=17.Findthesumofalltheprimesbelowtwomillion."我的代码是packageprojecteuler_1;importjava.math.BigInteger;importjava…
    2025-04-161
  • Out of memory java heap space

    Outofmemoryjavaheapspace我正在尝试将大量文件从服务器发送到多个客户端。当我尝试发送大小为700mb的文件时,它显示了"OutOfMemoryjavaheapspace"错误。我正在使用Netbeans7.1.2版本。我还在属性中尝试了VMoption。但仍然发生同样的错误。我认为阅读整个文件存在一些问题。下面的代码最多可用于300mb。请给我一些建议。提前致谢publicc…
    2025-04-161
  • Log4j 记录到共享日志文件

    Log4jLoggingtoaSharedLogFile有没有办法将log4j日志记录事件写入也被其他应用程序写入的日志文件。其他应用程序可以是非Java应用程序。有什么缺点?锁定问题?格式化?Log4j有一个SocketAppender,它将向服务发送事件,您可以自己实现或使用与Log4j捆绑的简单实现。它还支持syslogd和Windows事件日志,这对于尝试将日志输出与来自非Java应用程序…
    2025-04-161