Add perf exporter (#1274)

Signed-off-by: Daniel Hodges <hodges.daniel.scott@gmail.com>
This commit is contained in:
Daniel Hodges 2019-05-07 07:21:41 -04:00 committed by Ben Kochie
commit 7882009870
41 changed files with 4285 additions and 0 deletions

2
vendor/github.com/hodgesds/perf-utils/.gitignore generated vendored Normal file
View file

@ -0,0 +1,2 @@
*.swp
vendor

15
vendor/github.com/hodgesds/perf-utils/Gopkg.lock generated vendored Normal file
View file

@ -0,0 +1,15 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "90b0e4468f9980bf79a2290394adaf7f045c5d24"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "c188619af29e454f9af8a4b24b5d13720a55a70615395ba2ded3a628fa51776a"
solver-name = "gps-cdcl"
solver-version = 1

34
vendor/github.com/hodgesds/perf-utils/Gopkg.toml generated vendored Normal file
View file

@ -0,0 +1,34 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
[[constraint]]
branch = "master"
name = "golang.org/x/sys"
[prune]
go-tests = true
unused-packages = true

22
vendor/github.com/hodgesds/perf-utils/LICENSE generated vendored Normal file
View file

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2019 Daniel Hodges
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

120
vendor/github.com/hodgesds/perf-utils/README.md generated vendored Normal file
View file

@ -0,0 +1,120 @@
# Perf
[![GoDoc](https://godoc.org/github.com/hodgesds/perf-utils?status.svg)](https://godoc.org/github.com/hodgesds/perf-utils)
This package is a go library for interacting with the `perf` subsystem in
Linux. It allows you to do things like see how many CPU instructions a function
takes, profile a process for various hardware events, and other interesting
things. The library is by no means finalized and should be considered pre-alpha
at best.
# Use Cases
A majority of the utility methods in this package should only be used for
testing and/or debugging performance issues. Due to the nature of the go
runtime profiling on the goroutine level is extremely tricky, with the
exception of a long running worker goroutine locked to an OS thread. Eventually
this library could be used to implement many of the features of `perf` but in
accessible via Go directly.
## Caveats
* Some utility functions will call
[`runtime.LockOSThread`](https://golang.org/pkg/runtime/#LockOSThread) for
you, they will also unlock the thread after profiling. ***Note*** using these
utility functions will incur significant overhead.
* Overflow handling is not implemented.
# Setup
Most likely you will need to tweak some system settings unless you are running as root. From `man perf_event_open`:
```
perf_event related configuration files
Files in /proc/sys/kernel/
/proc/sys/kernel/perf_event_paranoid
The perf_event_paranoid file can be set to restrict access to the performance counters.
2 allow only user-space measurements (default since Linux 4.6).
1 allow both kernel and user measurements (default before Linux 4.6).
0 allow access to CPU-specific data but not raw tracepoint samples.
-1 no restrictions.
The existence of the perf_event_paranoid file is the official method for determining if a kernel supports perf_event_open().
/proc/sys/kernel/perf_event_max_sample_rate
This sets the maximum sample rate. Setting this too high can allow users to sample at a rate that impacts overall machine performance and potentially lock up the machine. The default value is 100000 (samples per
second).
/proc/sys/kernel/perf_event_max_stack
This file sets the maximum depth of stack frame entries reported when generating a call trace.
/proc/sys/kernel/perf_event_mlock_kb
Maximum number of pages an unprivileged user can mlock(2). The default is 516 (kB).
```
# Example
Say you wanted to see how many CPU instructions a particular function took:
```
package main
import (
"fmt"
"log"
"github.com/hodgesds/perf-utils"
)
func foo() error {
var total int
for i:=0;i<1000;i++ {
total++
}
return nil
}
func main() {
profileValue, err := perf.CPUInstructions(foo)
if err != nil {
log.Fatal(err)
}
fmt.Printf("CPU instructions: %+v\n", profileValue)
}
```
# Benchmarks
To profile a single function call there is an overhead of ~0.4ms.
```
$ go test -bench=BenchmarkCPUCycles .
goos: linux
goarch: amd64
pkg: github.com/hodgesds/perf-utils
BenchmarkCPUCycles-8 3000 397924 ns/op 32 B/op 1 allocs/op
PASS
ok github.com/hodgesds/perf-utils 1.255s
```
The `Profiler` interface has low overhead and suitable for many use cases:
```
$ go test -bench=BenchmarkProfiler .
goos: linux
goarch: amd64
pkg: github.com/hodgesds/perf-utils
BenchmarkProfiler-8 3000000 488 ns/op 32 B/op 1 allocs/op
PASS
ok github.com/hodgesds/perf-utils 1.981s
```
# BPF Support
BPF is supported by using the `BPFProfiler` which is available via the
`ProfileTracepoint` function. To use BPF you need to create the BPF program and
then call `AttachBPF` with the file descriptor of the BPF program. This is not
well tested so use at your own peril.
# Misc
Originally I set out to use `go generate` to build Go structs that were
compatible with perf, I found a really good
[article](https://utcc.utoronto.ca/~cks/space/blog/programming/GoCGoCompatibleStructs)
on how to do so. Eventually, after digging through some of the `/x/sys/unix`
code I found pretty much what I was needed. However, I think if you are
interested in interacting with the kernel it is a worthwhile read.

22
vendor/github.com/hodgesds/perf-utils/bpf.go generated vendored Normal file
View file

@ -0,0 +1,22 @@
// +build linux
package perf
import (
"golang.org/x/sys/unix"
)
// BPFProfiler is a Profiler that allows attaching a Berkeley
// Packet Filter (BPF) program to an existing kprobe tracepoint event.
// You need CAP_SYS_ADMIN privileges to use this interface. See:
// https://lwn.net/Articles/683504/
type BPFProfiler interface {
Profiler
AttachBPF(int) error
}
// AttachBPF is used to attach a BPF program to a profiler by using the file
// descriptor of the BPF program.
func (p *profiler) AttachBPF(fd int) error {
return unix.IoctlSetInt(p.fd, unix.PERF_EVENT_IOC_SET_BPF, fd)
}

336
vendor/github.com/hodgesds/perf-utils/cache_profiler.go generated vendored Normal file
View file

@ -0,0 +1,336 @@
// +build linux
package perf
import (
"go.uber.org/multierr"
"golang.org/x/sys/unix"
)
const (
// L1DataReadHit is a constant...
L1DataReadHit = (unix.PERF_COUNT_HW_CACHE_L1D) | (unix.PERF_COUNT_HW_CACHE_OP_READ << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
// L1DataReadMiss is a constant...
L1DataReadMiss = (unix.PERF_COUNT_HW_CACHE_L1D) | (unix.PERF_COUNT_HW_CACHE_OP_READ << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
// L1DataWriteHit is a constant...
L1DataWriteHit = (unix.PERF_COUNT_HW_CACHE_L1D) | (unix.PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
// L1InstrReadMiss is a constant...
L1InstrReadMiss = (unix.PERF_COUNT_HW_CACHE_L1I) | (unix.PERF_COUNT_HW_CACHE_OP_READ << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
// LLReadHit is a constant...
LLReadHit = (unix.PERF_COUNT_HW_CACHE_LL) | (unix.PERF_COUNT_HW_CACHE_OP_READ << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
// LLReadMiss is a constant...
LLReadMiss = (unix.PERF_COUNT_HW_CACHE_LL) | (unix.PERF_COUNT_HW_CACHE_OP_READ << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
// LLWriteHit is a constant...
LLWriteHit = (unix.PERF_COUNT_HW_CACHE_LL) | (unix.PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
// LLWriteMiss is a constant...
LLWriteMiss = (unix.PERF_COUNT_HW_CACHE_LL) | (unix.PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
// DataTLBReadHit is a constant...
DataTLBReadHit = (unix.PERF_COUNT_HW_CACHE_DTLB) | (unix.PERF_COUNT_HW_CACHE_OP_READ << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
// DataTLBReadMiss is a constant...
DataTLBReadMiss = (unix.PERF_COUNT_HW_CACHE_DTLB) | (unix.PERF_COUNT_HW_CACHE_OP_READ << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
// DataTLBWriteHit is a constant...
DataTLBWriteHit = (unix.PERF_COUNT_HW_CACHE_DTLB) | (unix.PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
// DataTLBWriteMiss is a constant...
DataTLBWriteMiss = (unix.PERF_COUNT_HW_CACHE_DTLB) | (unix.PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
// InstrTLBReadHit is a constant...
InstrTLBReadHit = (unix.PERF_COUNT_HW_CACHE_ITLB) | (unix.PERF_COUNT_HW_CACHE_OP_READ << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
// InstrTLBReadMiss is a constant...
InstrTLBReadMiss = (unix.PERF_COUNT_HW_CACHE_ITLB) | (unix.PERF_COUNT_HW_CACHE_OP_READ << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
// BPUReadHit is a constant...
BPUReadHit = (unix.PERF_COUNT_HW_CACHE_BPU) | (unix.PERF_COUNT_HW_CACHE_OP_READ << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
// BPUReadMiss is a constant...
BPUReadMiss = (unix.PERF_COUNT_HW_CACHE_BPU) | (unix.PERF_COUNT_HW_CACHE_OP_READ << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
// NodeCacheReadHit is a constant...
NodeCacheReadHit = (unix.PERF_COUNT_HW_CACHE_NODE) | (unix.PERF_COUNT_HW_CACHE_OP_READ << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
// NodeCacheReadMiss is a constant...
NodeCacheReadMiss = (unix.PERF_COUNT_HW_CACHE_NODE) | (unix.PERF_COUNT_HW_CACHE_OP_READ << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
// NodeCacheWriteHit is a constant...
NodeCacheWriteHit = (unix.PERF_COUNT_HW_CACHE_NODE) | (unix.PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
// NodeCacheWriteMiss is a constant...
NodeCacheWriteMiss = (unix.PERF_COUNT_HW_CACHE_NODE) | (unix.PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (unix.PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
)
type cacheProfiler struct {
// map of perf counter type to file descriptor
profilers map[int]Profiler
}
// NewCacheProfiler returns a new cache profiler.
func NewCacheProfiler(pid, cpu int, opts ...int) CacheProfiler {
profilers := map[int]Profiler{}
// L1 data
op := unix.PERF_COUNT_HW_CACHE_OP_READ
result := unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS
l1dataReadHit, err := NewL1DataProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[L1DataReadHit] = l1dataReadHit
}
op = unix.PERF_COUNT_HW_CACHE_OP_READ
result = unix.PERF_COUNT_HW_CACHE_RESULT_MISS
l1dataReadMiss, err := NewL1DataProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[L1DataReadMiss] = l1dataReadMiss
}
op = unix.PERF_COUNT_HW_CACHE_OP_WRITE
result = unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS
l1dataWriteHit, err := NewL1DataProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[L1DataWriteHit] = l1dataWriteHit
}
// L1 instruction
op = unix.PERF_COUNT_HW_CACHE_OP_READ
result = unix.PERF_COUNT_HW_CACHE_RESULT_MISS
l1InstrReadMiss, err := NewL1InstrProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[L1InstrReadMiss] = l1InstrReadMiss
}
// Last Level
op = unix.PERF_COUNT_HW_CACHE_OP_READ
result = unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS
llReadHit, err := NewLLCacheProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[LLReadHit] = llReadHit
}
op = unix.PERF_COUNT_HW_CACHE_OP_READ
result = unix.PERF_COUNT_HW_CACHE_RESULT_MISS
llReadMiss, err := NewLLCacheProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[LLReadMiss] = llReadMiss
}
op = unix.PERF_COUNT_HW_CACHE_OP_WRITE
result = unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS
llWriteHit, err := NewLLCacheProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[LLWriteHit] = llWriteHit
}
op = unix.PERF_COUNT_HW_CACHE_OP_WRITE
result = unix.PERF_COUNT_HW_CACHE_RESULT_MISS
llWriteMiss, err := NewLLCacheProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[LLWriteMiss] = llWriteMiss
}
// dTLB
op = unix.PERF_COUNT_HW_CACHE_OP_READ
result = unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS
dTLBReadHit, err := NewDataTLBProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[DataTLBReadHit] = dTLBReadHit
}
op = unix.PERF_COUNT_HW_CACHE_OP_READ
result = unix.PERF_COUNT_HW_CACHE_RESULT_MISS
dTLBReadMiss, err := NewDataTLBProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[DataTLBReadMiss] = dTLBReadMiss
}
op = unix.PERF_COUNT_HW_CACHE_OP_WRITE
result = unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS
dTLBWriteHit, err := NewDataTLBProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[DataTLBWriteHit] = dTLBWriteHit
}
op = unix.PERF_COUNT_HW_CACHE_OP_WRITE
result = unix.PERF_COUNT_HW_CACHE_RESULT_MISS
dTLBWriteMiss, err := NewDataTLBProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[DataTLBWriteMiss] = dTLBWriteMiss
}
// iTLB
op = unix.PERF_COUNT_HW_CACHE_OP_READ
result = unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS
iTLBReadHit, err := NewInstrTLBProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[InstrTLBReadHit] = iTLBReadHit
}
op = unix.PERF_COUNT_HW_CACHE_OP_READ
result = unix.PERF_COUNT_HW_CACHE_RESULT_MISS
iTLBReadMiss, err := NewInstrTLBProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[InstrTLBReadMiss] = iTLBReadMiss
}
// BPU
op = unix.PERF_COUNT_HW_CACHE_OP_READ
result = unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS
bpuReadHit, err := NewBPUProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[BPUReadHit] = bpuReadHit
}
op = unix.PERF_COUNT_HW_CACHE_OP_READ
result = unix.PERF_COUNT_HW_CACHE_RESULT_MISS
bpuReadMiss, err := NewBPUProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[BPUReadMiss] = bpuReadMiss
}
// Node
op = unix.PERF_COUNT_HW_CACHE_OP_READ
result = unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS
nodeReadHit, err := NewNodeCacheProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[NodeCacheReadHit] = nodeReadHit
}
op = unix.PERF_COUNT_HW_CACHE_OP_READ
result = unix.PERF_COUNT_HW_CACHE_RESULT_MISS
nodeReadMiss, err := NewNodeCacheProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[NodeCacheReadMiss] = nodeReadMiss
}
op = unix.PERF_COUNT_HW_CACHE_OP_WRITE
result = unix.PERF_COUNT_HW_CACHE_RESULT_ACCESS
nodeWriteHit, err := NewNodeCacheProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[NodeCacheWriteHit] = nodeWriteHit
}
op = unix.PERF_COUNT_HW_CACHE_OP_WRITE
result = unix.PERF_COUNT_HW_CACHE_RESULT_MISS
nodeWriteMiss, err := NewNodeCacheProfiler(pid, cpu, op, result, opts...)
if err == nil {
profilers[NodeCacheWriteMiss] = nodeWriteMiss
}
return &cacheProfiler{
profilers: profilers,
}
}
// Start is used to start the CacheProfiler, it will return an error if no
// profilers are configured.
func (p *cacheProfiler) Start() error {
if len(p.profilers) == 0 {
return ErrNoProfiler
}
var err error
for _, profiler := range p.profilers {
err = multierr.Append(err, profiler.Start())
}
return err
}
// Reset is used to reset the CacheProfiler.
func (p *cacheProfiler) Reset() error {
var err error
for _, profiler := range p.profilers {
err = multierr.Append(err, profiler.Reset())
}
return err
}
// Stop is used to reset the CacheProfiler.
func (p *cacheProfiler) Stop() error {
var err error
for _, profiler := range p.profilers {
err = multierr.Append(err, profiler.Stop())
}
return err
}
// Close is used to reset the CacheProfiler.
func (p *cacheProfiler) Close() error {
var err error
for _, profiler := range p.profilers {
err = multierr.Append(err, profiler.Close())
}
return err
}
// Profile is used to read the CacheProfiler CacheProfile it returns an
// error only if all profiles fail.
func (p *cacheProfiler) Profile() (*CacheProfile, error) {
var err error
cacheProfile := &CacheProfile{}
for profilerType, profiler := range p.profilers {
profileVal, err2 := profiler.Profile()
err = multierr.Append(err, err2)
if err2 == nil {
if cacheProfile.TimeEnabled == nil {
cacheProfile.TimeEnabled = &profileVal.TimeEnabled
}
if cacheProfile.TimeRunning == nil {
cacheProfile.TimeRunning = &profileVal.TimeRunning
}
switch {
// L1 data
case (profilerType ^ L1DataReadHit) == 0:
cacheProfile.L1DataReadHit = &profileVal.Value
case (profilerType ^ L1DataReadMiss) == 0:
cacheProfile.L1DataReadMiss = &profileVal.Value
case (profilerType ^ L1DataWriteHit) == 0:
cacheProfile.L1DataWriteHit = &profileVal.Value
// L1 instruction
case (profilerType ^ L1InstrReadMiss) == 0:
cacheProfile.L1InstrReadMiss = &profileVal.Value
// Last Level
case (profilerType ^ LLReadHit) == 0:
cacheProfile.LastLevelReadHit = &profileVal.Value
case (profilerType ^ LLReadMiss) == 0:
cacheProfile.LastLevelReadMiss = &profileVal.Value
case (profilerType ^ LLWriteHit) == 0:
cacheProfile.LastLevelWriteHit = &profileVal.Value
case (profilerType ^ LLWriteMiss) == 0:
cacheProfile.LastLevelWriteMiss = &profileVal.Value
// dTLB
case (profilerType ^ DataTLBReadHit) == 0:
cacheProfile.DataTLBReadHit = &profileVal.Value
case (profilerType ^ DataTLBReadMiss) == 0:
cacheProfile.DataTLBReadMiss = &profileVal.Value
case (profilerType ^ DataTLBWriteHit) == 0:
cacheProfile.DataTLBWriteHit = &profileVal.Value
case (profilerType ^ DataTLBWriteMiss) == 0:
cacheProfile.DataTLBWriteMiss = &profileVal.Value
// iTLB
case (profilerType ^ InstrTLBReadHit) == 0:
cacheProfile.InstrTLBReadHit = &profileVal.Value
case (profilerType ^ InstrTLBReadMiss) == 0:
cacheProfile.InstrTLBReadMiss = &profileVal.Value
// BPU
case (profilerType ^ BPUReadHit) == 0:
cacheProfile.BPUReadHit = &profileVal.Value
case (profilerType ^ BPUReadMiss) == 0:
cacheProfile.BPUReadMiss = &profileVal.Value
// node
case (profilerType ^ NodeCacheReadHit) == 0:
cacheProfile.NodeReadHit = &profileVal.Value
case (profilerType ^ NodeCacheReadMiss) == 0:
cacheProfile.NodeReadMiss = &profileVal.Value
case (profilerType ^ NodeCacheWriteHit) == 0:
cacheProfile.NodeWriteHit = &profileVal.Value
case (profilerType ^ NodeCacheWriteMiss) == 0:
cacheProfile.NodeWriteMiss = &profileVal.Value
}
}
}
if len(multierr.Errors(err)) == len(p.profilers) {
return nil, err
}
return cacheProfile, nil
}

98
vendor/github.com/hodgesds/perf-utils/events.go generated vendored Normal file
View file

@ -0,0 +1,98 @@
// +build linux
package perf
import (
"fmt"
"strconv"
"strings"
"unsafe"
"golang.org/x/sys/unix"
)
const (
// PERF_TYPE_TRACEPOINT is a kernel tracepoint.
PERF_TYPE_TRACEPOINT = 2
)
// AvailableEvents returns the list of available events.
func AvailableEvents() (map[string][]string, error) {
events := map[string][]string{}
rawEvents, err := fileToStrings(TracingDir + "/available_events")
// Events are colon delimited by type so parse the type and add sub
// events appropriately.
if err != nil {
return events, err
}
for _, rawEvent := range rawEvents {
splits := strings.Split(rawEvent, ":")
if len(splits) <= 1 {
continue
}
eventTypeEvents, found := events[splits[0]]
if found {
events[splits[0]] = append(eventTypeEvents, splits[1])
continue
}
events[splits[0]] = []string{splits[1]}
}
return events, err
}
// AvailableTracers returns the list of available tracers.
func AvailableTracers() ([]string, error) {
return fileToStrings(TracingDir + "/available_tracers")
}
// CurrentTracer returns the current tracer.
func CurrentTracer() (string, error) {
res, err := fileToStrings(TracingDir + "/current_tracer")
return res[0], err
}
// getTracepointConfig is used to get the configuration for a trace event.
func getTracepointConfig(kind, event string) (uint64, error) {
res, err := fileToStrings(TracingDir + fmt.Sprintf("/events/%s/%s/id", kind, event))
if err != nil {
return 0, err
}
return strconv.ParseUint(res[0], 10, 64)
}
// ProfileTracepoint is used to profile a kernel tracepoint event. Events can
// be listed with `perf list` for Tracepoint Events or in the
// /sys/kernel/debug/tracing/events directory with the kind being the directory
// and the event being the subdirectory.
func ProfileTracepoint(kind, event string, pid, cpu int, opts ...int) (BPFProfiler, error) {
config, err := getTracepointConfig(kind, event)
if err != nil {
return nil, err
}
eventAttr := &unix.PerfEventAttr{
Type: PERF_TYPE_TRACEPOINT,
Config: config,
Size: uint32(unsafe.Sizeof(unix.PerfEventAttr{})),
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
Sample_type: PERF_SAMPLE_IDENTIFIER,
}
var eventOps int
if len(opts) > 0 {
eventOps = opts[0]
}
fd, err := unix.PerfEventOpen(
eventAttr,
pid,
cpu,
-1,
eventOps,
)
if err != nil {
return nil, err
}
return &profiler{
fd: fd,
}, nil
}

102
vendor/github.com/hodgesds/perf-utils/fs_utils.go generated vendored Normal file
View file

@ -0,0 +1,102 @@
// +build linux
package perf
import (
"bufio"
"fmt"
"os"
"strings"
)
const (
// DebugFS is the filesystem type for debugfs.
DebugFS = "debugfs"
// TraceFS is the filesystem type for tracefs.
TraceFS = "tracefs"
// ProcMounts is the mount point for file systems in procfs.
ProcMounts = "/proc/mounts"
// PerfMaxStack is the mount point for the max perf event size.
PerfMaxStack = "/proc/sys/kernel/perf_event_max_stack"
// PerfMaxContexts is a sysfs mount that contains the max perf contexts.
PerfMaxContexts = "/proc/sys/kernel/perf_event_max_contexts_per_stack"
// SyscallsDir is a constant of the default tracing event syscalls directory.
SyscallsDir = "/sys/kernel/debug/tracing/events/syscalls/"
// TracingDir is a constant of the default tracing directory.
TracingDir = "/sys/kernel/debug/tracing"
)
var (
// ErrNoMount is when there is no such mount.
ErrNoMount = fmt.Errorf("no such mount")
)
// TraceFSMount returns the first found mount point of a tracefs file system.
func TraceFSMount() (string, error) {
mounts, err := GetFSMount(TraceFS)
if err != nil {
return "", err
}
if len(mounts) == 0 {
return "", ErrNoMount
}
return mounts[0], nil
}
// DebugFSMount returns the first found mount point of a debugfs file system.
func DebugFSMount() (string, error) {
mounts, err := GetFSMount(DebugFS)
if err != nil {
return "", err
}
if len(mounts) == 0 {
return "", ErrNoMount
}
return mounts[0], nil
}
// GetFSMount is a helper function to get a mount file system type.
func GetFSMount(mountType string) ([]string, error) {
mounts := []string{}
file, err := os.Open(ProcMounts)
if err != nil {
return mounts, err
}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
mountInfo := strings.Split(scanner.Text(), " ")
if len(mountInfo) > 3 && mountInfo[2] == mountType {
mounts = append(mounts, mountInfo[1])
}
}
if err := scanner.Err(); err != nil {
return mounts, err
}
return mounts, file.Close()
}
// fileToStrings is a helper method that reads a line line by line and returns
// a slice of strings.
func fileToStrings(path string) ([]string, error) {
res := []string{}
f, err := os.Open(path)
if err != nil {
return res, err
}
scanner := bufio.NewScanner(f)
for scanner.Scan() {
res = append(res, scanner.Text())
}
if err := scanner.Err(); err != nil {
return res, err
}
return res, nil
}

170
vendor/github.com/hodgesds/perf-utils/group_profiler.go generated vendored Normal file
View file

@ -0,0 +1,170 @@
// +build linux
package perf
import (
"encoding/binary"
"fmt"
"syscall"
"go.uber.org/multierr"
"golang.org/x/sys/unix"
)
// ErrNoLeader is returned when a leader of a GroupProfiler is not defined.
var ErrNoLeader = fmt.Errorf("No leader defined")
// GroupProfileValue is returned from a GroupProfiler.
type GroupProfileValue struct {
Events uint64
TimeEnabled uint64
TimeRunning uint64
Values []uint64
}
// GroupProfiler is used to setup a group profiler.
type GroupProfiler interface {
Start() error
Reset() error
Stop() error
Close() error
Profile() (*GroupProfileValue, error)
}
// groupProfiler implements the GroupProfiler interface.
type groupProfiler struct {
fds []int // leader is always element 0
}
// NewGroupProfiler returns a GroupProfiler.
func NewGroupProfiler(pid, cpu, opts int, eventAttrs ...unix.PerfEventAttr) (GroupProfiler, error) {
fds := make([]int, len(eventAttrs))
for i, eventAttr := range eventAttrs {
// common configs
eventAttr.Size = EventAttrSize
eventAttr.Sample_type = PERF_SAMPLE_IDENTIFIER
// Leader fd must be opened first
if i == 0 {
// leader specific configs
eventAttr.Bits = unix.PerfBitDisabled | unix.PerfBitExcludeHv
eventAttr.Read_format = unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED | unix.PERF_FORMAT_GROUP
fd, err := unix.PerfEventOpen(
&eventAttr,
pid,
cpu,
-1,
opts,
)
if err != nil {
return nil, err
}
fds[i] = fd
continue
}
// non leader configs
eventAttr.Read_format = unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED | unix.PERF_FORMAT_GROUP
eventAttr.Bits = unix.PerfBitExcludeHv
fd, err := unix.PerfEventOpen(
&eventAttr,
pid,
cpu,
fds[0],
opts,
)
if err != nil {
// cleanup any old Fds
for ii, fd2 := range fds {
if ii == i {
break
}
err = multierr.Append(err, unix.Close(fd2))
}
return nil, err
}
fds[i] = fd
}
return &groupProfiler{
fds: fds,
}, nil
}
// Start is used to start the GroupProfiler.
func (p *groupProfiler) Start() error {
if len(p.fds) == 0 {
return ErrNoLeader
}
return unix.IoctlSetInt(p.fds[0], unix.PERF_EVENT_IOC_ENABLE, 0)
}
// Reset is used to reset the GroupProfiler.
func (p *groupProfiler) Reset() error {
if len(p.fds) == 0 {
return ErrNoLeader
}
return unix.IoctlSetInt(p.fds[0], unix.PERF_EVENT_IOC_RESET, 0)
}
// Stop is used to stop the GroupProfiler.
func (p *groupProfiler) Stop() error {
if len(p.fds) == 0 {
return ErrNoLeader
}
return unix.IoctlSetInt(p.fds[0], unix.PERF_EVENT_IOC_DISABLE, 0)
}
// Close is used to close the GroupProfiler.
func (p *groupProfiler) Close() error {
var err error
for _, fd := range p.fds {
err = multierr.Append(err, unix.Close(fd))
}
return err
}
// Profile is used to return the GroupProfileValue of the GroupProfiler.
func (p *groupProfiler) Profile() (*GroupProfileValue, error) {
nEvents := len(p.fds)
if nEvents == 0 {
return nil, ErrNoLeader
}
// read format of the raw event looks like this:
/*
struct read_format {
u64 nr; // The number of events /
u64 time_enabled; // if PERF_FORMAT_TOTAL_TIME_ENABLED
u64 time_running; // if PERF_FORMAT_TOTAL_TIME_RUNNING
struct {
u64 value; // The value of the event
u64 id; // if PERF_FORMAT_ID
} values[nr];
};
*/
buf := make([]byte, 24+8*nEvents)
_, err := syscall.Read(p.fds[0], buf)
if err != nil {
return nil, err
}
val := &GroupProfileValue{
Events: binary.LittleEndian.Uint64(buf[0:8]),
TimeEnabled: binary.LittleEndian.Uint64(buf[8:16]),
TimeRunning: binary.LittleEndian.Uint64(buf[16:24]),
Values: make([]uint64, len(p.fds)),
}
offset := 24
for i := range p.fds {
val.Values[i] = binary.LittleEndian.Uint64(buf[offset : offset+8])
offset += 8
}
return val, nil
}

View file

@ -0,0 +1,157 @@
// +build linux
package perf
import (
"go.uber.org/multierr"
"golang.org/x/sys/unix"
)
type hardwareProfiler struct {
// map of perf counter type to file descriptor
profilers map[int]Profiler
}
// NewHardwareProfiler returns a new hardware profiler.
func NewHardwareProfiler(pid, cpu int, opts ...int) HardwareProfiler {
profilers := map[int]Profiler{}
cpuCycleProfiler, err := NewCPUCycleProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_HW_CPU_CYCLES] = cpuCycleProfiler
}
instrProfiler, err := NewInstrProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_HW_INSTRUCTIONS] = instrProfiler
}
cacheRefProfiler, err := NewCacheRefProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_HW_CACHE_REFERENCES] = cacheRefProfiler
}
cacheMissesProfiler, err := NewCacheMissesProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_HW_CACHE_MISSES] = cacheMissesProfiler
}
branchInstrProfiler, err := NewBranchInstrProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = branchInstrProfiler
}
branchMissesProfiler, err := NewBranchMissesProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_HW_BRANCH_MISSES] = branchMissesProfiler
}
busCyclesProfiler, err := NewBusCyclesProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_HW_BUS_CYCLES] = busCyclesProfiler
}
stalledCyclesFrontProfiler, err := NewStalledCyclesFrontProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = stalledCyclesFrontProfiler
}
stalledCyclesBackProfiler, err := NewStalledCyclesBackProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = stalledCyclesBackProfiler
}
refCPUCyclesProfiler, err := NewRefCPUCyclesProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_HW_REF_CPU_CYCLES] = refCPUCyclesProfiler
}
return &hardwareProfiler{
profilers: profilers,
}
}
// Start is used to start the HardwareProfiler.
func (p *hardwareProfiler) Start() error {
if len(p.profilers) == 0 {
return ErrNoProfiler
}
var err error
for _, profiler := range p.profilers {
err = multierr.Append(err, profiler.Start())
}
return err
}
// Reset is used to reset the HardwareProfiler.
func (p *hardwareProfiler) Reset() error {
var err error
for _, profiler := range p.profilers {
err = multierr.Append(err, profiler.Reset())
}
return err
}
// Stop is used to reset the HardwareProfiler.
func (p *hardwareProfiler) Stop() error {
var err error
for _, profiler := range p.profilers {
err = multierr.Append(err, profiler.Stop())
}
return err
}
// Close is used to reset the HardwareProfiler.
func (p *hardwareProfiler) Close() error {
var err error
for _, profiler := range p.profilers {
err = multierr.Append(err, profiler.Close())
}
return err
}
// Profile is used to read the HardwareProfiler HardwareProfile it returns an
// error only if all profiles fail.
func (p *hardwareProfiler) Profile() (*HardwareProfile, error) {
var err error
hwProfile := &HardwareProfile{}
for profilerType, profiler := range p.profilers {
profileVal, err2 := profiler.Profile()
err = multierr.Append(err, err2)
if err2 == nil {
if hwProfile.TimeEnabled == nil {
hwProfile.TimeEnabled = &profileVal.TimeEnabled
}
if hwProfile.TimeRunning == nil {
hwProfile.TimeRunning = &profileVal.TimeRunning
}
switch profilerType {
case unix.PERF_COUNT_HW_CPU_CYCLES:
hwProfile.CPUCycles = &profileVal.Value
case unix.PERF_COUNT_HW_INSTRUCTIONS:
hwProfile.Instructions = &profileVal.Value
case unix.PERF_COUNT_HW_CACHE_REFERENCES:
hwProfile.CacheRefs = &profileVal.Value
case unix.PERF_COUNT_HW_CACHE_MISSES:
hwProfile.CacheMisses = &profileVal.Value
case unix.PERF_COUNT_HW_BRANCH_INSTRUCTIONS:
hwProfile.BranchInstr = &profileVal.Value
case unix.PERF_COUNT_HW_BRANCH_MISSES:
hwProfile.BranchMisses = &profileVal.Value
case unix.PERF_COUNT_HW_BUS_CYCLES:
hwProfile.BusCycles = &profileVal.Value
case unix.PERF_COUNT_HW_STALLED_CYCLES_FRONTEND:
hwProfile.StalledCyclesFrontend = &profileVal.Value
case unix.PERF_COUNT_HW_STALLED_CYCLES_BACKEND:
hwProfile.StalledCyclesBackend = &profileVal.Value
case unix.PERF_COUNT_HW_REF_CPU_CYCLES:
hwProfile.RefCPUCycles = &profileVal.Value
}
}
}
if len(multierr.Errors(err)) == len(p.profilers) {
return nil, err
}
return hwProfile, nil
}

View file

@ -0,0 +1,507 @@
// +build linux
package perf
import (
"encoding/binary"
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/unix"
)
const (
// PERF_SAMPLE_IDENTIFIER is not defined in x/sys/unix.
PERF_SAMPLE_IDENTIFIER = 1 << 16
// PERF_IOC_FLAG_GROUP is not defined in x/sys/unix.
PERF_IOC_FLAG_GROUP = 1 << 0
)
var (
// ErrNoProfiler is returned when no profiler is available for profiling.
ErrNoProfiler = fmt.Errorf("No profiler available")
)
// Profiler is a profiler.
type Profiler interface {
Start() error
Reset() error
Stop() error
Close() error
Profile() (*ProfileValue, error)
}
// HardwareProfiler is a hardware profiler.
type HardwareProfiler interface {
Start() error
Reset() error
Stop() error
Close() error
Profile() (*HardwareProfile, error)
}
// HardwareProfile is returned by a HardwareProfiler. Depending on kernel
// configuration some fields may return nil.
type HardwareProfile struct {
CPUCycles *uint64 `json:"cpu_cycles,omitempty"`
Instructions *uint64 `json:"instructions,omitempty"`
CacheRefs *uint64 `json:"cache_refs,omitempty"`
CacheMisses *uint64 `json:"cache_misses,omitempty"`
BranchInstr *uint64 `json:"branch_instr,omitempty"`
BranchMisses *uint64 `json:"branch_misses,omitempty"`
BusCycles *uint64 `json:"bus_cycles,omitempty"`
StalledCyclesFrontend *uint64 `json:"stalled_cycles_frontend,omitempty"`
StalledCyclesBackend *uint64 `json:"stalled_cycles_backend,omitempty"`
RefCPUCycles *uint64 `json:"ref_cpu_cycles,omitempty"`
TimeEnabled *uint64 `json:"time_enabled,omitempty"`
TimeRunning *uint64 `json:"time_running,omitempty"`
}
// SoftwareProfiler is a software profiler.
type SoftwareProfiler interface {
Start() error
Reset() error
Stop() error
Close() error
Profile() (*SoftwareProfile, error)
}
// SoftwareProfile is returned by a SoftwareProfiler.
type SoftwareProfile struct {
CPUClock *uint64 `json:"cpu_clock,omitempty"`
TaskClock *uint64 `json:"task_clock,omitempty"`
PageFaults *uint64 `json:"page_faults,omitempty"`
ContextSwitches *uint64 `json:"context_switches,omitempty"`
CPUMigrations *uint64 `json:"cpu_migrations,omitempty"`
MinorPageFaults *uint64 `json:"minor_page_faults,omitempty"`
MajorPageFaults *uint64 `json:"major_page_faults,omitempty"`
AlignmentFaults *uint64 `json:"alignment_faults,omitempty"`
EmulationFaults *uint64 `json:"emulation_faults,omitempty"`
TimeEnabled *uint64 `json:"time_enabled,omitempty"`
TimeRunning *uint64 `json:"time_running,omitempty"`
}
// CacheProfiler is a cache profiler.
type CacheProfiler interface {
Start() error
Reset() error
Stop() error
Close() error
Profile() (*CacheProfile, error)
}
// CacheProfile is returned by a CacheProfiler.
type CacheProfile struct {
L1DataReadHit *uint64 `json:"l1_data_read_hit,omitempty"`
L1DataReadMiss *uint64 `json:"l1_data_read_miss,omitempty"`
L1DataWriteHit *uint64 `json:"l1_data_write_hit,omitempty"`
L1InstrReadMiss *uint64 `json:"l1_instr_read_miss,omitempty"`
LastLevelReadHit *uint64 `json:"last_level_read_hit,omitempty"`
LastLevelReadMiss *uint64 `json:"last_level_read_miss,omitempty"`
LastLevelWriteHit *uint64 `json:"last_level_write_hit,omitempty"`
LastLevelWriteMiss *uint64 `json:"last_level_write_miss,omitempty"`
DataTLBReadHit *uint64 `json:"data_tlb_read_hit,omitempty"`
DataTLBReadMiss *uint64 `json:"data_tlb_read_miss,omitempty"`
DataTLBWriteHit *uint64 `json:"data_tlb_write_hit,omitempty"`
DataTLBWriteMiss *uint64 `json:"data_tlb_write_miss,omitempty"`
InstrTLBReadHit *uint64 `json:"instr_tlb_read_hit,omitempty"`
InstrTLBReadMiss *uint64 `json:"instr_tlb_read_miss,omitempty"`
BPUReadHit *uint64 `json:"bpu_read_hit,omitempty"`
BPUReadMiss *uint64 `json:"bpu_read_miss,omitempty"`
NodeReadHit *uint64 `json:"node_read_hit,omitempty"`
NodeReadMiss *uint64 `json:"node_read_miss,omitempty"`
NodeWriteHit *uint64 `json:"node_write_hit,omitempty"`
NodeWriteMiss *uint64 `json:"node_write_miss,omitempty"`
TimeEnabled *uint64 `json:"time_enabled,omitempty"`
TimeRunning *uint64 `json:"time_running,omitempty"`
}
// ProfileValue is a value returned by a profiler.
type ProfileValue struct {
Value uint64
TimeEnabled uint64
TimeRunning uint64
}
// profiler is used to profile a process.
type profiler struct {
fd int
}
// NewProfiler creates a new hardware profiler. It does not support grouping.
func NewProfiler(profilerType uint32, config uint64, pid, cpu int, opts ...int) (Profiler, error) {
eventAttr := &unix.PerfEventAttr{
Type: profilerType,
Config: config,
Size: uint32(unsafe.Sizeof(unix.PerfEventAttr{})),
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeHv | unix.PerfBitInherit,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
Sample_type: PERF_SAMPLE_IDENTIFIER,
}
var eventOps int
if len(opts) > 0 {
eventOps = opts[0]
}
fd, err := unix.PerfEventOpen(
eventAttr,
pid,
cpu,
-1,
eventOps,
)
if err != nil {
return nil, err
}
return &profiler{
fd: fd,
}, nil
}
// NewCPUCycleProfiler returns a Profiler that profiles CPU cycles.
func NewCPUCycleProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HARDWARE,
unix.PERF_COUNT_HW_CPU_CYCLES,
pid,
cpu,
opts...,
)
}
// NewInstrProfiler returns a Profiler that profiles CPU instructions.
func NewInstrProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HARDWARE,
unix.PERF_COUNT_HW_INSTRUCTIONS,
pid,
cpu,
opts...,
)
}
// NewCacheRefProfiler returns a Profiler that profiles cache references.
func NewCacheRefProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HARDWARE,
unix.PERF_COUNT_HW_CACHE_REFERENCES,
pid,
cpu,
opts...,
)
}
// NewCacheMissesProfiler returns a Profiler that profiles cache misses.
func NewCacheMissesProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HARDWARE,
unix.PERF_COUNT_HW_CACHE_MISSES,
pid,
cpu,
opts...,
)
}
// NewBranchInstrProfiler returns a Profiler that profiles branch instructions.
func NewBranchInstrProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HARDWARE,
unix.PERF_COUNT_HW_BRANCH_INSTRUCTIONS,
pid,
cpu,
opts...,
)
}
// NewBranchMissesProfiler returns a Profiler that profiles branch misses.
func NewBranchMissesProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HARDWARE,
unix.PERF_COUNT_HW_BRANCH_MISSES,
pid,
cpu,
opts...,
)
}
// NewBusCyclesProfiler returns a Profiler that profiles bus cycles.
func NewBusCyclesProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HARDWARE,
unix.PERF_COUNT_HW_BUS_CYCLES,
pid,
cpu,
opts...,
)
}
// NewStalledCyclesFrontProfiler returns a Profiler that profiles stalled
// frontend cycles.
func NewStalledCyclesFrontProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HARDWARE,
unix.PERF_COUNT_HW_STALLED_CYCLES_FRONTEND,
pid,
cpu,
opts...,
)
}
// NewStalledCyclesBackProfiler returns a Profiler that profiles stalled
// backend cycles.
func NewStalledCyclesBackProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HARDWARE,
unix.PERF_COUNT_HW_STALLED_CYCLES_BACKEND,
pid,
cpu,
opts...,
)
}
// NewRefCPUCyclesProfiler returns a Profiler that profiles CPU cycles, it
// is not affected by frequency scaling.
func NewRefCPUCyclesProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HARDWARE,
unix.PERF_COUNT_HW_REF_CPU_CYCLES,
pid,
cpu,
opts...,
)
}
// NewCPUClockProfiler returns a Profiler that profiles CPU clock speed.
func NewCPUClockProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_SOFTWARE,
unix.PERF_COUNT_SW_CPU_CLOCK,
pid,
cpu,
opts...,
)
}
// NewTaskClockProfiler returns a Profiler that profiles clock count of the
// running task.
func NewTaskClockProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_SOFTWARE,
unix.PERF_COUNT_SW_TASK_CLOCK,
pid,
cpu,
opts...,
)
}
// NewPageFaultProfiler returns a Profiler that profiles the number of page
// faults.
func NewPageFaultProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_SOFTWARE,
unix.PERF_COUNT_SW_PAGE_FAULTS,
pid,
cpu,
opts...,
)
}
// NewCtxSwitchesProfiler returns a Profiler that profiles the number of context
// switches.
func NewCtxSwitchesProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_SOFTWARE,
unix.PERF_COUNT_SW_CONTEXT_SWITCHES,
pid,
cpu,
opts...,
)
}
// NewCPUMigrationsProfiler returns a Profiler that profiles the number of times
// the process has migrated to a new CPU.
func NewCPUMigrationsProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_SOFTWARE,
unix.PERF_COUNT_SW_CPU_MIGRATIONS,
pid,
cpu,
opts...,
)
}
// NewMinorFaultsProfiler returns a Profiler that profiles the number of minor
// page faults.
func NewMinorFaultsProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_SOFTWARE,
unix.PERF_COUNT_SW_PAGE_FAULTS_MIN,
pid,
cpu,
opts...,
)
}
// NewMajorFaultsProfiler returns a Profiler that profiles the number of major
// page faults.
func NewMajorFaultsProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_SOFTWARE,
unix.PERF_COUNT_SW_PAGE_FAULTS_MAJ,
pid,
cpu,
opts...,
)
}
// NewAlignFaultsProfiler returns a Profiler that profiles the number of
// alignment faults.
func NewAlignFaultsProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_SOFTWARE,
unix.PERF_COUNT_SW_ALIGNMENT_FAULTS,
pid,
cpu,
opts...,
)
}
// NewEmulationFaultsProfiler returns a Profiler that profiles the number of
// alignment faults.
func NewEmulationFaultsProfiler(pid, cpu int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_SOFTWARE,
unix.PERF_COUNT_SW_EMULATION_FAULTS,
pid,
cpu,
opts...,
)
}
// NewL1DataProfiler returns a Profiler that profiles L1 cache data.
func NewL1DataProfiler(pid, cpu, op, result int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HW_CACHE,
uint64((unix.PERF_COUNT_HW_CACHE_L1D)|(op<<8)|(result<<16)),
pid,
cpu,
opts...,
)
}
// NewL1InstrProfiler returns a Profiler that profiles L1 instruction data.
func NewL1InstrProfiler(pid, cpu, op, result int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HW_CACHE,
uint64((unix.PERF_COUNT_HW_CACHE_L1I)|(op<<8)|(result<<16)),
pid,
cpu,
opts...,
)
}
// NewLLCacheProfiler returns a Profiler that profiles last level cache.
func NewLLCacheProfiler(pid, cpu, op, result int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HW_CACHE,
uint64((unix.PERF_COUNT_HW_CACHE_LL)|(op<<8)|(result<<16)),
pid,
cpu,
opts...,
)
}
// NewDataTLBProfiler returns a Profiler that profiles the data TLB.
func NewDataTLBProfiler(pid, cpu, op, result int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HW_CACHE,
uint64((unix.PERF_COUNT_HW_CACHE_DTLB)|(op<<8)|(result<<16)),
pid,
cpu,
opts...,
)
}
// NewInstrTLBProfiler returns a Profiler that profiles the instruction TLB.
func NewInstrTLBProfiler(pid, cpu, op, result int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HW_CACHE,
uint64((unix.PERF_COUNT_HW_CACHE_ITLB)|(op<<8)|(result<<16)),
pid,
cpu,
opts...,
)
}
// NewBPUProfiler returns a Profiler that profiles the BPU (branch prediction unit).
func NewBPUProfiler(pid, cpu, op, result int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HW_CACHE,
uint64((unix.PERF_COUNT_HW_CACHE_BPU)|(op<<8)|(result<<16)),
pid,
cpu,
opts...,
)
}
// NewNodeCacheProfiler returns a Profiler that profiles the node cache accesses.
func NewNodeCacheProfiler(pid, cpu, op, result int, opts ...int) (Profiler, error) {
return NewProfiler(
unix.PERF_TYPE_HW_CACHE,
uint64((unix.PERF_COUNT_HW_CACHE_NODE)|(op<<8)|(result<<16)),
pid,
cpu,
opts...,
)
}
// Reset is used to reset the counters of the profiler.
func (p *profiler) Reset() error {
return unix.IoctlSetInt(p.fd, unix.PERF_EVENT_IOC_RESET, 0)
}
// Start is used to Start the profiler.
func (p *profiler) Start() error {
return unix.IoctlSetInt(p.fd, unix.PERF_EVENT_IOC_ENABLE, 0)
}
// Stop is used to stop the profiler.
func (p *profiler) Stop() error {
return unix.IoctlSetInt(p.fd, unix.PERF_EVENT_IOC_DISABLE, 0)
}
// Profile returns the current Profile.
func (p *profiler) Profile() (*ProfileValue, error) {
// The underlying struct that gets read from the profiler looks like:
/*
struct read_format {
u64 value; // The value of the event
u64 time_enabled; // if PERF_FORMAT_TOTAL_TIME_ENABLED
u64 time_running; // if PERF_FORMAT_TOTAL_TIME_RUNNING
u64 id; // if PERF_FORMAT_ID
};
*/
// read 24 bytes since PERF_FORMAT_TOTAL_TIME_ENABLED and
// PERF_FORMAT_TOTAL_TIME_RUNNING are always set.
// XXX: allow profile ids?
buf := make([]byte, 24, 24)
_, err := syscall.Read(p.fd, buf)
if err != nil {
return nil, err
}
return &ProfileValue{
Value: binary.LittleEndian.Uint64(buf[0:8]),
TimeEnabled: binary.LittleEndian.Uint64(buf[8:16]),
TimeRunning: binary.LittleEndian.Uint64(buf[16:24]),
}, nil
}
// Close is used to close the perf context.
func (p *profiler) Close() error {
return unix.Close(p.fd)
}

