Skip to content

Commit 0a85e0d

Browse files
author
Mike Kaufman
committed
Adding CPU times to timing counters where UI thread is blocked by GC
1 parent b691e7a commit 0a85e0d

File tree

3 files changed

+91
-4
lines changed

3 files changed

+91
-4
lines changed

lib/Common/Memory/Recycler.cpp

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5712,6 +5712,22 @@ Recycler::FinishConcurrentCollectWrapped(CollectionFlags flags)
57125712
return collected;
57135713
}
57145714

5715+
5716+
/**
5717+
* Compute ft1 - ft2, return result as a uint64
5718+
*/
5719+
uint64 DiffFileTimes(LPFILETIME ft1, LPFILETIME ft2)
5720+
{
5721+
ULARGE_INTEGER ul1;
5722+
ULARGE_INTEGER ul2;
5723+
ul1.HighPart = ft1->dwHighDateTime;
5724+
ul1.LowPart = ft1->dwLowDateTime;
5725+
ul2.HighPart = ft2->dwHighDateTime;
5726+
ul2.LowPart = ft2->dwLowDateTime;
5727+
ULONGLONG result = ul1.QuadPart - ul2.QuadPart;
5728+
return result;
5729+
}
5730+
57155731
BOOL
57165732
Recycler::WaitForConcurrentThread(DWORD waitTime, RecyclerWaitReason caller)
57175733
{
@@ -5726,8 +5742,22 @@ Recycler::WaitForConcurrentThread(DWORD waitTime, RecyclerWaitReason caller)
57265742
}
57275743

57285744
#ifdef ENABLE_BASIC_TELEMETRY
5729-
bool isBlockingMainThread = this->telemetryStats.IsOnScriptThread();
5730-
Js::Tick start = Js::Tick::Now();
5745+
bool isBlockingMainThread = false;
5746+
Js::Tick start;
5747+
FILETIME kernelTime1;
5748+
FILETIME userTime1;
5749+
HANDLE hProcess = GetCurrentProcess();
5750+
if (this->telemetryStats.ShouldStartTelemetryCapture())
5751+
{
5752+
isBlockingMainThread = this->telemetryStats.IsOnScriptThread();
5753+
if (isBlockingMainThread)
5754+
{
5755+
start = Js::Tick::Now();
5756+
FILETIME creationTime;
5757+
FILETIME exitTime;
5758+
GetProcessTimes(hProcess, &creationTime, &exitTime, &kernelTime1, &userTime1);
5759+
}
5760+
}
57315761
#endif
57325762

57335763
DWORD ret = WaitForSingleObject(concurrentWorkDoneEvent, waitTime);
@@ -5737,7 +5767,24 @@ Recycler::WaitForConcurrentThread(DWORD waitTime, RecyclerWaitReason caller)
57375767
{
57385768
Js::Tick end = Js::Tick::Now();
57395769
Js::TickDelta elapsed = end - start;
5770+
5771+
FILETIME creationTime;
5772+
FILETIME exitTime;
5773+
FILETIME kernelTime2;
5774+
FILETIME userTime2;
5775+
5776+
GetProcessTimes(hProcess, &creationTime, &exitTime, &kernelTime2, &userTime2);
5777+
uint64 kernelTime = DiffFileTimes(&kernelTime2 , &kernelTime1);
5778+
uint64 userTime = DiffFileTimes(&userTime2, &userTime1);
5779+
5780+
// userTime & kernelTime reported from GetProcessTimes is the number of 100-nanosecond ticks
5781+
// for consistency convert to microseconds.
5782+
kernelTime = kernelTime / 10;
5783+
userTime = userTime / 10;
5784+
57405785
this->telemetryStats.IncrementUserThreadBlockedCount(elapsed.ToMicroseconds(), caller);
5786+
this->telemetryStats.IncrementUserThreadBlockedCpuTimeUser(userTime, caller);
5787+
this->telemetryStats.IncrementUserThreadBlockedCpuTimeKernel(kernelTime, caller);
57415788
}
57425789
#endif
57435790

lib/Common/Memory/RecyclerTelemetryInfo.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,41 @@ namespace Memory
252252
}
253253
}
254254

