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
}
|