1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
15 func TestReadGCStats(t
*testing
.T
) {
16 defer SetGCPercent(SetGCPercent(-1))
19 var mstats runtime
.MemStats
20 var min
, max time
.Duration
22 // First ReadGCStats will allocate, second should not,
23 // especially if we follow up with an explicit garbage collection.
24 stats
.PauseQuantiles
= make([]time
.Duration
, 10)
28 // Assume these will return same data: no GC during ReadGCStats.
30 runtime
.ReadMemStats(&mstats
)
32 if stats
.NumGC
!= int64(mstats
.NumGC
) {
33 t
.Errorf("stats.NumGC = %d, but mstats.NumGC = %d", stats
.NumGC
, mstats
.NumGC
)
35 if stats
.PauseTotal
!= time
.Duration(mstats
.PauseTotalNs
) {
36 t
.Errorf("stats.PauseTotal = %d, but mstats.PauseTotalNs = %d", stats
.PauseTotal
, mstats
.PauseTotalNs
)
38 if stats
.LastGC
.UnixNano() != int64(mstats
.LastGC
) {
39 t
.Errorf("stats.LastGC.UnixNano = %d, but mstats.LastGC = %d", stats
.LastGC
.UnixNano(), mstats
.LastGC
)
41 n
:= int(mstats
.NumGC
)
42 if n
> len(mstats
.PauseNs
) {
43 n
= len(mstats
.PauseNs
)
45 if len(stats
.Pause
) != n
{
46 t
.Errorf("len(stats.Pause) = %d, want %d", len(stats
.Pause
), n
)
48 off
:= (int(mstats
.NumGC
) + len(mstats
.PauseNs
) - 1) % len(mstats
.PauseNs
)
49 for i
:= 0; i
< n
; i
++ {
51 if dt
!= time
.Duration(mstats
.PauseNs
[off
]) {
52 t
.Errorf("stats.Pause[%d] = %d, want %d", i
, dt
, mstats
.PauseNs
[off
])
57 if min
> dt || i
== 0 {
60 off
= (off
+ len(mstats
.PauseNs
) - 1) % len(mstats
.PauseNs
)
64 q
:= stats
.PauseQuantiles
66 if q
[0] != min || q
[nq
-1] != max
{
67 t
.Errorf("stats.PauseQuantiles = [%d, ..., %d], want [%d, ..., %d]", q
[0], q
[nq
-1], min
, max
)
70 for i
:= 0; i
< nq
-1; i
++ {
72 t
.Errorf("stats.PauseQuantiles[%d]=%d > stats.PauseQuantiles[%d]=%d", i
, q
[i
], i
+1, q
[i
+1])
76 // compare memory stats with gc stats:
77 if len(stats
.PauseEnd
) != n
{
78 t
.Fatalf("len(stats.PauseEnd) = %d, want %d", len(stats
.PauseEnd
), n
)
80 off
:= (int(mstats
.NumGC
) + len(mstats
.PauseEnd
) - 1) % len(mstats
.PauseEnd
)
81 for i
:= 0; i
< n
; i
++ {
82 dt
:= stats
.PauseEnd
[i
]
83 if dt
.UnixNano() != int64(mstats
.PauseEnd
[off
]) {
84 t
.Errorf("stats.PauseEnd[%d] = %d, want %d", i
, dt
.UnixNano(), mstats
.PauseEnd
[off
])
86 off
= (off
+ len(mstats
.PauseEnd
) - 1) % len(mstats
.PauseEnd
)
90 var big
= make([]byte, 1<<20)
92 func TestFreeOSMemory(t
*testing
.T
) {
93 var ms1
, ms2 runtime
.MemStats
96 t
.Skip("test is not reliable when run multiple times")
100 runtime
.ReadMemStats(&ms1
)
102 runtime
.ReadMemStats(&ms2
)
103 if ms1
.HeapReleased
>= ms2
.HeapReleased
{
104 t
.Errorf("released before=%d; released after=%d; did not go up", ms1
.HeapReleased
, ms2
.HeapReleased
)
109 setGCPercentBallast
interface{}
110 setGCPercentSink
interface{}
113 func TestSetGCPercent(t
*testing
.T
) {
114 testenv
.SkipFlaky(t
, 20076)
116 // Test that the variable is being set and returned correctly.
117 old
:= SetGCPercent(123)
118 new := SetGCPercent(old
)
120 t
.Errorf("SetGCPercent(123); SetGCPercent(x) = %d, want 123", new)
123 // Test that the percentage is implemented correctly.
126 setGCPercentBallast
, setGCPercentSink
= nil, nil
130 // Create 100 MB of live heap as a baseline.
131 const baseline
= 100 << 20
132 var ms runtime
.MemStats
133 runtime
.ReadMemStats(&ms
)
134 setGCPercentBallast
= make([]byte, baseline
-ms
.Alloc
)
136 runtime
.ReadMemStats(&ms
)
137 if abs64(baseline
-int64(ms
.Alloc
)) > 10<<20 {
138 t
.Fatalf("failed to set up baseline live heap; got %d MB, want %d MB", ms
.Alloc
>>20, baseline
>>20)
140 // NextGC should be ~200 MB.
141 const thresh
= 20 << 20 // TODO: Figure out why this is so noisy on some builders
142 if want
:= int64(2 * baseline
); abs64(want
-int64(ms
.NextGC
)) > thresh
{
143 t
.Errorf("NextGC = %d MB, want %d±%d MB", ms
.NextGC
>>20, want
>>20, thresh
>>20)
145 // Create some garbage, but not enough to trigger another GC.
146 for i
:= 0; float64(i
) < 1.2*baseline
; i
+= 1 << 10 {
147 setGCPercentSink
= make([]byte, 1<<10)
149 setGCPercentSink
= nil
150 // Adjust GOGC to 50. NextGC should be ~150 MB.
152 runtime
.ReadMemStats(&ms
)
153 if want
:= int64(1.5 * baseline
); abs64(want
-int64(ms
.NextGC
)) > thresh
{
154 t
.Errorf("NextGC = %d MB, want %d±%d MB", ms
.NextGC
>>20, want
>>20, thresh
>>20)
157 // Trigger a GC and get back to 100 MB live with GOGC=100.
160 // Raise live to 120 MB.
161 setGCPercentSink
= make([]byte, int(0.2*baseline
))
162 // Lower GOGC to 10. This must force a GC.
163 runtime
.ReadMemStats(&ms
)
166 // It may require an allocation to actually force the GC.
167 setGCPercentSink
= make([]byte, 1<<20)
168 runtime
.ReadMemStats(&ms
)
171 t
.Errorf("expected GC to run but it did not")
175 func abs64(a
int64) int64 {
182 func TestSetMaxThreadsOvf(t
*testing
.T
) {
183 // Verify that a big threads count will not overflow the int32
184 // maxmcount variable, causing a panic (see Issue 16076).
186 // This can only happen when ints are 64 bits, since on platforms
187 // with 32 bit ints SetMaxThreads (which takes an int parameter)
188 // cannot be given anything that will overflow an int32.
190 // Call SetMaxThreads with 1<<31, but only on 64 bit systems.
191 nt
:= SetMaxThreads(1 << (30 + ^uint(0)>>63))
192 SetMaxThreads(nt
) // restore previous value