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

Fix ARC hit rate #6989

Merged
merged 1 commit into from
Jan 8, 2018
Merged

Fix ARC hit rate #6989

merged 1 commit into from
Jan 8, 2018

Conversation

behlendorf
Copy link
Contributor

@behlendorf behlendorf commented Dec 21, 2017

Description

When the compressed ARC feature was added in commit d3c2ae1 the method of reference counting in the ARC was modified. As part of this accounting change the arc_buf_add_ref() function was removed entirely.

This would have been fine but the arc_buf_add_ref() function served a second undocumented purpose of updating the ARC access information when taking a hold on a dbuf. Without this logic in place a cached dbuf would not migrate its associated arc_buf_hdr_t to the MFU list. This negatively impacts the ARC hit rate, particularly on systems with a small ARC.

This change reinstates the missing call to arc_access() from dbuf_hold() by implementing a new arc_buf_access() function.

Motivation and Context

As reported in #6171 a significant drop in the ARC hit rate was reported by users upgrading to the 0.7.x releases.

How Has This Been Tested?

Manually with the following trivial test case which reads a file twice. After the first read the file size should be reflected in the arcstat mru_size. After the second read the file size should have been migrated to the arcstat mfu_size.

Notice that when testing without the patch the mfu_size doesn't increase on the second read.

$ zfs mount -a
$ grep -E 'mru_size|mfu_size' /proc/spl/kstat/zfs/arcstats
mru_size                        4    412672
mfu_size                        4    739328

$ cat /tank/file >/dev/null
 grep -E 'mru_size|mfu_size' /proc/spl/kstat/zfs/arcstats
mru_size                        4    21483008
mfu_size                        4    786432

$ cat /tank/file >/dev/null
 grep -E 'mru_size|mfu_size' /proc/spl/kstat/zfs/arcstats
mru_size                        4    21483008
mfu_size                        4    786432

After applying this patch the behavior is once again as expected. This matches the long standing behavior from the zfs-0.6.5.x releases.

$ zfs mount -a
$ grep -E 'mru_size|mfu_size' /proc/spl/kstat/zfs/arcstats
mru_size                        4    415232
mfu_size                        4    737792

$  cat /tank/file >/dev/null
$ grep -E 'mru_size|mfu_size' /proc/spl/kstat/zfs/arcstats
mru_size                        4    21384192
mfu_size                        4    889856

$ cat /tank/file >/dev/null
$ grep -E 'mru_size|mfu_size' /proc/spl/kstat/zfs/arcstats
mru_size                        4    1084928
mfu_size                        4    21198336

Additional testing included a full local run of the ZTS.

@grwilson since this code was also dropped from OpenZFS I believe it suffers from a similar regression. Can you please review this.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Performance enhancement (non-breaking change which improves efficiency)
  • Code cleanup (non-breaking change which makes code smaller or more readable)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation (a change to man pages or other documentation)

Checklist:

  • My code follows the ZFS on Linux code style requirements.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • All commit messages are properly formatted and contain Signed-off-by.
  • Change has been approved by a ZFS on Linux member.

module/zfs/arc.c Outdated
return;
}

mutex_exit(&buf->b_evict_lock);
Copy link
Contributor

Choose a reason for hiding this comment

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

lock b_evict_lock
lock hash_lock
unlock b_evict_lock
unlock hash_lock

I assume this is deadlock safe?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes it should be, the same ordering is used throughout the ARC.

@sempervictus
Copy link
Contributor

sempervictus commented Dec 22, 2017

Zloop seems happy, small vms with commensurately small ARCs show an improvement. I also havent seen one instance yet of the weird ARC collapse (ignoring min/max) syndrome observed on a number of systems since 0.7.0. Gonna fast track it to the staging boxes as i cant see a way this would hurt anything other than maybe some unforseen memory conditions leading to crash, but not eating the data (which is fine in staging).

module/zfs/arc.c Outdated
hash_lock = HDR_LOCK(buf->b_hdr);
mutex_enter(hash_lock);

