【问题标题】:strace -f on own recursive c++ program won't workstrace -f 在自己的递归 C++ 程序上不起作用
【发布时间】:2019-04-14 11:08:06
【问题描述】:

所以我有一个简单的递归 c++ 程序,非常基础:

#include <iostream>

int fibonacciRec(int no) {
    if (no == 0 || no == 1)
        return no;
    else
        return fibonacciRec(no-1) + fibonacciRec(no-2);
}

int main(int argc, char** argv) {
    int no = 42;
    for (int i = 1; i <= no; i++) {
        std::cout << fibonacciRec(i-1) << " ";
    }
    std::cout << std::endl;
    return 0;
}

现在我想在这个程序上运行strace,显示所有的系统调用。基本上我想看到很多 mmap 等,但是一旦调用第一个循环,strace -f 就会停止跟随系统调用,只显示最后一个 write 调用。 strace -c 也给出了不太可能的数字,因为程序需要超过 4-6 秒的时间来计算:

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
60.47    0.000078          78         1           munmap
26.36    0.000034          11         3           brk
13.18    0.000017           3         6           fstat
 0.00    0.000000           0         4           read
 0.00    0.000000           0         1           write
 0.00    0.000000           0         5           close
 0.00    0.000000           0        14           mmap
 0.00    0.000000           0        10           mprotect
 0.00    0.000000           0         6         6 access
 0.00    0.000000           0         1           execve
 0.00    0.000000           0         1           arch_prctl
 0.00    0.000000           0         5           openat
 ------ ----------- ----------- --------- --------- ----------------
 100.00    0.000129                    57         6 total

【问题讨论】:

  • strace -c 输出仅显示 系统调用 中的时间,而不是程序其余部分的时间。如果您想要非系统调用的时间,那么也许使用 profiler?
  • 至于strace -f 的问题,如果你降低循环的限制(即no 的值要小得多),那么strace -f 的输出可能小到可以在里面发布问题本身。这样我们就更容易知道发生了什么。

标签: c++ linux system-calls strace


【解决方案1】:

fibonacciRec 正在运行时,不需要任何 mmap 或任何其他系统调用。

唯一可能分配的内存是用于递归调用的堆栈内存,有几个原因导致您没有出现在 strace 中:

  • 真的不是很多内存。您的最大递归深度约为 42,并且您只有 1 个局部变量,因此堆栈帧很小。递归期间分配的总堆栈可能少于 1 页。
  • 即使是大量内存,堆栈分配也只会增长,不会缩小,因此您会看到它很快增长到最大值,然后在那里停留很长时间。不会是洪水。
  • 堆栈分配无论如何都不是通过系统调用完成的。要向内核请求更多堆栈,您所要做的就是假装您已经拥有它。内核捕获页面错误,注意到错误地址在您现有的堆栈附近,并分配更多。透明到连strace都看不到。

除了调用自身并返回一个值,fibonacciRec 除了操作局部变量之外什么都不做。没有系统调用。

【讨论】:

  • C++提供动态内存和自动内存。它包括一个“std::stack”容器,但从来没有(我认为)一个“堆栈”,也没有一个“堆”。 Linux 有一个堆栈,在 Lubuntu 18.04 上,每个线程的默认大小为 8 M 字节。我从未见过 Linux 页面错误会增加堆栈大小的想法。
  • @2785528 你可以在这里看到它,例如:unix.stackexchange.com/questions/145557/… 你的 8M 是一个限制。堆栈从小开始并按需增长。如果超出限制,您将收到段错误。通过检查/proc/$PID/maps 可以找到进程的当前堆栈大小
  • 非常好...谢谢你的参考。你向我展示了一些需要调查的新东西。我做了实验来增加堆栈直到发生某些事情,但我的实验总是强制出错(不记得是哪个)。我确实发现并确认我可以在运行我的应用程序之前更改命令行上的限制。
  • @Simon - 以下站点显示了一些可能的命令,用于为您的下一次试用设置更大的 ulimit nics.tennessee.edu/faq/…。在某些硬件上还有一个叫做硬限制的东西。我用“linux,如何设置堆栈限制”搜索。
  • 谢谢大家;我想我现在对记忆组织有了更多的了解。谢谢 wumpus。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 2019-06-28
  • 1970-01-01
  • 2016-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多