cmake:每个事务单元的编译统计信息

问题描述 投票:0回答:5

我需要弄清楚哪些翻译单元需要重组以缩短编译时间,如何使用 cmake 为我的翻译单元掌握编译时间?

c++ compilation cmake build-tools
5个回答
47
投票

以下属性可用于计算编译器和链接器调用的时间:

这些属性可以在全局、每个目录和每个目标上设置。这样,您只能让一部分目标(例如测试)受到此属性的影响。此外,您还可以为每个目标设置不同的“启动器”,这也可能很有用。

请记住,直接使用“时间”是不可移植的,因为该实用程序并非在 CMake 支持的所有平台上都可用。然而,CMake 在其命令行工具模式中提供了“时间”功能。例如:

# Set global property (all targets are impacted)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time")
# Set property for my_target only
set_property(TARGET my_target PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time")

CMake 输出示例:

[ 65%] Built target my_target
[ 67%] Linking C executable my_target
Elapsed time: 0 s. (time), 0.000672 s. (clock)

请注意,从 CMake 3.4 开始,只有 Makefile 和 Ninja 生成器支持此属性。

另请注意,从 CMake 3.4 开始,

cmake -E time
存在参数内空格的问题。例如:

cmake -E time cmake "-GUnix Makefiles"

将被解释为:

cmake -E time cmake "-GUnix" "Makefiles"

我提交了解决此问题的补丁


11
投票

我希望用“time original-cmd”替换编译器(和/或链接器)。 使用简单的“make”,我会说:

make CC="time gcc"

“时间”程序将运行命令并报告所花费的时间。 等效的机制可以与“cmake”一起使用。 如果您需要捕获命令和时间,那么您可以编写自己的类似于时间的命令(shell 脚本即可),以您想要的方式记录您想要的数据。


8
投票

为了扩展之前的答案,这是我刚刚写的一个具体解决方案 - 也就是说,它在实践中绝对有效,而不仅仅是理论上,但它只被一个人使用了大约三分钟,所以它可能有一些不妥之处。

#!/bin/bash
{ time clang "$@"; } 2> >(cat <(echo "clang $@") - >> /tmp/results.txt)

我把上面两行放入

/tmp/time-clang
然后运行

chmod +x /tmp/time-clang
cmake .. -DCMAKE_C_COMPILER=/tmp/time-clang
make

您可以使用

-DCMAKE_CXX_COMPILER=
以完全相同的方式挂钩 C++ 编译器。

  • 我没有使用

    make -j8
    ,因为我不希望结果以奇怪的方式交错。

  • 我必须在我的脚本上放置一个显式的 hashbang

    #!/bin/bash
    ,因为 Ubuntu 12.04 上的默认 shell(
    dash
    ,我想?)对这些重定向运算符不满意。


1
投票

我认为最好的选择是使用:

set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "time -v")
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "time -v")

尽管上面已经说了:

请记住,直接使用“时间”是不可移植的,因为该实用程序并非在 CMake 支持的所有平台上都可用。然而,CMake提供了“时间”...... https://stackoverflow.com/a/34888291/5052296

如果您的系统包含它,使用

-v
标志您将获得更好的结果。

例如

time -v  /usr/bin/c++     CMakeFiles/basic_ex.dir/main.cpp.o  -o basic_ex 
    Command being timed: "/usr/bin/c++ CMakeFiles/basic_ex.dir/main.cpp.o -o basic_ex"
    User time (seconds): 0.07
    System time (seconds): 0.01
    Percent of CPU this job got: 33%
    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.26
    Average shared text size (kbytes): 0
    Average unshared data size (kbytes): 0
    Average stack size (kbytes): 0
    Average total size (kbytes): 0
    Maximum resident set size (kbytes): 16920
    Average resident set size (kbytes): 0
    Major (requiring I/O) page faults: 0
    Minor (reclaiming a frame) page faults: 6237
    Voluntary context switches: 7
    Involuntary context switches: 23
    Swaps: 0
    File system inputs: 0
    File system outputs: 48
    Socket messages sent: 0
    Socket messages received: 0
    Signals delivered: 0
    Page size (bytes): 4096
    Exit status: 0

0
投票

我无法使自定义步骤执行任何明智的操作,但为了收集编译和链接时间,我发现以下内容很有用。

接近顶层的起点

CMakeLists.txt

set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${PROJECT_SOURCE_DIR}/timecompile")
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${PROJECT_SOURCE_DIR}/timelink")

timecompile
在哪里

#!/bin/bash

filename=[unknown]

i=1
while [ ${i} -le $# ]
do
  eval x='$'{${i}}
  if [ "$x" == "-c" ]
  then
    i=$((i + 1))
    eval filename='$'{${i}}
    break
  fi
  i=$((i + 1))
done

{ cmake -E time "$@"; } | awk "{print \"Compile time (s) ${filename}: \" \$4}"

timelink

#!/bin/bash

if [ "`basename $1`" == "ar" -o "`basename $1`" == "ranlib" ]
then
  filename="$1 $2"
else
  filename=[unknown]
fi

i=1
while [ ${i} -le $# ]
do
  eval x='$'{${i}}
  if [ "$x" == "-o" ]
  then
    i=$((i + 1))
    eval filename='$'{${i}}
    break
  fi
  i=$((i + 1))
done

if [ "${filename}" == "[unknown]" ]
then
  echo "[unknown] link line: $@"
fi

{ cmake -E time "$@"; } | awk "{print \"Link time (s) ${filename}: \" \$4}"

灵感来自https://stackoverflow.com/a/33357776

© www.soinside.com 2019 - 2024. All rights reserved.