if (!HDR_IN_HASH_TABLE(hdr)) {
Copy link
Member

Choose a reason for hiding this comment

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

Did you actually hit this case while testing? I'm trying to understand how a dbuf with data associated with it would not be in the hash table. I don't think we can evict it prior to someone calling remove_reference

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I did. It comes up pretty quickly when running the ZTS. What I think can happen here is we start with a dbuf which has data in it but before we can take the hash lock it gets released. This appears to be possible because I'm using HDR_LOCK to get the hash lock and buf_discard_identity() is called outside the b_evict_lock in arc_released(). I'd love a better solution for this if you have one.

Copy link
Contributor

@dweeezil dweeezil left a comment

Choose a reason for hiding this comment

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

@behlendorf I'm on vacation now and not in a position to give this a proper review [EDIT: until later in the week] but the rationale in the commit comment seems perfectly reasonable to me.

@sempervictus
Copy link
Contributor

We ended up tossing this PR into a prod fixup patch cycle when we hit an unrelated kernel bug (skipped staging on those hosts). There were a couple months of other commits in the branch which passed test and stage, so I can't quantify how much performance gain this gave us, but arc isn't collapsing, isn't ignoring min or max, and seems to be running great. Will toss up a note if we see something evil, but as of now, I'm a thumbs up on this.

When the compressed ARC feature was added in commit d3c2ae1
the method of reference counting in the ARC was modified.  As
part of this accounting change the arc_buf_add_ref() function
was removed entirely.

This would have be fine but the arc_buf_add_ref() function
served a second undocumented purpose of updating the ARC access
information when taking a hold on a dbuf.  Without this logic
in place a cached dbuf would not migrate its associated
arc_buf_hdr_t to the MFU list.  This would negatively impact
the ARC hit rate, particularly on systems with a small ARC.

This change reinstates the missing call to arc_access() from
dbuf_hold() by implementing a new arc_buf_access() function.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Issue openzfs#6171
* to handle the case where it is concurrently being released.
*/
if (hdr->b_l1hdr.b_state == arc_anon || HDR_EMPTY(hdr)) {
mutex_exit(&buf->b_evict_lock);
Copy link
Contributor

Choose a reason for hiding this comment

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

Any reason why arcstat_access_skip is not being bumped here? It's the same condition as below and results in an early exit.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In my local testing I did add an additional kstat here in order to determine if including this additional check was worthwhile. Keep in mind this check could be dropped entirely since it's safe to rely on the one under the mutex. Based on my test results 99.99+% of the released headers were caught here without the need to take the hash lock, so I opted to keep it as an optimization to minimize any potential lock contention. After determining that I was only really interested in how many slipped through since that was the exceptional case. So the value is only bumped in the second conditional.

@codecov
Copy link

codecov bot commented Dec 28, 2017

Codecov Report

Merging #6989 into master will decrease coverage by 0.12%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #6989      +/-   ##
==========================================
- Coverage   75.49%   75.36%   -0.13%     
==========================================
  Files         296      296              
  Lines       95500    95520      +20     
==========================================
- Hits        72095    71990     -105     
- Misses      23405    23530     +125
Flag Coverage Δ
#kernel 74.51% <100%> (-0.34%) ⬇️
#user 67.66% <95.23%> (-0.21%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 823d48b...e0014d5. Read the comment docs.

Copy link
Contributor

@dweeezil dweeezil left a comment

Choose a reason for hiding this comment

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

LGTM, however, I'm not sure why it's so important to update the access information in this context and will be posting additional follow-up outside of the review context. [EDIT] Apparently it's the introduction of the dbuf cache.

@dweeezil
Copy link
Contributor

As I alluded to in my review comment, its kind of a shame this type of interface is needed in the first place but at least it's a better documented interface with this patch. As @behlendorf pointed out, the arc_access() call was rather "buried" in arc_buf_add_ref() without any specific commentary.

@x041 x041 mentioned this pull request Jan 7, 2018
@behlendorf behlendorf merged commit 0873bb6 into openzfs:master Jan 8, 2018
prometheanfire pushed a commit to prometheanfire/zfs that referenced this pull request Jan 11, 2018
When the compressed ARC feature was added in commit d3c2ae1
the method of reference counting in the ARC was modified.  As
part of this accounting change the arc_buf_add_ref() function
was removed entirely.

This would have be fine but the arc_buf_add_ref() function
served a second undocumented purpose of updating the ARC access
information when taking a hold on a dbuf.  Without this logic
in place a cached dbuf would not migrate its associated
arc_buf_hdr_t to the MFU list.  This would negatively impact
the ARC hit rate, particularly on systems with a small ARC.

This change reinstates the missing call to arc_access() from
dbuf_hold() by implementing a new arc_buf_access() function.

Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Tim Chase <tim@chase2k.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes openzfs#6171 
Closes openzfs#6852 
Closes openzfs#6989
prometheanfire pushed a commit to prometheanfire/zfs that referenced this pull request Jan 11, 2018
When the compressed ARC feature was added in commit d3c2ae1
the method of reference counting in the ARC was modified.  As
part of this accounting change the arc_buf_add_ref() function
was removed entirely.

This would have be fine but the arc_buf_add_ref() function
served a second undocumented purpose of updating the ARC access
information when taking a hold on a dbuf.  Without this logic
in place a cached dbuf would not migrate its associated
arc_buf_hdr_t to the MFU list.  This would negatively impact
the ARC hit rate, particularly on systems with a small ARC.

This change reinstates the missing call to arc_access() from
dbuf_hold() by implementing a new arc_buf_access() function.

Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Tim Chase <tim@chase2k.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes openzfs#6171 
Closes openzfs#6852 
Closes openzfs#6989
tonyhutter pushed a commit to tonyhutter/zfs that referenced this pull request Jan 16, 2018
When the compressed ARC feature was added in commit d3c2ae1
the method of reference counting in the ARC was modified.  As
part of this accounting change the arc_buf_add_ref() function
was removed entirely.

This would have be fine but the arc_buf_add_ref() function
served a second undocumented purpose of updating the ARC access
information when taking a hold on a dbuf.  Without this logic
in place a cached dbuf would not migrate its associated
arc_buf_hdr_t to the MFU list.  This would negatively impact
the ARC hit rate, particularly on systems with a small ARC.

This change reinstates the missing call to arc_access() from
dbuf_hold() by implementing a new arc_buf_access() function.

Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Tim Chase <tim@chase2k.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes openzfs#6171
Closes openzfs#6852
Closes openzfs#6989
prometheanfire pushed a commit to prometheanfire/zfs that referenced this pull request Jan 17, 2018
When the compressed ARC feature was added in commit d3c2ae1
the method of reference counting in the ARC was modified.  As
part of this accounting change the arc_buf_add_ref() function
was removed entirely.

This would have be fine but the arc_buf_add_ref() function
served a second undocumented purpose of updating the ARC access
information when taking a hold on a dbuf.  Without this logic
in place a cached dbuf would not migrate its associated
arc_buf_hdr_t to the MFU list.  This would negatively impact
the ARC hit rate, particularly on systems with a small ARC.

This change reinstates the missing call to arc_access() from
dbuf_hold() by implementing a new arc_buf_access() function.

Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Tim Chase <tim@chase2k.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes openzfs#6171 
Closes openzfs#6852 
Closes openzfs#6989
tonyhutter pushed a commit to tonyhutter/zfs that referenced this pull request Jan 18, 2018
When the compressed ARC feature was added in commit d3c2ae1
the method of reference counting in the ARC was modified.  As
part of this accounting change the arc_buf_add_ref() function
was removed entirely.

This would have be fine but the arc_buf_add_ref() function
served a second undocumented purpose of updating the ARC access
information when taking a hold on a dbuf.  Without this logic
in place a cached dbuf would not migrate its associated
arc_buf_hdr_t to the MFU list.  This would negatively impact
the ARC hit rate, particularly on systems with a small ARC.

This change reinstates the missing call to arc_access() from
dbuf_hold() by implementing a new arc_buf_access() function.

Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Tim Chase <tim@chase2k.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes openzfs#6171
Closes openzfs#6852
Closes openzfs#6989
tonyhutter pushed a commit to tonyhutter/zfs that referenced this pull request Jan 18, 2018
When the compressed ARC feature was added in commit d3c2ae1
the method of reference counting in the ARC was modified.  As
part of this accounting change the arc_buf_add_ref() function
was removed entirely.

This would have be fine but the arc_buf_add_ref() function
served a second undocumented purpose of updating the ARC access
information when taking a hold on a dbuf.  Without this logic
in place a cached dbuf would not migrate its associated
arc_buf_hdr_t to the MFU list.  This would negatively impact
the ARC hit rate, particularly on systems with a small ARC.

This change reinstates the missing call to arc_access() from
dbuf_hold() by implementing a new arc_buf_access() function.

Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Tim Chase <tim@chase2k.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes openzfs#6171
Closes openzfs#6852
Closes openzfs#6989
tonyhutter pushed a commit to tonyhutter/zfs that referenced this pull request Jan 19, 2018
When the compressed ARC feature was added in commit d3c2ae1
the method of reference counting in the ARC was modified.  As
part of this accounting change the arc_buf_add_ref() function
was removed entirely.

This would have be fine but the arc_buf_add_ref() function
served a second undocumented purpose of updating the ARC access
information when taking a hold on a dbuf.  Without this logic
in place a cached dbuf would not migrate its associated
arc_buf_hdr_t to the MFU list.  This would negatively impact
the ARC hit rate, particularly on systems with a small ARC.

This change reinstates the missing call to arc_access() from
dbuf_hold() by implementing a new arc_buf_access() function.

Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Tim Chase <tim@chase2k.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes openzfs#6171
Closes openzfs#6852
Closes openzfs#6989
tonyhutter pushed a commit to tonyhutter/zfs that referenced this pull request Jan 22, 2018
When the compressed ARC feature was added in commit d3c2ae1
the method of reference counting in the ARC was modified.  As
part of this accounting change the arc_buf_add_ref() function
was removed entirely.

This would have be fine but the arc_buf_add_ref() function
served a second undocumented purpose of updating the ARC access
information when taking a hold on a dbuf.  Without this logic
in place a cached dbuf would not migrate its associated
arc_buf_hdr_t to the MFU list.  This would negatively impact
the ARC hit rate, particularly on systems with a small ARC.

This change reinstates the missing call to arc_access() from
dbuf_hold() by implementing a new arc_buf_access() function.

Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Tim Chase <tim@chase2k.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes openzfs#6171
Closes openzfs#6852
Closes openzfs#6989
tonyhutter pushed a commit to tonyhutter/zfs that referenced this pull request Jan 23, 2018
When the compressed ARC feature was added in commit d3c2ae1
the method of reference counting in the ARC was modified.  As
part of this accounting change the arc_buf_add_ref() function
was removed entirely.

This would have be fine but the arc_buf_add_ref() function
served a second undocumented purpose of updating the ARC access
information when taking a hold on a dbuf.  Without this logic
in place a cached dbuf would not migrate its associated
arc_buf_hdr_t to the MFU list.  This would negatively impact
the ARC hit rate, particularly on systems with a small ARC.

This change reinstates the missing call to arc_access() from
dbuf_hold() by implementing a new arc_buf_access() function.

Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Tim Chase <tim@chase2k.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes openzfs#6171
Closes openzfs#6852
Closes openzfs#6989
Nasf-Fan pushed a commit to Nasf-Fan/zfs that referenced this pull request Jan 29, 2018
When the compressed ARC feature was added in commit d3c2ae1
the method of reference counting in the ARC was modified.  As
part of this accounting change the arc_buf_add_ref() function
was removed entirely.

This would have be fine but the arc_buf_add_ref() function
served a second undocumented purpose of updating the ARC access
information when taking a hold on a dbuf.  Without this logic
in place a cached dbuf would not migrate its associated
arc_buf_hdr_t to the MFU list.  This would negatively impact
the ARC hit rate, particularly on systems with a small ARC.

This change reinstates the missing call to arc_access() from
dbuf_hold() by implementing a new arc_buf_access() function.

Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Tim Chase <tim@chase2k.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes openzfs#6171
Closes openzfs#6852
Closes openzfs#6989
tonyhutter pushed a commit that referenced this pull request Feb 6, 2018
When the compressed ARC feature was added in commit d3c2ae1
the method of reference counting in the ARC was modified.  As
part of this accounting change the arc_buf_add_ref() function
was removed entirely.

This would have be fine but the arc_buf_add_ref() function
served a second undocumented purpose of updating the ARC access
information when taking a hold on a dbuf.  Without this logic
in place a cached dbuf would not migrate its associated
arc_buf_hdr_t to the MFU list.  This would negatively impact
the ARC hit rate, particularly on systems with a small ARC.

This change reinstates the missing call to arc_access() from
dbuf_hold() by implementing a new arc_buf_access() function.

Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Tim Chase <tim@chase2k.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #6171
Closes #6852
Closes #6989
Nasf-Fan pushed a commit to Nasf-Fan/zfs that referenced this pull request Feb 13, 2018
When the compressed ARC feature was added in commit d3c2ae1
the method of reference counting in the ARC was modified.  As
part of this accounting change the arc_buf_add_ref() function
was removed entirely.

This would have be fine but the arc_buf_add_ref() function
served a second undocumented purpose of updating the ARC access
information when taking a hold on a dbuf.  Without this logic
in place a cached dbuf would not migrate its associated
arc_buf_hdr_t to the MFU list.  This would negatively impact
the ARC hit rate, particularly on systems with a small ARC.

This change reinstates the missing call to arc_access() from
dbuf_hold() by implementing a new arc_buf_access() function.

Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Tim Chase <tim@chase2k.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes openzfs#6171
Closes openzfs#6852
Closes openzfs#6989
@behlendorf behlendorf deleted the issue-6171 branch April 19, 2021 19:30
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.

7 participants