6

I'd like to make a basic profiling tool that collects time stamps and produces run times with a note. The only problem is I'm having trouble figuring out how to do this without using global variables. What's the "correct" way to implement the functionality I'm trying to achieve? If R already has this functionality built in, that's awesome, but what I'm really trying to figure out here is how to avoid using global variables and write more robust code.

timeStamps = c()
runTimes = list()

appendRunTimes <- function(note) {
  if(length(timeStamps) < 1) {
    timeStamps <<- Sys.time()
  }
  else {
    timeStamps <<- c(timeStamps, Sys.time())
    diff <- timeStamps[length(timeStamps) ] - timeStamps[length(timeStamps) - 1]
    runTimes <<- c(runTimes,  format(diff))
    names(runTimes)[length(runTimes)] <<-  note
  }

}


appendRunTimes('start')
Sys.sleep(4)
appendRunTimes('test')
2
  • 3
    I'd look at the code of system.time for ideas.. or use it! You can also look at the code for some of the benchmarking packages (microbenchmark for example). Commented Jan 4, 2013 at 22:57
  • In addition to the other suggestions, see "Introduction to R" (cran.r-project.org/doc/manuals/R-intro.pdf) section 10.7, page 50 (2.15.2 revision). Commented Jan 5, 2013 at 4:38

2 Answers 2

8

Here's your example rewritten using closures:

RTmonitor <- local({
  timeStamps = c()
  runTimes = list()

  list(
    appendRunTimes=function(note) {
      if(length(timeStamps) < 1) {
        timeStamps <<- Sys.time()
      }
      else {
        timeStamps <<- c(timeStamps, Sys.time())
        diff <- timeStamps[length(timeStamps) ] - timeStamps[length(timeStamps) - 1]
        runTimes <<- c(runTimes,  format(diff))
        names(runTimes)[length(runTimes)] <<-  note
      }
    },
    viewRunTimes=function() {
      return(list(timeStamps=timeStamps,runTimes=runTimes))
    })
})


> RTmonitor$appendRunTimes("start")
> RTmonitor$appendRunTimes("test")
> RTmonitor$viewRunTimes()
$timeStamps
[1] "2013-01-04 18:39:12 EST" "2013-01-04 18:39:21 EST"

$runTimes
$runTimes$test
[1] "8.855587 secs"

Observe that the values are stored inside the closure, not in the global environment:

> timeStamps
Error: object 'timeStamps' not found
> runTimes
Error: object 'runTimes' not found
> RTmonitor$timeStamps
NULL
> RTmonitor$runTimes
NULL

More reading on closures and avoiding globals:

Sign up to request clarification or add additional context in comments.

2 Comments

You're only one step from R.oo or possibly using ReferenceClasses here, aren't you?
@Spacedman Want to post a R.oo or RefClass solution? :-) I'd be interested in seeing what others come up with.
4

Here's now to do this using ReferenceClasses:

RTmonitor = setRefClass("RTmonitor",
  fields=list(
    timeStamps="POSIXct",
    runTimes = "list"
    ),
  methods=list(
    appendRunTimes=function(note){
      if(length(timeStamps)==0){
        timeStamps <<- Sys.time()
      }else{
        timeStamps <<- c(timeStamps, Sys.time())
        diff <- timeStamps[length(timeStamps) ] - timeStamps[length(timeStamps) - 1]
        runTimes <<- c(runTimes,  format(diff))
        names(runTimes)[length(runTimes)] <<-  note
      }
    }
    )
  )

Now you've defined a class, instantiate an object and use it:

> r = RTmonitor$new()
> r$appendRunTimes("start")
> r$appendRunTimes("test")
> r
Reference class object of class "RTmonitor"
Field "timeStamps":
[1] "2013-01-05 14:52:25 GMT" "2013-01-05 14:52:31 GMT"
Field "runTimes":
$test
[1] "5.175815 secs"

Very similar to the closure approach, but more formalised. I had to define the timeStamps field as POSIXct, for example. You can also create multiple RTmonitor objects this way and they work independently - you'd have to write a closure constructor that wrapped the closure to do that.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.