@ -14,6 +14,7 @@
# include "test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h"
# include "test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h"
# include <inttypes.h>
# include <stdlib.h>
# include <stdlib.h>
# include <algorithm>
# include <algorithm>
@ -30,6 +31,7 @@
# include <grpc/support/log.h>
# include <grpc/support/log.h>
# include <grpc/support/time.h>
# include <grpc/support/time.h>
# include "src/core/lib/debug/trace.h"
# include "src/core/lib/event_engine/tcp_socket_utils.h"
# include "src/core/lib/event_engine/tcp_socket_utils.h"
# include "src/core/lib/gpr/useful.h"
# include "src/core/lib/gpr/useful.h"
# include "src/core/lib/gprpp/time.h"
# include "src/core/lib/gprpp/time.h"
@ -40,6 +42,9 @@
extern gpr_timespec ( * gpr_now_impl ) ( gpr_clock_type clock_type ) ;
extern gpr_timespec ( * gpr_now_impl ) ( gpr_clock_type clock_type ) ;
static grpc_core : : TraceFlag trace_writes ( false , " fuzzing_ee_writes " ) ;
static grpc_core : : TraceFlag trace_timers ( false , " fuzzing_ee_timers " ) ;
using namespace std : : chrono_literals ;
using namespace std : : chrono_literals ;
namespace grpc_event_engine {
namespace grpc_event_engine {
@ -133,40 +138,47 @@ gpr_timespec FuzzingEventEngine::NowAsTimespec(gpr_clock_type clock_type) {
}
}
void FuzzingEventEngine : : Tick ( Duration max_time ) {
void FuzzingEventEngine : : Tick ( Duration max_time ) {
std : : vector < absl : : AnyInvocable < void ( ) > > to_run ;
bool incremented_time = false ;
{
while ( true ) {
grpc_core : : MutexLock lock ( & * mu_ ) ;
std : : vector < absl : : AnyInvocable < void ( ) > > to_run ;
grpc_core : : MutexLock now_lock ( & * now_mu_ ) ;
{
Duration incr = max_time ;
grpc_core : : MutexLock lock ( & * mu_ ) ;
// TODO(ctiller): look at tasks_by_time_ and jump forward (once iomgr
grpc_core : : MutexLock now_lock ( & * now_mu_ ) ;
// timers are gone)
if ( ! incremented_time ) {
if ( ! tasks_by_time_ . empty ( ) ) {
Duration incr = max_time ;
incr = std : : min ( incr , tasks_by_time_ . begin ( ) - > first - now_ ) ;
// TODO(ctiller): look at tasks_by_time_ and jump forward (once iomgr
}
// timers are gone)
if ( incr < exponential_gate_time_increment_ ) {
if ( ! tasks_by_time_ . empty ( ) ) {
exponential_gate_time_increment_ = std : : chrono : : milliseconds ( 1 ) ;
incr = std : : min ( incr , tasks_by_time_ . begin ( ) - > first - now_ ) ;
} else {
}
incr = std : : min ( incr , exponential_gate_time_increment_ ) ;
if ( incr < exponential_gate_time_increment_ ) {
exponential_gate_time_increment_ + =
exponential_gate_time_increment_ = std : : chrono : : milliseconds ( 1 ) ;
exponential_gate_time_increment_ / 1000 ;
} else {
}
incr = std : : min ( incr , exponential_gate_time_increment_ ) ;
incr = std : : max ( incr , std : : chrono : : duration_cast < Duration > (
exponential_gate_time_increment_ + =
std : : chrono : : milliseconds ( 1 ) ) ) ;
exponential_gate_time_increment_ / 1000 ;
now_ + = incr ;
}
GPR_ASSERT ( now_ . time_since_epoch ( ) . count ( ) > = 0 ) ;
incr = std : : max ( incr , std : : chrono : : duration_cast < Duration > (
+ + current_tick_ ;
std : : chrono : : milliseconds ( 1 ) ) ) ;
// Find newly expired timers.
now_ + = incr ;
while ( ! tasks_by_time_ . empty ( ) & & tasks_by_time_ . begin ( ) - > first < = now_ ) {
GPR_ASSERT ( now_ . time_since_epoch ( ) . count ( ) > = 0 ) ;
auto & task = * tasks_by_time_ . begin ( ) - > second ;
+ + current_tick_ ;
tasks_by_id_ . erase ( task . id ) ;
incremented_time = true ;
if ( task . closure ! = nullptr ) {
}
to_run . push_back ( std : : move ( task . closure ) ) ;
// Find newly expired timers.
while ( ! tasks_by_time_ . empty ( ) & & tasks_by_time_ . begin ( ) - > first < = now_ ) {
auto & task = * tasks_by_time_ . begin ( ) - > second ;
tasks_by_id_ . erase ( task . id ) ;
if ( task . closure ! = nullptr ) {
to_run . push_back ( std : : move ( task . closure ) ) ;
}
tasks_by_time_ . erase ( tasks_by_time_ . begin ( ) ) ;
}
}
tasks_by_time_ . erase ( tasks_by_time_ . begin ( ) ) ;
}
}
}
if ( to_run . empty ( ) ) return ;
for ( auto & closure : to_run ) {
for ( auto & closure : to_run ) {
closure ( ) ;
closure ( ) ;
}
}
}
}
}
@ -299,6 +311,10 @@ bool FuzzingEventEngine::EndpointMiddle::Write(SliceBuffer* data, int index) {
// If the write_len is zero, we still need to write something, so we write one
// If the write_len is zero, we still need to write something, so we write one
// byte.
// byte.
if ( write_len = = 0 ) write_len = 1 ;
if ( write_len = = 0 ) write_len = 1 ;
if ( trace_writes . enabled ( ) ) {
gpr_log ( GPR_INFO , " WRITE[%p:%d]: % " PRIdPTR " bytes " , this , index ,
write_len ) ;
}
// Expand the pending buffer.
// Expand the pending buffer.
size_t prev_len = pending [ index ] . size ( ) ;
size_t prev_len = pending [ index ] . size ( ) ;
pending [ index ] . resize ( prev_len + write_len ) ;
pending [ index ] . resize ( prev_len + write_len ) ;
@ -526,15 +542,31 @@ EventEngine::TaskHandle FuzzingEventEngine::RunAfterLocked(
RunType run_type , Duration when , absl : : AnyInvocable < void ( ) > closure ) {
RunType run_type , Duration when , absl : : AnyInvocable < void ( ) > closure ) {
const intptr_t id = next_task_id_ ;
const intptr_t id = next_task_id_ ;
+ + next_task_id_ ;
+ + next_task_id_ ;
Duration delay_taken = Duration : : zero ( ) ;
if ( run_type ! = RunType : : kExact & & ! task_delays_ . empty ( ) ) {
if ( run_type ! = RunType : : kExact & & ! task_delays_ . empty ( ) ) {
when + = grpc_core : : Clamp ( task_delays_ . front ( ) , Duration : : zero ( ) ,
delay_taken = grpc_core : : Clamp ( task_delays_ . front ( ) , Duration : : zero ( ) ,
max_delay_ [ static_cast < int > ( run_type ) ] ) ;
max_delay_ [ static_cast < int > ( run_type ) ] ) ;
when + = delay_taken ;
task_delays_ . pop ( ) ;
task_delays_ . pop ( ) ;
}
}
auto task = std : : make_shared < Task > ( id , std : : move ( closure ) ) ;
auto task = std : : make_shared < Task > ( id , std : : move ( closure ) ) ;
tasks_by_id_ . emplace ( id , task ) ;
tasks_by_id_ . emplace ( id , task ) ;
grpc_core : : MutexLock lock ( & * now_mu_ ) ;
Time final_time ;
tasks_by_time_ . emplace ( now_ + when , std : : move ( task ) ) ;
Time now ;
{
grpc_core : : MutexLock lock ( & * now_mu_ ) ;
final_time = now_ + when ;
now = now_ ;
tasks_by_time_ . emplace ( final_time , std : : move ( task ) ) ;
}
if ( trace_timers . enabled ( ) ) {
gpr_log ( GPR_INFO ,
" Schedule timer % " PRIx64 " @ % " PRIu64 " (now=% " PRIu64
" ; delay=% " PRIu64 " ; fuzzing_added=% " PRIu64 " ; type=%d) " ,
id , static_cast < uint64_t > ( final_time . time_since_epoch ( ) . count ( ) ) ,
now . time_since_epoch ( ) . count ( ) , when . count ( ) , delay_taken . count ( ) ,
static_cast < int > ( run_type ) ) ;
}
return TaskHandle { id , kTaskHandleSalt } ;
return TaskHandle { id , kTaskHandleSalt } ;
}
}
@ -549,6 +581,9 @@ bool FuzzingEventEngine::Cancel(TaskHandle handle) {
if ( it - > second - > closure = = nullptr ) {
if ( it - > second - > closure = = nullptr ) {
return false ;
return false ;
}
}
if ( trace_timers . enabled ( ) ) {
gpr_log ( GPR_INFO , " Cancel timer % " PRIx64 , id ) ;
}
it - > second - > closure = nullptr ;
it - > second - > closure = nullptr ;
return true ;
return true ;
}
}