Reputation: 63
I'm making a game in Node.js with a C++ component. This C++ component is invoked often (as a subprocess) and is a bottleneck. Thus, I hardcoded its assets as const arrays to make it run faster.
However, I noticed that my C++ code takes a long time to compile. Following is a demonstration of the problem:
#include <iostream>
#include <vector>
#define d 3,
#define _ 999,
// an array holding some game assets
const std::vector<std::vector<std::vector<int>>> STRUCTURES {
{ // you should make 80 copies of this paragraph before benchmarking
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
},
};
int main(int argc, char **argv){
// prevent optimizer from ignoring the big array
std::cout << STRUCTURES.size() << std::endl;
return 0;
}
If you repeat the middle paragraph 80 times, it'll be comparable in size to my C++ program. I compile with g++ test.cpp -O3
and it takes 36 seconds to compile. I don't understand why this is so slow. Is there something I can change to make it compile much faster?
Upvotes: 1
Views: 114
Reputation: 63
The solution, as suggested by Barmar and Sam Varshavchik, is to avoid std::vector.
There are too many vectors and the optimizer is taking a lot of time to deal with that. std::array can be used instead. For this sample, that means:
#include <iostream>
#include <vector>
#include <array>
#define d 3,
#define _ 999,
// an array holding some game assets
const std::vector<std::array<std::array<int,37>,37>> STRUCTURES {
{{ // you should make 80 copies of this paragraph before benchmarking
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ d d d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ d d d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ d d d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ d d d d d d d d d d d _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ d d d d d d d _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
{ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ },
}},
};
int main(int argc, char **argv){
// prevent optimizer from ignoring the big array
std::cout << STRUCTURES.size() << std::endl;
return 0;
}
Notice that I still used a single std::vector for the outermost dimension. This does not present a significant overhead when compiling.
Upvotes: 1
Reputation: 393969
Not using dynamic allocation helps:
template <typename T, int a, int b, int c>
using sprites = std::array<std::array<std::array<T, c>, b>, a>;
But not allocating at all must be faster. Now I don't know about you, but I find getting the initializers correct and lined up Very Tedious(TM) so, let's not:
// an array holding some game assets
static constexpr char STRUCTURES[] {
// pos 0
"_____________________________________"
"_____________________________________"
"_____________________________________"
"_____________________________________"
"_________________________ddddddd_____"
"______________________ddddddddddd____"
"_____________________ddddddddddddd___"
"____________________dddddddddddddd___"
"___________________ddddddddddddddd___"
"__________________dddddddddddddddd___"
"_________________dddddddddddddddd____"
"________________ddddddddddddddddd____"
"_______________ddddddddddddddddd_____"
"______________ddddddddddddddddd______"
"____________dddddddddddddddddd_______"
"___________dddddddddddddddddd________"
"__________ddddddddddddddddddd________"
"_________ddddddddddddddddddd_________"
"________ddddddddddddddddddd__________"
"________ddddddddddddddddddd__________"
"_______dddddddddddddddddddd__________"
"______dddddddddddddddddddd___________"
"______dddddddddddddddddddd___________"
"______dddddddddddddddddddd___________"
"______ddddddddddddddddddd____________"
"______ddddddddddddddddddd____________"
"______dddddddddddddddddd_____________"
"______ddddddddddddddddd______________"
"_______ddddddddddddddd_______________"
"________ddddddddddddd________________"
"_________ddddddddddd_________________"
"___________ddddddd___________________"
"_____________________________________"
"_____________________________________"
"_____________________________________"
"_____________________________________"
"_____________________________________"
// pos 1
// ....
// ....
// ....
"_____________________________________"
"_____________________________________"
// pos 81
"_____________________________________"
"_____________________________________"
"_____________________________________"
"_____________________________________"
"_________________________ddddddd_____"
"______________________ddddddddddd____"
"_____________________ddddddddddddd___"
"____________________dddddddddddddd___"
"___________________ddddddddddddddd___"
"__________________dddddddddddddddd___"
"_________________dddddddddddddddd____"
"________________ddddddddddddddddd____"
"_______________ddddddddddddddddd_____"
"______________ddddddddddddddddd______"
"____________dddddddddddddddddd_______"
"___________dddddddddddddddddd________"
"__________ddddddddddddddddddd________"
"_________ddddddddddddddddddd_________"
"________ddddddddddddddddddd__________"
"________ddddddddddddddddddd__________"
"_______dddddddddddddddddddd__________"
"______dddddddddddddddddddd___________"
"______dddddddddddddddddddd___________"
"______dddddddddddddddddddd___________"
"______ddddddddddddddddddd____________"
"______ddddddddddddddddddd____________"
"______dddddddddddddddddd_____________"
"______ddddddddddddddddd______________"
"_______ddddddddddddddd_______________"
"________ddddddddddddd________________"
"_________ddddddddddd_________________"
"___________ddddddd___________________"
"_____________________________________"
"_____________________________________"
"_____________________________________"
"_____________________________________"
"_____________________________________"
};
Now, of course, you wanted ints and mapped the chars to certain values (like 3 and 999 in this case). To get that, we can use a naive indexing helper:
struct Helper {
constexpr int operator()(int a, int b, int c) const {
switch (auto ch = STRUCTURES[a*37*37 + b*37 + c]) {
case 'd': return 999;
case '_': return 3;
}
return 0;
}
};
Now we can write main
to print a randomm "glyph", "sprite" or whatever those resources are:
#include <iostream>
#include <iomanip>
int main() {
auto a = rand() % 81;
Helper index;
for (int b = 0; b < 37; ++b) {
for (int c = 0; c < 37; ++c)
std::cout << std::setw(4) << index(a, b, c);
std::cout << "\n";
}
}
It prints (I had 81x the same "image"):
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 999 999 999 999 999 999 999 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
Much less code, much more features. Now you can use .size()
and ranged-for:
#include <boost/multi_array.hpp>
int main() {
constexpr std::array shape {81,37,37};
boost::const_multi_array_ref<char, 3> view(STRUCTURES, shape);
auto const& sprite = view[rand() % view.size()];
for (auto const& row : sprite) {
for (auto const& cell : row)
printf("%4d", (cell=='d'? 999 : 3));
putchar('\n');
}
}
Naive indexing Helper
version: Live On Coliru
Compilation: (on coliru!)
real 0m0.562s
user 0m0.432s
sys 0m0.124s
Runtime (on coliru!):
real 0m0.005s
user 0m0.000s
sys 0m0.004s
Boost Multi-Array version: Compiler Explorer/Coliru
Executable size is 118k (GCC) or 119k (clang) on my system (both approaches).
Upvotes: 2