A Discrete-Event Network Simulator
API
bench-packets.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2006 INRIA
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
18  */
19 
20 // This program can be used to benchmark packet serialization/deserialization
21 // operations using Headers and Tags, for various numbers of packets 'n'
22 // Sample usage: ./ns3 run 'bench-packets --n=10000'
23 
24 #include "ns3/command-line.h"
25 #include "ns3/packet-metadata.h"
26 #include "ns3/packet.h"
27 #include "ns3/system-wall-clock-ms.h"
28 
29 #include <algorithm>
30 #include <iostream>
31 #include <limits>
32 #include <sstream>
33 #include <stdlib.h> // for exit ()
34 #include <string>
35 
36 using namespace ns3;
37 
39 template <int N>
40 class BenchHeader : public Header
41 {
42  public:
43  BenchHeader();
51  bool IsOk() const;
52 
57  static TypeId GetTypeId();
58  TypeId GetInstanceTypeId() const override;
59  void Print(std::ostream& os) const override;
60  uint32_t GetSerializedSize() const override;
61  void Serialize(Buffer::Iterator start) const override;
62  uint32_t Deserialize(Buffer::Iterator start) override;
63 
64  private:
69  static std::string GetTypeName();
70  bool m_ok;
71 };
72 
73 template <int N>
75  : m_ok(false)
76 {
77 }
78 
79 template <int N>
80 bool
82 {
83  return m_ok;
84 }
85 
86 template <int N>
87 std::string
89 {
90  std::ostringstream oss;
91  oss << "ns3::BenchHeader<" << N << ">";
92  return oss.str();
93 }
94 
95 template <int N>
96 TypeId
98 {
99  static TypeId tid = TypeId(GetTypeName())
100  .SetParent<Header>()
101  .SetGroupName("Utils")
102  .HideFromDocumentation()
103  .AddConstructor<BenchHeader<N>>();
104  return tid;
105 }
106 
107 template <int N>
108 TypeId
110 {
111  return GetTypeId();
112 }
113 
114 template <int N>
115 void
116 BenchHeader<N>::Print(std::ostream& os) const
117 {
118  NS_ASSERT(false);
119 }
120 
121 template <int N>
122 uint32_t
124 {
125  return N;
126 }
127 
128 template <int N>
129 void
131 {
132  start.WriteU8(N, N);
133 }
134 
135 template <int N>
136 uint32_t
138 {
139  m_ok = true;
140  for (int i = 0; i < N; i++)
141  {
142  if (start.ReadU8() != N)
143  {
144  m_ok = false;
145  }
146  }
147  return N;
148 }
149 
151 template <int N>
152 class BenchTag : public Tag
153 {
154  public:
159  static std::string GetName()
160  {
161  std::ostringstream oss;
162  oss << "anon::BenchTag<" << N << ">";
163  return oss.str();
164  }
165 
170  static TypeId GetTypeId()
171  {
172  static TypeId tid = TypeId(GetName())
173  .SetParent<Tag>()
174  .SetGroupName("Utils")
175  .HideFromDocumentation()
176  .AddConstructor<BenchTag<N>>();
177  return tid;
178  }
179 
180  TypeId GetInstanceTypeId() const override
181  {
182  return GetTypeId();
183  }
184 
185  uint32_t GetSerializedSize() const override
186  {
187  return N;
188  }
189 
190  void Serialize(TagBuffer buf) const override
191  {
192  for (uint32_t i = 0; i < N; ++i)
193  {
194  buf.WriteU8(N);
195  }
196  }
197 
198  void Deserialize(TagBuffer buf) override
199  {
200  for (uint32_t i = 0; i < N; ++i)
201  {
202  buf.ReadU8();
203  }
204  }
205 
206  void Print(std::ostream& os) const override
207  {
208  os << "N=" << N;
209  }
210 
212  : Tag()
213  {
214  }
215 };
216 
217 static void
218 benchD(uint32_t n)
219 {
221  BenchHeader<8> udp;
222  BenchTag<16> tag1;
223  BenchTag<17> tag2;
224 
225  for (uint32_t i = 0; i < n; i++)
226  {
227  Ptr<Packet> p = Create<Packet>(2000);
228  p->AddPacketTag(tag1);
229  p->AddHeader(udp);
230  p->RemovePacketTag(tag1);
231  p->AddPacketTag(tag2);
232  p->AddHeader(ipv4);
233  Ptr<Packet> o = p->Copy();
234  o->RemoveHeader(ipv4);
235  p->RemovePacketTag(tag2);
236  o->RemoveHeader(udp);
237  }
238 }
239 
240 static void
241 benchA(uint32_t n)
242 {
244  BenchHeader<8> udp;
245 
246  // The original version of this program did not use BenchHeader::IsOK ()
247  // Below are two asserts that suggest how it can be used.
248  NS_ASSERT_MSG(ipv4.IsOk() == false, "IsOk() should be false before deserialization");
249  for (uint32_t i = 0; i < n; i++)
250  {
251  Ptr<Packet> p = Create<Packet>(2000);
252  p->AddHeader(udp);
253  p->AddHeader(ipv4);
254  Ptr<Packet> o = p->Copy();
255  o->RemoveHeader(ipv4);
256  o->RemoveHeader(udp);
257  }
258  NS_ASSERT_MSG(ipv4.IsOk() == true, "IsOk() should be true after deserialization");
259 }
260 
261 static void
262 benchB(uint32_t n)
263 {
265  BenchHeader<8> udp;
266 
267  for (uint32_t i = 0; i < n; i++)
268  {
269  Ptr<Packet> p = Create<Packet>(2000);
270  p->AddHeader(udp);
271  p->AddHeader(ipv4);
272  }
273 }
274 
275 static void
277 {
278  BenchHeader<8> udp;
279 
280  p->RemoveHeader(udp);
281 }
282 
283 static void
285 {
287  p->RemoveHeader(ipv4);
288  C2(p);
289 }
290 
291 static void
292 benchC(uint32_t n)
293 {
295  BenchHeader<8> udp;
296 
297  for (uint32_t i = 0; i < n; i++)
298  {
299  Ptr<Packet> p = Create<Packet>(2000);
300  p->AddHeader(udp);
301  p->AddHeader(ipv4);
302  C1(p);
303  }
304 }
305 
306 static void
307 benchFragment(uint32_t n)
308 {
310  BenchHeader<8> udp;
311 
312  for (uint32_t i = 0; i < n; i++)
313  {
314  Ptr<Packet> p = Create<Packet>(2000);
315  p->AddHeader(udp);
316  p->AddHeader(ipv4);
317 
318  Ptr<Packet> frag0 = p->CreateFragment(0, 250);
319  Ptr<Packet> frag1 = p->CreateFragment(250, 250);
320  Ptr<Packet> frag2 = p->CreateFragment(500, 500);
321  Ptr<Packet> frag3 = p->CreateFragment(1000, 500);
322  Ptr<Packet> frag4 = p->CreateFragment(1500, 500);
323 
324  /* Mix fragments in different order */
325  frag2->AddAtEnd(frag3);
326  frag4->AddAtEnd(frag1);
327  frag2->AddAtEnd(frag4);
328  frag0->AddAtEnd(frag2);
329 
330  frag0->RemoveHeader(ipv4);
331  frag0->RemoveHeader(udp);
332  }
333 }
334 
335 static void
336 benchByteTags(uint32_t n)
337 {
338  for (uint32_t i = 0; i < n; i++)
339  {
340  Ptr<Packet> p = Create<Packet>(2000);
341  for (uint32_t j = 0; j < 100; j++)
342  {
343  BenchTag<0> tag;
344  p->AddByteTag(tag);
345  }
346  Ptr<Packet> q = Create<Packet>(1000);
347 
348  // This should trigger adjustment of all byte tags
349  q->AddAtEnd(p);
350  }
351 }
352 
353 static uint64_t
354 runBenchOneIteration(void (*bench)(uint32_t), uint32_t n)
355 {
356  SystemWallClockMs time;
357  time.Start();
358  (*bench)(n);
359  uint64_t deltaMs = time.End();
360  return deltaMs;
361 }
362 
363 static void
364 runBench(void (*bench)(uint32_t), uint32_t n, uint32_t minIterations, const char* name)
365 {
366  uint64_t minDelay = std::numeric_limits<uint64_t>::max();
367  for (uint32_t i = 0; i < minIterations; i++)
368  {
369  uint64_t delay = runBenchOneIteration(bench, n);
370  minDelay = std::min(minDelay, delay);
371  }
372  double ps = n;
373  ps *= 1000;
374  ps /= minDelay;
375  std::cout << ps << " packets/s"
376  << " (" << minDelay << " ms elapsed)\t" << name << std::endl;
377 }
378 
379 int
380 main(int argc, char* argv[])
381 {
382  uint32_t n = 0;
383  uint32_t minIterations = 1;
384  bool enablePrinting = false;
385 
386  CommandLine cmd(__FILE__);
387  cmd.Usage("Benchmark Packet class");
388  cmd.AddValue("n", "number of iterations", n);
389  cmd.AddValue("min-iterations",
390  "number of subiterations to minimize iteration time over",
391  minIterations);
392  cmd.AddValue("enable-printing", "enable packet printing", enablePrinting);
393  cmd.Parse(argc, argv);
394 
395  if (n == 0)
396  {
397  std::cerr << "Error-- number of packets must be specified "
398  << "by command-line argument --n=(number of packets)" << std::endl;
399  exit(1);
400  }
401  std::cout << "Running bench-packets with n=" << n << std::endl;
402  std::cout << "All tests begin by adding UDP and IPv4 headers." << std::endl;
403 
404  runBench(&benchA, n, minIterations, "Copy packet, remove headers");
405  runBench(&benchB, n, minIterations, "Just add headers");
406  runBench(&benchC, n, minIterations, "Remove by func call");
407  runBench(&benchD, n, minIterations, "Intermixed add/remove headers and tags");
408  runBench(&benchFragment, n, minIterations, "Fragmentation and concatenation");
409  runBench(&benchByteTags, n, minIterations, "Benchmark byte tags");
410 
411  return 0;
412 }
#define min(a, b)
Definition: 80211b.c:41
#define max(a, b)
Definition: 80211b.c:42
static void benchB(uint32_t n)
static void runBench(void(*bench)(uint32_t), uint32_t n, uint32_t minIterations, const char *name)
static uint64_t runBenchOneIteration(void(*bench)(uint32_t), uint32_t n)
static void benchC(uint32_t n)
static void benchD(uint32_t n)
static void benchFragment(uint32_t n)
static void benchByteTags(uint32_t n)
static void benchA(uint32_t n)
static void C1(Ptr< Packet > p)
static void C2(Ptr< Packet > p)
BenchHeader class used for benchmarking packet serialization/deserialization.
TypeId GetInstanceTypeId() const override
Get the most derived TypeId for this Object.
void Serialize(Buffer::Iterator start) const override
uint32_t GetSerializedSize() const override
static std::string GetTypeName()
Get type name function.
bool m_ok
variable to track whether deserialization succeeded
bool IsOk() const
Returns true if the header has been deserialized and the deserialization was correct.
static TypeId GetTypeId()
Register this type.
void Print(std::ostream &os) const override
BenchTag class used for benchmarking packet serialization/deserialization.
void Serialize(TagBuffer buf) const override
void Deserialize(TagBuffer buf) override
static TypeId GetTypeId()
Register this type.
uint32_t GetSerializedSize() const override
void Print(std::ostream &os) const override
TypeId GetInstanceTypeId() const override
Get the most derived TypeId for this Object.
static std::string GetName()
Get the bench tag name.
iterator in a Buffer instance
Definition: buffer.h:100
Parse command-line arguments.
Definition: command-line.h:232
Protocol header serialization and deserialization.
Definition: header.h:44
virtual uint32_t Deserialize(Buffer::Iterator start)=0
Deserialize the object from a buffer iterator.
bool RemovePacketTag(Tag &tag)
Remove a packet tag.
Definition: packet.cc:967
uint32_t RemoveHeader(Header &header)
Deserialize and remove the header from the internal buffer.
Definition: packet.cc:294
void AddAtEnd(Ptr< const Packet > packet)
Concatenate the input packet at the end of the current packet.
Definition: packet.cc:354
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:268
Ptr< Packet > Copy() const
performs a COW copy of the packet.
Definition: packet.cc:131
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:960
Ptr< Packet > CreateFragment(uint32_t start, uint32_t length) const
Create a new packet which contains a fragment of the original packet.
Definition: packet.cc:238
void AddByteTag(const Tag &tag) const
Tag each byte included in this packet with a new byte tag.
Definition: packet.cc:915
Measure elapsed wall clock time in milliseconds.
int64_t End()
Stop measuring the time since Start() was called.
void Start()
Start a measure.
read and write tag data
Definition: tag-buffer.h:52
TAG_BUFFER_INLINE void WriteU8(uint8_t v)
Definition: tag-buffer.h:172
TAG_BUFFER_INLINE uint8_t ReadU8()
Definition: tag-buffer.h:196
tag a set of bytes in a packet
Definition: tag.h:39
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
void Print(ComponentCarrier cc)
Every class exported by the ns3 library is enclosed in the ns3 namespace.
cmd
Definition: second.py:40