summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron <aaron@10gen.com>2009-02-09 15:57:30 -0500
committerAaron <aaron@10gen.com>2009-02-09 15:57:30 -0500
commit166716bb25aefc6887939a0c35b9df36b8bc01f4 (patch)
treede59058e5339cd76c3bfd506185b37e2fc5ffab3
parent8356bec0709c3bad561c18344f3e866dc216f3cc (diff)
downloadmongo-166716bb25aefc6887939a0c35b9df36b8bc01f4.tar.gz
dbtop
-rw-r--r--db/db.h6
-rw-r--r--db/dbwebserver.cpp9
-rw-r--r--db/instance.cpp1
-rw-r--r--db/instance.h2
-rw-r--r--stdafx.h1
-rw-r--r--util/top.h103
-rw-r--r--util/util.cpp13
7 files changed, 131 insertions, 4 deletions
diff --git a/db/db.h b/db/db.h
index 48e430001ca..e98cc395374 100644
--- a/db/db.h
+++ b/db/db.h
@@ -18,6 +18,7 @@
#include "../stdafx.h"
#include "../util/message.h"
+#include "../util/top.h"
namespace mongo {
@@ -76,6 +77,7 @@ namespace mongo {
~dblock() {
/* todo: this should be inlined */
dbunlocking();
+ Top::clientStop();
}
};
@@ -129,7 +131,8 @@ namespace mongo {
variables.
*/
assert( dbMutexInfo.isLocked() );
-
+ Top::clientStart( ns );
+
curNs = ns;
string key = getKey( ns, path );
map<string,Database*>::iterator it = databases.find(key);
@@ -191,6 +194,7 @@ namespace mongo {
#else
boost::detail::thread::lock_ops<boost::mutex>::unlock(dbMutex);
#endif
+ Top::clientStop();
}
~dbtemprelease() {
#if BOOST_VERSION >= 103500
diff --git a/db/dbwebserver.cpp b/db/dbwebserver.cpp
index 29a97b65058..690a4805483 100644
--- a/db/dbwebserver.cpp
+++ b/db/dbwebserver.cpp
@@ -67,6 +67,7 @@ namespace mongo {
{
Timer lktm;
dblock lk;
+ Top::completeSnapshot();
q = (q+1)%NStats;
Timing timing;
dbMutexInfo.timingInfo(timing.start, timing.timeLocked);
@@ -127,6 +128,14 @@ namespace mongo {
if ( !seemCaughtUp ) ss << "</b>";
ss << '\n';
+ ss << "\n<b>DBTOP</b>\n";
+ ss << "<table border=1><tr align='left'><th>Namespace</th><th>%</th><th>Time</th>";
+ vector< Top::Usage > usage;
+ Top::usage( usage );
+ for( vector< Top::Usage >::iterator i = usage.begin(); i != usage.end(); ++i )
+ ss << setprecision( 2 ) << fixed << "<tr><td>" << i->ns << "</td><td>" << i->pct << "</td><td>" << i->time << "</td></tr>\n";
+ ss << "</table>";
+
ss << "\n<b>dt\ttlocked</b>\n";
unsigned i = q;
while ( 1 ) {
diff --git a/db/instance.cpp b/db/instance.cpp
index 41152a0f7c4..8674415d0ee 100644
--- a/db/instance.cpp
+++ b/db/instance.cpp
@@ -650,5 +650,4 @@ namespace mongo {
::exit(rc);
}
-
} // namespace mongo
diff --git a/db/instance.h b/db/instance.h
index 95de541b455..334090aa5b9 100644
--- a/db/instance.h
+++ b/db/instance.h
@@ -127,5 +127,5 @@ namespace mongo {
boost::thread_specific_ptr< AuthenticationInfo > backup_;
};
};
-
+
} // namespace mongo
diff --git a/stdafx.h b/stdafx.h
index 7e6c12d3662..01ae11d60fe 100644
--- a/stdafx.h
+++ b/stdafx.h
@@ -312,6 +312,7 @@ namespace mongo {
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/program_options.hpp>
diff --git a/util/top.h b/util/top.h
new file mode 100644
index 00000000000..05a4b30adc9
--- /dev/null
+++ b/util/top.h
@@ -0,0 +1,103 @@
+// top.h : DB usage monitor.
+//
+
+/**
+ * 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/>.
+ */
+
+namespace mongo {
+
+// No two functions of this class may be called concurrently.
+class Top {
+public:
+ typedef boost::posix_time::ptime T;
+ typedef boost::posix_time::time_duration D;
+ static void clientStart( const char *client ) {
+ clientStop();
+ currentStart_ = currentTime();
+ current_ = client;
+ }
+ static void clientStop() {
+ if ( currentStart_ == T() )
+ return;
+ D d = currentTime() - currentStart_;
+ size_t dot = current_.rfind( "." );
+ if ( dot == string::npos || dot != current_.length() - 1 )
+ recordUsage( current_, d );
+ while( dot != string::npos ) {
+ current_ = current_.substr( 0, dot );
+ recordUsage( current_, d );
+ dot = current_.rfind( "." );
+ }
+ currentStart_ = T();
+ }
+ struct Usage { string ns; D time; double pct; };
+ static void usage( vector< Usage > &res ) {
+ multimap< D, string, more > sorted;
+ for( map< string, D >::iterator i = snapshot_.begin(); i != snapshot_.end(); ++i )
+ sorted.insert( make_pair( i->second, i->first ) );
+ set< string > already;
+ for( multimap< D, string >::iterator i = sorted.begin(); i != sorted.end(); ++i ) {
+ Usage u;
+ already.insert( i->second );
+ u.ns = i->second;
+ u.time = totalUsage_[ u.ns ];
+ u.pct = snapshotDuration_ != D() ? 100.0 * i->first.ticks() / snapshotDuration_.ticks() : 0;
+ res.push_back( u );
+ }
+ for( map< string, D >::iterator i = totalUsage_.begin(); i != totalUsage_.end(); ++i ) {
+ if ( already.count( i->first ) != 0 )
+ continue;
+ Usage u;
+ u.ns = i->first;
+ u.time = i->second;
+ u.pct = 0;
+ res.push_back( u );
+ }
+ }
+ static void completeSnapshot() {
+ if ( &snapshot_ == &snapshotA_ ) {
+ snapshot_ = snapshotB_;
+ nextSnapshot_ = snapshotA_;
+ } else {
+ snapshot_ = snapshotA_;
+ nextSnapshot_ = snapshotB_;
+ }
+ snapshotDuration_ = currentTime() - snapshotStart_;
+ snapshotStart_ = currentTime();
+ nextSnapshot_.clear();
+ }
+private:
+ typedef map< string, D > UsageMap;
+ static T currentTime() {
+ return boost::posix_time::microsec_clock::universal_time();
+ }
+ static void recordUsage( const string &client, D duration ) {
+ totalUsage_[ client ] += duration;
+ nextSnapshot_[ client ] += duration;
+ }
+ struct more { bool operator()( const D &a, const D &b ) { return a > b; } };
+ static string current_;
+ static T currentStart_;
+ static T snapshotStart_;
+ static D snapshotDuration_;
+ static UsageMap totalUsage_;
+ static UsageMap snapshotA_;
+ static UsageMap snapshotB_;
+ static UsageMap &snapshot_;
+ static UsageMap &nextSnapshot_;
+};
+
+} // namespace mongo \ No newline at end of file
diff --git a/util/util.cpp b/util/util.cpp
index 1ccd7f15791..892f4a63f83 100644
--- a/util/util.cpp
+++ b/util/util.cpp
@@ -19,6 +19,7 @@
#include "stdafx.h"
#include "goodies.h"
#include "unittest.h"
+#include "top.h"
namespace mongo {
@@ -81,5 +82,15 @@ namespace mongo {
}
} utilTest;
-
+
+ string Top::current_;
+ Top::T Top::currentStart_;
+ Top::T Top::snapshotStart_ = Top::currentTime();
+ Top::D Top::snapshotDuration_;
+ Top::UsageMap Top::totalUsage_;
+ Top::UsageMap Top::snapshotA_;
+ Top::UsageMap Top::snapshotB_;
+ Top::UsageMap &Top::snapshot_ = Top::snapshotA_;
+ Top::UsageMap &Top::nextSnapshot_ = Top::snapshotB_;
+
} // namespace mongo