buffer_bench.cc 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. // $Id$
  15. #include <cassert>
  16. #include <stdint.h>
  17. #include <iostream>
  18. #include <bench/benchmark.h>
  19. #include <exceptions/exceptions.h>
  20. #include <dns/buffer.h>
  21. using namespace std;
  22. using namespace isc;
  23. using namespace isc::dns;
  24. using namespace isc::bench;
  25. namespace {
  26. // A simplified buffer implementation using plain old array for comparison
  27. // (omitting some validations for brevity)
  28. class ArrayOutputBuffer {
  29. public:
  30. ArrayOutputBuffer(size_t n) : limit_(n) {
  31. data_ = new uint8_t[n];
  32. }
  33. ~ArrayOutputBuffer() {
  34. delete[] data_;
  35. }
  36. void clear() { index_ = 0; }
  37. void writeUint8(const uint8_t data) {
  38. if (index_ + 1 > limit_) {
  39. isc_throw(InvalidBufferPosition, "write beyond the end of buffer");
  40. }
  41. data_[index_] = data;
  42. ++index_;
  43. }
  44. void writeUint16(const uint16_t data) {
  45. if (index_ + 2 > limit_) {
  46. isc_throw(InvalidBufferPosition, "write beyond the end of buffer");
  47. }
  48. const uint8_t net_data[2] = { (data & 0xff00U) >> 8, data & 0x00ffU };
  49. memcpy(&data_[index_], net_data, 2);
  50. index_ += 2;
  51. }
  52. void writeUint32(const uint32_t data) {
  53. if (index_ + 4 > limit_) {
  54. isc_throw(InvalidBufferPosition, "write beyond the end of buffer");
  55. }
  56. const uint8_t net_data[4] = { (data & 0xff000000) >> 24,
  57. (data & 0x00ff0000) >> 16,
  58. (data & 0x0000ff00) >> 8,
  59. data & 0x000000ff };
  60. memcpy(&data_[index_], net_data, 4);
  61. index_ += 4;
  62. }
  63. void writeData(const void *data, const size_t len) {
  64. if (len > limit_ || index_ > (limit_ - len)) {
  65. isc_throw(InvalidBufferPosition, "write beyond the end of buffer");
  66. }
  67. memcpy(&data_[index_], data, len);
  68. index_ += len;
  69. }
  70. size_t getLength() const { return (index_); }
  71. const void* getData() const { return (data_); }
  72. private:
  73. const size_t limit_;
  74. size_t index_;
  75. uint8_t* data_;
  76. };
  77. const uint8_t check_data[] = {
  78. 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x10, 192, 0, 2, 1,
  79. 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x10,
  80. 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
  81. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34 };
  82. template <typename T>
  83. class BufferBenchMark {
  84. public:
  85. BufferBenchMark(T& buffer, const bool use_writedata) :
  86. buffer_(buffer), use_writedata_(use_writedata) {}
  87. ~BufferBenchMark() {}
  88. unsigned int run() {
  89. // This test emulates writing 20 RR-like objects into the given buffer.
  90. buffer_.clear();
  91. for (int i = 0; i < 20; ++i) {
  92. buffer_.writeUint16(rrtype_val_);
  93. buffer_.writeUint16(rrclass_val_);
  94. buffer_.writeUint32(rrttl_val_);
  95. const uint8_t* data;
  96. size_t datalen;
  97. if ((i % 2) == 0) {
  98. data = data_a;
  99. datalen = sizeof(data_a);
  100. } else {
  101. data = data_aaaa;
  102. datalen = sizeof(data_aaaa);
  103. }
  104. if (use_writedata_) {
  105. buffer_.writeData(data, datalen);
  106. } else {
  107. for (int j = 0; j < datalen; ++j) {
  108. buffer_.writeUint8(data[j]);
  109. }
  110. }
  111. }
  112. return (1);
  113. }
  114. bool checkData() const {
  115. if (buffer_.getLength() < sizeof(check_data)) {
  116. isc_throw(Exception, "written buffer is too short: " <<
  117. buffer_.getLength());
  118. }
  119. if (memcmp(buffer_.getData(), check_data, sizeof(check_data)) != 0) {
  120. isc_throw(Exception, "data mismatch");
  121. }
  122. return (true);
  123. }
  124. bool isUsingWriteData() const { return (use_writedata_); }
  125. private:
  126. static const uint16_t rrtype_val_ = 1;
  127. static const uint16_t rrclass_val_ = 1;
  128. static const uint32_t rrttl_val_ = 3600;
  129. static const uint8_t data_a[4];
  130. static const uint8_t data_aaaa[16];
  131. T& buffer_;
  132. const bool use_writedata_;
  133. };
  134. template <typename T>
  135. const uint8_t BufferBenchMark<T>::data_a[] = { 192, 0, 2, 1 };
  136. template <typename T>
  137. const uint8_t BufferBenchMark<T>::data_aaaa[] = {
  138. 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
  139. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34 };
  140. }
  141. namespace isc {
  142. namespace bench {
  143. template <>
  144. void
  145. BenchMark<BufferBenchMark<OutputBuffer> >::setUp() {
  146. cout << "Benchmark for write operations using libdns OutputBuffer and "
  147. << (target_.isUsingWriteData() ? "writeData:" :
  148. "explicit loop:") << endl;
  149. }
  150. template <>
  151. void
  152. BenchMark<BufferBenchMark<OutputBuffer> >::tearDown() {
  153. assert(target_.checkData());
  154. }
  155. template <>
  156. void
  157. BenchMark<BufferBenchMark<ArrayOutputBuffer> >::setUp() {
  158. cout << "Benchmark for write operations using plain old array and "
  159. << (target_.isUsingWriteData() ? "writeData:" :
  160. "explicit loop:") << endl;
  161. }
  162. template <>
  163. void
  164. BenchMark<BufferBenchMark<ArrayOutputBuffer> >::tearDown() {
  165. assert(target_.checkData());
  166. }
  167. }
  168. }
  169. namespace {
  170. void
  171. usage() {
  172. cerr << "Usage: buffer_bench [-n iterations]" << endl;
  173. exit (1);
  174. }
  175. }
  176. int
  177. main(int argc, char* argv[]) {
  178. int ch;
  179. int iteration = 100000;
  180. while ((ch = getopt(argc, argv, "n:")) != -1) {
  181. switch (ch) {
  182. case 'n':
  183. iteration = atoi(optarg);
  184. break;
  185. case '?':
  186. default:
  187. usage();
  188. }
  189. }
  190. argc -= optind;
  191. if (argc > 0) {
  192. usage();
  193. }
  194. OutputBuffer dns_buffer(4096);
  195. BufferBenchMark<OutputBuffer> buffer_bench(dns_buffer, true);
  196. BenchMark<BufferBenchMark<OutputBuffer> > bench1(iteration, buffer_bench);
  197. bench1.run();
  198. ArrayOutputBuffer array_buffer(4096);
  199. BufferBenchMark<ArrayOutputBuffer> array_bench(array_buffer, true);
  200. BenchMark<BufferBenchMark<ArrayOutputBuffer> > bench2(iteration,
  201. array_bench);
  202. bench2.run();
  203. BufferBenchMark<OutputBuffer> buffer_bench2(dns_buffer, false);
  204. BenchMark<BufferBenchMark<OutputBuffer> > bench3(iteration, buffer_bench2);
  205. bench3.run();
  206. BufferBenchMark<ArrayOutputBuffer> array_bench2(array_buffer, false);
  207. BenchMark<BufferBenchMark<ArrayOutputBuffer> > bench4(iteration,
  208. array_bench2);
  209. bench4.run();
  210. return (0);
  211. }