add cluster and subcluster information to compareplot

This commit is contained in:
Christoph Kluge 2025-05-06 18:08:35 +02:00
parent aed2bd48fc
commit 4419df8d1b
6 changed files with 135 additions and 2 deletions

View File

@ -174,6 +174,8 @@ type JobStats {
jobId: Int! jobId: Int!
startTime: Int! startTime: Int!
duration: Int! duration: Int!
cluster: String!
subCluster: String!
numNodes: Int! numNodes: Int!
numHWThreads: Int numHWThreads: Int
numAccelerators: Int numAccelerators: Int

View File

@ -171,6 +171,7 @@ type ComplexityRoot struct {
} }
JobStats struct { JobStats struct {
Cluster func(childComplexity int) int
Duration func(childComplexity int) int Duration func(childComplexity int) int
JobID func(childComplexity int) int JobID func(childComplexity int) int
NumAccelerators func(childComplexity int) int NumAccelerators func(childComplexity int) int
@ -178,6 +179,7 @@ type ComplexityRoot struct {
NumNodes func(childComplexity int) int NumNodes func(childComplexity int) int
StartTime func(childComplexity int) int StartTime func(childComplexity int) int
Stats func(childComplexity int) int Stats func(childComplexity int) int
SubCluster func(childComplexity int) int
} }
JobsStatistics struct { JobsStatistics struct {
@ -945,6 +947,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.JobResultList.Offset(childComplexity), true return e.complexity.JobResultList.Offset(childComplexity), true
case "JobStats.cluster":
if e.complexity.JobStats.Cluster == nil {
break
}
return e.complexity.JobStats.Cluster(childComplexity), true
case "JobStats.duration": case "JobStats.duration":
if e.complexity.JobStats.Duration == nil { if e.complexity.JobStats.Duration == nil {
break break
@ -994,6 +1003,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.JobStats.Stats(childComplexity), true return e.complexity.JobStats.Stats(childComplexity), true
case "JobStats.subCluster":
if e.complexity.JobStats.SubCluster == nil {
break
}
return e.complexity.JobStats.SubCluster(childComplexity), true
case "JobsStatistics.histDuration": case "JobsStatistics.histDuration":
if e.complexity.JobsStatistics.HistDuration == nil { if e.complexity.JobsStatistics.HistDuration == nil {
break break
@ -2323,6 +2339,8 @@ type JobStats {
jobId: Int! jobId: Int!
startTime: Int! startTime: Int!
duration: Int! duration: Int!
cluster: String!
subCluster: String!
numNodes: Int! numNodes: Int!
numHWThreads: Int numHWThreads: Int
numAccelerators: Int numAccelerators: Int
@ -7533,6 +7551,94 @@ func (ec *executionContext) fieldContext_JobStats_duration(_ context.Context, fi
return fc, nil return fc, nil
} }
func (ec *executionContext) _JobStats_cluster(ctx context.Context, field graphql.CollectedField, obj *model.JobStats) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_JobStats_cluster(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.Cluster, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(string)
fc.Result = res
return ec.marshalNString2string(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_JobStats_cluster(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "JobStats",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _JobStats_subCluster(ctx context.Context, field graphql.CollectedField, obj *model.JobStats) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_JobStats_subCluster(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.SubCluster, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(string)
fc.Result = res
return ec.marshalNString2string(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_JobStats_subCluster(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "JobStats",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _JobStats_numNodes(ctx context.Context, field graphql.CollectedField, obj *model.JobStats) (ret graphql.Marshaler) { func (ec *executionContext) _JobStats_numNodes(ctx context.Context, field graphql.CollectedField, obj *model.JobStats) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_JobStats_numNodes(ctx, field) fc, err := ec.fieldContext_JobStats_numNodes(ctx, field)
if err != nil { if err != nil {
@ -11460,6 +11566,10 @@ func (ec *executionContext) fieldContext_Query_jobsMetricStats(ctx context.Conte
return ec.fieldContext_JobStats_startTime(ctx, field) return ec.fieldContext_JobStats_startTime(ctx, field)
case "duration": case "duration":
return ec.fieldContext_JobStats_duration(ctx, field) return ec.fieldContext_JobStats_duration(ctx, field)
case "cluster":
return ec.fieldContext_JobStats_cluster(ctx, field)
case "subCluster":
return ec.fieldContext_JobStats_subCluster(ctx, field)
case "numNodes": case "numNodes":
return ec.fieldContext_JobStats_numNodes(ctx, field) return ec.fieldContext_JobStats_numNodes(ctx, field)
case "numHWThreads": case "numHWThreads":
@ -17806,6 +17916,16 @@ func (ec *executionContext) _JobStats(ctx context.Context, sel ast.SelectionSet,
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
out.Invalids++ out.Invalids++
} }
case "cluster":
out.Values[i] = ec._JobStats_cluster(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "subCluster":
out.Values[i] = ec._JobStats_subCluster(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "numNodes": case "numNodes":
out.Values[i] = ec._JobStats_numNodes(ctx, field, obj) out.Values[i] = ec._JobStats_numNodes(ctx, field, obj)
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {

View File

@ -100,6 +100,8 @@ type JobStats struct {
JobID int `json:"jobId"` JobID int `json:"jobId"`
StartTime int `json:"startTime"` StartTime int `json:"startTime"`
Duration int `json:"duration"` Duration int `json:"duration"`
Cluster string `json:"cluster"`
SubCluster string `json:"subCluster"`
NumNodes int `json:"numNodes"` NumNodes int `json:"numNodes"`
NumHWThreads *int `json:"numHWThreads,omitempty"` NumHWThreads *int `json:"numHWThreads,omitempty"`
NumAccelerators *int `json:"numAccelerators,omitempty"` NumAccelerators *int `json:"numAccelerators,omitempty"`

View File

@ -621,6 +621,8 @@ func (r *queryResolver) JobsMetricStats(ctx context.Context, filter []*model.Job
JobID: int(job.JobID), JobID: int(job.JobID),
StartTime: int(job.StartTime.Unix()), StartTime: int(job.StartTime.Unix()),
Duration: int(job.Duration), Duration: int(job.Duration),
Cluster: job.Cluster,
SubCluster: job.SubCluster,
NumNodes: int(job.NumNodes), NumNodes: int(job.NumNodes),
NumHWThreads: &numThreadsInt, NumHWThreads: &numThreadsInt,
NumAccelerators: &numAccsInt, NumAccelerators: &numAccsInt,

View File

@ -41,6 +41,7 @@
let filter = [...filterBuffer]; let filter = [...filterBuffer];
let comparePlotData = {}; let comparePlotData = {};
let jobIds = []; let jobIds = [];
let jobClusters = [];
/*uPlot*/ /*uPlot*/
let plotSync = uPlot.sync("compareJobsView"); let plotSync = uPlot.sync("compareJobsView");
@ -54,6 +55,8 @@
jobId jobId
startTime startTime
duration duration
cluster
subCluster
numNodes numNodes
numHWThreads numHWThreads
numAccelerators numAccelerators
@ -130,8 +133,9 @@
if (jobs) { if (jobs) {
let plotIndex = 0 let plotIndex = 0
jobs.forEach((j) => { jobs.forEach((j) => {
// Collect JobIDs for X-Ticks // Collect JobIDs & Clusters for X-Ticks and Legend
jobIds.push(j.jobId) jobIds.push(j.jobId)
jobClusters.push(`${j.cluster} ${j.subCluster}`)
// Resources // Resources
comparePlotData['resources'].data[0].push(plotIndex) comparePlotData['resources'].data[0].push(plotIndex)
comparePlotData['resources'].data[1].push(j.startTime) comparePlotData['resources'].data[1].push(j.startTime)
@ -203,6 +207,7 @@
title={'Compare Resources'} title={'Compare Resources'}
xlabel="JobIDs" xlabel="JobIDs"
xticks={jobIds} xticks={jobIds}
xinfo={jobClusters}
ylabel={'Resource Counts'} ylabel={'Resource Counts'}
data={comparePlotData['resources'].data} data={comparePlotData['resources'].data}
{plotSync} {plotSync}
@ -217,6 +222,7 @@
title={`Compare Metric '${m}'`} title={`Compare Metric '${m}'`}
xlabel="JobIDs" xlabel="JobIDs"
xticks={jobIds} xticks={jobIds}
xinfo={jobClusters}
ylabel={m} ylabel={m}
metric={m} metric={m}
yunit={comparePlotData[m].unit} yunit={comparePlotData[m].unit}

View File

@ -24,6 +24,7 @@
export let data = null; export let data = null;
export let xlabel = ""; export let xlabel = "";
export let xticks = []; export let xticks = [];
export let xinfo = [];
export let ylabel = ""; export let ylabel = "";
export let yunit = ""; export let yunit = "";
export let title = ""; export let title = "";
@ -102,7 +103,7 @@
label: "JobID", label: "JobID",
scale: "x", scale: "x",
value: (u, ts, sidx, didx) => { value: (u, ts, sidx, didx) => {
return xticks[didx]; return `${xticks[didx]} | ${xinfo[didx]}`;
}, },
}, },
{ {