VS2012 使用大型硬编码数组"Generating Code"慢

VS2012 "Generating Code" slow with large hardcoded arrays

本文关键字:Generating Code 数组 编码 大型 VS2012      更新时间:2023-10-16

我们有一个工具,可以在头文件中用硬编码数组生成类。该自动生成由使用自动生成值的实际实现继承。

自动生成的例子:

class MyTestAutoGen
{
    std::vector<int> m_my_parameter1;
    std::vector<int> m_my_parameter2;
    ...
public:
    MyTestAutoGen()    
    {
        SetDefaultValueFor_my_parameter1();
        SetDefaultValueFor_my_parameter2();
        ...
    }
    void SetDefaultValueFor_my_parameter1()
    {
        int tmp[] = {121,221,333,411,225,556,227,.......};
        m_my_parameter1.assign(tmp, tmp + 65025);
    }
    void SetDefaultValueFor_my_parameter2()
    {
        int tmp[] = {333,444,333,987,327,16728,227,.......};
        m_my_parameter2.assign(tmp, tmp + 65025);
    }
    ...
 };

编译这需要很多时间,在VS的输出窗口中,我可以看到它挂在编译的"生成代码"阶段,但它将在大约15-30分钟后完成编译,除非编译器崩溃与堆栈溢出。

我已经尝试启用"多处理编译"answers"并行代码生成"标志,但它没有显示任何改进。禁用"整个程序优化"不是一个选项,因为在应用程序初始化之后,它应该尽可能地进行优化。

我对这个问题的解决办法是修改自动生成的模板,以编码的二进制字符串保存值,这样数据可能会存储在TEXT区域而不是库/可执行文件的STATIC区域。现在自动生成的代码看起来像这样(字符串十六进制值只是为了显示):

class MyTestAutoGen
{
    std::vector<int> m_my_parameter1;
    std::vector<int> m_my_parameter2;
    ...
public:
    MyTestAutoGen()    
    {
        SetDefaultValueFor_my_parameter1();
        SetDefaultValueFor_my_parameter2();
        ...
    }
    void SetDefaultValueFor_my_parameter1()
    {
        std::string codedDefaultValue = "x079.......";
        std::stringstream str(codedDefaultValue);
        int tmp;
        for (int i = 0; i < codedDefaultValue.length() / sizeof(int); i++)
        {
            str.read((char*) &tmp, sizeof(int));
            m_my_parameter1.push_back(tmp);
        }
    }
    void SetDefaultValueFor_my_parameter2()
    {
        std::string codedDefaultValue = "x04dx001.......";
        std::stringstream str(codedDefaultValue);
        int tmp;
        for (int i = 0; i < codedDefaultValue.length() / sizeof(int); i++)
        {
            str.read((char*) &tmp, sizeof(int));
            m_my_parameter2.push_back(tmp);
        }
    }
    ...
 };

编译速度快,但不容易读(这个文件不应该手工编辑,也不应该随意查看)。

有没有更好的方法来做到这一点,而不破坏它作为跨平台,不禁用优化和保持头文件?

看起来你的自动生成的数字应该是常量。这是用static const表示的:

static const int tmp[] = {121,221,333,411,225,556,227,.......};

有一个模糊的规则,对于"大"数组,不应该使用自动存储(即普通的局部变量);使用static代替(或者,使用动态分配,但这里不需要)。另外,因为你的数字不会被改变,所以也使用const

顺便说一句,打破这个"规则"会影响编译时间,这是相当令人惊讶的!

如果您必须保留变通方法:为了提高可读性,您可能希望提取解码字符串的函数。

void fill(std::vector<int>& dest, const std::string& src)
{
  std::stringstream str(src);
  const size_t size = src.length() / sizeof(int);
  int tmp;
  dest.clear();
  dest.reserve(size);
  for (int i = 0; i < size; i++)
  {
    str.read((char*) &tmp, sizeof(int));
    dest.push_back(tmp);
  }
}
void SetDefaultValueFor_my_parameter1()
{
  fill(m_my_parameter1, "x079.......");
}

我的直觉是您正在堆栈上压入一个未指定大小的大数组。因为堆栈缓冲区溢出是一个特别的安全问题。MSVC对他们很小心。但是把这个数组放在堆栈上是没有意义的。

应该在全局作用域

const int count = 65025;
int param1_initializer[count] = {121,221,333,411,225,556,227, ... }

注意,您已经硬编码了数组长度,因此强烈建议给编译器一个检查它的机会。此外,这使得编译器更容易知道期望有多少个初始化式,因此编译时间也可能受益。

[编辑]因为这是不够的,而且我们知道我们正在使用MSVC,所以使用#pragma optimize关闭数组定义的所有优化。反正它们也不可能被优化