blob: 8e99181602ad9660433ec5d81bddb4df115921fd [file] [log] [blame]
package dataframe
import (
"context"
"fmt"
"slices"
"strings"
"go.skia.org/infra/go/skerr"
"go.skia.org/infra/perf/go/config"
"go.skia.org/infra/perf/go/tracestore"
"go.skia.org/infra/perf/go/types"
)
// GetMetadataForTraces returns the metadata for the traces present in the data frame for the relevant commits.
func GetMetadataForTraces(ctx context.Context, df *DataFrame, metadataStore tracestore.MetadataStore) ([]types.TraceMetadata, error) {
// Extract the relevant trace ids from the data frame.
traceIds := []string{}
sourceFileIds := []int64{}
for traceId := range df.TraceSet {
traceIds = append(traceIds, traceId)
}
if len(traceIds) == 0 {
return []types.TraceMetadata{}, nil
}
// Collect all the source file ids for which we will extract metadata.
foundIds := map[int64]bool{}
for _, traceId := range traceIds {
sourceMap := df.SourceInfo[traceId]
if sourceMap != nil {
for _, sourceFileId := range sourceMap.GetAllSourceFileIds() {
foundIds[sourceFileId] = true
}
}
}
for sourceFileId := range foundIds {
sourceFileIds = append(sourceFileIds, sourceFileId)
}
if len(sourceFileIds) == 0 {
return []types.TraceMetadata{}, nil
}
slices.Sort(sourceFileIds)
// The return value is a map where the key is the source file name and value is the map of links.
linkInfo, err := metadataStore.GetMetadataForSourceFileIDs(ctx, sourceFileIds)
if err != nil {
return nil, skerr.Wrapf(err, "Error getting metadata")
}
traceMetadatas := []types.TraceMetadata{}
// rawLinks is a nested map that tracks links from database for a
// traceId->commitnum->links lookup.
rawLinks := map[string]map[types.CommitNumber]map[string]string{}
for traceId := range df.TraceSet {
traceMetadata := types.TraceMetadata{
TraceID: traceId,
CommitLinks: map[types.CommitNumber]map[string]types.TraceCommitLink{},
}
sourceInfo := df.SourceInfo[traceId]
if sourceInfo != nil {
// Populate the raw links for this trace for the relevant commit numbers.
rawLinks[traceId] = map[types.CommitNumber]map[string]string{}
for _, commitnum := range sourceInfo.GetAllCommitNumbers() {
sourceFileId, ok := sourceInfo.Get(commitnum)
if !ok {
continue
}
links, ok := linkInfo[sourceFileId]
if !ok {
continue
}
rawLinks[traceId][commitnum] = links
}
}
traceMetadatas = append(traceMetadatas, traceMetadata)
}
// Now that we have the metadata and the raw links, let's populate the commit links in
// the metadata objects based on instance configuration.
return PopulateTraceMetadataLinksBasedOnConfig(traceMetadatas, df.Header[0].Offset, rawLinks), nil
}
// PopulateTraceMetadataLinksBasedOnConfig populates the commit links for the trace metadata
// objects based on the specifications in the instance configs.
//
// Links which are commits are modified to show commit ranges from prev data points for well known keys.
// Links which are specified as useful in the instance config are added from the raw links.
// All other links are ignored.
func PopulateTraceMetadataLinksBasedOnConfig(traceCommitLinks []types.TraceMetadata, startCommitNumber types.CommitNumber, rawLinks map[string]map[types.CommitNumber]map[string]string) []types.TraceMetadata {
ret := []types.TraceMetadata{}
for _, traceCommitLink := range traceCommitLinks {
for currentCommit, currentCommitLinks := range rawLinks[traceCommitLink.TraceID] {
traceCommitLink.CommitLinks[currentCommit] = map[string]types.TraceCommitLink{}
if config.Config == nil {
for key, href := range currentCommitLinks {
traceCommitLink.CommitLinks[currentCommit][key] = types.TraceCommitLink{
Href: href,
}
}
continue
}
// Let's find the prev commit for this trace that has data.
prevCommit := currentCommit - 1
for prevCommit >= startCommitNumber {
if _, ok := rawLinks[traceCommitLink.TraceID][prevCommit]; !ok {
// if no data present, we move on.
prevCommit = prevCommit - 1
} else {
break
}
}
if prevCommit >= startCommitNumber {
// Define a func that will easily extract the commit id from a commit url.
getCommitIdFromCommitUrl := func(commitUrl string) string {
commitIdStartIdx := strings.LastIndex(commitUrl, "/")
return commitUrl[commitIdStartIdx+1:]
}
// Define a func that will easily extract the repo url from the commit url.
getRepoUrlFromCommitUrl := func(commitUrl string) string {
repoEndIdx := strings.Index(commitUrl, "+")
return commitUrl[:repoEndIdx]
}
prevCommitLinks := rawLinks[traceCommitLink.TraceID][prevCommit]
// Let's assemble the commit range urls if specified in the config.
if len(config.Config.DataPointConfig.KeysForCommitRange) > 0 {
for _, key := range config.Config.DataPointConfig.KeysForCommitRange {
currentCommitidInLinks := getCommitIdFromCommitUrl(currentCommitLinks[key])
if currentCommitidInLinks != "" {
prevCommitidInLinks := getCommitIdFromCommitUrl(prevCommitLinks[key])
switch key {
case "V8":
currentCommitLinks[key] = "https://chromium.googlesource.com/v8/v8/+/" + currentCommitidInLinks
if prevCommitLinks != nil {
prevCommitLinks[key] = "https://chromium.googlesource.com/v8/v8/+/" + prevCommitidInLinks
}
case "WebRTC":
currentCommitLinks[key] = "https://chromium.googlesource.com/external/webrtc/+/" + currentCommitidInLinks
if prevCommitLinks != nil {
prevCommitLinks[key] = "https://chromium.googlesource.com/external/webrtc/+/" + prevCommitidInLinks
}
}
var linkValue types.TraceCommitLink
// There is no relevant change in the commits specified in the links.
if currentCommitidInLinks == prevCommitidInLinks || prevCommitidInLinks == "" {
linkValue = types.TraceCommitLink{
Text: fmt.Sprintf("%s (No Change)", currentCommitidInLinks[:8]),
Href: currentCommitLinks[key],
}
} else {
// Since the prev commit and current commit are different, show is as a commit range url.
commitRangeUrl := fmt.Sprintf("%s+log/%s..%s", getRepoUrlFromCommitUrl(currentCommitLinks[key]), prevCommitidInLinks, currentCommitidInLinks)
linkValue = types.TraceCommitLink{
Text: fmt.Sprintf("%s - %s", prevCommitidInLinks[:8], currentCommitidInLinks[:8]),
Href: commitRangeUrl,
}
}
traceCommitLink.CommitLinks[currentCommit][key] = linkValue
}
}
}
}
// Let's assemble the other useful links if specified in the config.
if len(config.Config.DataPointConfig.KeysForUsefulLinks) > 0 {
for key, link := range currentCommitLinks {
if slices.Contains(config.Config.DataPointConfig.KeysForUsefulLinks, key) {
traceCommitLink.CommitLinks[currentCommit][key] = types.TraceCommitLink{
Href: link,
}
}
}
}
}
ret = append(ret, traceCommitLink)
}
return ret
}