diff --git a/_freeze/slides/debugging/index/execute-results/html.json b/_freeze/slides/debugging/index/execute-results/html.json index ae27743..7384319 100644 --- a/_freeze/slides/debugging/index/execute-results/html.json +++ b/_freeze/slides/debugging/index/execute-results/html.json @@ -1,8 +1,8 @@ { - "hash": "37d1438d65894950f2595fb337b993ac", + "hash": "1ddabd08f6a0ad667fdee614a10740dc", "result": { "engine": "knitr", - "markdown": "---\ntitle: \"Debugging, Profiling, and a Bit of Optimization\"\nauthor: \"Marcin Kierczak\"\nimage: \"assets/featured.jpg\"\nformat: revealjs\n---\n\n\n## {visibility=\"hidden\"}\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(tictoc)\nlibrary(DT)\nlibrary(profvis)\n# library(Rgraphviz)\nlibrary(proftools) # depends on \"graph\" and \"Rgraphviz\" packages\nlibrary(profr)\nlibrary(pryr)\nlibrary(microbenchmark)\nlibrary(ggplot2)\n# remotes::install_github(\"hadley/emo\")\nlibrary(emo)\n# remotes::install_github(\"cdeterman/gpuR\")\n#library(gpuR)\n```\n:::\n\n\n## Run Forrest, run!\n:::{.columns}\n:::{.column width=\"50%\"}\n\n


\n\n:::{.incremental}\n- *My code does not run!* -- **debugging**

\n- *Now it does run but... out of memory!* -- **profiling**

\n- *It runs! It says it will finish in 5 ~~minutes~~ years.* -- **optimization**\n:::\n:::\n:::{.column width=\"50%\"}\n\n:::\n::: \n\n## Types of bugs {background-image=\"assets/featured.jpg\"}\n\n- ๐Ÿ”ฃ Syntax errors\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"1|2\"}\nprin(var1) \nmean(sum(seq((x + 2) * (y - 9 * b))))\n```\n:::\n\n\n. . .\n\n- ๐Ÿ”ข Arithmetic \n\n\n::: {.cell}\n\n```{.r .cell-code}\ny <- 7 / 0\n```\n:::\n\n*Not in R though! `y = Inf`*\n\n. . .\n\n- ๐ŸŽ๐ŸŠ Type \n\n\n::: {.cell}\n\n```{.r .cell-code}\nmean('a')\n```\n:::\n\n\n. . .\n\n- ๐Ÿงฉ Logic\n\nEverything works and produces seemingly valid output that is WRONG! \nIMHO those are the hardest ๐Ÿ’€ to debug!\n\n## How to avoid bugs\n


\n\n:::{.incremental}\n- Encapsulate your code in smaller units ๐Ÿฑ (functions), you can test.

\n- Use classes and type checking ๐Ÿ†—.

\n- Test ๐Ÿงช at the boundaries, e.g. loops at min and max value.

\n- Feed your functions with test data ๐Ÿ’พ that should result with a known output.

\n- Use *antibugging* ๐Ÿ•ธ: `stopifnot(y <= 75)`\n:::\n\n## Floating confusion\n\n

\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"1|2-3\"}\n(vec <- seq(0.1, 0.9, by=0.1))\nvec == 0.7 \nvec == 0.5\n```\n:::\n\n\n. . .\n\n\n::: {.cell}\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9\n[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE\n[1] FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE\n```\n\n\n:::\n:::\n\n\n. . .\n\n
\n\n\n::: {.cell}\n\n```{.r .cell-code}\n(0.5 + 0.1) - 0.6\n(0.7 + 0.1) - 0.8 \n```\n:::\n\n\n. . .\n\n\n::: {.cell}\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] 0\n[1] -1.110223e-16\n```\n\n\n:::\n:::\n\n\n
\n\n
\n๐Ÿ’€ Beware of floating point arithmetic! ๐Ÿ’€\n
\n\n## How to float ๐ŸŠ\n

\n\n\n::: {.cell}\n\n```{.r .cell-code}\nround((0.7 + 0.1) , digits = 2) - 0.8\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] 0\n```\n\n\n:::\n:::\n\n\n. . .\n\nComparing floating point numbers: \n\n\n::: {.cell}\n\n```{.r .cell-code}\n(vec <- seq(0.1, 0.9, by=0.1))\nvec == 0.7\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9\n[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE\n```\n\n\n:::\n:::\n\n\n. . .\n\n\n::: {.cell}\n\n```{.r .cell-code}\nepsilon <- 0.001\nabs(vec - 0.7) <= epsilon\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE\n```\n\n\n:::\n:::\n\n\n## Final thoughts on floating \n\n\n::: {.cell}\n\n```{.r .cell-code}\nhead(unlist(.Machine))\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n double.eps double.neg.eps double.xmin double.xmax double.base \n 2.220446e-16 1.110223e-16 2.225074e-308 1.797693e+308 2.000000e+00 \n double.digits \n 5.300000e+01 \n```\n\n\n:::\n:::\n\n\n. . .\n\n\n::: {.cell}\n\n```{.r .cell-code}\nhead(unlist(.Platform))\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n OS.type file.sep dynlib.ext GUI endian pkgType \n \"unix\" \"/\" \".so\" \"X11\" \"little\" \"source\" \n```\n\n\n:::\n:::\n\n\n## Handling Errors\n\nLet us generate some errors:\n\n\n::: {.cell}\n\n```{.r .cell-code}\ninput <- c(1, 10, -7, -2/5, 0, 'char', 100, pi, NaN)\nfor (val in input) {\n (paste0('Log of ', val, 'is ', log10(val)))\n}\n```\n\n::: {.cell-output .cell-output-error}\n\n```\nError in log10(val): non-numeric argument to mathematical function\n```\n\n\n:::\n:::\n\n\n. . .\n\n:::{.columns}\n:::{.column width=\"30%\"}\n\n\n\n:::\n:::{.column width=\"70%\"}\n\n



So, how to handle this mess?\n\n:::\n:::\n\n## Handling Errors -- `try`\n

\n\n\n::: {.cell}\n\n```{.r .cell-code}\ntry(\n print(\n paste0('Log of ', input, ' is ', log10(as.numeric(input)))\n )\n)\n```\n:::\n\n\n. . .\n\n\n::: {.cell}\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] \"Log of 1 is 0\" \n[2] \"Log of 10 is 1\" \n[3] \"Log of -7 is NaN\" \n[4] \"Log of -0.4 is NaN\" \n[5] \"Log of 0 is -Inf\" \n[6] \"Log of char is NA\" \n[7] \"Log of 100 is 2\" \n[8] \"Log of 3.14159265358979 is 0.497149872694133\"\n[9] \"Log of NaN is NaN\" \n```\n\n\n:::\n:::\n\n\n## Handling Errors -- `tryCatch` block:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nresult <- tryCatch(log10(val), \n warning = function(w) { \n print('Warning! Negative argument supplied. Negating.') \n log10(-val) }, \n error = function(e) { \n print('ERROR! Not a number!')\n NaN\n }\n )\n```\n:::\n\n\n. . .\n\n\n::: {.cell}\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] \"Log of 1 is 0\"\n[1] \"Log of 10 is 1\"\n[1] \"Warning! Negative argument supplied. Negating.\"\n[1] \"Log of -7 is 0.845098040014257\"\n[1] \"Warning! Negative argument supplied. Negating.\"\n[1] \"Log of -0.4 is -0.397940008672038\"\n[1] \"Log of 0 is -Inf\"\n[1] \"Log of NA is NA\"\n[1] \"Log of 100 is 2\"\n[1] \"Log of 3.14159265358979 is 0.497149872694133\"\n[1] \"Log of NaN is NaN\"\n```\n\n\n:::\n:::\n\n\n## Debugging -- errors and warnings\n\n:::{.incremental}\n- An error in your code will result in a call to the `stop()` function that:\n - Breaks the execution of the program (loop, if-statement, etc.)\n - Performs the action defined by the global parameter `error`.\n- A warning just prints out the warning message (or reports it in another way)\n:::\n\n. . .\n\n- Global parameter `error` defines what R should do when an error occurs.\n\n\n::: {.cell}\n\n```{.r .cell-code}\noptions(error = )\n```\n:::\n\n\n. . .\n\n- You can use `simpleError()` and `simpleWarning()` to generate errors and warnings in your code:\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"4\"}\nf <- function(x) {\n if (x < 0) {\n x <- abs(x)\n w <- simpleWarning(\"Value less than 0. Taking abs(x)\")\n w\n }\n}\n```\n:::\n\n\n## Debugging -- what are my options?\n\n- Old-school debugging: a lot of `print` statements\n - print values of your variables at some checkpoints,\n - sometimes fine but often laborious,\n - need to remove/comment out manually after debugging.\n\n. . .\n\n- Dumping frames\n - on error, R state will be saved to a file,\n - file can be read into debugger,\n - values of all variables can be checked,\n - can debug on another machine, e.g. send dump to your colleague!\n \n. . .\n\n- Traceback\n - a list of the recent function calls with values of their parameters\n \n. . .\n\n- Step-by-step debugging\n - execute code line by line within the debugger\n\n## Option 1: dumping frames\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"2|4-6\"}\nf <- function(x) { sin(x) }\noptions(error = quote(dump.frames(dumpto = \"assets/testdump\", to.file = T)))\nf('test')\noptions(error = NULL) # reset the behavior\nload('assets/testdump.rda')\n# debugger(testdump)\n```\n:::\n\nHint: Last empty line brings you back to the environments menu.\n\n## Option 2: traceback\n\n\n::: {.cell}\n\n```{.r .cell-code}\nf <- function(x) { \n log10(x) \n}\ng <- function(x) { \n f(x) \n}\ng('test')\n```\n\n::: {.cell-output .cell-output-error}\n\n```\nError in log10(x): non-numeric argument to mathematical function\n```\n\n\n:::\n:::\n\n\n. . .\n\n```\n> traceback()\n2: f(x) at #2\n1: g(\"test\")\n```\n\n`traceback()` shows what were the function calls and what parameters were passed to them when the error occurred.\n\n## Option 3: step-by-step debugging\n\n:::: {.columns}\n::: {.column width=\"50%\"}\n\nLet us define a new function `h(x, y)`:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nh <- function(x, y) { \n f(x) \n f(y) \n}\n```\n:::\n\n\nNow, we can use `debug()` to debug the function in a step-by-step manner:\n\n\n::: {.cell}\n\n```{.r .cell-code}\ndebug(h)\nh('text', 7)\nundebug(h)\n```\n:::\n\n\n:::\n\n::: {.column .fragment width=\"50%\"}\n\n![](assets/debug.png)\n\n:::\n::::\n\n## Profiling -- `proc.time()`\n\nProfiling is the process of **identifying memory** and time **bottlenecks** ๐Ÿผ in your code.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nproc.time()\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n user system elapsed \n 2.204 1.819 1.519 \n```\n\n\n:::\n:::\n\n\n- `user time` -- CPU time charged for the execution of user instructions of the calling process,\n- `system time` -- CPU time charged for execution by the system on behalf of the calling process,\n- `elapsed time` -- total CPU time elapsed for the currently running R process.\n\n. . .\n\n\n::: {.cell}\n\n```{.r .cell-code}\npt1 <- proc.time()\ntmp <- runif(n = 10e5)\npt2 <- proc.time()\npt2 - pt1\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n user system elapsed \n 0.014 0.000 0.015 \n```\n\n\n:::\n:::\n\n\n## Profiling -- `system.time()`\n\n\n::: {.cell}\n\n```{.r .cell-code}\nsystem.time(runif(n = 10e6))\nsystem.time(rnorm(n = 10e6))\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n user system elapsed \n 0.167 0.002 0.168 \n user system elapsed \n 0.596 0.002 0.598 \n```\n\n\n:::\n:::\n\n\n. . .\n\nAn alternative approach is to use `tic` and `toc` statements from the `tictoc` package.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(tictoc)\ntic()\ntmp1 <- runif(n = 10e6)\ntoc()\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n0.135 sec elapsed\n```\n\n\n:::\n:::\n\n\n## Profiling in action\n\nThese 4 functions fill a **large vector** with values supplied by function `f`.\n\n. . .\n\n1 -- loop without memory allocation.\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"2|3-5\"}\nfun_fill_loop1 <- function(n = 10e6, f) {\n result <- NULL\n for (i in 1:n) {\n result <- c(result, eval(call(f, 1)))\n }\n return(result)\n}\n```\n:::\n\n\n. . .\n\n2 -- loop with memory allocation.\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"2|3-5\"}\nfun_fill_loop2 <- function(n = 10e6, f) {\n result <- vector(length = n)\n for (i in 1:n) {\n result[i] <- eval(call(f, 1))\n }\n return(result)\n}\n```\n:::\n\n\n## Profiling in action cted.\n\nBut it is maybe better to use...\n\n. . .\n\nvectorization!\n\n. . .\n\n3 -- vectorized loop without memory allocation.\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"2|3\"}\nfun_fill_vec1 <- function(n = 10e6, f) {\n result <- NULL\n result <- eval(call(f, n))\n return(result)\n}\n```\n:::\n\n\n. . .\n\n4 -- vectorized with memory allocation.\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"2|3\"}\nfun_fill_vec2 <- function(n = 10e6, f) {\n result <- vector(length = n)\n result <- eval(call(f, n))\n return(result)\n}\n```\n:::\n\n\n## Profiling our functions\n
\n\n\n::: {.cell}\n\n```{.r .cell-code}\np1 <- system.time(fun_fill_loop1(n = 10e4, \"runif\")) # 1 - loop, no alloc\np2 <- system.time(fun_fill_loop2(n = 10e4, \"runif\")) # 2 - loop, alloc \np3 <- system.time(fun_fill_vec1(n = 10e4, \"runif\")) # 3 - vector, no alloc\np4 <- system.time(fun_fill_vec2(n = 10e4, \"runif\")) # 4 - vector, alloc\n```\n:::\n\n\n|fn | user.self| sys.self| elapsed|\n|:---|---------:|--------:|-------:|\n|fn1 | 7.641| 0.05| 7.692|\n|fn2 | 0.320| 0.00| 0.320|\n|fn3 | 0.001| 0.00| 0.001|\n|fn4 | 0.002| 0.00| 0.002|\n\n\nThe `system.time()` function is not the most accurate though. During the lab, we will experiment with package `microbenchmark`.\n\n## More advanced profiling\n\nWe can also do a bit more advanced profiling, including the memory profiling, using, e.g. `Rprof()` function.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nRprof('profiler_test.out', interval = 0.01, memory.profiling = T)\nfor (i in 1:5) {\n result <- fun_fill_loop2(n = 10e4, \"runif\")\n print(result)\n}\nRprof(NULL)\n```\n:::\n\n\nAnd let us summarise:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nsummary <- summaryRprof(\"profiler_test.out\", memory = \"both\")\n#unlink(\"profiler_test.out\")\nknitr::kable(summary$by.self)\n```\n\n::: {.cell-output-display}\n\n\n| | self.time| self.pct| total.time| total.pct| mem.total|\n|:----------------|---------:|--------:|----------:|---------:|---------:|\n|\"runif\" | 2.13| 48.41| 2.13| 48.41| 1899.0|\n|\"eval\" | 1.04| 23.64| 3.29| 74.77| 3334.7|\n|\"print.default\" | 0.85| 19.32| 0.85| 19.32| 72.1|\n|\"fun_fill_loop2\" | 0.24| 5.45| 3.53| 80.23| 3646.3|\n|\"parent.frame\" | 0.06| 1.36| 0.06| 1.36| 64.6|\n|\"is.list\" | 0.05| 1.14| 0.05| 1.14| 82.3|\n|\"is.pairlist\" | 0.01| 0.23| 0.01| 0.23| 23.1|\n|\"mayCallBrowser\" | 0.01| 0.23| 0.01| 0.23| 1.0|\n|\"strsplit\" | 0.01| 0.23| 0.01| 0.23| 0.4|\n\n\n:::\n:::\n\n\n## Profiling -- `profr` package\n\nThere are also packages available that enable even more advanced profiling:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(profr)\nRprof(\"profiler_test2.out\", interval = 0.01)\ntmp <- table(sort(rnorm(1e5)))\nRprof(NULL)\nprofile_df <- parse_rprof('profiler_test2.out')\n```\n:::\n\n\nThis returns a table that can be visualised:\n\n\n\n\n::: {.cell}\n::: {.cell-output-display}\n\n\n| level| g_id| t_id|f | start| end| n|leaf | time|source |\n|-----:|----:|----:|:-----------------------|-----:|----:|--:|:-----|----:|:------|\n| 1| 1| 1|.main | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 2| 1| 1|execute | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 3| 1| 1|rmarkdown::render | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 4| 1| 1|knitr::knit | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 5| 1| 1|process_file | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 6| 1| 1|handle_error | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 7| 1| 1|withCallingHandlers | 0.00| 0.40| 1|FALSE | 0.40|base |\n| 8| 1| 1|withCallingHandlers | 0.00| 0.40| 1|FALSE | 0.40|base |\n| 9| 1| 1|process_group | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 10| 1| 1|process_group.block | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 11| 1| 1|call_block | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 12| 1| 1|block_exec | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 13| 1| 1|eng_r | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 14| 1| 1|in_input_dir | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 15| 1| 1|in_dir | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 16| 1| 1|evaluate | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 17| 1| 1|evaluate::evaluate | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 18| 1| 1|evaluate_call | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 19| 1| 1|timing_fn | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 20| 1| 1|handle | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 21| 1| 1|withCallingHandlers | 0.00| 0.40| 1|FALSE | 0.40|base |\n| 22| 1| 1|withVisible | 0.00| 0.40| 1|FALSE | 0.40|base |\n| 23| 1| 1|eval_with_user_handlers | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 24| 1| 1|eval | 0.00| 0.40| 1|FALSE | 0.40|base |\n| 25| 1| 1|eval | 0.00| 0.40| 1|FALSE | 0.40|base |\n| 26| 1| 1|table | 0.00| 0.40| 1|FALSE | 0.40|base |\n| 27| 1| 1|factor | 0.00| 0.38| 1|FALSE | 0.38|base |\n| 28| 1| 1|order | 0.00| 0.02| 1|TRUE | 0.02|base |\n| 28| 2| 1|unique | 0.02| 0.22| 1|FALSE | 0.20|base |\n| 29| 1| 1|unique.default | 0.02| 0.22| 1|TRUE | 0.20|base |\n\n\n:::\n:::\n\n\n## Profiling -- `profr` package cted.\n\nWe can also plot the results using -- `proftools` package-\n\n\n::: {.cell layout-align=\"center\"}\n\n```{.r .cell-code}\nlibrary(proftools)\nprofile_df2 <- readProfileData(\"profiler_test2.out\")\nplotProfileCallGraph(profile_df2, style = google.style, score = \"total\")\n```\n\n::: {.cell-output-display}\n![](index_files/figure-revealjs/show_profr_result_plot-1.png){fig-align='center' width=384}\n:::\n:::\n\n\n## Profiling with `profvis`\n\nYet another nice way to profile your code is by using Hadley Wickham's `profvis` package:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(profvis)\nprofvis({fun_fill_loop2(1e4, 'runif')\n fun_fill_vec2(1e4, 'runif')\n})\n```\n:::\n\n\n## Profiling with `profvis` cted.\n\n\n::: {.cell}\n::: {.cell-output-display}\n\n```{=html}\n
\n\n```\n\n:::\n:::\n\n\n## Optimizing your code\n\n::: {.blockquote}\nWe should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%. A good programmer will not be deluded into complacency by such reasoning, he will be wise to look carefully at the critical code; but only after that code has been identified.\n\n-- Donald Knuth\n:::\n\n:::: {.columns}\n::: {.column width=\"50%\"}\n![](assets/xkcd_automation.png){height=\"350px\"} \n[source: http://www.xkcd/com/1319]{.smaller}\n:::\n\n::: {.column width=\"50%\"}\n![](assets/xkcd_is_it_worth_the_time_2x.png){height=\"350px\"} \n[source: http://www.xkcd/com/1205]{.smaller}\n:::\n::::\n\n## Ways to optimize the code\n\n:::{.incremental}\n- write it in a more efficient way, e.g. use vectorization or `*apply` family instead of loops etc.,\n- allocating memory to avoid copy-on-modify,\n- use package `BLAS` for linear algebra,\n- use `bigmemory` package,\n- GPU computations,\n- multicore support, e.g. `multicore`, `snow`\n- use `futures`\n- use `data.table` or `tibble` instead of `data.frame`\n:::\n\n## Copy-on-modify\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(pryr)\norder <- 1024\nmatrix_A <- matrix(rnorm(order^2), nrow = order)\nmatrix_B <- matrix_A\n```\n:::\n\n\n. . .\n\nCheck where the objects are in the memory:\n\n. . .\n\n\n::: {.cell}\n\n```{.r .cell-code}\naddress(matrix_A)\naddress(matrix_B)\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] \"0x7fff977ff010\"\n[1] \"0x7fff977ff010\"\n```\n\n\n:::\n:::\n\n\n. . .\n\nWhat happens if we modify a value in one of the matrices?\n\n. . .\n\n\n::: {.cell}\n\n```{.r .cell-code}\nmatrix_B[1,1] <- 1\naddress(matrix_A)\naddress(matrix_B)\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] \"0x7fff977ff010\"\n[1] \"0x7fff96ffe010\"\n```\n\n\n:::\n:::\n\n\n## Avoid copying by allocating memory\n\nNo memory allocation\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"2|5\"}\nf1 <- function(to = 3, silent=F) {\n tmp <- c()\n for (i in 1:to) {\n a1 <- address(tmp)\n tmp <- c(tmp, i)\n a2 <- address(tmp)\n if (!silent) { print(paste0(a1, \" --> \", a2)) } \n }\n}\nf1()\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] \"0x5555555747c0 --> 0x555559c1a5a0\"\n[1] \"0x555559c1a5a0 --> 0x555559bd2a40\"\n[1] \"0x555559bd2a40 --> 0x55555b9a32e8\"\n```\n\n\n:::\n:::\n\n\n## Avoid copying by allocating memory cted.\n\nWith memory allocation\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"2|5\"}\nf2 <- function(to = 3, silent = FALSE) {\n tmp <- vector(length = to, mode='numeric')\n for (i in 1:to) {\n a1 <- address(tmp)\n tmp[i] <- i\n a2 <- address(tmp)\n if(!silent) { print(paste0(a1, \" --> \", a2)) }\n }\n}\nf2()\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] \"0x55555d85acb8 --> 0x55555d85acb8\"\n[1] \"0x55555d85acb8 --> 0x55555d85acb8\"\n[1] \"0x55555d85acb8 --> 0x55555d85acb8\"\n```\n\n\n:::\n:::\n\n\n## Allocating memory -- benchmark.\n\n\n::: {.cell layout-align=\"center\"}\n\n```{.r .cell-code}\nlibrary(microbenchmark)\nbenchmrk <- microbenchmark(f1(to = 1e3, silent = T), \n f2(to = 1e3, silent = T), \n times = 100L)\nggplot2::autoplot(benchmrk)\n```\n\n::: {.cell-output-display}\n![](index_files/figure-revealjs/unnamed-chunk-9-1.png){fig-align='center' width=960}\n:::\n:::\n\n\n## GPU\n\n\n::: {.cell}\n\n```{.r .cell-code}\nA = matrix(rnorm(1000^2), nrow=1000) # stored: RAM, computed: CPU\nB = matrix(rnorm(1000^2), nrow=1000) \ngpuA = gpuMatrix(A, type = \"float\") # stored: RAM, computed: GPU\ngpuB = gpuMatrix(B, type = \"float\")\nvclA = vclMatrix(A, type = \"float\") # stored: GPU, computed: GPU\nvclB = vclMatrix(B, type = \"float\")\nbch <- microbenchmark(\n cpu_ram = A %*% B,\n gpu_ram = gpuA %*% gpuB,\n gpu_vcl = vclA %*% vclB, \n times = 10L) \n```\n:::\n\n\n[More on [Charles Determan's Blog](https://www.r-bloggers.com/r-gpu-programming-for-all-with-gpur/).]{.smaller}\n\n## GPU cted.\n\n\n::: {.cell layout-align=\"center\"}\n\n```{.r .cell-code}\nggplot2::autoplot(bch)\n```\n:::\n\n\n![](assets/gpu.png)\n\n## Parallelization using package `parallel`\n\nEasiest to parallelize is `lapply`:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nresult <- lapply(1:2, function(x) { c(x, x^2, x^3) })\nresult\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[[1]]\n[1] 1 1 1\n\n[[2]]\n[1] 2 4 8\n```\n\n\n:::\n:::\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(parallel)\nnum_cores <- detectCores() - 1\ncl <- makeCluster(num_cores) # Init cluster\nparLapply(cl, 1:2, function(x) { c(x, x^2, x^3)} )\nstopCluster(cl)\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[[1]]\n[1] 1 1 1\n\n[[2]]\n[1] 2 4 8\n```\n\n\n:::\n:::\n\n\n## {background-image=\"/assets/images/cover.jpg\"}\n\n### Thank you! Questions?\n\n\n::: {.cell}\n::: {.cell-output .cell-output-stdout}\n\n```\n _ \nplatform x86_64-pc-linux-gnu\nos linux-gnu \nmajor 4 \nminor 3.2 \n```\n\n\n:::\n:::\n\n\n[{{< meta current_year >}} โ€ข [SciLifeLab](https://www.scilifelab.se/) โ€ข [NBIS](https://nbis.se/) โ€ข [RaukR](https://nbisweden.github.io/raukr-2024)]{.smaller}\n", + "markdown": "---\ntitle: \"Debugging, Profiling, and a Bit of Optimization\"\nauthor: \"Marcin Kierczak\"\nimage: \"assets/featured.jpg\"\nformat: revealjs\n---\n\n\n## {visibility=\"hidden\"}\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(tictoc)\nlibrary(DT)\nlibrary(profvis)\n# library(Rgraphviz)\nlibrary(proftools) # depends on \"graph\" and \"Rgraphviz\" packages\nlibrary(profr)\nlibrary(pryr)\nlibrary(microbenchmark)\nlibrary(ggplot2)\n# remotes::install_github(\"hadley/emo\")\nlibrary(emo)\n# remotes::install_github(\"cdeterman/gpuR\")\n#library(gpuR)\n```\n:::\n\n\n## Run Forrest, run!\n:::{.columns}\n:::{.column width=\"50%\"}\n\n


\n\n:::{.incremental}\n- *My code does not run!* -- **debugging**

\n- *Now it does run but... out of memory!* -- **profiling**

\n- *It runs! It says it will finish in 5 ~~minutes~~ years.* -- **optimization**\n:::\n:::\n:::{.column width=\"50%\"}\n\n:::\n::: \n\n## Types of bugs {background-image=\"assets/featured.jpg\"}\n\n- ๐Ÿ”ฃ Syntax errors\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"1|2\"}\nprin(var1) \nmean(sum(seq((x + 2) * (y - 9 * b))))\n```\n:::\n\n\n. . .\n\n- ๐Ÿ”ข Arithmetic \n\n\n::: {.cell}\n\n```{.r .cell-code}\ny <- 7 / 0\n```\n:::\n\n*Not in R though! `y = Inf`*\n\n. . .\n\n- ๐ŸŽ๐ŸŠ Type \n\n\n::: {.cell}\n\n```{.r .cell-code}\nmean('a')\n```\n:::\n\n\n. . .\n\n- ๐Ÿงฉ Logic\n\nEverything works and produces seemingly valid output that is WRONG! \nIMHO those are the hardest ๐Ÿ’€ to debug!\n\n## How to avoid bugs\n


\n\n:::{.incremental}\n- Encapsulate your code in smaller units ๐Ÿฑ (functions), you can test.

\n- Use classes and type checking ๐Ÿ†—.

\n- Test ๐Ÿงช at the boundaries, e.g. loops at min and max value.

\n- Feed your functions with test data ๐Ÿ’พ that should result with a known output.

\n- Use *antibugging* ๐Ÿ•ธ: `stopifnot(y <= 75)`\n:::\n\n## Floating confusion\n\n

\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"1|2-3\"}\n(vec <- seq(0.1, 0.9, by=0.1))\nvec == 0.7 \nvec == 0.5\n```\n:::\n\n\n. . .\n\n\n::: {.cell}\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9\n[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE\n[1] FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE\n```\n\n\n:::\n:::\n\n\n. . .\n\n
\n\n\n::: {.cell}\n\n```{.r .cell-code}\n(0.5 + 0.1) - 0.6\n(0.7 + 0.1) - 0.8 \n```\n:::\n\n\n. . .\n\n\n::: {.cell}\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] 0\n[1] -1.110223e-16\n```\n\n\n:::\n:::\n\n\n
\n\n
\n๐Ÿ’€ Beware of floating point arithmetic! ๐Ÿ’€\n
\n\n## How to float ๐ŸŠ\n

\n\n\n::: {.cell}\n\n```{.r .cell-code}\nround((0.7 + 0.1) , digits = 2) - 0.8\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] 0\n```\n\n\n:::\n:::\n\n\n. . .\n\nComparing floating point numbers: \n\n\n::: {.cell}\n\n```{.r .cell-code}\n(vec <- seq(0.1, 0.9, by=0.1))\nvec == 0.7\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9\n[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE\n```\n\n\n:::\n:::\n\n\n. . .\n\n\n::: {.cell}\n\n```{.r .cell-code}\nepsilon <- 0.001\nabs(vec - 0.7) <= epsilon\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE\n```\n\n\n:::\n:::\n\n\n## Final thoughts on floating \n\n\n::: {.cell}\n\n```{.r .cell-code}\nhead(unlist(.Machine))\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n double.eps double.neg.eps double.xmin double.xmax double.base \n 2.220446e-16 1.110223e-16 2.225074e-308 1.797693e+308 2.000000e+00 \n double.digits \n 5.300000e+01 \n```\n\n\n:::\n:::\n\n\n. . .\n\n\n::: {.cell}\n\n```{.r .cell-code}\nhead(unlist(.Platform))\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n OS.type file.sep dynlib.ext GUI endian pkgType \n \"unix\" \"/\" \".so\" \"X11\" \"little\" \"source\" \n```\n\n\n:::\n:::\n\n\n## Handling Errors\n\nLet us generate some errors:\n\n\n::: {.cell}\n\n```{.r .cell-code}\ninput <- c(1, 10, -7, -2/5, 0, 'char', 100, pi, NaN)\nfor (val in input) {\n (paste0('Log of ', val, 'is ', log10(val)))\n}\n```\n\n::: {.cell-output .cell-output-error}\n\n```\nError in log10(val): non-numeric argument to mathematical function\n```\n\n\n:::\n:::\n\n\n. . .\n\n:::{.columns}\n:::{.column width=\"30%\"}\n\n\n\n:::\n:::{.column width=\"70%\"}\n\n



So, how to handle this mess?\n\n:::\n:::\n\n## Handling Errors -- `try`\n

\n\n\n::: {.cell}\n\n```{.r .cell-code}\ntry(\n print(\n paste0('Log of ', input, ' is ', log10(as.numeric(input)))\n )\n)\n```\n:::\n\n\n. . .\n\n\n::: {.cell}\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] \"Log of 1 is 0\" \n[2] \"Log of 10 is 1\" \n[3] \"Log of -7 is NaN\" \n[4] \"Log of -0.4 is NaN\" \n[5] \"Log of 0 is -Inf\" \n[6] \"Log of char is NA\" \n[7] \"Log of 100 is 2\" \n[8] \"Log of 3.14159265358979 is 0.497149872694133\"\n[9] \"Log of NaN is NaN\" \n```\n\n\n:::\n:::\n\n\n## Handling Errors -- `tryCatch` block:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nresult <- tryCatch(log10(val), \n warning = function(w) { \n print('Warning! Negative argument supplied. Negating.') \n log10(-val) }, \n error = function(e) { \n print('ERROR! Not a number!')\n NaN\n }\n )\n```\n:::\n\n\n. . .\n\n\n::: {.cell}\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] \"Log of 1 is 0\"\n[1] \"Log of 10 is 1\"\n[1] \"Warning! Negative argument supplied. Negating.\"\n[1] \"Log of -7 is 0.845098040014257\"\n[1] \"Warning! Negative argument supplied. Negating.\"\n[1] \"Log of -0.4 is -0.397940008672038\"\n[1] \"Log of 0 is -Inf\"\n[1] \"Log of NA is NA\"\n[1] \"Log of 100 is 2\"\n[1] \"Log of 3.14159265358979 is 0.497149872694133\"\n[1] \"Log of NaN is NaN\"\n```\n\n\n:::\n:::\n\n\n## Debugging -- errors and warnings\n\n:::{.incremental}\n- An error in your code will result in a call to the `stop()` function that:\n - Breaks the execution of the program (loop, if-statement, etc.)\n - Performs the action defined by the global parameter `error`.\n- A warning just prints out the warning message (or reports it in another way)\n:::\n\n. . .\n\n- Global parameter `error` defines what R should do when an error occurs.\n\n\n::: {.cell}\n\n```{.r .cell-code}\noptions(error = )\n```\n:::\n\n\n. . .\n\n- You can use `simpleError()` and `simpleWarning()` to generate errors and warnings in your code:\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"4\"}\nf <- function(x) {\n if (x < 0) {\n x <- abs(x)\n w <- simpleWarning(\"Value less than 0. Taking abs(x)\")\n w\n }\n}\n```\n:::\n\n\n## Debugging -- what are my options?\n\n- Old-school debugging: a lot of `print` statements\n - print values of your variables at some checkpoints,\n - sometimes fine but often laborious,\n - need to remove/comment out manually after debugging.\n\n. . .\n\n- Dumping frames\n - on error, R state will be saved to a file,\n - file can be read into debugger,\n - values of all variables can be checked,\n - can debug on another machine, e.g. send dump to your colleague!\n \n. . .\n\n- Traceback\n - a list of the recent function calls with values of their parameters\n \n. . .\n\n- Step-by-step debugging\n - execute code line by line within the debugger\n\n## Option 1: dumping frames\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"2|4-6\"}\nf <- function(x) { sin(x) }\noptions(error = quote(dump.frames(dumpto = \"assets/testdump\", to.file = T)))\nf('test')\noptions(error = NULL) # reset the behavior\nload('assets/testdump.rda')\n# debugger(testdump)\n```\n:::\n\nHint: Last empty line brings you back to the environments menu.\n\n## Option 2: traceback\n\n\n::: {.cell}\n\n```{.r .cell-code}\nf <- function(x) { \n log10(x) \n}\ng <- function(x) { \n f(x) \n}\ng('test')\n```\n\n::: {.cell-output .cell-output-error}\n\n```\nError in log10(x): non-numeric argument to mathematical function\n```\n\n\n:::\n:::\n\n\n. . .\n\n```\n> traceback()\n2: f(x) at #2\n1: g(\"test\")\n```\n\n`traceback()` shows what were the function calls and what parameters were passed to them when the error occurred.\n\n## Option 3: step-by-step debugging\n\n:::: {.columns}\n::: {.column width=\"50%\"}\n\nLet us define a new function `h(x, y)`:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nh <- function(x, y) { \n f(x) \n f(y) \n}\n```\n:::\n\n\nNow, we can use `debug()` to debug the function in a step-by-step manner:\n\n\n::: {.cell}\n\n```{.r .cell-code}\ndebug(h)\nh('text', 7)\nundebug(h)\n```\n:::\n\n\n:::\n\n::: {.column .fragment width=\"50%\"}\n\n![](assets/debug.png)\n\n:::\n::::\n\n## Profiling -- `proc.time()`\n\nProfiling is the process of **identifying memory** and time **bottlenecks** ๐Ÿพ in your code.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nproc.time()\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n user system elapsed \n 1.798 0.708 1.532 \n```\n\n\n:::\n:::\n\n\n- `user time` -- CPU time charged for the execution of user instructions of the calling process,\n- `system time` -- CPU time charged for execution by the system on behalf of the calling process,\n- `elapsed time` -- total CPU time elapsed for the currently running R process.\n\n. . .\n\n\n::: {.cell}\n\n```{.r .cell-code}\npt1 <- proc.time()\ntmp <- runif(n = 10e5)\npt2 <- proc.time()\npt2 - pt1\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n user system elapsed \n 0.017 0.007 0.025 \n```\n\n\n:::\n:::\n\n\n## Profiling -- `system.time()`\n\n\n::: {.cell}\n\n```{.r .cell-code}\nsystem.time(runif(n = 10e6))\nsystem.time(rnorm(n = 10e6))\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n user system elapsed \n 0.260 0.009 0.268 \n user system elapsed \n 0.433 0.020 0.454 \n```\n\n\n:::\n:::\n\n\n. . .\n\nAn alternative approach is to use `tic` and `toc` statements from the `tictoc` package.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(tictoc)\ntic()\ntmp1 <- runif(n = 10e6)\ntoc()\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n0.228 sec elapsed\n```\n\n\n:::\n:::\n\n\n## Profiling in action\n\nThese 4 functions fill a **large vector** with values supplied by function `f`.\n\n. . .\n\n1 -- loop without memory allocation.\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"2|3-5\"}\nfun_fill_loop1 <- function(n = 10e6, f) {\n result <- NULL\n for (i in 1:n) {\n result <- c(result, eval(call(f, 1)))\n }\n return(result)\n}\n```\n:::\n\n\n. . .\n\n2 -- loop with memory allocation.\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"2|3-5\"}\nfun_fill_loop2 <- function(n = 10e6, f) {\n result <- vector(length = n)\n for (i in 1:n) {\n result[i] <- eval(call(f, 1))\n }\n return(result)\n}\n```\n:::\n\n\n## Profiling in action cted.\n\nBut it is maybe better to use...\n\n. . .\n\nvectorization!\n\n. . .\n\n3 -- vectorized loop without memory allocation.\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"2|3\"}\nfun_fill_vec1 <- function(n = 10e6, f) {\n result <- NULL\n result <- eval(call(f, n))\n return(result)\n}\n```\n:::\n\n\n. . .\n\n4 -- vectorized with memory allocation.\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"2|3\"}\nfun_fill_vec2 <- function(n = 10e6, f) {\n result <- vector(length = n)\n result <- eval(call(f, n))\n return(result)\n}\n```\n:::\n\n\n## Profiling our functions\n
\n\n\n::: {.cell}\n\n```{.r .cell-code}\np1 <- system.time(fun_fill_loop1(n = 10e4, \"runif\")) # 1 - loop, no alloc\np2 <- system.time(fun_fill_loop2(n = 10e4, \"runif\")) # 2 - loop, alloc \np3 <- system.time(fun_fill_vec1(n = 10e4, \"runif\")) # 3 - vector, no alloc\np4 <- system.time(fun_fill_vec2(n = 10e4, \"runif\")) # 4 - vector, alloc\n```\n:::\n\n\n|fn | user.self| sys.self| elapsed|\n|:---|---------:|--------:|-------:|\n|fn1 | 11.973| 0.099| 12.073|\n|fn2 | 0.386| 0.032| 0.418|\n|fn3 | 0.002| 0.000| 0.002|\n|fn4 | 0.002| 0.000| 0.002|\n\n\nThe `system.time()` function is not the most accurate though. During the lab, we will experiment with package `microbenchmark`.\n\n## More advanced profiling\n\nWe can also do a bit more advanced profiling, including the memory profiling, using, e.g. `Rprof()` function.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nRprof('profiler_test.out', interval = 0.01, memory.profiling = T)\nfor (i in 1:5) {\n result <- fun_fill_loop2(n = 10e4, \"runif\")\n print(result)\n}\nRprof(NULL)\n```\n:::\n\n\nAnd let us summarise:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nsummary <- summaryRprof(\"profiler_test.out\", memory = \"both\")\nknitr::kable(summary$by.self)\n```\n\n::: {.cell-output-display}\n\n\n| | self.time| self.pct| total.time| total.pct| mem.total|\n|:----------------|---------:|--------:|----------:|---------:|---------:|\n|\"runif\" | 2.13| 48.41| 2.13| 48.41| 1899.0|\n|\"eval\" | 1.04| 23.64| 3.29| 74.77| 3334.7|\n|\"print.default\" | 0.85| 19.32| 0.85| 19.32| 72.1|\n|\"fun_fill_loop2\" | 0.24| 5.45| 3.53| 80.23| 3646.3|\n|\"parent.frame\" | 0.06| 1.36| 0.06| 1.36| 64.6|\n|\"is.list\" | 0.05| 1.14| 0.05| 1.14| 82.3|\n|\"is.pairlist\" | 0.01| 0.23| 0.01| 0.23| 23.1|\n|\"mayCallBrowser\" | 0.01| 0.23| 0.01| 0.23| 1.0|\n|\"strsplit\" | 0.01| 0.23| 0.01| 0.23| 0.4|\n\n\n:::\n:::\n\n\n## Profiling -- `profr` package\n\nThere are also packages available that enable even more advanced profiling:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(profr)\nRprof(\"profiler_test2.out\", interval = 0.01)\ntmp <- table(sort(rnorm(1e5)))\nRprof(NULL)\nprofile_df <- parse_rprof('profiler_test2.out')\n```\n:::\n\n\nThis returns a table that can be visualised:\n\n\n\n\n::: {.cell}\n::: {.cell-output-display}\n\n\n| level| g_id| t_id|f | start| end| n|leaf | time|source |\n|-----:|----:|----:|:-----------------------|-----:|----:|--:|:-----|----:|:------|\n| 1| 1| 1|.main | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 2| 1| 1|execute | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 3| 1| 1|rmarkdown::render | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 4| 1| 1|knitr::knit | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 5| 1| 1|process_file | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 6| 1| 1|handle_error | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 7| 1| 1|withCallingHandlers | 0.00| 0.40| 1|FALSE | 0.40|base |\n| 8| 1| 1|withCallingHandlers | 0.00| 0.40| 1|FALSE | 0.40|base |\n| 9| 1| 1|process_group | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 10| 1| 1|process_group.block | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 11| 1| 1|call_block | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 12| 1| 1|block_exec | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 13| 1| 1|eng_r | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 14| 1| 1|in_input_dir | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 15| 1| 1|in_dir | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 16| 1| 1|evaluate | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 17| 1| 1|evaluate::evaluate | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 18| 1| 1|evaluate_call | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 19| 1| 1|timing_fn | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 20| 1| 1|handle | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 21| 1| 1|withCallingHandlers | 0.00| 0.40| 1|FALSE | 0.40|base |\n| 22| 1| 1|withVisible | 0.00| 0.40| 1|FALSE | 0.40|base |\n| 23| 1| 1|eval_with_user_handlers | 0.00| 0.40| 1|FALSE | 0.40|NA |\n| 24| 1| 1|eval | 0.00| 0.40| 1|FALSE | 0.40|base |\n| 25| 1| 1|eval | 0.00| 0.40| 1|FALSE | 0.40|base |\n| 26| 1| 1|table | 0.00| 0.40| 1|FALSE | 0.40|base |\n| 27| 1| 1|factor | 0.00| 0.40| 1|FALSE | 0.40|base |\n| 28| 1| 1|unique | 0.00| 0.22| 1|TRUE | 0.22|base |\n| 29| 1| 1|unique.default | 0.02| 0.22| 1|TRUE | 0.20|base |\n\n\n:::\n:::\n\n\n## Profiling -- `profr` package cted.\n\nWe can also plot the results using -- `proftools` package-\n\n\n::: {.cell layout-align=\"center\"}\n\n```{.r .cell-code}\nlibrary(proftools)\nprofile_df2 <- readProfileData(\"profiler_test2.out\")\nplotProfileCallGraph(profile_df2, style = google.style, score = \"total\")\n```\n\n::: {.cell-output-display}\n![](index_files/figure-revealjs/show_profr_result_plot-1.png){fig-align='center' width=384}\n:::\n:::\n\n\n## Profiling with `profvis`\n\nYet another nice way to profile your code is by using Hadley Wickham's `profvis` package:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(profvis)\nprofvis({fun_fill_loop2(1e4, 'runif')\n fun_fill_vec2(1e4, 'runif')\n})\n```\n:::\n\n\n## Profiling with `profvis` cted.\n\n\n::: {.cell}\n::: {.cell-output-display}\n\n```{=html}\n
\n\n```\n\n:::\n:::\n\n\n## Optimizing your code\n\n::: {.blockquote}\nWe should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%. A good programmer will not be deluded into complacency by such reasoning, he will be wise to look carefully at the critical code; but only after that code has been identified.\n\n-- Donald Knuth\n:::\n\n:::: {.columns}\n::: {.column width=\"50%\"}\n![](assets/xkcd_automation.png){height=\"350px\"} \n[source: http://www.xkcd/com/1319]{.smaller}\n:::\n\n::: {.column width=\"50%\"}\n![](assets/xkcd_is_it_worth_the_time_2x.png){height=\"350px\"} \n[source: http://www.xkcd/com/1205]{.smaller}\n:::\n::::\n\n## Ways to optimize the code\n\n:::{.incremental}\n- write it in a more efficient way, e.g. use vectorization or `*apply` family instead of loops etc.,\n- allocating memory to avoid copy-on-modify,\n- use package `BLAS` for linear algebra,\n- use `bigmemory` package,\n- GPU computations,\n- multicore support, e.g. `multicore`, `snow`\n- use `futures`\n- use `data.table` or `tibble` instead of `data.frame`\n:::\n\n## Copy-on-modify\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(pryr)\norder <- 1024\nmatrix_A <- matrix(rnorm(order^2), nrow = order)\nmatrix_B <- matrix_A\n```\n:::\n\n\n. . .\n\nCheck where the objects are in the memory:\n\n. . .\n\n\n::: {.cell}\n\n```{.r .cell-code}\naddress(matrix_A)\naddress(matrix_B)\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] \"0x7fe490ab0010\"\n[1] \"0x7fe490ab0010\"\n```\n\n\n:::\n:::\n\n\n. . .\n\nWhat happens if we modify a value in one of the matrices?\n\n. . .\n\n\n::: {.cell}\n\n```{.r .cell-code}\nmatrix_B[1,1] <- 1\naddress(matrix_A)\naddress(matrix_B)\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] \"0x7fe490ab0010\"\n[1] \"0x7fe4902af010\"\n```\n\n\n:::\n:::\n\n\n## Avoid copying by allocating memory\n\nNo memory allocation\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"2|5\"}\nf1 <- function(to = 3, silent=F) {\n tmp <- c()\n for (i in 1:to) {\n a1 <- address(tmp)\n tmp <- c(tmp, i)\n a2 <- address(tmp)\n if (!silent) { print(paste0(a1, \" --> \", a2)) } \n }\n}\nf1()\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] \"0x561c9d55e560 --> 0x561ca3e80678\"\n[1] \"0x561ca3e80678 --> 0x561ca3e802f8\"\n[1] \"0x561ca3e802f8 --> 0x561ca3e71908\"\n```\n\n\n:::\n:::\n\n\n## Avoid copying by allocating memory cted.\n\nWith memory allocation\n\n\n::: {.cell}\n\n```{.r .cell-code code-line-numbers=\"2|5\"}\nf2 <- function(to = 3, silent = FALSE) {\n tmp <- vector(length = to, mode='numeric')\n for (i in 1:to) {\n a1 <- address(tmp)\n tmp[i] <- i\n a2 <- address(tmp)\n if(!silent) { print(paste0(a1, \" --> \", a2)) }\n }\n}\nf2()\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] \"0x561ca87f50d8 --> 0x561ca87f50d8\"\n[1] \"0x561ca87f50d8 --> 0x561ca87f50d8\"\n[1] \"0x561ca87f50d8 --> 0x561ca87f50d8\"\n```\n\n\n:::\n:::\n\n\n## Allocating memory -- benchmark.\n\n\n::: {.cell layout-align=\"center\"}\n\n```{.r .cell-code}\nlibrary(microbenchmark)\nbenchmrk <- microbenchmark(f1(to = 1e3, silent = T), \n f2(to = 1e3, silent = T), \n times = 100L)\nggplot2::autoplot(benchmrk)\n```\n\n::: {.cell-output-display}\n![](index_files/figure-revealjs/unnamed-chunk-9-1.png){fig-align='center' width=960}\n:::\n:::\n\n\n## GPU\n\n\n::: {.cell}\n\n```{.r .cell-code}\nA = matrix(rnorm(1000^2), nrow=1000) # stored: RAM, computed: CPU\nB = matrix(rnorm(1000^2), nrow=1000) \ngpuA = gpuMatrix(A, type = \"float\") # stored: RAM, computed: GPU\ngpuB = gpuMatrix(B, type = \"float\")\nvclA = vclMatrix(A, type = \"float\") # stored: GPU, computed: GPU\nvclB = vclMatrix(B, type = \"float\")\nbch <- microbenchmark(\n cpu_ram = A %*% B,\n gpu_ram = gpuA %*% gpuB,\n gpu_vcl = vclA %*% vclB, \n times = 10L) \n```\n:::\n\n\n[More on [Charles Determan's Blog](https://www.r-bloggers.com/r-gpu-programming-for-all-with-gpur/).]{.smaller}\n\n## GPU cted.\n\n\n::: {.cell layout-align=\"center\"}\n\n```{.r .cell-code}\nggplot2::autoplot(bch)\n```\n:::\n\n\n![](assets/gpu.png)\n\n## Parallelization using package `parallel`\n\nEasiest to parallelize is `lapply`:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nresult <- lapply(1:2, function(x) { c(x, x^2, x^3) })\nresult\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[[1]]\n[1] 1 1 1\n\n[[2]]\n[1] 2 4 8\n```\n\n\n:::\n:::\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(parallel)\nnum_cores <- detectCores() - 1\ncl <- makeCluster(num_cores) # Init cluster\nparLapply(cl, 1:2, function(x) { c(x, x^2, x^3)} )\nstopCluster(cl)\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[[1]]\n[1] 1 1 1\n\n[[2]]\n[1] 2 4 8\n```\n\n\n:::\n:::\n\n\n## {background-image=\"/assets/images/cover.jpg\"}\n\n### Thank you! Questions?\n\n\n::: {.cell}\n::: {.cell-output .cell-output-stdout}\n\n```\n _ \nplatform x86_64-pc-linux-gnu\nos linux-gnu \nmajor 4 \nminor 3.2 \n```\n\n\n:::\n:::\n\n\n[{{< meta current_year >}} โ€ข [SciLifeLab](https://www.scilifelab.se/) โ€ข [NBIS](https://nbis.se/) โ€ข [RaukR](https://nbisweden.github.io/raukr-2024)]{.smaller}\n", "supporting": [], "filters": [ "rmarkdown/pagebreak.lua" diff --git a/_freeze/slides/debugging/index/figure-revealjs/show_profr_result_plot-1.png b/_freeze/slides/debugging/index/figure-revealjs/show_profr_result_plot-1.png index 284f764..1880042 100644 Binary files a/_freeze/slides/debugging/index/figure-revealjs/show_profr_result_plot-1.png and b/_freeze/slides/debugging/index/figure-revealjs/show_profr_result_plot-1.png differ diff --git a/_freeze/slides/debugging/index/figure-revealjs/unnamed-chunk-9-1.png b/_freeze/slides/debugging/index/figure-revealjs/unnamed-chunk-9-1.png index 257d614..ecb8f84 100644 Binary files a/_freeze/slides/debugging/index/figure-revealjs/unnamed-chunk-9-1.png and b/_freeze/slides/debugging/index/figure-revealjs/unnamed-chunk-9-1.png differ diff --git a/docs/404.html b/docs/404.html index 9a48fd6..fca983a 100644 --- a/docs/404.html +++ b/docs/404.html @@ -572,7 +572,7 @@

404: Page not found

- diff --git a/docs/labs/scripting/index.html b/docs/labs/scripting/index.html index b9a1203..a44d4d6 100644 --- a/docs/labs/scripting/index.html +++ b/docs/labs/scripting/index.html @@ -211,7 +211,7 @@

Functions & Scripts

Published
-

27-Jun-2023

+

21-Jun-2024

@@ -842,7 +842,7 @@

- +
+ @@ -1533,8 +1520,8 @@

Copy-on-modify

address(matrix_A)
 address(matrix_B)
-
[1] "0x7fff977ff010"
-[1] "0x7fff977ff010"
+
[1] "0x7fe490ab0010"
+[1] "0x7fe490ab0010"
@@ -1547,8 +1534,8 @@

Copy-on-modify

address(matrix_A) address(matrix_B)
-
[1] "0x7fff977ff010"
-[1] "0x7fff96ffe010"
+
[1] "0x7fe490ab0010"
+[1] "0x7fe4902af010"
@@ -1568,9 +1555,9 @@

Avoid copying by allocating memory

} f1()
-
[1] "0x5555555747c0 --> 0x555559c1a5a0"
-[1] "0x555559c1a5a0 --> 0x555559bd2a40"
-[1] "0x555559bd2a40 --> 0x55555b9a32e8"
+
[1] "0x561c9d55e560 --> 0x561ca3e80678"
+[1] "0x561ca3e80678 --> 0x561ca3e802f8"
+[1] "0x561ca3e802f8 --> 0x561ca3e71908"
@@ -1589,9 +1576,9 @@

Avoid copying by allocating memory cted.

} f2()
-
[1] "0x55555d85acb8 --> 0x55555d85acb8"
-[1] "0x55555d85acb8 --> 0x55555d85acb8"
-[1] "0x55555d85acb8 --> 0x55555d85acb8"
+
[1] "0x561ca87f50d8 --> 0x561ca87f50d8"
+[1] "0x561ca87f50d8 --> 0x561ca87f50d8"
+[1] "0x561ca87f50d8 --> 0x561ca87f50d8"
diff --git a/docs/slides/debugging/index_files/figure-revealjs/show_profr_result_plot-1.png b/docs/slides/debugging/index_files/figure-revealjs/show_profr_result_plot-1.png index 284f764..1880042 100644 Binary files a/docs/slides/debugging/index_files/figure-revealjs/show_profr_result_plot-1.png and b/docs/slides/debugging/index_files/figure-revealjs/show_profr_result_plot-1.png differ diff --git a/docs/slides/debugging/index_files/figure-revealjs/unnamed-chunk-10-1.png b/docs/slides/debugging/index_files/figure-revealjs/unnamed-chunk-10-1.png deleted file mode 100644 index 59bef79..0000000 Binary files a/docs/slides/debugging/index_files/figure-revealjs/unnamed-chunk-10-1.png and /dev/null differ diff --git a/docs/slides/debugging/index_files/figure-revealjs/unnamed-chunk-9-1.png b/docs/slides/debugging/index_files/figure-revealjs/unnamed-chunk-9-1.png index 257d614..ecb8f84 100644 Binary files a/docs/slides/debugging/index_files/figure-revealjs/unnamed-chunk-9-1.png and b/docs/slides/debugging/index_files/figure-revealjs/unnamed-chunk-9-1.png differ diff --git a/docs/slides/demo/index.html b/docs/slides/demo/index.html index c42d850..3db8d0c 100644 --- a/docs/slides/demo/index.html +++ b/docs/slides/demo/index.html @@ -509,7 +509,7 @@

