github.com/sealerio/sealer@v0.11.1-0.20240507115618-f4f89c5853ae/utils/platform/cpu.go (about)

     1  // Copyright © 2022 Alibaba Group Holding Ltd.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package platform
    16  
    17  import (
    18  	"bufio"
    19  	"os"
    20  	"runtime"
    21  	"strings"
    22  	"sync"
    23  
    24  	"github.com/pkg/errors"
    25  	"github.com/sirupsen/logrus"
    26  )
    27  
    28  const (
    29  	ARM     = "arm"
    30  	ARM64   = "arm64"
    31  	AMD     = "amd64"
    32  	UNKNOWN = "unknown"
    33  	WINDOWS = "windows"
    34  	DARWIN  = "darwin"
    35  	LINUX   = "linux"
    36  )
    37  
    38  var (
    39  	cpuVariantValue string
    40  	cpuVariantOnce  sync.Once
    41  )
    42  
    43  func cpuVariant() string {
    44  	cpuVariantOnce.Do(func() {
    45  		if isArmArch(runtime.GOARCH) {
    46  			variant, err := getCPUInfo("Cpu architecture")
    47  			if err != nil {
    48  				logrus.Error(err)
    49  			}
    50  			model, err := getCPUInfo("model name")
    51  			if err != nil && !strings.Contains(err.Error(), ErrNotFound.Error()) {
    52  				logrus.Error(err)
    53  			}
    54  			cpuVariantValue = GetCPUVariantByInfo(runtime.GOOS, runtime.GOARCH, variant, model)
    55  		}
    56  	})
    57  	return cpuVariantValue
    58  }
    59  
    60  // For Linux, We can just parse this information from "/proc/cpuinfo"
    61  func getCPUInfo(pattern string) (info string, err error) {
    62  	if !isLinuxOS(runtime.GOOS) {
    63  		return "", errors.Wrapf(ErrNotImplemented, "getCPUInfo for OS %s", runtime.GOOS)
    64  	}
    65  
    66  	cpuinfo, err := os.Open("/proc/cpuinfo")
    67  	if err != nil {
    68  		return "", err
    69  	}
    70  	defer func() {
    71  		if err := cpuinfo.Close(); err != nil {
    72  			logrus.Errorf("failed to close file: %v", err)
    73  		}
    74  	}()
    75  
    76  	scanner := bufio.NewScanner(cpuinfo)
    77  	for scanner.Scan() {
    78  		newline := scanner.Text()
    79  		list := strings.Split(newline, ":")
    80  
    81  		if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
    82  			return strings.TrimSpace(list[1]), nil
    83  		}
    84  	}
    85  
    86  	// Check whether the scanner encountered errors
    87  	err = scanner.Err()
    88  	if err != nil {
    89  		return "", err
    90  	}
    91  
    92  	return "", errors.Wrapf(ErrNotFound, "getCPUInfo for pattern: %s", pattern)
    93  }
    94  
    95  // GetCPUVariantByInfo get 'Cpu architecture', 'model name' from /proc/cpuinfo
    96  func GetCPUVariantByInfo(os, arch, variant, model string) string {
    97  	if os == WINDOWS || os == DARWIN {
    98  		// Windows/Darwin only supports v7 for ARM32 and v8 for ARM64, and so we can use
    99  		// runtime.GOARCH to determine the variants
   100  		var variant string
   101  		switch arch {
   102  		case ARM64:
   103  			variant = "v8"
   104  		case ARM:
   105  			variant = "v7"
   106  		default:
   107  			variant = UNKNOWN
   108  		}
   109  
   110  		return variant
   111  	}
   112  
   113  	if arch == ARM && variant == "7" {
   114  		if strings.HasPrefix(strings.ToLower(model), "armv6-compatible") {
   115  			variant = "6"
   116  		}
   117  	}
   118  
   119  	switch strings.ToLower(variant) {
   120  	case "8", "aarch64":
   121  		variant = "v8"
   122  	case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
   123  		variant = "v7"
   124  	case "6", "6tej":
   125  		variant = "v6"
   126  	case "5", "5t", "5te", "5tej":
   127  		variant = "v5"
   128  	case "4", "4t":
   129  		variant = "v4"
   130  	case "3":
   131  		variant = "v3"
   132  	default:
   133  		variant = "unknown"
   134  	}
   135  
   136  	return variant
   137  }