Skip to main content
gamedev.net
🔒 Locked

"Debug Mode" speed optimizations

Started by karwosts 7 replies 2.5k views
Original Post
karwosts
karwosts
Hi all. I'm working on a game, and in my game I have written a custom GLSL preprocessor to add some new features not supported by barebones GLSL (input/output semantics kind of stuff). To correctly implement this I need the ability to interpret #define/#ifdef/#if on the C++ side of my program and not rely on my OpenGL driver's preprocessor, so I've written a basic preprocessor myself to run against the GLSL source code before uploading it.

My complaint right now is that it's really painfully slow, even for something that only needs to run occasionally. I've profiled the issue down to the tokenizer, I'm using std::tr1::regex to tokenize the source code, and its often taking something like 100+ ms to tokenize a 30-50 line shader, which seems pretty extreme.

My caveat is that I'm running with debug optimizations on, but seeing as how I'm still in development I kind of need that. I'm sure that the regex performance would be hugely better in release mode, but right now it's just annoying me when my program locks up for 500ms every time I need to compile a few new shaders with some different defines set.

I'm trying to come up with some ways to make this less painful, I'm thinking something along the lines of:

1) Rewrite the code to not use regex. This would probably be a lot faster as I'm guessing tr1::regex is some super-templated/iterator'd mess that makes things slow when it has to run with debug information. I'd be kind of disappointed to do this as it seems a much less elegant solution.

2) Some visual studio option to compile the regex to run with speed optimization, while letting the rest of the program run in debug mode? I'm not really aware of what options are available here, maybe someone could explain if there's any way to do something like this. I tried enabling /O2 (optimize for speed) by right clicking on the .cpp file that contained all of the regex searches, but it didn't make a difference in the regex speed, so I guess that didn't do much.

This is the code I used to tokenize the file, I think it is not too complex

static const std::tr1::regex tokenRegexFull("([+\\-=*/<>^%!&|]+|[()]|[#\\w_]+|\\s+)");
static const std::tr1::regex tokenRegexSimple("([\\w]+)");

void Tokenizer::TokenizeString(std::string string, std::vector<Token>& tokens){
std::match_results<std::string::const_iterator> result;
bool simple = string.find("#") == std::string::npos; //if no preprocessor directives, use the simple regex to look for words only
while(string.length() != 0){
Token token;
if(std::tr1::regex_search(string,result,simple ? tokenRegexSimple : tokenRegexFull)){
token.text = result.prefix();
if(token.text.length() > 0){
tokens.push_back(token);
}
token.text = result[1].str();
tokens.push_back(token);
string = result.suffix();
} else {
token.text = string;
tokens.push_back(token);
break;
}
}
tokens.push_back(newlineToken);
}
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game
Antheus
Antheus
Disable iterator debugging.

Then, in release build configuration, turn on debug information. Maybe /Zx, I don't recall off-hand which combination of settings works.

It will not be accurate, any inlined functions will cause a mess, but it's enough for basic stepping through the code.


I'm sure that the regex performance would be hugely better in release mode[/quote]So, you made a release build and profiled it to determine regex is no longer a bottleneck?

For many projects, preprocessing is a bottleneck even in regular C++ compilers, so ccache is sometimes used.
kdmiller3
kdmiller3
Setting Debug Information Format to Program Database (/Zi) should work fine in a Release build, and keeps all the debug symbols in a separate .pdb file from your executable.

What we use at work is a custom Internal or Develop configuration based on Debug that enables optimizations in the game engine and its support libraries. It's otherwise configured as a debug build, though, with assert statements and trace output fully functional like an ordinary Debug build. In addition, game logic still has optimizations disabled so it's easy to step through and see what's going on.

...

Getting to the heart of the problem, you may be forcing the regexp to do more work than you might think since you seem to be passing the entire file to it all at once. The C/C++ (and presumably GLSL) preprocessor does its work a line at a time, so you may be able to leverage that knowledge to improve its performance even in debug.

