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

(PUP-3436) Optimize CPU intensitive Compiler methods #3155

Closed
wants to merge 3 commits into from

Conversation

thallgren
Copy link
Contributor

This commit contains some performance optimizations in methods
that showed up as very time consuming in the profiler when running
the rake following rake tests:

benchmark:many_modules:run
benchmark:defined_types4:run
benchmark:defined_types:run

CPU consumption with this patch in place is between 70% - 75% of
what it used to be.

Profiling was performed using stackprof
https://github.com/tmm1/stackprof

@@ -1,7 +1,7 @@
require 'puppet/util/tag_set'

module Puppet::Util::Tagging
ValidTagRegex = /^\w[-\w:.]*$/
ValidTagRegex = /^[0-9A-Za-z_][0-9A-Za-z_:.-]*$/
Copy link
Contributor

Choose a reason for hiding this comment

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

Why was this change made? Is it faster? The two regexps looks equivalent to me...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's significantly faster.

Copy link
Contributor

Choose a reason for hiding this comment

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

Wow, that is surprising! I think \w is used in the parser too. Will see if this optimization can be applies there as well. Thanks.

@hlindberg
Copy link
Contributor

Did you measure for Ruby 1.9 as well?

@thallgren
Copy link
Contributor Author

No, not possible since the profiler relies on features introduced in 2.1

@kylog
Copy link

kylog commented Oct 3, 2014

With 1.9 going EOL in Feb 2015, targeting 2.1 makes sense to me.

@puppetcla
Copy link

CLA signed by all contributors.

@in_to[ e.target][e.source] ||= []; @in_to[ e.target][e.source] |= [e]
@out_from[e.source][e.target] ||= []; @out_from[e.source][e.target] |= [e]
# Avoid multiple lookups here. This code is performance critical
(@in_to[e.target][e.source] ||= []) << e
Copy link
Contributor

Choose a reason for hiding this comment

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

These aren't equivalent, the first using |= will prevent duplicate instances of 'e' from appearing in the array.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok, so three alternatives to maintain uniqueness:

  1. Go back to using the |= operator and force an unnecessary creation of an extra array instance (well, using a variable it would be once instead of twice).
  2. Use a Set instead of an Array.
  3. Test using array.include? before adding.

My preference is 3. Thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

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

Is it the second lookup of @foo[e.target][e.source] that is expensive? The creation of an [e] array or the additional calls to e.target and e.source that is expensive?

Trying 3. sounds reasonable, but I don't know if an include? is faster, would be interesting to see.

How expensive is something like:
(@in_to[e.target][e.source] ||= []) |= [e]
compared to
into = @in_to[e.target][e.source] ||= []
into << e if !into.include?(e)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll measure it. But in my mind the former is more expensive since it must do what the latter does anyway. In addition it must:

  • create an array
  • add an element to the array
  • iterate over the array using an index

Copy link
Contributor

Choose a reason for hiding this comment

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

That makes sense.

@thallgren thallgren force-pushed the compiler-optimizations branch 2 times, most recently from 9ad9224 to 44f29d6 Compare October 4, 2014 07:10
@thallgren
Copy link
Contributor Author

Added a new optimization to avoid a lot of unnecessary execution when creating new resources as copies of existing ones. With that in place, the three aforementioned tests execute almost twice as fast as they do without this PR.

@kylog
Copy link

kylog commented Oct 9, 2014

@thallgren bookkeeping: can you file a ticket and reference it in the commits?

@thallgren
Copy link
Contributor Author

@kylog commits updates as requested.

@thallgren thallgren changed the title Optimize CPU intensitive Compiler methods (PUP-3436) Optimize CPU intensitive Compiler methods Oct 10, 2014
@hlindberg
Copy link
Contributor

@thallgren can you update the PR, it has gone stale

@thallgren
Copy link
Contributor Author

PR updated. All builds pass except one that fails when running ruby 1.8.7. I have verified that the failure is unrelated to this PR (it fails on master too). The failing test was introduced 8 days ago in commit 49c5dab and the error is:

unsatisfied expectations:
- expected exactly once, not yet invoked: Puppet.warning('pkg warning: [\'Certificate '/var/pkg/ssl/871b4ed0ade09926e6adf95f86bf17535f987684' for publisher 'solarisstudio', needed to access 'https://pkg.oracle.com/solarisstudio/release/', will expire in '29' days.\']')

The code incorrectly assumes that Array.to_s adds brackets. It doesn't in Ruby < 1.9

@joshcooper
Copy link
Contributor

@thallgren that was me actually last night. I will take a look, as I don't want to break compatibility with 1.8 for no good reason.

@joshcooper
Copy link
Contributor

@thallgren should be resolved now

This commit contains some performance optimizations in methods
that showed up as very time consuming in the profiler when running
the rake following rake tests:

benchmark:many_modules:run
benchmark:defined_types4:run
benchmark:defined_types:run

CPU consumption with this patch in place is between 70% - 75% of
what it used to be.

Profiling was performed using stackprof
https://github.com/tmm1/stackprof
The Resource::copy_as_resource first created a new Resource
instance with all bells and whistles which means extracting
title, munching, and tagging. This commit ensures that these
fields are more effiently initialized when the source is
known to be a Resource.
This commit removes an unnecessary cloning of a tag set in the method
Puppet::Parser::Resource#add_scope_tags. It also removes unnecessary
processing of the tags since they have undergone this processing
already.
@thallgren
Copy link
Contributor Author

@joshcooper looks good now. Thanks.

@hlindberg
Copy link
Contributor

sigh - this again needs a rebase - I am doing that locally and will merge this in.

@hlindberg
Copy link
Contributor

Manually merged at 2d0e0a6 - closing

@hlindberg hlindberg closed this Nov 26, 2014
@thallgren thallgren deleted the compiler-optimizations branch January 15, 2015 11:42
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

7 participants