This analysis compares performance between the odbc package and the RStudio Professional Drivers against the RPostgreSQL package. These tests are compared on small and large tables:

There are many ways to collect data into R from a database. These methods were examined, ranked in order from best performing to least:

odbc connection

con1 <- dbConnect(odbc::odbc(),
  Driver = conf$driver,
  Database = conf$database,
  Port = conf$port,
  Server = conf$server, 
  UID = conf$UID, 
  PWD = conf$PWD
)

RPostgreSQL connection

con2 <- dbConnect(RPostgreSQL::PostgreSQL(),
  dbname = conf$database,
  port = conf$port,
  host = conf$server, 
  user = conf$UID, 
  password = conf$PWD
)

Query functions

Median result (odbc / RPostgreSQL):

cat("# dbSendQuery\n")
# dbSendQuery
f <- function(con){
  rs <- dbSendQuery(con, "select * from mtcars")
  dbFetch(rs)
  dbClearResult(rs)
}
microbenchmark(
  odbc = f(con1),
  RPostgreSQL = f(con2),
  times = 100
)
Unit: milliseconds
        expr       min        lq      mean   median        uq      max neval
        odbc  4.280109  4.424589  5.123516  4.52174  4.628829 59.40869   100
 RPostgreSQL 10.708193 10.941653 12.106602 11.01144 11.139357 86.00633   100
cat("# dbGetQuery\n")
# dbGetQuery
microbenchmark(
  odbc = dbGetQuery(con1, "select * from mtcars"),
  RPostgreSQL = dbGetQuery(con2, "select * from mtcars"),
  times = 100
)
Unit: milliseconds
        expr       min        lq      mean    median       uq       max neval
        odbc  4.369826  4.462516  4.639547  4.605441  4.78284  5.970596   100
 RPostgreSQL 11.303488 11.523170 11.844457 11.642717 11.84386 21.660472   100
cat("# dbReadTable\n")
# dbReadTable
microbenchmark(
  odbc = dbReadTable(con1, "mtcars"),
  RPostgreSQL = dbReadTable(con2, "mtcars"),
  times = 100
)
Unit: milliseconds
        expr       min        lq      mean    median        uq      max neval
        odbc  5.014894  5.224398  5.615451  5.402754  5.563106 16.63474   100
 RPostgreSQL 11.410670 11.746018 12.680341 11.995234 12.305746 45.56513   100
cat("# collect\n")
# collect
t1 <- tbl(con1, "mtcars")
t2 <- tbl(con2, "mtcars")
microbenchmark(
  odbc = collect(t1),
  RPostgreSQL = collect(t2),
  times = 100
)
Unit: milliseconds
        expr       min        lq      mean    median       uq      max neval
        odbc  6.823231  7.073533  7.937514  7.219613  7.46282 27.94842   100
 RPostgreSQL 13.195611 13.699607 14.808574 13.937911 14.55319 71.37980   100
cat("# dplyr\n")
# dplyr
microbenchmark(
  odbc = tbl(con1, "mtcars") %>% collect,
  RPostgreSQL = tbl(con2, "mtcars") %>% collect,
  times = 100
)
Unit: milliseconds
        expr      min       lq     mean   median       uq      max neval
        odbc 13.38358 13.94573 14.34430 14.22169 14.56148 19.21916   100
 RPostgreSQL 24.56986 25.83352 27.05007 26.66041 27.83492 47.06476   100

Select all

Median result (small table / large table):

cat("# Small table\n")
# Small table
microbenchmark(
  odbc = dbGetQuery(con1, "select * from mtcars"),
  RPostgreSQL = dbGetQuery(con2, "select * from mtcars"),
  times = 100
)
Unit: milliseconds
        expr       min        lq      mean    median        uq       max neval
        odbc  4.321348  4.611888  4.858451  4.855945  5.062818  6.202066   100
 RPostgreSQL 11.200706 12.134937 12.514874 12.486769 12.801218 16.967667   100