(You may also be better off doing the text processing yourself instead of using the full power of regexp.)
karwosts
karwosts

So, you made a release build and profiled it to determine regex is no longer a bottleneck?
[/quote]

I didn't until just now, but on running in release mode the tokenizing time is at least an order of magnitude faster. I don't have exact numbers (my timers are optimized out in release), but the delay is barely perceptible in comparison to the jarring halt of debug mode.

I tried using "#define _HAS_ITERATOR_DEBUGGING 0" at the top of my .cpp file that contains the regex searches, but it made no difference at all in the debug mode delay. Do I have to disable it for the whole program by inserting it before main(), or can I disable it on a file-by-file basis?



Getting to the heart of the problem, you may be forcing the regexp to do more work than you might think since you seem to be passing the entire file to it all at once.
[/quote]
I'm sorry if I gave that impression, but I am doing this on a line by line basis which I forgot to show. I call the method I posted above once for each line of the shader, so it only searches one line at a time.
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game
Antheus
Antheus
I don't have exact numbers (my timers are optimized out in release), but the delay is barely perceptible in comparison to the jarring halt of debug mode. [/quote]So you don't know. How about running AMD CodeAnalyst (free, works on Intel), integrates with VS.

I tried using "#define _HAS_ITERATOR_DEBUGGING 0" at the top of my .cpp file that contains the regex searches, but it made no difference at all in the debug mode delay. [/quote]Profiling in Debug mode makes no sense. Whatever the numbers reported are irrelevant. Debug mode includes a huge amount of checks and is intended to be run under debugger.

Do I have to disable it for the whole program by inserting it before main(), or can I disable it on a file-by-file basis?[/quote]
It's best to make a compiler directive. Mixing containers with iterators inconsistently enabled will likely lead to obscure crashes.

Especially for templated code which may get instantiated differently from declaration.

Regexes are still likely to be quite slow, compared to typical parsers found in other implementations.
karwosts
karwosts

So you don't know.
[/quote]

I don't know why you claim this, I don't need a stopwatch to notice the difference between 1 second and 5 milliseconds. In my program I activate a switch to recompile the shaders during runtime. In debug mode this takes very long, and the delay (which I have measured), comes from the tokenizing of the shaders. In release mode there is barely any noticeable delay when I recompile the shaders. Therefore I claim that my bottleneck (tokenizing), is not a bottleneck in release mode. If you think this logic is faulty I'd like to hear why.


Profiling in Debug mode makes no sense. Whatever the numbers reported are irrelevant.
[/quote]
I'm not trying to 'profile' my program for release, I'm trying to make it run faster when it is in debug mode, because I need debugging enabled for most of my program when I am doing development. I just have this one section of code (tokenizing) which I don't need to debug, so I was curious if there was a way to compile that one small part of my program for speed, and let the rest of the program still have full featured debugging.


From what you're saying, I gather that it is not possible to have different optimization for different parts of the code, so I will try to find some other way to deal with this.
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game
kdmiller3
kdmiller3
You can have different optimization for different parts of code, either by moving the low-level engine bits to another project with optimizations enabled, overriding the project settings for a specific file, or wrapping the function with an appropriate #pragma optimize.
Vectorian
Vectorian
Most likely the time is spent inside regex_search, which is probably part of the compiler's runtime library and statically linked and as such not affected by your optimization switches. I don't think it's possibly to like both the debug and release version of the runtime library at the same time, so you're out of luck.
karwosts
karwosts

Most likely the time is spent inside regex_search, which is probably part of the compiler's runtime library and statically linked and as such not affected by your optimization switches.
[/quote]

Yeah, I kind of noticed that the switches that I was trying to toggle weren't really doing anything for the overall performance. I went ahead and replaced regex_search with my own simple char-by-char algorithm, and with some other simplifications, I was able to reduce the time spent by 80%, so I'm reasonably satisfied with it now.
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.