“const unordered_map”编译速度慢作为全局变量

发布于 2025-01-16 00:42:49 字数 1238 浏览 4 评论 0原文

我的编译时间非常慢,可能是由于存在 std::unordered_map 类型的全局变量。您可以在下面找到代码行,它们位于名为 correspondance.h 的文件中

    using Entry_t = std::tuple<Cfptr_t, short int, short int>;
    ...
    #include "map_content.h"
        inline const std::unordered_map<std::string, Entry_t> squaredampl{MAP_CONTENT};
    #undef MAP_CONTENT

,并且 map_content.h 中有地图的内容:

     #define MAP_CONTENT \
    { {EMPTYCHAR+corr::su_R,ANTICHAR,EMPTYCHAR+corr::sd_L,EMPTYCHAR+corr::A,EMPTYCHAR+corr::W},{    &mssm2to2::sumSqAmpl_su_R_anti_sd_L_to_A_W, 9,2}},\
    { {EMPTYCHAR+corr::su_L,ANTICHAR,EMPTYCHAR+corr::sd_R,EMPTYCHAR+corr::A,EMPTYCHAR+corr::W},{  &mssm2to2::sumSqAmpl_su_L_anti_sd_R_to_A_W, 9,2}},\
    ...

它继续像这样大约3500行。 请注意,

  1. Cfptr_t 是一个函数指针
  2. EMPTYCHAR,并且所有 corr::something 类型的变量都是整数,因此它们定义了键值字符串

我遇到的问题是,每个包含 correspondace.h 的文件的 makefile 需要 10 分钟,因为确实有很多行代码需要处理。

您可能已经了解,需要此映射来允许用户在不知道函数名称的情况下仅使用字符串来访问函数。因此,我目前无法消除此功能,因为它是基础功能。

尽我所能,我尝试将此文件包含在尽可能少的文件中。无论如何,不​​可避免地将它包含在将生成可执行文件的每个文件中,因此,总的来说,这迫使我每次必须调试某些内容时都要等待很长时间。

如果您对如何加快编译速度并保持此功能有任何建议,这对我来说真的很有帮助:)

I am experiencing really slow compilation time, probably due to the existence of a global variable of the kind std::unordered_map. Below you can find the lines of code, which are located in a file called correspondance.h

    using Entry_t = std::tuple<Cfptr_t, short int, short int>;
    ...
    #include "map_content.h"
        inline const std::unordered_map<std::string, Entry_t> squaredampl{MAP_CONTENT};
    #undef MAP_CONTENT

and, in map_content.h there is the content of the map:

     #define MAP_CONTENT \
    { {EMPTYCHAR+corr::su_R,ANTICHAR,EMPTYCHAR+corr::sd_L,EMPTYCHAR+corr::A,EMPTYCHAR+corr::W},{    &mssm2to2::sumSqAmpl_su_R_anti_sd_L_to_A_W, 9,2}},\
    { {EMPTYCHAR+corr::su_L,ANTICHAR,EMPTYCHAR+corr::sd_R,EMPTYCHAR+corr::A,EMPTYCHAR+corr::W},{  &mssm2to2::sumSqAmpl_su_L_anti_sd_R_to_A_W, 9,2}},\
    ...

it goes on like this for about 3500 lines.
Note that

  1. Cfptr_t is a function pointer
  2. EMPTYCHAR and all the variables of the type corr::something are integers, so they define the key value string

The problem I encounter is that the makefile takes 10 minutes for each file that includes correspondace.h, since indeed there are so many lines of code to process.

As you may have understood, this map is needed to allow the user to access functions without knowing their names, but just with a string. For this reason I cannot at the moment eliminate this feature, since it's fundamental.

As far as I could do, I tried to include this file in as few files as possible. Anyways, it is inevitable to include it in every file that will generate the executable, so, overall, this forces me to wait a long time each time I have to debug something.

If you have any suggestion on how to speed up compilation keeping this feature, it would be really helpful for me :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

魔法唧唧 2025-01-23 00:42:50

更改

#include "map_content.h"
inline const std::unordered_map<std::string, Entry_t> squaredampl{MAP_CONTENT};
#undef MAP_CONTENT

extern const std::unordered_map<std::string, Entry_t> squaredampl;

新的 .cpp 文件:

#include "correspondance.h"
#include "map_content.h"
const std::unordered_map<std::string, Entry_t> squaredampl{MAP_CONTENT};
#undef MAP_CONTENT

这将导致仅发出映射的一个定义(与 inline 相比,它将在每个翻译单元 odr 中发出) -使用它)。

只要在进入 main 之前构造另一个静态存储持续时间对象期间不使用映射,它就是安全的。如果需要的话,最好将映射设置为函数中的局部静态变量,通过引用返回它以供调用者使用。这将避免“静态初始化顺序惨败”。


