1// Copyright 2009 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
5// Memory statistics
6
7package runtime
8
9import (
10	"runtime/internal/atomic"
11	"runtime/internal/sys"
12	"unsafe"
13)
14
15// Statistics.
16// If you edit this structure, also edit type MemStats below.
17// Their layouts must match exactly.
18//
19// For detailed descriptions see the documentation for MemStats.
20// Fields that differ from MemStats are further documented here.
21//
22// Many of these fields are updated on the fly, while others are only
23// updated when updatememstats is called.
24type mstats struct {
25	// General statistics.
26	alloc       uint64 // bytes allocated and not yet freed
27	total_alloc uint64 // bytes allocated (even if freed)
28	sys         uint64 // bytes obtained from system (should be sum of xxx_sys below, no locking, approximate)
29	nlookup     uint64 // number of pointer lookups (unused)
30	nmalloc     uint64 // number of mallocs
31	nfree       uint64 // number of frees
32
33	// Statistics about malloc heap.
34	// Updated atomically, or with the world stopped.
35	//
36	// Like MemStats, heap_sys and heap_inuse do not count memory
37	// in manually-managed spans.
38	heap_alloc    uint64 // bytes allocated and not yet freed (same as alloc above)
39	heap_sys      uint64 // virtual address space obtained from system for GC'd heap
40	heap_idle     uint64 // bytes in idle spans
41	heap_inuse    uint64 // bytes in mSpanInUse spans
42	heap_released uint64 // bytes released to the os
43
44	// heap_objects is not used by the runtime directly and instead
45	// computed on the fly by updatememstats.
46	heap_objects uint64 // total number of allocated objects
47
48	// Statistics about allocation of low-level fixed-size structures.
49	// Protected by FixAlloc locks.
50	stacks_inuse uint64 // bytes in manually-managed stack spans; updated atomically or during STW
51	stacks_sys   uint64 // only counts newosproc0 stack in mstats; differs from MemStats.StackSys
52	mspan_inuse  uint64 // mspan structures
53	mspan_sys    uint64
54	mcache_inuse uint64 // mcache structures
55	mcache_sys   uint64
56	buckhash_sys uint64 // profiling bucket hash table
57	gc_sys       uint64 // updated atomically or during STW
58	other_sys    uint64 // updated atomically or during STW
59
60	// Statistics about garbage collector.
61	// Protected by mheap or stopping the world during GC.
62	next_gc         uint64 // goal heap_live for when next GC ends; ^0 if disabled
63	last_gc_unix    uint64 // last gc (in unix time)
64	pause_total_ns  uint64
65	pause_ns        [256]uint64 // circular buffer of recent gc pause lengths
66	pause_end       [256]uint64 // circular buffer of recent gc end times (nanoseconds since 1970)
67	numgc           uint32
68	numforcedgc     uint32  // number of user-forced GCs
69	gc_cpu_fraction float64 // fraction of CPU time used by GC
70	enablegc        bool
71	debuggc         bool
72
73	// Statistics about allocation size classes.
74
75	by_size [_NumSizeClasses]struct {
76		size    uint32
77		nmalloc uint64
78		nfree   uint64
79	}
80
81	// Statistics below here are not exported to MemStats directly.
82
83	last_gc_nanotime uint64 // last gc (monotonic time)
84	tinyallocs       uint64 // number of tiny allocations that didn't cause actual allocation; not exported to go directly
85	last_next_gc     uint64 // next_gc for the previous GC
86	last_heap_inuse  uint64 // heap_inuse at mark termination of the previous GC
87
88	// triggerRatio is the heap growth ratio that triggers marking.
89	//
90	// E.g., if this is 0.6, then GC should start when the live
91	// heap has reached 1.6 times the heap size marked by the
92	// previous cycle. This should be ≤ GOGC/100 so the trigger
93	// heap size is less than the goal heap size. This is set
94	// during mark termination for the next cycle's trigger.
95	triggerRatio float64
96
97	// gc_trigger is the heap size that triggers marking.
98	//
99	// When heap_live ≥ gc_trigger, the mark phase will start.
100	// This is also the heap size by which proportional sweeping
101	// must be complete.
102	//
103	// This is computed from triggerRatio during mark termination
104	// for the next cycle's trigger.
105	gc_trigger uint64
106
107	// heap_live is the number of bytes considered live by the GC.
108	// That is: retained by the most recent GC plus allocated
109	// since then. heap_live <= heap_alloc, since heap_alloc
110	// includes unmarked objects that have not yet been swept (and
111	// hence goes up as we allocate and down as we sweep) while
112	// heap_live excludes these objects (and hence only goes up
113	// between GCs).
114	//
115	// This is updated atomically without locking. To reduce
116	// contention, this is updated only when obtaining a span from
117	// an mcentral and at this point it counts all of the
118	// unallocated slots in that span (which will be allocated
119	// before that mcache obtains another span from that
120	// mcentral). Hence, it slightly overestimates the "true" live
121	// heap size. It's better to overestimate than to
122	// underestimate because 1) this triggers the GC earlier than
123	// necessary rather than potentially too late and 2) this
124	// leads to a conservative GC rate rather than a GC rate that
125	// is potentially too low.
126	//
127	// Reads should likewise be atomic (or during STW).
128	//
129	// Whenever this is updated, call traceHeapAlloc() and
130	// gcController.revise().
131	heap_live uint64
132
133	// heap_scan is the number of bytes of "scannable" heap. This
134	// is the live heap (as counted by heap_live), but omitting
135	// no-scan objects and no-scan tails of objects.
136	//
137	// Whenever this is updated, call gcController.revise().
138	heap_scan uint64
139
140	// heap_marked is the number of bytes marked by the previous
141	// GC. After mark termination, heap_live == heap_marked, but
142	// unlike heap_live, heap_marked does not change until the
143	// next mark termination.
144	heap_marked uint64
145}
146
147var memstats mstats
148
149// A MemStats records statistics about the memory allocator.
150type MemStats struct {
151	// General statistics.
152
153	// Alloc is bytes of allocated heap objects.
154	//
155	// This is the same as HeapAlloc (see below).
156	Alloc uint64
157
158	// TotalAlloc is cumulative bytes allocated for heap objects.
159	//
160	// TotalAlloc increases as heap objects are allocated, but
161	// unlike Alloc and HeapAlloc, it does not decrease when
162	// objects are freed.
163	TotalAlloc uint64
164
165	// Sys is the total bytes of memory obtained from the OS.
166	//
167	// Sys is the sum of the XSys fields below. Sys measures the
168	// virtual address space reserved by the Go runtime for the
169	// heap, stacks, and other internal data structures. It's
170	// likely that not all of the virtual address space is backed
171	// by physical memory at any given moment, though in general
172	// it all was at some point.
173	Sys uint64
174
175	// Lookups is the number of pointer lookups performed by the
176	// runtime.
177	//
178	// This is primarily useful for debugging runtime internals.
179	Lookups uint64
180
181	// Mallocs is the cumulative count of heap objects allocated.
182	// The number of live objects is Mallocs - Frees.
183	Mallocs uint64
184
185	// Frees is the cumulative count of heap objects freed.
186	Frees uint64
187
188	// Heap memory statistics.
189	//
190	// Interpreting the heap statistics requires some knowledge of
191	// how Go organizes memory. Go divides the virtual address
192	// space of the heap into "spans", which are contiguous
193	// regions of memory 8K or larger. A span may be in one of
194	// three states:
195	//
196	// An "idle" span contains no objects or other data. The
197	// physical memory backing an idle span can be released back
198	// to the OS (but the virtual address space never is), or it
199	// can be converted into an "in use" or "stack" span.
200	//
201	// An "in use" span contains at least one heap object and may
202	// have free space available to allocate more heap objects.
203	//
204	// A "stack" span is used for goroutine stacks. Stack spans
205	// are not considered part of the heap. A span can change
206	// between heap and stack memory; it is never used for both
207	// simultaneously.
208
209	// HeapAlloc is bytes of allocated heap objects.
210	//
211	// "Allocated" heap objects include all reachable objects, as
212	// well as unreachable objects that the garbage collector has
213	// not yet freed. Specifically, HeapAlloc increases as heap
214	// objects are allocated and decreases as the heap is swept
215	// and unreachable objects are freed. Sweeping occurs
216	// incrementally between GC cycles, so these two processes
217	// occur simultaneously, and as a result HeapAlloc tends to
218	// change smoothly (in contrast with the sawtooth that is
219	// typical of stop-the-world garbage collectors).
220	HeapAlloc uint64
221
222	// HeapSys is bytes of heap memory obtained from the OS.
223	//
224	// HeapSys measures the amount of virtual address space
225	// reserved for the heap. This includes virtual address space
226	// that has been reserved but not yet used, which consumes no
227	// physical memory, but tends to be small, as well as virtual
228	// address space for which the physical memory has been
229	// returned to the OS after it became unused (see HeapReleased
230	// for a measure of the latter).
231	//
232	// HeapSys estimates the largest size the heap has had.
233	HeapSys uint64
234
235	// HeapIdle is bytes in idle (unused) spans.
236	//
237	// Idle spans have no objects in them. These spans could be
238	// (and may already have been) returned to the OS, or they can
239	// be reused for heap allocations, or they can be reused as
240	// stack memory.
241	//
242	// HeapIdle minus HeapReleased estimates the amount of memory
243	// that could be returned to the OS, but is being retained by
244	// the runtime so it can grow the heap without requesting more
245	// memory from the OS. If this difference is significantly
246	// larger than the heap size, it indicates there was a recent
247	// transient spike in live heap size.
248	HeapIdle uint64
249
250	// HeapInuse is bytes in in-use spans.
251	//
252	// In-use spans have at least one object in them. These spans
253	// can only be used for other objects of roughly the same
254	// size.
255	//
256	// HeapInuse minus HeapAlloc estimates the amount of memory
257	// that has been dedicated to particular size classes, but is
258	// not currently being used. This is an upper bound on
259	// fragmentation, but in general this memory can be reused
260	// efficiently.
261	HeapInuse uint64
262
263	// HeapReleased is bytes of physical memory returned to the OS.
264	//
265	// This counts heap memory from idle spans that was returned
266	// to the OS and has not yet been reacquired for the heap.
267	HeapReleased uint64
268
269	// HeapObjects is the number of allocated heap objects.
270	//
271	// Like HeapAlloc, this increases as objects are allocated and
272	// decreases as the heap is swept and unreachable objects are
273	// freed.
274	HeapObjects uint64
275
276	// Stack memory statistics.
277	//
278	// Stacks are not considered part of the heap, but the runtime
279	// can reuse a span of heap memory for stack memory, and
280	// vice-versa.
281
282	// StackInuse is bytes in stack spans.
283	//
284	// In-use stack spans have at least one stack in them. These
285	// spans can only be used for other stacks of the same size.
286	//
287	// There is no StackIdle because unused stack spans are
288	// returned to the heap (and hence counted toward HeapIdle).
289	StackInuse uint64
290
291	// StackSys is bytes of stack memory obtained from the OS.
292	//
293	// StackSys is StackInuse, plus any memory obtained directly
294	// from the OS for OS thread stacks (which should be minimal).
295	StackSys uint64
296
297	// Off-heap memory statistics.
298	//
299	// The following statistics measure runtime-internal
300	// structures that are not allocated from heap memory (usually
301	// because they are part of implementing the heap). Unlike
302	// heap or stack memory, any memory allocated to these
303	// structures is dedicated to these structures.
304	//
305	// These are primarily useful for debugging runtime memory
306	// overheads.
307
308	// MSpanInuse is bytes of allocated mspan structures.
309	MSpanInuse uint64
310
311	// MSpanSys is bytes of memory obtained from the OS for mspan
312	// structures.
313	MSpanSys uint64
314
315	// MCacheInuse is bytes of allocated mcache structures.
316	MCacheInuse uint64
317
318	// MCacheSys is bytes of memory obtained from the OS for
319	// mcache structures.
320	MCacheSys uint64
321
322	// BuckHashSys is bytes of memory in profiling bucket hash tables.
323	BuckHashSys uint64
324
325	// GCSys is bytes of memory in garbage collection metadata.
326	GCSys uint64
327
328	// OtherSys is bytes of memory in miscellaneous off-heap
329	// runtime allocations.
330	OtherSys uint64
331
332	// Garbage collector statistics.
333
334	// NextGC is the target heap size of the next GC cycle.
335	//
336	// The garbage collector's goal is to keep HeapAlloc ≤ NextGC.
337	// At the end of each GC cycle, the target for the next cycle
338	// is computed based on the amount of reachable data and the
339	// value of GOGC.
340	NextGC uint64
341
342	// LastGC is the time the last garbage collection finished, as
343	// nanoseconds since 1970 (the UNIX epoch).
344	LastGC uint64
345
346	// PauseTotalNs is the cumulative nanoseconds in GC
347	// stop-the-world pauses since the program started.
348	//
349	// During a stop-the-world pause, all goroutines are paused
350	// and only the garbage collector can run.
351	PauseTotalNs uint64
352
353	// PauseNs is a circular buffer of recent GC stop-the-world
354	// pause times in nanoseconds.
355	//
356	// The most recent pause is at PauseNs[(NumGC+255)%256]. In
357	// general, PauseNs[N%256] records the time paused in the most
358	// recent N%256th GC cycle. There may be multiple pauses per
359	// GC cycle; this is the sum of all pauses during a cycle.
360	PauseNs [256]uint64
361
362	// PauseEnd is a circular buffer of recent GC pause end times,
363	// as nanoseconds since 1970 (the UNIX epoch).
364	//
365	// This buffer is filled the same way as PauseNs. There may be
366	// multiple pauses per GC cycle; this records the end of the
367	// last pause in a cycle.
368	PauseEnd [256]uint64
369
370	// NumGC is the number of completed GC cycles.
371	NumGC uint32
372
373	// NumForcedGC is the number of GC cycles that were forced by
374	// the application calling the GC function.
375	NumForcedGC uint32
376
377	// GCCPUFraction is the fraction of this program's available
378	// CPU time used by the GC since the program started.
379	//
380	// GCCPUFraction is expressed as a number between 0 and 1,
381	// where 0 means GC has consumed none of this program's CPU. A
382	// program's available CPU time is defined as the integral of
383	// GOMAXPROCS since the program started. That is, if
384	// GOMAXPROCS is 2 and a program has been running for 10
385	// seconds, its "available CPU" is 20 seconds. GCCPUFraction
386	// does not include CPU time used for write barrier activity.
387	//
388	// This is the same as the fraction of CPU reported by
389	// GODEBUG=gctrace=1.
390	GCCPUFraction float64
391
392	// EnableGC indicates that GC is enabled. It is always true,
393	// even if GOGC=off.
394	EnableGC bool
395
396	// DebugGC is currently unused.
397	DebugGC bool
398
399	// BySize reports per-size class allocation statistics.
400	//
401	// BySize[N] gives statistics for allocations of size S where
402	// BySize[N-1].Size < S ≤ BySize[N].Size.
403	//
404	// This does not report allocations larger than BySize[60].Size.
405	BySize [61]struct {
406		// Size is the maximum byte size of an object in this
407		// size class.
408		Size uint32
409
410		// Mallocs is the cumulative count of heap objects
411		// allocated in this size class. The cumulative bytes
412		// of allocation is Size*Mallocs. The number of live
413		// objects in this size class is Mallocs - Frees.
414		Mallocs uint64
415
416		// Frees is the cumulative count of heap objects freed
417		// in this size class.
418		Frees uint64
419	}
420}
421
422// Size of the trailing by_size array differs between mstats and MemStats,
423// and all data after by_size is local to runtime, not exported.
424// NumSizeClasses was changed, but we cannot change MemStats because of backward compatibility.
425// sizeof_C_MStats is the size of the prefix of mstats that
426// corresponds to MemStats. It should match Sizeof(MemStats{}).
427var sizeof_C_MStats = unsafe.Offsetof(memstats.by_size) + 61*unsafe.Sizeof(memstats.by_size[0])
428
429func init() {
430	var memStats MemStats
431	if sizeof_C_MStats != unsafe.Sizeof(memStats) {
432		println(sizeof_C_MStats, unsafe.Sizeof(memStats))
433		throw("MStats vs MemStatsType size mismatch")
434	}
435
436	if unsafe.Offsetof(memstats.heap_live)%8 != 0 {
437		println(unsafe.Offsetof(memstats.heap_live))
438		throw("memstats.heap_live not aligned to 8 bytes")
439	}
440}
441
442// ReadMemStats populates m with memory allocator statistics.
443//
444// The returned memory allocator statistics are up to date as of the
445// call to ReadMemStats. This is in contrast with a heap profile,
446// which is a snapshot as of the most recently completed garbage
447// collection cycle.
448func ReadMemStats(m *MemStats) {
449	stopTheWorld("read mem stats")
450
451	systemstack(func() {
452		readmemstats_m(m)
453	})
454
455	startTheWorld()
456}
457
458func readmemstats_m(stats *MemStats) {
459	updatememstats()
460
461	// The size of the trailing by_size array differs between
462	// mstats and MemStats. NumSizeClasses was changed, but we
463	// cannot change MemStats because of backward compatibility.
464	memmove(unsafe.Pointer(stats), unsafe.Pointer(&memstats), sizeof_C_MStats)
465
466	// memstats.stacks_sys is only memory mapped directly for OS stacks.
467	// Add in heap-allocated stack memory for user consumption.
468	stats.StackSys += stats.StackInuse
469}
470
471//go:linkname readGCStats runtime..z2fdebug.readGCStats
472func readGCStats(pauses *[]uint64) {
473	systemstack(func() {
474		readGCStats_m(pauses)
475	})
476}
477
478// readGCStats_m must be called on the system stack because it acquires the heap
479// lock. See mheap for details.
480//go:systemstack
481func readGCStats_m(pauses *[]uint64) {
482	p := *pauses
483	// Calling code in runtime/debug should make the slice large enough.
484	if cap(p) < len(memstats.pause_ns)+3 {
485		throw("short slice passed to readGCStats")
486	}
487
488	// Pass back: pauses, pause ends, last gc (absolute time), number of gc, total pause ns.
489	lock(&mheap_.lock)
490
491	n := memstats.numgc
492	if n > uint32(len(memstats.pause_ns)) {
493		n = uint32(len(memstats.pause_ns))
494	}
495
496	// The pause buffer is circular. The most recent pause is at
497	// pause_ns[(numgc-1)%len(pause_ns)], and then backward
498	// from there to go back farther in time. We deliver the times
499	// most recent first (in p[0]).
500	p = p[:cap(p)]
501	for i := uint32(0); i < n; i++ {
502		j := (memstats.numgc - 1 - i) % uint32(len(memstats.pause_ns))
503		p[i] = memstats.pause_ns[j]
504		p[n+i] = memstats.pause_end[j]
505	}
506
507	p[n+n] = memstats.last_gc_unix
508	p[n+n+1] = uint64(memstats.numgc)
509	p[n+n+2] = memstats.pause_total_ns
510	unlock(&mheap_.lock)
511	*pauses = p[:n+n+3]
512}
513
514//go:nowritebarrier
515func updatememstats() {
516	memstats.mcache_inuse = uint64(mheap_.cachealloc.inuse)
517	memstats.mspan_inuse = uint64(mheap_.spanalloc.inuse)
518	memstats.sys = memstats.heap_sys + memstats.stacks_sys + memstats.mspan_sys +
519		memstats.mcache_sys + memstats.buckhash_sys + memstats.gc_sys + memstats.other_sys
520
521	// We also count stacks_inuse as sys memory.
522	memstats.sys += memstats.stacks_inuse
523
524	// Calculate memory allocator stats.
525	// During program execution we only count number of frees and amount of freed memory.
526	// Current number of alive object in the heap and amount of alive heap memory
527	// are calculated by scanning all spans.
528	// Total number of mallocs is calculated as number of frees plus number of alive objects.
529	// Similarly, total amount of allocated memory is calculated as amount of freed memory
530	// plus amount of alive heap memory.
531	memstats.alloc = 0
532	memstats.total_alloc = 0
533	memstats.nmalloc = 0
534	memstats.nfree = 0
535	for i := 0; i < len(memstats.by_size); i++ {
536		memstats.by_size[i].nmalloc = 0
537		memstats.by_size[i].nfree = 0
538	}
539
540	// Flush mcache's to mcentral.
541	systemstack(flushallmcaches)
542
543	// Aggregate local stats.
544	cachestats()
545
546	// Collect allocation stats. This is safe and consistent
547	// because the world is stopped.
548	var smallFree, totalAlloc, totalFree uint64
549	// Collect per-spanclass stats.
550	for spc := range mheap_.central {
551		// The mcaches are now empty, so mcentral stats are
552		// up-to-date.
553		c := &mheap_.central[spc].mcentral
554		memstats.nmalloc += c.nmalloc
555		i := spanClass(spc).sizeclass()
556		memstats.by_size[i].nmalloc += c.nmalloc
557		totalAlloc += c.nmalloc * uint64(class_to_size[i])
558	}
559	// Collect per-sizeclass stats.
560	for i := 0; i < _NumSizeClasses; i++ {
561		if i == 0 {
562			memstats.nmalloc += mheap_.nlargealloc
563			totalAlloc += mheap_.largealloc
564			totalFree += mheap_.largefree
565			memstats.nfree += mheap_.nlargefree
566			continue
567		}
568
569		// The mcache stats have been flushed to mheap_.
570		memstats.nfree += mheap_.nsmallfree[i]
571		memstats.by_size[i].nfree = mheap_.nsmallfree[i]
572		smallFree += mheap_.nsmallfree[i] * uint64(class_to_size[i])
573	}
574	totalFree += smallFree
575
576	memstats.nfree += memstats.tinyallocs
577	memstats.nmalloc += memstats.tinyallocs
578
579	// Calculate derived stats.
580	memstats.total_alloc = totalAlloc
581	memstats.alloc = totalAlloc - totalFree
582	memstats.heap_alloc = memstats.alloc
583	memstats.heap_objects = memstats.nmalloc - memstats.nfree
584}
585
586// cachestats flushes all mcache stats.
587//
588// The world must be stopped.
589//
590//go:nowritebarrier
591func cachestats() {
592	for _, p := range allp {
593		c := p.mcache
594		if c == nil {
595			continue
596		}
597		purgecachedstats(c)
598	}
599}
600
601// flushmcache flushes the mcache of allp[i].
602//
603// The world must be stopped.
604//
605//go:nowritebarrier
606func flushmcache(i int) {
607	p := allp[i]
608	c := p.mcache
609	if c == nil {
610		return
611	}
612	c.releaseAll()
613}
614
615// flushallmcaches flushes the mcaches of all Ps.
616//
617// The world must be stopped.
618//
619//go:nowritebarrier
620func flushallmcaches() {
621	for i := 0; i < int(gomaxprocs); i++ {
622		flushmcache(i)
623	}
624}
625
626//go:nosplit
627func purgecachedstats(c *mcache) {
628	// Protected by either heap or GC lock.
629	h := &mheap_
630	memstats.heap_scan += uint64(c.local_scan)
631	c.local_scan = 0
632	memstats.tinyallocs += uint64(c.local_tinyallocs)
633	c.local_tinyallocs = 0
634	h.largefree += uint64(c.local_largefree)
635	c.local_largefree = 0
636	h.nlargefree += uint64(c.local_nlargefree)
637	c.local_nlargefree = 0
638	for i := 0; i < len(c.local_nsmallfree); i++ {
639		h.nsmallfree[i] += uint64(c.local_nsmallfree[i])
640		c.local_nsmallfree[i] = 0
641	}
642}
643
644// Atomically increases a given *system* memory stat. We are counting on this
645// stat never overflowing a uintptr, so this function must only be used for
646// system memory stats.
647//
648// The current implementation for little endian architectures is based on
649// xadduintptr(), which is less than ideal: xadd64() should really be used.
650// Using xadduintptr() is a stop-gap solution until arm supports xadd64() that
651// doesn't use locks.  (Locks are a problem as they require a valid G, which
652// restricts their useability.)
653//
654// A side-effect of using xadduintptr() is that we need to check for
655// overflow errors.
656//go:nosplit
657func mSysStatInc(sysStat *uint64, n uintptr) {
658	if sysStat == nil {
659		return
660	}
661	if sys.BigEndian {
662		atomic.Xadd64(sysStat, int64(n))
663		return
664	}
665	if val := atomic.Xadduintptr((*uintptr)(unsafe.Pointer(sysStat)), n); val < n {
666		print("runtime: stat overflow: val ", val, ", n ", n, "\n")
667		exit(2)
668	}
669}
670
671// Atomically decreases a given *system* memory stat. Same comments as
672// mSysStatInc apply.
673//go:nosplit
674func mSysStatDec(sysStat *uint64, n uintptr) {
675	if sysStat == nil {
676		return
677	}
678	if sys.BigEndian {
679		atomic.Xadd64(sysStat, -int64(n))
680		return
681	}
682	if val := atomic.Xadduintptr((*uintptr)(unsafe.Pointer(sysStat)), uintptr(-int64(n))); val+n < n {
683		print("runtime: stat underflow: val ", val, ", n ", n, "\n")
684		exit(2)
685	}
686}
687