Apply clang-format to codebase
This commit is contained in:
@@ -23,15 +23,16 @@
|
||||
// Sample usage: ./ns3 run 'bench-packets --n=10000'
|
||||
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/system-wall-clock-ms.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/packet-metadata.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <stdlib.h> // for exit ()
|
||||
#include <limits>
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/system-wall-clock-ms.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <stdlib.h> // for exit ()
|
||||
#include <string>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
@@ -39,352 +40,374 @@ using namespace ns3;
|
||||
template <int N>
|
||||
class BenchHeader : public Header
|
||||
{
|
||||
public:
|
||||
BenchHeader ();
|
||||
/**
|
||||
* Returns true if the header has been deserialized and the
|
||||
* deserialization was correct. If Deserialize() has not yet been
|
||||
* called on the header, will return false.
|
||||
*
|
||||
* \returns true if success, false if failed or if deserialization not tried
|
||||
*/
|
||||
bool IsOk () const;
|
||||
public:
|
||||
BenchHeader();
|
||||
/**
|
||||
* Returns true if the header has been deserialized and the
|
||||
* deserialization was correct. If Deserialize() has not yet been
|
||||
* called on the header, will return false.
|
||||
*
|
||||
* \returns true if success, false if failed or if deserialization not tried
|
||||
*/
|
||||
bool IsOk() const;
|
||||
|
||||
/**
|
||||
* Register this type.
|
||||
* \return The TypeId.
|
||||
*/
|
||||
static TypeId GetTypeId ();
|
||||
TypeId GetInstanceTypeId () const override;
|
||||
void Print (std::ostream &os) const override;
|
||||
uint32_t GetSerializedSize () const override;
|
||||
void Serialize (Buffer::Iterator start) const override;
|
||||
uint32_t Deserialize (Buffer::Iterator start) override;
|
||||
private:
|
||||
/**
|
||||
* Get type name function
|
||||
* \returns the type name string
|
||||
*/
|
||||
static std::string GetTypeName ();
|
||||
bool m_ok; ///< variable to track whether deserialization succeeded
|
||||
/**
|
||||
* Register this type.
|
||||
* \return The TypeId.
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
TypeId GetInstanceTypeId() const override;
|
||||
void Print(std::ostream& os) const override;
|
||||
uint32_t GetSerializedSize() const override;
|
||||
void Serialize(Buffer::Iterator start) const override;
|
||||
uint32_t Deserialize(Buffer::Iterator start) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Get type name function
|
||||
* \returns the type name string
|
||||
*/
|
||||
static std::string GetTypeName();
|
||||
bool m_ok; ///< variable to track whether deserialization succeeded
|
||||
};
|
||||
|
||||
template <int N>
|
||||
BenchHeader<N>::BenchHeader ()
|
||||
: m_ok (false)
|
||||
{}
|
||||
BenchHeader<N>::BenchHeader()
|
||||
: m_ok(false)
|
||||
{
|
||||
}
|
||||
|
||||
template <int N>
|
||||
bool
|
||||
BenchHeader<N>::IsOk () const
|
||||
BenchHeader<N>::IsOk() const
|
||||
{
|
||||
return m_ok;
|
||||
return m_ok;
|
||||
}
|
||||
|
||||
template <int N>
|
||||
std::string
|
||||
BenchHeader<N>::GetTypeName ()
|
||||
BenchHeader<N>::GetTypeName()
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "ns3::BenchHeader<" << N << ">";
|
||||
return oss.str ();
|
||||
std::ostringstream oss;
|
||||
oss << "ns3::BenchHeader<" << N << ">";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
template <int N>
|
||||
TypeId
|
||||
BenchHeader<N>::GetTypeId ()
|
||||
BenchHeader<N>::GetTypeId()
|
||||
{
|
||||
static TypeId tid = TypeId (GetTypeName ())
|
||||
.SetParent<Header> ()
|
||||
.SetGroupName ("Utils")
|
||||
.HideFromDocumentation ()
|
||||
.AddConstructor<BenchHeader <N> > ()
|
||||
;
|
||||
return tid;
|
||||
static TypeId tid = TypeId(GetTypeName())
|
||||
.SetParent<Header>()
|
||||
.SetGroupName("Utils")
|
||||
.HideFromDocumentation()
|
||||
.AddConstructor<BenchHeader<N>>();
|
||||
return tid;
|
||||
}
|
||||
|
||||
template <int N>
|
||||
TypeId
|
||||
BenchHeader<N>::GetInstanceTypeId () const
|
||||
BenchHeader<N>::GetInstanceTypeId() const
|
||||
{
|
||||
return GetTypeId ();
|
||||
return GetTypeId();
|
||||
}
|
||||
|
||||
template <int N>
|
||||
void
|
||||
BenchHeader<N>::Print (std::ostream &os) const
|
||||
BenchHeader<N>::Print(std::ostream& os) const
|
||||
{
|
||||
NS_ASSERT (false);
|
||||
NS_ASSERT(false);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
uint32_t
|
||||
BenchHeader<N>::GetSerializedSize () const
|
||||
BenchHeader<N>::GetSerializedSize() const
|
||||
{
|
||||
return N;
|
||||
return N;
|
||||
}
|
||||
|
||||
template <int N>
|
||||
void
|
||||
BenchHeader<N>::Serialize (Buffer::Iterator start) const
|
||||
BenchHeader<N>::Serialize(Buffer::Iterator start) const
|
||||
{
|
||||
start.WriteU8 (N, N);
|
||||
start.WriteU8(N, N);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
uint32_t
|
||||
BenchHeader<N>::Deserialize (Buffer::Iterator start)
|
||||
BenchHeader<N>::Deserialize(Buffer::Iterator start)
|
||||
{
|
||||
m_ok = true;
|
||||
for (int i = 0; i < N; i++)
|
||||
m_ok = true;
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
if (start.ReadU8 () != N)
|
||||
if (start.ReadU8() != N)
|
||||
{
|
||||
m_ok = false;
|
||||
m_ok = false;
|
||||
}
|
||||
}
|
||||
return N;
|
||||
return N;
|
||||
}
|
||||
|
||||
/// BenchTag class used for benchmarking packet serialization/deserialization
|
||||
template <int N>
|
||||
class BenchTag : public Tag
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Get the bench tag name.
|
||||
* \return the name.
|
||||
*/
|
||||
static std::string GetName () {
|
||||
std::ostringstream oss;
|
||||
oss << "anon::BenchTag<" << N << ">";
|
||||
return oss.str ();
|
||||
}
|
||||
/**
|
||||
* Register this type.
|
||||
* \return The TypeId.
|
||||
*/
|
||||
static TypeId GetTypeId () {
|
||||
static TypeId tid = TypeId (GetName ())
|
||||
.SetParent<Tag> ()
|
||||
.SetGroupName ("Utils")
|
||||
.HideFromDocumentation ()
|
||||
.AddConstructor<BenchTag<N> > ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
TypeId GetInstanceTypeId () const override {
|
||||
return GetTypeId ();
|
||||
}
|
||||
uint32_t GetSerializedSize () const override {
|
||||
return N;
|
||||
}
|
||||
void Serialize (TagBuffer buf) const override {
|
||||
for (uint32_t i = 0; i < N; ++i)
|
||||
{
|
||||
buf.WriteU8 (N);
|
||||
}
|
||||
}
|
||||
void Deserialize (TagBuffer buf) override {
|
||||
for (uint32_t i = 0; i < N; ++i)
|
||||
{
|
||||
buf.ReadU8 ();
|
||||
}
|
||||
}
|
||||
void Print (std::ostream &os) const override {
|
||||
os << "N=" << N;
|
||||
}
|
||||
BenchTag ()
|
||||
: Tag () {}
|
||||
public:
|
||||
/**
|
||||
* Get the bench tag name.
|
||||
* \return the name.
|
||||
*/
|
||||
static std::string GetName()
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "anon::BenchTag<" << N << ">";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register this type.
|
||||
* \return The TypeId.
|
||||
*/
|
||||
static TypeId GetTypeId()
|
||||
{
|
||||
static TypeId tid = TypeId(GetName())
|
||||
.SetParent<Tag>()
|
||||
.SetGroupName("Utils")
|
||||
.HideFromDocumentation()
|
||||
.AddConstructor<BenchTag<N>>();
|
||||
return tid;
|
||||
}
|
||||
|
||||
TypeId GetInstanceTypeId() const override
|
||||
{
|
||||
return GetTypeId();
|
||||
}
|
||||
|
||||
uint32_t GetSerializedSize() const override
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
void Serialize(TagBuffer buf) const override
|
||||
{
|
||||
for (uint32_t i = 0; i < N; ++i)
|
||||
{
|
||||
buf.WriteU8(N);
|
||||
}
|
||||
}
|
||||
|
||||
void Deserialize(TagBuffer buf) override
|
||||
{
|
||||
for (uint32_t i = 0; i < N; ++i)
|
||||
{
|
||||
buf.ReadU8();
|
||||
}
|
||||
}
|
||||
|
||||
void Print(std::ostream& os) const override
|
||||
{
|
||||
os << "N=" << N;
|
||||
}
|
||||
|
||||
BenchTag()
|
||||
: Tag()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
benchD (uint32_t n)
|
||||
benchD(uint32_t n)
|
||||
{
|
||||
BenchHeader<25> ipv4;
|
||||
BenchHeader<8> udp;
|
||||
BenchTag<16> tag1;
|
||||
BenchTag<17> tag2;
|
||||
BenchHeader<25> ipv4;
|
||||
BenchHeader<8> udp;
|
||||
BenchTag<16> tag1;
|
||||
BenchTag<17> tag2;
|
||||
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
Ptr<Packet> p = Create<Packet> (2000);
|
||||
p->AddPacketTag (tag1);
|
||||
p->AddHeader (udp);
|
||||
p->RemovePacketTag (tag1);
|
||||
p->AddPacketTag (tag2);
|
||||
p->AddHeader (ipv4);
|
||||
Ptr<Packet> o = p->Copy ();
|
||||
o->RemoveHeader (ipv4);
|
||||
p->RemovePacketTag (tag2);
|
||||
o->RemoveHeader (udp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
benchA (uint32_t n)
|
||||
{
|
||||
BenchHeader<25> ipv4;
|
||||
BenchHeader<8> udp;
|
||||
|
||||
// The original version of this program did not use BenchHeader::IsOK ()
|
||||
// Below are two asserts that suggest how it can be used.
|
||||
NS_ASSERT_MSG (ipv4.IsOk () == false, "IsOk() should be false before deserialization");
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
Ptr<Packet> p = Create<Packet> (2000);
|
||||
p->AddHeader (udp);
|
||||
p->AddHeader (ipv4);
|
||||
Ptr<Packet> o = p->Copy ();
|
||||
o->RemoveHeader (ipv4);
|
||||
o->RemoveHeader (udp);
|
||||
}
|
||||
NS_ASSERT_MSG (ipv4.IsOk () == true, "IsOk() should be true after deserialization");
|
||||
}
|
||||
|
||||
static void
|
||||
benchB (uint32_t n)
|
||||
{
|
||||
BenchHeader<25> ipv4;
|
||||
BenchHeader<8> udp;
|
||||
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
Ptr<Packet> p = Create<Packet> (2000);
|
||||
p->AddHeader (udp);
|
||||
p->AddHeader (ipv4);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
C2 (Ptr<Packet> p)
|
||||
{
|
||||
BenchHeader<8> udp;
|
||||
|
||||
p->RemoveHeader (udp);
|
||||
}
|
||||
|
||||
static void
|
||||
C1 (Ptr<Packet> p)
|
||||
{
|
||||
BenchHeader<25> ipv4;
|
||||
p->RemoveHeader (ipv4);
|
||||
C2 (p);
|
||||
}
|
||||
|
||||
static void
|
||||
benchC (uint32_t n)
|
||||
{
|
||||
BenchHeader<25> ipv4;
|
||||
BenchHeader<8> udp;
|
||||
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
Ptr<Packet> p = Create<Packet> (2000);
|
||||
p->AddHeader (udp);
|
||||
p->AddHeader (ipv4);
|
||||
C1 (p);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
benchFragment (uint32_t n)
|
||||
{
|
||||
BenchHeader<25> ipv4;
|
||||
BenchHeader<8> udp;
|
||||
|
||||
for (uint32_t i= 0; i < n; i++) {
|
||||
Ptr<Packet> p = Create<Packet> (2000);
|
||||
p->AddHeader (udp);
|
||||
p->AddHeader (ipv4);
|
||||
|
||||
Ptr<Packet> frag0 = p->CreateFragment (0, 250);
|
||||
Ptr<Packet> frag1 = p->CreateFragment (250, 250);
|
||||
Ptr<Packet> frag2 = p->CreateFragment (500, 500);
|
||||
Ptr<Packet> frag3 = p->CreateFragment (1000, 500);
|
||||
Ptr<Packet> frag4 = p->CreateFragment (1500, 500);
|
||||
|
||||
/* Mix fragments in different order */
|
||||
frag2->AddAtEnd (frag3);
|
||||
frag4->AddAtEnd (frag1);
|
||||
frag2->AddAtEnd (frag4);
|
||||
frag0->AddAtEnd (frag2);
|
||||
|
||||
frag0->RemoveHeader (ipv4);
|
||||
frag0->RemoveHeader (udp);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
benchByteTags (uint32_t n)
|
||||
{
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
Ptr<Packet> p = Create<Packet> (2000);
|
||||
for (uint32_t j = 0; j < 100; j++)
|
||||
{
|
||||
BenchTag<0> tag;
|
||||
p->AddByteTag (tag);
|
||||
}
|
||||
Ptr<Packet> q = Create<Packet> (1000);
|
||||
Ptr<Packet> p = Create<Packet>(2000);
|
||||
p->AddPacketTag(tag1);
|
||||
p->AddHeader(udp);
|
||||
p->RemovePacketTag(tag1);
|
||||
p->AddPacketTag(tag2);
|
||||
p->AddHeader(ipv4);
|
||||
Ptr<Packet> o = p->Copy();
|
||||
o->RemoveHeader(ipv4);
|
||||
p->RemovePacketTag(tag2);
|
||||
o->RemoveHeader(udp);
|
||||
}
|
||||
}
|
||||
|
||||
// This should trigger adjustment of all byte tags
|
||||
q->AddAtEnd (p);
|
||||
static void
|
||||
benchA(uint32_t n)
|
||||
{
|
||||
BenchHeader<25> ipv4;
|
||||
BenchHeader<8> udp;
|
||||
|
||||
// The original version of this program did not use BenchHeader::IsOK ()
|
||||
// Below are two asserts that suggest how it can be used.
|
||||
NS_ASSERT_MSG(ipv4.IsOk() == false, "IsOk() should be false before deserialization");
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
Ptr<Packet> p = Create<Packet>(2000);
|
||||
p->AddHeader(udp);
|
||||
p->AddHeader(ipv4);
|
||||
Ptr<Packet> o = p->Copy();
|
||||
o->RemoveHeader(ipv4);
|
||||
o->RemoveHeader(udp);
|
||||
}
|
||||
NS_ASSERT_MSG(ipv4.IsOk() == true, "IsOk() should be true after deserialization");
|
||||
}
|
||||
|
||||
static void
|
||||
benchB(uint32_t n)
|
||||
{
|
||||
BenchHeader<25> ipv4;
|
||||
BenchHeader<8> udp;
|
||||
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
Ptr<Packet> p = Create<Packet>(2000);
|
||||
p->AddHeader(udp);
|
||||
p->AddHeader(ipv4);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
C2(Ptr<Packet> p)
|
||||
{
|
||||
BenchHeader<8> udp;
|
||||
|
||||
p->RemoveHeader(udp);
|
||||
}
|
||||
|
||||
static void
|
||||
C1(Ptr<Packet> p)
|
||||
{
|
||||
BenchHeader<25> ipv4;
|
||||
p->RemoveHeader(ipv4);
|
||||
C2(p);
|
||||
}
|
||||
|
||||
static void
|
||||
benchC(uint32_t n)
|
||||
{
|
||||
BenchHeader<25> ipv4;
|
||||
BenchHeader<8> udp;
|
||||
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
Ptr<Packet> p = Create<Packet>(2000);
|
||||
p->AddHeader(udp);
|
||||
p->AddHeader(ipv4);
|
||||
C1(p);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
benchFragment(uint32_t n)
|
||||
{
|
||||
BenchHeader<25> ipv4;
|
||||
BenchHeader<8> udp;
|
||||
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
Ptr<Packet> p = Create<Packet>(2000);
|
||||
p->AddHeader(udp);
|
||||
p->AddHeader(ipv4);
|
||||
|
||||
Ptr<Packet> frag0 = p->CreateFragment(0, 250);
|
||||
Ptr<Packet> frag1 = p->CreateFragment(250, 250);
|
||||
Ptr<Packet> frag2 = p->CreateFragment(500, 500);
|
||||
Ptr<Packet> frag3 = p->CreateFragment(1000, 500);
|
||||
Ptr<Packet> frag4 = p->CreateFragment(1500, 500);
|
||||
|
||||
/* Mix fragments in different order */
|
||||
frag2->AddAtEnd(frag3);
|
||||
frag4->AddAtEnd(frag1);
|
||||
frag2->AddAtEnd(frag4);
|
||||
frag0->AddAtEnd(frag2);
|
||||
|
||||
frag0->RemoveHeader(ipv4);
|
||||
frag0->RemoveHeader(udp);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
benchByteTags(uint32_t n)
|
||||
{
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
Ptr<Packet> p = Create<Packet>(2000);
|
||||
for (uint32_t j = 0; j < 100; j++)
|
||||
{
|
||||
BenchTag<0> tag;
|
||||
p->AddByteTag(tag);
|
||||
}
|
||||
Ptr<Packet> q = Create<Packet>(1000);
|
||||
|
||||
// This should trigger adjustment of all byte tags
|
||||
q->AddAtEnd(p);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
runBenchOneIteration (void (*bench) (uint32_t), uint32_t n)
|
||||
runBenchOneIteration(void (*bench)(uint32_t), uint32_t n)
|
||||
{
|
||||
SystemWallClockMs time;
|
||||
time.Start ();
|
||||
(*bench) (n);
|
||||
uint64_t deltaMs = time.End ();
|
||||
return deltaMs;
|
||||
SystemWallClockMs time;
|
||||
time.Start();
|
||||
(*bench)(n);
|
||||
uint64_t deltaMs = time.End();
|
||||
return deltaMs;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
runBench (void (*bench) (uint32_t), uint32_t n, uint32_t minIterations, char const *name)
|
||||
runBench(void (*bench)(uint32_t), uint32_t n, uint32_t minIterations, const char* name)
|
||||
{
|
||||
uint64_t minDelay = std::numeric_limits<uint64_t>::max();
|
||||
for (uint32_t i = 0; i < minIterations; i++)
|
||||
uint64_t minDelay = std::numeric_limits<uint64_t>::max();
|
||||
for (uint32_t i = 0; i < minIterations; i++)
|
||||
{
|
||||
uint64_t delay = runBenchOneIteration(bench, n);
|
||||
minDelay = std::min(minDelay, delay);
|
||||
uint64_t delay = runBenchOneIteration(bench, n);
|
||||
minDelay = std::min(minDelay, delay);
|
||||
}
|
||||
double ps = n;
|
||||
ps *= 1000;
|
||||
ps /= minDelay;
|
||||
std::cout << ps << " packets/s"
|
||||
<< " (" << minDelay << " ms elapsed)\t"
|
||||
<< name
|
||||
<< std::endl;
|
||||
double ps = n;
|
||||
ps *= 1000;
|
||||
ps /= minDelay;
|
||||
std::cout << ps << " packets/s"
|
||||
<< " (" << minDelay << " ms elapsed)\t" << name << std::endl;
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
uint32_t n = 0;
|
||||
uint32_t minIterations = 1;
|
||||
bool enablePrinting = false;
|
||||
uint32_t n = 0;
|
||||
uint32_t minIterations = 1;
|
||||
bool enablePrinting = false;
|
||||
|
||||
CommandLine cmd (__FILE__);
|
||||
cmd.Usage ("Benchmark Packet class");
|
||||
cmd.AddValue ("n", "number of iterations", n);
|
||||
cmd.AddValue ("min-iterations", "number of subiterations to minimize iteration time over", minIterations);
|
||||
cmd.AddValue ("enable-printing", "enable packet printing", enablePrinting);
|
||||
cmd.Parse (argc, argv);
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Usage("Benchmark Packet class");
|
||||
cmd.AddValue("n", "number of iterations", n);
|
||||
cmd.AddValue("min-iterations",
|
||||
"number of subiterations to minimize iteration time over",
|
||||
minIterations);
|
||||
cmd.AddValue("enable-printing", "enable packet printing", enablePrinting);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
if (n == 0)
|
||||
if (n == 0)
|
||||
{
|
||||
std::cerr << "Error-- number of packets must be specified " <<
|
||||
"by command-line argument --n=(number of packets)" << std::endl;
|
||||
exit (1);
|
||||
std::cerr << "Error-- number of packets must be specified "
|
||||
<< "by command-line argument --n=(number of packets)" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
std::cout << "Running bench-packets with n=" << n << std::endl;
|
||||
std::cout << "All tests begin by adding UDP and IPv4 headers." << std::endl;
|
||||
std::cout << "Running bench-packets with n=" << n << std::endl;
|
||||
std::cout << "All tests begin by adding UDP and IPv4 headers." << std::endl;
|
||||
|
||||
runBench (&benchA, n, minIterations, "Copy packet, remove headers");
|
||||
runBench (&benchB, n, minIterations, "Just add headers");
|
||||
runBench (&benchC, n, minIterations, "Remove by func call");
|
||||
runBench (&benchD, n, minIterations, "Intermixed add/remove headers and tags");
|
||||
runBench (&benchFragment, n, minIterations, "Fragmentation and concatenation");
|
||||
runBench (&benchByteTags, n, minIterations, "Benchmark byte tags");
|
||||
runBench(&benchA, n, minIterations, "Copy packet, remove headers");
|
||||
runBench(&benchB, n, minIterations, "Just add headers");
|
||||
runBench(&benchC, n, minIterations, "Remove by func call");
|
||||
runBench(&benchD, n, minIterations, "Intermixed add/remove headers and tags");
|
||||
runBench(&benchFragment, n, minIterations, "Fragmentation and concatenation");
|
||||
runBench(&benchByteTags, n, minIterations, "Benchmark byte tags");
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -18,14 +18,14 @@
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include <cmath> // sqrt
|
||||
#include "ns3/core-module.h"
|
||||
|
||||
#include <cmath> // sqrt
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include <vector>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
@@ -35,11 +35,15 @@ bool g_debug = false;
|
||||
/** Name of this program. */
|
||||
std::string g_me;
|
||||
/** Log to std::cout */
|
||||
#define LOG(x) std::cout << x << std::endl
|
||||
#define LOG(x) std::cout << x << std::endl
|
||||
/** Log with program name prefix. */
|
||||
#define LOGME(x) LOG (g_me << x)
|
||||
#define LOGME(x) LOG(g_me << x)
|
||||
/** Log debugging output. */
|
||||
#define DEB(x) if (g_debug) { LOGME (x); }
|
||||
#define DEB(x) \
|
||||
if (g_debug) \
|
||||
{ \
|
||||
LOGME(x); \
|
||||
}
|
||||
|
||||
/** Output field width for numeric data. */
|
||||
int g_fwidth = 6;
|
||||
@@ -54,352 +58,333 @@ int g_fwidth = 6;
|
||||
*/
|
||||
class Bench
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* \param [in] population The number of events to keep in the scheduler.
|
||||
* \param [in] total The total number of events to execute.
|
||||
*/
|
||||
Bench (const uint64_t population, const uint64_t total)
|
||||
: m_population (population),
|
||||
m_total (total),
|
||||
m_count (0)
|
||||
{
|
||||
}
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* \param [in] population The number of events to keep in the scheduler.
|
||||
* \param [in] total The total number of events to execute.
|
||||
*/
|
||||
Bench(const uint64_t population, const uint64_t total)
|
||||
: m_population(population),
|
||||
m_total(total),
|
||||
m_count(0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the event delay interval random stream.
|
||||
*
|
||||
* \param [in] stream The random variable stream to be used to generate
|
||||
* delays for future events.
|
||||
*/
|
||||
void SetRandomStream (Ptr<RandomVariableStream> stream)
|
||||
{
|
||||
m_rand = stream;
|
||||
}
|
||||
/**
|
||||
* Set the event delay interval random stream.
|
||||
*
|
||||
* \param [in] stream The random variable stream to be used to generate
|
||||
* delays for future events.
|
||||
*/
|
||||
void SetRandomStream(Ptr<RandomVariableStream> stream)
|
||||
{
|
||||
m_rand = stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of events to populate the scheduler with.
|
||||
* Each event executed schedules a new event, maintaining the population.
|
||||
* \param [in] population The number of events to keep in the scheduler.
|
||||
*/
|
||||
void SetPopulation (const uint64_t population)
|
||||
{
|
||||
m_population = population;
|
||||
}
|
||||
/**
|
||||
* Set the number of events to populate the scheduler with.
|
||||
* Each event executed schedules a new event, maintaining the population.
|
||||
* \param [in] population The number of events to keep in the scheduler.
|
||||
*/
|
||||
void SetPopulation(const uint64_t population)
|
||||
{
|
||||
m_population = population;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the total number of events to execute.
|
||||
* \param [in] total The total number of events to execute.
|
||||
*/
|
||||
void SetTotal (const uint64_t total)
|
||||
{
|
||||
m_total = total;
|
||||
}
|
||||
/**
|
||||
* Set the total number of events to execute.
|
||||
* \param [in] total The total number of events to execute.
|
||||
*/
|
||||
void SetTotal(const uint64_t total)
|
||||
{
|
||||
m_total = total;
|
||||
}
|
||||
|
||||
/** The output. */
|
||||
struct Result
|
||||
{
|
||||
double init; /**< Time (s) for initialization. */
|
||||
double simu; /**< Time (s) for simulation. */
|
||||
uint64_t pop; /**< Event population. */
|
||||
uint64_t events; /**< Number of events executed. */
|
||||
};
|
||||
/** The output. */
|
||||
struct Result
|
||||
{
|
||||
double init; /**< Time (s) for initialization. */
|
||||
double simu; /**< Time (s) for simulation. */
|
||||
uint64_t pop; /**< Event population. */
|
||||
uint64_t events; /**< Number of events executed. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Run the benchmark as configured.
|
||||
*
|
||||
* \returns The Result.
|
||||
*/
|
||||
Result Run ();
|
||||
/**
|
||||
* Run the benchmark as configured.
|
||||
*
|
||||
* \returns The Result.
|
||||
*/
|
||||
Result Run();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Event function. This checks for completion (total number of events
|
||||
* executed) and schedules a new event if not complete.
|
||||
*/
|
||||
void Cb ();
|
||||
private:
|
||||
/**
|
||||
* Event function. This checks for completion (total number of events
|
||||
* executed) and schedules a new event if not complete.
|
||||
*/
|
||||
void Cb();
|
||||
|
||||
Ptr<RandomVariableStream> m_rand; /**< Stream for event delays. */
|
||||
uint64_t m_population; /**< Event population size. */
|
||||
uint64_t m_total; /**< Total number of events to execute. */
|
||||
uint64_t m_count; /**< Count of events executed so far. */
|
||||
Ptr<RandomVariableStream> m_rand; /**< Stream for event delays. */
|
||||
uint64_t m_population; /**< Event population size. */
|
||||
uint64_t m_total; /**< Total number of events to execute. */
|
||||
uint64_t m_count; /**< Count of events executed so far. */
|
||||
|
||||
}; // class Bench
|
||||
}; // class Bench
|
||||
|
||||
Bench::Result
|
||||
Bench::Run ()
|
||||
Bench::Run()
|
||||
{
|
||||
SystemWallClockMs timer;
|
||||
double init;
|
||||
double simu;
|
||||
SystemWallClockMs timer;
|
||||
double init;
|
||||
double simu;
|
||||
|
||||
DEB ("initializing");
|
||||
m_count = 0;
|
||||
DEB("initializing");
|
||||
m_count = 0;
|
||||
|
||||
timer.Start ();
|
||||
for (uint64_t i = 0; i < m_population; ++i)
|
||||
timer.Start();
|
||||
for (uint64_t i = 0; i < m_population; ++i)
|
||||
{
|
||||
Time at = NanoSeconds (m_rand->GetValue ());
|
||||
Simulator::Schedule (at, &Bench::Cb, this);
|
||||
Time at = NanoSeconds(m_rand->GetValue());
|
||||
Simulator::Schedule(at, &Bench::Cb, this);
|
||||
}
|
||||
init = timer.End () / 1000.0;
|
||||
DEB ("initialization took " << init << "s");
|
||||
init = timer.End() / 1000.0;
|
||||
DEB("initialization took " << init << "s");
|
||||
|
||||
DEB ("running");
|
||||
timer.Start ();
|
||||
Simulator::Run ();
|
||||
simu = timer.End () / 1000.0;
|
||||
DEB ("run took " << simu << "s");
|
||||
DEB("running");
|
||||
timer.Start();
|
||||
Simulator::Run();
|
||||
simu = timer.End() / 1000.0;
|
||||
DEB("run took " << simu << "s");
|
||||
|
||||
Simulator::Destroy ();
|
||||
Simulator::Destroy();
|
||||
|
||||
return Result {init, simu, m_population, m_count};
|
||||
return Result{init, simu, m_population, m_count};
|
||||
}
|
||||
|
||||
void
|
||||
Bench::Cb ()
|
||||
Bench::Cb()
|
||||
{
|
||||
if (m_count >= m_total)
|
||||
if (m_count >= m_total)
|
||||
{
|
||||
Simulator::Stop ();
|
||||
return;
|
||||
Simulator::Stop();
|
||||
return;
|
||||
}
|
||||
DEB ("event at " << Simulator::Now ().GetSeconds () << "s");
|
||||
DEB("event at " << Simulator::Now().GetSeconds() << "s");
|
||||
|
||||
Time after = NanoSeconds (m_rand->GetValue ());
|
||||
Simulator::Schedule (after, &Bench::Cb, this);
|
||||
++m_count;
|
||||
Time after = NanoSeconds(m_rand->GetValue());
|
||||
Simulator::Schedule(after, &Bench::Cb, this);
|
||||
++m_count;
|
||||
}
|
||||
|
||||
|
||||
/** Benchmark which performs an ensemble of runs. */
|
||||
class BenchSuite
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Perform the runs for a single scheduler type.
|
||||
*
|
||||
* This will create and set the scheduler, then execute a priming run
|
||||
* followed by the number of data runs requested.
|
||||
*
|
||||
* Output will be in the form of a table showing performance for each run.
|
||||
*
|
||||
* \param [in] factory Factory pre-configured to create the desired Scheduler.
|
||||
* \param [in] pop The event population size.
|
||||
* \param [in] total The total number of events to execute.
|
||||
* \param [in] runs The number of replications.
|
||||
* \param [in] eventStream The random stream of event delays.
|
||||
* \param [in] calRev For the CalendarScheduler, whether the Reverse attribute was set.
|
||||
*/
|
||||
BenchSuite (ObjectFactory & factory,
|
||||
uint64_t pop, uint64_t total, uint64_t runs,
|
||||
Ptr<RandomVariableStream> eventStream,
|
||||
bool calRev);
|
||||
|
||||
/** Write the results to \c LOG() */
|
||||
void Log () const;
|
||||
|
||||
private:
|
||||
|
||||
/** Print the table header. */
|
||||
void Header () const;
|
||||
|
||||
/** Statistics from a single phase, init or run. */
|
||||
struct PhaseResult
|
||||
{
|
||||
double time; /**< Phase run time time (s). */
|
||||
double rate; /**< Phase event rate (events/s). */
|
||||
double period; /**< Phase period (s/event). */
|
||||
};
|
||||
|
||||
/** Results from initialization and execution of a single run. */
|
||||
struct Result
|
||||
{
|
||||
PhaseResult init; /**< Initialization phase results. */
|
||||
PhaseResult run; /**< Run (simulation) phase results. */
|
||||
public:
|
||||
/**
|
||||
* Construct from the individual run result.
|
||||
* Perform the runs for a single scheduler type.
|
||||
*
|
||||
* \param [in] r The result from a single run.
|
||||
* \returns The run result.
|
||||
*/
|
||||
static Result Bench (Bench::Result r);
|
||||
|
||||
/**
|
||||
* Log this result.
|
||||
* This will create and set the scheduler, then execute a priming run
|
||||
* followed by the number of data runs requested.
|
||||
*
|
||||
* \tparam T The type of the label.
|
||||
* \param label The label for the line.
|
||||
* Output will be in the form of a table showing performance for each run.
|
||||
*
|
||||
* \param [in] factory Factory pre-configured to create the desired Scheduler.
|
||||
* \param [in] pop The event population size.
|
||||
* \param [in] total The total number of events to execute.
|
||||
* \param [in] runs The number of replications.
|
||||
* \param [in] eventStream The random stream of event delays.
|
||||
* \param [in] calRev For the CalendarScheduler, whether the Reverse attribute was set.
|
||||
*/
|
||||
template <typename T>
|
||||
void Log(T label) const;
|
||||
}; // struct Result
|
||||
BenchSuite(ObjectFactory& factory,
|
||||
uint64_t pop,
|
||||
uint64_t total,
|
||||
uint64_t runs,
|
||||
Ptr<RandomVariableStream> eventStream,
|
||||
bool calRev);
|
||||
|
||||
std::string m_scheduler; /**< Descriptive string for the scheduler. */
|
||||
std::vector<Result> m_results; /**< Store for the run results. */
|
||||
/** Write the results to \c LOG() */
|
||||
void Log() const;
|
||||
|
||||
}; // BenchSuite
|
||||
private:
|
||||
/** Print the table header. */
|
||||
void Header() const;
|
||||
|
||||
/** Statistics from a single phase, init or run. */
|
||||
struct PhaseResult
|
||||
{
|
||||
double time; /**< Phase run time time (s). */
|
||||
double rate; /**< Phase event rate (events/s). */
|
||||
double period; /**< Phase period (s/event). */
|
||||
};
|
||||
|
||||
/** Results from initialization and execution of a single run. */
|
||||
struct Result
|
||||
{
|
||||
PhaseResult init; /**< Initialization phase results. */
|
||||
PhaseResult run; /**< Run (simulation) phase results. */
|
||||
/**
|
||||
* Construct from the individual run result.
|
||||
*
|
||||
* \param [in] r The result from a single run.
|
||||
* \returns The run result.
|
||||
*/
|
||||
static Result Bench(Bench::Result r);
|
||||
|
||||
/**
|
||||
* Log this result.
|
||||
*
|
||||
* \tparam T The type of the label.
|
||||
* \param label The label for the line.
|
||||
*/
|
||||
template <typename T>
|
||||
void Log(T label) const;
|
||||
}; // struct Result
|
||||
|
||||
std::string m_scheduler; /**< Descriptive string for the scheduler. */
|
||||
std::vector<Result> m_results; /**< Store for the run results. */
|
||||
|
||||
}; // BenchSuite
|
||||
|
||||
/* static */
|
||||
BenchSuite::Result
|
||||
BenchSuite::Result::Bench (Bench::Result r)
|
||||
BenchSuite::Result::Bench(Bench::Result r)
|
||||
{
|
||||
return Result { {r.init, r.pop / r.init, r.init / r.pop },
|
||||
{r.simu, r.events / r.simu, r.simu / r.events}
|
||||
};
|
||||
return Result{{r.init, r.pop / r.init, r.init / r.pop},
|
||||
{r.simu, r.events / r.simu, r.simu / r.events}};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
BenchSuite::Result::Log(T label) const
|
||||
{
|
||||
// Need std::left for string labels
|
||||
// Need std::left for string labels
|
||||
|
||||
LOG (std::left << std::setw (g_fwidth) << label <<
|
||||
std::setw (g_fwidth) << init.time <<
|
||||
std::setw (g_fwidth) << init.rate <<
|
||||
std::setw (g_fwidth) << init.period <<
|
||||
std::setw (g_fwidth) << run.time <<
|
||||
std::setw (g_fwidth) << run.rate <<
|
||||
std::setw (g_fwidth) << run.period
|
||||
);
|
||||
LOG(std::left << std::setw(g_fwidth) << label << std::setw(g_fwidth) << init.time
|
||||
<< std::setw(g_fwidth) << init.rate << std::setw(g_fwidth) << init.period
|
||||
<< std::setw(g_fwidth) << run.time << std::setw(g_fwidth) << run.rate
|
||||
<< std::setw(g_fwidth) << run.period);
|
||||
}
|
||||
|
||||
BenchSuite::BenchSuite (ObjectFactory & factory,
|
||||
uint64_t pop, uint64_t total, uint64_t runs,
|
||||
Ptr<RandomVariableStream> eventStream,
|
||||
bool calRev)
|
||||
BenchSuite::BenchSuite(ObjectFactory& factory,
|
||||
uint64_t pop,
|
||||
uint64_t total,
|
||||
uint64_t runs,
|
||||
Ptr<RandomVariableStream> eventStream,
|
||||
bool calRev)
|
||||
{
|
||||
Simulator::SetScheduler (factory);
|
||||
Simulator::SetScheduler(factory);
|
||||
|
||||
m_scheduler = factory.GetTypeId ().GetName ();
|
||||
if (m_scheduler == "ns3::CalendarScheduler")
|
||||
m_scheduler = factory.GetTypeId().GetName();
|
||||
if (m_scheduler == "ns3::CalendarScheduler")
|
||||
{
|
||||
m_scheduler += ": insertion order: "
|
||||
+ std::string (calRev ? "reverse" : "normal");
|
||||
m_scheduler += ": insertion order: " + std::string(calRev ? "reverse" : "normal");
|
||||
}
|
||||
if (m_scheduler == "ns3::MapScheduler")
|
||||
if (m_scheduler == "ns3::MapScheduler")
|
||||
{
|
||||
m_scheduler += " (default)";
|
||||
m_scheduler += " (default)";
|
||||
}
|
||||
|
||||
Bench bench (pop, total);
|
||||
bench.SetRandomStream (eventStream);
|
||||
bench.SetPopulation (pop);
|
||||
bench.SetTotal (total);
|
||||
Bench bench(pop, total);
|
||||
bench.SetRandomStream(eventStream);
|
||||
bench.SetPopulation(pop);
|
||||
bench.SetTotal(total);
|
||||
|
||||
m_results.reserve (runs);
|
||||
Header ();
|
||||
m_results.reserve(runs);
|
||||
Header();
|
||||
|
||||
// Prime
|
||||
DEB ("priming");
|
||||
auto prime = bench.Run ();
|
||||
Result::Bench (prime).Log ("prime");
|
||||
// Prime
|
||||
DEB("priming");
|
||||
auto prime = bench.Run();
|
||||
Result::Bench(prime).Log("prime");
|
||||
|
||||
// Perform the actual runs
|
||||
for (uint64_t i = 0; i < runs; i++)
|
||||
// Perform the actual runs
|
||||
for (uint64_t i = 0; i < runs; i++)
|
||||
{
|
||||
auto run = bench.Run ();
|
||||
m_results.push_back (Result::Bench (run));
|
||||
m_results.back ().Log (i);
|
||||
auto run = bench.Run();
|
||||
m_results.push_back(Result::Bench(run));
|
||||
m_results.back().Log(i);
|
||||
}
|
||||
|
||||
Simulator::Destroy ();
|
||||
Simulator::Destroy();
|
||||
|
||||
} // BenchSuite::Run
|
||||
} // BenchSuite::Run
|
||||
|
||||
void
|
||||
BenchSuite::Header () const
|
||||
BenchSuite::Header() const
|
||||
{
|
||||
// table header
|
||||
LOG ("");
|
||||
LOG (m_scheduler);
|
||||
LOG (std::left << std::setw (g_fwidth) << "Run #" <<
|
||||
std::left << std::setw (3 * g_fwidth) << "Initialization:" <<
|
||||
std::left << "Simulation:"
|
||||
);
|
||||
LOG (std::left << std::setw (g_fwidth) << "" <<
|
||||
std::left << std::setw (g_fwidth) << "Time (s)" <<
|
||||
std::left << std::setw (g_fwidth) << "Rate (ev/s)" <<
|
||||
std::left << std::setw (g_fwidth) << "Per (s/ev)" <<
|
||||
std::left << std::setw (g_fwidth) << "Time (s)" <<
|
||||
std::left << std::setw (g_fwidth) << "Rate (ev/s)" <<
|
||||
std::left << "Per (s/ev)"
|
||||
);
|
||||
LOG (std::setfill ('-') <<
|
||||
std::right << std::setw (g_fwidth) << " " <<
|
||||
std::right << std::setw (g_fwidth) << " " <<
|
||||
std::right << std::setw (g_fwidth) << " " <<
|
||||
std::right << std::setw (g_fwidth) << " " <<
|
||||
std::right << std::setw (g_fwidth) << " " <<
|
||||
std::right << std::setw (g_fwidth) << " " <<
|
||||
std::right << std::setw (g_fwidth) << " " <<
|
||||
std::setfill (' ')
|
||||
);
|
||||
|
||||
// table header
|
||||
LOG("");
|
||||
LOG(m_scheduler);
|
||||
LOG(std::left << std::setw(g_fwidth) << "Run #" << std::left << std::setw(3 * g_fwidth)
|
||||
<< "Initialization:" << std::left << "Simulation:");
|
||||
LOG(std::left << std::setw(g_fwidth) << "" << std::left << std::setw(g_fwidth) << "Time (s)"
|
||||
<< std::left << std::setw(g_fwidth) << "Rate (ev/s)" << std::left
|
||||
<< std::setw(g_fwidth) << "Per (s/ev)" << std::left << std::setw(g_fwidth)
|
||||
<< "Time (s)" << std::left << std::setw(g_fwidth) << "Rate (ev/s)" << std::left
|
||||
<< "Per (s/ev)");
|
||||
LOG(std::setfill('-') << std::right << std::setw(g_fwidth) << " " << std::right
|
||||
<< std::setw(g_fwidth) << " " << std::right << std::setw(g_fwidth) << " "
|
||||
<< std::right << std::setw(g_fwidth) << " " << std::right
|
||||
<< std::setw(g_fwidth) << " " << std::right << std::setw(g_fwidth) << " "
|
||||
<< std::right << std::setw(g_fwidth) << " " << std::setfill(' '));
|
||||
}
|
||||
|
||||
void
|
||||
BenchSuite::Log () const
|
||||
BenchSuite::Log() const
|
||||
{
|
||||
if (m_results.size () < 2)
|
||||
if (m_results.size() < 2)
|
||||
{
|
||||
LOG ("");
|
||||
return;
|
||||
LOG("");
|
||||
return;
|
||||
}
|
||||
|
||||
// Average the results
|
||||
// Average the results
|
||||
|
||||
// See Welford's online algorithm for these expressions,
|
||||
// which avoid subtracting large numbers.
|
||||
// https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm
|
||||
// See Welford's online algorithm for these expressions,
|
||||
// which avoid subtracting large numbers.
|
||||
// https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm
|
||||
|
||||
uint64_t n {0}; // number of samples
|
||||
Result average {m_results[0]}; // average
|
||||
Result moment2 { {0, 0, 0}, // 2nd moment, to calculate stdev
|
||||
{0, 0, 0} };
|
||||
uint64_t n{0}; // number of samples
|
||||
Result average{m_results[0]}; // average
|
||||
Result moment2{{0, 0, 0}, // 2nd moment, to calculate stdev
|
||||
{0, 0, 0}};
|
||||
|
||||
for ( ; n < m_results.size (); ++n)
|
||||
for (; n < m_results.size(); ++n)
|
||||
{
|
||||
double deltaPre;
|
||||
double deltaPost;
|
||||
const auto & run = m_results[n];
|
||||
uint64_t count = n + 1;
|
||||
double deltaPre;
|
||||
double deltaPost;
|
||||
const auto& run = m_results[n];
|
||||
uint64_t count = n + 1;
|
||||
|
||||
#define ACCUMULATE(phase, field) \
|
||||
deltaPre = run.phase.field - average.phase.field; \
|
||||
average.phase.field += deltaPre / count ; \
|
||||
deltaPost = run.phase.field - average.phase.field; \
|
||||
moment2.phase.field += deltaPre * deltaPost
|
||||
#define ACCUMULATE(phase, field) \
|
||||
deltaPre = run.phase.field - average.phase.field; \
|
||||
average.phase.field += deltaPre / count; \
|
||||
deltaPost = run.phase.field - average.phase.field; \
|
||||
moment2.phase.field += deltaPre * deltaPost
|
||||
|
||||
ACCUMULATE (init, time);
|
||||
ACCUMULATE (init, rate);
|
||||
ACCUMULATE (init, period);
|
||||
ACCUMULATE (run, time);
|
||||
ACCUMULATE (run, rate);
|
||||
ACCUMULATE (run, period);
|
||||
ACCUMULATE(init, time);
|
||||
ACCUMULATE(init, rate);
|
||||
ACCUMULATE(init, period);
|
||||
ACCUMULATE(run, time);
|
||||
ACCUMULATE(run, rate);
|
||||
ACCUMULATE(run, period);
|
||||
|
||||
#undef ACCUMULATE
|
||||
}
|
||||
|
||||
auto stdev = Result {
|
||||
{ std::sqrt (moment2.init.time / n),
|
||||
std::sqrt (moment2.init.rate / n),
|
||||
std::sqrt (moment2.init.period / n)},
|
||||
{ std::sqrt (moment2.run.time / n),
|
||||
std::sqrt (moment2.run.rate / n),
|
||||
std::sqrt (moment2.run.period / n)}
|
||||
};
|
||||
auto stdev = Result{{std::sqrt(moment2.init.time / n),
|
||||
std::sqrt(moment2.init.rate / n),
|
||||
std::sqrt(moment2.init.period / n)},
|
||||
{std::sqrt(moment2.run.time / n),
|
||||
std::sqrt(moment2.run.rate / n),
|
||||
std::sqrt(moment2.run.period / n)}};
|
||||
|
||||
average.Log ("average");
|
||||
stdev.Log ("stdev");
|
||||
average.Log("average");
|
||||
stdev.Log("stdev");
|
||||
|
||||
LOG ("");
|
||||
|
||||
} // BenchSuite::Log()
|
||||
LOG("");
|
||||
|
||||
} // BenchSuite::Log()
|
||||
|
||||
/**
|
||||
* Create a RandomVariableStream to generate next event delays.
|
||||
@@ -413,162 +398,160 @@ BenchSuite::Log () const
|
||||
* \returns The RandomVariableStream.
|
||||
*/
|
||||
Ptr<RandomVariableStream>
|
||||
GetRandomStream (std::string filename)
|
||||
GetRandomStream(std::string filename)
|
||||
{
|
||||
Ptr<RandomVariableStream> stream = nullptr;
|
||||
Ptr<RandomVariableStream> stream = nullptr;
|
||||
|
||||
if (filename == "")
|
||||
if (filename == "")
|
||||
{
|
||||
LOG (" Event time distribution: default exponential");
|
||||
auto erv = CreateObject<ExponentialRandomVariable> ();
|
||||
erv->SetAttribute ("Mean", DoubleValue (100));
|
||||
stream = erv;
|
||||
LOG(" Event time distribution: default exponential");
|
||||
auto erv = CreateObject<ExponentialRandomVariable>();
|
||||
erv->SetAttribute("Mean", DoubleValue(100));
|
||||
stream = erv;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
std::istream *input;
|
||||
std::istream* input;
|
||||
|
||||
if (filename == "-")
|
||||
if (filename == "-")
|
||||
{
|
||||
LOG (" Event time distribution: from stdin");
|
||||
input = &std::cin;
|
||||
LOG(" Event time distribution: from stdin");
|
||||
input = &std::cin;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
LOG (" Event time distribution: from " << filename);
|
||||
input = new std::ifstream (filename.c_str ());
|
||||
LOG(" Event time distribution: from " << filename);
|
||||
input = new std::ifstream(filename.c_str());
|
||||
}
|
||||
|
||||
double value;
|
||||
std::vector<double> nsValues;
|
||||
double value;
|
||||
std::vector<double> nsValues;
|
||||
|
||||
while (!input->eof ())
|
||||
while (!input->eof())
|
||||
{
|
||||
if (*input >> value)
|
||||
if (*input >> value)
|
||||
{
|
||||
uint64_t ns = (uint64_t) (value * 1000000000);
|
||||
nsValues.push_back (ns);
|
||||
uint64_t ns = (uint64_t)(value * 1000000000);
|
||||
nsValues.push_back(ns);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
input->clear ();
|
||||
std::string line;
|
||||
*input >> line;
|
||||
input->clear();
|
||||
std::string line;
|
||||
*input >> line;
|
||||
}
|
||||
}
|
||||
LOG (" Found " << nsValues.size () << " entries");
|
||||
auto drv = CreateObject<DeterministicRandomVariable> ();
|
||||
drv->SetValueArray (&nsValues[0], nsValues.size ());
|
||||
stream = drv;
|
||||
LOG(" Found " << nsValues.size() << " entries");
|
||||
auto drv = CreateObject<DeterministicRandomVariable>();
|
||||
drv->SetValueArray(&nsValues[0], nsValues.size());
|
||||
stream = drv;
|
||||
}
|
||||
|
||||
return stream;
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
bool allSched = false;
|
||||
bool schedCal = false;
|
||||
bool schedHeap = false;
|
||||
bool schedList = false;
|
||||
bool schedMap = false; // default scheduler
|
||||
bool schedPQ = false;
|
||||
|
||||
bool allSched = false;
|
||||
bool schedCal = false;
|
||||
bool schedHeap = false;
|
||||
bool schedList = false;
|
||||
bool schedMap = false; // default scheduler
|
||||
bool schedPQ = false;
|
||||
uint64_t pop = 100000;
|
||||
uint64_t total = 1000000;
|
||||
uint64_t runs = 1;
|
||||
std::string filename = "";
|
||||
bool calRev = false;
|
||||
|
||||
uint64_t pop = 100000;
|
||||
uint64_t total = 1000000;
|
||||
uint64_t runs = 1;
|
||||
std::string filename = "";
|
||||
bool calRev = false;
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Usage("Benchmark the simulator scheduler.\n"
|
||||
"\n"
|
||||
"Event intervals are taken from one of:\n"
|
||||
" an exponential distribution, with mean 100 ns,\n"
|
||||
" an ascii file, given by the --file=\"<filename>\" argument,\n"
|
||||
" or standard input, by the argument --file=\"-\"\n"
|
||||
"In the case of either --file form, the input is expected\n"
|
||||
"to be ascii, giving the relative event times in ns.\n"
|
||||
"\n"
|
||||
"If no scheduler is specified the MapScheduler will be run.");
|
||||
cmd.AddValue("all", "use all schedulers", allSched);
|
||||
cmd.AddValue("cal", "use CalendarSheduler", schedCal);
|
||||
cmd.AddValue("calrev", "reverse ordering in the CalendarScheduler", calRev);
|
||||
cmd.AddValue("heap", "use HeapScheduler", schedHeap);
|
||||
cmd.AddValue("list", "use ListSheduler", schedList);
|
||||
cmd.AddValue("map", "use MapScheduler (default)", schedMap);
|
||||
cmd.AddValue("pri", "use PriorityQueue", schedPQ);
|
||||
cmd.AddValue("debug", "enable debugging output", g_debug);
|
||||
cmd.AddValue("pop", "event population size", pop);
|
||||
cmd.AddValue("total", "total number of events to run", total);
|
||||
cmd.AddValue("runs", "number of runs", runs);
|
||||
cmd.AddValue("file", "file of relative event times", filename);
|
||||
cmd.AddValue("prec", "printed output precision", g_fwidth);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
CommandLine cmd (__FILE__);
|
||||
cmd.Usage ("Benchmark the simulator scheduler.\n"
|
||||
"\n"
|
||||
"Event intervals are taken from one of:\n"
|
||||
" an exponential distribution, with mean 100 ns,\n"
|
||||
" an ascii file, given by the --file=\"<filename>\" argument,\n"
|
||||
" or standard input, by the argument --file=\"-\"\n"
|
||||
"In the case of either --file form, the input is expected\n"
|
||||
"to be ascii, giving the relative event times in ns.\n"
|
||||
"\n"
|
||||
"If no scheduler is specified the MapScheduler will be run.");
|
||||
cmd.AddValue ("all", "use all schedulers", allSched);
|
||||
cmd.AddValue ("cal", "use CalendarSheduler", schedCal);
|
||||
cmd.AddValue ("calrev", "reverse ordering in the CalendarScheduler", calRev);
|
||||
cmd.AddValue ("heap", "use HeapScheduler", schedHeap);
|
||||
cmd.AddValue ("list", "use ListSheduler", schedList);
|
||||
cmd.AddValue ("map", "use MapScheduler (default)", schedMap);
|
||||
cmd.AddValue ("pri", "use PriorityQueue", schedPQ);
|
||||
cmd.AddValue ("debug", "enable debugging output", g_debug);
|
||||
cmd.AddValue ("pop", "event population size", pop);
|
||||
cmd.AddValue ("total", "total number of events to run", total);
|
||||
cmd.AddValue ("runs", "number of runs", runs);
|
||||
cmd.AddValue ("file", "file of relative event times", filename);
|
||||
cmd.AddValue ("prec", "printed output precision", g_fwidth);
|
||||
cmd.Parse (argc, argv);
|
||||
g_me = cmd.GetName() + ": ";
|
||||
g_fwidth += 6; // 5 extra chars in '2.000002e+07 ': . e+0 _
|
||||
|
||||
g_me = cmd.GetName () + ": ";
|
||||
g_fwidth += 6; // 5 extra chars in '2.000002e+07 ': . e+0 _
|
||||
LOG(std::setprecision(g_fwidth - 6)); // prints blank line
|
||||
LOGME(" Benchmark the simulator scheduler");
|
||||
LOG(" Event population size: " << pop);
|
||||
LOG(" Total events per run: " << total);
|
||||
LOG(" Number of runs per scheduler: " << runs);
|
||||
DEB("debugging is ON");
|
||||
|
||||
LOG (std::setprecision (g_fwidth - 6)); // prints blank line
|
||||
LOGME (" Benchmark the simulator scheduler");
|
||||
LOG (" Event population size: " << pop);
|
||||
LOG (" Total events per run: " << total);
|
||||
LOG (" Number of runs per scheduler: " << runs);
|
||||
DEB ("debugging is ON");
|
||||
|
||||
if (allSched)
|
||||
if (allSched)
|
||||
{
|
||||
schedCal = schedHeap = schedList = schedMap = schedPQ = true;
|
||||
schedCal = schedHeap = schedList = schedMap = schedPQ = true;
|
||||
}
|
||||
// Set the default case if nothing else is set
|
||||
if (! (schedCal || schedHeap || schedList || schedMap || schedPQ))
|
||||
// Set the default case if nothing else is set
|
||||
if (!(schedCal || schedHeap || schedList || schedMap || schedPQ))
|
||||
{
|
||||
schedMap = true;
|
||||
schedMap = true;
|
||||
}
|
||||
|
||||
auto eventStream = GetRandomStream (filename);
|
||||
auto eventStream = GetRandomStream(filename);
|
||||
|
||||
|
||||
ObjectFactory factory ("ns3::MapScheduler");
|
||||
if (schedCal)
|
||||
ObjectFactory factory("ns3::MapScheduler");
|
||||
if (schedCal)
|
||||
{
|
||||
factory.SetTypeId ("ns3::CalendarScheduler");
|
||||
factory.Set ("Reverse", BooleanValue (calRev));
|
||||
BenchSuite (factory, pop, total, runs, eventStream, calRev).Log ();
|
||||
if (allSched)
|
||||
factory.SetTypeId("ns3::CalendarScheduler");
|
||||
factory.Set("Reverse", BooleanValue(calRev));
|
||||
BenchSuite(factory, pop, total, runs, eventStream, calRev).Log();
|
||||
if (allSched)
|
||||
{
|
||||
factory.Set ("Reverse", BooleanValue (!calRev));
|
||||
BenchSuite (factory, pop, total, runs, eventStream, !calRev).Log ();
|
||||
factory.Set("Reverse", BooleanValue(!calRev));
|
||||
BenchSuite(factory, pop, total, runs, eventStream, !calRev).Log();
|
||||
}
|
||||
}
|
||||
if (schedHeap)
|
||||
if (schedHeap)
|
||||
{
|
||||
factory.SetTypeId ("ns3::HeapScheduler");
|
||||
BenchSuite (factory, pop, total, runs, eventStream, calRev).Log ();
|
||||
factory.SetTypeId("ns3::HeapScheduler");
|
||||
BenchSuite(factory, pop, total, runs, eventStream, calRev).Log();
|
||||
}
|
||||
if (schedList)
|
||||
if (schedList)
|
||||
{
|
||||
factory.SetTypeId ("ns3::ListScheduler");
|
||||
auto listTotal = total;
|
||||
if (allSched)
|
||||
factory.SetTypeId("ns3::ListScheduler");
|
||||
auto listTotal = total;
|
||||
if (allSched)
|
||||
{
|
||||
LOG ("Running List scheduler with 1/10 total events");
|
||||
listTotal /= 10;
|
||||
LOG("Running List scheduler with 1/10 total events");
|
||||
listTotal /= 10;
|
||||
}
|
||||
BenchSuite (factory, pop, listTotal, runs, eventStream, calRev).Log ();
|
||||
BenchSuite(factory, pop, listTotal, runs, eventStream, calRev).Log();
|
||||
}
|
||||
if (schedMap)
|
||||
if (schedMap)
|
||||
{
|
||||
factory.SetTypeId ("ns3::MapScheduler");
|
||||
BenchSuite (factory, pop, total, runs, eventStream, calRev).Log ();
|
||||
factory.SetTypeId("ns3::MapScheduler");
|
||||
BenchSuite(factory, pop, total, runs, eventStream, calRev).Log();
|
||||
}
|
||||
if (schedPQ)
|
||||
if (schedPQ)
|
||||
{
|
||||
factory.SetTypeId ("ns3::PriorityQueueScheduler");
|
||||
BenchSuite (factory, pop, total, runs, eventStream, calRev).Log ();
|
||||
factory.SetTypeId("ns3::PriorityQueueScheduler");
|
||||
BenchSuite(factory, pop, total, runs, eventStream, calRev).Log();
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -14,15 +14,13 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <chrono>
|
||||
#include "ns3/core-module.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
@@ -37,13 +35,13 @@ using namespace ns3;
|
||||
* \param size The buffer size.
|
||||
*/
|
||||
void
|
||||
PerfFile (FILE *file, uint32_t n, const char *buffer, uint32_t size)
|
||||
PerfFile(FILE* file, uint32_t n, const char* buffer, uint32_t size)
|
||||
{
|
||||
for (uint32_t i = 0; i < n; ++i)
|
||||
for (uint32_t i = 0; i < n; ++i)
|
||||
{
|
||||
if (std::fwrite (buffer, 1, size, file) != size)
|
||||
if (std::fwrite(buffer, 1, size, file) != size)
|
||||
{
|
||||
NS_ABORT_MSG ("PerfFile(): fwrite error");
|
||||
NS_ABORT_MSG("PerfFile(): fwrite error");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,88 +57,92 @@ PerfFile (FILE *file, uint32_t n, const char *buffer, uint32_t size)
|
||||
* \param size The buffer size.
|
||||
*/
|
||||
void
|
||||
PerfStream (std::ostream &stream, uint32_t n, const char *buffer, uint32_t size)
|
||||
PerfStream(std::ostream& stream, uint32_t n, const char* buffer, uint32_t size)
|
||||
{
|
||||
for (uint32_t i = 0; i < n; ++i)
|
||||
for (uint32_t i = 0; i < n; ++i)
|
||||
{
|
||||
stream.write (buffer, size);
|
||||
stream.write(buffer, size);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
uint32_t n = 100000;
|
||||
uint32_t iter = 50;
|
||||
bool doStream = false;
|
||||
bool binmode = true;
|
||||
uint32_t n = 100000;
|
||||
uint32_t iter = 50;
|
||||
bool doStream = false;
|
||||
bool binmode = true;
|
||||
|
||||
CommandLine cmd (__FILE__);
|
||||
cmd.AddValue ("n", "How many times to write (defaults to 100000", n);
|
||||
cmd.AddValue ("iter", "How many times to run the test looking for a min (defaults to 50)", iter);
|
||||
cmd.AddValue ("doStream", "Run the C++ I/O benchmark otherwise the C I/O ", doStream);
|
||||
cmd.AddValue ("binmode", "Select binary mode for the C++ I/O benchmark (defaults to true)", binmode);
|
||||
cmd.Parse (argc, argv);
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.AddValue("n", "How many times to write (defaults to 100000", n);
|
||||
cmd.AddValue("iter", "How many times to run the test looking for a min (defaults to 50)", iter);
|
||||
cmd.AddValue("doStream", "Run the C++ I/O benchmark otherwise the C I/O ", doStream);
|
||||
cmd.AddValue("binmode",
|
||||
"Select binary mode for the C++ I/O benchmark (defaults to true)",
|
||||
binmode);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
auto minResultNs = std::chrono::duration_cast<std::chrono::nanoseconds> (
|
||||
std::chrono::nanoseconds::max ());
|
||||
auto minResultNs =
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::nanoseconds::max());
|
||||
|
||||
char buffer[1024];
|
||||
char buffer[1024];
|
||||
|
||||
if (doStream)
|
||||
if (doStream)
|
||||
{
|
||||
//
|
||||
// This will probably run on a machine doing other things. Run it some
|
||||
// relatively large number of times and try to find a minimum, which
|
||||
// will hopefully represent a time when it runs free of interference.
|
||||
//
|
||||
for (uint32_t i = 0; i < iter; ++i)
|
||||
//
|
||||
// This will probably run on a machine doing other things. Run it some
|
||||
// relatively large number of times and try to find a minimum, which
|
||||
// will hopefully represent a time when it runs free of interference.
|
||||
//
|
||||
for (uint32_t i = 0; i < iter; ++i)
|
||||
{
|
||||
std::ofstream stream;
|
||||
if (binmode)
|
||||
std::ofstream stream;
|
||||
if (binmode)
|
||||
{
|
||||
stream.open ("streamtest", std::ios_base::binary | std::ios_base::out);
|
||||
stream.open("streamtest", std::ios_base::binary | std::ios_base::out);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
stream.open ("streamtest", std::ios_base::out);
|
||||
stream.open("streamtest", std::ios_base::out);
|
||||
}
|
||||
|
||||
auto start = std::chrono::steady_clock::now ();
|
||||
PerfStream (stream, n, buffer, 1024);
|
||||
auto end = std::chrono::steady_clock::now ();
|
||||
auto resultNs = std::chrono::duration_cast<std::chrono::nanoseconds> (end - start);
|
||||
resultNs = std::min (resultNs, minResultNs);
|
||||
stream.close ();
|
||||
std::cout << "."; std::cout.flush ();
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
PerfStream(stream, n, buffer, 1024);
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
auto resultNs = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
|
||||
resultNs = std::min(resultNs, minResultNs);
|
||||
stream.close();
|
||||
std::cout << ".";
|
||||
std::cout.flush();
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
//
|
||||
// This will probably run on a machine doing other things. Run it some
|
||||
// relatively large number of times and try to find a minimum, which
|
||||
// will hopefully represent a time when it runs free of interference.
|
||||
//
|
||||
for (uint32_t i = 0; i < iter; ++i)
|
||||
//
|
||||
// This will probably run on a machine doing other things. Run it some
|
||||
// relatively large number of times and try to find a minimum, which
|
||||
// will hopefully represent a time when it runs free of interference.
|
||||
//
|
||||
for (uint32_t i = 0; i < iter; ++i)
|
||||
{
|
||||
FILE *file = fopen ("filetest", "w");
|
||||
FILE* file = fopen("filetest", "w");
|
||||
|
||||
auto start = std::chrono::steady_clock::now ();
|
||||
PerfFile (file, n, buffer, 1024);
|
||||
auto end = std::chrono::steady_clock::now ();
|
||||
auto resultNs = std::chrono::duration_cast<std::chrono::nanoseconds> (end - start);
|
||||
resultNs = std::min (resultNs, minResultNs);
|
||||
fclose (file);
|
||||
file = nullptr;
|
||||
std::cout << "."; std::cout.flush ();
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
PerfFile(file, n, buffer, 1024);
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
auto resultNs = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
|
||||
resultNs = std::min(resultNs, minResultNs);
|
||||
fclose(file);
|
||||
file = nullptr;
|
||||
std::cout << ".";
|
||||
std::cout.flush();
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
std::cout << argv[0] << ": " << minResultNs.count () << "ns" << std::endl;
|
||||
std::cout << argv[0] << ": " << minResultNs.count() << "ns" << std::endl;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,8 @@
|
||||
|
||||
#include "ns3/test.h"
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
return ns3::TestRunner::Run (argc, argv);
|
||||
return ns3::TestRunner::Run(argc, argv);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user