Demo Slides

RaukR 2024 โ€ข Advanced R for Bioinformatics

Roy Francis

-

19-Feb-2024

+

21-Jun-2024

diff --git a/docs/slides/ggplot/index.html b/docs/slides/ggplot/index.html index db5ce4b..a711a7a 100644 --- a/docs/slides/ggplot/index.html +++ b/docs/slides/ggplot/index.html @@ -425,7 +425,7 @@

Plotting with ggplot2

RaukR 2024 โ€ข Advanced R for Bioinformatics

Roy Francis

-

12-Jun-2024

+

21-Jun-2024

diff --git a/docs/slides/git/index.html b/docs/slides/git/index.html index 6a36868..1817f9f 100644 --- a/docs/slides/git/index.html +++ b/docs/slides/git/index.html @@ -407,7 +407,7 @@

git and R

RaukR 2024 โ€ข Advanced R for Bioinformatics

Sebastian DiLorenzo

-

19-Feb-2024

+

21-Jun-2024

diff --git a/docs/slides/index.html b/docs/slides/index.html index 8bc97dc..308a948 100644 --- a/docs/slides/index.html +++ b/docs/slides/index.html @@ -245,7 +245,7 @@

Slides

-
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ diff --git a/docs/slides/ml/index_files/figure-revealjs/unnamed-chunk-11-1.png b/docs/slides/ml/index_files/figure-revealjs/unnamed-chunk-11-1.png deleted file mode 100644 index a34085c..0000000 Binary files a/docs/slides/ml/index_files/figure-revealjs/unnamed-chunk-11-1.png and /dev/null differ diff --git a/docs/slides/ml/index_files/figure-revealjs/unnamed-chunk-18-1.png b/docs/slides/ml/index_files/figure-revealjs/unnamed-chunk-18-1.png deleted file mode 100644 index cf8f758..0000000 Binary files a/docs/slides/ml/index_files/figure-revealjs/unnamed-chunk-18-1.png and /dev/null differ diff --git a/docs/slides/ml/index_files/figure-revealjs/unnamed-chunk-23-1.png b/docs/slides/ml/index_files/figure-revealjs/unnamed-chunk-23-1.png deleted file mode 100644 index f7a9fd2..0000000 Binary files a/docs/slides/ml/index_files/figure-revealjs/unnamed-chunk-23-1.png and /dev/null differ diff --git a/docs/slides/ml/index_files/figure-revealjs/unnamed-chunk-28-1.png b/docs/slides/ml/index_files/figure-revealjs/unnamed-chunk-28-1.png deleted file mode 100644 index 8c2da75..0000000 Binary files a/docs/slides/ml/index_files/figure-revealjs/unnamed-chunk-28-1.png and /dev/null differ diff --git a/docs/slides/ml/index_files/figure-revealjs/unnamed-chunk-29-1.png b/docs/slides/ml/index_files/figure-revealjs/unnamed-chunk-29-1.png deleted file mode 100644 index 396feb4..0000000 Binary files a/docs/slides/ml/index_files/figure-revealjs/unnamed-chunk-29-1.png and /dev/null differ diff --git a/docs/slides/oop/index.html b/docs/slides/oop/index.html index c305526..c9ed4bd 100644 --- a/docs/slides/oop/index.html +++ b/docs/slides/oop/index.html @@ -407,7 +407,7 @@

Object-Oriented Programming Models in R

RaukR 2024 โ€ข Advanced R for Bioinformatics

Marcin Kierczak

-

12-Jun-2024

+

21-Jun-2024

diff --git a/docs/slides/packages/index.html b/docs/slides/packages/index.html index e5b7f87..c6ebbee 100644 --- a/docs/slides/packages/index.html +++ b/docs/slides/packages/index.html @@ -407,7 +407,7 @@

R packages

RaukR 2024 โ€ข Advanced R for Bioinformatics

Sebastian DiLorenzo

-

19-Feb-2024

+

21-Jun-2024

diff --git a/docs/slides/quarto/index.html b/docs/slides/quarto/index.html index 6f5c688..9942b05 100644 --- a/docs/slides/quarto/index.html +++ b/docs/slides/quarto/index.html @@ -423,7 +423,7 @@

Literate programming with Quarto

RaukR 2024 โ€ข Advanced R for Bioinformatics

Roy Francis

-

12-Jun-2024

+

21-Jun-2024

diff --git a/docs/slides/r-env/index.html b/docs/slides/r-env/index.html index ed63ff4..d1be8b5 100644 --- a/docs/slides/r-env/index.html +++ b/docs/slides/r-env/index.html @@ -407,7 +407,7 @@

Renv: Project environments in R

RaukR 2024 โ€ข Advanced R for Bioinformatics

Roy Francis

-

12-Jun-2024

+

21-Jun-2024

diff --git a/docs/slides/reticulate/index.html b/docs/slides/reticulate/index.html index ed39411..f4b4755 100644 --- a/docs/slides/reticulate/index.html +++ b/docs/slides/reticulate/index.html @@ -11,7 +11,7 @@ - + Reticulate @@ -45,7 +45,7 @@ } @media print { pre > code.sourceCode { white-space: pre-wrap; } - pre > code.sourceCode > span { display: inline-block; text-indent: -5em; padding-left: 5em; } + pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } } pre.numberSource code { counter-reset: source-line 0; } @@ -73,7 +73,7 @@ code span.at { color: #657422; } /* Attribute */ code span.bn { color: #ad0000; } /* BaseN */ code span.bu { } /* BuiltIn */ - code span.cf { color: #003b4f; font-weight: bold; } /* ControlFlow */ + code span.cf { color: #003b4f; } /* ControlFlow */ code span.ch { color: #20794d; } /* Char */ code span.cn { color: #8f5902; } /* Constant */ code span.co { color: #5e5e5e; } /* Comment */ @@ -87,7 +87,7 @@ code span.fu { color: #4758ab; } /* Function */ code span.im { color: #00769e; } /* Import */ code span.in { color: #5e5e5e; } /* Information */ - code span.kw { color: #003b4f; font-weight: bold; } /* Keyword */ + code span.kw { color: #003b4f; } /* Keyword */ code span.op { color: #5e5e5e; } /* Operator */ code span.ot { color: #003b4f; } /* Other */ code span.pp { color: #ad0000; } /* Preprocessor */ @@ -408,7 +408,7 @@

Reticulate

RaukR 2024 โ€ข Advanced R for Bioinformatics

Nina Norgren

-

14-Jun-2024

+

21-Jun-2024

@@ -650,7 +650,7 @@

Python in R Markdown

subset <- movies_r %>% select(5:6, 8:10) knitr::kable(subset[1:7,],'html')
- +
@@ -744,7 +744,7 @@

Type conversions

Conversion table

-
originalTitle
+
@@ -1279,7 +1279,18 @@

Thank you! Questions?

} return false; } - const onCopySuccess = function(e) { + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { // button target const button = e.trigger; // don't keep focus @@ -1311,47 +1322,7 @@

Thank you! Questions?

}, 1000); // clear code selection e.clearSelection(); - } - const getTextToCopy = function(trigger) { - const codeEl = trigger.previousElementSibling.cloneNode(true); - for (const childEl of codeEl.children) { - if (isCodeAnnotation(childEl)) { - childEl.remove(); - } - } - return codeEl.innerText; - } - const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', { - text: getTextToCopy }); - clipboard.on('success', onCopySuccess); - if (window.document.getElementById('quarto-embedded-source-code-modal')) { - // For code content inside modals, clipBoardJS needs to be initialized with a container option - // TODO: Check when it could be a function (/~https://github.com/zenorocha/clipboard.js/issues/860) - const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', { - text: getTextToCopy, - container: window.document.getElementById('quarto-embedded-source-code-modal') - }); - clipboardModal.on('success', onCopySuccess); - } - var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//); - var mailtoRegex = new RegExp(/^mailto:/); - var filterRegex = new RegExp("https:\/\/nbisweden\.github\.io\/raukr-2024\/"); - var isInternal = (href) => { - return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href); - } - // Inspect non-navigation links and adorn them if external - var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)'); - for (var i=0; iThank you! Questions? try { href = new URL(href).hash; } catch {} const id = href.replace(/^#\/?/, ""); const note = window.document.getElementById(id); - if (note) { - return note.innerHTML; - } else { - return ""; - } + return note.innerHTML; }); } const findCites = (el) => { diff --git a/docs/slides/reticulate/index_files/figure-revealjs/unnamed-chunk-21-1.png b/docs/slides/reticulate/index_files/figure-revealjs/unnamed-chunk-21-1.png new file mode 100644 index 0000000..4075d29 Binary files /dev/null and b/docs/slides/reticulate/index_files/figure-revealjs/unnamed-chunk-21-1.png differ diff --git a/docs/slides/scripting/index.html b/docs/slides/scripting/index.html index bff5e3a..79cb219 100644 --- a/docs/slides/scripting/index.html +++ b/docs/slides/scripting/index.html @@ -407,7 +407,7 @@

Functions and scripts

RaukR 2024 โ€ข Advanced R for Bioinformatics

Sebastian DiLorenzo

-

19-Feb-2024

+

21-Jun-2024

diff --git a/docs/slides/shiny/index.html b/docs/slides/shiny/index.html index 1cf25f2..cb0c525 100644 --- a/docs/slides/shiny/index.html +++ b/docs/slides/shiny/index.html @@ -413,7 +413,7 @@

Interactive web apps with Shiny

RaukR 2024 โ€ข Advanced R for Bioinformatics

Roy Francis

-

29-May-2024

+

21-Jun-2024

diff --git a/docs/slides/tidyverse/index.html b/docs/slides/tidyverse/index.html index fd7c05f..3bb43fe 100644 --- a/docs/slides/tidyverse/index.html +++ b/docs/slides/tidyverse/index.html @@ -409,7 +409,7 @@

Tidy work in Tidyverse

RaukR 2024 โ€ข Advanced R for Bioinformatics

Marcin Kierczak

-

19-Feb-2024

+

21-Jun-2024

diff --git a/docs/slides/vectorization/index.html b/docs/slides/vectorization/index.html index aac4af1..34f912d 100644 --- a/docs/slides/vectorization/index.html +++ b/docs/slides/vectorization/index.html @@ -407,7 +407,7 @@

