mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2024-12-26 13:29:05 +01:00
Merge pull request #232 from ClusterCockpit/196_add_footprint
196 add footprint
This commit is contained in:
commit
04f37a85ce
@ -28,6 +28,11 @@ type Job {
|
|||||||
resources: [Resource!]!
|
resources: [Resource!]!
|
||||||
concurrentJobs: JobLinkResultList
|
concurrentJobs: JobLinkResultList
|
||||||
|
|
||||||
|
memUsedMax: Float
|
||||||
|
flopsAnyAvg: Float
|
||||||
|
memBwAvg: Float
|
||||||
|
loadAvg: Float
|
||||||
|
|
||||||
metaData: Any
|
metaData: Any
|
||||||
userData: User
|
userData: User
|
||||||
}
|
}
|
||||||
|
@ -88,8 +88,12 @@ type ComplexityRoot struct {
|
|||||||
ConcurrentJobs func(childComplexity int) int
|
ConcurrentJobs func(childComplexity int) int
|
||||||
Duration func(childComplexity int) int
|
Duration func(childComplexity int) int
|
||||||
Exclusive func(childComplexity int) int
|
Exclusive func(childComplexity int) int
|
||||||
|
FlopsAnyAvg func(childComplexity int) int
|
||||||
ID func(childComplexity int) int
|
ID func(childComplexity int) int
|
||||||
JobID func(childComplexity int) int
|
JobID func(childComplexity int) int
|
||||||
|
LoadAvg func(childComplexity int) int
|
||||||
|
MemBwAvg func(childComplexity int) int
|
||||||
|
MemUsedMax func(childComplexity int) int
|
||||||
MetaData func(childComplexity int) int
|
MetaData func(childComplexity int) int
|
||||||
MonitoringStatus func(childComplexity int) int
|
MonitoringStatus func(childComplexity int) int
|
||||||
NumAcc func(childComplexity int) int
|
NumAcc func(childComplexity int) int
|
||||||
@ -303,6 +307,7 @@ type JobResolver interface {
|
|||||||
Tags(ctx context.Context, obj *schema.Job) ([]*schema.Tag, error)
|
Tags(ctx context.Context, obj *schema.Job) ([]*schema.Tag, error)
|
||||||
|
|
||||||
ConcurrentJobs(ctx context.Context, obj *schema.Job) (*model.JobLinkResultList, error)
|
ConcurrentJobs(ctx context.Context, obj *schema.Job) (*model.JobLinkResultList, error)
|
||||||
|
|
||||||
MetaData(ctx context.Context, obj *schema.Job) (interface{}, error)
|
MetaData(ctx context.Context, obj *schema.Job) (interface{}, error)
|
||||||
UserData(ctx context.Context, obj *schema.Job) (*model.User, error)
|
UserData(ctx context.Context, obj *schema.Job) (*model.User, error)
|
||||||
}
|
}
|
||||||
@ -485,6 +490,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Job.Exclusive(childComplexity), true
|
return e.complexity.Job.Exclusive(childComplexity), true
|
||||||
|
|
||||||
|
case "Job.flopsAnyAvg":
|
||||||
|
if e.complexity.Job.FlopsAnyAvg == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Job.FlopsAnyAvg(childComplexity), true
|
||||||
|
|
||||||
case "Job.id":
|
case "Job.id":
|
||||||
if e.complexity.Job.ID == nil {
|
if e.complexity.Job.ID == nil {
|
||||||
break
|
break
|
||||||
@ -499,6 +511,27 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Job.JobID(childComplexity), true
|
return e.complexity.Job.JobID(childComplexity), true
|
||||||
|
|
||||||
|
case "Job.loadAvg":
|
||||||
|
if e.complexity.Job.LoadAvg == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Job.LoadAvg(childComplexity), true
|
||||||
|
|
||||||
|
case "Job.memBwAvg":
|
||||||
|
if e.complexity.Job.MemBwAvg == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Job.MemBwAvg(childComplexity), true
|
||||||
|
|
||||||
|
case "Job.memUsedMax":
|
||||||
|
if e.complexity.Job.MemUsedMax == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Job.MemUsedMax(childComplexity), true
|
||||||
|
|
||||||
case "Job.metaData":
|
case "Job.metaData":
|
||||||
if e.complexity.Job.MetaData == nil {
|
if e.complexity.Job.MetaData == nil {
|
||||||
break
|
break
|
||||||
@ -1628,6 +1661,11 @@ type Job {
|
|||||||
resources: [Resource!]!
|
resources: [Resource!]!
|
||||||
concurrentJobs: JobLinkResultList
|
concurrentJobs: JobLinkResultList
|
||||||
|
|
||||||
|
memUsedMax: Float
|
||||||
|
flopsAnyAvg: Float
|
||||||
|
memBwAvg: Float
|
||||||
|
loadAvg: Float
|
||||||
|
|
||||||
metaData: Any
|
metaData: Any
|
||||||
userData: User
|
userData: User
|
||||||
}
|
}
|
||||||
@ -4054,6 +4092,170 @@ func (ec *executionContext) fieldContext_Job_concurrentJobs(ctx context.Context,
|
|||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Job_memUsedMax(ctx context.Context, field graphql.CollectedField, obj *schema.Job) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_Job_memUsedMax(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) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.MemUsedMax, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(float64)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOFloat2float64(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_Job_memUsedMax(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "Job",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type Float does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Job_flopsAnyAvg(ctx context.Context, field graphql.CollectedField, obj *schema.Job) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_Job_flopsAnyAvg(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) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.FlopsAnyAvg, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(float64)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOFloat2float64(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_Job_flopsAnyAvg(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "Job",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type Float does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Job_memBwAvg(ctx context.Context, field graphql.CollectedField, obj *schema.Job) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_Job_memBwAvg(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) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.MemBwAvg, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(float64)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOFloat2float64(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_Job_memBwAvg(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "Job",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type Float does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Job_loadAvg(ctx context.Context, field graphql.CollectedField, obj *schema.Job) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_Job_loadAvg(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) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.LoadAvg, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(float64)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOFloat2float64(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_Job_loadAvg(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "Job",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type Float does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Job_metaData(ctx context.Context, field graphql.CollectedField, obj *schema.Job) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Job_metaData(ctx context.Context, field graphql.CollectedField, obj *schema.Job) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_Job_metaData(ctx, field)
|
fc, err := ec.fieldContext_Job_metaData(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -4778,6 +4980,14 @@ func (ec *executionContext) fieldContext_JobResultList_items(ctx context.Context
|
|||||||
return ec.fieldContext_Job_resources(ctx, field)
|
return ec.fieldContext_Job_resources(ctx, field)
|
||||||
case "concurrentJobs":
|
case "concurrentJobs":
|
||||||
return ec.fieldContext_Job_concurrentJobs(ctx, field)
|
return ec.fieldContext_Job_concurrentJobs(ctx, field)
|
||||||
|
case "memUsedMax":
|
||||||
|
return ec.fieldContext_Job_memUsedMax(ctx, field)
|
||||||
|
case "flopsAnyAvg":
|
||||||
|
return ec.fieldContext_Job_flopsAnyAvg(ctx, field)
|
||||||
|
case "memBwAvg":
|
||||||
|
return ec.fieldContext_Job_memBwAvg(ctx, field)
|
||||||
|
case "loadAvg":
|
||||||
|
return ec.fieldContext_Job_loadAvg(ctx, field)
|
||||||
case "metaData":
|
case "metaData":
|
||||||
return ec.fieldContext_Job_metaData(ctx, field)
|
return ec.fieldContext_Job_metaData(ctx, field)
|
||||||
case "userData":
|
case "userData":
|
||||||
@ -7152,6 +7362,14 @@ func (ec *executionContext) fieldContext_Query_job(ctx context.Context, field gr
|
|||||||
return ec.fieldContext_Job_resources(ctx, field)
|
return ec.fieldContext_Job_resources(ctx, field)
|
||||||
case "concurrentJobs":
|
case "concurrentJobs":
|
||||||
return ec.fieldContext_Job_concurrentJobs(ctx, field)
|
return ec.fieldContext_Job_concurrentJobs(ctx, field)
|
||||||
|
case "memUsedMax":
|
||||||
|
return ec.fieldContext_Job_memUsedMax(ctx, field)
|
||||||
|
case "flopsAnyAvg":
|
||||||
|
return ec.fieldContext_Job_flopsAnyAvg(ctx, field)
|
||||||
|
case "memBwAvg":
|
||||||
|
return ec.fieldContext_Job_memBwAvg(ctx, field)
|
||||||
|
case "loadAvg":
|
||||||
|
return ec.fieldContext_Job_loadAvg(ctx, field)
|
||||||
case "metaData":
|
case "metaData":
|
||||||
return ec.fieldContext_Job_metaData(ctx, field)
|
return ec.fieldContext_Job_metaData(ctx, field)
|
||||||
case "userData":
|
case "userData":
|
||||||
@ -12504,6 +12722,14 @@ func (ec *executionContext) _Job(ctx context.Context, sel ast.SelectionSet, obj
|
|||||||
}
|
}
|
||||||
|
|
||||||
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
|
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
|
||||||
|
case "memUsedMax":
|
||||||
|
out.Values[i] = ec._Job_memUsedMax(ctx, field, obj)
|
||||||
|
case "flopsAnyAvg":
|
||||||
|
out.Values[i] = ec._Job_flopsAnyAvg(ctx, field, obj)
|
||||||
|
case "memBwAvg":
|
||||||
|
out.Values[i] = ec._Job_memBwAvg(ctx, field, obj)
|
||||||
|
case "loadAvg":
|
||||||
|
out.Values[i] = ec._Job_loadAvg(ctx, field, obj)
|
||||||
case "metaData":
|
case "metaData":
|
||||||
field := field
|
field := field
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ func GetJobRepository() *JobRepository {
|
|||||||
var jobColumns []string = []string{
|
var jobColumns []string = []string{
|
||||||
"job.id", "job.job_id", "job.user", "job.project", "job.cluster", "job.subcluster", "job.start_time", "job.partition", "job.array_job_id",
|
"job.id", "job.job_id", "job.user", "job.project", "job.cluster", "job.subcluster", "job.start_time", "job.partition", "job.array_job_id",
|
||||||
"job.num_nodes", "job.num_hwthreads", "job.num_acc", "job.exclusive", "job.monitoring_status", "job.smt", "job.job_state",
|
"job.num_nodes", "job.num_hwthreads", "job.num_acc", "job.exclusive", "job.monitoring_status", "job.smt", "job.job_state",
|
||||||
"job.duration", "job.walltime", "job.resources", // "job.meta_data",
|
"job.duration", "job.walltime", "job.resources", "job.mem_used_max", "job.flops_any_avg", "job.mem_bw_avg", "job.load_avg", // "job.meta_data",
|
||||||
}
|
}
|
||||||
|
|
||||||
func scanJob(row interface{ Scan(...interface{}) error }) (*schema.Job, error) {
|
func scanJob(row interface{ Scan(...interface{}) error }) (*schema.Job, error) {
|
||||||
@ -68,7 +68,7 @@ func scanJob(row interface{ Scan(...interface{}) error }) (*schema.Job, error) {
|
|||||||
if err := row.Scan(
|
if err := row.Scan(
|
||||||
&job.ID, &job.JobID, &job.User, &job.Project, &job.Cluster, &job.SubCluster, &job.StartTimeUnix, &job.Partition, &job.ArrayJobId,
|
&job.ID, &job.JobID, &job.User, &job.Project, &job.Cluster, &job.SubCluster, &job.StartTimeUnix, &job.Partition, &job.ArrayJobId,
|
||||||
&job.NumNodes, &job.NumHWThreads, &job.NumAcc, &job.Exclusive, &job.MonitoringStatus, &job.SMT, &job.State,
|
&job.NumNodes, &job.NumHWThreads, &job.NumAcc, &job.Exclusive, &job.MonitoringStatus, &job.SMT, &job.State,
|
||||||
&job.Duration, &job.Walltime, &job.RawResources /*&job.RawMetaData*/); err != nil {
|
&job.Duration, &job.Walltime, &job.RawResources, &job.MemUsedMax, &job.FlopsAnyAvg, &job.MemBwAvg, &job.LoadAvg /*&job.RawMetaData*/); err != nil {
|
||||||
log.Warnf("Error while scanning rows (Job): %v", err)
|
log.Warnf("Error while scanning rows (Job): %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -483,6 +483,7 @@ func (r *JobRepository) MarkArchived(
|
|||||||
case "mem_bw":
|
case "mem_bw":
|
||||||
stmt = stmt.Set("mem_bw_avg", stats.Avg)
|
stmt = stmt.Set("mem_bw_avg", stats.Avg)
|
||||||
case "load":
|
case "load":
|
||||||
|
stmt = stmt.Set("load_avg", stats.Avg)
|
||||||
case "cpu_load":
|
case "cpu_load":
|
||||||
stmt = stmt.Set("load_avg", stats.Avg)
|
stmt = stmt.Set("load_avg", stats.Avg)
|
||||||
case "net_bw":
|
case "net_bw":
|
||||||
|
@ -54,10 +54,10 @@ type Job struct {
|
|||||||
BaseJob
|
BaseJob
|
||||||
StartTimeUnix int64 `json:"-" db:"start_time" example:"1649723812"` // Start epoch time stamp in seconds
|
StartTimeUnix int64 `json:"-" db:"start_time" example:"1649723812"` // Start epoch time stamp in seconds
|
||||||
StartTime time.Time `json:"startTime"` // Start time as 'time.Time' data type
|
StartTime time.Time `json:"startTime"` // Start time as 'time.Time' data type
|
||||||
MemUsedMax float64 `json:"-" db:"mem_used_max"` // MemUsedMax as Float64
|
MemUsedMax float64 `json:"memUsedMax" db:"mem_used_max"` // MemUsedMax as Float64
|
||||||
FlopsAnyAvg float64 `json:"-" db:"flops_any_avg"` // FlopsAnyAvg as Float64
|
FlopsAnyAvg float64 `json:"flopsAnyAvg" db:"flops_any_avg"` // FlopsAnyAvg as Float64
|
||||||
MemBwAvg float64 `json:"-" db:"mem_bw_avg"` // MemBwAvg as Float64
|
MemBwAvg float64 `json:"memBwAvg" db:"mem_bw_avg"` // MemBwAvg as Float64
|
||||||
LoadAvg float64 `json:"-" db:"load_avg"` // LoadAvg as Float64
|
LoadAvg float64 `json:"loadAvg" db:"load_avg"` // LoadAvg as Float64
|
||||||
NetBwAvg float64 `json:"-" db:"net_bw_avg"` // NetBwAvg as Float64
|
NetBwAvg float64 `json:"-" db:"net_bw_avg"` // NetBwAvg as Float64
|
||||||
NetDataVolTotal float64 `json:"-" db:"net_data_vol_total"` // NetDataVolTotal as Float64
|
NetDataVolTotal float64 `json:"-" db:"net_data_vol_total"` // NetDataVolTotal as Float64
|
||||||
FileBwAvg float64 `json:"-" db:"file_bw_avg"` // FileBwAvg as Float64
|
FileBwAvg float64 `json:"-" db:"file_bw_avg"` // FileBwAvg as Float64
|
||||||
|
166
web/frontend/package-lock.json
generated
166
web/frontend/package-lock.json
generated
@ -13,7 +13,9 @@
|
|||||||
"@urql/svelte": "^4.0.1",
|
"@urql/svelte": "^4.0.1",
|
||||||
"chart.js": "^4.3.3",
|
"chart.js": "^4.3.3",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
|
"date-fns": "^2.30.0",
|
||||||
"graphql": "^16.6.0",
|
"graphql": "^16.6.0",
|
||||||
|
"mathjs": "^12.0.0",
|
||||||
"svelte-chartjs": "^3.1.2",
|
"svelte-chartjs": "^3.1.2",
|
||||||
"sveltestrap": "^5.11.1",
|
"sveltestrap": "^5.11.1",
|
||||||
"uplot": "^1.6.24",
|
"uplot": "^1.6.24",
|
||||||
@ -102,6 +104,9 @@
|
|||||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
"node_modules/@jridgewell/trace-mapping": {
|
||||||
|
"version": "0.3.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz",
|
||||||
|
"integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==",
|
||||||
"version": "0.3.20",
|
"version": "0.3.20",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz",
|
||||||
"integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==",
|
"integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==",
|
||||||
@ -151,6 +156,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/plugin-node-resolve": {
|
"node_modules/@rollup/plugin-node-resolve": {
|
||||||
|
"version": "15.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz",
|
||||||
|
"integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==",
|
||||||
"version": "15.2.3",
|
"version": "15.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz",
|
||||||
"integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==",
|
"integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==",
|
||||||
@ -168,6 +176,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"rollup": "^2.78.0||^3.0.0||^4.0.0"
|
"rollup": "^2.78.0||^3.0.0||^4.0.0"
|
||||||
|
"rollup": "^2.78.0||^3.0.0||^4.0.0"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"rollup": {
|
"rollup": {
|
||||||
@ -176,18 +185,23 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/plugin-replace": {
|
"node_modules/@rollup/plugin-replace": {
|
||||||
|
"version": "5.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.5.tgz",
|
||||||
|
"integrity": "sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==",
|
||||||
"version": "5.0.5",
|
"version": "5.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.5.tgz",
|
||||||
"integrity": "sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==",
|
"integrity": "sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rollup/pluginutils": "^5.0.1",
|
"@rollup/pluginutils": "^5.0.1",
|
||||||
"magic-string": "^0.30.3"
|
"magic-string": "^0.30.3"
|
||||||
|
"magic-string": "^0.30.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
|
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
|
||||||
|
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"rollup": {
|
"rollup": {
|
||||||
@ -206,7 +220,21 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@rollup/plugin-replace/node_modules/magic-string": {
|
||||||
|
"version": "0.30.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz",
|
||||||
|
"integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@rollup/plugin-terser": {
|
"node_modules/@rollup/plugin-terser": {
|
||||||
|
"version": "0.4.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
|
||||||
|
"integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
|
||||||
"version": "0.4.4",
|
"version": "0.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
|
||||||
"integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
|
"integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
|
||||||
@ -221,6 +249,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"rollup": "^2.0.0||^3.0.0||^4.0.0"
|
"rollup": "^2.0.0||^3.0.0||^4.0.0"
|
||||||
|
"rollup": "^2.0.0||^3.0.0||^4.0.0"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"rollup": {
|
"rollup": {
|
||||||
@ -242,6 +271,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
|
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
|
||||||
|
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"rollup": {
|
"rollup": {
|
||||||
@ -259,6 +289,9 @@
|
|||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
||||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
|
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/resolve": {
|
"node_modules/@types/resolve": {
|
||||||
"version": "1.20.2",
|
"version": "1.20.2",
|
||||||
@ -288,6 +321,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
|
"version": "8.11.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz",
|
||||||
|
"integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==",
|
||||||
"version": "8.11.2",
|
"version": "8.11.2",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz",
|
||||||
"integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==",
|
"integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==",
|
||||||
@ -333,6 +369,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/chart.js": {
|
"node_modules/chart.js": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.0.tgz",
|
||||||
|
"integrity": "sha512-vQEj6d+z0dcsKLlQvbKIMYFHd3t8W/7L2vfJIbYcfyPcRx92CsHqECpueN8qVGNlKyDcr5wBrYAYKnfu/9Q1hQ==",
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.0.tgz",
|
||||||
"integrity": "sha512-vQEj6d+z0dcsKLlQvbKIMYFHd3t8W/7L2vfJIbYcfyPcRx92CsHqECpueN8qVGNlKyDcr5wBrYAYKnfu/9Q1hQ==",
|
"integrity": "sha512-vQEj6d+z0dcsKLlQvbKIMYFHd3t8W/7L2vfJIbYcfyPcRx92CsHqECpueN8qVGNlKyDcr5wBrYAYKnfu/9Q1hQ==",
|
||||||
@ -355,6 +394,18 @@
|
|||||||
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
|
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/complex.js": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-8njCHOTtFFLtegk6zQo0kkVX1rngygb/KQI6z1qZxlFI3scluC+LVTCFbrkWjBv4vvLlbQ9t88IPMC6k95VTTg==",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/infusion"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/date-fns": {
|
"node_modules/date-fns": {
|
||||||
"version": "2.30.0",
|
"version": "2.30.0",
|
||||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
|
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
|
||||||
@ -370,6 +421,11 @@
|
|||||||
"url": "https://opencollective.com/date-fns"
|
"url": "https://opencollective.com/date-fns"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/decimal.js": {
|
||||||
|
"version": "10.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
|
||||||
|
"integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA=="
|
||||||
|
},
|
||||||
"node_modules/deepmerge": {
|
"node_modules/deepmerge": {
|
||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||||
@ -379,11 +435,28 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/escape-latex": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw=="
|
||||||
|
},
|
||||||
"node_modules/estree-walker": {
|
"node_modules/estree-walker": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
|
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
|
||||||
},
|
},
|
||||||
|
"node_modules/fraction.js": {
|
||||||
|
"version": "4.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.4.tgz",
|
||||||
|
"integrity": "sha512-pwiTgt0Q7t+GHZA4yaLjObx4vXmmdcS0iSJ19o8d/goUGgItX9UZWKWNnLHehxviD8wU2IWRsnR8cD5+yOJP2Q==",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://github.com/sponsors/rawify"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fs.realpath": {
|
"node_modules/fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
@ -412,6 +485,13 @@
|
|||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/glob": {
|
"node_modules/glob": {
|
||||||
"version": "8.1.0",
|
"version": "8.1.0",
|
||||||
@ -433,6 +513,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/graphql": {
|
"node_modules/graphql": {
|
||||||
|
"version": "16.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz",
|
||||||
|
"integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==",
|
||||||
"version": "16.8.1",
|
"version": "16.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz",
|
||||||
"integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==",
|
"integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==",
|
||||||
@ -440,6 +523,10 @@
|
|||||||
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
|
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/hasown": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
|
||||||
"node_modules/hasown": {
|
"node_modules/hasown": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
|
||||||
@ -447,9 +534,11 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"function-bind": "^1.1.2"
|
"function-bind": "^1.1.2"
|
||||||
|
"function-bind": "^1.1.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/inflight": {
|
"node_modules/inflight": {
|
||||||
@ -484,12 +573,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/is-core-module": {
|
"node_modules/is-core-module": {
|
||||||
|
"version": "2.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
|
||||||
|
"integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
|
||||||
"version": "2.13.1",
|
"version": "2.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
|
||||||
"integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
|
"integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"hasown": "^2.0.0"
|
"hasown": "^2.0.0"
|
||||||
|
"hasown": "^2.0.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
@ -510,11 +603,17 @@
|
|||||||
"@types/estree": "*"
|
"@types/estree": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/javascript-natural-sort": {
|
||||||
|
"version": "0.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
|
||||||
|
"integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw=="
|
||||||
|
},
|
||||||
"node_modules/magic-string": {
|
"node_modules/magic-string": {
|
||||||
"version": "0.27.0",
|
"version": "0.27.0",
|
||||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz",
|
||||||
"integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==",
|
"integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.13"
|
"@jridgewell/sourcemap-codec": "^1.4.13"
|
||||||
},
|
},
|
||||||
@ -522,6 +621,28 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mathjs": {
|
||||||
|
"version": "12.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mathjs/-/mathjs-12.0.0.tgz",
|
||||||
|
"integrity": "sha512-Oz3swPplNPe7taoP6WrkKhQzhDE2SwvOgLzu8H3EN+hEadw2GjEJUm6Xl+hrioHoB8g2BYb3gfw1glSzhdBKYw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.23.2",
|
||||||
|
"complex.js": "^2.1.1",
|
||||||
|
"decimal.js": "^10.4.3",
|
||||||
|
"escape-latex": "^1.2.0",
|
||||||
|
"fraction.js": "4.3.4",
|
||||||
|
"javascript-natural-sort": "^0.7.1",
|
||||||
|
"seedrandom": "^3.0.5",
|
||||||
|
"tiny-emitter": "^2.1.0",
|
||||||
|
"typed-function": "^4.1.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"mathjs": "bin/cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/minimatch": {
|
"node_modules/minimatch": {
|
||||||
"version": "5.1.6",
|
"version": "5.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
||||||
@ -574,7 +695,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
|
||||||
"integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA=="
|
"integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/regenerator-runtime": {
|
||||||
|
"version": "0.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
|
||||||
|
"integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA=="
|
||||||
|
},
|
||||||
"node_modules/resolve": {
|
"node_modules/resolve": {
|
||||||
|
"version": "1.22.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
||||||
|
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
|
||||||
"version": "1.22.8",
|
"version": "1.22.8",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
||||||
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
|
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
|
||||||
@ -601,6 +730,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
|
"version": "3.29.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
|
||||||
|
"integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
|
||||||
"version": "3.29.4",
|
"version": "3.29.4",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
|
||||||
"integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
|
"integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
|
||||||
@ -617,6 +749,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup-plugin-css-only": {
|
"node_modules/rollup-plugin-css-only": {
|
||||||
|
"version": "4.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-4.5.2.tgz",
|
||||||
|
"integrity": "sha512-7rj9+jB17Pz8LNcPgtMUb16JcgD8lxQMK9HcGfAVhMK3na/WXes3oGIo5QsrQQVqtgAU6q6KnQNXJrYunaUIQQ==",
|
||||||
"version": "4.5.2",
|
"version": "4.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-4.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-4.5.2.tgz",
|
||||||
"integrity": "sha512-7rj9+jB17Pz8LNcPgtMUb16JcgD8lxQMK9HcGfAVhMK3na/WXes3oGIo5QsrQQVqtgAU6q6KnQNXJrYunaUIQQ==",
|
"integrity": "sha512-7rj9+jB17Pz8LNcPgtMUb16JcgD8lxQMK9HcGfAVhMK3na/WXes3oGIo5QsrQQVqtgAU6q6KnQNXJrYunaUIQQ==",
|
||||||
@ -629,6 +764,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"rollup": "<5"
|
"rollup": "<5"
|
||||||
|
"rollup": "<5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup-plugin-svelte": {
|
"node_modules/rollup-plugin-svelte": {
|
||||||
@ -681,6 +817,11 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/seedrandom": {
|
||||||
|
"version": "3.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
|
||||||
|
"integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg=="
|
||||||
|
},
|
||||||
"node_modules/serialize-javascript": {
|
"node_modules/serialize-javascript": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
|
||||||
@ -691,6 +832,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/smob": {
|
"node_modules/smob": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==",
|
||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz",
|
||||||
"integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==",
|
"integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==",
|
||||||
@ -745,6 +889,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/sveltestrap": {
|
"node_modules/sveltestrap": {
|
||||||
|
"version": "5.11.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/sveltestrap/-/sveltestrap-5.11.2.tgz",
|
||||||
|
"integrity": "sha512-fkLqIUh2QHBoom7v6kHI85grLeOqplmvtnTiA5Ck2gchzpVmwXWaWpf8qWhCFxfDuMhJBPlWbJvtSmwpDEowrg==",
|
||||||
"version": "5.11.2",
|
"version": "5.11.2",
|
||||||
"resolved": "https://registry.npmjs.org/sveltestrap/-/sveltestrap-5.11.2.tgz",
|
"resolved": "https://registry.npmjs.org/sveltestrap/-/sveltestrap-5.11.2.tgz",
|
||||||
"integrity": "sha512-fkLqIUh2QHBoom7v6kHI85grLeOqplmvtnTiA5Ck2gchzpVmwXWaWpf8qWhCFxfDuMhJBPlWbJvtSmwpDEowrg==",
|
"integrity": "sha512-fkLqIUh2QHBoom7v6kHI85grLeOqplmvtnTiA5Ck2gchzpVmwXWaWpf8qWhCFxfDuMhJBPlWbJvtSmwpDEowrg==",
|
||||||
@ -756,6 +903,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
|
"version": "5.24.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz",
|
||||||
|
"integrity": "sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==",
|
||||||
"version": "5.24.0",
|
"version": "5.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz",
|
||||||
"integrity": "sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==",
|
"integrity": "sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==",
|
||||||
@ -773,10 +923,26 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tiny-emitter": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
|
||||||
|
},
|
||||||
|
"node_modules/typed-function": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-Pq1DVubcvibmm8bYcMowjVnnMwPVMeh0DIdA8ad8NZY2sJgapANJmiigSUwlt+EgXxpfIv8MWrQXTIzkfYZLYQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/uplot": {
|
"node_modules/uplot": {
|
||||||
"version": "1.6.27",
|
"version": "1.6.27",
|
||||||
"resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.27.tgz",
|
"resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.27.tgz",
|
||||||
"integrity": "sha512-78U4ss5YeU65kQkOC/QAKiyII+4uo+TYUJJKvuxRzeSpk/s5sjpY1TL0agkmhHBBShpvLtmbHIEiM7+C5lBULg=="
|
"integrity": "sha512-78U4ss5YeU65kQkOC/QAKiyII+4uo+TYUJJKvuxRzeSpk/s5sjpY1TL0agkmhHBBShpvLtmbHIEiM7+C5lBULg=="
|
||||||
|
"version": "1.6.27",
|
||||||
|
"resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.27.tgz",
|
||||||
|
"integrity": "sha512-78U4ss5YeU65kQkOC/QAKiyII+4uo+TYUJJKvuxRzeSpk/s5sjpY1TL0agkmhHBBShpvLtmbHIEiM7+C5lBULg=="
|
||||||
},
|
},
|
||||||
"node_modules/wonka": {
|
"node_modules/wonka": {
|
||||||
"version": "6.3.4",
|
"version": "6.3.4",
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
"chart.js": "^4.3.3",
|
"chart.js": "^4.3.3",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
"graphql": "^16.6.0",
|
"graphql": "^16.6.0",
|
||||||
|
"mathjs": "^12.0.0",
|
||||||
"svelte-chartjs": "^3.1.2",
|
"svelte-chartjs": "^3.1.2",
|
||||||
"sveltestrap": "^5.11.1",
|
"sveltestrap": "^5.11.1",
|
||||||
"uplot": "^1.6.24",
|
"uplot": "^1.6.24",
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
import TagManagement from "./TagManagement.svelte";
|
import TagManagement from "./TagManagement.svelte";
|
||||||
import MetricSelection from "./MetricSelection.svelte";
|
import MetricSelection from "./MetricSelection.svelte";
|
||||||
import StatsTable from "./StatsTable.svelte";
|
import StatsTable from "./StatsTable.svelte";
|
||||||
|
import JobFootprint from "./JobFootprint.svelte";
|
||||||
import { getContext } from "svelte";
|
import { getContext } from "svelte";
|
||||||
|
|
||||||
export let dbid;
|
export let dbid;
|
||||||
@ -46,7 +47,8 @@
|
|||||||
resources { hostname, hwthreads, accelerators },
|
resources { hostname, hwthreads, accelerators },
|
||||||
metaData,
|
metaData,
|
||||||
userData { name, email },
|
userData { name, email },
|
||||||
concurrentJobs { items { id, jobId }, count, listQuery }
|
concurrentJobs { items { id, jobId }, count, listQuery },
|
||||||
|
flopsAnyAvg, memBwAvg, loadAvg
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
@ -134,7 +136,9 @@
|
|||||||
|
|
||||||
let plots = {},
|
let plots = {},
|
||||||
jobTags,
|
jobTags,
|
||||||
statsTable;
|
statsTable,
|
||||||
|
jobFootprint;
|
||||||
|
|
||||||
$: document.title = $initq.fetching
|
$: document.title = $initq.fetching
|
||||||
? "Loading..."
|
? "Loading..."
|
||||||
: $initq.error
|
: $initq.error
|
||||||
@ -202,6 +206,17 @@
|
|||||||
<Spinner secondary />
|
<Spinner secondary />
|
||||||
{/if}
|
{/if}
|
||||||
</Col>
|
</Col>
|
||||||
|
{#if $jobMetrics.data}
|
||||||
|
{#key $jobMetrics.data}
|
||||||
|
<Col>
|
||||||
|
<JobFootprint
|
||||||
|
bind:this={jobFootprint}
|
||||||
|
job={$initq.data.job}
|
||||||
|
jobMetrics={$jobMetrics.data.jobMetrics}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
{/key}
|
||||||
|
{/if}
|
||||||
{#if $jobMetrics.data && $initq.data}
|
{#if $jobMetrics.data && $initq.data}
|
||||||
{#if $initq.data.job.concurrentJobs != null && $initq.data.job.concurrentJobs.items.length != 0}
|
{#if $initq.data.job.concurrentJobs != null && $initq.data.job.concurrentJobs.items.length != 0}
|
||||||
{#if authlevel > roles.manager}
|
{#if authlevel > roles.manager}
|
||||||
|
230
web/frontend/src/JobFootprint.svelte
Normal file
230
web/frontend/src/JobFootprint.svelte
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
<script>
|
||||||
|
import { getContext } from 'svelte'
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
CardBody,
|
||||||
|
Progress,
|
||||||
|
Icon,
|
||||||
|
Tooltip
|
||||||
|
} from "sveltestrap";
|
||||||
|
import { mean, round } from 'mathjs'
|
||||||
|
|
||||||
|
export let job
|
||||||
|
export let jobMetrics
|
||||||
|
export let view = 'job'
|
||||||
|
export let width = 'auto'
|
||||||
|
|
||||||
|
const clusters = getContext('clusters')
|
||||||
|
const subclusterConfig = clusters.find((c) => c.name == job.cluster).subClusters.find((sc) => sc.name == job.subCluster)
|
||||||
|
|
||||||
|
const footprintMetrics = (job.numAcc !== 0)
|
||||||
|
? (job.exclusive !== 1)
|
||||||
|
? ['cpu_load', 'flops_any', 'acc_utilization']
|
||||||
|
: ['cpu_load', 'flops_any', 'acc_utilization', 'mem_bw']
|
||||||
|
: (job.exclusive !== 1)
|
||||||
|
? ['cpu_load', 'flops_any', 'mem_used']
|
||||||
|
: ['cpu_load', 'flops_any', 'mem_used', 'mem_bw']
|
||||||
|
|
||||||
|
const footprintData = footprintMetrics.map((fm) => {
|
||||||
|
// Mean: Primarily use backend sourced avgs from job.*, secondarily calculate/read from metricdata
|
||||||
|
let mv = null
|
||||||
|
if (fm === 'cpu_load' && job.loadAvg !== 0) {
|
||||||
|
mv = round(job.loadAvg, 2)
|
||||||
|
} else if (fm === 'flops_any' && job.flopsAnyAvg !== 0) {
|
||||||
|
mv = round(job.flopsAnyAvg, 2)
|
||||||
|
} else if (fm === 'mem_bw' && job.memBwAvg !== 0) {
|
||||||
|
mv = round(job.memBwAvg, 2)
|
||||||
|
} else { // Calculate from jobMetrics
|
||||||
|
const jm = jobMetrics.find((jm) => jm.name === fm && jm.scope === 'node')
|
||||||
|
if (jm?.metric?.statisticsSeries) {
|
||||||
|
mv = round(mean(jm.metric.statisticsSeries.mean), 2)
|
||||||
|
} else if (jm?.metric?.series?.length > 1) {
|
||||||
|
const avgs = jm.metric.series.map(jms => jms.statistics.avg)
|
||||||
|
mv = round(mean(avgs), 2)
|
||||||
|
} else {
|
||||||
|
mv = jm.metric.series[0].statistics.avg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unit
|
||||||
|
const fmc = getContext('metrics')(job.cluster, fm)
|
||||||
|
let unit = ''
|
||||||
|
if (fmc?.unit?.base) unit = fmc.unit.prefix + fmc.unit.base
|
||||||
|
|
||||||
|
// Threshold / -Differences
|
||||||
|
const fmt = findJobThresholds(job, fmc, subclusterConfig)
|
||||||
|
if (fm === 'flops_any') fmt.peak = round((fmt.peak * 0.85), 0)
|
||||||
|
|
||||||
|
// Define basic data
|
||||||
|
const fmBase = {
|
||||||
|
name: fm,
|
||||||
|
unit: unit,
|
||||||
|
avg: mv,
|
||||||
|
max: fmt.peak
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evalFootprint(fm, mv, fmt, 'alert')) {
|
||||||
|
return {
|
||||||
|
...fmBase,
|
||||||
|
color: 'danger',
|
||||||
|
message:`Metric average way ${fm === 'mem_used' ? 'above' : 'below' } expected normal thresholds.`,
|
||||||
|
impact: 3
|
||||||
|
}
|
||||||
|
} else if (evalFootprint(fm, mv, fmt, 'caution')) {
|
||||||
|
return {
|
||||||
|
...fmBase,
|
||||||
|
color: 'warning',
|
||||||
|
message: `Metric average ${fm === 'mem_used' ? 'above' : 'below' } expected normal thresholds.`,
|
||||||
|
impact: 2
|
||||||
|
}
|
||||||
|
} else if (evalFootprint(fm, mv, fmt, 'normal')) {
|
||||||
|
return {
|
||||||
|
...fmBase,
|
||||||
|
color: 'success',
|
||||||
|
message: 'Metric average within expected thresholds.',
|
||||||
|
impact: 1
|
||||||
|
}
|
||||||
|
} else if (evalFootprint(fm, mv, fmt, 'peak')) {
|
||||||
|
return {
|
||||||
|
...fmBase,
|
||||||
|
color: 'info',
|
||||||
|
message: 'Metric average above expected normal thresholds: Check for artifacts recommended.',
|
||||||
|
impact: 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
...fmBase,
|
||||||
|
color: 'secondary',
|
||||||
|
message: 'Metric average above expected peak threshold: Check for artifacts!',
|
||||||
|
impact: -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function evalFootprint(metric, mean, thresholds, level) {
|
||||||
|
// mem_used has inverse logic regarding threshold levels
|
||||||
|
switch (level) {
|
||||||
|
case 'peak':
|
||||||
|
if (metric === 'mem_used') return (mean <= thresholds.peak && mean > thresholds.alert)
|
||||||
|
else return (mean <= thresholds.peak && mean > thresholds.normal)
|
||||||
|
case 'alert':
|
||||||
|
if (metric === 'mem_used') return (mean <= thresholds.alert && mean > thresholds.caution)
|
||||||
|
else return (mean <= thresholds.alert && mean > 0)
|
||||||
|
case 'caution':
|
||||||
|
if (metric === 'mem_used') return (mean <= thresholds.caution && mean > thresholds.normal)
|
||||||
|
else return (mean <= thresholds.caution && mean > thresholds.alert)
|
||||||
|
case 'normal':
|
||||||
|
if (metric === 'mem_used') return (mean <= thresholds.normal && mean > 0)
|
||||||
|
else return (mean <= thresholds.normal && mean > thresholds.caution)
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script context="module">
|
||||||
|
export function findJobThresholds(job, metricConfig, subClusterConfig) {
|
||||||
|
|
||||||
|
if (!job || !metricConfig || !subClusterConfig) {
|
||||||
|
console.warn('Argument missing for findJobThresholds!')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const subclusterThresholds = metricConfig.subClusters.find(sc => sc.name == subClusterConfig.name)
|
||||||
|
const defaultThresholds = {
|
||||||
|
peak: subclusterThresholds ? subclusterThresholds.peak : metricConfig.peak,
|
||||||
|
normal: subclusterThresholds ? subclusterThresholds.normal : metricConfig.normal,
|
||||||
|
caution: subclusterThresholds ? subclusterThresholds.caution : metricConfig.caution,
|
||||||
|
alert: subclusterThresholds ? subclusterThresholds.alert : metricConfig.alert
|
||||||
|
}
|
||||||
|
|
||||||
|
if (job.exclusive === 1) { // Exclusive: Use as defined
|
||||||
|
return defaultThresholds
|
||||||
|
} else { // Shared: Handle specifically
|
||||||
|
if (metricConfig.name === 'cpu_load') { // Special: Avg Aggregation BUT scaled based on #hwthreads
|
||||||
|
return {
|
||||||
|
peak: job.numHWThreads,
|
||||||
|
normal: job.numHWThreads,
|
||||||
|
caution: defaultThresholds.caution,
|
||||||
|
alert: defaultThresholds.alert
|
||||||
|
}
|
||||||
|
} else if (metricConfig.aggregation === 'avg' ){
|
||||||
|
return defaultThresholds
|
||||||
|
} else if (metricConfig.aggregation === 'sum' ){
|
||||||
|
const jobFraction = job.numHWThreads / subClusterConfig.topology.node.length
|
||||||
|
return {
|
||||||
|
peak: round((defaultThresholds.peak * jobFraction), 0),
|
||||||
|
normal: round((defaultThresholds.normal * jobFraction), 0),
|
||||||
|
caution: round((defaultThresholds.caution * jobFraction), 0),
|
||||||
|
alert: round((defaultThresholds.alert * jobFraction), 0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('Missing or unkown aggregation mode (sum/avg) for metric:', metricConfig)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
} // Other job.exclusive cases?
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Card class="h-auto mt-1" style="width: {width}px;">
|
||||||
|
{#if view === 'job'}
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle class="mb-0 d-flex justify-content-center">
|
||||||
|
Core Metrics Footprint
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
{/if}
|
||||||
|
<CardBody>
|
||||||
|
{#each footprintData as fpd, index}
|
||||||
|
<div class="mb-1 d-flex justify-content-between">
|
||||||
|
<div> <b>{fpd.name}</b></div> <!-- For symmetry, see below ...-->
|
||||||
|
<div class="cursor-help d-inline-flex" id={`footprint-${job.jobId}-${index}`}>
|
||||||
|
<div class="mx-1">
|
||||||
|
<!-- Alerts Only -->
|
||||||
|
{#if fpd.impact === 3 || fpd.impact === -1}
|
||||||
|
<Icon name="exclamation-triangle-fill" class="text-danger"/>
|
||||||
|
{:else if fpd.impact === 2}
|
||||||
|
<Icon name="exclamation-triangle" class="text-warning"/>
|
||||||
|
{/if}
|
||||||
|
<!-- Emoji for all states-->
|
||||||
|
{#if fpd.impact === 3}
|
||||||
|
<Icon name="emoji-frown" class="text-danger"/>
|
||||||
|
{:else if fpd.impact === 2}
|
||||||
|
<Icon name="emoji-neutral" class="text-warning"/>
|
||||||
|
{:else if fpd.impact === 1}
|
||||||
|
<Icon name="emoji-smile" class="text-success"/>
|
||||||
|
{:else if fpd.impact === 0}
|
||||||
|
<Icon name="emoji-laughing" class="text-info"/>
|
||||||
|
{:else if fpd.impact === -1}
|
||||||
|
<Icon name="emoji-dizzy" class="text-danger"/>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<!-- Print Values -->
|
||||||
|
{fpd.avg} / {fpd.max} {fpd.unit} <!-- To increase margin to tooltip: No other way manageable ... -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Tooltip target={`footprint-${job.jobId}-${index}`} placement="right" offset={[0, 20]}>{fpd.message}</Tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<Progress
|
||||||
|
value={fpd.avg}
|
||||||
|
max={fpd.max}
|
||||||
|
color={fpd.color}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{#if job?.metaData?.message}
|
||||||
|
<hr class="mt-1 mb-2"/>
|
||||||
|
{@html job.metaData.message}
|
||||||
|
{/if}
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.cursor-help {
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
</style>
|
@ -23,6 +23,9 @@
|
|||||||
let metrics = filterPresets.cluster
|
let metrics = filterPresets.cluster
|
||||||
? ccconfig[`plot_list_selectedMetrics:${filterPresets.cluster}`] || ccconfig.plot_list_selectedMetrics
|
? ccconfig[`plot_list_selectedMetrics:${filterPresets.cluster}`] || ccconfig.plot_list_selectedMetrics
|
||||||
: ccconfig.plot_list_selectedMetrics
|
: ccconfig.plot_list_selectedMetrics
|
||||||
|
let showFootprint = filterPresets.cluster
|
||||||
|
? !!ccconfig[`plot_list_showFootprint:${filterPresets.cluster}`]
|
||||||
|
: !!ccconfig.plot_list_showFootprint
|
||||||
let selectedCluster = filterPresets?.cluster ? filterPresets.cluster : null
|
let selectedCluster = filterPresets?.cluster ? filterPresets.cluster : null
|
||||||
|
|
||||||
// The filterPresets are handled by the Filters component,
|
// The filterPresets are handled by the Filters component,
|
||||||
@ -81,7 +84,8 @@
|
|||||||
bind:metrics={metrics}
|
bind:metrics={metrics}
|
||||||
bind:sorting={sorting}
|
bind:sorting={sorting}
|
||||||
bind:matchedJobs={matchedJobs}
|
bind:matchedJobs={matchedJobs}
|
||||||
bind:this={jobList} />
|
bind:this={jobList}
|
||||||
|
bind:showFootprint={showFootprint} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
@ -93,4 +97,6 @@
|
|||||||
bind:cluster={selectedCluster}
|
bind:cluster={selectedCluster}
|
||||||
configName="plot_list_selectedMetrics"
|
configName="plot_list_selectedMetrics"
|
||||||
bind:metrics={metrics}
|
bind:metrics={metrics}
|
||||||
bind:isOpen={isMetricsSelectionOpen} />
|
bind:isOpen={isMetricsSelectionOpen}
|
||||||
|
bind:showFootprint={showFootprint}
|
||||||
|
view='list'/>
|
||||||
|
@ -17,12 +17,15 @@
|
|||||||
export let configName
|
export let configName
|
||||||
export let allMetrics = null
|
export let allMetrics = null
|
||||||
export let cluster = null
|
export let cluster = null
|
||||||
|
export let showFootprint
|
||||||
|
export let view = 'job'
|
||||||
|
|
||||||
const clusters = getContext('clusters'),
|
const clusters = getContext('clusters'),
|
||||||
onInit = getContext('on-init')
|
onInit = getContext('on-init')
|
||||||
|
|
||||||
let newMetricsOrder = []
|
let newMetricsOrder = []
|
||||||
let unorderedMetrics = [...metrics]
|
let unorderedMetrics = [...metrics]
|
||||||
|
let pendingShowFootprint = !!showFootprint
|
||||||
|
|
||||||
onInit(() => {
|
onInit(() => {
|
||||||
if (allMetrics == null) allMetrics = new Set()
|
if (allMetrics == null) allMetrics = new Set()
|
||||||
@ -90,6 +93,8 @@
|
|||||||
metrics = newMetricsOrder.filter(m => unorderedMetrics.includes(m))
|
metrics = newMetricsOrder.filter(m => unorderedMetrics.includes(m))
|
||||||
isOpen = false
|
isOpen = false
|
||||||
|
|
||||||
|
showFootprint = !!pendingShowFootprint
|
||||||
|
|
||||||
updateConfigurationMutation({
|
updateConfigurationMutation({
|
||||||
name: cluster == null ? configName : `${configName}:${cluster}`,
|
name: cluster == null ? configName : `${configName}:${cluster}`,
|
||||||
value: JSON.stringify(metrics)
|
value: JSON.stringify(metrics)
|
||||||
@ -99,6 +104,16 @@
|
|||||||
// console.log('Error on subscription: ' + res.error)
|
// console.log('Error on subscription: ' + res.error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
updateConfigurationMutation({
|
||||||
|
name: cluster == null ? 'plot_list_showFootprint' : `plot_list_showFootprint:${cluster}`,
|
||||||
|
value: JSON.stringify(showFootprint)
|
||||||
|
}).subscribe(res => {
|
||||||
|
if (res.fetching === false && res.error) {
|
||||||
|
console.log('Error on footprint subscription: ' + res.error)
|
||||||
|
throw res.error
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -121,6 +136,12 @@
|
|||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<ListGroup>
|
<ListGroup>
|
||||||
|
{#if view === 'list'}
|
||||||
|
<li class="list-group-item">
|
||||||
|
<input type="checkbox" bind:checked={pendingShowFootprint}> Show Footprint
|
||||||
|
</li>
|
||||||
|
<hr/>
|
||||||
|
{/if}
|
||||||
{#each newMetricsOrder as metric, index (metric)}
|
{#each newMetricsOrder as metric, index (metric)}
|
||||||
<li class="cc-config-column list-group-item"
|
<li class="cc-config-column list-group-item"
|
||||||
draggable={true} ondragover="return false"
|
draggable={true} ondragover="return false"
|
||||||
|
@ -25,6 +25,9 @@
|
|||||||
let metrics = ccconfig.plot_list_selectedMetrics, isMetricsSelectionOpen = false
|
let metrics = ccconfig.plot_list_selectedMetrics, isMetricsSelectionOpen = false
|
||||||
let w1, w2, histogramHeight = 250
|
let w1, w2, histogramHeight = 250
|
||||||
let selectedCluster = filterPresets?.cluster ? filterPresets.cluster : null
|
let selectedCluster = filterPresets?.cluster ? filterPresets.cluster : null
|
||||||
|
let showFootprint = filterPresets.cluster
|
||||||
|
? !!ccconfig[`plot_list_showFootprint:${filterPresets.cluster}`]
|
||||||
|
: !!ccconfig.plot_list_showFootprint
|
||||||
|
|
||||||
const client = getContextClient();
|
const client = getContextClient();
|
||||||
$: stats = queryStore({
|
$: stats = queryStore({
|
||||||
@ -165,7 +168,8 @@
|
|||||||
<JobList
|
<JobList
|
||||||
bind:metrics={metrics}
|
bind:metrics={metrics}
|
||||||
bind:sorting={sorting}
|
bind:sorting={sorting}
|
||||||
bind:this={jobList} />
|
bind:this={jobList}
|
||||||
|
bind:showFootprint={showFootprint} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
@ -177,4 +181,6 @@
|
|||||||
bind:cluster={selectedCluster}
|
bind:cluster={selectedCluster}
|
||||||
configName="plot_list_selectedMetrics"
|
configName="plot_list_selectedMetrics"
|
||||||
bind:metrics={metrics}
|
bind:metrics={metrics}
|
||||||
bind:isOpen={isMetricsSelectionOpen} />
|
bind:isOpen={isMetricsSelectionOpen}
|
||||||
|
bind:showFootprint={showFootprint}
|
||||||
|
view='list'/>
|
@ -28,6 +28,7 @@
|
|||||||
export let sorting = { field: "startTime", order: "DESC" };
|
export let sorting = { field: "startTime", order: "DESC" };
|
||||||
export let matchedJobs = 0;
|
export let matchedJobs = 0;
|
||||||
export let metrics = ccconfig.plot_list_selectedMetrics;
|
export let metrics = ccconfig.plot_list_selectedMetrics;
|
||||||
|
export let showFootprint;
|
||||||
|
|
||||||
let itemsPerPage = ccconfig.plot_list_jobsPerPage;
|
let itemsPerPage = ccconfig.plot_list_jobsPerPage;
|
||||||
let page = 1;
|
let page = 1;
|
||||||
@ -73,6 +74,9 @@
|
|||||||
name
|
name
|
||||||
}
|
}
|
||||||
metaData
|
metaData
|
||||||
|
flopsAnyAvg
|
||||||
|
memBwAvg
|
||||||
|
loadAvg
|
||||||
}
|
}
|
||||||
count
|
count
|
||||||
}
|
}
|
||||||
@ -134,12 +138,19 @@
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let plotWidth = null;
|
||||||
let tableWidth = null;
|
let tableWidth = null;
|
||||||
let jobInfoColumnWidth = 250;
|
let jobInfoColumnWidth = 250;
|
||||||
|
|
||||||
$: plotWidth = Math.floor(
|
$: if (showFootprint) {
|
||||||
|
plotWidth = Math.floor(
|
||||||
|
(tableWidth - jobInfoColumnWidth) / (metrics.length + 1) - 10
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
plotWidth = Math.floor(
|
||||||
(tableWidth - jobInfoColumnWidth) / metrics.length - 10
|
(tableWidth - jobInfoColumnWidth) / metrics.length - 10
|
||||||
);
|
)
|
||||||
|
}
|
||||||
|
|
||||||
let headerPaddingTop = 0;
|
let headerPaddingTop = 0;
|
||||||
stickyHeader(
|
stickyHeader(
|
||||||
@ -160,6 +171,15 @@
|
|||||||
>
|
>
|
||||||
Job Info
|
Job Info
|
||||||
</th>
|
</th>
|
||||||
|
{#if showFootprint}
|
||||||
|
<th
|
||||||
|
class="position-sticky top-0"
|
||||||
|
scope="col"
|
||||||
|
style="width: {plotWidth}px; padding-top: {headerPaddingTop}px"
|
||||||
|
>
|
||||||
|
Job Footprint
|
||||||
|
</th>
|
||||||
|
{/if}
|
||||||
{#each metrics as metric (metric)}
|
{#each metrics as metric (metric)}
|
||||||
<th
|
<th
|
||||||
class="position-sticky top-0 text-center"
|
class="position-sticky top-0 text-center"
|
||||||
@ -212,7 +232,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{:else if $jobs.data && $initialized}
|
{:else if $jobs.data && $initialized}
|
||||||
{#each $jobs.data.jobs.items as job (job)}
|
{#each $jobs.data.jobs.items as job (job)}
|
||||||
<JobListRow {job} {metrics} {plotWidth} />
|
<JobListRow {job} {metrics} {plotWidth} {showFootprint}/>
|
||||||
{:else}
|
{:else}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan={metrics.length + 1}>
|
<td colspan={metrics.length + 1}>
|
||||||
|
@ -14,22 +14,28 @@
|
|||||||
import { Card, Spinner } from "sveltestrap";
|
import { Card, Spinner } from "sveltestrap";
|
||||||
import MetricPlot from "../plots/MetricPlot.svelte";
|
import MetricPlot from "../plots/MetricPlot.svelte";
|
||||||
import JobInfo from "./JobInfo.svelte";
|
import JobInfo from "./JobInfo.svelte";
|
||||||
|
import JobFootprint from "../JobFootprint.svelte";
|
||||||
import { maxScope, checkMetricDisabled } from "../utils.js";
|
import { maxScope, checkMetricDisabled } from "../utils.js";
|
||||||
|
|
||||||
export let job;
|
export let job;
|
||||||
export let metrics;
|
export let metrics;
|
||||||
export let plotWidth;
|
export let plotWidth;
|
||||||
export let plotHeight = 275;
|
export let plotHeight = 275;
|
||||||
|
export let showFootprint;
|
||||||
|
|
||||||
let { id } = job;
|
let { id } = job;
|
||||||
let scopes = [job.numNodes == 1 ? "core" : "node"];
|
let scopes = [job.numNodes == 1 ? "core" : "node"];
|
||||||
|
|
||||||
|
function distinct(value, index, array) {
|
||||||
|
return array.indexOf(value) === index;
|
||||||
|
}
|
||||||
|
|
||||||
const cluster = getContext("clusters").find((c) => c.name == job.cluster);
|
const cluster = getContext("clusters").find((c) => c.name == job.cluster);
|
||||||
const metricConfig = getContext("metrics"); // Get all MetricConfs which include subCluster-specific settings for this job
|
const metricConfig = getContext("metrics"); // Get all MetricConfs which include subCluster-specific settings for this job
|
||||||
const client = getContextClient();
|
const client = getContextClient();
|
||||||
const query = gql`
|
const query = gql`
|
||||||
query ($id: ID!, $metrics: [String!]!, $scopes: [MetricScope!]!) {
|
query ($id: ID!, $queryMetrics: [String!]!, $scopes: [MetricScope!]!) {
|
||||||
jobMetrics(id: $id, metrics: $metrics, scopes: $scopes) {
|
jobMetrics(id: $id, metrics: $queryMetrics, scopes: $scopes) {
|
||||||
name
|
name
|
||||||
scope
|
scope
|
||||||
metric {
|
metric {
|
||||||
@ -61,14 +67,23 @@
|
|||||||
$: metricsQuery = queryStore({
|
$: metricsQuery = queryStore({
|
||||||
client: client,
|
client: client,
|
||||||
query: query,
|
query: query,
|
||||||
variables: { id, metrics, scopes }
|
variables: { id, queryMetrics, scopes }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let queryMetrics = null
|
||||||
|
$: if (showFootprint) {
|
||||||
|
queryMetrics = ['cpu_load', 'flops_any', 'mem_used', 'mem_bw', 'acc_utilization', ...metrics].filter(distinct)
|
||||||
|
scopes = ["node"]
|
||||||
|
} else {
|
||||||
|
queryMetrics = [...metrics]
|
||||||
|
scopes = [job.numNodes == 1 ? "core" : "node"]
|
||||||
|
}
|
||||||
|
|
||||||
export function refresh() {
|
export function refresh() {
|
||||||
metricsQuery = queryStore({
|
metricsQuery = queryStore({
|
||||||
client: client,
|
client: client,
|
||||||
query: query,
|
query: query,
|
||||||
variables: { id, metrics, scopes },
|
variables: { id, queryMetrics, scopes },
|
||||||
// requestPolicy: 'network-only' // use default cache-first for refresh
|
// requestPolicy: 'network-only' // use default cache-first for refresh
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -122,6 +137,16 @@
|
|||||||
</Card>
|
</Card>
|
||||||
</td>
|
</td>
|
||||||
{:else}
|
{:else}
|
||||||
|
{#if showFootprint}
|
||||||
|
<td>
|
||||||
|
<JobFootprint
|
||||||
|
job={job}
|
||||||
|
jobMetrics={$metricsQuery.data.jobMetrics}
|
||||||
|
width={plotWidth}
|
||||||
|
view="list"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
{/if}
|
||||||
{#each sortAndSelectScope($metricsQuery.data.jobMetrics) as metric, i (metric || i)}
|
{#each sortAndSelectScope($metricsQuery.data.jobMetrics) as metric, i (metric || i)}
|
||||||
<td>
|
<td>
|
||||||
<!-- Subluster Metricconfig remove keyword for jobtables (joblist main, user joblist, project joblist) to be used here as toplevel case-->
|
<!-- Subluster Metricconfig remove keyword for jobtables (joblist main, user joblist, project joblist) to be used here as toplevel case-->
|
||||||
|
@ -176,12 +176,12 @@
|
|||||||
// Debug get zoomLevel from browser
|
// Debug get zoomLevel from browser
|
||||||
// console.log("Zoom", Math.round(window.devicePixelRatio * 100))
|
// console.log("Zoom", Math.round(window.devicePixelRatio * 100))
|
||||||
|
|
||||||
if (scalarKneeX < (width * window.devicePixelRatio) - (padding[1] * window.devicePixelRatio)) { // Top horizontal roofline
|
if (scalarKneeX < (width * window.devicePixelRatio) - (padding[1] * window.devicePixelRatio)) { // Lower horizontal roofline
|
||||||
u.ctx.moveTo(scalarKneeX, flopRateScalarY)
|
u.ctx.moveTo(scalarKneeX, flopRateScalarY)
|
||||||
u.ctx.lineTo((width * window.devicePixelRatio) - (padding[1] * window.devicePixelRatio), flopRateScalarY)
|
u.ctx.lineTo((width * window.devicePixelRatio) - (padding[1] * window.devicePixelRatio), flopRateScalarY)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (simdKneeX < (width * window.devicePixelRatio) - (padding[1] * window.devicePixelRatio)) { // Lower horitontal roofline
|
if (simdKneeX < (width * window.devicePixelRatio) - (padding[1] * window.devicePixelRatio)) { // Top horitontal roofline
|
||||||
u.ctx.moveTo(simdKneeX, flopRateSimdY)
|
u.ctx.moveTo(simdKneeX, flopRateSimdY)
|
||||||
u.ctx.lineTo((width * window.devicePixelRatio) - (padding[1] * window.devicePixelRatio), flopRateSimdY)
|
u.ctx.lineTo((width * window.devicePixelRatio) - (padding[1] * window.devicePixelRatio), flopRateSimdY)
|
||||||
}
|
}
|
||||||
@ -214,6 +214,7 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
// cursor: { drag: { x: true, y: true } } // Activate zoom
|
||||||
};
|
};
|
||||||
uplot = new uPlot(opts, plotData, plotWrapper);
|
uplot = new uPlot(opts, plotData, plotWrapper);
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user