using static initialisation for paralelization?

Started by
26 comments, last by Hodgman 9 years, 10 months ago

Months a go i found somthing like 'bug' in my code it is when turning

static DWORD processID = 0;
processID = GetCurrentProcessId();

into

static DWORD processID = GetCurrentProcessId();

my exe size jumped from 25k to 75k and I also noticed

slowdown of my game frame (from 3ms to 4ms) (though i still

do not know how it is possible (as this static initialization should

only appear once not each frame) and how to understand/explain it,

is this some cache efect appearing when exe bigges its size, got no idea)

there was answer

samoth,


"One notable difference of whether you compile C or C++ is for example that C++ (at least C++11, but GCC since ca. version 4.6 also does that for C++03) mandates initialization of function-local static variables being thread-safe. I'm mentioning that since you use that feature (maybe without being aware)."

if so I do understand that c++ language did that to can do static initializations

multithreading so i mean such kode like this

static int one = f1(); // potetntialy referencing and updating other data

static int two = f2();

static int three = f3();

static int four = f4();

void main() { printf("\n done."); }

can/will execute on many cores in parralel ? will main then wait untill the last one of initializing functions end it work? so it potentially could be used for

cheap form of multithreading?

Advertisement

No. It did it so if you are initializing static-local functions in a multi-threaded environment, it will have defined results.

It certainly does not affect namespace-level static initialization, not does it imply anything about the introduction of a threaded environment during application initialization.

Stephen M. Webb
Professional Free Software Developer

No. It did it so if you are initializing static-local functions in a multi-threaded environment, it will have defined results.

It certainly does not affect namespace-level static initialization, not does it imply anything about the introduction of a threaded environment during application initialization.

i do not understood (partialt through weak english)

so will this maybe work?

void main()

{

static int one = f1(); // potetntialy referencing and updating other data

static int two = f2();

static int three = f3();

static int four = f4();

printf("\n done.");
}

if this is not done to allow some parallel works what it is for?

and how is the mechanizm it slowed my program and growed it +50KB

size

if this is not done to allow some parallel works what it is for?
and how is the mechanizm it slowed my program and growed it +50KB
size


No, that will not do anything in parallel either.
It is there so that when you call functions from threads the static data is setup in a thread safe manner.
In order to ensure this the runtime will have to add some code/mutex locks to make sure two threads can't try to initialise at the same time.

[source]
void foo()
{
static int one = f1(); // potetntialy referencing and updating other data
static int two = f2();
static int three = f3();
static int four = f4();
}

int main()
{
parallel_invoke(foo, foo); // some function which will run supplied functions on multiple threads
printf("\n done.");
}
[/source]

So, in the above code 'foo' is invoked on two threads via the helper function. In C++03 the static initialisation of the function's variables would not be safe as both threads might end up running the setup functions. In C++11 only one thread would.


how is the mechanizm it slowed my program and growed it +50KB

I suspect, without proof, that it pulled in some library code to wrap and serialize the initialization of the function-local statics, and the slowdown is because that code gets executed. Thread serialization generally requires context switches and pipeline stalls. Without knowing the code, I suspect that code path needs to be executed every time so it can check to see if the object has been initialized.

Stephen M. Webb
Professional Free Software Developer

if this is not done to allow some parallel works what it is for?
and how is the mechanizm it slowed my program and growed it +50KB
size


No, that will not do anything in parallel either.
It is there so that when you call functions from threads the static data is setup in a thread safe manner.
In order to ensure this the runtime will have to add some code/mutex locks to make sure two threads can't try to initialise at the same time.

[source]
void foo()
{
static int one = f1(); // potetntialy referencing and updating other data
static int two = f2();
static int three = f3();
static int four = f4();
}

int main()
{
parallel_invoke(foo, foo); // some function which will run supplied functions on multiple threads
printf("\n done.");
}
[/source]

So, in the above code 'foo' is invoked on two threads via the helper function. In C++03 the static initialisation of the function's variables would not be safe as both threads might end up running the setup functions. In C++11 only one thread would.

I do not understand, iznt the static data initialized at startup (pre-main) time?

If you call it from 2 threads this statics are shared but if it was initialized before in pre mian time so it cannot be collision on threads initialization of this (as they do not nitialize it, its already initialized) (?)

Im not quite sure as i was doing a little multithreading in my life but I understand that static data are unsafe at all so you nead thread local

storage (?)


how is the mechanizm it slowed my program and growed it +50KB

I suspect, without proof, that it pulled in some library code to wrap and serialize the initialization of the function-local statics, and the slowdown is because that code gets executed. Thread serialization generally requires context switches and pipeline stalls. Without knowing the code, I suspect that code path needs to be executed every time so it can check to see if the object has been initialized.

I can provide the code if you want


 
#define WIN32_LEAN_AND_MEAN
#define WIN32_EXTRA_LEAN
#include <windows.h>
 
#include <psapi.h>
 
#include "..\allmyheaders\allmyheaders.h" //that was temporary skip it
 

long working_set_size = -1;
long paged_pool_size = -1;
long nonpaged_pool_size = -1;
 
static PROCESS_MEMORY_COUNTERS process_memory_counters;
 
long GetMemoryInfo()
{
 
    static HANDLE hProcess;
 
    static int initialised = 0;
    if(!initialised)
    {
     static DWORD processID = GetCurrentProcessId(); // <---THIS CRITICAL LINE
 
     hProcess = OpenProcess(  PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID );
 
     if (NULL == hProcess)  ERROR_EXIT("cant open process for get memory info");
 
     initialised = 1;
 
 
    }
 
 
    if(GetProcessMemoryInfo(hProcess, &process_memory_counters, sizeof(process_memory_counters)))
    {
      working_set_size    = process_memory_counters.WorkingSetSize;
      paged_pool_size     = process_memory_counters.QuotaPagedPoolUsage;
      nonpaged_pool_size  = process_memory_counters.QuotaNonPagedPoolUsage ;
    }
 
    if(0)
      CloseHandle( hProcess );
 
    return working_set_size;
}
 

damn those bug that cutts the rest of the post after /code tag

(eated a 20 lines of text)

this is code for measuring memmory consumption in my window program - it is called each frame but ini block is called only once as you see (some technique with 'initialized' flag of my own 'invention' (though probably other people use it too as its fine )

understanding what reaseo id for this and what is realli going on under the hood would be very velocome as it is some slowdown and exe bloat pitfall for me (its obviously not needed in my case as i say breaking those line on two makes execution faster and exe is smaller)

No, function-scope statics are initialized only when the function s executed. Imaging there's a bool that's initialized before main, which is used in an "if !initialized" in every function call.

No, function-scope statics are initialized only when the function s executed. Imaging there's a bool that's initialized before main, which is used in an "if !initialized" in every function call.

if so alrighte, so i understand the option for possible collistion

anyway this is a pitfal trap for me putting something slowing and bloating my program implicitely

there should be a large text * * * WARNING POSSIBLE CODE SLOWDOWN (reasone here) * * *

it would be nice to know what really is putted there just some critical

section around this function? why it slows so much if ti is only one run called?

does mingw compiler has more such slowdown pitfals (Im compiling pure c winapi codes trying to be very carefull against any slowdown

in my generated code - it would be very important to me to be sure

that i got all such overhead slowdowns avoided)

it would be nice to know what really is putted there just some critical
section around this function? why it slows so much if ti is only one run called?


The initialisation code is only called once but the 'is initialised' flag must be checked every time the function is run; depending on the compile this could involve locking a mutex pre-check which is not a cheap operation.

This topic is closed to new replies.

Advertisement