The loop in outputfilter can be simplified quite a bit

All the extra handling of the asyncprocess can be reduced to the following lines (the event handlers can be removed):

       if fProcess is TAsyncProcess then begin
         Count:=TAsyncProcess(fProcess).NumBytesAvailable;
         if Count > 0 then
           Count:=fProcess.Output.Read(Buf[1], Min(Count, length(Buf)));
       end
       else
         // using a blocking TProcess
         Count:=fProcess.Output.Read(Buf[1], length(Buf));
       if (Count=0) and (not fProcess.Running) then
         break
       else if count = 0 then
         sleep(30);

Works on windows / shouldn't change anything on *nix


Martin wrote:
Vincent Snijders wrote:
I have looked a bit more why outputfilter is so slow at parsing a lot of compiler output (e.g. compiling a simple LCL app with -va). The pipe buffer is rather small, NumBytesAvailable is not bigger than 1280 bytes. So OnAsyncReadData reads only 1280 bytes at a time. OnAsyncReadData is only called after an application.handlemessage. So on line 319 of outputfilter.pas, the buffer is most times empty, but NumBytesAvailable = 1280, and we are sleeping until Application.HandleMessage is called.

I had some success with the following patch. It does a sleep(0) to give the compiler the chance to write to the pipe again and tries to read it again.
--- ide/outputfilter.pas
+++ ide/outputfilter.pas
@@ -1206,9 +1206,12 @@ var
   Count: LongWord;
 begin
   if fProcess=nil then exit;
-  Count:=TAsyncProcess(fProcess).NumBytesAvailable;
-  if Count>0 then
-    FAsyncOutput.Push(TStream(TAsyncProcess(fProcess).Output),Count);
+  repeat
+    Count:=TAsyncProcess(fProcess).NumBytesAvailable;
+    if Count>0 then
+      FAsyncOutput.Push(TStream(TAsyncProcess(fProcess).Output),Count);
+    sleep(0);
+  until Count=0;
 end;

function TOutputFilter.CreateScanners(ScannerOptions: TStrings): boolean;
If I understand it correctly the problem is that TAsyncProcess, currently only reads data, when the event is triggered, which is in a ProcessMessages. Ouch.

Either TAsyncProcess.OnReadData is transferred into the main loop, in a similar way as for the normal TProcess. I have not tested this, but it should work, as NumBytesAvailable seems to be none blocking. => This could simplify the overall loop as the handling of the 2 projects would be more or less the same.

Alternatively, before we sleep(3), we could check for data, and process it.
       end else begin
         // no new input, but process still running
         if TheAsyncProcess.NumBytesAvailable > 0 then
           Application.ProcessMessages
         else
           Sleep(30);
       end;



--
_______________________________________________
Lazarus mailing list
[email protected]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus


--
_______________________________________________
Lazarus mailing list
[email protected]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

Reply via email to