Skip to content
This repository has been archived by the owner on Jun 23, 2022. It is now read-only.

util: make rand a standalone util decoupled from rdsn runtime #163

Merged
merged 13 commits into from
Sep 24, 2018
11 changes: 0 additions & 11 deletions include/dsn/c/api_layer1.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,20 +345,9 @@ replace the underneath implementation of these primitives.
extern DSN_API uint64_t dsn_runtime_init_time_ms();
extern DSN_API uint64_t dsn_now_ns();

/*! return [min, max] */
extern DSN_API uint64_t dsn_random64(uint64_t min, uint64_t max);

__inline uint64_t dsn_now_us() { return dsn_now_ns() / 1000; }
__inline uint64_t dsn_now_ms() { return dsn_now_ns() / 1000000; }

/*! return [min, max] */
__inline uint32_t dsn_random32(uint32_t min, uint32_t max)
{
return (uint32_t)(dsn_random64(min, max));
}

__inline double dsn_probability() { return (double)(dsn_random64(0, 1000000000)) / 1000000000.0; }

/*@}*/

/*!
Expand Down
5 changes: 0 additions & 5 deletions include/dsn/tool-api/env_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,6 @@ class env_provider
env_provider(env_provider *inner_provider);

DSN_API virtual uint64_t now_ns() const;

DSN_API virtual uint64_t random64(uint64_t min, uint64_t max);

protected:
DSN_API static void set_thread_local_random_seed(int s);
};
/*@}*/
} // end namespace
9 changes: 5 additions & 4 deletions include/dsn/tool-api/group_address.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <dsn/c/api_layer1.h>
#include <dsn/utility/synchronize.h>
#include <dsn/utility/autoref_ptr.h>
#include <dsn/utility/rand.h>
#include <dsn/tool-api/rpc_address.h>

namespace dsn {
Expand All @@ -60,7 +61,7 @@ class rpc_group_address : public dsn::ref_counter
{
alr_t l(_lock);
return _members.empty() ? rpc_address::s_invalid_address
: _members[dsn_random32(0, (uint32_t)_members.size() - 1)];
: _members[rand::uint32in(0, (uint32_t)_members.size() - 1)];
}
rpc_address next(rpc_address current) const;
rpc_address leader() const
Expand Down Expand Up @@ -158,7 +159,7 @@ inline rpc_address rpc_group_address::possible_leader()
if (_members.empty())
return rpc_address::s_invalid_address;
if (_leader_index == -1)
_leader_index = dsn_random32(0, (uint32_t)_members.size() - 1);
_leader_index = rand::uint32in(0, (uint32_t)_members.size() - 1);
return _members[_leader_index];
}

