Improve reproducibility of test runs.

Add random seed to run-tests.py, using either a user supplied
value or a random number generated by random.SystemRandom().
This same random seed is passed to all test cases, making sure
that we can easily reproduce test failures that depend on
random numbers (i.e. bugs related to our handwritten ASLR).

Also fix all uses of rand() to make use of our RNG class
instead.

R=machenbach@chromium.org

Review URL: https://codereview.chromium.org/231443002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20637 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
bmeurer@chromium.org 2014-04-10 07:25:49 +00:00
parent 707a583116
commit 5a564648dd
6 changed files with 32 additions and 13 deletions

View File

@ -34,6 +34,7 @@
#include "diy-fp.h"
#include "double.h"
#include "strtod.h"
#include "utils/random-number-generator.h"
using namespace v8::internal;
@ -448,13 +449,13 @@ static const int kShortStrtodRandomCount = 2;
static const int kLargeStrtodRandomCount = 2;
TEST(RandomStrtod) {
srand(static_cast<unsigned int>(time(NULL)));
RandomNumberGenerator rng;
char buffer[kBufferSize];
for (int length = 1; length < 15; length++) {
for (int i = 0; i < kShortStrtodRandomCount; ++i) {
int pos = 0;
for (int j = 0; j < length; ++j) {
buffer[pos++] = rand() % 10 + '0';
buffer[pos++] = rng.NextInt(10) + '0';
}
int exponent = DeterministicRandom() % (25*2 + 1) - 25 - length;
buffer[pos] = '\0';
@ -467,7 +468,7 @@ TEST(RandomStrtod) {
for (int i = 0; i < kLargeStrtodRandomCount; ++i) {
int pos = 0;
for (int j = 0; j < length; ++j) {
buffer[pos++] = rand() % 10 + '0';
buffer[pos++] = rng.NextInt(10) + '0';
}
int exponent = DeterministicRandom() % (308*2 + 1) - 308 - length;
buffer[pos] = '\0';

View File

@ -29,6 +29,7 @@
#include "cctest.h"
#include "types.h"
#include "utils/random-number-generator.h"
using namespace v8::internal;
@ -112,6 +113,8 @@ class Types {
objects.push_back(array);
}
RandomNumberGenerator rng;
TypeHandle Representation;
TypeHandle Semantic;
TypeHandle None;
@ -180,14 +183,14 @@ class Types {
}
TypeHandle Fuzz(int depth = 5) {
switch (rand() % (depth == 0 ? 3 : 20)) {
switch (rng.NextInt(depth == 0 ? 3 : 20)) {
case 0: { // bitset
int n = 0
#define COUNT_BITSET_TYPES(type, value) + 1
BITSET_TYPE_LIST(COUNT_BITSET_TYPES)
#undef COUNT_BITSET_TYPES
;
int i = rand() % n;
int i = rng.NextInt(n);
#define PICK_BITSET_TYPE(type, value) \
if (i-- == 0) return Type::type(region_);
BITSET_TYPE_LIST(PICK_BITSET_TYPE)
@ -195,13 +198,13 @@ class Types {
UNREACHABLE();
}
case 1: // class
switch (rand() % 2) {
switch (rng.NextInt(2)) {
case 0: return ObjectClass;
case 1: return ArrayClass;
}
UNREACHABLE();
case 2: // constant
switch (rand() % 6) {
switch (rng.NextInt(6)) {
case 0: return SmiConstant;
case 1: return Signed32Constant;
case 2: return ObjectConstant1;
@ -211,7 +214,7 @@ class Types {
}
UNREACHABLE();
default: { // union
int n = rand() % 10;
int n = rng.NextInt(10);
TypeHandle type = None;
for (int i = 0; i < n; ++i) {
type = Type::Union(type, Fuzz(depth - 1), region_);

View File

@ -93,7 +93,11 @@
# This test sets the umask on a per-process basis and hence cannot be
# used in multi-threaded runs.
# On android there is no /tmp directory.
'd8-os': [PASS, ['isolates or arch == android_arm or arch == android_arm64 or arch == android_ia32', SKIP]],
# Currently d8-os generates a temporary directory name using Math.random(), so
# we cannot run several variants of d8-os simultaneously, since all of them
# get the same random seed and would generate the same directory name. Besides
# that, it doesn't make sense to run several variants of d8-os anyways.
'd8-os': [PASS, NO_VARIANTS, ['isolates or arch == android_arm or arch == android_arm64 or arch == android_ia32', SKIP]],
'tools/tickprocessor': [PASS, ['arch == android_arm or arch == android_arm64 or arch == android_ia32', SKIP]],
##############################################################################

View File

@ -34,6 +34,7 @@ import optparse
import os
from os.path import join
import platform
import random
import shlex
import subprocess
import sys
@ -200,6 +201,8 @@ def BuildOptions():
result.add_option("--junittestsuite",
help="The testsuite name in the JUnit output file",
default="v8tests")
result.add_option("--random-seed", default=0, dest="random_seed",
help="Default seed for initializing random generator")
return result
@ -250,6 +253,9 @@ def ProcessOptions(options):
if options.j == 0:
options.j = multiprocessing.cpu_count()
while options.random_seed == 0:
options.random_seed = random.SystemRandom().randint(-2147483648, 2147483647)
def excl(*args):
"""Returns true if zero or one of multiple arguments are true."""
return reduce(lambda x, y: x + y, args) <= 1
@ -396,7 +402,8 @@ def Execute(arch, mode, args, options, suites, workspace):
timeout, options.isolates,
options.command_prefix,
options.extra_flags,
options.no_i18n)
options.no_i18n,
options.random_seed)
# TODO(all): Combine "simulator" and "simulator_run".
simulator_run = not options.dont_skip_simulator_slow_tests and \

View File

@ -171,6 +171,7 @@ class Runner(object):
cmd = (self.context.command_prefix +
[os.path.abspath(os.path.join(self.context.shell_dir, shell))] +
d8testflag +
["--random-seed=%s" % self.context.random_seed] +
test.suite.GetFlagsForTestCase(test, self.context) +
self.context.extra_flags)
return cmd

View File

@ -28,7 +28,7 @@
class Context():
def __init__(self, arch, mode, shell_dir, mode_flags, verbose, timeout,
isolates, command_prefix, extra_flags, noi18n):
isolates, command_prefix, extra_flags, noi18n, random_seed):
self.arch = arch
self.mode = mode
self.shell_dir = shell_dir
@ -39,13 +39,16 @@ class Context():
self.command_prefix = command_prefix
self.extra_flags = extra_flags
self.noi18n = noi18n
self.random_seed = random_seed
def Pack(self):
return [self.arch, self.mode, self.mode_flags, self.timeout, self.isolates,
self.command_prefix, self.extra_flags, self.noi18n]
self.command_prefix, self.extra_flags, self.noi18n,
self.random_seed]
@staticmethod
def Unpack(packed):
# For the order of the fields, refer to Pack() above.
return Context(packed[0], packed[1], None, packed[2], False,
packed[3], packed[4], packed[5], packed[6], packed[7])
packed[3], packed[4], packed[5], packed[6], packed[7],
packed[8])