8

I need to prevent the processor from entering an idle state (non C0 C state). Admittedly I do not know much about processor C and P states so bear with me. We use a camera from a third party vendor which occasionally delivers corrupted frames. The vendor has determined that when the CPU enters an idle state it interferes with the transmission of the frame over the firewire. To confirm this I used the following code on a Windows 7 PC and indeed, disabling the idle states resolved the issue.

   //WIN7
const DWORD DISABLED = 1;
const DWORD ENABLED = 0;
GUID *scheme;
PowerGetActiveScheme(NULL, &scheme);
PowerWriteACValueIndex(NULL, scheme, &GUID_PROCESSOR_SETTINGS_SUBGROUP, &GUID_PROCESSOR_IDLE_DISABLE, DISABLED);
PowerSetActiveScheme(NULL, scheme);

If I run my application and open Windows permon and add the %C1 Time, %C2 Time and %C3 time I see that they are all zero when I disable these states, when I enable them I see quite a bit of time spent in the C3 state (this is on a Dell Precision T3500 quad core PC).

I also need to do this on XP however these calls are not available on XP. So I attempted to do the following to disable the idle states

  unsigned int ActPwrSch; 
DWORD currPolicy,newPolicy, curr1Policy,curr2Policy, new1Policy, new2Policy;
MACHINE_PROCESSOR_POWER_POLICY Policy; 
if(GetActivePwrScheme(&ActPwrSch)) 
{ 
    if(ReadProcessorPwrScheme(ActPwrSch,&Policy)) 
    { 
        printf("Read Power Scheme:\n"); 
        //if(Policy.ProcessorPolicyAc.DisableCStates!=0) 
        currPolicy = Policy.ProcessorPolicyAc.Policy[0].AllowPromotion;
        curr1Policy = Policy.ProcessorPolicyAc.Policy[1].AllowPromotion;
        curr2Policy = Policy.ProcessorPolicyAc.Policy[2].AllowPromotion;
        Policy.ProcessorPolicyAc.Policy[0].AllowPromotion = 0;
        Policy.ProcessorPolicyAc.Policy[1].AllowPromotion = 0;
        Policy.ProcessorPolicyAc.Policy[2].AllowPromotion = 0;
        newPolicy = Policy.ProcessorPolicyAc.Policy[0].AllowPromotion;

        if(WriteProcessorPwrScheme(ActPwrSch,&Policy)) 
        { 
            printf("WriteProcessorPwrScheme succeed\n"); 
            if(SetActivePwrScheme(ActPwrSch,0,0)) 
            { 
                printf("SetActivePwrScheme succeed!!\n");
            } 
        }

    } 

However when I run my application I still see that the processor is spending time in the C1 state (by looking at the same counters in perfmon). And I still get my corrupted image problem. The XP PC is an single core Dell optiplex PC.

Does anybody know how I can prevent entry into any of the C1-C3 states on XP? As I said it seems that I have done it on Windows 7.

mash
  • 467
  • 7
  • 14
  • 3
    Wow, that sounds painful. I suppose getting the vendor to just deliver a driver that *works* is out of the question? – jalf Mar 15 '12 at 14:07
  • Not sure if this is entirely relevant, but wouldn't setting `Policy.ProcessorPolicyAc.DynamicThrottle` to `PO_THROTTLE_NONE` possibly help? – Hasturkun Mar 15 '12 at 14:10
  • Ha...it seems to be for now jalf. We are working on changing vendors but for now I'm stuck. Painful indeed. – mash Mar 15 '12 at 14:10
  • Hasturkun, thanks but this did not prevent the CPU from entering the C1 state, maybe that just affects the P states? I'm not sure – mash Mar 15 '12 at 16:42

3 Answers3

4

You can use SetThreadExecutionState function which enables the application to inform the system that it is in use.

EDIT: After a little research and testing I came to a solution or I think I did. You're on the right track for Windows XP. If you read the documentation for the PROCESSOR_POWER_POLICY structure , you'll notice you can disable each C-states that offends you:

Policy[0].AllowPromotion = 0; // Disable's C1 (usually C1 won't cause problems, so you should leave it alone.)
Policy[1].AllowPromotion = 0; // Disable's C2
Policy[2].AllowPromotion = 0; // Disable's C3


In Vista and Windows7 you can't use this interface instead you have to do this:

GUID *scheme;
PowerGetActiveScheme(NULL, &scheme); 
PowerWriteACValueIndex(NULL, scheme, &GUID_PROCESSOR_SETTINGS_SUBGROUP,  &GUID_PROCESSOR_IDLE_DISABLE, 1); 
PowerSetActiveScheme(NULL, scheme);


I haven't found a way to disable individual C states on Vista and Windows 7. If you need some sample codes please email me I can help you out.

Dylan Cole
  • 396
  • 3
  • 8
  • I tried this, I think this will prevent the PC from going to sleep but doesn't have an effect on the C states of individual CPU's? I'm not sure...but my CPU still entered the C1 state.Thanks – mash Mar 15 '12 at 16:43
  • Hey Dylan, I actually have that same code in the original post. For some reason the XP code doesn't seem to be working. I still see my CPU enter the C1 state. On Win7 I don't see the CPU enter the C1 state. – mash Mar 15 '12 at 20:07
2

Surely a TSR running a mathematical calculation every 5 minutes will prevent an idle state? Alternatively you can purchase a cheap hardware or software mouse emulator that sends a mouse move signal at defined intervals.

  • 2
    This sort of thing might ensure that the computer itself won't go to sleep, but it won't stop the computer from deciding that it doesn't need all four CPU cores running and putting one or more of them to sleep. – Harry Johnston Sep 11 '12 at 22:08
  • User activity is almost completely unrelated to CPU states, but you could still fire junk load on every logical cpu to be 99.9% sure idle is never achieved. That may in turn steal precious cpu time from your main task though. And especially in this day and age of turbo states and PL2 trickery, it would also feel like a waste of energy. I mean, not that C0 already isn't (non-enhanced C1 should be virtually lagless everywhere) but at least the CPU should only run at its nominal TDP in the worst case scenario. With *actual* instructions to run instead, you could be easily consuming 1.5x as much. – mirh Dec 16 '22 at 18:10
2

This seems to be working for me:

void PowerState(bool bEnable)
{
    // CPU idle state
    unsigned int ActPwrSch;
    MACHINE_PROCESSOR_POWER_POLICY Policy;
    if (GetActivePwrScheme(&ActPwrSch))
    {
        if (ReadProcessorPwrScheme(ActPwrSch, &Policy))
        {
            Policy.ProcessorPolicyAc.Policy[0].AllowPromotion = bEnable ? 1: 0; // C1
            Policy.ProcessorPolicyAc.Policy[1].AllowPromotion = bEnable ? 1: 0; // C2
            Policy.ProcessorPolicyAc.Policy[2].AllowPromotion = bEnable ? 1: 0; // C3
            if (WriteProcessorPwrScheme(ActPwrSch, &Policy))
                SetActivePwrScheme(ActPwrSch, 0, 0);
        }
    }
    OSVERSIONINFO osvi;
    memset(&osvi, 0, sizeof(OSVERSIONINFO));
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    GetVersionEx(&osvi);
    // For Vista and above
    if (osvi.dwMajorVersion >= 6)
    {
        static const GUID processor_idle_disable_guid = {0x5d76a2ca, 0xe8c0, 0x402f, 0xa1, 0x33, 0x21, 0x58, 0x49, 0x2d, 0x58, 0xad};
        GUID *scheme;
        PowerGetActiveScheme(NULL, &scheme);
        PowerWriteACValueIndex(NULL, scheme, &GUID_PROCESSOR_SETTINGS_SUBGROUP, &processor_idle_disable_guid, bEnable ? 0 :  1);
        PowerSetActiveScheme(NULL, scheme);
    }
}
Dylan Cole
  • 396
  • 3
  • 8
  • Thanks for trying this. When I run it I see that the CPU will not enter C2 or the C3 state but it will enter the C1 state. I tried this on multiple XP systems (single core and multi core) and I get the same results. It seems that I can't prevent the system from entering all C states on XP. On Win7 it seems that I can. – mash Mar 16 '12 at 15:57
  • I've sent you an email. It seems as if all C states can't be disabled on XP as they can on Windows 7. I've tried playing around with the AllowDemotion settings as well but that seems to have no effect. – mash Mar 16 '12 at 17:37