当前位置: 首页 > 面试题库 >

如何描述Linux上运行的C ++代码?

赵明亮
2023-03-14
问题内容

我有一个正在Linux上运行的C ++应用程序,我正在对其进行优化。如何确定我的代码哪些区域运行缓慢?


问题答案:

如果您的目标是使用探查器,请使用建议的探查器之一。

但是,如果您急于在主观上很慢的情况下在调试器下手动中断程序,则有一种简单的方法可以查找性能问题。

暂停几次,每次查看调用堆栈。如果有一些代码浪费了一定百分比的时间(20%或50%或其他),那么这就是您在每次采样时都将其捕获的概率。因此,这大约是您将看到样品的百分比。不需要有根据的猜测。如果您确实怀疑问题出在哪里,这将证明或不证明它。

您可能会遇到多个不同大小的性能问题。如果清除其中任何一个,其余的将在以后的传递中占更大的比例,并且更容易发现。当放大多个问题时,这种放大效果会导致真正巨大的加速因素。

警告:除非他们自己使用过,否则程序员往往会对这种技术持怀疑态度。他们会说探查器会为您提供此信息,但是只有当他们对整个调用堆栈进行采样,然后让您检查随机的一组采样时,这才是正确的。(摘要是丢失洞察力的地方。)调用图不会为您提供相同的信息,因为

他们没有在教学水平上进行总结,并且
在递归存在的情况下,它们给出了令人困惑的摘要。
他们还会说,它实际上仅对玩具程序有效,而实际上对任何程序都有效,并且似乎在较大的程序上效果更好,因为它们往往会发现更多的问题。他们会说有时发现没有问题的东西,但这只有在您看到一次之后才是真的。如果您在多个样本上发现问题,那是真实的。

PS如果可以像Java中那样在某个时间点收集线程池的调用堆栈样本,也可以在多线程程序上完成。

PPS大致来说,软件中的抽象层越多,您越有可能发现这是性能问题的原因(并且有提高速度的机会)。

补充:可能并不明显,但是在递归存在的情况下,堆栈采样技术同样有效。原因是通过删除一条指令可以节省的时间近似于包含一条指令的样本所占的比例,而与该指令在一个样本中可能发生的次数无关。

我经常听到的另一个反对意见是:“它将在某个地方随机停止,并且将错过真正的问题”。这源于对实际问题有一个先验的概念。性能问题的一个关键特性是它们无法兑现预期。抽样告诉您某些问题,而您的第一个反应是难以置信。那是很自然的,但是您可以确定它是否发现了真正的问题,反之亦然。

补充:让我对它的工作原理进行贝叶斯解释。假设有一些指令I(调用或其他方式)在调用堆栈f上占时间的一部分(因此花费了很多)。为简单起见,假设我们不知道这f是什么,但是假设它是0.1、0.2、0.3,… 0.9、1.0,并且每种可能性的先验概率为0.1,因此所有这些成本都是一样的先验的。

然后假设我们仅取了2个堆栈样本,并且我们I在两个样本上都看到了指示,称为观察o=2/2。这给我们的频率的新的估计f的I,按照这样的:

Prior                                    
P(f=x) x  P(o=2/2|f=x) P(o=2/2&&f=x)  P(o=2/2&&f >= x)  P(f >= x | o=2/2)

0.1    1     1             0.1          0.1            0.25974026
0.1    0.9   0.81          0.081        0.181          0.47012987
0.1    0.8   0.64          0.064        0.245          0.636363636
0.1    0.7   0.49          0.049        0.294          0.763636364
0.1    0.6   0.36          0.036        0.33           0.857142857
0.1    0.5   0.25          0.025        0.355          0.922077922
0.1    0.4   0.16          0.016        0.371          0.963636364
0.1    0.3   0.09          0.009        0.38           0.987012987
0.1    0.2   0.04          0.004        0.384          0.997402597
0.1    0.1   0.01          0.001        0.385          1

                  P(o=2/2) 0.385                

最后一栏说,例如,f> = 0.5的概率为92%,高于先前假设的60%。

假设先前的假设是不同的。假设我们假设P(f=0.1)0.991(几乎可以肯定),那么所有其他可能性几乎都是不可能的(0.001)。换句话说,我们的先验I是便宜。然后我们得到:

Prior                                    
P(f=x) x  P(o=2/2|f=x) P(o=2/2&& f=x)  P(o=2/2&&f >= x)  P(f >= x | o=2/2)

0.001  1    1              0.001        0.001          0.072727273
0.001  0.9  0.81           0.00081      0.00181        0.131636364
0.001  0.8  0.64           0.00064      0.00245        0.178181818
0.001  0.7  0.49           0.00049      0.00294        0.213818182
0.001  0.6  0.36           0.00036      0.0033         0.24
0.001  0.5  0.25           0.00025      0.00355        0.258181818
0.001  0.4  0.16           0.00016      0.00371        0.269818182
0.001  0.3  0.09           0.00009      0.0038         0.276363636
0.001  0.2  0.04           0.00004      0.00384        0.279272727
0.991  0.1  0.01           0.00991      0.01375        1

                  P(o=2/2) 0.01375                

