Skip to content

Instantly share code, notes, and snippets.

@steipete
Created October 22, 2012 18:13
Show Gist options
  • Save steipete/3933090 to your computer and use it in GitHub Desktop.
Save steipete/3933090 to your computer and use it in GitHub Desktop.
Simple main thread usage detector that I'm using in PSPDFKit to find performance problems early on.
// Smart little helper to find main thread hangs. Enable in appDidFinishLaunching.
// Only available with source code in DEBUG mode.
@interface PSPDFHangDetector : NSObject
+ (void)startHangDetector;
@end
@implementation PSPDFHangDetector
+ (void)startHangDetector {
#ifdef DEBUG
NSThread *hangDetectionThread = [[NSThread alloc] initWithTarget:self selector:@selector(deadThreadMain) object:nil];
[hangDetectionThread start];
#endif
}
#ifdef DEBUG
static volatile NSInteger DEAD_SIGNAL = 0;
+ (void)deadThreadTick {
if (DEAD_SIGNAL == 1) {
NSLog(@"Main Thread doesn't answer...");
}
DEAD_SIGNAL = 1;
dispatch_async(dispatch_get_main_queue(), ^{DEAD_SIGNAL = 0;});
}
+ (void)deadThreadMain {
[NSThread currentThread].name = @"PSPDFHangDetection";
@autoreleasepool {
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(deadThreadTick) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
}
}
#endif
@end
@steipete
Copy link
Author

This idea is not 100% from me, can't recall who brought this to me. Tweak the 0.5 to make the watchdog sharper or less annoying :) MIT licensed - feel free to use.

@steipete
Copy link
Author

And if you wanna support me, purchase PSPDFKit or recommend it to someone who is working with PDF :) http://pspdfkit.com/

@tewha
Copy link

tewha commented Oct 22, 2012

Couldn't DEAD_SIGNAL be a block local within deadThreadTick?

@DerAndereAndi
Copy link

I think you got the idea from here: https://gist.github.com/1513472 :)

@DerAndereAndi
Copy link

I am trying to make this usable as part of HockeySDK (for beta versions), but running into some issues. The goal is to have a flag set in a file which tells the app that the last time it ended, the main thread was blocked and try to make this as bullet proof as possible.

  1. The background thread continues to run once the app goes into background. Which will cause the watchdog to jump in after 10 seconds, because the app runs in the background for longer than it is allowed (default behavior). It would crash (watchdog doesn't kill an app after startup if it blocks the main thread), but the reason is different than the intend is, so this is not wanted.
  2. To solve this I would change this to just GCD and when going into background or terminate it would release the background queue.
  3. But if the main thread is blocked (e.g. endless loop), the app won't be notified that it is going to background, since that is all handled by UIKit in the main thread only.
  4. To solve this I would stop the ticket in the background queue, after the main thread did not answer the first time.
  5. Now it could happen that the app just stalled for some time, which is a little longer than the ticker interval. So another "ticker" should then started on the main thread which would restart the background ticker in this case.

Any ideas or does that sound feasible to you?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment