diff mbox series

[bug#53895,2/5] gnu: cpu: Add detection for AMD CPUs.

Message ID ea1c58ab259264fce6e09026fc1afef83e04544e.1644401681.git.efraim@flashner.co.il
State Accepted
Headers show
Series More CPU detection | expand

Checks

Context Check Description
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job
cbaines/issue success View issue

Commit Message

Efraim Flashner Feb. 9, 2022, 10:21 a.m. UTC
* guix/cpu.scm <cpu>: Add vendor field.
(current-cpu): Also fill in the 'vendor' field.
(cpu->gcc-architecture): Add detection logic for AMD CPUs.
---
 guix/cpu.scm | 60 ++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 51 insertions(+), 9 deletions(-)

Comments

Efraim Flashner Feb. 9, 2022, 10:54 a.m. UTC | #1
On Wed, Feb 09, 2022 at 11:43:21AM +0100, Ludovic Courtès wrote:
> Efraim Flashner <efraim@flashner.co.il> skribis:
> 
> > * guix/cpu.scm <cpu>: Add vendor field.
> > (current-cpu): Also fill in the 'vendor' field.
> > (cpu->gcc-architecture): Add detection logic for AMD CPUs.
> 
> [...]
> 
> > +         (and (equal? "AuthenticAMD" (cpu-vendor cpu))
> 
> Isn’t that equivalent to (= (cpu-family cpu) some-value)?

It looks to me like 'family' started as the prefix for iX86, so Intel is
mostly using family 6, except when a couple of other processors slip in.
I wasn't able to find a hard and fast rule for what family AMD typically
uses, on my machine its 23. In driver-i386.c it's sort by vendor first:
if (vendor == VENDOR_AMD)

> > +              (letrec-syntax ((if-flags (syntax-rules (=>)
> > +                                          ((_)
> > +                                           #f)
> > +                                          ((_ (flags ... => name) rest ...)
> > +                                           (if (every (lambda (flag)
> > +                                                        (set-contains? (cpu-flags cpu)
> > +                                                                       flag))
> > +                                                      '(flags ...))
> > +                                             name
> > +                                             (if-flags rest ...))))))
> > +
> > +                (when (= 22 (cpu-family cpu))
> > +                  (if-flags ("movbe" => "btver2")))
> > +                (when (= 6 (cpu-family cpu))
> > +                  (if-flags ("3dnowp" => "athalon")))
> 
> This has no effect (because ‘if-flags’ returns a value that is ignored
> since it’s not returned.)
> 
> What we could do is extend ‘if-flags’ so that it can optionally check
> for a family number:
> 
>   (if-flags ((family 22) "movbe" => "btver2")
>              …)

That sounds like a good idea.

> > +                (if-flags ("vaes" => "znver3")
> > +                          ("clwb" => "znver2")
> > +                          ("clzero" => "znver1")
> 
> However, the code in driver-i386.c seems to look at model IDs (the big
> “switch (processor)” thing) and not feature flags.  Or am I overlooking
> something?

switch (processor) comes after all the AMD chips are sorted. It looks
like all of Intel's i686 and x86_64 are PROCESSOR_PENTIUMPRO, while AMD
has a separate processor per chip design. The AMD chips are sorted about
90 lines above the switch (processor) line

> Thanks,
> Ludo’.
Efraim Flashner Feb. 9, 2022, 11:41 a.m. UTC | #2
On Wed, Feb 09, 2022 at 11:43:21AM +0100, Ludovic Courtès wrote:
> Efraim Flashner <efraim@flashner.co.il> skribis:
> 
> > +              (letrec-syntax ((if-flags (syntax-rules (=>)
> > +                                          ((_)
> > +                                           #f)
> > +                                          ((_ (flags ... => name) rest ...)
> > +                                           (if (every (lambda (flag)
> > +                                                        (set-contains? (cpu-flags cpu)
> > +                                                                       flag))
> > +                                                      '(flags ...))
> > +                                             name
> > +                                             (if-flags rest ...))))))
> > +
> > +                (when (= 22 (cpu-family cpu))
> > +                  (if-flags ("movbe" => "btver2")))
> > +                (when (= 6 (cpu-family cpu))
> > +                  (if-flags ("3dnowp" => "athalon")))
> 
> This has no effect (because ‘if-flags’ returns a value that is ignored
> since it’s not returned.)
> 
> What we could do is extend ‘if-flags’ so that it can optionally check
> for a family number:
> 
>   (if-flags ((family 22) "movbe" => "btver2")
>              …)

Another option would be to just move it to the bottom of the if-flags so
it should take effect then.
Ludovic Courtès Feb. 10, 2022, 8:42 p.m. UTC | #3
Efraim Flashner <efraim@flashner.co.il> skribis:

>> What we could do is extend ‘if-flags’ so that it can optionally check
>> for a family number:
>> 
>>   (if-flags ((family 22) "movbe" => "btver2")
>>              …)
>
> Another option would be to just move it to the bottom of the if-flags so
> it should take effect then.

Yes, your call!

Ludo’.
Efraim Flashner Feb. 13, 2022, 1:04 p.m. UTC | #4
On Thu, Feb 10, 2022 at 09:42:44PM +0100, Ludovic Courtès wrote:
> Efraim Flashner <efraim@flashner.co.il> skribis:
> 
> >> What we could do is extend ‘if-flags’ so that it can optionally check
> >> for a family number:
> >> 
> >>   (if-flags ((family 22) "movbe" => "btver2")
> >>              …)
> >
> > Another option would be to just move it to the bottom of the if-flags so
> > it should take effect then.
> 
> Yes, your call!

Just moving it to the end didn't end up being enough to make it work, my
processor was determined to be <unspecified>. I changed it to an 'or'
which seemed to make it work, and my testing seemed to show that it
would work (alternating substituting junk and my processor flags to make
it obviously one or the other).

Thanks for the review and the feedback. And for doing the work in the
first place!
diff mbox series

Patch

diff --git a/guix/cpu.scm b/guix/cpu.scm
index 5bb3fa9d2f..6d44599822 100644
--- a/guix/cpu.scm
+++ b/guix/cpu.scm
@@ -27,6 +27,7 @@  (define-module (guix cpu)
   #:export (current-cpu
             cpu?
             cpu-architecture
+            cpu-vendor
             cpu-family
             cpu-model
             cpu-flags
@@ -42,9 +43,10 @@  (define-module (guix cpu)
 
 ;; CPU description.
 (define-record-type <cpu>
-  (cpu architecture family model flags)
+  (cpu architecture vendor family model flags)
   cpu?
   (architecture cpu-architecture)                 ;string, from 'uname'
+  (vendor       cpu-vendor)                       ;string
   (family       cpu-family)                       ;integer
   (model        cpu-model)                        ;integer
   (flags        cpu-flags))                       ;set of strings
@@ -58,28 +60,33 @@  (define (prefix? prefix)
 
     (call-with-input-file "/proc/cpuinfo"
       (lambda (port)
-        (let loop ((family #f)
+        (let loop ((vendor #f)
+                   (family #f)
                    (model #f))
           (match (read-line port)
             ((? eof-object?)
              #f)
+            ((? (prefix? "vendor_id") str)
+             (match (string-tokenize str)
+               (("vendor_id" ":" vendor)
+                (loop vendor family model))))
             ((? (prefix? "cpu family") str)
              (match (string-tokenize str)
                (("cpu" "family" ":" family)
-                (loop (string->number family) model))))
+                (loop vendor (string->number family) model))))
             ((? (prefix? "model") str)
              (match (string-tokenize str)
                (("model" ":" model)
-                (loop family (string->number model)))
+                (loop vendor family (string->number model)))
                (_
-                (loop family model))))
+                (loop vendor family model))))
             ((? (prefix? "flags") str)
              (match (string-tokenize str)
                (("flags" ":" flags ...)
                 (cpu (utsname:machine (uname))
-                     family model (list->set flags)))))
+                     vendor family model (list->set flags)))))
             (_
-             (loop family model))))))))
+             (loop vendor family model))))))))
 
 (define (cpu->gcc-architecture cpu)
   "Return the architecture name, suitable for GCC's '-march' flag, that
@@ -87,7 +94,8 @@  (define (cpu->gcc-architecture cpu)
   (match (cpu-architecture cpu)
     ("x86_64"
      ;; Transcribed from GCC's 'host_detect_local_cpu' in driver-i386.c.
-     (or (and (= 6 (cpu-family cpu))              ;the "Pentium Pro" family
+     (or (and (equal? "GenuineIntel" (cpu-vendor cpu))
+              (= 6 (cpu-family cpu))              ;the "Pentium Pro" family
               (letrec-syntax ((if-flags (syntax-rules (=>)
                                           ((_)
                                            #f)
@@ -122,6 +130,40 @@  (define (cpu->gcc-architecture cpu)
                           ("ssse3" => "core2")
                           ("longmode" => "x86-64"))))
 
+         (and (equal? "AuthenticAMD" (cpu-vendor cpu))
+              (letrec-syntax ((if-flags (syntax-rules (=>)
+                                          ((_)
+                                           #f)
+                                          ((_ (flags ... => name) rest ...)
+                                           (if (every (lambda (flag)
+                                                        (set-contains? (cpu-flags cpu)
+                                                                       flag))
+                                                      '(flags ...))
+                                             name
+                                             (if-flags rest ...))))))
+
+                (when (= 22 (cpu-family cpu))
+                  (if-flags ("movbe" => "btver2")))
+                (when (= 6 (cpu-family cpu))
+                  (if-flags ("3dnowp" => "athalon")))
+
+                (if-flags ("vaes" => "znver3")
+                          ("clwb" => "znver2")
+                          ("clzero" => "znver1")
+                          ("avx2" => "bdver4")
+                          ("xsaveopt" => "bdver3")
+                          ("bmi" => "bdver2")
+                          ("xop" => "bdver1")
+                          ("sse4a" "has_ssse3" => "btver1")
+                          ("sse4a" => "amdfam10")
+                          ("sse2" "sse3" => "k8-sse3")
+                          ("longmode" "sse3" => "k8-sse3")
+                          ("sse2" => "k8")
+                          ("longmode" => "k8")
+                          ("mmx" "3dnow" => "k6-3")
+                          ("mmx" => "k6")
+                          (_ => "pentium"))))
+
          ;; Fallback case for non-Intel processors or for Intel processors not
          ;; recognized above.
          (letrec-syntax ((if-flags (syntax-rules (=>)
@@ -147,7 +189,7 @@  (define (cpu->gcc-architecture cpu)
                      ("ssse3" "movbe" => "bonnell")
                      ("ssse3" => "core2")))
 
-         ;; TODO: Recognize AMD models (bdver*, znver*, etc.)?
+         ;; TODO: Recognize CENTAUR/CYRIX/NSC?
 
          "x86_64"))
     (architecture