[Mono-bugs] [Bug 70337][Maj] New - Performance problem with TcpChannel

bugzilla-daemon@bugzilla.ximian.com bugzilla-daemon@bugzilla.ximian.com
Wed, 8 Dec 2004 13:43:27 -0500 (EST)


Please do not reply to this email- if you want to comment on the bug, go to the
URL shown below and enter your comments there.

Changed by sebastien.robitaille@croesus.com.

http://bugzilla.ximian.com/show_bug.cgi?id=70337

--- shadow/70337	2004-12-08 13:43:27.000000000 -0500
+++ shadow/70337.tmp.3471	2004-12-08 13:43:27.000000000 -0500
@@ -0,0 +1,271 @@
+Bug#: 70337
+Product: Mono: Class Libraries
+Version: 1.0
+OS: Red Hat 9.0
+OS Details: 
+Status: NEW   
+Resolution: 
+Severity: 
+Priority: Major
+Component: CORLIB
+AssignedTo: mono-bugs@ximian.com                            
+ReportedBy: sebastien.robitaille@croesus.com               
+QAContact: mono-bugs@ximian.com
+TargetMilestone: ---
+URL: 
+Cc: 
+Summary: Performance problem with TcpChannel
+
+Description of Problem:
+
+I developed a small client and a small server to test the performance of 
+remoting. The execution results are very interesting.
+
+I ran the client and the server using all combinations of tcp, http, 
+binary and soap.
+The execution was done for MS.NET on a Windows XP Pro 1GHz Pentium III. 
+For Mono, it was done on a RH9 Xeon 1.5GHz 8CPUs.
+(Note: This test should be done on the same machine for both mono and 
+MS.NET to make a better comparision).
+
+-----------------------------------
+The results (Requests per second):
+-----------------------------------
+		MS.NET	Mono
+
+SOAP/HTTP	190	60
+SOAP/TCP	280	12
+BINARY/HTTP	340	100
+BINARY/TCP	1050	12
+-----------------------------------
+
+The interesting point here is that both SOAP and BINARY gave the same 
+number for TCP in mono. While HTTP is slower in mono than in MS.NET, the 
+results are at least consistents (SOAP is, as expected, slower tant 
+Binary).
+
+Hint: I had a quick look at the TcpChannel code and I found many places 
+that a networkStream was read or written one Byte at a time.
+
+Steps to reproduce the problem:
+[1] Create 3 files (Client.cs, Server.cs and IServerInterface.cs) 
+containing the following code:
+
+----------------- Client.cs -----------------------------------------
+//#define HTTP
+//#define SOAP
+
+using System;
+using System.Collections;
+using System.Runtime.Remoting.Channels;
+using System.Runtime.Remoting.Channels.Tcp;
+using System.Runtime.Remoting.Channels.Http;
+using ServerInterface;
+
+namespace Client
+{
+	class Client
+	{
+		[STAThread]
+		static void Main(string[] args)
+		{
+			string serverName	= "localhost";
+			int timeout			= 1000;
+
+			if(args.Length > 0)
+			{
+				serverName = args[0];
+			}
+
+			if(args.Length > 1)
+			{
+				timeout = Int32.Parse(args[1]);
+			}
+#if SOAP
+			SoapClientFormatterSinkProvider formatterProvider 
+= new SoapClientFormatterSinkProvider();
+#else
+			BinaryClientFormatterSinkProvider 
+formatterProvider = new BinaryClientFormatterSinkProvider();
+#endif
+		
+			Hashtable channelProperties = new Hashtable();
+			channelProperties["port"] = 0;
+
+#if HTTP
+			HttpClientChannel channel = new HttpClientChannel
+(channelProperties, formatterProvider);
+			string prefix = "http://";
+#else
+			TcpClientChannel channel = new TcpClientChannel
+(channelProperties, formatterProvider);
+			string prefix = "tcp://";
+#endif
+			ChannelServices.RegisterChannel(channel);
+
+			IServerInterface serverObject = 
+(IServerInterface) 
+				Activator.GetObject(typeof
+(IServerInterface), prefix + serverName + ":8999/IServerInterface");
+
+			while(true)
+			{
+				serverObject.ExecuteRequest(null);
+			}
+		}
+	}
+}
+
+
+
+-------------- Server.cs ---------------------------------------
+//#define HTTP
+//#define SOAP
+
+using System;
+using System.Collections;
+using System.Runtime.Remoting;
+using System.Runtime.Remoting.Channels;
+using System.Runtime.Remoting.Channels.Tcp;
+using System.Runtime.Remoting.Channels.Http;
+using System.Runtime.Serialization.Formatters;
+using System.Threading;
+using ServerInterface;
+
+namespace Server
+{
+	class Server
+	{
+		static bool running = true;
+		static int refresh = 1000;
+
+		[STAThread]
+		static void Main(string[] args)
+		{
+			if(args.Length > 0)
+			{
+				refresh = Int32.Parse(args[0]);
+			}
+
+			RemotingConfiguration.RegisterWellKnownServiceType
+(
+									
+	typeof(RemoteObject),
+									
+	"IServerInterface",
+									
+	WellKnownObjectMode.Singleton);
+#if SOAP
+			SoapServerFormatterSinkProvider formatterProvider 
+= new SoapServerFormatterSinkProvider();
+#else
+			BinaryServerFormatterSinkProvider 
+formatterProvider = new BinaryServerFormatterSinkProvider();
+#endif
+			Hashtable channelProperties = new Hashtable();
+			channelProperties["port"] = 8999;
+#if HTTP
+			HttpServerChannel channel = new HttpServerChannel
+(channelProperties, formatterProvider);
+#else
+			TcpServerChannel channel = new TcpServerChannel
+(channelProperties, formatterProvider);
+#endif
+			ChannelServices.RegisterChannel(channel);
+
+			System.Console.WriteLine("Press Enter to stop the 
+program.");
+
+			ThreadPool.QueueUserWorkItem(new WaitCallback
+(StatsPrinter));
+
+			System.Console.ReadLine();
+			running = false;
+		}
+
+		private static void StatsPrinter(object o)
+		{
+			int count = 0;
+			while(running)
+			{
+				DateTime start = DateTime.Now;
+				Thread.Sleep(refresh);
+				int newCount = 
+RemoteObject.GetRequestCount();
+				DateTime stop = DateTime.Now;
+				int diff = newCount - count;
+				TimeSpan timediff = stop - start;
+
+				int reqPerSec = (int) (diff / 
+timediff.TotalSeconds);
+
+				System.Console.WriteLine
+("Request/sec:   " + reqPerSec);
+				System.Console.WriteLine("Request 
+Count: " + newCount);
+				System.Console.WriteLine();
+				count = newCount;
+			}
+		}
+	}
+
+	public class RemoteObject : MarshalByRefObject, IServerInterface
+	{
+		private static int requestCount = 0;
+
+		public RemoteObject()
+		{
+		}
+
+		static public int GetRequestCount()
+		{
+			int result = -1;
+			Interlocked.Exchange(ref result, requestCount);
+
+			return result;
+		}
+
+		public bool ExecuteRequest(object param)
+		{
+			Interlocked.Increment(ref requestCount);
+			return true;
+		}
+	}
+}
+
+
+
+--------------- IServerInterface.cs --------------------------------
+using System;
+
+namespace ServerInterface
+{
+	public interface IServerInterface
+	{
+		bool ExecuteRequest(object param);
+	}
+}
+
+
+[2] Uncomment the #defines at the begining of Client.cs and Server.cs to 
+reflect what you need to test (HTTP/TCP and SOAP/Binary)
+
+[3]Use the following commands to compile the source code:
+
+mcs -out:ServerInterface.dll -target:library IServerInterface.cs
+
+mcs -r:ServerInterface.dll -r:System.Runtime.Remoting.dll -
+out:Server.exe -target:exe Server.cs
+
+mcs -r:ServerInterface.dll -r:System.Runtime.Remoting.dll -
+out:Client.exe -target:exe Client.cs
+
+
+[4] run Server.exe and Client.exe (in this order, with ou without 
+parameters) and watch for the server's output.
+
+
+How often does this happen? 
+Always
+
+Additional Information: