Advertisement

Cutting Compile Times

Started by April 27, 2000 09:59 AM
24 comments, last by Kylotan 24 years, 8 months ago
quote: Original post by null_pointer

In my stab at building a large lib (20+ modules)


20 is large? I must have about 50 or so

quote:
Move #include "stdafx.h" line from the .cpp files to the header files of the modules, and just #include the class header files in the .cpp files, and you get instant performance...drop! It''s slightly faster (about 1 second) when you change one header, and the change doesn''t affect any other class, but otherwise the thing takes 2 or 3 seconds, per module! :/

You say 2 or 3 seconds per module as if that''s a bad thing I am lucky to beat 15 seconds per module, 30 is more common.

quote: I don''t know if the experts would agree, but putting everything in stdafx.h and letting the compiler juggle which ones to compile first never seems to be worth the trouble of adding in like 2-5 includes for each module to track which classes are dependent on each other.


Well, keeping unnecessary headers out of your files is generally good so that you don''t pollute your namespace, too, but obviously that matters less and less with classes and encapsulation. The other issue is of course performance, but if you get a speedup by precompiling, obviously that benefit is gone too. What happens if you then want to compile on a compiler which can''t handle precompiled headers? Do GCC or EGCS handle them?

quote:

    1) Place forward declarations of all classes (except templates, of course) in the stdafx.h.

    2) Include the stdafx.h in all .cpp files.

    3) In each class header, include only the necessary headers (base classes, library functions, classes used as data members, etc.) to ensure that particular header will compile fine on its own, in any order. (optional)

    4) Place the customary #ifdef/#endif compiler directives around the contents of each header.

    5) Place this line in each file, just inside of the compiler directives, but before anything else:

    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000

That''s what I do, and I''ve never had a problem with compile time. Let me know if I''m wrong somewhere though.


With the exception of stages 1 and 2 (I don''t use stdafx.h right now) and stage 5 (redundant if you use stage 4, surely?) then I do exactly what you say above. And it takes 20 minutes or so to compile. No good. I do only have a P233 with 48mb ram, but I''ve heard of slower machines doing much better.
quote: Original post by SiCrane

If you've got enough memory you might consider doing your compiles on a project on a RAM disk. Alternately consider moving the contents of your lib and include directories to a the RAM drive.


How do you make a ram disk or drive on a PC? I thought only macs could do that.... I too suffer from horrible compile times... and these are short (1000 line) console apps that take 2 min to compile! I think this could help me. I have a PII 333 with 128mb of ram running Win98.

Edited by - Yanroy on 4/28/00 9:30:45 AM
--------------------

You are not a real programmer until you end all your sentences with semicolons; (c) 2000 ROAD Programming
You are unique. Just like everybody else.
"Mechanical engineers design weapons; civil engineers design targets."
"Sensitivity is adjustable, so you can set it to detect elephants and other small creatures." -- Product Description for a vibration sensor

Yanroy@usa.com

Advertisement
Ah.... back to the oldies again....
To create a RAMdrive for a Win9x system, add a line in CONFIG.SYS:

device=c:\windows\ramdrive.sys

Lookup the help for additional options/parameters/switches.
I don''t have any idea on NT. Anyone?
"after many years of singularity, i'm still searching on the event horizon"
The precompiled headers thing is a moot point because I guarantee you that you won''t be able to get more than one or two STL headers into StdAfx.h even if you wanted to. There are known bugs regarding large amounts of data in the .pch, which still persist in vc6 sp3, and it doesn''t take too much STL in there to crash the compiler.

As for portability, putting things in StdAfx.h will still work on other platforms, it will just be grossly inefficient since you''re including way too much for the average file most likely.

Finally, you should not sluff off the point about forward declarations. If you define class CFoo in Foo.h and a function on CFoo takes a CBar*, do NOT include Bar.h to get this to compile!!! Either make a forward declaration "class CBar;" ahead of the CFoo definition or change your function from "FunctionInCFoo(CBar* pBar);" to "FunctionInCFoo(class CBar* pBar);". This right here is one of the main reasons I still use pointers instead of references... if you use a reference or (by-value), the compiler needs to have CBar be properly declared. In my code, typically the only files I ever include in header files are the header file for a base class (since the compiler needs that definition to subclass). I''d say if you''re getting above 2-3 #includes inside of a header file, you''re doing something wrong.
quote: Original post by Kylotan
I use list extensively, vector a fair bit, and map and deque a little. But I would have no idea how to go about wrapping them in some way that would not break all my code and/or take forever. And would I not really have to either do another template class (thus reducing any benefits) or a separate instance of the container for each type (really not an option)? Any hints or pointers on this?

As I said, this is only an option if you use only a few STL classes as in list<cow> and list<pig> and that''s it. Normally I typedef my STL declarations ex: typedef list<cow> CowList; so it isn''t a big deal for code breaking. I always forget that other people don''t. Anyway you could probably run a sed/awk script to replace the instances of list<cow> with CowList. Then name the new class CowList and keep all the same function call names and retypedef the iterators inside the class.
Yep - I usually do wrappers for roughly a half dozen fundamental things - vector<int>, vector<string>, etc. Not only does this help your compile times, but it also might save you should you decide to switch STL libraries (yeah, they're supposed to be exactly the same, but often they vary on some little things).

Setting up a RAM drive and then doing a build all *will* make you smile. I've seen them cut times by 50-75%. For best results grab a couple more memory chips at Fry's, and make a 128 or 256 MB one, and use it as a scratch disk for PCH and OBJs.

Also, check your code. If you're constantly having to rebuild the world because you change one member of one class, you might want to re-evaluate your design. There are some techniques that can both cut your compile time and make your code more flexible (the Visitor pattern springs to mind).








Mason McCuskey
Spin Studios - home of Quaternion, 2000 GDC Indie Games Fest Finalist!
www.spin-studios.com

Edited by - mason on 4/28/00 12:45:39 PM
Founder, Cuttlefish Industries
The Cuttlefish Engine lets anyone develop great games for iPad, iPhone, Android, WP7, the web, and more!
Advertisement
Anonymous: I knew it would be technically portable, I was wondering about the precompilation ability of other compilers. I''d rather not have to ''unpick'' it all just to get it to compile on Linux within a day. And regarding forward declarations, I know all about them and use them a fair bit. But my classes have fairly clean interfaces so I rarely need more than 1 or 2 such declarations per header. So that base is already covered. Oh, and forward declarations work just as well for references as for pointers - I''m not sure why they don''t for you. After all, they are just pointers that look different I do tend to have more than 2 or 3 includes per CPP file though, very often. I am not confident this could be cut down without using 10x as many CPP files, however. For instance, one file covers all the commands available to an admin player: this player needs to be able to query the details of a room class, a monster class, another player class, an area class, etc etc. Therefore to implement these commands, I need to include the command class header and the header files for all these classes, in order to call their public accessors.

SiCrane: I do typedef all my stl container classes like that, exactly like that in fact, but there''s a hell of a lot of them! I would still have no idea of how to reimplement STL effectively, given that I may want to use the algorithms, etc etc. I just don''t have time to work out exactly how all those obfuscated header files work and do my own version of numerous containers, iterators and algorithms.

Mason: my code is fairly clean in some places, and not so good in others. Unfortunately my time is limited, and I am more interested in a finished result than perfect code, so I cannot devote the months it would take to clean it all up perfectly. I''m not familiar with the Visitor pattern but I''d already decided to invest in the Design Patterns book tomorrow as it happens, so I will be looking into that. I don''t tend to have to recompile the whole thing often, but quite often I have to add a function to an important class and this forces a recompile of 1/5 to 3/4 of the project. So I tend to have to ''batch'' my amendments, coding 4 or 5 changes before rebuilding, otherwise I''d spend longer compiling than programming
Oh, one other thing I remembered: the STL bug (in all implementations that I''ve seen, at least) which means it can''t handle pointers in containers without having the full class definition forces me to include slightly more class headers than I''d like.
You don''t need to re-implement the STL classes; just wrap them. ex:
Let''s say you''ve got
typedef list<cow> CowList;
replace that with
class CowList {  public:    typedef list<cow>::iterator iterator;    iterator begin(void);    // lots more function declarations  protected:    list<cow> impl_list;} 

And in a C file:
CowList::iterator CowList::begin(void) {  return impl_list.begin();} 

Then the list<cow> implementation is still used, but it isn''t inlined, so it''s still compiled only once, instead of ten billion times.
quote: Original post by DerekSaw

Ah.... back to the oldies again....
To create a RAMdrive for a Win9x system, add a line in CONFIG.SYS:

device=c:\windows\ramdrive.sys

Lookup the help for additional options/parameters/switches.
I don''t have any idea on NT. Anyone?


I did this... After several hours of debugging, I figured out that it is creating the ramdrive in base memory (max 640K), so this may not be that useful... I am using devicehigh in my config.sys too. The other problem I have with it is that it creates drive D, my CD-ROM (well, not anymore!) I would rather keep the CD-ROM drive D and make the ramdisk drive E... If anyone could help me with this, I would appreciate it very much. I really think this is what I need to cut a lot of time of compiles

--------------------


You are not a real programmer until you end all your sentences with semicolons;

Yanroy@usa.com

Visit the ROAD Programming Website for more programming help.

--------------------

You are not a real programmer until you end all your sentences with semicolons; (c) 2000 ROAD Programming
You are unique. Just like everybody else.
"Mechanical engineers design weapons; civil engineers design targets."
"Sensitivity is adjustable, so you can set it to detect elephants and other small creatures." -- Product Description for a vibration sensor

Yanroy@usa.com

This topic is closed to new replies.

Advertisement