I'm trying to see where my expensive queries are and want to measure if it's the query that's the bottleneck, or something else. And also measure if certain queries are faster than others within our app. I was wondering how I could do this with Instruments. I see that there's a time profiler tool and was wondering if I could use this.
I tried running Time Profiler, clicking on the button that presents my viewController that accesses the database. I don't see my sql call itself and was wondering what the best way to measure the time a method takes from start to finish. Thanks.
Why you don't print in console the time when it starts and when it finish. I do that in many languages like iOS/Java[Android]/PHP. To debug plugins times
I hope it helps
For finding time differences between calls, I usually use a StopWatch class that uses the machine time (at least milliseconds, maybe microseconds accuracy).
This version is designed specifically for autorelease and objective-c. It has a method, stopWithContext:, which will also log a message with the time. This is handy for start/stop measurements in multiple functions. Tailor it as you see fit.
I have a c++ version as well if needed. [You can find the c++ version here][1].
StopWatch.h
#import <Foundation/Foundation.h>
#interface StopWatch : NSObject
{
uint64_t _start;
uint64_t _stop;
uint64_t _elapsed;
}
-(void) Start;
-(void) Stop;
-(void) StopWithContext:(NSString*) context;
-(double) seconds;
-(NSString*) description;
+(StopWatch*) stopWatch;
-(StopWatch*) init;
#end
StopWatch.m
#import "StopWatch.h"
#include <mach/mach_time.h>
#implementation StopWatch
-(void) Start
{
_stop = 0;
_elapsed = 0;
_start = mach_absolute_time();
}
-(void) Stop
{
_stop = mach_absolute_time();
if(_stop > _start)
{
_elapsed = _stop - _start;
}
else
{
_elapsed = 0;
}
_start = mach_absolute_time();
}
-(void) StopWithContext:(NSString*) context
{
_stop = mach_absolute_time();
if(_stop > _start)
{
_elapsed = _stop - _start;
}
else
{
_elapsed = 0;
}
NSLog([NSString stringWithFormat:#"[%#] Stopped at %f",context,[self seconds]]);
_start = mach_absolute_time();
}
-(double) seconds
{
if(_elapsed > 0)
{
uint64_t elapsedTimeNano = 0;
mach_timebase_info_data_t timeBaseInfo;
mach_timebase_info(&timeBaseInfo);
elapsedTimeNano = _elapsed * timeBaseInfo.numer / timeBaseInfo.denom;
double elapsedSeconds = elapsedTimeNano * 1.0E-9;
return elapsedSeconds;
}
return 0.0;
}
-(NSString*) description
{
return [NSString stringWithFormat:#"%f secs.",[self seconds]];
}
+(StopWatch*) stopWatch
{
StopWatch* obj = [[[StopWatch alloc] init] autorelease];
return obj;
}
-(StopWatch*) init
{
[super init];
return self;
}
#end
The class has a static stopWatch method that returns an autoreleased object.
Once you call start, use the seconds method to get the elapsed time. Call start again to restart it. Or stop to stop it. You can still read the time (call seconds) anytime after calling stop.
Example In A Function (Timing call of execution)
-(void)SomeFunc
{
StopWatch* stopWatch = [StopWatch stopWatch];
[stopWatch Start];
... do stuff
[stopWatch StopWithContext:[NSString stringWithFormat:#"Created %d Records",[records count]]];
}
Related
I've been getting FPS lag. I've looked around and people say to use
[self schedule:#selector(gameLoop:) interval: 1/60.0f];
When I use this I get choppy lag. but when I use
[self schedule:#selector(gameLoop:)];
It's a lot smoother. Here is a snippet of my movement code.
- (void)gameLoop :(ccTime)dt
{
[self manageCannon:dt];
[self manageBullets:dt];
[self manageEnemies:dt];
[self manageAllies:dt];
}
- (void) manageEnemies :(ccTime)dt
{
enemyClass *tempEnemy;
for(int i = 0; i < [enemies count]; i++)
{
tempEnemy = [enemyClass new];
tempEnemy = [enemies objectAtIndex:i];
tempEnemy.position = ccp(tempEnemy.position.x-tempEnemy.speed*dt,tempEnemy.position.y);
if((tempEnemy.position.x - tempEnemy.range) < [wall getwally])
{
tempEnemy.speed = 0;
}
if(tempEnemy.health < 1)
{
tempEnemy.alive = false;
}
if(tempEnemy.alive == false)
{
[enemies removeObjectAtIndex:i];
[tempEnemy removeFromParentAndCleanup:true];
}
}
}
I always try to write my own code from scratch, so if you can help me out with other things that i'm doing that is incorrect that would be very helpful towards me.
It's hard to say what is slowing down your app from the information given. As LearnCocos2D suggested, you can use Instruments to figure out where the slow stuff is. Or if you want to get very granular analysis, you can always use the following macros in your code:
#define TIC start = [NSDate date]
#define TOC -[start timeIntervalSinceNow]
#define TOCP NSLog(#"TIME: %f", TOC)
Before using, be sure to declare NSDate *start in scope of use. Then just put a series of TIC/TOC or TIC/TOCP pairs in your code to print out times your code is taking in different places. You can very quickly find the bottlenecks this way.
I have an iOS app with about 50 views. I want to perform some operation after every 5th screen that the user visits. I know I can create a sort of global counter variable and update that on viewDidLoad of each view, and if count is 5, then perform that operation, and reset that counter variable. Is there a better, more efficient way of doing this? Also looking ahead, if I require to alter something, I would rather do it in a single file than all of my views. Would really appreciate some inputs on this.
I would create a singleton class to keep track of your counter logic, create a base class for all of your view controllers and then make your call to the counter singleton in the viewDidLoad of your base class.
I think something like this would work for you:
#interface ViewCountManager()
#property(nonatomic) NSInteger viewCount;
#end
#implementation ViewCountManager
#define kOperateOnCount 5
+(ViewCountManager *)viewCountManager
{
static ViewCountManager *viewCountManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
viewCountManager = [[self alloc] init];
});
return viewCountManager;
}
-(BOOL)shouldPerformOperation
{
BOOL retValue = NO;
if( self.viewCount == kOperateOnCount - 1 )
{
retValue = YES;
self.viewCount = 0;
}
else
{
self.viewCount++;
}
return retValue;
}
#end
#implementation CountedViewController
-(void)viewDidLoad:(BOOL)animated
{
[super viewDidLoad:animated];
BOOL shouldPerform = [[ViewCountManager viewCountManager] shouldPerformOperation];
[self performOperation];
}
#end
Currently I am developing a game which needs a stop watch say 1 minute,when user taps the play button it enters the game screen,I want the to run the stop watch count down of 1 minute 01:00,00:59,00:58 etc. For that reason I searched and found NSTimer would be the ideal choice to implement a stop watch.Hence I took a label,created an instance of NSTimer,assigned time interval and started decrementing the value in timer label,i.e.:
-(void)viewDidAppear:(BOOL)animated
{
self.stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(viewWillAppear:) userInfo:nil repeats:YES];
[super viewDidAppear:YES];
}
-(void)viewWillAppear:(BOOL)animated
{
static int currentTime = 60;
int newTime = currentTime--;
int minutesRemaining = newTime / 60; // integer division, truncates fractional part
int secondsRemaining = newTime % 60; // modulo division
self.timerLabel.text = [NSString stringWithFormat:#"%02d:%02d", minutesRemaining, secondsRemaining];
if ([self.timerLabel.text isEqualToString:#"00:00"])
{
[stopWatchTimer invalidate];
}
[super viewWillAppear:YES];
}
The problem here is the timer starts running 01:00,00:59,00:58 and goes on,say at 53rd second,I navigated to another view and came back,it is running from 00:53,00:52 and so on,but I want it to run from 01:00 and for that I implemented invalidating NSTimer in viewDidDisappear i.e.
-(void)viewDidDisappear:(BOOL)animated
{
if ([stopWatchTimer isValid])
{
[stopWatchTimer invalidate];
self.stopWatchTimer = nil;
}
[super viewDidDisappear:YES];
}
Still the same issue exists!
Done lots of Research on the issue and found no answer useful and working.
Can some one please guide me,any help is appreciated.
Thanks every one in advance :)
You are use the selector viewWillAppear for the timer. viewWillAppear is a method on a viewController that gets called when the view appears on screen, you should not call it yourself. Instead, create your own method that decrements the timer:
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTime:) userInfo:nil repeats:YES];
currentTime = 60; // This could be an instance variable
self.timerLabel.text = #"01:00";
}
-(void)updateTime {
int newTime = currentTime--;
int minutesRemaining = newTime / 60; // integer division, truncates fractional part
int secondsRemaining = newTime % 60; // modulo division
self.timerLabel.text = [NSString stringWithFormat:#"%02d:%02d", minutesRemaining, secondsRemaining];
if ([self.timerLabel.text isEqualToString:#"00:00"])
{
[self.stopWatchTimer invalidate];
}
}
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
if ([self.stopWatchTimer isValid])
{
[self.stopWatchTimer invalidate];
self.stopWatchTimer = nil;
}
}
With this technique the timer is responsible for calling every second, but you will probably have timing issues after some seconds. To have a more accurate timing, you should store the time that you started the countdown and then on every updateTime call, compare the current time with the stored started time.
Add to your interface:
#property (nonatomic) NSTimeInterval startTime;
then in the implementation:
-(void)viewDidAppear:(BOOL)animated
{
self.startTime = [NSDate timeIntervalSinceReferenceDate];
self.duration = 60; // How long the countdown should be
self.stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:#selector(updateTime)
userInfo:nil
repeats:YES];
self.timerLabel.text = #"01:00"; // Make sure this represents the countdown time
}
-(void)updateTime {
int newTime = self.duration - (round([NSDate timeIntervalSinceReferenceDate] - self.startTime));
int minutesRemaining = newTime / 60; // integer division, truncates fractional part
int secondsRemaining = newTime % 60; // modulo division
self.timerLabel.text = [NSString stringWithFormat:#"%02d:%02d", minutesRemaining, secondsRemaining];
if (newTime < 1)
{
[self.stopWatchTimer invalidate];
/* Do more stuff here */
}
}
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
if ([self.stopWatchTimer isValid])
{
[self.stopWatchTimer invalidate];
self.stopWatchTimer = nil;
}
}
Some extra (unrelated) comments on the code:
when implementing viewDidDisappear: pass the animated parameter to the call to super:
[super viewDidDisappear:animated];
when implementing viewDidAppear: pass the animated parameter to the call to super, also, make sure you call super first this in the method, before doing anything else
Is there any way to measure scroll performance in an iPhone app, e.g. updates per second? I'm trying various techniques to improve the scrolling performance but it's sometimes hard to judge if they're actually having an effect.
if you have a scroll delegate, you can implement the method scrollViewDidScroll:. Specifically:
//header:
#interface MyClass : NSObject <UIScrollViewDelegate> {
CFAbsoluteTime last;
int updateCount;
CFTimeInterval timeTotal;
}
#end
//implementation:
#implementation MyClass
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CFAbsoluteTime time = CFAbsoluteTimeGetCurrent();
if (last > 0) {
timeTotal += time - last;
++updateCount;
if (timeTotal > 1) {
NSLog(#"Updates Per Second: %.2f", updateCount / timeTotal);
updateCount = 0;
timeTotal = 0;
}
}
last = time;
}
#end
Something like that. It's untested, so the logging may be incorrect. But to use it, just assign your delegate to the scrollview.delegate property.
I am currently using the cocos2d Director for controlling my animation with the pause, resume, and stopAnimation methods. Is it also possible to use the Director to return the time that the animation has played?
I am currently using this method:
-(void)stopAnimation:(id)sender {
//Timer initialized elsewhere: startTimer = [NSDate timeIntervalSinceReferenceDate];
//Do other method stuff here
[[Director sharedDirector] stopAnimation];
stopTimer = [NSDate timeIntervalSinceReferenceDate];
elapsedTime = (stopTimer - startTimer);
NSLog(#"elapsedTime = %f", elapsedTime);
}
I looked through the Director source and didn't see anything that would help you. I did notice that your code, as written, doesn't take into account the time your animation was paused or when other scenes were playing.
If that is a concern you can keep track of the elapsed time in a tick method that you schedule in your Scene or Layer.
MyLayer.h
#interface MyLayer : Layer {
ccTime totalTime;
}
#property (nonatomic, assign) ccTime totalTime;
MyLayer.m
-(id)init
{
if( (self = [super init]) )
{
[self schedule:#selector(update:)];
}
return self;
}
// deltaTime is the amount of running time that has passed
// since the last time update was called
// Will only be called when the director is not paused
// and when it is part of the active scene
-(void)update:(ccTime)deltaTime
{
totalTime += deltaTime;
}