代码之家  ›  专栏  ›  技术社区  ›  Mahmoud Al-Qudsi

随机完整系统无响应运行数学函数

  •  6
  • Mahmoud Al-Qudsi  · 技术社区  · 14 年前

    我有一个程序,它一次加载一个文件(从10MB到5GB),每个块执行一组数学运算(基本上计算散列值)。

    在计算散列之后,它将关于块的信息存储在STL映射中(基本上 <chunkID, hash> )然后将块本身写入另一个文件(writefile)。

    就这样。这个程序会导致某些PC卡死。鼠标开始结巴,任务管理器需要2分钟来显示,ctrl+alt+del没有响应,正在运行的程序很慢…作品。

    我已经尽了我所能优化程序,并对所有对象进行了三次检查。

    我所做的一切:

    • 尝试了不同的(不太密集的)散列算法。
    • 已将所有分配切换到nedmalloc,而不是默认的新运算符
    • 从stl::map切换到unordered_set,发现性能仍然很糟糕,所以我再次切换到谷歌的密集_hash_map。
    • 转换所有对象以存储指向对象的指针,而不是对象本身。
    • 缓存所有读写操作。我没有读取16K块文件并对其执行数学运算,而是将4MB读取到缓冲区,并从中读取16K块 那里 相反。所有写操作都是一样的-它们在写入磁盘之前被合并为4MB块。
    • 使用Visual Studio 2010、AMD代码分析师和Perfmon运行广泛的分析。
    • 将线程优先级设置为线程\模式\背景\开始
    • 将线程优先级设置为线程优先级空闲
    • 在每个循环之后添加了一个sleep(100)调用。

    即使在这之后 在某些情况下,应用程序仍会导致系统范围内的某些机器挂起。

    PerfMon和Process Explorer显示最小的CPU使用率(睡眠状态下),没有从磁盘进行持续的读/写,很少的硬页面故障(在5GB输入文件上,应用程序的生命周期内只有大约30K个页面故障),很少的虚拟内存(从不超过150MB),没有泄漏的句柄,没有内存泄漏。

    我在运行Windows XP上测试过的机器包括Windows 7、x86和x64版本。没有一个内存小于2GB,尽管在较低的内存条件下问题总是会恶化。

    我不知道下一步该怎么办。我不知道是什么造成的-我被CPU或内存撕裂成了罪魁祸首。CPU因为没有睡眠和不同的线程优先级,系统性能会发生显著的变化。内存,因为在使用无序集和谷歌密集散列图时,问题发生的频率有很大的不同。

    什么是真正奇怪的?显然,NT内核设计应该防止这种行为 曾经 正在发生(一个用户模式应用程序将系统驱动到这种极端糟糕的性能!……)但是,当我编译代码并在OS X或Linux上运行它(它是相当标准的C++)时,即使在没有RAM和较弱CPU的糟糕机器上,它也能很好地运行。

    接下来我该怎么办?我怎么知道当所有的指示器都显示应用程序本身并没有做任何极端的事情时,Windows在幕后做什么会破坏系统性能?

    任何建议都是最受欢迎的。

    6 回复  |  直到 14 年前
        1
  •  3
  •   Mark B    14 年前

    我知道你说过你监控过内存的使用,这里看起来很小,但是症状听起来很像是操作系统疯狂的抖动,这肯定会导致操作系统的响应能力像你看到的那样一般性的丧失。

    当您在一个文件上运行应用程序时,比如说可用物理内存大小的1/4到1/2,它是否工作得更好?

    我怀疑可能发生的情况是,Windows将磁盘读数据缓存到内存中“非常有用”,而不会将缓存内存放弃给应用程序使用,从而迫使它进行交换。因此,即使交换使用是最小的(150MB),在计算散列值时,它也会不断进出。然后,这就让系统屈服了。

        2
  •  1
  •   Skizz    14 年前

    要检查的一些事项:

    • 防病毒软件。这些文件经常在打开时扫描以检查病毒。在应用程序读取任何数据之前是否发生延迟?
    • 一般系统性能。使用资源管理器复制文件是否也显示此问题?
    • 您的代码。把它分成不同的阶段。编写一个只读取文件的程序,然后编写一个读写文件的程序,然后编写一个只散列随机RAM块(即删除磁盘IO部分)的程序,看看是否有任何特定的步骤有问题。如果您可以得到一个分析器,那么也可以使用它来查看代码中是否有任何慢点。

    编辑

    更多的想法。也许你的程序对gdi锁持有太多。这就解释了其他所有东西都很慢而没有高CPU使用率。一次只能有一个应用程序拥有gdi锁。这是一个GUI应用程序,还是只是一个简单的控制台应用程序?

    您还提到了rtlentercriticalsection。这是一个昂贵的操作,并且可以非常容易地挂起系统,即不匹配的进入和离开。你是多线程的吗?是否由于线程之间的竞争条件而减慢速度?

        3
  •  1
  •   Ana Betts    14 年前

    xperf是你的向导-看 PDC Video 关于它,然后追踪行为不端的应用程序。它会告诉你整个系统到底发生了什么,它非常强大。

        4
  •  1
  •   LarryW    14 年前

    我喜欢磁盘缓存/抖动建议,但如果不是这样,这里有一些零散的建议:

    如果有非MSVC库,您要链接到哪些库?

    您的程序是否可以修改(ifdef'd)以在没有GUI的情况下运行?问题是否发生?

    您在每个线程中的每个循环之后添加了::sleep(100),对吗?你在说多少线?一把还是几百?每个循环大概需要多长时间?如果你这样做会发生什么:睡眠(10000)?

    您的程序是否正在执行锁定有限资源的其他操作(ProcExp可以向您显示正在获取的句柄…当然,您可能很难不响应ProcExp:-[)

    您确定CriticalSections是仅限userland吗?我记得我以前在Windows上工作的时候(我相信是这样),但是微软可以修改它。我看不到MSDN文章中有任何保证 关键截面对象 ( http://msdn.microsoft.com/en-us/library/ms682530%28VS.85%29.aspx )这让我想到: Anti-convoy locks in Windows Server 2003 SP1 and Windows Vista

    六羟甲基三聚氰胺六甲醚。。。假设我们现在都是多处理器,那么你是在设置CS的自旋计数吗?

    运行其中一个操作系统的调试版本并监视内核调试输出(使用dbgview)如何?可能正在使用平台SDK中的内核调试器…如果微软仍然这么叫?

    我想知道vmmap(另一个sysinternal/ms实用程序)是否有助于磁盘缓存假设。

        5
  •  1
  •   Mahmoud Al-Qudsi    14 年前

    结果发现这是Visual Studio编译器中的一个bug。使用不同的编译器可以完全解决问题。

    在我的例子中,我安装并使用了英特尔C++编译器,即使所有优化都被禁用了,我也没有看到我正在体验WOR/Visual Studio 2005到2010编译器在这个库上的全系统挂起。

    我不确定是什么导致了编译器生成这样一个损坏的代码,但看起来我们会买一个英特尔编译器的副本。

        6
  •  0
  •   Community c0D3l0g1c    7 年前

    听起来你是在不知道问题所在的情况下到处找东西。 Take stackshots. 当问题发生时,他们会告诉你你的程序在做什么。如果问题发生在不能使用IDE或堆栈采样器的其他计算机上,那么获取stackshots可能不容易。一种可能是在应用程序运行时终止应用程序并获取堆栈转储。您需要在一个可以得到堆栈转储的环境中重现这个问题。


    补充:你说它在OSX和Linux上运行得很好,在Windows上运行得很差。我假设完成时间的比率是一个相当大的数字,比如10或100,如果你有耐心等待的话。我在评论中说过,但这是一个关键点。程序正在等待一些东西,您需要找出什么。这可能是人们提到的任何事情,但它是 不是随机的 .

    每一个程序在运行时,都有一个调用堆栈,由特定地址的调用指令层次结构组成。如果在某个时间点进行计算,则堆栈上的最后一条指令是非调用指令。如果它在I/O中,那么堆栈可能会进入一些您看不到的库调用级别。没关系。堆栈上的每个调用指令都在等待。它正在等待它要求完成的工作。如果您查看调用堆栈,并查看调用指令在哪里 你的代码 ,您将知道您的程序在等待什么。

    你的计划,因为它正在采取 这么久 完成,就是消费 几乎所有 在等待某件事情完成的时候,正如我所说,这就是你需要了解的。当速度慢的时候,得到一个堆栈转储,它会给你答案。它错过的概率是慢度比的1%。

    很抱歉这么简单, 但是很多人( 和探查器制造商 ) 不要得到它 . 他们认为他们必须测量。