Watch, Follow, &
Connect with Us
Public Report
Report From: Delphi-BCB/Database/DataSnap    [ Add a report in this area ]  
Report #:  81333   Status: Closed
DataSnap 2010 filter performance problem
Project:  Delphi Build #:  14.0.3593.25826
Version:    14.0 Submitted By:   Bob Swart
Report Type:  Basic functionality failure Date Reported:  1/20/2010 6:29:50 AM
Severity:    Critical / Show Stopper Last Updated: 3/20/2012 2:24:39 AM
Platform:    All platforms Internal Tracking #:   274718
Resolution: Fixed (Resolution Comments) Resolved in Build: : 15.0.3845.32532
Duplicate of:  None
Voting and Rating
Overall Rating: (3 Total Ratings)
5.00 out of 5
Total Votes: 89
Description
There is a serious problem with the DataSnap 2010 filter performance. When using filters, even do-nothing pass-through filters, the performance can drop by a factor 5-100 (yes, that's up to 100 times as slow as the same request without a filter). The performance gets a little better if you increase the buffer size (at client and server) to a maximum of 1000 KB, but when using an ISAPI DLL, the max buffer size that can be used is 48 KB.

As example I've used the ZLibCompression filter, but you can also use a do-nothing filter with the same results.

I've created a small demo DataSnap application consisting of four applications.

1. DataSnapServer.exe - A DataSnap 2010 VCL Forms server with a main form where you can enable / disable the use of the Compression filter, and set the BufferKBSize (to a choice of 32, 48, 64, 128, 256 or 1000). Communication protocols are both TCP/IP and HTTP.

2. DataSnapISAPIServer.dll - A DataSnap ISAPI Server with no filters

3. DataSnapISAPIServerFilters.dll - A DataSnap ISAPI Server that uses the Compression Filter

4. DataSnapClient.exe - a DataSnap 2010 client application that can connect to the DataSnap VCL Forms server using TCP (port 211) or HTTP (port 8042), or to either of the DataSnap ISAPI servers. You can also set the Data Size (by default 1024 KB, but you can go from a minimum of 1 KB to any size you want), plus you can configure the BufferSize (same choices as the VCL Forms server - for the ISAPI DLLs you should stick to 48 KB as maximum, otherwise you'll get an error from the ISAPI server).

Feel free to test the client and the server. When they both reside on the same machine, there is no performance problem. However, as soon as the client is moved to another (similar!!) machine, the performance problem will show itself. When the Compression Filter is enabled at the VCL Forms DataSnap server, or the ISAPI Server with Filters is used, then the response times increases with a factor 5-100.

The trouble is that both the client and server machine appear to be doing "nothing". The CPU load remains low, and the application itself doesn't come above 5% CPU usage, so it cannot be a problem with the processing or filter itself. Especially if you consider that using the filter on the same machine (client and server on same machine) shows no performance loss. The network usage is also very low, so it's not "waiting for data" either, although I suspect that the underlying problem is somewhere connected to an Indy client waiting for filter data to come in? (remember that it also fails for an ISAPI DataSnap server).

I've spent almost a week trying to figure out where the bottle-neck is, and I just give up and have to report it here. Hope someone can shine a light on this, as this problem renders the use of filters almost impossible unless you stick to very small data packages (but even then the performance hit is noticable, and relatively worse of all).

Delphi 2010, Update 4+5 applied. Using Windows XP, 2003 and 7, but the same problem bas been reproduced by others using Delphi 2010 as well.
Steps to Reproduce:
Create DataSnap 2010 Server, use any filter and connect a DataSnap 2010 client to it. Compare the response time to a server with the use of a filter.

See the attached project for a ready-to-use example of three DataSnap servers and a client.
Workarounds
Do not use DataSnap 2010 filters. Or use very small data packages (so you won't notice the performance hit).
Attachment
81333.zip
Comments

Tomohiro Takahashi at 1/20/2010 9:10:09 PM -
I guess that passing TBytes instance and return another TBytes instance are time consuming work.
>TTransportCompressionFilter = class(TTransportFilter)
> ...
>  function ProcessInput(const Data: TBytes): TBytes; override;
>  function ProcessOutput(const Data: TBytes): TBytes; override;

The paramters should be passed as 'var' ?

Bob Swart at 1/20/2010 11:34:53 PM -
If this was time consuming, then the performance hit would also show up if you run the client and server ON THE SAME MACHINE. But it doesn't.

The performance hit also happens if you have a do-nothing filter.

The performance problem only shows when the client and server are on different machines. And while the data is transferred, neither the client nor the server show heavy CPU usage. So passing TBytes is IMHO *not* what's going on.

Tomohiro Takahashi at 1/21/2010 12:08:59 AM -
I also will try to find root cause of the bottle neck...

P.S.
Although I don't know whether this behavior is related to the bottle neck..., basically, if we use HTTP transport to connect to ISAPI server, client call the server multiple times per one server method invocation to ensure session via Tunneling URL. You can see the round trips with packet sniffer or TCP/IP monitor.
Thanks.

Bob Swart at 1/21/2010 1:35:53 PM -
HTTP is indeed slower than TCP/IP, but even if connecting to a VCL Forms Server using TCP/IP, the performance hit can be seen (when using filters vs. when not using filters)...

Francisco J Ruiz Nuñez at 1/21/2010 3:13:16 AM -
I think the problem is not in the filter itself. It is directly in datasnap.

I just make one another test (without any filter) :
Storedproc Client to SQL Server thru DBXpress : 4 seconds.
Client to Datasnap Server in the same machine : 9 seconds.
Client to Datasnap Server in different machines : 97 seconds.

Datasnap tests are all without filter. Calling 1000 times to a storedprocedure on a SQL Server. Because of this, the problem is not in the filters. It's in the Datasnap server.

Bob Swart at 1/21/2010 10:45:49 PM -
Connecting without filters - to different machines - does not result in the big performance hit. Please try my example projects and connect to www.bobswart.nl for example, which will demonstrate that connecting to the ISAPI Server over HTTP without filters is fast, but with filters is slow.

Francisco J Ruiz Nuñez at 1/21/2010 3:19:25 AM -
Sorry, this is not correct:

Client to Datasnap Server in different machines : 97 seconds.

The real one is this:

Client to Datasnap Server in different machines : 197 seconds.

Luigi Sandon at 1/21/2010 6:47:02 AM -
You can edit your own posts

Tomohiro Takahashi at 1/27/2010 8:49:43 PM -
In my test cases,
-----------------
Case#1
- remote HTTP DataSnap Server executable with no filter
- remote HTTP DataSnap Client with no filter
- server method is sample EchoString using large string parameter
- buffer size is not configured
Result#1
- it takes about 530ms per method call
-----------------
-----------------
Case#2
- remote HTTP DataSnap Server executable with ZLibCompressionFilter
- remote HTTP DataSnap Client with no filter with ZLibCompressionFilter
- server method is sample EchoString using large string parameter
- buffer size is not configured
Result#1
- it takes about 2100ms per method call
-----------------

If I profile them with 'LTProf v1.5', it reports that almost all of time are consumed in TIdSocketListWindows.FDSelect when reading response data. However, I can NOT find any bottle neck around Filter processing...

Michiel Spoor at 1/29/2010 5:49:37 AM -
The processing of the filter(s) itself is not the problem i.m.h.o, because:

A. - there is no delay when server en client are on the same machine
B. - adding more filters doesn't give a bigger performance hit

It also had little to do with the HTTP layers, because we use the TDSTCPServerTransport and it also suffers from the performance degradation.

My guess would be that there is something different in the way DataSnap handles or packages the data to the network layer, depending on whether there are filters or not (regardless of what filter, because even an empty filter which does nothing causes the performance hit).

All in all this is a major problem for us, and renders the use of filters totally useless. By the way, we -do- use the generated classes.

Francisco J Ruiz Nuñez at 1/28/2010 3:08:40 AM -
Hi Tomohiro,

Thank you for your test. I just found the degradation in performance becames because I was not using the "prepare" before call the servermethod or using generated client classes which call the prepare method before execute it.

Thank you very much. Now this works really really fast.

Server Response from: ETNACODE01