Re: Enhancements to nprof

Thomas Strauß <[email protected]> Tue, 28 Dec 2004 09:21:48 +0100
Newsgroups gmane.comp.windows.dotnet.nprof.devel
Message-ID <[email protected]>
--=====================_51187533==_
Content-Type: text/plain; charset="us-ascii"; format=flowed

Hi Matthew,

Please have a look at my changes. The main change is the creation of an 
tcp-connection from the profiler to the profilee. This connection allows to 
toggle the capture behaviour. The overall structure of the profiler-hook 
was not changed. There are only some saves in the hashmap lookups.

The Glue was adapted to the changes in the hook.

In the GUI a menu item was added. The name is not perfect. Please feel free 
to give it a better name. The UI also suppresses threads with no times taken.

If you have more questions please don't hesitate to ask.

Cheers Thomas

At 02:58 28.12.2004, you wrote:
>Excellent.  Can you send me a patch in "unified diff" format to review?
>I'd like to take a look before committing it, but I imagine we can get it 
>in there ASAP.
>
>[email protected] wrote:
>
>>Hi,
>>
>>i was extending nprof to be able to switch on/off the sampling in the 
>>profiler. Is there a way to put this to the archive?
>>
>>Thanks and best regards
>>
>>Thomas

--=====================_51187533==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="nprof.patch"

Index: NProf.Hook/functioninfo.cpp
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.Hook/functioninfo.cpp,v
retrieving revision 1.2
diff -u -w -b -r1.2 functioninfo.cpp
--- NProf.Hook/functioninfo.cpp	27 Dec 2003 21:10:42 -0000	1.2
+++ NProf.Hook/functioninfo.cpp	22 Dec 2004 19:48:14 -0000
@@ -34,14 +34,15 @@
 
 CalleeFunctionInfo* FunctionInfo::GetCalleeFunctionInfo( FunctionID fid )
 {
-  if ( _mCalleeInfo.find( fid ) == _mCalleeInfo.end() )
+  map< FunctionID, CalleeFunctionInfo* >::const_iterator result = _mCalleeInfo.find( fid );
+  if ( result == _mCalleeInfo.end() )
   {
     CalleeFunctionInfo* pFunctionInfo = new CalleeFunctionInfo();
-    _mCalleeInfo.insert( make_pair( fid, pFunctionInfo ) );
+    _mCalleeInfo[fid] = pFunctionInfo;
     return pFunctionInfo;
   }
 
-  return _mCalleeInfo[ fid ];
+  return result->second;
 }
 
 /** No descriptions */
Index: NProf.Hook/profiler.cpp
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.Hook/profiler.cpp,v
retrieving revision 1.3
diff -u -w -b -r1.3 profiler.cpp
--- NProf.Hook/profiler.cpp	27 Dec 2003 21:10:42 -0000	1.3
+++ NProf.Hook/profiler.cpp	22 Dec 2004 12:16:26 -0000
@@ -23,6 +23,7 @@
 {
   _pPrfInfo = pPrfInfo;
   _phHelper.Initialize( _pPrfInfo );
+  instance = this;
 }
 
 Profiler::~Profiler()
@@ -32,8 +33,9 @@
 /** No descriptions */
 void Profiler::Enter( FunctionID fid )
 {
-  FunctionInfo* pFunctionInfo = GetCurrentThreadInfo()->GetFunctionInfo( fid );
-  GetCurrentThreadInfo()->GetStackInfo()->PushFunction( pFunctionInfo, rdtsc() );
+  ThreadInfo *currentThreadInfo = GetCurrentThreadInfo();
+  FunctionInfo* pFunctionInfo = currentThreadInfo->GetFunctionInfo( fid );
+  currentThreadInfo->GetStackInfo()->PushFunction( pFunctionInfo, rdtsc() );
 }
 
 /** No descriptions */
@@ -50,8 +52,9 @@
 
 void Profiler::UnmanagedToManagedCall( FunctionID fid )
 {
-  FunctionInfo* pFunctionInfo = GetCurrentThreadInfo()->GetFunctionInfo( fid );
-  GetCurrentThreadInfo()->GetStackInfo()->PushFunction( pFunctionInfo, rdtsc() );
+  ThreadInfo *currentThreadInfo = GetCurrentThreadInfo();
+  FunctionInfo* pFunctionInfo = currentThreadInfo->GetFunctionInfo( fid );
+  currentThreadInfo->GetStackInfo()->PushFunction( pFunctionInfo, rdtsc() );
 }
 
 void Profiler::ManagedToUnmanagedCall( FunctionID fid )
@@ -129,3 +132,14 @@
 {
   _tic.Trace( _phHelper );
 }
+/** No descriptions */
+
+void Profiler::Enable(bool enabled)
+{
+	Profiler::enabled = enabled;
+	instance->_tic.EnableProfiler(enabled);
+}
+
+bool Profiler::enabled = false;
+
+Profiler *Profiler::instance = 0;
Index: NProf.Hook/profiler.h
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.Hook/profiler.h,v
retrieving revision 1.1.1.1
diff -u -w -b -r1.1.1.1 profiler.h
--- NProf.Hook/profiler.h	9 Mar 2003 20:37:29 -0000	1.1.1.1
+++ NProf.Hook/profiler.h	21 Dec 2004 12:18:22 -0000
@@ -46,13 +46,17 @@
   void AppDomainEnd( AppDomainID aid );
   void End();
   void ThreadMap( ThreadID tid, DWORD dwOSThread );