cat("# Large table\n")
# Large table
microbenchmark(
  odbc = dbGetQuery(con1, "select * from flights"),
  RPostgreSQL = dbGetQuery(con2, "select * from flights"),
  times = 5
)
Unit: seconds
        expr      min       lq     mean   median       uq      max neval
        odbc 2.591428 2.633310 2.763152 2.636291 2.692626 3.262106     5
 RPostgreSQL 4.637700 4.650428 4.713604 4.658108 4.718158 4.903626     5

Count records

Median result (small table / large table):

cat("# Small table\n")
# Small table
microbenchmark(
  odbc = dbGetQuery(con1, "select count(*) from mtcars"),
  RPostgreSQL = dbGetQuery(con2, "select count(*) from mtcars"),
  times = 100
)
Unit: milliseconds
        expr      min       lq     mean   median       uq       max neval
        odbc 3.869836 3.972087 4.277864 4.034261 4.095987 26.725616   100
 RPostgreSQL 2.092483 2.139317 2.263315 2.186958 2.311471  4.324677   100
cat("# Large table\n")
# Large table
microbenchmark(
  odbc = dbGetQuery(con1, "select count(*) from flights"),
  RPostgreSQL = dbGetQuery(con2, "select count(*) from flights"),
  times = 100
)
Unit: milliseconds
        expr      min       lq     mean   median       uq      max neval
        odbc 29.93849 30.42176 30.72725 30.72235 30.93322  33.8406   100
 RPostgreSQL 28.07182 28.47232 29.79854 28.66594 28.86219 105.1817   100

Aggregate

Median result (month / origin & dest):

cat("# By month\n")
# By month
microbenchmark(
  odbc = dbGetQuery(con1, "select month, count(*) from flights group by month"),
  RPostgreSQL = dbGetQuery(con2, "select month, count(*) from flights group by month"),
  times = 25
)
Unit: milliseconds
        expr      min       lq     mean   median       uq      max neval
        odbc 68.27169 68.52957 69.49427 69.54900 70.02755 71.79220    25
 RPostgreSQL 67.36743 67.98919 69.43012 68.41578 68.78742 92.34194    25
cat("# By origin & dest\n")
# By origin & dest
microbenchmark(
  odbc = dbGetQuery(con1, "select origin, dest, count(*) from flights group by origin, dest"),
  RPostgreSQL = dbGetQuery(con2, "select origin, dest, count(*) from flights group by origin, dest"),
  times = 25
)
Unit: milliseconds
        expr      min       lq     mean   median       uq      max neval
        odbc 124.9043 125.8146 131.6079 126.9300 127.8341 190.1420    25
 RPostgreSQL 124.2582 125.3030 126.0579 125.9069 126.5720 131.3172    25

Join and aggregate

Median result:

cat("# Join and aggregate\n")
# Join and aggregate
microbenchmark(
  odbc = dbGetQuery(con1, "select name, count(*) from flights, airports where origin = faa group by name"),
  RPostgreSQL = dbGetQuery(con2, "select name, count(*) from flights, airports where origin = faa group by name"),
  times = 25
)
Unit: milliseconds
        expr      min       lq     mean   median       uq      max neval
        odbc 151.2754 154.3244 156.4881 154.7501 155.4205 198.0783    25
 RPostgreSQL 150.3930 151.8969 154.4057 153.2702 154.3652 177.8400    25

Write table

Median result (small / large):

cat("# Small table\n")
# Small table
microbenchmark(
  odbc = dbWriteTable(con1, "tmp1", mtcars, overwrite = TRUE),
  RPostgreSQL = dbWriteTable(con2, "tmp2", mtcars, overwrite = TRUE),
  times = 25
)
Unit: milliseconds
        expr      min       lq     mean   median       uq      max neval
        odbc 78.44993 80.11186 81.54664 80.57682 81.30703 99.96081    25
 RPostgreSQL 32.84248 33.83805 34.73810 34.11803 35.70990 37.38110    25
