为什么这种 RTTI 优化会使速度变慢?
我有一个在循环中重复调用的操作。使用 TRttiField:
if (field.name = '') or (field.Name[1] <> 'F') then
continue;
分析表明我因此在 UStrAsg 和 UStrClr 上花费了大量时间。 Field.Name 必须对 TRttiInstanceFieldEx.GetName 进行虚拟调用,后者必须对底层 RTTI 结构的名称执行 UTF8 到字符串的转换。每个循环迭代会发生两次这种情况。
我试图通过绕过字符串转换来消除所有这些:
handle := PFieldExEntry(field.Handle);
if (handle.name = '') or (handle.Name[1] <> 'F') then
continue;
我预计由此会获得大约 5% 的速度增益。相反,循环的执行时间要长几秒,大约慢 20-25%!我检查了生成的 ASM,以确保它没有做任何奇怪的事情,比如将字符串从 RTTI 结构复制到本地堆栈,但事实并非如此。我看不出有什么理由让它变慢。有人知道这里会发生什么吗?
I've got an operation that's being called repeatedly in a loop. With a TRttiField:
if (field.name = '') or (field.Name[1] <> 'F') then
continue;
Profiling shows that I'm spending a lot of time in UStrAsg and UStrClr because of this. Field.Name has to make a virtual call to TRttiInstanceFieldEx.GetName, which has to perform a UTF8-to-string conversion on the underlying RTTI structure's name. This is happening twice per loop iteration.
I tried to cut all that out by bypassing the string conversions:
handle := PFieldExEntry(field.Handle);
if (handle.name = '') or (handle.Name[1] <> 'F') then
continue;
I expected to see about a 5% speed gain from this. Instead, the loop takes several seconds longer to execute, approximately 20-25% slower! I checked the generated ASM to make sure it wasn't doing anything screwy like making string copies from the RTTI structures to the local stack, but it isn't. I can't see any reason why this should have gotten slower. Anyone have any idea what might be going on here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
新代码读取的字段被声明为 ShortString。从 Delphi 5 开始,编译器在生成大多数字符串操作的代码之前将 ShortString 转换为长字符串。 (至少,非 Unicode Delphi 就是这样。也许 Unicode Delphi 恢复了一些与 ShortString 相关的优化。)
而 TRttiField 包装器可能会利用这样的知识:它正在用已经占用一个 UTF-8 字符串的数据填充 UTF-8 字符串。每个字符字节,我希望您的新循环使用的 ShortString 到字符串代码可能会使用更通用的转换例程,并且您正在为通用性付出代价。
您可以完全尝试上述字符串转换操作。相反,获取指向第一个字节的指针:
请注意,虽然它被声明为 ShortString,但它实际上并不是一个。它实际上并不占用256字节。相反,它占用保存其长度字节及其字符所需的最小内存量。
The field your new code reads is declared as a ShortString. As of Delphi 5, the compiler converts ShortStrings to long strings before generating the code for most string operations. (At least, that's the way it was with non-Unicode Delphi. Maybe Unicode Delphi restores some ShortString-related optimizations.)
Whereas the TRttiField wrapper might take advantage of the knowledge that it's populating a UTF-8 string with data that's already occupying one byte per character, I'd expect the ShortString-to-string code that your new loop employs might use a more general-purpose conversion routine, and you're paying the price for generality.
You might try foregoing string-conversion operations entirely. Instead, get a pointer to the first byte:
Note that although it's declared as a ShortString, it's not really one. It doesnn't really occupy 256 bytes. Instead, it occupies the minimum amount of memory required to hold its length byte and its characters.