2

我目前正在将 VS2005 C++ 应用程序从 CE5 移植到 CE6,并且遇到了严重的性能问题。到目前为止,检索动态内容的单个 HTTP 请求在 CE5 上需要 40 毫秒,在 CE6 上需要 350 毫秒。由于我已经清理了一堆低效率,提高了两个系统的性能,这些值过去更糟,但目前我被困在那个延迟上。作为记录,这两项测试都是在同一台机器上进行的,并且网络服务器不是 CE 提供的服务器,而是用 C++ 实现的自定义服务器。另请注意,问题不在于网络 IO,CE6 在提供静态文件时甚至在同一台机器上的性能优于 CE5,而在于动态内容处理。

在试图弄清楚为什么程序执行如此糟糕的过程中,我偶然发现了一些让我感到困惑的事情:在 CE5 下,用于 x86 的 Interlocked* API 既不使用编译器内在函数,也不使用真正的函数调用,而是使用内联汇编代码。这段代码有一条注释说,内在函数包含仅多处理器系统需要的锁定前缀,并且会减慢仅在 CE5 等单核上运行的代码。在 CE6 上,这些函数是使用编译器内部函数(包括锁定前缀)实现的。由于这些函数被 Boost 和 STLport 等使用,它们都在网络服务器内部使用,我想知道这些函数是否是罪魁祸首。

我注意到的另一件事是一些字符串解析函数需要很长时间。更糟糕的是,似乎在第一次之后第二次调用相同的函数花费的时间更少,所以看起来好像正在进行某种缓存。由于这是一个通过 TCP 接收并在内存中解析的短字符串(<1kB),我无法想象哪个缓存可能对此负责。唯一的缓存可能是指令缓存,但程序不大于 CE5 版本,如果代码从未缓存的内存中运行,则不会显示这些缓存效果。

TLDR - 问题:

  • CE6 是否能够处理多个处理器?
  • 有没有一种简单的方法可以告诉编译器它应该省略锁定前缀?我目前实现这一目标的方法是简单地从 CE5 SDK 复制内联程序集,但这太难看了。
  • 我也很感激任何其他建议看什么或尝试什么。提前谢谢了!

总结依赖可执行文件没有问题,更不用说Interlocked API了。运行相同的可执行文件证明了这一点。但是,在具有不同平台设置的不同机器上运行会有所不同。我们现在回到 Platform Builder,试图找出两个平台之间的差异。

4

2 回答 2

2
  1. 否。 SMP 支持需要 WEC7。OEM 很可能在 CE6 中禁用了其他内核。

  2. 没有我知道的。

  3. 要么使用性能分析工具,要么使用计时调用来检测代码,以缩小耗时过长的地方。

于 2013-01-15T22:29:17.127 回答
1

我终于找到了性能行为的原因,它只是分页。CE6 有一个池管理器(请参阅http://blogs.msdn.com/b/ce_base/archive/2008/01/19/paging-and-the-windows-ce-paging-pool.aspx)处理未使用的分页映射的 DLL 和 EXE。当映射的二进制文件的数量超过一定大小时,它开始(以低优先级)页出内存。默认情况下,它开始分页时的限制仅为 3MiB,这对于当前的应用程序来说是相当低的。此外,缓存不是 LRU 缓存,只是按照页面加载的顺序丢弃页面。

事实证明,我们的系统超过了这个限制,导致分页开始。由于使用的算法,它总是会丢弃使用过的那些,然后必须再次调入。提供静态文件的代码很小,因此受此限制的影响不大。不过,为动态页面提供服务的代码要大得多,因此它会对 IO 的整个系统造成严重破坏。这也解释了为什么问题不能归因于特定的代码,不是代码本身,而是加载它。

我通过 IOCTL_HAL_GET_POOL_PARAMETERS 检测到了这一点,它给了我相关的配置参数、当前状态、pageout-thread 运行的频率以及多长时间(尽管后者只是换出页面所需的时间)。既然我知道我在寻找什么,我也应该能够在内核跟踪器中找到由此产生的页面错误。我还可以观察到 CF 卡适配器上的活动 LED 现在在首次加载文件时亮起,但在随后的请求中不会亮起,因为它是从缓存中获取的。这过去总是导致 LED 在动态页面上闪烁。

简单的解决方案是增加池管理器的限制,因此它不会开始扔东西。这可以通过使用相应值修补 kernel.dll 在 config.bib 中轻松完成。或者,减小可执行文件的大小会有所帮助,但这并不容易。

于 2013-01-29T22:28:44.533 回答