blob: 1320c38afe01cc861e2d51cac7ef8aea144ccb2f [file] [log] [blame]
package regression
import (
"context"
"fmt"
"net/url"
"go.skia.org/infra/go/query"
"go.skia.org/infra/go/vcsinfo"
"go.skia.org/infra/perf/go/dataframe"
"go.skia.org/infra/perf/go/types"
)
// DataFrameIterator is an iterator that produces DataFrames.
//
// for it.Next() {
// df, err := it.Value(ctx)
// // Do something with df.
// }
type DataFrameIterator interface {
Next() bool
Value(ctx context.Context) (*dataframe.DataFrame, error)
}
// dataframeSlicer implements DataFrameIterator by slicing sub-dataframes from
// a larger dataframe.
type dataframeSlicer struct {
df *dataframe.DataFrame
size int
offset int
}
// See DataFrameIterator.
func (d *dataframeSlicer) Next() bool {
return d.offset+d.size <= len(d.df.Header)
}
// See DataFrameIterator.
func (d *dataframeSlicer) Value(ctx context.Context) (*dataframe.DataFrame, error) {
// Slice off a sub-dataframe from d.df.
df, err := d.df.Slice(d.offset, d.size)
if err != nil {
return nil, err
}
d.offset += 1
return df, nil
}
// NewDataFrameIterator returns a DataFrameIterator that produces a set of
// dataframes for the given RegressionDetectionRequest.
func NewDataFrameIterator(ctx context.Context, progress types.Progress, req *RegressionDetectionRequest, dfBuilder dataframe.DataFrameBuilder, vcs vcsinfo.VCS) (DataFrameIterator, error) {
u, err := url.ParseQuery(req.Alert.Query)
if err != nil {
return nil, err
}
q, err := query.New(u)
if err != nil {
return nil, err
}
var df *dataframe.DataFrame
if req.Domain.Offset == 0 {
df, err = dfBuilder.NewNFromQuery(ctx, req.Domain.End, q, req.Domain.N, progress)
if err != nil {
return nil, fmt.Errorf("Failed to build dataframe iterator source dataframe: %s", err)
}
} else {
// We can get an iterator that returns just a single dataframe by making
// sure that the size of the origin dataframe is the same size as the
// slicer size, so we set them both to 2*Radius+1.
n := int32(2*req.Alert.Radius + 1)
// Need to find an End time, which is the commit time of the commit at Offset+Radius.
ci, err := vcs.ByIndex(ctx, int(req.Domain.Offset)+req.Alert.Radius-1)
if err != nil {
return nil, fmt.Errorf("Failed to look up Offset of a single cluster request: %s", err)
}
df, err = dfBuilder.NewNFromQuery(ctx, ci.Timestamp, q, n, progress)
if err != nil {
return nil, fmt.Errorf("Failed to build dataframe iterator source dataframe: %s", err)
}
}
return &dataframeSlicer{
df: df,
size: 2*req.Alert.Radius + 1,
offset: 0,
}, nil
}