rud.is

Measuring & Monitoring Internet Speed in R

R-bloggers Measuring & Monitoring Internet Speed in R

library(speedtest)
library(stringi)
library(hrbrthemes)
library(ggbeeswarm)
Loading required package: ggplot2
library(tidyverse)
── Attaching packages ─────────────────────────── tidyverse 1.2.0 ──
✔ tibble  1.4.1     ✔ purrr   0.2.4
✔ tidyr   0.7.2     ✔ dplyr   0.7.4
✔ readr   1.1.1     ✔ stringr 1.2.0
✔ tibble  1.4.1     ✔ forcats 0.2.0
── Conflicts ────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
config <- spd_config()
servers <- spd_servers(config=config)
closest_servers <- spd_closest_servers(servers, config=config)
only_the_best_severs <- spd_best_servers(closest_servers, config)
glimpse(spd_download_test(closest_servers[1,], config=config))

|========                                  | 20% ~1 s remaining     
|============                              | 30% ~1 s remaining     
|================                          | 40% ~1 s remaining     
|=====================                     | 50% ~1 s remaining     
|=========================                 | 60% ~1 s remaining     
|=============================             | 70% ~1 s remaining     
|=================================         | 80% ~1 s remaining     
|=====================================     | 90% ~1 s remaining     
|==========================================|100% ~0 s remaining     Observations: 1
Variables: 15
$ url     <chr> "http://speedtest.tekify.com/speedtest/upload.php"
$ lat     <dbl> 37.5483
$ lng     <dbl> -121.9886
$ name    <chr> "Fremont, CA"
$ country <chr> "United States"
$ cc      <chr> "US"
$ sponsor <chr> "Tekify Broadband Internet Services"
$ id      <chr> "6468"
$ host    <chr> "speedtest.tekify.com:8080"
$ url2    <chr> "http://speedtest.tekify.com/speedtest2/upload....
$ min     <dbl> 16.28029
$ mean    <dbl> 58.79093
$ median  <dbl> 55.71502
$ max     <dbl> 103.3104
$ sd      <dbl> 30.87936
glimpse(spd_upload_test(only_the_best_severs[1,], config=config))

|==============                            | 33% ~0 s remaining     
|=====================                     | 50% ~0 s remaining     
|============================              | 67% ~0 s remaining     
|===================================       | 83% ~0 s remaining     
|==========================================|100% ~0 s remaining     Observations: 1
Variables: 17
$ total_time     <dbl> 0.072741
$ retrieval_time <dbl> 3.2e-05
$ url            <chr> "http://speedtest-pa.singnet.com.sg/spee...
$ lat            <dbl> 37.4419
$ lng            <dbl> -122.1419
$ name           <chr> "Palo Alto, CA"
$ country        <chr> "United States"
$ cc             <chr> "US"
$ sponsor        <chr> "SingTel"
$ id             <chr> "2761"
$ host           <chr> "speedtest-pa.singnet.com.sg:8080"
$ url2           <chr> "http://speedtest-pa2.singnet.com.sg/spe...
$ min            <dbl> 11.6966
$ mean           <dbl> 12.68652
$ median         <dbl> 12.23808
$ max            <dbl> 14.36649
$ sd             <dbl> 1.132289
set.seed(8675309)
bind_rows(
  closest_servers[1:3,] %>%
    mutate(type="closest"),
  only_the_best_severs[1:3,] %>%
    mutate(type="best"),
  filter(servers, !(id %in% c(closest_servers[1:3,]$id, only_the_best_severs[1:3,]$id))) %>%
    sample_n(3) %>%
    mutate(type="random")
) %>%
  group_by(type) %>%
  ungroup() -> to_compare
select(to_compare, sponsor, name, country, host, type)
map_df(1:nrow(to_compare), ~{
  spd_download_test(to_compare[.x,], config=config, summarise=FALSE, timeout=30)
}) -> dl_results_full

