1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*++
6
7Module Name:
8
9 gcrecord.h
10
11--*/
12
13#ifndef __gc_record_h__
14#define __gc_record_h__
15
16//#define max_generation 2
17
18// We pack the dynamic tuning for deciding which gen to condemn in a uint32_t.
19// We assume that 2 bits are enough to represent the generation.
20#define bits_generation 2
21#define generation_mask (~(~0u << bits_generation))
22//=======================note !!!===================================//
23// If you add stuff to this enum, remember to update total_gen_reasons
24// and record_condemn_gen_reasons below.
25//=======================note !!!===================================//
26
27// These are condemned reasons related to generations.
28// Each reason takes up 2 bits as we have 3 generations.
29// So we can store up to 16 reasons in this uint32_t.
30// They need processing before being used.
31// See the set and the get method for details.
32enum gc_condemn_reason_gen
33{
34 gen_initial = 0, // indicates the initial gen to condemn.
35 gen_final_per_heap = 1, // indicates the final gen to condemn per heap.
36 gen_alloc_budget = 2, // indicates which gen's budget is exceeded.
37 gen_time_tuning = 3, // indicates the gen number that time based tuning decided.
38 gcrg_max = 4
39};
40
41// These are condemned reasons related to conditions we are in.
42// For example, we are in very high memory load which is a condition.
43// Each condition takes up a single bit indicates TRUE or FALSE.
44// We can store 32 of these.
45enum gc_condemn_reason_condition
46{
47 gen_induced_fullgc_p = 0,
48 gen_expand_fullgc_p = 1,
49 gen_high_mem_p = 2,
50 gen_very_high_mem_p = 3,
51 gen_low_ephemeral_p = 4,
52 gen_low_card_p = 5,
53 gen_eph_high_frag_p = 6,
54 gen_max_high_frag_p = 7,
55 gen_max_high_frag_e_p = 8,
56 gen_max_high_frag_m_p = 9,
57 gen_max_high_frag_vm_p = 10,
58 gen_max_gen1 = 11,
59 gen_before_oom = 12,
60 gen_gen2_too_small = 13,
61 gen_induced_noforce_p = 14,
62 gen_before_bgc = 15,
63 gen_almost_max_alloc = 16,
64 gcrc_max = 17
65};
66
67#ifdef DT_LOG
68static char* record_condemn_reasons_gen_header = "[cg]i|f|a|t|";
69static char* record_condemn_reasons_condition_header = "[cc]i|e|h|v|l|l|e|m|m|m|m|g|o|s|n|b|a|";
70static char char_gen_number[4] = {'0', '1', '2', '3'};
71#endif //DT_LOG
72
73class gen_to_condemn_tuning
74{
75 uint32_t condemn_reasons_gen;
76 uint32_t condemn_reasons_condition;
77
78#ifdef DT_LOG
79 char str_reasons_gen[64];
80 char str_reasons_condition[64];
81#endif //DT_LOG
82
83 void init_str()
84 {
85#ifdef DT_LOG
86 memset (str_reasons_gen, '|', sizeof (char) * 64);
87 str_reasons_gen[gcrg_max*2] = 0;
88 memset (str_reasons_condition, '|', sizeof (char) * 64);
89 str_reasons_condition[gcrc_max*2] = 0;
90#endif //DT_LOG
91 }
92
93public:
94 void init()
95 {
96 condemn_reasons_gen = 0;
97 condemn_reasons_condition = 0;
98 init_str();
99 }
100
101 void init (gen_to_condemn_tuning* reasons)
102 {
103 condemn_reasons_gen = reasons->condemn_reasons_gen;
104 condemn_reasons_condition = reasons->condemn_reasons_condition;
105 init_str();
106 }
107
108 void set_gen (gc_condemn_reason_gen condemn_gen_reason, uint32_t value)
109 {
110 assert ((value & (~generation_mask)) == 0);
111 condemn_reasons_gen |= (value << (condemn_gen_reason * 2));
112 }
113
114 void set_condition (gc_condemn_reason_condition condemn_gen_reason)
115 {
116 condemn_reasons_condition |= (1 << condemn_gen_reason);
117 }
118
119 // This checks if condition_to_check is the only condition set.
120 BOOL is_only_condition (gc_condemn_reason_condition condition_to_check)
121 {
122 uint32_t temp_conditions = 1 << condition_to_check;
123 return !(condemn_reasons_condition ^ temp_conditions);
124 }
125
126 uint32_t get_gen (gc_condemn_reason_gen condemn_gen_reason)
127 {
128 uint32_t value = ((condemn_reasons_gen >> (condemn_gen_reason * 2)) & generation_mask);
129 return value;
130 }
131
132 uint32_t get_condition (gc_condemn_reason_condition condemn_gen_reason)
133 {
134 uint32_t value = (condemn_reasons_condition & (1 << condemn_gen_reason));
135 return value;
136 }
137
138 uint32_t get_reasons0()
139 {
140 return condemn_reasons_gen;
141 }
142
143 uint32_t get_reasons1()
144 {
145 return condemn_reasons_condition;
146 }
147
148#ifdef DT_LOG
149 char get_gen_char (uint32_t value)
150 {
151 return char_gen_number[value];
152 }
153 char get_condition_char (uint32_t value)
154 {
155 return (value ? 'Y' : 'N');
156 }
157#endif //DT_LOG
158
159 void print (int heap_num);
160};
161
162// Right now these are all size_t's but if you add a type that requires
163// padding you should add a pragma pack here since I am firing this as
164// a struct in an ETW event.
165struct gc_generation_data
166{
167 // data recorded at the beginning of a GC
168 size_t size_before; // including fragmentation.
169 size_t free_list_space_before;
170 size_t free_obj_space_before;
171
172 // data recorded at the end of a GC
173 size_t size_after; // including fragmentation.
174 size_t free_list_space_after;
175 size_t free_obj_space_after;
176 size_t in;
177 size_t pinned_surv;
178 size_t npinned_surv;
179 size_t new_allocation;
180
181 void print (int heap_num, int gen_num);
182};
183
184struct maxgen_size_increase
185{
186 size_t free_list_allocated;
187 size_t free_list_rejected;
188 size_t end_seg_allocated;
189 size_t condemned_allocated;
190 size_t pinned_allocated;
191 size_t pinned_allocated_advance;
192 uint32_t running_free_list_efficiency;
193};
194
195// The following indicates various mechanisms and one value
196// related to each one. Each value has its corresponding string
197// representation so if you change the enum's, make sure you
198// also add its string form.
199
200// Note that if we are doing a gen1 GC, we won't
201// really expand the heap if we are reusing, but
202// we'll record the can_expand_into_p result here.
203enum gc_heap_expand_mechanism
204{
205 expand_reuse_normal = 0,
206 expand_reuse_bestfit = 1,
207 expand_new_seg_ep = 2, // new seg with ephemeral promotion
208 expand_new_seg = 3,
209 expand_no_memory = 4, // we can't get a new seg.
210 expand_next_full_gc = 5,
211 max_expand_mechanisms_count = 6
212};
213
214#ifdef DT_LOG
215static char* str_heap_expand_mechanisms[] =
216{
217 "reused seg with normal fit",
218 "reused seg with best fit",
219 "expand promoting eph",
220 "expand with a new seg",
221 "no memory for a new seg",
222 "expand in next full GC"
223};
224#endif //DT_LOG
225
226enum gc_heap_compact_reason
227{
228 compact_low_ephemeral = 0,
229 compact_high_frag = 1,
230 compact_no_gaps = 2,
231 compact_loh_forced = 3,
232 compact_last_gc = 4,
233 compact_induced_compacting = 5,
234 compact_fragmented_gen0 = 6,
235 compact_high_mem_load = 7,
236 compact_high_mem_frag = 8,
237 compact_vhigh_mem_frag = 9,
238 compact_no_gc_mode = 10,
239 max_compact_reasons_count = 11
240};
241
242#ifndef DACCESS_COMPILE
243static BOOL gc_heap_compact_reason_mandatory_p[] =
244{
245 TRUE, //compact_low_ephemeral = 0,
246 FALSE, //compact_high_frag = 1,
247 TRUE, //compact_no_gaps = 2,
248 TRUE, //compact_loh_forced = 3,
249 TRUE, //compact_last_gc = 4
250 TRUE, //compact_induced_compacting = 5,
251 FALSE, //compact_fragmented_gen0 = 6,
252 FALSE, //compact_high_mem_load = 7,
253 TRUE, //compact_high_mem_frag = 8,
254 TRUE, //compact_vhigh_mem_frag = 9,
255 TRUE //compact_no_gc_mode = 10
256};
257
258static BOOL gc_expand_mechanism_mandatory_p[] =
259{
260 FALSE, //expand_reuse_normal = 0,
261 TRUE, //expand_reuse_bestfit = 1,
262 FALSE, //expand_new_seg_ep = 2, // new seg with ephemeral promotion
263 TRUE, //expand_new_seg = 3,
264 FALSE, //expand_no_memory = 4, // we can't get a new seg.
265 TRUE //expand_next_full_gc = 5
266};
267#endif //!DACCESS_COMPILE
268
269#ifdef DT_LOG
270static char* str_heap_compact_reasons[] =
271{
272 "low on ephemeral space",
273 "high fragmentation",
274 "couldn't allocate gaps",
275 "user specfied compact LOH",
276 "last GC before OOM",
277 "induced compacting GC",
278 "fragmented gen0 (ephemeral GC)",
279 "high memory load (ephemeral GC)",
280 "high memory load and frag",
281 "very high memory load and frag",
282 "no gc mode"
283};
284#endif //DT_LOG
285
286enum gc_mechanism_per_heap
287{
288 gc_heap_expand,
289 gc_heap_compact,
290 max_mechanism_per_heap
291};
292
293enum gc_mechanism_bit_per_heap
294{
295 gc_mark_list_bit = 0,
296 gc_demotion_bit = 1,
297 max_gc_mechanism_bits_count = 2
298};
299
300#ifdef DT_LOG
301struct gc_mechanism_descr
302{
303 char* name;
304 char** descr;
305};
306
307static gc_mechanism_descr gc_mechanisms_descr[max_mechanism_per_heap] =
308{
309 {"expanded heap ", str_heap_expand_mechanisms},
310 {"compacted because of ", str_heap_compact_reasons}
311};
312#endif //DT_LOG
313
314// Get the 0-based index of the most-significant bit in the value.
315// Returns -1 if the input value is zero (i.e. has no set bits).
316int index_of_highest_set_bit (size_t value);
317
318#define mechanism_mask (1 << (sizeof (uint32_t) * 8 - 1))
319// interesting per heap data we want to record for each GC.
320class gc_history_per_heap
321{
322public:
323 gc_generation_data gen_data[max_generation+2];
324 maxgen_size_increase maxgen_size_info;
325 gen_to_condemn_tuning gen_to_condemn_reasons;
326
327 // The mechanisms data is compacted in the following way:
328 // most significant bit indicates if we did the operation.
329 // the rest of the bits indicate the reason/mechanism
330 // why we chose to do the operation. For example:
331 // if we did a heap expansion using best fit we'd have
332 // 0x80000002 for the gc_heap_expand mechanism.
333 // Only one value is possible for each mechanism - meaning the
334 // values are all exclusive
335 // TODO: for the config stuff I need to think more about how to represent this
336 // because we might want to know all reasons (at least all mandatory ones) for
337 // compact.
338 // TODO: no need to the MSB for this
339 uint32_t mechanisms[max_mechanism_per_heap];
340
341 // Each bit in this uint32_t represent if a mechanism was used or not.
342 uint32_t machanism_bits;
343
344 uint32_t heap_index;
345
346 size_t extra_gen0_committed;
347
348 void set_mechanism (gc_mechanism_per_heap mechanism_per_heap, uint32_t value);
349
350 void set_mechanism_bit (gc_mechanism_bit_per_heap mech_bit)
351 {
352 machanism_bits |= 1 << mech_bit;
353 }
354
355 void clear_mechanism_bit (gc_mechanism_bit_per_heap mech_bit)
356 {
357 machanism_bits &= ~(1 << mech_bit);
358 }
359
360 BOOL is_mechanism_bit_set (gc_mechanism_bit_per_heap mech_bit)
361 {
362 return (machanism_bits & (1 << mech_bit));
363 }
364
365 void clear_mechanism(gc_mechanism_per_heap mechanism_per_heap)
366 {
367 uint32_t* mechanism = &mechanisms[mechanism_per_heap];
368 *mechanism = 0;
369 }
370
371 int get_mechanism (gc_mechanism_per_heap mechanism_per_heap)
372 {
373 uint32_t mechanism = mechanisms[mechanism_per_heap];
374
375 if (mechanism & mechanism_mask)
376 {
377 int index = index_of_highest_set_bit ((size_t)(mechanism & (~mechanism_mask)));
378 assert (index != -1);
379 return index;
380 }
381
382 return -1;
383 }
384
385 void print();
386};
387
388// we store up to 32 boolean settings.
389enum gc_global_mechanism_p
390{
391 global_concurrent = 0,
392 global_compaction = 1,
393 global_promotion = 2,
394 global_demotion = 3,
395 global_card_bundles = 4,
396 global_elevation = 5,
397 max_global_mechanisms_count
398};
399
400struct gc_history_global
401{
402 // We may apply other factors after we calculated gen0 budget in
403 // desired_new_allocation such as equalization or smoothing so
404 // record the final budget here.
405 size_t final_youngest_desired;
406 uint32_t num_heaps;
407 int condemned_generation;
408 int gen0_reduction_count;
409 gc_reason reason;
410 int pause_mode;
411 uint32_t mem_pressure;
412 uint32_t global_mechanims_p;
413
414 void set_mechanism_p (gc_global_mechanism_p mechanism)
415 {
416 global_mechanims_p |= (1 << mechanism);
417 }
418
419 BOOL get_mechanism_p (gc_global_mechanism_p mechanism)
420 {
421 return (global_mechanims_p & (1 << mechanism));
422 }
423
424 void print();
425};
426
427#endif //__gc_record_h__
428