You are not logged in.
Pages: 1
Hi Arnaud,
I wanted to follow up and share that, after extensive testing with the new TCrtSocket.RetryCount property, the results have been sensational. The implementation works exactly as expected, providing a clean and robust way to handle flow control without the overhead of a full async stack.
It is impressive how such a surgically precise addition to the framework can solve complex non-blocking challenges for cases like mine. I truly appreciate your responsiveness and the technical elegance you bring to mORMot 2.
Thank you again for the stellar support. This topic is now perfectly resolved on my end.
Best regards,
ec
Hi Arnaud,
Thank you for the quick and insightful feedback.
That makes perfect sense. My use case doesn't involve thousands of simultaneous clients, so the mormot.net.async complexity would indeed be overkill.
The new TCrtSocket.RetryCount property is exactly what I needed to safely check for nrRetry / WSAEWOULDBLOCK without overhead. I have already updated my local mORMot 2 files to include your latest commit and I am adjusting my send logic to use it.
I appreciate you taking the time to add this property to the framework. It makes the flow control much cleaner for my implementation.
Thanks for the detailed explanation. It makes perfect sense.
Since I am already working with an event-driven model, I will follow your advice and switch to non-blocking mode. This will allow me to properly handle flow control on the application side without stalling the execution thread when the OS buffers or TCP window are full.
Instead of trying to predict the buffer occupancy, I'll rely on the write readiness events and handle WSAEWOULDBLOCK (or equivalent) by queuing the remaining data in user-space.
Regarding the 'wait counter' in SendFrame/TrySndBuf, don't worry about it for now. Moving to a true non-blocking flow is a cleaner architectural solution for my current needs.
Thank you for the clarification. You are right; I am using TWebCrtSocketProcess.SendFrame() on the client side, and I now understand that it blocks once the OS TCP buffer is full.
Measuring the execution time with QueryPerformanceMicroSeconds() is a good suggestion for a reactive approach. However, to avoid the 'blocking' state altogether and keep the UI or other tasks fluid, would it be feasible to check the socket's write readiness before calling SendFrame()?
On the client side, could we use something like fSocket.WaitFor(1, [neWrite]) to see if the kernel is ready to accept more data without blocking?
If fSocket (TCrtSocket) could expose a way to check if send() would block, we could implement the same threshold-based logic we now have on the server, but based on 'Socket Readiness' instead of 'Pending Bytes'.
What do you think about this 'proactive' check for the client-side TCrtSocket?
Hi Arnaud,
I've been stress-testing the PendingWrite implementation on the server side, and it is a game-changer for stability. It allows a very graceful flow control for our DICOM streaming.
However, I've hit a 'mirror' issue on the Client Side (Delphi Client injecting frames to Server). When the client producer is faster than the uplink, we lack the same visibility. Without a way to check the client's outbound buffer, the application eventually blocks or consumes RAM unpredictably, and using fixed Sleep() calls is suboptimal for performance.
Since TRawSocket and the async engine already handle these buffers, would it be possible to expose PendingWrite (or an equivalent 'low-level' bytes-pending metric) for the Client classes as well?
Having this symmetry between Client and Server would allow us to implement a unified backpressure strategy across the entire mORMot 2 ecosystem.
What are your thoughts on making this metric available for THttpClientWebSockets or its underlying socket layer?
Hi Arnaud,
Thank you very much for the quick fix!
This change is very helpful for monitoring connection health and latency in our infrastructure. I've already tested it and it works perfectly.
Hi Arnaud and community,
I'm working on a mission-critical infrastructure using mORMot 2 asynchronous WebSockets and I've encountered a limitation regarding connection health monitoring.
Looking at TWebSocketProcess.ProcessLoopReceived in mormot.net.ws.core.pas, I noticed that fOnBeforeIncomingFrame (and consequently OnBeforeIncomingFrame) is only triggered for focText and focBinary opcodes:
case request.opcode of
focPing:
begin
request.opcode := focPong;
SendFrame(request);
end;
focPong:
; // nothing to do
focText,
focBinary:
if Assigned(fProtocol) then
if (not Assigned(fProtocol.fOnBeforeIncomingFrame)) or
(not fProtocol.fOnBeforeIncomingFrame(self, request)) then
fProtocol.ProcessIncomingFrame(self, request, '');
Was it intentional to exclude control frames (focPing / focPong) from the interceptor?
In high-availability systems, we need to monitor real-time health and latency without injecting application-level heartbeats (to keep the protocol clean). If focPing and focPong were passed to OnBeforeIncomingFrame, we could intercept them for auditing and metrics before the framework handles the automatic response.
Would you consider moving the fOnBeforeIncomingFrame check to the beginning of the ProcessLoopReceived procedure, or at least including these opcodes in the dispatcher?
Something like:
procedure TWebSocketProcess.ProcessLoopReceived(var request: TWebSocketFrame);
begin
if Assigned(fProtocol.fOnBeforeIncomingFrame) then
if fProtocol.fOnBeforeIncomingFrame(self, request) then
exit; // Allow manual override or sniffing
case request.opcode of
// ... rest of the logic
Thank you for this amazing framework!
Hi Arnaud,
Thank you again for the PendingWrite implementation in the async server; it works perfectly for managing backpressure on the server side.
Following that logic, I am now tuning the Client Side (high-throughput frame injection). I noticed that when a client sends a massive amount of data in a loop, it can still hit a "blocking" state or saturate the local kernel buffers if the producer is faster than the network, sometimes leading to local freezing if not handled with manual Sleep() calls.
Is there (or could there be) a similar way to monitor the outbound buffer state on the Client classes (e.g., TWebSocketClient or the underlying TRawSocket)?
Having a Client.PendingWrite (or a way to check if the outgoing TCP window is full) would allow us to implement the same "threshold-based pause" on the client, ensuring a graceful flow control without relying on arbitrary Sleep() intervals.
What do you think about exposing this metrics-gathering for client-side sockets as well?
Best regards,
ec
Hi Arnaud,
Thank you very much for the prompt update! The PendingWrite property is exactly what I needed to implement a smarter flow control.
Regarding your question on how to pause the flow: my plan is to use a threshold-based approach.
Since I am streaming frames (like video or large DICOM datasets), I can now check PendingWrite before injecting the next chunk into the async server. If PendingWrite exceeds a predefined safety limit (e.g., 2MB), I will pause the frame producer (the source) and wait for the buffer to drain below a certain 'low-water mark' before resuming.
This way, I can leverage mORMot's high-performance async architecture without overwhelming the server's RAM when the network throughput is slower than the data production rate.
I really appreciate the support and the commitment to mORMot 2!
Hi Arnaud,
Thank you for the insights.
Actually, dropping frames or flushing the buffers is exactly what I would like to avoid. My goal is to ensure data integrity without losing any frames, even when the RAM reaches a critical point.
Instead of discarding data, I am looking for a way to implement proper backpressure within the mORMot 2 async server architecture. My intention is to have the server 'wait' or slow down the injection of new frames until the current buffers are successfully transmitted and acknowledged at the TCP/Websocket layer.
Is there a recommended way in mORMot 2 to monitor the state of the async output buffers or the underlying socket readiness, so I can pause the data flow instead of saturating the RAM or being forced to flush pending data?
Hi Arnaud,
I am currently leveraging the excellent TWebSocketAsyncServer in mORMot 2 for a high-throughput application involving massive broadcasting from server to clients.
While implementing the asynchronous transmission, I noticed that under heavy network congestion or with slow clients, the outbound data can accumulate significantly. To ensure server stability and avoid excessive memory consumption (or potential contention during WaitLock), I am looking for the "mORMot-way" of detecting the optimal moment to push more data into the websocket.
Specifically:
Is monitoring TPollAsyncConnection.fWr.Len the recommended approach to implement a backpressure mechanism, or is there a higher-level event/callback in the TWebSocketAsyncProcess that I should use to detect when the outgoing buffer has reached a safe threshold?
In the context of THttpAsyncServer, would you recommend manually dropping frames when the outbound buffer exceeds a certain limit, or is there a built-in gathering strategy (like SendDelay) that I should tune to handle thousands of concurrent massive sends more gracefully?
I want to avoid any "freezing" effects caused by RAM saturation or lock contention when the kernel's TCP buffers are full.
Thank you for your tireless work on this amazing framework.
Best regards
It seems more stable to me.
In Firefox, it works perfectly. The browser displays the warning: MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT, as expected.
In other browsers, the exception occurs: "Project ecentric.exe raised exception class ESChannel with message '<>: HandshakeStep returned 80090327 [SEC_E_CERT_UNKNOWN], System Error 87 [ERROR_INVALID_PARAMETER]'.". The browser displays the warning: NET::ERR_CERT_AUTHORITY_INVALID. However, now it is possible to ignore this type of exception, and the execution continues normally.
Thank you!
What browser are you using? I recently noticed a similar situation in browsers other than Firefox.
In case anyone is interested, InitNetTlsContextSelfSignedServer works in Firefox too, with the pre-computed certificate.
Ab, I apologize for the language barrier, and I thank you in advance for your attention.
I was able to identify the issue that caused confusion here. The conclusion is that when SChannel is used, the certificate generated by the call to InitNetTlsContextSelfSignedServer(FTls, Algo, {UsePreComputed=}TRUE) only works with mormot2, or curl, and is not valid and/or compatible with current browsers. However, when a .pfx certificate is used, and not the precomputed one, it works normally.
But, I think ignoring this exception may not be a good idea, things may not work correctly
Ab, check this out:
I ran an additional step with openssl, as documented in TSChannelNetTls.AfterBind:
openssl pkcs12 -inkey private.key -in certificate.crt -export -out certificate.pfx
Using ...
InitNetTlsContext(FTls, True, 'C:\Devel\eCentric-11\certificate\certificate.pfx', 'C:\Devel\eCentric-11\certificate\private.key');
Or ...
FWsServer.WaitStarted(10, 'C:\Devel\eCentric-11\certificate\certificate.pfx', 'C:\Devel\eCentric-11\certificate\private.key');
And, ignoring the server-side exception...
It worked again!!!
The browser displays the usual warning:
Your connection is not private Attackers might be trying to steal your information from 192.168.0.128 (for example, passwords, messages, or credit cards). Learn more about this warning net::ERR_CERT_AUTHORITY_INVALID Turn on enhanced protection to get Chrome's highest level of security This server could not prove that it is 192.168.0.128; its security certificate is not trusted by your computer's operating system. This may be caused by a misconfiguration or an attacker intercepting your connection.
Proceed to 192.168.0.128 (unsafe).
And the websocket client (wss) also works.
The certificate has been deleted from Windows!!!
Working with or without openssl
Ab, in my understanding it doesn't work when we use InitNetTlsContextSelfSignedServer(FTls, Algo).
What do you think ?
Ab, I did this (with and without openssl):
1. openssl genrsa -out private.key 2048
2. openssl req -new -key private.key -out request.csr
3. openssl x509 -req -days 365 -in request .csr -signkey private.key -out certificate.crt
4. I installed the certificate on Windows
When I use one of the ways:
...
FWsServer.WaitStarted(10, 'C:\Devel\eCentric-11\certificate\certificate.crt' , 'C:\Devel\eCentric-11\certificate\private.key');
Or
...
InitNetTlsContext(FTls, {server=}True, 'C:\Devel\eCentric-11\certificate\certificate.crt', 'C:\Devel\eCentric-11\certificate\private.key');
FWsServer .WaitStarted(10, @FTls);
Now the following exception is occurring:
Project ecentric.exe raised exception class ESChannel with message '<>: PFXImportCertStoreSEC_E_CERT_UNKNOWN returned 80090327 [SEC_E_CERT_UNKNOWN], System Error -2146885630 [Error during encryption operation or decoding]'.
Ok, I'll test as suggested.
I tried using openssl but I'm getting the following error:
[dcc64 Error] mormot.crypt.openssl.pas(879): E2250 There is no overloaded version of 'AlgoName' that can be called with these arguments
[dcc64 Error] mormot.crypt .openssl.pas(966): E2250 There is no overloaded version of 'AlgoName' that can be called with these arguments
[dcc64 Fatal Error] mor.wss.acceptor.pas(918): F2063 Could not compile used unit 'mormot. crypt.openssl.pas' Failed
PS C:\Windows\system32> [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls13
PS C:\Windows\system32> Invoke-WebRequest -Uri https://192.168.0.128:7799
Invoke-WebRequest : The underlying connection was closed: Could not establish trust relationship for the
SSL/TLS secure channel. At line:1 character:1 + Invoke-WebRequest -Uri https://192.168.0.128:7799 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo: InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebExc eption + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
Ab, I also tested it this way, and the exception continues to occur on the server side, in any version of TLS
PS C:\Windows\system32> [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls11
PS C:\Windows\system32> Invoke-WebRequest -Uri https://192.168.0.128:7799
PS C:\Windows\system32> [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
PS C:\Windows\system32> Invoke-WebRequest -Uri https://192.168.0.128:7799
PS C:\Windows\system32> [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls13
PS C:\Windows\system32> Invoke-WebRequest -Uri https://192.168.0.128:7799
I'm using Windows 11 on the server side. Until a few days ago, this exception was not occurring. Now the browser's websocket client causes this exception on the server!
Ab, with curl, there is no exception at server side:
C:\Tools\curl\bin>curl -v -k "https://192.168.0.128:7799"
* Trying 192.168.0.128:7799...
* Connected to 192.168.0.128 (192.168.0.128) port 7799
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Unknown (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / [blank] / UNDEF
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
* subject: CN=127.0.0.1
* start date: Jul 6 20:15:22 2022 GMT
* expire date: Jul 3 20:15:22 2032 GMT
* issuer: CN=127.0.0.1
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
* Certificate level 0: Public key type ? (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* using HTTP/1.x
> GET / HTTP/1.1
> Host: 192.168.0.128:7799
> User-Agent: curl/8.6.0
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Server: ecentric.I11
< Content-Length: 0
<
* Connection #0 to host 192.168.0.128 left intact
Sorry for the inconvenience, ab. The code snippet was just intended to illustrate how I was doing it on both sides (client and server). The exception that is appearing on the server side is:
Project ecentric.exe raised exception class ESChannel with message '<>: HandshakeStep returned 80090326 [SEC_E_ILLEGAL_MESSAGE], System Error 87 [ERROR_INVALID_PARAMETER]'.
The error at the browser side is:
ERR_SSL_KEY_USAGE_INCOMPATIBLE
Hi Ab,
I'm using InitNetTlsContextSelfSignedServer. It was working perfectly since my first tests. Now, it only works in mormot2 connections (wss client, for example) to mormot2 (wss server, for example), and the following exception occurs when connected via browser (https, or wss):
:00007FFFD9D0FABC ; C:\Windows\System32\KERNELBASE.dll
System._RaiseAtExcept(???,???)
System._RaiseExcept(???)
mormot.net.sock.TSChannelNetTls.ESChannelRaiseLastError('''¼'#0#0#0#0#0'&'#3#9'€'#0#0#0#0#0#0#0#0#3#0#0#0'xy’'#7#0#0#0#0#$1C#1#1#0'&'#3#9'€ày’'#7#0#0#0#0'¨&¼'#0#0#0#0#0'€¼Á'#4#0#0#0#0'Õ''¼'#0#0#0#0#0'&'#3#9'€'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'P'#$B'¼'#0#0#0#0#0'ðD»'#4#0#0#0#0#8'ÿ’'#7#0#0#0#0'Àz’'#7#0#0#0#0#0#0#0#0#0#0#0#0'<'#4#0#0#0#0#0#0'ðD»'#4'8J'#0#0'PNî'#6#0#0#0#0#0#0#0#0'&'#3#9'€`z’'#7#0#0#0#0' !¼'#0#0#0#0#0'€¼Á'#4#0#0#0#0'Â!¼'#0#0#0#0#0#0#0#0#0#0#0#0#0'P"ñ'#6#0#0,2148074278)
mormot.net.sock.TSChannelNetTls.CheckSEC_E_OK('''¼'#0#0#0#0#0'&'#3#9'€'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'P'#$B'¼'#0#0#0#0#0'ðD»'#4#0#0#0#0#8'ÿ’'#7#0#0#0#0'Àz’'#7#0#0#0#0#0#0#0#0#0#0#0#0'<'#4#0#0#0#0#0#0'ðD»'#4'8J'#0#0'PNî'#6#0#0#0#0#0#0#0#0'&'#3#9'€`z’'#7#0#0#0#0' !¼'#0#0#0#0#0'€¼Á'#4#0#0#0#0'Â!¼'#0#0#0#0#0#0#0#0#0#0#0#0#0'P"ñ'#6#0#0#0#0'Àz’'#7#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'°¼Á'#4#0#0#0#0#0#0#0#0#0#0#0#0#$90'¿'#$12#1#0#0#0#0'Àz’'#7#0#0#0#0#0#0#0#0#0#0,-2146893018)
mormot.net.sock.TSChannelNetTls.HandshakeLoop
mormot.net.sock.TSChannelNetTls.AfterAccept($43C,(True, True, True, True, False, False, False, '', nil, '', ),???,nil {''})
mormot.net.async.TAsyncServer.OnFirstReadDoTls($4B93F30)
mormot.net.async.TPollAsyncConnection.OnFirstRead($4BDBFB0)
mormot.net.async.TPollAsyncSockets.ProcessRead($4C66CD0,1152921504686096176)
mormot.net.async.TAsyncConnectionsThread.Execute
System.Classes.ThreadProc($4C66CD0)
System.ThreadWrapper($4BB44E0)
:00007FFFDADE257D ; C:\Windows\System32\KERNEL32.DLL
:00007FFFDC82AF28 ; ntdll.dll
...
InitNetTlsContextSelfSignedServer(FTls, caaRS256);
FTls.IgnoreCertificateErrors := True;
...
FWsServer :=
TWebSocketAsyncServer.Create(
Target, Nil, Nil, 'Acceptor', FOuAccepts, 30000, [
hsoNoStats, hsoEnableTls,
hsoNoXPoweredHeader,
hsoHeadersInterning,
hsoCreateSuspended,
hsoThreadSmooting ]);
...
FWsServer.Start;
FWsServer.WaitStarted(10, @FTls);
...
Hi,
Browsers return ERR_SSL_KEY_USAGE_INCOMPATIBLE when accessing any resource with a self-signed certificate, on Windows, for example:
https://192.168.0.128:7799
What is wrong ?
I understood. Perfect ! The implementation, as it stands, already meets the needs. In the production environment, we will have thousands of concurrent connections, and, in addition to Linux, with several clients using the Windows server. This is why the synchronous version does not suit us.
Once again, thank you very much for your attention
Hi Arnaud !
I understood.
Anyway, I noticed that with a small increase in the number of test connections, the increase in connection time is also happening with openssl, only on the server side! But, despite the increase in connection time, the server continues to work, and new connections are established normally.
Thank you very much for your attention
Good morning Arnaud !
When I define USE_OPENSSL in the project it works normally.
Hi Arnaud !
I'm not sure if this is the same problem observed by @maro.
Tested only with Default SSPI Windows API (Windows 10 and 11). I'm sure this only occurs on the server side.
Reproducing what I observed is very simple.
1) I created a websocket listener:
FWsServer :=
TWebSocketAsyncServer.Create('0.0.0.0:7799', Nil, Nil, 'Acceptor', 32, 30000, [
hsoNoXPoweredHeader, hsoHeadersInterning, hsoThreadSmooting,
hsoNoStats, hsoBan40xIP, hsoEnableTls ]);
...
2) The reproduction of what I observed can be done as follows:
In Google Chrome, using two instances of the "Simple Websocket Client" extension,
pointing to: "wss://192.168.0.109:7799/Test", it is observed that the connection of the first instance occurs normally.
Connecting and disconnecting, with a single instance, occurs quickly.
With the first instance connected, the second instance's connection behaves differently, the time to connect increases,
and, after several repetitions, the server stops responding.
It only occurs when I'm using TLS.
I hope I have contributed in some way.
Thank you very much for your attention.
Good morning Arnaud !
What do you think could be happening ?
Thank you for your attention
Good morning !
The following situation was also observed: Quickly connecting and disconnecting a single websocket client, everything works well, it is possible to connect and disconnect quickly and efficiently. From the second websocket client onwards, the behavior of new connections changes. Thereafter, there is an unusual delay in all new connections, until, finally, the new connections are rejected. In the test carried out there is no data traffic, only websocket connection and disconnection.
** This does not happen without TLS !!!
I hope I contributed in some way
Good morning !
What excellent news, Ab. Our team thanks you immensely for all your attention and effort.
Okay Ab.
I got better results as follows:
fEvent.ResetEvent;
fWaitForReadPending := true; // should be set before wakeup
if new <> 0 then
fOwner.ThreadPollingWakeup(new)
else
{ ec...
} begin
new := fOwner.fClients.fRead.PollForPendingEvents(ms);
If new = 0 Then Begin
TThread.Sleep(1);
Continue;
End;
fOwner.ThreadPollingWakeup(new);
end;
Or simply ...
atpReadPoll:
// main thread will just fill pending events from socket polls
// (no process because a faulty service would delay all reading)
begin
fWaitForReadPending := false;
{ new := fOwner.fClients.fRead.PollForPendingEvents(ms);
} new := fOwner.fClients.fRead.PollForPendingEvents(ms + 1100); // << it works too
I hope it helps !
Thank you very much for your attention.
Testing like this now
...
atpReadPoll:
// main thread will just fill pending events from socket polls
// (no process because a faulty service would delay all reading)
...
if new <> 0 then
fOwner.ThreadPollingWakeup(new)
else
begin
new := fOwner.fClients.fRead.PollForPendingEvents(ms);
If new = 0 Then Begin
TThread.Sleep(1); // Without this things don't work, anyway
Continue;
End;
end;
...
It didn't stabilize! It stopped working, with the same symptoms as before, after an hour of testing
Good morning !
With this change, a single connection causes high CPU consumption!
It appears to be working normally again with the following:
...
fWaitForReadPending := true; // should be set before wakeup
if new <> 0 then
fOwner.ThreadPollingWakeup(new)
Else Begin
fEvent.WaitFor(1); // ec **
Continue;
End;
...
Goodnight !
Ab, me, again. On the same subject!
...
procedure TAsyncConnectionsThread.Execute;
...
{$ifdef OSWINDOWS}
{ start := -1; // ensure never SleepHiRes(0)
} start := 1; // ec
{$else}
start := 0; // best reactivity
{$endif OSWINDOWS}
...
After two hours of testing (30 clients), with the start value = -1, the following situation occurs:
-One of the connections stops working. The other 29 are still working;
-No new connections to the server are possible;
-CPU consumption goes up to 50% or more.
Changing the value of start to 1, and adding another 70 clients, no problem occurs and, strangely, one has the impression of better performance and stability!
What do you think ?
Good morning !
If so, it's much more efficient! Correct me if I'm wrong: -1 = INFINITE, which is the same as mormot.core.os.windows.inc.WaitFor(INFINITE), in the given snippet. Tested with thousands of operations.
Working perfectly, with minimal CPU consumption!!!
Thank you very much for your attention.
Good afternoon !
About the high CPU consumption, I tested it a little while ago and apparently it works correctly. See if that makes any sense to you...
Excessive context switching of threads is causing high CPU consumption.
At mormot.cor.windows.inc we have:
...
procedure SleepHiRes(ms: cardinal);
begin
if ms <> 0 then
Windows.Sleep(ms) // follow the HW timer: typically up to 16ms on Windows
else
SwitchToThread; // <-- Executed millions of times per minute
end;
...
At mormot.net.async.pas
...
procedure TAsyncConnectionsThread.Execute;
...
atpReadPoll:
// main thread will just fill pending events from socket polls
// (no process because a faulty service would delay all reading)
begin
{ start := 0;
} start := 1; // < -- My Test is this. It is the same as SleepHiRes(1)
while not Terminated do
...
Disregarding possible side effects, it works !!!
What do you think ?
Adding hsoThreadSmooting option, with a thread pool of 16, receiving 4 frames of 50 bytes, per second, without any processing, consumption drops to 6%.
I understood. Anyway, thank you immensely for your attention. I will provide the logs as soon as possible.
Yes. I even just tested with the new stable version released today
Thanks for the quick feedback.
Well, the question is exactly this. When using a ServerThreadPoolCount > 1 (4, 8, or the default 32) CPU consumption increases substantially, up to 20%, for no processing no Delphi 11.3
Good morning !
Considering the code ...
...
FServer := TWebSocketAsyncServer.Create('[::1]:12345', Nil, Nil, 'Acceptor', 2, 30000, []);
...
For every ServerThreadPoolCount > 1, when frames of any size are received at a rate of, say, two per second, CPU consumption increases substantially. There is no processing after receiving the frames. This does not happen when ServerThreadPoolCount = 1 !
This is normal ?
Pages: 1