1
2
3
4
5 package main
6
7 import (
8 "flag"
9 "fmt"
10 "log"
11 "maps"
12 "os"
13 "os/exec"
14 "path/filepath"
15 "runtime"
16 "slices"
17 "strings"
18
19 "simd/archsimd/_gen/gentools"
20 )
21
22 var printFlag = flag.Bool("print", false, "Print reproduction steps without executing them")
23
24 var (
25 hostinfoDir string
26 goroot string
27 workDir string
28 )
29
30
31 func shellQuote(s string) string {
32 if s == "" {
33 return "''"
34 }
35 safe := true
36 for _, r := range s {
37 if !((r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') ||
38 r == '_' || r == '-' || r == '.' || r == '/' || r == '=' || r == ':' || r == ',') {
39 safe = false
40 break
41 }
42 }
43 if safe {
44 return s
45 }
46 return "'" + strings.ReplaceAll(s, "'", `'\''`) + "'"
47 }
48
49 func run(args ...string) {
50 if len(args) == 0 {
51 return
52 }
53 if *printFlag {
54 words := make([]string, len(args))
55 for i, a := range args {
56 words[i] = shellQuote(a)
57 }
58 fmt.Println(strings.Join(words, " "))
59 return
60 }
61
62 var env []string
63 for len(args) > 0 && strings.Contains(args[0], "=") {
64 env = append(env, args[0])
65 args = args[1:]
66 }
67 if len(args) == 0 {
68 return
69 }
70
71 c := exec.Command(args[0], args[1:]...)
72 if len(env) > 0 {
73 c.Env = append(os.Environ(), env...)
74 }
75 c.Stdin, c.Stdout, c.Stderr = os.Stdin, os.Stdout, os.Stderr
76 if err := c.Run(); err != nil {
77 log.Fatalf("%s failed: %v", args[0], err)
78 }
79 }
80
81 func compile(goos, goarch string) string {
82 bin := filepath.Join(workDir, fmt.Sprintf("hostinfo-%s-%s", goos, goarch))
83 run("GOOS="+goos, "GOARCH="+goarch, "GOEXPERIMENT=simd", "go", "build", "-C", hostinfoDir, "-o", bin, ".")
84 return bin
85 }
86
87 func runGomote(builder, goarch string) {
88 bin := compile("linux", goarch)
89 run("GOMOTE_GROUP=simd", "gomote", "create", builder)
90 run("gomote", "-group", "simd", "put", bin, "hostinfo")
91 run("gomote", "-group", "simd", "run", "./hostinfo", "-host", builder)
92 run("gomote", "-group", "simd", "destroy")
93 }
94
95 func runQEMUarm64(name, cpu string) {
96 bin := compile("linux", "arm64")
97 run("qemu-aarch64", "-cpu", cpu, bin, "-host", name)
98 }
99
100 var hosts = map[string]func(){
101 "local": func() {
102 run("GOEXPERIMENT=simd", "go", "run", "-C", hostinfoDir, ".", "-host", "local")
103 },
104 "gotip-linux-amd64_avx512": func() {
105 runGomote("gotip-linux-amd64_avx512", "amd64")
106 },
107 "gotip-linux-amd64": func() {
108 runGomote("gotip-linux-amd64", "amd64")
109 },
110 "gotip-linux-arm64": func() {
111 runGomote("gotip-linux-arm64", "arm64")
112 },
113 "qemu-aarch64-neon": func() {
114 runQEMUarm64("qemu-aarch64-neon", "neoverse-n1")
115 },
116 "qemu-aarch64-sve128": func() {
117 runQEMUarm64("qemu-aarch64-sve128", "neoverse-n2")
118 },
119 "qemu-aarch64-sve256": func() {
120 runQEMUarm64("qemu-aarch64-sve256", "neoverse-v1")
121 },
122 "wasip1-wasmtime": func() {
123 bin := compile("wasip1", "wasm")
124 run("wasmtime", "run", bin, "-host", "wasip1-wasmtime")
125 },
126 "wasip1-wazero": func() {
127 bin := compile("wasip1", "wasm")
128 run("wazero", "run", bin, "-host", "wasip1-wazero")
129 },
130 "js-node": func() {
131 bin := compile("js", "wasm")
132 run("node", filepath.Join(goroot, "lib/wasm/wasm_exec_node.js"), bin, "-host", "js-node")
133 },
134 }
135
136 func usage() {
137 fmt.Printf("Usage: gather [-print] <all | host ...>\n\n")
138 fmt.Println("Known pseudo-hosts:")
139 fmt.Println(" - all (all known pseudo-hosts; must appear alone)")
140 for _, host := range slices.Sorted(maps.Keys(hosts)) {
141 fmt.Printf(" - %s\n", host)
142 }
143 fmt.Println("\nFlags:")
144 flag.PrintDefaults()
145 }
146
147 func main() {
148 flag.Usage = func() {
149 usage()
150 os.Exit(0)
151 }
152 flag.Parse()
153
154 args := flag.Args()
155 if len(args) == 0 {
156 usage()
157 os.Exit(1)
158 }
159
160 var targets []string
161 if args[0] == "all" {
162 if len(args) > 1 {
163 fmt.Fprintln(os.Stderr, "Error: 'all' must appear alone")
164 os.Exit(1)
165 }
166 targets = slices.Sorted(maps.Keys(hosts))
167 } else {
168 for _, arg := range args {
169 if arg == "all" {
170 fmt.Fprintln(os.Stderr, "Error: 'all' must appear alone")
171 os.Exit(1)
172 }
173 if _, ok := hosts[arg]; !ok {
174 fmt.Fprintf(os.Stderr, "Unknown host: %s\n\n", arg)
175 usage()
176 os.Exit(1)
177 }
178 targets = append(targets, arg)
179 }
180 }
181
182 _, filename, _, ok := runtime.Caller(0)
183 if !ok {
184 log.Fatal("cannot determine script directory")
185 }
186 gatherDir := filepath.Dir(filename)
187 hostinfoDir = filepath.Dir(gatherDir)
188 goroot = gentools.DefaultGOROOT()
189
190 if *printFlag {
191 workDir = "/tmp"
192 } else {
193 var err error
194 workDir, err = os.MkdirTemp("", "hostinfo-*")
195 if err != nil {
196 log.Fatal(err)
197 }
198 defer os.RemoveAll(workDir)
199 }
200
201 for i, target := range targets {
202 if i > 0 {
203 fmt.Println()
204 }
205 hosts[target]()
206 }
207 }
208
View as plain text