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.
4
5package debug
6
7import (
8	"runtime"
9	"sort"
10	"time"
11)
12
13// GCStats collect information about recent garbage collections.
14type GCStats struct {
15	LastGC         time.Time       // time of last collection
16	NumGC          int64           // number of garbage collections
17	PauseTotal     time.Duration   // total pause for all collections
18	Pause          []time.Duration // pause history, most recent first
19	PauseQuantiles []time.Duration
20}
21
22// Implemented in package runtime.
23func readGCStats(*[]time.Duration)
24func enableGC(bool) bool
25func setGCPercent(int) int
26func freeOSMemory()
27func setMaxStack(int) int
28func setMaxThreads(int) int
29
30// ReadGCStats reads statistics about garbage collection into stats.
31// The number of entries in the pause history is system-dependent;
32// stats.Pause slice will be reused if large enough, reallocated otherwise.
33// ReadGCStats may use the full capacity of the stats.Pause slice.
34// If stats.PauseQuantiles is non-empty, ReadGCStats fills it with quantiles
35// summarizing the distribution of pause time. For example, if
36// len(stats.PauseQuantiles) is 5, it will be filled with the minimum,
37// 25%, 50%, 75%, and maximum pause times.
38func ReadGCStats(stats *GCStats) {
39	// Create a buffer with space for at least two copies of the
40	// pause history tracked by the runtime. One will be returned
41	// to the caller and the other will be used as a temporary buffer
42	// for computing quantiles.
43	const maxPause = len(((*runtime.MemStats)(nil)).PauseNs)
44	if cap(stats.Pause) < 2*maxPause {
45		stats.Pause = make([]time.Duration, 2*maxPause)
46	}
47
48	// readGCStats fills in the pause history (up to maxPause entries)
49	// and then three more: Unix ns time of last GC, number of GC,
50	// and total pause time in nanoseconds. Here we depend on the
51	// fact that time.Duration's native unit is nanoseconds, so the
52	// pauses and the total pause time do not need any conversion.
53	readGCStats(&stats.Pause)
54	n := len(stats.Pause) - 3
55	stats.LastGC = time.Unix(0, int64(stats.Pause[n]))
56	stats.NumGC = int64(stats.Pause[n+1])
57	stats.PauseTotal = stats.Pause[n+2]
58	stats.Pause = stats.Pause[:n]
59
60	if len(stats.PauseQuantiles) > 0 {
61		if n == 0 {
62			for i := range stats.PauseQuantiles {
63				stats.PauseQuantiles[i] = 0
64			}
65		} else {
66			// There's room for a second copy of the data in stats.Pause.
67			// See the allocation at the top of the function.
68			sorted := stats.Pause[n : n+n]
69			copy(sorted, stats.Pause)
70			sort.Sort(byDuration(sorted))
71			nq := len(stats.PauseQuantiles) - 1
72			for i := 0; i < nq; i++ {
73				stats.PauseQuantiles[i] = sorted[len(sorted)*i/nq]
74			}
75			stats.PauseQuantiles[nq] = sorted[len(sorted)-1]
76		}
77	}
78}
79
80type byDuration []time.Duration
81
82func (x byDuration) Len() int           { return len(x) }
83func (x byDuration) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
84func (x byDuration) Less(i, j int) bool { return x[i] < x[j] }
85
86// SetGCPercent sets the garbage collection target percentage:
87// a collection is triggered when the ratio of freshly allocated data
88// to live data remaining after the previous collection reaches this percentage.
89// SetGCPercent returns the previous setting.
90// The initial setting is the value of the GOGC environment variable
91// at startup, or 100 if the variable is not set.
92// A negative percentage disables garbage collection.
93func SetGCPercent(percent int) int {
94	return setGCPercent(percent)
95}
96
97// FreeOSMemory forces a garbage collection followed by an
98// attempt to return as much memory to the operating system
99// as possible. (Even if this is not called, the runtime gradually
100// returns memory to the operating system in a background task.)
101func FreeOSMemory() {
102	freeOSMemory()
103}
104
105// SetMaxStack sets the maximum amount of memory that
106// can be used by a single goroutine stack.
107// If any goroutine exceeds this limit while growing its stack,
108// the program crashes.
109// SetMaxStack returns the previous setting.
110// The initial setting is 1 GB on 64-bit systems, 250 MB on 32-bit systems.
111//
112// SetMaxStack is useful mainly for limiting the damage done by
113// goroutines that enter an infinite recursion. It only limits future
114// stack growth.
115func SetMaxStack(bytes int) int {
116	return setMaxStack(bytes)
117}
118
119// SetMaxThreads sets the maximum number of operating system
120// threads that the Go program can use. If it attempts to use more than
121// this many, the program crashes.
122// SetMaxThreads returns the previous setting.
123// The initial setting is 10,000 threads.
124//
125// The limit controls the number of operating system threads, not the number
126// of goroutines. A Go program creates a new thread only when a goroutine
127// is ready to run but all the existing threads are blocked in system calls, cgo calls,
128// or are locked to other goroutines due to use of runtime.LockOSThread.
129//
130// SetMaxThreads is useful mainly for limiting the damage done by
131// programs that create an unbounded number of threads. The idea is
132// to take down the program before it takes down the operating system.
133func SetMaxThreads(threads int) int {
134	return setMaxThreads(threads)
135}
136