+  static void Enable(bool enabled);
 
   /** No descriptions */
   void Trace();
+  static bool enabled;
 private:
   ThreadID GetCurrentThreadID();
   ThreadInfo* GetCurrentThreadInfo();
 
+  static Profiler* instance;
+
   ThreadInfoCollection _tic;
   CComPtr< ICorProfilerInfo > _pPrfInfo;
   ProfilerHelper _phHelper;
Index: NProf.Hook/profiler_helper.h
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.Hook/profiler_helper.h,v
retrieving revision 1.1.1.1
diff -u -w -b -r1.1.1.1 profiler_helper.h
--- NProf.Hook/profiler_helper.h	9 Mar 2003 20:37:29 -0000	1.1.1.1
+++ NProf.Hook/profiler_helper.h	22 Dec 2004 23:03:22 -0000
@@ -29,3 +29,4 @@
 											    char *buffer );
   CComPtr< ICorProfilerInfo > _pPrfInfo;
 };
+
Index: NProf.Hook/profiler_socket.cpp
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.Hook/profiler_socket.cpp,v
retrieving revision 1.5
diff -u -w -b -r1.5 profiler_socket.cpp
--- NProf.Hook/profiler_socket.cpp	2 Jul 2004 22:16:58 -0000	1.5
+++ NProf.Hook/profiler_socket.cpp	20 Dec 2004 08:13:12 -0000
@@ -1,5 +1,7 @@
 #include "stdafx.h"
 #include "profiler_socket.h"
