setTimeLimit fails to terminate idle call in R
Asked Answered
W

2

10

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

Worriment answered 15/5, 2013 at 23:24 Comment(6)
For what it's worth, I just tried this on Ubuntu 12.04 + R3.0.0, Mac OSX + R 2.15.3 via GUI and Terminal and RStudio on both machines. Unfortunately, I could not reproduce your error in any of thoseRacehorse
Interesting. So they all terminate after 3 seconds in your case? Perhaps it's a bug. I added a link to a video to demo the problem.Worriment
indeed... sessionInfo()?Racehorse
What happens if instead of Sys.sleep(10) you instead invoke for (i in seq(10)) Sys.sleep(1)?Hoodlum
In that case it works. The problem specifically appears to calls that are stuck waiting.Worriment
Does it make any difference if you sudo the command (or the session)?Charpentier
W
4

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

Worriment answered 16/5, 2013 at 19:46 Comment(0)
G
0

This is an interesting problem, which I also encountered. Jereon's solution above does not work, however, if your function executes a subprocess, e.g. through system(). In that case, there are no time checks until after the full process has executed (which in my case can sometimes take hours).

However, I found an alternate solution for anyone else who might have the same issue. What I did was set wait = FALSE in the system() call, and then force an evaluation of whether or not the script was done every 1 s. It requires you adding some external side-effect to your script, such as creating a temporary file when it is complete.

An edited version of Jeroen's answer shows this below.

testlimit <- function() {
  setTimeLimit(elapsed = 3, transient = TRUE)
  system("sleep 10 && touch done", wait = FALSE)
  while (!file.exists("done")) {
    Sys.sleep(1)
  }
}
system.time(testlimit())
# Error in Sys.sleep(1) : reached elapsed time limit
# Timing stopped at: 0.008 0.005 3.009
Gatling answered 9/1, 2022 at 11:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.