Share Your Code

Output FPS and texture memory usage in your app

Posted by Wizem, Posted on October 21, 2010, Last updated October 22, 2010

A small widget that outputs the current fps, the minimum fps during the last 30 frames and the current texture memory usage.

Change the value of maxSavedFps to some other value to get the minimum FPS during a different amount of frames.

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
module(..., package.seeall)
PerformanceOutput = {};
PerformanceOutput.mt = {};
PerformanceOutput.mt.__index = PerformanceOutput;
 
 
local prevTime = 0;
local maxSavedFps = 30;
 
local function createLayout(self)
        local group = display.newGroup();
 
        self.memory = display.newText("0/10",20,0, Helvetica, 15);
        self.framerate = display.newText("0", 30, self.memory.height, "Helvetica", 20);
        local background = display.newRect(-50,0, 175, 50);
        
        self.memory:setTextColor(255,255,255);
        self.framerate:setTextColor(255,255,255);
        background:setFillColor(0,0,0);
        
        group:insert(background);
        group:insert(self.memory);
        group:insert(self.framerate);
        
 
        return group;
end
 
local function minElement(table)
        local min = 10000;
        for i = 1, #table do
                if(table[i] < min) then min = table[i]; end
        end
        return min;
end
 
 
local function getLabelUpdater(self)
        local lastFps = {};
        local lastFpsCounter = 1;
        return function(event)
                local curTime = system.getTimer();
                local dt = curTime - prevTime;
                prevTime = curTime;
        
                local fps = math.floor(1000/dt);
                
                lastFps[lastFpsCounter] = fps;
                lastFpsCounter = lastFpsCounter + 1;
                if(lastFpsCounter > maxSavedFps) then lastFpsCounter = 1; end
                local minLastFps = minElement(lastFps); 
                
                self.framerate.text = "FPS: "..fps.."(min: "..minLastFps..")";
                
                self.memory.text = "Mem: "..(system.getInfo("textureMemoryUsed")/1000000).." mb";
        end
end
 
 
local instance = nil;
-- Singleton
function PerformanceOutput.new()
        if(instance ~= nil) then return instance; end
        local self = {};
        setmetatable(self, PerformanceOutput.mt);
        
        self.group = createLayout(self);
        
        Runtime:addEventListener("enterFrame", getLabelUpdater(self));
 
        instance = self;
        return self;
end

Usage: save as fps.lua (or any other filename, obviously, but modify the first line in the code snippet below then), then

1
2
3
4
local fps = require("fps")
local performance = fps.PerformanceOutput.new();
performance.group.x, performance.group.y = display.contentWidth/2,  0;
performance.alpha = 0.6; -- So it doesn't get in the way of the rest of the scene

Also note that this class is coded as a singleton, so you won't be able to create more than one instance.

Compatibility: 
Corona 2.0

Replies

Magenda
User offline. Last seen 10 weeks 6 days ago. Offline
Joined: 2 Jul 2010

Thanks for sharing!

posburn
User offline. Last seen 10 weeks 3 days ago. Offline
Joined: 17 Jun 2010

This is great ... thanks!

Wizem
User offline. Last seen 1 year 25 weeks ago. Offline
Joined: 10 Aug 2010

:) glad it's useful

Stephen Lewis
User offline. Last seen 9 hours 40 min ago. Offline
Joined: 24 Sep 2010

Thanks for sharing, this is very useful.

Has anyone else noticed a huge difference in texture memory reported on the Corona Sim vs. on the actual device?

My test app reports 5.074 mb when running on the Corona Sim, but only 0.003 mb on my iPhone 3gs. The corona sim version seems to be the more realistic number, but that means system.getInfo("textureMemoryUsed") is not accurate for the device. Running the same app on the Xcode Simulator shows 0.006 mb used.

dweezil
User offline. Last seen 18 weeks 3 days ago. Offline
Joined: 23 Sep 2010

This is great but how do you unload / free the object from memory

Wizem
User offline. Last seen 1 year 25 weeks ago. Offline
Joined: 10 Aug 2010

Objects that aren't in use and don't have any references to them will automatically be gc'ed after a time.

If you want to explicitly call the garbage collector, the command is collectgarbage("collect");

eg

1
2
local image = display.newImage("SomethingThatTakesUpALotOfMemory.png");
timer.performWithDelay(3000, function() image:removeSelf(); collectgarbage("collect"); end );

If you want to see how objects are removed from memory, try replacing the image with a group of several objects, add some buttons to remove things from the scene with explicit garbage collection and without. In the latter case, it's worth trying to load some new objects into the scene after removing the old ones, because automatic garbage collection can be lazy, but that doesn't mean you always want to collect garbage explicitly. (and use the memory output widget to watch what happens to the memory)

dweezil
User offline. Last seen 18 weeks 3 days ago. Offline
Joined: 23 Sep 2010

Thanks but what I meant was in your code you are doing:

display.newText

but the object that's created is never removed

Wizem
User offline. Last seen 1 year 25 weeks ago. Offline
Joined: 10 Aug 2010

I'm assuming that this widget is either used for the lifespan of the application, or not at all - i.e. it will only be in the game at a debug stage. If you want to remove it from the scene at runtime, you'll need to modify the code slightly.

dweezil
User offline. Last seen 18 weeks 3 days ago. Offline
Joined: 23 Sep 2010

I'm after a light weight version. I trust stripping it down to just the following is still correct?

curTime = system.getTimer()
dt = curTime - prevTime
prevTime = curTime

fps = math.floor(1000/dt)

return fps

Wizem
User offline. Last seen 1 year 25 weeks ago. Offline
Joined: 10 Aug 2010

Depends on what you mean by "return" (i.e. I set the output for the text, and I don't calculate the fps in a function, so I'm assuming you mean some code rearranging). And of course it's correct if it suits your needs :) - personally I had trouble focusing on a fps value that jumped around every frame, which was why I put in the min-fps counter.

dweezil
User offline. Last seen 18 weeks 3 days ago. Offline
Joined: 23 Sep 2010

I know what you mean about the jumping value so did this

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
module(..., package.seeall)
 
local curTime=0
local prevTime=0
local dt=0
local fps=0
local delay=0
local delay_time = 10
 
function get_fps()
        
   delay = delay + 1
   curTime = system.getTimer()
   dt = curTime - prevTime
   prevTime = curTime
        
   fps = math.floor(1000/dt)
        
   if(delay > delay_time) then
     delay = 0
     return fps
   else
     return 0
   end
        
end

Then call fps() and only display it when it's not 0. It gives me a rough idea of what the FPS is. Though in the simulator it's 62 when it should be 60!

dweezil
User offline. Last seen 18 weeks 3 days ago. Offline
Joined: 23 Sep 2010

Do you mind if I post this light weight version to the community

Wizem
User offline. Last seen 1 year 25 weeks ago. Offline
Joined: 10 Aug 2010

Actually, your code is not noticeably more efficient (for an application that needs optimization, this would not make any difference at all), and gives less information; I'd recommend using my version. The min fps gives the least fps among the last frames, instead of a random fps, which is more significant in terms of optimizing

dweezil
User offline. Last seen 18 weeks 3 days ago. Offline
Joined: 23 Sep 2010

The trouble with your version is (whilst it is great!) its just that I'm not clear on how to 'unload' it in the director class that i'm using!

Buyt as you say perhaps I should just load it at the top...

iphone_2010
User offline. Last seen 3 years 23 weeks ago. Offline
Joined: 5 Nov 2010

Guys I'm lost here! I'm new to Corona!
What is this FPS? and what is used for? What benefits I can get from this code above?

Thanks

dweezil
User offline. Last seen 18 weeks 3 days ago. Offline
Joined: 23 Sep 2010

FPS == Frames Per Second

This routine provides a sanity check. Shows you how many FPS your app is running at plus the slowest FPS in the last few frames.

drnelson
User offline. Last seen 48 weeks 1 day ago. Offline
Joined: 25 Jan 2011

Thanks for posting this. It's amazing how much has been posted here.

When using this I noticed it's a singleton. I am using it in my menu, I load a new file (using director) and if I come back I notice I get an insert error.

When return to the main menu it's trying to call a new instance but that instance has been dealloc'ed already? Should I be declaring this globally and if so how do I do this? I'm assuming it's losing it's memory once the group is unloaded but since it's a singleton that's not actually fully dealloc'ed. Anyone else have this problem?

thanks!

craig.stowers
User offline. Last seen 1 year 51 weeks ago. Offline
Joined: 21 Feb 2011

Thanks for this class file. Getting a lot of good use out of it. Top idea with the running minimum.

nicholasclayg
User offline. Last seen 5 days 15 hours ago. Offline
Joined: 16 May 2011

I like this utility.

I like that I can put it at the top of my main.lua file and comment out when I don't need it anymore.

good stuff.
ng

roottony
User offline. Last seen 40 weeks 1 day ago. Offline
Joined: 27 Jun 2011

1
2
3
self.framerate.text = "FPS: "..fps.."(min: "..minLastFps..")";
                
self.memory.text = "Mem: "..(system.getInfo("textureMemoryUsed")/1000000).." mb";

