-
Notifications
You must be signed in to change notification settings - Fork 898
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
Refactor get_ems_folders to create less strings #17358
Refactor get_ems_folders to create less strings #17358
Conversation
@miq-bot assign @gmcculloug |
This pull request is not mergeable. Please rebase and repush. |
2aa8d34
to
c12c75b
Compare
app/models/miq_request_workflow.rb
Outdated
if path.blank? | ||
path << folder.name.to_s | ||
else | ||
path << FOLDER_PATH_SEPARATOR << folder.name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NickLaMuro - Since there isn't a ternary here constantly generating new String
objects. Within the confines of a conditional Is the CONSTANT
still more performant than just including the "/" here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to say "yes", but I would rather have some proof. Let me run some tests quick.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ended up doing by testing against the DATACENTER_FOLDER_TYPE
constant and putting my findings there:
https://github.com/ManageIQ/manageiq/pull/17358/files#r188783333
but the same should apply here as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So my tendency is to go the easier to read path, which would mean pulling out the constants and replacing them with string_name.freeze
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmmk, I can go with that. I tend to do constants myself because I can wrap my brain around it a little easier. When it is in the "string".freeze
mode, I still think of/read it as "allocate string, then make it immutable", when it really isn't doing the "allocate string" bit at all.
Any who, I will make the change. 👍
app/models/miq_request_workflow.rb
Outdated
else | ||
path << FOLDER_PATH_SEPARATOR << folder.name | ||
end | ||
dh[folder.id] = path unless folder.type == DATACENTER_FOLDER_TYPE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, so turns out the CONSTANT
isn't necessary, but a .freeze
if it isn't a constant definitely is. So with the following:
What we have currently
dh[folder.id] = path unless folder.type == DATACENTER_FOLDER_TYPE
# Total allocated: 2055942638 bytes (22741876 objects)
#
# allocated objects by gem
# -----------------------------------
# 9665227 pending
# 5076997 manageiq/app
# 3513259 manageiq/lib
# 2512007 activerecord-5.0.7
# 861280 activesupport-5.0.7
# 418737 ancestry-2.2.2
# 278793 activemodel-5.0.7
# 178419 ruby-2.3.3/lib
# 165577 arel-7.1.4
# 52875 manageiq-providers-vmware-e2e2b8029538
# 14424 fast_gettext-1.2.0
# 4115 other
# 75 default_value_for-3.0.5
# 68 concurrent-ruby-1.0.5
# 16 memoist-0.15.0
# 4 rubygems
# 3 manageiq-providers-lenovo-ed197e6bea5b
With a normal string
dh[folder.id] = path unless folder.type == "Datacenter"
# Total allocated: 2066619256 bytes (23009605 objects)
#
# allocated objects by gem
# -----------------------------------
# 9665227 pending
# 5344726 manageiq/app
# 3513259 manageiq/lib
# 2512007 activerecord-5.0.7
# 861280 activesupport-5.0.7
# 418737 ancestry-2.2.2
# 278793 activemodel-5.0.7
# 178419 ruby-2.3.3/lib
# 165577 arel-7.1.4
# 52875 manageiq-providers-vmware-e2e2b8029538
# 14424 fast_gettext-1.2.0
# 4115 other
# 75 default_value_for-3.0.5
# 68 concurrent-ruby-1.0.5
# 16 memoist-0.15.0
# 4 rubygems
# 3 manageiq-providers-lenovo-ed197e6bea5b
With a frozen string (not a constant though)
dh[folder.id] = path unless folder.type == "Datacenter".freeze
# Total allocated: 2055940416 bytes (22741876 objects)
#
# allocated objects by gem
# -----------------------------------
# 9665227 pending
# 5076997 manageiq/app
# 3513259 manageiq/lib
# 2512007 activerecord-5.0.7
# 861280 activesupport-5.0.7
# 418737 ancestry-2.2.2
# 278793 activemodel-5.0.7
# 178419 ruby-2.3.3/lib
# 165577 arel-7.1.4
# 52875 manageiq-providers-vmware-e2e2b8029538
# 14424 fast_gettext-1.2.0
# 4115 other
# 75 default_value_for-3.0.5
# 68 concurrent-ruby-1.0.5
# 16 memoist-0.15.0
# 4 rubygems
# 3 manageiq-providers-lenovo-ed197e6bea5b
With a non-frozen constant
# DATACENTER_FOLDER_TYPE = "Datacenter".freeze
DATACENTER_FOLDER_TYPE = "Datacenter"
# ...
dh[folder.id] = path unless folder.type == DATACENTER_FOLDER_TYPE
# Total allocated: 2055902327 bytes (22741876 objects)
#
# allocated objects by gem
# -----------------------------------
# 9665227 pending
# 5076997 manageiq/app
# 3513259 manageiq/lib
# 2512007 activerecord-5.0.7
# 861280 activesupport-5.0.7
# 418737 ancestry-2.2.2
# 278793 activemodel-5.0.7
# 178419 ruby-2.3.3/lib
# 165577 arel-7.1.4
# 52875 manageiq-providers-vmware-e2e2b8029538
# 14424 fast_gettext-1.2.0
# 4115 other
# 75 default_value_for-3.0.5
# 68 concurrent-ruby-1.0.5
# 16 memoist-0.15.0
# 4 rubygems
# 3 manageiq-providers-lenovo-ed197e6bea5b
So basically is it is a matter of preference between the 1st, 3rd, and 4th options since they all perform the same.
Creating some strings in this method is inevitable, since we are generating string paths based on this compiled info, but there were a lot of excessive strings being created because of it: - Both of the strings in this method were being created every time this method was called. For the "Datacenter".freeze one, it was just used as a comparison as well - Using << where possible will avoid generating new substrings, so we are only creating one new string at most. - Deferred the `.dup` of full_path until a new string was known that it would be generated. This did require creating a new variable to hold on to the existing variable, but that wasn't a big deal and didn't increase the number of allocations. Split up some ternary operators as well just to make running profilers on this code easier to determine what as causing allocations (granularity in tracing object allocations in ruby is only down to a line by line basis).
c12c75b
to
1e0d6af
Compare
Checked commit NickLaMuro@1e0d6af with ruby 2.3.3, rubocop 0.52.1, haml-lint 0.20.0, and yamllint 1.10.0 app/models/miq_request_workflow.rb
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NickLaMuro - Thanks - LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM - just the one possible change (am good either way)
else | ||
path << " / ".freeze << folder.name | ||
end | ||
dh[folder.id] = path unless folder.type == "Datacenter".freeze |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would it make sense to have `elseif folder.type != "Datacenter".freeze ?
(not sure if you want to pull out into a const)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(not sure if you want to pull out into a const)
Per @syncrou 's previous review, he thought it was easier to read when it was not a constant. I already had it as a constant originally.
would it make sense to have `elseif folder.type != "Datacenter".freeze ?
Possibly, though I was mostly trying to keep the logic the same, and just adjusting things to limit object allocations. If you look at the previous code, the if
logic is basically exactly the same, I just expanded out the ternary operator since I thought it was easier to read in that form. Figured trying to tweak the logic would add unneeded risk.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aah - you are actually using path below
Added |
…_get_ems_folders Refactor get_ems_folders to create less strings (cherry picked from commit 7060b2d) https://bugzilla.redhat.com/show_bug.cgi?id=1593798
Fine backport details:
|
…_get_ems_folders Refactor get_ems_folders to create less strings (cherry picked from commit 7060b2d) https://bugzilla.redhat.com/show_bug.cgi?id=1593797
Gaprindashvili backport details:
|
Creating some strings in this method is inevitable, since we are generating string paths based on this compiled info, but there were a lot of excessive strings being created because of it:
"Datacenter".freeze
one, it was just used as a comparison as well<<
where possible will avoid generating new substrings, so we are only creating one new string at most..dup
of full_path until a new string was known that it would be generated. This did require creating a new variable to hold on to the existing variable, but that wasn't a big deal and didn't increase the number of allocations.Split up some ternary operators as well just to make running profilers on this code easier to determine what as causing allocations (granularity in tracing object allocations in ruby is only down to a line by line basis).
Benchmarks
The benchmark script used here basically runs the following:
And is targeting a fairly large EMS, with about 600 hosts.
Note: The benchmarks for this change do NOT include the changes from other PRs (#17354 for example). Benchmarks of all changes can be found here.
Links