它还可能有助于创建一个函数,为每个条目使用 insert 语句初始化映射,而不是在初始化程序中完成所有操作,即有一个函数 initSquaredampl 返回 < code>std::unordered_map按值,然后:

auto initSquaredampl() {
    std::unordered_map<std::string, Entry_t> squaredampl;
    // Insert items one-by-one
    return squaredampl;
}

const std::unordered_map<std::string, Entry_t> squaredampl = initSquaredampl();

可能有帮助,因为编译器可能未针对编译很长的表达式进行优化,或者初始化器。然而,他们也可能在处理很长的函数时遇到问题。

Change

#include "map_content.h"
inline const std::unordered_map<std::string, Entry_t> squaredampl{MAP_CONTENT};
#undef MAP_CONTENT

to

extern const std::unordered_map<std::string, Entry_t> squaredampl;

and in a new .cpp file:

#include "correspondance.h"
#include "map_content.h"
const std::unordered_map<std::string, Entry_t> squaredampl{MAP_CONTENT};
#undef MAP_CONTENT

This will cause only one definition of the map to be emitted (in contrast to inline which will emit it in every translation unit odr-using it).

It is safe as long as the map isn't used during the construction of another static storage duration object before main is entered. If that is required, it would be preferable to make the map a local static variable in a function returning it by-reference to be used by callers. This would avoid the "static initialization order fiasco".


It might also help to make a function to initialize the map with an insert statement for each entry instead of doing it all in the initializer, i.e. have a function initSquaredampl returning a std::unordered_map<std::string, Entry_t> by-value and then:

auto initSquaredampl() {
    std::unordered_map<std::string, Entry_t> squaredampl;
    // Insert items one-by-one
    return squaredampl;
}

const std::unordered_map<std::string, Entry_t> squaredampl = initSquaredampl();

This may help, because a compiler might not be optimized for compilation of very long expressions or initializers. However, they may also have trouble with very long functions.

嗫嚅 2025-01-23 00:42:50

我要感谢@Kaldrr 和@user17732522 的精彩见解。我通过以下方式解决了我的问题。在 correspondance.h 中,我刚刚输入:

inline std::unordered_map<std::string, Entry_t> squaredampl;

即​​空地图的简单初始化。
然后,我创建了一个新的标头 init_map.h ,其中包含以下几行:

#include "correspondance.h"

int Initialise();

当然,还有一个相应的 initialise_map.cpp 文件,其中包含函数的定义

#include "initialise_map.h"

int Initialise()
{
  if (!corr::squaredampl.empty()) return 0;
  corr::squaredampl.reserve(3500);
  corr::squaredampl = {
#include "map_content_body.h"
  };
  return 0;
}

,其中 map_content_body.h 是地图内容的行。通过这种方式:

  1. 地图的代码仅在一个文件中
  2. 我避免定义宏并复制它
  3. 一旦我有了目标文件 initialise_map.o,所有将生成可执行文件的 .cpp 文件将不包含代码,但该函数将在链接阶段存在

因此,除非我删除 initialise_map.o 或更新 initialise_map.cpp,否则我的代码将在一个正常的速度,理应如此。

当然,我在每个头文件中都添加了 #pragma Once 或类似内容,以避免无用的代码复制。

也非常感谢@JaMiT 的鼓励的话:)

编辑:正如我在评论中建议的那样,我最终实现了@user17732522 的解决方案。这样我就不必每次都调用函数来进行初始化。

I want to thank @Kaldrr and @user17732522 for the nice insights. I solved my problem in the following way. In correspondance.h I just put:

inline std::unordered_map<std::string, Entry_t> squaredampl;

i.e. a simple initialisation of the empty map.
Then, I created a new header init_map.h with the following lines:

#include "correspondance.h"

int Initialise();

and, of course, a correspondant initialise_map.cpp file with the definition of the function

#include "initialise_map.h"

int Initialise()
{
  if (!corr::squaredampl.empty()) return 0;
  corr::squaredampl.reserve(3500);
  corr::squaredampl = {
#include "map_content_body.h"
  };
  return 0;
}

where map_content_body.h are the lines of the content of the map. In this way:

  1. The code for the map is in only one file
  2. I avoided defining a macro and copying it
  3. Once that I have the object file initialise_map.o, all the .cpp files that will generate the executable will not contain the code, but the function will be there in linking phase

As a result, unless I remove initialise_map.o or I update initialise_map.cpp, my code compiles at a normal speed, as it should be.

Of course, I took care of having a #pragma once or similar in each header file to avoid useless code copies.

Many thanks also to @JaMiT for the encouraging words :)

EDIT : As I was suggested in the comments, I eventually implemented the solution by @user17732522. In this way I don't have to call a function each time to do the initialisation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文