Apply @rpkgoptskill to farm some better implementations - #334
Merged
Conversation
MichaelChirico
force-pushed
the
rpkgoptskill
branch
from
August 18, 2026 20:26
d87a52f to
a4c6743
Compare
MichaelChirico
force-pushed
the
rpkgoptskill
branch
from
August 18, 2026 20:29
a4c6743 to
d4866f0
Compare
Merged
MichaelChirico
force-pushed
the
rpkgoptskill
branch
from
August 18, 2026 20:30
d4866f0 to
21fafc9
Compare
Owner
Author
|
@dshkol most of the intermediate commits are stylistic (and so would be captured by having better R style skills on my end), but some have meaningful potential improvements to the SKILL, please have CC take a look and distill. |
Owner
Author
|
From the benchmark result comparing the initial implementation to now: Across packages, the additional refinements (vectorized
*Note: 3. Summary of Refinements in Current Tree
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
cc @dshkol. Gemini output:
Performance Optimization Report for
{potools}Following the principles and workflow in
r-pkg-optimizer, we profiled{potools}workflows, diagnosed the dominant bottlenecks across R and C source extraction and serialization, implemented targeted optimizations preserving all idioms and public API contracts, and verified semantic equivalence and test suite integrity.1. Workload & Bottleneck Diagnostics
Line and stage profiling (
Rprof,summaryRprof,bench::mark) on local package extraction (get_message_data(".")) and large multi-file packages (tools,utils,grid) revealed several hot spots:R/get_src_messages.R):is_outside_char_array()andmatch_parens()constructed single-pointdata.table(start = char_pos, end = char_pos)instances and ranfoverlaps()against character array boundaries. Because quote arrays are sorted and non-overlapping, binary search viafindInterval()performs the exact same point-in-interval check without building trees or allocating tables.R/get_r_messages.R):get_named_args()rannamed_args[expr_data, on = c('file', id = 'parent'), arg_value := i.text], forcingdata.tableto iterate through all rows inexpr_data(often 10,000–500,000+ rows) to match a handful of named arguments.get_call_args()used grouped.SDfiltering (if (.N == 1L || 'NS_GET' %chin% token) .SD[...]) over every function call AST node.get_strings_from_expr()iteratively grewstringswithrbind(..., fill = TRUE)in awhileloop.get_dots_strings()recomputedexclude_parentsand repeatedly subsettedexpr_data[!exclude_parents]even when empty.R/get_r_messages.R):msg[, by = c('file', 'line1', 'col1', 'line2', 'col2'), call := build_call(...)]grouped over every extracted message and rancomments[.(.BY$file, .BY$line1:.BY$line2), .SD, nomatch=NULL]. For single-line calls (which represent >90% of messages), the grammar guarantees no comments can appear within the expression columns (col1:col2).R/get_r_messages.R):clean_text()unconditionally executed 5 consecutive Perl regex lookarounds across every string constant in the package, even though strings containing\are rare.R/write_po_file.R):make_src_location()usedglue("{files}:{lines}")inside a loop; replaced with vectorizedpaste0(files, ":", lines).2. Implemented Optimizations
All changes were made in-place across 3 files:
R/get_src_messages.R:foverlaps()inis_outside_char_array()andmatch_parens()withfindInterval()over sorted non-overlapping array boundaries (144x faster in isolation, 0 allocations).R/get_r_messages.R:setindexv(expr_data, c("file", "line1", "col1", "line2", "col2")).get_call_args()to bypass.SDgrouping and return early on zero matches.expr_datascanning inget_named_args()with direct subset query:expr_data[named_args, on = c('file', parent = 'id'), mult = 'last', x.text].rbind()inget_strings_from_expr()with a list collector and singlerbindlist(str_list, fill = TRUE).get_r_messages(), evaluating comment ranges only for multi-line expressions.clean_text()withgrepl('\\', x, fixed = TRUE).R/write_po_file.R:glue("{files}:{lines}")inmake_src_location()withpaste0(files, ":", lines).3. Verification & Correctness
Verified 100% identical outputs (
all.equal() == TRUE) acrosspotoolsand diverse packages:potools(86 messages)tests/testthat/test_packages/r_cat_msg(16 messages)tests/testthat/test_packages/r_msg(6 messages)tests/testthat/test_packages/r_non_template(10 messages)tests/testthat/test_packages/r_fuzzy(4 messages)tests/testthat/test_packages/custom_translation(5 messages)tools(1,242 R messages, 146 src messages)utils(1,007 R messages, 157 src messages)grid(294 R messages, 60 src messages)parallel(55 R messages)Executed
pkgload::load_all('.'); testthat::test_dir('tests/testthat'):[ FAIL 0 | WARN 0 | SKIP 2 | PASS 146 ](all 146 tests passing, duration reduced from 13.4s to 12.1s).4. Reproducible Before/After Benchmarks
Environment: Linux (
x86_64), R Under development (unstable 2026-08-15 r90413),data.table1.18.4,potools0.2.4.get_r_messages()Latencypotools(24 R files, 86 msgs)tools(48 R files, 1,242 msgs)utils(38 R files, 1,007 msgs)grid(22 R files, 294 msgs)Isolated Helper Benchmarks
is_outside_char_array()clean_text()(1,149 strings)build_calls(100x onpotools)