Here's some investigation into my attempts to see what it would take to be able to effectively run in an "open" clamshell mode. That is, connected to an external display, with the laptop open, but the internal display disabled. And before you say "iog=0x0", I have a section about that, why you're wrong (it's actually 0x2) and about how it's not a perfect solution.
## Motivation
Laptop run hot, fan go brr.
More formally, connecting to an external display requires use of the discrete GPU, because in an absolutely boneheaded decision they decided to save some money on wiring the gmux to the external ports as well. If I'd known this before I'd have gotten the BTO iGPU only version, but oh well. Though this saving makes sense from a power-standpoint (because if you're using an external display you have AC power available) it is madness from a temperature standpoint where the nvidia gpu has a much higher power draw than the iGPU. And this higher power draw translates to about 20F higher temperatures, as quantatively shown in this amazing [1] regression analysis.
So what can we do to prevent the laptop from becoming a space heater? You can play with fan controls, but that's just patching over the symptom (and I hate fan noise). You can disable turbo boost and enforce CPU power limits, but that only really gets you so far since it just buys you more headroom, since the GPU is still cranking away.
## Control GPU P-State
The hackintosh guys (and 2010 mbp owners) are probably familiar with AppleGraphicsPowerManagement kext, which has some configurations for gpu p-state and vp-state. There are entries for the retina mbps as well, they look something like for the discrete gpu
followed by some "heuristics" that probably define when to switch to which p-state
and then a table of numbers 0-29 which I think define the possible values for VPState and PState.
It's conceivable that by modifying these you could force it to remain at the lowest power-level (which is actually the highest numerical value for PState. I.e. P0 is actuall max power consumption), but I'm really not sure what the 6/14/14/6 corresponds to, nor what the actual values in MinVP* represent.
Maybe if someone has ideas here, please chime in?
## Disable Internal Display
So then an orthogonal approach to reduce temps is to run with the laptop open to allow for better dissipation. Normally, opening the display will undo "clamshell mode" and result in the internal display activating as well, but as some are aware, there is the supposed boot-args "iog=0x0" trick to restore the pre-Lion behavior that allows opening the laptop when in "clamshell mode".
Now the actual invocation for 10.9 should actually be "iog=0x2", because if you read the IOFramebuffer source [2], you see that lid open behavior is controlled by the lowest bit, and the default is 0x3. Setting to 0x0 also unsets FBVBLThrottle, whatever that does (probably not good?).
What does "unsetting" gIOFBLidOpenMode actually do? Again, reading the IOFramebuffer source we see that it influences whether "desktopMode" is set, and also influences whether a reprobe is issued upon "clamshell reset". "DesktopMode" seems to be used to set an IOPM bit that controls whether closing a laptop allows it go into sleep. It should be noted that I think there are kexts (Insomnia) that use the same mechanism to prevent the laptop from sleeping on lid close.
This is great and almost what we want, except when waking from sleep the internal display gets re-enabled. Now, you may be aware of tools like SwitchResX that are able to disable internal display. These make use of the private CGSSetDisplayEnabled call (same as open source tool on github), but these are not 100% complete solution as you can see from switchresx faq. I haven't checked with IORegistryExplorer, but I suspect the display will still be attached in the tree. I guess it satisfies the condition that no resources are wasted on rendering to it, but it is too much hassle when unplugging displays since it's not seamless.
By contrast when the display is disabled in clamshell mode, it is completely gone from the ioreg hierarchy. I'm still not sure how exactly this works, since as far as I can see the call to disable internal display when closing laptop is done via `fb->deliverFramebufferNotification(kIOFBNotifyClamshellChange, clamshellProperty);` and then in IOBacklitDisplay it changes power state to 0. I also need to explore and see whether this is reflected in gIOFBBacklightDisplayCount being 0.
Upon wake, we a kIOFBEventResetClamshell event is posted, which is handled via
so if it's the case that IOFramebuffer still retains a reference (via gIOFBBacklightDisplayCount) to the display then it's the re-probe causing the internal display to be re-activated. Of course, maybe (even most likely) upon a wake from sleep the internal display is activated regardless of whether or not a reprobe is issued (I'm not sure where this would be handled, but I assume it's treated similar to a new display being powered and coming online) in which case patching this wouldn't do anything.
The other way to do this would be to get a reference to gAllFramebuffers in kernel memory and then just issue issue a kIOFBNotifyClamshellChange for all the active framebuffers. That should "simulate" the laptop going to sleep, and allow you to manually disable the internal display.
[1] https://apple.stackexchange.com/que...s-a-mid-2015-retina-macbook-pro-with-only-int
[2] https://github.com/st3fan/osx-10.9/blob/master/IOGraphics-468/IOGraphicsFamily/IOFramebuffer.cpp
## Motivation
Laptop run hot, fan go brr.
More formally, connecting to an external display requires use of the discrete GPU, because in an absolutely boneheaded decision they decided to save some money on wiring the gmux to the external ports as well. If I'd known this before I'd have gotten the BTO iGPU only version, but oh well. Though this saving makes sense from a power-standpoint (because if you're using an external display you have AC power available) it is madness from a temperature standpoint where the nvidia gpu has a much higher power draw than the iGPU. And this higher power draw translates to about 20F higher temperatures, as quantatively shown in this amazing [1] regression analysis.
So what can we do to prevent the laptop from becoming a space heater? You can play with fan controls, but that's just patching over the symptom (and I hate fan noise). You can disable turbo boost and enforce CPU power limits, but that only really gets you so far since it just buys you more headroom, since the GPU is still cranking away.
## Control GPU P-State
The hackintosh guys (and 2010 mbp owners) are probably familiar with AppleGraphicsPowerManagement kext, which has some configurations for gpu p-state and vp-state. There are entries for the retina mbps as well, they look something like for the discrete gpu
Code:
<key>BoostPState</key>
<array>
<integer>6</integer>
<integer>14</integer>
<integer>14</integer>
<integer>6</integer>
</array>
<key>BoostTime</key>
<array>
<integer>1</integer>
<integer>1</integer>
<integer>1</integer>
<integer>1</integer>
</array>
followed by some "heuristics" that probably define when to switch to which p-state
Code:
<key>MinP0P1</key>
<integer>10</integer>
<key>MinP5</key>
<integer>14</integer>
<key>MinP8</key>
<integer>15</integer>
<key>MinVP0</key>
<integer>10</integer>
<key>MinVP1</key>
<integer>21</integer>
<key>MinVP5</key>
<integer>28</integer>
<key>MinVP8</key>
<integer>29</integer>
and then a table of numbers 0-29 which I think define the possible values for VPState and PState.
It's conceivable that by modifying these you could force it to remain at the lowest power-level (which is actually the highest numerical value for PState. I.e. P0 is actuall max power consumption), but I'm really not sure what the 6/14/14/6 corresponds to, nor what the actual values in MinVP* represent.
Maybe if someone has ideas here, please chime in?
## Disable Internal Display
So then an orthogonal approach to reduce temps is to run with the laptop open to allow for better dissipation. Normally, opening the display will undo "clamshell mode" and result in the internal display activating as well, but as some are aware, there is the supposed boot-args "iog=0x0" trick to restore the pre-Lion behavior that allows opening the laptop when in "clamshell mode".
Now the actual invocation for 10.9 should actually be "iog=0x2", because if you read the IOFramebuffer source [2], you see that lid open behavior is controlled by the lowest bit, and the default is 0x3. Setting to 0x0 also unsets FBVBLThrottle, whatever that does (probably not good?).
What does "unsetting" gIOFBLidOpenMode actually do? Again, reading the IOFramebuffer source we see that it influences whether "desktopMode" is set, and also influences whether a reprobe is issued upon "clamshell reset". "DesktopMode" seems to be used to set an IOPM bit that controls whether closing a laptop allows it go into sleep. It should be noted that I think there are kexts (Insomnia) that use the same mechanism to prevent the laptop from sleeping on lid close.
This is great and almost what we want, except when waking from sleep the internal display gets re-enabled. Now, you may be aware of tools like SwitchResX that are able to disable internal display. These make use of the private CGSSetDisplayEnabled call (same as open source tool on github), but these are not 100% complete solution as you can see from switchresx faq. I haven't checked with IORegistryExplorer, but I suspect the display will still be attached in the tree. I guess it satisfies the condition that no resources are wasted on rendering to it, but it is too much hassle when unplugging displays since it's not seamless.
By contrast when the display is disabled in clamshell mode, it is completely gone from the ioreg hierarchy. I'm still not sure how exactly this works, since as far as I can see the call to disable internal display when closing laptop is done via `fb->deliverFramebufferNotification(kIOFBNotifyClamshellChange, clamshellProperty);` and then in IOBacklitDisplay it changes power state to 0. I also need to explore and see whether this is reflected in gIOFBBacklightDisplayCount being 0.
Upon wake, we a kIOFBEventResetClamshell event is posted, which is handled via
Code:
if ((gIOFBLidOpenMode && (gIOFBCurrentClamshellState != gIOFBLastReadClamshellState))
// clamshell changed since last probe
|| (!gIOFBLidOpenMode && (gIOFBBacklightDisplayCount && gIOFBLastReadClamshellState && !gIOFBCurrentClamshellState)))
// clamshell was closed during last probe, now open => reprobe
{
DEBG1("S", " clamshell caused reprobe\n");
events |= kIOFBEventProbeAll;
OSBitOrAtomic(kIOFBEventProbeAll, &gIOFBGlobalEvents);
}
else
{
AbsoluteTime deadline;
clock_interval_to_deadline(kIOFBClamshellEnableDelayMS, kMillisecondScale, &deadline );
thread_call_enter1_delayed(gIOFBClamshellCallout,
(thread_call_param_t) kIOFBEventEnableClamshell, deadline );
}
so if it's the case that IOFramebuffer still retains a reference (via gIOFBBacklightDisplayCount) to the display then it's the re-probe causing the internal display to be re-activated. Of course, maybe (even most likely) upon a wake from sleep the internal display is activated regardless of whether or not a reprobe is issued (I'm not sure where this would be handled, but I assume it's treated similar to a new display being powered and coming online) in which case patching this wouldn't do anything.
The other way to do this would be to get a reference to gAllFramebuffers in kernel memory and then just issue issue a kIOFBNotifyClamshellChange for all the active framebuffers. That should "simulate" the laptop going to sleep, and allow you to manually disable the internal display.
[1] https://apple.stackexchange.com/que...s-a-mid-2015-retina-macbook-pro-with-only-int
[2] https://github.com/st3fan/osx-10.9/blob/master/IOGraphics-468/IOGraphicsFamily/IOFramebuffer.cpp