STL 替代方案
我真的很讨厌使用 STL 容器,因为它们使我的代码的调试版本运行得非常慢。 其他人使用什么来代替具有合理性能的调试构建 STL?
我是一名游戏程序员,这在我参与的许多项目中都是一个问题。 当你使用 STL 容器处理所有事情时,获得 60 fps 是相当困难的。
我的大部分工作都使用 MSVC。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
EASTL 是一种可能性,但仍然不完美。 Electronic Arts 的 Paul Pedriana 对游戏应用程序中的各种 STL 实现的性能进行了调查,其摘要如下:
http://www.open-std.org /jtc1/sc22/wg21/docs/papers/2007/n2271.html
其中一些调整正在接受审查,以便纳入 C++ 标准中。
请注意,即使 EASTL 也不会针对非优化情况进行优化。 不久前我有一个 excel 文件,但我想我已经丢失了它,但对于访问来说,它是这样的:
我最成功的就是滚动我自己的容器。 您可以将它们降低到接近 array[x] 的性能。
EASTL is a possibility, but still not perfect. Paul Pedriana of Electronic Arts did an investigation of various STL implementations with respect to performance in game applications the summary of which is found here:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html
Some of these adjustments to are being reviewed for inclusion in the C++ standard.
And note, even EASTL doesn't optimize for the non-optimized case. I had an excel file w/ some timing a while back but I think I've lost it, but for access it was something like:
The most success I've had was rolling my own containers. You can get those down to near array[x] performance.
我的经验是,设计良好的 STL 代码在调试版本中运行缓慢,因为优化器已关闭。 STL 容器发出大量对构造函数和运算符= 的调用,这些调用(如果它们是轻量级的)会在发布版本中内联/删除。
此外,Visual C++ 2005 及更高版本在发布和调试版本中都启用了 STL 检查。 对于 STL 密集型软件来说,这是一个巨大的性能消耗。 可以通过为所有编译单元定义 _SECURE_SCL=0 来禁用它。 请注意,在不同的编译单元中具有不同的 _SECURE_SCL 状态几乎肯定会导致灾难。
您可以创建第三个构建配置并关闭检查,并使用它来进行性能调试。 我建议您保留调试配置并进行检查,因为它对于捕获错误的数组索引和类似的东西非常有帮助。
My experience is that well designed STL code runs slowly in debug builds because the optimizer is turned off. STL containers emit a lot of calls to constructors and operator= which (if they are light weight) gets inlined/removed in release builds.
Also, Visual C++ 2005 and up has checking enabled for STL in both release and debug builds. It is a huge performance hog for STL-heavy software. It can be disabled by defining _SECURE_SCL=0 for all your compilation units. Please note that having different _SECURE_SCL status in different compilation units will almost certainly lead to disaster.
You could create a third build configuration with checking turned off and use that to debug with performance. I recommend you to keep a debug configuration with checking on though, since it's very helpful to catch erroneous array indices and stuff like that.
我敢打赌你的 STL 使用经过检查的实现来进行调试。 这可能是一件好事,因为它会捕获迭代器溢出等。 如果这对你来说是一个很大的问题,可能有一个编译器开关可以将其关闭。 检查你的文档。
I'll bet your STL uses a checked implementation for debug. This is probably a good thing, as it will catch iterator overruns and such. If it's that much of a problem for you, there may be a compiler switch to turn it off. Check your docs.
对于大型、性能关键的应用程序,专门针对您的需求构建自己的容器可能值得投入时间。
我在这里谈论的是真正的游戏开发。
For big, performance critical applications, building your own containers specifically tailored to your needs may be worth the time investment.
I´m talking about real game development here.
如果您正在运行视觉工作室,您可能需要考虑以下事项:
这仅适用于迭代器,您要执行什么类型的 STL 操作? 您可能需要考虑优化内存操作; 即,使用 resize() 一次插入多个元素,而不是使用 pop/push 一次插入一个元素。
If your running visual studios you may want to consider the following:
That's just for iterators, what type of STL operations are you preforming? You may want to look at optimizing your memory operations; ie, using resize() to insert several elements at once instead of using pop/push to insert elements one at a time.
MSVC 在调试版本中使用了检查迭代器的非常重量级的实现,其他人已经讨论过,所以我不会重复它(但从这里开始)
您可能感兴趣的另一件事是您的“调试版本”和“发布版本”可能涉及更改(至少)4 个松散相关的设置。
这些可以独立切换。 第一种方法虽然增加了大小,但对运行时性能没有任何影响。 第二个使得一些函数更加昂贵,但是对malloc和free影响巨大; 调试运行时版本会小心地“毒害”它们所接触的内存,以清除未初始化的数据错误。 我相信,通过 MSVCP* STL 实现,它还消除了通常完成的所有分配池,因此泄漏准确地显示您所认为的块,而不是它正在子分配的更大的内存块; 这意味着它会在速度慢得多的情况下对 malloc 进行更多调用。 第三; 好吧,那个人做了很多事情(这个问题对该主题有一些很好的讨论)。 不幸的是,如果您希望单步运行顺利,则需要它。 第四个以各种方式影响许多库,但最值得注意的是它编译或消除了断言()和朋友。
因此,您可能会考虑使用这些选择的一些较小组合来进行构建。 我大量使用了具有符号(/Zi 和链接 /DEBUG)和断言(/DDEBUG)的构建,但仍然进行了优化(/O1 或 /O2 或您使用的任何标志),但保留了堆栈帧指针清除回溯(/Oy-)并使用正常的运行时库(/MT)。 它的性能接近我的发布版本,并且是半可调试的(回溯很好,单步在源代码级别有点古怪;当然,汇编级别工作得很好)。 您可以拥有任意多种配置; 只需克隆您的版本并打开调试中看起来有用的任何部分即可。
MSVC uses a very heavyweight implementation of checked iterators in debug builds, which others have already discussed, so I won't repeat it (but start there)
One other thing that might be of interest to you is that your "debug build" and "release build" probably involves changing (at least) 4 settings which are only loosely related.
These can be switched independently. The first costs nothing in runtime performance, though it adds size. The second makes a number of functions more expensive, but has a huge impact on malloc and free; the debug runtime versions are careful to "poison" the memory they touch with values to make uninitialized data bugs clear. I believe with the MSVCP* STL implementations it also eliminates all the allocation pooling that is usually done, so that leaks show exactly the block you'd think and not some larger chunk of memory that it's been sub-allocating; that means it makes more calls to malloc on top of them being much slower. The third; well, that one does lots of things (this question has some good discussion of the subject). Unfortunately, it's needed if you want single-stepping to work smoothly. The fourth affects lots of libraries in various ways, but most notable it compiles in or eliminates assert() and friends.
So you might consider making a build with some lesser combination of these selections. I make a lot of use of builds that use have symbols (/Zi and link /DEBUG) and asserts (/DDEBUG), but are still optimized (/O1 or /O2 or whatever flags you use) but with stack frame pointers kept for clear backtraces (/Oy-) and using the normal runtime library (/MT). This performs close to my release build and is semi-debuggable (backtraces are fine, single-stepping is a bit wacky at the source level; assembly level works fine of course). You can have however many configurations you want; just clone your release one and turn on whatever parts of the debugging seem useful.
查看EASTL。
Check out EASTL.
如果您使用的是 Visual C++,那么您应该看看这个:
http://channel9.msdn.com/shows/Going+Deep/STL-Iterator-Debugging-and-Secure-SCL/
以及该页面中的链接,其中涵盖MS/Dinkware STL 执行的所有调试模式检查的各种成本和选项。
如果您要问这样一个与平台相关的问题,最好也提及您的平台......
If you're using Visual C++, then you should have a look at this:
http://channel9.msdn.com/shows/Going+Deep/STL-Iterator-Debugging-and-Secure-SCL/
and the links from that page, which cover the various costs and options of all the debug-mode checking which the MS/Dinkware STL does.
If you're going to ask such a platform dependent question, it would be a good idea to mention your platform, too...
使用 C++ 中的面向对象设计模式检查数据结构和算法
布鲁诺·普莱斯
http://www.brpreiss.com/
Checkout Data Structures and Algorithms with Object-Oriented Design Patterns in C++
By Bruno Preiss
http://www.brpreiss.com/
ACE 库怎么样? 它是一个用于并发通信软件的开源面向对象框架,但它也有一些容器类。
What about the ACE library? It's an open-source object-oriented framework for concurrent communication software, but it also has some container classes.
抱歉,我无法发表评论,所以这里有一个答案:EASTL 现已在 github 上提供: https://github .com/paulhodge/EASTL
Sorry, I can't leave a comment, so here's an answer: EASTL is now available at github: https://github.com/paulhodge/EASTL
Ultimate++ 有自己的一组容器 - 不确定您是否可以与库的其余部分分开使用它们: http:// www.ultimatepp.org/
Ultimate++ has its own set of containers - not sure if you can use them separatelly from the rest of the library: http://www.ultimatepp.org/
Qt 使用不同的接口重新实现了大多数 C++ 标准库内容。 它看起来相当不错,但商业授权版本可能会很昂贵。
编辑:Qt 此后已在 LGPL 下发布,这通常使得可以在商业中使用它产品没有商业版本(仍然存在)。
Qt has reimplemented most c++ standard library stuff with different interfaces. It looks pretty good, but it can be expensive for the commercially licensed version.
Edit: Qt has since been released under LGPL, which usually makes it possible to use it in commercial product without bying the commercial version (which also still exists).
还有 ETL https://www.etlcpp.com/。 该库特别针对时间关键(确定性)应用程序
从网页:
There is also the ETL https://www.etlcpp.com/. This library aims especially for time critical (deterministic) applications
From the webpage:
STL 容器不应在调试或其他任何地方运行“非常慢”。 也许你误用了它们。 你在调试时不会遇到像 ElectricFence 或 Valgrind 这样的东西,是吗? 它们会减慢任何进行大量分配的操作。
所有容器都可以使用自定义分配器,有些人用它来提高性能 - 但我自己从来不需要使用它们。
STL containers should not run "really slowly" in debug or anywhere else. Perhaps you're misusing them. You're not running against something like ElectricFence or Valgrind in debug are you? They slow anything down that does lots of allocations.
All the containers can use custom allocators, which some people use to improve performance - but I've never needed to use them myself.