github.com/likebike/go--@v0.0.0-20190911215757-0bd925d16e96/go/src/runtime/testdata/testprog/numcpu_freebsd.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bytes" 9 "fmt" 10 "os" 11 "os/exec" 12 "runtime" 13 "strconv" 14 "strings" 15 "syscall" 16 ) 17 18 func init() { 19 register("FreeBSDNumCPU", FreeBSDNumCPU) 20 register("FreeBSDNumCPUHelper", FreeBSDNumCPUHelper) 21 } 22 23 func FreeBSDNumCPUHelper() { 24 fmt.Printf("%d\n", runtime.NumCPU()) 25 } 26 27 func FreeBSDNumCPU() { 28 _, err := exec.LookPath("cpuset") 29 if err != nil { 30 // Can not test without cpuset command. 31 fmt.Println("OK") 32 return 33 } 34 _, err = exec.LookPath("sysctl") 35 if err != nil { 36 // Can not test without sysctl command. 37 fmt.Println("OK") 38 return 39 } 40 cmd := exec.Command("sysctl", "-n", "kern.smp.active") 41 output, err := cmd.CombinedOutput() 42 if err != nil { 43 fmt.Printf("fail to launch '%s', error: %s, output: %s\n", strings.Join(cmd.Args, " "), err, output) 44 return 45 } 46 if bytes.Equal(output, []byte("1\n")) == false { 47 // SMP mode deactivated in kernel. 48 fmt.Println("OK") 49 return 50 } 51 52 list, err := getList() 53 if err != nil { 54 fmt.Printf("%s\n", err) 55 return 56 } 57 err = checkNCPU(list) 58 if err != nil { 59 fmt.Printf("%s\n", err) 60 return 61 } 62 if len(list) >= 2 { 63 err = checkNCPU(list[:len(list)-1]) 64 if err != nil { 65 fmt.Printf("%s\n", err) 66 return 67 } 68 } 69 fmt.Println("OK") 70 return 71 } 72 73 func getList() ([]string, error) { 74 pid := syscall.Getpid() 75 76 // Launch cpuset to print a list of available CPUs: pid <PID> mask: 0, 1, 2, 3. 77 cmd := exec.Command("cpuset", "-g", "-p", strconv.Itoa(pid)) 78 cmdline := strings.Join(cmd.Args, " ") 79 output, err := cmd.CombinedOutput() 80 if err != nil { 81 return nil, fmt.Errorf("fail to execute '%s': %s", cmdline, err) 82 } 83 pos := bytes.IndexRune(output, ':') 84 if pos == -1 { 85 return nil, fmt.Errorf("invalid output from '%s', ':' not found: %s", cmdline, output) 86 } 87 88 var list []string 89 for _, val := range bytes.Split(output[pos+1:], []byte(",")) { 90 index := string(bytes.TrimSpace(val)) 91 if len(index) == 0 { 92 continue 93 } 94 list = append(list, index) 95 } 96 if len(list) == 0 { 97 return nil, fmt.Errorf("empty CPU list from '%s': %s", cmdline, output) 98 } 99 return list, nil 100 } 101 102 func checkNCPU(list []string) error { 103 listString := strings.Join(list, ",") 104 if len(listString) == 0 { 105 return fmt.Errorf("could not check against an empty CPU list") 106 } 107 108 // Launch FreeBSDNumCPUHelper() with specified CPUs list. 109 cmd := exec.Command("cpuset", "-l", listString, os.Args[0], "FreeBSDNumCPUHelper") 110 cmdline := strings.Join(cmd.Args, " ") 111 output, err := cmd.CombinedOutput() 112 if err != nil { 113 return fmt.Errorf("fail to launch child '%s', error: %s, output: %s", cmdline, err, output) 114 } 115 116 // NumCPU from FreeBSDNumCPUHelper come with '\n'. 117 output = bytes.TrimSpace(output) 118 n, err := strconv.Atoi(string(output)) 119 if err != nil { 120 return fmt.Errorf("fail to parse output from child '%s', error: %s, output: %s", cmdline, err, output) 121 } 122 if n != len(list) { 123 return fmt.Errorf("runtime.NumCPU() expected to %d, got %d when run with CPU list %s", len(list), n, listString) 124 } 125 return nil 126 }