Skip to content

Commit

Permalink
perf: new XPathContext structs are copied and not initialized
Browse files Browse the repository at this point in the history
Copying the struct and the hash tables is slightly faster than calling
xmlXpathNewContext:

  Comparison:
      large: optimized:    17780.0 i/s
           large: main:    15143.4 i/s - same-ish: difference falls within error

  Comparison:
      small: optimized:    62891.9 i/s
           small: main:    49413.5 i/s - 1.27x  slower

But still slower than re-using the context object ("edge", v1.18.0.rc1):

  Comparison:
           large: edge:    22230.9 i/s
      large: optimized:    17780.0 i/s - 1.25x  slower
           large: main:    15143.4 i/s - 1.47x  slower

  Comparison:
           small: edge:   129162.0 i/s
      small: optimized:    62891.9 i/s - 2.05x  slower
           small: main:    49413.5 i/s - 2.61x  slower
  • Loading branch information
flavorjones committed Dec 20, 2024
1 parent 175cc9f commit 0f75b59
Showing 1 changed file with 76 additions and 11 deletions.
87 changes: 76 additions & 11 deletions ext/nokogiri/xml_xpath_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,78 @@ noko_xml_xpath_context_evaluate(int argc, VALUE *argv, VALUE rb_context)
return rb_xpath_object;
}

static xmlXPathContextPtr
_noko_xml_xpath_context_initialize(void)
{
xmlXPathContextPtr c_context = xmlXPathNewContext(NULL);

xmlXPathRegisterNs(c_context, NOKOGIRI_PREFIX, NOKOGIRI_URI);
xmlXPathRegisterNs(c_context, NOKOGIRI_BUILTIN_PREFIX, NOKOGIRI_BUILTIN_URI);

xmlXPathRegisterFuncNS(c_context,
(const xmlChar *)"css-class", NOKOGIRI_BUILTIN_URI,
noko_xml_xpath_context_xpath_func_css_class);
xmlXPathRegisterFuncNS(c_context,
(const xmlChar *)"local-name-is", NOKOGIRI_BUILTIN_URI,
noko_xml_xpath_context_xpath_func_local_name_is);

return c_context;
}

static VALUE
_noko_xml_xpath_context_protocontext(void)
{
VALUE rb_context = rb_iv_get(cNokogiriXmlXpathContext, "@protocontext");

if (NIL_P(rb_context)) {
xmlXPathContextPtr c_context = _noko_xml_xpath_context_initialize();
rb_context = TypedData_Wrap_Struct(cNokogiriXmlXpathContext, &_noko_xml_xpath_context_type, c_context);
rb_iv_set(cNokogiriXmlXpathContext, "@protocontext", rb_context);
}

return rb_context;
}

static void *
_noko_xml_xpath_context__xmlHashCopyPtr(void *payload, const xmlChar *name)
{
return payload;
}

static void *
_noko_xml_xpath_context__xmlHashCopyString(void *payload, const xmlChar *name)
{
return xmlStrdup(payload);
}

static xmlHashTablePtr
_noko_xml_xpath_context_copy_nsHash(xmlHashTablePtr hash)
{
return xmlHashCopy(hash, _noko_xml_xpath_context__xmlHashCopyString);
}

static xmlHashTablePtr
_noko_xml_xpath_context_copy_funcHash(xmlHashTablePtr hash)
{
return xmlHashCopy(hash, _noko_xml_xpath_context__xmlHashCopyPtr);
}

static xmlXPathContextPtr
_noko_xml_xpath_context_fast_initialize(void)
{
xmlXPathContextPtr c_protocontext;
VALUE rb_protocontext = _noko_xml_xpath_context_protocontext();
TypedData_Get_Struct(rb_protocontext, xmlXPathContext, &_noko_xml_xpath_context_type, c_protocontext);

xmlXPathContextPtr c_context = xmlMalloc(sizeof(xmlXPathContext));
memcpy(c_context, c_protocontext, sizeof(xmlXPathContext));

c_context->funcHash = _noko_xml_xpath_context_copy_funcHash(c_protocontext->funcHash);
c_context->nsHash = _noko_xml_xpath_context_copy_nsHash(c_protocontext->nsHash);

return c_context;
}

/*
* call-seq:
* new(node)
Expand All @@ -431,19 +503,10 @@ noko_xml_xpath_context_new(VALUE klass, VALUE rb_node)
xmlXPathInit(); /* deprecated in 40483d0 */
#endif

c_context = xmlXPathNewContext(c_node->doc);
c_context = _noko_xml_xpath_context_fast_initialize();
c_context->doc = c_node->doc;
c_context->node = c_node;

xmlXPathRegisterNs(c_context, NOKOGIRI_PREFIX, NOKOGIRI_URI);
xmlXPathRegisterNs(c_context, NOKOGIRI_BUILTIN_PREFIX, NOKOGIRI_BUILTIN_URI);

xmlXPathRegisterFuncNS(c_context,
(const xmlChar *)"css-class", NOKOGIRI_BUILTIN_URI,
noko_xml_xpath_context_xpath_func_css_class);
xmlXPathRegisterFuncNS(c_context,
(const xmlChar *)"local-name-is", NOKOGIRI_BUILTIN_URI,
noko_xml_xpath_context_xpath_func_local_name_is);

rb_context = TypedData_Wrap_Struct(klass, &_noko_xml_xpath_context_type, c_context);

return rb_context;
Expand Down Expand Up @@ -476,6 +539,8 @@ noko_init_xml_xpath_context(void)

rb_undef_alloc_func(cNokogiriXmlXpathContext);

rb_iv_set(cNokogiriXmlXpathContext, "@protocontext", Qnil);

rb_define_singleton_method(cNokogiriXmlXpathContext, "new", noko_xml_xpath_context_new, 1);

rb_define_method(cNokogiriXmlXpathContext, "evaluate", noko_xml_xpath_context_evaluate, -1);
Expand Down

0 comments on commit 0f75b59

Please sign in to comment.