diff --git a/.gitignore b/.gitignore index 9f448aa..0e18666 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ /archive-manager var/job.db-shm var/job.db-wal + +dist/ diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..8400874 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,70 @@ +# This is an example .goreleaser.yml file with some sensible defaults. +before: + hooks: + - go mod tidy +builds: + - env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + goarch: + - amd64 + - arm64 + goamd64: + - v2 + - v3 + goarm: + - "7" + id: "cc-backend" + main: ./cmd/cc-backend + tags: + - static_build + +archives: + - format: tar.gz + # this name template makes the OS and Arch compatible with the results of uname. + name_template: >- + {{ .ProjectName }}_ + {{- title .Os }}_ + {{- if eq .Arch "amd64" }}x86_64 + {{- else }}{{ .Arch }}{{ end }} + {{- if .Arm }}v{{ .Arm }}{{ end }} +checksum: + name_template: 'checksums.txt' +snapshot: + name_template: "{{ incpatch .Version }}-next" +changelog: + sort: asc + filters: + exclude: + - "^test:" + - "^chore" + - "merge conflict" + - Merge pull request + - Merge remote-tracking branch + - Merge branch + groups: + - title: "Dependency updates" + regexp: '^.*?(feat|fix)\(deps\)!?:.+$' + order: 300 + - title: "New Features" + regexp: '^.*?feat(\([[:word:]]+\))??!?:.+$' + order: 100 + - title: "Security updates" + regexp: '^.*?sec(\([[:word:]]+\))??!?:.+$' + order: 150 + - title: "Bug fixes" + regexp: '^.*?fix(\([[:word:]]+\))??!?:.+$' + order: 200 + - title: "Documentation updates" + regexp: ^.*?doc(\([[:word:]]+\))??!?:.+$ + order: 400 + - title: Other work + order: 9999 +release: + draft: true + footer: | + Supports job archive version 1 and database version 4. + +# vim: set ts=2 sw=2 tw=0 fo=cnqoj diff --git a/Makefile b/Makefile index 1210850..032559b 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ FRONTEND = ./web/frontend VERSION = 1.0.0 GIT_HASH := $(shell git rev-parse --short HEAD || echo 'development') CURRENT_TIME = $(shell date +"%Y-%m-%d:T%H:%M:%S") -LD_FLAGS = '-s -X main.buildTime=${CURRENT_TIME} -X main.version=${VERSION} -X main.hash=${GIT_HASH}' +LD_FLAGS = '-s -X main.date=${CURRENT_TIME} -X main.version=${VERSION} -X main.commit=${GIT_HASH}' EXECUTABLES = go npm K := $(foreach exec,$(EXECUTABLES),\ diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 97dd8de..4c204b0 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -8,7 +8,7 @@ implementation of ClusterCockpit. **Breaking changes** The aggregate job statistic core hours is now computed using the job table -column `num_hwthreads`. In a the future release this column will be renamed to +column `num_hwthreads`. In a future release this column will be renamed to `num_cores`. For correct display of core hours `num_hwthreads` must be correctly filled on job start. If your existing jobs do not provide the correct value in this column then you can set this with one SQL INSERT statement. This only applies @@ -16,7 +16,7 @@ if you have exclusive jobs, only. Please be aware that we treat this column as it is the number of cores. In case you have SMT enabled and `num_hwthreads` is not the number of cores the core hours will be too high by a factor! -**Features** +**Notable changes** * Supports user roles admin, support, manager, user, and api. * Unified search bar supports job id, job name, project id, user name, and name * Performance improvements for sqlite db backend @@ -24,4 +24,3 @@ is not the number of cores the core hours will be too high by a factor! * Better support for shared jobs * More flexible metric list configuration * Versioning and migration for database and job archive - diff --git a/cmd/cc-backend/main.go b/cmd/cc-backend/main.go index 02eb33b..f9868e6 100644 --- a/cmd/cc-backend/main.go +++ b/cmd/cc-backend/main.go @@ -59,9 +59,9 @@ const logoString = ` ` var ( - buildTime string - hash string - version string + date string + commit string + version string ) func main() { @@ -86,8 +86,8 @@ func main() { if flagVersion { fmt.Print(logoString) fmt.Printf("Version:\t%s\n", version) - fmt.Printf("Git hash:\t%s\n", hash) - fmt.Printf("Build time:\t%s\n", buildTime) + fmt.Printf("Git hash:\t%s\n", commit) + fmt.Printf("Build time:\t%s\n", date) fmt.Printf("SQL db version:\t%d\n", repository.Version) fmt.Printf("Job archive version:\t%d\n", archive.Version) os.Exit(0) @@ -245,7 +245,7 @@ func main() { } r := mux.NewRouter() - buildInfo := web.Build{Version: version, Hash: hash, Buildtime: buildTime} + buildInfo := web.Build{Version: version, Hash: commit, Buildtime: date} r.HandleFunc("/login", func(rw http.ResponseWriter, r *http.Request) { rw.Header().Add("Content-Type", "text/html; charset=utf-8") @@ -320,7 +320,7 @@ func main() { }) // Mount all /monitoring/... and /api/... routes. - routerConfig.SetupRoutes(secured, version, hash, buildTime) + routerConfig.SetupRoutes(secured, version, commit, date) api.MountRoutes(secured) if config.Keys.EmbedStaticFiles { diff --git a/go.mod b/go.mod index f684bf8..12fc2fd 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/99designs/gqlgen v0.17.24 github.com/ClusterCockpit/cc-units v0.4.0 github.com/Masterminds/squirrel v1.5.3 + github.com/go-co-op/gocron v1.25.0 github.com/go-ldap/ldap/v3 v3.4.4 github.com/go-sql-driver/mysql v1.7.0 github.com/golang-jwt/jwt/v4 v4.5.0 @@ -25,6 +26,7 @@ require ( github.com/swaggo/swag v1.8.10 github.com/vektah/gqlparser/v2 v2.5.1 golang.org/x/crypto v0.6.0 + golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea ) require ( @@ -40,7 +42,6 @@ require ( github.com/felixge/httpsnoop v1.0.3 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect - github.com/go-co-op/gocron v1.25.0 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/spec v0.20.8 // indirect @@ -56,7 +57,6 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kr/pretty v0.3.0 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -70,14 +70,11 @@ require ( github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect - github.com/rogpeppe/go-internal v1.8.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/stretchr/testify v1.8.2 // indirect github.com/swaggo/files v1.0.0 // indirect github.com/urfave/cli/v2 v2.24.4 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.uber.org/atomic v1.10.0 // indirect - golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea // indirect golang.org/x/mod v0.8.0 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/oauth2 v0.5.0 // indirect diff --git a/go.sum b/go.sum index 0e12d13..691fef1 100644 --- a/go.sum +++ b/go.sum @@ -828,7 +828,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= @@ -1010,7 +1009,6 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1073,9 +1071,7 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= -github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= @@ -1155,7 +1151,6 @@ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1F github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/swaggo/files v1.0.0 h1:1gGXVIeUFCS/dta17rnP0iOpr6CXFwKD7EO5ID233e4= github.com/swaggo/files v1.0.0/go.mod h1:N59U6URJLyU1PQgFqPM7wXLMhJx7QAolnvfQkqO13kc= diff --git a/internal/auth/ldap.go b/internal/auth/ldap.go index 672f10d..81b0d93 100644 --- a/internal/auth/ldap.go +++ b/internal/auth/ldap.go @@ -6,6 +6,7 @@ package auth import ( "errors" + "fmt" "net/http" "os" "strings" @@ -85,8 +86,8 @@ func (la *LdapAuthenticator) Login( userDn := strings.Replace(la.config.UserBind, "{username}", user.Username, -1) if err := l.Bind(userDn, r.FormValue("password")); err != nil { - log.Error("Error while binding to ldap connection") - return nil, err + log.Errorf("AUTH/LOCAL > Authentication for user %s failed: %v", user.Username, err) + return nil, fmt.Errorf("AUTH/LDAP > Authentication failed") } return user, nil diff --git a/internal/auth/local.go b/internal/auth/local.go index 0813e23..29996a4 100644 --- a/internal/auth/local.go +++ b/internal/auth/local.go @@ -8,6 +8,7 @@ import ( "fmt" "net/http" + "github.com/ClusterCockpit/cc-backend/pkg/log" "golang.org/x/crypto/bcrypt" ) @@ -39,7 +40,8 @@ func (la *LocalAuthenticator) Login( r *http.Request) (*User, error) { if e := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(r.FormValue("password"))); e != nil { - return nil, fmt.Errorf("AUTH/LOCAL > user '%s' provided the wrong password (%w)", user.Username, e) + log.Errorf("AUTH/LOCAL > Authentication for user %s failed!", user.Username) + return nil, fmt.Errorf("AUTH/LOCAL > Authentication failed") } return user, nil diff --git a/web/frontend/src/Status.root.svelte b/web/frontend/src/Status.root.svelte index 2b57bfa..41615a1 100644 --- a/web/frontend/src/Status.root.svelte +++ b/web/frontend/src/Status.root.svelte @@ -4,6 +4,7 @@ import Histogram from './plots/Histogram.svelte' import { Row, Col, Spinner, Card, CardHeader, CardTitle, CardBody, Table, Progress, Icon } from 'sveltestrap' import { init } from './utils.js' + import { scaleNumbers } from './units.js' import { queryStore, gql, getContextClient } from '@urql/svelte' const { query: initq } = init() @@ -50,15 +51,17 @@ ? sum + (node.metrics.find(m => m.name == metric)?.metric.series.reduce((sum, series) => sum + series.data[series.data.length - 1], 0) || 0) : sum, 0) - let allocatedNodes = {}, flopRate = {}, flopRateUnit = {}, memBwRate = {}, memBwRateUnit = {} + let allocatedNodes = {}, flopRate = {}, flopRateUnitPrefix = {}, flopRateUnitBase = {}, memBwRate = {}, memBwRateUnitPrefix = {}, memBwRateUnitBase = {} $: if ($initq.data && $mainQuery.data) { let subClusters = $initq.data.clusters.find(c => c.name == cluster).subClusters for (let subCluster of subClusters) { - allocatedNodes[subCluster.name] = $mainQuery.data.allocatedNodes.find(({ name }) => name == subCluster.name)?.count || 0 - flopRate[subCluster.name] = Math.floor(sumUp($mainQuery.data.nodeMetrics, subCluster.name, 'flops_any') * 100) / 100 - flopRateUnit[subCluster.name] = subCluster.flopRateSimd.unit.prefix + subCluster.flopRateSimd.unit.base - memBwRate[subCluster.name] = Math.floor(sumUp($mainQuery.data.nodeMetrics, subCluster.name, 'mem_bw') * 100) / 100 - memBwRateUnit[subCluster.name] = subCluster.memoryBandwidth.unit.prefix + subCluster.memoryBandwidth.unit.base + allocatedNodes[subCluster.name] = $mainQuery.data.allocatedNodes.find(({ name }) => name == subCluster.name)?.count || 0 + flopRate[subCluster.name] = Math.floor(sumUp($mainQuery.data.nodeMetrics, subCluster.name, 'flops_any') * 100) / 100 + flopRateUnitPrefix[subCluster.name] = subCluster.flopRateSimd.unit.prefix + flopRateUnitBase[subCluster.name] = subCluster.flopRateSimd.unit.base + memBwRate[subCluster.name] = Math.floor(sumUp($mainQuery.data.nodeMetrics, subCluster.name, 'mem_bw') * 100) / 100 + memBwRateUnitPrefix[subCluster.name] = subCluster.memoryBandwidth.unit.prefix + memBwRateUnitBase[subCluster.name] = subCluster.memoryBandwidth.unit.base } } @@ -111,17 +114,27 @@ Allocated Nodes
- ({allocatedNodes[subCluster.name]} Nodes / {subCluster.numberOfNodes} Total Nodes) + {allocatedNodes[subCluster.name]} / {subCluster.numberOfNodes} Nodes Flop Rate (Any)
- ({flopRate[subCluster.name]} {flopRateUnit[subCluster.name]} / {(subCluster.flopRateSimd.value * subCluster.numberOfNodes)} {flopRateUnit[subCluster.name]} [Max]) + + {scaleNumbers(flopRate[subCluster.name], + (subCluster.flopRateSimd.value * subCluster.numberOfNodes), + flopRateUnitPrefix[subCluster.name]) + }{flopRateUnitBase[subCluster.name]} [Max] + MemBw Rate
- ({memBwRate[subCluster.name]} {memBwRateUnit[subCluster.name]} / {(subCluster.memoryBandwidth.value * subCluster.numberOfNodes)} {memBwRateUnit[subCluster.name]} [Max]) + + {scaleNumbers(memBwRate[subCluster.name], + (subCluster.memoryBandwidth.value * subCluster.numberOfNodes), + memBwRateUnitPrefix[subCluster.name]) + }{memBwRateUnitBase[subCluster.name]} [Max] + diff --git a/web/frontend/src/filters/DoubleRangeSlider.svelte b/web/frontend/src/filters/DoubleRangeSlider.svelte index aca460a..2d4795f 100644 --- a/web/frontend/src/filters/DoubleRangeSlider.svelte +++ b/web/frontend/src/filters/DoubleRangeSlider.svelte @@ -21,6 +21,8 @@ Changes: remove dependency, text inputs, configurable value ranges, on:change ev export let max; export let firstSlider; export let secondSlider; + export let inputFieldFrom = 0; + export let inputFieldTo = 0; const dispatch = createEventDispatcher(); @@ -33,7 +35,6 @@ Changes: remove dependency, text inputs, configurable value ranges, on:change ev let leftHandle; let body; let slider; - let inputFieldFrom, inputFieldTo; let timeoutId = null; function queueChangeEvent() { @@ -45,10 +46,10 @@ Changes: remove dependency, text inputs, configurable value ranges, on:change ev timeoutId = null; // Show selection but avoid feedback loop - if (values[0] != null && inputFieldFrom.value != values[0].toString()) - inputFieldFrom.value = values[0].toString(); - if (values[1] != null && inputFieldTo.value != values[1].toString()) - inputFieldTo.value = values[1].toString(); + if (values[0] != null && inputFieldFrom != values[0].toString()) + inputFieldFrom = values[0].toString(); + if (values[1] != null && inputFieldTo != values[1].toString()) + inputFieldTo = values[1].toString(); dispatch('change', values); }, 250); @@ -176,7 +177,7 @@ Changes: remove dependency, text inputs, configurable value ranges, on:change ev const leftHandleLeft = leftHandle.getBoundingClientRect().left; - const pxStart = clamp((leftHandleLeft + event.detail.dx) - left, 0, parentWidth - width); + const pxStart = clamp((leftHandleLeft + evt.detail.dx) - left, 0, parentWidth - width); const pxEnd = clamp(pxStart + width, width, parentWidth); const pStart = pxStart / parentWidth; @@ -190,12 +191,12 @@ Changes: remove dependency, text inputs, configurable value ranges, on:change ev
- inputChanged(0, e)} /> Full Range: {min} - {max} - inputChanged(1, e)} />
diff --git a/web/frontend/src/filters/Filters.svelte b/web/frontend/src/filters/Filters.svelte index d4c390e..b8264d3 100644 --- a/web/frontend/src/filters/Filters.svelte +++ b/web/frontend/src/filters/Filters.svelte @@ -60,7 +60,10 @@ isTagsOpen = false, isDurationOpen = false, isResourcesOpen = false, - isStatsOpen = false + isStatsOpen = false, + isNodesModified = false, + isHwthreadsModified = false, + isAccsModified = false // Can be called from the outside to trigger a 'update' event from this component. export function update(additionalFilters = null) { @@ -181,7 +184,7 @@ Tags (isResourcesOpen = true)}> - Nodes/Accelerators + Resources (isStatsOpen = true)}> (isStatsOpen = true)}/> Statistics @@ -268,9 +271,15 @@ {/if} - {#if filters.numNodes.from != null || filters.numNodes.to != null} + {#if filters.numNodes.from != null || filters.numNodes.to != null || + filters.numHWThreads.from != null || filters.numHWThreads.to != null || + filters.numAccelerators.from != null || filters.numAccelerators.to != null } (isResourcesOpen = true)}> - Nodes: {filters.numNodes.from} - {filters.numNodes.to} + {#if isNodesModified } Nodes: {filters.numNodes.from} - {filters.numNodes.to} {/if} + {#if isNodesModified && isHwthreadsModified }, {/if} + {#if isHwthreadsModified } HWThreads: {filters.numHWThreads.from} - {filters.numHWThreads.to} {/if} + {#if (isNodesModified || isHwthreadsModified) && isAccsModified }, {/if} + {#if isAccsModified } Accelerators: {filters.numAccelerators.from} - {filters.numAccelerators.to} {/if} {/if} @@ -316,6 +325,9 @@ bind:numNodes={filters.numNodes} bind:numHWThreads={filters.numHWThreads} bind:numAccelerators={filters.numAccelerators} + bind:isNodesModified={isNodesModified} + bind:isHwthreadsModified={isHwthreadsModified} + bind:isAccsModified={isAccsModified} on:update={() => update()} /> clusters.reduce((max, cluster) => Math.max(max, cluster.subClusters.reduce((max, sc) => Math.max(max, sc.topology.accelerators?.length || 0), 0)), 0) - // console.log(header) + // Limited to Single-Node Thread Count + const findMaxNumHWTreadsPerNode = clusters => clusters.reduce((max, cluster) => Math.max(max, + cluster.subClusters.reduce((max, sc) => Math.max(max, (sc.threadsPerCore * sc.coresPerSocket * sc.socketsPerNode) || 0), 0)), 0) + + // console.log(header) let minNumNodes = 1, maxNumNodes = 0, minNumHWThreads = 1, maxNumHWThreads = 0, minNumAccelerators = 0, maxNumAccelerators = 0 $: { if ($initialized) { @@ -33,11 +36,13 @@ minNumNodes = filterRanges.numNodes.from maxNumNodes = filterRanges.numNodes.to maxNumAccelerators = findMaxNumAccels([{ subClusters }]) + maxNumHWThreads = findMaxNumHWTreadsPerNode([{ subClusters }]) } else if (clusters.length > 0) { const { filterRanges } = header.clusters[0] minNumNodes = filterRanges.numNodes.from maxNumNodes = filterRanges.numNodes.to maxNumAccelerators = findMaxNumAccels(clusters) + maxNumHWThreads = findMaxNumHWTreadsPerNode(clusters) for (let cluster of header.clusters) { const { filterRanges } = cluster minNumNodes = Math.min(minNumNodes, filterRanges.numNodes.from) @@ -52,27 +57,53 @@ pendingNumNodes = { from: 0, to: maxNumNodes } } } + + $: { + if (isOpen && $initialized && ((pendingNumHWThreads.from == null && pendingNumHWThreads.to == null) || (isHwthreadsModified == false))) { + pendingNumHWThreads = { from: 0, to: maxNumHWThreads } + } + } + + $: if ( maxNumAccelerators != null && maxNumAccelerators > 1 ) { + if (isOpen && $initialized && pendingNumAccelerators.from == null && pendingNumAccelerators.to == null) { + pendingNumAccelerators = { from: 0, to: maxNumAccelerators } + } + } (isOpen = !isOpen)}> - Select Number of Nodes, HWThreads and Accelerators + Select number of utilized Resources -

