blob: cccfce1ef73727a4f114244d5d7cce8be507ff33 [file] [log] [blame]
package analyzer
import (
"sort"
"sync"
cpb "go.skia.org/infra/cabe/go/proto"
"go.chromium.org/luci/common/api/swarming/swarming/v1"
)
// SwarmingTaskDiagnostics contains task-specific diagnostic messages generated by the Analyzer.
type SwarmingTaskDiagnostics struct {
TaskID string
Message []string `json:",omitempty"`
}
// ReplicaDiagnostics contains replica, or task pair-specific diagnostic messages generated by the Analyzer.
type ReplicaDiagnostics struct {
Number int
ControlTaskID string
TreatmentTaskID string
Message []string `json:",omitempty"`
}
// Diagnostics contains diagnostic messages about the replica task pairs and individual tasks generated
// by the Analyzer.
type Diagnostics struct {
mu *sync.Mutex
// Bad news: things that had to be excluded from the analysis, and why.
ExcludedSwarmingTasks map[string]*SwarmingTaskDiagnostics `json:",omitempty"`
ExcludedReplicas map[int]*ReplicaDiagnostics `json:",omitempty"`
// Good news: things that were included in the analysis.
IncludedSwarmingTasks map[string]*SwarmingTaskDiagnostics `json:",omitempty"`
IncludedReplicas map[int]*ReplicaDiagnostics `json:",omitempty"`
}
func newDiagnostics() *Diagnostics {
return &Diagnostics{
mu: &sync.Mutex{},
ExcludedSwarmingTasks: map[string]*SwarmingTaskDiagnostics{},
ExcludedReplicas: map[int]*ReplicaDiagnostics{},
IncludedSwarmingTasks: map[string]*SwarmingTaskDiagnostics{},
IncludedReplicas: map[int]*ReplicaDiagnostics{},
}
}
func (d *Diagnostics) excludeSwarmingTask(taskInfo *swarming.SwarmingRpcsTaskRequestMetadata, msg string) {
d.mu.Lock()
defer d.mu.Unlock()
taskDiag := d.ExcludedSwarmingTasks[taskInfo.TaskId]
if taskDiag == nil {
taskDiag = &SwarmingTaskDiagnostics{
TaskID: taskInfo.TaskId,
Message: []string{},
}
d.ExcludedSwarmingTasks[taskInfo.TaskId] = taskDiag
}
taskDiag.Message = append(taskDiag.Message, msg)
}
func (d *Diagnostics) includeSwarmingTask(taskInfo *swarming.SwarmingRpcsTaskRequestMetadata) {
d.mu.Lock()
defer d.mu.Unlock()
d.IncludedSwarmingTasks[taskInfo.TaskId] = &SwarmingTaskDiagnostics{
TaskID: taskInfo.TaskId,
}
}
func (d *Diagnostics) excludeReplica(replicaNumber int, pair pairedTasks, msg string) {
d.mu.Lock()
defer d.mu.Unlock()
replicaDiag := d.ExcludedReplicas[replicaNumber]
if replicaDiag == nil {
replicaDiag = &ReplicaDiagnostics{
Number: replicaNumber,
ControlTaskID: pair.control.taskID,
TreatmentTaskID: pair.treatment.taskID,
Message: []string{},
}
d.ExcludedReplicas[replicaNumber] = replicaDiag
}
replicaDiag.Message = append(replicaDiag.Message, msg)
}
func (d *Diagnostics) includeReplica(replicaNumber int, pair pairedTasks) {
d.mu.Lock()
defer d.mu.Unlock()
d.IncludedReplicas[replicaNumber] = &ReplicaDiagnostics{
Number: replicaNumber,
ControlTaskID: pair.control.taskID,
TreatmentTaskID: pair.treatment.taskID,
}
}
type bySwarmingTaskId []*cpb.SwarmingTaskDiagnostics
func (a bySwarmingTaskId) Len() int { return len(a) }
func (a bySwarmingTaskId) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a bySwarmingTaskId) Less(i, j int) bool {
if a[i].Id.Project != a[j].Id.Project {
return a[i].Id.Project < a[j].Id.Project
}
return a[i].Id.TaskId < a[j].Id.TaskId
}
type byReplicaNumber []*cpb.ReplicaDiagnostics
func (a byReplicaNumber) Len() int { return len(a) }
func (a byReplicaNumber) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byReplicaNumber) Less(i, j int) bool {
return a[i].ReplicaNumber < a[j].ReplicaNumber
}
func (d *Diagnostics) AnalysisDiagnostics() *cpb.AnalysisDiagnostics {
ret := &cpb.AnalysisDiagnostics{}
for taskId, taskDiag := range d.ExcludedSwarmingTasks {
ret.ExcludedSwarmingTasks = append(ret.ExcludedSwarmingTasks, &cpb.SwarmingTaskDiagnostics{
Id: &cpb.SwarmingTaskId{
TaskId: taskId,
},
Message: taskDiag.Message,
})
}
for replicaNumber, replicaDiag := range d.ExcludedReplicas {
ret.ExcludedReplicas = append(ret.ExcludedReplicas, &cpb.ReplicaDiagnostics{
ReplicaNumber: int32(replicaNumber),
ControlTask: &cpb.SwarmingTaskId{
TaskId: replicaDiag.ControlTaskID,
},
TreatmentTask: &cpb.SwarmingTaskId{
TaskId: replicaDiag.TreatmentTaskID,
},
Message: replicaDiag.Message,
})
}
for taskId, taskDiag := range d.IncludedSwarmingTasks {
ret.IncludedSwarmingTasks = append(ret.IncludedSwarmingTasks, &cpb.SwarmingTaskDiagnostics{
Id: &cpb.SwarmingTaskId{
TaskId: taskId,
},
Message: taskDiag.Message,
})
}
for replicaNumber, replicaDiag := range d.IncludedReplicas {
ret.IncludedReplicas = append(ret.IncludedReplicas, &cpb.ReplicaDiagnostics{
ReplicaNumber: int32(replicaNumber),
ControlTask: &cpb.SwarmingTaskId{
TaskId: replicaDiag.ControlTaskID,
},
TreatmentTask: &cpb.SwarmingTaskId{
TaskId: replicaDiag.TreatmentTaskID,
},
Message: replicaDiag.Message,
})
}
sort.Sort(bySwarmingTaskId(ret.ExcludedSwarmingTasks))
sort.Sort(byReplicaNumber(ret.ExcludedReplicas))
sort.Sort(bySwarmingTaskId(ret.IncludedSwarmingTasks))
sort.Sort(byReplicaNumber(ret.IncludedReplicas))
return ret
}