Measure Initialization Time of Global Variables

NOTICE: The technique describes in the article may not be supported in future release of VC. You should not use it in production code

There are two kinds of initialization in C++: static initialization and dynamic initialization.

According to the standard, static initialization shall always be performed before any dynamic initialization takes place.

In VC, static initialization is done at compile time. The value is stored in the data section of the generated executable. On the other hand, dynamic initialization happens at runtime. Before entering main, CRT will call the dynamic initializers of the global variables.

Sometimes you may need to measure the startup time of your program. However, dynamic initialization happens before main, so your measurement will not include it.

This article "CRT Initialization" describes the detailed information of how dynamic initialization works in VC.

VC provides pragma init_seg to fine-control the initialization process. It will place the dynamic initializers in the specific section. Besides predefined compiler, lib and user (the corresponding section names are ".CRT$XCC", ".CRT$XCL" and ".CRT$XCU"), you can also specify the section name explicitly.

With these knowledge, we can use the following code to measure the initialization time of global variables.

Let’s create two files: InitTime_Start.cpp and InitTime_End.cpp (we have to use two files because one file can only have one init_seg)

//InitTime_Start.cpp

#pragma warning(disable : 4075)

#pragma init_seg(".CRT$XCB")

Timer gInitTimer;

//InitTime_End.cpp

#pragma warning(disable : 4075)

#pragma init_seg(".CRT$XCY")

double gInitTime = gInitTimer.GetTime();

Here, "Timer" is a class which will start timing in ctor and return the elapsed time in member function GetTime. Because ".CRT$XCB" will be placed before ".CRT$XCC", the dynamic initializer of the timer will be called before any dynamic initializers of compiler generated global variables. Similarly, gInitTimer.GetTime will be called after all the dynamic initializers of user defined global variables. Then "gInitTime" will contain the initialization time of all global variables including those generated by compiler, library and user.