summaryrefslogtreecommitdiff
path: root/dbtests/perf
diff options
context:
space:
mode:
authorAntonin Kral <a.kral@bobek.cz>2010-01-31 08:32:52 +0100
committerAntonin Kral <a.kral@bobek.cz>2010-01-31 08:32:52 +0100
commit4eefaf421bfeddf040d96a3dafb12e09673423d7 (patch)
treecb2e5ccc7f98158894f977ff131949da36673591 /dbtests/perf
downloadmongodb-4eefaf421bfeddf040d96a3dafb12e09673423d7.tar.gz
Imported Upstream version 1.3.1
Diffstat (limited to 'dbtests/perf')
-rw-r--r--dbtests/perf/perftest.cpp695
1 files changed, 695 insertions, 0 deletions
diff --git a/dbtests/perf/perftest.cpp b/dbtests/perf/perftest.cpp
new file mode 100644
index 0000000..6fe9d6a
--- /dev/null
+++ b/dbtests/perf/perftest.cpp
@@ -0,0 +1,695 @@
+// perftest.cpp : Run db performance tests.
+//
+
+/**
+ * Copyright (C) 2009 10gen Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "stdafx.h"
+
+#include "../../client/dbclient.h"
+#include "../../db/instance.h"
+#include "../../db/query.h"
+#include "../../db/queryoptimizer.h"
+#include "../../util/file_allocator.h"
+
+#include "../framework.h"
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+namespace mongo {
+ extern string dbpath;
+} // namespace mongo
+
+
+using namespace mongo;
+using namespace mongo::regression;
+
+DBClientBase *client_;
+
+// Each test runs with a separate db, so no test does any of the startup
+// (ie allocation) work for another test.
+template< class T >
+string testDb( T *t = 0 ) {
+ string name = mongo::regression::demangleName( typeid( T ) );
+ // Make filesystem safe.
+ for( string::iterator i = name.begin(); i != name.end(); ++i )
+ if ( *i == ':' )
+ *i = '_';
+ return name;
+}
+
+template< class T >
+string testNs( T *t ) {
+ stringstream ss;
+ ss << testDb( t ) << ".perftest";
+ return ss.str();
+}
+
+template <class T>
+class Runner {
+public:
+ void run() {
+ T test;
+ string name = testDb( &test );
+ boost::posix_time::ptime start = boost::posix_time::microsec_clock::universal_time();
+ test.run();
+ boost::posix_time::ptime end = boost::posix_time::microsec_clock::universal_time();
+ long long micro = ( end - start ).total_microseconds();
+ cout << "{'" << name << "': "
+ << micro / 1000000
+ << "."
+ << setw( 6 ) << setfill( '0' ) << micro % 1000000
+ << "}" << endl;
+ }
+ ~Runner() {
+ theFileAllocator().waitUntilFinished();
+ client_->dropDatabase( testDb< T >().c_str() );
+ }
+};
+
+class RunnerSuite : public Suite {
+public:
+ RunnerSuite( string name ) : Suite( name ){}
+protected:
+ template< class T >
+ void add() {
+ Suite::add< Runner< T > >();
+ }
+};
+
+namespace Insert {
+ class IdIndex {
+ public:
+ void run() {
+ string ns = testNs( this );
+ for( int i = 0; i < 100000; ++i ) {
+ client_->insert( ns.c_str(), BSON( "_id" << i ) );
+ }
+ }
+ };
+
+ class TwoIndex {
+ public:
+ TwoIndex() : ns_( testNs( this ) ) {
+ client_->ensureIndex( ns_, BSON( "_id" << 1 ), "my_id" );
+ }
+ void run() {
+ for( int i = 0; i < 100000; ++i )
+ client_->insert( ns_.c_str(), BSON( "_id" << i ) );
+ }
+ string ns_;
+ };
+
+ class TenIndex {
+ public:
+ TenIndex() : ns_( testNs( this ) ) {
+ const char *names = "aaaaaaaaa";
+ for( int i = 0; i < 9; ++i ) {
+ client_->resetIndexCache();
+ client_->ensureIndex( ns_.c_str(), BSON( "_id" << 1 ), false, names + i );
+ }
+ }
+ void run() {
+ for( int i = 0; i < 100000; ++i )
+ client_->insert( ns_.c_str(), BSON( "_id" << i ) );
+ }
+ string ns_;
+ };
+
+ class Capped {
+ public:
+ Capped() : ns_( testNs( this ) ) {
+ client_->createCollection( ns_.c_str(), 100000, true );
+ }
+ void run() {
+ for( int i = 0; i < 100000; ++i )
+ client_->insert( ns_.c_str(), BSON( "_id" << i ) );
+ }
+ string ns_;
+ };
+
+ class OneIndexReverse {
+ public:
+ OneIndexReverse() : ns_( testNs( this ) ) {
+ client_->ensureIndex( ns_, BSON( "_id" << 1 ) );
+ }
+ void run() {
+ for( int i = 0; i < 100000; ++i )
+ client_->insert( ns_.c_str(), BSON( "_id" << ( 100000 - 1 - i ) ) );
+ }
+ string ns_;
+ };
+
+ class OneIndexHighLow {
+ public:
+ OneIndexHighLow() : ns_( testNs( this ) ) {
+ client_->ensureIndex( ns_, BSON( "_id" << 1 ) );
+ }
+ void run() {
+ for( int i = 0; i < 100000; ++i ) {
+ int j = 50000 + ( ( i % 2 == 0 ) ? 1 : -1 ) * ( i / 2 + 1 );
+ client_->insert( ns_.c_str(), BSON( "_id" << j ) );
+ }
+ }
+ string ns_;
+ };
+
+ class All : public RunnerSuite {
+ public:
+ All() : RunnerSuite( "insert" ){}
+
+ void setupTests(){
+ add< IdIndex >();
+ add< TwoIndex >();
+ add< TenIndex >();
+ add< Capped >();
+ add< OneIndexReverse >();
+ add< OneIndexHighLow >();
+ }
+ } all;
+} // namespace Insert
+
+namespace Update {
+ class Smaller {
+ public:
+ Smaller() : ns_( testNs( this ) ) {
+ for( int i = 0; i < 100000; ++i )
+ client_->insert( ns_.c_str(), BSON( "_id" << i << "b" << 2 ) );
+ }
+ void run() {
+ for( int i = 0; i < 100000; ++i )
+ client_->update( ns_.c_str(), QUERY( "_id" << i ), BSON( "_id" << i ) );
+ }
+ string ns_;
+ };
+
+ class Bigger {
+ public:
+ Bigger() : ns_( testNs( this ) ) {
+ for( int i = 0; i < 100000; ++i )
+ client_->insert( ns_.c_str(), BSON( "_id" << i ) );
+ }
+ void run() {
+ for( int i = 0; i < 100000; ++i )
+ client_->update( ns_.c_str(), QUERY( "_id" << i ), BSON( "_id" << i << "b" << 2 ) );
+ }
+ string ns_;
+ };
+
+ class Inc {
+ public:
+ Inc() : ns_( testNs( this ) ) {
+ for( int i = 0; i < 10000; ++i )
+ client_->insert( ns_.c_str(), BSON( "_id" << i << "i" << 0 ) );
+ }
+ void run() {
+ for( int j = 0; j < 10; ++j )
+ for( int i = 0; i < 10000; ++i )
+ client_->update( ns_.c_str(), QUERY( "_id" << i ), BSON( "$inc" << BSON( "i" << 1 ) ) );
+ }
+ string ns_;
+ };
+
+ class Set {
+ public:
+ Set() : ns_( testNs( this ) ) {
+ for( int i = 0; i < 10000; ++i )
+ client_->insert( ns_.c_str(), BSON( "_id" << i << "i" << 0 ) );
+ }
+ void run() {
+ for( int j = 1; j < 11; ++j )
+ for( int i = 0; i < 10000; ++i )
+ client_->update( ns_.c_str(), QUERY( "_id" << i ), BSON( "$set" << BSON( "i" << j ) ) );
+ }
+ string ns_;
+ };
+
+ class SetGrow {
+ public:
+ SetGrow() : ns_( testNs( this ) ) {
+ for( int i = 0; i < 10000; ++i )
+ client_->insert( ns_.c_str(), BSON( "_id" << i << "i" << "" ) );
+ }
+ void run() {
+ for( int j = 9; j > -1; --j )
+ for( int i = 0; i < 10000; ++i )
+ client_->update( ns_.c_str(), QUERY( "_id" << i ), BSON( "$set" << BSON( "i" << "aaaaaaaaaa"[j] ) ) );
+ }
+ string ns_;
+ };
+
+ class All : public RunnerSuite {
+ public:
+ All() : RunnerSuite( "update" ){}
+ void setupTests(){
+ add< Smaller >();
+ add< Bigger >();
+ add< Inc >();
+ add< Set >();
+ add< SetGrow >();
+ }
+ } all;
+} // namespace Update
+
+namespace BSON {
+
+ const char *sample =
+ "{\"one\":2, \"two\":5, \"three\": {},"
+ "\"four\": { \"five\": { \"six\" : 11 } },"
+ "\"seven\": [ \"a\", \"bb\", \"ccc\", 5 ],"
+ "\"eight\": Dbref( \"rrr\", \"01234567890123456789aaaa\" ),"
+ "\"_id\": ObjectId( \"deadbeefdeadbeefdeadbeef\" ),"
+ "\"nine\": { \"$binary\": \"abc=\", \"$type\": \"02\" },"
+ "\"ten\": Date( 44 ), \"eleven\": /foooooo/i }";
+
+ const char *shopwikiSample =
+ "{ '_id' : '289780-80f85380b5c1d4a0ad75d1217673a4a2' , 'site_id' : 289780 , 'title'"
+ ": 'Jubilee - Margaret Walker' , 'image_url' : 'http://www.heartlanddigsandfinds.c"
+ "om/store/graphics/Product_Graphics/Product_8679.jpg' , 'url' : 'http://www.heartla"
+ "nddigsandfinds.com/store/store_product_detail.cfm?Product_ID=8679&Category_ID=2&Su"
+ "b_Category_ID=910' , 'url_hash' : 3450626119933116345 , 'last_update' : null , '"
+ "features' : { '$imagePrefetchDate' : '2008Aug30 22:39' , '$image.color.rgb' : '5a7"
+ "574' , 'Price' : '$10.99' , 'Description' : 'Author--s 1st Novel. A Houghton Miffl"
+ "in Literary Fellowship Award novel by the esteemed poet and novelist who has demon"
+ "strated a lifelong commitment to the heritage of black culture. An acclaimed story"
+ "of Vyry, a negro slave during the 19th Century, facing the biggest challenge of h"
+ "er lifetime - that of gaining her freedom, fighting for all the things she had nev"
+ "er known before. The author, great-granddaughter of Vyry, reveals what the Civil W"
+ "ar in America meant to the Negroes. Slavery W' , '$priceHistory-1' : '2008Dec03 $1"
+ "0.99' , 'Brand' : 'Walker' , '$brands_in_title' : 'Walker' , '--path' : '//HTML[1]"
+ "/BODY[1]/TABLE[1]/TR[1]/TD[1]/P[1]/TABLE[1]/TR[1]/TD[1]/TABLE[1]/TR[2]/TD[2]/TABLE"
+ "[1]/TR[1]/TD[1]/P[1]/TABLE[1]/TR[1]' , '~location' : 'en_US' , '$crawled' : '2009J"
+ "an11 03:22' , '$priceHistory-2' : '2008Nov15 $10.99' , '$priceHistory-0' : '2008De"
+ "c24 $10.99'}}";
+
+ class Parse {
+ public:
+ void run() {
+ for( int i = 0; i < 10000; ++i )
+ fromjson( sample );
+ }
+ };
+
+ class ShopwikiParse {
+ public:
+ void run() {
+ for( int i = 0; i < 10000; ++i )
+ fromjson( shopwikiSample );
+ }
+ };
+
+ class Json {
+ public:
+ Json() : o_( fromjson( sample ) ) {}
+ void run() {
+ for( int i = 0; i < 10000; ++i )
+ o_.jsonString();
+ }
+ BSONObj o_;
+ };
+
+ class ShopwikiJson {
+ public:
+ ShopwikiJson() : o_( fromjson( shopwikiSample ) ) {}
+ void run() {
+ for( int i = 0; i < 10000; ++i )
+ o_.jsonString();
+ }
+ BSONObj o_;
+ };
+
+ class All : public RunnerSuite {
+ public:
+ All() : RunnerSuite( "bson" ){}
+ void setupTests(){
+ add< Parse >();
+ add< ShopwikiParse >();
+ add< Json >();
+ add< ShopwikiJson >();
+ }
+ } all;
+
+} // namespace BSON
+
+namespace Index {
+
+ class Int {
+ public:
+ Int() : ns_( testNs( this ) ) {
+ for( int i = 0; i < 100000; ++i )
+ client_->insert( ns_.c_str(), BSON( "a" << i ) );
+ }
+ void run() {
+ client_->ensureIndex( ns_, BSON( "a" << 1 ) );
+ }
+ string ns_;
+ };
+
+ class ObjectId {
+ public:
+ ObjectId() : ns_( testNs( this ) ) {
+ OID id;
+ for( int i = 0; i < 100000; ++i ) {
+ id.init();
+ client_->insert( ns_.c_str(), BSON( "a" << id ) );
+ }
+ }
+ void run() {
+ client_->ensureIndex( ns_, BSON( "a" << 1 ) );
+ }
+ string ns_;
+ };
+
+ class String {
+ public:
+ String() : ns_( testNs( this ) ) {
+ for( int i = 0; i < 100000; ++i ) {
+ stringstream ss;
+ ss << i;
+ client_->insert( ns_.c_str(), BSON( "a" << ss.str() ) );
+ }
+ }
+ void run() {
+ client_->ensureIndex( ns_, BSON( "a" << 1 ) );
+ }
+ string ns_;
+ };
+
+ class Object {
+ public:
+ Object() : ns_( testNs( this ) ) {
+ for( int i = 0; i < 100000; ++i ) {
+ client_->insert( ns_.c_str(), BSON( "a" << BSON( "a" << i ) ) );
+ }
+ }
+ void run() {
+ client_->ensureIndex( ns_, BSON( "a" << 1 ) );
+ }
+ string ns_;
+ };
+
+ class All : public RunnerSuite {
+ public:
+ All() : RunnerSuite( "index" ){}
+ void setupTests(){
+ add< Int >();
+ add< ObjectId >();
+ add< String >();
+ add< Object >();
+ }
+ } all;
+
+} // namespace Index
+
+namespace QueryTests {
+
+ class NoMatch {
+ public:
+ NoMatch() : ns_( testNs( this ) ) {
+ for( int i = 0; i < 100000; ++i )
+ client_->insert( ns_.c_str(), BSON( "_id" << i ) );
+ }
+ void run() {
+ client_->findOne( ns_.c_str(), QUERY( "_id" << 100000 ) );
+ }
+ string ns_;
+ };
+
+ class NoMatchIndex {
+ public:
+ NoMatchIndex() : ns_( testNs( this ) ) {
+ for( int i = 0; i < 100000; ++i )
+ client_->insert( ns_.c_str(), BSON( "_id" << i ) );
+ }
+ void run() {
+ client_->findOne( ns_.c_str(),
+ QUERY( "a" << "b" ).hint( BSON( "_id" << 1 ) ) );
+ }
+ string ns_;
+ };
+
+ class NoMatchLong {
+ public:
+ NoMatchLong() : ns_( testNs( this ) ) {
+ const char *names = "aaaaaaaaaa";
+ for( int i = 0; i < 100000; ++i ) {
+ BSONObjBuilder b;
+ for( int j = 0; j < 10; ++j )
+ b << ( names + j ) << i;
+ client_->insert( ns_.c_str(), b.obj() );
+ }
+ }
+ void run() {
+ client_->findOne( ns_.c_str(), QUERY( "a" << 100000 ) );
+ }
+ string ns_;
+ };
+
+ class SortOrdered {
+ public:
+ SortOrdered() : ns_( testNs( this ) ) {
+ for( int i = 0; i < 50000; ++i )
+ client_->insert( ns_.c_str(), BSON( "_id" << i ) );
+ }
+ void run() {
+ auto_ptr< DBClientCursor > c =
+ client_->query( ns_.c_str(), Query( BSONObj() ).sort( BSON( "_id" << 1 ) ) );
+ int i = 0;
+ for( ; c->more(); c->nextSafe(), ++i );
+ ASSERT_EQUALS( 50000, i );
+ }
+ string ns_;
+ };
+
+ class SortReverse {
+ public:
+ SortReverse() : ns_( testNs( this ) ) {
+ for( int i = 0; i < 50000; ++i )
+ client_->insert( ns_.c_str(), BSON( "_id" << ( 50000 - 1 - i ) ) );
+ }
+ void run() {
+ auto_ptr< DBClientCursor > c =
+ client_->query( ns_.c_str(), Query( BSONObj() ).sort( BSON( "_id" << 1 ) ) );
+ int i = 0;
+ for( ; c->more(); c->nextSafe(), ++i );
+ ASSERT_EQUALS( 50000, i );
+ }
+ string ns_;
+ };
+
+ class GetMore {
+ public:
+ GetMore() : ns_( testNs( this ) ) {
+ for( int i = 0; i < 100000; ++i )
+ client_->insert( ns_.c_str(), BSON( "a" << i ) );
+ c_ = client_->query( ns_.c_str(), Query() );
+ }
+ void run() {
+ int i = 0;
+ for( ; c_->more(); c_->nextSafe(), ++i );
+ ASSERT_EQUALS( 100000, i );
+ }
+ string ns_;
+ auto_ptr< DBClientCursor > c_;
+ };
+
+ class GetMoreIndex {
+ public:
+ GetMoreIndex() : ns_( testNs( this ) ) {
+ for( int i = 0; i < 100000; ++i )
+ client_->insert( ns_.c_str(), BSON( "a" << i ) );
+ client_->ensureIndex( ns_, BSON( "a" << 1 ) );
+ c_ = client_->query( ns_.c_str(), QUERY( "a" << GT << -1 ).hint( BSON( "a" << 1 ) ) );
+ }
+ void run() {
+ int i = 0;
+ for( ; c_->more(); c_->nextSafe(), ++i );
+ ASSERT_EQUALS( 100000, i );
+ }
+ string ns_;
+ auto_ptr< DBClientCursor > c_;
+ };
+
+ class GetMoreKeyMatchHelps {
+ public:
+ GetMoreKeyMatchHelps() : ns_( testNs( this ) ) {
+ for( int i = 0; i < 1000000; ++i )
+ client_->insert( ns_.c_str(), BSON( "a" << i << "b" << i % 10 << "c" << "d" ) );
+ client_->ensureIndex( ns_, BSON( "a" << 1 << "b" << 1 ) );
+ c_ = client_->query( ns_.c_str(), QUERY( "a" << GT << -1 << "b" << 0 ).hint( BSON( "a" << 1 << "b" << 1 ) ) );
+ }
+ void run() {
+ int i = 0;
+ for( ; c_->more(); c_->nextSafe(), ++i );
+ ASSERT_EQUALS( 100000, i );
+ }
+ string ns_;
+ auto_ptr< DBClientCursor > c_;
+ };
+
+ class All : public RunnerSuite {
+ public:
+ All() : RunnerSuite( "query" ){}
+ void setupTests(){
+ add< NoMatch >();
+ add< NoMatchIndex >();
+ add< NoMatchLong >();
+ add< SortOrdered >();
+ add< SortReverse >();
+ add< GetMore >();
+ add< GetMoreIndex >();
+ add< GetMoreKeyMatchHelps >();
+ }
+ } all;
+
+} // namespace QueryTests
+
+namespace Count {
+
+ class Count {
+ public:
+ Count() : ns_( testNs( this ) ) {
+ BSONObj obj = BSON( "a" << 1 );
+ for( int i = 0; i < 100000; ++i )
+ client_->insert( ns_, obj );
+ }
+ void run() {
+ ASSERT_EQUALS( 100000U, client_->count( ns_, BSON( "a" << 1 ) ) );
+ }
+ string ns_;
+ };
+
+ class CountIndex {
+ public:
+ CountIndex() : ns_( testNs( this ) ) {
+ BSONObj obj = BSON( "a" << 1 );
+ for( int i = 0; i < 100000; ++i )
+ client_->insert( ns_, obj );
+ client_->ensureIndex( ns_, obj );
+ }
+ void run() {
+ // 'simple' match does not work for numbers
+ ASSERT_EQUALS( 100000U, client_->count( ns_, BSON( "a" << 1 ) ) );
+ }
+ string ns_;
+ };
+
+ class CountSimpleIndex {
+ public:
+ CountSimpleIndex() : ns_( testNs( this ) ) {
+ BSONObj obj = BSON( "a" << "b" );
+ for( int i = 0; i < 100000; ++i )
+ client_->insert( ns_, obj );
+ client_->ensureIndex( ns_, obj );
+ }
+ void run() {
+ ASSERT_EQUALS( 100000U, client_->count( ns_, BSON( "a" << "b" ) ) );
+ }
+ string ns_;
+ };
+
+ class All : public RunnerSuite {
+ public:
+ All() : RunnerSuite( "count" ){}
+ void setupTests(){
+ add< Count >();
+ add< CountIndex >();
+ add< CountSimpleIndex >();
+ }
+ } all;
+
+} // namespace Count
+
+namespace Plan {
+
+ class Hint {
+ public:
+ Hint() : ns_( testNs( this ) ) {
+ const char *names = "aaaaaaaaa";
+ for( int i = 0; i < 9; ++i ) {
+ client_->resetIndexCache();
+ client_->ensureIndex( ns_.c_str(), BSON( ( names + i ) << 1 ), false, names + i );
+ }
+ lk_.reset( new dblock );
+ setClient( ns_.c_str() );
+ hint_ = BSON( "hint" << BSON( "a" << 1 ) );
+ hintElt_ = hint_.firstElement();
+ }
+ void run() {
+ for( int i = 0; i < 10000; ++i )
+ QueryPlanSet s( ns_.c_str(), BSONObj(), BSONObj(), &hintElt_ );
+ }
+ string ns_;
+ auto_ptr< dblock > lk_;
+ BSONObj hint_;
+ BSONElement hintElt_;
+ };
+
+ class Sort {
+ public:
+ Sort() : ns_( testNs( this ) ) {
+ const char *names = "aaaaaaaaaa";
+ for( int i = 0; i < 10; ++i ) {
+ client_->resetIndexCache();
+ client_->ensureIndex( ns_.c_str(), BSON( ( names + i ) << 1 ), false, names + i );
+ }
+ lk_.reset( new dblock );
+ setClient( ns_.c_str() );
+ }
+ void run() {
+ for( int i = 0; i < 10000; ++i )
+ QueryPlanSet s( ns_.c_str(), BSONObj(), BSON( "a" << 1 ) );
+ }
+ string ns_;
+ auto_ptr< dblock > lk_;
+ };
+
+ class Query {
+ public:
+ Query() : ns_( testNs( this ) ) {
+ const char *names = "aaaaaaaaaa";
+ for( int i = 0; i < 10; ++i ) {
+ client_->resetIndexCache();
+ client_->ensureIndex( ns_.c_str(), BSON( ( names + i ) << 1 ), false, names + i );
+ }
+ lk_.reset( new dblock );
+ setClient( ns_.c_str() );
+ }
+ void run() {
+ for( int i = 0; i < 10000; ++i )
+ QueryPlanSet s( ns_.c_str(), BSON( "a" << 1 ), BSONObj() );
+ }
+ string ns_;
+ auto_ptr< dblock > lk_;
+ };
+
+ class All : public RunnerSuite {
+ public:
+ All() : RunnerSuite("plan" ){}
+ void setupTests(){
+ add< Hint >();
+ add< Sort >();
+ add< Query >();
+ }
+ } all;
+
+} // namespace Plan
+
+int main( int argc, char **argv ) {
+ logLevel = -1;
+ client_ = new DBDirectClient();
+
+ return Suite::run(argc, argv, "/data/db/perftest");
+}