[rkward/work/faster_watch] rkward/rbackend: Make object modification detection faster (step 1).

Thomas Friedrichsmeier null at kde.org
Sat Apr 7 19:58:30 UTC 2018


Git commit 92d979a868706ac5b17226a5a939c96559fce09e by Thomas Friedrichsmeier.
Committed on 07/04/2018 at 19:57.
Pushed by tfry into branch 'work/faster_watch'.

Make object modification detection faster (step 1).

This first step avoids get and assign calls. Results in ~30% less time taken on a simple testcase:
  system.time(for (i in 1:100000) x <- i)
(with x and i being watched symbols).

TODO: Adjust code for "unwatching".
Next step will be to avoid the .Call().

CCBUG: 380580

M  +5    -4    rkward/rbackend/rkrbackend.cpp
M  +4    -6    rkward/rbackend/rpackages/rkward/R/internal.R

https://commits.kde.org/rkward/92d979a868706ac5b17226a5a939c96559fce09e

diff --git a/rkward/rbackend/rkrbackend.cpp b/rkward/rbackend/rkrbackend.cpp
index 548d8d1f..d09ba41a 100644
--- a/rkward/rbackend/rkrbackend.cpp
+++ b/rkward/rbackend/rkrbackend.cpp
@@ -957,13 +957,14 @@ SEXP doGetGlobalEnvStructure (SEXP name, SEXP envlevel, SEXP namespacename) {
 }
 
 /** copy a symbol without touching it (esp. not forcing any promises) */
-SEXP doCopyNoEval (SEXP name, SEXP fromenv, SEXP toenv) {
+SEXP doCopyNoEval (SEXP fromname, SEXP fromenv, SEXP toname, SEXP toenv) {
 	RK_TRACE (RBACKEND);
 
-	if(!Rf_isString (name) || Rf_length (name) != 1) Rf_error ("name is not a single string");
+	if(!Rf_isString (fromname) || Rf_length (fromname) != 1) Rf_error ("fromname is not a single string");
+	if(!Rf_isString (toname) || Rf_length (toname) != 1) Rf_error ("toname is not a single string");
 	if(!Rf_isEnvironment (fromenv)) Rf_error ("fromenv is not an environment");
 	if(!Rf_isEnvironment (toenv)) Rf_error ("toenv is not an environment");
-	Rf_defineVar (Rf_install (CHAR (STRING_ELT (name, 0))), Rf_findVar (Rf_install (CHAR (STRING_ELT (name, 0))), fromenv), toenv);
+	Rf_defineVar (Rf_install (CHAR (STRING_ELT (toname, 0))), Rf_findVar (Rf_install (CHAR (STRING_ELT (fromname, 0))), fromenv), toenv);
 	return (R_NilValue);
 }
 
@@ -1048,7 +1049,7 @@ bool RKRBackend::startR () {
 		{ "rk.do.generic.request", (DL_FUNC) &doPlainGenericRequest, 2 },
 		{ "rk.get.structure", (DL_FUNC) &doGetStructure, 4 },
 		{ "rk.get.structure.global", (DL_FUNC) &doGetGlobalEnvStructure, 3 },
-		{ "rk.copy.no.eval", (DL_FUNC) &doCopyNoEval, 3 },
+		{ "rk.copy.no.eval", (DL_FUNC) &doCopyNoEval, 4 },
 		{ "rk.edit.files", (DL_FUNC) &doEditFiles, 4 },
 		{ "rk.show.files", (DL_FUNC) &doShowFiles, 5 },
 		{ "rk.dialog", (DL_FUNC) &doDialog, 6 },
diff --git a/rkward/rbackend/rpackages/rkward/R/internal.R b/rkward/rbackend/rpackages/rkward/R/internal.R
index 82ce60a3..625e1d2c 100644
--- a/rkward/rbackend/rpackages/rkward/R/internal.R
+++ b/rkward/rbackend/rpackages/rkward/R/internal.R
@@ -232,22 +232,20 @@
 	# else, for instance, if the user names a symbol "missing", and we try to resolve it in the
 	# wrapper function below, evaluation would recurse to look up "missing" in the .GlobalEnv
 	# due to the call to "if (!missing(value))".
-	get <- base::get
 	missing <- base::missing
-	assign <- base::assign
 	.rk.do.call <- rkward::.rk.do.call
 	invisible <- base::invisible
 
 	function (value) {
 		if (!missing (value)) {
-			assign (k, value, envir=.rk.watched.symbols)
+			x <<- value
 			.Call ("rk.do.command", c ("ws", k), PACKAGE="(embedding)");
 #			NOTE: the above is essentially the same a
 #				.rk.do.call ("ws", k);
 #			only minimally faster.
-			invisible (value)
+			invisible (x)
 		} else {
-			get (k, envir=.rk.watched.symbols)
+			x
 		}
 	}
 }
@@ -255,7 +253,7 @@
 #' @export
 ".rk.watch.symbol" <- function (k) {
 	f <- .rk.make.watch.f (k)
-	.Call ("rk.copy.no.eval", k, globalenv(), .rk.watched.symbols, PACKAGE="(embedding)");
+	.Call ("rk.copy.no.eval", k, globalenv(), "x", environment (f), PACKAGE="(embedding)");
 	#assign (k, get (k, envir=globalenv ()), envir=.rk.watched.symbols)
 	rm (list=k, envir=globalenv ())
 



More information about the rkward-tracker mailing list