speed up status
This commit is contained in:
parent
a81dbe21be
commit
84737b1fbe
|
@ -12,7 +12,7 @@ class JsonBuilderArray;
|
|||
typedef JsonBuilder JsonString;
|
||||
template <typename T> class JsonBuilderObjectSetter;
|
||||
|
||||
// Class for building JSON string values.
|
||||
// Class for building JSON string values.
|
||||
// Default value is null, as in the JSON type
|
||||
class JsonBuilder {
|
||||
protected:
|
||||
|
@ -20,15 +20,21 @@ protected:
|
|||
|
||||
public:
|
||||
// Default value is null, which will be considered "empty"
|
||||
JsonBuilder() : type(NULLVALUE), elements(0) {}
|
||||
JsonBuilder() : type(NULLVALUE), elements(0), bytes(0) {}
|
||||
|
||||
int getFinalLength() const {
|
||||
return jsonText.size() + strlen(getEnd());
|
||||
return bytes + strlen(getEnd());
|
||||
}
|
||||
|
||||
// TODO: Remove the need for this by changing usages to steal this's content
|
||||
std::string getJson() const {
|
||||
return jsonText + getEnd();
|
||||
std::string result;
|
||||
result.reserve(bytes + 1);
|
||||
for(auto& it : jsonText) {
|
||||
result.append(it.begin(), it.end());
|
||||
}
|
||||
result.append(getEnd());
|
||||
return result;
|
||||
}
|
||||
|
||||
int size() const {
|
||||
|
@ -43,11 +49,35 @@ public:
|
|||
|
||||
protected:
|
||||
EType type;
|
||||
std::string jsonText;
|
||||
Arena arena;
|
||||
mutable std::vector<VectorRef<uint8_t>> jsonText;
|
||||
int elements;
|
||||
int bytes;
|
||||
|
||||
template<typename T> inline void write(T &&s) {
|
||||
jsonText.append(std::forward<T>(s));
|
||||
inline void write( const std::string& s) {
|
||||
if(!jsonText.size()) {
|
||||
jsonText.push_back( VectorRef<uint8_t>() );
|
||||
}
|
||||
bytes += s.size();
|
||||
jsonText.back().append(arena, (const uint8_t*)&s[0], s.size());
|
||||
//printf("%p: after write: '%s'\n", this, jsonText.c_str());
|
||||
}
|
||||
|
||||
inline void write(const char* s) {
|
||||
if(!jsonText.size()) {
|
||||
jsonText.push_back( VectorRef<uint8_t>() );
|
||||
}
|
||||
bytes += strlen(s);
|
||||
jsonText.back().append(arena, (const uint8_t*)&s[0], strlen(s));
|
||||
//printf("%p: after write: '%s'\n", this, jsonText.c_str());
|
||||
}
|
||||
|
||||
inline void write(char s) {
|
||||
if(!jsonText.size()) {
|
||||
jsonText.push_back( VectorRef<uint8_t>() );
|
||||
}
|
||||
bytes++;
|
||||
jsonText.back().push_back(arena, s);
|
||||
//printf("%p: after write: '%s'\n", this, jsonText.c_str());
|
||||
}
|
||||
|
||||
|
@ -57,9 +87,66 @@ protected:
|
|||
write(json_spirit::write_string(val));
|
||||
}
|
||||
|
||||
void writeValue(const bool& val) {
|
||||
write(val ? "true" : "false");
|
||||
}
|
||||
|
||||
void writeValue(const int64_t& val) {
|
||||
write(format("%lld",val));
|
||||
}
|
||||
|
||||
void writeValue(const uint64_t& val) {
|
||||
write(format("%llu",val));
|
||||
}
|
||||
|
||||
void writeValue(const int& val) {
|
||||
write(format("%d",val));
|
||||
}
|
||||
|
||||
void writeValue(const double& val) {
|
||||
write(format("%g",val));
|
||||
}
|
||||
|
||||
bool shouldEscape(char c) {
|
||||
switch( c ) {
|
||||
case '"':
|
||||
case '\\':
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void writeValue(const std::string& val) {
|
||||
write('"');
|
||||
int beginCopy = 0;
|
||||
for (int i = 0; i < val.size(); i++) {
|
||||
if (shouldEscape(val[i])) {
|
||||
jsonText.back().append(arena, (const uint8_t*)&(val[beginCopy]), i - beginCopy);
|
||||
beginCopy = i + 1;
|
||||
write('\\');
|
||||
write(val[i]);
|
||||
}
|
||||
}
|
||||
if(beginCopy < val.size()) {
|
||||
jsonText.back().append(arena, (const uint8_t*)&(val[beginCopy]), val.size() - beginCopy);
|
||||
}
|
||||
write('"');
|
||||
}
|
||||
|
||||
// Write the finalized (closed) form of val
|
||||
void writeValue(const JsonBuilder &val) {
|
||||
write(val.jsonText);
|
||||
bytes += val.bytes;
|
||||
for(auto& it : val.jsonText) {
|
||||
jsonText.push_back(it);
|
||||
}
|
||||
val.jsonText.push_back(VectorRef<uint8_t>());
|
||||
arena.dependsOn(val.arena);
|
||||
write(val.getEnd());
|
||||
}
|
||||
|
||||
|
@ -82,12 +169,12 @@ class JsonBuilderArray : public JsonBuilder {
|
|||
public:
|
||||
JsonBuilderArray() {
|
||||
type = ARRAY;
|
||||
write("[");
|
||||
write('[');
|
||||
}
|
||||
|
||||
template<typename VT> inline JsonBuilderArray & push_back(VT &&val) {
|
||||
if(elements++ > 0) {
|
||||
write(",");
|
||||
write(',');
|
||||
}
|
||||
writeValue(std::forward<VT>(val));
|
||||
return *this;
|
||||
|
@ -101,7 +188,18 @@ public:
|
|||
}
|
||||
|
||||
JsonBuilderArray & addContents(const JsonBuilderArray &arr) {
|
||||
jsonText.append(arr.jsonText.substr(1));
|
||||
if(!arr.jsonText.size()) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
bytes += arr.bytes - 1;
|
||||
jsonText.push_back(VectorRef<uint8_t>((uint8_t*)&arr.jsonText[0][1], arr.jsonText[0].size()-1));
|
||||
for(int i = 1; i < arr.jsonText.size(); i++) {
|
||||
jsonText.push_back(arr.jsonText[i]);
|
||||
}
|
||||
arr.jsonText.push_back(VectorRef<uint8_t>());
|
||||
arena.dependsOn(arr.arena);
|
||||
|
||||
elements += arr.elements;
|
||||
return *this;
|
||||
}
|
||||
|
@ -111,16 +209,17 @@ class JsonBuilderObject : public JsonBuilder {
|
|||
public:
|
||||
JsonBuilderObject() {
|
||||
type = OBJECT;
|
||||
write("{");
|
||||
write('{');
|
||||
}
|
||||
|
||||
template<typename KT, typename VT> inline JsonBuilderObject & setKey(KT &&name, VT &&val) {
|
||||
if(elements++ > 0) {
|
||||
write(",");
|
||||
write(',');
|
||||
}
|
||||
write("\"");
|
||||
write(std::forward<KT>(name));
|
||||
write("\":");
|
||||
write('"');
|
||||
write(name);
|
||||
write('"');
|
||||
write(':');
|
||||
writeValue(std::forward<VT>(val));
|
||||
return *this;
|
||||
}
|
||||
|
@ -135,7 +234,18 @@ public:
|
|||
}
|
||||
|
||||
JsonBuilderObject & addContents(const JsonBuilderObject &obj) {
|
||||
jsonText.append(obj.jsonText.substr(1));
|
||||
if(!obj.jsonText.size()) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
bytes += obj.bytes - 1;
|
||||
jsonText.push_back(VectorRef<uint8_t>((uint8_t*)&obj.jsonText[0][1], obj.jsonText[0].size()-1));
|
||||
for(int i = 1; i < obj.jsonText.size(); i++) {
|
||||
jsonText.push_back(obj.jsonText[i]);
|
||||
}
|
||||
obj.jsonText.push_back(VectorRef<uint8_t>());
|
||||
arena.dependsOn(obj.arena);
|
||||
|
||||
elements += obj.elements;
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -2048,20 +2048,6 @@ TEST_CASE("status/json/builder") {
|
|||
return Void();
|
||||
}
|
||||
|
||||
|
||||
json_spirit::mValue randomValue(const std::vector<std::string> &strings) {
|
||||
switch(g_random->randomInt(0, 3)) {
|
||||
case 0:
|
||||
return g_random->randomInt(0, 10000000);
|
||||
case 1:
|
||||
return strings[g_random->randomInt(0, strings.size())];
|
||||
case 2:
|
||||
default:
|
||||
return g_random->random01();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
JsonBuilderObject randomDocument(const std::vector<std::string> &strings, int &limit, int level);
|
||||
JsonBuilderArray randomArray(const std::vector<std::string> &strings, int &limit, int level);
|
||||
|
||||
|
@ -2080,7 +2066,15 @@ JsonBuilderArray randomArray(const std::vector<std::string> &strings, int &limit
|
|||
r.push_back(randomArray(strings, limit, level - 1));
|
||||
}
|
||||
else {
|
||||
r.push_back(randomValue(strings));
|
||||
switch(g_random->randomInt(0, 3)) {
|
||||
case 0:
|
||||
r.push_back(g_random->randomInt(0, 10000000));
|
||||
case 1:
|
||||
r.push_back(strings[g_random->randomInt(0, strings.size())]);
|
||||
case 2:
|
||||
default:
|
||||
r.push_back(g_random->random01());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2104,7 +2098,15 @@ JsonBuilderObject randomDocument(const std::vector<std::string> &strings, int &l
|
|||
r[key] = randomArray(strings, limit, level - 1);
|
||||
}
|
||||
else {
|
||||
r[key] = randomValue(strings);
|
||||
switch(g_random->randomInt(0, 3)) {
|
||||
case 0:
|
||||
r[key] = g_random->randomInt(0, 10000000);
|
||||
case 1:
|
||||
r[key] = strings[g_random->randomInt(0, strings.size())];
|
||||
case 2:
|
||||
default:
|
||||
r[key] = g_random->random01();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2120,20 +2122,27 @@ TEST_CASE("status/json/builderPerf") {
|
|||
|
||||
int elements = 100000;
|
||||
int level = 6;
|
||||
int iterations = 200;
|
||||
|
||||
printf("Generating and serializing random document\n");
|
||||
double start = timer();
|
||||
|
||||
int n = elements;
|
||||
JsonBuilderObject obj = randomDocument(strings, n, level);
|
||||
double generated = timer();
|
||||
int bytes = 0;
|
||||
double generated = 0;
|
||||
for(int i = 0; i < iterations; i++) {
|
||||
int n = elements;
|
||||
double gstart = timer();
|
||||
JsonBuilderObject obj = randomDocument(strings, n, level);
|
||||
generated += (timer() - gstart);
|
||||
|
||||
std::string s = obj.getJson();
|
||||
std::string s = obj.getJson();
|
||||
bytes += s.size();
|
||||
}
|
||||
double end = timer();
|
||||
|
||||
double elapsed = end - start;
|
||||
printf("RESULT: %lu bytes %d elements %d levels %f seconds (%f gen, %f serialize) %f MB/s %f items/s\n",
|
||||
s.size(), elements, level, elapsed, generated - start, end - generated, s.size() / elapsed / 1e6, elements / elapsed);
|
||||
bytes, iterations*elements, level, elapsed, generated, elapsed - generated, bytes / elapsed / 1e6, iterations*elements / elapsed);
|
||||
|
||||
return Void();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue