Skip to content

Files

Latest commit

 

History

History
 
 

plots

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Oct 18, 2023
Oct 18, 2023
Oct 18, 2023
Oct 18, 2023

Figures from “Can My WiFi Handle the Metaverse? A Performance Evaluation Of Meta’s Flagship Virtual Reality Hardware”

Article Figures

All Content

Setup

Libraries used for plotting.

library(tidyverse)
library(here)
theme_set(theme_bw())
library(knitr)
library(forcats)
library(data.table)
library(cowplot)
library(ggbreak)
library(gghighlight)
library(ggtext)
library(zoo)
library(RColorBrewer)

saveplot <- function(filename, ...) {
  ggsave2(filename, ...)
  knitr::plot_crop(filename)
}

here::i_am("plots/README.Rmd")

Baseline Performance

These plots visualize data obtained from the baseline experiment, in which we play a popular game on the Meta Quest Pro under good conditions.

fps <- system(paste('grep -Po "(?<=FPS=)[0-9]+"', here("experiments", "headset-cable-2", "logcat_VrApi.log")), intern = TRUE)
data <- tibble(fps) %>%
  mutate(fps = as.numeric(fps)) %>%
  mutate(ts = 0:(n() - 1)) %>%
  select(ts, everything())
data %>%
  ggplot(aes(x = ts, y = fps)) +
  geom_line() +
  ylim(0, 90) +
  theme_half_open() +
  background_grid() +
  labs(x = "Time [s]", y = "Frames per second     ")

cpu <- system(paste('grep -Po "(?<=CPU%=)[0-9]+.[0-9]+"', here("experiments", "headset-cable-2", "logcat_VrApi.log")), intern = TRUE)
data <- tibble(cpu) %>%
  mutate(cpu = as.numeric(cpu) * 100) %>%
  mutate(ts = 0:(n() - 1)) %>%
  select(ts, everything())
data %>%
  ggplot(aes(x = ts, y = cpu)) +
  geom_line() +
  ylim(0, 50) +
  theme_half_open() +
  background_grid() +
  labs(x = "Time [s]", y = "CPU utilization     ")

gpu <- system(paste('grep -Po "(?<=GPU%=)[0-9]+.[0-9]+"', here("experiments", "headset-cable-2", "logcat_VrApi.log")), intern = TRUE)
data <- tibble(gpu) %>%
  mutate(gpu = as.numeric(gpu) * 100) %>%
  mutate(ts = 0:(n() - 1)) %>%
  select(ts, everything())
data %>%
  ggplot(aes(x = ts, y = gpu)) +
  geom_line() +
  ylim(0, 100) +
  theme_half_open() +
  background_grid() +
  labs(x = "Time [s]", y = "GPU utilization     ")

mem_usage <- system(paste('grep -Po "(?<=Free=)[0-9]+"', here("experiments", "headset-cable-2", "logcat_VrApi.log")), intern = TRUE)
data <- tibble(mem_usage) %>%
  mutate(mem_usage = 12288 - as.numeric(mem_usage)) %>%
  mutate(mem_usage = mem_usage / 1024) %>%
  mutate(ts = 0:(n() - 1)) %>%
  select(ts, everything())
data %>%
  ggplot(aes(x = ts, y = mem_usage)) +
  geom_line() +
  ylim(0, 11.5) +
  theme_half_open() +
  background_grid() +
  labs(x = "Time [s]", y = "Memory usage [GB]     ")

Local vs Streaming

Translate filenames to human-readable names.

to_human_name <- function(name) {
  if (name == "beat-headset-wirelessadb") {
    "Local"
  } else if (name == "beat-pc-wiredadb") {
    "Wired"
  } else if (name == "beat-pc-wirelessadb") {
    "Wireless"
  } else {
    name
  }
}

experiments <- c("beat-headset-wirelessadb", "beat-pc-wiredadb", "beat-pc-wirelessadb")

Read measurement data into table.

data <- NULL
for (f in experiments) {
  data <- system(paste('grep -Po "(?<=level: )[0-9]+"', here("experiments", f, "battery.log")), intern = TRUE) %>%
    tibble(battery = .) %>%
    mutate(battery = as.numeric(battery)) %>%
    mutate(ts = 0:(n() - 1)) %>%
    select(ts, everything()) %>%
    mutate(config = f) %>%
    bind_rows(data, .)
}
data <- data %>%
  mutate(config = map_chr(config, to_human_name))

Figure 5d

Plot the relative battery usage of the device.

colors <- RColorBrewer::brewer.pal(3, "Greens")[2:3]
tmax <- 1500
tmin <- 500
data %>%
  group_by(config) %>%
  filter(ts > tmin & ts < tmax) %>%
  mutate(ts = ts - min(ts)) %>%
  mutate(ts = ts / 60) %>%
  filter(config != "Wired") %>%
  mutate(rel_battery = battery + 100 - max(battery)) %>%
  ggplot(aes(x = ts, y = rel_battery, color = config)) +
  geom_line() +
  theme_half_open() +
  background_grid() +
  theme(legend.position = c(0.05, 0.40)) +
  ylim(0, NA) +
  labs(x = "Time [m]", y = "Battery charge") +
  scale_color_manual(name = "Config", values = colors)

Print battery usage statistics to use in the article.

data %>%
  filter(ts > tmin & ts < tmax) %>%
  mutate(ts = ts - min(ts)) %>%
  group_by(config) %>%
  summarize(max = max(battery), min = min(battery), diff = max - min, diff_per_minute = 60 * diff / (tmax - tmin), max_play_time = 100 / diff_per_minute)
## # A tibble: 3 × 6
##   config     max   min  diff diff_per_minute max_play_time
##   <chr>    <dbl> <dbl> <dbl>           <dbl>         <dbl>
## 1 Local       92    81    11            0.66          152.
## 2 Wired       72    72     0            0             Inf 
## 3 Wireless    77    64    13            0.78          128.

Plot the expected total battery lifetime based on the observed battery levels.

data %>%
  filter(config != "Wired") %>%
  group_by(config) %>%
  filter(ts > tmin & ts < tmax) %>%
  mutate(ts = ts - min(ts)) %>%
  group_by(config) %>%
  summarize(max = max(battery), min = min(battery), diff = max - min, diff_per_minute = 60 * diff / (tmax - tmin), max_play_time = 100 / diff_per_minute) %>%
  ggplot(aes(x = max_play_time, y = config)) +
  geom_col() +
  theme_half_open() +
  background_grid() +
  labs(x = "Approx. maximum battery life [m]                ", y = "Config")

Controllers

Plot the battery levels of the controllers for varying configurations.

data <- NULL
for (f in experiments) {
  data <- system(paste("grep -Po '(?<=Type:)\\s+(Left|Right),.+Battery:\\s+[0-9]+(?=%)'", here("experiments", f, "OVRRemoteService.log"), "| tr -s ' ' | sed -e \'s/^[[:space:]]*//\' -e \'s/\\n[[:space:]]*//\' | cut -d' ' -f 1,5"), intern = TRUE) %>%
    tibble(battery = .) %>%
    separate(battery, c("hand", "level"), convert = TRUE) %>%
    group_by(hand) %>%
    mutate(ts = 0:(n() - 1)) %>%
    select(ts, everything()) %>%
    mutate(config = f) %>%
    bind_rows(data, .)
}
data %>%
  ggplot(aes(x = ts, y = level, color = config, shape = hand, group = interaction(config, hand))) +
  geom_line() +
  ylim(0, NA) +
  theme_half_open() +
  background_grid()

Calculate expected battery life for the controllers for varying configurations.

d <- data %>%
  group_by(hand, config) %>%
  summarize(max = max(level), min = min(level), diff = max - min, diff_per_minute = 60 * diff / (tmax - tmin), max_play_time = 100 / diff_per_minute) %>%
  group_by(config) %>%
  print()
## `summarise()` has grouped output by 'hand'. You can override using the
## `.groups` argument.

## # A tibble: 6 × 7
## # Groups:   config [3]
##   hand  config                     max   min  diff diff_per_minute max_play_time
##   <chr> <chr>                    <int> <int> <int>           <dbl>         <dbl>
## 1 Left  beat-headset-wirelessadb    28    25     3            0.18          556.
## 2 Left  beat-pc-wiredadb            37    33     4            0.24          417.
## 3 Left  beat-pc-wirelessadb         31    27     4            0.24          417.
## 4 Right beat-headset-wirelessadb    27    25     2            0.12          833.
## 5 Right beat-pc-wiredadb            38    34     4            0.24          417.
## 6 Right beat-pc-wirelessadb         32    27     5            0.3           333.
d %>%
  summarize(max_play_time = max(max_play_time)) %>%
  print()
## # A tibble: 3 × 2
##   config                   max_play_time
##   <chr>                            <dbl>
## 1 beat-headset-wirelessadb          833.
## 2 beat-pc-wiredadb                  417.
## 3 beat-pc-wirelessadb               417.

Function for translating filenames into human-readable names.

to_human_name <- function(name) {
  if (name == "headset-cable-2") {
    "Local"
  } else if (name == "oculus-cable-2") {
    "Wired"
  } else if (name == "oculus-wireless-dynamic-100-mix-5ghz-2") {
    "Wireless"
  } else {
    name
  }
}

experiments <- c("headset-cable-2", "oculus-cable-2", "oculus-wireless-dynamic-100-mix-5ghz-2")
start_time <- 125
end_time <- 350

Reading measurement data into tables.

data <- NULL
for (f in experiments) {
  data <- system(paste('grep -Po "(?<=FPS=)[0-9]+"', here("experiments", f, "logcat_VrApi.log")), intern = TRUE) %>%
    tibble(fps = .) %>%
    mutate(fps = as.numeric(fps)) %>%
    mutate(ts = 0:(n() - 1)) %>%
    select(ts, everything()) %>%
    mutate(config = f) %>%
    bind_rows(data, .)
}
data <- data %>%
  mutate(config = map_chr(config, to_human_name))

Exploratory plot showing the frame rate over time for varying configurations.

data %>%
  ggplot(aes(x = ts, y = fps, color = config)) +
  geom_vline(xintercept = start_time, color = "black") +
  geom_vline(xintercept = end_time, color = "black") +
  geom_line() +
  ylim(0, NA) +
  theme_half_open() +
  background_grid() +
  theme(legend.position = "bottom") +
  scale_color_viridis_d(begin = 0.3, direction = -1)

Figure 5a

data %>%
  filter(ts >= start_time & ts <= end_time) %>%
  ggplot(aes(x = fps, y = config)) +
  geom_boxplot() +
  xlim(0, NA) +
  labs(x = "Frames per second", y = "Setup") +
  theme_half_open() +
  background_grid() +
  theme(legend.position = "bottom") +
  scale_color_viridis_d(begin = 0.3, direction = -1)

Operational Plot for Figure 5a

Operational plot showing the CPU utilization for varying configurations.

cpu_data <- NULL
for (f in experiments) {
  cpu_data <- system(paste('grep -Po "(?<=CPU%=)[0-9]+.[0-9]+"', here("experiments", f, "logcat_VrApi.log")), intern = TRUE) %>%
    tibble(cpu_util = .) %>%
    mutate(cpu_util = 100 * as.numeric(cpu_util)) %>%
    mutate(ts = 0:(n() - 1)) %>%
    select(ts, everything()) %>%
    mutate(config = f) %>%
    bind_rows(cpu_data, .)
}
cpu_data <- cpu_data %>%
  mutate(config = map_chr(config, to_human_name))
cpu_data %>%
  ggplot(aes(x = ts, y = cpu_util, color = config)) +
  geom_vline(xintercept = start_time, color = "black") +
  geom_vline(xintercept = end_time, color = "black") +
  geom_line() +
  ylim(0, NA) +
  theme_half_open() +
  background_grid() +
  theme(legend.position = "bottom") +
  scale_color_viridis_d(begin = 0.3, direction = -1)

Figure 5b

cpu_data %>%
  filter(ts >= start_time & ts <= end_time) %>%
  ggplot(aes(x = cpu_util, y = config)) +
  geom_boxplot() +
  xlim(0, NA) +
  labs(x = "CPU utilization [%]", y = "Setup") +
  theme_half_open() +
  background_grid()

Operational Plot for Figure 5b

data <- NULL
for (f in experiments) {
  data <- system(paste('grep -Po "(?<=GPU%=)[0-9]+.[0-9]+"', here("experiments", f, "logcat_VrApi.log")), intern = TRUE) %>%
    tibble(gpu_util = .) %>%
    mutate(gpu_util = 100 * as.numeric(gpu_util)) %>%
    mutate(ts = 0:(n() - 1)) %>%
    select(ts, everything()) %>%
    mutate(config = f) %>%
    bind_rows(data, .)
}
data <- data %>%
  mutate(config = map_chr(config, to_human_name))
data %>%
  ggplot(aes(x = ts, y = gpu_util, color = config)) +
  geom_vline(xintercept = start_time, color = "black") +
  geom_vline(xintercept = end_time, color = "black") +
  geom_line() +
  ylim(0, NA) +
  theme_half_open() +
  background_grid() +
  theme(legend.position = "bottom") +
  scale_color_viridis_d(begin = 0.3, direction = -1)

Figure 5c

data %>%
  filter(ts >= start_time & ts <= end_time) %>%
  ggplot(aes(x = gpu_util, y = config)) +
  geom_boxplot() +
  xlim(0, NA) +
  labs(y = "Setup", x = "GPU utilization [%]") +
  theme_half_open() +
  background_grid() +
  theme(legend.position = "none") +
  scale_color_viridis_d(begin = 0.3, direction = -1)

Operational Plot for Figure 5c

data <- read_csv(here("experiments", "beat-pc-wiredadb", "usb_packet_data.csv"))
## Rows: 7053933 Columns: 7
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (4): Source, Destination, Protocol, Info
## dbl (3): No., Time, Length
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
data %>%
  filter(Source == "host") %>%
  mutate(second = as.integer(Time)) %>%
  group_by(second) %>%
  summarize(Mbps = 8 * sum(Length) / 1000000) %>%
  ggplot(aes(x = second, y = Mbps)) +
  geom_line() +
  theme_half_open() +
  background_grid()

data %>%
  filter(Source == "host") %>%
  mutate(second = as.integer(Time)) %>%
  group_by(second) %>%
  summarize(Mbps = 8 * sum(Length) / 1000000) %>%
  ggplot(aes(x = Mbps)) +
  geom_boxplot() +
  theme_half_open() +
  background_grid()

data %>%
  filter(Source == "host") %>%
  mutate(second = as.integer(Time)) %>%
  group_by(second) %>%
  summarize(Mbps = 8 * sum(Length) / 1000000) %>%
  ungroup() %>%
  summarize(p25 = quantile(Mbps, 0.25), p50 = quantile(Mbps, 0.5), p75 = quantile(Mbps, 0.75))
## # A tibble: 1 × 3
##     p25   p50   p75
##   <dbl> <dbl> <dbl>
## 1  90.5  102.  110.
data %>%
  mutate(mode = ifelse(Source == "host", "receive", ifelse(Destination == "host", "send", "other"))) %>%
  filter(mode != "other") %>%
  mutate(second = as.integer(Time)) %>%
  group_by(mode, second) %>%
  summarize(Mbps = 8 * sum(Length) / 1000000) %>%
  ggplot(aes(x = second, y = Mbps, color = mode)) +
  geom_line() +
  theme_half_open() +
  background_grid()
