Skip to content

Commit 374bb3b

Browse files
authored
Merge pull request #44 from jpetso/master
Add an encoding/decoding benchmark to test/ and CI bots
2 parents ee58156 + 83578fa commit 374bb3b

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,4 @@ script:
142142
- cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ${CXX_STD_ARG} "$SRC_DIR"
143143
- make -j2 # cores according to https://docs.travis-ci.com/user/reference/overview/
144144
- CTEST_OUTPUT_ON_FAILURE=1 make test
145+
- test/benchmark_cppcodec

appveyor.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,4 @@ test_script:
5858
- cd %BUILD_DIR%
5959
- set CTEST_OUTPUT_ON_FAILURE=1
6060
- ctest -C %CONFIGURATION% -VV
61+
- test\%CONFIGURATION%\benchmark_cppcodec.exe

test/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@ endif()
1616

1717
add_executable(test_cppcodec test_cppcodec.cpp)
1818
add_test(cppcodec test_cppcodec)
19+
20+
add_executable(benchmark_cppcodec benchmark_cppcodec.cpp)

test/benchmark_cppcodec.cpp

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/**
2+
* Copyright (C) 2018 Jakob Petsovits
3+
* All rights reserved.
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to
7+
* deal in the Software without restriction, including without limitation the
8+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9+
* sell copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21+
* IN THE SOFTWARE.
22+
*/
23+
24+
#include <cppcodec/hex_lower.hpp>
25+
#include <cppcodec/base32_rfc4648.hpp>
26+
#include <cppcodec/base64_rfc4648.hpp>
27+
28+
#include <chrono>
29+
#include <iostream>
30+
#include <iomanip>
31+
#include <random>
32+
#include <stdint.h>
33+
#include <string>
34+
#include <vector>
35+
36+
const size_t max_iterations = 1000000; // 1m iterations ought to be enough for anybody
37+
const size_t iteration_max_ms = 500; // half a second
38+
39+
uint8_t random_uint8()
40+
{
41+
static std::random_device rd;
42+
static std::mt19937 pseudo_random(rd());
43+
static std::uniform_int_distribution<int> dist(0, 255);
44+
return static_cast<uint8_t>(dist(pseudo_random));
45+
}
46+
47+
template <typename Codec>
48+
void benchmark(std::ostream& stream, const std::vector<size_t>& decoded_sizes)
49+
{
50+
using clock = std::chrono::high_resolution_clock;
51+
52+
// Measure decoding into both uint8_t and string.
53+
std::vector<double> time_encoding_str(decoded_sizes.size());
54+
std::vector<double> time_decoding_vec_u8(decoded_sizes.size());
55+
std::vector<double> time_decoding_str(decoded_sizes.size());
56+
std::vector<std::vector<uint8_t>> decoded_vec_u8(decoded_sizes.size());
57+
std::vector<std::string> decoded_str(decoded_sizes.size());
58+
std::vector<std::string> encoded_str(decoded_sizes.size());
59+
60+
for (size_t i = 0; i < decoded_sizes.size(); ++i) {
61+
decoded_vec_u8[i].resize(decoded_sizes[i]);
62+
for (size_t j = 0; j < decoded_sizes[i]; ++j) {
63+
decoded_vec_u8[i][j] = random_uint8();
64+
}
65+
}
66+
67+
auto flags = stream.flags();
68+
auto precision = stream.precision();
69+
stream << std::fixed << std::setprecision(4)
70+
<< "Encoding:\n";
71+
72+
for (size_t i = 0; i < decoded_sizes.size(); ++i) {
73+
encoded_str[i] = std::string();
74+
clock::time_point start = clock::now();
75+
clock::time_point end = start + std::chrono::milliseconds(iteration_max_ms);
76+
size_t j = 0;
77+
for (; j < max_iterations; ++j) {
78+
if (clock::now() > end) {
79+
break;
80+
}
81+
encoded_str[i] = Codec::encode(decoded_vec_u8[i]);
82+
}
83+
time_encoding_str[i] = std::chrono::duration_cast<std::chrono::microseconds>(
84+
clock::now() - start).count() / static_cast<double>(j);
85+
86+
stream << (i == 0 ? "" : "\t") << decoded_sizes[i] << ": "
87+
<< time_encoding_str[i] << std::flush;
88+
}
89+
90+
stream << "\n" << "Decoding to string:\n";
91+
92+
for (size_t i = 0; i < decoded_sizes.size(); ++i) {
93+
decoded_str[i] = std::string();
94+
clock::time_point start = clock::now();
95+
clock::time_point end = start + std::chrono::milliseconds(iteration_max_ms);
96+
size_t j = 0;
97+
for (; j < max_iterations; ++j) {
98+
if (clock::now() > end) {
99+
break;
100+
}
101+
#ifdef _MSC_VER
102+
decoded_str[i] = Codec::decode<std::string>(encoded_str[i]);
103+
#else
104+
decoded_str[i] =
105+
Codec::template decode<std::string>(encoded_str[i]);
106+
#endif
107+
}
108+
time_decoding_str[i] = std::chrono::duration_cast<std::chrono::microseconds>(
109+
clock::now() - start).count() / static_cast<double>(j);
110+
111+
stream << (i == 0 ? "" : "\t") << decoded_sizes[i] << ": "
112+
<< time_decoding_str[i] << std::flush;
113+
}
114+
115+
stream << "\n" << "Decoding to vector<uint8_t>:\n";
116+
117+
for (size_t i = 0; i < decoded_sizes.size(); ++i) {
118+
decoded_vec_u8[i] = std::vector<uint8_t>();
119+
clock::time_point start = clock::now();
120+
clock::time_point end = start + std::chrono::milliseconds(iteration_max_ms);
121+
size_t j = 0;
122+
for (; j < max_iterations; ++j) {
123+
if (clock::now() > end) {
124+
break;
125+
}
126+
decoded_vec_u8[i] = Codec::decode(encoded_str[i]);
127+
}
128+
time_decoding_vec_u8[i] = std::chrono::duration_cast<std::chrono::microseconds>(
129+
clock::now() - start).count() / static_cast<double>(j);
130+
131+
stream << (i == 0 ? "" : "\t") << decoded_sizes[i] << ": "
132+
<< time_decoding_vec_u8[i] << std::flush;
133+
}
134+
135+
stream << std::setprecision(precision) << "\n";
136+
stream.flags(flags);
137+
}
138+
139+
int main(int argc, char *argv[])
140+
{
141+
std::vector<size_t> decoded_sizes = {
142+
1, 4, 8, 16, 32, 64, 128, 256, 2048, 4096, 32768
143+
};
144+
145+
std::cout << "base64_rfc4648: [decoded size: microseconds]\n";
146+
benchmark<cppcodec::base64_rfc4648>(std::cout, decoded_sizes);
147+
return 0;
148+
}

0 commit comments

Comments
 (0)