Repository navigation
Apply xpath-style findings for efficiency, robustness - #846
MichaelChirico wants to merge 3 commits into
Conversation
|
I have a change adding the
|
renkun-ken
left a comment
There was a problem hiding this comment.
Thanks for the XPath improvements. I found one performance regression in class parsing; details are inline. The focused tests passed locally, and the hosted checks are green.
| # Check if this specific value expression contains a FUNCTION keyword | ||
| func_node <- class_xml_first(value_expr, ".//FUNCTION") | ||
| is_function <- length(func_node) > 0 | ||
| is_function <- xml_find_lgl(value_expr, "boolean(.//FUNCTION)") |
There was a problem hiding this comment.
[P2] Keep namespace discovery out of the class-member loop
xml_find_lgl() defaults to ns = xml_ns(x), which scans the entire parser XML document. This runs once per R6 member during class_parse_data() on each parse, whereas the previous class_xml_first() call passed ns = character(). With 20 R6 classes of 25 members each followed by 5,000 simple assignments, I measured parse_document() at 1.11 s here versus 0.90 s when only this query used ns = character(), with identical class results. The overhead grows with both document size and member count. Could this pass ns = character() (or use a class-specific boolean wrapper)? The new placeholder query in class_xml_arguments() at R/class_index.R:50 has the same issue for piped calls.
There was a problem hiding this comment.
Thanks! That's exactly my proposed follow-up, which will have much broader benefits than just this one callsite. Let me upload the PR.
renkun-ken
left a comment
There was a problem hiding this comment.
Rechecked 1a66a1c. The rebase restores R 4.0-compatible syntax; the focused semantic-token, range-index, and type-hierarchy tests pass locally, and #846's hosted checks are green.
My earlier performance finding remains at this head. For 20 classes with 500 members and 10,000 additional assignments, class_parse_data() took 0.37–0.45 s on #846 versus 0.13–0.19 s with #847 applied, with identical member results. #847 addresses both affected call sites, but is still open separately, so I'm keeping the existing change request until the fix is included in #846.
|
I am thinking that it's nicer to keep the PRs more cleanly separate. I will merge them as a stack, so If you're thinking it's good for performance to be monotonically improving on |
|
I'm okay with either way. @randy3k what do you think? |
In {lintr}, we started the
@xpath-style:https://github.com/r-lib/lintr/tree/main/.agents/skills/xpath-style
Most importantly, it encodes some accumulated learnings about performant XPath (on {xml2}, at least).
A few repeated themes emerge here:
xml_*query that returns a full node set if it's not actually needed (e.g. we can usexml_find_lgl()and phrase the XPath itself to return a logical value, no nodeset needed)//*queries, which visit every node in the document. Go//to the most specific node involved (e.g.//OP-COMMAcan appear a large % of the time, too;//exprare only slightly better than//*)preceding-sibling::*can be better to avoid, e.g. test files where 100s of elements are written intoc(...); rephrased XPaths can be more concise by using theparent::first too.EQ_SUBoverSYMBOL_SUBto allow more cases offoo("a" = 1)to WAI without much further investment. I tend to think it's not worth phrasing the XPaths to accomodate this unusual pattern, but if we can get those "for free" by just usingEQ_SUB, all the better.I'm not very familiar with how to score ourselves here, but I deployed LLM to come up with some reasonable estimates, it produced:
masterxpath-skilltextDocument/inlayHintonR/completion.R)inlay_hint_reply()(XML)1,809.0 ms324.0 mstextDocument/inlayHinton scroll/edit)inlay_hint_reply()(XML)151.1 ms33.5 mstextDocument/foldingRange)get_document_blocks()14.4 ms9.0 mstextDocument/documentSymbol)extract_document_block_lines()13.8 ms9.1 msxdoc_top_level_index()40.8 ms35.5 mstextDocument/prepareTypeHierarchyonR/document.R)detect_type_definition()+find_r6_*()19.6 ms18.0 mstextDocument/semanticTokens/fullonR/folding.R)semantic_tokens_full_reply()(XML)96.9 ms92.4 mstextDocument/codeAction, 5 selections inR/completion.R)refactor_code_actions()850.3 ms811.6 msOne thing I didn't do here is add the faster
xml2::wrappers that pre-setns = NULL:See r-lib/lintr#3050, r-lib/xml2#327