## `summarise()` has grouped output by 'mode'. You can override using the
## `.groups` argument.

data %>%
  filter(Source == "host") %>%
  mutate(second = as.integer(Time)) %>%
  group_by(Destination, second) %>%
  summarize(Mbps = 8 * sum(Length) / 1000000) %>%
  ggplot(aes(x = second, y = Mbps, color = Destination)) +
  geom_line() +
  theme_half_open() +
  background_grid()
## `summarise()` has grouped output by 'Destination'. You can override using the
## `.groups` argument.

network_data <- NULL
for (f in experiments) {
  network_data <- system(paste('grep -P "\\s+wlan0\\W"', here("experiments", f, "net_dev.log"), '| tr -s " " | sed -e \'s/^[[:space:]]*//\' -e \'s/\\n[[:space:]]*//\''), intern = TRUE) %>%
    tibble(network = .) %>%
    separate(network, c("interface", "bytes_rx", "packets_rx", "errs_rx", "drop_rx", "fifo_rx", "frame_rx", "compressed_rx", "multicast_rx", "bytes_tx", "packets_tx", "errs_tx", "drop_tx", "fifo_tx", "colls_tx", "carrier_tx", "compressed_tx"), sep = " ", convert = TRUE) %>%
    mutate(ts = 0:(n() - 1)) %>%
    mutate(config = f) %>%
    bind_rows(network_data, .)
}
network_data %>%
  mutate(bytes_rx = 8 * (bytes_rx - lag(bytes_rx)) / 1000000) %>%
  drop_na() %>%
  ggplot(aes(x = ts, y = bytes_rx, color = config)) +
  geom_line() +
  ylab("Bytes received [Mbps]") +
  ylim(0, NA) +
  # scale_y_continuous(trans = "log10") +
  theme_half_open() +
  background_grid()

network_data %>%
  mutate(bytes_rx = 8 * (bytes_rx - lag(bytes_rx)) / 1000000) %>%
  drop_na() %>%
  filter(ts >= 200 & ts <= 400) %>%
  mutate(config = map_chr(config, to_human_name)) %>%
  ggplot(aes(x = bytes_rx, y = config)) +
  geom_boxplot() +
  labs(x = "Bytes received [Mbps]", y = "Setup") +
  xlim(0, 100) +
  # scale_x_continuous(trans = "log10") +
  theme_half_open() +
  background_grid() +
  theme(legend.position = "bottom")

mem_data <- NULL
for (f in experiments) {
  mem_data <- system(paste('grep -Po "(?<=Free=)[0-9]+"', here("experiments", f, "logcat_VrApi.log")), intern = TRUE) %>%
    tibble(mem_usage = .) %>%
    mutate(mem_usage = 12288 - as.numeric(mem_usage)) %>%
    mutate(mem_usage = mem_usage / 1024) %>%
    mutate(ts = 0:(n() - 1)) %>%
    select(ts, everything()) %>%
    mutate(config = f) %>%
    bind_rows(mem_data, .)
}
mem_data <- mem_data %>%
  mutate(config = map_chr(config, to_human_name))
mem_data %>%
  ggplot(aes(x = ts, y = mem_usage, color = config)) +
  geom_line() +
  ylim(0, 11.5) +
  theme_half_open() +
  background_grid() +
  labs(x = "Time [s]", y = "Memory usage [GB]     ")

mem_data %>%
  ggplot(aes(x = mem_usage, y = config)) +
  geom_boxplot() +
  xlim(0, NA) +
  theme_half_open() +
  background_grid() +
  labs(x = "Memory usage [GB]", y = "Setup")

Effect of WiFi Networks

to_human_name <- function(name) {
  if (name == "oculus-wireless-dynamic-100-b_g_n-2_4ghz") {
    "2.4GHz WiFi 4"
  } else if (name == "oculus-wireless-dynamic-100-ax-5ghz") {
    "5GHz WiFi 6"
  } else if (name == "oculus-wireless-dynamic-100-ax-2_4ghz") {
    "2.4GHz WiFi 6"
  } else if (name == "oculus-wireless-dynamic-100-a_n_ac-5ghz") {
    "5GHz WiFi 5"
  } else if (name == "oculus-wireless-dynamic-100-mix-5ghz-2") {
    "5GHz WiFi 5/6"
  } else {
    name
  }
}

wifi_order <- c("2.4GHz WiFi 4", "5GHz WiFi 5", "5GHz WiFi 5/6", "2.4GHz WiFi 6", "5GHz WiFi 6")
experiments <- c("oculus-wireless-dynamic-100-mix-5ghz-2", "oculus-wireless-dynamic-100-a_n_ac-5ghz", "oculus-wireless-dynamic-100-ax-2_4ghz", "oculus-wireless-dynamic-100-ax-5ghz", "oculus-wireless-dynamic-100-b_g_n-2_4ghz")
# experiments <- c("oculus-wireless-dynamic-100-a_n_ac-5ghz", "oculus-wireless-dynamic-100-ax-2_4ghz", "oculus-wireless-dynamic-100-ax-5ghz", "oculus-wireless-dynamic-100-b_g_n-2_4ghz")
start_time <- 125
end_time <- 350
data <- NULL
for (f in experiments) {
  data <- system(paste('grep -Po "(?<=FPS=)[0-9]+"', here("experiments", f, "logcat_VrApi.log")), intern = TRUE) %>%
    tibble(fps = .) %>%
    mutate(fps = as.numeric(fps)) %>%
    mutate(ts = 0:(n() - 1)) %>%
    select(ts, everything()) %>%
    mutate(config = f) %>%
    bind_rows(data, .)
}
data <- data %>%
  mutate(config = map_chr(config, to_human_name))