View file

@ -0,0 +1,151 @@
// +build linux
package perf
import (
"go.uber.org/multierr"
"golang.org/x/sys/unix"
)
type softwareProfiler struct {
// map of perf counter type to file descriptor
profilers map[int]Profiler
}
// NewSoftwareProfiler returns a new software profiler.
func NewSoftwareProfiler(pid, cpu int, opts ...int) SoftwareProfiler {
profilers := map[int]Profiler{}
cpuClockProfiler, err := NewCPUClockProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_SW_CPU_CLOCK] = cpuClockProfiler
}
taskClockProfiler, err := NewTaskClockProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_SW_TASK_CLOCK] = taskClockProfiler
}
pageFaultProfiler, err := NewPageFaultProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_SW_PAGE_FAULTS] = pageFaultProfiler
}
ctxSwitchesProfiler, err := NewCtxSwitchesProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_SW_CONTEXT_SWITCHES] = ctxSwitchesProfiler
}
cpuMigrationsProfiler, err := NewCPUMigrationsProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_SW_CPU_MIGRATIONS] = cpuMigrationsProfiler
}
minorFaultProfiler, err := NewMinorFaultsProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_SW_PAGE_FAULTS_MIN] = minorFaultProfiler
}
majorFaultProfiler, err := NewMajorFaultsProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_SW_PAGE_FAULTS_MAJ] = majorFaultProfiler
}
alignFaultsFrontProfiler, err := NewAlignFaultsProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_SW_ALIGNMENT_FAULTS] = alignFaultsFrontProfiler
}
emuFaultProfiler, err := NewEmulationFaultsProfiler(pid, cpu, opts...)
if err == nil {
profilers[unix.PERF_COUNT_SW_EMULATION_FAULTS] = emuFaultProfiler
}
return &softwareProfiler{
profilers: profilers,
}
}
// Start is used to start the SoftwareProfiler.
func (p *softwareProfiler) Start() error {
if len(p.profilers) == 0 {
return ErrNoProfiler
}
var err error
for _, profiler := range p.profilers {
err = multierr.Append(err, profiler.Start())
}
return err
}
// Reset is used to reset the SoftwareProfiler.
func (p *softwareProfiler) Reset() error {
var err error
for _, profiler := range p.profilers {
err = multierr.Append(err, profiler.Reset())
}
return err
}
// Stop is used to reset the SoftwareProfiler.
func (p *softwareProfiler) Stop() error {
var err error
for _, profiler := range p.profilers {
err = multierr.Append(err, profiler.Stop())
}
return err
}
// Close is used to reset the SoftwareProfiler.
func (p *softwareProfiler) Close() error {
var err error
for _, profiler := range p.profilers {
err = multierr.Append(err, profiler.Close())
}
return err
}
// Profile is used to read the SoftwareProfiler SoftwareProfile it returns an
// error only if all profiles fail.
func (p *softwareProfiler) Profile() (*SoftwareProfile, error) {
var err error
swProfile := &SoftwareProfile{}
for profilerType, profiler := range p.profilers {
profileVal, err2 := profiler.Profile()
err = multierr.Append(err, err2)
if err2 == nil {
if swProfile.TimeEnabled == nil {
swProfile.TimeEnabled = &profileVal.TimeEnabled
}
if swProfile.TimeRunning == nil {
swProfile.TimeRunning = &profileVal.TimeRunning
}
switch profilerType {
case unix.PERF_COUNT_SW_CPU_CLOCK:
swProfile.CPUClock = &profileVal.Value
case unix.PERF_COUNT_SW_TASK_CLOCK:
swProfile.TaskClock = &profileVal.Value
case unix.PERF_COUNT_SW_PAGE_FAULTS:
swProfile.PageFaults = &profileVal.Value
case unix.PERF_COUNT_SW_CONTEXT_SWITCHES:
swProfile.ContextSwitches = &profileVal.Value
case unix.PERF_COUNT_SW_CPU_MIGRATIONS:
swProfile.CPUMigrations = &profileVal.Value
case unix.PERF_COUNT_SW_PAGE_FAULTS_MIN:
swProfile.MinorPageFaults = &profileVal.Value
case unix.PERF_COUNT_SW_PAGE_FAULTS_MAJ:
swProfile.MajorPageFaults = &profileVal.Value
case unix.PERF_COUNT_SW_ALIGNMENT_FAULTS:
swProfile.AlignmentFaults = &profileVal.Value
case unix.PERF_COUNT_SW_EMULATION_FAULTS:
swProfile.EmulationFaults = &profileVal.Value
default:
}
}
}
if len(multierr.Errors(err)) == len(p.profilers) {
return nil, err
}
return swProfile, nil
}

