Friday, July 22, 2011

What is an "Engineer Architect"

A question that i get asked rather a lot is "What is an Engineer Architect"

en·gi·neer
noun /ˌenjəˈni(ə)r/ 
A person who designs, builds, or maintains engines, machines, or public works

ar·chi·tect

noun /ˈärkiˌtekt/ 
((computer science) the structure and organization of a computer's hardware or system software) "the architecture of a computer's system software"

This basically translates to the same thing all engineers do:

  • Analyze the problem
  • Formulate a possible set of solutions
  • Analyze the solutions
  • Decide what to implement
  • Implement
  • Test/bug fix
  • Profile/sanitize
  • Repeat until satisfied

however with one important difference. My role involves the entire program, how its parts interact and how they are designed, what their dependencies are and how they affect the final output and the performance of that output. Combine this with data parallel infrastructure, task parallel objects, multiple platforms, myriad hardware limitations and a large programming team ... under many circumstances one might imagine something akin to

and you often wouldn't be too far from the truth on a daily basis. Long term however we (the team) have a plan and a set of goals. Over time we re-assess based on those we hit and those we don't, new requirements and ultimately how the game is progressing and where it needs to go. The role I play in this is simply to ensure that under the stress and strain of day to day development, we're still aiming in the right direction as a whole. That decisions take into account as much of the big picture as possible and weigh that against the immediate requirements of the current goal. There are several people in similar roles at Bungie and our interactions provide a simple but effective method of applying "Checks & Balances" to the progress we make; we each bring our own flavor to the table.

Day to day this involves tasks such as

  • Advising/Teaching on how to handle concurrency
  • Long term interface design
  • Short term prototyping/bug fix hacks
  • Discussing/Advising on future platforms
  • Optimizing programmer iteration, debugging & general workflow
  • Managing external teams
  • Auditioning Middleware
  • designing/writing/debugging infrastructure systems

Technically i'm a member of Bungies "Infrastructure" team. This means that if its something "unexciting", "behind the scenes" or seemingly doesn't affect the final game at all... we handle it. This involves systems like

  • Memory Allocation
  • File System
  • Network Transport
  • Crash Handling, Minidumps
  • Debugger Plugins
  • Multi-threading Infrastructure & Architecture
  • Asset import/baking
  • Math Library
  • Schematization/Reflection
  • Audio Engine
  • Container Classes
  • Profiler Infrastructure
  • Compiler Configuration
  • Low & High level Optimization
  • Build systems
  • Flux Capacitor Maintenance
  • - you still reading?

as i said... the stuff most most programmers find tiresome and boring. Our team love this stuff and we're good at it.

So there you have it, a much better idea of what i do @ Bungie and hopefully a guide to those in school who might want to progress towards a similar role (or avoid it).

Thursday, July 7, 2011

Writing a "Pre-Main" function - Forcing Global Initialization order within VC++

One rule of C/C++ programming that bites everyone eventually is that initialization order of global variables across compilation units is not guaranteed. I've seen programs with global variable dependencies run fine for years then suddenly develop "issues" resulting in a hard lock before main(..) is hit. I've seen other programs have dependency issues but not actually crash resulting in subtle bugs that never seem to negatively affect run-time... until they do, usually on the day before gold master when the lead programmer is in Peru.

So here's the situation, you want to create objects "a" through "g" in various files who register themselves with a manager into a list on construction... a relatively common setup and relatively simple within a single compilation module; for VC++ define them from bottom to top manager first and it will work. However across compilation modules things are not so simple and more often than not the manager will construct itself at a very inopportune time; likely after some objects have registered themselves and before all objects have.

Without simply knowing that the manager will initialize first there really isn't a "Good" solution tho there are several lazy initialization techniques.

So here's where things get "fun" and by "fun" i mean, people look at the code and get confused looks on their face.

Put the following code into a cpp file on its own and add it to your project of choice.

#pragma init_seg( ".CRT$XCB" )

class c_blog_first_class_construction
{
public:
    c_blog_first_class_construction() 
    {
        printf("first class construction\n");
    }

    ~c_blog_first_class_construction() {};
};

static c_blog_first_class_construction blog_first_class_construction;

the constructor for c_blog_first_class_construction will be called before any other constructor in your code (assuming you have nothing else like this in there).

NOTE: Expect C4075: initializers put in unrecognized initialization area, disable it if you feel the need.

the key to the code is
#pragma init_seg(...)

for more info on what this does see kb104248

The crux of it however is we are naming this compilation unit with a specific identifier, when the linker reads various .CRT groups, it combines them in one section and orders them alphabetically. This means that the user-defined global initializers (which the Visual C++ compiler puts in .CRT$XCU) will always come after CRT$XCA and before .CRT$XCZ.

So we are depending linker to do the right thing and insert our section into the CRT sorted sections (verified in VS2010 as of 7/6/2011 for x86,x64,x360). It works and its very useful.

Now if you want to get really fancy... make the constructor for c_blog_first_class_construction call a function that initializes your "Pre construction" requirements engine wide (usually memory management, assert systems).

For other platforms (GCC/SNC are the only others i use) there are other options such as "init_priority" which is a per instance attribute. These can be used to achieve the same result but on a more granular level.

It should be noted that this is not a method that one should use all over a codebase, personally i only ever use it on one compilation module and it is always VERY well commented.

enjoy.