[Rd] R_CheckUserInterrupt() can be a performance bottleneck within GUIs

Jeroen Ooms jeroenoom@ @end|ng |rom gm@||@com
Tue Dec 17 15:51:36 CET 2024


A more generic solution would be for R to throttle calls to
R_CheckUserInterrupt(), because it makes no sense to check 1000 times
per second if a user has interrupted, but it is difficult for the
caller to know when R_CheckUserInterrupt() has been last called, or do
it regularly without over-doing it.

Here is a simple patch: https://github.com/r-devel/r-svn/pull/125

See also: https://stat.ethz.ch/pipermail/r-devel/2023-May/082597.html



On Tue, Dec 17, 2024 at 10:47 AM Martin Becker
<martin.becker using mx.uni-saarland.de> wrote:
>
> tl;dr: R_CheckUserInterrupt() can be a performance bottleneck
>         within GUIs. This also affects functions in the 'stats'
>         package, which could be improved by changing the position
>         of calls to R_CheckUserInterrupt().
>
>
> Dear all,
>
> Recently I was puzzled because some code in a package under development,
> which consisted almost entirely of a .Call() to a function written in C,
> was running much slower within RStudio compared to R in a terminal. It
> took me some time to identify the cause, so I thought I would share my
> findings; perhaps they will be helpful to others.
>
> The performance drop was caused by R_CheckUserInterrupt(), which I call
> (perhaps too often) in my C code. While calling R_CheckUserInterrupt()
> seems to be quite cheap when running R or Rscript in a terminal, it is
> more expensive when running R within a GUI, especially within RStudio,
> as I noticed (but also, e.g., within R.app on MacOS). In fact, using a
> GUI (especially RStudio) can change the cost of (frequent) calls to
> R_CheckUserInterrupt() from negligible to critical (in real-world
> applications). Significant performance drops are also visible for
> functions in the 'stats' package, e.g., pwilcox().
>
> The following MWE (using Rcpp) illustrates the problem. Consider the
> following code:
>
> ---
>
> library(Rcpp)
> cppFunction('double nonsense(const int n, const int m, const int check) {
>    int i, j;
>    double result;
>    for (i=0;i<n;i++) {
>      if (check) R_CheckUserInterrupt();
>      result = 1.;
>      for (j=1;j<=m;j++) if (j%2) result *= j; else result /=j;
>    }
>    return(result);
> }')
>
> tmp1 <- system.time(nonsense(1e8,10,0))[1]
> tmp2 <- system.time(nonsense(1e8,10,1))[1]
> cat("w/o check:",tmp1,"sec., with check:",tmp2,"sec.,
> diff.:",tmp2-tmp1,"sec.\n")
>
> tmp3 <- system.time(pwilcox(rwilcox(1e5,40,60),40,60))[1]
> cat("wilcox example:",tmp3,"sec.\n")
>
> ---
>
> Running this code when R (4.4.2) is started in a terminal window
> produces the following measurements/output (Apple M1, MacOS 15.1.1):
>
>    w/o check: 0.525 sec., with check: 0.752 sec., diff.: 0.227 sec.
>    wilcox example: 1.028 sec.
>
> Running the same code when R is used within R.app (1.81 (8462)
> aarch64-apple-darwin20) on the same machine results in:
>
>    w/o check: 0.525 sec., with check: 1.683 sec., diff.: 1.158 sec.
>    wilcox example: 2.13 sec.
>
> Running the same code when R is used within RStudio Desktop (2024.12.0
> Build 467) on the same machine results in:
>
>    w/o check: 0.507 sec., with check: 22.905 sec., diff.: 22.398 sec.
>    wilcox example: 29.686 sec.
>
> So, the performance drop is already remarkable for R.app, but really
> huge for RStudio.
>
> Presumably, checking for user interrupts within a GUI is more involved
> than within a terminal window, so there may not be much room for
> improvement in R.app or RStudio (and I know that this list is not the
> right place to suggest improvements for RStudio or to report unwanted
> behaviour). However, it might be worth considering
>
> 1. an addition to the documentation in WRE (explaining that too many
> calls to R_CheckUserInterrupt() can cause a performance bottleneck,
> especially when the code is running within a GUI),
> 2. check (and possibly change) the position of R_CheckUserInterrupt() in
> some base R functions. For example, moving R_CheckUserInterrupt() from
> cwilcox() to pwilcox() and qwilcox() in src/nmath/wilcox.c may lead to a
> significant improvement (while still being feasible in terms of response
> time).
>
> Best,
> Martin
>
>
> --
> apl. Prof. Dr. Martin Becker, Akad. Oberrat
> Lehrstab Statistik
> Quantitative Methoden
> Fakultät für Empirische Humanwissenschaften und Wirtschaftswissenschaft
> Universität des Saarlandes
> Campus C3 1, Raum 2.17
> 66123 Saarbrücken
> Deutschland
>
> ______________________________________________
> R-devel using r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel



More information about the R-devel mailing list