Skip to content

Commit fec38a7

Browse files
committed
benchmarks for direct conversions
1 parent 159a8f3 commit fec38a7

File tree

6 files changed

+339
-131
lines changed

6 files changed

+339
-131
lines changed

bench/Jamfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ exe bench :
3535
/boost/json//boost_json
3636
:
3737
<include>../test
38+
<include>../example
3839
$(has_nlohmann_json)<define>BOOST_JSON_HAS_NLOHMANN_JSON
3940
$(has_rapidjson)<define>BOOST_JSON_HAS_RAPIDJSON
4041
;

bench/bench.cpp

Lines changed: 200 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
#include <vector>
4040

4141
#include "test_suite.hpp"
42+
#include "canada.hpp"
43+
#include "citm_catalog.hpp"
4244

4345
/* References
4446
@@ -48,7 +50,7 @@
4850
*/
4951

5052
std::string s_tests = "ps";
51-
std::string s_impls = "busorn";
53+
std::string s_impls = "busodrn";
5254
std::size_t s_trials = 6;
5355
std::string s_branch = "";
5456
std::string s_alloc = "p";
@@ -747,6 +749,173 @@ class boost_operator_impl : public any_impl
747749
}
748750
};
749751

752+
class boost_direct_impl : public any_impl
753+
{
754+
private:
755+
struct canada_support
756+
{
757+
using type = canada;
758+
static constexpr char const* const name = "canada.json";
759+
};
760+
struct citm_catalog_support
761+
{
762+
using type = citm_catalog;
763+
static constexpr char const* const name = "citm_catalog.json";
764+
};
765+
using supported_files = mp11::mp_list<
766+
canada_support, citm_catalog_support>;
767+
768+
static
769+
int
770+
find_supported_file(file_item const& fi)
771+
{
772+
int result = -1;
773+
using N = mp11::mp_size<supported_files>;
774+
mp11::mp_for_each<mp11::mp_iota<N>>([&](auto index)
775+
{
776+
using supported_file = mp11::mp_at_c<supported_files, index.value>;
777+
std::size_t const name_len = std::strlen(supported_file::name);
778+
779+
std::size_t pos = fi.name.rfind(
780+
supported_file::name, string_view::npos, name_len);
781+
if(pos == string_view::npos)
782+
return;
783+
if( pos + name_len != fi.name.size() )
784+
return;
785+
if( pos != 0 && fi.name[pos - 1] != '/'
786+
&& fi.name[pos - 1] != '\\' )
787+
{
788+
return;
789+
}
790+
791+
result = static_cast<int>(index);
792+
});
793+
return result;
794+
}
795+
796+
public:
797+
boost_direct_impl(bool with_file_io, parse_options const& popts)
798+
: any_impl("boost (direct)", true, false, with_file_io, popts)
799+
{}
800+
801+
clock_type::duration
802+
parse_string(file_item const& fi, std::size_t repeat) const override
803+
{
804+
auto const i = find_supported_file(fi);
805+
if( i < 0 )
806+
return clock_type::duration::zero();
807+
808+
using N = mp11::mp_size<supported_files>;
809+
return mp11::mp_with_index<N>(i, [&](auto index)
810+
{
811+
using supported_file = mp11::mp_at_c<supported_files, index.value>;
812+
813+
auto const start = clock_type::now();
814+
while(repeat--)
815+
{
816+
using data_type = typename supported_file::type;
817+
data_type v;
818+
system::error_code ec;
819+
parser_for<data_type> p(get_parse_options(), &v);
820+
821+
auto const n = p.write_some(
822+
false, fi.text.data(), fi.text.size(), ec );
823+
if( !ec.failed() && n < fi.text.size() )
824+
ec = error::extra_data;
825+
if( ec.failed() )
826+
throw system::system_error( ec );
827+
}
828+
return clock_type::now() - start;
829+
});
830+
}
831+
832+
clock_type::duration
833+
parse_file(file_item const& fi, std::size_t repeat) const override
834+
{
835+
auto const i = find_supported_file(fi);
836+
if( i < 0 )
837+
return clock_type::duration::zero();
838+
839+
using N = mp11::mp_size<supported_files>;
840+
return mp11::mp_with_index<N>(i, [&](auto index)
841+
{
842+
using supported_file = mp11::mp_at_c<supported_files, index.value>;
843+
844+
auto const start = clock_type::now();
845+
char s[ BOOST_JSON_STACK_BUFFER_SIZE];
846+
while(repeat--)
847+
{
848+
using data_type = typename supported_file::type;
849+
data_type v;
850+
system::error_code ec;
851+
parser_for<data_type> p(get_parse_options(), &v);
852+
853+
FILE* f = fopen(fi.name.data(), "rb");
854+
855+
while( true )
856+
{
857+
std::size_t const sz = fread(s, 1, sizeof(s), f);
858+
if( ferror(f) )
859+
break;
860+
861+
p.write_some(true, s, sz, ec);
862+
if( ec.failed() )
863+
throw system::system_error(ec);
864+
865+
if( feof(f) )
866+
break;
867+
}
868+
869+
if( !p.done() )
870+
{
871+
p.write_some(false, nullptr, 0, ec);
872+
if( ec.failed() )
873+
throw system::system_error(ec);
874+
}
875+
876+
fclose(f);
877+
}
878+
return clock_type::now() - start;
879+
});
880+
}
881+
882+
clock_type::duration
883+
serialize_string(file_item const& fi, std::size_t repeat) const override
884+
{
885+
auto const i = find_supported_file(fi);
886+
if( i < 0 )
887+
return clock_type::duration::zero();
888+
889+
using N = mp11::mp_size<supported_files>;
890+
return mp11::mp_with_index<N>(i, [&](auto index)
891+
{
892+
using supported_file = mp11::mp_at_c<supported_files, index.value>;
893+
typename supported_file::type v;
894+
json::parse_into(v, fi.text);
895+
896+
auto const start = clock_type::now();
897+
serializer sr;
898+
string out;
899+
out.reserve(512);
900+
while(repeat--)
901+
{
902+
sr.reset(&v);
903+
out.clear();
904+
for(;;)
905+
{
906+
auto const sv = sr.read(
907+
out.end(), out.capacity() - out.size() );
908+
out.grow( sv.size() );
909+
if( sr.done() )
910+
break;
911+
out.reserve( out.capacity() + 1 );
912+
}
913+
}
914+
return clock_type::now() - start;
915+
});
916+
}
917+
};
918+
750919
//----------------------------------------------------------
751920

