diff -r 3e4e052d5058 regression.py --- a/regression.py Mon May 04 20:22:08 2009 +0200 +++ b/regression.py Mon May 04 13:13:03 2009 -0700 @@ -92,12 +92,6 @@ class regression_test_task(Task.TaskBase assert self.test_name.startswith('test-') short_name = self.test_name[len('test-'):] - trace_dir_name = getattr(mod, "trace_dir_name", None) - if trace_dir_name is None: - trace_dir_name = "%s.ref" % short_name - trace_output_path = os.path.join(self.build_traces_dir, trace_dir_name) - reference_traces_path = os.path.join(self.reference_traces_dir, trace_dir_name) - if hasattr(mod, 'get_arguments'): arguments = mod.get_arguments(self.env, '..') else: @@ -120,35 +114,69 @@ class regression_test_task(Task.TaskBase self.result = None return 0 - if Options.options.regression_generate: - # clean the target dir - try: - shutil.rmtree(reference_traces_path) - except OSError, ex: - if ex.errno not in [errno.ENOENT]: - raise - os.makedirs(reference_traces_path) - result = self.run_reference_generate(reference_traces_path, program, arguments, is_pyscript) - if result == 0: - print "GENERATE " + self.test_name + # + # By default, we do a simple reference trace comparison test. + # + trace_compare = getattr(mod, "trace_compare", True) + + if trace_compare: + trace_dir_name = getattr(mod, "trace_dir_name", None) + if trace_dir_name is None: + trace_dir_name = "%s.ref" % short_name + trace_output_path = os.path.join(self.build_traces_dir, trace_dir_name) + reference_traces_path = os.path.join(self.reference_traces_dir, trace_dir_name) + + if Options.options.regression_generate: + # clean the target dir + try: + shutil.rmtree(reference_traces_path) + except OSError, ex: + if ex.errno not in [errno.ENOENT]: + raise + os.makedirs(reference_traces_path) + result = self.run_reference_generate(reference_traces_path, program, arguments, is_pyscript) + if result == 0: + print "GENERATE " + self.test_name + else: + print "GENERATE FAIL " + self.test_name else: - print "GENERATE FAIL " + self.test_name + # clean the target dir + try: + shutil.rmtree(trace_output_path) + except OSError, ex: + if ex.errno not in [errno.ENOENT]: + raise + os.makedirs(trace_output_path) + # run it + result = self.run_reference_test(reference_traces_path, trace_output_path, program, arguments, is_pyscript) else: - # clean the target dir - try: - shutil.rmtree(trace_output_path) - except OSError, ex: - if ex.errno not in [errno.ENOENT]: - raise - os.makedirs(trace_output_path) - # run it - result = self.run_reference_test(reference_traces_path, trace_output_path, program, arguments, is_pyscript) - if result == 0: - print "PASS " + self.test_name - else: - print "FAIL " + self.test_name + result = self.run_return_value_test(program, arguments, is_pyscript) + + if result == 0: + print "PASS " + self.test_name + else: + print "FAIL " + self.test_name + self.result = result return 0 + + def run_return_value_test(self, program, arguments, is_pyscript): + if is_pyscript: + script = os.path.abspath(os.path.join('..', *os.path.split(program))) + argv = [self.env['PYTHON'], script] + arguments + try: + wutils.run_argv(argv, self.env, cwd=trace_output_path, force_no_valgrind=True) + except Utils.WafError, ex: + print >> sys.stderr, ex + return 1 + else: + try: + rc = wutils.run_program(program, self.env, + command_template=wutils.get_command_template(self.env, arguments)) + except Utils.WafError, ex: + print >> sys.stderr, ex + return 1 + return rc def run_reference_test(self, reference_traces_path, trace_output_path, program, arguments, is_pyscript): if not os.path.exists(reference_traces_path): @@ -184,7 +212,6 @@ class regression_test_task(Task.TaskBase print "Or re-run regression testing with option -v" print "----------" return rc - def run_reference_generate(self, trace_output_path, program, arguments, is_pyscript): if is_pyscript: diff -r 3e4e052d5058 regression/tests/test-csma-bridge.py --- a/regression/tests/test-csma-bridge.py Mon May 04 20:22:08 2009 +0200 +++ b/regression/tests/test-csma-bridge.py Mon May 04 13:13:03 2009 -0700 @@ -1,6 +1,6 @@ #! /usr/bin/env python -"""Generic trace-comparison-type regression test.""" +"""Run a test using Python bindings.""" import os.path @@ -12,3 +12,5 @@ def may_run(env, options): return "Python bindings not available." pyscript = os.path.join('examples', 'csma-bridge.py') + +trace_compare = True; diff -r 3e4e052d5058 regression/tests/test-rng-exponential.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/regression/tests/test-rng-exponential.py Mon May 04 13:13:03 2009 -0700 @@ -0,0 +1,6 @@ +#! /usr/bin/env python + +"""Validation test for the exponential distribution random number generator.""" + +trace_compare = False; + diff -r 3e4e052d5058 regression/tests/test-rng-normal.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/regression/tests/test-rng-normal.py Mon May 04 13:13:03 2009 -0700 @@ -0,0 +1,6 @@ +#! /usr/bin/env python + +"""Validation test for the normal distribution random number generator.""" + +trace_compare = False; + diff -r 3e4e052d5058 regression/tests/test-rng-pareto.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/regression/tests/test-rng-pareto.py Mon May 04 13:13:03 2009 -0700 @@ -0,0 +1,6 @@ +#! /usr/bin/env python + +"""Validation test for the pareto distribution random number generator.""" + +trace_compare = False; + diff -r 3e4e052d5058 regression/tests/test-rng-uniform.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/regression/tests/test-rng-uniform.py Mon May 04 13:13:03 2009 -0700 @@ -0,0 +1,6 @@ +#! /usr/bin/env python + +"""Validation test for the uniform distribution random number generator.""" + +trace_compare = False; + diff -r 3e4e052d5058 valver/rng/rng-exponential.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/valver/rng/rng-exponential.cc Mon May 04 13:13:03 2009 -0700 @@ -0,0 +1,124 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ns3/core-module.h" +#include +#include +#include +#include +#include +#include + +NS_LOG_COMPONENT_DEFINE ("ValidateRngExponential"); + +using namespace ns3; + +#define N_RUNS 5 // .05^5 => less than one nightly regression failure per thousand years. +#define N_BINS 50 +#define N_MEASUREMENTS 1000000 +#define MAX_STATISTIC gsl_cdf_chisq_Qinv (0.05, N_BINS) // DOF = N_BINS since mean given + +void +fill_range_uniformly (double *array, uint32_t n, double start, double end) +{ + double increment = (end - start) / (n - 1.); + double d = start; + + for (uint32_t i = 0; i < n; ++i) + { + array[i] = d; + d += increment; + } +} + +double +test (ExponentialVariable &e, double mu) +{ + gsl_histogram * h = gsl_histogram_alloc (N_BINS); + + double range[N_BINS + 1]; + fill_range_uniformly (range, N_BINS + 1, 0., 10.); + range[N_BINS] = std::numeric_limits::max (); + + gsl_histogram_set_ranges (h, range, N_BINS + 1); + + double expectedMax = std::numeric_limits::min (); + double expectedMin = std::numeric_limits::max (); + + double expected[N_BINS]; + + for (uint32_t i = 0; i < N_BINS; ++i) + { + expected[i] = gsl_cdf_exponential_P (range[i + 1], mu) - gsl_cdf_exponential_P (range[i], mu); + expected[i] *= N_MEASUREMENTS; + NS_ASSERT_MSG (expected[i] >= 5, "Insufficient counts in bin " << i); + expectedMax = expected[i] > expectedMax ? expected[i] : expectedMax; + expectedMin = expected[i] < expectedMin ? expected[i] : expectedMin; + } + + for (uint32_t i = 0; i < N_MEASUREMENTS; ++i) + { + gsl_histogram_increment (h, e.GetValue ()); + } + + double tmp[N_BINS]; + + for (uint32_t i = 0; i < N_BINS; ++i) + { + tmp[i] = gsl_histogram_get (h, i); + tmp[i] -= expected[i]; + tmp[i] *= tmp[i]; + tmp[i] /= expected[i]; + } + + gsl_histogram_free (h); + + double chiSquared = 0; + + for (uint32_t i = 0; i < N_BINS; ++i) + { + chiSquared += tmp[i]; + } + + return chiSquared; +} + + int +main (int argc, char *argv[]) +{ + SeedManager::SetSeed (time (0)); + + double sum = 0.; + + for (uint32_t i = 0; i < N_RUNS; ++i) + { + ExponentialVariable e; + + double result = test (e, 1.); + NS_LOG_INFO ("X^2: " << result << ", limit: " << MAX_STATISTIC); + sum += result; + } + sum /= (double)N_RUNS; + + if (sum > MAX_STATISTIC) + { + return -1; + } + else + { + return 0; + } +} diff -r 3e4e052d5058 valver/rng/rng-normal.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/valver/rng/rng-normal.cc Mon May 04 13:13:03 2009 -0700 @@ -0,0 +1,123 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ns3/core-module.h" +#include +#include +#include +#include +#include +#include + +NS_LOG_COMPONENT_DEFINE ("ValidateRngNormal"); + +using namespace ns3; + +#define N_RUNS 5 // .05^5 => less than one nightly regression failure per thousand years. +#define N_BINS 50 +#define N_MEASUREMENTS 1000000 +#define MAX_STATISTIC gsl_cdf_chisq_Qinv (0.05, N_BINS) // DOF = N_BINS since mean given + +void +fill_range_uniformly (double *array, uint32_t n, double start, double end) +{ + double increment = (end - start) / (n - 1.); + double d = start; + + for (uint32_t i = 0; i < n; ++i) + { + array[i] = d; + d += increment; + } +} + +double +test (NormalVariable &n, double sigma) +{ + gsl_histogram * h = gsl_histogram_alloc (N_BINS); + + double range[N_BINS + 1]; + fill_range_uniformly (range, N_BINS + 1, -4., 4.); + range[0] = -std::numeric_limits::max (); + range[N_BINS] = std::numeric_limits::max (); + + gsl_histogram_set_ranges (h, range, N_BINS + 1); + + double expectedMax = std::numeric_limits::min (); + double expectedMin = std::numeric_limits::max (); + + double expected[N_BINS]; + + for (uint32_t i = 0; i < N_BINS; ++i) + { + expected[i] = gsl_cdf_gaussian_P (range[i + 1], sigma) - gsl_cdf_gaussian_P (range[i], sigma); + expected[i] *= N_MEASUREMENTS; + NS_ASSERT_MSG (expected[i] >= 5, "Insufficient counts in bin " << i); + expectedMax = expected[i] > expectedMax ? expected[i] : expectedMax; + expectedMin = expected[i] < expectedMin ? expected[i] : expectedMin; + } + + for (uint32_t i = 0; i < N_MEASUREMENTS; ++i) + { + gsl_histogram_increment (h, n.GetValue ()); + } + + double tmp[N_BINS]; + + for (uint32_t i = 0; i < N_BINS; ++i) + { + tmp[i] = gsl_histogram_get (h, i); + tmp[i] -= expected[i]; + tmp[i] *= tmp[i]; + tmp[i] /= expected[i]; + } + + gsl_histogram_free (h); + + double chiSquared = 0; + + for (uint32_t i = 0; i < N_BINS; ++i) + { + chiSquared += tmp[i]; + } + + return chiSquared; +} + + int +main (int argc, char *argv[]) +{ + double sum = 0.; + + for (uint32_t i = 0; i < N_RUNS; ++i) + { + NormalVariable n; + + double result = test (n, 1.); + NS_LOG_INFO ("X^2: " << result << ", limit: " << MAX_STATISTIC); + sum += result; + } + sum /= (double)N_RUNS; + + if (sum > MAX_STATISTIC) + { + return -1; + } + else + { + return 0; + } +} diff -r 3e4e052d5058 valver/rng/rng-pareto.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/valver/rng/rng-pareto.cc Mon May 04 13:13:03 2009 -0700 @@ -0,0 +1,132 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ns3/core-module.h" +#include +#include +#include +#include +#include +#include + +NS_LOG_COMPONENT_DEFINE ("ValidateRngPareto"); + +using namespace ns3; + +#define N_RUNS 5 // .05^5 => less than one nightly regression failure per thousand years. +#define N_BINS 50 +#define N_MEASUREMENTS 1000000 +#define MAX_STATISTIC gsl_cdf_chisq_Qinv (0.05, N_BINS) // DOF = N_BINS since mean given + +void +fill_range_uniformly (double *array, uint32_t n, double start, double end) +{ + double increment = (end - start) / (n - 1.); + double d = start; + + for (uint32_t i = 0; i < n; ++i) + { + array[i] = d; + d += increment; + } +} + +double +test (ParetoVariable &p, double a, double b) +{ + gsl_histogram * h = gsl_histogram_alloc (N_BINS); + + double range[N_BINS + 1]; + fill_range_uniformly (range, N_BINS + 1, 1., 10.); + range[N_BINS] = std::numeric_limits::max (); + + gsl_histogram_set_ranges (h, range, N_BINS + 1); + + double expectedMax = std::numeric_limits::min (); + double expectedMin = std::numeric_limits::max (); + + double expected[N_BINS]; + + for (uint32_t i = 0; i < N_BINS; ++i) + { + expected[i] = gsl_cdf_pareto_P (range[i + 1], a, b) - gsl_cdf_pareto_P (range[i], a, b); + expected[i] *= N_MEASUREMENTS; + NS_ASSERT_MSG (expected[i] >= 5, "Insufficient counts in bin " << i); + expectedMax = expected[i] > expectedMax ? expected[i] : expectedMax; + expectedMin = expected[i] < expectedMin ? expected[i] : expectedMin; + } + + for (uint32_t i = 0; i < N_MEASUREMENTS; ++i) + { + gsl_histogram_increment (h, p.GetValue ()); + } + + double tmp[N_BINS]; + + for (uint32_t i = 0; i < N_BINS; ++i) + { + tmp[i] = gsl_histogram_get (h, i); + tmp[i] -= expected[i]; + tmp[i] *= tmp[i]; + tmp[i] /= expected[i]; + } + + gsl_histogram_free (h); + + double chiSquared = 0; + + for (uint32_t i = 0; i < N_BINS; ++i) + { + chiSquared += tmp[i]; + } + + return chiSquared; +} + + int +main (int argc, char *argv[]) +{ + double sum = 0.; + + for (uint32_t i = 0; i < N_RUNS; ++i) + { + // + // There's a disconnect between the gsl pareto parameters and the ns-3. + // + // gsl wants a (shape) and b (scale) + // ns-3 wants a (shape) and m (mean) + // + // By default, ns-3 uses a=1.5, m=1. What is b? + // + // m = ba/(a-1) for pareto => b = 0.33333333 + // + ParetoVariable p; + + double result = test (p, 1.5, 0.33333333); + NS_LOG_INFO ("X^2: " << result << ", limit: " << MAX_STATISTIC); + sum += result; + } + sum /= (double)N_RUNS; + + if (sum > MAX_STATISTIC) + { + return -1; + } + else + { + return 0; + } +} diff -r 3e4e052d5058 valver/rng/rng-uniform.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/valver/rng/rng-uniform.cc Mon May 04 13:13:03 2009 -0700 @@ -0,0 +1,94 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ns3/core-module.h" +#include +#include +#include +#include +#include + +NS_LOG_COMPONENT_DEFINE ("ValidateRngUniform"); + +using namespace ns3; + +#define N_RUNS 5 // .05^5 => less than one nightly regression failure per thousand years. +#define N_BINS 50 +#define N_MEASUREMENTS 1000000 +#define EXPECTED ((double)N_MEASUREMENTS / (double)N_BINS) +#define MAX_STATISTIC gsl_cdf_chisq_Qinv (0.05, N_BINS) // DOF = N_BINS since mean given + +double +test (UniformVariable &u) +{ + gsl_histogram * h = gsl_histogram_alloc (N_BINS); + gsl_histogram_set_ranges_uniform (h, 0., 1.); + + for (uint32_t i = 0; i < N_MEASUREMENTS; ++i) + { + gsl_histogram_increment (h, u.GetValue ()); + } + + double tmp[N_BINS]; + + for (uint32_t i = 0; i < N_BINS; ++i) + { + tmp[i] = gsl_histogram_get (h, i); + NS_ASSERT_MSG (tmp[i] >= 5, "Insufficient counts in bin " << i); + tmp[i] -= EXPECTED; + tmp[i] *= tmp[i]; + tmp[i] /= EXPECTED; + } + + gsl_histogram_free (h); + + double chiSquared = 0; + + for (uint32_t i = 0; i < N_BINS; ++i) + { + chiSquared += tmp[i]; + } + + return chiSquared; +} + + int +main (int argc, char *argv[]) +{ + SeedManager::SetSeed (time (0)); + + double sum = 0.; + + for (uint32_t i = 0; i < N_RUNS; ++i) + { + UniformVariable u; + + double result = test (u); + NS_LOG_INFO ("X^2: " << result << ", limit: " << MAX_STATISTIC); + sum += result; + } + + sum /= (double)N_RUNS; + + if (sum > MAX_STATISTIC) + { + return -1; + } + else + { + return 0; + } +} diff -r 3e4e052d5058 valver/rng/waf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/valver/rng/waf Mon May 04 13:13:03 2009 -0700 @@ -0,0 +1,1 @@ +exec "`dirname "$0"`"/../../waf "$@" diff -r 3e4e052d5058 valver/rng/wscript --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/valver/rng/wscript Mon May 04 13:13:03 2009 -0700 @@ -0,0 +1,30 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def configure(conf): + # gsl depends on gslcblas and so if you use the usual conf.check trick the test compilation will fail + # since these libraries typically come together, we'll treat them as a unit. + conf.env['HAVE_GSLCBLAS'] = conf.check(lib='gslcblas', uselib='GSLCBLAS', define_name='HAVE_GSLCBLAS') + conf.report_optional_feature("GSLCBLAS", "GSL/GSLCBLAS", conf.env['HAVE_GSLCBLAS'], + "library 'gslcblas' not found") + + if conf.env['HAVE_GSLCBLAS']: + conf.env['LIB_GSL'] = 'gsl' + +def build(bld): + + obj = bld.create_ns3_program('rng-uniform', ['core']) + obj.uselib = 'GSL GSLCBLAS' + obj.source = 'rng-uniform.cc' + + obj = bld.create_ns3_program('rng-normal', ['core']) + obj.uselib = 'GSL GSLCBLAS' + obj.source = 'rng-normal.cc' + + obj = bld.create_ns3_program('rng-exponential', ['core']) + obj.uselib = 'GSL GSLCBLAS' + obj.source = 'rng-exponential.cc' + + obj = bld.create_ns3_program('rng-pareto', ['core']) + obj.uselib = 'GSL GSLCBLAS' + obj.source = 'rng-pareto.cc' + diff -r 3e4e052d5058 valver/waf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/valver/waf Mon May 04 13:13:03 2009 -0700 @@ -0,0 +1,1 @@ +exec "`dirname "$0"`"/../waf "$@" diff -r 3e4e052d5058 valver/wscript --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/valver/wscript Mon May 04 13:13:03 2009 -0700 @@ -0,0 +1,11 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +all_tests = ( + 'rng', + ) + +def configure(conf): + conf.sub_config('rng') + +def build(bld): + bld.add_subdirs(list(all_tests)) diff -r 3e4e052d5058 wscript --- a/wscript Mon May 04 20:22:08 2009 +0200 +++ b/wscript Mon May 04 13:13:03 2009 -0700 @@ -265,6 +265,7 @@ def configure(conf): conf.sub_config('src') conf.sub_config('utils') conf.sub_config('bindings/python') + conf.sub_config('valver') if Options.options.enable_modules: conf.env['NS3_ENABLED_MODULES'] = ['ns3-'+mod for mod in @@ -432,6 +433,7 @@ def build(bld): # process subfolders from here bld.add_subdirs('src') bld.add_subdirs('samples utils examples') + bld.add_subdirs('valver') add_scratch_programs(bld)