23
23
package org .powerapi .app
24
24
25
25
import java .lang .management .ManagementFactory
26
- import org .powerapi .core .target .{ Application , All , Process , Target }
26
+ import org .powerapi .core .target ._
27
27
import org .powerapi .module .rapl .RAPLModule
28
28
import org .powerapi .reporter .{FileDisplay , JFreeChartDisplay , ConsoleDisplay }
29
- import org .powerapi .{PowerMonitoring , PowerMeter }
29
+ import org .powerapi .{PowerDisplay , PowerMonitoring , PowerMeter }
30
30
import org .powerapi .core .power ._
31
31
import org .powerapi .module .cpu .dvfs .CpuDvfsModule
32
32
import org .powerapi .module .cpu .simple .{SigarCpuSimpleModule , ProcFSCpuSimpleModule }
33
- import org .powerapi .module .libpfm .{ LibpfmModule , LibpfmHelper , LibpfmCoreProcessModule , LibpfmCoreModule , LibpfmProcessModule }
33
+ import org .powerapi .module .libpfm ._
34
34
import org .powerapi .module .extPMeter .powerspy .PowerSpyModule
35
35
import org .powerapi .module .extPMeter .g5k .G5kOmegaWattModule
36
36
import scala .concurrent .duration .DurationInt
37
37
import scala .sys
38
38
import scala .sys .process .stringSeqToProcess
39
+ import scala .util .matching .Regex
39
40
40
41
/**
41
42
* PowerAPI CLI.
@@ -47,8 +48,9 @@ object PowerAPI extends App {
47
48
val modulesR = """ (procfs-cpu-simple|sigar-cpu-simple|cpu-dvfs|libpfm|libpfm-process|libpfm-core|libpfm-core-process|powerspy|g5k-omegawatt|rapl)(,(procfs-cpu-simple|sigar-cpu-simple|cpu-dvfs|libpfm|libpfm-process|libpfm-core|libpfm-core-process|powerspy|g5k-omegawatt|rapl))*""" .r
48
49
val aggR = """ max|min|geomean|logsum|mean|median|stdev|sum|variance""" .r
49
50
val durationR = """ \d+""" .r
50
- val pidR = """ (\d+)""" .r
51
- val appR = """ (.+)""" .r
51
+ val pidsR = """ (\d+)(,(\d+))*""" .r
52
+ val appsR = """ ([^,]+)(,([^,]+))*""" .r
53
+ val containersR = """ ([^,]+)(,([^,]+))*""" .r
52
54
53
55
@ volatile var powerMeters = Seq [PowerMeter ]()
54
56
@ volatile var monitors = Seq [PowerMonitoring ]()
@@ -60,13 +62,8 @@ object PowerAPI extends App {
60
62
powerMeters = Seq ()
61
63
}
62
64
63
- def validateModules (str : String ) = str match {
64
- case modulesR(_* ) => true
65
- case _ => false
66
- }
67
-
68
- def validateAgg (str : String ): Boolean = str match {
69
- case aggR(_* ) => true
65
+ def validate (regex : Regex , str : String ) = str match {
66
+ case regex(_* ) => true
70
67
case _ => false
71
68
}
72
69
@@ -84,42 +81,25 @@ object PowerAPI extends App {
84
81
}
85
82
}
86
83
87
- def validateDuration (str : String ): Boolean = str match {
88
- case durationR(_* ) => true
89
- case _ => false
90
- }
91
-
92
- implicit def targetsStrToTargets (str : String ): Seq [Target ] = {
93
- val strTargets = if (str.split(" ," ).contains(" all" )) {
94
- " all"
95
- }
96
- else str
97
-
98
- (for (target <- strTargets.split(" ," )) yield {
99
- target match {
100
- case " " => Process (ManagementFactory .getRuntimeMXBean.getName.split(" @" )(0 ).toInt)
101
- case " all" => All
102
- case pidR(pid) => Process (pid.toInt)
103
- case appR(app) => Application (app)
104
- }
105
- }).toSeq
106
- }
107
-
108
84
def printHelp (): Unit = {
109
85
val str =
110
86
"""
111
87
|PowerAPI, Spirals Team
112
88
|
113
89
|Build a software-defined power meter. Do not forget to configure correctly the modules.
114
- |You can use different settings per software-defined power meter for some modules by using the optional prefix option.
90
+ |Different settings can be used per software-defined power meter by using the prefix option.
115
91
|Please, refer to the documentation inside the GitHub wiki for further details.
116
92
|
117
- |usage: ./powerapi modules [procfs-cpu-simple|sigar-cpu-simple|cpu-dvfs|libpfm|libpfm-process|libpfm-core|libpfm-core-proces|powerspy|g5k-omegawatt|rapl,...] *--prefix [name]* \
118
- | monitor --frequency [ms] --targets [pid, ..., app, ...|all] --agg [max|min|geomean|logsum|mean|median|stdev|sum|variance] --[console,file [filepath],chart] \
93
+ |usage: ./powerapi modules procfs-cpu-simple|sigar-cpu-simple|cpu-dvfs|libpfm|libpfm-process|libpfm-core|libpfm-core-process|powerspy|g5k-omegawatt|rapl (1, *) *--prefix [name]*
94
+ | monitor (1, *)
95
+ | --frequency $MILLISECONDS
96
+ | --self (0, 1) --pids [pid, ...] (0, *) --apps [app, ...] (0, *) --containers [id, ...] (0, *) | all (0, 1)
97
+ | --agg max|min|geomean|logsum|mean|median|stdev|sum|variance
98
+ | --console (0, 1) --file $FILEPATH (0, *) --chart (0, 1)
119
99
| duration [s]
120
100
|
121
- |example: ./powerapi modules procfs-cpu-simple monitor --frequency 1000 --targets firefox,chrome --agg max --console \
122
- | modules powerspy --prefix powermeter2 monitor --frequency 1000 --targets all --agg max --console \
101
+ |example: ./powerapi modules procfs-cpu-simple monitor --frequency 1000 --apps firefox,chrome --agg max --console \
102
+ | modules powerspy --prefix powermeter2 monitor --frequency 1000 --all --agg max --console \
123
103
| duration 30
124
104
""" .stripMargin
125
105
@@ -128,30 +108,34 @@ object PowerAPI extends App {
128
108
129
109
def cli (options : List [Map [Symbol , Any ]], duration : String , args : List [String ]): (List [Map [Symbol , Any ]], String ) = args match {
130
110
case Nil => (options, duration)
131
- case " modules" :: value :: " --prefix" :: prefix :: " monitor" :: tail if validateModules( value) => {
111
+ case " modules" :: value :: " --prefix" :: prefix :: " monitor" :: tail if validate(modulesR, value) => {
132
112
val (remainingArgs, monitors) = cliMonitorsSubcommand(List (), Map (), tail.map(_.toString))
133
113
cli(options :+ Map (' modules -> value, ' prefix -> Some (prefix), ' monitors -> monitors), duration, remainingArgs)
134
114
}
135
- case " modules" :: value :: " monitor" :: tail if validateModules( value) => {
115
+ case " modules" :: value :: " monitor" :: tail if validate(modulesR, value) => {
136
116
val (remainingArgs, monitors) = cliMonitorsSubcommand(List (), Map (), tail.map(_.toString))
137
117
cli(options :+ Map (' modules -> value, ' prefix -> None , ' monitors -> monitors), duration, remainingArgs)
138
118
}
139
- case " duration" :: value :: tail if validateDuration( value) => cli(options, value, tail)
119
+ case " duration" :: value :: tail if validate(durationR, value) => cli(options, value, tail)
140
120
case option :: tail => println(s " unknown cli option $option" ); sys.exit(1 )
141
121
}
142
122
143
123
def cliMonitorsSubcommand (options : List [Map [Symbol , Any ]], currentMonitor : Map [Symbol , Any ], args : List [String ]): (List [String ], List [Map [Symbol , Any ]]) = args match {
144
124
case Nil => (List (), options :+ currentMonitor)
145
- case " modules" :: value :: " --prefix" :: prefix :: " monitor" :: tail if validateModules( value) => (List (" modules" , value, " --prefix" , prefix, " monitor" ) ++ tail, options :+ currentMonitor)
146
- case " modules" :: value :: " monitor" :: tail if validateModules( value) => (List (" modules" , value, " monitor" ) ++ tail, options :+ currentMonitor)
147
- case " duration" :: value :: tail if validateDuration( value) => (List (" duration" , value) ++ tail, options :+ currentMonitor)
125
+ case " modules" :: value :: " --prefix" :: prefix :: " monitor" :: tail if validate(modulesR, value) => (List (" modules" , value, " --prefix" , prefix, " monitor" ) ++ tail, options :+ currentMonitor)
126
+ case " modules" :: value :: " monitor" :: tail if validate(modulesR, value) => (List (" modules" , value, " monitor" ) ++ tail, options :+ currentMonitor)
127
+ case " duration" :: value :: tail if validate(durationR, value) => (List (" duration" , value) ++ tail, options :+ currentMonitor)
148
128
case " monitor" :: tail => cliMonitorsSubcommand(options :+ currentMonitor, Map (), tail)
149
- case " --frequency" :: value :: tail if validateDuration(value) => cliMonitorsSubcommand(options, currentMonitor ++ Map (' frequency -> value), tail)
150
- case " --targets" :: value :: tail => cliMonitorsSubcommand(options, currentMonitor ++ Map (' targets -> value), tail)
151
- case " --agg" :: value :: tail if validateAgg(value) => cliMonitorsSubcommand(options, currentMonitor ++ Map (' agg -> value), tail)
152
- case " --console" :: tail => cliMonitorsSubcommand(options, currentMonitor ++ Map (' console -> " true" ), tail)
153
- case " --file" :: value :: tail => cliMonitorsSubcommand(options, currentMonitor ++ Map (' file -> value), tail)
154
- case " --chart" :: tail => cliMonitorsSubcommand(options, currentMonitor ++ Map (' chart -> " true" ), tail)
129
+ case " --frequency" :: value :: tail if validate(durationR, value) => cliMonitorsSubcommand(options, currentMonitor ++ Map (' frequency -> value), tail)
130
+ case " --self" :: tail => cliMonitorsSubcommand(options, currentMonitor + (' targets -> (currentMonitor.getOrElse(' targets , Set [Any ]()).asInstanceOf [Set [Any ]] + Process (ManagementFactory .getRuntimeMXBean.getName.split(" @" )(0 ).toInt))), tail)
131
+ case " --pids" :: value :: tail if validate(pidsR, value) => cliMonitorsSubcommand(options, currentMonitor + (' targets -> (currentMonitor.getOrElse(' targets , Set [Any ]()).asInstanceOf [Set [Any ]] ++ value.split(" ," ).map(pid => Process (pid.toInt)))), tail)
132
+ case " --apps" :: value :: tail if validate(appsR, value) => cliMonitorsSubcommand(options, currentMonitor + (' targets -> (currentMonitor.getOrElse(' targets , Set [Any ]()).asInstanceOf [Set [Any ]] ++ value.split(" ," ).map(app => Application (app)))), tail)
133
+ case " --containers" :: value :: tail if validate(containersR, value) => cliMonitorsSubcommand(options, currentMonitor + (' targets -> (currentMonitor.getOrElse(' targets , Set [Any ]()).asInstanceOf [Set [Any ]] ++ value.split(" ," ).map(container => Container (container)))), tail)
134
+ case " --all" :: tail => cliMonitorsSubcommand(options, currentMonitor + (' targets -> (currentMonitor.getOrElse(' targets , Set [Any ]()).asInstanceOf [Set [Any ]] + All )), tail)
135
+ case " --agg" :: value :: tail if validate(aggR, value) => cliMonitorsSubcommand(options, currentMonitor ++ Map (' agg -> value), tail)
136
+ case " --console" :: tail => cliMonitorsSubcommand(options, currentMonitor + (' displays -> (currentMonitor.getOrElse(' displays , Set [Any ]()).asInstanceOf [Set [Any ]] + new ConsoleDisplay )), tail)
137
+ case " --file" :: value :: tail => cliMonitorsSubcommand(options, currentMonitor + (' displays -> (currentMonitor.getOrElse(' displays , Set [Any ]()).asInstanceOf [Set [Any ]] + new FileDisplay (value))), tail)
138
+ case " --chart" :: tail => cliMonitorsSubcommand(options, currentMonitor + (' displays -> (currentMonitor.getOrElse(' displays , Set [Any ]()).asInstanceOf [Set [Any ]] + new JFreeChartDisplay )), tail)
155
139
case option :: tail => println(s " unknown monitor option $option" ); sys.exit(1 )
156
140
}
157
141
@@ -162,6 +146,8 @@ object PowerAPI extends App {
162
146
163
147
else {
164
148
if (System .getProperty(" os.name" ).toLowerCase.indexOf(" nix" ) >= 0 || System .getProperty(" os.name" ).toLowerCase.indexOf(" nux" ) >= 0 ) Seq (" bash" , " scripts/system.bash" ).!
149
+ System .setProperty(" java.library.path" , " lib" )
150
+
165
151
val (configuration, duration) = cli(List (), " 3600" , args.toList)
166
152
167
153
var libpfmHelper : Option [LibpfmHelper ] = None
@@ -192,28 +178,18 @@ object PowerAPI extends App {
192
178
193
179
for (monitorConf <- powerMeterConf(' monitors ).asInstanceOf [List [Map [Symbol , Any ]]]) {
194
180
val frequency = monitorConf.getOrElse(' frequency , " 1000" ).toString.toInt.milliseconds
195
- val targets : Seq [Target ] = monitorConf.getOrElse(' targets , " " ).toString.toLowerCase
181
+ val targets = {
182
+ val uniqueTargets = monitorConf.getOrElse(' targets , Set (Process (ManagementFactory .getRuntimeMXBean.getName.split(" @" )(0 ).toInt))).asInstanceOf [Set [Target ]].toSeq
183
+ if (uniqueTargets.contains(All )) Seq (All ) else uniqueTargets
184
+ }
196
185
val agg : Seq [Power ] => Power = aggStrToAggFunction(monitorConf.getOrElse(' agg , " max" ).toString.toLowerCase)
197
- val console = monitorConf.getOrElse(' console , " " ).toString
198
- val file = monitorConf.getOrElse(' file , " " ).toString
199
- val chart = monitorConf.getOrElse(' chart , " " ).toString
186
+ val displays = monitorConf.getOrElse(' displays , Set (new ConsoleDisplay )).asInstanceOf [Set [PowerDisplay ]]
200
187
201
188
val monitor = powerMeter.monitor(frequency)(targets : _* )(agg)
202
189
monitors :+= monitor
203
190
204
- if (console != " " ) {
205
- val consoleDisplay = new ConsoleDisplay ()
206
- monitor.to(consoleDisplay)
207
- }
208
-
209
- if (file != " " ) {
210
- val fileDisplay = new FileDisplay (file)
211
- monitor.to(fileDisplay)
212
- }
213
-
214
- if (chart != " " ) {
215
- val chartDisplay = new JFreeChartDisplay ()
216
- monitor.to(chartDisplay)
191
+ for (display <- displays) {
192
+ monitor.to(display)
217
193
}
218
194
}
219
195
}
@@ -231,3 +207,4 @@ object PowerAPI extends App {
231
207
shutdownHookThread.remove()
232
208
sys.exit(0 )
233
209
}
210
+
0 commit comments