+#include "profiler.h"
+#include <process.h>
 
 #define SAFE_SEND( socket, data ) \
 	{ \
@@ -39,6 +41,98 @@
 bool ProfilerSocket::_bInitialized = false;
 int ProfilerSocket::_nApplicationID = -1;
 
+class MessageReceiver {
+public:
+	MessageReceiver() {
+		cout << "MessageReceiver " << endl;
+		_s = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
+		if ( _s == INVALID_SOCKET ) {
+			HandleError( "WSASocket", WSAGetLastError() );
+		} else {
+
+			name.sin_family = AF_INET;
+			name.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+//			name.sin_port = htons(12346);
+			name.sin_port = htons(0);
+
+			int on = 1;
+			setsockopt( _s, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
+                    sizeof(on) );
+
+			if ( bind( _s, (SOCKADDR*) &name, sizeof(name) ) == SOCKET_ERROR ) {
+				printf( "bind() failed.\n" );
+				closesocket(_s);
+				_s = INVALID_SOCKET;
+				return;
+			}
+			int len = sizeof(name);
+
+			getsockname(_s, (SOCKADDR*) &name, &len);
+
+			// Listen on the Socket.
+			if ( listen( _s, 1 ) == SOCKET_ERROR ) {
+				printf( "Error listening on socket.\n");
+				closesocket(_s);
+				_s = INVALID_SOCKET;
+				return;
+			}
+
+			cout << "server on port = " << GetPort() << endl;
+
+			_beginthread(MessageReceiverCallback, 0,(void *) this);
+
+			return;
+
+		}
+
+		_s = INVALID_SOCKET;
+	}
+	int GetPort() {
+		return ntohs(name.sin_port);
+	}
+private:
+	SOCKET _s;
+	sockaddr_in name;
+	void HandleError( const char* szCaller, int nError ) {
+		cout << "error : " << nError << endl;
+	}
+	void HandleWrongRecvLength( const char* szCaller, int nExpected, int nSent ) {
+	}
+	static void MessageReceiverCallback(void *instance) {
+		MessageReceiver *receiver = (MessageReceiver *) instance;
+		while (true) {
+			cout << " accept " << endl;
+			SOCKET s = accept(receiver->_s, 0, 0);
+			cout << "MessageReceiverCallback() " << endl;
+			if (s == INVALID_SOCKET) {
+				receiver->HandleError("Error in MessageReceiverCallback() : ", WSAGetLastError());
+			}
+			BYTE b;
+			if (((MessageReceiver *) instance)->ReadByte(s, b) == 0) {
+				if (b == 42) {
+					Profiler::Enable(true);
+					cout << "Enabled" << endl;
+				}
+
+				if (b == 43) {
+					Profiler::Enable(false);
+					cout << "Disabled" << endl;
+				}
+			}
+			closesocket(s);
+		}
+	}
+	int ReadByte( SOCKET &s, BYTE& b ) {
+		int result;
+		SAFE_READ( s, b, result );
+
+		return result;
+	}
+
+};
+
+MessageReceiver *ProfilerSocket::receiver = 0;
+
 ProfilerSocket::ProfilerSocket()
 {
 	_szOperation = "ctor";
@@ -84,9 +178,13 @@
 	cout << "WSAStartup: " << WSAGetLastError() << endl;
 	cout << "port = " << atoi( getenv( "NPROF_PROFILING_SOCKET" ) ) << endl;
 	ProfilerSocket ps;
+	if (ProfilerSocket::receiver == 0) {
+		ProfilerSocket::receiver = new MessageReceiver();
+	}
 	ps.SendInitialize();
 }
 
+
 void ProfilerSocket::SendInitialize()
 {
 	_szOperation = "SendInitialize";
@@ -108,6 +206,10 @@
 			ReadByte( b );
 			_nApplicationID = b;
 
+			cout << "Listen on port = " << receiver->GetPort() << endl;
+
+			SendUINT32( receiver->GetPort() );
+
 			cout << "Application ID = " << _nApplicationID << endl;
 
 			SendUINT32( ::GetCurrentProcessId() );
Index: NProf.Hook/profiler_socket.h
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.Hook/profiler_socket.h,v
retrieving revision 1.4
diff -u -w -b -r1.4 profiler_socket.h
--- NProf.Hook/profiler_socket.h	2 Jul 2004 22:16:58 -0000	1.4
+++ NProf.Hook/profiler_socket.h	17 Dec 2004 11:59:40 -0000
@@ -16,6 +16,8 @@
 
 const int NETWORK_PROTOCOL_VERSION = 3;
 
+class MessageReceiver;
+
 class ProfilerSocket
 {
 public:
@@ -48,7 +50,6 @@
   inline void SendAppDomainID( AppDomainID aid );
   inline void SendThreadID( ThreadID tid );
   inline void SendFunctionID( FunctionID fid );
-
 private:
   SOCKET _s;
   const char* _szOperation;
@@ -56,4 +57,7 @@
 
   static bool _bInitialized;
   static int _nApplicationID;
+
+  static MessageReceiver *receiver;
+  
 };
Index: NProf.Hook/stackinfo.cpp
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.Hook/stackinfo.cpp,v
retrieving revision 1.2
diff -u -w -b -r1.2 stackinfo.cpp
--- NProf.Hook/stackinfo.cpp	27 Dec 2003 21:10:42 -0000	1.2
+++ NProf.Hook/stackinfo.cpp	22 Dec 2004 12:45:32 -0000
@@ -18,6 +18,7 @@
 #include "stdafx.h"
 #include "stackinfo.h"
 #include "threadinfo.h"
+#include "profiler.h"
 
 StackInfo::StackInfo( ThreadInfo* pThreadInfo )
 {
@@ -31,7 +32,7 @@
 /** No descriptions */
 void StackInfo::PushFunction( FunctionInfo* pFunctionInfo, INT64 llCycleCount )
 {
-	if ( _sFunctionStack.size() > 0 )
+	if ( !_sFunctionStack.empty())
 	{
 		// Increment the recursive count of this callee function info so we don't double-book entries
 		FunctionInfo* pCallerFunctionInfo = _sFunctionStack.top().pFunctionInfo;
@@ -39,12 +40,16 @@
 		
 		CalleeFunctionInfo* pCalleeFunctionInfo = pCallerFunctionInfo->GetCalleeFunctionInfo( fidCallee );
 		pCalleeFunctionInfo->nRecursiveCount++;
+		if (Profiler::enabled) {
 		pCalleeFunctionInfo->nCalls++;
 	}
+	}
 
 	// Increment the recursive count of this function info so we don't double-book entries
 	pFunctionInfo->nRecursiveCount++;
+    if (Profiler::enabled) {
 	pFunctionInfo->nCalls++;
+	}
 
 	_sFunctionStack.push( StackEntryInfo( pFunctionInfo, llCycleCount ) );
 }
@@ -52,33 +57,44 @@
 /** No descriptions */
 INT64 StackInfo::PopFunction( INT64 llCycleCount )
 {
-	INT64 llElapsed = llCycleCount - _sFunctionStack.top().llCycleStart;
-	FunctionInfo* pFunctionInfo = _sFunctionStack.top().pFunctionInfo;
+	StackEntryInfo stackEntry = _sFunctionStack.top();
+	INT64 llElapsed = llCycleCount - stackEntry.llCycleStart;
+	FunctionInfo* pFunctionInfo = stackEntry.pFunctionInfo;
 
 	FunctionID fidCallee = pFunctionInfo->fid;
 
 	// Only add the time if we're at the lowest call to the function on the stack
 	// Prevents double-accounting of recursive functions
 	pFunctionInfo->nRecursiveCount--;
-	if ( pFunctionInfo->nRecursiveCount == 0 )
+	if ( pFunctionInfo->nRecursiveCount == 0 ) {
+		if (Profiler::enabled) {
 		pFunctionInfo->llCycleCount += llElapsed;
-	else
+		}
+	} else {
+		if (Profiler::enabled) {
 		pFunctionInfo->llRecursiveCycleCount += llElapsed;
+		}
+	}
 
 	_sFunctionStack.pop();
 
-	if ( _sFunctionStack.size() > 0 )
+	if ( !_sFunctionStack.empty())
 	{
 		CalleeFunctionInfo* pCalleeFunctionInfo = _sFunctionStack.top().pFunctionInfo->GetCalleeFunctionInfo( fidCallee );
 
 		// Only add the time if we're at the lowest call to the function on the stack
 		// Prevents double-accounting of recursive functions
 		pCalleeFunctionInfo->nRecursiveCount--;
-		if ( pCalleeFunctionInfo->nRecursiveCount == 0 )
+		if ( pCalleeFunctionInfo->nRecursiveCount == 0 ) {
+			if (Profiler::enabled) {
 			pCalleeFunctionInfo->llCycleCount += llElapsed;
-		else
+			}
+		} else {
+			if (Profiler::enabled) {
 			pCalleeFunctionInfo->llRecursiveCycleCount += llElapsed;
 	}
+		}
+	}
 
 	return llElapsed;
 }
@@ -87,11 +103,11 @@
 void StackInfo::SuspendFunction( INT64 llCycleCount )
 {
 	_llSuspendStart = llCycleCount;
-	if ( _sFunctionStack.size() == 0 ) 
-	{
-		cout << "Suspend with no call stack!" << endl;
-		return;
-	}
+//	if ( _sFunctionStack.empty() ) 
+//	{
+//		cout << "Suspend with no call stack!" << endl;
+//		return;
+//	}
 	//cout << "Suspended function ID: " << _sFunctionStack.top().pFunctionInfo->fid << endl;
 }
 
@@ -100,7 +116,7 @@
 {
 	INT64 llElapsed = llCycleCount - _llSuspendStart;
 	// Resume with no call stack, ignore
-	if ( _sFunctionStack.size() == 0 ) 
+	if ( _sFunctionStack.empty() ) 
 	{
 		cout << "Resume with no call stack!" << endl;
 		return;
Index: NProf.Hook/threadinfo.cpp
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.Hook/threadinfo.cpp,v
retrieving revision 1.2
diff -u -w -b -r1.2 threadinfo.cpp
--- NProf.Hook/threadinfo.cpp	27 Dec 2003 21:10:42 -0000	1.2
+++ NProf.Hook/threadinfo.cpp	22 Dec 2004 12:42:46 -0000
@@ -18,11 +18,14 @@
 #include "stdafx.h"
 #include "threadinfo.h"
 #include "profiler_socket.h"
+#include "profiler.h"
 
-ThreadInfo::ThreadInfo()
+ThreadInfo::ThreadInfo(ThreadID tid)
 {
   _bRunning = false;
   _llSuspendTime = 0;
+  _llElapsed = 0;
+  _tid = tid;
   _pStackInfo = new StackInfo( this );
 }
 
@@ -31,6 +34,18 @@
 	delete _pStackInfo;
 }
 
+void ThreadInfo::EnableProfiler(bool enabled) {
+  INT64 time = rdtsc();
+  if (enabled) {
+    _llStartTime = time;
+  } else {
+    _llElapsed += (time - _llStartTime);
+	_llEndTime = time;
+	_llStartTime = time - _llElapsed; 
+  }
+}
+
+
 void ThreadInfo::Start()
 {
   _llStartTime = rdtsc();
@@ -39,7 +54,10 @@
 
 void ThreadInfo::End()
 {
+	if (Profiler::enabled) {
   _llEndTime = rdtsc();
+		_llStartTime -= _llElapsed;
+	}
   _bRunning = false;
 }
 
@@ -48,21 +66,17 @@
   return _bRunning;
 }
 
-StackInfo* ThreadInfo::GetStackInfo()
-{
-  return _pStackInfo;
-}
-
 FunctionInfo* ThreadInfo::GetFunctionInfo( FunctionID fid )
 {
-  if ( _mFunctionInfo.find( fid ) == _mFunctionInfo.end() )
+  map< FunctionID, FunctionInfo* >::const_iterator result = _mFunctionInfo.find( fid );
+  if ( result == _mFunctionInfo.end() )
   {
     FunctionInfo* pFunctionInfo = new FunctionInfo( fid );
-    _mFunctionInfo.insert( make_pair( fid, pFunctionInfo ) );
+    _mFunctionInfo[fid] = pFunctionInfo;
     return pFunctionInfo;
   }
 
-  return _mFunctionInfo[ fid ];
+  return result->second;
 }
 
 /** No descriptions */
Index: NProf.Hook/threadinfo.h
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.Hook/threadinfo.h,v
retrieving revision 1.2
diff -u -w -b -r1.2 threadinfo.h
--- NProf.Hook/threadinfo.h	27 Dec 2003 21:10:42 -0000	1.2
+++ NProf.Hook/threadinfo.h	22 Dec 2004 12:12:18 -0000
@@ -31,24 +31,29 @@
 class ThreadInfo
 {
 public: 
-	ThreadInfo();
+	ThreadInfo(ThreadID tid);
 	~ThreadInfo();
 
   void Start();
   void End();
+  void EnableProfiler(bool enabled);
   bool IsRunning();
-  StackInfo* GetStackInfo();
+  StackInfo* GetStackInfo() {
+	return _pStackInfo;
+  }
   FunctionInfo* GetFunctionInfo( FunctionID fid );
   void Trace( ProfilerHelper& ph );
   void Dump( ProfilerSocket& ps, ProfilerHelper& ph );
   INT64 _llStartTime;
   INT64 _llEndTime;
   INT64 _llSuspendTime;
+  ThreadID _tid;
   
 private:
   bool  _bRunning;
   StackInfo* _pStackInfo;
   map< FunctionID, FunctionInfo* > _mFunctionInfo;
+  INT64 _llElapsed;
 };
 
 #endif
Index: NProf.Hook/threadinfocollection.cpp
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.Hook/threadinfocollection.cpp,v
retrieving revision 1.1.1.1
diff -u -w -b -r1.1.1.1 threadinfocollection.cpp
--- NProf.Hook/threadinfocollection.cpp	9 Mar 2003 20:37:30 -0000	1.1.1.1
+++ NProf.Hook/threadinfocollection.cpp	22 Dec 2004 12:42:46 -0000
@@ -20,6 +20,7 @@
 
 ThreadInfoCollection::ThreadInfoCollection()
 {
+	lastThreadInfo = 0;
 }
 
 ThreadInfoCollection::~ThreadInfoCollection()
@@ -44,14 +45,18 @@
 
 ThreadInfo* ThreadInfoCollection::GetThreadInfo( ThreadID tid )
 {
-  if ( _mThreadInfo.find( tid ) == _mThreadInfo.end() )
+  if (lastThreadInfo != 0 && lastThreadInfo->_tid == tid) {
+    return lastThreadInfo;
+  }
+  map< ThreadID, ThreadInfo* >::const_iterator result = _mThreadInfo.find( tid );
+  if ( result == _mThreadInfo.end() )
   {
-    ThreadInfo* pThreadInfo = new ThreadInfo();
-    _mThreadInfo.insert( make_pair( tid, pThreadInfo ) );
-    return pThreadInfo;
+    lastThreadInfo = new ThreadInfo(tid);
+    _mThreadInfo[tid] = lastThreadInfo;
+  } else {
+	lastThreadInfo = result->second;
   }
-  
-  return _mThreadInfo[ tid ];
+  return lastThreadInfo;
 }
 
 /** No descriptions */
@@ -78,6 +83,13 @@
   }
 }
 
+void ThreadInfoCollection::EnableProfiler(bool enabled) {
+  for ( map< ThreadID, ThreadInfo* >::iterator it = _mThreadInfo.begin(); it != _mThreadInfo.end(); it++ )
+  {
+	it->second->EnableProfiler(enabled);
+  }
+}
+
 void ThreadInfoCollection::Dump( ProfilerHelper& ph, ThreadID tid )
 {
   ProfilerSocket ps;
Index: NProf.Hook/threadinfocollection.h
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.Hook/threadinfocollection.h,v
retrieving revision 1.1.1.1
diff -u -w -b -r1.1.1.1 threadinfocollection.h
--- NProf.Hook/threadinfocollection.h	9 Mar 2003 20:37:30 -0000	1.1.1.1
+++ NProf.Hook/threadinfocollection.h	22 Dec 2004 12:10:56 -0000
@@ -41,8 +41,10 @@
   void DumpAll( ProfilerHelper& ph );
   void Dump( ProfilerHelper& ph, ThreadID tid );
   void Trace( ProfilerHelper& ph );
+  void EnableProfiler(bool enabled);
 private:
   map< ThreadID, ThreadInfo* > _mThreadInfo;
+  ThreadInfo *lastThreadInfo;
 };
 
 #endif
Index: NProf.Glue/Profiler/Info/FunctionInfoCollection.cs
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.Glue/Profiler/Info/FunctionInfoCollection.cs,v
retrieving revision 1.2
diff -u -w -b -r1.2 FunctionInfoCollection.cs
--- NProf.Glue/Profiler/Info/FunctionInfoCollection.cs	2 Jul 2004 22:16:57 -0000	1.2
+++ NProf.Glue/Profiler/Info/FunctionInfoCollection.cs	20 Dec 2004 08:53:52 -0000
@@ -35,5 +35,11 @@
 		}
 
 		Hashtable _htFunctionInfo;
+
+        public int Count {
+            get {
+                return _htFunctionInfo.Count;
+            }
+        }
 	}
 }
Index: NProf.Glue/Profiler/Info/ProcessInfo.cs
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.Glue/Profiler/Info/ProcessInfo.cs,v
retrieving revision 1.1
diff -u -w -b -r1.1 ProcessInfo.cs
--- NProf.Glue/Profiler/Info/ProcessInfo.cs	2 Jul 2004 22:16:57 -0000	1.1
+++ NProf.Glue/Profiler/Info/ProcessInfo.cs	21 Dec 2004 07:07:00 -0000
@@ -32,12 +32,16 @@
 			set { _nProcessID = value; }
 		}
 
-		public string Name
-		{
+        public string Name {
 			get { return _strName; }
 			set { _strName = value; }
 		}
 
+        public int Port {
+            get { return _port; }
+            set { _port = value; }
+        }
+
 		public FunctionSignatureMap Functions
 		{
 			get { return _fsm; }
@@ -50,6 +54,15 @@
 			set { _tic = value; }
 		}
 
+        public bool Completed {
+            get {
+                return _completed;
+            }
+            set {
+                _completed = value;
+            }
+        }
+
 		public override string ToString()
 		{
 			return String.Format( "{0} ({1})", _strName, _nProcessID );
@@ -57,8 +70,10 @@
 
 		private int _nID;
 		private int _nProcessID;
+        private int _port;
 		private FunctionSignatureMap _fsm;
 		private ThreadInfoCollection _tic;
 		private string _strName;
+        private bool _completed;
 	}
 }
