VS C++:树状 if/else 结构的代码生成需要很长时间

VS C++: Code generation of tree-like if/else structure takes very long

我有一个(公认的大)if/else 条件结构:

if ( a > 0 )
{
    if ( b > 0 )
    {
        ...
    }
}else
{
   ...
}

结构呈树状,深度为9(共512个节点)。

更糟糕的是,还有500个需要编译...

但是,代码生成似乎要花很长时间。我停用了优化(调试模式),所以在我看来,生成应该不会花那么长时间...

您知道如何提高代码生成速度吗?

更新:

该代码只是一个由几棵树组成的随机森林分类器。所以,是的,我可以把它放在不同的结构中,但最快的代码执行将是硬编码的 if 条件。

更新2:

我仔细查看了输出,似乎是链接过程的问题。 你能解释一下,为什么,或者如何改进吗?

更新3:

这是我的链接器命令:

/OUT:"C:\ProjectFolder\MyFile.exe" 
/MANIFEST /LTCG /NXCOMPAT   
/PDB:"C:\ProjectFolder\install\x64\Release\MyFile.pdb" 
/DYNAMICBASE "ThirdPartyLibrary1.lib" "ThirsPartyLibrary2.lib" 
"kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" 
/DEBUG /MACHINE:X64 /OPT:REF /INCREMENTAL:NO 
/PGD:"C:\ProjectFolder\install\x64\Release\MyFile.pgd" 
/SUBSYSTEM:CONSOLE 
/MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"C:\ProjectFolder\build\x64\Release\MyFile.exe.intermediate.manifest" 
/OPT:ICF /ERRORREPORT:PROMPT /NOLOGO 
/LIBPATH:"D:rd\x64\lib1" /LIBPATH:"D:rd\x64\lib2" /TLBID:1 

更新4:

仅供参考,目前,链接进程占用 655MB RAM,正在缓慢上升...

你已经知道了,但我要再说一遍:你不应该有一个 if/else 块的打包树到深度 9。你甚至不应该有一个这样的构造,更不用说 500他们中的。无论您从该设计中得到什么,您都应该仔细寻找其他方法来获得它。

您确定这些结构是罪魁祸首吗? C++ 编译时间可能会令人惊讶。它们是否在包含在许多地方的头文件中?

无论如何,因为这是一件非常不寻常的事情,你的编译器没有优化以有效地编译它,所以你的编译速度很慢。如果您可以使用 gcc 或 clang 进行编译,那么 可能 会有所帮助,但您的问题更有可能没有解决方案,如前所述:如果您希望编译速度更快,那么您必须停止执行你正在做的事情很奇怪,然后做一些更像普通 C++ 的事情。

回复:Do you have an idea how to improve the speed of the code generation?

如果您确实需要将代码分支 512 种方式(我不确定您是否这样做),您可以构造一个整数值,其中每个最低 9 位都反映条件 (a > 0)(b > 0), 等。然后有一个开关有 512 个案例,从 0 到 511.

[添加示例代码]

这是我会做的:

int mask(0);
if(a > 0) mask |= 0x01;
if(b > 0) mask |= 0x02;
if(c > 0) mask |= 0x04;
...
if(h > 0) mask |= 0x80;
if(i > 0) mask |= 0x100;
switch(mask)
{
case 0x01: // only (a>0) was true
  ...
break;
....
case 0x77: // all but (i>0) were true
  ...
break;
}

根据最新的 it's the linker that seems to take forever 说明...如果这是 release/optimized 使用 Whole Program Optimization enabled, then be sure to mind the caveats at Quick Tips On Using Whole Program Optimization 构建:

  • When building from the command line or via makefiles, you need to add the /LTCG switch to the link command line to tell the linker to expect to see one or more object files that were compiled with /GL. If you don’t, some build time will be wasted because the linker will have to start over when it gets to the module compiled with /GL. If you build through the IDE this is in your project configuration settings on the Linker optimization page.

  • Using /GL reduces your compile times, but your link time will increase, because work is being moved to during the link. Overall build time might increase a little, but shouldn’t increase a lot.

这是我所做的:

我目前保留 if-else 语句,如果在某个时候我需要一定的速度。

现在,我创建了树的参数化版本(见下文)。

代码如下所示(对于具有 16 个节点的树,每个节点两个参数):

// "sample" denotes the thing that I want to classify.
// nodeFunction evaluates to a true/false statement the detemines the next leaf

double decisionTree( sample )
{
    const bool isTerminalNode[ 15 ] = {false, false, true, true, false, ...};
    const double parameters[ 15 ][ 2 ] = {{1.0, 2.0}, {1.5, 7.5}, {1.7, 7.7}, ...};
    const double returnValues[ 31 ] = {-1.0, -1.0, 1.5, 3.7, ...};

    int nCurrentIdx = 0;

    while( !isTerminalNode[ nCurrentIdx ] )
    {
        if ( nodeFunction( parameters[ nCurrentIdx ], sample ) )
            nCurrentIdx = nCurrentIdx * 2 + 1; // go left
        else
            nCurrentIdx = (nCurrentIdx + 1) * 2; // go right
    }

    return returnValues[ nCurrentIdx ];
}

树结构如下所示:

          0
       /     \
      1       2
    /   \   /   \
   3    4  5     6
  ...  ... ... ... ... etc