752921
#ifdef BOOST_JSON_HAS_RAPIDJSON
@@ -988,6 +1157,10 @@ bool add_impl(impl_list & vi, char kind, char alloc, char io, char num)
9881157
is_pool, with_file_io, popts);
9891158
break;
9901159

1160+
case 'd':
1161+
impl = std::make_unique<boost_direct_impl>(with_file_io, popts);
1162+
break;
1163+
9911164
#ifdef BOOST_JSON_HAS_RAPIDJSON
9921165
case 'r':
9931166
if(is_pool)
@@ -1058,35 +1231,36 @@ main(
10581231
std::cerr <<
10591232
"Usage: bench [options...] <file>...\n"
10601233
"\n"
1061-
"Options: -t:[p][s] Test parsing, serialization or both\n"
1062-
" (default both)\n"
1063-
" -i:[b][u][s][o][r][n] Test the specified implementations\n"
1064-
" (b: Boost.JSON)\n"
1065-
" (u: Boost.JSON, null parser)\n"
1066-
" (s: Boost.JSON, convenient functions)\n"
1067-
" (o: Boost.JSON, stream operators)\n"
1234+
"Options: -t:[p][s] Test parsing, serialization or both\n"
1235+
" (default both)\n"
1236+
" -i:[b][u][s][o][d][r][n] Test the specified implementations\n"
1237+
" (b: Boost.JSON)\n"
1238+
" (u: Boost.JSON, null parser)\n"
1239+
" (s: Boost.JSON, convenient functions)\n"
1240+
" (o: Boost.JSON, stream operators)\n"
1241+
" (d: Boost.JSON, direct conversion)\n"
10681242
#ifdef BOOST_JSON_HAS_RAPIDJSON
1069-
" (r: RapidJSON)\n"
1243+
" (r: RapidJSON)\n"
10701244
#endif // BOOST_JSON_HAS_RAPIDJSON
10711245
#ifdef BOOST_JSON_HAS_NLOHMANN_JSON
1072-
" (n: nlohmann/json)\n"
1246+
" (n: nlohmann/json)\n"
10731247
#endif // BOOST_JSON_HAS_NLOHMANN_JSON
1074-
" (default all)\n"
1075-
" -a:(p|d) Memory allocation strategy\n"
1076-
" (p: memory pool)\n"
1077-
" (d: default strategy)\n"
1078-
" (default memory pool)\n"
1079-
" -n:<number> Number of trials (default 6)\n"
1080-
" -b:<branch> Branch label for boost implementations\n"
1081-
" -m:(i|p|n) Number parsing mode\n"
1082-
" (i: imprecise)\n"
1083-
" (p: precise)\n"
1084-
" (n: none)\n"
1085-
" (default imprecise)\n"
1086-
" -f:(y|n) Include file IO into consideration when testing parsers\n"
1087-
" (y: yes)\n"
1088-
" (n: no)\n"
1089-
" (default no)\n"
1248+
" (default all)\n"
1249+
" -a:[p][d] Memory allocation strategy\n"
1250+
" (p: memory pool)\n"
1251+
" (d: default strategy)\n"
1252+
" (default memory pool)\n"
1253+
" -n:<number> Number of trials (default 6)\n"
1254+
" -b:<branch> Branch label for boost implementations\n"
1255+
" -m:[i][p][n] Number parsing mode\n"
1256+
" (i: imprecise)\n"
1257+
" (p: precise)\n"
1258+
" (n: none)\n"
1259+
" (default imprecise)\n"
1260+
" -f:[y][n] Include file IO into consideration when testing parsers\n"
1261+
" (y: yes)\n"
1262+
" (n: no)\n"
1263+
" (default no)\n"
10901264
;
10911265

10921266
return 4;

example/canada.hpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//
2+
// Copyright (c) 2021 Peter Dimov
3+
//
4+
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5+
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6+
//
7+
// Official repository: https://github.com/boostorg/json
8+
//
9+
10+
#ifndef BOOST_JSON_EXAMPLE_CANADA_HPP
11+
#define BOOST_JSON_EXAMPLE_CANADA_HPP
12+
13+
#include <boost/describe/class.hpp>
14+
15+
#include <map>
16+
#include <string>
17+
#include <vector>
18+
#include <utility>
19+
20+
struct geometry_type
21+
{
22+
std::string type;
23+
std::vector< std::vector<std::pair<double, double>> > coordinates;
24+
};
25+
26+
BOOST_DESCRIBE_STRUCT(geometry_type, (), (type, coordinates))
27+
28+
struct feature
29+
{
30+
std::string type;
31+
std::map<std::string, std::string> properties;
32+
geometry_type geometry;
33+
};
34+
35+
BOOST_DESCRIBE_STRUCT(feature, (), (type, properties, geometry))
36+
37+
struct canada
38+
{
39+
std::string type;
40+
std::vector<feature> features;
41+
};
42+
43+
BOOST_DESCRIBE_STRUCT(canada, (), (type, features))
44+
45+
#endif // BOOST_JSON_EXAMPLE_CANADA_HPP

0 commit comments

Comments
 (0)