问题描述
在我们的代码库中有一个方法可以正常工作,但不能再修改(
void XXX :: setCSVFileName()
{
//获取当前工作目录
char the_path [1024]
getcwd(the_path,1023);
printf(current dir:%s \\\
,the_path);
std :: string currentPath(the_path);
std :: string currentPathTmp = currentPath +/ tmp _+ pathSetParam-> pathSetTravelTimeTmpTableName;
std :: string cmd =mkdir -p+ currentPathTmp;
if(system(cmd.c_str())== 0)//停在这里
{
csvFileName = currentPathTmp +/+ pathSetParam-> pathSetTravelTimeTmpTableName +.csv;
}
// ...
}
调试它,发现原因是 if(system(cmd.c_str())== 0)
。我在那条线上放了一个断点,试图 跳过。它只是呆在那里。
调试程序显示的 cmd
的值为:
我不知道系统在做什么,但我的应用程序在 top
显示大约100%的CPU使用率。
您是否遇到过这种情况?
重要更新
像往常一样,我开始还原我的代码更改一个接一个地回到问题之前的状态。令人惊讶的是,我发现了问题(但不是解决方案....)。
我添加了 -pg 到我的编译选项 gprof
。这就是造成这个问题的原因。
可能你有一些知识为什么 gropf
不行 system
或 mkdir
??
感谢
$ b 您需要使用gprof来支持您自己的分析器生成的结果。 $ b
换句话说,你想写一个profiler,并将其与gprof进行比较,你会质疑 -pg
标志是否使 system
挂起。
我说的是忘记了 -pg
标志。所有这一切都是gprof的调用计数代码在编译器看到的函数中。
如果我是你,我会找到更好的比较你的profiler。
请记住,人们使用分析器的典型原因是查找加速比 ,
,他们可能认为收集测量结果将有助于他们这样做。
它不。
它做什么,而是说服他们没有加速器被发现。
(他们问 new
占用了5%的时间,这是我的瓶颈,我该如何加速?)
这是gprof为我们做的。
这里有一个分析器功能表,从差到更好到最好:
gprof perf zoom pausing
示例程序计数器| X | X | X | X |
显示self%by function | X | X | X | X |
显示包含%by function | | X | X | X |
samples stack | | X | X | X |
检测额外调用| | X | X | X |
显示self%by line | | X | X | X |
显示包含%by line | | ? | X | X |
正确处理递归| | ? | X | X |
采样在挂钟时间| | | X | X |
让你检查样品| | | | X |
这些重要的原因是,加速是非常好的隐藏profilers:
- 如果%by行未显示,则加速可能是大函数中的任何位置。
- 如果样本未按挂钟时间进行,则无法显示外部I / O或阻止。
- 如果显示了call-graph,则加速可以隐藏在其中,而不是本地化到A调用B,例如通过
$ b
但他们不能简单地检查堆栈样本。
下面是加速器如何隐藏分析器的一些示例。
如果分析器显示热路径,它只显示堆栈样本的一小部分,因此它只能显示小问题。
但是,如果只比较堆栈样本的相似性,而不是平等,则可能存在一个很大的问题:
加速也可以隐藏在调用图中,因为在这种情况下A1总是呼叫C2和A2,总是呼叫C1被隧道功能B(其可以是多个层)遮蔽。
调用堆栈显示在右边,并且人类容易识别该模式:
在这种情况下,A总是调用C的事实被A遮蔽
再次,该模式在调用堆栈中很容易识别:
另一种方法是如果堆栈样本显示很多时间花费在调用具有相同名称但属于不同类(因此是不同的函数)或具有不同名称但是通过相似目的相关的函数。
在分析器中,这些阴谋将时间分成少量,告诉你没有什么大事。
这是人们寻找缓慢功能的结果,这实际上是一种盲人的形式。
There is a method in our codebase which used to work fine, but not any more(without any modification to this method):
void XXX::setCSVFileName()
{
//get current working directory
char the_path[1024];
getcwd(the_path, 1023);
printf("current dir: %s \n",the_path);
std::string currentPath(the_path);
std::string currentPathTmp = currentPath + "/tmp_"+pathSetParam->pathSetTravelTimeTmpTableName;
std::string cmd = "mkdir -p "+currentPathTmp;
if (system(cmd.c_str()) == 0) // stops here
{
csvFileName = currentPathTmp+"/"+pathSetParam->pathSetTravelTimeTmpTableName + ".csv";
}
//...
}
I tried to debug it and found the culprit line to be if (system(cmd.c_str()) == 0)
. I put a breakpoint on that line and tried to step over it. it just stays there.The value of cmd
as debugger shows is:
I dont know what the system is doing but my application in top
shows around 100% cpu usage.Have you ever hit such a situation?
IMPORTANT UPDATEAs usual, I started reverting changes in my code one-by-one back to the state prior to the problem. Surprisingly, I found the problem(but not the solution....yet).
I added -pg to my compilation options to enable gprof
. and that is what caused the issue.
May be you have some knowledge of why gropf
doesn't line system()
or mkdir
??
thanks
You said in a comment on your other question that you needed to use gprof to support the results generated by your own profiler.
In other words, you want to write a profiler, and compare it to gprof, and you're questioning if the -pg
flag is making system
hang.
I'm saying forget about the -pg
flag. All that does is put call-counting code for gprof in the functions the compiler sees.
If I were you I would find something better to compare your profiler to.Remember the typical reason why people use a profiler is to find speedups,and they may think collecting measurements will help them do that.It doesn't.What it does instead is convince them there are no speedups to be found.(They ask questions like "new
is taking 5% of the time, and that's my bottleneck, how can I speed it up?")That's what gprof has done for us.
Here's a table of profiler features, from poor to better to best:
gprof perf zoom pausing
samples program counter | X | X | X | X |
show self % by function | X | X | X | X |
show inclusive % by function | | X | X | X |
samples stack | | X | X | X |
detects extra calls | | X | X | X |
show self % by line | | X | X | X |
show inclusive % by line | | ? | X | X |
handles recursion properly | | ? | X | X |
samples on wall-clock time | | | X | X |
let you examine samples | | | | X |
The reason these are important is that speedups are really good at hiding from profilers:
- If % by line not shown, speedup may be anywhere in a large function.
- If inclusive % not shown, extraneous calls are not seen.
- If samples not taken on wall-clock time, extraneous I/O or blocking not seen.
- If hot-path is shown, speedups can hide on either side of it.
- If call-graph is shown, speedups can hide in it by not being localized to A calls B, such as by a "tunnel" function.
- If flame-graph is shown, speedups can hide in it by not aggregating samples that could be removed.
But they can't hide from simply examining stack samples.
P.S. Here are some examples of how speedups can hide from profilers.
If the profiler shows a "hot-path", it only shows a small subset of the stack samples, so it can only show small problems.But there could be a large problem that would be evident if only comparing stack samples for similarity, not equality:
Speedups can also hide in call graphs, as in this case the fact that A1 always calls C2 and A2 always calls C1 is obscured by the "tunnel function" B (which might be multiple layers).The call stacks are shown on the right, and a human recognizes the pattern easily:
In this case, the fact that A always calls C is obscured by A calling any of a number of Bi functions (possibly over multiple layers) that then call C.Again, the pattern is easily recognized in call stacks:
Another way is if the stack samples show that a lot of time is spent calling functions that have the same name but belong to different classes (and are therefore different functions), or have different names but are related by a similar purpose.
In a profiler these conspire to divide the time into small amounts, telling you there is nothing big going on.That's a consequence of people "looking for slow functions" which is actually a form of blinders.
这篇关于系统(mkdir)挂在我的应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!