2016-10-17 21:31:10 -04:00
package main
import (
"bufio"
"fmt"
"log"
"os"
"os/exec"
"strings"
"syscall"
"time"
"strconv"
"math"
"container/ring"
"sort"
)
type Victim struct {
Watts float64
Host string
}
type VictimSorter [ ] Victim
func ( slice VictimSorter ) Len ( ) int {
return len ( slice )
}
func ( slice VictimSorter ) Less ( i , j int ) bool {
return slice [ i ] . Watts >= slice [ j ] . Watts
}
func ( slice VictimSorter ) Swap ( i , j int ) {
slice [ i ] , slice [ j ] = slice [ j ] , slice [ i ]
}
var RAPLUnits = math . Pow ( 2 , - 32 )
func mean ( values * ring . Ring ) float64 {
total := 0.0
count := 0.0
values . Do ( func ( x interface { } ) {
if val , ok := x . ( float64 ) ; ok { //Add it if we can get a float
total += val
count ++
}
} )
if count == 0.0 {
return 0.0
}
count /= 2
return ( total / count )
}
//func median(values *ring.Ring) {
//}
func main ( ) {
prefix := "test"
logging := new ( bool )
* logging = true
const pcpCommand string = "pmdumptext -m -l -f '' -t 1.0 -d , -c config"
cmd := exec . Command ( "sh" , "-c" , pcpCommand )
cmd . SysProcAttr = & syscall . SysProcAttr { Setpgid : true }
startTime := time . Now ( ) . Format ( "20060102150405" )
logFile , err := os . Create ( "./" + prefix + startTime + ".pcplog" )
if err != nil {
log . Fatal ( err )
}
defer logFile . Close ( )
pipe , err := cmd . StdoutPipe ( )
if err != nil {
log . Fatal ( err )
}
//cmd.Stdout = stdout
scanner := bufio . NewScanner ( pipe )
go func ( logging * bool ) {
// Get names of the columns
scanner . Scan ( )
// Write to logfile
logFile . WriteString ( scanner . Text ( ) + "\n" )
headers := strings . Split ( scanner . Text ( ) , "," )
powerIndexes := make ( [ ] int , 0 , 0 )
powerAverage := make ( map [ string ] * ring . Ring )
indexToHost := make ( map [ int ] string )
for i , hostMetric := range headers {
split := strings . Split ( hostMetric , ":" )
fmt . Printf ( "%d Host %s: Metric: %s\n" , i , split [ 0 ] , split [ 1 ] )
if strings . Contains ( split [ 1 ] , "RAPL_ENERGY_PKG" ) {
fmt . Println ( "Index: " , i )
powerIndexes = append ( powerIndexes , i )
indexToHost [ i ] = split [ 0 ]
2016-10-18 14:56:07 -04:00
powerAverage [ split [ 0 ] ] = ring . New ( 10 ) // Two PKGS per node, 10 = 5 seconds tracking
2016-10-17 21:31:10 -04:00
}
}
// Throw away first set of results
scanner . Scan ( )
seconds := 0
for scanner . Scan ( ) {
if * logging {
log . Println ( "Logging PCP..." )
split := strings . Split ( scanner . Text ( ) , "," )
logFile . WriteString ( scanner . Text ( ) + "\n" )
totalPower := 0.0
for _ , powerIndex := range powerIndexes {
power , _ := strconv . ParseFloat ( split [ powerIndex ] , 64 )
host := indexToHost [ powerIndex ]
powerAverage [ host ] . Value = power
powerAverage [ host ] = powerAverage [ host ] . Next ( )
log . Printf ( "Host: %s, Index: %d, Power: %f" , indexToHost [ powerIndex ] , powerIndex , ( power * RAPLUnits ) )
totalPower += power
}
log . Println ( "Total power: " , totalPower * RAPLUnits )
victims := make ( [ ] Victim , 8 , 8 )
// TODO: Just keep track of the largest to reduce fron nlogn to n
for name , ring := range powerAverage {
victims = append ( victims , Victim { mean ( ring ) , name } )
//log.Printf("host: %s, Avg: %f", name, mean(ring) * RAPLUnits)
}
sort . Sort ( VictimSorter ( victims ) )
log . Printf ( "Current Victim %s Avg. Wattage: %f" , victims [ 0 ] . Host , victims [ 0 ] . Watts * RAPLUnits )
}
seconds ++
}
} ( logging )
log . Println ( "PCP logging started" )
if err := cmd . Start ( ) ; err != nil {
log . Fatal ( err )
}
if err := cmd . Wait ( ) ; err != nil {
log . Fatal ( err )
}
/ *
pgid , err := syscall . Getpgid ( cmd . Process . Pid )
select {
case <- quit :
log . Println ( "Stopping PCP logging in 5 seconds" )
time . Sleep ( 5 * time . Second )
// http://stackoverflow.com/questions/22470193/why-wont-go-kill-a-child-process-correctly
// kill process and all children processes
syscall . Kill ( - pgid , 15 )
return
} * /
}