Pauses/computation between function execution? - objective-c

I'm working on a game and the speed of the game is 60fps, giving me about 16ms to execute what I need to execute. What I'm finding tho is that certain code paths are taking a while to execute. At first I thought this must be an issue with memory allocation/deallocation. It could possibly be, but I have implemented object pooling for the more heavyweight objects, and this seems to have had little effect.
I have stripped out the offendingly large objects, and replaced them with a much simpler object, yet it still takes about 3ms to make this object. The simple object consists of two custom objects, 2 arrays, and 2 dictionaries. The large object is of an arbitrary complexity. Making the more complex larger objects seem to take linearly more time, taking up to 20-30ms. In many instances in my game I can make a much more complicated object in a fraction of the time. But somehow these specific locations in code cause a serious slowdown.
I am using the following code to profile my functions (from SO originally):
NSDate* methodStart = [NSDate date];
// My code here.
NSDate *methodFinish = [NSDate date];
NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart];
NSLog(#"[CH] executionTime to create %# = %f", myObject , executionTime );
As best as I can confirm if I do something like the above in an inner and outer function, it looks like there can be a serious slowdown:
Inner function call completed: 4ms
...no code between inner and outer code except timer...
Outer function call completed: 8ms
My current theory is there is 'in-between' computation that occurs between the functions that is causing the serious slowdowns. As I'm new to Obj-C/C I'm not entirely sure what this slowdown could be. It could be threading, it could be because of memory alloc/autorelease/dealloc, or some other kind of unrelated issue. I have attempted to get more info from Instruments with little benefit.
So my question is: Does this sound logical? Is it possible that some kind of computation could be happening between my functions that would take up 2-4ms of cpu on an ipad2? And if my theory isn't possible, any ideas what it could be?

The best way to track down this type of problem is to use Instruments to profile the execution of the code. Often, you can run this against the code on the Mac under the simulator to see where the time is going, however, in this case you may need to profile it on your iPad to be certain.
Remove your NSDate-based profiling code, as NSDate can be a pretty heavy-weight object, especially when you put the results into the autorelease pool, which you are doing here.
If you feel you must do NSDate-based profiling, you should only need to create a single NSDate object and the use:
[methodStart timeIntervalSinceNow]
to calculate the time delta without having to create a separate object and perform a date subtraction operation.

Related

Best way to do a massive data sync from HealthKit?

I am looking for a smart way to import ALL data for ALL time from HealthKit in a smart way for high volume users who log certain HealthKit values hundreds of times a day for months or years. I'm also looking to do this off the main thread and in a way that is robust to the fact that users can close the app whenever they feel like. Here's what my current implementation is:
- (void) fullHealthKitSyncFromEarliestDate {
dispatch_queue_t serialQueue = dispatch_queue_create("com.blah.queue", DISPATCH_QUEUE_SERIAL);
NSLog(#"fullHealthKitSyncFromEarliestDate");
NSDate *latestDate = [PFUser currentUser][#"earliestHKDate"];
if (!latestDate) latestDate = [NSDate date];
NSDate *earliestDate = [healthStore earliestPermittedSampleDate];
NSLog(#"earliest date %# and latest date %#", earliestDate, latestDate);
if ([earliestDate earlierDate:[[NSDate date] dateByAddingYears:-2]] == earliestDate) {
earliestDate = [[NSDate date] dateByAddingYears:-1];
}
__block NSDate *laterDate = latestDate;
__block NSDate *earlierDate = [latestDate dateByAddingMonths:-1];
int i = 0;
while ([earlierDate earlierDate:earliestDate] == earliestDate) {
// DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(i * 30 * NSEC_PER_SEC)), serialQueue, ^{
NSLog(#"calling sync from %# to %#", earlierDate, laterDate);
[self syncfromDate: earlierDate toDate:laterDate];
laterDate = [laterDate dateByAddingMonths:-1];
earlierDate = [laterDate dateByAddingMonths:-1];
earlierDate = [[earliestDate dateByAddingSeconds:1] laterDate:earlierDate];
});
}
}
I am having a few problems with the above code:
earlierDate is sometimes not getting updated for the next iteration. It's like there's some weird overlap that sometimes the same date range gets called twice or even more times.
Kernel memory allocation issues (as I retrieve objects I queue them for upload to a remote server)
Interface stops responding entirely even though this is all happening off the main queue. There may be something way down stream that gets called at the end of the entire query...but I'm still surprised the interface basically stops responding altogether. It usually does fine with similar syncing for short time periods. And here I'm just doing a month at a time in queries spaced 30 seconds apart
I realize without the details of additional code this may be too murky to address, but can people tell me what sort of solutions you have implemented for cases where you want to retrieve massive amounts of data from HealthKit. I realize I may get responses like 'that's what HealthKit is for...why are you duplicating all that data?'. Suffice it to say it's required and there's no way around it.
Also, am I just misunderstanding entirely how to use a serial queue?
Ideally I'd like to do the following: (1) Run only one query at a time in this for loop (2) and run them with some reasonable period of time between them, say 30 seconds apart, because at the end of each query I do need to do some interface updates on the main qeue (3) do all the queries on a background loop in such a way that it's not degrading interface performance and can be killed at any time the user decides he's gonna kill the app. That's what I thought I would achieve with the above...if folks can tell me where my threading is going wrong I'd really appreciate it. Thanks!

Non-deterministic crash in BlocksKit bk_apply block

I have a function that constructs an NSMutableDictionary using bk_apply, a method provided by the third-party block utility library BlocksKit. The function's test suite usually passes just fine, but once every couple runs it crashes.
NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
[inputSet bk_apply:^(NSString *property) {
NSString *localValueName = propertyToLocalName[property];
NSObject *localValue = [self valueForKey:localValueName];
result[property] = localValue ?: defaults[property]; // Crash
// Convert all dates in result to ISO 8601 strings
if ([result[property] isKindOfClass:[NSDate class]]) { // Crash
result[property] = ((NSDate *)result[property]).ISODateString; // Crash
}
}];
The crash always happens on a line where result is referenced, but it's not the same line every time.
Examining the contents of result in the debugger, I've seen very strange values like
po result
{
val1 = "Some reasonable value";
val2 = "Also reasonable value";
(null) = (null);
}
It's impossible for an NSDictionary to have null keys or values, so clearly some invariant is being violated.
What is causing this crash and how do I fix it?
From the BlocksKit documentation for bk_apply:
Enumeration will occur on appropriate background queues. This will
have a noticeable speed increase, especially on dual-core devices, but
you must be aware of the thread safety of the objects you message
from within the block.
The code above is highly unsafe with respect to threading, because it reads from and writes to a mutable variable on multiple threads.
The intermittent nature of the crash comes from the fact that the thread scheduler is non-deterministic. The crash won't happen when several threads accessing shared memory happen to have their execution scheduled in sequence rather than in parallel. It is therefore possible to "get lucky" some or even most of the time, but the code is still wrong.
The debugger printout is a good example of the danger. The thread that's paused is most likely reading from result while another thread performs an insertion.
NSMutableDictionary insertions are likely not atomic; example steps might be,
allocate memory for the new entry
copy the entry's key into the memory
copy the entry's value into the memory
If you read the dictionary from another thread between steps 1 and 2, you will see an entry for which memory has been allocated, but the memory contains no values.
The simplest fix is to switch to bk_each. bk_each does the same thing as bk_apply but it's implemented in a way that guarantees sequential execution.

Objective-C Declaring Variables Within Loop -- Performance

I've been teaching myself Objective-C via some lectures from iTunes U.
I like the course, but the professor routinely writes code like this:
while (index < [self.textToAnalyze length]) {
NSRange range;
id value = [self.textToAnalyze attribute:attributeName atIndex:index effectiveRange:&range];
....
}
I have mostly worked in C and C++, and there are a couple of things about this code that seem glaringly wrong to me from a performance / style perspective.
The code declares two variables (of type NSRange and id) inside the loop. A naive compiler would reserve space for each of these types of variables at each iteration through the loop.
The code calls the length selector ([self.textToAnalyze length]) in the loop condition. As the programmer, I know that the length of the textToAnalyze property does not change while the loop is iterating. However, I'm not convinced that the compiler will know this. Won't this code call the length selector every single iteration of the loop?
I know that compilers can be very crafty, but I think it is bad code to declare variables within a loop and call functions within the loop conditions. It could affect the performance, and in my mind, it is certainly poor style.
However, I am new to Objective-C, so here is my question:
Is this bad code, or are these Objective-C idioms that are fine to use?
The answer is: it depends.
For variables in loops, moving them out of the loop might improve performance of the loop, but now you've changed the scope and effected performance in another way. Which is better is definitely going to be situation-based.
But, as far as I'm concerned, a variable with a scope any wider than necessary is bad practice. Variables with unnecessarily wide scope and lead to user error. The amount of performance improvement you might get here is not worth ANY amount of debugging that could've been avoided with a narrower variable scope.
As for calling methods in loop conditions, again, this depends.
I'm quite certain that the length method of NSString is quite optimized. The length of a string is not analyzed every time length is called, and especially not so for NSString (as opposed to NSMutableString. If we're talking about an immutable string, calling length is simply returning an NSInteger value stored within the class and performance will be fine.
If, however, we're talking about an immutable string, we need to call length every time if it's important that we're only within the length of the string.
It's a mutable string. Even if this loop doesn't modify the string, it can be modified else where by anyone that has a reference to it. If you're concerned about performance, make an immutable copy of the string and use that immutable copy in the loop.
[myString length]
According to this answer, for both mutable and immutable versions, there is a variable within the class that stores the string's length. For immutable strings, this is calculated when the string is created and never changed. For mutable strings, this variable is calculated and set each time the string changes. At the end of the day, when you call string, it's purely returning the value of an internally stored int value in the class and will not be any slower than storing this length in a separate variable before the loop and comparing against this.
I think it is theoretically possible for some loop conditions to be cached, but in practice that doesn't seem to happen — the length method will be called every time through the loop.
Does that make this bad code? Not necessarily. The overhead of a function call is not that huge. If this loop needs to be tight, then yes, caching the string's length is a great idea. But in many cases, it just doesn't make any measurable difference, so less code is better code.
As for declaring variables in a loop, that isn't problematic. There are two mainstream Objective-C compilers in existence, and neither has any trouble compiling that to efficient code. I doubt even POC has trouble with that. Muddling your variables' scope just to please a hypothetical awful compiler isn't good code — it's premature optimization. (Incidentally, the same holds true for C++ too.)

Bundle declarations into one statement or not?

Given the following Objective-C example, is it simply a matter of style and ease of reading to keep separate statements or to bundle them into one? Are there any actual benefits of either? Is it a waste of memory to declare individual variables?
NSDictionary *theDict = [anObject methodToCreateDictionary];
NSArray *theValues = [theDict allValues];
NSString *theResult = [theArray componentsJoinedByString:#" "];
or
NSString *theResult = [[[anObject methodToCreateDictionary] theValues] componentsJoinedByString:#" "];
I take the following into consideration when I declare a separate variable:
If I might want to see its value in the debugger.
If I am accessing the variable more than once.
If the line is too long.
There is no practical difference between the two approaches, however.
Also, you haven't asked directly about this, but be aware, when you access objects using dot notation, for example:
myObject.myObjectProperty1.myObjectProperty1Property;
If you are going to access myObjectProperty1Property more than once, it can be advisable to assign it to a local named variable. If you don't, the look-up will be executed more than once.
Now I can't emphasise enough, for many if not most situations this time saving is so infinitesimal as to seriously call into question whether it is worth even spending the time doing extra typing for the assignation! So why am I raising this? Because having said that - stylistic "anality" apart (I just made up a new word) - if the section of code you are writing is running in a tight loop, it can be worth taking the extra care. An example would be when writing the code which populates the cells in a UICollectionView that contains a large number of cells. Additionally, if you are using Core Data and you are using the dot notation to refer to the properties of NSManagedObject properties, then there is far greater overhead with each and every look-up, in which case it is much more surely worth taking the time to assign any values referred to by "nested" dot notation calls to a local variable first.

Smoothness of NSProgressIndicator: incrementBy vs setDoubleValue

I suspect that NSProgressIndicator runs smoother when its value is updated through incrementBy as compared to setDoubleValue.
Does anyone know if there's any real difference between the two methods of updating its value?
I don't have any knowledge of the internals, but I would be very surprised if incrementBy were not the equivalent of
[self setDoubleValue:[self doubleValue] + delta];
Of course, since it has access to internal state, it could presumably skip all the method calls.But the act of actually rendering pixels to the screen almost certainly overpowers any minor performance difference between the two methods.
I suspect that NSProgressIndicator runs smoother when its value is
updated through incrementBy as compared to setDoubleValue.
Makes no difference on macOS 10.14. When I set the maxValue to 1000 and then have a timer call a method every 100 ms, it looks identical, whether the method always calls [self.progress incrementBy:1] or [self.progress setDoubleValue:self.step++], with step being an instance variable of type NSUInteger that is initially zero.