@@ -102,6 +102,26 @@ typedef struct QUIC_CACHEALIGN CXPLAT_WORKER {
102102 //
103103 BOOLEAN Running ;
104104
105+ //
106+ // Statistics tracking for active time measurement.
107+ //
108+ struct {
109+ //
110+ // Timestamp (in microseconds) when the worker thread started.
111+ //
112+ uint64_t StartedTimeUs ;
113+
114+ //
115+ // Timestamp (in microseconds) when the current active period started.
116+ //
117+ uint64_t ActiveStartTimeUs ;
118+
119+ //
120+ // Cumulative time (in microseconds) the worker was active (not waiting or yielding).
121+ //
122+ uint64_t CumulativeActiveTimeUs ;
123+ } Stats ;
124+
105125} CXPLAT_WORKER ;
106126
107127typedef struct CXPLAT_WORKER_POOL {
@@ -734,12 +754,23 @@ CxPlatProcessEvents(
734754 )
735755{
736756 CXPLAT_CQE Cqes [16 ];
757+
758+ if (Worker -> State .WaitTime > 0 ) {
759+ Worker -> Stats .CumulativeActiveTimeUs +=
760+ CxPlatTimeDiff64 (Worker -> Stats .ActiveStartTimeUs , CxPlatTimeUs64 ());
761+ }
762+
737763 uint32_t CqeCount =
738764 CxPlatEventQDequeue (
739765 & Worker -> EventQ ,
740766 Cqes ,
741767 ARRAYSIZE (Cqes ),
742768 Worker -> State .WaitTime );
769+
770+ if (Worker -> State .WaitTime > 0 ) {
771+ Worker -> Stats .ActiveStartTimeUs = CxPlatTimeUs64 ();
772+ }
773+
743774 uint32_t CurrentCqeCount = CqeCount ;
744775 CXPLAT_CQE * CurrentCqe = Cqes ;
745776
@@ -796,6 +827,8 @@ CXPLAT_THREAD_CALLBACK(CxPlatWorkerThread, Context)
796827
797828 Worker -> State .ThreadID = CxPlatCurThreadID ();
798829 Worker -> Running = TRUE;
830+ Worker -> Stats .StartedTimeUs = CxPlatTimeUs64 ();
831+ Worker -> Stats .ActiveStartTimeUs = Worker -> Stats .StartedTimeUs ;
799832
800833 while (!Worker -> StoppedThread ) {
801834
@@ -816,7 +849,10 @@ CXPLAT_THREAD_CALLBACK(CxPlatWorkerThread, Context)
816849 if (Worker -> State .NoWorkCount == 0 ) {
817850 Worker -> State .LastWorkTime = Worker -> State .TimeNow ;
818851 } else if (Worker -> State .NoWorkCount > CXPLAT_WORKER_IDLE_WORK_THRESHOLD_COUNT ) {
852+ Worker -> Stats .CumulativeActiveTimeUs +=
853+ CxPlatTimeDiff64 (Worker -> Stats .ActiveStartTimeUs , CxPlatTimeUs64 ());
819854 CxPlatSchedulerYield ();
855+ Worker -> Stats .ActiveStartTimeUs = CxPlatTimeUs64 ();
820856 Worker -> State .NoWorkCount = 0 ;
821857 }
822858
@@ -826,6 +862,8 @@ CXPLAT_THREAD_CALLBACK(CxPlatWorkerThread, Context)
826862 }
827863 }
828864
865+ Worker -> Stats .CumulativeActiveTimeUs +=
866+ CxPlatTimeDiff64 (Worker -> Stats .ActiveStartTimeUs , CxPlatTimeUs64 ());
829867 Worker -> Running = FALSE;
830868
831869#if DEBUG
@@ -839,3 +877,25 @@ CXPLAT_THREAD_CALLBACK(CxPlatWorkerThread, Context)
839877
840878 CXPLAT_THREAD_RETURN (0 );
841879}
880+
881+ void
882+ CxPlatWorkerPoolGetStatistics (
883+ _In_ CXPLAT_WORKER_POOL * WorkerPool ,
884+ _In_ uint32_t Index ,
885+ _Out_ CXPLAT_WORKER_STATISTICS * Stats
886+ )
887+ {
888+ CXPLAT_DBG_ASSERT (Index < WorkerPool -> WorkerCount );
889+
890+ const uint64_t Now = CxPlatTimeUs64 ();
891+ const CXPLAT_WORKER * Worker = & WorkerPool -> Workers [Index ];
892+
893+ Stats -> IdealProcessor = Worker -> IdealProcessor ;
894+ Stats -> CumulativeWallTimeUs = CxPlatTimeDiff64 (Worker -> Stats .StartedTimeUs , Now );
895+ Stats -> CumulativeActiveTimeUs = Worker -> Stats .CumulativeActiveTimeUs ;
896+
897+ const uint64_t ActiveStartTime = Worker -> Stats .ActiveStartTimeUs ;
898+ if (ActiveStartTime < Now ) {
899+ Stats -> CumulativeActiveTimeUs += CxPlatTimeDiff64 (ActiveStartTime , Now );
900+ }
901+ }
0 commit comments