FSP/Memory profiler : SWFProfiler ported for Corona

14 replies [Last post]
don
User offline. Last seen 6 years 29 weeks ago. Offline
Joined: 24 Jan 2011

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
-- 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()

Replies

MarkHenryC
User offline. Last seen 6 weeks 5 days ago. Offline
Joined: 11 Nov 2009

Looks useful. How about putting it in the Code Exchange?

don
User offline. Last seen 6 years 29 weeks ago. Offline
Joined: 24 Jan 2011

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?

m.dev
User offline. Last seen 9 years 4 weeks ago. Offline
Joined: 3 Mar 2011

Thanks!!

teex84
User offline. Last seen 9 years 7 weeks ago. Offline
Joined: 12 Dec 2010

Can I use this with director class? I cant make it work.

don
User offline. Last seen 6 years 29 weeks ago. Offline
Joined: 24 Jan 2011

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.

jonlaidler
User offline. Last seen 5 years 29 weeks ago. Offline
Joined: 23 Jan 2011

Thanks Don, this is Just what I was looking for.

don
User offline. Last seen 6 years 29 weeks ago. Offline
Joined: 24 Jan 2011

Hi jonlaidler,

You should replace lines 167-169 with this snippet:

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

That should fix a tiny memory leak in the profiler.

jonlaidler
User offline. Last seen 5 years 29 weeks ago. Offline
Joined: 23 Jan 2011

Hi Don,

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

Thanks

Jon

oskwish
User offline. Last seen 29 weeks 6 days ago. Offline
Joined: 21 Jan 2011

Can there be performance differences between the simulator and a actual device (I'm developing for the iPad) ?

afonseca
User offline. Last seen 8 years 16 weeks ago. Offline
Joined: 4 Sep 2010

Hey don, this is awesome! Thank you for contributing, I just put it into the app I'm developing and it works great.

afonseca
User offline. Last seen 8 years 16 weeks ago. Offline
Joined: 4 Sep 2010

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.

don
User offline. Last seen 6 years 29 weeks ago. Offline
Joined: 24 Jan 2011

@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". :) 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.

M.Y.developers
User offline. Last seen 4 years 15 weeks ago. Offline
Joined: 24 Apr 2011

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%C2%AE-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

KenRogoway
User offline. Last seen 4 years 4 weeks ago. Offline
Joined: 17 Jan 2011

Does anyone have this working with Director 1.4?

Viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.