diff --git a/bindings/python/ns3modulegen.py b/bindings/python/ns3modulegen.py index c38185f95..a54fb5768 100755 --- a/bindings/python/ns3modulegen.py +++ b/bindings/python/ns3modulegen.py @@ -137,7 +137,7 @@ def main(): root_module.classes.remove(root_module['ns3::%s' % clsname]) if 'RealTime' not in enabled_features: - for clsname in ['WallClockSynchronizer', 'RealtimeSimulatorImpl', 'RealtimeEventLock']: + for clsname in ['WallClockSynchronizer', 'RealtimeSimulatorImpl']: root_module.classes.remove(root_module['ns3::%s' % clsname]) root_module.enums.remove(root_module['ns3::RealtimeSimulatorImpl::SynchronizationMode']) @@ -146,5 +146,14 @@ def main(): out.close() if __name__ == '__main__': - main() + if 0: + try: + import cProfile as profile + except ImportError: + main() + else: + print >> sys.stderr, "** running under profiler" + profile.run('main()', 'ns3modulegen.pstat') + else: + main() diff --git a/bindings/python/wscript b/bindings/python/wscript index 794334f7d..69825e2b6 100644 --- a/bindings/python/wscript +++ b/bindings/python/wscript @@ -14,11 +14,6 @@ import Logs import Build import Utils -## Adjust python path to look for our local copy of pybindgen -LOCAL_PYBINDGEN_PATH = os.path.join(os.getcwd(), "bindings", "python", "pybindgen") -#PYBINDGEN_BRANCH = 'lp:pybindgen' -PYBINDGEN_BRANCH = 'https://launchpad.net/pybindgen' - ## https://launchpad.net/pybindgen/ REQUIRED_PYBINDGEN_VERSION = (0, 9, 0, 605) REQUIRED_PYGCCXML_VERSION = (0, 9, 5) @@ -33,8 +28,6 @@ def add_to_python_path(path): def set_pybindgen_pythonpath(env): if env['WITH_PYBINDGEN']: add_to_python_path(env['WITH_PYBINDGEN']) - else: - add_to_python_path(LOCAL_PYBINDGEN_PATH) def set_options(opt): @@ -47,67 +40,11 @@ def set_options(opt): help=("Rescan Python bindings. Needs working GCCXML / pygccxml environment."), action="store_true", default=False, dest='python_scan') - opt.add_option('--pybindgen-checkout', - help=("During configure, force checkout of pybingen inside ns-3, " - "instead of using the system installed version."), - action="store_true", default=False, - dest='pybindgen_checkout') opt.add_option('--with-pybindgen', help=('Path to an existing pybindgen source tree to use.'), default=None, dest='with_pybindgen', type="string") -def fetch_pybindgen(conf): - """ - Fetches pybindgen from launchpad as bindings/python/pybindgen. - Returns True if successful, False it not. - """ - bzr = conf.find_program("bzr") - if not bzr: - Logs.warn("the program 'bzr' is needed in order to fetch pybindgen") - return False - if len(REQUIRED_PYBINDGEN_VERSION) == 4: - rev = "-rrevno:%i" % REQUIRED_PYBINDGEN_VERSION[3] - else: - rev = "-rtag:%s" % '.'.join([str(x) for x in REQUIRED_PYBINDGEN_VERSION]) - - if os.path.exists(LOCAL_PYBINDGEN_PATH): - print "Trying to update pybindgen; this will fail if no network connection is available. Hit Ctrl-C to skip." - - cmd = [bzr, "pull", rev, PYBINDGEN_BRANCH] - print " => ", ' '.join(cmd) - try: - if subprocess.Popen(cmd, cwd=LOCAL_PYBINDGEN_PATH).wait(): - return False - except KeyboardInterrupt: - print "Interrupted; Python bindings will be disabled." - return False - print "Update was successful." - else: - print "Trying to fetch pybindgen; this will fail if no network connection is available. Hit Ctrl-C to skip." - cmd = [bzr, "checkout", rev, PYBINDGEN_BRANCH, LOCAL_PYBINDGEN_PATH] - print " => ", ' '.join(cmd) - try: - if subprocess.Popen(cmd).wait(): - return False - except KeyboardInterrupt: - print "Interrupted; Python bindings will be disabled." - shutil.rmtree(LOCAL_PYBINDGEN_PATH, True) - return False - print "Fetch was successful." - - ## generate a fake version.py file in pybindgen it's safer this - ## way, since the normal version generation process requires - ## bazaar python bindings, which may not be available. - vfile = open(os.path.join(LOCAL_PYBINDGEN_PATH, "pybindgen", "version.py"), "wt") - vfile.write(""" -# (fake version generated by ns-3) -__version__ = %r -""" % list(REQUIRED_PYBINDGEN_VERSION)) - vfile.close() - - return True - def configure(conf): conf.env['ENABLE_PYTHON_BINDINGS'] = False @@ -140,9 +77,6 @@ def configure(conf): conf.env['WITH_PYBINDGEN'] = os.path.abspath(Options.options.with_pybindgen) no_net = True - if Options.options.pybindgen_checkout: - fetch_pybindgen(conf) - set_pybindgen_pythonpath(conf.env) try: @@ -484,7 +418,8 @@ def build(bld): bindgen = bld.new_task_gen('command', source=source, target=target, command=argv, variables=dict(FEATURES=(','.join(features)))) - + bindgen.before = 'cxx' + bindgen.after = 'gen_everything_h_task' ## we build python bindings if either we have the tools to ## generate them or if the pregenerated source file is already @@ -499,7 +434,15 @@ def build(bld): pymod.target = 'ns3/_ns3' pymod.name = 'ns3module' pymod.uselib_local = "ns3" - pymod.env.append_value('CXXDEFINES', ['NS_DEPRECATED=', 'NS3_DEPRECATED_H']) + + defines = list(pymod.env['CXXDEFINES']) + defines.extend(['NS_DEPRECATED=', 'NS3_DEPRECATED_H']) + if Options.platform == 'win32': + try: + defines.remove('_DEBUG') # causes undefined symbols on win32 + except ValueError: + pass + pymod.env['CXXDEFINES'] = defines # copy the __init__.py file to the build dir. waf can't handle # this, it's against waf's principles to have build dir files diff --git a/examples/wifi-ap.py b/examples/wifi-ap.py new file mode 100644 index 000000000..75f180d48 --- /dev/null +++ b/examples/wifi-ap.py @@ -0,0 +1,166 @@ +# -*- Mode: Python; -*- +# /* +# * Copyright (c) 2005,2006,2007 INRIA +# * Copyright (c) 2009 INESC Porto +# * +# * 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 +# * +# * Authors: Mathieu Lacage +# * Gustavo Carneiro +# */ + +import sys +import ns3 + +# void +# DevTxTrace (std::string context, Ptr p, Mac48Address address) +# { +# std::cout << " TX to=" << address << " p: " << *p << std::endl; +# } +# void +# DevRxTrace (std::string context, Ptr p, Mac48Address address) +# { +# std::cout << " RX from=" << address << " p: " << *p << std::endl; +# } +# void +# PhyRxOkTrace (std::string context, Ptr packet, double snr, WifiMode mode, enum WifiPreamble preamble) +# { +# std::cout << "PHYRXOK mode=" << mode << " snr=" << snr << " " << *packet << std::endl; +# } +# void +# PhyRxErrorTrace (std::string context, Ptr packet, double snr) +# { +# std::cout << "PHYRXERROR snr=" << snr << " " << *packet << std::endl; +# } +# void +# PhyTxTrace (std::string context, Ptr packet, WifiMode mode, WifiPreamble preamble, uint8_t txPower) +# { +# std::cout << "PHYTX mode=" << mode << " " << *packet << std::endl; +# } +# void +# PhyStateTrace (std::string context, Time start, Time duration, enum WifiPhy::State state) +# { +# std::cout << " state="; +# switch (state) { +# case WifiPhy::TX: +# std::cout << "tx "; +# break; +# case WifiPhy::SYNC: +# std::cout << "sync "; +# break; +# case WifiPhy::CCA_BUSY: +# std::cout << "cca-busy"; +# break; +# case WifiPhy::IDLE: +# std::cout << "idle "; +# break; +# } +# std::cout << " start="< /dev/null 2>&1") - if pyscript is None: - Options.options.cwd_launch = traceDirName - wutils.run_program(testName, command_template=wutils.get_command_template(*arguments)) + 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 - before = os.getcwd() - os.chdir(traceDirName) - try: - wutils.run_argv(argv) - finally: - os.chdir(before) + wutils.run_argv(argv, cwd=traceDirName) if verbose: #diffCmd = "diff traces " + refTestDirName + " | head" @@ -179,22 +139,15 @@ def _find_tests(testdir): def run_regression(reference_traces): """Execute regression tests. Called with cwd set to the 'regression' subdir of ns-3. - @param reference_traces: reference traces directory, or None for default. + @param reference_traces: reference traces directory. """ - testdir = "tests" + testdir = os.path.join("regression", "tests") if not os.path.exists(testdir): print "Tests directory does not exist" sys.exit(3) - dir_name = (wutils.APPNAME + '-' + wutils.VERSION + REGRESSION_SUFFIX) - if reference_traces is None: - reference_traces = dir_name - no_net = False - else: - no_net = True - sys.path.append(testdir) sys.modules['tracediff'] = Regression(testdir, reference_traces) @@ -205,32 +158,6 @@ def run_regression(reference_traces): print "========== Running Regression Tests ==========" env = Build.bld.env - if not no_net: - if env['MERCURIAL']: - print "Synchronizing reference traces using Mercurial." - if not os.path.exists(reference_traces): - print "Cloning " + REGRESSION_TRACES_REPO + dir_name + " from repo." - argv = ["hg", "clone", REGRESSION_TRACES_REPO + dir_name, reference_traces] - rv = subprocess.Popen(argv).wait() - else: - _dir = os.getcwd() - os.chdir(reference_traces) - try: - print "Pulling " + REGRESSION_TRACES_REPO + dir_name + " from repo." - result = subprocess.Popen(["hg", "-q", "pull", REGRESSION_TRACES_REPO + dir_name]).wait() - if not result: - result = subprocess.Popen(["hg", "-q", "update"]).wait() - finally: - os.chdir("..") - if result: - raise Utils.WafError("Synchronizing reference traces using Mercurial failed.") - else: - if not os.path.exists(reference_traces): - traceball = dir_name + wutils.TRACEBALL_SUFFIX - print "Retrieving " + traceball + " from web." - urllib.urlretrieve(REGRESSION_TRACES_URL + traceball, traceball) - os.system("tar -xjf %s -C .." % (traceball)) - print "Done." if not os.path.exists(reference_traces): print "Reference traces directory (%s) does not exist" % reference_traces @@ -252,7 +179,7 @@ def run_regression(reference_traces): except NotImplementedError: print "SKIP " + test - return len(bad) > 0 + return (len(bad) > 0) def _run_regression_test(test): @@ -261,15 +188,15 @@ def _run_regression_test(test): Arguments: test -- the name of the test """ - - if os.path.exists("traces"): - files = os.listdir("traces") + 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") + os.mkdir(traces_dir) mod = __import__(test, globals(), locals(), []) return mod.run(verbose=(Options.options.verbose > 0), diff --git a/samples/wscript b/samples/wscript index d1c1e8fa1..5286f56c9 100644 --- a/samples/wscript +++ b/samples/wscript @@ -19,8 +19,9 @@ def build(bld): obj = bld.create_ns3_program('main-test') obj.source = 'main-test.cc' - obj = bld.create_ns3_program('main-test-sync') - obj.source = 'main-test-sync.cc' + if bld.env['ENABLE_THREADING']: + obj = bld.create_ns3_program('main-test-sync') + obj.source = 'main-test-sync.cc' obj = bld.create_ns3_program('main-simple', ['node', 'internet-stack', 'onoff']) diff --git a/src/common/pcap-writer.cc b/src/common/pcap-writer.cc index 56ec492d3..0c8175fa5 100644 --- a/src/common/pcap-writer.cc +++ b/src/common/pcap-writer.cc @@ -86,7 +86,7 @@ PcapWriter::Open (std::string const &name) NS_LOG_LOGIC ("Created writer " << m_writer); - m_writer->open (name.c_str ()); + m_writer->open (name.c_str (), std::ios_base::binary | std::ios_base::out); NS_ABORT_MSG_IF (m_writer->fail (), "PcapWriter::Open(): m_writer->open(" << name.c_str () << ") failed"); NS_ASSERT_MSG (m_writer->is_open (), "PcapWriter::Open(): m_writer not open"); diff --git a/src/devices/wifi/wifi-mac-queue.cc b/src/devices/wifi/wifi-mac-queue.cc index ec300b76a..ab7d5e30b 100644 --- a/src/devices/wifi/wifi-mac-queue.cc +++ b/src/devices/wifi/wifi-mac-queue.cc @@ -28,6 +28,9 @@ using namespace std; namespace ns3 { +NS_OBJECT_ENSURE_REGISTERED (WifiMacQueue); + + WifiMacQueue::Item::Item (Ptr packet, WifiMacHeader const &hdr, Time tstamp) @@ -37,7 +40,7 @@ WifiMacQueue::Item::Item (Ptr packet, TypeId WifiMacQueue::GetTypeId (void) { - static TypeId tid = TypeId ("WifiMacQueue") + static TypeId tid = TypeId ("ns3::WifiMacQueue") .SetParent () .AddConstructor () .AddAttribute ("MaxPacketNumber", "If a packet arrives when there are already this number of packets, it is dropped.", diff --git a/src/simulator/calendar-scheduler.cc b/src/simulator/calendar-scheduler.cc index 904ecfcf2..a1ff087d0 100644 --- a/src/simulator/calendar-scheduler.cc +++ b/src/simulator/calendar-scheduler.cc @@ -331,6 +331,7 @@ CalendarScheduler::DoResize (uint32_t newSize, uint32_t newWidth) DoInsert (*j); } } + delete [] oldBuckets; } void CalendarScheduler::Resize (uint32_t newSize) diff --git a/src/simulator/ns2-calendar-scheduler.cc b/src/simulator/ns2-calendar-scheduler.cc new file mode 100644 index 000000000..d2cc19e75 --- /dev/null +++ b/src/simulator/ns2-calendar-scheduler.cc @@ -0,0 +1,495 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; -*- */ +/* + * Copyright (c) 1997 David Wetherall + * Copyright (c) 2005 David Wei + * Copyright (c) 2009 INRIA + * + * 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 "ns2-calendar-scheduler.h" +#include "event-impl.h" +#include "ns3/assert.h" +#include "ns3/log.h" +#include +#include +#include + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("Ns2CalendarScheduler"); + +NS_OBJECT_ENSURE_REGISTERED (Ns2CalendarScheduler); + +#define CALENDAR_HASH(key) ((key.m_ts / width_) % nbuckets_) + +TypeId +Ns2CalendarScheduler::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::Ns2CalendarScheduler") + .SetParent () + .AddConstructor () + ; + return tid; +} + +Ns2CalendarScheduler::Ns2CalendarScheduler () +{ + NS_LOG_FUNCTION (this); + + adjust_new_width_interval_ = 10; + min_bin_width_ = 1; + avg_gap_ = -2; + last_time_ = 0; + gap_num_ = 0; + head_search_ = 0; + insert_search_ = 0; + round_num_ = 0; + time_to_newwidth_ = adjust_new_width_interval_; + cal_clock_ = Scheduler::EventKey (); + reinit(4, 1, cal_clock_); +} +Ns2CalendarScheduler::~Ns2CalendarScheduler () +{ + NS_LOG_FUNCTION (this); + + for (int i = 0; i < nbuckets_; i++) { + Bucket *bucket = &buckets_[i]; + if (bucket->list_ == 0) { + continue; + } + if (bucket->list_->next_ == bucket->list_) { + delete bucket->list_; + continue; + } + BucketItem *next; + BucketItem *cur; + for (cur = bucket->list_; + cur->next_ != bucket->list_; + cur = next) { + next = cur->next_; + delete cur; + } + delete cur; + } + delete [] buckets_; + qsize_ = 0; + stat_qsize_ = 0; +} +void +Ns2CalendarScheduler::Insert (const Event &event) +{ + NS_LOG_FUNCTION (this); + + Scheduler::EventKey newtime = event.key; + int i = CALENDAR_HASH(newtime); + + Bucket* current=(&buckets_[i]); + BucketItem *head = current->list_; + BucketItem *after=0; + BucketItem *e = new BucketItem (); + e->event = event; + + if (!head) { + current->list_ = e; + e->next_ = e->prev_ = e; + ++stat_qsize_; + ++(current->count_); + } else { + insert_search_++; + if (newtime < head->event.key) { + // e-> head -> ... + e->next_ = head; + e->prev_ = head->prev_; + e->prev_->next_ = e; + head->prev_ = e; + current->list_ = e; + ++stat_qsize_; + ++(current->count_); + } else { + for (after = head->prev_; newtime < after->event.key; after = after->prev_) + { insert_search_++; }; + //...-> after -> e -> ... + e->next_ = after->next_; + e->prev_ = after; + e->next_->prev_ = e; + after->next_ = e; + if (after->event.key < newtime) { + //unique timing + ++stat_qsize_; + ++(current->count_); + } + } + } + ++qsize_; + //assert(e == buckets_[i].list_ || e->prev_->time_ <= e->time_); + //assert(e == buckets_[i].list_->prev_ || e->next_->time_ >= e->time_); + + if (stat_qsize_ > top_threshold_) { + resize(nbuckets_ << 1, cal_clock_); + return; + } +} +bool +Ns2CalendarScheduler::IsEmpty (void) const +{ + return qsize_ == 0; +} +Scheduler::Event +Ns2CalendarScheduler::PeekNext (void) const +{ + NS_LOG_FUNCTION (this); + NS_ASSERT (!IsEmpty ()); + + BucketItem *e = const_cast (this)->head (); + NS_ASSERT (e != 0); + + return e->event; +} + + +Scheduler::Event +Ns2CalendarScheduler::RemoveNext (void) +{ + NS_LOG_FUNCTION (this); + NS_ASSERT (!IsEmpty ()); + + BucketItem *e = head (); + NS_ASSERT (e != 0); + + if (last_time_ == 0) last_time_ = e->event.key.m_ts; + else + { + gap_num_ ++; + if (gap_num_ >= qsize_ ) { + uint64_t tt_gap_ = e->event.key.m_ts - last_time_; + avg_gap_ = tt_gap_ / gap_num_; + gap_num_ = 0; + last_time_ = e->event.key.m_ts; + round_num_ ++; + if ((round_num_ > 20) && + (( head_search_> (insert_search_<<1)) + ||( insert_search_> (head_search_<<1)) )) + { + resize(nbuckets_, cal_clock_); + round_num_ = 0; + } else { + if (round_num_ > 100) { + round_num_ = 0; + head_search_ = 0; + insert_search_ = 0; + } + } + } + } + + int l = lastbucket_; + + // update stats and unlink + if (e->next_ == e || e->next_->event.key != e->event.key) { + --stat_qsize_; + //assert(stat_qsize_ >= 0); + --buckets_[l].count_; + //assert(buckets_[l].count_ >= 0); + } + --qsize_; + + if (e->next_ == e) + buckets_[l].list_ = 0; + else { + e->next_->prev_ = e->prev_; + e->prev_->next_ = e->next_; + buckets_[l].list_ = e->next_; + } + + e->next_ = e->prev_ = NULL; + + + //if (buckets_[l].count_ == 0) + // assert(buckets_[l].list_ == 0); + + if (stat_qsize_ < bot_threshold_) { + resize(nbuckets_ >> 1, cal_clock_); + } + + Scheduler::Event event = e->event; + delete e; + return event; +} + +void +Ns2CalendarScheduler::Remove (const Event &ev) +{ + NS_ASSERT (!IsEmpty ()); + + + int i = CALENDAR_HASH(ev.key); + + Bucket* current=(&buckets_[i]); + BucketItem *head = current->list_; + BucketItem *e=0; + + if (!head) { + NS_LOG_DEBUG ("event not in scheduler"); + return; + } + for (e = head->prev_; ev.key != e->event.key; e = e->prev_) {} + --stat_qsize_; + --buckets_[i].count_; + if (e->next_ == e) { + assert(buckets_[i].list_ == e); + buckets_[i].list_ = 0; + } else { + e->next_->prev_ = e->prev_; + e->prev_->next_ = e->next_; + if (buckets_[i].list_ == e) + buckets_[i].list_ = e->next_; + } + + if (buckets_[i].count_ == 0) + assert(buckets_[i].list_ == 0); + + e->next_ = e->prev_ = NULL; + + delete e; + + --qsize_; + + return; +} + +Ns2CalendarScheduler::BucketItem * +Ns2CalendarScheduler::head (void) +{ + NS_ASSERT (!IsEmpty ()); + + int l = -1, i = lastbucket_; + int lastbucket_dec = (lastbucket_) ? lastbucket_ - 1 : nbuckets_ - 1; + uint64_t diff; + BucketItem *e, *min_e = NULL; +#define CAL_DEQUEUE(x) \ +do { \ + head_search_++; \ + if ((e = buckets_[i].list_) != NULL) { \ + diff = e->event.key.m_ts - cal_clock_.m_ts; \ + if (diff < diff##x##_) { \ + l = i; \ + goto found_l; \ + } \ + if (min_e == NULL || min_e->event.key > e->event.key) { \ + min_e = e; \ + l = i; \ + } \ + } \ + if (++i == nbuckets_) i = 0; \ +} while (0) + + // CAL_DEQUEUE applied successively will find the event to + // dequeue (within one year) and keep track of the + // minimum-priority event seen so far; the argument controls + // the criteria used to decide whether the event should be + // considered `within one year'. Importantly, the number of + // buckets should not be less than 4. + CAL_DEQUEUE(0); + CAL_DEQUEUE(1); + for (; i != lastbucket_dec; ) { + CAL_DEQUEUE(2); + } + // one last bucket is left unchecked - take the minimum + // [could have done CAL_DEQUEUE(3) with diff3_ = bwidth*(nbuck*3/2-1)] + e = buckets_[i].list_; + if (min_e != NULL && + (e == NULL || min_e->event.key < e->event.key)) + e = min_e; + else { + //assert(e); + l = i; + } + found_l: + //assert(buckets_[l].count_ >= 0); + //assert(buckets_[l].list_ == e); + + /* l is the index of the bucket to dequeue, e is the event */ + /* + * still want to advance lastbucket_ and cal_clock_ to save + * time when deque() follows. + */ + assert (l != -1); + lastbucket_ = l; + cal_clock_ = e->event.key; + + return e; +} + +void +Ns2CalendarScheduler::reinit(int nbuck, uint64_t bwidth, Scheduler::EventKey start) +{ + buckets_ = new Bucket[nbuck]; + + memset(buckets_, 0, sizeof(Bucket)*nbuck); //faster than ctor + + width_ = bwidth; + nbuckets_ = nbuck; + qsize_ = 0; + stat_qsize_ = 0; + + lastbucket_ = CALENDAR_HASH(start); + + diff0_ = bwidth*nbuck/2; + diff1_ = diff0_ + bwidth; + diff2_ = bwidth*nbuck; + //diff3_ = bwidth*(nbuck*3/2-1); + + bot_threshold_ = (nbuck >> 1) - 2; + top_threshold_ = (nbuck << 1); +} + +void +Ns2CalendarScheduler::resize(int newsize, Scheduler::EventKey start) +{ + uint64_t bwidth; + if (newsize == nbuckets_) { + /* we resize for bwidth*/ + if (head_search_) bwidth = head_search_; else bwidth = 1; + if (insert_search_) bwidth = bwidth / insert_search_; + bwidth = static_cast (sqrt (bwidth) * width_); + if (bwidth < min_bin_width_) { + if (time_to_newwidth_>0) { + time_to_newwidth_ --; + head_search_ = 0; + insert_search_ = 0; + round_num_ = 0; + return; //failed to adjust bwidth + } else { + // We have many (adjust_new_width_interval_) times failure in adjusting bwidth. + // should do a reshuffle with newwidth + bwidth = newwidth(newsize); + } + } + //snoopy queue calculation + } else { + /* we resize for size */ + bwidth = newwidth(newsize); + if (newsize < 4) + newsize = 4; + } + + Bucket *oldb = buckets_; + int oldn = nbuckets_; + + reinit(newsize, bwidth, start); + + // copy events to new buckets + int i; + + for (i = 0; i < oldn; ++i) { + // we can do inserts faster, if we use insert2, but to + // preserve FIFO, we have to start from the end of + // each bucket and use insert2 + if (oldb[i].list_) { + BucketItem *tail = oldb[i].list_->prev_; + BucketItem *e = tail; + do { + BucketItem* ep = e->prev_; + e->next_ = e->prev_ = 0; + insert2(e); + e = ep; + } while (e != tail); + } + } + head_search_ = 0; + insert_search_ = 0; + round_num_ = 0; + delete [] oldb; +} + +void +Ns2CalendarScheduler::insert2(Ns2CalendarScheduler::BucketItem* e) +{ + // Same as insert, but for inserts e *before* any same-time-events, if + // there should be any. Since it is used only by CalendarScheduler::newwidth(), + // some important checks present in insert() need not be performed. + + int i = CALENDAR_HASH(e->event.key); + BucketItem *head = buckets_[i].list_; + BucketItem *before=0; + if (!head) { + buckets_[i].list_ = e; + e->next_ = e->prev_ = e; + ++stat_qsize_; + ++buckets_[i].count_; + } else { + bool newhead; + if (e->event.key > head->prev_->event.key) { //strict LIFO, so > and not >= + // insert at the tail + before = head; + newhead = false; + } else { + // insert event in time sorted order, LIFO for sim-time events + for (before = head; e->event.key > before->event.key; before = before->next_) + ; + newhead = (before == head); + } + + e->next_ = before; + e->prev_ = before->prev_; + before->prev_ = e; + e->prev_->next_ = e; + if (newhead) { + buckets_[i].list_ = e; + //assert(e->time_ <= e->next_->time_); + } + + if (e != e->next_ && e->next_->event.key != e->event.key) { + // unique timing + ++stat_qsize_; + ++buckets_[i].count_; + } + } + //assert(e == buckets_[i].list_ || e->prev_->time_ <= e->time_); + //assert(e == buckets_[i].list_->prev_ || e->next_->time_ >= e->time_); + + ++qsize_; + // no need to check resizing +} + +uint64_t +Ns2CalendarScheduler::newwidth(int newsize) +{ + if (adjust_new_width_interval_) { + time_to_newwidth_ = adjust_new_width_interval_; + if (avg_gap_ > 0) return avg_gap_*4; + } + int i; + int max_bucket = 0; // index of the fullest bucket + for (i = 1; i < nbuckets_; ++i) { + if (buckets_[i].count_ > buckets_[max_bucket].count_) + max_bucket = i; + } + int nsamples = buckets_[max_bucket].count_; + + if (nsamples <= 4) return width_; + + uint64_t nw = (buckets_[max_bucket].list_->prev_->event.key.m_ts + - buckets_[max_bucket].list_->event.key.m_ts) * 4; + + nw /= ((newsize < nsamples) ? newsize : nsamples); // min (newsize, nsamples) + + nw = std::max (nw, min_bin_width_); + + return nw; +} + + +} // namespace ns3 diff --git a/src/simulator/ns2-calendar-scheduler.h b/src/simulator/ns2-calendar-scheduler.h new file mode 100644 index 000000000..bb06ead21 --- /dev/null +++ b/src/simulator/ns2-calendar-scheduler.h @@ -0,0 +1,100 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 1997 David Wetherall + * Copyright (c) 2005 David Wei + * Copyright (c) 2009 INRIA + * + * 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 + * + * Authors: + * David Wetherall : originally, in ns-2, back in 1997 + * David X. Wei: optimizations in ns-2.28 + * Mathieu Lacage : port to ns-3 + */ + +#ifndef NS2_CALENDAR_SCHEDULER_H +#define NS2_CALENDAR_SCHEDULER_H + +#include "scheduler.h" +#include +#include + +namespace ns3 { + +class EventImpl; + +/** + * \ingroup scheduler + * \brief a calendar queue event scheduler + * + * This event scheduler is a copy/paste of the ns2.29 calendar scheduler. + */ +class Ns2CalendarScheduler : public Scheduler +{ +public: + static TypeId GetTypeId (void); + + Ns2CalendarScheduler (); + virtual ~Ns2CalendarScheduler (); + + virtual void Insert (const Event &ev); + virtual bool IsEmpty (void) const; + virtual Event PeekNext (void) const; + virtual Event RemoveNext (void); + virtual void Remove (const Event &ev); + +private: + struct BucketItem { + ns3::Scheduler::Event event; + struct BucketItem *next_; + struct BucketItem *prev_; + }; + struct Bucket { + struct BucketItem *list_; + int count_; + }; + + void reinit(int nbuck, uint64_t bwidth, Scheduler::EventKey start); + void resize(int newsize, Scheduler::EventKey start); + uint64_t newwidth(int newsize); + void insert2 (Ns2CalendarScheduler::BucketItem *e); + Ns2CalendarScheduler::BucketItem *head (void); + + + uint64_t min_bin_width_; // minimum bin width for Calendar Queue + unsigned int adjust_new_width_interval_; // The interval (in unit of resize time) for adjustment of bin width. A zero value disables automatic bin width adjustment + unsigned time_to_newwidth_; // how many time we failed to adjust the width based on snoopy-queue + long unsigned head_search_; + long unsigned insert_search_; + int round_num_; + long int gap_num_; //the number of gap samples in this window (in process of calculation) + uint64_t last_time_; //the departure time of first event in this window + int64_t avg_gap_; //the average gap in last window (finished calculation) + + uint64_t width_; + uint64_t diff0_, diff1_, diff2_; /* wrap-around checks */ + + int stat_qsize_; /* # of distinct priorities in queue*/ + int nbuckets_; + int lastbucket_; + int top_threshold_; + int bot_threshold_; + int qsize_; + struct Bucket *buckets_; + Scheduler::EventKey cal_clock_; +}; + +} // namespace ns3 + +#endif /* NS2_CALENDAR_SCHEDULER_H */ diff --git a/src/simulator/scheduler.h b/src/simulator/scheduler.h index 72331baba..394987f7c 100644 --- a/src/simulator/scheduler.h +++ b/src/simulator/scheduler.h @@ -115,6 +115,28 @@ inline bool operator < (const Scheduler::EventKey &a, const Scheduler::EventKey return false; } } +inline bool operator != (const Scheduler::EventKey &a, const Scheduler::EventKey &b) +{ + return a.m_uid != b.m_uid; +} +inline bool operator > (const Scheduler::EventKey &a, const Scheduler::EventKey &b) +{ + if (a.m_ts > b.m_ts) + { + return true; + } + else if (a.m_ts == b.m_ts && + a.m_uid > b.m_uid) + { + return true; + } + else + { + return false; + } +} + + inline bool operator < (const Scheduler::Event &a, const Scheduler::Event &b) { diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index efd1c80bc..0eae117b1 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -17,11 +17,13 @@ * * Author: Mathieu Lacage */ - +#include "ns3/core-config.h" #include "simulator.h" #include "simulator-impl.h" #include "default-simulator-impl.h" -#include "realtime-simulator-impl.h" +#ifdef HAVE_PTHREAD_H +# include "realtime-simulator-impl.h" +#endif #include "scheduler.h" #include "event-impl.h" @@ -314,6 +316,8 @@ Simulator::GetImplementation (void) #include "list-scheduler.h" #include "heap-scheduler.h" #include "map-scheduler.h" +#include "calendar-scheduler.h" +#include "ns2-calendar-scheduler.h" namespace ns3 { @@ -740,6 +744,20 @@ SimulatorTests::RunTests (void) } Simulator::Destroy (); + Simulator::SetScheduler (CreateObject ()); + if (!RunOneTest ()) + { + result = false; + } + Simulator::Destroy (); + + Simulator::SetScheduler (CreateObject ()); + if (!RunOneTest ()) + { + result = false; + } + Simulator::Destroy (); + Simulator::Schedule (Seconds (0.0), &foo0); Simulator::Schedule (Seconds (0.0), &foo1, 0); Simulator::Schedule (Seconds (0.0), &foo2, 0, 0); diff --git a/src/simulator/simulator.h b/src/simulator/simulator.h index d0d66a9c4..a0732fb53 100644 --- a/src/simulator/simulator.h +++ b/src/simulator/simulator.h @@ -97,8 +97,8 @@ public: static void Destroy (void); /** - * If there any any events lefts to be scheduled and simulation time - * has not yet reached the "stop time" (see Simulator::Stop()), + * If there are no more events lefts to be scheduled, or if simulation + * time has already reached the "stop time" (see Simulator::Stop()), * return true. Return false otherwise. */ static bool IsFinished (void); diff --git a/src/simulator/wscript b/src/simulator/wscript index f4bd1145a..1824bd486 100644 --- a/src/simulator/wscript +++ b/src/simulator/wscript @@ -49,6 +49,7 @@ def build(bld): 'map-scheduler.cc', 'heap-scheduler.cc', 'calendar-scheduler.cc', + 'ns2-calendar-scheduler.cc', 'event-impl.cc', 'simulator.cc', 'default-simulator-impl.cc', @@ -73,6 +74,7 @@ def build(bld): 'map-scheduler.h', 'heap-scheduler.h', 'calendar-scheduler.h', + 'ns2-calendar-scheduler.h', 'simulation-singleton.h', 'timer.h', 'timer-impl.h', diff --git a/waf b/waf index 886a0e7f8..1d61ab7a2 100755 Binary files a/waf and b/waf differ diff --git a/wscript b/wscript index 9dd11b79a..6197d4304 100644 --- a/wscript +++ b/wscript @@ -53,9 +53,6 @@ def dist_hook(): shutil.rmtree("doc/latex", True) shutil.rmtree("nsc", True) - if not os.path.exists("bindings/python/pybindgen"): - raise Utils.WafError("Missing pybindgen checkout; run './waf configure --pybindgen-checkout' first.") - ## build the name of the traces subdirectory. Will be something like ## ns-3-dev-ref-traces traces_name = APPNAME + '-' + VERSION + regression.REGRESSION_SUFFIX @@ -197,9 +194,7 @@ def configure(conf): variant_name = Options.options.build_profile if Options.options.regression_traces is not None: - variant_env['REGRESSION_TRACES'] = os.path.join("..", Options.options.regression_traces) - else: - variant_env['REGRESSION_TRACES'] = None + variant_env['REGRESSION_TRACES'] = os.path.abspath(Options.options.regression_traces) if Options.options.enable_gcov: variant_name += '-gcov' @@ -309,33 +304,19 @@ def add_scratch_programs(bld): continue if os.path.isdir(os.path.join("scratch", filename)): obj = bld.create_ns3_program(filename, all_modules) - obj.path = obj.path.find_dir('scratch') - obj.find_sources_in_dirs(filename) - obj.target = os.path.join(filename, filename) + obj.path = obj.path.find_dir('scratch').find_dir(filename) + obj.find_sources_in_dirs('.') + obj.target = filename obj.name = obj.target elif filename.endswith(".cc"): name = filename[:-len(".cc")] obj = bld.create_ns3_program(name, all_modules) - obj.source = "scratch/%s" % filename - obj.target = "scratch/%s" % name + obj.path = obj.path.find_dir('scratch') + obj.source = filename + obj.target = name obj.name = obj.target -## -## This replacement spawn function increases the maximum command line length to 32k -## -def _exec_command_interact_win32(s): - if Params.g_verbose: - print s - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW - proc = subprocess.Popen(s, shell=False, startupinfo=startupinfo) - stat = proc.wait() - if stat & 0xff: - return stat | 0x80 - return stat >> 8 - - def build(bld): if Options.options.no_task_lines: import Runner @@ -343,10 +324,6 @@ def build(bld): pass Runner.printout = null_printout - if sys.platform == 'win32': - import Runner - Runner.exec_command = _exec_command_interact_win32 - Options.cwd_launch = bld.path.abspath() bld.create_ns3_program = types.MethodType(create_ns3_program, bld) bld.create_suid_program = types.MethodType(create_suid_program, bld) @@ -436,7 +413,7 @@ def build(bld): # nothing more; this greatly speeds up compilation when all you # want to do is run a test program. if not Options.options.compile_targets: - Options.options.compile_targets = program_name + Options.options.compile_targets = os.path.basename(program_name) @@ -462,15 +439,11 @@ def shutdown(): if not env['DIFF']: raise Utils.WafError("Cannot run regression tests: the 'diff' program is not installed.") - _dir = os.getcwd() - os.chdir("regression") regression_traces = env['REGRESSION_TRACES'] if not regression_traces: - regression_traces = None - try: - retval = regression.run_regression(regression_traces) - finally: - os.chdir(_dir) + 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) diff --git a/wutils.py b/wutils.py index 1b0413692..9cebb2a5d 100644 --- a/wutils.py +++ b/wutils.py @@ -38,9 +38,30 @@ def get_command_template(*arguments): return cmd +if hasattr(os.path, "relpath"): + relpath = os.path.relpath # since Python 2.6 +else: + def relpath(path, start=os.path.curdir): + """Return a relative version of a path""" + + if not path: + raise ValueError("no path specified") + + start_list = os.path.abspath(start).split(os.path.sep) + path_list = os.path.abspath(path).split(os.path.sep) + + # Work out how much of the filepath is shared by start and path. + i = len(os.path.commonprefix([start_list, path_list])) + + rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:] + if not rel_list: + return os.path.curdir + return os.path.join(*rel_list) + def find_program(program_name, env): launch_dir = os.path.abspath(Options.cwd_launch) + top_dir = os.path.abspath(Options.launch_dir) found_programs = [] for obj in Build.bld.all_task_gen: if not getattr(obj, 'is_ns3_program', False): @@ -51,8 +72,11 @@ def find_program(program_name, env): or obj.path.abspath(env).startswith(launch_dir)): continue - found_programs.append(obj.target) - if obj.target == program_name: + name1 = obj.target + name2 = os.path.join(relpath(obj.path.abspath(), top_dir), obj.target) + names = [name1, name2] + found_programs.extend(names) + if program_name in names: return obj raise ValueError("program '%s' not found; available programs are: %r" % (program_name, found_programs)) @@ -93,10 +117,10 @@ def get_proc_env(os_env=None): return proc_env -def run_argv(argv, os_env=None): +def run_argv(argv, os_env=None, cwd=None): proc_env = get_proc_env(os_env) #env = Build.bld.env - retval = subprocess.Popen(argv, env=proc_env).wait() + retval = subprocess.Popen(argv, env=proc_env, cwd=cwd).wait() if retval: raise Utils.WafError("Command %s exited with code %i" % (argv, retval)) return retval @@ -143,7 +167,7 @@ def get_run_program(program_string, command_template=None): execvec = shlex.split(command_template % (program_node.abspath(env),)) return program_name, execvec -def run_program(program_string, command_template=None): +def run_program(program_string, command_template=None, cwd=None): """ if command_template is not None, then program_string == program name and argv is given by command_template with %s replaced by the @@ -151,34 +175,23 @@ def run_program(program_string, command_template=None): a shell command with first name being the program name. """ dummy_program_name, execvec = get_run_program(program_string, command_template) - former_cwd = os.getcwd() - if (Options.options.cwd_launch): - os.chdir(Options.options.cwd_launch) - else: - os.chdir(Options.cwd_launch) - try: - retval = run_argv(execvec) - finally: - os.chdir(former_cwd) - - return retval + if cwd is None: + if (Options.options.cwd_launch): + cwd = Options.options.cwd_launch + else: + cwd = Options.cwd_launch + return run_argv(execvec, cwd=cwd) def run_python_program(program_string): env = Build.bld.env execvec = shlex.split(program_string) - - former_cwd = os.getcwd() - if (Options.options.cwd_launch): - os.chdir(Options.options.cwd_launch) - else: - os.chdir(Options.cwd_launch) - try: - retval = run_argv([env['PYTHON']] + execvec) - finally: - os.chdir(former_cwd) - - return retval + if cwd is None: + if (Options.options.cwd_launch): + cwd = Options.options.cwd_launch + else: + cwd = Options.cwd_launch + return run_argv([env['PYTHON']] + execvec, cwd=cwd)