现在它说P(f >= 0.5)是26%,高于先前假设的0.6%。因此,贝叶斯允许我们更新对的可能费用的估算I。如果数据量很小,它并不能准确地告诉我们成本是多少,而只是告诉我们它足够大,值得修复。

另一种看待它的方法称为继承规则。如果您掷硬币两次,并且两次都出现正面,那么这可能告诉您硬币的权重是多少?尊重的回答方式是说它是Beta分布,具有平均值(number of hits + 1) / (number of tries + 2) = (2+1)/(2+2) = 75%

(关键是我们看到I不止一次。如果只看到一次,那么除了f> 0之外,其他信息就不多了。)

因此,即使是非常少量的样本也可以告诉我们有关它所看到的指令成本的很多信息。(而且将看到他们的频率,平均成比例的成本。如果n采取试样,f是成本,那么I将出现在nf+/-sqrt(nf(1-f))样品。实施例,n=10,f=0.3,即3+/-1.4样品)。

补充:为了直观地了解测量和随机堆栈采样之间的区别:
现在有分析器即使在墙上时钟时间对堆栈进行采样,但结果是测量(或热路径或热点,从中“瓶颈”很容易隐藏)。他们没有向您显示(并且很容易做到)是实际样本本身。而且,如果您的目标是找到瓶颈,那么平均而言,您需要查看的瓶颈数量为2除以所需的时间分数。因此,如果花费30%的时间,则平均将显示2 / .3 = 6.7个样本,而20个样本将显示99.2%的机会。

这是检验测量值和检验堆栈样本之间差异的现成插图。瓶颈可能是这样的一个大斑点,也可能是很多小的斑点,这没有什么区别。

测量是水平的;它告诉您特定例程花费的时间比例。采样是垂直的。如果有什么办法可以避免整个程序在那时的工作,并且在第二个示例中看到它,那么您已经找到了瓶颈。这就是与众不同的原因-查看花费时间的全部原因,而不仅仅是花多少时间。



 类似资料:
  • 问题内容: 我如何在Linux终端上执行C#代码作为Shell脚本。 我有以下示例代码: 当我运行shell bash时,我使用。使用C#怎么做? 问题答案: 该(hashbang)标签是用来告诉使用哪种解释让你的Perl,PHP,庆典,SH等脚本将正确运行shell。 但是C#不是脚本语言,它旨在被编译成可执行格式。如果要使用C#,则至少需要安装编译器和运行时,最好是安装IDE(集成开发环境)来

  • 问题内容: 我想找到在Linux中为某个进程打开的所有fds。 我可以使用glib库函数吗? 问题答案: 由于您使用的是Linux,因此(几乎可以肯定)已挂载了文件系统。这意味着最简单的方法是获取清单的内容; 其中的每个文件都以FD命名。(当然,请使用,并列出信息。) 否则获取信息会有些尴尬(例如,没有有用的POSIX API;这是一个尚未标准化的领域)。

  • 问题内容: 我正在使用epoll(边缘触发)和线程在线程网络服务器上工作,并且正在使用httperf对服务器进行基准测试。 到目前为止,它的性能确实非常好,或者几乎完全按照发送请求的速度执行。直到1024屏障为止,那里的所有内容都减慢到大约30个请求/秒。 在64位Ubuntu 9.04上运行。 我已经尝试过: 成功增加文件描述符的ulimit数量。只是并不能提高1024个并发连接以上的性能。 a

  • 有数百个jest测试文件,在每个单元测试文件中可能有多个块。 在每个

  • 问题内容: 您知道在Linux下运行C#项目的任何方法吗?是否有任何框架或库? 问题答案: 您正在寻找Mono项目 -.NET Framework和CLR的跨平台(但主要针对Linux)实现。它能够运行为CLR(MS .NET)编译的二进制文件,或创建自己的本机Linux二进制文件。 该项目已经进行了一段时间,即使是用于生产目的,它的当前版本(2.4)也非常有用。有关当前和将来版本的主要功能和里程

  • 问题内容: 有人告诉我,我的服务器拒绝在特定端口接受客户端网络连接可能是由于缺少文件描述符所致。我查找了所有内容,并在此处阅读了有关内容:http : //www.netadmintools.com/art295.html 所以我测试了我的系统,我得到了: 这是什么意思?我的限制很高,但是我有0个可用的文件描述符?为什么?如何为我的服务器解决此问题? 即使关闭服务器后,第二列实际上仍为0,甚至在引