diff --git a/arangosh/V8Client/BenchmarkThread.h b/arangosh/V8Client/BenchmarkThread.h index f936b2b95d..c607203638 100644 --- a/arangosh/V8Client/BenchmarkThread.h +++ b/arangosh/V8Client/BenchmarkThread.h @@ -54,21 +54,58 @@ namespace triagens { struct BenchmarkRequest { BenchmarkRequest (const char* url, map params, - const char* payload, - PB_ArangoMessageContentType contentType, + char* (*genFunc)(), + void (*jsonFunc)(PB_ArangoBlobRequest*), SimpleHttpClient::http_method type) : url(url), params(params), - payload(payload), - contentType(contentType), - type(type) { + genFunc(genFunc), + jsonFunc(jsonFunc), + type(type), + ptr(0) { }; + ~BenchmarkRequest () { + if (ptr) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, ptr); + } + } + + void createString () { + if (genFunc == NULL) { + cerr << "invalid call to createString" << endl; + exit(EXIT_FAILURE); + } + ptr = (void*) genFunc(); + } + + void createString (PB_ArangoBlobRequest* blob) { + createString(); + blob->set_content(getString(), getStringLength()); + } + + void createJson (PB_ArangoBlobRequest* blob) { + if (jsonFunc == NULL) { + cerr << "invalid call to createJson" << endl; + exit(EXIT_FAILURE); + } + jsonFunc(blob); + } + + char* getString () { + return (char*) ptr; + } + + size_t getStringLength () { + return strlen((char*) ptr); + } + string url; map params; - string payload; - PB_ArangoMessageContentType contentType; + char* (*genFunc)(); + void (*jsonFunc)(PB_ArangoBlobRequest*); SimpleHttpClient::http_method type; + void* ptr; }; // ----------------------------------------------------------------------------- @@ -88,6 +125,7 @@ namespace triagens { ConditionVariable* condition, const unsigned long batchSize, SharedCounter* operationsCounter, + bool useJson, Endpoint* endpoint, const string& username, const string& password) @@ -96,11 +134,13 @@ namespace triagens { _startCondition(condition), _batchSize(batchSize), _operationsCounter(operationsCounter), + _useJson(useJson), _endpoint(endpoint), _username(username), _password(password), _client(0), - _connection(0) { + _connection(0), + _time(0.0) { } ~BenchmarkThread () { @@ -218,16 +258,23 @@ namespace triagens { blob->set_requesttype(getRequestType(r.type)); blob->set_url(r.url); - blob->set_contenttype(r.contentType); - blob->set_content(r.payload); - + + if (_useJson) { + r.createJson(blob); + blob->set_contenttype(PB_JSON_CONTENT); + } + else { + r.createString(blob); + blob->set_contenttype(PB_NO_CONTENT); + } + for (map::const_iterator it = r.params.begin(); it != r.params.end(); ++it) { kv = blob->add_values(); kv->set_key((*it).first); kv->set_value((*it).second); } } - + size_t messageSize = messages.ByteSize(); char* message = new char[messageSize]; @@ -246,7 +293,9 @@ namespace triagens { //std::cout << "body length: " << messageSize << ", hash: " << TRI_FnvHashPointer(message, (size_t) messageSize) << "\n"; + Timing timer(Timing::TI_WALLCLOCK); SimpleHttpResult* result = _client->request(SimpleHttpClient::POST, "/_api/batch", message, (size_t) messageSize, headerFields); + _time += ((double) timer.time()) / 1000000.0; delete[] message; if (result == 0) { @@ -296,8 +345,14 @@ namespace triagens { url.append((*i).second); } + r.createString(); + map headerFields; - SimpleHttpResult* result = _client->request(r.type, url, r.payload.c_str(), r.payload.size(), headerFields); + Timing timer(Timing::TI_WALLCLOCK); + + SimpleHttpResult* result = _client->request(r.type, url, r.getString(), r.getStringLength(), headerFields); + _time += ((double) timer.time()) / 1000000.0; + if (result == 0) { _operationsCounter->incFailures(); return; @@ -309,6 +364,13 @@ namespace triagens { delete result; } + + public: + + double getTime () const { + return _time; + } + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// @@ -344,6 +406,12 @@ namespace triagens { SharedCounter* _operationsCounter; +//////////////////////////////////////////////////////////////////////////////// +/// @brief use binary json? +//////////////////////////////////////////////////////////////////////////////// + + bool _useJson; + //////////////////////////////////////////////////////////////////////////////// /// @brief endpoint to use //////////////////////////////////////////////////////////////////////////////// @@ -374,6 +442,12 @@ namespace triagens { triagens::httpclient::GeneralClientConnection* _connection; +//////////////////////////////////////////////////////////////////////////////// +/// @brief time +//////////////////////////////////////////////////////////////////////////////// + + double _time; + }; } } diff --git a/arangosh/V8Client/arangob.cpp b/arangosh/V8Client/arangob.cpp index 9d7ce7deb1..c221247675 100644 --- a/arangosh/V8Client/arangob.cpp +++ b/arangosh/V8Client/arangob.cpp @@ -87,6 +87,12 @@ static int Operations = 1000; static int BatchSize = 1; +//////////////////////////////////////////////////////////////////////////////// +/// @brief use binary json? +//////////////////////////////////////////////////////////////////////////////// + +static bool UseJson = false; + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// @@ -111,6 +117,7 @@ static void ParseProgramOptions (int argc, char* argv[]) { ("concurrency", &Concurrency, "number of parallel connections") ("requests", &Operations, "total number of operations") ("batch-size", &BatchSize, "number of operations in one batch") + ("binary-json", &UseJson, "use binary json") ; BaseClient.setupGeneral(description); @@ -136,19 +143,95 @@ static void ParseProgramOptions (int argc, char* argv[]) { /// @{ //////////////////////////////////////////////////////////////////////////////// +char* SEmpty () { + return TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, ""); +} + +void JEmpty (PB_ArangoBlobRequest* blob) { +} + BenchmarkRequest VersionFunc () { map params; - BenchmarkRequest r("/_api/version", params, "", PB_NO_CONTENT, SimpleHttpClient::GET); + BenchmarkRequest r("/_api/version", params, &SEmpty, &JEmpty, SimpleHttpClient::GET); return r; } -BenchmarkRequest InsertFunc () { +char* SFunc1 () { + return TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, "{\"some value\" : 1}"); +} + +void JFunc1 (PB_ArangoBlobRequest* blob) { + PB_ArangoJsonContent* json = blob->mutable_json(); + json->set_type(PB_REQUEST_TYPE_ARRAY); + + json->mutable_value()->add_objects(); // key + json->mutable_value()->add_objects(); // value + + PB_ArangoJsonContent* k = json->mutable_value()->mutable_objects(0); + PB_ArangoJsonContent* v = json->mutable_value()->mutable_objects(1); + + k->set_type(PB_REQUEST_TYPE_STRING); + k->mutable_value()->set_stringvalue("some value"); + v->set_type(PB_REQUEST_TYPE_NUMBER); + v->mutable_value()->set_numbervalue(1.0); +} + +BenchmarkRequest InsertFunc1 () { map params; params["createCollection"] = "true"; params["collection"] = "BenchmarkInsert"; - BenchmarkRequest r("/_api/document", params, "{\"some value\" : 1}", PB_NO_CONTENT, SimpleHttpClient::POST); + BenchmarkRequest r("/_api/document", params, &SFunc1, &JFunc1, SimpleHttpClient::POST); + + return r; +} + +char* SFunc2 () { + StringBuffer s(TRI_UNKNOWN_MEM_ZONE); + + s.appendChar('{'); + for (size_t i = 0; i < 1; ++i) { + s.appendText("\"some value"); + s.appendInteger(i); + s.appendText("\":"); + s.appendDecimal((double) i); + if (i < 0) { + s.appendChar(','); + } + } + + s.appendChar('}'); + + return TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, s.c_str()); +} + +void JFunc2 (PB_ArangoBlobRequest* blob) { + PB_ArangoJsonContent* json = blob->mutable_json(); + json->set_type(PB_REQUEST_TYPE_ARRAY); + + for (size_t i = 0; i < 1; ++i) { + json->mutable_value()->add_objects(); // key + json->mutable_value()->add_objects(); // value + + PB_ArangoJsonContent* k = json->mutable_value()->mutable_objects(i * 2); + PB_ArangoJsonContent* v = json->mutable_value()->mutable_objects((i * 2) + 1); + + k->set_type(PB_REQUEST_TYPE_STRING); + ostringstream ks; + ks << "some value " << i; + k->mutable_value()->set_stringvalue(ks.str()); + v->set_type(PB_REQUEST_TYPE_NUMBER); + v->mutable_value()->set_numbervalue((double) i); + } +} + +BenchmarkRequest InsertFunc2 () { + map params; + params["createCollection"] = "true"; + params["collection"] = "BenchmarkInsert"; + + BenchmarkRequest r("/_api/document", params, &SFunc2, &JFunc2, SimpleHttpClient::POST); return r; } @@ -192,10 +275,11 @@ int main (int argc, char* argv[]) { Endpoint* endpoint = Endpoint::clientFactory(BaseClient.endpointString()); endpoints.push_back(endpoint); - BenchmarkThread* thread = new BenchmarkThread(&InsertFunc, + BenchmarkThread* thread = new BenchmarkThread(&InsertFunc2, &startCondition, (unsigned long) BatchSize, &operationsCounter, + UseJson, endpoint, BaseClient.username(), BaseClient.password()); @@ -225,9 +309,15 @@ int main (int argc, char* argv[]) { } double time = ((double) timer.time()) / 1000000.0; + double requestTime = 0.0; + + for (int i = 0; i < Concurrency; ++i) { + requestTime += threads[i]->getTime(); + } cout << "Total number of operations: " << Operations << ", batch size: " << BatchSize << ", concurrency level: " << Concurrency << endl; cout << "Total duration: " << fixed << time << " s" << endl; + cout << "Total request duration: " << fixed << requestTime << " s" << endl; cout << "Duration per operation: " << fixed << (time / Operations) << " s" << endl; cout << "Duration per operation per thread: " << fixed << (time / (double) Operations * (double) Concurrency) << " s" << endl << endl;