Skip to content
This repository was archived by the owner on Mar 11, 2019. It is now read-only.

Commit dd1a093

Browse files
committed
refactor(core): add Supervisors, fix bugs, cleaning, a Clock is not automatically created anymore
A Clock for producing periodic ticks is created only when the "every(frequency)" method is called on a PowerMonitoring object. It allows then to have external ticks when needed. Sensors, formulae and reporters have now their own Supervisor, and each component actor is now responsible to handle one target at a time. Two reporters are not refactored yet (Rest, Fuse). refactor(tests): improve the coverage, and clean tests Several tests have been rewritten and cleaned. The coverage is now up to more than 70%. refactor(examples): change the external dependency to a local one The examples were written to use PowerAPI as en external dependency. The dependency is now local (PowerAPIBuild), and allows to get the examples up-to-date with the powerapi-core library.
1 parent 61b8f46 commit dd1a093

File tree

296 files changed

+9978
-24183
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

296 files changed

+9978
-24183
lines changed

.travis.yml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
1+
sudo: required
2+
3+
cache:
4+
directories:
5+
- $HOME/.m2/repository
6+
- $HOME/.sbt
7+
- $HOME/.ivy2
8+
19
language: scala
10+
211
scala:
3-
- 2.11.6
12+
- 2.11.7
13+
414
script:
5-
- sbt clean "project powerapi-core" coverage test
15+
- sbt compile test:compile
16+
- sbt 'set concurrentRestrictions in Global += Tags.limit(Tags.Test, 1)' "project powerapi-core" coverage test
17+
- find $HOME/.sbt -name "*.lock" | xargs rm
18+
619
after_success:
720
- sbt "project powerapi-core" coverageReport
821
- sbt "project powerapi-core" codacyCoverage

README.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,7 @@ We all stand on the shoulders of giants and get by with a little help from our f
5656
* [Scala IO](http://jesseeichar.github.io/scala-io-doc/0.4.3/index.html#!/overview) (version 0.4.3 under [3-clause BSD license](http://www.scala-lang.org/license.html)), for an extensions of IO.
5757
* [Saddle](http://saddle.github.io/) (version 1.3.4 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for data manipulation.
5858
* [Sigar](https://support.hyperic.com/display/SIGAR/Home) (version 1.6.5 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for providing a portable interface for gathering system information.
59-
* [spray-can](http://spray.io/) (version 1.3.3 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for providing a low-level, low-overhead, high-performance HTTP server and client.
60-
* [spray-client](http://spray.io/) (version 1.3.3 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for providing high-level HTTP client.
61-
* [spray-routing](http://spray.io/) (version 1.3.3 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for providing a high-level, very flexible routing DSL for elegantly defining RESTful web services.
62-
* [spray-json](http://spray.io/) (version 1.2.2 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for (de)serializing JSON.
63-
* [nscala-time](https://github.com/nscala-time/nscala-time) (version 2.8.0 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for using a scala wrapper for Joda Time (quality replacement for the Java date and time classes).
59+
* [spray-json](http://spray.io/) (version 1.3.2 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for (de)serializing JSON.
6460
* [docker-java](https://github.com/docker-java/docker-java) (version 2.1.4 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for using the JAVA Docker API.
6561

6662
# License

powerapi-cli/build.sbt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
name := "powerapi-cli"
22

3-
mappings in Universal += downloadBluecove.value -> s"lib/${downloadBluecove.value.name}"
4-
5-
mappings in Universal += downloadBluecoveGpl.value -> s"lib/${downloadBluecoveGpl.value.name}"
6-
73
mappings in Universal ++= {
84
val dir = baseDirectory.value.getParentFile
95

powerapi-cli/src/main/scala/org/powerapi/app/PowerAPI.scala

Lines changed: 89 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -23,27 +23,29 @@
2323
package org.powerapi.app
2424

2525
import java.lang.management.ManagementFactory
26-
import org.powerapi.core.target._
27-
import org.powerapi.module.rapl.RAPLModule
28-
import org.powerapi.reporter.{FileDisplay, JFreeChartDisplay, ConsoleDisplay}
29-
import org.powerapi.{PowerDisplay, PowerMonitoring, PowerMeter}
30-
import org.powerapi.core.power._
31-
import org.powerapi.module.cpu.dvfs.CpuDvfsModule
32-
import org.powerapi.module.cpu.simple.{SigarCpuSimpleModule, ProcFSCpuSimpleModule}
33-
import org.powerapi.module.libpfm._
34-
import org.powerapi.module.extPMeter.powerspy.PowerSpyModule
35-
import org.powerapi.module.extPMeter.g5k.G5kOmegaWattModule
26+
3627
import scala.concurrent.duration.DurationInt
3728
import scala.sys
3829
import scala.sys.process.stringSeqToProcess
3930
import scala.util.matching.Regex
4031

32+
import org.powerapi.core.power._
33+
import org.powerapi.core.target._
34+
import org.powerapi.module.cpu.dvfs.CpuDvfsModule
35+
import org.powerapi.module.cpu.simple.{ProcFSCpuSimpleModule, SigarCpuSimpleModule}
36+
import org.powerapi.module.extpowermeter.g5komegawatt.G5kOmegaWattModule
37+
import org.powerapi.module.extpowermeter.powerspy.PowerSpyModule
38+
import org.powerapi.module.extpowermeter.rapl.RAPLModule
39+
import org.powerapi.module.libpfm.{LibpfmCoreModule, LibpfmCoreProcessModule, LibpfmHelper, LibpfmModule, LibpfmProcessModule}
40+
import org.powerapi.reporter.{ConsoleDisplay, FileDisplay, JFreeChartDisplay}
41+
import org.powerapi.{PowerDisplay, PowerMeter, PowerMonitoring}
42+
4143
/**
42-
* PowerAPI CLI.
43-
*
44-
* @author <a href="mailto:maxime.colmant@gmail.com">Maxime Colmant</a>
45-
* @author <a href="mailto:l.huertas.pro@gmail.com">Loïc Huertas</a>
46-
*/
44+
* PowerAPI CLI.
45+
*
46+
* @author <a href="mailto:maxime.colmant@gmail.com">Maxime Colmant</a>
47+
* @author <a href="mailto:l.huertas.pro@gmail.com">Loïc Huertas</a>
48+
*/
4749
object PowerAPI extends App {
4850
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
4951
val aggR = """max|min|geomean|logsum|mean|median|stdev|sum|variance""".r
@@ -107,88 +109,116 @@ object PowerAPI extends App {
107109
}
108110

109111
def cli(options: List[Map[Symbol, Any]], duration: String, args: List[String]): (List[Map[Symbol, Any]], String) = args match {
110-
case Nil => (options, duration)
111-
case "modules" :: value :: "--prefix" :: prefix :: "monitor" :: tail if validate(modulesR, value) => {
112+
case Nil =>
113+
(options, duration)
114+
case "modules" :: value :: "--prefix" :: prefix :: "monitor" :: tail if validate(modulesR, value) =>
112115
val (remainingArgs, monitors) = cliMonitorsSubcommand(List(), Map(), tail.map(_.toString))
113116
cli(options :+ Map('modules -> value, 'prefix -> Some(prefix), 'monitors -> monitors), duration, remainingArgs)
114-
}
115-
case "modules" :: value :: "monitor" :: tail if validate(modulesR, value) => {
117+
case "modules" :: value :: "monitor" :: tail if validate(modulesR, value) =>
116118
val (remainingArgs, monitors) = cliMonitorsSubcommand(List(), Map(), tail.map(_.toString))
117119
cli(options :+ Map('modules -> value, 'prefix -> None, 'monitors -> monitors), duration, remainingArgs)
118-
}
119-
case "duration" :: value :: tail if validate(durationR, value) => cli(options, value, tail)
120-
case option :: tail => println(s"unknown cli option $option"); sys.exit(1)
120+
case "duration" :: value :: tail if validate(durationR, value) =>
121+
cli(options, value, tail)
122+
case option :: tail =>
123+
println(s"unknown cli option $option")
124+
sys.exit(1)
121125
}
122126

123127
def cliMonitorsSubcommand(options: List[Map[Symbol, Any]], currentMonitor: Map[Symbol, Any], args: List[String]): (List[String], List[Map[Symbol, Any]]) = args match {
124-
case Nil => (List(), 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)
128-
case "monitor" :: tail => cliMonitorsSubcommand(options :+ currentMonitor, Map(), 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)
139-
case option :: tail => println(s"unknown monitor option $option"); sys.exit(1)
128+
case Nil =>
129+
(List(), options :+ currentMonitor)
130+
case "modules" :: value :: "--prefix" :: prefix :: "monitor" :: tail if validate(modulesR, value) =>
131+
(List("modules", value, "--prefix", prefix, "monitor") ++ tail, options :+ currentMonitor)
132+
case "modules" :: value :: "monitor" :: tail if validate(modulesR, value) =>
133+
(List("modules", value, "monitor") ++ tail, options :+ currentMonitor)
134+
case "duration" :: value :: tail if validate(durationR, value) =>
135+
(List("duration", value) ++ tail, options :+ currentMonitor)
136+
case "monitor" :: tail =>
137+
cliMonitorsSubcommand(options :+ currentMonitor, Map(), tail)
138+
case "--frequency" :: value :: tail if validate(durationR, value) =>
139+
cliMonitorsSubcommand(options, currentMonitor ++ Map('frequency -> value), tail)
140+
case "--self" :: tail =>
141+
cliMonitorsSubcommand(options, currentMonitor + ('targets -> (currentMonitor.getOrElse('targets, Set[Any]()).asInstanceOf[Set[Any]] + Process(ManagementFactory.getRuntimeMXBean.getName.split("@")(0).toInt))), tail)
142+
case "--pids" :: value :: tail if validate(pidsR, value) =>
143+
cliMonitorsSubcommand(options, currentMonitor + ('targets -> (currentMonitor.getOrElse('targets, Set[Any]()).asInstanceOf[Set[Any]] ++ value.split(",").map(pid => Process(pid.toInt)))), tail)
144+
case "--apps" :: value :: tail if validate(appsR, value) =>
145+
cliMonitorsSubcommand(options, currentMonitor + ('targets -> (currentMonitor.getOrElse('targets, Set[Any]()).asInstanceOf[Set[Any]] ++ value.split(",").map(app => Application(app)))), tail)
146+
case "--containers" :: value :: tail if validate(containersR, value) =>
147+
cliMonitorsSubcommand(options, currentMonitor + ('targets -> (currentMonitor.getOrElse('targets, Set[Any]()).asInstanceOf[Set[Any]] ++ value.split(",").map(container => Container(container)))), tail)
148+
case "--all" :: tail =>
149+
cliMonitorsSubcommand(options, currentMonitor + ('targets -> (currentMonitor.getOrElse('targets, Set[Any]()).asInstanceOf[Set[Any]] + All)), tail)
150+
case "--agg" :: value :: tail if validate(aggR, value) =>
151+
cliMonitorsSubcommand(options, currentMonitor ++ Map('agg -> value), tail)
152+
case "--console" :: tail =>
153+
cliMonitorsSubcommand(options, currentMonitor + ('displays -> (currentMonitor.getOrElse('displays, Set[Any]()).asInstanceOf[Set[Any]] + new ConsoleDisplay)), tail)
154+
case "--file" :: value :: tail =>
155+
cliMonitorsSubcommand(options, currentMonitor + ('displays -> (currentMonitor.getOrElse('displays, Set[Any]()).asInstanceOf[Set[Any]] + new FileDisplay(value))), tail)
156+
case "--chart" :: tail =>
157+
cliMonitorsSubcommand(options, currentMonitor + ('displays -> (currentMonitor.getOrElse('displays, Set[Any]()).asInstanceOf[Set[Any]] + new JFreeChartDisplay)), tail)
158+
case option :: tail =>
159+
println(s"unknown monitor option $option")
160+
sys.exit(1)
140161
}
141162

142-
if(args.size == 0) {
163+
if (args.isEmpty) {
143164
printHelp()
144165
sys.exit(1)
145166
}
146167

147168
else {
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")
169+
if (System.getProperty("os.name").toLowerCase.indexOf("nix") >= 0 || System.getProperty("os.name").toLowerCase.indexOf("nux") >= 0) Seq("bash", "scripts/system.bash").!
150170

151171
val (configuration, duration) = cli(List(), "3600", args.toList)
152172

153173
var libpfmHelper: Option[LibpfmHelper] = None
154174

155-
if(configuration.count(powerMeterConf => powerMeterConf('modules).toString.contains("libpfm")) != 0) {
175+
if (configuration.count(powerMeterConf => powerMeterConf('modules).toString.contains("libpfm")) != 0) {
156176
libpfmHelper = Some(new LibpfmHelper)
157177
libpfmHelper.get.init()
158178
}
159179

160-
for(powerMeterConf <- configuration) {
161-
val modules = (for(module <- powerMeterConf('modules).toString.split(",")) yield {
180+
for (powerMeterConf <- configuration) {
181+
val modules = (for (module <- powerMeterConf('modules).toString.split(",")) yield {
162182
module match {
163-
case "procfs-cpu-simple" => ProcFSCpuSimpleModule()
164-
case "sigar-cpu-simple" => SigarCpuSimpleModule()
165-
case "cpu-dvfs" => CpuDvfsModule()
166-
case "libpfm" => LibpfmModule(powerMeterConf('prefix).asInstanceOf[Option[String]], libpfmHelper.get)
167-
case "libpfm-process" => LibpfmProcessModule(powerMeterConf('prefix).asInstanceOf[Option[String]], libpfmHelper.get)
168-
case "libpfm-core" => LibpfmCoreModule(powerMeterConf('prefix).asInstanceOf[Option[String]], libpfmHelper.get)
169-
case "libpfm-core-process" => LibpfmCoreProcessModule(powerMeterConf('prefix).asInstanceOf[Option[String]], libpfmHelper.get)
170-
case "powerspy" => PowerSpyModule(powerMeterConf('prefix).asInstanceOf[Option[String]])
171-
case "g5k-omegawatt" => G5kOmegaWattModule(powerMeterConf('prefix).asInstanceOf[Option[String]])
172-
case "rapl" => RAPLModule()
183+
case "procfs-cpu-simple" =>
184+
ProcFSCpuSimpleModule()
185+
case "sigar-cpu-simple" =>
186+
SigarCpuSimpleModule()
187+
case "cpu-dvfs" =>
188+
CpuDvfsModule()
189+
case "libpfm" =>
190+
LibpfmModule(powerMeterConf('prefix).asInstanceOf[Option[String]], libpfmHelper.get)
191+
case "libpfm-process" =>
192+
LibpfmProcessModule(powerMeterConf('prefix).asInstanceOf[Option[String]], libpfmHelper.get)
193+
case "libpfm-core" =>
194+
LibpfmCoreModule(powerMeterConf('prefix).asInstanceOf[Option[String]], libpfmHelper.get)
195+
case "libpfm-core-process" =>
196+
LibpfmCoreProcessModule(powerMeterConf('prefix).asInstanceOf[Option[String]], libpfmHelper.get)
197+
case "powerspy" =>
198+
PowerSpyModule(powerMeterConf('prefix).asInstanceOf[Option[String]])
199+
case "g5k-omegawatt" =>
200+
G5kOmegaWattModule(powerMeterConf('prefix).asInstanceOf[Option[String]])
201+
case "rapl" =>
202+
RAPLModule()
173203
}
174204
}).toSeq
175205

176206
val powerMeter = PowerMeter.loadModule(modules: _*)
177207
powerMeters :+= powerMeter
178208

179-
for(monitorConf <- powerMeterConf('monitors).asInstanceOf[List[Map[Symbol, Any]]]) {
209+
for (monitorConf <- powerMeterConf('monitors).asInstanceOf[List[Map[Symbol, Any]]]) {
180210
val frequency = monitorConf.getOrElse('frequency, "1000").toString.toInt.milliseconds
181211
val targets = {
182212
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
213+
if (uniqueTargets.contains(All)) Seq(All) else uniqueTargets
184214
}
185215
val agg: Seq[Power] => Power = aggStrToAggFunction(monitorConf.getOrElse('agg, "max").toString.toLowerCase)
186216
val displays = monitorConf.getOrElse('displays, Set(new ConsoleDisplay)).asInstanceOf[Set[PowerDisplay]]
187217

188-
val monitor = powerMeter.monitor(frequency)(targets: _*)(agg)
218+
val monitor = powerMeter.monitor(targets: _*)(agg).every(frequency)
189219
monitors :+= monitor
190220

191-
for(display <- displays) {
221+
for (display <- displays) {
192222
monitor.to(display)
193223
}
194224
}
@@ -198,7 +228,7 @@ object PowerAPI extends App {
198228

199229
libpfmHelper match {
200230
case Some(helper) => helper.deinit()
201-
case _ => {}
231+
case _ =>
202232
}
203233
}
204234

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
include "akka"
2+
include "rapl"
23
include "powerapi"

powerapi-cli/src/universal/conf/log4j2.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
~
2222
~ If not, please consult http://www.gnu.org/licenses/agpl-3.0.html.
2323
-->
24-
<Configuration status="INFO">
24+
<Configuration shutdownHook="disable" status="INFO">
2525
<Appenders>
2626
<Console name="Console" target="SYSTEM_OUT">
2727
<PatternLayout pattern="[%level] [%d{MM/dd/yyyy HH:mm:ss.SSS}] [%t] [%logger{36}] - %msg%n" />
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<configuration scan="true">
3+
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
4+
<encoder>
5+
<charset>UTF-8</charset>
6+
<Pattern>[%-5level] [d{MM/dd/yyyy HH:mm:ss.SSS}] [%thread] [%logger{36}] - %msg%n</Pattern>
7+
</encoder>
8+
</appender>
9+
10+
<root level="ERROR">
11+
<appender-ref ref="Console"/>
12+
</root>
13+
</configuration>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
rapl.supported-architectures = [
2+
{id = 42, model = "Sandybridge"}
3+
{id = 45, model = "Sandybridge-EP"}
4+
{id = 58, model = "Ivybridge"}
5+
{id = 62, model = "Ivybridge-EP"}
6+
{id = 60, model = "Haswell"}
7+
{id = 63, model = "Haswell-EP"}
8+
{id = 61, model = "Broadwell"}
9+
]

0 commit comments

Comments
 (0)