Hi Torsten, Hi Ben, 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?
Ben's reply reminded me of a prototype I did in VW that we never released that could be adapted. I added a ConstantBinding class alongside VariableBinding. The compiler accessed the value of the ConstantBinding directly instead of going through it. But the compiler included the ConstantBinding in the method's literals just as it includes the selectors of optimized messages such as ifTrue:. There was a convention whereby code could be recompiled after the values of ConstantBindings were evaluated during class initialization. It was something like initialize self recompileChangedConstantsAfter: [...] Assigning to a ConstantBinding raised a proceedable exception that was caught by recompileChangedConstantsAfter:, which would allow the assignment to proceed and add the ConstantBinding to a set. After the block had evaluated recompileChangedConstantsAfter: would use the ConstantBindings scopes (they need back pointers to their defining scopes) to find the set of methods that referred to ConstantBindings modified in the block and recompile them. Now if one used this scheme one could also modify the compiler to compile certain idioms specially. For example a ConstantBinding assigned a block, or a ConstantBinding assigned a Boolean flag. The key here is that the ConstantBinding included in the method's literals provides a way to quickly distinguish between a method merely making use of true or false and a method making optimized use of a flag in a ConstantBinding.
- Any pointers on how Opal does optimizations? Do we have similar optimizations (removing code that could not be reached) that could be used.
Remember that Opal, just like most Smalltalk compilers, optimizes ifTrue:, whileTrue:, and: at al. And just like my closure extension to the Squeak compiler Opal optimizes temp vars accessed in blocks but defined in outer scopes into copied variables if possible.
- How do you usually deal with additional tracing code when you do not want to have too much runtime overhead.
Thanks T.