Add perf exporter (#1274)
Signed-off-by: Daniel Hodges <hodges.daniel.scott@gmail.com>
This commit is contained in:
parent
0c6b90be4e
commit
7882009870
41 changed files with 4285 additions and 0 deletions
2
vendor/github.com/hodgesds/perf-utils/.gitignore
generated
vendored
Normal file
2
vendor/github.com/hodgesds/perf-utils/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*.swp
|
||||
vendor
|
||||
15
vendor/github.com/hodgesds/perf-utils/Gopkg.lock
generated
vendored
Normal file
15
vendor/github.com/hodgesds/perf-utils/Gopkg.lock
generated
vendored
Normal 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
34
vendor/github.com/hodgesds/perf-utils/Gopkg.toml
generated
vendored
Normal 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
22
vendor/github.com/hodgesds/perf-utils/LICENSE
generated
vendored
Normal 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
120
vendor/github.com/hodgesds/perf-utils/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
# Perf
|
||||
[](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
22
vendor/github.com/hodgesds/perf-utils/bpf.go
generated
vendored
Normal 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
336
vendor/github.com/hodgesds/perf-utils/cache_profiler.go
generated
vendored
Normal 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
98
vendor/github.com/hodgesds/perf-utils/events.go
generated
vendored
Normal 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
102
vendor/github.com/hodgesds/perf-utils/fs_utils.go
generated
vendored
Normal 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
170
vendor/github.com/hodgesds/perf-utils/group_profiler.go
generated
vendored
Normal 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
|
||||
}
|
||||
157
vendor/github.com/hodgesds/perf-utils/hardware_profiler.go
generated
vendored
Normal file
157
vendor/github.com/hodgesds/perf-utils/hardware_profiler.go
generated
vendored
Normal 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
|
||||
}
|
||||
507
vendor/github.com/hodgesds/perf-utils/process_profile.go
generated
vendored
Normal file
507
vendor/github.com/hodgesds/perf-utils/process_profile.go
generated
vendored
Normal 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)
|
||||
}
|
||||
151
vendor/github.com/hodgesds/perf-utils/software_profiler.go
generated
vendored
Normal file
151
vendor/github.com/hodgesds/perf-utils/software_profiler.go
generated
vendored
Normal 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
681
vendor/github.com/hodgesds/perf-utils/utils.go
generated
vendored
Normal 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,
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue