On Thu, Sep 14, 2017 at 03:41:25PM +0200, Reyk Floeter wrote:
> 
> On Fri, Aug 25, 2017 at 12:43:44PM +0200, Mike Belopuhov wrote:
> > On Fri, Aug 25, 2017 at 00:40 -0700, Mike Larkin wrote:
> > > On Thu, Aug 24, 2017 at 12:39:33PM +0800, Adam Steen wrote:
> > > > On Thu, Aug 24, 2017 at 2:35 AM, Mike Larkin <mlar...@azathoth.net> 
> > > > wrote:
> > > > > On Wed, Aug 23, 2017 at 09:29:15PM +0800, Adam Steen wrote:
> > > > >>
> > > > >> Thank you Mike on the feedback on the last patch, please see the diff
> > > > >> below, update with your input and style(9)
> > > > >>
> > > > >> I have continued to use tsc as my timecounter and /var/db/ntpd.driff
> > > > >> has stayed under 10.
> > > > >>
> > > > >> cat /var/db/ntpd.drift
> > > > >> 6.665
> > > > >>
> > > > >> ntpctl -s all
> > > > >> 4/4 peers valid, constraint offset -1s, clock synced, stratum 3
> > > > >>
> > > > >> peer
> > > > >>    wt tl st  next  poll          offset       delay      jitter
> > > > >> 144.48.166.166 from pool pool.ntp.org
> > > > >>     1 10  2    4s   32s        -3.159ms    87.723ms    10.389ms
> > > > >> 13.55.50.68 from pool pool.ntp.org
> > > > >>     1 10  3   11s   32s        -3.433ms    86.053ms    18.095ms
> > > > >> 14.202.204.182 from pool pool.ntp.org
> > > > >>     1 10  1   14s   32s         1.486ms    86.545ms    16.483ms
> > > > >> 27.124.125.250 from pool pool.ntp.org
> > > > >>  *  1 10  2   12s   30s       -10.275ms    54.156ms    70.389ms
> > > > >>
> > > > >> Cheers
> > > > >> Adam
> > > > >
> > > > > IIRC you have an x220, right?
> > > > >
> > > > > If so, could you try letting the clock run for a bit (while using tsc
> > > > > timecounter selection) after apm -L to drop the speed? (make sure
> > > > > apm shows that it dropped).
> > > > >
> > > > > Even though my x230 supposedly has a constant/invar TSC (according to
> > > > > cpuid), the TSC drops from 2.5GHz to 1.2GHz when apm -L runs, which
> > > > > causes time to run too slowly when tsc is selected there.
> > > > >
> > > > > -ml
> > > > >
> > > >
> > > > Yes, x220
> > > > (bios: LENOVO version "8DET69WW (1.39 )" date 07/18/2013)
> > > > (cpu: Intel(R) Core(TM) i5-2520M CPU @ 2.50GHz, 2491.91 MHz)
> > > >
> > > > I took some measurements to before starting the test.
> > > >
> > > > note: the laptop has been up for a few days with apm -A set via 
> > > > rc.conf.local
> > > > and sysctl kern.timecounter.hardware as tsc via sysctl.conf and mostly
> > > > idle.
> > > >
> > > > cat /var/db/ntpd.drift
> > > > 6.459
> > > >
> > > > apm -v
> > > > Battery state: high, 100% remaining, unknown life estimate
> > > > A/C adapter state: connected
> > > > Performance adjustment mode: auto (800 MHz)
> > > >
> > > > 6 hours ago i ran apm -L, verified it was running slowly (800 MHz),
> > > > and got the following results
> > > >
> > > > The clock appears correct (comparing to other computers)
> > > >
> > > > apm -v
> > > > Battery state: high, 100% remaining, unknown life estimate
> > > > A/C adapter state: connected
> > > > Performance adjustment mode: manual (800 MHz)
> > > >
> > > > cat /var/db/ntpd.drift
> > > > 6.385
> > > >
> > > > ntpctl -s all
> > > > 4/4 peers valid, constraint offset 0s, clock synced, stratum 4
> > > >
> > > > peer
> > > >    wt tl st  next  poll          offset       delay      jitter
> > > > 203.23.237.200 from pool pool.ntp.org
> > > >     1 10  2  153s 1505s       -25.546ms    73.450ms     2.644ms
> > > > 203.114.73.24 from pool pool.ntp.org
> > > >     1 10  2  253s 1560s        -1.042ms    75.133ms     0.752ms
> > > > 192.189.54.33 from pool pool.ntp.org
> > > >  *  1 10  2  204s 1558s        31.644ms    70.910ms     3.388ms
> > > > 54.252.165.245 from pool pool.ntp.org
> > > >     1 10  2  238s 1518s         0.146ms    73.005ms     2.025ms
> > > >
> > > > I will leave the laptop in lower power mode over the weekend and see
> > > > what happens.
> > > >
> > >
> > > No need, I think you've convinced me that it works :)
> > 
> > But does it actually work on x230 as well?  I'm surprised to learn
> > that you've observed TSC frequency change on Ivy Bridge.  I was
> > under impression that everything since at least Sandy Bridge (x220)
> > has constant and invariant TSC as advertised.
> > 
> > Adam, I've readjusted and simplified your diff a bit.  The biggest
> > change is that we can select the reference tc based on it's quality
> > so there's no need to have acpitimer and acpihpet specific functions
> > and variables.
> > 
> > There's one big thing missing here: increasing the timecounter
> > quality so that OS can pick it.  Something like this:
> > 
> > https://github.com/mbelop/src/commit/99d6ef3ae95bbd8ea93c27e0425eb65e5a3359a1
> > 
> > I'd say we should try getting this in after 6.3 unlock unless there
> > are objections.  Further cleanup and testing is welcome of course.
> > 
> > 
> 
> I'd like to raise another point: as we figured out, the TSC frequency
> can be different than the CPU frequency on modern Intel CPUs.  The
> const+invar TSC can even run faster than the CPU.
> 
> For example, my X1 4th Gen currently boots up with the following speeds:
> 
> cpu0: Intel(R) Core(TM) i7-6600U CPU @ 2.60GHz, 2808.00 MHz
> ...
> cpu0: Enhanced SpeedStep 2808 MHz: speeds: 2701, 2700, 2600, 2500, 2300, 
> 2100, 1900, 1800, 1600, 1400, 1300, 1100, 800, 700, 600, 400 MHz
> 
> The 2.8GHz is actually the TSC speed, the fastest CPU speed is 2.7GHz.
> 
> (I didn't figure out why ark.intel.com says max turbo speed is 3.4GHz,
> but the 2.7GHz is probably a vendor configuration from Lenovo based on
> the Laptop's cooling capabilities).

Turbo modes do not show as fixed clock speeds in p-states beyond
the 2701 in the above.  To find the current cpu speed when in turbo
mode requires looking at various msrs (MSR_TURBO_RATIO_LIMIT,
MSR_PLATFORM_INFO etc) and running a performance counter for a period
of time from memory.

> 
> But the MSR function returns a different value which is supposed to be
> the actual CPU speed (of core 0) after going out of power-saving mode.
> This caused problems on Skylake because the returned value can be very
> different to the TSC - using this value, the kernel failed to
> calibrated the TSC timecounter correctly.  That's why I added the code
> that reads the TSC frequency from CPUID 0x15 and skips the
> MSR/RDTSC-based calibration, if CPUID 0x15 is supported and present.
> 
> For example, without the CPUID method, I get the MSR-derived speed
> (depending on the on-boot power state that is configured in the BIOS):
> 
> cpu0: Intel(R) Core(TM) i7-6600U CPU @ 2.60GHz, 2494.75 MHz
> 
> But here is my mistake: I actually thought that the MSR function is
> "wrong" on Skylake.  But it is just a different thing.  We have to
> differentiate if we want to obtain the TSC or the CPU frequency, but
> the CPU frequency might just be derived from the TSC on older CPUs
> that don't support the MSR.
> 
> I attached a diff that illustrates the problem on the -current code,
> but the same could be adjusted for the TSC recalibration diff.
> 
> I split the cpu_tsc_freq() function into two functions:
> 
> 1. cpu_freq() tries to get the CPU frequency from the MSR, falls back
> to the TSC via cpu_tsc_freq().  This is used for cpuX dmesg printfs
> and for the global speedstep "cpuspeed" variable.
> 
> 2. cpu_tsc_freq() tries to get the TSC frequency from CPUID 0x15 or
> falls back to the less accurate rdtsc() method.  This is used for the
> (initial) TSC timecounter frequency.
> 
> Thoughts?
> 
> (I'm not asking for OKs on the diff)
> 
> Reyk
> 
> Index: sys/arch/amd64/amd64/identcpu.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/amd64/amd64/identcpu.c,v
> retrieving revision 1.87
> diff -u -p -u -p -r1.87 identcpu.c
> --- sys/arch/amd64/amd64/identcpu.c   20 Jun 2017 05:34:41 -0000      1.87
> +++ sys/arch/amd64/amd64/identcpu.c   14 Sep 2017 12:49:47 -0000
> @@ -47,8 +47,9 @@
>  #include <machine/cpufunc.h>
>  
>  void replacesmap(void);
> +u_int64_t cpu_freq(struct cpu_info *);
> +u_int64_t cpu_freq_ctr(struct cpu_info *);
>  u_int64_t cpu_tsc_freq(struct cpu_info *);
> -u_int64_t cpu_tsc_freq_ctr(struct cpu_info *);
>  #if NVMM > 0
>  void cpu_check_vmm_cap(struct cpu_info *);
>  #endif /* NVMM > 0 */
> @@ -388,12 +389,11 @@ via_update_sensor(void *args)
>  #endif
>  
>  u_int64_t
> -cpu_tsc_freq_ctr(struct cpu_info *ci)
> +cpu_freq_ctr(struct cpu_info *ci)
>  {
>       u_int64_t count, last_count, msr;
>  
>       if ((ci->ci_flags & CPUF_CONST_TSC) == 0 ||
> -         (ci->ci_flags & CPUF_INVAR_TSC) ||
>           (cpu_perf_eax & CPUIDEAX_VERID) <= 1 ||
>           CPUIDEDX_NUM_FC(cpu_perf_edx) <= 1)
>               return (0);
> @@ -426,6 +426,23 @@ cpu_tsc_freq_ctr(struct cpu_info *ci)
>  }
>  
>  u_int64_t
> +cpu_freq(struct cpu_info *ci)
> +{
> +     u_int64_t count;
> +
> +     /*
> +      * Try to get the currently running CPU frequency.  On modern CPUs,
> +      * this does not have to match the TSC frequency.
> +      */
> +     count = cpu_freq_ctr(ci);
> +     if (count != 0)
> +             return (count);
> +
> +     /* Fallback to the TSC frequency which was identical on old CPUs. */
> +     return (cpu_tsc_freq(ci));
> +}
> +
> +u_int64_t
>  cpu_tsc_freq(struct cpu_info *ci)
>  {
>       u_int64_t last_count, count;
> @@ -464,10 +481,6 @@ cpu_tsc_freq(struct cpu_info *ci)
>               }
>       }
>  
> -     count = cpu_tsc_freq_ctr(ci);
> -     if (count != 0)
> -             return (count);
> -
>       last_count = rdtsc();
>       delay(100000);
>       count = rdtsc();
> @@ -489,6 +502,7 @@ identifycpu(struct cpu_info *ci)
>       int i;
>       char *brandstr_from, *brandstr_to;
>       int skipspace;
> +     uint64_t freq;
>  
>       CPUID(1, ci->ci_signature, val, dummy, ci->ci_feature_flags);
>       CPUID(0x80000000, ci->ci_pnfeatset, dummy, dummy, dummy);
> @@ -568,18 +582,17 @@ identifycpu(struct cpu_info *ci)
>                       ci->ci_flags |= CPUF_INVAR_TSC;
>       }
>  
> -     ci->ci_tsc_freq = cpu_tsc_freq(ci);
> -
>       amd_cpu_cacheinfo(ci);
>  
>       printf("%s: %s", ci->ci_dev->dv_xname, mycpu_model);
>  
> -     if (ci->ci_tsc_freq != 0)
> -             printf(", %llu.%02llu MHz", (ci->ci_tsc_freq + 4999) / 1000000,
> -                 ((ci->ci_tsc_freq + 4999) / 10000) % 100);
> +     freq = cpu_freq(ci);
> +     if (freq != 0)
> +             printf(", %llu.%02llu MHz", (freq + 4999) / 1000000,
> +                 ((freq + 4999) / 10000) % 100);
>  
>       if (ci->ci_flags & CPUF_PRIMARY) {
> -             cpuspeed = (ci->ci_tsc_freq + 4999) / 1000000;
> +             cpuspeed = (freq + 4999) / 1000000;
>               cpu_cpuspeed = cpu_amd64speed;
>       }
>  
> @@ -726,10 +739,10 @@ identifycpu(struct cpu_info *ci)
>       if ((ci->ci_flags & CPUF_PRIMARY) &&
>           (ci->ci_flags & CPUF_CONST_TSC) &&
>           (ci->ci_flags & CPUF_INVAR_TSC)) {
> -             printf("%s: TSC frequency %llu Hz\n",
> -                 ci->ci_dev->dv_xname, ci->ci_tsc_freq);
> -             tsc_timecounter.tc_frequency = ci->ci_tsc_freq;
> +             tsc_timecounter.tc_frequency = cpu_tsc_freq(ci);
>               tc_init(&tsc_timecounter);
> +             printf("%s: TSC frequency %llu Hz\n",
> +                 ci->ci_dev->dv_xname, tsc_timecounter.tc_frequency);
>       }
>  
>       cpu_topology(ci);
> Index: sys/arch/amd64/include/cpu.h
> ===================================================================
> RCS file: /cvs/src/sys/arch/amd64/include/cpu.h,v
> retrieving revision 1.114
> diff -u -p -u -p -r1.114 cpu.h
> --- sys/arch/amd64/include/cpu.h      11 Aug 2017 20:19:14 -0000      1.114
> +++ sys/arch/amd64/include/cpu.h      14 Sep 2017 12:49:47 -0000
> @@ -138,7 +138,6 @@ struct cpu_info {
>       u_int32_t       ci_family;
>       u_int32_t       ci_model;
>       u_int32_t       ci_cflushsz;
> -     u_int64_t       ci_tsc_freq;
>  
>       int             ci_inatomic;
>  
> 

Reply via email to