Using all global variables?

Started by
24 comments, last by JohnBolton 18 years, 7 months ago
Quote:globals are better because they increase application speed.
Simply fallacious.
Advertisement
Quote:Original post by Deyja
Quote:globals are better because they increase application speed.
Simply fallacious.

Beyond fallacious, a downright lie - the opposite is true, globals can hinder application speed.

Fixxer, you are hereby charged with being a rumor zombie. Anything you say can and will be ignored in a forum like this [to prevent furhter contamination].

In cases where making a variable global will affect preformance, it will usually do so by hindering it. Let's compare two implementations of a function:

//Version 1:int i;void function() {    for ( i = 0 ; i < 10 ; ++i ) {        ...    }}//Version 2:void function() {    for ( int i = 0 ; i < 10 ; ++i ) {        ...    }}


So, what's the difference? Version 1 is ugly, and not only that, but i must be stored in memory. "i" can be modified and looked up from any place in the program. In version 2, i is a local variable, which in most circmstances will allow the optimizer to never allocate memory for i, instead using one of the many registers of the processor. Assuming we don't do anything in the loop, the compiler can completely eliminate the loop in function() and remove it. The function will inline into a no-op. Version 1 must at least assign i to 10.

So what's the big deal? Nothing much, until you start accounting for cache misses. If a program forces the OS to load in a 4KB page (possibly from disk if it's been paged out) just because your program writes a variable which is never used anywhere else in the program, that's really bad.



Further, there's no really good reason to use globals in most circumstances. I'd prehaps even argue ALL circumstances. They're brittle in that they limit you to a single instance of that variable - what happens when your program needs to access multiple screens? If you've stored the screen width and height in globals used throughout your program, everything comes tumbling down when they just don't cut the mustard anymore.

If instead you pass things a reference to the screen as needed, all that's needed is to provide the correct screen when you call the function.

Basically, instead of:

int width, height;void random_render_function( ... ) {    render_square( 0 , 0 , width / 2 , height / 2 );}int main () {    GetRandomAPIMetrics( & width , & height );    random_render_function( ... );}


I do:

struct screen_data {    int width, height;};void random_render_function( screen_data & screen , ... ) {    render_square( 0 , 0 , screen.width / 2 , screen.height / 2 );}int main () {    screen_data screen;    GetRandomAPIMetrics( & screen.width , & screen.height );    random_render_function( screen , ... );}


As the program grows more complex, I can retool and relocate things easily:

int main () {    big_huge_screen_manager bhsm;    random_render_function( bhsm.get_default_screen() , ... );}


Rewiring and relocating data when you depend on global names for access is much harder - they're a hinderance to higher level refactorings.
Quote:Original post by Fixxer
If you can be organized with your code, globals are better because they increase application speed.


Why don't we take a brief tour of the memory subsystem of your computer? A modern personal computer has a hierarchical memory system. The fastest memory is the registers, and then you have two to three levels of cache, which are slower than the registers. Following that is the main memory, and at the bottom is the disk which is used for virtual memory. Now, roughly speaking each level is an order of magnitude slower than the level above it. Following me so far? Now to get better performance we need to keep the working set of memory as small as possible so it fits in the smallest part of the memory hierarchy. If your working set spills out too far then you'll waste a lot of time just waiting for memory to load or store.

Now, roughly speaking, there are a number of different regions in memory that you need to deal with. There's the code segment of your executable which contains the actual machine instructions your program executes, there's the data segments of your executable which is where globals get stored, there's the stack and the heap, and then there are the code and data segments of any dynamic libraries you use as well as kernel memory. Now then, we need to concern ourselves with the tight loop: the ultimate bottleneck of every game. Hopefully in your tight loop you've managed to do away with any system or library calls so all you're concerned about is your executable's data and your executable's code.

Now then, you've got the data on the stack. You're stuck with accessing that since thats where your local variables, return address and what not get put. Now if you're running any sort of non-trivial program you've got some memory on the heap you need to manipulate. And of course, you've got the code you're running. What happens when you throw in a global variable access? Now, you've got a memory reference that is physically non-local to any of the other memory addresses that you need to be working with in this tight loop. This means it takes up a dispropotionately large part of the memory hiearchy, since it won't share a cache line with the stack, code or heap data. The increases the working set. And the real bugger is that the L1 cache for a processor is generally not fully associative, and due to the way that linkers generally lay down the data segments of global variables, the chances are that if you access multiple globals from multiple translation units you're going to get mapped to the same cache line set, which seems likely as your are advocating the use of global variables as a speed "enhancer". This in turn will make it so much more likely that your working set is going to spill out of the L1 into the L2. Or out of the cache and into main memory. This is bad.
Loop variables, and variables that are not accessed by any other function, should not be made into globals.

If your working in C, than thats really the just of it.

Else If C++, than you get your Singletons, Accessor Methods, and Encapsulation (I'm just listing whats been mentioned on this post).
Quote:Original post by BKBen7
It helps me keep track of things easier then having local variables and passing them back and forth.


Once you start doing anything non-trivial, you are almost certain to find that the opposite is true.
A direct link to the data segment means less stack exercise, on a small uC it could be significant,; that's where the idea that globals are faster comes form.

Lots of good examples to the contrary for PC's though!
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Quote:Original post by Fixxer
If you can be organized with your code, globals are better because they increase application speed.
Using a global for something that should be a local is not better, it is downright WRONG!
I suggest (nay, insist) that you do your own searching around to find out why.
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms
Another reason against the use of global variable is that the constructor of that variable is called before the main entry point. This means that if an exception is raised during this execution period it will never be caught.
sorry it was me. Forgetting to log in.
[ILTUOMONDOFUTURO]
Intel C++ compiler does not even allow global variables without prior "extern" declaration. That is very nasty.

What about you have a Singleton, someone has to create at least one instance?!

test.h:

class CTest : public mySingleton<CTest>
{
public:
CTest() {...}

void DoSomething(...)
}

test.cpp:

static CTest myTestInstance;

The problem here is, that without static it does not work. When I use a singleton in some kind of static library, i can not say: CTest::GetInstance()->DoSomething since no instance of CTest does exist. If I use Statitc the compiler does not complain anymore, but why does static set him allright?

This topic is closed to new replies.

Advertisement