1// Copyright 2023 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 main 6 7// #cgo noescape annotations for a C function means its arguments won't escape to heap. 8 9// We assume that there won't be 100 new allocated heap objects in other places, 10// i.e. runtime.ReadMemStats or other runtime background works. 11// So, the tests are: 12// 1. at least 100 new allocated heap objects after invoking withoutNoEscape 100 times. 13// 2. less than 100 new allocated heap objects after invoking withoutNoEscape 100 times. 14 15/* 16// TODO(#56378): #cgo noescape runCWithNoEscape 17 18void runCWithNoEscape(void *p) { 19} 20void runCWithoutNoEscape(void *p) { 21} 22*/ 23import "C" 24 25import ( 26 "fmt" 27 "runtime" 28 "runtime/debug" 29 "unsafe" 30) 31 32const num = 100 33 34func init() { 35 register("CgoNoEscape", CgoNoEscape) 36} 37 38//go:noinline 39func withNoEscape() { 40 var str string 41 C.runCWithNoEscape(unsafe.Pointer(&str)) 42} 43 44//go:noinline 45func withoutNoEscape() { 46 var str string 47 C.runCWithoutNoEscape(unsafe.Pointer(&str)) 48} 49 50func CgoNoEscape() { 51 // make GC stop to see the heap objects allocated 52 debug.SetGCPercent(-1) 53 54 var stats runtime.MemStats 55 runtime.ReadMemStats(&stats) 56 preHeapObjects := stats.HeapObjects 57 58 for i := 0; i < num; i++ { 59 withNoEscape() 60 } 61 62 runtime.ReadMemStats(&stats) 63 nowHeapObjects := stats.HeapObjects 64 65 if nowHeapObjects-preHeapObjects >= num { 66 fmt.Printf("too many heap objects allocated, pre: %v, now: %v\n", preHeapObjects, nowHeapObjects) 67 } 68 69 runtime.ReadMemStats(&stats) 70 preHeapObjects = stats.HeapObjects 71 72 for i := 0; i < num; i++ { 73 withoutNoEscape() 74 } 75 76 runtime.ReadMemStats(&stats) 77 nowHeapObjects = stats.HeapObjects 78 79 if nowHeapObjects-preHeapObjects < num { 80 fmt.Printf("too few heap objects allocated, pre: %v, now: %v\n", preHeapObjects, nowHeapObjects) 81 } 82 83 fmt.Println("OK") 84} 85