681
vendor/github.com/hodgesds/perf-utils/utils.go generated vendored Normal file
View file

@ -0,0 +1,681 @@
// +build linux
package perf
import (
"encoding/binary"
"runtime"
"syscall"
"unsafe"
"golang.org/x/sys/unix"
)
var (
// EventAttrSize is the size of a PerfEventAttr
EventAttrSize = uint32(unsafe.Sizeof(unix.PerfEventAttr{}))
)
// profileFn is a helper function to profile a function.
func profileFn(eventAttr *unix.PerfEventAttr, f func() error) (*ProfileValue, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
fd, err := unix.PerfEventOpen(
eventAttr,
unix.Gettid(),
-1,
-1,
0,
)
if err != nil {
return nil, err
}
if err := unix.IoctlSetInt(fd, unix.PERF_EVENT_IOC_RESET, 0); err != nil {
return nil, err
}
if err := unix.IoctlSetInt(fd, unix.PERF_EVENT_IOC_ENABLE, 0); err != nil {
return nil, err
}
if err := f(); err != nil {
return nil, err
}
if err := unix.IoctlSetInt(fd, unix.PERF_EVENT_IOC_DISABLE, 0); err != nil {
return nil, err
}
buf := make([]byte, 24)
if _, err := syscall.Read(fd, buf); err != nil {
return nil, err
}
return &ProfileValue{
Value: binary.LittleEndian.Uint64(buf[0:8]),
TimeEnabled: binary.LittleEndian.Uint64(buf[8:16]),
TimeRunning: binary.LittleEndian.Uint64(buf[16:24]),
}, unix.Close(fd)
}
// CPUInstructions is used to profile a function and return the number of CPU instructions.
// Note that it will call runtime.LockOSThread to ensure accurate profilng.
func CPUInstructions(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_HARDWARE,
Config: unix.PERF_COUNT_HW_INSTRUCTIONS,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// CPUInstructionsEventAttr returns a unix.PerfEventAttr configured for CPUInstructions.
func CPUInstructionsEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_HARDWARE,
Config: unix.PERF_COUNT_HW_INSTRUCTIONS,
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// CPUCycles is used to profile a function and return the number of CPU cycles.
// Note that it will call runtime.LockOSThread to ensure accurate profilng.
func CPUCycles(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_HARDWARE,
Config: unix.PERF_COUNT_HW_CPU_CYCLES,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// CPUCyclesEventAttr returns a unix.PerfEventAttr configured for CPUCycles.
func CPUCyclesEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_HARDWARE,
Config: unix.PERF_COUNT_HW_CPU_CYCLES,
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// CacheRef is used to profile a function and return the number of cache
// references. Note that it will call runtime.LockOSThread to ensure accurate
// profilng.
func CacheRef(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_HARDWARE,
Config: unix.PERF_COUNT_HW_CACHE_REFERENCES,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// CacheRefEventAttr returns a unix.PerfEventAttr configured for CacheRef.
func CacheRefEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_HARDWARE,
Config: unix.PERF_COUNT_HW_CACHE_REFERENCES,
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// CacheMiss is used to profile a function and return the number of cache
// misses. Note that it will call runtime.LockOSThread to ensure accurate
// profilng.
func CacheMiss(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_HARDWARE,
Config: unix.PERF_COUNT_HW_CACHE_MISSES,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// CacheMissEventAttr returns a unix.PerfEventAttr configured for CacheMisses.
func CacheMissEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_HARDWARE,
Config: unix.PERF_COUNT_HW_CACHE_MISSES,
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// BusCycles is used to profile a function and return the number of bus
// cycles. Note that it will call runtime.LockOSThread to ensure accurate
// profilng.
func BusCycles(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_HARDWARE,
Config: unix.PERF_COUNT_HW_BUS_CYCLES,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// BusCyclesEventAttr returns a unix.PerfEventAttr configured for BusCycles.
func BusCyclesEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_HARDWARE,
Config: unix.PERF_COUNT_HW_BUS_CYCLES,
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// StalledFrontendCycles is used to profile a function and return the number of
// stalled frontend cycles. Note that it will call runtime.LockOSThread to
// ensure accurate profilng.
func StalledFrontendCycles(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_HARDWARE,
Config: unix.PERF_COUNT_HW_STALLED_CYCLES_FRONTEND,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// StalledFrontendCyclesEventAttr returns a unix.PerfEventAttr configured for StalledFrontendCycles.
func StalledFrontendCyclesEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_HARDWARE,
Config: unix.PERF_COUNT_HW_STALLED_CYCLES_FRONTEND,
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// StalledBackendCycles is used to profile a function and return the number of
// stalled backend cycles. Note that it will call runtime.LockOSThread to
// ensure accurate profilng.
func StalledBackendCycles(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_HARDWARE,
Config: unix.PERF_COUNT_HW_STALLED_CYCLES_BACKEND,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// StalledBackendCyclesEventAttr returns a unix.PerfEventAttr configured for StalledBackendCycles.
func StalledBackendCyclesEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_HARDWARE,
Config: unix.PERF_COUNT_HW_STALLED_CYCLES_BACKEND,
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// CPURefCycles is used to profile a function and return the number of CPU
// references cycles which are not affected by frequency scaling. Note that it
// will call runtime.LockOSThread to ensure accurate profilng.
func CPURefCycles(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_HARDWARE,
Config: unix.PERF_COUNT_HW_REF_CPU_CYCLES,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// CPURefCyclesEventAttr returns a unix.PerfEventAttr configured for CPURefCycles.
func CPURefCyclesEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_HARDWARE,
Config: unix.PERF_COUNT_HW_REF_CPU_CYCLES,
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// CPUClock is used to profile a function and return the CPU clock timer. Note
// that it will call runtime.LockOSThread to ensure accurate profilng.
func CPUClock(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_CPU_CLOCK,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// CPUClockEventAttr returns a unix.PerfEventAttr configured for CPUClock.
func CPUClockEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_CPU_CLOCK,
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// CPUTaskClock is used to profile a function and return the CPU clock timer
// for the running task. Note that it will call runtime.LockOSThread to ensure
// accurate profilng.
func CPUTaskClock(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_TASK_CLOCK,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// CPUTaskClockEventAttr returns a unix.PerfEventAttr configured for CPUTaskClock.
func CPUTaskClockEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_TASK_CLOCK,
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// PageFaults is used to profile a function and return the number of page
// faults. Note that it will call runtime.LockOSThread to ensure accurate
// profilng.
func PageFaults(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_PAGE_FAULTS,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// PageFaultsEventAttr returns a unix.PerfEventAttr configured for PageFaults.
func PageFaultsEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_PAGE_FAULTS,
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// ContextSwitches is used to profile a function and return the number of
// context switches. Note that it will call runtime.LockOSThread to ensure
// accurate profilng.
func ContextSwitches(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_CONTEXT_SWITCHES,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// ContextSwitchesEventAttr returns a unix.PerfEventAttr configured for ContextSwitches.
func ContextSwitchesEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_CONTEXT_SWITCHES,
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// CPUMigrations is used to profile a function and return the number of times
// the thread has been migrated to a new CPU. Note that it will call
// runtime.LockOSThread to ensure accurate profilng.
func CPUMigrations(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_CPU_MIGRATIONS,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// CPUMigrationsEventAttr returns a unix.PerfEventAttr configured for CPUMigrations.
func CPUMigrationsEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_CPU_MIGRATIONS,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// MinorPageFaults is used to profile a function and return the number of minor
// page faults. Note that it will call runtime.LockOSThread to ensure accurate
// profilng.
func MinorPageFaults(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_PAGE_FAULTS_MIN,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// MinorPageFaultsEventAttr returns a unix.PerfEventAttr configured for MinorPageFaults.
func MinorPageFaultsEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_PAGE_FAULTS_MIN,
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// MajorPageFaults is used to profile a function and return the number of major
// page faults. Note that it will call runtime.LockOSThread to ensure accurate
// profilng.
func MajorPageFaults(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_PAGE_FAULTS_MAJ,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// MajorPageFaultsEventAttr returns a unix.PerfEventAttr configured for MajorPageFaults.
func MajorPageFaultsEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_PAGE_FAULTS_MAJ,
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// AlignmentFaults is used to profile a function and return the number of alignment
// faults. Note that it will call runtime.LockOSThread to ensure accurate
// profilng.
func AlignmentFaults(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_ALIGNMENT_FAULTS,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// AlignmentFaultsEventAttr returns a unix.PerfEventAttr configured for AlignmentFaults.
func AlignmentFaultsEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_ALIGNMENT_FAULTS,
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// EmulationFaults is used to profile a function and return the number of emulation
// faults. Note that it will call runtime.LockOSThread to ensure accurate
// profilng.
func EmulationFaults(f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_EMULATION_FAULTS,
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// EmulationFaultsEventAttr returns a unix.PerfEventAttr configured for EmulationFaults.
func EmulationFaultsEventAttr() unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_SOFTWARE,
Config: unix.PERF_COUNT_SW_EMULATION_FAULTS,
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// L1Data is used to profile a function and the L1 data cache faults. Use
// PERF_COUNT_HW_CACHE_OP_READ, PERF_COUNT_HW_CACHE_OP_WRITE, or
// PERF_COUNT_HW_CACHE_OP_PREFETCH for the opt and
// PERF_COUNT_HW_CACHE_RESULT_ACCESS or PERF_COUNT_HW_CACHE_RESULT_MISS for the
// result. Note that it will call runtime.LockOSThread to ensure accurate
// profilng.
func L1Data(op, result int, f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_HW_CACHE,
Config: uint64((unix.PERF_COUNT_HW_CACHE_L1D) | (op << 8) | (result << 16)),
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// L1DataEventAttr returns a unix.PerfEventAttr configured for L1Data.
func L1DataEventAttr(op, result int) unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_HW_CACHE,
Config: uint64((unix.PERF_COUNT_HW_CACHE_L1D) | (op << 8) | (result << 16)),
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// L1Instructions is used to profile a function for the instruction level L1
// cache. Use PERF_COUNT_HW_CACHE_OP_READ, PERF_COUNT_HW_CACHE_OP_WRITE, or
// PERF_COUNT_HW_CACHE_OP_PREFETCH for the opt and
// PERF_COUNT_HW_CACHE_RESULT_ACCESS or PERF_COUNT_HW_CACHE_RESULT_MISS for the
// result. Note that it will call runtime.LockOSThread to ensure accurate
// profilng.
func L1Instructions(op, result int, f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_HW_CACHE,
Config: uint64((unix.PERF_COUNT_HW_CACHE_L1I) | (op << 8) | (result << 16)),
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// L1InstructionsEventAttr returns a unix.PerfEventAttr configured for L1Instructions.
func L1InstructionsEventAttr(op, result int) unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_HW_CACHE,
Config: uint64((unix.PERF_COUNT_HW_CACHE_L1I) | (op << 8) | (result << 16)),
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// LLCache is used to profile a function and return the number of emulation
// PERF_COUNT_HW_CACHE_OP_READ, PERF_COUNT_HW_CACHE_OP_WRITE, or
// PERF_COUNT_HW_CACHE_OP_PREFETCH for the opt and
// PERF_COUNT_HW_CACHE_RESULT_ACCESS or PERF_COUNT_HW_CACHE_RESULT_MISS for the
// result. Note that it will call runtime.LockOSThread to ensure accurate
// profilng.
func LLCache(op, result int, f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_HW_CACHE,
Config: uint64((unix.PERF_COUNT_HW_CACHE_LL) | (op << 8) | (result << 16)),
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// LLCacheEventAttr returns a unix.PerfEventAttr configured for LLCache.
func LLCacheEventAttr(op, result int) unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_HW_CACHE,
Config: uint64((unix.PERF_COUNT_HW_CACHE_LL) | (op << 8) | (result << 16)),
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// DataTLB is used to profile the data TLB. Use PERF_COUNT_HW_CACHE_OP_READ,
// PERF_COUNT_HW_CACHE_OP_WRITE, or PERF_COUNT_HW_CACHE_OP_PREFETCH for the opt
// and PERF_COUNT_HW_CACHE_RESULT_ACCESS or PERF_COUNT_HW_CACHE_RESULT_MISS for
// the result. Note that it will call runtime.LockOSThread to ensure accurate
// profilng.
func DataTLB(op, result int, f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_HW_CACHE,
Config: uint64((unix.PERF_COUNT_HW_CACHE_DTLB) | (op << 8) | (result << 16)),
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// DataTLBEventAttr returns a unix.PerfEventAttr configured for DataTLB.
func DataTLBEventAttr(op, result int) unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_HW_CACHE,
Config: uint64((unix.PERF_COUNT_HW_CACHE_DTLB) | (op << 8) | (result << 16)),
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// InstructionTLB is used to profile the instruction TLB. Use
// PERF_COUNT_HW_CACHE_OP_READ, PERF_COUNT_HW_CACHE_OP_WRITE, or
// PERF_COUNT_HW_CACHE_OP_PREFETCH for the opt and
// PERF_COUNT_HW_CACHE_RESULT_ACCESS or PERF_COUNT_HW_CACHE_RESULT_MISS for the
// result. Note that it will call runtime.LockOSThread to ensure accurate
// profilng.
func InstructionTLB(op, result int, f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_HW_CACHE,
Config: uint64((unix.PERF_COUNT_HW_CACHE_ITLB) | (op << 8) | (result << 16)),
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// InstructionTLBEventAttr returns a unix.PerfEventAttr configured for InstructionTLB.
func InstructionTLBEventAttr(op, result int) unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_HW_CACHE,
Config: uint64((unix.PERF_COUNT_HW_CACHE_ITLB) | (op << 8) | (result << 16)),
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// BPU is used to profile a function for the Branch Predictor Unit.
// Use PERF_COUNT_HW_CACHE_OP_READ, PERF_COUNT_HW_CACHE_OP_WRITE, or
// PERF_COUNT_HW_CACHE_OP_PREFETCH for the opt and
// PERF_COUNT_HW_CACHE_RESULT_ACCESS or PERF_COUNT_HW_CACHE_RESULT_MISS for the
// result. Note that it will call runtime.LockOSThread to ensure accurate
// profilng.
func BPU(op, result int, f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_HW_CACHE,
Config: uint64((unix.PERF_COUNT_HW_CACHE_BPU) | (op << 8) | (result << 16)),
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// BPUEventAttr returns a unix.PerfEventAttr configured for BPU events.
func BPUEventAttr(op, result int) unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_HW_CACHE,
Config: uint64((unix.PERF_COUNT_HW_CACHE_BPU) | (op << 8) | (result << 16)),
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}
// NodeCache is used to profile a function for NUMA operations. Use Use
// PERF_COUNT_HW_CACHE_OP_READ, PERF_COUNT_HW_CACHE_OP_WRITE, or
// PERF_COUNT_HW_CACHE_OP_PREFETCH for the opt and
// PERF_COUNT_HW_CACHE_RESULT_ACCESS or PERF_COUNT_HW_CACHE_RESULT_MISS for the
// result. Note that it will call runtime.LockOSThread to ensure accurate
// profilng.
func NodeCache(op, result int, f func() error) (*ProfileValue, error) {
eventAttr := &unix.PerfEventAttr{
Type: unix.PERF_TYPE_HW_CACHE,
Config: uint64((unix.PERF_COUNT_HW_CACHE_NODE) | (op << 8) | (result << 16)),
Size: EventAttrSize,
Bits: unix.PerfBitDisabled | unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
return profileFn(eventAttr, f)
}
// NodeCacheEventAttr returns a unix.PerfEventAttr configured for NUMA cache operations.
func NodeCacheEventAttr(op, result int) unix.PerfEventAttr {
return unix.PerfEventAttr{
Type: unix.PERF_TYPE_HW_CACHE,
Config: uint64((unix.PERF_COUNT_HW_CACHE_NODE) | (op << 8) | (result << 16)),
Size: EventAttrSize,
Bits: unix.PerfBitExcludeKernel | unix.PerfBitExcludeHv,
Read_format: unix.PERF_FORMAT_TOTAL_TIME_RUNNING | unix.PERF_FORMAT_TOTAL_TIME_ENABLED,
}
}