我目前正在为某些代码编写各种优化。每个优化都会对代码效率产生很大影响(希望如此),但也会影响源代码。但是,我希望保留启用和禁用其中任何一个以进行基准测试的可能性。
我传统上使用#ifdef OPTIM_X_ENABLE/#else/#endif
方法,但代码很快就难以维护。
还可以为每个优化创建SCM分支。在您想要启用或禁用多个优化之前,代码可读性要好得多。
是否还有其他希望更好的方法可以使用优化?
编辑: 一些优化不能同时工作。我可能需要禁用旧的优化来替换新的优化,看看我应该保留哪一个。
答案 0 :(得分:8)
我会为优化创建一个分支,对它进行基准测试直到你知道它有显着的改进,然后简单地将它合并回主干。一旦它回到主干上,我就不会打扰#ifdefs;一旦你知道它是好的,为什么你需要禁用它?如果您希望能够回滚特定更改,则始终拥有存储库历史记录。
答案 1 :(得分:3)
有很多方法可以选择要执行的代码部分。根据我的经验,使用预处理器的条件包含通常是最难维护的。如果可以的话,尽量减少这种情况。您可以在不同的功能中分离功能(优化,未优化)。然后根据标志有条件地调用这些函数。或者,您可以创建继承层次结构并使用虚拟分派。当然这取决于你的具体情况。也许如果你能更详细地描述它,你会得到更好的答案。
但是,这是一个可能适合您的简单方法:创建两组函数(或类,无论您使用哪种范例)。将函数分成不同的名称空间,一个用于优化代码,另一个用于可读代码。然后只需有条件地using
选择要使用的集合。像这样:
#include <iostream>
#include "optimized.h"
#include "readable.h"
#define USE_OPTIMIZED
#if defined(USE_OPTIMIZED)
using namespace optimized;
#else
using namespace readable;
#endif
int main()
{
f();
}
然后在optimized.h
:
namespace optimized
{
void f() { std::cout << "optimized selected" << std::endl; }
}
和readable.h
:
namespace readable
{
void f() { std::cout << "readable selected" << std::endl; }
}
遗憾的是,此方法需要使用预处理器,但使用率很低。当然,您可以通过引入包装头来改进这一点:
wrapper.h
:
#include "optimized.h"
#include "readable.h"
#define USE_OPTIMIZED
#if defined(USE_OPTIMIZED)
using namespace optimized;
#else
using namespace readable;
#endif
现在只需包含此标头,并进一步减少潜在的预处理器使用。顺便说一句,标题/ cpp的通常分离仍应该完成。
祝你好运!答案 2 :(得分:1)
我会在类级别(或C的文件级别)工作,并将所有各种版本嵌入到同一个工作软件中(无#ifdef),并通过一些配置文件或命令行选项在运行时选择一个实现或另一个实现。 它应该非常简单,因为优化不应该在内部API级别进行任何更改。
如果您使用C ++,另一种方法是实例化模板以避免重复高级代码或在运行时选择分支(即使这通常是可接受的选项,有些交换机通常不会出现这样的情况大问题。)
最后,各种优化的后端最终可以转向库。
单元测试应该能够在不修改每个实现变体的情况下工作。
我的理由是,嵌入每个变体主要会改变软件大小,而且很少出现问题。这种方法还有其他好处:您可以轻松地关注不断变化的环境。某些操作系统或某些硬件的优化可能不是一个在另一个上。在许多情况下,甚至可以很容易地在运行时选择最佳版本。
答案 3 :(得分:1)
您可以使用以下名称优化的两个(三个/更多)功能版本: 功能 function_optimized 它们具有相同的参数并返回相同的结果。
然后你可以在som标题中#define选择器,如:
#if OPTIM_X_ENABLE
#define OPT(f) f##_optimized
#else
#define OPT(f) f
#endif
然后调用具有优化变体的函数作为OPT(函数)(参数,参数...)。这种方法并非如此,但确实如此。
您可以进一步使用re#define names来表示所有优化函数:
#if OPTIM_X_ENABLE
#define foo foo_optimized
#define bar bar_optimized
...
#endif
并保持调用者代码不变。预处理器为您进行功能替换。我最喜欢它,因为它在每个函数(以及每个数据类型和每个变量)的粒度下透明地工作,这在大多数情况下对我来说足够了。
更奇特的方法是为非优化和优化的代码制作单独的.c文件,并仅编译其中一个。它们可能具有相同的名称但具有不同的路径,因此可以通过在命令行中更改单个选项来进行切换。
答案 4 :(得分:0)
我很困惑。你为什么不找出每个性能问题的位置,修复它并继续。 Here's an example.