data %>%
  ggplot(aes(x = ts, y = fps, color = config)) +
  geom_vline(xintercept = start_time, color = "black") +
  geom_vline(xintercept = end_time, color = "black") +
  geom_line() +
  ylim(0, NA) +
  theme_half_open() +
  background_grid() +
  theme(legend.position = "bottom") +
  scale_color_viridis_d(begin = 0.3, direction = -1)

Figure 7b

data %>%
  filter(ts >= start_time & ts <= end_time) %>%
  mutate(config = factor(config, levels = wifi_order)) %>%
  ggplot(aes(x = fps, y = config)) +
  # geom_vline(xintercept = 72, color = "green") +
  geom_boxplot() +
  xlim(0, NA) +
  labs(x = "Frames per second ", y = "Network type") +
  # scale_x_break(breaks = c(15, 55), scales = 2) +
  theme_half_open() +
  background_grid() +
  # scale_x_break(c(10, 50)) +
  theme(legend.position = "bottom") +
  scale_color_viridis_d(begin = 0.3, direction = -1)

data %>%
  filter(ts >= start_time & ts <= end_time) %>%
  mutate(config = factor(config, levels = wifi_order)) %>%
  group_by(config) %>%
  summarize(min = min(fps), p01 = quantile(fps, 0.01), p05 = quantile(fps, 0.05), p10 = quantile(fps, 0.1), mean = mean(fps), median = median(fps), max = max(fps))
## # A tibble: 5 × 8
##   config          min   p01   p05   p10  mean median   max
##   <fct>         <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl> <dbl>
## 1 2.4GHz WiFi 4    59  65.2    68    70  71.4     72    73
## 2 5GHz WiFi 5      72  72      72    72  72       72    72
## 3 5GHz WiFi 5/6    69  71.2    72    72  72.5     73    73
## 4 2.4GHz WiFi 6    70  70.2    72    72  72.0     72    72
## 5 5GHz WiFi 6      72  73      73    73  73.0     73    73
cpu_data <- NULL
for (f in experiments) {
  cpu_data <- system(paste('grep -Po "(?<=CPU%=)[0-9]+.[0-9]+"', here("experiments", f, "logcat_VrApi.log")), intern = TRUE) %>%
    tibble(cpu_util = .) %>%
    mutate(cpu_util = 100 * as.numeric(cpu_util)) %>%
    mutate(ts = 0:(n() - 1)) %>%
    select(ts, everything()) %>%
    mutate(config = f) %>%
    bind_rows(cpu_data, .)
}
cpu_data <- cpu_data %>%
  mutate(config = map_chr(config, to_human_name))
cpu_data %>%
  ggplot(aes(x = ts, y = cpu_util, color = config)) +
  geom_vline(xintercept = start_time, color = "black") +
  geom_vline(xintercept = end_time, color = "black") +
  geom_line() +
  ylim(0, NA) +
  theme_half_open() +
  background_grid() +
  theme(legend.position = "bottom") +
  scale_color_viridis_d(begin = 0.3, direction = -1)

cpu_data %>%
  filter(ts >= start_time & ts <= end_time) %>%
  mutate(config = factor(config, levels = wifi_order)) %>%
  ggplot(aes(x = cpu_util, y = config)) +
  geom_boxplot() +
  xlim(0, NA) +
  labs(x = "CPU utilization [%]", y = "Network type") +
  theme_half_open() +
  background_grid()

data <- NULL
for (f in experiments) {
  data <- system(paste('grep -Po "(?<=GPU%=)[0-9]+.[0-9]+"', here("experiments", f, "logcat_VrApi.log")), intern = TRUE) %>%
    tibble(gpu_util = .) %>%
    mutate(gpu_util = 100 * as.numeric(gpu_util)) %>%
    mutate(ts = 0:(n() - 1)) %>%
    select(ts, everything()) %>%
    mutate(config = f) %>%
    bind_rows(data, .)
}
data <- data %>%
  mutate(config = map_chr(config, to_human_name))
data %>%
  ggplot(aes(x = ts, y = gpu_util, color = config)) +
  geom_vline(xintercept = start_time, color = "black") +
  geom_vline(xintercept = end_time, color = "black") +
  geom_line() +
  ylim(0, NA) +
  theme_half_open() +
  background_grid() +
  theme(legend.position = "bottom") +
  scale_color_viridis_d(begin = 0.3, direction = -1)

data %>%
  filter(ts >= start_time & ts <= end_time) %>%
  mutate(config = factor(config, levels = wifi_order)) %>%
  ggplot(aes(x = gpu_util, y = config)) +
  geom_boxplot() +
  xlim(0, NA) +
  labs(y = "Network type", x = "GPU utilization [%]") +
  theme_half_open() +
  background_grid() +
  theme(legend.position = "none") +
  scale_color_viridis_d(begin = 0.3, direction = -1)

