File: internal.R

package info (click to toggle)
r-cran-microbenchmark 1.5.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 392 kB
  • sloc: ansic: 257; makefile: 2; sh: 1
file content (211 lines) | stat: -rw-r--r-- 7,300 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
## Internal utility functions

# Internal helper functions that returns a generic error if timings fail.
.all_na_stop <- function() {
  msg <- "All measured timings are NA. This is bad!

There are several causes for this. The most likely are

 * You are running under a hypervisor. This can do all sorts of things
   to the timing functions of your operating system.

 * You have frequency scaling turned on. Most modern CPUs can reduce
   their core frequency if they are not busy. microbenchmark tries
   hard to spin up the CPU before the actual timing, but there is no
   guarantee this works, so you are advised to disable this
   feature. Under Linux this can be done using the 'cpufreq'
   utilities.

 * You have a machine with many CPU cores and the timers provided by
   your operating system are not synchronized across cores. Your best
   bet is to peg your R process to a single core. On Linux systems,
   this can be achieved using the 'taskset' utility.

 * Your machine is super fast. If the difference between the estimated
   overhead and the actual execution time is zero (or possibly even
   negative), you will get this error. Sorry,
   you're out of luck, benchmark more complex code.

If this problem persists for you, please contact me and I will try to
resolve the issue with you."

  stop(msg, call.=FALSE)
}

#' Convert timings to different units.
#'
#' The following units of time are supported \describe{
#' \item{\dQuote{ns}}{Nanoseconds.}
#' \item{\dQuote{us}}{Microseconds.}
#' \item{\dQuote{ms}}{Milliseconds.}
#' \item{\dQuote{s}}{Seconds.}
#' \item{\dQuote{t}}{Appropriately prefixed time unit.}
#' \item{\dQuote{hz}}{Hertz / evaluations per second.}
#' \item{\dQuote{eps}}{Evaluations per second / Hertz.}
#' \item{\dQuote{khz}}{Kilohertz / 1000s of evaluations per second.}
#' \item{\dQuote{mhz}}{Megahertz / 1000000s of evaluations per second.}
#' \item{\dQuote{f}}{Appropriately prefixed frequency unit.}
#' }
#' 
#' @param object A \code{microbenchmark} object.
#' @param unit A unit of time. See details.
#'
#' @return A matrix containing the converted time values with an
#'   attribute \code{unit} which is a printable name of the unit of
#'   time.
#'
#' @author Olaf Mersmann
#'
#' @keywords internal
convert_to_unit <- function(object, unit)
{
  unit <- determine_unit(object, unit)
  x <- object$time

  switch (unit,
          t=unit <- sprintf ("%ss", find_prefix(x * 1e-9,
            minexp = -9, maxexp = 0, mu = FALSE)),
          f=unit <- sprintf ("%shz", find_prefix(1e9 / x,
            minexp =  0, maxexp = 6, mu = FALSE))
          )
  unit <- tolower(unit)
  switch (unit,
          ns  ={attr(x, "unit") <- "nanoseconds"           ; unclass(x      )},
          us  ={attr(x, "unit") <- "microseconds"          ; unclass(x / 1e3)},
          ms  ={attr(x, "unit") <- "milliseconds"          ; unclass(x / 1e6)}, 
          s   ={attr(x, "unit") <- "seconds"               ; unclass(x / 1e9)},
          eps ={attr(x, "unit") <- "evaluations per second"; unclass(1e9 / x)},
          hz  ={attr(x, "unit") <- "hertz"                 ; unclass(1e9 / x)},
          khz ={attr(x, "unit") <- "kilohertz"             ; unclass(1e6 / x)},
          mhz ={attr(x, "unit") <- "megahertz"             ; unclass(1e3 / x)},
          stop("Unknown unit '", unit, "'.")
          )
}

#' Find SI prefix for unit
#' 
#' @param x a numeric
#' @param f function that produces the number from \code{x} that is used to
#'   determine the prefix, e.g. \code{\link[base]{min}} or
#'   \code{\link[stats]{median}}.
#' @param minexp minimum (decimal) exponent to consider, 
#'   e.g. -3 to suppress prefixes smaller than milli (m).
#' @param maxexp maximum (decimal) exponent to consider, 
#'   e.g. 3 to suppress prefixes larger than kilo (k).
#' @param mu if \code{TRUE}, should a proper mu be used for micro, otherwise use
#'  u as ASCII-compatible replacement
#'
#' @return character with the SI prefix
#' @author Claudia Beleites 
#'
#' @keywords internal
find_prefix <- function (x, f=min, minexp=-Inf, maxexp=Inf, mu=TRUE) {
  prefixes <- c ("y", "z", "a", "f", "p", "n", "u", "m", "",
                 "k", "M", "G", "T", "P", "E", "Z", "Y")
  if (mu) prefixes [7] <- "\u03bc"

  if (is.numeric (minexp)) minexp <- floor (minexp / 3) 
  if (is.numeric (minexp)) maxexp <- floor (maxexp / 3) 

  e3 <- floor (log10 (f (x)) / 3)
  e3 <- max (e3, minexp, -8) # prefixes go from 10^-24 = 10^(3 * -8)
  e3 <- min (e3, maxexp,  8) # to 10^24 = 10^(3 * 8)

  prefixes [e3 + 9] # e3 of -8 => index 1
 }

#' Return first non null argument.
#'
#' This function is useful when processing complex arguments with multiple
#' possible defaults based on other arguments that may or may not have been
#' provided.
#'
#' @param ... List of values.
#' @return First non null element in \code{...}.
#'
#' @author Olaf Mersmann
#'
#' @keywords internal
coalesce <- function(...) {
  isnotnull <- function(x) !is.null(x)
  Find(isnotnull, list(...))
}

#' Normalize timing units to one of the supported values
#'
#' We support the following units of time
#' \describe{
#'   \item{\dQuote{ns}, \dQuote{nanoseconds}}{}
#'   \item{\dQuote{us}, \dQuote{microseconds}}{}
#'   \item{\dQuote{ms}, \dQuote{milliseconds}}{}
#'   \item{\dQuote{s}, \dQuote{secs}, \dQuote{seconds}}{}
#'   \item{\dQuote{t}, \dQuote{time}}{Appropriately prefixed time unit.}
#'   \item{\dQuote{eps}}{Evaluations per second / Hertz.}
#'   \item{\dQuote{hz}}{Hertz / evaluations per second.}
#'   \item{\dQuote{khz}}{Kilohertz / 1000s of evaluations per second.}
#'   \item{\dQuote{mhz}}{Megahertz / 1000000s of evaluations per second.}
#'   \item{\dQuote{f}, \dQuote{frequency}}{Appropriately prefixed frequency unit.}
#' }
#'
#' @param object A 'microbenchmark' object.
#' @param unit A unit of time. See details.
#'
#' @return A matrix containing the converted time values with an
#'   attribute \code{unit} which is a printable name of the unit of
#'   time.
#'
#' @author Joshua M. Ulrich
#'
#' @keywords internal
determine_unit <-
function(object = NULL,
         unit = NULL)
{
  # all supported unit values
  values <- c("nanoseconds", "ns",
              "microseconds", "us",
              "milliseconds", "ms",
              "seconds",
              "time", "auto",
              "frequency",
              "hz", "khz", "mhz",
              "eps", "relative")

  # Order of precedence:
  # 1) 'unit' argument
  # 2) 'unit' attribute on 'object' argument
  # 3) 'microbenchmark.unit' option
  object_unit <- attr(object, "unit")
  if (is.null(unit)) {
    if (is.null(object_unit)) {
        unit <- getOption("microbenchmark.unit", "auto")
    } else {
        unit <- object_unit
    }
  } else {
    # include support for 'secs' because it doesn't match 'seconds'
    unit <- if (unit == "secs") "seconds" else unit
  }

  unit <- tolower(unit)
  unit <- match.arg(unit, values)

  unit <-
    switch(unit,
           nanoseconds = ,
           ns = "ns",
           microseconds = ,
           us = "us",
           milliseconds = ,
           ms = "ms",
           seconds = "s",
           auto = ,
           time = "t",
           frequency = "f",
           hz = "hz",
           khz = "khz",
           mhz = "mhz",
           eps = "eps",
           relative = "relative")
  unit
}