|========                                   | 20% ~1 s remaining     
|============                               | 30% ~1 s remaining     
|=================                          | 40% ~1 s remaining     
|=====================                      | 50% ~1 s remaining     
|=========================                  | 60% ~1 s remaining     
|==============================             | 70% ~1 s remaining     
|==================================         | 80% ~1 s remaining     
|======================================     | 90% ~1 s remaining     
|===========================================|100% ~0 s remaining     
|========                                   | 20% ~1 s remaining     
|============                               | 30% ~1 s remaining     
|=================                          | 40% ~1 s remaining     
|=====================                      | 50% ~0 s remaining     
|=========================                  | 60% ~0 s remaining     
|==============================             | 70% ~0 s remaining     
|==================================         | 80% ~1 s remaining     
|======================================     | 90% ~1 s remaining     
|===========================================|100% ~0 s remaining     
|========                                   | 20% ~1 s remaining     
|============                               | 30% ~1 s remaining     
|=================                          | 40% ~1 s remaining     
|=====================                      | 50% ~1 s remaining     
|=========================                  | 60% ~1 s remaining     
|==============================             | 70% ~1 s remaining     
|==================================         | 80% ~1 s remaining     
|======================================     | 90% ~0 s remaining     
|===========================================|100% ~0 s remaining     
|============                               | 30% ~0 s remaining     
|=================                          | 40% ~0 s remaining     
|=====================                      | 50% ~0 s remaining     
|=========================                  | 60% ~0 s remaining     
|==============================             | 70% ~0 s remaining     
|==================================         | 80% ~0 s remaining     
|======================================     | 90% ~0 s remaining     
|===========================================|100% ~0 s remaining     
|========                                   | 20% ~1 s remaining     
|============                               | 30% ~1 s remaining     
|=================                          | 40% ~1 s remaining     
|=====================                      | 50% ~1 s remaining     
|=========================                  | 60% ~1 s remaining     
|==============================             | 70% ~1 s remaining     
|==================================         | 80% ~1 s remaining     
|======================================     | 90% ~0 s remaining     
|===========================================|100% ~0 s remaining     
|========                                   | 20% ~1 s remaining     
|============                               | 30% ~1 s remaining     
|=================                          | 40% ~1 s remaining     
|=====================                      | 50% ~1 s remaining     
|=========================                  | 60% ~1 s remaining     
|==============================             | 70% ~1 s remaining     
|==================================         | 80% ~1 s remaining     
|======================================     | 90% ~0 s remaining     
|===========================================|100% ~0 s remaining     
|========                                   | 20% ~7 s remaining     
|============                               | 30% ~5 s remaining     
|=================                          | 40% ~4 s remaining     
|=====================                      | 50% ~3 s remaining     
|=========================                  | 60% ~2 s remaining     
|==============================             | 70% ~2 s remaining     
|==================================         | 80% ~2 s remaining     
|======================================     | 90% ~1 s remaining     
|===========================================|100% ~0 s remaining     
|========                                   | 20% ~1 s remaining     
|============                               | 30% ~1 s remaining     
|=================                          | 40% ~0 s remaining     
|=====================                      | 50% ~0 s remaining     
|=========================                  | 60% ~0 s remaining     
|==============================             | 70% ~0 s remaining     
|==================================         | 80% ~0 s remaining     
|======================================     | 90% ~0 s remaining     
|===========================================|100% ~0 s remaining     
|========                                   | 20% ~16 s remaining    
|============                               | 30% ~25 s remaining    
|=================                          | 40% ~34 s remaining    
|=====================                      | 50% ~28 s remaining    
|=========================                  | 60% ~24 s remaining    
|==============================             | 70% ~28 s remaining    
|==================================         | 80% ~24 s remaining    
|======================================     | 90% ~13 s remaining    
|===========================================|100% ~0 s remaining     
mutate(dl_results_full, type=stri_trans_totitle(type)) %>%
  ggplot(aes(type, bw, fill=type)) +
  geom_quasirandom(aes(size=size, color=type), width=0.15, shape=21, stroke=0.25) +
  scale_y_continuous(expand=c(0,5), labels=c(sprintf("%s", seq(0,150,50)), "200 Mb/s"), limits=c(0,200)) +
  scale_size(range=c(2,6)) +
  scale_color_manual(values=c(Random="#b2b2b2", Best="#2b2b2b", Closest="#2b2b2b")) +
  scale_fill_ipsum() +
  labs(x=NULL, y=NULL, title="Download bandwidth test by selected server type",
       subtitle="Circle size scaled by size of file used in that speed test") +
  theme_ipsum_rc(grid="Y") +
  theme(legend.position="none")