You create new text every frame in these lines. That is VERY expensive operation. It decreases FPS on real devices (Nexus One) a lot.
So, the FPS it shows on real devices is much lower than it would be without this FPS output.

Wizem
User offline. Last seen 1 year 25 weeks ago. Offline
Joined: 10 Aug 2010

Is there a way to make it faster? The FPS jumps every frame; I don't know of a way to change the value of a string in Lua/Corona, I believe they are immutable. I don't think creating strings is THAT expensive ;-).

dj1
User offline. Last seen 2 years 27 weeks ago. Offline
Joined: 7 Aug 2011

performance.alpha = 0.6;
shouldn't this be
performance.group.alpha = 0.6;

Thanks for the widget. Really helps :)

roottony
User offline. Last seen 40 weeks 1 day ago. Offline
Joined: 27 Jun 2011

Wizem,
yes, strings are immutable. And I dont know a way to make it faster too.
Creating new string every frame is realy not so expensive, but creating a OpenGL object, that represents that string IS VERY expensive.
To me it took about 70% of draw fucntion execution time.

necrozyablo
User offline. Last seen 2 years 23 weeks ago. Offline
Joined: 16 Nov 2011

Great work!

Is it possible to use "director" to do "fps layer" was available in all scenes?

mkelly
User offline. Last seen 16 hours 45 min ago. Offline
Joined: 4 Feb 2012

when I switch scenes, bodies reappear that I have removed before leaving the previous scene. any idea why? they are clearly destroyed in hybrid view. but when the new scene starts up, they reappear in the same spot they were in and still have their physical properties.

if I add removeSelf() and nil them, the next scene hangs. any advice would be appreciated. I'm using director 1.3 to jump scenes.

thanks!

jocf
User offline. Last seen 31 weeks 5 days ago. Offline
Joined: 21 Jun 2011

Very good (widget)tool!!!

Thanks

ovidiu
User offline. Last seen 1 year 24 weeks ago. Offline
Joined: 9 Feb 2012

Awesome widget! Thank you very much!

emanouel
User offline. Last seen 8 weeks 4 days ago. Offline
Joined: 17 Jan 2011

thanks for a good monitor tool. really works and easy to impolite

Pixin
User offline. Last seen 1 week 18 hours ago. Offline
Joined: 21 Feb 2011

HAS ANYONE HAD THIS PROBLEM?

My apps with physics are *drastically* different (lower) on the device AND in the xCode Simulator vs the Corona Simulator. For example I tested my own app that's running between 30-60 fps in the Corona Simulator but in the xCode Simulator and device it runs about 7 fps.

CHAINS TEST
I tested a simple physics app: the "Chains" sample that comes with Corona SDK. That sets the fps to 60 in the main.lua.

CHAINS RESULTS
Corona Simuator - FPS ran about 30
xCode Simulator - FPS ran about 1/2 of what the Corona Simulator result
iPhone4 Device - FPS ran close to 30* But in my apps (that are more complex), the FPS is always drastically lower.

nicholasclayg
User offline. Last seen 5 days 15 hours ago. Offline
Joined: 16 May 2011

@pixin

I've noticed that since, well forever. In my game I use anywhere from 500 to 2000 vertices on a single screen (1 level). Simulator, I will tell you lies - it doesn't throttle to match an iphone vs an iphone 4s, or ipad2 vs ipad3, etc. What I mean by that is, an iphone runs at say 500mhz (just making that up) and your PC/Mac runs at 2ghz, I don't know what corona does if it sandboxes a virtual pool off resources or something but it's never accurate.

What am I saying here?

Don't trust anything but the device - ever. It doesn't lie to you, Xcode acts goofy, simulator while great for quick testing the TRUE test comes from device testing.

So yes, I know what you are saying and I have experienced it and well, it's a kind of "Deal with it" scenario. I'm a "test driver" right now, but that's only due to i'm not close to release. I did have an iOS subscription for a year, but not renewing it until I'm good and ready to release.

I also noticed, you are running an iphone4 (didn't say S so I don't know) well, I can tell you this. My app with 275 vertices gets 55 to 60 on ipad2 and iphone4s on ipod4g and iphone4 (pretty much the same I think) I get mid 30's to lower 40's

Anything 4s and up seems to run like butter.

That probably didn't help, but maybe you will regain some sanity. :)

-ng

Pixin
User offline. Last seen 1 week 18 hours ago. Offline
Joined: 21 Feb 2011

Thanks Nicholas, that does help a lot, even if simply to make me feel like I'm in good company. I was hoping for a magic code snippet to add to the fps code that would tell it to be more realistic so I wouldn't have to build a million times to test. Well, I'll just deal with it! ;) Thanks again for your help and quick reply.