POD means primitive data type without constructor and destructor.
I am curious, how compilers handle lazy initialization of POD static local variables. What is the implication of lazy initialization if the function are meant to be run inside tight loops in multithreaded applications? These are the possible choices. Which one is better?
void foo_1() {
static const int v[4] = {1, 2, 3, 4};
}
void foo_2() {
const int v[4] = {1, 2, 3, 4};
}
How about this? No lazy initialization, but slightly clumsy syntax?
struct Bar
{
static const int v[4];
void foo_3()
{
// do something
}
};
const int My::v[4] = {1, 2, 3, 4};
When a static variable is initialized with constant data, all compilers that I'm familiar with will initialize the values at compile time so that there is no run time overhead whatsoever.
If the variable isn't static it must be allocated on each function invocation, and the values must be copied into it. I suppose it's possible that the compiler might optimize this into a static if it's a const variable, except that const-ness can be cast away.
In foo_1(), v is initialized sometime before main() starts. In foo_2(), v is created and initialized every time foo_2() is called. Use foo_1() to eliminate that extra cost.
In the second example, Bar::v is also initialized sometime before main().
Performance is more complex than just allocation. For example, you could cause an extra cache line to have to be in cache with the static variable, because it's not contiguous with other local memory that you're using, and increase cache pressure, cache misses, and suchlike. In comparison to this cost, I would say that the incredibly tiny overhead of re-allocating the array on the stack every time would be very trivial. Not just that, but any compiler is excellent at optimizing things like that, whereas it can't do anything about static variables.
In any case, I would suggest that the performance difference between the two is minimal - even for inside a tight loop.
Finally, you may as well use foo_2()- the compiler is perfectly within it's rights to make a variable like that static. As it was initially defined as const, const_casting the const away is undefined behaviour, regardless of whether or not it's static. However, it can't choose to make a static constant non-static, as you could be depending upon the ability to return it's address, for example.
An easy method to find out how variables are initialized is to print an assembly language listing of a function that has static and local variables.
Not all compiler initialize variables in the same method. Here is a common practice:
Before the main() method global variables are initialized by copying a section of values into the variables. Many compilers will place the constants into an area so that the data can be assigned using simple assembly move or copy instructions.
Local variables (variables with local scope) may be initialized upon entering the local scope and before the first statement in the scope is executed. This depends upon many factors, one of them is the constness of the variable.
Constants may be placed directly into the executable code, or they may be a pointer to a value in ROM, or copied into memory or register. This is decided by the compiler for best performance or code size, depending on the compiler's settings.
On the technical side, foo_1 and foo_3 are required to initialize their arrays before any functions, including class constructors, are called. That guarantee is essentially as good as no runtime. And in practice, most implementations don't need any runtime to initialize them.
This guarantee applies only to objects of POD type with static storage duration which are initialized with "constant expressions". A few more contrasting examples:
void foo_4() {
static const int v[4] = { firstv(), 2, 3, 4 };
}
namespace { // anonymous
const int foo_5_data[4] = { firstv(), 2, 3, 4 };
}
void foo_5() {
const int (&v)[4] = foo_5_data;
}
The data for foo_4 is initialized the first time foo_4 is called. (Check your compiler documentation to find out whether this is thread-safe!)
The data for foo_5 is initialized at some time before main() but might be after some other dynamic initializations.
But none of this really answers questions about performance, and I'm not qualified to comment on that. #DeadMG's answer looks helpful.
You have a static initialization in all those cases, all your static variables will be initialized by the virtue of loading data segment into memory. The const in foo_2 can be initialized away if compiler finds it possible.
If you had a dynamic initialization, then initialization of variables in the namespace scope can be deferred until their first use. Similarly, dynamic initialization of local static variables in the scope of function can be performed during the first pass through the function or earlier. Additionally, compiler can statically initialize those variables if it's able to do that. I don't remember the exact verbiage from the Standard.
Related
Imagine the following declaration:
void foo(){
const std::array<int, 80000> arr = {/* a lot of different values*/};
//do stuff
}
And a second one:
void foo(){
static const std::array<int, 80000> arr = {/* a lot of different values*/};
//do stuff
}
What are the possible performance differences between these two if any? And is there any danger associated with any of these solutions?
Forget the array for a moment. That muddles two separate issues. You've got answers that address the lifetime and storage issue. I'll address the initialization issue.
void f() {
static const int x = get_x();
// do something with x
}
void g() {
const int x = get_x();
// do something with x
}
The difference between these two is that the first one will only call get_x() the first time that f() is called; x retains that value through the remainder of the program. The second one will call get_x() each time that g() is called.
That matters if get_x() returns different values on subsequent calls:
int current_x = 0;
int get_x() { return current_x++; }
And is there any danger associated with any of these solutions?
Non-static is dangerous because the array is huge, and the memory reserved for automatic storage is limited. Depending on the system and configuration, that array could use about 30% of the space available for automatic storage. As such, it greatly increases the possibility of stack overflow.
While an optimiser might certainly avoid allocating memory on the stack, there are good reasons why you would want your non-optimised debug build to also not crash.
What are the possible performance differences between these two if any?And is there any danger associated with any of these solutions?
The difference depends exactly on how you use foo().
1st case:(low probability): Your implementation is such that you will call foo() only once , maybe you have created separate function to divide code logic as practiced. Well in this case declaring as static is very bad, because a static variable or object remains in memory until programs ends . So just imagine that your variable occupying memory unnecessarily.
2nd case:(high probability): Your implementation is such that you will call foo() again and again . Then non-static object will get allocated and de allocated again and again.This will take huge amount of cpu clock cycles which is not desired .Use static in this case.
In this particular context, one point to consider regarding using static on a variable with initialization:
From C++17 standard:
6.7.1 Static storage duration [basic.stc.static]
...
2 If a variable with static storage duration has initialization or a destructor with side effects, it shall not be eliminated even if it appears to be unused, except that a class object or its copy/move may be eliminated as specified in 15.8.
Let's say that I have a function that I call a lot which has an array in it:
char foo[LENGTH];
Depending upon the value of LENGTH this may be expensive to allocate every time the function is called. I have seen:
static char foo[LENGTH];
So that it is only allocated once and that array is always used: https://en.cppreference.com/w/cpp/language/storage_duration#Static_local_variables
Is that best practice for arrays?
EDIT:
I've seen several responses that static locals are not best. But what about initialization cost? What if I'd called:
char foo[LENGTH] = "lorem ipsum";
Isn't that going to have to be copied every time I call the function?
As LENGTH is supposed to be a compile time constant (C++, no C99 VLA), foo is just going to use space on the stack. Very fast.
First off, time to allocate automatic array of char is not dependent on it's size, and on any sane implementation is a constant time complexity of incrementing stack pointer, which is superfast. Please note, this would be the same even for VLA (which are not valid in C++), only that increment would be a run-time operand. Also please note, the answer would be different if your array would be initialized.
So it is really unclear what performance drawback you are referring to.
On the other hand, if you make the said array static, you would incur no penalty whatsoever in the provided example - since char is not initialized, there will be no normal synchronization which prevents static variables from getting doubly initialized. However, your function will (likely) become thread-unsafe.
Bottom line: premature optimization is the root of evil.
"Allocating" an object of primitive data type and with automatic storage duration is usually not a big deal. The question is more: Do you want that the contents of foo to survive the execution of the function or not?
Consider, for example, following function:
char* bar() {
char foo[LENGTH];
strcpy(foo, "Hello!");
return foo; // returning a pointer to a local variable; undefined behaviour if someone will use it.
}
In this case, foo will go out of scope and will not be (legally) accessible when bar has finished.
Everything is OK, however, if you write
char* bar() {
static char foo[LENGTH];
strcpy(foo, "Hello!");
return foo; // foo has static storage duration and will be destroyed at the end of your program (not at the end of bar())
}
An issue with large variables with automatic storage duration might arise, if they get so large that they will exceed a (limited) stack size, or if you call the function recursively. To overcome this issue, however, you'd need to use dynamic memory allocation instead (i.e. new/delete).
Here is the code:
int factorial(int n)
{
if ( n < 0 ) return -1; //indicates input error
else if ( n == 0 ) return 1;
else return n * factorial(n-1);
}
int const a = 10 ; //static initialization
//10 is known at compile time. Its 10!
int const b = factorial(8); //dynamic initialization
//factorial(8) isn't known at compile time,
//rather it's computed at runtime.
(stolen from here)
So it makes sense to me why b is dynamically initialized and a is statically initialized.
But what if a and b had automatic storage duration(maybe they had been initialized in main()), could you then still call their initialization either static or dynamic? Because, to me, they sound like a more general name for initialization than for example Copy initialization.
Also, I have read this and can anybody tell me why they have not directly explained what static and dynamic initialization are? I mean, it looks like that they only have explained in what situations they happen, but maybe there is a reason why?
cppreference states the initializer may invoke (some intializations, like value initialization etc.), but later in the article, they mention static and dynamic initialization as if those two were more general names for some initializations. This could sound confusing, but here I have illustrated what I understand:
(not the most beautiful thing)
Static and dynamic initialization describe the process of loading a binary and getting to the point when main is ready to run.
static initialization describes the information the compiler can work out at compile time, and allows for fixed values to be stored in the binary so at the point when the binary is loaded by the operating system, it has the correct value.
dynamic initialization describes the code which is inserted by the compiler before main runs, which initializes the information which the compiler was unable to calculate. That may be because it involves code directly, or that it refers to information which was not visible to the compiler at compile time.
But what if a and b had automatic storage duration
The simple case when a is an automatic variable of limited scope.
int a = 12;
This could not be statically initialized, because the compiler will not know where to initialize a, as it would be different each time, and on each thread which called it.
The compiler will be able to initialize a with something like.
mov (_addr_of_a), 12
As _addr_of_a is unknown until runtime, and the value 12 is embedded in the code, a case for statically initializing it would not be done.
More complex cases ...
int a[] = { /* some integer values */ };
This is possibly going to be implemented by the compiler as a mixture of static and dynamic code as below.
static int a_init = { /* some integer values */ };
memcpy( a, a_init, length_in_bytes_of_a );
So some cases there will be "leakage" from static initialization into runtime behaviour.
Dynamic behavior is more problematic - it assumes that a function which does not normally expose its implementation, has both a slow execution time, and is a constexpr to give value to the caching at start of the result. I have not seen this optimization occur.
Static and dynamic initialization are technical terms which describe the process of creating a running program. Similar patterns may exist for local variables, but they would not fall into the technical definition of static and dynamic initialization.
This is a very simple question:
Does 0-initializing global and static variables have any performance penalty (albeit very small) at runtime?
No, since the C++ (and C) standard says that all global/static variables that are not initialized explicitly by the programmer, must be initialized to zero. Such variables are placed in a special segment called .bss. They are initialized to zero before main() is called.
If you initialize your global/static explicitly, but to the value 0, the compiler is smart enough to realize this and still put it in the bss segment.
You can test this for yourself with an example like this:
#include <stdio.h>
static int uninit;
static int init_zero=0;
static int init_one=1;
int main (void)
{
printf("%p\n", &uninit);
printf("%p\n", &init_zero);
printf("%p\n", &init_one);
return 0;
}
In this example, the uninit and init_zero variables will end up at adjacent memory addresses (likely 4 bytes away from each other), since they are both in the .bss segment. But the init_one variable will end up somewhere else entirely, because it is allocated in the .data segment.
Extending the question from 0-initialization (which is just a subset of) to default initialization, we still can conclude that it usually has no measurable impact on application performance. However, it is easy to design a class which will do, for example, database lookup in it's constructor - thus leading for interesting effects noticeable during application startup.
I noticed that if you initialize a static variable in C++ in code, the initialization only runs the first time you run the function.
That is cool, but how is that implemented? Does it translate to some kind of twisted if statement? (if given a value, then ..)
void go( int x )
{
static int j = x ;
cout << ++j << endl ; // see 6, 7, 8
}
int main()
{
go( 5 ) ;
go( 5 ) ;
go( 5 ) ;
}
Yes, it does normally translate into an implicit if statement with an internal boolean flag. So, in the most basic implementation your declaration normally translates into something like
void go( int x ) {
static int j;
static bool j_initialized;
if (!j_initialized) {
j = x;
j_initialized = true;
}
...
}
On top of that, if your static object has a non-trivial destructor, the language has to obey another rule: such static objects have to be destructed in the reverse order of their construction. Since the construction order is only known at run-time, the destruction order becomes defined at run-time as well. So, every time you construct a local static object with non-trivial destructor, the program has to register it in some kind of linear container, which it will later use to destruct these objects in proper order.
Needless to say, the actual details depend on implementation.
It is worth adding that when it comes to static objects of "primitive" types (like int in your example) initialized with compile-time constants, the compiler is free to initialize that object at startup. You will never notice the difference. However, if you take a more complicated example with a "non-primitive" object
void go( int x ) {
static std::string s = "Hello World!";
...
then the above approach with if is what you should expect to find in the generated code even when the object is initialized with a compile-time constant.
In your case the initializer is not known at compile time, which means that the compiler has to delay the initialization and use that implicit if.
Yes, the compiler usually generates a hidden boolean "has this been initialized?" flag and an if that runs every time the function is executed.
There is more reading material here: How is static variable initialization implemented by the compiler?
While it is indeed "some kind of twisted if", the twist may be more than you imagined...
ZoogieZork's comment on AndreyT's answer touches on an important aspect: the initialisation of static local variables - on some compilers including GCC - is by default thread safe (a compiler command-line option can disable it). Consequently, it's using some inter-thread synchronisation mechanism (a mutex or atomic operation of some kind) which can be relatively slow. If you wouldn't be comfortable - performance wise - with explicit use of such an operation in your function, then you should consider whether there's a lower-impact alternative to the lazy initialisation of the variable (i.e. explicitly construct it in a threadsafe way yourself somewhere just once). Very few functions are so performance sensitive that this matters though - don't let it spoil your day, or make your code more complicated, unless your programs too slow and your profiler's fingering that area.
They are initialized only once because that's what the C++ standard mandates. How this happens is entirely up to compiler vendors. In my experience, a local hidden flag is generated and used by the compiler.