github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/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/alibaba/sealer/logger"
    25  
    26  	"github.com/pkg/errors"
    27  )
    28  
    29  const (
    30  	ARM     = "arm"
    31  	ARM64   = "arm64"
    32  	AMD     = "amd64"
    33  	UNKNOWN = "unknown"
    34  	WINDOWS = "windows"
    35  	DARWIN  = "darwin"
    36  	LINUX   = "linux"
    37  )
    38  
    39  var (
    40  	cpuVariantValue string
    41  	cpuVariantOnce  sync.Once
    42  )
    43  
    44  func cpuVariant() string {
    45  	cpuVariantOnce.Do(func() {
    46  		if isArmArch(runtime.GOARCH) {
    47  			variant, err := getCPUInfo("Cpu architecture")
    48  			if err != nil {
    49  				logger.Error(err)
    50  			}
    51  			model, err := getCPUInfo("model name")
    52  			if !strings.Contains(err.Error(), ErrNotFound.Error()) {
    53  				logger.Error(err)
    54  			}
    55  			cpuVariantValue = GetCPUVariantByInfo(runtime.GOOS, runtime.GOARCH, variant, model)
    56  		}
    57  	})
    58  	return cpuVariantValue
    59  }
    60  
    61  // For Linux, We can just parse this information from "/proc/cpuinfo"
    62  func getCPUInfo(pattern string) (info string, err error) {
    63  	if !isLinuxOS(runtime.GOOS) {
    64  		return "", errors.Wrapf(ErrNotImplemented, "getCPUInfo for OS %s", runtime.GOOS)
    65  	}
    66  
    67  	cpuinfo, err := os.Open("/proc/cpuinfo")
    68  	if err != nil {
    69  		return "", err
    70  	}
    71  	defer func() {
    72  		if err := cpuinfo.Close(); err != nil {
    73  			logger.Error("failed to close file")
    74  		}
    75  	}()
    76  
    77  	scanner := bufio.NewScanner(cpuinfo)
    78  	for scanner.Scan() {
    79  		newline := scanner.Text()
    80  		list := strings.Split(newline, ":")
    81  
    82  		if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
    83  			return strings.TrimSpace(list[1]), nil
    84  		}
    85  	}
    86  
    87  	// Check whether the scanner encountered errors
    88  	err = scanner.Err()
    89  	if err != nil {
    90  		return "", err
    91  	}
    92  
    93  	return "", errors.Wrapf(ErrNotFound, "getCPUInfo for pattern: %s", pattern)
    94  }
    95  
    96  // GetCPUVariantByInfo get 'Cpu architecture', 'model name' from /proc/cpuinfo
    97  func GetCPUVariantByInfo(os, arch, variant, model string) string {
    98  	if os == WINDOWS || os == DARWIN {
    99  		// Windows/Darwin only supports v7 for ARM32 and v8 for ARM64, and so we can use
   100  		// runtime.GOARCH to determine the variants
   101  		var variant string
   102  		switch arch {
   103  		case ARM64:
   104  			variant = "v8"
   105  		case ARM:
   106  			variant = "v7"
   107  		default:
   108  			variant = UNKNOWN
   109  		}
   110  
   111  		return variant
   112  	}
   113  
   114  	if arch == ARM && variant == "7" {
   115  		if strings.HasPrefix(strings.ToLower(model), "armv6-compatible") {
   116  			variant = "6"
   117  		}
   118  	}
   119  
   120  	switch strings.ToLower(variant) {
   121  	case "8", "aarch64":
   122  		variant = "v8"
   123  	case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
   124  		variant = "v7"
   125  	case "6", "6tej":
   126  		variant = "v6"
   127  	case "5", "5t", "5te", "5tej":
   128  		variant = "v5"
   129  	case "4", "4t":
   130  		variant = "v4"
   131  	case "3":
   132  		variant = "v3"
   133  	default:
   134  		variant = "unknown"
   135  	}
   136  
   137  	return variant
   138  }