network_data <- NULL
for (f in experiments) {
  network_data <- system(paste('grep -P "\\s+wlan0\\W"', here("experiments", f, "net_dev.log"), '| tr -s " " | sed -e \'s/^[[:space:]]*//\' -e \'s/\\n[[:space:]]*//\''), intern = TRUE) %>%
    tibble(network = .) %>%
    separate(network, c("interface", "bytes_rx", "packets_rx", "errs_rx", "drop_rx", "fifo_rx", "frame_rx", "compressed_rx", "multicast_rx", "bytes_tx", "packets_tx", "errs_tx", "drop_tx", "fifo_tx", "colls_tx", "carrier_tx", "compressed_tx"), sep = " ", convert = TRUE) %>%
    mutate(ts = 0:(n() - 1)) %>%
    mutate(config = f) %>%
    bind_rows(network_data, .)
}
network_data %>%
  mutate(bytes_rx = 8 * (bytes_rx - lag(bytes_rx)) / 1000000) %>%
  drop_na() %>%
  ggplot(aes(x = ts, y = bytes_rx, color = config)) +
  geom_line() +
  ylab("Bytes received [Mbps]") +
  ylim(0, NA) +
  # scale_y_continuous(trans = "log10") +
  theme_half_open() +
  background_grid()
## Warning: Removed 2 row(s) containing missing values (geom_path).

Figure 7a

network_data %>%
  mutate(bytes_rx = 8 * (bytes_rx - lag(bytes_rx)) / 1000000) %>%
  drop_na() %>%
  filter(ts >= 200 & ts <= 400) %>%
  mutate(config = map_chr(config, to_human_name)) %>%
  mutate(config = factor(config, levels = wifi_order)) %>%
  ggplot(aes(x = bytes_rx, y = config)) +
  geom_boxplot() +
  labs(x = "Bytes received [Mbps]      ", y = "Network type") +
  xlim(0, 100) +
  # scale_x_continuous(trans = "log10") +
  theme_half_open() +
  background_grid() +
  theme(legend.position = "bottom")

network_data %>%
  mutate(bytes_rx = 8 * (bytes_rx - lag(bytes_rx)) / 1000000) %>%
  drop_na() %>%
  filter(ts >= 200 & ts <= 400) %>%
  mutate(config = map_chr(config, to_human_name)) %>%
  mutate(config = factor(config, levels = wifi_order)) %>%
  group_by(config) %>%
  summarize(mean = mean(bytes_rx), median = median(bytes_rx))
## # A tibble: 5 × 3
##   config         mean median
##   <fct>         <dbl>  <dbl>
## 1 2.4GHz WiFi 4  45.9   45.5
## 2 5GHz WiFi 5    82.3   91.1
## 3 5GHz WiFi 5/6  91.1   91.7
## 4 2.4GHz WiFi 6  46.6   47.4
## 5 5GHz WiFi 6    91.1   91.8
mem_data <- NULL
for (f in experiments) {
  mem_data <- system(paste('grep -Po "(?<=Free=)[0-9]+"', here("experiments", f, "logcat_VrApi.log")), intern = TRUE) %>%
    tibble(mem_usage = .) %>%
    mutate(mem_usage = 12288 - as.numeric(mem_usage)) %>%
    mutate(mem_usage = mem_usage / 1024) %>%
    mutate(ts = 0:(n() - 1)) %>%
    select(ts, everything()) %>%
    mutate(config = f) %>%
    bind_rows(mem_data, .)
}
mem_data <- mem_data %>%
  mutate(config = map_chr(config, to_human_name))
mem_data %>%
  ggplot(aes(x = ts, y = mem_usage, color = config)) +
  geom_line() +
  ylim(0, 11.5) +
  theme_half_open() +
  background_grid() +
  labs(x = "Time [s]", y = "Memory usage [GB]     ")

mem_data %>%
  ggplot(aes(x = mem_usage, y = config)) +
  geom_boxplot() +
  xlim(0, NA) +
  theme_half_open() +
  background_grid() +
  labs(x = "Memory usage [GB]    ", y = "Setup")

Impact of WiFi Distance

to_human_name <- function(name) {
  if (name == "alyx-wired") {
    "Wired"
  } else if (name == "alyx-wireless") {
    "Near"
  } else if (name == "alyx-wireless-upstairs") {
    "Far"
  } else {
    name
  }
}

wifi_order <- c("Wired", "Near", "Far")
experiments <- c("alyx-wired", "alyx-wireless", "alyx-wireless-upstairs")
# experiments <- c("oculus-wireless-dynamic-100-a_n_ac-5ghz", "oculus-wireless-dynamic-100-ax-2_4ghz", "oculus-wireless-dynamic-100-ax-5ghz", "oculus-wireless-dynamic-100-b_g_n-2_4ghz")
start_time <- 125
end_time <- 900
data <- NULL
for (f in experiments) {
  data <- system(paste('grep -Po "(?<=FPS=)[0-9]+"', here("experiments", f, "logcat_VrApi.log")), intern = TRUE) %>%
    tibble(fps = .) %>%
    mutate(fps = as.numeric(fps)) %>%
    mutate(ts = 0:(n() - 1)) %>%
    select(ts, everything()) %>%
    mutate(config = f) %>%
    bind_rows(data, .)
}
data <- data %>%
  mutate(config = map_chr(config, to_human_name))

Figure 6b

my_colors <- RColorBrewer::brewer.pal(3, "Greens")[2:3]
data %>%
  filter(config == "Far" | config == "Near") %>%
  filter(ts >= start_time & ts <= end_time) %>%
  mutate(ts = ts - min(ts)) %>%
  ggplot(aes(x = ts, y = fps, color = config)) +
  geom_line() +
  xlim(0, NA) +
  theme_half_open() +
  background_grid() +
  theme(legend.position = c(0.05, 0.10), legend.direction = "horizontal") +
  labs(x = "Time [s]", y = "Frames per second         ") +
  scale_color_manual(values = my_colors)

Figure 1

my_colors <- RColorBrewer::brewer.pal(3, "Greens")[2:3]
data %>%
  filter(config == "Far" | config == "Near") %>%
  filter(ts >= start_time & ts <= end_time) %>%
  mutate(ts = ts - min(ts)) %>%
  ggplot(aes(x = ts, y = fps, color = config)) +
  geom_line(size = 1) +
  xlim(0, NA) +
  ylim(0, 100) +
  theme_half_open() +
  background_grid() +
  theme(legend.position = c(0.04, 0.85), legend.direction = "horizontal") +
  labs(x = "Time [s]", y = "Frames per second         ") +
  scale_color_manual(values = my_colors, name = "Proximity of wireless access point") +
  # scale_size_manual(values = c(Near = 1, Far = 1), name = "") +
  annotate("text", x = 0, y = 10, label = "Target frame rate: 72 Hz. Higher is better", fill = "white", label.size = NA, hjust = 0, size = 5)
## Warning: Ignoring unknown parameters: fill, label.size

Figure 6a

data %>%
  filter(ts >= start_time & ts <= end_time) %>%
  mutate(config = factor(config, levels = wifi_order)) %>%
  ggplot(aes(x = fps, y = config)) +
  geom_boxplot() +
  xlim(0, NA) +
  labs(x = "Frames per second ", y = "AP distance") +
  theme_half_open() +
  background_grid() +
  # scale_x_break(c(10, 50)) +
  theme(legend.position = "bottom") +
  scale_color_viridis_d(begin = 0.3, direction = -1)

cpu_data <- NULL
for (f in experiments) {
  cpu_data <- system(paste('grep -Po "(?<=CPU%=)[0-9]+.[0-9]+"', here("experiments", f, "logcat_VrApi.log")), intern = TRUE) %>%
    tibble(cpu_util = .) %>%
    mutate(cpu_util = 100 * as.numeric(cpu_util)) %>%
    mutate(ts = 0:(n() - 1)) %>%
    select(ts, everything()) %>%
    mutate(config = f) %>%
    bind_rows(cpu_data, .)
}
cpu_data <- cpu_data %>%
  mutate(config = map_chr(config, to_human_name))
cpu_data %>%
  ggplot(aes(x = ts, y = cpu_util, color = config)) +
  geom_vline(xintercept = start_time, color = "black") +
  geom_vline(xintercept = end_time, color = "black") +
  geom_line() +
  ylim(0, NA) +
  theme_half_open() +
  background_grid() +
  theme(legend.position = "bottom") +
  scale_color_viridis_d(begin = 0.3, direction = -1)

cpu_data %>%
  filter(ts >= start_time & ts <= end_time) %>%
  mutate(config = factor(config, levels = wifi_order)) %>%
  ggplot(aes(x = cpu_util, y = config)) +
  geom_boxplot() +
  xlim(0, NA) +
  labs(x = "CPU utilization [%]", y = "AP distance") +
  theme_half_open() +
  background_grid()

data <- NULL
for (f in experiments) {
  data <- system(paste('grep -Po "(?<=GPU%=)[0-9]+.[0-9]+"', here("experiments", f, "logcat_VrApi.log")), intern = TRUE) %>%
    tibble(gpu_util = .) %>%
    mutate(gpu_util = 100 * as.numeric(gpu_util)) %>%
    mutate(ts = 0:(n() - 1)) %>%
    select(ts, everything()) %>%
    mutate(config = f) %>%
    bind_rows(data, .)
}
data <- data %>%
  mutate(config = map_chr(config, to_human_name))
data %>%
  ggplot(aes(x = ts, y = gpu_util, color = config)) +
  geom_vline(xintercept = start_time, color = "black") +
  geom_vline(xintercept = end_time, color = "black") +
  geom_line() +
  ylim(0, NA) +
  theme_half_open() +
  background_grid() +
  theme(legend.position = "bottom") +
  scale_color_viridis_d(begin = 0.3, direction = -1)

Figure 6c

data %>%
  filter(ts >= start_time & ts <= end_time) %>%
  mutate(config = factor(config, levels = wifi_order)) %>%
  ggplot(aes(x = gpu_util, y = config)) +
  geom_boxplot() +
  xlim(0, NA) +
  labs(y = "AP distance", x = "GPU utilization [%]") +
  theme_half_open() +
  background_grid() +
  theme(legend.position = "none") +
  scale_color_viridis_d(begin = 0.3, direction = -1)

network_data <- NULL
for (f in experiments) {
  network_data <- system(paste('grep -P "\\s+wlan0\\W"', here("experiments", f, "net_dev.log"), '| tr -s " " | sed -e \'s/^[[:space:]]*//\' -e \'s/\\n[[:space:]]*//\''), intern = TRUE) %>%
    tibble(network = .) %>%
    separate(network, c("interface", "bytes_rx", "packets_rx", "errs_rx", "drop_rx", "fifo_rx", "frame_rx", "compressed_rx", "multicast_rx", "bytes_tx", "packets_tx", "errs_tx", "drop_tx", "fifo_tx", "colls_tx", "carrier_tx", "compressed_tx"), sep = " ", convert = TRUE) %>%
    mutate(ts = 0:(n() - 1)) %>%
    mutate(config = f) %>%
    bind_rows(network_data, .)
}
network_data %>%
  mutate(bytes_rx = 8 * (bytes_rx - lag(bytes_rx)) / 1000000) %>%
  drop_na() %>%
  ggplot(aes(x = ts, y = bytes_rx, color = config)) +
  geom_line() +
  ylab("Bytes received [Mbps]") +
  ylim(0, NA) +
  # scale_y_continuous(trans = "log10") +
  theme_half_open() +
  background_grid()
## Warning: Removed 1 row(s) containing missing values (geom_path).

network_data %>%
  mutate(bytes_rx = 8 * (bytes_rx - lag(bytes_rx)) / 1000000) %>%
  drop_na() %>%
  filter(ts >= 200 & ts <= 400) %>%
  mutate(config = map_chr(config, to_human_name)) %>%
  mutate(config = factor(config, levels = wifi_order)) %>%
  ggplot(aes(x = bytes_rx, y = config)) +
  geom_boxplot() +
  labs(x = "Bytes received [Mbps]      ", y = "AP distance") +
  xlim(0, 100) +
  # scale_x_continuous(trans = "log10") +
  theme_half_open() +
  background_grid() +
  theme(legend.position = "bottom")
## Warning: Removed 1 rows containing non-finite values (stat_boxplot).

Figure 6d

frankenstein <- network_data %>%
  mutate(Mbps = 8 * (bytes_rx - lag(bytes_rx)) / 1000000) %>%
  drop_na() %>%
  filter(ts >= 200 & ts <= 400) %>%
  mutate(config = map_chr(config, to_human_name)) %>%
  mutate(config = factor(config, levels = wifi_order)) %>%
  select(config, Mbps) %>%
  filter(config != "Wired")


data <- read_csv(here("experiments", "beat-pc-wiredadb", "usb_packet_data.csv"))
## Rows: 7053933 Columns: 7
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (4): Source, Destination, Protocol, Info
## dbl (3): No., Time, Length
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
wired <- "*Wired*<br>*(USB)*"
my.labels <- c(wired, "Near", "Far")

frankenstein <- data %>%
  filter(Source == "host") %>%
  mutate(second = as.integer(Time)) %>%
  filter(second >= 500 & second <= 1750) %>%
  group_by(second) %>%
  summarize(Mbps = 8 * sum(Length) / 1000000) %>%
  mutate(config = wired) %>%
  select(config, Mbps) %>%
  bind_rows(frankenstein)

frankenstein %>%
  mutate(config = factor(config, levels = my.labels)) %>%
  ggplot(aes(x = Mbps, y = config)) +
  geom_boxplot() +
  labs(x = "Bytes received [Mbps]      ", y = "AP distance") +
  xlim(0, 100) +
  # scale_x_continuous(trans = "log10") +
  theme_half_open() +
  background_grid() +
  theme(legend.position = "bottom") +
  theme(axis.text.y = element_markdown()) +
  annotate("rect", xmin = -Inf, xmax = Inf, ymin = .5, ymax = 1.5, alpha = .2)
## Warning: Removed 868 rows containing non-finite values (stat_boxplot).

# #Plot
# ggplot(data=samplecounts,aes(variable2,variable1))+
#   geom_col(color='black')+
#   scale_x_discrete(labels=my.labels) +
#   theme(axis.text.y = element_markdown())+
mem_data <- NULL
for (f in experiments) {
  mem_data <- system(paste('grep -Po "(?<=Free=)[0-9]+"', here("experiments", f, "logcat_VrApi.log")), intern = TRUE) %>%
    tibble(mem_usage = .) %>%
    mutate(mem_usage = 12288 - as.numeric(mem_usage)) %>%
    mutate(mem_usage = mem_usage / 1024) %>%
    mutate(ts = 0:(n() - 1)) %>%
    select(ts, everything()) %>%
    mutate(config = f) %>%
    bind_rows(mem_data, .)
}
mem_data <- mem_data %>%
  mutate(config = map_chr(config, to_human_name))
mem_data %>%
  ggplot(aes(x = ts, y = mem_usage, color = config)) +
  geom_line() +
  ylim(0, 11.5) +
  theme_half_open() +
  background_grid() +
  labs(x = "Time [s]", y = "Memory usage [GB]     ")

mem_data %>%
  ggplot(aes(x = mem_usage, y = config)) +
  geom_boxplot() +
  xlim(0, NA) +
  theme_half_open() +
  background_grid() +
  labs(x = "Memory usage [GB]    ", y = "Setup")