From 4eda3b7ea112a1db20b78ecd52d03c1b67a3c4fa Mon Sep 17 00:00:00 2001 From: "Peter D. Barnes, Jr." Date: Thu, 18 Jul 2013 12:01:05 -0700 Subject: [PATCH] Hashed TypeId Speed LookupByName with std::map, add LookupByHash Hash chaining, alphabetized TypeId test suite --- src/core/model/type-id.cc | 244 ++++++++++++++++----- src/core/model/type-id.h | 40 +++- src/core/test/type-id-test-suite.cc | 321 ++++++++++++++++++++++++++++ src/core/wscript | 1 + 4 files changed, 552 insertions(+), 54 deletions(-) create mode 100644 src/core/test/type-id-test-suite.cc diff --git a/src/core/model/type-id.cc b/src/core/model/type-id.cc index 165a0103f..079cf6c7a 100644 --- a/src/core/model/type-id.cc +++ b/src/core/model/type-id.cc @@ -17,21 +17,56 @@ * * Author: Mathieu Lacage */ +#include "log.h" // NS_ASSERT and NS_LOG +#include "hash.h" #include "type-id.h" #include "singleton.h" #include "trace-source-accessor.h" -#include "log.h" + +#include #include #include +#include /********************************************************************* * Helper code *********************************************************************/ -NS_LOG_COMPONENT_DEFINE ("TypeID"); +namespace ns3 { -namespace { +NS_LOG_COMPONENT_DEFINE ("TypeId"); +// IidManager needs to be in ns3 namespace for NS_ASSERT and NS_LOG +// to find g_log + +/** + * \brief TypeId information manager + * + * Information records are stored in a vector. Name and hash lookup + * are performed by maps to the vector index. + * + * \internal + * Hash Chaining + * + * We require all types to produce distinct hashes. What if we encounter + * two types that produce the same hash value? As we move to a + * federated distribution model (the App store), it becomes increasingly + * likely that the core ns3 team *won't* discover this in test builds. + * Therefore, we need to handle this case explicitly. + * + * Note, we expect this to be *extremely* rare. As of this writing we + * have ~400 < 2^9 types, so the probability of getting a collision + * when we introduce a new type is ~2^9/2^31 = 2^-22, assuming we + * reserve 31 bits for the hash, and one bit for chaining. Even with + * double the number of types the probability of having a collision + * is only 2 x 10^-4. The probability for a three-fold collision is + * 1 x 10^-10. + * + * Therefore, we'll handle one collision explicitly by reserving + * the high order bit of the hash value, and assert on higher level + * collisions. The three-fold collision probability should be an + * acceptablly small error rate. + */ class IidManager { public: @@ -39,13 +74,15 @@ public: uint16_t AllocateUid (std::string name); void SetParent (uint16_t uid, uint16_t parent); void SetGroupName (uint16_t uid, std::string groupName); - void AddConstructor (uint16_t uid, ns3::Callback callback); + void AddConstructor (uint16_t uid, Callback callback); void HideFromDocumentation (uint16_t uid); uint16_t GetUid (std::string name) const; + uint16_t GetUid (TypeId::hash_t hash) const; std::string GetName (uint16_t uid) const; + TypeId::hash_t GetHash (uint16_t uid) const; uint16_t GetParent (uint16_t uid) const; std::string GetGroupName (uint16_t uid) const; - ns3::Callback GetConstructor (uint16_t uid) const; + Callback GetConstructor (uint16_t uid) const; bool HasConstructor (uint16_t uid) const; uint32_t GetRegisteredN (void) const; uint16_t GetRegistered (uint32_t i) const; @@ -53,41 +90,54 @@ public: std::string name, std::string help, uint32_t flags, - ns3::Ptr initialValue, - ns3::Ptr spec, - ns3::Ptr checker); + Ptr initialValue, + Ptr spec, + Ptr checker); void SetAttributeInitialValue(uint16_t uid, uint32_t i, - ns3::Ptr initialValue); + Ptr initialValue); uint32_t GetAttributeN (uint16_t uid) const; - struct ns3::TypeId::AttributeInformation GetAttribute(uint16_t uid, uint32_t i) const; + struct TypeId::AttributeInformation GetAttribute(uint16_t uid, uint32_t i) const; void AddTraceSource (uint16_t uid, std::string name, std::string help, - ns3::Ptr accessor); + Ptr accessor); uint32_t GetTraceSourceN (uint16_t uid) const; - struct ns3::TypeId::TraceSourceInformation GetTraceSource(uint16_t uid, uint32_t i) const; + struct TypeId::TraceSourceInformation GetTraceSource(uint16_t uid, uint32_t i) const; bool MustHideFromDocumentation (uint16_t uid) const; private: bool HasTraceSource (uint16_t uid, std::string name); bool HasAttribute (uint16_t uid, std::string name); + static TypeId::hash_t Hasher (const std::string name); struct IidInformation { std::string name; + TypeId::hash_t hash; uint16_t parent; std::string groupName; bool hasConstructor; - ns3::Callback constructor; + Callback constructor; bool mustHideFromDocumentation; - std::vector attributes; - std::vector traceSources; + std::vector attributes; + std::vector traceSources; }; typedef std::vector::const_iterator Iterator; struct IidManager::IidInformation *LookupInformation (uint16_t uid) const; std::vector m_information; + + typedef std::map namemap_t; + namemap_t m_namemap; + + typedef std::map hashmap_t; + hashmap_t m_hashmap; + + + // To handle the first collision, we reserve the high bit as a + // chain flag: + enum { HashChainFlag = 0x80000000}; }; IidManager::IidManager () @@ -95,22 +145,70 @@ IidManager::IidManager () NS_LOG_FUNCTION (this); } + //static +TypeId::hash_t +IidManager::Hasher (const std::string name) +{ + static ns3::Hasher hasher ( Create () ); + return hasher.clear ().GetHash32 (name); +} + uint16_t IidManager::AllocateUid (std::string name) { NS_LOG_FUNCTION (this << name); - uint16_t j = 1; - for (Iterator i = m_information.begin (); i != m_information.end (); i++) - { - if (i->name == name) - { - NS_FATAL_ERROR ("Trying to allocate twice the same uid: " << name); - return 0; - } - j++; - } - struct IidInformation information; + // Type names are definitive: equal names are equal types + NS_ASSERT_MSG (m_namemap.count (name) == 0, + "Trying to allocate twice the same uid: " << name); + + TypeId::hash_t hash = Hasher (name) & (~HashChainFlag); + if (m_hashmap.count (hash) == 1) { + NS_LOG_ERROR ("Hash chaining TypeId for '" << name << "'. " + << "This is not a bug, but is extremely unlikely. " + << "Please contact the ns3 developers."); + // ns3 developer contacted about this message: + // You have four options (in order of difficulty): + // 1. Let it ride, and play the odds that a third collision + // never appears. + // 2. Change the name of the new (or old) tag, even trivially, to + // remove the collision. + // 3. Switch to 64-bit hashes. + // 4. Implement 2-bit (or higher) chaining. + // + // Oh, by the way, I owe you a beer, since I bet Mathieu that + // this would never happen.. -- Peter Barnes, LLNL + + NS_ASSERT_MSG (m_hashmap.count (hash | HashChainFlag) == 0, + "Triplicate hash detected while chaining TypeId for '" + << name + << "'. Please contact the ns3 developers for assistance."); + // ns3 developer contacted about this message: + // You have three options: #2-4 above. + // + // Oh, by the way, I have no idea how this crazy hashing idea got + // into ns3. -- Peter Barnes, LLNL + + // Alphabetize the two types, so it's deterministic + struct IidInformation * hinfo = LookupInformation (GetUid (hash)); + if (name > hinfo->name) + { // new type gets chained + NS_LOG_LOGIC ("New TypeId '" << name << "' getting chained."); + hash = hash | HashChainFlag; + } + else + { // chain old type + NS_LOG_LOGIC ("Old TypeId '" << hinfo->name << "' getting chained."); + uint32_t oldUid = GetUid (hinfo->hash); + m_hashmap.erase (m_hashmap.find (hinfo->hash)); + hinfo->hash = hash | HashChainFlag; + m_hashmap.insert (std::make_pair (hinfo->hash, oldUid)); + // leave new hash unchained + } + } + + struct IidInformation information; information.name = name; + information.hash = hash; information.parent = 0; information.groupName = ""; information.hasConstructor = false; @@ -118,6 +216,10 @@ IidManager::AllocateUid (std::string name) m_information.push_back (information); uint32_t uid = m_information.size (); NS_ASSERT (uid <= 0xffff); + + // Add to both maps: + m_namemap.insert (std::make_pair (name, uid)); + m_hashmap.insert (std::make_pair (hash, uid)); return uid; } @@ -153,7 +255,7 @@ IidManager::HideFromDocumentation (uint16_t uid) } void -IidManager::AddConstructor (uint16_t uid, ns3::Callback callback) +IidManager::AddConstructor (uint16_t uid, Callback callback) { NS_LOG_FUNCTION (this << uid << &callback); struct IidInformation *information = LookupInformation (uid); @@ -169,17 +271,28 @@ uint16_t IidManager::GetUid (std::string name) const { NS_LOG_FUNCTION (this << name); - uint32_t j = 1; - for (Iterator i = m_information.begin (); i != m_information.end (); i++) + namemap_t::const_iterator it = m_namemap.find (name); + if (it != m_namemap.end ()) { - if (i->name == name) - { - NS_ASSERT (j <= 0xffff); - return j; - } - j++; + return it->second; + } + else + { + return 0; + } +} +uint16_t +IidManager::GetUid (TypeId::hash_t hash) const +{ + hashmap_t::const_iterator it = m_hashmap.find (hash); + if (it != m_hashmap.end ()) + { + return it->second; + } + else + { // hash not found + return 0; } - return 0; } std::string IidManager::GetName (uint16_t uid) const @@ -188,6 +301,13 @@ IidManager::GetName (uint16_t uid) const struct IidInformation *information = LookupInformation (uid); return information->name; } +TypeId::hash_t +IidManager::GetHash (uint16_t uid) const +{ + NS_LOG_FUNCTION (this << uid); + struct IidInformation *information = LookupInformation (uid); + return information->hash; +} uint16_t IidManager::GetParent (uint16_t uid) const { @@ -203,7 +323,7 @@ IidManager::GetGroupName (uint16_t uid) const return information->groupName; } -ns3::Callback +Callback IidManager::GetConstructor (uint16_t uid) const { NS_LOG_FUNCTION (this << uid); @@ -244,7 +364,7 @@ IidManager::HasAttribute (uint16_t uid, struct IidInformation *information = LookupInformation (uid); while (true) { - for (std::vector::const_iterator i = information->attributes.begin (); + for (std::vector::const_iterator i = information->attributes.begin (); i != information->attributes.end (); ++i) { if (i->name == name) @@ -269,9 +389,9 @@ IidManager::AddAttribute (uint16_t uid, std::string name, std::string help, uint32_t flags, - ns3::Ptr initialValue, - ns3::Ptr accessor, - ns3::Ptr checker) + Ptr initialValue, + Ptr accessor, + Ptr checker) { NS_LOG_FUNCTION (this << uid << name << help << flags << initialValue << accessor << checker); struct IidInformation *information = LookupInformation (uid); @@ -280,7 +400,7 @@ IidManager::AddAttribute (uint16_t uid, NS_FATAL_ERROR ("Attribute \"" << name << "\" already registered on tid=\"" << information->name << "\""); } - struct ns3::TypeId::AttributeInformation info; + struct TypeId::AttributeInformation info; info.name = name; info.help = help; info.flags = flags; @@ -293,7 +413,7 @@ IidManager::AddAttribute (uint16_t uid, void IidManager::SetAttributeInitialValue(uint16_t uid, uint32_t i, - ns3::Ptr initialValue) + Ptr initialValue) { NS_LOG_FUNCTION (this << uid << i << initialValue); struct IidInformation *information = LookupInformation (uid); @@ -310,7 +430,7 @@ IidManager::GetAttributeN (uint16_t uid) const struct IidInformation *information = LookupInformation (uid); return information->attributes.size (); } -struct ns3::TypeId::AttributeInformation +struct TypeId::AttributeInformation IidManager::GetAttribute(uint16_t uid, uint32_t i) const { NS_LOG_FUNCTION (this << uid << i); @@ -327,7 +447,7 @@ IidManager::HasTraceSource (uint16_t uid, struct IidInformation *information = LookupInformation (uid); while (true) { - for (std::vector::const_iterator i = information->traceSources.begin (); + for (std::vector::const_iterator i = information->traceSources.begin (); i != information->traceSources.end (); ++i) { if (i->name == name) @@ -351,7 +471,7 @@ void IidManager::AddTraceSource (uint16_t uid, std::string name, std::string help, - ns3::Ptr accessor) + Ptr accessor) { NS_LOG_FUNCTION (this << uid << name << help << accessor); struct IidInformation *information = LookupInformation (uid); @@ -360,7 +480,7 @@ IidManager::AddTraceSource (uint16_t uid, NS_FATAL_ERROR ("Trace source \"" << name << "\" already registered on tid=\"" << information->name << "\""); } - struct ns3::TypeId::TraceSourceInformation source; + struct TypeId::TraceSourceInformation source; source.name = name; source.help = help; source.accessor = accessor; @@ -373,7 +493,7 @@ IidManager::GetTraceSourceN (uint16_t uid) const struct IidInformation *information = LookupInformation (uid); return information->traceSources.size (); } -struct ns3::TypeId::TraceSourceInformation +struct TypeId::TraceSourceInformation IidManager::GetTraceSource(uint16_t uid, uint32_t i) const { NS_LOG_FUNCTION (this << uid << i); @@ -389,7 +509,7 @@ IidManager::MustHideFromDocumentation (uint16_t uid) const return information->mustHideFromDocumentation; } -} // anonymous namespace +} // namespace ns3 namespace ns3 { @@ -431,6 +551,25 @@ TypeId::LookupByNameFailSafe (std::string name, TypeId *tid) *tid = TypeId (uid); return true; } +TypeId +TypeId::LookupByHash (hash_t hash) +{ + uint16_t uid = Singleton::Get ()->GetUid (hash); + NS_ASSERT_MSG (uid != 0, "Assert in TypeId::LookupByHash: 0x" + << std::hex << hash << std::dec << " not found"); + return TypeId (uid); +} +bool +TypeId::LookupByHashFailSafe (hash_t hash, TypeId *tid) +{ + uint16_t uid = Singleton::Get ()->GetUid (hash); + if (uid == 0) + { + return false; + } + *tid = TypeId (uid); + return true; +} uint32_t TypeId::GetRegisteredN (void) @@ -522,6 +661,13 @@ TypeId::GetName (void) const return name; } +TypeId::hash_t +TypeId::GetHash (void) const +{ + hash_t hash = Singleton::Get ()->GetHash (m_tid); + return hash; +} + bool TypeId::HasConstructor (void) const { diff --git a/src/core/model/type-id.h b/src/core/model/type-id.h index 32f129f09..1f5bb6820 100644 --- a/src/core/model/type-id.h +++ b/src/core/model/type-id.h @@ -25,6 +25,7 @@ #include "trace-source-accessor.h" #include "attribute-helper.h" #include "callback.h" +#include "hash.h" #include #include @@ -40,6 +41,10 @@ class ObjectBase; * - the base class of the subclass * - the set of accessible constructors in the subclass * - the set of 'attributes' accessible in the subclass + * + * \internal + * See the discussion in IidManager about hash chaining of TypeId's. + * */ class TypeId { @@ -57,17 +62,22 @@ public: std::string name; std::string help; uint32_t flags; - ns3::Ptr originalInitialValue; - ns3::Ptr initialValue; - ns3::Ptr accessor; - ns3::Ptr checker; + Ptr originalInitialValue; + Ptr initialValue; + Ptr accessor; + Ptr checker; }; struct TraceSourceInformation { std::string name; std::string help; - ns3::Ptr accessor; + Ptr accessor; }; + /** + * Type of hash values + */ + typedef uint32_t hash_t; + /** * \param name the name of the requested TypeId * \returns the unique id associated with the requested @@ -84,6 +94,21 @@ public: * \returns true if the requested name was found, false otherwise. */ static bool LookupByNameFailSafe (std::string name, TypeId *tid); + /** + * \param hash the hash to lookup + * \returns the unique id associated with the requested hash. + * + * This method cannot fail: it will crash if the input + * hash does not match an existing TypeId. + */ + static TypeId LookupByHash (hash_t hash); + /** + * \param hash the hash of the requested TypeId + * \param tid a pointer to the TypeId instance where the + * result of this function should be stored. + * \returns true if the requested hash was found, false otherwise. + */ + static bool LookupByHashFailSafe (hash_t hash, TypeId *tid); /** * \returns the number of TypeId instances registered. @@ -137,6 +162,11 @@ public: */ std::string GetName (void) const; + /** + * \returns the hash of this interface. + */ + hash_t GetHash (void) const; + /** * \returns true if this TypeId has a constructor */ diff --git a/src/core/test/type-id-test-suite.cc b/src/core/test/type-id-test-suite.cc new file mode 100644 index 000000000..6d14bf3c5 --- /dev/null +++ b/src/core/test/type-id-test-suite.cc @@ -0,0 +1,321 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2012 Lawrence Livermore National Laboratory + * + * 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 + * + * Author: Peter D. Barnes, Jr. + */ + +#include +#include +#include + +#include "ns3/type-id.h" +#include "ns3/test.h" +#include "ns3/log.h" + +using namespace std; + +namespace ns3 { + + +const std::string suite("type-id: "); + +//---------------------------- +// +// Test for uniqueness of all TypeIds + +class UniqueTypeIdTestCase : public TestCase +{ +public: + UniqueTypeIdTestCase (); + virtual ~UniqueTypeIdTestCase (); +private: + virtual void DoRun (void); + enum { HashChainFlag = 0x80000000}; +}; + +UniqueTypeIdTestCase::UniqueTypeIdTestCase () + : TestCase ("Check uniqueness of all TypeIds") +{ +} + +UniqueTypeIdTestCase::~UniqueTypeIdTestCase () +{ +} + +void +UniqueTypeIdTestCase::DoRun (void) +{ + cout << suite << endl; + cout << suite << GetName () << endl; + + // Use same custom hasher as TypeId + ns3::Hasher hasher = ns3::Hasher ( Create () ); + + uint32_t nids = TypeId::GetRegisteredN (); + + cout << suite << "UniqueTypeIdTestCase: nids: " << nids << endl; + cout << suite << "TypeId list:" << endl; + cout << suite << "TypeId Chain hash Name" << endl; + + for (uint32_t i = 0; i < nids; ++i) + { + const TypeId tid = TypeId::GetRegistered (i); + cout << suite << "" << std::setw(6) << tid.GetUid (); + if (tid.GetHash () & HashChainFlag) + { + cout << " chain"; + } + else + { + cout << " "; + } + cout << " 0x" << std::setfill ('0') << std::hex << std::setw (8) + << tid.GetHash () << std::dec << std::setfill (' ') + << " " << tid.GetName () + << endl; + + NS_TEST_ASSERT_MSG_EQ (tid.GetUid (), + TypeId::LookupByName (tid.GetName ()).GetUid (), + "LookupByName returned different TypeId for " + << tid.GetName ()); + + // Mask off HashChainFlag in this test, since tid might have been chained + NS_TEST_ASSERT_MSG_EQ ((tid.GetHash () & (~HashChainFlag)), + (hasher.clear ().GetHash32 (tid.GetName ()) & (~HashChainFlag)), + "TypeId .hash and Hash32 (.name) unequal for " + << tid.GetName ()); + + NS_TEST_ASSERT_MSG_EQ (tid.GetUid (), + TypeId::LookupByHash (tid.GetHash ()).GetUid (), + "LookupByHash returned different TypeId for " + << tid.GetName ()); + + } + + cout << suite << "<-- end TypeId list -->" << endl; +} + + +//---------------------------- +// +// Collision test + +class CollisionTestCase : public TestCase +{ +public: + CollisionTestCase (); + virtual ~CollisionTestCase (); +private: + virtual void DoRun (void); + enum { HashChainFlag = 0x80000000}; +}; + +CollisionTestCase::CollisionTestCase () + : TestCase ("Check behavour when type names collide") +{ +} + +CollisionTestCase::~CollisionTestCase () +{ +} + +void +CollisionTestCase::DoRun (void) +{ + cout << suite << endl; + cout << suite << GetName () << endl; + + // Register two types whose hashes collide, in alphabetical order + // Murmur3 collision from /usr/share/dict/web2 + string t1Name = "daemon"; + string t2Name = "unerring"; + cout << suite << "creating colliding types " + << "'" << t1Name << "', '" << t2Name << "'" + << " in alphabetical order:" + << endl; + TypeId t1 (t1Name.c_str ()); + TypeId t2 (t2Name.c_str ()); + + // Check that they are alphabetical: t1 name < t2 name + NS_TEST_ASSERT_MSG_EQ ( (t1.GetHash () & HashChainFlag), 0, + "First and lesser TypeId has HashChainFlag set"); + cout << suite << "collision: first,lesser not chained: OK" << endl; + + NS_TEST_ASSERT_MSG_NE ( (t2.GetHash () & HashChainFlag), 0, + "Second and greater TypeId does not have HashChainFlag set"); + cout << suite << "collision: second,greater chained: OK" << endl; + + + // Register colliding types in reverse alphabetical order + // Murmur3 collision from /usr/share/dict/web2 + string t3Name = "trigonon"; + string t4Name = "seriation"; + cout << suite << "creating colliding types " + << "'" << t3Name << "', '" << t4Name << "'" + << " in reverse alphabetical order:" + << endl; + TypeId t3 (t3Name.c_str ()); + TypeId t4 (t4Name.c_str ()); + + // Check that they are alphabetical: t3 name > t4 name + NS_TEST_ASSERT_MSG_NE ( (t3.GetHash () & HashChainFlag), 0, + "First and greater TypeId does not have HashChainFlag set"); + cout << suite << "collision: first,greater chained: OK" << endl; + + NS_TEST_ASSERT_MSG_EQ ( (t4.GetHash () & HashChainFlag), 0, + "Second and lesser TypeId has HashChainFlag set"); + cout << suite << "collision: second,lesser not chained: OK" << endl; + + /** TODO Extra credit: register three types whose hashes collide + * + * None found in /usr/share/dict/web2 + */ + +} + + +//---------------------------- +// +// Performance test + +class LookupTimeTestCase : public TestCase +{ +public: + LookupTimeTestCase (); + virtual ~LookupTimeTestCase (); +private: + void DoRun (void); + void DoSetup (void); + void Report (const std::string how, const uint32_t delta) const ; + + enum { REPETITIONS = 100000 }; +}; + +LookupTimeTestCase::LookupTimeTestCase () + : TestCase ("Measure average lookup time") +{ +} + +LookupTimeTestCase::~LookupTimeTestCase () +{ +} + +void +LookupTimeTestCase::DoRun (void) +{ + cout << suite << endl; + cout << suite << GetName () << endl; + + uint32_t nids = TypeId::GetRegisteredN (); + + int start = clock (); + for (uint32_t j = 0; j < REPETITIONS; ++j) + { + for (uint32_t i = 0; i < nids; ++i) + { + const TypeId tid = TypeId::GetRegistered (i); + const TypeId sid = TypeId::LookupByName (tid.GetName ()); + } + } + int stop = clock (); + Report ("name", stop - start); + + start = clock (); + for (uint32_t j = 0; j < REPETITIONS; ++j) + { + for (uint32_t i = 0; i < nids; ++i) + { + const TypeId tid = TypeId::GetRegistered (i); + const TypeId sid = TypeId::LookupByHash (tid.GetHash ()); + } + } + stop = clock (); + Report ("hash", stop - start); + +} + +void +LookupTimeTestCase::DoSetup (void) +{ + uint32_t nids = TypeId::GetRegisteredN (); + + cout << suite << "Lookup time: reps: " << REPETITIONS + << ", num TypeId's: " << nids + << endl; + +} + +void +LookupTimeTestCase::Report (const std::string how, + const uint32_t delta) const +{ + double nids = TypeId::GetRegisteredN (); + double reps = nids * REPETITIONS; + + double per = 1E6 * double(delta) / (reps * double(CLOCKS_PER_SEC)); + + cout << suite << "Lookup time: by " << how << ": " + << "ticks: " << delta + << "\tper: " << per + << " microsec/lookup" + << endl; +} + + +//---------------------------- +// +// TypeId test suites + +class TypeIdTestSuite : public TestSuite +{ +public: + TypeIdTestSuite (); +}; + +TypeIdTestSuite::TypeIdTestSuite () + : TestSuite ("type-id", UNIT) +{ + // Turn on logging, so we see the result of collisions + LogComponentEnable ("TypeId", ns3::LogLevel(LOG_ERROR|LOG_PREFIX_FUNC)); + + // If the CollisionTestCase is performed before the + // UniqueIdTestCase, the artificial collisions added by + // CollisionTestCase will show up in the list of TypeIds + // as chained. + AddTestCase (new UniqueTypeIdTestCase); + AddTestCase (new CollisionTestCase); +} + +static TypeIdTestSuite g_TypeIdTestSuite; + + +class TypeIdPerformanceSuite : public TestSuite +{ +public: + TypeIdPerformanceSuite (); +}; + +TypeIdPerformanceSuite::TypeIdPerformanceSuite () + : TestSuite ("type-id-perf", PERFORMANCE) +{ + AddTestCase (new LookupTimeTestCase); +} + +static TypeIdPerformanceSuite g_TypeIdPerformanceSuite; + + +} // namespace ns3 diff --git a/src/core/wscript b/src/core/wscript index 64ba9d123..d82252165 100644 --- a/src/core/wscript +++ b/src/core/wscript @@ -178,6 +178,7 @@ def build(bld): 'test/type-traits-test-suite.cc', 'test/watchdog-test-suite.cc', 'test/hash-test-suite.cc', + 'test/type-id-test-suite.cc', ] headers = bld(features='ns3header')