You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
4.2 KiB
152 lines
4.2 KiB
// +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
|
|
}
|