Index: NProf.GUI/ProcessTree.cs
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.GUI/ProcessTree.cs,v
retrieving revision 1.1
diff -u -w -b -r1.1 ProcessTree.cs
--- NProf.GUI/ProcessTree.cs	2 Jul 2004 22:16:55 -0000	1.1
+++ NProf.GUI/ProcessTree.cs	20 Dec 2004 08:53:52 -0000
@@ -62,21 +62,21 @@
 				tnProcess.SelectedImageIndex = 0;
 				tnProcess.Tag = pi;
 
-				foreach ( ThreadInfo ti in pi.Threads )
-				{
+                foreach ( ThreadInfo ti in pi.Threads ) {
+                    if (ti.FunctionInfoCollection.Count != 0) {
 					TreeNode tnThread = tnProcess.Nodes.Add( ti.ToString() );
 					tnThread.ImageIndex = 1;
 					tnThread.SelectedImageIndex = 1;
 					tnThread.Tag = ti;
 
-					if ( bFirst )
-					{
+                        if ( bFirst ) {
 						_tvProcess.SelectedNode = tnThread;
 						bFirst = false;
 					}
 				}
 			}
 		}
+		}
 
 		#region Component Designer generated code
 		/// <summary> 
Index: NProf.GUI/ProfilerControl.cs
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.GUI/ProfilerControl.cs,v
retrieving revision 1.16
diff -u -w -b -r1.16 ProfilerControl.cs
--- NProf.GUI/ProfilerControl.cs	22 Sep 2004 15:35:43 -0000	1.16
+++ NProf.GUI/ProfilerControl.cs	20 Dec 2004 08:59:14 -0000
@@ -563,6 +563,9 @@
 				tnRoot.Checked = true;
 
 				ThreadInfo tiCurrentThread = _tiCurrent;
