| // run |
| |
| // Copyright 2015 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Test that tiny allocations with finalizers are correctly profiled. |
| // Previously profile special records could have been processed prematurely |
| // (while the object is still live). |
| |
| package main |
| |
| import ( |
| "runtime" |
| "time" |
| "unsafe" |
| ) |
| |
| func main() { |
| runtime.MemProfileRate = 1 |
| // Allocate 1M 4-byte objects and set a finalizer for every third object. |
| // Assuming that tiny block size is 16, some objects get finalizers setup |
| // only for middle bytes. The finalizer resurrects that object. |
| // As the result, all allocated memory must stay alive. |
| const ( |
| N = 1 << 20 |
| tinyBlockSize = 16 // runtime._TinySize |
| ) |
| hold := make([]*int32, 0, N) |
| for i := 0; i < N; i++ { |
| x := new(int32) |
| if i%3 == 0 { |
| runtime.SetFinalizer(x, func(p *int32) { |
| hold = append(hold, p) |
| }) |
| } |
| } |
| // Finalize as much as possible. |
| // Note: the sleep only increases probility of bug detection, |
| // it cannot lead to false failure. |
| for i := 0; i < 5; i++ { |
| runtime.GC() |
| time.Sleep(10 * time.Millisecond) |
| } |
| // Read memory profile. |
| var prof []runtime.MemProfileRecord |
| for { |
| if n, ok := runtime.MemProfile(prof, false); ok { |
| prof = prof[:n] |
| break |
| } else { |
| prof = make([]runtime.MemProfileRecord, n+10) |
| } |
| } |
| // See how much memory in tiny objects is profiled. |
| var totalBytes int64 |
| for _, p := range prof { |
| bytes := p.AllocBytes - p.FreeBytes |
| nobj := p.AllocObjects - p.FreeObjects |
| size := bytes / nobj |
| if size == tinyBlockSize { |
| totalBytes += bytes |
| } |
| } |
| // 2*tinyBlockSize slack is for any boundary effects. |
| if want := N*int64(unsafe.Sizeof(int32(0))) - 2*tinyBlockSize; totalBytes < want { |
| println("got", totalBytes, "want >=", want) |
| panic("some of the tiny objects are not profiled") |
| } |
| // Just to keep hold alive. |
| if len(hold) != 0 && hold[0] == nil { |
| panic("bad") |
| } |
| } |