// Copyright (C) NHR@FAU, University Erlangen-Nuremberg. // All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. package schema import ( "fmt" "strconv" ) type Accelerator struct { ID string `json:"id"` Type string `json:"type"` Model string `json:"model"` } type Topology struct { Node []int `json:"node"` Socket [][]int `json:"socket"` MemoryDomain [][]int `json:"memoryDomain"` Die [][]*int `json:"die,omitempty"` Core [][]int `json:"core"` Accelerators []*Accelerator `json:"accelerators,omitempty"` } type MetricValue struct { Unit Unit `json:"unit"` Value float64 `json:"value"` } type SubCluster struct { Name string `json:"name"` Nodes string `json:"nodes"` ProcessorType string `json:"processorType"` Topology Topology `json:"topology"` FlopRateScalar MetricValue `json:"flopRateScalar"` FlopRateSimd MetricValue `json:"flopRateSimd"` MemoryBandwidth MetricValue `json:"memoryBandwidth"` MetricConfig []MetricConfig `json:"metricConfig,omitempty"` Footprint []string `json:"footprint,omitempty"` EnergyFootprint []string `json:"energyFootprint,omitempty"` SocketsPerNode int `json:"socketsPerNode"` CoresPerSocket int `json:"coresPerSocket"` ThreadsPerCore int `json:"threadsPerCore"` } type SubClusterConfig struct { Name string `json:"name"` Footprint string `json:"footprint,omitempty"` Energy string `json:"energy"` Peak float64 `json:"peak"` Normal float64 `json:"normal"` Caution float64 `json:"caution"` Alert float64 `json:"alert"` Remove bool `json:"remove"` LowerIsBetter bool `json:"lowerIsBetter"` } type MetricConfig struct { Unit Unit `json:"unit"` Energy string `json:"energy"` Name string `json:"name"` Scope MetricScope `json:"scope"` Aggregation string `json:"aggregation"` Footprint string `json:"footprint,omitempty"` SubClusters []*SubClusterConfig `json:"subClusters,omitempty"` Peak float64 `json:"peak"` Caution float64 `json:"caution"` Alert float64 `json:"alert"` Timestep int `json:"timestep"` Normal float64 `json:"normal"` LowerIsBetter bool `json:"lowerIsBetter"` } type Cluster struct { Name string `json:"name"` MetricConfig []*MetricConfig `json:"metricConfig"` SubClusters []*SubCluster `json:"subClusters"` } type ClusterSupport struct { Cluster string `json:"cluster"` SubClusters []string `json:"subclusters"` } type GlobalMetricListItem struct { Name string `json:"name"` Unit Unit `json:"unit"` Scope MetricScope `json:"scope"` Footprint string `json:"footprint,omitempty"` Availability []ClusterSupport `json:"availability"` } // Return a list of socket IDs given a list of hwthread IDs. Even if just one // hwthread is in that socket, add it to the list. If no hwthreads other than // those in the argument list are assigned to one of the sockets in the first // return value, return true as the second value. TODO: Optimize this, there // must be a more efficient way/algorithm. func (topo *Topology) GetSocketsFromHWThreads( hwthreads []int, ) (sockets []int, exclusive bool) { socketsMap := map[int]int{} for _, hwthread := range hwthreads { for socket, hwthreadsInSocket := range topo.Socket { for _, hwthreadInSocket := range hwthreadsInSocket { if hwthread == hwthreadInSocket { socketsMap[socket] += 1 } } } } exclusive = true hwthreadsPerSocket := len(topo.Node) / len(topo.Socket) sockets = make([]int, 0, len(socketsMap)) for socket, count := range socketsMap { sockets = append(sockets, socket) exclusive = exclusive && count == hwthreadsPerSocket } return sockets, exclusive } // Return a list of core IDs given a list of hwthread IDs. Even if just one // hwthread is in that core, add it to the list. If no hwthreads other than // those in the argument list are assigned to one of the cores in the first // return value, return true as the second value. TODO: Optimize this, there // must be a more efficient way/algorithm. func (topo *Topology) GetCoresFromHWThreads( hwthreads []int, ) (cores []int, exclusive bool) { coresMap := map[int]int{} for _, hwthread := range hwthreads { for core, hwthreadsInCore := range topo.Core { for _, hwthreadInCore := range hwthreadsInCore { if hwthread == hwthreadInCore { coresMap[core] += 1 } } } } exclusive = true hwthreadsPerCore := len(topo.Node) / len(topo.Core) cores = make([]int, 0, len(coresMap)) for core, count := range coresMap { cores = append(cores, core) exclusive = exclusive && count == hwthreadsPerCore } return cores, exclusive } // Return a list of memory domain IDs given a list of hwthread IDs. Even if // just one hwthread is in that memory domain, add it to the list. If no // hwthreads other than those in the argument list are assigned to one of the // memory domains in the first return value, return true as the second value. // TODO: Optimize this, there must be a more efficient way/algorithm. func (topo *Topology) GetMemoryDomainsFromHWThreads( hwthreads []int, ) (memDoms []int, exclusive bool) { memDomsMap := map[int]int{} for _, hwthread := range hwthreads { for memDom, hwthreadsInmemDom := range topo.MemoryDomain { for _, hwthreadInmemDom := range hwthreadsInmemDom { if hwthread == hwthreadInmemDom { memDomsMap[memDom] += 1 } } } } exclusive = true hwthreadsPermemDom := len(topo.Node) / len(topo.MemoryDomain) memDoms = make([]int, 0, len(memDomsMap)) for memDom, count := range memDomsMap { memDoms = append(memDoms, memDom) exclusive = exclusive && count == hwthreadsPermemDom } return memDoms, exclusive } // Temporary fix to convert back from int id to string id for accelerators func (topo *Topology) GetAcceleratorID(id int) (string, error) { if id < 0 { fmt.Printf("ID smaller than 0!\n") return topo.Accelerators[0].ID, nil } else if id < len(topo.Accelerators) { return topo.Accelerators[id].ID, nil } else { return "", fmt.Errorf("index %d out of range", id) } } func (topo *Topology) GetAcceleratorIDs() ([]int, error) { accels := make([]int, 0) for _, accel := range topo.Accelerators { id, err := strconv.Atoi(accel.ID) if err != nil { return nil, err } accels = append(accels, id) } return accels, nil }