Expand Down Expand Up @@ -194,11 +195,11 @@ inline rpc_address rpc_group_address::next(rpc_address current) const
if (_members.empty())
return rpc_address::s_invalid_address;
if (current.is_invalid())
return _members[dsn_random32(0, (uint32_t)_members.size() - 1)];
return _members[rand::uint32in(0, (uint32_t)_members.size() - 1)];
else {
auto it = std::find(_members.begin(), _members.end(), current);
if (it == _members.end())
return _members[dsn_random32(0, (uint32_t)_members.size() - 1)];
return _members[rand::uint32in(0, (uint32_t)_members.size() - 1)];
else {
it++;
return it == _members.end() ? _members[0] : *it;
Expand Down
48 changes: 48 additions & 0 deletions include/dsn/utility/rand.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) 2017, Xiaomi, Inc. All rights reserved.
// This source code is licensed under the Apache License Version 2.0, which
// can be found in the LICENSE file in the root directory of this source tree.

#pragma once

#include <cstdint>
#include <cstddef>
#include <limits>

namespace dsn {
namespace rand {

// uint64n returns, as an uint64_t, a non-negative pseudo-random number in [min, max].
Copy link
Contributor

Choose a reason for hiding this comment

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

注视是uint64n, 代码是uint64in。
不过这命名没看懂,n和in代表啥?

extern uint64_t uint64in(uint64_t min, uint64_t max);

// uint32n returns, as an uint32_t, a non-negative pseudo-random number in [min, max].
inline uint32_t uint32in(uint32_t min, uint32_t max)
{
return static_cast<uint32_t>(uint64in(min, max));
}

// uint64n returns, as an uint64_t, a non-negative pseudo-random number in [0, n).
// If n == 0, it returns 0.
inline uint64_t uint64n(uint64_t n)
{
if (n == 0)
return 0;
return uint64in(0, n - 1);
}

// uint32n returns, as an uint32_t, a non-negative pseudo-random number in [0, n).
// If n == 0, it returns 0.
inline uint32_t uint32n(uint32_t n) { return static_cast<uint32_t>(uint64n(n)); }

// uint32 returns a pseudo-random 32-bit value as a uint32_t.
inline uint32_t uint32() { return uint32in(0, std::numeric_limits<uint32_t>::max()); }

// uint64 returns a pseudo-random 64-bit value as a uint64_t.
inline uint64_t uint64() { return uint64in(0, std::numeric_limits<uint64_t>::max()); }

// float64 returns, as a double, a pseudo-random number in [0.0,1.0].
inline double float64n() { return uint64in(0, 1000000000) / 1000000000.0; }
Copy link
Contributor

Choose a reason for hiding this comment

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

float64n的命名反而不如原来的probability好。因为概率一定是[0, 1]的,而float不一定是


extern void set_seed_thread_local_rng(uint64_t seed);

} // namespace rand
} // namespace dsn
24 changes: 0 additions & 24 deletions src/core/core/env_provider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,33 +41,9 @@
namespace dsn {

//------------ env_provider ---------------
__thread unsigned int env_provider__tls_magic;
__thread std::ranlux48_base *env_provider__rng;

env_provider::env_provider(env_provider *inner_provider) {}

uint64_t env_provider::now_ns() const { return utils::get_current_physical_time_ns(); }

void env_provider::set_thread_local_random_seed(int s)
{
if (env_provider__tls_magic != 0xdeadbeef) {
env_provider__rng =
new std::remove_pointer<decltype(env_provider__rng)>::type(std::random_device{}());
env_provider__tls_magic = 0xdeadbeef;
}

env_provider__rng->seed(s);
}

uint64_t env_provider::random64(uint64_t min, uint64_t max)
{
dassert(min <= max, "invalid random range");
if (env_provider__tls_magic != 0xdeadbeef) {
env_provider__rng =
new std::remove_pointer<decltype(env_provider__rng)>::type(std::random_device{}());
env_provider__tls_magic = 0xdeadbeef;
}
return std::uniform_int_distribution<uint64_t>{min, max}(*env_provider__rng);
}

} // end namespace
3 changes: 2 additions & 1 deletion src/core/core/fail_point.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include <dsn/c/api_layer1.h>
#include <boost/regex.hpp>
#include <dsn/utility/rand.h>

namespace dsn {
namespace fail {
Expand Down Expand Up @@ -97,7 +98,7 @@ bool fail_point::parse_from_string(string_view action)

const std::string *fail_point::eval()
{
uint32_t r = dsn_random32(0, 100);
uint32_t r = rand::uint32in(0, 100);
if (r > _freq) {
return nullptr;
}
Expand Down
3 changes: 2 additions & 1 deletion src/core/core/partition_resolver_simple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

#include "partition_resolver_simple.h"
#include <dsn/utility/utils.h>
#include <dsn/utility/rand.h>
#include <dsn/tool-api/async_calls.h>

namespace dsn {
Expand Down Expand Up @@ -419,7 +420,7 @@ rpc_address partition_resolver_simple::get_address(const partition_configuration
if (config.last_drops.size() == 0) {
return rpc_address();
} else {
return config.last_drops[dsn_random32(0, config.last_drops.size() - 1)];
return config.last_drops[rand::uint32in(0, config.last_drops.size() - 1)];
}
}

Expand Down
21 changes: 21 additions & 0 deletions src/core/core/rand.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) 2017, Xiaomi, Inc. All rights reserved.
Copy link
Contributor

Choose a reason for hiding this comment

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

文件名还是统一用cpp吧

// This source code is licensed under the Apache License Version 2.0, which
// can be found in the LICENSE file in the root directory of this source tree.

#include <dsn/utility/rand.h>
#include <random>

namespace dsn {
namespace rand {

thread_local std::ranlux48_base g_thread_local_rng(std::random_device{}());

/*extern*/ uint64_t uint64in(uint64_t min, uint64_t max)
{
return std::uniform_int_distribution<uint64_t>(min, max)(g_thread_local_rng);
}

/*extern*/ void set_seed_thread_local_rng(uint64_t seed) { g_thread_local_rng.seed(seed); }

} // namespace rand
} // namespace dsn
3 changes: 2 additions & 1 deletion src/core/core/rpc_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
#include <dsn/tool-api/task_queue.h>
#include <dsn/tool-api/async_calls.h>
#include <dsn/cpp/serialization.h>
#include <dsn/utility/rand.h>
#include <set>

namespace dsn {
Expand Down Expand Up @@ -634,7 +635,7 @@ void rpc_engine::call(message_ex *request, const rpc_response_task_ptr &call)
{
auto &hdr = *request->header;
hdr.from_address = primary_address();
hdr.trace_id = dsn_random64(std::numeric_limits<decltype(hdr.trace_id)>::min(),
hdr.trace_id = rand::uint64in(std::numeric_limits<decltype(hdr.trace_id)>::min(),
std::numeric_limits<decltype(hdr.trace_id)>::max());

call_address(request->server_address, request, call);
Expand Down
5 changes: 0 additions & 5 deletions src/core/core/service_api_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,11 +381,6 @@ DSN_API uint64_t dsn_now_ns()
return ::dsn::service_engine::instance().env()->now_ns();
}

DSN_API uint64_t dsn_random64(uint64_t min, uint64_t max) // [min, max]
{
return ::dsn::service_engine::instance().env()->random64(min, max);
}

static uint64_t s_runtime_init_time_ms;
DSN_API uint64_t dsn_runtime_init_time_ms() { return s_runtime_init_time_ms; }

Expand Down
3 changes: 2 additions & 1 deletion src/core/core/task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <dsn/tool-api/env_provider.h>
#include <dsn/utility/utils.h>
#include <dsn/utility/synchronize.h>
#include <dsn/utility/rand.h>
#include <dsn/tool/node_scoper.h>

#include "task_engine.h"
Expand Down Expand Up @@ -431,7 +432,7 @@ void timer_task::enqueue()
{
// enable timer randomization to avoid lots of timers execution simultaneously
if (delay_milliseconds() == 0 && spec().randomize_timer_delay_if_zero) {
set_delay(dsn_random32(0, _interval_milliseconds));
set_delay(rand::uint32in(0, _interval_milliseconds));
}

return task::enqueue();
Expand Down
5 changes: 3 additions & 2 deletions src/core/tests/env.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

#include <dsn/tool-api/env_provider.h>
#include <gtest/gtest.h>
#include <dsn/utility/rand.h>
#include "../tools/simulator/env.sim.h"

using namespace ::dsn;
Expand All @@ -44,10 +45,10 @@ TEST(core, env)
uint64_t xs[] = {0, std::numeric_limits<uint64_t>::max() - 1, 0xdeadbeef};

for (auto &x : xs) {
auto r = dsn_random64(x, x);
auto r = rand::uint64in(x, x);
EXPECT_EQ(r, x);

r = dsn_random64(x, x + 1);
r = rand::uint64in(x, x + 1);
EXPECT_TRUE(r == x || r == (x + 1));
}
}
69 changes: 69 additions & 0 deletions src/core/tests/rand_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) 2017, Xiaomi, Inc. All rights reserved.
// This source code is licensed under the Apache License Version 2.0, which
// can be found in the LICENSE file in the root directory of this source tree.

#include <dsn/utility/rand.h>
#include <gtest/gtest.h>
#include <thread>

namespace dsn {

TEST(random, sanity)
{
{ // edge cases
ASSERT_EQ(rand::uint64n(0), 0);
ASSERT_EQ(rand::uint64in(0, 0), 0);
ASSERT_EQ(rand::uint32n(0), 0);
ASSERT_EQ(rand::uint32in(0, 0), 0);

ASSERT_EQ(rand::uint64in(12, 12), 12);
ASSERT_EQ(rand::uint32in(12, 12), 12);
}

constexpr int kTestSize = 1000;

{ // 32-bit repeatability, uniqueness
rand::set_seed_thread_local_rng(0xdeadbeef);
std::vector<uint32_t> vals(kTestSize);
for (int i = 0; i < kTestSize; ++i) {
vals[i] = rand::uint32();
}

rand::set_seed_thread_local_rng(0xdeadbeef);
for (int i = 0; i < kTestSize; ++i) {
ASSERT_EQ(rand::uint32(), vals[i]);
}
}

{ // 64-bit repeatability, uniqueness
rand::set_seed_thread_local_rng(0xdeadbeef);
std::vector<uint64_t> vals(kTestSize);
for (int i = 0; i < kTestSize; ++i) {
vals[i] = rand::uint64();
}

rand::set_seed_thread_local_rng(0xdeadbeef);
for (int i = 0; i < kTestSize; ++i) {
ASSERT_EQ(rand::uint64(), vals[i]);
}
}
}

TEST(random, multi_threaded)
{
const int n = 100;
std::vector<uint32_t> seeds(n);
std::vector<std::thread> threads;
for (int i = 0; i < n; ++i) {
threads.push_back(std::thread([i, &seeds] { seeds[i] = rand::uint32(); }));
}
for (auto &t : threads) {
t.join();
}
std::sort(seeds.begin(), seeds.end());
for (int i = 0; i < n - 1; ++i) {
EXPECT_LT(seeds[i], seeds[i + 1]);
}
}

} // namespace dsn
3 changes: 2 additions & 1 deletion src/core/tests/service_api_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <dsn/utility/filesystem.h>
#include <gtest/gtest.h>
#include <thread>
#include <dsn/utility/rand.h>
#include "core/core/service_engine.h"

using namespace dsn;
Expand Down Expand Up @@ -288,7 +289,7 @@ TEST(core, dsn_env)
std::this_thread::sleep_for(std::chrono::milliseconds(1));
uint64_t now2 = dsn_now_ns();
ASSERT_LE(now1 + 1000000, now2);
uint64_t r = dsn_random64(100, 200);
uint64_t r = rand::uint64in(100, 200);
ASSERT_LE(100, r);
ASSERT_GE(200, r);
}
Expand Down
3 changes: 2 additions & 1 deletion src/core/tests/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <dsn/utility/autoref_ptr.h>
#include <dsn/c/api_layer1.h>
#include <gtest/gtest.h>
#include <dsn/utility/rand.h>

using namespace ::dsn;
using namespace ::dsn::utils;
Expand All @@ -59,7 +60,7 @@ TEST(core, crc)
{
char buffer[24];
for (int i = 0; i < sizeof(buffer) / sizeof(char); i++) {
buffer[i] = dsn_random32(0, 200);
buffer[i] = rand::uint32in(0, 200);
}

auto c1 = dsn::utils::crc32_calc(buffer, 12, 0);
Expand Down
Loading