diff options
author | dalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-23 02:14:28 +0000 |
---|---|---|
committer | dalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-23 02:14:28 +0000 |
commit | c910c5a68ca7baf2da4edfd722f55f2b089402e2 (patch) | |
tree | b844a63d20f8c7437e4ace80dfef4da86aa3f94f /base | |
parent | 52bd819c62c4e6983f2c34a449beadca49d7cdd6 (diff) | |
download | chromium_src-c910c5a68ca7baf2da4edfd722f55f2b089402e2.zip chromium_src-c910c5a68ca7baf2da4edfd722f55f2b089402e2.tar.gz chromium_src-c910c5a68ca7baf2da4edfd722f55f2b089402e2.tar.bz2 |
Improve base::RandBytes() performance by 1.75x-2.10x on POSIX.
No real changes, just avoids doling out Uint64 sized chunks by
using the underlying method to hand out correctly sized blocks.
Windows is the only platform which doesn't have a byte stream
based generator, so I've moved the generic RandBytes() method
there and added native methods for other platforms which reuse
each platforms internal generator.
Performance measured by the new benchmark test over 5 runs,
each representing 10 generations of 1mb of random data:
Linux x64:
Original: 1199625.4
Modified: 686480.2
Improvement: 1.75x
On OSX (10.9.1):
Original: 1532669.8
Modified: 734808.0
Improvement: 2.10x
BUG=none
TEST=new benchmark unittest.
Review URL: https://codereview.chromium.org/140773006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@246486 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/rand_util.cc | 10 | ||||
-rw-r--r-- | base/rand_util_nacl.cc | 22 | ||||
-rw-r--r-- | base/rand_util_posix.cc | 21 | ||||
-rw-r--r-- | base/rand_util_unittest.cc | 22 | ||||
-rw-r--r-- | base/rand_util_win.cc | 10 |
5 files changed, 55 insertions, 30 deletions
diff --git a/base/rand_util.cc b/base/rand_util.cc index 9641ff4..1525b91 100644 --- a/base/rand_util.cc +++ b/base/rand_util.cc @@ -61,16 +61,6 @@ uint64 RandGenerator(uint64 range) { return value % range; } -void RandBytes(void* output, size_t output_length) { - uint64 random_int; - size_t random_int_size = sizeof(random_int); - for (size_t i = 0; i < output_length; i += random_int_size) { - random_int = base::RandUint64(); - size_t copy_count = std::min(output_length - i, random_int_size); - memcpy(((uint8*)output) + i, &random_int, copy_count); - } -} - std::string RandBytesAsString(size_t length) { DCHECK_GT(length, 0u); std::string result; diff --git a/base/rand_util_nacl.cc b/base/rand_util_nacl.cc index 47450aa..f975121 100644 --- a/base/rand_util_nacl.cc +++ b/base/rand_util_nacl.cc @@ -14,21 +14,21 @@ namespace { class NaclRandom { public: NaclRandom() { - size_t result = nacl_interface_query(NACL_IRT_RANDOM_v0_1, - &random_, sizeof(random_)); + const size_t result = + nacl_interface_query(NACL_IRT_RANDOM_v0_1, &random_, sizeof(random_)); CHECK_EQ(result, sizeof(random_)); } - ~NaclRandom() { - } + ~NaclRandom() {} - void GetRandomBytes(char* buffer, uint32_t num_bytes) { + void GetRandomBytes(void* output, size_t num_bytes) { + char* output_ptr = static_cast<char*>(output); while (num_bytes > 0) { size_t nread; - int error = random_.get_random_bytes(buffer, num_bytes, &nread); + const int error = random_.get_random_bytes(output_ptr, num_bytes, &nread); CHECK_EQ(error, 0); CHECK_LE(nread, num_bytes); - buffer += nread; + output_ptr += nread; num_bytes -= nread; } } @@ -43,11 +43,15 @@ base::LazyInstance<NaclRandom>::Leaky g_nacl_random = LAZY_INSTANCE_INITIALIZER; namespace base { +// NOTE: This function must be cryptographically secure. http://crbug.com/140076 uint64 RandUint64() { uint64 result; - g_nacl_random.Pointer()->GetRandomBytes( - reinterpret_cast<char*>(&result), sizeof(result)); + g_nacl_random.Pointer()->GetRandomBytes(&result, sizeof(result)); return result; } +void RandBytes(void* output, size_t output_length) { + g_nacl_random.Pointer()->GetRandomBytes(output, output_length); +} + } // namespace base diff --git a/base/rand_util_posix.cc b/base/rand_util_posix.cc index 082d649..0a72a20 100644 --- a/base/rand_util_posix.cc +++ b/base/rand_util_posix.cc @@ -20,19 +20,16 @@ namespace { // we can use LazyInstance to handle opening it on the first access. class URandomFd { public: - URandomFd() { - fd_ = open("/dev/urandom", O_RDONLY); + URandomFd() : fd_(open("/dev/urandom", O_RDONLY)) { DCHECK_GE(fd_, 0) << "Cannot open /dev/urandom: " << errno; } - ~URandomFd() { - close(fd_); - } + ~URandomFd() { close(fd_); } int fd() const { return fd_; } private: - int fd_; + const int fd_; }; base::LazyInstance<URandomFd>::Leaky g_urandom_fd = LAZY_INSTANCE_INITIALIZER; @@ -44,13 +41,15 @@ namespace base { // NOTE: This function must be cryptographically secure. http://crbug.com/140076 uint64 RandUint64() { uint64 number; + RandBytes(&number, sizeof(number)); + return number; +} - int urandom_fd = g_urandom_fd.Pointer()->fd(); - bool success = ReadFromFD(urandom_fd, reinterpret_cast<char*>(&number), - sizeof(number)); +void RandBytes(void* output, size_t output_length) { + const int urandom_fd = g_urandom_fd.Pointer()->fd(); + const bool success = + ReadFromFD(urandom_fd, static_cast<char*>(output), output_length); CHECK(success); - - return number; } int GetUrandomFD(void) { diff --git a/base/rand_util_unittest.cc b/base/rand_util_unittest.cc index e0e85ec..d262275 100644 --- a/base/rand_util_unittest.cc +++ b/base/rand_util_unittest.cc @@ -7,6 +7,9 @@ #include <algorithm> #include <limits> +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/time/time.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -120,3 +123,22 @@ TEST(RandUtilTest, RandUint64ProducesBothValuesOfAllBits) { FAIL() << "Didn't achieve all bit values in maximum number of tries."; } + +// Benchmark test for RandBytes(). Disabled since it's intentionally slow and +// does not test anything that isn't already tested by the existing RandBytes() +// tests. +TEST(RandUtilTest, DISABLED_RandBytesPerf) { + // Benchmark the performance of |kTestIterations| of RandBytes() using a + // buffer size of |kTestBufferSize|. + const int kTestIterations = 10; + const size_t kTestBufferSize = 1 * 1024 * 1024; + + scoped_ptr<uint8[]> buffer(new uint8[kTestBufferSize]); + const base::TimeTicks now = base::TimeTicks::HighResNow(); + for (int i = 0; i < kTestIterations; ++i) + base::RandBytes(buffer.get(), kTestBufferSize); + const base::TimeTicks end = base::TimeTicks::HighResNow(); + + LOG(INFO) << "RandBytes(" << kTestBufferSize << ") took: " + << (end - now).InMicroseconds() << "µs"; +} diff --git a/base/rand_util_win.cc b/base/rand_util_win.cc index 391fe5b..52103eb 100644 --- a/base/rand_util_win.cc +++ b/base/rand_util_win.cc @@ -28,4 +28,14 @@ uint64 RandUint64() { return (static_cast<uint64>(first_half) << 32) + second_half; } +void RandBytes(void* output, size_t output_length) { + uint64 random_int; + const size_t random_int_size = sizeof(random_int); + for (size_t i = 0; i < output_length; i += random_int_size) { + random_int = base::RandUint64(); + const size_t copy_count = std::min(output_length - i, random_int_size); + memcpy(((uint8*)output) + i, &random_int, copy_count); + } +} + } // namespace base |