VC2005 CRT (x86/IA64) 性能提升






4.84/5 (14投票s)
2005 年 12 月 1 日
3分钟阅读

39867

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
- 链接到静态 CRT,然后重新编译 tidtable.c 文件。
CRT 的重新编译已在 Michael S. Kaplan 的一篇文章中进行了说明,此处不再赘述。在此,我将解释一个(简单的)步骤,将 tidtable.c 文件添加到您的项目中并使用您修改后的版本。要完成此任务,您需要执行以下操作
- 创建一个 Win32 控制台应用程序。
- 更改项目设置以使用静态 CRT(而不是 DLL 版本!)。
- 从您的项目中移除“预编译头文件”。
- 更改链接器设置,使其不使用默认库。
- 将 libcmt(d).lib 添加到附加库中。
- 将 tidtable.c 从 CRT 源目录复制到您的项目目录,并将其添加到您的项目中。
- 按照上述说明对 tidtable.c 进行修改。
- 在 tidtable.c 文件顶部添加以下内容
#define _CRTBLD
- 如果您是 UNICODE 构建,还需要将整个文件中的“
LoadLibrary
”替换为“LoadLibraryA
”,并将“GetModuleHandle
”替换为“GetModuleHandleA
”。 - 右键单击 tidtable.c 文件,然后选择“属性”。
- 为此文件添加一个附加包含路径:
"$(DevEnvDir)\..\..\VC\crt\src"
。 - 对 Debug 和 Release 项目设置执行上述更改。
- 全部重新构建。
您可以下载包含所有这些步骤的示例项目……(由于版权限制,不包含步骤 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
- 添加了指向该错误条目的链接。