This repository has been archived on 2024-04-10. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
elektron/def/taskUtils.go

115 lines
3.1 KiB
Go
Raw Normal View History

package def
import (
"github.com/mdesenfants/gokmeans"
"sort"
)
// The watts consumption observations are taken into consideration.
func getObservations(tasks []Task) []gokmeans.Node {
observations := []gokmeans.Node{}
for i := 0; i < len(tasks); i++ {
task := tasks[i]
// If observations present for the power-classes, then using it
if task.ClassToWatts != nil {
observation := gokmeans.Node{}
for _, watts := range task.ClassToWatts {
observation = append(observation, watts)
}
observations = append(observations, observation)
} else {
// Using the watts attribute alone
observations = append(observations, gokmeans.Node{task.Watts})
}
}
return observations
}
func clusterSize(tasks []Task) float64 {
size := 0.0
for _, task := range tasks {
if task.ClassToWatts != nil {
for _, powerClassWatts := range task.ClassToWatts {
size += powerClassWatts
}
} else {
size += task.Watts
}
}
return size
}
// information about a cluster of tasks
type TaskCluster struct {
clusterIndex int
tasks []Task
sizeScore int // how many other clusters is this one bigger than (in the current workload)
}
// Sorting TaskClusters based on sizeScore
type TaskClusterSorter []TaskCluster
func (slice TaskClusterSorter) Len() int {
return len(slice)
}
func (slice TaskClusterSorter) Less(i, j int) bool {
return slice[i].sizeScore <= slice[j].sizeScore
}
func (slice TaskClusterSorter) Swap(i, j int) {
slice[i], slice[j] = slice[j], slice[i]
}
// order clusters in increasing order of task heaviness
// TODO: Make this look into task.ClassToWatts, if present.
func order(clusters map[int][]Task, numberOfClusters int) []TaskCluster {
// determine the position of the cluster in the ordered list of clusters
clusterSizeScores := []TaskCluster{}
for i := 0; i < numberOfClusters; i++ {
// sizing the current cluster
sizeI := clusterSize(clusters[i])
// comparing with the other clusters
for j := 0; j != i; j++ {
if sizeI >= clusterSize(clusters[j]) {
if len(clusterSizeScores) >= i {
clusterSizeScores[i].sizeScore++
} else {
clusterSizeScores[i] = TaskCluster{
clusterIndex: i,
tasks: clusters[i],
sizeScore: 1,
}
}
}
}
}
// Sorting the clusters based on sizeScore
sort.Sort(TaskClusterSorter(clusterSizeScores))
return clusterSizeScores
}
// Classification of Tasks using KMeans clustering using the watts consumption observations
type TasksToClassify []Task
func (tc TasksToClassify) ClassifyTasks(numberOfClusters int) []TaskCluster {
clusters := make(map[int][]Task)
observations := getObservations(tc)
// TODO: Make the number of rounds configurable based on the size of the workload
if trained, centroids := gokmeans.Train(observations, numberOfClusters, 50); trained {
for i := 0; i < len(observations); i++ {
observation := observations[i]
classIndex := gokmeans.Nearest(observation, centroids)
if _, ok := clusters[classIndex]; ok {
clusters[classIndex] = append(clusters[classIndex], tc[i])
} else {
clusters[classIndex] = []Task{tc[i]}
}
}
}
return order(clusters, numberOfClusters)
}