9
9
#ifdef ENABLE_BASIC_TELEMETRY
10
10
11
11
#include " Recycler.h"
12
+ #include " DataStructures/SList.h"
12
13
#include " HeapBucketStats.h"
13
14
#include " BucketStatsReporter.h"
14
15
#include < psapi.h>
@@ -24,7 +25,7 @@ namespace Memory
24
25
RecyclerTelemetryInfo::RecyclerTelemetryInfo (Recycler * recycler, RecyclerTelemetryHostInterface* hostInterface) :
25
26
passCount (0 ),
26
27
hostInterface (hostInterface),
27
- lastPassStats ( nullptr ),
28
+ gcPassStats (&HeapAllocator::Instance ),
28
29
recyclerStartTime (Js::Tick::Now()),
29
30
abortTelemetryCapture (false ),
30
31
inPassActiveState (false ),
@@ -35,11 +36,14 @@ namespace Memory
35
36
36
37
RecyclerTelemetryInfo::~RecyclerTelemetryInfo ()
37
38
{
38
- if (this ->hostInterface != nullptr && this -> passCount > 0 )
39
+ if (this ->hostInterface != nullptr )
39
40
{
40
41
AssertOnValidThread (this , RecyclerTelemetryInfo::~RecyclerTelemetryInfo);
41
- this ->hostInterface ->TransmitTelemetry (*this );
42
- this ->FreeGCPassStats ();
42
+ if (this ->gcPassStats .Empty () == false )
43
+ {
44
+ this ->hostInterface ->TransmitTelemetry (*this );
45
+ this ->FreeGCPassStats ();
46
+ }
43
47
}
44
48
}
45
49
@@ -70,32 +74,49 @@ namespace Memory
70
74
sizes->numberOfSegments = allocator->GetNumberOfSegments ();
71
75
}
72
76
77
+ GCPassStatsList::Iterator RecyclerTelemetryInfo::GetGCPassStatsIterator () const
78
+ {
79
+ return this ->gcPassStats .GetIterator ();
80
+ }
81
+
82
+ RecyclerTelemetryGCPassStats* RecyclerTelemetryInfo::GetLastPassStats () const
83
+ {
84
+ RecyclerTelemetryGCPassStats* stats = nullptr ;
85
+ if (this ->gcPassStats .Empty () == false )
86
+ {
87
+ RecyclerTelemetryGCPassStats& ref = const_cast <RecyclerTelemetryGCPassStats&>(this ->gcPassStats .Head ());
88
+ stats = &ref;
89
+ }
90
+ return stats;
91
+ }
92
+
73
93
void RecyclerTelemetryInfo::StartPass ()
74
94
{
75
95
this ->inPassActiveState = false ;
76
96
if (this ->ShouldStartTelemetryCapture ())
77
97
{
78
98
Js::Tick start = Js::Tick::Now ();
79
99
AssertOnValidThread (this , RecyclerTelemetryInfo::StartPass);
100
+
80
101
#if DBG
81
102
// validate state of existing GC pass stats structs
82
103
uint16 count = 0 ;
83
- if (this ->lastPassStats != nullptr )
104
+ if (this ->gcPassStats . Empty () == false )
84
105
{
85
- RecyclerTelemetryGCPassStats* head = this ->lastPassStats ->next ;
86
- RecyclerTelemetryGCPassStats* curr = head;
87
- do
106
+ GCPassStatsList::Iterator it = this ->GetGCPassStatsIterator ();
107
+ while (it.Next ())
88
108
{
89
- AssertMsg ( curr-> isGCPassActive == false , " unexpected value for isGCPassActive " );
90
- count++ ;
91
- curr = curr-> next ;
92
- } while (curr != head);
109
+ RecyclerTelemetryGCPassStats& curr = it. Data ( );
110
+ AssertMsg (curr. isGCPassActive == false , " unexpected value for isGCPassActive " ) ;
111
+ ++count ;
112
+ }
93
113
}
94
114
AssertMsg (count == this ->passCount , " RecyclerTelemetryInfo::StartPass() - mismatch between passCount and count." );
95
115
#endif
96
116
97
- RecyclerTelemetryGCPassStats* p = HeapNewNoThrow (RecyclerTelemetryGCPassStats);
98
- if (p == nullptr )
117
+
118
+ RecyclerTelemetryGCPassStats* stats = this ->gcPassStats .PrependNodeNoThrow (&HeapAllocator::Instance);
119
+ if (stats == nullptr )
99
120
{
100
121
// failed to allocate memory - disable any further telemetry capture for this recycler
101
122
// and free any existing GC stats we've accumulated
@@ -107,41 +128,30 @@ namespace Memory
107
128
{
108
129
this ->inPassActiveState = true ;
109
130
passCount++;
110
- memset (p, 0 , sizeof (RecyclerTelemetryGCPassStats));
111
- if (this ->lastPassStats == nullptr )
112
- {
113
- p->next = p;
114
- }
115
- else
116
- {
117
- p->next = lastPassStats->next ;
118
- this ->lastPassStats ->next = p;
119
- }
120
- this ->lastPassStats = p;
131
+ memset (stats, 0 , sizeof (RecyclerTelemetryGCPassStats));
121
132
122
- this -> lastPassStats ->isGCPassActive = true ;
123
- this -> lastPassStats ->passStartTimeTick = Js::Tick::Now ();
124
- GetSystemTimePreciseAsFileTime (&this -> lastPassStats ->passStartTimeFileTime );
133
+ stats ->isGCPassActive = true ;
134
+ stats ->passStartTimeTick = Js::Tick::Now ();
135
+ GetSystemTimePreciseAsFileTime (&stats ->passStartTimeFileTime );
125
136
if (this ->hostInterface != nullptr )
126
137
{
127
138
LPFILETIME ft = this ->hostInterface ->GetLastScriptExecutionEndTime ();
128
- this -> lastPassStats ->lastScriptExecutionEndTime = *ft;
139
+ stats ->lastScriptExecutionEndTime = *ft;
129
140
}
130
141
131
- this -> lastPassStats ->processCommittedBytes_start = RecyclerTelemetryInfo::GetProcessCommittedBytes ();
132
- this -> lastPassStats ->processAllocaterUsedBytes_start = PageAllocator::GetProcessUsedBytes ();
133
- this -> lastPassStats ->isInScript = this ->recycler ->GetIsInScript ();
134
- this -> lastPassStats ->isScriptActive = this ->recycler ->GetIsScriptActive ();
142
+ stats ->processCommittedBytes_start = RecyclerTelemetryInfo::GetProcessCommittedBytes ();
143
+ stats ->processAllocaterUsedBytes_start = PageAllocator::GetProcessUsedBytes ();
144
+ stats ->isInScript = this ->recycler ->GetIsInScript ();
145
+ stats ->isScriptActive = this ->recycler ->GetIsScriptActive ();
135
146
136
- this ->FillInSizeData (this ->recycler ->GetHeapInfo ()->GetRecyclerLeafPageAllocator (), &this -> lastPassStats ->threadPageAllocator_start );
137
- this ->FillInSizeData (this ->recycler ->GetHeapInfo ()->GetRecyclerPageAllocator (), &this -> lastPassStats ->recyclerLeafPageAllocator_start );
138
- this ->FillInSizeData (this ->recycler ->GetHeapInfo ()->GetRecyclerLargeBlockPageAllocator (), &this -> lastPassStats ->recyclerLargeBlockPageAllocator_start );
147
+ this ->FillInSizeData (this ->recycler ->GetHeapInfo ()->GetRecyclerLeafPageAllocator (), &stats ->threadPageAllocator_start );
148
+ this ->FillInSizeData (this ->recycler ->GetHeapInfo ()->GetRecyclerPageAllocator (), &stats ->recyclerLeafPageAllocator_start );
149
+ this ->FillInSizeData (this ->recycler ->GetHeapInfo ()->GetRecyclerLargeBlockPageAllocator (), &stats ->recyclerLargeBlockPageAllocator_start );
139
150
#ifdef RECYCLER_WRITE_BARRIER_ALLOC_SEPARATE_PAGE
140
- this ->FillInSizeData (this ->recycler ->GetHeapInfo ()->GetRecyclerWithBarrierPageAllocator (), &this -> lastPassStats ->recyclerWithBarrierPageAllocator_start );
151
+ this ->FillInSizeData (this ->recycler ->GetHeapInfo ()->GetRecyclerWithBarrierPageAllocator (), &stats ->recyclerWithBarrierPageAllocator_start );
141
152
#endif
142
- this -> lastPassStats ->startPassProcessingElapsedTime = Js::Tick::Now () - start;
153
+ stats ->startPassProcessingElapsedTime = Js::Tick::Now () - start;
143
154
}
144
-
145
155
}
146
156
}
147
157
@@ -156,34 +166,35 @@ namespace Memory
156
166
Js::Tick start = Js::Tick::Now ();
157
167
158
168
AssertOnValidThread (this , RecyclerTelemetryInfo::EndPass);
169
+ RecyclerTelemetryGCPassStats* lastPassStats = this ->GetLastPassStats ();
159
170
160
- this -> lastPassStats ->isGCPassActive = false ;
161
- this -> lastPassStats ->passEndTimeTick = Js::Tick::Now ();
171
+ lastPassStats->isGCPassActive = false ;
172
+ lastPassStats->passEndTimeTick = Js::Tick::Now ();
162
173
163
- this -> lastPassStats ->processCommittedBytes_end = RecyclerTelemetryInfo::GetProcessCommittedBytes ();
164
- this -> lastPassStats ->processAllocaterUsedBytes_end = PageAllocator::GetProcessUsedBytes ();
174
+ lastPassStats->processCommittedBytes_end = RecyclerTelemetryInfo::GetProcessCommittedBytes ();
175
+ lastPassStats->processAllocaterUsedBytes_end = PageAllocator::GetProcessUsedBytes ();
165
176
166
- this ->FillInSizeData (this ->recycler ->GetHeapInfo ()->GetRecyclerLeafPageAllocator (), &this -> lastPassStats ->threadPageAllocator_end );
167
- this ->FillInSizeData (this ->recycler ->GetHeapInfo ()->GetRecyclerPageAllocator (), &this -> lastPassStats ->recyclerLeafPageAllocator_end );
168
- this ->FillInSizeData (this ->recycler ->GetHeapInfo ()->GetRecyclerLargeBlockPageAllocator (), &this -> lastPassStats ->recyclerLargeBlockPageAllocator_end );
177
+ this ->FillInSizeData (this ->recycler ->GetHeapInfo ()->GetRecyclerLeafPageAllocator (), &lastPassStats->threadPageAllocator_end );
178
+ this ->FillInSizeData (this ->recycler ->GetHeapInfo ()->GetRecyclerPageAllocator (), &lastPassStats->recyclerLeafPageAllocator_end );
179
+ this ->FillInSizeData (this ->recycler ->GetHeapInfo ()->GetRecyclerLargeBlockPageAllocator (), &lastPassStats->recyclerLargeBlockPageAllocator_end );
169
180
#ifdef RECYCLER_WRITE_BARRIER_ALLOC_SEPARATE_PAGE
170
- this ->FillInSizeData (this ->recycler ->GetHeapInfo ()->GetRecyclerWithBarrierPageAllocator (), &this -> lastPassStats ->recyclerWithBarrierPageAllocator_end );
181
+ this ->FillInSizeData (this ->recycler ->GetHeapInfo ()->GetRecyclerWithBarrierPageAllocator (), &lastPassStats->recyclerWithBarrierPageAllocator_end );
171
182
#endif
172
183
173
184
// get bucket stats
174
185
Js::Tick bucketStatsStart = Js::Tick::Now ();
175
186
BucketStatsReporter bucketReporter (this ->recycler );
176
187
this ->recycler ->GetHeapInfo ()->GetBucketStats (bucketReporter);
177
- memcpy (&this -> lastPassStats ->bucketStats , bucketReporter.GetTotalStats (), sizeof (HeapBucketStats));
178
- this -> lastPassStats ->computeBucketStatsElapsedTime = Js::Tick::Now () - bucketStatsStart;
188
+ memcpy (&lastPassStats->bucketStats , bucketReporter.GetTotalStats (), sizeof (HeapBucketStats));
189
+ lastPassStats->computeBucketStatsElapsedTime = Js::Tick::Now () - bucketStatsStart;
179
190
180
- this -> lastPassStats ->endPassProcessingElapsedTime = Js::Tick::Now () - start;
191
+ lastPassStats->endPassProcessingElapsedTime = Js::Tick::Now () - start;
181
192
182
193
if (ShouldTransmit () && this ->hostInterface != nullptr )
183
194
{
184
195
if (this ->hostInterface ->TransmitTelemetry (*this ))
185
196
{
186
- this ->lastTransmitTime = this -> lastPassStats ->passEndTimeTick ;
197
+ this ->lastTransmitTime = lastPassStats->passEndTimeTick ;
187
198
Reset ();
188
199
}
189
200
}
@@ -200,27 +211,11 @@ namespace Memory
200
211
201
212
void RecyclerTelemetryInfo::FreeGCPassStats ()
202
213
{
203
- if (this ->lastPassStats != nullptr )
214
+ if (this ->gcPassStats . Empty () == false )
204
215
{
216
+ AssertMsg (this ->passCount > 0 , " unexpected value for passCount" );
205
217
AssertOnValidThread (this , RecyclerTelemetryInfo::FreeGCPassStats);
206
- RecyclerTelemetryGCPassStats* head = this ->lastPassStats ->next ;
207
- RecyclerTelemetryGCPassStats* curr = head;
208
- #ifdef DBG
209
- uint16 freeCount = 0 ;
210
- #endif
211
- do
212
- {
213
- RecyclerTelemetryGCPassStats* next = curr->next ;
214
- HeapDelete (curr);
215
- curr = next;
216
- #ifdef DBG
217
- freeCount++;
218
- #endif
219
- } while (curr != head);
220
- #ifdef DBG
221
- AssertMsg (freeCount == this ->passCount , " Unexpected mismatch between freeCount and passCount" );
222
- #endif
223
- this ->lastPassStats = nullptr ;
218
+ this ->gcPassStats .Clear ();
224
219
this ->passCount = 0 ;
225
220
}
226
221
}
@@ -233,17 +228,18 @@ namespace Memory
233
228
234
229
void RecyclerTelemetryInfo::IncrementUserThreadBlockedCount (Js::TickDelta waitTime, RecyclerWaitReason caller)
235
230
{
231
+ RecyclerTelemetryGCPassStats* lastPassStats = this ->GetLastPassStats ();
236
232
#ifdef DBG
237
233
if (this ->inPassActiveState )
238
234
{
239
- AssertMsg (this -> lastPassStats != nullptr && this -> lastPassStats ->isGCPassActive == true , " unexpected Value in RecyclerTelemetryInfo::IncrementUserThreadBlockedCount" );
235
+ AssertMsg (lastPassStats != nullptr && lastPassStats->isGCPassActive == true , " unexpected Value in RecyclerTelemetryInfo::IncrementUserThreadBlockedCount" );
240
236
}
241
237
#endif
242
238
243
- if (this ->inPassActiveState && this -> lastPassStats != nullptr )
239
+ if (this ->inPassActiveState && lastPassStats != nullptr )
244
240
{
245
241
AssertOnValidThread (this , RecyclerTelemetryInfo::IncrementUserThreadBlockedCount);
246
- this -> lastPassStats ->uiThreadBlockedTimes [caller] += waitTime;
242
+ lastPassStats->uiThreadBlockedTimes [caller] += waitTime;
247
243
}
248
244
}
249
245
0 commit comments