Hi Torsten, On Jun 12, 2015, at 2:49 PM, "Torsten Bergmann" <astares@gmx.de> wrote:
Hi,
for tracing and logging one could easily write:
foo ... Log enabled ifTrue: [ "do some tracing here" ]. ...
but this always requires some message sends/checks if the debug mode is active. This is OK while debugging/tracing to find errors - but for runtime one whishes to have the best performance without any effect of tracing/debug code.
Smalltalk/MT had a nice optimization feature that allowed to mix in debug code without additional overhead when in non-debug mode. If I remember correctly the basic idea was the following: there is a pool constant _DEBUG_INTERNAL that you compare to another pool constant TRUE (representing the value 1).
So with an expresion like _DEBUG_INTERNAL == TRUE this ends up in 1 == 1 comparision which is always true if the pool constants/values have the same value of 1. A followup message send of #ifTrue: will always be executed - therefore means for the compiler to included the (debug) code:
foo ... _DEBUG_INTERNAL == TRUE ifTrue: [ Processor outputDebugLine: 'Trace something' ]. ...
So in this case (always true) this was optimized by the compiler to
foo ... Processor outputDebugLine: 'Trace something' ...
When _DEBUG_INTERNAL was set to FALSE (represented by value 0 as in C/C++) this ends up in 0 == 1 which is always false and will never be true. So a followup message send of #ifTrue: was optimized (removed as it was dead code and never reached).
foo ... ...
So depending on pool flag _DEBUG_INTERNAL and recompilation of (all) methods one could add debug/trace/logging code without runtime overhead. Yes this is very C language like to have conditional compilation - but very effective in keeping debug/tracing code influence low.
I know we usually have the debugger in front of us - but sometimes a trace or log is required to see where code crashes. Think of a headless situation in a webserver or a small device like the pi where you want to reduce the performance overhead.
This leads to several questions: - Is something like this feasible/already possible in Pharo? - Any pointers on how Opal does optimizations? Do we have similar optimizations (removing code that could not be reached) that could be used. - How do you usually deal with additional tracing code when you do not want to have too much runtime overhead.
One way is to hold the logger in an inst var and have two loggers, one null and one not. Then the overhead in the null case is marshaling arguments and a frameless send. If there are no expensive arguments to Marshall (such as a block or an expression) then I expect thus will be quite cheap. The analogue of this approach that I use in the VM are the many many assertions which compile Tia macro invocation that in production code compiles to null.
Thanks T.