Simulate other ARM CPUs when running tests.
We test all Intel variants via SDE. For ARM, we can do the next best thing and tweak with OPENSSL_armcap_P. If the host CPU does not support the instructions we wish to test, skip it, but print something so we know whether we need a more featureful test device. Also fix the "CRASHED" status to "CRASH", to match https://chromium.googlesource.com/chromium/src/+/master/docs/testing/json_test_results_format.md (It's unclear if anything actually parses that JSON very carefully...) Bug: 19 Change-Id: I811cc00a0d210a454287ac79c06f18fbc54f96dd Reviewed-on: https://boringssl-review.googlesource.com/c/33204 Commit-Queue: David Benjamin <davidben@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org> Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
parent
444c2e59fb
commit
6ce93ccb80
@ -102,6 +102,10 @@ HIDDEN uint32_t OPENSSL_armcap_P =
|
||||
|
||||
#else
|
||||
HIDDEN uint32_t OPENSSL_armcap_P = 0;
|
||||
|
||||
uint32_t *OPENSSL_get_armcap_pointer_for_test(void) {
|
||||
return &OPENSSL_armcap_P;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -150,6 +150,14 @@ extern "C" {
|
||||
void OPENSSL_cpuid_setup(void);
|
||||
#endif
|
||||
|
||||
#if (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) && \
|
||||
!defined(OPENSSL_STATIC_ARMCAP)
|
||||
// OPENSSL_get_armcap_pointer_for_test returns a pointer to |OPENSSL_armcap_P|
|
||||
// for unit tests. Any modifications to the value must be made after
|
||||
// |CRYPTO_library_init| but before any other function call in BoringSSL.
|
||||
OPENSSL_EXPORT uint32_t *OPENSSL_get_armcap_pointer_for_test(void);
|
||||
#endif
|
||||
|
||||
|
||||
#if (!defined(_MSC_VER) || defined(__clang__)) && defined(OPENSSL_64_BIT)
|
||||
#define BORINGSSL_HAS_UINT128
|
||||
|
@ -12,13 +12,22 @@
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <openssl/cpu.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "gtest_main.h"
|
||||
#include "../internal.h"
|
||||
|
||||
#if (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) && \
|
||||
!defined(OPENSSL_STATIC_ARMCAP)
|
||||
#include <openssl/arm_arch.h>
|
||||
#define TEST_ARM_CPUS
|
||||
#endif
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
@ -33,5 +42,33 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(TEST_ARM_CPUS)
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strncmp(argv[i], "--cpu=", 6) == 0) {
|
||||
const char *cpu = argv[i] + 6;
|
||||
uint32_t armcap;
|
||||
if (strcmp(cpu, "none") == 0) {
|
||||
armcap = 0;
|
||||
} else if (strcmp(cpu, "neon") == 0) {
|
||||
armcap = ARMV7_NEON;
|
||||
} else if (strcmp(cpu, "crypto") == 0) {
|
||||
armcap = ARMV7_NEON | ARMV8_AES | ARMV8_SHA1 | ARMV8_SHA256 | ARMV8_PMULL;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown CPU: %s\n", cpu);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uint32_t *armcap_ptr = OPENSSL_get_armcap_pointer_for_test();
|
||||
if ((armcap & *armcap_ptr) != armcap) {
|
||||
fprintf(stderr,
|
||||
"Host CPU does not support features for testing CPU '%s'.\n",
|
||||
cpu);
|
||||
exit(89);
|
||||
}
|
||||
*armcap_ptr = armcap;
|
||||
}
|
||||
}
|
||||
#endif // TEST_ARM_CPUS
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
@ -45,13 +46,19 @@ var (
|
||||
jsonOutput = flag.String("json-output", "", "The file to output JSON results to.")
|
||||
mallocTest = flag.Int64("malloc-test", -1, "If non-negative, run each test with each malloc in turn failing from the given number onwards.")
|
||||
mallocTestDebug = flag.Bool("malloc-test-debug", false, "If true, ask each test to abort rather than fail a malloc. This can be used with a specific value for --malloc-test to identity the malloc failing that is causing problems.")
|
||||
simulateARMCPUs = flag.Bool("simulate-arm-cpus", simulateARMCPUsDefault(), "If true, runs tests simulating different ARM CPUs.")
|
||||
)
|
||||
|
||||
func simulateARMCPUsDefault() bool {
|
||||
return runtime.GOOS == "linux" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64")
|
||||
}
|
||||
|
||||
type test struct {
|
||||
args []string
|
||||
shard, numShards int
|
||||
// cpu, if not empty, contains an Intel CPU code to simulate. Run
|
||||
// `sde64 -help` to get a list of these codes.
|
||||
// cpu, if not empty, contains a code to simulate. For SDE, run `sde64
|
||||
// -help` to get a list of these codes. For ARM, see gtest_main.cc for
|
||||
// the supported values.
|
||||
cpu string
|
||||
}
|
||||
|
||||
@ -100,6 +107,12 @@ var sdeCPUs = []string{
|
||||
"knm", // Knights Mill
|
||||
}
|
||||
|
||||
var armCPUs = []string{
|
||||
"none", // No support for any ARM extensions.
|
||||
"neon", // Support for NEON.
|
||||
"crypto", // Support for NEON and crypto extensions.
|
||||
}
|
||||
|
||||
func newTestOutput() *testOutput {
|
||||
return &testOutput{
|
||||
Version: 3,
|
||||
@ -114,10 +127,14 @@ func (t *testOutput) addResult(name, result string) {
|
||||
if _, found := t.Tests[name]; found {
|
||||
panic(name)
|
||||
}
|
||||
expected := "PASS"
|
||||
if result == "SKIP" {
|
||||
expected = "SKIP"
|
||||
}
|
||||
t.Tests[name] = testResult{
|
||||
Actual: result,
|
||||
Expected: "PASS",
|
||||
IsUnexpected: result != "PASS",
|
||||
Expected: expected,
|
||||
IsUnexpected: result != expected,
|
||||
}
|
||||
t.NumFailuresByType[result]++
|
||||
}
|
||||
@ -178,17 +195,17 @@ func sdeOf(cpu, path string, args ...string) *exec.Cmd {
|
||||
return exec.Command(*sdePath, sdeArgs...)
|
||||
}
|
||||
|
||||
type moreMallocsError struct{}
|
||||
|
||||
func (moreMallocsError) Error() string {
|
||||
return "child process did not exhaust all allocation calls"
|
||||
}
|
||||
|
||||
var errMoreMallocs = moreMallocsError{}
|
||||
var (
|
||||
errMoreMallocs = errors.New("child process did not exhaust all allocation calls")
|
||||
errTestSkipped = errors.New("test was skipped")
|
||||
)
|
||||
|
||||
func runTestOnce(test test, mallocNumToFail int64) (passed bool, err error) {
|
||||
prog := path.Join(*buildDir, test.args[0])
|
||||
args := test.args[1:]
|
||||
if *simulateARMCPUs && test.cpu != "" {
|
||||
args = append([]string{"--cpu=" + test.cpu}, args...)
|
||||
}
|
||||
var cmd *exec.Cmd
|
||||
if *useValgrind {
|
||||
cmd = valgrindOf(false, prog, args...)
|
||||
@ -218,8 +235,12 @@ func runTestOnce(test test, mallocNumToFail int64) (passed bool, err error) {
|
||||
}
|
||||
if err := cmd.Wait(); err != nil {
|
||||
if exitError, ok := err.(*exec.ExitError); ok {
|
||||
if exitError.Sys().(syscall.WaitStatus).ExitStatus() == 88 {
|
||||
switch exitError.Sys().(syscall.WaitStatus).ExitStatus() {
|
||||
case 88:
|
||||
return false, errMoreMallocs
|
||||
case 89:
|
||||
fmt.Print(string(outBuf.Bytes()))
|
||||
return false, errTestSkipped
|
||||
}
|
||||
}
|
||||
fmt.Print(string(outBuf.Bytes()))
|
||||
@ -433,6 +454,15 @@ func main() {
|
||||
testForCPU.cpu = cpu
|
||||
tests <- testForCPU
|
||||
}
|
||||
} else if *simulateARMCPUs {
|
||||
// This mode is run instead of the default path,
|
||||
// so also include the native flow.
|
||||
tests <- test
|
||||
for _, cpu := range armCPUs {
|
||||
testForCPU := test
|
||||
testForCPU.cpu = cpu
|
||||
tests <- testForCPU
|
||||
}
|
||||
} else {
|
||||
shards, err := test.getGTestShards()
|
||||
if err != nil {
|
||||
@ -451,16 +481,21 @@ func main() {
|
||||
}()
|
||||
|
||||
testOutput := newTestOutput()
|
||||
var failed []test
|
||||
var failed, skipped []test
|
||||
for testResult := range results {
|
||||
test := testResult.Test
|
||||
args := test.args
|
||||
|
||||
if testResult.Error != nil {
|
||||
if testResult.Error == errTestSkipped {
|
||||
fmt.Printf("%s\n", test.longName())
|
||||
fmt.Printf("%s was skipped\n", args[0])
|
||||
skipped = append(skipped, test)
|
||||
testOutput.addResult(test.longName(), "SKIP")
|
||||
} else if testResult.Error != nil {
|
||||
fmt.Printf("%s\n", test.longName())
|
||||
fmt.Printf("%s failed to complete: %s\n", args[0], testResult.Error)
|
||||
failed = append(failed, test)
|
||||
testOutput.addResult(test.longName(), "CRASHED")
|
||||
testOutput.addResult(test.longName(), "CRASH")
|
||||
} else if !testResult.Passed {
|
||||
fmt.Printf("%s\n", test.longName())
|
||||
fmt.Printf("%s failed to print PASS on the last line.\n", args[0])
|
||||
@ -478,6 +513,13 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
if len(skipped) > 0 {
|
||||
fmt.Printf("\n%d of %d tests were skipped:\n", len(skipped), len(testCases))
|
||||
for _, test := range skipped {
|
||||
fmt.Printf("\t%s%s\n", strings.Join(test.args, " "), test.cpuMsg())
|
||||
}
|
||||
}
|
||||
|
||||
if len(failed) > 0 {
|
||||
fmt.Printf("\n%d of %d tests failed:\n", len(failed), len(testCases))
|
||||
for _, test := range failed {
|
||||
|
Loading…
Reference in New Issue
Block a user