From f0685919fdc98979e045732cb63a4bd577a30fd1 Mon Sep 17 00:00:00 2001 From: Jan Eitzinger Date: Thu, 15 Jun 2023 12:00:45 +0200 Subject: [PATCH 1/6] Streamline auth error handling --- internal/auth/ldap.go | 5 +++-- internal/auth/local.go | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) 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 From 2146fccaaeebe95ca83346a0a0dab0ac1f238e36 Mon Sep 17 00:00:00 2001 From: Christoph Kluge Date: Thu, 15 Jun 2023 15:40:24 +0200 Subject: [PATCH 2/6] Improve resources filter --- .../src/filters/DoubleRangeSlider.svelte | 17 ++--- web/frontend/src/filters/Filters.svelte | 20 ++++-- web/frontend/src/filters/Resources.svelte | 67 ++++++++++++++----- web/frontend/src/filters/Stats.svelte | 6 +- 4 files changed, 81 insertions(+), 29 deletions(-) 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) { + 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 From dbd2b491ed96136575b9602a2f4c43fda9d9aa21 Mon Sep 17 00:00:00 2001 From: Christoph Kluge Date: Thu, 15 Jun 2023 16:11:51 +0200 Subject: [PATCH 3/6] Correct default values when switching clusters --- web/frontend/src/filters/Resources.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/frontend/src/filters/Resources.svelte b/web/frontend/src/filters/Resources.svelte index b95e04e..ae1bc10 100644 --- a/web/frontend/src/filters/Resources.svelte +++ b/web/frontend/src/filters/Resources.svelte @@ -59,7 +59,7 @@ } $: { - if (isOpen && $initialized && pendingNumHWThreads.from == null && pendingNumHWThreads.to == null) { + if (isOpen && $initialized && ((pendingNumHWThreads.from == null && pendingNumHWThreads.to == null) || (isHwthreadsModified == false))) { pendingNumHWThreads = { from: 0, to: maxNumHWThreads } } } From ece57bf65ea8b2228a7bc02b63f13e049e9256a0 Mon Sep 17 00:00:00 2001 From: Christoph Kluge Date: Fri, 16 Jun 2023 12:44:34 +0200 Subject: [PATCH 4/6] Introduce units.js, centralizes value normalizing --- web/frontend/src/Status.root.svelte | 29 +++++++++++++++++------- web/frontend/src/plots/Histogram.svelte | 2 +- web/frontend/src/plots/MetricPlot.svelte | 4 +++- web/frontend/src/plots/Roofline.svelte | 11 +-------- web/frontend/src/plots/Scatter.svelte | 2 +- web/frontend/src/units.js | 29 ++++++++++++++++++++++++ web/frontend/src/utils.js | 16 ------------- 7 files changed, 56 insertions(+), 37 deletions(-) create mode 100644 web/frontend/src/units.js diff --git a/web/frontend/src/Status.root.svelte b/web/frontend/src/Status.root.svelte index 2b57bfa..8dcc82e 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 } } @@ -116,12 +119,22 @@ 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/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 @@ +
+