MetalKit app launches too slow, kernel_task kicks in and Mac becomes briefly unresponsive

I've built a lightweight app that displays some advanced animated graphics UI using the Metal Kit

Unfortunately, the app launches too slow. The app's icon in the Dock bounces 3-5 times, the icon's bounce animation is jerky, and also the whole Mac becomes temporarily sluggish and may become much less responsive for a few seconds. So it's not merely a matter of my app's launch-time optimization. Also I don't have this problem with other apps that don't use Metal.

I narrowed down the problem and figured that the problem disappears if I comment out the code starting from -[CAMetalLayer setDevice:] in my -[NSApplicationDelegate applicationWillFinishLaunching:].

I also noticed in the Activity Monitor that when I launch my app, the kernel_task instantly becomes hugely active, taking up 100 or 200% of CPU, and quickly goes back to 3-4% after the launch is complete. This apparently causes the whole Mac to become sluggish temporarily.

I have a theory that for some reason, macOS maxes out the kernel_task when my app calls the GPU for initialization.

I know that the kernel_task is used to throttle CPU to avoid overheating, but my Macbook has normal temperature and no other CPU-intense tasks are running.

I am running MacBook Pro (16-inch, 2019) 2.6 GHz 6-Core Intel Core i7 16 GB 2667 MHz DDR4 AMD Radeon Pro 5300M 4 GB Intel UHD Graphics 630 1536 MB

Can someone please advise about the possible causes of this problem and how to deal with it? My app is extremely lightweight and I really want it to launch instantly.

Accepted Reply

To answer my own question: The problem was caused by the MTLCreateSystemDefaultDevice() function, that returns the discrete GPU's device by default. The discrete GPU indeed takes a few moments to start up, unless some other apps are already using it. But my app would be totally fine with the integrated GPU, no real need for the more powerful discrete GPU. Once I changed my code to use CGDirectDisplayCopyCurrentMetalDevice(screenNumber) of my view's screen's NSScreenNumber, the launch time has dropped to a really small duration, as desired. More on the subject here:

https://developer.apple.com/documentation/metal/gpu_selection_in_macos/selecting_device_objects_for_graphics_rendering?language=objc

  • Glad you see that you figured out the problem. Your observation is indeed correct, this caused by switching from the integrated to the discrete GPU.

Add a Comment

Replies

I also noticed that if I make a copy of my app's binary and launch another instance after one is already running, the second instance launches instantly without any delay or slugglishness.

To answer my own question: The problem was caused by the MTLCreateSystemDefaultDevice() function, that returns the discrete GPU's device by default. The discrete GPU indeed takes a few moments to start up, unless some other apps are already using it. But my app would be totally fine with the integrated GPU, no real need for the more powerful discrete GPU. Once I changed my code to use CGDirectDisplayCopyCurrentMetalDevice(screenNumber) of my view's screen's NSScreenNumber, the launch time has dropped to a really small duration, as desired. More on the subject here:

https://developer.apple.com/documentation/metal/gpu_selection_in_macos/selecting_device_objects_for_graphics_rendering?language=objc

  • Glad you see that you figured out the problem. Your observation is indeed correct, this caused by switching from the integrated to the discrete GPU.

Add a Comment