Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize LVCssSelectorRule::check() #528

Merged
merged 1 commit into from
Oct 3, 2023
Merged

Conversation

bbshelper
Copy link
Contributor

@bbshelper bbshelper commented Sep 27, 2023

  1. isRoot() is not free. Move it up the hierarchy.
  2. avoid unnecessary string copy
  3. don't allocate new strings when matching class name.

This change is Reviewable

@bbshelper
Copy link
Contributor Author

These are some local optimizations. Tested on some large epubs from Project Gutenburg by LoadDocument() and then Render(). Overall time is reduced by around 0.7% (median). Some files show better results:

filename reduction %
pg48661 -48.59
pg40588 -39.01
pg44562 -37.07
pg61526 -35.74
pg54383 -30.82

Despite these numbers, their fundamental problem remain unsolved: check() is called way too many times. This requires (IMO) some larger changes.

lString32 value_w_spaces_before_after = " " + _value + " ";
if (val.pos(value_w_spaces_before_after) != -1)
return true; // in between or at end
lString32::size_type start = 0, pos;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still not a fan of those declarations ;p.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine. Any particular reason?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're error-prone, potentially confusing, and serve no purpose besides cadging a line ;).

Comment on lines +5171 to +5178
while ((pos = val.pos(_value, start)) >= 0) {
if ((pos == 0 || val[pos - 1] == ' ') && val[pos + _value.length()] == ' ')
return true;
start += _value.length();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving by the pattern length to continue the search feels like you may miss some stuff, like finding aaa in aa aa aaaa aaa aa aaa. It may work because of the boundary checks for a space, but it feels not obvious :)
Sure it's all sane?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My assumption is that _value doesn't contain any spaces. With that I can write start += _value.length() + 1 but that looks even more suspicious :p

Comment on lines 4921 to 4924
bool LVCssSelectorRule::check( const ldomNode * & node, bool allow_cache )
{
if (!node || node->isNull() || node->isRoot())
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this LVCssSelectorRule::check() may be called from elsewhere than LVStyleSheet::apply() (where you moved the isRoot() check), ie. LVCssSelectorRule::checkNextRules() which may LVCssSelectorRule::check() on a parent/sibling node, where you will then not do the isRoot() check.

Are you sure isRoot() is expensive? The code and its switch/cases feels obscure, but not that much. I never really manage to understand the persistent stuff (and it it is really doing what it's supposed to do, swaping/trashing nodes from memory) - but I think at the point we do that, all the nodes are in memory, so it would be the first case return !NPELEM->_parentNode.

About !node || node->isNull(), I guess it's just sanity checks, and if we do things right elsewhere, we shouldn't have this called with a null node. But who knows if we did things right :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. I've reverted this part. isRoot() by itself is not very expensive, but it's called very often so it accounts for like 0.x% total load-and-render time. If #529 gets solved, isRoot() shouldn't be a problem.

@bbshelper bbshelper force-pushed the perf-css branch 2 times, most recently from 96bbfdc to df89e5e Compare September 29, 2023 16:06
Comment on lines 5172 to 5173
lString32::size_type start = 0;
lString32::size_type pos;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure we need to be that lString32-tied ? :) We don't have any such lString32::size_type in the codebase.
We use int (or size_t or offset_t if you want to please @NiLuJe :) mostly everywhere as string indices, which feels more readable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original author used that a lot in their lvstring.cpp :) I guess they got the idea from the std library.

Indices really should be size_t, but the author were very liberal about integer signedness and many string functions has int return type. So I use this size_type to pretend I'm using some correct type, while playing nice with other string functions, though it's actually defined as int.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll let lvstring.cpp do its own type business.
As for lvstsheet.cpp, I'll play mimicry rather than nice :) just so a future non-C++-specialist (like I was) can feel in a consistent home :)

Avoid unnecessary string copy, and don't allocate new strings when
matching class name.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants