Merge pull request #19948 from rmstar/timer_test

Added test for timer wakeups
pull/19856/head^2
rmstar 5 years ago committed by GitHub
commit 1c89c363b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 43
      CMakeLists.txt
  2. 48
      Makefile
  3. 11
      build.yaml
  4. 9
      src/core/lib/iomgr/timer_manager.cc
  5. 2
      src/core/lib/iomgr/timer_manager.h
  6. 13
      test/cpp/common/BUILD
  7. 150
      test/cpp/common/timer_test.cc
  8. 24
      tools/run_tests/generated/tests.json

@ -730,6 +730,7 @@ add_dependencies(buildtests_cxx thread_stress_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx time_change_test)
endif()
add_dependencies(buildtests_cxx timer_test)
add_dependencies(buildtests_cxx transport_pid_controller_test)
add_dependencies(buildtests_cxx transport_security_common_api_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@ -17355,6 +17356,48 @@ endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(timer_test
test/cpp/common/timer_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(timer_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_UPB_GENERATED_DIR}
PRIVATE ${_gRPC_UPB_GRPC_GENERATED_DIR}
PRIVATE ${_gRPC_UPB_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest
PRIVATE third_party/googletest/googlemock/include
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(timer_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc++
grpc
gpr
${_gRPC_GFLAGS_LIBRARIES}
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(transport_pid_controller_test
test/core/transport/pid_controller_test.cc
third_party/googletest/googletest/src/gtest-all.cc

@ -1293,6 +1293,7 @@ string_view_test: $(BINDIR)/$(CONFIG)/string_view_test
thread_manager_test: $(BINDIR)/$(CONFIG)/thread_manager_test
thread_stress_test: $(BINDIR)/$(CONFIG)/thread_stress_test
time_change_test: $(BINDIR)/$(CONFIG)/time_change_test
timer_test: $(BINDIR)/$(CONFIG)/timer_test
transport_pid_controller_test: $(BINDIR)/$(CONFIG)/transport_pid_controller_test
transport_security_common_api_test: $(BINDIR)/$(CONFIG)/transport_security_common_api_test
writes_per_rpc_test: $(BINDIR)/$(CONFIG)/writes_per_rpc_test
@ -1764,6 +1765,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/thread_manager_test \
$(BINDIR)/$(CONFIG)/thread_stress_test \
$(BINDIR)/$(CONFIG)/time_change_test \
$(BINDIR)/$(CONFIG)/timer_test \
$(BINDIR)/$(CONFIG)/transport_pid_controller_test \
$(BINDIR)/$(CONFIG)/transport_security_common_api_test \
$(BINDIR)/$(CONFIG)/writes_per_rpc_test \
@ -1932,6 +1934,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/thread_manager_test \
$(BINDIR)/$(CONFIG)/thread_stress_test \
$(BINDIR)/$(CONFIG)/time_change_test \
$(BINDIR)/$(CONFIG)/timer_test \
$(BINDIR)/$(CONFIG)/transport_pid_controller_test \
$(BINDIR)/$(CONFIG)/transport_security_common_api_test \
$(BINDIR)/$(CONFIG)/writes_per_rpc_test \
@ -2475,6 +2478,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/thread_stress_test || ( echo test thread_stress_test failed ; exit 1 )
$(E) "[RUN] Testing time_change_test"
$(Q) $(BINDIR)/$(CONFIG)/time_change_test || ( echo test time_change_test failed ; exit 1 )
$(E) "[RUN] Testing timer_test"
$(Q) $(BINDIR)/$(CONFIG)/timer_test || ( echo test timer_test failed ; exit 1 )
$(E) "[RUN] Testing transport_pid_controller_test"
$(Q) $(BINDIR)/$(CONFIG)/transport_pid_controller_test || ( echo test transport_pid_controller_test failed ; exit 1 )
$(E) "[RUN] Testing transport_security_common_api_test"
@ -19813,6 +19818,49 @@ endif
endif
TIMER_TEST_SRC = \
test/cpp/common/timer_test.cc \
TIMER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TIMER_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/timer_test: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
$(BINDIR)/$(CONFIG)/timer_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/timer_test: $(PROTOBUF_DEP) $(TIMER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(TIMER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/timer_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/cpp/common/timer_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_timer_test: $(TIMER_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(TIMER_TEST_OBJS:.o=.dep)
endif
endif
TRANSPORT_PID_CONTROLLER_TEST_SRC = \
test/core/transport/pid_controller_test.cc \

@ -5960,6 +5960,17 @@ targets:
- mac
- linux
- posix
- name: timer_test
gtest: true
build: test
language: c++
src:
- test/cpp/common/timer_test.cc
deps:
- grpc_test_util
- grpc++
- grpc
- gpr
- name: transport_pid_controller_test
build: test
language: c++

@ -18,6 +18,8 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/iomgr/timer_manager.h"
#include <inttypes.h>
#include <grpc/support/alloc.h>
@ -26,7 +28,6 @@
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/iomgr/timer_manager.h"
struct completed_thread {
grpc_core::Thread thd;
@ -58,6 +59,8 @@ static bool g_has_timed_waiter;
static grpc_millis g_timed_waiter_deadline;
// generation counter to track which thread is waiting for the next timer
static uint64_t g_timed_waiter_generation;
// number of timer wakeups
static uint64_t g_wakeups;
static void timer_thread(void* completed_thread_ptr);
@ -206,6 +209,7 @@ static bool wait_until(grpc_millis next) {
// that there's now no timed waiter... we'll look for a replacement if
// there's work to do after checking timers (code above)
if (my_timed_waiter_generation == g_timed_waiter_generation) {
++g_wakeups;
g_has_timed_waiter = false;
g_timed_waiter_deadline = GRPC_MILLIS_INF_FUTURE;
}
@ -326,6 +330,7 @@ static void stop_threads(void) {
gc_completed_threads();
}
}
g_wakeups = 0;
gpr_mu_unlock(&g_mu);
}
@ -354,3 +359,5 @@ void grpc_kick_poller(void) {
gpr_cv_signal(&g_cv_wait);
gpr_mu_unlock(&g_mu);
}
uint64_t grpc_timer_manager_get_wakeups_testonly(void) { return g_wakeups; }

@ -35,5 +35,7 @@ void grpc_timer_manager_set_threading(bool enabled);
/* explicitly perform one tick of the timer system - for when threading is
* disabled */
void grpc_timer_manager_tick(void);
/* get global counter that tracks timer wakeups */
uint64_t grpc_timer_manager_get_wakeups_testonly(void);
#endif /* GRPC_CORE_LIB_IOMGR_TIMER_MANAGER_H */

@ -28,7 +28,18 @@ grpc_cc_test(
"//:grpc++_unsecure",
"//test/core/util:grpc_test_util_unsecure",
],
tags = ["no_windows"],
)
grpc_cc_test(
name = "timer_test",
srcs = ["timer_test.cc"],
external_deps = [
"gtest",
],
deps = [
"//:grpc++",
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(

@ -0,0 +1,150 @@
/*
*
* Copyright 2019 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 <grpc/grpc.h>
#include <grpc/support/log.h>
#include <gtest/gtest.h>
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/iomgr/timer_manager.h"
#include "test/core/util/test_config.h"
// MAYBE_SKIP_TEST is a macro to determine if this particular test configuration
// should be skipped based on a decision made at SetUp time.
#define MAYBE_SKIP_TEST \
do { \
if (do_not_test_) { \
return; \
} \
} while (0)
class TimerTest : public ::testing::Test {
protected:
void SetUp() override {
// Skip test if slowdown factor > 1.
do_not_test_ = (grpc_test_slowdown_factor() != 1);
grpc_init();
}
void TearDown() override { grpc_shutdown_blocking(); }
bool do_not_test_{false};
};
TEST_F(TimerTest, NoTimers) {
MAYBE_SKIP_TEST;
grpc_core::ExecCtx exec_ctx;
gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(1500));
// We expect to get 1 wakeup per second. Sometimes we also get a wakeup
// during initialization, so in 1.5 seconds we expect to get 1 or 2 wakeups.
int64_t wakeups = grpc_timer_manager_get_wakeups_testonly();
GPR_ASSERT(wakeups == 1 || wakeups == 2);
}
TEST_F(TimerTest, OneTimerExpires) {
MAYBE_SKIP_TEST;
grpc_core::ExecCtx exec_ctx;
grpc_timer timer;
int timer_fired = 0;
grpc_timer_init(&timer, 500,
GRPC_CLOSURE_CREATE(
[](void* arg, grpc_error*) {
int* timer_fired = static_cast<int*>(arg);
++*timer_fired;
},
&timer_fired, grpc_schedule_on_exec_ctx));
gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(1500));
GPR_ASSERT(1 == timer_fired);
// We expect to get 1 wakeup/second + 1 wakeup for the expired timer + maybe 1
// wakeup during initialization. i.e. in 1.5 seconds we expect 2 or 3 wakeups.
// Actual number of wakeups is more due to bug
// https://github.com/grpc/grpc/issues/19947
int64_t wakeups = grpc_timer_manager_get_wakeups_testonly();
gpr_log(GPR_DEBUG, "wakeups: %" PRId64 "", wakeups);
}
TEST_F(TimerTest, MultipleTimersExpire) {
MAYBE_SKIP_TEST;
grpc_core::ExecCtx exec_ctx;
const int kNumTimers = 10;
grpc_timer timers[kNumTimers];
int timer_fired = 0;
for (int i = 0; i < kNumTimers; ++i) {
grpc_timer_init(&timers[i], 500 + i,
GRPC_CLOSURE_CREATE(
[](void* arg, grpc_error*) {
int* timer_fired = static_cast<int*>(arg);
++*timer_fired;
},
&timer_fired, grpc_schedule_on_exec_ctx));
}
gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(1500));
GPR_ASSERT(kNumTimers == timer_fired);
// We expect to get 1 wakeup/second + 1 wakeup for per timer fired + maybe 1
// wakeup during initialization. i.e. in 1.5 seconds we expect 11 or 12
// wakeups. Actual number of wakeups is more due to bug
// https://github.com/grpc/grpc/issues/19947
int64_t wakeups = grpc_timer_manager_get_wakeups_testonly();
gpr_log(GPR_DEBUG, "wakeups: %" PRId64 "", wakeups);
}
TEST_F(TimerTest, CancelSomeTimers) {
MAYBE_SKIP_TEST;
grpc_core::ExecCtx exec_ctx;
const int kNumTimers = 10;
grpc_timer timers[kNumTimers];
int timer_fired = 0;
for (int i = 0; i < kNumTimers; ++i) {
grpc_timer_init(&timers[i], 500 + i,
GRPC_CLOSURE_CREATE(
[](void* arg, grpc_error* error) {
if (error == GRPC_ERROR_CANCELLED) {
return;
}
int* timer_fired = static_cast<int*>(arg);
++*timer_fired;
},
&timer_fired, grpc_schedule_on_exec_ctx));
}
for (int i = 0; i < kNumTimers / 2; ++i) {
grpc_timer_cancel(&timers[i]);
}
gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(1500));
GPR_ASSERT(kNumTimers / 2 == timer_fired);
// We expect to get 1 wakeup/second + 1 wakeup per timer fired + maybe 1
// wakeup during initialization. i.e. in 1.5 seconds we expect 6 or 7 wakeups.
// Actual number of wakeups is more due to bug
// https://github.com/grpc/grpc/issues/19947
int64_t wakeups = grpc_timer_manager_get_wakeups_testonly();
gpr_log(GPR_DEBUG, "wakeups: %" PRId64 "", wakeups);
}
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -5970,6 +5970,30 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "timer_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save