bind_rows(
  closest_servers[1:3,] %>% mutate(type="closest"),
  only_the_best_severs[1:3,] %>% mutate(type="best")
) %>%
  distinct(.keep_all=TRUE) -> to_compare
select(to_compare, sponsor, name, country, host, type)
map_df(1:nrow(to_compare), ~{
  spd_upload_test(to_compare[.x,], config=config, summarise=FALSE, timeout=30)
}) -> ul_results_full

|==============                             | 33% ~0 s remaining     
|=====================                      | 50% ~0 s remaining     
|============================               | 67% ~0 s remaining     
|===================================        | 83% ~0 s remaining     
|===========================================|100% ~0 s remaining     
|==============                             | 33% ~1 s remaining     
|=====================                      | 50% ~1 s remaining     
|============================               | 67% ~1 s remaining     
|===================================        | 83% ~0 s remaining     
|===========================================|100% ~0 s remaining     
|==============                             | 33% ~1 s remaining     
|=====================                      | 50% ~1 s remaining     
|============================               | 67% ~1 s remaining     
|===================================        | 83% ~1 s remaining     
|===========================================|100% ~0 s remaining     
|==============                             | 33% ~0 s remaining     
|=====================                      | 50% ~0 s remaining     
|============================               | 67% ~0 s remaining     
|===================================        | 83% ~0 s remaining     
|===========================================|100% ~0 s remaining     
|==============                             | 33% ~0 s remaining     
|=====================                      | 50% ~0 s remaining     
|============================               | 67% ~0 s remaining     
|===================================        | 83% ~0 s remaining     
|===========================================|100% ~0 s remaining     
|==============                             | 33% ~0 s remaining     
|=====================                      | 50% ~0 s remaining     
|============================               | 67% ~0 s remaining     
|===================================        | 83% ~0 s remaining     
|===========================================|100% ~0 s remaining     
ggplot(ul_results_full, aes(x="Upload Test", y=bw)) +
  geom_quasirandom(aes(size=size, fill="col"), width=0.1, shape=21, stroke=0.25, color="#2b2b2b") +
  scale_y_continuous(expand=c(0,0.5), breaks=seq(0,16,4),
                     labels=c(sprintf("%s", seq(0,12,4)), "16 Mb/s"), limits=c(0,16)) +
  scale_size(range=c(2,6)) +
  scale_fill_ipsum() +
  labs(x=NULL, y=NULL, title="Upload bandwidth test by selected server type",
       subtitle="Circle size scaled by size of file used in that speed test") +
  theme_ipsum_rc(grid="Y") +
  theme(legend.position="none")

