mirror of https://github.com/grpc/grpc.git
commit
6b085d242b
27 changed files with 565 additions and 451 deletions
@ -0,0 +1,76 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016 gRPC 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_SUPPORT_MANUAL_CONSTRUCTOR_H |
||||
#define GRPC_CORE_LIB_SUPPORT_MANUAL_CONSTRUCTOR_H |
||||
|
||||
// manually construct a region of memory with some type
|
||||
|
||||
#include <stddef.h> |
||||
#include <new> |
||||
#include <type_traits> |
||||
#include <utility> |
||||
|
||||
namespace grpc_core { |
||||
|
||||
template <typename Type> |
||||
class ManualConstructor { |
||||
public: |
||||
// No constructor or destructor because one of the most useful uses of
|
||||
// this class is as part of a union, and members of a union could not have
|
||||
// constructors or destructors till C++11. And, anyway, the whole point of
|
||||
// this class is to bypass constructor and destructor.
|
||||
|
||||
Type* get() { return reinterpret_cast<Type*>(&space_); } |
||||
const Type* get() const { return reinterpret_cast<const Type*>(&space_); } |
||||
|
||||
Type* operator->() { return get(); } |
||||
const Type* operator->() const { return get(); } |
||||
|
||||
Type& operator*() { return *get(); } |
||||
const Type& operator*() const { return *get(); } |
||||
|
||||
void Init() { new (&space_) Type; } |
||||
|
||||
// Init() constructs the Type instance using the given arguments
|
||||
// (which are forwarded to Type's constructor).
|
||||
//
|
||||
// Note that Init() with no arguments performs default-initialization,
|
||||
// not zero-initialization (i.e it behaves the same as "new Type;", not
|
||||
// "new Type();"), so it will leave non-class types uninitialized.
|
||||
template <typename... Ts> |
||||
void Init(Ts&&... args) { |
||||
new (&space_) Type(std::forward<Ts>(args)...); |
||||
} |
||||
|
||||
// Init() that is equivalent to copy and move construction.
|
||||
// Enables usage like this:
|
||||
// ManualConstructor<std::vector<int>> v;
|
||||
// v.Init({1, 2, 3});
|
||||
void Init(const Type& x) { new (&space_) Type(x); } |
||||
void Init(Type&& x) { new (&space_) Type(std::move(x)); } |
||||
|
||||
void Destroy() { get()->~Type(); } |
||||
|
||||
private: |
||||
typename std::aligned_storage<sizeof(Type), alignof(Type)>::type space_; |
||||
}; |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif |
@ -1,162 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016 gRPC 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. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/lib/transport/bdp_estimator.h" |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
#include <grpc/support/useful.h> |
||||
#include <limits.h> |
||||
#include "src/core/lib/iomgr/timer_manager.h" |
||||
#include "src/core/lib/support/string.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type); |
||||
|
||||
static int g_clock = 0; |
||||
|
||||
static gpr_timespec fake_gpr_now(gpr_clock_type clock_type) { |
||||
return (gpr_timespec){ |
||||
.tv_sec = g_clock, .tv_nsec = 0, .clock_type = clock_type, |
||||
}; |
||||
} |
||||
|
||||
static void inc_time(void) { g_clock += 30; } |
||||
|
||||
static void test_noop(void) { |
||||
gpr_log(GPR_INFO, "test_noop"); |
||||
grpc_bdp_estimator est; |
||||
grpc_bdp_estimator_init(&est, "test"); |
||||
} |
||||
|
||||
static void test_get_estimate_no_samples(void) { |
||||
gpr_log(GPR_INFO, "test_get_estimate_no_samples"); |
||||
grpc_bdp_estimator est; |
||||
grpc_bdp_estimator_init(&est, "test"); |
||||
int64_t estimate; |
||||
grpc_bdp_estimator_get_estimate(&est, &estimate); |
||||
} |
||||
|
||||
static void add_samples(grpc_bdp_estimator *estimator, int64_t *samples, |
||||
size_t n) { |
||||
grpc_bdp_estimator_add_incoming_bytes(estimator, 1234567); |
||||
inc_time(); |
||||
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; |
||||
GPR_ASSERT(grpc_bdp_estimator_need_ping(&exec_ctx, estimator) == true); |
||||
grpc_bdp_estimator_schedule_ping(estimator); |
||||
grpc_bdp_estimator_start_ping(estimator); |
||||
for (size_t i = 0; i < n; i++) { |
||||
grpc_bdp_estimator_add_incoming_bytes(estimator, samples[i]); |
||||
GPR_ASSERT(grpc_bdp_estimator_need_ping(&exec_ctx, estimator) == false); |
||||
} |
||||
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), |
||||
gpr_time_from_millis(1, GPR_TIMESPAN))); |
||||
grpc_bdp_estimator_complete_ping(&exec_ctx, estimator); |
||||
grpc_exec_ctx_finish(&exec_ctx); |
||||
} |
||||
|
||||
static void add_sample(grpc_bdp_estimator *estimator, int64_t sample) { |
||||
add_samples(estimator, &sample, 1); |
||||
} |
||||
|
||||
static void test_get_estimate_1_sample(void) { |
||||
gpr_log(GPR_INFO, "test_get_estimate_1_sample"); |
||||
grpc_bdp_estimator est; |
||||
grpc_bdp_estimator_init(&est, "test"); |
||||
add_sample(&est, 100); |
||||
int64_t estimate; |
||||
grpc_bdp_estimator_get_estimate(&est, &estimate); |
||||
} |
||||
|
||||
static void test_get_estimate_2_samples(void) { |
||||
gpr_log(GPR_INFO, "test_get_estimate_2_samples"); |
||||
grpc_bdp_estimator est; |
||||
grpc_bdp_estimator_init(&est, "test"); |
||||
add_sample(&est, 100); |
||||
add_sample(&est, 100); |
||||
int64_t estimate; |
||||
grpc_bdp_estimator_get_estimate(&est, &estimate); |
||||
} |
||||
|
||||
static int64_t get_estimate(grpc_bdp_estimator *estimator) { |
||||
int64_t out; |
||||
GPR_ASSERT(grpc_bdp_estimator_get_estimate(estimator, &out)); |
||||
return out; |
||||
} |
||||
|
||||
static void test_get_estimate_3_samples(void) { |
||||
gpr_log(GPR_INFO, "test_get_estimate_3_samples"); |
||||
grpc_bdp_estimator est; |
||||
grpc_bdp_estimator_init(&est, "test"); |
||||
add_sample(&est, 100); |
||||
add_sample(&est, 100); |
||||
add_sample(&est, 100); |
||||
int64_t estimate; |
||||
grpc_bdp_estimator_get_estimate(&est, &estimate); |
||||
} |
||||
|
||||
static int64_t next_pow_2(int64_t v) { |
||||
v--; |
||||
v |= v >> 1; |
||||
v |= v >> 2; |
||||
v |= v >> 4; |
||||
v |= v >> 8; |
||||
v |= v >> 16; |
||||
v |= v >> 32; |
||||
v++; |
||||
return v; |
||||
} |
||||
|
||||
static void test_get_estimate_random_values(size_t n) { |
||||
gpr_log(GPR_INFO, "test_get_estimate_random_values(%" PRIdPTR ")", n); |
||||
grpc_bdp_estimator est; |
||||
grpc_bdp_estimator_init(&est, "test"); |
||||
const int kMaxSample = 65535; |
||||
int min = kMaxSample; |
||||
int max = 0; |
||||
for (size_t i = 0; i < n; i++) { |
||||
int sample = rand() % (kMaxSample + 1); |
||||
if (sample < min) min = sample; |
||||
if (sample > max) max = sample; |
||||
add_sample(&est, sample); |
||||
if (i >= 3) { |
||||
gpr_log(GPR_DEBUG, "est:%" PRId64 " min:%d max:%d", get_estimate(&est), |
||||
min, max); |
||||
GPR_ASSERT(get_estimate(&est) <= GPR_MAX(65536, 2 * next_pow_2(max))); |
||||
} |
||||
} |
||||
} |
||||
|
||||
int main(int argc, char **argv) { |
||||
grpc_test_init(argc, argv); |
||||
gpr_now_impl = fake_gpr_now; |
||||
grpc_init(); |
||||
grpc_timer_manager_set_threading(false); |
||||
test_noop(); |
||||
test_get_estimate_no_samples(); |
||||
test_get_estimate_1_sample(); |
||||
test_get_estimate_2_samples(); |
||||
test_get_estimate_3_samples(); |
||||
for (size_t i = 3; i < 1000; i = i * 3 / 2) { |
||||
test_get_estimate_random_values(i); |
||||
} |
||||
grpc_shutdown(); |
||||
return 0; |
||||
} |
@ -0,0 +1,158 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016 gRPC 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. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/lib/transport/bdp_estimator.h" |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
#include <grpc/support/useful.h> |
||||
#include <gtest/gtest.h> |
||||
#include <limits.h> |
||||
#include "src/core/lib/iomgr/timer_manager.h" |
||||
#include "src/core/lib/support/string.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
extern "C" gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type); |
||||
|
||||
namespace grpc_core { |
||||
namespace testing { |
||||
namespace { |
||||
int g_clock = 0; |
||||
|
||||
gpr_timespec fake_gpr_now(gpr_clock_type clock_type) { |
||||
return (gpr_timespec){ |
||||
.tv_sec = g_clock, .tv_nsec = 0, .clock_type = clock_type, |
||||
}; |
||||
} |
||||
|
||||
void inc_time(void) { g_clock += 30; } |
||||
} // namespace
|
||||
|
||||
TEST(BdpEstimatorTest, NoOp) { BdpEstimator est("test"); } |
||||
|
||||
TEST(BdpEstimatorTest, EstimateBdpNoSamples) { |
||||
BdpEstimator est("test"); |
||||
int64_t estimate; |
||||
est.EstimateBdp(&estimate); |
||||
} |
||||
|
||||
namespace { |
||||
void AddSamples(BdpEstimator *estimator, int64_t *samples, size_t n) { |
||||
estimator->AddIncomingBytes(1234567); |
||||
inc_time(); |
||||
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; |
||||
EXPECT_TRUE(estimator->NeedPing(&exec_ctx)); |
||||
estimator->SchedulePing(); |
||||
estimator->StartPing(); |
||||
for (size_t i = 0; i < n; i++) { |
||||
estimator->AddIncomingBytes(samples[i]); |
||||
EXPECT_FALSE(estimator->NeedPing(&exec_ctx)); |
||||
} |
||||
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), |
||||
gpr_time_from_millis(1, GPR_TIMESPAN))); |
||||
grpc_exec_ctx_invalidate_now(&exec_ctx); |
||||
estimator->CompletePing(&exec_ctx); |
||||
grpc_exec_ctx_finish(&exec_ctx); |
||||
} |
||||
|
||||
void AddSample(BdpEstimator *estimator, int64_t sample) { |
||||
AddSamples(estimator, &sample, 1); |
||||
} |
||||
} // namespace
|
||||
|
||||
TEST(BdpEstimatorTest, GetEstimate1Sample) { |
||||
BdpEstimator est("test"); |
||||
AddSample(&est, 100); |
||||
int64_t estimate; |
||||
est.EstimateBdp(&estimate); |
||||
} |
||||
|
||||
TEST(BdpEstimatorTest, GetEstimate2Samples) { |
||||
BdpEstimator est("test"); |
||||
AddSample(&est, 100); |
||||
AddSample(&est, 100); |
||||
int64_t estimate; |
||||
est.EstimateBdp(&estimate); |
||||
} |
||||
|
||||
TEST(BdpEstimatorTest, GetEstimate3Samples) { |
||||
BdpEstimator est("test"); |
||||
AddSample(&est, 100); |
||||
AddSample(&est, 100); |
||||
AddSample(&est, 100); |
||||
int64_t estimate; |
||||
est.EstimateBdp(&estimate); |
||||
} |
||||
|
||||
namespace { |
||||
static int64_t GetEstimate(const BdpEstimator &estimator) { |
||||
int64_t out; |
||||
EXPECT_TRUE(estimator.EstimateBdp(&out)); |
||||
return out; |
||||
} |
||||
|
||||
int64_t NextPow2(int64_t v) { |
||||
v--; |
||||
v |= v >> 1; |
||||
v |= v >> 2; |
||||
v |= v >> 4; |
||||
v |= v >> 8; |
||||
v |= v >> 16; |
||||
v |= v >> 32; |
||||
v++; |
||||
return v; |
||||
} |
||||
} // namespace
|
||||
|
||||
class BdpEstimatorRandomTest : public ::testing::TestWithParam<size_t> {}; |
||||
|
||||
TEST_P(BdpEstimatorRandomTest, GetEstimateRandomValues) { |
||||
BdpEstimator est("test"); |
||||
const int kMaxSample = 65535; |
||||
int min = kMaxSample; |
||||
int max = 0; |
||||
for (size_t i = 0; i < GetParam(); i++) { |
||||
int sample = rand() % (kMaxSample + 1); |
||||
if (sample < min) min = sample; |
||||
if (sample > max) max = sample; |
||||
AddSample(&est, sample); |
||||
if (i >= 3) { |
||||
EXPECT_LE(GetEstimate(est), GPR_MAX(65536, 2 * NextPow2(max))) |
||||
<< " min:" << min << " max:" << max << " sample:" << sample; |
||||
} |
||||
} |
||||
} |
||||
|
||||
INSTANTIATE_TEST_CASE_P(TooManyNames, BdpEstimatorRandomTest, |
||||
::testing::Values(3, 4, 6, 9, 13, 19, 28, 42, 63, 94, |
||||
141, 211, 316, 474, 711)); |
||||
} // namespace testing
|
||||
} // namespace grpc_core
|
||||
|
||||
int main(int argc, char **argv) { |
||||
grpc_test_init(argc, argv); |
||||
gpr_now_impl = grpc_core::testing::fake_gpr_now; |
||||
grpc_init(); |
||||
grpc_timer_manager_set_threading(false); |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
int ret = RUN_ALL_TESTS(); |
||||
grpc_shutdown(); |
||||
return ret; |
||||
} |
Loading…
Reference in new issue