首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >_L_unlock_16的性能瓶颈

_L_unlock_16的性能瓶颈
EN

Stack Overflow用户
提问于 2013-07-08 10:43:48
回答 1查看 304关注 0票数 0

我正在尝试使用google工具CPU分析器来调试多线程程序上的性能问题。对于单线程,它需要250 ms,而4个线程大约需要900 ms。

我的程序有一个mmap‘’ed文件,它是跨线程共享的,所有操作都是只读的。另外,我的程序创建了大量的对象,这些对象不是在线程之间共享的。(具体来说,我的程序使用CRF++库进行一些查询)。我正试图找出如何使我的程序更好地执行多线程。gperf工具的CPU分析器生成的调用图显示,我的程序在_L_unlock_16上花费了大量时间(约50%)。

搜索_L_unlock_16时,会发现一些带有规范的bug报告,这表明它与libp线程有关。但除此之外,我无法找到任何有用的信息进行调试。

对我的程序做了一个简短的描述。我在档案里没有几个字。在我的程序中,我有一个processWord(),它使用CRF++处理一个单词。这个processWord()是每个线程执行的内容。main()从文件中读取单词,每个线程并行运行processWord()。如果我处理一个单词(因此只有一个线程),它需要250 ms,因此,如果我处理所有4个单词(因此,4个线程),我期望它在同一时间完成250 ms,但正如我前面提到的,它大约需要900毫秒。这是执行的调用图- n2.png

我想了解为什么我的程序要花很多时间在_L_unlock_16上,以及我能做些什么来减轻它。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-07-08 12:40:08

同样,_L_unlock_16不是代码的函数。您看过上面的stracktraces 函数吗?当程序等待时,它的调用者是什么?你说过这个计划浪费了50%的时间在里面等着。但是,程序的哪一部分命令了这一操作?是不是又是从内存分配/去分配操作?

函数似乎来自libp线程。CRF+以任何方式处理线程/ Does线程吗?如果是,那么可能库配置错误?或者,它可能通过在任何地方添加锁来实现一些“基本线程安全”,而不是为多线程构建得很好?医生是怎么说的?

就我个人而言,我猜它会忽略线程,并且您已经添加了所有线程。我可能错了,但如果是这样的话,那么CRF++可能根本不会调用“解锁”函数,而“解锁”是从您的代码中调用的,这些代码编排了线程/锁/队列/消息等?停止程序几次,看看是谁发出的解锁。如果它真的花了50%的时间坐在解锁上,你很快就会知道是谁让锁被使用了,你可以消除它,或者至少进行一项更精细的研究。

编辑#1:

嗯..。当我说“堆栈跟踪”时,我指的是堆栈跟踪,而不是调用图。cases在一些琐碎的情况下可能看起来不错,但在更复杂的情况下,它会被破坏和无法读懂,并且会将宝贵的细节隐藏在“压缩”的形式中。不过,幸运的是,这个案子看起来很简单。

请注意开头:“处理单词,99x”。我假设"99x“是呼叫计数。然后,看看“”:97x。从这一点来看:

  • 61x进入rebuildFeatures,41x直接进入解锁,20(13)间接进入解锁
  • 23x从buildLattice进入解锁,其中21x进入解锁

我猜可能是CRF++使用的锁太重了。对我来说,你似乎只是观察CRF内部锁定的效果。当然,它内部也不是没有锁的。

它似乎在"processWord“中至少锁定了一次。如果不看代码就很难说了(这是开源吗?)),但是如果它真的在每个"processWord“中锁定一次,那么它甚至可能是一种”全局锁“,它保护”所有“不受”所有线程“的影响,并导致所有作业序列化。管他呢。不管怎么说,显然是CRF++的内部锁和等待。

如果您的CRF对象实际上不是跨线程共享的(确实是),那么从CRF中删除线程配置标志,祈祷它们足够正常,不使用任何静态变量或全局对象,在最顶层的作业/结果级别添加一些自己的锁定(如果需要的话),然后重试。你现在应该快得多。

如果CRF对象是共享的,则取消它们的共享,并参见上面的内容。

但是,如果它们是在幕后共享的,那么就没有什么可行的了。将库更改为具有更好的线程支持的库,或修复库,或忽略库,并在当前性能的情况下使用它。

最后的建议听起来可能很奇怪(它慢慢地起作用,对吗?)那么,为什么要忽略它呢?),但实际上是最重要的,你应该先尝试一下。如果并行任务具有相似的“数据配置文件”,那么它们很有可能在相同的时间内试图命中相同的锁。想象一下,一个中等大小的缓存保存了按其第一个字母排序的单词。在托普莱尔,有26条条目。每个条目都有一个锁和一个单词列表。如果您运行100个线程,每个线程首先检查“妈妈”,然后是“爸爸”,然后是“子”--那么这100个线程首先在"M“处单击并等待对方,然后在"D”然后在"S“处等待。嗯,大概.当然了。但你知道这个主意。如果数据配置文件是比较随机的,那么它们之间的阻塞就会少得多。请记住,处理一个单词是一个..。小任务,你试着处理同一个单词。即使内部CRF的锁定是聪明的,它肯定会击中相同的领域。使用更分散的数据再试一次。

再加上线程花费了这个事实。如果有什么东西是防止使用锁的比赛,那么每个锁/解锁成本,因为至少他们必须“停止和检查锁是否打开”(抱歉,非常不准确的措辞)。如果数据到进程相对于锁检查的数量很小,那么添加更多的线程不会有帮助,只会浪费时间。为了检查一个单词,甚至可能会发生这样的情况:对单个锁的唯一处理要比处理该单词花费的时间长!但是,如果要处理的数据量更大,那么与处理数据相比,翻转锁的成本可能会被忽略。

准备一套100个或更多单词。运行并在一个线程上测量它。然后随机划分单词,并在2和4个线程上运行它。以及测量。如果不是更好的话,试着用1000字和10000字。当然,越好越好,记住考试不应该持续到下一个生日;)

如果您注意到10k字分裂成4个线程(2500 w/ th)工作约40%-30%-甚至比一个线程快25% -在这里!你给了它一份太小的工作。它是为更大的人量身定做和优化!

但是,另一方面,在4个线程上拆分10k字可能不会工作得更快,或者更糟的是,工作速度更慢--这可能表明库处理多线程非常错误。现在,尝试其他的事情,如从它剥离线程或修理它。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17524652

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档