blob: 48a8b3a9554252082c474f825941bb831ca2baf3 [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package power
import (
"context"
"chromiumos/tast/common/perf"
"chromiumos/tast/errors"
)
const package0PowerConstraintName = "package-0-pl"
// RAPLPowerMetrics records the power consumption in Watt of the DUT.
type RAPLPowerMetrics struct {
snapshot *RAPLSnapshot
metrics map[string]perf.Metric
prefix string
}
// Assert that RAPLPowerMetrics can be used in perf.Timeline.
var _ perf.TimelineDatasource = &RAPLPowerMetrics{}
// NewRAPLPowerMetrics creates a timeline metric to collect Intel RAPL energy
// numbers.
func NewRAPLPowerMetrics() *RAPLPowerMetrics {
return &RAPLPowerMetrics{nil, make(map[string]perf.Metric), ""}
}
// Setup creates a RAPLSnapshot which lets us sample energy numbers without
// worrying about overflow. We do this in Setup because there's some extra work
// scanning sysfs that might be expensive if done during the test.
func (r *RAPLPowerMetrics) Setup(_ context.Context, prefix string) error {
snapshot, err := NewRAPLSnapshot()
if err != nil {
return errors.Wrap(err, "failed to create RAPL Snapshot")
}
r.snapshot = snapshot
r.prefix = prefix
return nil
}
// Start collects initial energy numbers which we can use to compute the average
// power consumption between now and the first Snapshot.
func (r *RAPLPowerMetrics) Start(_ context.Context) error {
if r.snapshot == nil {
// RAPL is not supported.
return nil
}
if _, err := r.snapshot.DiffWithCurrentRAPLAndReset(); err != nil {
return errors.Wrap(err, "failed to collect initial RAPL metrics")
}
for name := range r.snapshot.start.joules {
r.metrics[name] = perf.Metric{Name: r.prefix + name, Unit: "W",
Direction: perf.SmallerIsBetter, Multiple: true}
}
r.metrics[package0PowerConstraintName] = perf.Metric{Name: r.prefix + package0PowerConstraintName, Unit: "W", Direction: perf.SmallerIsBetter, Multiple: true}
return nil
}
// Snapshot computes the energy consumption between this and the previous
// snapshot, and reports them as metrics.
func (r *RAPLPowerMetrics) Snapshot(_ context.Context, values *perf.Values) error {
if r.snapshot == nil {
// RAPL is not supported.
return nil
}
energy, err := r.snapshot.DiffWithCurrentRAPLAndReset()
if err != nil {
return errors.Wrap(err, "failed to collect initial RAPL metrics")
}
for name := range r.metrics {
if name == package0PowerConstraintName {
values.Append(r.metrics[package0PowerConstraintName], energy.package0PowerConstraint)
} else {
// Report Converted values from Joules to Watt
values.Append(r.metrics[name], energy.joules[name]/energy.duration.Seconds())
}
}
return nil
}
// Stop does nothing.
func (r *RAPLPowerMetrics) Stop(_ context.Context, values *perf.Values) error {
return nil
}