Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setTimeLimit fails to terminate idle call in R

Tags:

r

cran

I would like to use setTimeLimit to abort operations that are stuck waiting (idle) after n seconds. Below a toy example in which Sys.sleep is a placeholder call that is idle:

testlimit <- function(){
  setTimeLimit(elapsed=3, transient=TRUE);
  Sys.sleep(10);
}

system.time(testlimit());

However this is giving inconsistent results. On windows and in r-studio server (linux) the call is correctly aborted after 3 seconds win video. However, when I run this in a terminal session in either on linux or osx, the timeout is not triggered until after Sys.sleep() and the total script takes 10 seconds to complete.

What causes this difference? Is there something I can set in my terminal R session such that the time limit is triggered? I am using Ubuntu 13.04 amd64, R version 3.0.1 RC, and osx 10.8

like image 430
Jeroen Ooms Avatar asked May 15 '13 23:05

Jeroen Ooms


1 Answers

The question was answered by Simon Urbanek on the r-devel mailing list. Below a copy of his response for future reference:

What causes this difference?

The time limit can only be checked in R_ProcessEvents() so for all practical purposes it can be only triggered by interruptible code that calls R_CheckUserInterrupt(). Now, it is entirely up to the front-end to decide how it will the the event loop. For example the terminal version of R has no other interrupts to worry about other than input handlers which trigger asynchronously, so it doesn't need to do any polling. Sys.sleep() only triggers on input handlers, so if you don't have any external event source hook as input handler, there is no reason to process any events so Sys.sleep() won't see any reason to check the time limit.

Is there something I can set in my terminal R session such that the time limit is triggered?

On OS X it's actually very easy: quartz(); dev.off() will do the trick. The reason is that Quartz needs to force the event loop in order to process events from the window asynchronously. It does so by installing a timer-based input handler. This handler will make sure that Sys.sleep() will wake up every 100ms (you can change the value using QuartzCocoa_SetLatency) so it will timeout with that resolution:

> testlimit <- function(){
+  setTimeLimit(elapsed=3, transient=TRUE);
+  Sys.sleep(10);
+ }
> system.time(testlimit());
Error in Sys.sleep(10) : reached elapsed time limit
Timing stopped at: 0 0.001 10.001 
> quartz(); dev.off()
null device 
          1 
> testlimit <- function(){
+  setTimeLimit(elapsed=3, transient=TRUE);
+  Sys.sleep(10);
+ }
> system.time(testlimit());
Error in Sys.sleep(10) : reached elapsed time limit
Timing stopped at: 0.002 0.003 3.019 

On Linux, there is no built-in timer, so you'd have to add an input handler that will pre-empt Sys.sleep(). If you want a constant timer, you can simply borrow the code from Quartz (have a look at QuartzCocoa_SetupEventLoop in src/library/grDevices/src/qdCocoa.m) or the CarbonEL package. It's really just a pipe that is added as an input handler into which you write asynchronously when you want to wake up the event loop. On top of my head I can't think of a built-in solution in R at this point (even though it could be argued that R might install a handler itself when the limit is set ...).

But note that this is really just a special case of of Sys.sleep(). If you actually run R code, then ProcessEvents is triggered automatically during the evaluation (or in interruptible C code).

Cheers, Simon

like image 115
Jeroen Ooms Avatar answered Sep 30 '22 13:09

Jeroen Ooms