FSP/Memory profiler : SWFProfiler ported for Corona

Hi everyone,

Here’s a profiler I ported from shanem’s AS3 SWFProfiler. It’ll give you a graph of your fps and texture memory usage, current fps, and average fps.

Just require(“gr_profiler”) at the bottom of your main.lua

[code]
– by Don-Duong Quach
– Corona profiler ported from shanem’s AS3 com.flashdynamix.utils.SWFProfiler

– To use just require(“gr_profiler”)

local Profiler = {}

local instance

local minFps = 10000000
local maxFps = 0
local minMem = 10000000
local maxMem = 0

local itvTime
local initTime
local currentTime
local frameCount
local totalCount

local history = 60
local fpsList = {}
local memList = {}
function Profiler:initialize()

self.container = display.newGroup()
self.foreground = display.newGroup(self.container)
self.infoTxt = display.newText(self.foreground, “Fps”, 0, 98, native.systemFont, 11)
self.infoTxt:setTextColor(0xcc, 0xcc, 0xcc)

self.minFpsTxt = display.newText(self.foreground, “0”, 17, 37, native.systemFont, 9)
self.minFpsTxt:setTextColor(0xcc, 0xcc, 0xcc)
self.maxFpsTxt = display.newText(self.foreground, “0”, 17, 5, native.systemFont, 9)
self.maxFpsTxt:setTextColor(0xcc, 0xcc, 0xcc)
self.minMemTxt = display.newText(self.foreground, “0”, 17, 83, native.systemFont, 9)
self.minMemTxt:setTextColor(0xcc, 0xcc, 0xcc)
self.maxMemTxt = display.newText(self.foreground, “0”, 17, 50, native.systemFont, 9)
self.maxMemTxt:setTextColor(0xcc, 0xcc, 0xcc)

self:resize()

self.fpsGroup = display.newGroup()
self.memGroup = display.newGroup()

self.fpsGroup.x = 65
self.fpsGroup.y = 45

self.container:insert(self.fpsGroup)

self.memGroup.x = 65
self.memGroup.y = 90

self.container:insert(self.memGroup)

initTime = system.getTimer()
itvTime = initTime
totalCount, frameCount = 0, 0

Runtime:addEventListener(“enterFrame”, self)

return self
end

function Profiler:currentFps()
return frameCount / self:intervalTime()
end

function Profiler:currentMem()
return system.getInfo(“textureMemoryUsed”) / 1024
end

function Profiler:averageFps()
return totalCount / self:runningTime()
end

function Profiler:runningTime()
return (currentTime - initTime) / 1000
end

function Profiler:intervalTime()
return (currentTime - itvTime) / 1000
end

function Profiler:backline(_x1, _y1, _x2, _y2)
local line = display.newLine(self.container, _x1, _y1, _x2, _y2)
line:setColor(255, 255, 255, 50)
line.width = 1
return line
end

function Profiler:resize()
local back = display.newRect(self.container, 0, 0, display.contentWidth, 120)
back:setFillColor(0, 0, 0, 128)
self:backline(65, 45, 65, 10)
self:backline(65, 45, display.contentWidth -15, 45)
self:backline(65, 90, 65, 55)
self:backline(65, 90, display.contentWidth -15, 90)

self.infoTxt.x = self.infoTxt.contentWidth / 2 + 10
end

function Profiler:enterFrame(event)
currentTime = system.getTimer()
frameCount = frameCount + 1
totalCount = totalCount + 1

if self:intervalTime() >= 1 then
table.insert(fpsList, 1, self:currentFps())
table.insert(memList, 1, self:currentMem())

if #fpsList > history then
table.remove(fpsList, #fpsList)
local min = 1000000
local max = 0
for i = 1, #fpsList do
if fpsList[i] > max then
max = fpsList[i]
end

if fpsList[i] < min then
min = fpsList[i]
end
end

minFps = min
maxFps = max
end

if #memList > history then
table.remove(memList, #memList)
local min = 1000000
local max = 0
for i = 1, #memList do
if memList[i] > max then
max = memList[i]
end

if memList[i] < min then
min = memList[i]
end
end

minMem = min
maxMem = max
end

minFps = self:currentFps() < minFps and self:currentFps() or minFps
self.minFpsTxt.text = string.format("%d Fps", minFps)
maxFps = self:currentFps() > maxFps and self:currentFps() or maxFps
self.maxFpsTxt.text = string.format("%d Fps", maxFps)
minMem = self:currentMem() < minMem and self:currentMem() or minMem
self.minMemTxt.text = string.format("%d Kb", minMem)
maxMem = self:currentMem() > maxMem and self:currentMem() or maxMem
self.maxMemTxt.text = string.format("%d Kb", maxMem)

itvTime = currentTime
frameCount = 0

– fps
for i = self.fpsGroup.numChildren, 1, -1 do
self.fpsGroup:remove(i)
end

local height = 35
local width = display.contentWidth - 80
local inc = width / (history -1)
local rateRange = maxFps - minFps
rateRange = rateRange > 0 and rateRange or 1
local value
local fpsline

if #fpsList > 1 then
local val1 = (fpsList[1] - minFps) / rateRange
local val2 = (fpsList[2] - minFps) / rateRange
fpsline = display.newLine(self.fpsGroup, 0, -val1 * height, inc, -val2 * height)
fpsline:setColor(0x33, 0xcc, 0, 255)
end

if #fpsList > 2 then
for i = 3, #fpsList do
value = (fpsList[i] - minFps) / rateRange
fpsline:append((i-1)*inc, -value * height)
end
end

– mem
for i = self.memGroup.numChildren, 1, -1 do
self.memGroup:remove(i)
end

rateRange = maxMem - minMem
rateRange = rateRange > 0 and rateRange or 1

local memline
if #memList > 1 then
local val1 = (memList[1] - minMem) / rateRange
local val2 = (memList[2] - minMem) / rateRange
memline = display.newLine(self.memGroup, 0, -val1 * height, inc, -val2 * height)
memline:setColor(0xdd, 0x66, 0x00, 255)
end

if #memList > 2 then
for i = 3, #memList do
value = (memList[i] - minMem) / rateRange
memline:append((i-1)*inc, -value * height)
end
end
end

self.infoTxt.text = “Avg Fps " … math.floor(self:averageFps()) … " | Mem " … math.floor(self:currentMem()) … " Kb” … " | Fps " … math.floor(self:currentFps())
self.infoTxt.x = self.infoTxt.contentWidth / 2 + 10
end

Profiler:initialize()

[/code] [import]uid: 27183 topic_id: 7243 reply_id: 307243[/import]

Looks useful. How about putting it in the Code Exchange? [import]uid: 3953 topic_id: 7243 reply_id: 26078[/import]

I’d like to, but I’ve looked up and down the Code Exchange pages, and I didn’t see a way to submit the code. Do I have to be a subscriber? [import]uid: 27183 topic_id: 7243 reply_id: 26115[/import]

Thanks!! [import]uid: 42670 topic_id: 7243 reply_id: 26492[/import]

Can I use this with director class? I cant make it work.
[import]uid: 12455 topic_id: 7243 reply_id: 30574[/import]

I haven’t used Director, but you can remove the last line that does the initialize, and replace it with “return Profiler”. Then you can get a reference to the profiler to initialize it wherever you want.
[import]uid: 27183 topic_id: 7243 reply_id: 30624[/import]

Thanks Don, this is Just what I was looking for.
[import]uid: 26397 topic_id: 7243 reply_id: 43623[/import]

Hi jonlaidler,

You should replace lines 167-169 with this snippet:

for i = self.fpsGroup.numChildren, 1, -1 do  
 self.fpsGroup:remove(i)  
end  

That should fix a tiny memory leak in the profiler. [import]uid: 27183 topic_id: 7243 reply_id: 43625[/import]

Hi Don,

That was a fast response :). I have applied the memory leak fix.

Thanks

Jon [import]uid: 26397 topic_id: 7243 reply_id: 43629[/import]

Can there be performance differences between the simulator and a actual device (I’m developing for the iPad) ? [import]uid: 24111 topic_id: 7243 reply_id: 50508[/import]

Hey don, this is awesome! Thank you for contributing, I just put it into the app I’m developing and it works great. [import]uid: 8692 topic_id: 7243 reply_id: 50541[/import]

oskwish, there are most certainly performance differences between the two. I’m also developing for the iPad and get about 30fps (still need to optimize code) but the Corona simulator is pegged at 60. I don’t think it tries to simulate the performance of the device. [import]uid: 8692 topic_id: 7243 reply_id: 50543[/import]

@okwish I’m assuming you ran it on the simulator and on the device. There are most certainly differences. That’s why it’s called a Corona Simulator not an “emulator”. :slight_smile: Even emulators can be slower than the emulated device though.

@afonseca I’ve improved the profiler to display the application time, have the option to stay on top always, and collect each frame to give a better report for application memory. It’s a part of the Spriteloq API Library now. You can find it here: http://www.loqheart.com/spriteloq/download.html

You can see the docs for it here: http://www.loqheart.com/spriteloq/apidocs/files/loq_profiler-lua.html

You also might want to check out loq_util. I’m updating it to include an unrequire function to release a required module’s application memory after you’re done with it. [import]uid: 27183 topic_id: 7243 reply_id: 50598[/import]

If you are getting low FPS and you want to see the EXACT lines of code and functions causing your program to slow down, please check out Corona® Profiler (https://developer.anscamobile.com/forum/2011/11/19/corona®-profiler-line-line-analysis-your-code-promo-codes-included-0)
This will save you the hassle of hunting and pecking at what lines are slowing your code.
-Thank You,
M.Y. Developers [import]uid: 55057 topic_id: 7243 reply_id: 68637[/import]

Does anyone have this working with Director 1.4? [import]uid: 16734 topic_id: 7243 reply_id: 75410[/import]