Commits

Peter Hosey committed 241e3e5

Switched from NSTimer to GCD for the view-update timers. Shaves 0.01% of a CPU according to Activity Monitor in 10.7.2 on my 1.6 GHz 2010 MBA.

  • Participants
  • Parent commits 66e9c1a
  • Branches modernization

Comments (0)

Files changed (1)

File CPUUsageMonitor.m

 
 //Main thread.
 - (void)updateCPUUsageButNotViews:(NSTimer *)timer;
-- (void)startViewUpdateThreads;
+- (void) commenceDispatchTimerForProcessor:(unsigned)processorIndex;
 //Threaded.
-- (void)threadedLaunchTimer:(NSNumber *)CPUIndexNum;
+- (void) threadedUpdateCPUUsageViewForProcessor:(unsigned)processorIndex;
 
 @end
 
 	mach_msg_type_number_t numProcessorInfo, numLastProcessorInfo;
 	unsigned numCPUs;
 	float *CPUUsage;
+	dispatch_source_t *runningSources;
 	NSLock *deathLock;
 	NSUInteger threadsRemainingToDie;
 	BOOL threadsShouldExit;
 												   repeats:YES] retain];
 	[updateTimer fire];
 
-	[self performSelector:@selector(startViewUpdateThreads)
-			   withObject:nil
-			   afterDelay:1.];
+	runningSources = malloc(sizeof(runningSources[0]) * numCPUs);
+	//Launch the threaded (well, queued, now) timers that sweep our CPU usage array looking for views.
+	for(unsigned i = 0U; i < numCPUs; ++i) {
+		[self commenceDispatchTimerForProcessor:i];
+	}
 
 	if(shouldDrawToWindow)
 		[window orderFront:nil];
 }
 
-- (void)startViewUpdateThreads {
-	//Launch the threaded timers that sweep our CPU usage array looking for views.
-	for(unsigned i = 0U; i < numCPUs; ++i) {
-		[NSThread detachNewThreadSelector:@selector(threadedLaunchTimer:)
-								 toTarget:self
-							   withObject:[NSNumber numberWithUnsignedInt:i]];
-	}
-}	
-
 - (void)applicationWillTerminate:(NSNotification *)notification {
 	//First, wait for our resize animation to finish.
 	if (windowResizeAnimation) {
 	[anim setDuration:0.5];
 	[anim setAnimationBlockingMode:NSAnimationNonblockingThreaded];
 
-	//Tell the threads to stop, then wait for them to comply.
+	//Tell the timers to stop, then wait for them to comply.
+	for (unsigned i = 0U; i < numCPUs; ++i) {
+		dispatch_source_cancel(runningSources[i]);
+	}
 //	threadsShouldExit = YES;
 	deathLock = [[NSLock alloc] init];
 	threadsRemainingToDie = [usageViews count];
 		[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
 
 	[deathLock release];
+	free(runningSources);
 
 	//Wait for the animation to run out.
 	while([anim isAnimating])
 
 #pragma mark Timer
 
-- (void)threadedUpdateCPUUsageView:(NSTimer *)timer {
-	unsigned i = [[timer userInfo] unsignedIntValue];
+- (void) threadedUpdateCPUUsageViewForProcessor:(unsigned)processorIndex {
+	CPUUsageView *view = [usageViews objectAtIndex:processorIndex];
+	CPUUsageView *viewInDockIcon = [dockIconUsageViews objectAtIndex:processorIndex];
 
-	CPUUsageView *view = [usageViews objectAtIndex:i];
-	CPUUsageView *viewInDockIcon = [dockIconUsageViews objectAtIndex:i];
-
-	float currentUsage = CPUUsage[i];
+	float currentUsage = CPUUsage[processorIndex];
 	[view setCPUUsage:currentUsage];
 	[viewInDockIcon setCPUUsage:currentUsage];
 
 		[view threadedDisplay];
 	}
 	//Don't draw any Dock icon view here anymore—with NSDockTile, that must happen on the main thread.
+}
+- (void) commenceDispatchTimerForProcessor:(unsigned)processorIndex {
+	dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, /*handle*/ 0, /*mask*/ 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, /*flags*/ 0));
+	dispatch_source_set_timer(source, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 4), NSEC_PER_SEC / 2, /*leeway*/ NSEC_PER_SEC / 10);
 
-	if(threadsRemainingToDie) {
-		[timer invalidate];
+	__block id bself = self;
+	dispatch_source_set_event_handler(source, ^{
+		NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
-		[deathLock lock];
-		--threadsRemainingToDie;
-		[deathLock unlock];
-	}
-}
-- (void)threadedLaunchTimer:(NSNumber *)CPUIndexNum {
-	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+		[bself threadedUpdateCPUUsageViewForProcessor:processorIndex];
 
-	NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
+		if(threadsRemainingToDie) {
+			dispatch_source_cancel(source);
 
-	NSTimer *timer = [NSTimer timerWithTimeInterval:0.5
-											 target:self
-										   selector:@selector(threadedUpdateCPUUsageView:)
-										   userInfo:CPUIndexNum //userInfo
-											repeats:YES];
-	[timer setFireDate:[NSDate dateWithTimeIntervalSinceNow:0.25]];
+			[deathLock lock];
+			--threadsRemainingToDie;
+			[deathLock unlock];
+		}
 
-	[runLoop addTimer:timer forMode:NSDefaultRunLoopMode];
-	[runLoop run];
+		[pool drain];
+	});
 
-	[pool release];
+	dispatch_resume(source);
+
+	runningSources[processorIndex] = source;
 }
 
 //Main thread.