From f29b7f51a90b728d81291fe64698a31f56408373 Mon Sep 17 00:00:00 2001 From: Pradyumna Kaushik Date: Wed, 23 Aug 2017 19:35:19 -0400 Subject: [PATCH 1/7] Added a generic task sorter utility. This allows for an array of tasks to be sorted based on any resource. The possible resources by which an array of tasks can be sorted currently are listed in def/sortingCriteria.go. One can add more to this if required. --- def/sortingCriteria.go | 29 +++++++++++++++++++++++++++++ def/taskUtils.go | 15 +++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 def/sortingCriteria.go diff --git a/def/sortingCriteria.go b/def/sortingCriteria.go new file mode 100644 index 0000000..fadf562 --- /dev/null +++ b/def/sortingCriteria.go @@ -0,0 +1,29 @@ +package def + +// Creating an enumeration of the resources in def.Task. +var TaskResourceNames []string + +type SortCriteria int + +// Map a task's resource name to the sorting criteria (an integer corresponding to the enumeration). +func resourceToSortCriteria(resourceName string) SortCriteria { + // Appending resourceName to TaskResourceNames. + TaskResourceNames = append(TaskResourceNames, resourceName) + + // Considering index of resource in TaskResourceNames to be the int mapping. + return SortCriteria(len(TaskResourceNames) - 1) +} + +func (sc SortCriteria) String() string { + return TaskResourceNames[int(sc)] +} + +// Possible Sorting Criteria +// Note: the value of the string passed as argument to resourceToSortCriteria() should be the same (case-sensitive) +// as the name of the of the corresponding resource in the struct. +var ( + CPU = resourceToSortCriteria("CPU") + RAM = resourceToSortCriteria("RAM") + Watts = resourceToSortCriteria("Watts") + Instances = resourceToSortCriteria("Instances") +) diff --git a/def/taskUtils.go b/def/taskUtils.go index 2b56be3..5dbeb4a 100644 --- a/def/taskUtils.go +++ b/def/taskUtils.go @@ -4,6 +4,7 @@ import ( "github.com/mdesenfants/gokmeans" "sort" "log" + "reflect" ) // Information about a cluster of tasks @@ -114,3 +115,17 @@ func labelAndOrder(clusters map[int][]Task, numberOfClusters int, taskObservatio }) return sizedClusters } + +// Generic Task Sorter. +// Be able to sort an array of tasks based on any of the tasks' resources. + +// Retrieve a sorter (same signature as 'Less' function in sort.Interface) for the given sorting criteria. +func TaskSorter(sc SortCriteria, tasks []Task) func (i, j int) bool { + return func (i, j int) bool { + taskIFields := reflect.Indirect(reflect.ValueOf(tasks[i])) + tasksJFields := reflect.Indirect(reflect.ValueOf(tasks[j])) + resourceI := taskIFields.FieldByName(sc.String()).Float() + resourceJ := tasksJFields.FieldByName(sc.String()).Float() + return resourceI <= resourceJ + } +} From c2c7a2c09093e29cda88a6e7d99d44ffa7ce400a Mon Sep 17 00:00:00 2001 From: Pradyumna Kaushik Date: Wed, 23 Aug 2017 20:06:44 -0400 Subject: [PATCH 2/7] Added TODO to use the generic task sorters and get rid of the existing sorters present in def/task.go --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d93a97c..c59816d 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ To Do: * **Critical** -- Retrofit to use Go 1.8 sorting techniques. Use def/taskUtils.go for reference. * Handle powerclass not configured on a node condition. As of now, an assumption is made that the powerclass is configured * Refine the sorting algorithm that sorts the clusters of tasks retrieved using the kmeans algorithm. This also involves the reduction in time complexity of the same. + * Use the generic task sorter in def/taskUtils.go to sort the tasks based on CPU or RAM etc. Remove the existing sorters present in def/task.go. for all the nodes. **Requires [Performance Co-Pilot](http://pcp.io/) tool pmdumptext to be installed on the From 3c65bdf02e67dac4a03190fb7ee453952cadb8ed Mon Sep 17 00:00:00 2001 From: Pradyumna Kaushik Date: Wed, 23 Aug 2017 20:10:33 -0400 Subject: [PATCH 3/7] changed the scope of TaskResourceNames and SortCriteria to be package private. --- def/sortingCriteria.go | 14 +++++++------- def/taskUtils.go | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/def/sortingCriteria.go b/def/sortingCriteria.go index fadf562..994581a 100644 --- a/def/sortingCriteria.go +++ b/def/sortingCriteria.go @@ -1,21 +1,21 @@ package def // Creating an enumeration of the resources in def.Task. -var TaskResourceNames []string +var taskResourceNames []string -type SortCriteria int +type sortCriteria int // Map a task's resource name to the sorting criteria (an integer corresponding to the enumeration). -func resourceToSortCriteria(resourceName string) SortCriteria { +func resourceToSortCriteria(resourceName string) sortCriteria { // Appending resourceName to TaskResourceNames. - TaskResourceNames = append(TaskResourceNames, resourceName) + taskResourceNames = append(taskResourceNames, resourceName) // Considering index of resource in TaskResourceNames to be the int mapping. - return SortCriteria(len(TaskResourceNames) - 1) + return sortCriteria(len(taskResourceNames) - 1) } -func (sc SortCriteria) String() string { - return TaskResourceNames[int(sc)] +func (sc sortCriteria) String() string { + return taskResourceNames[int(sc)] } // Possible Sorting Criteria diff --git a/def/taskUtils.go b/def/taskUtils.go index 5dbeb4a..e175e5f 100644 --- a/def/taskUtils.go +++ b/def/taskUtils.go @@ -120,7 +120,7 @@ func labelAndOrder(clusters map[int][]Task, numberOfClusters int, taskObservatio // Be able to sort an array of tasks based on any of the tasks' resources. // Retrieve a sorter (same signature as 'Less' function in sort.Interface) for the given sorting criteria. -func TaskSorter(sc SortCriteria, tasks []Task) func (i, j int) bool { +func TaskSorter(sc sortCriteria, tasks []Task) func (i, j int) bool { return func (i, j int) bool { taskIFields := reflect.Indirect(reflect.ValueOf(tasks[i])) tasksJFields := reflect.Indirect(reflect.ValueOf(tasks[j])) From 0869bea2d86fb2ebc7b4faac5fafdb278bf0333b Mon Sep 17 00:00:00 2001 From: Pradyumna Kaushik Date: Sat, 26 Aug 2017 15:19:30 -0400 Subject: [PATCH 4/7] Used closures instead of strings for the generic sorter. This removed the need for reflection. --- def/sortingCriteria.go | 30 +++++++----------------------- def/taskUtils.go | 10 +++------- 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/def/sortingCriteria.go b/def/sortingCriteria.go index 994581a..b4b6213 100644 --- a/def/sortingCriteria.go +++ b/def/sortingCriteria.go @@ -1,29 +1,13 @@ package def -// Creating an enumeration of the resources in def.Task. -var taskResourceNames []string - -type sortCriteria int - -// Map a task's resource name to the sorting criteria (an integer corresponding to the enumeration). -func resourceToSortCriteria(resourceName string) sortCriteria { - // Appending resourceName to TaskResourceNames. - taskResourceNames = append(taskResourceNames, resourceName) - - // Considering index of resource in TaskResourceNames to be the int mapping. - return sortCriteria(len(taskResourceNames) - 1) -} - -func (sc sortCriteria) String() string { - return taskResourceNames[int(sc)] -} +// the sortBy function that takes a task reference and returns the resource to consider when sorting. +type sortBy func (task *Task) float64 // Possible Sorting Criteria -// Note: the value of the string passed as argument to resourceToSortCriteria() should be the same (case-sensitive) -// as the name of the of the corresponding resource in the struct. +// Each holds a closure that fetches the required resource from the +// given task reference. var ( - CPU = resourceToSortCriteria("CPU") - RAM = resourceToSortCriteria("RAM") - Watts = resourceToSortCriteria("Watts") - Instances = resourceToSortCriteria("Instances") + SortByCPU = func (task *Task) float64 {return task.CPU} + SortByRAM = func (task *Task) float64 {return task.RAM} + SortByWatts = func (task *Task) float64 {return task.Watts} ) diff --git a/def/taskUtils.go b/def/taskUtils.go index e175e5f..2a318dc 100644 --- a/def/taskUtils.go +++ b/def/taskUtils.go @@ -4,7 +4,6 @@ import ( "github.com/mdesenfants/gokmeans" "sort" "log" - "reflect" ) // Information about a cluster of tasks @@ -120,12 +119,9 @@ func labelAndOrder(clusters map[int][]Task, numberOfClusters int, taskObservatio // Be able to sort an array of tasks based on any of the tasks' resources. // Retrieve a sorter (same signature as 'Less' function in sort.Interface) for the given sorting criteria. -func TaskSorter(sc sortCriteria, tasks []Task) func (i, j int) bool { +type TasksToSort []Task +func (ts TasksToSort) TaskSorter(sb sortBy) func (i, j int) bool { return func (i, j int) bool { - taskIFields := reflect.Indirect(reflect.ValueOf(tasks[i])) - tasksJFields := reflect.Indirect(reflect.ValueOf(tasks[j])) - resourceI := taskIFields.FieldByName(sc.String()).Float() - resourceJ := tasksJFields.FieldByName(sc.String()).Float() - return resourceI <= resourceJ + return sb(&ts[i]) <= sb(&ts[j]) } } From 9e620eaede16c12e3216cd84c6434202fe80e839 Mon Sep 17 00:00:00 2001 From: Pradyumna Kaushik Date: Sat, 26 Aug 2017 15:39:45 -0400 Subject: [PATCH 5/7] changed def.TaskSorter(...) to def.SortTasks(...) for semantics. Now, def.SortTasks(...) also sorts the tasks instead of returning just a func (i, j int) bool {}. Removed TODO from the README associated with this PR --- README.md | 1 - def/taskUtils.go | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c59816d..2e0ee06 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,6 @@ To Do: * Have a centralised logFile that can be filtered by identifier. All electron logs should go into this file. * Make def.Task an interface for further modularization and flexibility. * Convert def#WattsToConsider(...) to be a receiver of def.Task and change the name of it to Watts(...). - * Have a generic sorter for task resources instead of having one for each kind of resource. * **Critical** -- Add software requirements to the README.md (Mesos version, RAPL version, PCP version, Go version...) * **Critical** -- Retrofit to use Go 1.8 sorting techniques. Use def/taskUtils.go for reference. * Handle powerclass not configured on a node condition. As of now, an assumption is made that the powerclass is configured diff --git a/def/taskUtils.go b/def/taskUtils.go index 2a318dc..d36875d 100644 --- a/def/taskUtils.go +++ b/def/taskUtils.go @@ -119,9 +119,8 @@ func labelAndOrder(clusters map[int][]Task, numberOfClusters int, taskObservatio // Be able to sort an array of tasks based on any of the tasks' resources. // Retrieve a sorter (same signature as 'Less' function in sort.Interface) for the given sorting criteria. -type TasksToSort []Task -func (ts TasksToSort) TaskSorter(sb sortBy) func (i, j int) bool { - return func (i, j int) bool { +func SortTasks(ts []Task, sb sortBy) { + sort.SliceStable(ts, func (i, j int) bool { return sb(&ts[i]) <= sb(&ts[j]) - } + }) } From 8bc408dea12ab3693c7807111f46d464e24d0a7c Mon Sep 17 00:00:00 2001 From: Pradyumna Kaushik Date: Sat, 26 Aug 2017 15:43:09 -0400 Subject: [PATCH 6/7] fixed comments. Removed an old comment that no longer made sense. --- def/taskUtils.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/def/taskUtils.go b/def/taskUtils.go index d36875d..bbe53d7 100644 --- a/def/taskUtils.go +++ b/def/taskUtils.go @@ -117,8 +117,6 @@ func labelAndOrder(clusters map[int][]Task, numberOfClusters int, taskObservatio // Generic Task Sorter. // Be able to sort an array of tasks based on any of the tasks' resources. - -// Retrieve a sorter (same signature as 'Less' function in sort.Interface) for the given sorting criteria. func SortTasks(ts []Task, sb sortBy) { sort.SliceStable(ts, func (i, j int) bool { return sb(&ts[i]) <= sb(&ts[j]) From 3a9db01fa0b21f0c4a53d577d971b95f4c9d7c02 Mon Sep 17 00:00:00 2001 From: Pradyumna Kaushik Date: Sat, 26 Aug 2017 22:33:06 -0400 Subject: [PATCH 7/7] formatted files --- def/sortingCriteria.go | 8 ++++---- def/taskUtils.go | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/def/sortingCriteria.go b/def/sortingCriteria.go index b4b6213..e595266 100644 --- a/def/sortingCriteria.go +++ b/def/sortingCriteria.go @@ -1,13 +1,13 @@ package def // the sortBy function that takes a task reference and returns the resource to consider when sorting. -type sortBy func (task *Task) float64 +type sortBy func(task *Task) float64 // Possible Sorting Criteria // Each holds a closure that fetches the required resource from the // given task reference. var ( - SortByCPU = func (task *Task) float64 {return task.CPU} - SortByRAM = func (task *Task) float64 {return task.RAM} - SortByWatts = func (task *Task) float64 {return task.Watts} + SortByCPU = func(task *Task) float64 { return task.CPU } + SortByRAM = func(task *Task) float64 { return task.RAM } + SortByWatts = func(task *Task) float64 { return task.Watts } ) diff --git a/def/taskUtils.go b/def/taskUtils.go index bbe53d7..733754e 100644 --- a/def/taskUtils.go +++ b/def/taskUtils.go @@ -2,8 +2,8 @@ package def import ( "github.com/mdesenfants/gokmeans" - "sort" "log" + "sort" ) // Information about a cluster of tasks @@ -118,7 +118,7 @@ func labelAndOrder(clusters map[int][]Task, numberOfClusters int, taskObservatio // Generic Task Sorter. // Be able to sort an array of tasks based on any of the tasks' resources. func SortTasks(ts []Task, sb sortBy) { - sort.SliceStable(ts, func (i, j int) bool { + sort.SliceStable(ts, func(i, j int) bool { return sb(&ts[i]) <= sb(&ts[j]) }) }