Vectorization in R

RaukR 2024 โ€ข Advanced R for Bioinformatics

Marcin Kierczak

-

19-Feb-2024

+

21-Jun-2024

diff --git a/slides/debugging/profiler_test2.Rdat b/slides/debugging/profiler_test2.Rdat index e1ad40e..ddb0dfc 100644 Binary files a/slides/debugging/profiler_test2.Rdat and b/slides/debugging/profiler_test2.Rdat differ diff --git a/slides/debugging/profiler_test2.out b/slides/debugging/profiler_test2.out index a90713b..36e687a 100644 --- a/slides/debugging/profiler_test2.out +++ b/slides/debugging/profiler_test2.out @@ -1,5 +1,5 @@ sample.interval=10000 -"order" "factor" "table" "eval" "eval" "eval_with_user_handlers" "withVisible" "withCallingHandlers" "handle" "timing_fn" "evaluate_call" "evaluate::evaluate" "evaluate" "in_dir" "in_input_dir" "eng_r" "block_exec" "call_block" "process_group.block" "process_group" "withCallingHandlers" "withCallingHandlers" "handle_error" "process_file" "knitr::knit" "rmarkdown::render" "execute" ".main" +"unique" "factor" "table" "eval" "eval" "eval_with_user_handlers" "withVisible" "withCallingHandlers" "handle" "timing_fn" "evaluate_call" "evaluate::evaluate" "evaluate" "in_dir" "in_input_dir" "eng_r" "block_exec" "call_block" "process_group.block" "process_group" "withCallingHandlers" "withCallingHandlers" "handle_error" "process_file" "knitr::knit" "rmarkdown::render" "execute" ".main" "unique.default" "unique" "factor" "table" "eval" "eval" "eval_with_user_handlers" "withVisible" "withCallingHandlers" "handle" "timing_fn" "evaluate_call" "evaluate::evaluate" "evaluate" "in_dir" "in_input_dir" "eng_r" "block_exec" "call_block" "process_group.block" "process_group" "withCallingHandlers" "withCallingHandlers" "handle_error" "process_file" "knitr::knit" "rmarkdown::render" "execute" ".main" "unique.default" "unique" "factor" "table" "eval" "eval" "eval_with_user_handlers" "withVisible" "withCallingHandlers" "handle" "timing_fn" "evaluate_call" "evaluate::evaluate" "evaluate" "in_dir" "in_input_dir" "eng_r" "block_exec" "call_block" "process_group.block" "process_group" "withCallingHandlers" "withCallingHandlers" "handle_error" "process_file" "knitr::knit" "rmarkdown::render" "execute" ".main" "unique.default" "unique" "factor" "table" "eval" "eval" "eval_with_user_handlers" "withVisible" "withCallingHandlers" "handle" "timing_fn" "evaluate_call" "evaluate::evaluate" "evaluate" "in_dir" "in_input_dir" "eng_r" "block_exec" "call_block" "process_group.block" "process_group" "withCallingHandlers" "withCallingHandlers" "handle_error" "process_file" "knitr::knit" "rmarkdown::render" "execute" ".main" @@ -18,4 +18,4 @@ sample.interval=10000 "factor" "table" "eval" "eval" "eval_with_user_handlers" "withVisible" "withCallingHandlers" "handle" "timing_fn" "evaluate_call" "evaluate::evaluate" "evaluate" "in_dir" "in_input_dir" "eng_r" "block_exec" "call_block" "process_group.block" "process_group" "withCallingHandlers" "withCallingHandlers" "handle_error" "process_file" "knitr::knit" "rmarkdown::render" "execute" ".main" "factor" "table" "eval" "eval" "eval_with_user_handlers" "withVisible" "withCallingHandlers" "handle" "timing_fn" "evaluate_call" "evaluate::evaluate" "evaluate" "in_dir" "in_input_dir" "eng_r" "block_exec" "call_block" "process_group.block" "process_group" "withCallingHandlers" "withCallingHandlers" "handle_error" "process_file" "knitr::knit" "rmarkdown::render" "execute" ".main" "factor" "table" "eval" "eval" "eval_with_user_handlers" "withVisible" "withCallingHandlers" "handle" "timing_fn" "evaluate_call" "evaluate::evaluate" "evaluate" "in_dir" "in_input_dir" "eng_r" "block_exec" "call_block" "process_group.block" "process_group" "withCallingHandlers" "withCallingHandlers" "handle_error" "process_file" "knitr::knit" "rmarkdown::render" "execute" ".main" -"table" "eval" "eval" "eval_with_user_handlers" "withVisible" "withCallingHandlers" "handle" "timing_fn" "evaluate_call" "evaluate::evaluate" "evaluate" "in_dir" "in_input_dir" "eng_r" "block_exec" "call_block" "process_group.block" "process_group" "withCallingHandlers" "withCallingHandlers" "handle_error" "process_file" "knitr::knit" "rmarkdown::render" "execute" ".main" +"factor" "table" "eval" "eval" "eval_with_user_handlers" "withVisible" "withCallingHandlers" "handle" "timing_fn" "evaluate_call" "evaluate::evaluate" "evaluate" "in_dir" "in_input_dir" "eng_r" "block_exec" "call_block" "process_group.block" "process_group" "withCallingHandlers" "withCallingHandlers" "handle_error" "process_file" "knitr::knit" "rmarkdown::render" "execute" ".main"
R