Do I need to think about how much debug spew I print out?

My game has a ton of print statements that spew out various game states. This helps me debug issues, though I would like to eventually change it from just print statements to putting contents into a log that I can include in my analytics.

My question is: How does Corona handle print statements when running on a device? Obviously it doesn’t get shown anywhere, but if I have copious debug spew, is that going to have performance impact, or are print statements excluded from actual device builds?

Obviously it doesn’t get shown anywhere

Plug your device into a PC/Mac and you’ll see that’s not true. You can see the output of the logs using adb for Android, or Xcode for iOS devices. Really you should be looking at these logs before releasing an app, as you can’t guarantee that everything will work the same on a device as it will in the simulator.

But to answer your question, yes having lots of print statement will slow things down. As a general rule doing anything that uses strings is a fairly expensive process, especially if you have lots of concatenations. A simple way around this is to override the print function in your release build:

if isRelease then print = function() end end

Now it will do nothing when called. Alternatively if you wanted to be a bit more thorough, you could write an ant script which comment out all of the print calls so that they don’t get called in the first place.

My personal approach is this: I keep a “debug” layer on top of my game while developing to keep track of a couple of things - I mean really a visual layer, semi-transparent, that shows me memory use and a couple of other things (nr. of objects and groups on screen etc). The cool things is this allows you to monitor this stuff on device while playing.

Then I use print statements, but only when things do not work as expected - for example to see which code blocks are executed and which aren’t. When things DO work correctly I comment out the print statements.

I use this method as a “clean” method: my final build can’t output any print statements, because as a rule when things work I comment the print statements out. And of course I then disable the “debug” layer in my app as well.

You do need to care, but if you want to turn off the output when you release, add this to the first line of your main.lua file:

print = function() end

You’ll still pay the cost of calling print(), but no output will be produced.

If you have lots of print() statements, this will save you memory and bandwidth (logging), and thus make your game/app perform better than if you left the print() function in.

SAM: If your debug code involves string catenation (mine typically does) there will be a performance penalty even if not displayed. So you should find a way to work around that for production release.

Hi all,

I would like to once again stress that I think the best programming practice is to try to only use print statements when something does not work, using those to understand the bug, fix it and then removing the print statements. At first it’s tricky, but once you start splitting up your code into “logical” modules or code blocks this is the way to go.

Thanks everyone for the detailed information. Perhaps I am overthinking this (in my day job I’m a project manager for a product that manages a log with different levels of detail for different debug levels - but it’s native kernel level events for retail skus so perf impact is negligible).

In Lua is there anything like a precompiler command I might use to let me leave in debug spew for debugging, but omit them from ship builds? I looked through Corona SDK build file documentation and was surprised that there’s nothing like this.

I don’t think Lua has any precompiler commands, certainly I’ve never seen anything about them.  

As I mentioned before, I use an Ant script to comment out all of my print commands, and then reverse that when I go back to debugging (projectDir is the location of your Corona project):

\<!-- COMMENT ALL INSTANCES OF PRINT --\> \<replaceregexp byline="true" match="print\((.\*)" replace="--RELEASEPRNT\(\1"\> \<fileset dir="${projectDir}"\> \<include name="\*.lua"/\> \</fileset\> \</replaceregexp\> \<!-- UNCOMMENT ALL INSTANCES OF PRINT --\> \<replaceregexp byline="true" match="--RELEASEPRNT\((.\*)" replace="print\(\1"\> \<fileset dir="${projectDir}"\> \<include name="\*.lua"/\> \</fileset\> \</replaceregexp\>

One thing to mention is that this will break your code if you have any inline print statements. For example this:

if something then print("something happened") end

would become this:

if something then --RELEASEPRNT("something happened") end

and so the “end” would be commented out and the if statement would be broken.

To fix this just change any inline print calls so they are on multiple lines:

--now this if something then print("something happened") end --becomes this if something then --RELEASEPRNT("something happened") end

@thomas6 - to a certain degree I would agree with you, for instance when you just print things like “aaa”, “bbb” etc to try and find exactly where some code is breaking then yes I would remove those after the problem is fixed.

But for a larger project, having print statements in the project is still useful throughout debugging. It’s very easy to change one part of the project and accidentally have it affect another part, so having a healthy amount of data printing out is extremely useful. I’m not saying that my method is perfect, but it lets me have as much output as I like during debugging, and zero print calls being made on release builds, which seems pretty good to me.

@ Alan: You’re right, that is definitely a very good and practical way of working.

More flavor for the conversation.

Time cost for following:

  • 1 - Empty defunct print x 1,000,000 iterations
  • 2 - Concatenation + math.random() call in defunct print x 1,000,000 iterations
  • 3 - Same as 2 + ‘debug’ shortcut flag  – Flag set to true
  • 4 - Same as 3 – Flag set to false (i.e. don’t do catenation or math.random() call)

Results on my machine:

Test 1 43 ms -- Baseline Test 2 1121 ms -- Expensive, even if defunct. Test 3 1103 ms -- About the same w/ test Test 4 74 ms -- Big savings!

The code:

local getTimer = system.getTimer local \_print = print print = function() end local iterations = 1000000 -- Test 1 local began = getTimer() for i = 1, iterations do print() end local ended = getTimer() \_print("Test 1 " .. ended - began .. " ms") -- Test 2 local began = getTimer() for i = 1, iterations do print( "Corona" .. " is " .. "Cool: " .. tostring(math.random(1, iterations) ) ) end local ended = getTimer() \_print("Test 2 " .. ended - began .. " ms") -- Test 3 - Debug control flag (ON) \_G.myDebugEn = true local began = getTimer() for i = 1, iterations do print( myDebugEn and ("Corona" .. " is " .. "Cool: " .. tostring(math.random(1, iterations) ) or "" ) ) end local ended = getTimer() \_print("Test 3 " .. ended - began .. " ms") -- Test 4 - Debug control flag (OFF) \_G.myDebugEn = false local began = getTimer() for i = 1, iterations do print( myDebugEn and ("Corona" .. " is " .. "Cool: " .. tostring(math.random(1, iterations) ) or "" ) ) end local ended = getTimer() \_print("Test 4 " .. ended - began .. " ms")

You guys are awesome!!

Thank you for the input and the data, this is really powerful. I’m not familiar with Ant scripts, but I understand what you’re doing, this is really smart.

I heard a rumor that a coworker used to be a dev lead at LucasArts and is allegedly is a Lua guru, so surely he’s come across something like this… I’m going to try to chase him down today or tomorrow, I’ll report back as soon as I learn more.

I suspect I’ll take Alan’s approach and use some sort of script to toggle my builds in/out of debug mode.

how the suggested “isRelease” flag could be implemented in a cross-platform manner ?

Well the simplest way would be to add this to the top of your main.lua file:

isRelease = false

and then set it to:

isRelease = true&nbsp;

when building your release mode builds.

I spoke to my coworker (who was a dev lead on several AAA titles that used lua). They solved this problem unfortunately through making changes to the Lua compiler to basically implement precompiler commands of their own. I doubt this is feasible for us in Corona.

His suggestion was to use Alan’s first suggestion where you just override the definition of print().

Well, you could probably do something in Enterprise, but for Pro … probably no so much.

Obviously it doesn’t get shown anywhere

Plug your device into a PC/Mac and you’ll see that’s not true. You can see the output of the logs using adb for Android, or Xcode for iOS devices. Really you should be looking at these logs before releasing an app, as you can’t guarantee that everything will work the same on a device as it will in the simulator.

But to answer your question, yes having lots of print statement will slow things down. As a general rule doing anything that uses strings is a fairly expensive process, especially if you have lots of concatenations. A simple way around this is to override the print function in your release build:

if isRelease then print = function() end end

Now it will do nothing when called. Alternatively if you wanted to be a bit more thorough, you could write an ant script which comment out all of the print calls so that they don’t get called in the first place.

My personal approach is this: I keep a “debug” layer on top of my game while developing to keep track of a couple of things - I mean really a visual layer, semi-transparent, that shows me memory use and a couple of other things (nr. of objects and groups on screen etc). The cool things is this allows you to monitor this stuff on device while playing.

Then I use print statements, but only when things do not work as expected - for example to see which code blocks are executed and which aren’t. When things DO work correctly I comment out the print statements.

I use this method as a “clean” method: my final build can’t output any print statements, because as a rule when things work I comment the print statements out. And of course I then disable the “debug” layer in my app as well.

You do need to care, but if you want to turn off the output when you release, add this to the first line of your main.lua file:

print = function() end

You’ll still pay the cost of calling print(), but no output will be produced.

If you have lots of print() statements, this will save you memory and bandwidth (logging), and thus make your game/app perform better than if you left the print() function in.

SAM: If your debug code involves string catenation (mine typically does) there will be a performance penalty even if not displayed. So you should find a way to work around that for production release.

Hi all,

I would like to once again stress that I think the best programming practice is to try to only use print statements when something does not work, using those to understand the bug, fix it and then removing the print statements. At first it’s tricky, but once you start splitting up your code into “logical” modules or code blocks this is the way to go.