2323package org .powerapi .app
2424
2525import java .lang .management .ManagementFactory
26- import org .powerapi .core .target .{ Application , All , Process , Target }
26+ import org .powerapi .core .target ._
2727import org .powerapi .module .rapl .RAPLModule
2828import org .powerapi .reporter .{FileDisplay , JFreeChartDisplay , ConsoleDisplay }
29- import org .powerapi .{PowerMonitoring , PowerMeter }
29+ import org .powerapi .{PowerDisplay , PowerMonitoring , PowerMeter }
3030import org .powerapi .core .power ._
3131import org .powerapi .module .cpu .dvfs .CpuDvfsModule
3232import org .powerapi .module .cpu .simple .{SigarCpuSimpleModule , ProcFSCpuSimpleModule }
33- import org .powerapi .module .libpfm .{ LibpfmModule , LibpfmHelper , LibpfmCoreProcessModule , LibpfmCoreModule , LibpfmProcessModule }
33+ import org .powerapi .module .libpfm ._
3434import org .powerapi .module .extPMeter .powerspy .PowerSpyModule
3535import org .powerapi .module .extPMeter .g5k .G5kOmegaWattModule
3636import scala .concurrent .duration .DurationInt
3737import scala .sys
3838import scala .sys .process .stringSeqToProcess
39+ import scala .util .matching .Regex
3940
4041/**
4142 * PowerAPI CLI.
@@ -47,8 +48,9 @@ object PowerAPI extends App {
4748 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
4849 val aggR = """ max|min|geomean|logsum|mean|median|stdev|sum|variance""" .r
4950 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
5254
5355 @ volatile var powerMeters = Seq [PowerMeter ]()
5456 @ volatile var monitors = Seq [PowerMonitoring ]()
@@ -60,13 +62,8 @@ object PowerAPI extends App {
6062 powerMeters = Seq ()
6163 }
6264
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
7067 case _ => false
7168 }
7269
@@ -84,42 +81,25 @@ object PowerAPI extends App {
8481 }
8582 }
8683
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-
10884 def printHelp (): Unit = {
10985 val str =
11086 """
11187 |PowerAPI, Spirals Team
11288 |
11389 |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.
11591 |Please, refer to the documentation inside the GitHub wiki for further details.
11692 |
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)
11999 | duration [s]
120100 |
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 \
123103 | duration 30
124104 """ .stripMargin
125105
@@ -128,30 +108,34 @@ object PowerAPI extends App {
128108
129109 def cli (options : List [Map [Symbol , Any ]], duration : String , args : List [String ]): (List [Map [Symbol , Any ]], String ) = args match {
130110 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) => {
132112 val (remainingArgs, monitors) = cliMonitorsSubcommand(List (), Map (), tail.map(_.toString))
133113 cli(options :+ Map (' modules -> value, ' prefix -> Some (prefix), ' monitors -> monitors), duration, remainingArgs)
134114 }
135- case " modules" :: value :: " monitor" :: tail if validateModules( value) => {
115+ case " modules" :: value :: " monitor" :: tail if validate(modulesR, value) => {
136116 val (remainingArgs, monitors) = cliMonitorsSubcommand(List (), Map (), tail.map(_.toString))
137117 cli(options :+ Map (' modules -> value, ' prefix -> None , ' monitors -> monitors), duration, remainingArgs)
138118 }
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)
140120 case option :: tail => println(s " unknown cli option $option" ); sys.exit(1 )
141121 }
142122
143123 def cliMonitorsSubcommand (options : List [Map [Symbol , Any ]], currentMonitor : Map [Symbol , Any ], args : List [String ]): (List [String ], List [Map [Symbol , Any ]]) = args match {
144124 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)
148128 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)
155139 case option :: tail => println(s " unknown monitor option $option" ); sys.exit(1 )
156140 }
157141
@@ -162,6 +146,8 @@ object PowerAPI extends App {
162146
163147 else {
164148 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+
165151 val (configuration, duration) = cli(List (), " 3600" , args.toList)
166152
167153 var libpfmHelper : Option [LibpfmHelper ] = None
@@ -192,28 +178,18 @@ object PowerAPI extends App {
192178
193179 for (monitorConf <- powerMeterConf(' monitors ).asInstanceOf [List [Map [Symbol , Any ]]]) {
194180 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+ }
196185 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 ]]
200187
201188 val monitor = powerMeter.monitor(frequency)(targets : _* )(agg)
202189 monitors :+= monitor
203190
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)
217193 }
218194 }
219195 }
@@ -231,3 +207,4 @@ object PowerAPI extends App {
231207 shutdownHookThread.remove()
232208 sys.exit(0 )
233209}
210+
0 commit comments