print() using external module with global flag - good performance or should I rethink this?

Hi all! I saw a thread asking about how much debug to spew out and when (link) and since I am using a different method than everything suggested, I wanted to see what you all thought. Would this end up performing well?

What I do is I have a global debug variable. I also have a utilities file/module that I normally use throughout my code. One of the functions in this utilities module is a custom print function…

--Print function - Uses globally defined 'debugOn' boolean -- Parameters -- caller: The object or function that called this print function -- output: The text string to be output to the console -- debugOverwrite: Optional boolean that overwrites the global 'debugOn' function M.print(caller, output, debugOverwrite) if output==nil then return false; end if debugOn or debugOverwrite then local c = caller if c==nil then c=""; end print( c .. ": " .. output ) return true end return false end

I then use that print function throughout my code…

local utils = require("Utils") ... utils.print( \_sceneName, "my debug message" ) -- or if I want a specific print statement even during release... utils.print( \_sceneName, "my debug message", true )

This works fine and is easy for me to manage. I can turn all debug off by switching the global debug to false. My question is mainly performance related. Thanks in advance!

@flowjoe,

Well, you’ve got the right idea, but I think you’re complicating it a bit.  Bear with me.  First let me explain the example I gave from the thread you mentioned:

\_G.dprintEn = true print( dprintEn and ("Corona" .. "Rocks") or "" )

The above print statement is using the equivalent of a ternary operator (you may be familiar with this from C)

In essence, the body of the content passed to the print() function is split like this:

print( A and B or C )
  • A - This is the test
  • B - This is what we want to print when debugging and costs a lot when we do it.
  • C - This is the light-weight substitute for when debugging is off.

The reason this statement speeds up execution when A is false, is because it shortcuts the execution of B and skips to C.  So, B does not execute.

So, what about your example?  Well, you’ve got some similar things going on, but it can be optimized a bit.

function M.print(caller, output, debugOverwrite) if( ( debugOn or debugOverwrite ) and output ) then --print( (caller or "") .. " : " .. output ) -- I like the following better print( caller and (caller .. " : " .. output) or output ) return true end return false end

I’ve done the following:

  • Shortened the code.
  • Got rid of the NOT logic.  Avoid when possible.
  • Ordered abort code by likelihood. We want to exit as early as possible.
  • Gotten rid of unnecessary temporary string creation.

I think, if you test this version you’ll find it a bit faster.  Other than that, good idea and good job.  You’re paying some overhead for the function call, but you’ve modularized the concept which is a nice trade off. 

That was a great explanation! The optmized code looks so tidy and I can understand what was done to it and why.

About your initial explanation (which was a great bonus)…

\_G.dprintEn = true print( dprintEn and ("Corona" .. "Rocks") or "" )

Just to be clear and for my sanity, when you did this, it was only to illustrate the point and measure the overhead of doing string concatenation, correct? I wouldn’t really want to do this as it still prints an empty line, right? 

Your’re welcome and I’m glad it was useful.

Yes, it was purely an example to demonstrate a concept.  Preferably one would produce no (or little) output at all in production code.

Ok great. Well thanks again, this really helped!!!  :slight_smile:

@flowjoe,

Well, you’ve got the right idea, but I think you’re complicating it a bit.  Bear with me.  First let me explain the example I gave from the thread you mentioned:

\_G.dprintEn = true print( dprintEn and ("Corona" .. "Rocks") or "" )

The above print statement is using the equivalent of a ternary operator (you may be familiar with this from C)

In essence, the body of the content passed to the print() function is split like this:

print( A and B or C )
  • A - This is the test
  • B - This is what we want to print when debugging and costs a lot when we do it.
  • C - This is the light-weight substitute for when debugging is off.

The reason this statement speeds up execution when A is false, is because it shortcuts the execution of B and skips to C.  So, B does not execute.

So, what about your example?  Well, you’ve got some similar things going on, but it can be optimized a bit.

function M.print(caller, output, debugOverwrite) if( ( debugOn or debugOverwrite ) and output ) then --print( (caller or "") .. " : " .. output ) -- I like the following better print( caller and (caller .. " : " .. output) or output ) return true end return false end

I’ve done the following:

  • Shortened the code.
  • Got rid of the NOT logic.  Avoid when possible.
  • Ordered abort code by likelihood. We want to exit as early as possible.
  • Gotten rid of unnecessary temporary string creation.

I think, if you test this version you’ll find it a bit faster.  Other than that, good idea and good job.  You’re paying some overhead for the function call, but you’ve modularized the concept which is a nice trade off. 

That was a great explanation! The optmized code looks so tidy and I can understand what was done to it and why.

About your initial explanation (which was a great bonus)…

\_G.dprintEn = true print( dprintEn and ("Corona" .. "Rocks") or "" )

Just to be clear and for my sanity, when you did this, it was only to illustrate the point and measure the overhead of doing string concatenation, correct? I wouldn’t really want to do this as it still prints an empty line, right? 

Your’re welcome and I’m glad it was useful.

Yes, it was purely an example to demonstrate a concept.  Preferably one would produce no (or little) output at all in production code.

Ok great. Well thanks again, this really helped!!!  :slight_smile: