Nulik
Nulik

Reputation: 7360

stack (local) or global variables?

Will using global variables give a speed up? In Intel's Architecture Software Developer Manual (about the microprocessor) it is recommended to use local variables instead of global. But, consider the following code:

void process_tcp_packets(void) {
    char tcp_data[128];

    do some stuff with the tcp_data[]....
}

void process_udp_packets(void) {
    char udp_data[128];

    do some stuff with the udp_data[]
}
void main_event_loop(void) {

    while(1) {
         if (pending_tcp_requests) {
             process_tcp_packets();
         }
         if (pending_udp_requests) {
             process_udp_packets();
         }
   }
}

When main_event_loop() is executed, the control of the flow depends on the variables "pending_tcp_requests" and "pending_udp_requests". Both functions process_tcp_packets() and process_udp_packets(), when called, will allocate local variables at the current stack pointer. This means if the code is constantly switching both functions, the local variables will be allocated at the same memory address. Sharing the memory address between both functions will evict data from current L1 cache and slow execution. So, by using global variables instead of local ones we can speed up execution. Is it correct or not?

If so, is there any drawback for using global variable in this case?

Upvotes: 2

Views: 1643

Answers (5)

Crashworks
Crashworks

Reputation: 41374

Global variables are very unlikely to give you a benefit over the stack in this case.

  1. "Allocating" memory on the stack is simply adding a number to the stack pointer, a ½ cycle operation.
  2. At 64kb, the L1 cache is large enough to contain many stack frames. Moreover the most recent few stack frames are (because you push params when calling a function) almost always in the cache. In fact, the region for the next frame to be allocated is usually in L1, because you've often just exited some other function that used it.
  3. By contrast, global variables quickly fall out of L1. Remember, the stack is touched at the beginning and end of every function (just to push the return address), and process_tcp_packets() and process_udp_packets() will both use approximately the same address space to store their locals.
  4. Sharing memory addresses between functions does not evict data from cache. On the contrary, it makes you more likely to hit cache. The more recently you have touched an address, the more likely it is to be in cache.

Upvotes: 4

MSN
MSN

Reputation: 54584

Sharing the memory address between both functions will evict data from current L1 cache and slow execution. So, by using global variables instead of local ones we can speed up execution. Is it correct or not?

Your premise is not correct for single-threaded use of memory.

Sharing the same memory between threads using different CPU caches will cause cache contention (and usually flushing). Sharing memory between functions on the same thread using the same CPU cache will not do this at all.

Also, on some platforms, local variables require less instructions to access than global variables (as they are offsets local to the stack pointer and can usually be encoded in <=2 bytes, where as global variables may not be).

Upvotes: 4

Alexander Kondratskiy
Alexander Kondratskiy

Reputation: 4275

One middle of the road compromise to what you're suggesting is declaring those array variables as static within the function. They "act" as global variables, in that all calls to the function reuse the same memory location for the array, but you have none of the scope issues of global variables- the arrays can only be accessed from their respective functions.

void process_tcp_packets(void) {
    static char tcp_data[128];

    do some stuff with the tcp_data[]....
}

void process_udp_packets(void) {
    static char udp_data[128];

    do some stuff with the udp_data[]
}

Upvotes: 0

Edwin Buck
Edwin Buck

Reputation: 70909

The problem you are describing can be fixed without resorting to using a global variable. Make a local variable in the stack above and pass a reference (pointer) to the method. It's the best of both worlds.

void process_tcp_packets(char** tcp_data) {
    do some stuff with the tcp_data[]....
}

void process_udp_packets(char** udp_data) {
    do some stuff with the udp_data[]
}

void main_event_loop(void) {
    char udp_data[128];
    char tcp_data[128];
    while(1) {
         if (pending_tcp_requests) {
             process_tcp_packets(&tcp_data);
         }
         if (pending_udp_requests) {
             process_udp_packets(&udp_data);
         }
   }
}

Global variables are to be avoided for more than one reason. Eventually it becomes difficult to know why the data changes in a global due to too many places where the global might be accessed (i.e. the whole program). By using local variables, the variable cannot be accessed from outside of the block of execution, unless explicitly passed. This permits partitioning of your program to a few methods which can access that particular piece of memory, vastly simplifying debugging and ability to maintain a program (over time).

Upvotes: 1

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 153820

The best thing to do is to measure. Note, however, that the arrays are semantically always new ones although they will end up holding the previous bytes. If you actually intend to keep some state in these arrays, you'd need to make them static in which case they would also get different memory regions. I haven't measured but I would expect that using local variable is faster than global variables because there is never any need to actually write them to memory unless the caches overflow.

Upvotes: 1

Related Questions