@@ -16,6 +16,7 @@ import (
1616// Each map represents a row, with column names as keys and values as strings.
1717// Adds a "timestamp" key to each row, if TIME and INTERVAL are included in
1818// the output by the collection script.
19+ // Only the Summary and Packages rows are returned, i.e., rows for individual cores/CPUs are ignored.
1920func parseTurbostatOutput (output string ) ([]map [string ]string , error ) {
2021 var (
2122 headers []string
@@ -85,7 +86,9 @@ func parseTurbostatOutput(output string) ([]map[string]string, error) {
8586 return rows , nil
8687}
8788
88- // turbostatPlatformRows parses the output of the turbostat script and returns a slice of rows with the specified field names.
89+ // turbostatPlatformRows parses the output of the turbostat script and returns the rows
90+ // for the platform (summary) only, for the specified field names.
91+ // The "platform" rows are those where Package, Die, Core, and CPU are all "-".
8992// The first column is the sample time, and the rest are the values for the specified fields.
9093func turbostatPlatformRows (turboStatScriptOutput string , fieldNames []string ) ([][]string , error ) {
9194 if len (fieldNames ) == 0 {
@@ -105,9 +108,7 @@ func turbostatPlatformRows(turboStatScriptOutput string, fieldNames []string) ([
105108 // filter the rows to the summary rows only
106109 var fieldValues [][]string
107110 for _ , row := range rows {
108- if (row ["Package" ] != "-" && row ["Package" ] != "" ) ||
109- (row ["Core" ] != "-" && row ["Core" ] != "" ) ||
110- (row ["CPU" ] != "-" && row ["CPU" ] != "" ) {
111+ if ! isPlatformRow (row ) {
111112 continue
112113 }
113114 // this is a summary row, extract the values for the specified fields
@@ -129,8 +130,21 @@ func turbostatPlatformRows(turboStatScriptOutput string, fieldNames []string) ([
129130 return fieldValues , nil
130131}
131132
133+ // isPlatformRow returns true if the row represents a platform (summary) row.
134+ // only consider rows where Package, Die, Node, Core, and CPU are "-" (or don't exist), these rows contain the sum of all packages
135+ func isPlatformRow (row map [string ]string ) bool {
136+ for _ , header := range []string {"Package" , "Die" , "Node" , "Core" , "CPU" } {
137+ if val , ok := row [header ]; ok && val != "-" {
138+ return false
139+ }
140+ }
141+ return true
142+ }
143+
132144// turbostatPackageRows
133- // packages -> rows
145+ // parses the output of the turbostat script and returns the rows
146+ // for each package, for the specified field names.
147+ // The first column is the sample time, and the rest are the values for the specified fields.
134148func turbostatPackageRows (turboStatScriptOutput string , fieldNames []string ) ([][][]string , error ) {
135149 if len (fieldNames ) == 0 {
136150 err := fmt .Errorf ("no field names provided" )
@@ -146,16 +160,19 @@ func turbostatPackageRows(turboStatScriptOutput string, fieldNames []string) ([]
146160 return nil , err
147161 }
148162 var packageRows [][][]string
149- prevPackage := ""
150163 for _ , row := range rows {
151- // the first row with a new package number is the package row
152- if row ["Package" ] == "" || row ["Package" ] == "-" {
153- continue // skip rows that are not package rows
164+ // not all instances of turbostat output include a Package column
165+ // if it is missing assume 1 package, set it to 0 for rows where CPU is 0
166+ if _ , ok := row ["Package" ]; ! ok {
167+ if row ["CPU" ] == "0" {
168+ row ["Package" ] = "0"
169+ } else {
170+ continue // skip rows that are not package rows
171+ }
154172 }
155- if row [ "Package" ] == prevPackage {
156- continue // skip rows that are not the first row for this package
173+ if ! isPackageRow ( row ) {
174+ continue
157175 }
158- prevPackage = row ["Package" ]
159176 // this is a package row, extract the values for the specified fields
160177 rowValues := make ([]string , len (fieldNames )+ 1 ) // +1 for the sample time
161178 rowValues [0 ] = row ["timestamp" ] // first column is the sample time
@@ -185,6 +202,15 @@ func turbostatPackageRows(turboStatScriptOutput string, fieldNames []string) ([]
185202 return packageRows , nil
186203}
187204
205+ // isPackageRow returns true if the row represents a package row.
206+ // only consider rows where Package is not "-" or empty
207+ func isPackageRow (row map [string ]string ) bool {
208+ if val , ok := row ["Package" ]; ok && val != "-" {
209+ return true
210+ }
211+ return false
212+ }
213+
188214// maxTotalPackagePowerFromOutput calculates the maximum total package power from the turbostat output.
189215func maxTotalPackagePowerFromOutput (turbostatOutput string ) string {
190216 rows , err := parseTurbostatOutput (turbostatOutput )
0 commit comments