cpu.scm 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2022 Efraim Flashner <efraim@flashner.co.il>
  4. ;;;
  5. ;;; This file is part of GNU Guix.
  6. ;;;
  7. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  8. ;;; under the terms of the GNU General Public License as published by
  9. ;;; the Free Software Foundation; either version 3 of the License, or (at
  10. ;;; your option) any later version.
  11. ;;;
  12. ;;; GNU Guix is distributed in the hope that it will be useful, but
  13. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;;; GNU General Public License for more details.
  16. ;;;
  17. ;;; You should have received a copy of the GNU General Public License
  18. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  19. (define-module (guix cpu)
  20. #:use-module (guix sets)
  21. #:use-module (guix memoization)
  22. #:use-module (srfi srfi-1)
  23. #:use-module (srfi srfi-9)
  24. #:use-module (ice-9 match)
  25. #:use-module (ice-9 rdelim)
  26. #:export (current-cpu
  27. cpu?
  28. cpu-architecture
  29. cpu-vendor
  30. cpu-family
  31. cpu-model
  32. cpu-flags
  33. cpu->gcc-architecture))
  34. ;;; Commentary:
  35. ;;;
  36. ;;; This module provides tools to determine the micro-architecture supported
  37. ;;; by the CPU and to map it to a name known to GCC's '-march'.
  38. ;;;
  39. ;;; Code:
  40. ;; CPU description.
  41. (define-record-type <cpu>
  42. (cpu architecture vendor family model flags)
  43. cpu?
  44. (architecture cpu-architecture) ;string, from 'uname'
  45. (vendor cpu-vendor) ;string
  46. (family cpu-family) ;integer
  47. (model cpu-model) ;integer
  48. (flags cpu-flags)) ;set of strings
  49. (define current-cpu
  50. (mlambda ()
  51. "Return a <cpu> record representing the host CPU."
  52. (define (prefix? prefix)
  53. (lambda (str)
  54. (string-prefix? prefix str)))
  55. (call-with-input-file "/proc/cpuinfo"
  56. (lambda (port)
  57. (let loop ((vendor #f)
  58. (family #f)
  59. (model #f))
  60. (match (read-line port)
  61. ((? eof-object?)
  62. #f)
  63. ((? (prefix? "vendor_id") str)
  64. (match (string-tokenize str)
  65. (("vendor_id" ":" vendor)
  66. (loop vendor family model))))
  67. ((? (prefix? "cpu family") str)
  68. (match (string-tokenize str)
  69. (("cpu" "family" ":" family)
  70. (loop vendor (string->number family) model))))
  71. ((? (prefix? "model") str)
  72. (match (string-tokenize str)
  73. (("model" ":" model)
  74. (loop vendor family (string->number model)))
  75. (_
  76. (loop vendor family model))))
  77. ((? (prefix? "flags") str)
  78. (match (string-tokenize str)
  79. (("flags" ":" flags ...)
  80. (cpu (utsname:machine (uname))
  81. vendor family model (list->set flags)))))
  82. (_
  83. (loop vendor family model))))))))
  84. (define (cpu->gcc-architecture cpu)
  85. "Return the architecture name, suitable for GCC's '-march' flag, that
  86. corresponds to CPU, a record as returned by 'current-cpu'."
  87. (match (cpu-architecture cpu)
  88. ("x86_64"
  89. ;; Transcribed from GCC's 'host_detect_local_cpu' in driver-i386.c.
  90. (or (and (equal? "GenuineIntel" (cpu-vendor cpu))
  91. (= 6 (cpu-family cpu)) ;the "Pentium Pro" family
  92. (letrec-syntax ((if-flags (syntax-rules (=>)
  93. ((_)
  94. #f)
  95. ((_ (flags ... => name) rest ...)
  96. (if (every (lambda (flag)
  97. (set-contains? (cpu-flags cpu)
  98. flag))
  99. '(flags ...))
  100. name
  101. (if-flags rest ...))))))
  102. (if-flags ("avx" "avx512vp2intersect" "tsxldtrk" => "sapphirerapids")
  103. ("avx" "avx512vp2intersect" => "tigerlake")
  104. ("avx" "avx512bf16" => "cooperlake")
  105. ("avx" "wbnoinvd" => "icelake-server")
  106. ("avx" "avx512bitalg" => "icelake-client")
  107. ("avx" "avx512vbmi" => "cannonlake")
  108. ("avx" "avx5124vnniw" => "knm")
  109. ("avx" "avx512er" => "knl")
  110. ("avx" "avx512f" => "skylake-avx512")
  111. ("avx" "serialize" => "alderlake")
  112. ("avx" "clflushopt" => "skylake")
  113. ("avx" "adx" => "broadwell")
  114. ("avx" "avx2" => "haswell")
  115. ("avx" => "sandybridge")
  116. ("sse4_2" "gfni" => "tremont")
  117. ("sse4_2" "sgx" => "goldmont-plus")
  118. ("sse4_2" "xsave" => "goldmont")
  119. ("sse4_2" "movbe" => "silvermont")
  120. ("sse4_2" => "nehalem")
  121. ("ssse3" "movbe" => "bonnell")
  122. ("ssse3" => "core2")
  123. ("longmode" => "x86-64"))))
  124. (and (equal? "AuthenticAMD" (cpu-vendor cpu))
  125. (letrec-syntax ((if-flags (syntax-rules (=>)
  126. ((_)
  127. #f)
  128. ((_ (flags ... => name) rest ...)
  129. (if (every (lambda (flag)
  130. (set-contains? (cpu-flags cpu)
  131. flag))
  132. '(flags ...))
  133. name
  134. (if-flags rest ...))))))
  135. (or (and (= 22 (cpu-family cpu))
  136. (if-flags ("movbe" => "btver2")))
  137. (and (= 6 (cpu-family cpu))
  138. (if-flags ("3dnowp" => "athalon")))
  139. (if-flags ("vaes" => "znver3")
  140. ("clwb" => "znver2")
  141. ("clzero" => "znver1")
  142. ("avx2" => "bdver4")
  143. ("xsaveopt" => "bdver3")
  144. ("bmi" => "bdver2")
  145. ("xop" => "bdver1")
  146. ("sse4a" "has_ssse3" => "btver1")
  147. ("sse4a" => "amdfam10")
  148. ("sse2" "sse3" => "k8-sse3")
  149. ("longmode" "sse3" => "k8-sse3")
  150. ("sse2" => "k8")
  151. ("longmode" => "k8")
  152. ("mmx" "3dnow" => "k6-3")
  153. ("mmx" => "k6")
  154. (_ => "pentium")))))
  155. ;; Fallback case for non-Intel processors or for Intel processors not
  156. ;; recognized above.
  157. (letrec-syntax ((if-flags (syntax-rules (=>)
  158. ((_)
  159. #f)
  160. ((_ (flags ... => name) rest ...)
  161. (if (every (lambda (flag)
  162. (set-contains? (cpu-flags cpu)
  163. flag))
  164. '(flags ...))
  165. name
  166. (if-flags rest ...))))))
  167. (if-flags ("avx512" => "knl")
  168. ("adx" => "broadwell")
  169. ("avx2" => "haswell")
  170. ;; TODO: tigerlake, cooperlake, etc.
  171. ("avx" => "sandybridge")
  172. ("sse4_2" "gfni" => "tremont")
  173. ("sse4_2" "sgx" => "goldmont-plus")
  174. ("sse4_2" "xsave" => "goldmont")
  175. ("sse4_2" "movbe" => "silvermont")
  176. ("sse4_2" => "nehalem")
  177. ("ssse3" "movbe" => "bonnell")
  178. ("ssse3" => "core2")))
  179. ;; TODO: Recognize CENTAUR/CYRIX/NSC?
  180. "x86_64"))
  181. (architecture
  182. ;; TODO: AArch64.
  183. architecture)))