65.9K
CodeProject 正在变化。 阅读更多。
Home

VC2005 CRT (x86/IA64) 性能提升

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.84/5 (14投票s)

2005 年 12 月 1 日

3分钟阅读

viewsIcon

39867

downloadIcon

175

VC2005 的 CRT 中存在性能下降的问题;本文将介绍为了获得“更快”的 CRT 所需做的更改。

前导码

本文基于一个微型基准测试,该测试与*实际*应用程序*完全无关*!此处展示的代码仅会提高 CRT 中一个小型函数 (_getptd_noexit) 的速度。VC2005 编译器/CRT 的整体改进非常出色。我强烈建议您尽快迁移到 VS2005!

引言

在对一个使用 TLS(线程局部存储)的单一 CRT 函数的微型基准测试中,您会发现该函数存在性能下降。此实现可以得到改进。这将使 _getptd() 的性能提高约 18%。

本文展示了可以在 _getptd_noexit() 函数(由 _getptd() 调用)内部进行的改进。要使用这些更改,您需要链接到静态 CRT 或重新编译整个 CRT。

此函数在 TLS(或 FLS)中扮演着重要角色。TLS(或更确切地说 FLS)在 CRT 的许多地方都有使用。例如,所有需要为后续调用存储某些内部数据(如 strtok)的函数,或者其他依赖于某些 区域设置的函数。CRT 将指向内部数据结构的指针存储在 FLS 中,以确保这些信息对每个协程/线程都是安全的。因此,此函数必须非常快速!

如果您希望在服务包或 VC 的未来版本中获得此性能提升,请投票支持它

对 _getptd_noexit() 函数的更改

在分析了对 _getptd_noexit() 的调用后,我发现 TlsGetValue 被不必要地调用了两次。接下来的代码更改将在此处进行改进。

对 tidtable.c 的更改

需要在 CRT 源目录(通常位于:%ProgramFiles%\Microsoft Visual Studio 8\VC\crt\src)中的 tidtable.c 文件中进行一些更改。您需要将第 546-553 行替换为以下代码

#ifndef _M_AMD64
  PVOID flsGetValue;
  TL_LastError = GetLastError();
  flsGetValue = FLS_GETVALUE;
  if (!flsGetValue)
  {
     flsGetValue = _decode_pointer(gpFlsGetValue);
     TlsSetValue(__getvalueindex, flsGetValue);
  }
  if ((ptd = ((PFLS_GETVALUE_FUNCTION)flsGetValue)(__flsindex)) == 
                                                               NULL)
  {
#else
     TL_LastError = GetLastError();
     if ( (ptd = FLS_GETVALUE(__flsindex)) == NULL ) {
#endif

总的来说,您有两种选择可以进行此更改,以便在您的项目中进行使用

CRT 的重新编译已在 Michael S. Kaplan 的一篇文章中进行了说明,此处不再赘述。在此,我将解释一个(简单的)步骤,将 tidtable.c 文件添加到您的项目中并使用您修改后的版本。要完成此任务,您需要执行以下操作

  1. 创建一个 Win32 控制台应用程序。
  2. 更改项目设置以使用静态 CRT(而不是 DLL 版本!)。
  3. 从您的项目中移除“预编译头文件”。
  4. 更改链接器设置,使其不使用默认库。
  5. libcmt(d).lib 添加到附加库中。
  6. tidtable.c 从 CRT 源目录复制到您的项目目录,并将其添加到您的项目中。
  7. 按照上述说明对 tidtable.c 进行修改。
  8. tidtable.c 文件顶部添加以下内容
    #define _CRTBLD
  9. 如果您是 UNICODE 构建,还需要将整个文件中的“LoadLibrary”替换为“LoadLibraryA”,并将“GetModuleHandle”替换为“GetModuleHandleA”。
  10. 右键单击 tidtable.c 文件,然后选择“属性”。
  11. 为此文件添加一个附加包含路径:"$(DevEnvDir)\..\..\VC\crt\src"
  12. 对 Debug 和 Release 项目设置执行上述更改。
  13. 全部重新构建。

您可以下载包含所有这些步骤的示例项目……(由于版权限制,不包含步骤 6-9)。

希望此(或类似)修改能在 VS8 的下一个服务包中找到一席之地……

本文来源

源自一个德语新闻组线程(Kai Huebner 于 2005 年 11 月 28 日 17:01:02 +0100 发表的 Schleifenlaufzeit VS2003 vs. VS2005),我不得不深入挖掘,以找出以下(微型基准测试)代码与 VC2003 相比,在 VC2005 下编译时变慢的原因。

double d = 0; 
for (int i=0; i<5000000; i++) 
 d += rand();

完整的分析可以在此处找到。

此解决方案的起源

在找出“出了什么问题”以及实现为何发生变化后,我尝试改进代码,减少对 TlsGetValue 的调用次数,并减少指令。我的第一个版本在“Ted”的改进下(更好地“内联”)得到了优化。最终的代码是本文的主题……

历史

  • 2005-12-01
    • 首次公开发布。
  • 2005-12-06
    • 添加了指向该错误条目的链接。
© . All rights reserved.