)
 
 var (
-       canRun  = true  // whether we can run go or ./testgo
        canRace = false // whether we can run the race detector
        canCgo  = false // whether we can use cgo
        canMSan = false // whether we can run the memory sanitizer
-
-       exeSuffix string // ".exe" on Windows
-
-       skipExternal = false // skip external tests
 )
 
+var exeSuffix string = func() string {
+       if runtime.GOOS == "windows" {
+               return ".exe"
+       }
+       return ""
+}()
+
 func tooSlow(t *testing.T) {
        if testing.Short() {
                // In -short mode; skip test, except run it on the {darwin,linux,windows}/amd64 builders.
                if testenv.Builder() != "" && runtime.GOARCH == "amd64" && (runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows") {
                        return
                }
+               t.Helper()
                t.Skip("skipping test in -short mode")
        }
 }
 
-func init() {
-       switch runtime.GOOS {
-       case "android", "js":
-               canRun = false
-       case "darwin":
-               // nothing to do
-       case "ios":
-               canRun = false
-       case "linux":
-               switch runtime.GOARCH {
-               case "arm":
-                       // many linux/arm machines are too slow to run
-                       // the full set of external tests.
-                       skipExternal = true
-               case "mips", "mipsle", "mips64", "mips64le":
-                       // Also slow.
-                       skipExternal = true
-                       if testenv.Builder() != "" {
-                               // On the builders, skip the cmd/go
-                               // tests. They're too slow and already
-                               // covered by other ports. There's
-                               // nothing os/arch specific in the
-                               // tests.
-                               canRun = false
-                       }
-               }
-       case "freebsd":
-               switch runtime.GOARCH {
-               case "arm":
-                       // many freebsd/arm machines are too slow to run
-                       // the full set of external tests.
-                       skipExternal = true
-                       canRun = false
-               }
-       case "plan9":
-               switch runtime.GOARCH {
-               case "arm":
-                       // many plan9/arm machines are too slow to run
-                       // the full set of external tests.
-                       skipExternal = true
-               }
-       case "windows":
-               exeSuffix = ".exe"
-       }
-}
-
 // testGOROOT is the GOROOT to use when running testgo, a cmd/go binary
 // build from this process's current GOROOT, but run from a different
 // (temp) directory.
        }
 
        testGOCACHE = cache.DefaultDir()
-       if canRun {
+       if testenv.HasGoBuild() {
                testBin = filepath.Join(testTmpDir, "testbin")
                if err := os.Mkdir(testBin, 0777); err != nil {
                        log.Fatal(err)
                cmd.Stderr = new(strings.Builder)
                if out, err := cmd.Output(); err != nil {
                        fmt.Fprintf(os.Stderr, "running testgo failed: %v\n%s", err, cmd.Stderr)
-                       canRun = false
+                       os.Exit(2)
                } else {
                        canCgo, err = strconv.ParseBool(strings.TrimSpace(string(out)))
                        if err != nil {
 func testgo(t *testing.T) *testgoData {
        t.Helper()
        testenv.MustHaveGoBuild(t)
-
-       if skipExternal {
-               t.Skipf("skipping external tests on %s/%s", runtime.GOOS, runtime.GOARCH)
-       }
+       testenv.SkipIfShortAndSlow(t)
 
        return &testgoData{t: t}
 }
 // returning exit status.
 func (tg *testgoData) doRun(args []string) error {
        tg.t.Helper()
-       if !canRun {
-               panic("testgoData.doRun called but canRun false")
-       }
        if tg.inParallel {
                for _, arg := range args {
                        if strings.HasPrefix(arg, "testdata") || strings.HasPrefix(arg, "./testdata") {
 
        }
        return cmd
 }
+
+// CPUIsSlow reports whether the CPU running the test is suspected to be slow.
+func CPUIsSlow() bool {
+       switch runtime.GOARCH {
+       case "arm", "mips", "mipsle", "mips64", "mips64le":
+               return true
+       }
+       return false
+}
+
+// SkipIfShortAndSlow skips t if -short is set and the CPU running the test is
+// suspected to be slow.
+//
+// (This is useful for CPU-intensive tests that otherwise complete quickly.)
+func SkipIfShortAndSlow(t testing.TB) {
+       if testing.Short() && CPUIsSlow() {
+               t.Helper()
+               t.Skipf("skipping test in -short mode on %s", runtime.GOARCH)
+       }
+}