Pavel gave some helpful direction regarding where concurrency might be
especially helpful: graphics conversion.

Attached is a work-in-progress patch, as well as an example file.

When testing with the attached document, remember to clear the cache in
your user directory before opening LyX. For example, I do the following:

  rm -rf ~/.lyx/cache/* && lyx

The modified code is just about LyX's display, not about converters used
for PDF export.

While testing, it works surprisingly smoothly and the improvement is
quite noticeable. I'm surprised that there are no known *observable*
problems I've encountered, although I still consider the patch hackish
at its current state.

The concurrency design of the patch is not good. It was just the most
minimal changes I could make to the current code to get a simple
prototype. I have not worked on thread safety. To do that I need to
study more about the signals mechanism that's being used.

I also need to test problems like what happens if a process exits with
error, what if it hangs, etc.

The reason I send this preliminary patch in is to (1) see if there is at
least preliminary support for this kind of code change; (2) see if
anyone has intuition for whether I am on the right track (i.e., is this
the right place in the code to introduce this functionality?); (3) any
thoughts on how I can stress-test this patch, and future patches?; (4)
what should the default be for number of concurrent processes forked and
what interface could I provide to change the default? e.g., default to
current master behavior and allow for a hidden preference?

Regarding (3), how can I force a bunch of conversions that take a long
time? Maybe a svg that is very small (or scalled down?) but is a large
file size? Currently these conversions are all quick, so quick that the
bars on my 'htop' don't even dance.

Thanks,
Scott
>From 64278aecb9647a04e8591bba1d01df5f18bd2afd Mon Sep 17 00:00:00 2001
From: Scott Kostyshak <skost...@lyx.org>
Date: Fri, 23 Sep 2022 00:28:52 -0400
Subject: [PATCH] Working on concurrent forks

---
 src/support/ForkedCalls.cpp | 45 ++++++++++++++++++++++++-------------
 1 file changed, 30 insertions(+), 15 deletions(-)

diff --git a/src/support/ForkedCalls.cpp b/src/support/ForkedCalls.cpp
index b9462153e0..ec23db026b 100644
--- a/src/support/ForkedCalls.cpp
+++ b/src/support/ForkedCalls.cpp
@@ -20,6 +20,7 @@
 #include "support/lyxlib.h"
 #include "support/os.h"
 #include "support/Timeout.h"
+#include "support/lassert.h"
 
 #include "support/bind.h"
 
@@ -443,6 +444,13 @@ static queue<Process> callQueue_;
 /// flag whether queue is running
 static bool running_ = false;
 
+// change nforks_max = 1 to current master behavior
+static const int nforks_max = 20;
+
+// number of current running threads.
+static int nforks_current = 0;
+
+
 ///
 void startCaller();
 ///
@@ -450,6 +458,7 @@ void stopCaller();
 ///
 void callback(pid_t, int);
 
+// FIXME: adapt this description
 /** Add a process to the queue. Processes are forked sequentially
  *  only one is running at a time.
  *  Connect to the returned signal and you'll be informed when
@@ -468,26 +477,32 @@ ForkedCall::sigPtr add(string const & process)
 
 void callNext()
 {
-	if (callQueue_.empty())
-		return;
-	Process pro = callQueue_.front();
-	callQueue_.pop();
-	// Bind our chain caller
-	pro.second->connect(callback);
-	ForkedCall call;
-	//If we fail to fork the process, then emit the signal
-	//to tell the outside world that it failed.
-	if (call.startScript(pro.first, pro.second) > 0)
-		pro.second->operator()(0,1);
+	while(!callQueue_.empty() && nforks_current <= nforks_max) {
+		lyxerr << "callQueue size: " << callQueue_.size() << std::endl;
+		Process pro = callQueue_.front();
+		callQueue_.pop();
+		// Bind our chain caller
+		pro.second->connect(callback);
+		ForkedCall call;
+		//If we fail to fork the process, then emit the signal
+		//to tell the outside world that it failed.
+		++nforks_current;
+		if (call.startScript(pro.first, pro.second) > 0)
+			pro.second->operator()(0,1);
+	}
+	stopCaller();
 }
 
 
 void callback(pid_t, int)
 {
-	if (callQueue_.empty())
-		stopCaller();
-	else
-		callNext();
+	// FIXME: this code is not threadsafe. Can this function be called
+	//        concurrently? I would imagine yes.
+	//        Does this have to do with the signals and nod thing?
+	//        it seems there is a concurrency policy there (?).
+	--nforks_current;
+	LASSERT(nforks_current >= 0, return );
+	callNext();
 }
 
 
-- 
2.34.1

Attachment: graphics-conversions.lyx
Description: application/lyx

-- 
lyx-devel mailing list
lyx-devel@lists.lyx.org
http://lists.lyx.org/mailman/listinfo/lyx-devel

Reply via email to