cat("# Large table\n")
# Large table
tmpdat <- nycflights13::flights[1:1000,]
microbenchmark(
  odbc = dbWriteTable(con1, "tmp3", tmpdat, overwrite = TRUE),
  RPostgreSQL = dbWriteTable(con2, "tmp4", tmpdat, overwrite = TRUE),
  times = 5
)
Unit: milliseconds
        expr       min        lq      mean    median        uq      max neval
        odbc 769.39862 776.23975 796.75253 794.52786 820.40447 823.1920     5
 RPostgreSQL  45.63735  46.53974  47.50063  47.15208  47.90107  50.2729     5

Summary

There was no one decisive winner for all tests. The odbc R package along with the RStudio Professional Drivers was decisively faster than RPostgreSQL when collecting records. For all other operations, the differences in performance between the two packages were comparable.

LS0tCnRpdGxlOiAnUGVyZm9ybWFuY2UgY29tcGFyaXNvbjogb2RiYyB2cyBSUG9zdGdyZVNRTCcKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChjb2xsYXBzZSA9IFRSVUUpCmxpYnJhcnkoREJJKQpsaWJyYXJ5KFJQb3N0Z3JlU1FMKQpsaWJyYXJ5KG1pY3JvYmVuY2htYXJrKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShjb25maWcpCmNvbmYgPC0gZ2V0KCkKYGBgCgpUaGlzIGFuYWx5c2lzIGNvbXBhcmVzIHBlcmZvcm1hbmNlIGJldHdlZW4gdGhlIG9kYmMgcGFja2FnZSBhbmQgdGhlIFJTdHVkaW8gUHJvZmVzc2lvbmFsIERyaXZlcnMgYWdhaW5zdCB0aGUgUlBvc3RncmVTUUwgcGFja2FnZS4gVGhlc2UgdGVzdHMgYXJlIGNvbXBhcmVkIG9uIHNtYWxsIGFuZCBsYXJnZSB0YWJsZXM6CgpgYGB7ciBlY2hvPUZBTFNFfQpkYXRhLmZyYW1lKAogIFRlc3QgPSBjKCJSZWFkIiwgIkNvdW50IiwgIkdyb3VwIiwgIkpvaW4iLCAiV3JpdGUiKSwKICBvZGJjID0gYygyNzAwLCAzMSwgMTI3LjEsIDE1NC44LCA4NzYuOCksCiAgUlBvc3RncmVTUUwgPSBjKDUxMDAsIDI4LjgsIDEyNi4wLCAxNTUuMCwgNDkuNyksCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCikgJT4lCiAgZ2F0aGVyKCJwYWNrYWdlIiwgIm1pbGxpc2Vjb25kcyIsIG9kYmMsIFJQb3N0Z3JlU1FMKSAlPiUKICBnZ3Bsb3QoYWVzKHJlb3JkZXIoVGVzdCwgbWlsbGlzZWNvbmRzLCBtZWFuKSwgbWlsbGlzZWNvbmRzLCBmaWxsPXBhY2thZ2UpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsgCiAgY29vcmRfZmxpcCgpICsKICBnZ3RpdGxlKCJQZXJmb3JtYW5jZSBDb21wYXJpc29uOiBvZGJjIHZzIFJQb3N0Z3JlU1FMIiwgIk1lZGlhbiB0aW1lIGluIGxvZzEwIG1pbGxpc2Vjb25kcyIpICsKICB4bGFiKCIiKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iQmx1ZXMiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKVGhlcmUgYXJlIG1hbnkgd2F5cyB0byBjb2xsZWN0IGRhdGEgaW50byBSIGZyb20gYSBkYXRhYmFzZS4gVGhlc2UgbWV0aG9kcyB3ZXJlIGV4YW1pbmVkLCByYW5rZWQgaW4gb3JkZXIgZnJvbSBiZXN0IHBlcmZvcm1pbmcgdG8gbGVhc3Q6CgpgYGB7ciwgZWNobz1GQUxTRX0KZGF0YS5mcmFtZSgKICBGdW5jdGlvbiA9IGMoImRiU2VuZFF1ZXJ5IiwgImRiR2V0UXVlcnkiLCAiZGJSZWFkVGFibGUiLCAiZHBseXIgY29sbGVjdCBvbmx5IiwgImRwbHlyIiksCiAgTVMgPSBjKDEyLjAsIDEyLjUsIDEyLjksIDE0LjQsIDI3LjYpCikgJT4lCiAgZ2dwbG90KGFlcyhyZW9yZGVyKEZ1bmN0aW9uLCAtTVMpLCBNUykpICsKICBnZW9tX2JhcihzdGF0ID0gIklkZW50aXR5IiwgZmlsbCA9ICJzdGVlbGJsdWUiKSArCiAgY29vcmRfZmxpcCgpICsKICBnZ3RpdGxlKCJQZXJmb3JtYW5jZSBjb21wYXJpc29uOiBRdWVyeSBtZXRob2RzIiwgIk1lZGlhbiB0aW1lIGluIG1pbGxpc2Vjb25kcyIpICsKICB4bGFiKCIiKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iQmx1ZXMiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKIyMjIG9kYmMgY29ubmVjdGlvbgoKYGBge3J9CmNvbjEgPC0gZGJDb25uZWN0KG9kYmM6Om9kYmMoKSwKICBEcml2ZXIgPSBjb25mJGRyaXZlciwKICBEYXRhYmFzZSA9IGNvbmYkZGF0YWJhc2UsCiAgUG9ydCA9IGNvbmYkcG9ydCwKICBTZXJ2ZXIgPSBjb25mJHNlcnZlciwgCiAgVUlEID0gY29uZiRVSUQsIAogIFBXRCA9IGNvbmYkUFdECikKYGBgCgojIyMgUlBvc3RncmVTUUwgY29ubmVjdGlvbgoKYGBge3J9CmNvbjIgPC0gZGJDb25uZWN0KFJQb3N0Z3JlU1FMOjpQb3N0Z3JlU1FMKCksCiAgZGJuYW1lID0gY29uZiRkYXRhYmFzZSwKICBwb3J0ID0gY29uZiRwb3J0LAogIGhvc3QgPSBjb25mJHNlcnZlciwgCiAgdXNlciA9IGNvbmYkVUlELCAKICBwYXNzd29yZCA9IGNvbmYkUFdECikKYGBgCgojIyMgUXVlcnkgZnVuY3Rpb25zCgpNZWRpYW4gcmVzdWx0IChvZGJjIC8gUlBvc3RncmVTUUwpOgoKKiBkYlNlbmRRdWVyeSAoNC45IG1zIC8gMTIuMCBtcykKKiBkYkdldFF1ZXJ5ICg0LjkgbXMgLyAxMi41IG1zKQoqIGRiUmVhZFRhYmxlICg1LjggbXMgLyAxMi45IG1zKQoqIGNvbGxlY3QgKDcuNCBtcyAvIDE0LjQgbXMpCiogZHBseXIgKDE0LjkgbXMgLyAyNy42IG1zKQoKYGBge3IsIGNvbGxhcHNlPVRSVUV9CmNhdCgiIyBkYlNlbmRRdWVyeVxuIikKZiA8LSBmdW5jdGlvbihjb24pewogIHJzIDwtIGRiU2VuZFF1ZXJ5KGNvbiwgInNlbGVjdCAqIGZyb20gbXRjYXJzIikKICBkYkZldGNoKHJzKQogIGRiQ2xlYXJSZXN1bHQocnMpCn0KbWljcm9iZW5jaG1hcmsoCiAgb2RiYyA9IGYoY29uMSksCiAgUlBvc3RncmVTUUwgPSBmKGNvbjIpLAogIHRpbWVzID0gMTAwCikKY2F0KCIjIGRiR2V0UXVlcnlcbiIpCm1pY3JvYmVuY2htYXJrKAogIG9kYmMgPSBkYkdldFF1ZXJ5KGNvbjEsICJzZWxlY3QgKiBmcm9tIG10Y2FycyIpLAogIFJQb3N0Z3JlU1FMID0gZGJHZXRRdWVyeShjb24yLCAic2VsZWN0ICogZnJvbSBtdGNhcnMiKSwKICB0aW1lcyA9IDEwMAopCmNhdCgiIyBkYlJlYWRUYWJsZVxuIikKbWljcm9iZW5jaG1hcmsoCiAgb2RiYyA9IGRiUmVhZFRhYmxlKGNvbjEsICJtdGNhcnMiKSwKICBSUG9zdGdyZVNRTCA9IGRiUmVhZFRhYmxlKGNvbjIsICJtdGNhcnMiKSwKICB0aW1lcyA9IDEwMAopCmNhdCgiIyBjb2xsZWN0XG4iKQp0MSA8LSB0YmwoY29uMSwgIm10Y2FycyIpCnQyIDwtIHRibChjb24yLCAibXRjYXJzIikKbWljcm9iZW5jaG1hcmsoCiAgb2RiYyA9IGNvbGxlY3QodDEpLAogIFJQb3N0Z3JlU1FMID0gY29sbGVjdCh0MiksCiAgdGltZXMgPSAxMDAKKQpjYXQoIiMgZHBseXJcbiIpCm1pY3JvYmVuY2htYXJrKAogIG9kYmMgPSB0YmwoY29uMSwgIm10Y2FycyIpICU+JSBjb2xsZWN0LAogIFJQb3N0Z3JlU1FMID0gdGJsKGNvbjIsICJtdGNhcnMiKSAlPiUgY29sbGVjdCwKICB0aW1lcyA9IDEwMAopCmBgYAoKIyMjIFNlbGVjdCBhbGwKCk1lZGlhbiByZXN1bHQgKHNtYWxsIHRhYmxlIC8gbGFyZ2UgdGFibGUpOgoKKiBvZGJjICg1LjIgbXMgLyAyLjcgcykKKiBSUG9zdGdyZXMgKDEzLjIgbXMgLyA1LjAgcykKCmBgYHtyLCBjb2xsYXBzZT1UUlVFfQpjYXQoIiMgU21hbGwgdGFibGVcbiIpCm1pY3JvYmVuY2htYXJrKAogIG9kYmMgPSBkYkdldFF1ZXJ5KGNvbjEsICJzZWxlY3QgKiBmcm9tIG10Y2FycyIpLAogIFJQb3N0Z3JlU1FMID0gZGJHZXRRdWVyeShjb24yLCAic2VsZWN0ICogZnJvbSBtdGNhcnMiKSwKICB0aW1lcyA9IDEwMAopCmNhdCgiIyBMYXJnZSB0YWJsZVxuIikKbWljcm9iZW5jaG1hcmsoCiAgb2RiYyA9IGRiR2V0UXVlcnkoY29uMSwgInNlbGVjdCAqIGZyb20gZmxpZ2h0cyIpLAogIFJQb3N0Z3JlU1FMID0gZGJHZXRRdWVyeShjb24yLCAic2VsZWN0ICogZnJvbSBmbGlnaHRzIiksCiAgdGltZXMgPSA1CikKYGBgCgojIyMgQ291bnQgcmVjb3JkcwoKTWVkaWFuIHJlc3VsdCAoc21hbGwgdGFibGUgLyBsYXJnZSB0YWJsZSk6CgoqIG9kYmMgKDQuNiBtcyAvIDMxLjAgbXMpCiogUlBvc3RncmVTUUwgKDIuMyAgbXMgLyAyOC44IG1zKQoKYGBge3IsIGNvbGxhcHNlPVRSVUV9CmNhdCgiIyBTbWFsbCB0YWJsZVxuIikKbWljcm9iZW5jaG1hcmsoCiAgb2RiYyA9IGRiR2V0UXVlcnkoY29uMSwgInNlbGVjdCBjb3VudCgqKSBmcm9tIG10Y2FycyIpLAogIFJQb3N0Z3JlU1FMID0gZGJHZXRRdWVyeShjb24yLCAic2VsZWN0IGNvdW50KCopIGZyb20gbXRjYXJzIiksCiAgdGltZXMgPSAxMDAKKQpjYXQoIiMgTGFyZ2UgdGFibGVcbiIpCm1pY3JvYmVuY2htYXJrKAogIG9kYmMgPSBkYkdldFF1ZXJ5KGNvbjEsICJzZWxlY3QgY291bnQoKikgZnJvbSBmbGlnaHRzIiksCiAgUlBvc3RncmVTUUwgPSBkYkdldFF1ZXJ5KGNvbjIsICJzZWxlY3QgY291bnQoKikgZnJvbSBmbGlnaHRzIiksCiAgdGltZXMgPSAxMDAKKQpgYGAKCiMjIyBBZ2dyZWdhdGUKCk1lZGlhbiByZXN1bHQgKG1vbnRoIC8gb3JpZ2luICYgZGVzdCk6CgoqIG9kYmMgKDcwLjAgbXMgLyAxMjcuMSBtcykKKiBSUG9zdGdyZVNRTCAoNjguNCBtcyAvIDEyNi4wIG1zKQoKYGBge3IsIGNvbGxhcHNlPVRSVUV9CmNhdCgiIyBCeSBtb250aFxuIikKbWljcm9iZW5jaG1hcmsoCiAgb2RiYyA9IGRiR2V0UXVlcnkoY29uMSwgInNlbGVjdCBtb250aCwgY291bnQoKikgZnJvbSBmbGlnaHRzIGdyb3VwIGJ5IG1vbnRoIiksCiAgUlBvc3RncmVTUUwgPSBkYkdldFF1ZXJ5KGNvbjIsICJzZWxlY3QgbW9udGgsIGNvdW50KCopIGZyb20gZmxpZ2h0cyBncm91cCBieSBtb250aCIpLAogIHRpbWVzID0gMjUKKQpjYXQoIiMgQnkgb3JpZ2luICYgZGVzdFxuIikKbWljcm9iZW5jaG1hcmsoCiAgb2RiYyA9IGRiR2V0UXVlcnkoY29uMSwgInNlbGVjdCBvcmlnaW4sIGRlc3QsIGNvdW50KCopIGZyb20gZmxpZ2h0cyBncm91cCBieSBvcmlnaW4sIGRlc3QiKSwKICBSUG9zdGdyZVNRTCA9IGRiR2V0UXVlcnkoY29uMiwgInNlbGVjdCBvcmlnaW4sIGRlc3QsIGNvdW50KCopIGZyb20gZmxpZ2h0cyBncm91cCBieSBvcmlnaW4sIGRlc3QiKSwKICB0aW1lcyA9IDI1CikKYGBgCgojIyMgSm9pbiBhbmQgYWdncmVnYXRlCgpNZWRpYW4gcmVzdWx0OgoKKiBvZGJjICgxNTQuNyBtcykKKiBSUG9zdGdyZVNRTCAoMTUzLjkgbXMpCgpgYGB7ciwgY29sbGFwc2U9VFJVRX0KY2F0KCIjIEpvaW4gYW5kIGFnZ3JlZ2F0ZVxuIikKbWljcm9iZW5jaG1hcmsoCiAgb2RiYyA9IGRiR2V0UXVlcnkoY29uMSwgInNlbGVjdCBuYW1lLCBjb3VudCgqKSBmcm9tIGZsaWdodHMsIGFpcnBvcnRzIHdoZXJlIG9yaWdpbiA9IGZhYSBncm91cCBieSBuYW1lIiksCiAgUlBvc3RncmVTUUwgPSBkYkdldFF1ZXJ5KGNvbjIsICJzZWxlY3QgbmFtZSwgY291bnQoKikgZnJvbSBmbGlnaHRzLCBhaXJwb3J0cyB3aGVyZSBvcmlnaW4gPSBmYWEgZ3JvdXAgYnkgbmFtZSIpLAogIHRpbWVzID0gMjUKKQpgYGAKCiMjIyBXcml0ZSB0YWJsZQoKTWVkaWFuIHJlc3VsdCAoc21hbGwgLyBsYXJnZSk6CgoqIG9kYmMgKDg4LjggbXMgLyA4NzYuOCBtcykKKiBSUG9zdGdyZVNRTCAoMzkuMyBtcyAvIDQ5LjcgbXMpCgpgYGB7ciwgY29sbGFwc2U9VFJVRX0KY2F0KCIjIFNtYWxsIHRhYmxlXG4iKQptaWNyb2JlbmNobWFyaygKICBvZGJjID0gZGJXcml0ZVRhYmxlKGNvbjEsICJ0bXAxIiwgbXRjYXJzLCBvdmVyd3JpdGUgPSBUUlVFKSwKICBSUG9zdGdyZVNRTCA9IGRiV3JpdGVUYWJsZShjb24yLCAidG1wMiIsIG10Y2Fycywgb3ZlcndyaXRlID0gVFJVRSksCiAgdGltZXMgPSAyNQopCmNhdCgiIyBMYXJnZSB0YWJsZVxuIikKdG1wZGF0IDwtIG55Y2ZsaWdodHMxMzo6ZmxpZ2h0c1sxOjEwMDAsXQptaWNyb2JlbmNobWFyaygKICBvZGJjID0gZGJXcml0ZVRhYmxlKGNvbjEsICJ0bXAzIiwgdG1wZGF0LCBvdmVyd3JpdGUgPSBUUlVFKSwKICBSUG9zdGdyZVNRTCA9IGRiV3JpdGVUYWJsZShjb24yLCAidG1wNCIsIHRtcGRhdCwgb3ZlcndyaXRlID0gVFJVRSksCiAgdGltZXMgPSA1CikKYGBgCgojIyMgU3VtbWFyeQoKVGhlcmUgd2FzIG5vIG9uZSBkZWNpc2l2ZSB3aW5uZXIgZm9yIGFsbCB0ZXN0cy4gVGhlIG9kYmMgUiBwYWNrYWdlIGFsb25nIHdpdGggdGhlIFJTdHVkaW8gUHJvZmVzc2lvbmFsIERyaXZlcnMgd2FzIGRlY2lzaXZlbHkgZmFzdGVyIHRoYW4gUlBvc3RncmVTUUwgd2hlbiBjb2xsZWN0aW5nIHJlY29yZHMuIEZvciBhbGwgb3RoZXIgb3BlcmF0aW9ucywgdGhlIGRpZmZlcmVuY2VzIGluIHBlcmZvcm1hbmNlIGJldHdlZW4gdGhlIHR3byBwYWNrYWdlcyB3ZXJlIGNvbXBhcmFibGUuCgoqIFNlbGVjdCBhbGwgKG9kYmMgZmFzdGVyKQoqIENvdW50IGFsbCByZWNvcmRzIChSUG9zdGdyZVNRTCBmYXN0ZXIpCiogQWdncmVnYXRlIChSUG9zdGdyZVNRTCBmYXN0ZXIpCiogSm9pbiBhbmQgQWdncmVnYXRlIChvZGJjIGZhc3RlcikKKiBXcml0ZSB0YWJsZSAob2RiYyBmYXN0ZXIpCg==