+                if (tiCurrentThread == null) {
+                    return;
+                }
 				foreach ( FunctionInfo fi in tiCurrentThread.FunctionInfoCollection )
 				{
 					TreeNodeCollection tnc = tnRoot.Nodes;
@@ -616,6 +619,9 @@
 				_lvFunctionInfo.BeginUpdate();
 
 				ThreadInfo tiCurrentThread = _tiCurrent;
+                if (tiCurrentThread == null) {
+                    return;
+                }
 				foreach ( FunctionInfo fi in tiCurrentThread.FunctionInfoCollection )
 				{
 					if ( !htNamespaces.Contains( fi.Signature.NamespaceString ) )
Index: NProf.GUI/ProfilerForm.cs
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.GUI/ProfilerForm.cs,v
retrieving revision 1.28
diff -u -w -b -r1.28 ProfilerForm.cs
--- NProf.GUI/ProfilerForm.cs	3 Oct 2004 15:58:42 -0000	1.28
+++ NProf.GUI/ProfilerForm.cs	22 Dec 2004 10:19:42 -0000
@@ -64,6 +64,8 @@
 		private Reflector.UserInterface.CommandBarManager commandBarManager1;
 		private Reflector.UserInterface.CommandBar commandBar1;
 		private Reflector.UserInterface.CommandBar commandBar2;
+        private Crownwood.Magic.Menus.MenuCommand _sep5;
+        private Crownwood.Magic.Menus.MenuCommand _cmdProjectEnabled;
 
 		/// <summary>
 		/// Required designer variable.
@@ -83,6 +85,7 @@
 			_stackBack = new Stack();
 			_stackForward = new Stack();
 			_p = new Profiler();
+            ProfilerEnabled = false;
 			//_p.ProcessCompleted += new Profiler.ProcessCompletedHandler( OnProfileComplete );
 			_p.Error += new Profiler.ErrorHandler( OnError );
 			_piInitialProject = null;
@@ -150,6 +153,8 @@
 			this._sbpMessage = new System.Windows.Forms.StatusBarPanel();
 			this.commandBarManager1 = new Reflector.UserInterface.CommandBarManager();
 			this.commandBar1 = new Reflector.UserInterface.CommandBar();
+            this._sep5 = new Crownwood.Magic.Menus.MenuCommand();
+            this._cmdProjectEnabled = new Crownwood.Magic.Menus.MenuCommand();
 			((System.ComponentModel.ISupportInitialize)(this._sbpMessage)).BeginInit();
 			this.SuspendLayout();
 			// 
@@ -280,7 +285,9 @@
 																								this._cmdProjectOptions,
 																								this._sep4,
 																								this._cmdProjectRunViewMessages,
-																								this._cmdProjectRunCopy});
+                                                                                                this._cmdProjectRunCopy,
+                                                                                                this._sep5,
+                                                                                                this._cmdProjectEnabled});
 			this._menuProject.Text = "&Project";
 			// 
 			// _cmdProjectRun
@@ -409,6 +416,18 @@
 			this.commandBar1.TabStop = false;
 			this.commandBar1.Text = "commandBar1";
 			// 
+            // _sep5
+            // 
+            this._sep5.Description = "-";
+            this._sep5.Text = "-";
+            // 
+            // _cmdProjectEnabled
+            // 
+            this._cmdProjectEnabled.Checked = true;
+            this._cmdProjectEnabled.Description = "MenuItem";
+            this._cmdProjectEnabled.Text = "Enabled";
+            this._cmdProjectEnabled.Click += new System.EventHandler(this._cmdProjectEnabled_Click);
+            // 
 			// ProfilerForm
 			// 
 			this.AllowDrop = true;
@@ -536,13 +555,12 @@
 			commandBarManager1.CommandBars.Add( commandBar2 );
 
 			_pic = new ProjectInfoCollection();
-			_pt = new ProjectTree();
+			_pt = new ProjectTree(this);
 
 			_pic.ProjectRemoved +=new NProf.Glue.Profiler.Project.ProjectInfoCollection.ProjectEventHandler(_pic_ProjectRemoved);
 
 			_pt.Projects = _pic;
 			_pt.ProjectDoubleClicked += new ProjectTree.ProjectDoubleClickedHandler( _pt_ProjectDoubleClicked );
-			_pt.RunDoubleClicked += new ProjectTree.RunDoubleClickedHandler( _pt_RunDoubleClicked );
 			_pt.ExecutablesDropped +=new ProjectTree.ExecutablesDroppedHandler( _pt_ExecutableDropped );
 
 			_dock = new Crownwood.Magic.Docking.DockingManager( this, Crownwood.Magic.Common.VisualStyle.IDE );
@@ -974,6 +992,32 @@
 			_cmdViewNavForward.Enabled = ( !IsShowingBlankTab() );
 		}
 
+        private void _cmdProjectEnabled_Click(object sender, System.EventArgs e) {
+            ProfilerEnabled = !ProfilerEnabled;
+        }
+
+        private bool ProfilerEnabled {
+            set {
+                _p.EnableProfiler = value;
+                _cmdProjectEnabled.Checked = value;
+            }
+            get {
+                return _cmdProjectEnabled.Checked;
+            }
+        }
+
+        public Run ActiveRun {
+            set {
+                foreach (Crownwood.Magic.Controls.TabPage tp in _tcProfilers.TabPages) {
+                    if (tp.Tag.Equals(value)) {
+                        int index = _tcProfilers.TabPages.IndexOf(tp);
+                        _tcProfilers.SelectedIndex = index;
+                        break;                        
+                    }
+                }
+            }
+        }
+
 		private class Images
 		{
 			private static Image[] images = null;
Index: NProf.GUI/ProjectTree.cs
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.GUI/ProjectTree.cs,v
retrieving revision 1.9
diff -u -w -b -r1.9 ProjectTree.cs
--- NProf.GUI/ProjectTree.cs	2 Jul 2004 22:16:55 -0000	1.9
+++ NProf.GUI/ProjectTree.cs	22 Dec 2004 10:24:12 -0000
@@ -16,18 +16,19 @@
 	public class ProjectTree : System.Windows.Forms.UserControl
 	{
 		private System.Windows.Forms.TreeView _tvProjects;
-		private System.ComponentModel.IContainer components;
 		private System.Windows.Forms.ImageList _ilState;
+        private ProfilerForm _form;
 
 		private ProjectInfoCollection _pic;
 
-		public ProjectTree()
+		public ProjectTree(ProfilerForm form)
 		{
 			// This call is required by the Windows.Forms Form Designer.
 			InitializeComponent();
 
 			// TODO: Add any initialization after the InitForm call
 			_pic = null;
+            _form = form;
 		}
 
 		/// <summary> 
@@ -37,10 +38,6 @@
 		{
 			if( disposing )
 			{
-				if(components != null)
-				{
-					components.Dispose();
-				}
 			}
 			base.Dispose( disposing );
 		}
@@ -75,6 +72,7 @@
 			this.Controls.Add(this._tvProjects);
 			this.Name = "ProjectTree";
 			this.Size = new System.Drawing.Size(344, 464);
+            this.Click += new System.EventHandler(this.ProjectTree_Click);
 			this.Load += new System.EventHandler(this.ProjectTree_Load);
 			this.ResumeLayout(false);
 
@@ -312,6 +310,13 @@
 				ExecutablesDropped.BeginInvoke( files, null, null );
 		}
 
+        private void ProjectTree_Click(object sender, System.EventArgs e) {
+            Run _run = _tvProjects.SelectedNode.Tag as Run;
+            if (_run != null) {
+                _form.ActiveRun = _run;
+            }
+        }
+
 		public event ProjectDoubleClickedHandler ProjectDoubleClicked;
 		public event RunDoubleClickedHandler RunDoubleClicked;
 		public event ExecutablesDroppedHandler ExecutablesDropped;
Index: NProf.Glue/Profiler/Profiler.cs
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.Glue/Profiler/Profiler.cs,v
retrieving revision 1.16
diff -u -w -b -r1.16 Profiler.cs
--- NProf.Glue/Profiler/Profiler.cs	2 Jul 2004 22:16:56 -0000	1.16
+++ NProf.Glue/Profiler/Profiler.cs	17 Dec 2004 14:59:02 -0000
@@ -44,6 +44,15 @@
 			return true;
 		}
 
+        public bool EnableProfiler {
+            set {
+                if (_pss != null) {
+                    _pss.EnableProfiler = value;
+                }
+                enabled = value;
+            }
+        }
+
 		public bool Start( ProjectInfo pi, Run run, ProcessCompletedHandler pch )
 		{
 			_dtStart = DateTime.Now;
@@ -53,10 +62,10 @@
 			_run.State = Run.RunState.Initializing;
 
 			_pss = new ProfilerSocketServer( pi.Options, run );
+            _pss.EnableProfiler = enabled;
 			_pss.Start();
 			_pss.Exited += new EventHandler( OnProcessExited );
 			_pss.Error += new ProfilerSocketServer.ErrorHandler( OnError );
-			_pss.Message += new ProfilerSocketServer.MessageHandler( OnMessage );
 
 			switch ( pi.ProjectType )
 			{
@@ -71,7 +80,6 @@
 					_p.StartInfo.Arguments = pi.Arguments;
 					_p.StartInfo.WorkingDirectory = pi.WorkingDirectory;
 					_p.EnableRaisingEvents = true;
-					//_p.Exited += new EventHandler( OnProcessExited );
 
 					return _p.Start();
 				}
@@ -281,7 +289,6 @@
 		}
 
 		public delegate void ProcessCompletedHandler( Run run );
-		public event ProcessCompletedHandler ProcessCompleted;
 		public delegate void ErrorHandler( Exception e );
 		public event ErrorHandler Error;
 		public delegate void MessageHandler( string strMessage );
@@ -300,5 +307,6 @@
 		private Process _p;
 		private ProjectInfo _pi;
 		private ProfilerSocketServer _pss;
+        private bool enabled;
 	}
 }
