forked from open-telemetry/opentelemetry-collector
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add utility for generating random 64-bit numbers (open-telemetry#57)
* Add fork utility * Add random number generator * Add test coverage for random * Add cmake build files * Format * Add missing noexcept * Fix macro * Add FastRandomNumberGenerator
- Loading branch information
Showing
18 changed files
with
435 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,6 @@ | ||
package(default_visibility = ["//:__subpackages__"]) | ||
|
||
config_setting( | ||
name = "windows", | ||
constraint_values = ["@bazel_tools//platforms:windows"], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
add_subdirectory(common) | ||
add_subdirectory(trace) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Copyright 2020, OpenTelemetry Authors | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
package(default_visibility = ["//visibility:public"]) | ||
|
||
cc_library( | ||
name = "random", | ||
srcs = ["random.cc"], | ||
hdrs = [ | ||
"fast_random_number_generator.h", | ||
"random.h", | ||
], | ||
include_prefix = "src/common", | ||
deps = [ | ||
"//api", | ||
"//sdk/src/common/platform:fork", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
set(COMMON_SRCS random.cc) | ||
if(WIN32) | ||
list(APPEND COMMON_SRCS platform/fork_windows.cc) | ||
else() | ||
list(APPEND COMMON_SRCS platform/fork_unix.cc) | ||
endif() | ||
|
||
add_library(opentelemetry_common ${COMMON_SRCS}) | ||
target_link_libraries(opentelemetry_common Threads::Threads) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#pragma once | ||
|
||
#include <array> | ||
#include <cstdint> | ||
#include <limits> | ||
|
||
#include "opentelemetry/version.h" | ||
|
||
OPENTELEMETRY_BEGIN_NAMESPACE | ||
namespace sdk | ||
{ | ||
namespace common | ||
{ | ||
/** | ||
* Profiling shows that random number generation can be a significant cost of | ||
* span generation. This provides a faster random number generator than | ||
* std::mt19937_64; and since we don't care about the other beneficial random | ||
* number properties that std:mt19937_64 provides for this application, it's a | ||
* entirely appropriate replacement. | ||
*/ | ||
class FastRandomNumberGenerator | ||
{ | ||
public: | ||
using result_type = uint64_t; | ||
|
||
FastRandomNumberGenerator() noexcept = default; | ||
|
||
template <class SeedSequence> | ||
FastRandomNumberGenerator(SeedSequence &seed_sequence) noexcept | ||
{ | ||
seed(seed_sequence); | ||
} | ||
|
||
uint64_t operator()() noexcept | ||
{ | ||
// Uses the xorshift128p random number generation algorithm described in | ||
// https://en.wikipedia.org/wiki/Xorshift | ||
auto &state_a = state_[0]; | ||
auto &state_b = state_[1]; | ||
auto t = state_a; | ||
auto s = state_b; | ||
state_a = s; | ||
t ^= t << 23; // a | ||
t ^= t >> 17; // b | ||
t ^= s ^ (s >> 26); // c | ||
state_b = t; | ||
return t + s; | ||
} | ||
|
||
// RandomNumberGenerator concept functions required from standard library. | ||
// See http://www.cplusplus.com/reference/random/mt19937/ | ||
template <class SeedSequence> | ||
void seed(SeedSequence &seed_sequence) noexcept | ||
{ | ||
seed_sequence.generate(reinterpret_cast<uint32_t *>(state_.data()), | ||
reinterpret_cast<uint32_t *>(state_.data() + state_.size())); | ||
} | ||
|
||
static constexpr uint64_t min() noexcept { return 0; } | ||
|
||
static constexpr uint64_t max() noexcept { return std::numeric_limits<uint64_t>::max(); } | ||
|
||
private: | ||
std::array<uint64_t, 2> state_{}; | ||
}; | ||
} // namespace common | ||
} // namespace sdk | ||
OPENTELEMETRY_END_NAMESPACE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Copyright 2020, OpenTelemetry Authors | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
package(default_visibility = ["//visibility:public"]) | ||
|
||
cc_library( | ||
name = "fork", | ||
srcs = select({ | ||
"//bazel:windows": ["fork_windows.cc"], | ||
"//conditions:default": ["fork_unix.cc"], | ||
}), | ||
hdrs = [ | ||
"fork.h", | ||
], | ||
include_prefix = "src/common/platform", | ||
deps = [ | ||
"//api", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#pragma once | ||
|
||
#include "opentelemetry/version.h" | ||
|
||
OPENTELEMETRY_BEGIN_NAMESPACE | ||
namespace sdk | ||
{ | ||
namespace common | ||
{ | ||
namespace platform | ||
{ | ||
/** | ||
* Portable wrapper for pthread_atfork. | ||
* See | ||
* https://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_atfork.html | ||
*/ | ||
int AtFork(void (*prepare)(), void (*parent)(), void (*child)()) noexcept; | ||
} // namespace platform | ||
} // namespace common | ||
} // namespace sdk | ||
OPENTELEMETRY_END_NAMESPACE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#include "src/common/platform/fork.h" | ||
|
||
#include <pthread.h> | ||
|
||
OPENTELEMETRY_BEGIN_NAMESPACE | ||
namespace sdk | ||
{ | ||
namespace common | ||
{ | ||
namespace platform | ||
{ | ||
int AtFork(void (*prepare)(), void (*parent)(), void (*child)()) noexcept | ||
{ | ||
return ::pthread_atfork(prepare, parent, child); | ||
} | ||
} // namespace platform | ||
} // namespace common | ||
} // namespace sdk | ||
OPENTELEMETRY_END_NAMESPACE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#include "src/common/platform/fork.h" | ||
|
||
OPENTELEMETRY_BEGIN_NAMESPACE | ||
namespace sdk | ||
{ | ||
namespace common | ||
{ | ||
namespace platform | ||
{ | ||
int AtFork(void (*prepare)(), void (*parent)(), void (*child)()) noexcept | ||
{ | ||
(void)prepare; | ||
(void)parent; | ||
(void)child; | ||
return 0; | ||
} | ||
} // namespace platform | ||
} // namespace common | ||
} // namespace sdk | ||
OPENTELEMETRY_END_NAMESPACE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
#include "src/common/random.h" | ||
#include "src/common/platform/fork.h" | ||
|
||
OPENTELEMETRY_BEGIN_NAMESPACE | ||
namespace sdk | ||
{ | ||
namespace common | ||
{ | ||
// Wraps a thread_local random number generator, but adds a fork handler so that | ||
// the generator will be correctly seeded after forking. | ||
// | ||
// See https://stackoverflow.com/q/51882689/4447365 and | ||
// https://github.com/opentracing-contrib/nginx-opentracing/issues/52 | ||
namespace | ||
{ | ||
class TlsRandomNumberGenerator | ||
{ | ||
public: | ||
TlsRandomNumberGenerator() noexcept | ||
{ | ||
Seed(); | ||
platform::AtFork(nullptr, nullptr, OnFork); | ||
} | ||
|
||
static FastRandomNumberGenerator &engine() noexcept { return engine_; } | ||
|
||
private: | ||
static thread_local FastRandomNumberGenerator engine_; | ||
|
||
static void OnFork() noexcept { Seed(); } | ||
|
||
static void Seed() noexcept | ||
{ | ||
std::random_device random_device; | ||
std::seed_seq seed_seq{random_device(), random_device(), random_device(), random_device()}; | ||
engine_.seed(seed_seq); | ||
} | ||
}; | ||
|
||
thread_local FastRandomNumberGenerator TlsRandomNumberGenerator::engine_{}; | ||
} // namespace | ||
|
||
FastRandomNumberGenerator &GetRandomNumberGenerator() noexcept | ||
{ | ||
static thread_local TlsRandomNumberGenerator random_number_generator{}; | ||
return TlsRandomNumberGenerator::engine(); | ||
} | ||
} // namespace common | ||
} // namespace sdk | ||
OPENTELEMETRY_END_NAMESPACE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#pragma once | ||
|
||
#include <random> | ||
|
||
#include "opentelemetry/version.h" | ||
#include "src/common/fast_random_number_generator.h" | ||
|
||
OPENTELEMETRY_BEGIN_NAMESPACE | ||
namespace sdk | ||
{ | ||
namespace common | ||
{ | ||
/** | ||
* @return a seeded thread-local random number generator. | ||
*/ | ||
FastRandomNumberGenerator &GetRandomNumberGenerator() noexcept; | ||
} // namespace common | ||
} // namespace sdk | ||
OPENTELEMETRY_END_NAMESPACE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
add_subdirectory(common) | ||
add_subdirectory(trace) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") | ||
|
||
cc_test( | ||
name = "random_test", | ||
srcs = [ | ||
"random_test.cc", | ||
], | ||
deps = [ | ||
"//sdk/src/common:random", | ||
"@com_google_googletest//:gtest_main", | ||
], | ||
) | ||
|
||
cc_test( | ||
name = "fast_random_number_generator_test", | ||
srcs = [ | ||
"fast_random_number_generator_test.cc", | ||
], | ||
deps = [ | ||
"//sdk/src/common:random", | ||
"@com_google_googletest//:gtest_main", | ||
], | ||
) | ||
|
||
cc_test( | ||
name = "random_fork_test", | ||
srcs = [ | ||
"random_fork_test.cc", | ||
], | ||
deps = [ | ||
"//sdk/src/common:random", | ||
"@com_google_googletest//:gtest_main", | ||
], | ||
) | ||
|
||
otel_cc_benchmark( | ||
name = "random_benchmark", | ||
srcs = ["random_benchmark.cc"], | ||
deps = ["//sdk/src/common:random"], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
foreach(testname random_test fast_random_number_generator_test) | ||
add_executable(${testname} "${testname}.cc") | ||
target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} | ||
${CMAKE_THREAD_LIBS_INIT} opentelemetry_common) | ||
gtest_add_tests(TARGET ${testname} TEST_PREFIX trace. TEST_LIST ${testname}) | ||
endforeach() | ||
|
||
add_executable(random_fork_test random_fork_test.cc) | ||
target_link_libraries(random_fork_test opentelemetry_common) | ||
add_test(random_fork_test random_fork_test) | ||
|
||
add_executable(random_benchmark random_benchmark.cc) | ||
target_link_libraries(random_benchmark benchmark::benchmark | ||
${CMAKE_THREAD_LIBS_INIT} opentelemetry_common) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#include "src/common/random.h" | ||
|
||
#include <gtest/gtest.h> | ||
using opentelemetry::sdk::common::FastRandomNumberGenerator; | ||
|
||
TEST(FastRandomNumberGeneratorTest, GenerateUniqueNumbers) | ||
{ | ||
std::seed_seq seed_sequence{1, 2, 3}; | ||
FastRandomNumberGenerator random_number_generator; | ||
random_number_generator.seed(seed_sequence); | ||
std::set<uint64_t> values; | ||
for (int i = 0; i < 1000; ++i) | ||
{ | ||
EXPECT_TRUE(values.insert(random_number_generator()).second); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#include "src/common/random.h" | ||
|
||
#include <benchmark/benchmark.h> | ||
#include <cstdint> | ||
|
||
namespace | ||
{ | ||
using opentelemetry::sdk::common::GetRandomNumberGenerator; | ||
|
||
void BM_RandomIdGeneration(benchmark::State &state) | ||
{ | ||
auto &generator = GetRandomNumberGenerator(); | ||
while (state.KeepRunning()) | ||
{ | ||
benchmark::DoNotOptimize(generator()); | ||
} | ||
} | ||
BENCHMARK(BM_RandomIdGeneration); | ||
|
||
void BM_RandomIdStdGeneration(benchmark::State &state) | ||
{ | ||
std::mt19937_64 generator{0}; | ||
while (state.KeepRunning()) | ||
{ | ||
benchmark::DoNotOptimize(generator()); | ||
} | ||
} | ||
BENCHMARK(BM_RandomIdStdGeneration); | ||
|
||
} // namespace | ||
BENCHMARK_MAIN(); |
Oops, something went wrong.