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 spa_get_random(). #12183

Merged
merged 1 commit into from
Jun 22, 2021
Merged

Optimize spa_get_random(). #12183

merged 1 commit into from
Jun 22, 2021

Conversation

amotin
Copy link
Member

@amotin amotin commented Jun 2, 2021

In all places except two spa_get_random() is used for small values,
and the consumers do not need well seeded high quality values.
Switch those two exceptions directly to random_get_pseudo_bytes()
and optimize spa_get_random(), renaming it to random_in_range(),
since it is not related to SPA or ZFS in general.

On FreeBSD directly map random_in_range() to new prng32_bounded() KPI
added in FreeBSD 13. On Linux and in user-space just reduce the type
used to uint32_t to avoid more expensive 64bit division.

How Has This Been Tested?

On 40-thread FreeBSD system heavy uncached 4KB reads from 8 ZVOLs show reduction of time spent inside dbuf_evict_one() by ~10%. Previously it was consumed by ChaCha encryption, backing random_get_pseudo_bytes(), producing excessively strong random numbers for this purpose.

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)
  • Library ABI change (libzfs, libzfs_core, libnvpair, libuutil and libzfsbootenv)
  • Documentation (a change to man pages or other documentation)

Checklist:

@amotin amotin added the Status: Code Review Needed Ready for review and testing label Jun 2, 2021
@amotin amotin requested a review from a user June 2, 2021 20:47
@amotin amotin force-pushed the random branch 3 times, most recently from 14029a0 to b84b8b1 Compare June 2, 2021 21:26
Copy link
Contributor

@behlendorf behlendorf left a comment

Choose a reason for hiding this comment

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

Makes good sense to me.

@behlendorf behlendorf added Status: Accepted Ready to integrate (reviewed, tested) and removed Status: Code Review Needed Ready for review and testing labels Jun 3, 2021
Copy link
Contributor

@mmaybee mmaybee left a comment

Choose a reason for hiding this comment

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

I think it's a little awkward to move spa_get_random() into the os-specific random.h header file. Would you consider refactoring to introduce something like random_in_range() which, for freebsd would look like:

static inline uint32_t
random_in_range(uint32_t range)
{
#if  __FreeBSD_version >= 1300108
	return (prng32_bounded(range));
#else
	uint32_t r;

	(void) random_get_pseudo_bytes((void *)&r, sizeof (r));

	return (r % range);
#endif
}

and then spa_get_random could be left in spa_misc.c and look like:

uint32_t
spa_get_random(uint32_t range)
{
	ASSERT(range != 0);

	if (range == 1)
		return (0);

	return (random_in_range(range));
}

@amotin
Copy link
Member Author

amotin commented Jun 11, 2021

@mmaybee I suppose it is about "spa_" in the function name? Otherwise I am not sure why to split one trivial function with two.

@mmaybee
Copy link
Contributor

mmaybee commented Jun 12, 2021

Correct. spa_get_random() should be declared in spa.h, not in random.h

@amotin
Copy link
Member Author

amotin commented Jun 12, 2021

I think it should not be spa_* then. It has nothing to do with spa or ZFS at all. I'll think how to rename it.

@mmaybee
Copy link
Contributor

mmaybee commented Jun 14, 2021

I think that is a reasonable alternative.

In all places except two spa_get_random() is used for small values,
and the consumers do not require well seeded high quality values.
Switch those two exceptions directly to random_get_pseudo_bytes()
and optimize spa_get_random(), renaming it to random_in_range(),
since it is not related to SPA or ZFS in general.

On FreeBSD directly map random_in_range() to new prng32_bounded() KPI
added in FreeBSD 13.  On Linux and in user-space just reduce the type
used to uint32_t to avoid more expensive 64bit division.

Signed-off-by: Alexander Motin <mav@FreeBSD.org>
Sponsored-By: iXsystems, Inc.
@amotin
Copy link
Member Author

amotin commented Jun 14, 2021

I've renamed spa_get_random() to random_in_range().

@amotin
Copy link
Member Author

amotin commented Jun 21, 2021

Any more comments here?

@mmaybee mmaybee merged commit 29274c9 into openzfs:master Jun 22, 2021
random_in_range(uint32_t range)
{
#if __FreeBSD_version >= 1300108
return (prng32_bounded(range));
Copy link
Contributor

Choose a reason for hiding this comment

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

@amotin shouldn't this be #if defined(_KERNEL) && __FreeBSD_version >= 1300108

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think this file is used in user-space. It has separate implementation in include/sys/zfs_context.h. Am I wrong?

Copy link
Contributor

Choose a reason for hiding this comment

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

I am currently doing the merge to main multiple things break. I will send you an e-mail.

@amotin amotin deleted the random branch August 24, 2021 20:18
behlendorf pushed a commit to behlendorf/zfs that referenced this pull request Aug 24, 2021
In all places except two spa_get_random() is used for small values,
and the consumers do not require well seeded high quality values.
Switch those two exceptions directly to random_get_pseudo_bytes()
and optimize spa_get_random(), renaming it to random_in_range(),
since it is not related to SPA or ZFS in general.

On FreeBSD directly map random_in_range() to new prng32_bounded() KPI
added in FreeBSD 13.  On Linux and in user-space just reduce the type
used to uint32_t to avoid more expensive 64bit division.

Reviewed-by: Ryan Moeller <ryan@iXsystems.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Alexander Motin <mav@FreeBSD.org>
Sponsored-By: iXsystems, Inc.
Closes openzfs#12183
behlendorf pushed a commit that referenced this pull request Aug 31, 2021
In all places except two spa_get_random() is used for small values,
and the consumers do not require well seeded high quality values.
Switch those two exceptions directly to random_get_pseudo_bytes()
and optimize spa_get_random(), renaming it to random_in_range(),
since it is not related to SPA or ZFS in general.

On FreeBSD directly map random_in_range() to new prng32_bounded() KPI
added in FreeBSD 13.  On Linux and in user-space just reduce the type
used to uint32_t to avoid more expensive 64bit division.

Reviewed-by: Ryan Moeller <ryan@iXsystems.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Alexander Motin <mav@FreeBSD.org>
Sponsored-By: iXsystems, Inc.
Closes #12183
tonyhutter pushed a commit to tonyhutter/zfs that referenced this pull request Sep 15, 2021
In all places except two spa_get_random() is used for small values,
and the consumers do not require well seeded high quality values.
Switch those two exceptions directly to random_get_pseudo_bytes()
and optimize spa_get_random(), renaming it to random_in_range(),
since it is not related to SPA or ZFS in general.

On FreeBSD directly map random_in_range() to new prng32_bounded() KPI
added in FreeBSD 13.  On Linux and in user-space just reduce the type
used to uint32_t to avoid more expensive 64bit division.

Reviewed-by: Ryan Moeller <ryan@iXsystems.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Alexander Motin <mav@FreeBSD.org>
Sponsored-By: iXsystems, Inc.
Closes openzfs#12183
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Accepted Ready to integrate (reviewed, tested)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants