@@ -474,7 +474,7 @@ static void ELDHistogramNew(const FunctionCallbackInfo<Value>& args) {
474474  Environment* env = Environment::GetCurrent (args);
475475  CHECK (args.IsConstructCall ());
476476  int32_t  resolution = args[0 ]->IntegerValue (env->context ()).FromJust ();
477-   CHECK_GT (resolution, 0 );
477+   CHECK_GE (resolution, 0 );
478478  new  ELDHistogram (env, args.This (), resolution);
479479}
480480}  //  namespace
@@ -489,31 +489,59 @@ ELDHistogram::ELDHistogram(
489489                          Histogram (1 , 3.6e12 ),
490490                          resolution_(resolution) {
491491  MakeWeak ();
492-   uv_timer_init (env->event_loop (), &timer_);
492+   CHECK_EQ (uv_timer_init (env->event_loop (), &timer_), 0 );
493+ 
494+   if  (is_precise ()) {
495+     CHECK_EQ (uv_prepare_init (env->event_loop (), &prepare_), 0 );
496+     CHECK_EQ (uv_check_init (env->event_loop (), &check_), 0 );
497+   }
498+ }
499+ 
500+ void  ELDHistogram::Close (Local<Value> close_callback) {
501+   //  HandleWrap::Close will call `uv_close()` on `timer_` and
502+   //  deallocate `ELDHistogram` in `HandleWrap::OnClose`.
503+   //  Therefore, it is safe to call `uv_close` with `nullptr` here since
504+   //  both `prepare_` and `check_`.
505+   if  (is_precise () && !IsHandleClosing ()) {
506+     uv_close (reinterpret_cast <uv_handle_t *>(&prepare_), nullptr );
507+     uv_close (reinterpret_cast <uv_handle_t *>(&check_), nullptr );
508+   }
509+ 
510+   HandleWrap::Close (close_callback);
511+ }
512+ 
513+ void  ELDHistogram::TraceHistogram () {
514+   TRACE_COUNTER1 (TRACING_CATEGORY_NODE2 (perf, event_loop), " min" Min ());
515+   TRACE_COUNTER1 (TRACING_CATEGORY_NODE2 (perf, event_loop), " max" Max ());
516+   TRACE_COUNTER1 (TRACING_CATEGORY_NODE2 (perf, event_loop), " mean" Mean ());
517+   TRACE_COUNTER1 (TRACING_CATEGORY_NODE2 (perf, event_loop), " stddev" Stddev ());
493518}
494519
495520void  ELDHistogram::DelayIntervalCallback (uv_timer_t * req) {
496521  ELDHistogram* histogram = ContainerOf (&ELDHistogram::timer_, req);
497-   histogram->RecordDelta ();
498-   TRACE_COUNTER1 (TRACING_CATEGORY_NODE2 (perf, event_loop),
499-                  " min" Min ());
500-   TRACE_COUNTER1 (TRACING_CATEGORY_NODE2 (perf, event_loop),
501-                  " max" Max ());
502-   TRACE_COUNTER1 (TRACING_CATEGORY_NODE2 (perf, event_loop),
503-                  " mean" Mean ());
504-   TRACE_COUNTER1 (TRACING_CATEGORY_NODE2 (perf, event_loop),
505-                  " stddev" Stddev ());
522+   histogram->RecordCoarseDelta ();
523+   histogram->TraceHistogram ();
524+ }
525+ 
526+ void  ELDHistogram::CheckCallback (uv_check_t * handle) {
527+   ELDHistogram* histogram = ContainerOf (&ELDHistogram::check_, handle);
528+   histogram->RecordPreciseDelayStart ();
506529}
507530
508- bool  ELDHistogram::RecordDelta () {
531+ void  ELDHistogram::PrepareCallback (uv_prepare_t * handle) {
532+   ELDHistogram* histogram = ContainerOf (&ELDHistogram::prepare_, handle);
533+   histogram->RecordPreciseDelayStop ();
534+   histogram->TraceHistogram ();
535+ }
536+ 
537+ void  ELDHistogram::RecordCoarseDelta () {
509538  uint64_t  time = uv_hrtime ();
510-   bool  ret = true ;
511539  if  (prev_ > 0 ) {
512540    int64_t  delta = time - prev_;
513541    if  (delta > 0 ) {
514-       ret = Record (delta);
542+       bool   ret = Record (delta);
515543      TRACE_COUNTER1 (TRACING_CATEGORY_NODE2 (perf, event_loop),
516-                       " delay" 
544+           " delay" 
517545      if  (!ret) {
518546        if  (exceeds_ < 0xFFFFFFFF )
519547          exceeds_++;
@@ -525,25 +553,76 @@ bool ELDHistogram::RecordDelta() {
525553    }
526554  }
527555  prev_ = time;
528-   return  ret;
556+ }
557+ 
558+ void  ELDHistogram::RecordPreciseDelayStart () {
559+   prev_ = uv_hrtime ();
560+ }
561+ 
562+ void  ELDHistogram::RecordPreciseDelayStop () {
563+   if  (prev_ == 0 ) {
564+     return ;
565+   }
566+ 
567+   uint64_t  time = uv_hrtime ();
568+   int64_t  delta = time - prev_;
569+   if  (delta <= 0 ) {
570+     return ;
571+   }
572+   bool  ret = Record (delta);
573+   TRACE_COUNTER1 (TRACING_CATEGORY_NODE2 (perf, event_loop),
574+                  " delay" 
575+   if  (ret) {
576+     return ;
577+   }
578+   if  (exceeds_ < 0xFFFFFFFF ) {
579+     exceeds_++;
580+   }
581+   ProcessEmitWarning (
582+       env (),
583+       " Event loop delay exceeded 1 hour: %" "  nanoseconds" 
584+       delta);
529585}
530586
531587bool  ELDHistogram::Enable () {
532588  if  (enabled_ || IsHandleClosing ()) return  false ;
533589  enabled_ = true ;
534590  prev_ = 0 ;
535-   uv_timer_start (&timer_,
536-                  DelayIntervalCallback,
537-                  resolution_,
538-                  resolution_);
539-   uv_unref (reinterpret_cast <uv_handle_t *>(&timer_));
591+ 
592+   if  (is_precise ()) {
593+     //  `uv_prepare_start`/`uv_check_start` prepend the handles to the queue.
594+     //  Newly started handles will have their callbacks invoked **before** the
595+     //  old handles' callbacks.
596+     // 
597+     //  This is important because of `immediate_check_handle` in `src/env.cc`.
598+     //  `immediate_check_handle` is used for invoking user callbacks queued with
599+     //  `setImmediate()` API call. `ELDHistogram` has to record the delay
600+     //  induced by `setImmediate()` callbacks too so the order of handles is
601+     //  important.
602+     CHECK_EQ (uv_prepare_start (&prepare_, PrepareCallback), 0 );
603+     CHECK_EQ (uv_check_start (&check_, CheckCallback), 0 );
604+     uv_unref (reinterpret_cast <uv_handle_t *>(&prepare_));
605+     uv_unref (reinterpret_cast <uv_handle_t *>(&check_));
606+   } else  {
607+     CHECK_EQ (uv_timer_start (&timer_,
608+                             DelayIntervalCallback,
609+                             resolution_,
610+                             resolution_),
611+         0 );
612+     uv_unref (reinterpret_cast <uv_handle_t *>(&timer_));
613+   }
540614  return  true ;
541615}
542616
543617bool  ELDHistogram::Disable () {
544618  if  (!enabled_ || IsHandleClosing ()) return  false ;
545619  enabled_ = false ;
546-   uv_timer_stop (&timer_);
620+   if  (is_precise ()) {
621+     CHECK_EQ (uv_prepare_stop (&prepare_), 0 );
622+     CHECK_EQ (uv_check_stop (&check_), 0 );
623+   } else  {
624+     CHECK_EQ (uv_timer_stop (&timer_), 0 );
625+   }
547626  return  true ;
548627}
549628
0 commit comments