LS0tCnRpdGxlOiAic3BlZWR0ZXN0MDEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCltydWQuaXNdKGh0dHBzOi8vcnVkLmlzL2IvKQoKW01lYXN1cmluZyAmIE1vbml0b3JpbmcgSW50ZXJuZXQgU3BlZWQgaW4gUl0oaHR0cHM6Ly9ydWQuaXMvYi8yMDE3LzExLzExL21lYXN1cmluZy1tb25pdG9yaW5nLWludGVybmV0LXNwZWVkLXdpdGgtci8pCgpbUi1ibG9nZ2VycyBNZWFzdXJpbmcgJiBNb25pdG9yaW5nIEludGVybmV0IFNwZWVkIGluIFJdKGh0dHBzOi8vd3d3LnItYmxvZ2dlcnMuY29tL21lYXN1cmluZy1tb25pdG9yaW5nLWludGVybmV0LXNwZWVkLXdpdGgtci8pCgoKYGBge3J9CmxpYnJhcnkoc3BlZWR0ZXN0KQpsaWJyYXJ5KHN0cmluZ2kpCmxpYnJhcnkoaHJicnRoZW1lcykKbGlicmFyeShnZ2JlZXN3YXJtKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgoKYGBge3J9CmNvbmZpZyA8LSBzcGRfY29uZmlnKCkKCnNlcnZlcnMgPC0gc3BkX3NlcnZlcnMoY29uZmlnPWNvbmZpZykKY2xvc2VzdF9zZXJ2ZXJzIDwtIHNwZF9jbG9zZXN0X3NlcnZlcnMoc2VydmVycywgY29uZmlnPWNvbmZpZykKb25seV90aGVfYmVzdF9zZXZlcnMgPC0gc3BkX2Jlc3Rfc2VydmVycyhjbG9zZXN0X3NlcnZlcnMsIGNvbmZpZykKYGBgCgpgYGB7cn0KZ2xpbXBzZShzcGRfZG93bmxvYWRfdGVzdChjbG9zZXN0X3NlcnZlcnNbMSxdLCBjb25maWc9Y29uZmlnKSkKYGBgCgoKCmBgYHtyfQpnbGltcHNlKHNwZF91cGxvYWRfdGVzdChvbmx5X3RoZV9iZXN0X3NldmVyc1sxLF0sIGNvbmZpZz1jb25maWcpKQpgYGAKCmBgYHtyfQpzZXQuc2VlZCg4Njc1MzA5KQoKYmluZF9yb3dzKAoKICBjbG9zZXN0X3NlcnZlcnNbMTozLF0gJT4lCiAgICBtdXRhdGUodHlwZT0iY2xvc2VzdCIpLAoKICBvbmx5X3RoZV9iZXN0X3NldmVyc1sxOjMsXSAlPiUKICAgIG11dGF0ZSh0eXBlPSJiZXN0IiksCgogIGZpbHRlcihzZXJ2ZXJzLCAhKGlkICVpbiUgYyhjbG9zZXN0X3NlcnZlcnNbMTozLF0kaWQsICBvbmx5X3RoZV9iZXN0X3NldmVyc1sxOjMsXSRpZCkpKSAlPiUKICAgIHNhbXBsZV9uKDMpICU+JQogICAgbXV0YXRlKHR5cGU9InJhbmRvbSIpCgopICU+JQogIGdyb3VwX2J5KHR5cGUpICU+JQogIHVuZ3JvdXAoKSAtPiB0b19jb21wYXJlCgpzZWxlY3QodG9fY29tcGFyZSwgc3BvbnNvciwgbmFtZSwgY291bnRyeSwgaG9zdCwgdHlwZSkKYGBgCgoKYGBge3J9Cm1hcF9kZigxOm5yb3codG9fY29tcGFyZSksIH57CiAgc3BkX2Rvd25sb2FkX3Rlc3QodG9fY29tcGFyZVsueCxdLCBjb25maWc9Y29uZmlnLCBzdW1tYXJpc2U9RkFMU0UsIHRpbWVvdXQ9MzApCn0pIC0+IGRsX3Jlc3VsdHNfZnVsbAoKbXV0YXRlKGRsX3Jlc3VsdHNfZnVsbCwgdHlwZT1zdHJpX3RyYW5zX3RvdGl0bGUodHlwZSkpICU+JQogIGdncGxvdChhZXModHlwZSwgYncsIGZpbGw9dHlwZSkpICsKICBnZW9tX3F1YXNpcmFuZG9tKGFlcyhzaXplPXNpemUsIGNvbG9yPXR5cGUpLCB3aWR0aD0wLjE1LCBzaGFwZT0yMSwgc3Ryb2tlPTAuMjUpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kPWMoMCw1KSwgbGFiZWxzPWMoc3ByaW50ZigiJXMiLCBzZXEoMCwxNTAsNTApKSwgIjIwMCBNYi9zIiksIGxpbWl0cz1jKDAsMjAwKSkgKwogIHNjYWxlX3NpemUocmFuZ2U9YygyLDYpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKFJhbmRvbT0iI2IyYjJiMiIsIEJlc3Q9IiMyYjJiMmIiLCBDbG9zZXN0PSIjMmIyYjJiIikpICsKICBzY2FsZV9maWxsX2lwc3VtKCkgKwogIGxhYnMoeD1OVUxMLCB5PU5VTEwsIHRpdGxlPSJEb3dubG9hZCBiYW5kd2lkdGggdGVzdCBieSBzZWxlY3RlZCBzZXJ2ZXIgdHlwZSIsCiAgICAgICBzdWJ0aXRsZT0iQ2lyY2xlIHNpemUgc2NhbGVkIGJ5IHNpemUgb2YgZmlsZSB1c2VkIGluIHRoYXQgc3BlZWQgdGVzdCIpICsKICB0aGVtZV9pcHN1bV9yYyhncmlkPSJZIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpCmBgYAoKYGBge3J9CmJpbmRfcm93cygKICBjbG9zZXN0X3NlcnZlcnNbMTozLF0gJT4lIG11dGF0ZSh0eXBlPSJjbG9zZXN0IiksCiAgb25seV90aGVfYmVzdF9zZXZlcnNbMTozLF0gJT4lIG11dGF0ZSh0eXBlPSJiZXN0IikKKSAlPiUKICBkaXN0aW5jdCgua2VlcF9hbGw9VFJVRSkgLT4gdG9fY29tcGFyZQoKc2VsZWN0KHRvX2NvbXBhcmUsIHNwb25zb3IsIG5hbWUsIGNvdW50cnksIGhvc3QsIHR5cGUpCgptYXBfZGYoMTpucm93KHRvX2NvbXBhcmUpLCB+ewogIHNwZF91cGxvYWRfdGVzdCh0b19jb21wYXJlWy54LF0sIGNvbmZpZz1jb25maWcsIHN1bW1hcmlzZT1GQUxTRSwgdGltZW91dD0zMCkKfSkgLT4gdWxfcmVzdWx0c19mdWxsCgpnZ3Bsb3QodWxfcmVzdWx0c19mdWxsLCBhZXMoeD0iVXBsb2FkIFRlc3QiLCB5PWJ3KSkgKwogIGdlb21fcXVhc2lyYW5kb20oYWVzKHNpemU9c2l6ZSwgZmlsbD0iY29sIiksIHdpZHRoPTAuMSwgc2hhcGU9MjEsIHN0cm9rZT0wLjI1LCBjb2xvcj0iIzJiMmIyYiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kPWMoMCwwLjUpLCBicmVha3M9c2VxKDAsMTYsNCksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKHNwcmludGYoIiVzIiwgc2VxKDAsMTIsNCkpLCAiMTYgTWIvcyIpLCBsaW1pdHM9YygwLDE2KSkgKwogIHNjYWxlX3NpemUocmFuZ2U9YygyLDYpKSArCiAgc2NhbGVfZmlsbF9pcHN1bSgpICsKICBsYWJzKHg9TlVMTCwgeT1OVUxMLCB0aXRsZT0iVXBsb2FkIGJhbmR3aWR0aCB0ZXN0IGJ5IHNlbGVjdGVkIHNlcnZlciB0eXBlIiwKICAgICAgIHN1YnRpdGxlPSJDaXJjbGUgc2l6ZSBzY2FsZWQgYnkgc2l6ZSBvZiBmaWxlIHVzZWQgaW4gdGhhdCBzcGVlZCB0ZXN0IikgKwogIHRoZW1lX2lwc3VtX3JjKGdyaWQ9IlkiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikKYGBgCgoK