diff --git a/bindings/python/ns3/__init__.py b/bindings/python/ns3/__init__.py index 943a01575..cd1f9ec82 100644 --- a/bindings/python/ns3/__init__.py +++ b/bindings/python/ns3/__init__.py @@ -1,4 +1,7 @@ from _ns3 import * +import atexit +atexit.register(Simulator.Destroy) +del atexit diff --git a/bindings/python/wscript b/bindings/python/wscript index 69825e2b6..403cbca07 100644 --- a/bindings/python/wscript +++ b/bindings/python/wscript @@ -70,12 +70,21 @@ def configure(conf): conf.report_optional_feature("python", "Python Bindings", False, str(ex)) return - ## Check for pybindgen + # Check for the location of pybindgen + if Options.options.with_pybindgen is not None: + if os.path.isdir(Options.options.with_pybindgen): + conf.check_message("pybindgen location", '', True, ("%s (given)" % Options.options.with_pybindgen)) + conf.env['WITH_PYBINDGEN'] = os.path.abspath(Options.options.with_pybindgen) + else: + pybindgen_dir = os.path.join('..', "pybindgen") + if os.path.isdir(pybindgen_dir): + conf.check_message("pybindgen location", '', True, ("%s (guessed)" % pybindgen_dir)) + conf.env['WITH_PYBINDGEN'] = os.path.abspath(pybindgen_dir) + del pybindgen_dir + if not conf.env['WITH_PYBINDGEN']: + conf.check_message("pybindgen location", '', False) - no_net = False - if Options.options.with_pybindgen: - conf.env['WITH_PYBINDGEN'] = os.path.abspath(Options.options.with_pybindgen) - no_net = True + # Check for pybindgen set_pybindgen_pythonpath(conf.env) @@ -100,10 +109,9 @@ def configure(conf): Logs.warn("pybindgen (found %s) is too old (need %s)" % (pybindgen_version_str, '.'.join([str(x) for x in REQUIRED_PYBINDGEN_VERSION]))) - if no_net or not fetch_pybindgen(conf): - conf.report_optional_feature("python", "Python Bindings", False, - "PyBindGen too old and newer version could not be retrieved") - return + conf.report_optional_feature("python", "Python Bindings", False, + "PyBindGen too old and newer version could not be retrieved") + return ## If all has gone well, we finally enable the Python bindings conf.env['ENABLE_PYTHON_BINDINGS'] = True diff --git a/doc/WifiArchitecture.dia b/doc/WifiArchitecture.dia new file mode 100644 index 000000000..71deb6830 Binary files /dev/null and b/doc/WifiArchitecture.dia differ diff --git a/doc/WifiArchitecture.png b/doc/WifiArchitecture.png new file mode 100644 index 000000000..3bed78bce Binary files /dev/null and b/doc/WifiArchitecture.png differ diff --git a/doc/manual/Makefile b/doc/manual/Makefile index 7dc11ceef..6775f1f7a 100644 --- a/doc/manual/Makefile +++ b/doc/manual/Makefile @@ -7,6 +7,7 @@ CSS = --css-include=manual.css SPLIT = --split section FIGURES = figures +DOC_FIGURES = .. VPATH = $(FIGURES) IMAGES_EPS = \ @@ -18,7 +19,8 @@ IMAGES_EPS = \ $(FIGURES)/sockets-overview.eps \ $(FIGURES)/testbed.eps \ $(FIGURES)/emulated-channel.eps \ - $(FIGURES)/snir.eps + $(FIGURES)/snir.eps \ + $(DOC_FIGURES)/WifiArchitecture.eps IMAGES_PNG = ${IMAGES_EPS:.eps=.png} IMAGES_PDF = ${IMAGES_EPS:.eps=.pdf} diff --git a/doc/manual/wifi.texi b/doc/manual/wifi.texi index cd200f4d1..29f1e451e 100644 --- a/doc/manual/wifi.texi +++ b/doc/manual/wifi.texi @@ -83,6 +83,11 @@ is no model for cross-channel interference or coupling. The source code for the Wifi NetDevice lives in the directory @code{src/devices/wifi}. +@float Figure,fig:WifiArchitecture +@caption{Wifi NetDevice architecture.} +@image{../WifiArchitecture,5in} +@end float + @node Using the WifiNetDevice @section Using the WifiNetDevice diff --git a/regression.py b/regression.py index 037c8d96e..d92683af1 100644 --- a/regression.py +++ b/regression.py @@ -9,6 +9,7 @@ import urllib import Build import Options import Utils +import Task # local modules import wutils @@ -21,106 +22,6 @@ def dev_null(): return open("/dev/null", "w") -### Regression testing -class Regression(object): - def __init__(self, testdir, reference_traces): - self.testdir = testdir - self.reference_traces = reference_traces - self.env = Build.bld.env - - def run_test(self, verbose, generate, testName, arguments=[], pyscript=None, refTestName=None): - """ - @param verbose: enable verbose execution - - @param generate: generate new traces instead of comparing with the reference - - @param testName: name of the test - - @arguments: list of extra parameters to pass to the program to be tested - - @pyscript: if not None, the test is written in Python and this - parameter contains the path to the python script, relative to - the project root dir - - @param refTestName: if not None, this is the name of the directory under refDirName - that contains the reference traces. Otherwise "refDirname/testName + .ref" is used. - - """ - if not isinstance(arguments, list): - raise TypeError - - if refTestName is None: - refTestDirName = os.path.join(self.reference_traces, (testName + ".ref")) - else: - refTestDirName = os.path.join(self.reference_traces, refTestName) - - if not os.path.exists(self.reference_traces): - print"No reference trace repository" - return 1 - - if generate: - if not os.path.exists(refTestDirName): - print "creating new " + refTestDirName - os.mkdir(refTestDirName) - - if pyscript is None: - tmpl = "%s" - for arg in arguments: - tmpl = tmpl + " " + arg - wutils.run_program(testName, tmpl, cwd=refTestDirName) - else: - argv = [self.env['PYTHON'], os.path.join(Options.cwd_launch, *os.path.split(pyscript))] + arguments - wutils.run_argv(argv, cwd=refTestDirName) - print "Remember to commit " + refTestDirName - return 0 - else: - if not os.path.exists(refTestDirName): - print "Cannot locate reference traces in " + refTestDirName - return 1 - - if refTestName is None: - traceDirName = testName + ".ref" - else: - traceDirName = refTestName - traceDirName = os.path.join('regression', 'traces', traceDirName) - - try: - shutil.rmtree(traceDirName) - except OSError: - pass - os.mkdir(traceDirName) - - if pyscript is None: - wutils.run_program(testName, - command_template=wutils.get_command_template(*arguments), - cwd=traceDirName) - else: - argv = [self.env['PYTHON'], os.path.join('..', '..', '..', *os.path.split(pyscript))] + arguments - wutils.run_argv(argv, cwd=traceDirName) - - if verbose: - #diffCmd = "diff traces " + refTestDirName + " | head" - diffCmd = subprocess.Popen([self.env['DIFF'], traceDirName, refTestDirName], - stdout=subprocess.PIPE) - headCmd = subprocess.Popen("head", stdin=diffCmd.stdout) - rc2 = headCmd.wait() - diffCmd.stdout.close() - rc1 = diffCmd.wait() - rc = rc1 or rc2 - else: - rc = subprocess.Popen([self.env['DIFF'], traceDirName, refTestDirName], stdout=dev_null()).wait() - if rc: - print "----------" - print "Traces differ in test: test-" + testName - print "Reference traces in directory: regression/" + refTestDirName - print "Traces in directory: traces" - print "Rerun regression test as: " + \ - "\"./waf --regression --regression-tests=test-" + testName + "\"" - print "Then do \"diff -u regression/" + refTestDirName + " regression/" + traceDirName +\ - "\" for details" - print "----------" - return rc - def _find_tests(testdir): """Return a list of test modules in the test directory @@ -136,7 +37,161 @@ def _find_tests(testdir): tests.sort() return tests -def run_regression(reference_traces): + +class regression_test_task(Task.TaskBase): + after = 'cc cxx cc_link cxx_link' + color = 'BLUE' + + def __init__(self, env, test_name, test_scripts_dir, build_traces_dir, reference_traces): + super(regression_test_task, self).__init__() + self.env = env + self.test_name = test_name + self.test_scripts_dir = test_scripts_dir + self.build_traces_dir = build_traces_dir + self.reference_traces_dir = reference_traces + + def __str__(self): + return 'regression-test (%s)\n' % self.test_name + + def run(self): + """Run a single test""" + sys.path.insert(0, self.test_scripts_dir) + try: + mod = __import__(self.test_name, globals(), locals(), []) + finally: + sys.path.remove(self.test_scripts_dir) + + 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: + arguments = getattr(mod, "arguments", []) + + pyscript = getattr(mod, "pyscript", None) + if pyscript: + is_pyscript = True + program = pyscript + else: + is_pyscript = False + program = getattr(mod, "program", short_name) + + if hasattr(mod, 'may_run'): + reason_cannot_run = mod.may_run(self.env) + else: + reason_cannot_run = None + if reason_cannot_run: + print "SKIP %s (%s)" % (self.test_name, reason_cannot_run) + self.result = None + return 0 + + if Options.options.regression_generate: + # clean the target dir + shutil.rmtree(reference_traces_path, ignore_errors=True) + 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: + # clean the target dir + shutil.rmtree(trace_output_path, ignore_errors=True) + 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 + self.result = result + return 0 + + def run_reference_test(self, reference_traces_path, trace_output_path, program, arguments, is_pyscript): + if not os.path.exists(reference_traces_path): + print "Cannot locate reference traces in " + reference_traces_path + return 1 + + if is_pyscript: + script = os.path.abspath(os.path.join('..', *os.path.split(program))) + argv = [self.env['PYTHON'], script] + arguments + wutils.run_argv(argv, cwd=trace_output_path) + else: + wutils.run_program(program, + command_template=wutils.get_command_template(self.env, arguments), + cwd=trace_output_path) + + if Options.options.verbose: + #diffCmd = "diff traces " + refTestDirName + " | head" + diffCmd = subprocess.Popen([self.env['DIFF'], trace_output_path, reference_traces_path], + stdout=subprocess.PIPE) + headCmd = subprocess.Popen("head", stdin=diffCmd.stdout) + rc2 = headCmd.wait() + diffCmd.stdout.close() + rc1 = diffCmd.wait() + rc = rc1 or rc2 + else: + rc = subprocess.Popen([self.env['DIFF'], trace_output_path, reference_traces_path], stdout=dev_null()).wait() + if rc: + print "----------" + print "Traces differ in test: ", self.test_name + print "Reference traces in directory: " + reference_traces_path + print "Traces in directory: " + trace_output_path + print "Run the following command for details:" + print "\tdiff -u %s %s" % (reference_traces_path, trace_output_path) + print "----------" + return rc + + + def run_reference_generate(self, trace_output_path, program, arguments, is_pyscript): + if is_pyscript: + script = os.path.abspath(os.path.join('..', *os.path.split(program))) + argv = [self.env['PYTHON'], script] + arguments + retval = wutils.run_argv(argv, cwd=trace_output_path) + else: + retval = wutils.run_program(program, + command_template=wutils.get_command_template(self.env, arguments), + cwd=trace_output_path) + return retval + + +class regression_test_collector_task(Task.TaskBase): + after = 'regression_test_task' + color = 'BLUE' + + def __init__(self, test_tasks): + super(regression_test_collector_task, self).__init__() + self.test_tasks = test_tasks + + def __str__(self): + return 'regression-test-collector\n' + + def run(self): + failed_tests = [test for test in self.test_tasks if test.result is not None and test.result != 0] + skipped_tests = [test for test in self.test_tasks if test.result is None] + print "Regression testing summary:" + if skipped_tests: + print "SKIP: %i of %i tests have been skipped (%s)" % ( + len(skipped_tests), len(self.test_tasks), + ', '.join([test.test_name for test in skipped_tests])) + if failed_tests: + print "FAIL: %i of %i tests have failed (%s)" % ( + len(failed_tests), len(self.test_tasks), + ', '.join([test.test_name for test in failed_tests])) + return 1 + else: + print "PASS: %i of %i tests passed" % (len(self.test_tasks) - len(skipped_tests), + len(self.test_tasks)) + return 0 + +def run_regression(bld, reference_traces): """Execute regression tests. Called with cwd set to the 'regression' subdir of ns-3. @param reference_traces: reference traces directory. @@ -148,57 +203,18 @@ def run_regression(reference_traces): print "Tests directory does not exist" sys.exit(3) - sys.path.append(testdir) - sys.modules['tracediff'] = Regression(testdir, reference_traces) - if Options.options.regression_tests: tests = Options.options.regression_tests.split(',') else: tests = _find_tests(testdir) - print "========== Running Regression Tests ==========" - env = Build.bld.env - if not os.path.exists(reference_traces): print "Reference traces directory (%s) does not exist" % reference_traces return 3 - bad = [] - + test_scripts_dir = bld.path.find_dir('regression/tests').abspath() + build_traces_dir = bld.path.find_or_declare('regression/traces').abspath(bld.env) + tasks = [] for test in tests: - try: - result = _run_regression_test(test) - if result == 0: - if Options.options.regression_generate: - print "GENERATE " + test - else: - print "PASS " + test - else: - bad.append(test) - print "FAIL " + test - except NotImplementedError: - print "SKIP " + test - - return (len(bad) > 0) - - -def _run_regression_test(test): - """Run a single test. - - Arguments: - test -- the name of the test - """ - traces_dir = os.path.join("regression", "traces") - if os.path.exists(traces_dir): - files = os.listdir(traces_dir) - for file in files: - if file == '.' or file == '..': - continue - shutil.rmtree(os.path.join("traces", file), ignore_errors=True) - else: - os.mkdir(traces_dir) - - mod = __import__(test, globals(), locals(), []) - return mod.run(verbose=(Options.options.verbose > 0), - generate=Options.options.regression_generate) - + tasks.append(regression_test_task(bld.env, test, test_scripts_dir, build_traces_dir, reference_traces)) + regression_test_collector_task(tasks) diff --git a/regression/tests/test-csma-bridge.py b/regression/tests/test-csma-bridge.py index 67a1b4475..e0905d33e 100644 --- a/regression/tests/test-csma-bridge.py +++ b/regression/tests/test-csma-bridge.py @@ -2,15 +2,13 @@ """Generic trace-comparison-type regression test.""" -import os -import sys -import tracediff +import os.path -def run(verbose, generate): - """Execute a test.""" - if tracediff.env['ENABLE_PYTHON_BINDINGS']: - return tracediff.run_test(verbose, generate, - "csma-bridge", pyscript=os.path.join('examples', 'csma-bridge.py')) +def may_run(env): + """Returns 0 when it can run, return non-zero or string (reason) when it cannot run""" + if env['ENABLE_PYTHON_BINDINGS']: + return 0 else: - print >> sys.stderr, "Skipping csma-bridge: Python bindings not available." - raise NotImplementedError + return "Python bindings not available." + +pyscript = os.path.join('examples', 'csma-bridge.py') diff --git a/regression/tests/test-csma-broadcast.py b/regression/tests/test-csma-broadcast.py index b34d136dc..4c77bc125 100644 --- a/regression/tests/test-csma-broadcast.py +++ b/regression/tests/test-csma-broadcast.py @@ -2,11 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, "csma-broadcast") diff --git a/regression/tests/test-csma-multicast.py b/regression/tests/test-csma-multicast.py index c128f273b..b8afea9f8 100644 --- a/regression/tests/test-csma-multicast.py +++ b/regression/tests/test-csma-multicast.py @@ -1,12 +1,3 @@ #! /usr/bin/env python """Generic trace-comparison-type regression test.""" - -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, "csma-multicast") diff --git a/regression/tests/test-csma-one-subnet.py b/regression/tests/test-csma-one-subnet.py index b5d4645fc..4c77bc125 100644 --- a/regression/tests/test-csma-one-subnet.py +++ b/regression/tests/test-csma-one-subnet.py @@ -2,11 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, "csma-one-subnet") diff --git a/regression/tests/test-csma-packet-socket.py b/regression/tests/test-csma-packet-socket.py index ca71d7b9d..4c77bc125 100644 --- a/regression/tests/test-csma-packet-socket.py +++ b/regression/tests/test-csma-packet-socket.py @@ -2,12 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, - "csma-packet-socket") diff --git a/regression/tests/test-csma-ping.py b/regression/tests/test-csma-ping.py index 4cae6945f..4c77bc125 100644 --- a/regression/tests/test-csma-ping.py +++ b/regression/tests/test-csma-ping.py @@ -2,11 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, "csma-ping") diff --git a/regression/tests/test-csma-raw-ip-socket.py b/regression/tests/test-csma-raw-ip-socket.py index 3c45b023d..4c77bc125 100644 --- a/regression/tests/test-csma-raw-ip-socket.py +++ b/regression/tests/test-csma-raw-ip-socket.py @@ -2,11 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, "csma-raw-ip-socket") diff --git a/regression/tests/test-csma-star.py b/regression/tests/test-csma-star.py index 4e39f0443..4c77bc125 100644 --- a/regression/tests/test-csma-star.py +++ b/regression/tests/test-csma-star.py @@ -2,11 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, "csma-star") diff --git a/regression/tests/test-dynamic-global-routing.py b/regression/tests/test-dynamic-global-routing.py index 9a7ff13a3..4c77bc125 100644 --- a/regression/tests/test-dynamic-global-routing.py +++ b/regression/tests/test-dynamic-global-routing.py @@ -2,11 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, "dynamic-global-routing") diff --git a/regression/tests/test-global-routing-slash32.py b/regression/tests/test-global-routing-slash32.py index bf613b6e1..4c77bc125 100644 --- a/regression/tests/test-global-routing-slash32.py +++ b/regression/tests/test-global-routing-slash32.py @@ -2,11 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, "global-routing-slash32") diff --git a/regression/tests/test-ns2-mob.py b/regression/tests/test-ns2-mob.py index 6f5503590..7ed54ce01 100644 --- a/regression/tests/test-ns2-mob.py +++ b/regression/tests/test-ns2-mob.py @@ -2,11 +2,12 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff +import os.path -def run(verbose, generate): - """Execute a test.""" - arguments = ["../../../samples/ns2-mob.tr", "out.tr"] - return tracediff.run_test(verbose, generate, "main-ns2-mob", arguments=arguments) +program = "main-ns2-mob" + +def get_arguments(env, top_dir): + ns2_tracefile = os.path.abspath(os.path.join(top_dir, "samples", "ns2-mob.tr")) + return [ns2_tracefile, "out.tr"] + +trace_dir_name = "main-ns2-mob.ref" diff --git a/regression/tests/test-realtime-udp-echo.py b/regression/tests/test-realtime-udp-echo.py index b1344cdad..4c77bc125 100644 --- a/regression/tests/test-realtime-udp-echo.py +++ b/regression/tests/test-realtime-udp-echo.py @@ -2,11 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, "realtime-udp-echo") diff --git a/regression/tests/test-second.py b/regression/tests/test-second.py index 56dd9b5e5..4c77bc125 100644 --- a/regression/tests/test-second.py +++ b/regression/tests/test-second.py @@ -2,11 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, "second") diff --git a/regression/tests/test-simple-error-model.py b/regression/tests/test-simple-error-model.py index 6a9dece25..4c77bc125 100644 --- a/regression/tests/test-simple-error-model.py +++ b/regression/tests/test-simple-error-model.py @@ -2,12 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, - "simple-error-model") diff --git a/regression/tests/test-simple-global-routing.py b/regression/tests/test-simple-global-routing.py index 271fb8f85..4c77bc125 100644 --- a/regression/tests/test-simple-global-routing.py +++ b/regression/tests/test-simple-global-routing.py @@ -2,12 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, - "simple-global-routing") diff --git a/regression/tests/test-simple-point-to-point-olsr.py b/regression/tests/test-simple-point-to-point-olsr.py index b581b876f..4c77bc125 100644 --- a/regression/tests/test-simple-point-to-point-olsr.py +++ b/regression/tests/test-simple-point-to-point-olsr.py @@ -2,12 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, - "simple-point-to-point-olsr") diff --git a/regression/tests/test-static-routing-slash32.py b/regression/tests/test-static-routing-slash32.py index 6ac8550cc..4c77bc125 100644 --- a/regression/tests/test-static-routing-slash32.py +++ b/regression/tests/test-static-routing-slash32.py @@ -2,11 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, "static-routing-slash32") diff --git a/regression/tests/test-tcp-large-transfer.py b/regression/tests/test-tcp-large-transfer.py index 3078fa69d..4c77bc125 100644 --- a/regression/tests/test-tcp-large-transfer.py +++ b/regression/tests/test-tcp-large-transfer.py @@ -2,12 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, - "tcp-large-transfer") diff --git a/regression/tests/test-tcp-nsc-lfn.py b/regression/tests/test-tcp-nsc-lfn.py index bff77dfd0..b58d4b227 100644 --- a/regression/tests/test-tcp-nsc-lfn.py +++ b/regression/tests/test-tcp-nsc-lfn.py @@ -2,32 +2,25 @@ """Trace-comparison-type regression test for the Network Simulation Cradle.""" -import os -import shutil -import sys -import tracediff import platform -def run(verbose, generate): - """Run a Network Simulation Cradle test involving two TCP streams.""" - - if not tracediff.env['ENABLE_NSC']: - print >>sys.stderr, "Skipping tcp-nsc-lfn: NSC not available." - raise NotImplementedError - - testName = "tcp-nsc-lfn" - arguments = ["--ns3::OnOffApplication::DataRate=40000", "--runtime=20"] - platform_bits = platform.architecture()[0] - - if platform_bits == "64bit": - traceDirName = testName + "_64bit.ref" - elif platform_bits == "32bit": - traceDirName = testName + "_32bit.ref" +def may_run(env): + if not env['NSC_ENABLED']: + return "NSC not available" else: - # Something unexpected. How should we signal an error here? Rasing a - # string might not be the best idea? - raise "Unknown architecture, not 64 or 32 bit?" + return 0 + + +platform_bits = platform.architecture()[0] +if platform_bits == "64bit": + trace_dir_name = "tcp-nsc-lfn_64bit.ref" +elif platform_bits == "32bit": + trace_dir_name = "tcp-nsc-lfn_32bit.ref" +else: + raise AssertionError("Unknown architecture, not 64 or 32 bit?") +del platform_bits + +arguments = ["--ns3::OnOffApplication::DataRate=40000", "--runtime=20"] + - return tracediff.run_test(verbose, generate, - testName, arguments=arguments, refTestName=traceDirName) diff --git a/regression/tests/test-third.py b/regression/tests/test-third.py index 582e8b44a..4c77bc125 100644 --- a/regression/tests/test-third.py +++ b/regression/tests/test-third.py @@ -2,11 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, "third") diff --git a/regression/tests/test-udp-echo.py b/regression/tests/test-udp-echo.py index 6fe71055a..4c77bc125 100644 --- a/regression/tests/test-udp-echo.py +++ b/regression/tests/test-udp-echo.py @@ -2,11 +2,3 @@ """Generic trace-comparison-type regression test.""" -import os -import shutil -import tracediff - -def run(verbose, generate): - """Execute a test.""" - #print tracediff.env - return tracediff.run_test(verbose, generate, "udp-echo") diff --git a/regression/tests/test-wifi-wired-bridging.py b/regression/tests/test-wifi-wired-bridging.py index 9ff8ae0e5..263c2c892 100644 --- a/regression/tests/test-wifi-wired-bridging.py +++ b/regression/tests/test-wifi-wired-bridging.py @@ -2,11 +2,5 @@ """Compare that Wifi-Wired Bridging generates correct traces.""" -import os -import shutil -import tracediff +arguments = ["--SendIp=0"] -def run(verbose, generate): - """Execute a test.""" - - return tracediff.run_test(verbose, generate, "wifi-wired-bridging", ["--SendIp=0"]) diff --git a/samples/wscript b/samples/wscript index 5286f56c9..deba5598e 100644 --- a/samples/wscript +++ b/samples/wscript @@ -19,7 +19,7 @@ def build(bld): obj = bld.create_ns3_program('main-test') obj.source = 'main-test.cc' - if bld.env['ENABLE_THREADING']: + if bld.env['ENABLE_THREADING'] and bld.env["ENABLE_REAL_TIME"]: obj = bld.create_ns3_program('main-test-sync') obj.source = 'main-test-sync.cc' diff --git a/src/core/wscript b/src/core/wscript index cdcd0bc31..a15b6fee6 100644 --- a/src/core/wscript +++ b/src/core/wscript @@ -1,6 +1,6 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- import sys - +import Options def configure(conf): if conf.check(header_name='stdlib.h'): @@ -9,9 +9,33 @@ def configure(conf): conf.check(header_name='signal.h', define_name='HAVE_SIGNAL_H') - conf.check(lib='rt', uselib='RT', define_name='HAVE_RT') + # Check for POSIX threads + test_env = conf.env.copy() + if Options.platform != 'darwin': + test_env.append_value('LINKFLAGS', '-pthread') + test_env.append_value('CXXFLAGS', '-pthread') + test_env.append_value('CCFLAGS', '-pthread') + fragment = r""" +#include +int main () +{ + pthread_mutex_t m; + pthread_mutex_init (&m, NULL); + return 0; +} +""" + have_pthread = conf.check(header_name='pthread.h', define_name='HAVE_PTHREAD_H', + env=test_env, fragment=fragment, + errmsg='Could not find pthread support (build/config.log for details)', + mandatory=False) + if have_pthread: + # darwin accepts -pthread but prints a warning saying it is ignored + if Options.platform != 'darwin': + conf.env['CXXFLAGS_PTHREAD'] = '-pthread' + conf.env['CCFLAGS_PTHREAD'] = '-pthread' + conf.env['LINKFLAGS_PTHREAD'] = '-pthread' - conf.env['ENABLE_THREADING'] = conf.check(header_name='pthread.h', define_name='HAVE_PTHREAD_H') + conf.env['ENABLE_THREADING'] = have_pthread conf.report_optional_feature("Threading", "Threading Primitives", conf.env['ENABLE_THREADING'], @@ -55,7 +79,6 @@ def build(bld): 'callback.cc', 'names.cc', ] - core.uselib = 'RT' headers = bld.new_task_gen('ns3header') headers.module = 'core' @@ -117,6 +140,7 @@ def build(bld): 'unix-system-mutex.cc', 'unix-system-condition.cc', ]) + core.uselib = 'PTHREAD' headers.source.extend([ 'system-mutex.h', 'system-thread.h', diff --git a/src/devices/emu/wscript b/src/devices/emu/wscript index 8400d1288..53761d516 100644 --- a/src/devices/emu/wscript +++ b/src/devices/emu/wscript @@ -1,11 +1,16 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- def configure(conf): - conf.env['ENABLE_EMU'] = conf.check(header_name='linux/if_ether.h', - define_name='HAVE_IF_ETHER_H') - conf.report_optional_feature("EmuNetDevice", "Emulated Net Device", - conf.env['ENABLE_EMU'], - " include not detected") + if conf.env['ENABLE_THREADING']: + conf.env['ENABLE_EMU'] = conf.check(header_name='linux/if_ether.h', + define_name='HAVE_IF_ETHER_H') + conf.report_optional_feature("EmuNetDevice", "Emulated Net Device", + conf.env['ENABLE_EMU'], + " include not detected") + else: + conf.report_optional_feature("EmuNetDevice", "Emulated Net Device", + False, + "needs threading support which is not available") def build(bld): module = bld.create_ns3_module('emu', ['node']) diff --git a/src/devices/wifi/wifi.h b/src/devices/wifi/wifi.h index 3ced79bf5..38df2a3a4 100644 --- a/src/devices/wifi/wifi.h +++ b/src/devices/wifi/wifi.h @@ -105,4 +105,7 @@ * Finally, we provide access to the per-remote-station SLRC couter that * indications the number of retransmissions of data. Changes to this * counter are traced using the ns3::WifiRemoteStation::m_slrc source. + * + * \subsection wifil2stack Layer 2 Stack Overview + * \image html WifiArchitecture.png "Overview of the Wifi L2 sublayers traversed for transmitting and receiving a packet" */ diff --git a/src/internet-stack/wscript b/src/internet-stack/wscript index 9f2ef127f..b2989d18e 100644 --- a/src/internet-stack/wscript +++ b/src/internet-stack/wscript @@ -29,16 +29,22 @@ def configure(conf): # conf.check_tool('flex bison') # conf.check(lib='fl', mandatory=True) - if not Options.options.with_nsc: - conf.report_optional_feature("nsc", "Network Simulation Cradle", False, - "--with-nsc configure option not given") - return - - #check_nsc_buildutils() + # Check for the location of NSC if Options.options.with_nsc: - if not os.path.isdir(Options.options.with_nsc): - raise Utils.WafError("--with-nsc nsc path %r does not exist" % Options.options.with_nsc) - conf.env['WITH_NSC'] = Options.options.with_nsc + if os.path.isdir(Options.options.with_nsc): + conf.check_message("NSC location", '', True, ("%s (given)" % Options.options.with_nsc)) + conf.env['WITH_NSC'] = os.path.abspath(Options.options.with_nsc) + else: + nsc_dir = os.path.join('..', "nsc") + if os.path.isdir(nsc_dir): + conf.check_message("NSC location", '', True, ("%s (guessed)" % nsc_dir)) + conf.env['WITH_NSC'] = os.path.abspath(nsc_dir) + del nsc_dir + if not conf.env['WITH_NSC']: + conf.check_message("NSC location", '', False) + conf.report_optional_feature("nsc", "Network Simulation Cradle", False, + "NSC not found (see option --with-nsc)") + return arch = os.uname()[4] ok = False diff --git a/src/simulator/wscript b/src/simulator/wscript index 1824bd486..e4ae5c0b8 100644 --- a/src/simulator/wscript +++ b/src/simulator/wscript @@ -33,9 +33,14 @@ def configure(conf): conf.write_config_header('ns3/simulator-config.h') - conf.report_optional_feature("RealTime", "Real Time Simulator", - conf.env['ENABLE_THREADING'], - "threading not enabled") + if not conf.check(lib='rt', uselib='RT', define_name='HAVE_RT'): + conf.report_optional_feature("RealTime", "Real Time Simulator", + False, "librt is not available") + else: + conf.report_optional_feature("RealTime", "Real Time Simulator", + conf.env['ENABLE_THREADING'], + "threading not enabled") + conf.env["ENABLE_REAL_TIME"] = conf.env['ENABLE_THREADING'] def build(bld): @@ -101,7 +106,7 @@ def build(bld): 'cairo-wideint-private.h', ]) - if env['ENABLE_THREADING']: + if env['ENABLE_REAL_TIME']: headers.source.extend([ 'realtime-simulator-impl.h', 'wall-clock-synchronizer.h', @@ -110,4 +115,6 @@ def build(bld): 'realtime-simulator-impl.cc', 'wall-clock-synchronizer.cc', ]) + sim.uselib = 'RT' + diff --git a/src/wscript b/src/wscript index df774e0e8..d91e6b8cc 100644 --- a/src/wscript +++ b/src/wscript @@ -9,10 +9,7 @@ import TaskGen import Task import Options import Build -#import Action -#import Common -#import Object -#import Params +from Utils import md5 all_modules = ( @@ -177,6 +174,21 @@ class gen_ns3_module_header_task(Task.Task): outfile.close() return 0 + def sig_explicit_deps(self): + m = md5() + m.update('\n'.join([node.abspath(self.env) for node in self.inputs])) + return m.digest() + + def unique_id(self): + try: + return self.uid + except AttributeError: + "this is not a real hot zone, but we want to avoid surprizes here" + m = md5() + m.update("ns-3-module-header-%s" % self.module) + self.uid = m.digest() + return self.uid + class ns3moduleheader_taskgen(TaskGen.task_gen): """ diff --git a/wscript b/wscript index 6197d4304..2c372ef1b 100644 --- a/wscript +++ b/wscript @@ -42,6 +42,14 @@ APPNAME = 'ns' wutils.VERSION = VERSION wutils.APPNAME = APPNAME +# +# The last part of the path name to use to find the regression traces. The +# path will be APPNAME + '-' + VERSION + REGRESSION_SUFFIX, e.g., +# ns-3-dev-ref-traces +# +REGRESSION_SUFFIX = "-ref-traces" + + # these variables are mandatory ('/' are converted automatically) srcdir = '.' blddir = 'build' @@ -193,8 +201,19 @@ def configure(conf): variant_env = conf.env.copy() variant_name = Options.options.build_profile + # Check for the location of regression reference traces if Options.options.regression_traces is not None: - variant_env['REGRESSION_TRACES'] = os.path.abspath(Options.options.regression_traces) + if os.path.isdir(Options.options.regression_traces): + conf.check_message("regression traces location", '', True, ("%s (given)" % Options.options.regression_traces)) + variant_env['REGRESSION_TRACES'] = os.path.abspath(Options.options.regression_traces) + else: + traces = os.path.join('..', "%s-%s%s" % (APPNAME, VERSION, REGRESSION_SUFFIX)) + if os.path.isdir(traces): + conf.check_message("regression reference traces", '', True, ("%s (guessed)" % traces)) + variant_env['REGRESSION_TRACES'] = os.path.abspath(traces) + del traces + if not variant_env['REGRESSION_TRACES']: + conf.check_message("regression reference traces", '', False) if Options.options.enable_gcov: variant_name += '-gcov' @@ -242,6 +261,8 @@ def configure(conf): # we cannot pull regression traces without mercurial conf.find_program('hg', var='MERCURIAL') + conf.find_program('valgrind', var='VALGRIND') + # Write a summary of optional features status print "---- Summary of optional NS-3 features:" for (name, caption, was_enabled, reason_not_enabled) in conf.env['NS3_OPTIONAL_FEATURES']: @@ -407,7 +428,7 @@ def build(bld): if Options.options.run: # Check that the requested program name is valid - program_name, dummy_program_argv = wutils.get_run_program(Options.options.run, get_command_template()) + program_name, dummy_program_argv = wutils.get_run_program(Options.options.run, wutils.get_command_template(env)) # When --run'ing a program, tell WAF to only build that program, # nothing more; this greatly speeds up compilation when all you @@ -415,26 +436,6 @@ def build(bld): if not Options.options.compile_targets: Options.options.compile_targets = os.path.basename(program_name) - - -def get_command_template(*arguments): - if Options.options.valgrind: - if Options.options.command_template: - raise Utils.WafError("Options --command-template and --valgrind are conflicting") - cmd = "valgrind --leak-check=full %s" - else: - cmd = Options.options.command_template or '%s' - for arg in arguments: - cmd = cmd + " " + arg - return cmd - - -def shutdown(): - env = Build.bld.env - - if Options.commands['check']: - _run_waf_check() - if Options.options.regression or Options.options.regression_generate: if not env['DIFF']: raise Utils.WafError("Cannot run regression tests: the 'diff' program is not installed.") @@ -443,15 +444,20 @@ def shutdown(): if not regression_traces: raise Utils.WafError("Cannot run regression tests: reference traces directory not given" " (--with-regression-traces configure option)") - retval = regression.run_regression(regression_traces) - if retval: - sys.exit(retval) + regression.run_regression(bld, regression_traces) + + +def shutdown(): + env = Build.bld.env + + if Options.commands['check']: + _run_waf_check() if Options.options.lcov_report: lcov_report() if Options.options.run: - wutils.run_program(Options.options.run, get_command_template()) + wutils.run_program(Options.options.run, wutils.get_command_template(env)) raise SystemExit(0) if Options.options.pyrun: @@ -476,7 +482,7 @@ def _run_waf_check(): out.close() print "-- Running NS-3 C++ core unit tests..." - wutils.run_program('run-tests', get_command_template()) + wutils.run_program('run-tests', wutils.get_command_template(env)) if env['ENABLE_PYTHON_BINDINGS']: print "-- Running NS-3 Python bindings unit tests..." diff --git a/wutils.py b/wutils.py index 9cebb2a5d..4e29cfd07 100644 --- a/wutils.py +++ b/wutils.py @@ -26,11 +26,13 @@ TRACEBALL_SUFFIX = ".tar.bz2" -def get_command_template(*arguments): +def get_command_template(env, arguments=()): if Options.options.valgrind: if Options.options.command_template: raise Utils.WafError("Options --command-template and --valgrind are conflicting") - cmd = "valgrind --leak-check=full %s" + if not env['VALGRIND']: + raise Utils.WafError("valgrind is not installed") + cmd = env['VALGRIND'] + " --leak-check=full --error-exitcode=1 %s" else: cmd = Options.options.command_template or '%s' for arg in arguments: