[education/rkward] rkward/rbackend: Significant speed-up to modification detection

Thomas Friedrichsmeier null at kde.org
Thu May 26 10:06:45 BST 2022


Git commit a873b072edc510d0555740bca7cd15719696b8b1 by Thomas Friedrichsmeier.
Committed on 25/05/2022 at 13:40.
Pushed by tfry into branch 'master'.

Significant speed-up to modification detection

M  +22   -14   rkward/rbackend/rkrsupport.cpp
M  +1    -1    rkward/rbackend/rkstructuregetter.cpp

https://invent.kde.org/education/rkward/commit/a873b072edc510d0555740bca7cd15719696b8b1

diff --git a/rkward/rbackend/rkrsupport.cpp b/rkward/rbackend/rkrsupport.cpp
index d13614c5..467685f7 100644
--- a/rkward/rbackend/rkrsupport.cpp
+++ b/rkward/rbackend/rkrsupport.cpp
@@ -326,14 +326,10 @@ RKRShadowEnvironment::Result RKRShadowEnvironment::diffAndUpdate() {
 	RK_TRACE (RBACKEND);
 	Result res;
 
-	SEXP symbols = R_lsInternal(baseenvir, TRUE);
+	// find the changed symbols, and copy them to the shadow environment
+	SEXP symbols = R_lsInternal3(baseenvir, TRUE, FALSE);  // envir, all.names, sorted
 	PROTECT(symbols);
 	int count = Rf_length(symbols);
-	SEXP symbols2 = R_lsInternal(shadowenvir, TRUE);
-	PROTECT(symbols2);
-	int count2 = Rf_length (symbols2);
-
-	// find the changed symbols, and copy them to the shadow environment
 	for (int i = 0; i < count; ++i) {
 		SEXP name = Rf_installChar(STRING_ELT(symbols, i));
 		PROTECT(name);
@@ -341,7 +337,7 @@ RKRShadowEnvironment::Result RKRShadowEnvironment::diffAndUpdate() {
 		SEXP cached = Rf_findVar(name, shadowenvir);
 		if (main != cached) {
 			Rf_defineVar(name, main, shadowenvir);
-			if (/*Rf_isNull(cached) && */ !Rf_isNull(main) && !nameInList(STRING_ELT(symbols, i), symbols2)) {
+			if (cached == R_UnboundValue) {
 				res.added.append(RKRSupport::SEXPToString(name));
 			} else {
 				res.changed.append(RKRSupport::SEXPToString(name));
@@ -349,16 +345,28 @@ RKRShadowEnvironment::Result RKRShadowEnvironment::diffAndUpdate() {
 		}
 		UNPROTECT(1);
 	}
+	UNPROTECT(1); // symbols
 
-	// find the symbols only in the shadow environment (those that were removed)
-	for (int i = 0; i < count2; ++i) {
-		if (!nameInList(STRING_ELT(symbols2, i), symbols)) {
-			res.removed.append(RKRSupport::SEXPToString(Rf_installChar(STRING_ELT(symbols2, i))));
-			R_removeVarFromFrame(Rf_installChar(STRING_ELT(symbols2, i)), shadowenvir);
+	// find the symbols only in the shadow environment (those that were removed in the base)
+	SEXP symbols2 = R_lsInternal3(shadowenvir, TRUE, FALSE);
+	PROTECT(symbols2);
+	int count2 = Rf_length(symbols2);
+	if (count != count2) {  // most of the time, no symbols have been removed, so we can skip the expensive check
+		for (int i = 0; i < count2; ++i) {
+			SEXP name = Rf_installChar(STRING_ELT(symbols2, i));
+			PROTECT(name);
+			// NOTE: R_findVar(), here, is enormously faster than searching the result of ls() for the name, at least when there is a large number of symbols.
+			// Importantly, environments provided hash-based lookup, by default.
+			SEXP main = Rf_findVar(name, baseenvir);
+			if (main == R_UnboundValue) {
+				res.removed.append(RKRSupport::SEXPToString(name));
+				R_removeVarFromFrame(name, shadowenvir);
+				if (++count >= count2) break;
+			}
+			UNPROTECT(1);
 		}
 	}
-
-	UNPROTECT(2); // symbols, symbols2
+	UNPROTECT(1);  // symbols2
 
 	RK_DEBUG(RBACKEND, DL_DEBUG, "added %s\n", qPrintable(res.added.join(", ")));
 	RK_DEBUG(RBACKEND, DL_DEBUG, "changed %s\n", qPrintable(res.changed.join(", ")));
diff --git a/rkward/rbackend/rkstructuregetter.cpp b/rkward/rbackend/rkstructuregetter.cpp
index b096f755..71d5d3db 100644
--- a/rkward/rbackend/rkstructuregetter.cpp
+++ b/rkward/rbackend/rkstructuregetter.cpp
@@ -346,7 +346,7 @@ void RKStructureGetter::getStructureWorker (SEXP val, const QString &name, int a
 		// fetch list of child names
 		SEXP childnames_s;
 		if (do_env) {
-			childnames_s = R_lsInternal (value, (Rboolean) 1);
+			childnames_s = R_lsInternal3(value, TRUE, FALSE);
 		} else if (do_cont) {
 			childnames_s = RKRSupport::callSimpleFun (names_fun, value, baseenv);
 		} else {



More information about the rkward-tracker mailing list