255+
256+
void RecyclerTelemetryInfo::IncrementUserThreadBlockedCpuTimeUser(uint64 userMicroseconds, RecyclerWaitReason caller)
257+
{
258+
RecyclerTelemetryGCPassStats* lastPassStats = this->GetLastPassStats();
259+
#ifdef DBG
260+
if (this->inPassActiveState)
261+
{
262+
AssertMsg(lastPassStats != nullptr && lastPassStats->isGCPassActive == true, "unexpected Value in RecyclerTelemetryInfo::IncrementUserThreadBlockedCpuTimeUser");
263+
}
264+
#endif
265+
266+
if (this->inPassActiveState && lastPassStats != nullptr)
267+
{
268+
AssertOnValidThread(this, RecyclerTelemetryInfo::IncrementUserThreadBlockedCpuTimeUser);
269+
lastPassStats->uiThreadBlockedCpuTimesUser[caller] += userMicroseconds;
270+
}
271+
}
272+
273+
void RecyclerTelemetryInfo::IncrementUserThreadBlockedCpuTimeKernel(uint64 kernelMicroseconds, RecyclerWaitReason caller)
274+
{
275+
RecyclerTelemetryGCPassStats* lastPassStats = this->GetLastPassStats();
276+
#ifdef DBG
277+
if (this->inPassActiveState)
278+
{
279+
AssertMsg(lastPassStats != nullptr && lastPassStats->isGCPassActive == true, "unexpected Value in RecyclerTelemetryInfo::IncrementUserThreadBlockedCpuTimeKernel");
280+
}
281+
#endif
282+
283+
if (this->inPassActiveState && lastPassStats != nullptr)
284+
{
285+
AssertOnValidThread(this, RecyclerTelemetryInfo::IncrementUserThreadBlockedCpuTimeKernel);
286+
lastPassStats->uiThreadBlockedCpuTimesKernel[caller] += kernelMicroseconds;
287+
}
288+
}
289+
255290
bool RecyclerTelemetryInfo::IsOnScriptThread() const
256291
{
257292
bool isValid = false;

lib/Common/Memory/RecyclerTelemetryInfo.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ namespace Memory
5959
Js::TickDelta computeBucketStatsElapsedTime;
6060
FILETIME lastScriptExecutionEndTime;
6161
Js::TickDelta uiThreadBlockedTimes[static_cast<size_t>(RecyclerWaitReason::Other) + 1];
62+
uint64 uiThreadBlockedCpuTimesUser[static_cast<size_t>(RecyclerWaitReason::Other) + 1];
63+
uint64 uiThreadBlockedCpuTimesKernel[static_cast<size_t>(RecyclerWaitReason::Other) + 1];
6264
bool isInScript;
6365
bool isScriptActive;
6466
bool isGCPassActive;
@@ -99,7 +101,9 @@ namespace Memory
99101
void StartPass(CollectionState collectionState);
100102
void EndPass(CollectionState collectionState);
101103
void IncrementUserThreadBlockedCount(Js::TickDelta waitTime, RecyclerWaitReason source);
102-
104+
void IncrementUserThreadBlockedCpuTimeUser(uint64 userMicroseconds, RecyclerWaitReason caller);
105+
void IncrementUserThreadBlockedCpuTimeKernel(uint64 kernelMicroseconds, RecyclerWaitReason caller);
106+
103107
inline const Js::Tick& GetRecyclerStartTime() const { return this->recyclerStartTime; }
104108
RecyclerTelemetryGCPassStats* GetLastPassStats() const;
105109
inline const Js::Tick& GetLastTransmitTime() const { return this->lastTransmitTime; }
@@ -116,6 +120,8 @@ namespace Memory
116120
AllocatorDecommitStats* GetRecyclerWithBarrierPageAllocator_decommitStats() { return &this->recyclerWithBarrierPageAllocator_decommitStats; }
117121
#endif
118122

123+
bool ShouldStartTelemetryCapture() const;
124+
119125
private:
120126
Recycler* recycler;
121127
DWORD mainThreadID;
@@ -135,7 +141,6 @@ namespace Memory
135141
AllocatorDecommitStats recyclerWithBarrierPageAllocator_decommitStats;
136142
#endif
137143

138-
bool ShouldStartTelemetryCapture() const;
139144
bool ShouldTransmit() const;
140145
void FreeGCPassStats();
141146
void Reset();

0 commit comments

Comments
 (0)