svn commit: r326383 - head/sys/x86/cpufreq

Jung-uk Kim jkim at FreeBSD.org
Thu Nov 30 19:21:40 UTC 2017


On 11/30/2017 13:57, Conrad Meyer wrote:
> Hi Jung-uk,
> 
> I have some questions about this change.
> 
> On Wed, Nov 29, 2017 at 5:40 PM, Jung-uk Kim <jkim at freebsd.org> wrote:
>> Author: jkim
>> Date: Thu Nov 30 01:40:07 2017
>> New Revision: 326383
>> URL: https://svnweb.freebsd.org/changeset/base/326383
>>
>> Log:
>>   Add a tunable "debug.hwpstate_verify" to check P-state after changing it and
>>   turn it off by default.  It is very inefficient to verify current P-state of
>>   each core, especially for CPUs with many cores.  When multiple commands are
>>   requested to the same power domain before completion of pending transitions,
>>   the last command is executed according to the manual.  Because requests are
>>   serialized by the caller, all cores will receive the same command for each
>>   call.  Do not call sched_bind() and sched_unbind().  It is redundant because
>>   the caller does it anyway.
>> ...
>> @@ -176,47 +178,57 @@ hwpstate_goto_pstate(device_t dev, int pstate)
>>         if (limit > id)
>>                 id = limit;
>>
> 
> Should we bind the thread and record PCPU_GET() here?
> 
>> +       HWPSTATE_DEBUG(dev, "setting P%d-state on cpu%d\n", id,
>> +           PCPU_GET(cpuid));
>> +       /* Go To Px-state */
>> +       wrmsr(MSR_AMD_10H_11H_CONTROL, id);
>> +
>>         /*
>>          * We are going to the same Px-state on all cpus.
>>          * Probably should take _PSD into account.
>>          */
>> -       error = 0;
>>         CPU_FOREACH(i) {
>> +               if (i == PCPU_GET(cpuid))
> 
> It seems like this check could evaluate to a different CPU every time?
>  When really we are trying to avoid setting on the CPU we set on
> initially above?
> 
>> +                       continue;
>> +
>>                 /* Bind to each cpu. */
>>                 thread_lock(curthread);
>>                 sched_bind(curthread, i);
>>                 thread_unlock(curthread);
>> -               HWPSTATE_DEBUG(dev, "setting P%d-state on cpu%d\n",
>> -                   id, PCPU_GET(cpuid));
>> +               HWPSTATE_DEBUG(dev, "setting P%d-state on cpu%d\n", id, i);
>>                 /* Go To Px-state */
>>                 wrmsr(MSR_AMD_10H_11H_CONTROL, id);
>>         }
>> -       CPU_FOREACH(i) {
>> -               /* Bind to each cpu. */
>> -               thread_lock(curthread);
>> -               sched_bind(curthread, i);
>> -               thread_unlock(curthread);
>> -               /* wait loop (100*100 usec is enough ?) */
>> -               for (j = 0; j < 100; j++) {
>> -                       /* get the result. not assure msr=id */
>> -                       msr = rdmsr(MSR_AMD_10H_11H_STATUS);
>> -                       if (msr == id)
>> -                               break;
>> -                       sbt = SBT_1MS / 10;
>> -                       tsleep_sbt(dev, PZERO, "pstate_goto", sbt,
>> -                           sbt >> tc_precexp, 0);
>> +
>> +       /*
>> +        * Verify whether each core is in the requested P-state.
>> +        */
>> +       if (hwpstate_verify) {
>> +               CPU_FOREACH(i) {
>> +                       thread_lock(curthread);
>> +                       sched_bind(curthread, i);
>> +                       thread_unlock(curthread);
>> +                       /* wait loop (100*100 usec is enough ?) */
>> +                       for (j = 0; j < 100; j++) {
>> +                               /* get the result. not assure msr=id */
>> +                               msr = rdmsr(MSR_AMD_10H_11H_STATUS);
>> +                               if (msr == id)
>> +                                       break;
>> +                               sbt = SBT_1MS / 10;
>> +                               tsleep_sbt(dev, PZERO, "pstate_goto", sbt,
>> +                                   sbt >> tc_precexp, 0);
>> +                       }
>> +                       HWPSTATE_DEBUG(dev, "result: P%d-state on cpu%d\n",
>> +                           (int)msr, i);
>> +                       if (msr != id) {
>> +                               HWPSTATE_DEBUG(dev,
>> +                                   "error: loop is not enough.\n");
> 
> In this error return, should the current thread be unbinded?  The old
> code did this by setting error and falling through to the ordinary
> exit path.  We could use 'goto out;' to avoid looping through the rest
> of the CPUs.
> 
>> +                               return (ENXIO);
>> +                       }
>>                 }
>> -               HWPSTATE_DEBUG(dev, "result: P%d-state on cpu%d\n",
>> -                   (int)msr, PCPU_GET(cpuid));
>> -               if (msr != id) {
>> -                       HWPSTATE_DEBUG(dev, "error: loop is not enough.\n");
>> -                       error = ENXIO;
>> -               }
>>         }
>> -       thread_lock(curthread);
>> -       sched_unbind(curthread);
>> -       thread_unlock(curthread);
>> -       return (error);
>> +
>> +       return (0);
>>  }
>>
>>  static int
>>

This driver is only called via cpufreq(4) (i.e., sys/kern/kern_cpu.c),
and sched_bind()/sched_unbind() is done from cf_set_method() for cpu0.
If you want to see the sequence, try "sysctl debug.cpufreq.verbose=1"
and "sysctl debug.hwpstate_verbose=1".

Jung-uk Kim

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://lists.freebsd.org/pipermail/svn-src-all/attachments/20171130/27ab9057/attachment.sig>


More information about the svn-src-all mailing list