Number of Nodes

+
Number of Nodes
(pendingNumNodes = { from: detail[0], to: detail[1] })} + on:change={({ detail }) => { + pendingNumNodes = { from: detail[0], to: detail[1] } + isNodesModified = true + }} min={minNumNodes} max={maxNumNodes} - firstSlider={pendingNumNodes.from} secondSlider={pendingNumNodes.to} /> - + firstSlider={pendingNumHWThreads.from} secondSlider={pendingNumHWThreads.to} + inputFieldFrom={pendingNumHWThreads.from} inputFieldTo={pendingNumHWThreads.to}/> {#if maxNumAccelerators != null && maxNumAccelerators > 1} +
Number of Accelerators
(pendingNumAccelerators = { from: detail[0], to: detail[1] })} + on:change={({ detail }) => { + pendingNumAccelerators = { from: detail[0], to: detail[1] } + isAccsModified = true + }} min={minNumAccelerators} max={maxNumAccelerators} - firstSlider={pendingNumAccelerators.from} secondSlider={pendingNumAccelerators.to} /> + firstSlider={pendingNumAccelerators.from} secondSlider={pendingNumAccelerators.to} + inputFieldFrom={pendingNumAccelerators.from} inputFieldTo={pendingNumAccelerators.to}/> {/if}
@@ -80,7 +111,10 @@ disabled={pendingNumNodes.from == null || pendingNumNodes.to == null} on:click={() => { isOpen = false - numNodes = { from: pendingNumNodes.from, to: pendingNumNodes.to } + pendingNumNodes = isNodesModified ? pendingNumNodes : { from: null, to: null } + pendingNumHWThreads = isHwthreadsModified ? pendingNumHWThreads : { from: null, to: null } + pendingNumAccelerators = isAccsModified ? pendingNumAccelerators : { from: null, to: null } + numNodes ={ from: pendingNumNodes.from, to: pendingNumNodes.to } numHWThreads = { from: pendingNumHWThreads.from, to: pendingNumHWThreads.to } numAccelerators = { from: pendingNumAccelerators.from, to: pendingNumAccelerators.to } dispatch('update', { numNodes, numHWThreads, numAccelerators }) @@ -95,6 +129,9 @@ numNodes = { from: pendingNumNodes.from, to: pendingNumNodes.to } numHWThreads = { from: pendingNumHWThreads.from, to: pendingNumHWThreads.to } numAccelerators = { from: pendingNumAccelerators.from, to: pendingNumAccelerators.to } + isNodesModified = false + isHwthreadsModified = false + isAccsModified = false dispatch('update', { numNodes, numHWThreads, numAccelerators }) }}>Reset diff --git a/web/frontend/src/filters/Stats.svelte b/web/frontend/src/filters/Stats.svelte index e7b658d..cf559da 100644 --- a/web/frontend/src/filters/Stats.svelte +++ b/web/frontend/src/filters/Stats.svelte @@ -93,7 +93,8 @@ (stat.from = detail[0], stat.to = detail[1], stat.enabled = true)} min={0} max={stat.peak} - firstSlider={stat.from} secondSlider={stat.to} /> + firstSlider={stat.from} secondSlider={stat.to} + inputFieldFrom={stat.from} inputFieldTo={stat.to}/> {/each} @@ -104,7 +105,8 @@ }}>Close & Apply diff --git a/web/frontend/src/plots/Histogram.svelte b/web/frontend/src/plots/Histogram.svelte index eaaf49c..12d9fc2 100644 --- a/web/frontend/src/plots/Histogram.svelte +++ b/web/frontend/src/plots/Histogram.svelte @@ -196,7 +196,7 @@ +
+