Nothing
time_units <- function() {
stats::setNames(
c(1e-9,
1e-6,
if (is_utf8_output()) 1e-6,
1e-3,
1,
60,
60 * 60,
60 * 60 * 24,
60 * 60 * 24 * 7),
c("ns",
"us",
if (is_utf8_output()) "\U00B5s",
"ms",
"s",
"m",
"h",
"d",
"w")
)
}
#' Human readable times
#'
#' Construct, manipulate and display vectors of elapsed times in seconds. These
#' are numeric vectors, so you can compare them numerically, but they can also
#' be compared to human readable values such as '10ms'.
#'
#' @param x A numeric or character vector. Character representations can use
#' shorthand sizes (see examples).
#' @examples
#' as_bench_time("1ns")
#' as_bench_time("1")
#' as_bench_time("1us")
#' as_bench_time("1ms")
#' as_bench_time("1s")
#'
#' as_bench_time("100ns") < "1ms"
#'
#' sum(as_bench_time(c("1MB", "5MB", "500KB")))
#' @export
as_bench_time <- function(x) {
UseMethod("as_bench_time")
}
new_bench_time <- function(x) {
structure(x, class = c("bench_time", "numeric"))
}
setOldClass(c("bench_time", "numeric"), numeric())
#' @export
as_bench_time.default <- function(x) {
x <- as.character(x)
re <- glue::glue("
^(?<size>[[:digit:].]+)\\s*(?<unit>{nms}?)$
", nms = paste0(names(time_units()), collapse = "|"))
m <- captures(x, regexpr(re, x, perl = TRUE))
m$unit[m$unit == ""] <- "s"
new_bench_time(unname(as.numeric(m$size) * time_units()[m$unit]))
}
#' @export
as_bench_time.bench_time <- function(x) {
return(x)
}
#' @export
as_bench_time.numeric <- function(x) {
is_small <- x < 1e-9 & !is.infinite(x) & x != 0
x[is_small] <- 1e-9
new_bench_time(x)
}
tolerance <- sqrt(.Machine$double.eps)
find_unit <- function(x, units) {
if (is.na(x) || is.nan(x) || x <= 0 || is.infinite(x)) {
return(NA_character_)
}
epsilon <- 1 - (x * (1 / units))
names(
utils::tail(n = 1,
which(epsilon < tolerance)))
}
# Adapted from https://github.com/gaborcsardi/prettyunits
# Aims to be consistent with ls -lh, so uses 1024 KiB units, 3 or less digits etc.
#' @export
format.bench_time <- function(x, scientific = FALSE, digits = 3, drop0trailing = TRUE, ...) {
nms <- names(x)
# convert negative times to 1ns, this can happen if the minimum calculated
# overhead is higher than the time.
x[x < 1e-9 & !is.infinite(x) & x != 0] <- 1e-9
seconds <- unclass(x)
unit <- vcapply(x, find_unit, time_units())
res <- round(seconds / time_units()[unit], digits = digits)
## Zero seconds
res[seconds == 0] <- 0
unit[seconds == 0] <- ""
## NA, NaN, Inf, -Inf, seconds
res[is.na(seconds)] <- NA_real_
res[is.nan(seconds)] <- NaN
res[is.infinite(seconds)] <- Inf
res[is.infinite(seconds) & seconds < 0] <- -Inf
unit[is.na(seconds) | is.infinite(seconds)] <- ""
res <- format(res, scientific = scientific, digits = digits, drop0trailing = drop0trailing, ...)
stats::setNames(paste0(res, unit), nms)
}
#' @export
as.character.bench_time <- format.bench_time
#' @export
print.bench_time <- function(x, ...) {
print(format.bench_time(x, ...), quote = FALSE)
}
#' @export
sum.bench_time <- function(x, ...) {
new_bench_time(NextMethod())
}
#' @export
min.bench_time <- function(x, ...) {
new_bench_time(NextMethod())
}
#' @export
max.bench_time <- function(x, ...) {
new_bench_time(NextMethod())
}
#' @export
`[.bench_time` <- function(x, i, ...) {
new_bench_time(NextMethod("["))
}
#' @export
`[[.bench_time` <- function(x, i, ...) {
new_bench_time(NextMethod("[["))
}
#' @export
# Adapted from Ops.numeric_version
Ops.bench_time <- function(e1, e2, ...) {
if (nargs() == 1L) {
stop(sprintf("unary '%s' not defined for \"bench_time\" objects", .Generic),
call. = FALSE)
}
boolean <- switch(.Generic,
`+` = TRUE,
`-` = TRUE,
`*` = TRUE,
`/` = TRUE,
`^` = TRUE,
`<` = TRUE,
`>` = TRUE,
`==` = TRUE,
`!=` = TRUE,
`<=` = TRUE,
`>=` = TRUE,
`%%` = TRUE,
FALSE)
if (!boolean) {
stop(sprintf("'%s' not defined for \"bench_time\" objects", .Generic),
call. = FALSE)
}
e1 <- as_bench_time(e1)
e2 <- as_bench_time(e2)
NextMethod(.Generic)
}
#' @export
Summary.bench_time <- function(..., na.rm = FALSE) {
new_bench_time(NextMethod(.Generic))
}
#' @export
mean.bench_time <- function(x, ...) {
new_bench_time(NextMethod(.Generic))
}
#' @export
pillar_shaft.bench_time <- function(x, ...) {
pillar::new_pillar_shaft_simple(format.bench_time(x), align = "right", ...)
}
#' @export
type_sum.bench_time <- function(x) {
"bch:tm"
}
#' Benchmark time transformation
#'
#' This both log transforms the times and formats the labels as a `bench_time`
#' object.
#' @inheritParams scales::log_trans
#' @keywords internal
#' @export
bench_time_trans <- function(base = 10) {
if (is.null(base)) {
return(
scales::trans_new("bch:tm", as.numeric, as_bench_time,
scales::pretty_breaks(), domain = c(1e-100, Inf)
)
)
}
trans <- function(x) log(as.numeric(x), base)
inv <- function(x) as_bench_time(base ^ as.numeric(x))
scales::trans_new(paste0("bch:tm-", format(base)), trans, inv,
scales::log_breaks(base = base), domain = c(1e-100, Inf))
}
scale_type.bench_time <- function(x) "bench_time"
#' Position scales for bench_time data
#'
#' Default scales for the `bench_time` class, these are added to plots using
#' `bench_time` objects automatically.
#' @name scale_bench_time
#' @param base The base of the logarithm, if `NULL` instead use a
#' non-logarithmic scale.
#' @keywords internal
#' @export
scale_x_bench_time <- function(base = 10, ...) {
ggplot2::scale_x_continuous(..., trans = bench_time_trans(base = base))
}
#' @rdname scale_bench_time
#' @keywords internal
#' @export
scale_y_bench_time <- function(base = 10, ...) {
ggplot2::scale_y_continuous(..., trans = bench_time_trans(base = base))
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.