diff options
author | Aaron <aaron@10gen.com> | 2009-02-09 15:57:30 -0500 |
---|---|---|
committer | Aaron <aaron@10gen.com> | 2009-02-09 15:57:30 -0500 |
commit | 166716bb25aefc6887939a0c35b9df36b8bc01f4 (patch) | |
tree | de59058e5339cd76c3bfd506185b37e2fc5ffab3 | |
parent | 8356bec0709c3bad561c18344f3e866dc216f3cc (diff) | |
download | mongo-166716bb25aefc6887939a0c35b9df36b8bc01f4.tar.gz |
dbtop
-rw-r--r-- | db/db.h | 6 | ||||
-rw-r--r-- | db/dbwebserver.cpp | 9 | ||||
-rw-r--r-- | db/instance.cpp | 1 | ||||
-rw-r--r-- | db/instance.h | 2 | ||||
-rw-r--r-- | stdafx.h | 1 | ||||
-rw-r--r-- | util/top.h | 103 | ||||
-rw-r--r-- | util/util.cpp | 13 |
7 files changed, 131 insertions, 4 deletions
@@ -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 @@ -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 |