Index: NProf.Glue/Profiler/Core/ProfilerSocketServer.cs
===================================================================
RCS file: /cvsroot/nprof/nprof/NProf.Glue/Profiler/Core/ProfilerSocketServer.cs,v
retrieving revision 1.10
diff -u -w -b -r1.10 ProfilerSocketServer.cs
--- NProf.Glue/Profiler/Core/ProfilerSocketServer.cs	2 Jul 2004 22:16:56 -0000	1.10
+++ NProf.Glue/Profiler/Core/ProfilerSocketServer.cs	21 Dec 2004 07:07:00 -0000
@@ -30,6 +30,7 @@
 		public void Start()
 		{
 			_t = new Thread( new ThreadStart( ListenThread ) );
+            _t.IsBackground = true;
 			_mreStarted = new ManualResetEvent( false );
 			_t.Start();
 			_mreStarted.WaitOne();
@@ -40,6 +41,7 @@
 			lock ( _s )
 				Interlocked.Increment( ref _nStopFlag );
 			_s.Close();
+            _s = null;
 		}
 
 		public bool HasStoppedGracefully
@@ -50,19 +52,16 @@
 		private void ListenThread()
 		{
 			Thread.CurrentThread.Name = "ProfilerSocketServer Listen Thread";
-			try
-			{
+            try {
 				_mreReceivedMessage = new ManualResetEvent( false );
-				using ( _s = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp ) )
-				{
+                using ( _s = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp ) ) {
 					IPEndPoint ep = new IPEndPoint( IPAddress.Loopback, 0 );
 					_s.Bind( ep );
 					_nPort = ( ( IPEndPoint )_s.LocalEndPoint ).Port;
 					_mreStarted.Set();
 					_s.Listen( 100 );
 
-					while ( true )
-					{
+                    while ( true ) {
 						_mreReceivedMessage.Reset();
 						lock ( _s )
 							if ( _nStopFlag == 1 )
@@ -72,12 +71,43 @@
 					}
 				}
 			}
-			catch ( Exception e )
-			{
+            catch ( Exception) {
 				_mreStarted.Set();
 			}
 		}
 
+        public bool EnableProfiler {
+            set {
+                _profilerEnabled = value;
+                if (_s != null) {
+                    SendEnabled();
+                }
+            }
+        }
+
+        private void SendEnabled() {
+            foreach (ProcessInfo processInfo in _run.Processes) {
+                if (processInfo != null && !processInfo.Completed) {
+                    try {
+                        IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, processInfo.Port);
+                        Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+                        s.Connect(ep);
+                        NetworkStream ns = new NetworkStream(s, true);
+                        if (_profilerEnabled) {
+                            ns.WriteByte(42);
+                        } else {
+                            ns.WriteByte(43);
+                        }
+                        s.Close();
+                    } catch (Exception e) {
+                        _run.Messages.AddMessage( "Port: " + processInfo.Port );
+                        _run.Messages.AddMessage( "ProcessID: " + processInfo.ID );
+                        _run.Messages.AddMessage( "Exception: " + e );
+                    }
+                }
+            }
+        }
+
 		private string ReadLengthEncodedASCIIString( BinaryReader br )
 		{
 			int nLength = br.ReadInt32();
@@ -191,6 +221,9 @@
 
 								ns.WriteByte( ( byte )nApplicationID );
 
+                                piCurrent.Port = ( int )br.ReadUInt32();
+                                _run.Messages.AddMessage( "port: " + piCurrent.Port);
+
 								piCurrent.ProcessID = ( int )br.ReadUInt32();
 								int nArgs = ( int )br.ReadUInt32();
 
@@ -210,6 +243,7 @@
 
 								_nProfileCount++;
 								_run.Messages.AddMessage( "Connected to " + piCurrent.Name + " with process ID " + piCurrent.ProcessID );
+                                SendEnabled();
 							}
 
 							// We're off!
@@ -222,6 +256,8 @@
 							_nProfileCount--;
 							_run.Messages.AddMessage( "Profiling completed for " + piCurrent.Name );
 
+                            piCurrent.Completed = true;
+
 							if ( _nProfileCount == 0 )
 							{
 								_bHasStopped = true;
@@ -296,7 +332,9 @@
 								CalleeFunctionInfo[] acfi = ( CalleeFunctionInfo[] )alCallees.ToArray( typeof( CalleeFunctionInfo ) );
 
 								FunctionInfo fi = new FunctionInfo( piCurrent.Threads[ nThreadID ], nFunctionID, fs, nCalls, lTotalTime, lTotalRecursiveTime, lTotalSuspendTime, acfi );
+                                if (fi.Calls != 0) {
 								piCurrent.Threads[ nThreadID ].FunctionInfoCollection.Add( fi );
+                                }
 								
 								nFunctionID = br.ReadInt32();
 								nIndex++;
@@ -328,7 +366,6 @@
 
 		public event EventHandler Exited;
 		public event ErrorHandler Error;
-		public event MessageHandler Message;
 
 		public delegate void ErrorHandler( Exception e );
 		public delegate void MessageHandler( string strMessage );
@@ -342,7 +379,7 @@
 			THREAD_CREATE,
 			THREAD_END,
 			FUNCTION_DATA,
-			PROFILER_MESSAGE,
+			PROFILER_MESSAGE
 		};
 
 		const int NETWORK_PROTOCOL_VERSION = 3;
@@ -358,5 +395,7 @@
 		private Project.Options			_po;
 		private Run						_run;
 		private bool					_bHasStopped;
+        private bool                    _profilerEnabled;
+
 	}
 }

***** CVS exited normally with code 1 *****



--=====================_51187533==_--



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now. 
http://productguide.itmanagersjournal.com/