Regres: Make it work on windows.
Change-Id: Iff9400cabd5cbf8e7fcffb042c993e29a3acfdc7
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/40608
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/tests/regres/cmd/regres/main.go b/tests/regres/cmd/regres/main.go
index 9ab0735..0b55569 100644
--- a/tests/regres/cmd/regres/main.go
+++ b/tests/regres/cmd/regres/main.go
@@ -83,10 +83,6 @@
)
func main() {
- if runtime.GOOS != "linux" {
- log.Fatal("regres only currently runs on linux")
- }
-
flag.ErrHelp = errors.New("regres is a tool to detect regressions between versions of SwiftShader")
flag.Parse()
diff --git a/tests/regres/cmd/run_testlist/main.go b/tests/regres/cmd/run_testlist/main.go
index f489adb..212aef8 100644
--- a/tests/regres/cmd/run_testlist/main.go
+++ b/tests/regres/cmd/run_testlist/main.go
@@ -25,7 +25,6 @@
"flag"
"fmt"
"io/ioutil"
- "log"
"os"
"runtime"
"sort"
@@ -95,10 +94,6 @@
}
func main() {
- if runtime.GOOS != "linux" {
- log.Fatal("regres only currently runs on linux")
- }
-
flag.ErrHelp = errors.New("regres is a tool to detect regressions between versions of SwiftShader")
flag.Parse()
if err := runTests(); err != nil {
diff --git a/tests/regres/run.bat b/tests/regres/run.bat
new file mode 100644
index 0000000..e014bbd
--- /dev/null
+++ b/tests/regres/run.bat
@@ -0,0 +1 @@
+go run %~dp0cmd\regres\main.go %*
\ No newline at end of file
diff --git a/tests/regres/run_testlist.bat b/tests/regres/run_testlist.bat
new file mode 100644
index 0000000..ae9aaf1
--- /dev/null
+++ b/tests/regres/run_testlist.bat
@@ -0,0 +1 @@
+go run %~dp0cmd\run_testlist\main.go %*
\ No newline at end of file
diff --git a/tests/regres/shell/shell.go b/tests/regres/shell/shell.go
index 7622295..0b6f84c 100644
--- a/tests/regres/shell/shell.go
+++ b/tests/regres/shell/shell.go
@@ -16,73 +16,17 @@
package shell
import (
- "bytes"
"fmt"
- "log"
- "os"
- "os/exec"
- "os/signal"
- "strconv"
- "syscall"
"time"
"../cause"
)
-// MaxProcMemory is the maximum virtual memory per child process
+// MaxProcMemory is the maximum virtual memory per child process.
+// Note: This is not used on Windows, as there is no sensible way to limit
+// process memory.
var MaxProcMemory uint64 = 4 * 1024 * 1024 * 1024 // 4GB
-func init() {
- // As we are going to be running a number of tests concurrently, we need to
- // limit the amount of virtual memory each test uses, otherwise memory
- // hungry tests can bring the whole system down into a swapping apocalypse.
- //
- // Linux has the setrlimit() function to limit a process (and child's)
- // virtual memory usage - but we cannot call this from the regres process
- // as this process may need more memory than the limit allows.
- //
- // Unfortunately golang has no native support for setting rlimits for child
- // processes (https://github.com/golang/go/issues/6603), so we instead wrap
- // the exec to the test executable with another child regres process using a
- // special --exec mode:
- //
- // [regres] -> [regres --exec <test-exe N args...>] -> [test-exe]
- // ^^^^
- // (calls rlimit() with memory limit of N bytes)
-
- if len(os.Args) > 3 && os.Args[1] == "--exec" {
- exe := os.Args[2]
- limit, err := strconv.ParseUint(os.Args[3], 10, 64)
- if err != nil {
- log.Fatalf("Expected memory limit as 3rd argument. %v\n", err)
- }
- if limit > 0 {
- if err := syscall.Setrlimit(syscall.RLIMIT_AS, &syscall.Rlimit{Cur: limit, Max: limit}); err != nil {
- log.Fatalln(cause.Wrap(err, "Setrlimit").Error())
- }
- }
- cmd := exec.Command(exe, os.Args[4:]...)
- cmd.Stdin = os.Stdin
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- if err := cmd.Start(); err != nil {
- os.Stderr.WriteString(err.Error())
- os.Exit(1)
- }
- // Forward signals to the child process
- c := make(chan os.Signal, 1)
- signal.Notify(c, os.Interrupt)
- go func() {
- for sig := range c {
- cmd.Process.Signal(sig)
- }
- }()
- cmd.Wait()
- close(c)
- os.Exit(cmd.ProcessState.ExitCode())
- }
-}
-
// Shell runs the executable exe with the given arguments, in the working
// directory wd.
// If the process does not finish within timeout a errTimeout will be returned.
@@ -93,41 +37,6 @@
return nil
}
-// Exec runs the executable exe with the given arguments, in the working
-// directory wd, with the custom environment flags.
-// If the process does not finish within timeout a errTimeout will be returned.
-func Exec(timeout time.Duration, exe, wd string, env []string, args ...string) ([]byte, error) {
- // Shell via regres: --exec N <exe> <args...>
- // See main() for details.
- args = append([]string{"--exec", exe, fmt.Sprintf("%v", MaxProcMemory)}, args...)
- b := bytes.Buffer{}
- c := exec.Command(os.Args[0], args...)
- c.Dir = wd
- c.Env = env
- c.Stdout = &b
- c.Stderr = &b
-
- if err := c.Start(); err != nil {
- return nil, err
- }
-
- res := make(chan error)
- go func() { res <- c.Wait() }()
-
- select {
- case <-time.NewTimer(timeout).C:
- c.Process.Signal(syscall.SIGINT)
- time.Sleep(time.Second * 3)
- if !c.ProcessState.Exited() {
- log.Printf("Process %v still has not exited, killing\n", c.Process.Pid)
- syscall.Kill(-c.Process.Pid, syscall.SIGKILL)
- }
- return b.Bytes(), ErrTimeout{exe, timeout}
- case err := <-res:
- return b.Bytes(), err
- }
-}
-
// ErrTimeout is the error returned when a process does not finish with its
// permitted time.
type ErrTimeout struct {
diff --git a/tests/regres/shell/shell_unix.go b/tests/regres/shell/shell_unix.go
new file mode 100644
index 0000000..447098b
--- /dev/null
+++ b/tests/regres/shell/shell_unix.go
@@ -0,0 +1,128 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build darwin linux
+
+package shell
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "os/signal"
+ "strconv"
+ "syscall"
+ "time"
+
+ "../cause"
+)
+
+func init() {
+ // As we are going to be running a number of tests concurrently, we need to
+ // limit the amount of virtual memory each test uses, otherwise memory
+ // hungry tests can bring the whole system down into a swapping apocalypse.
+ //
+ // Linux has the setrlimit() function to limit a process (and child's)
+ // virtual memory usage - but we cannot call this from the regres process
+ // as this process may need more memory than the limit allows.
+ //
+ // Unfortunately golang has no native support for setting rlimits for child
+ // processes (https://github.com/golang/go/issues/6603), so we instead wrap
+ // the exec to the test executable with another child regres process using a
+ // special --exec mode:
+ //
+ // [regres] -> [regres --exec <test-exe N args...>] -> [test-exe]
+ // ^^^^
+ // (calls rlimit() with memory limit of N bytes)
+
+ if len(os.Args) > 3 && os.Args[1] == "--exec" {
+ exe := os.Args[2]
+ limit, err := strconv.ParseUint(os.Args[3], 10, 64)
+ if err != nil {
+ log.Fatalf("Expected memory limit as 3rd argument. %v\n", err)
+ }
+ if limit > 0 {
+ if err := syscall.Setrlimit(syscall.RLIMIT_AS, &syscall.Rlimit{Cur: limit, Max: limit}); err != nil {
+ log.Fatalln(cause.Wrap(err, "Setrlimit").Error())
+ }
+ }
+ cmd := exec.Command(exe, os.Args[4:]...)
+ cmd.Stdin = os.Stdin
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Start(); err != nil {
+ os.Stderr.WriteString(err.Error())
+ os.Exit(1)
+ }
+ // Forward signals to the child process
+ c := make(chan os.Signal, 1)
+ signal.Notify(c, os.Interrupt)
+ go func() {
+ for sig := range c {
+ cmd.Process.Signal(sig)
+ }
+ }()
+ cmd.Wait()
+ close(c)
+ os.Exit(cmd.ProcessState.ExitCode())
+ }
+}
+
+// Exec runs the executable exe with the given arguments, in the working
+// directory wd, with the custom environment flags.
+// If the process does not finish within timeout a errTimeout will be returned.
+func Exec(timeout time.Duration, exe, wd string, env []string, args ...string) ([]byte, error) {
+ // Shell via regres: --exec N <exe> <args...>
+ // See main() for details.
+ args = append([]string{"--exec", exe, fmt.Sprintf("%v", MaxProcMemory)}, args...)
+ b := bytes.Buffer{}
+ c := exec.Command(os.Args[0], args...)
+ c.Dir = wd
+ c.Env = env
+ c.Stdout = &b
+ c.Stderr = &b
+
+ if err := c.Start(); err != nil {
+ return nil, err
+ }
+
+ res := make(chan error)
+ go func() { res <- c.Wait() }()
+
+ select {
+ case <-time.NewTimer(timeout).C:
+ c.Process.Signal(syscall.SIGINT)
+ time.Sleep(time.Second * 3)
+ if !c.ProcessState.Exited() {
+ log.Printf("Process %v still has not exited, killing\n", c.Process.Pid)
+ syscall.Kill(-c.Process.Pid, syscall.SIGKILL)
+ }
+ return b.Bytes(), ErrTimeout{exe, timeout}
+ case err := <-res:
+ return b.Bytes(), err
+ }
+}
+
+// ErrTimeout is the error returned when a process does not finish with its
+// permitted time.
+type ErrTimeout struct {
+ process string
+ timeout time.Duration
+}
+
+func (e ErrTimeout) Error() string {
+ return fmt.Sprintf("'%v' did not return after %v", e.process, e.timeout)
+}
diff --git a/tests/regres/shell/shell_windows.go b/tests/regres/shell/shell_windows.go
new file mode 100644
index 0000000..cf193d4
--- /dev/null
+++ b/tests/regres/shell/shell_windows.go
@@ -0,0 +1,48 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package shell
+
+import (
+ "bytes"
+ "os/exec"
+ "time"
+)
+
+// Exec runs the executable exe with the given arguments, in the working
+// directory wd, with the custom environment flags.
+// If the process does not finish within timeout a errTimeout will be returned.
+func Exec(timeout time.Duration, exe, wd string, env []string, args ...string) ([]byte, error) {
+ b := bytes.Buffer{}
+ c := exec.Command(exe, args...)
+ c.Dir = wd
+ c.Env = env
+ c.Stdout = &b
+ c.Stderr = &b
+
+ if err := c.Start(); err != nil {
+ return nil, err
+ }
+
+ res := make(chan error)
+ go func() { res <- c.Wait() }()
+
+ select {
+ case <-time.NewTimer(timeout).C:
+ c.Process.Kill()
+ return b.Bytes(), ErrTimeout{exe, timeout}
+ case err := <-res:
+ return b.Bytes(), err
+ }
+}