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

Commit 1b9e8f6

Browse files
committed
Merge pull request #69 from Spirals-Team/develop
Merge branch "develop" into "master" (Milestone 3.2)
2 parents c8a9d0b + 47049c9 commit 1b9e8f6

File tree

264 files changed

+8063
-17478
lines changed

Some content is hidden

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

264 files changed

+8063
-17478
lines changed

.travis.yml

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
language: scala
22
scala:
3-
- 2.11.4
3+
- 2.11.6
44
script:
5-
- sbt clean coverage test
6-
before_install:
7-
- openssl aes-256-cbc -K $encrypted_48ebb0d1c0b9_key -iv $encrypted_48ebb0d1c0b9_iv
8-
-in secrets.tar.enc -out secrets.tar -d
9-
- tar xvf secrets.tar
5+
- sbt clean "project powerapi-core" coverage test
106
after_success:
11-
- sbt coverageReport
12-
- sbt coverageAggregate
13-
- sbt codacyCoverage
7+
- sbt "project powerapi-core" coverageReport
8+
- sbt "project powerapi-core" codacyCoverage
9+
- sbt "project powerapi-core" coveralls

README.md

+17-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
<img src="https://rawgit.com/Spirals-Team/powerapi/master/resources/logo/PowerAPI-logo.png" alt="Powerapi" width="300px">
22

3+
[![Join the chat at https://gitter.im/Spirals-Team/powerapi](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Spirals-Team/powerapi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4+
35
[![OSS Licence](http://img.shields.io/badge/license-AGPLv3-532553.svg)](https://www.gnu.org/licenses/agpl-3.0.html)
46
[![Build Status](https://travis-ci.org/Spirals-Team/powerapi.svg)](https://travis-ci.org/Spirals-Team/powerapi)
5-
[![Codacy Badge](https://www.codacy.com/project/badge/e0b0e331ca414250a7240b6be74aaa7b)](https://www.codacy.com/public/maximecolmant/powerapi)
6-
7-
[![Join the chat at https://gitter.im/Spirals-Team/powerapi](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Spirals-Team/powerapi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
7+
[![Coverage Status](https://coveralls.io/repos/Spirals-Team/powerapi/badge.svg)](https://coveralls.io/r/Spirals-Team/powerapi)
8+
[![Codacy Badge](https://www.codacy.com/project/badge/31f7762213c340fbb5fe1463a5b871d4)](https://www.codacy.com/app/mcolmant/powerapi)
89

910
PowerAPI is a middleware toolkit for building software-defined power meters.
1011
Software-defined power meters are configurable software libraries that can estimate the power consumption of software in real-time.
@@ -34,18 +35,24 @@ When submitting code, please make every effort to follow existing conventions an
3435
* **[Runtime Monitoring of Software Energy Hotspots](https://hal.inria.fr/hal-00715331)**: A. Noureddine, A. Bourdon, R. Rouvoy, L. Seinturier. *International Conference on Automated Software Engineering* (ASE), September 2012, Essen, Germany. pp.160-169.
3536
* **[A Preliminary Study of the Impact of Software Engineering on GreenIT](https://hal.inria.fr/hal-00681560)**: A. Noureddine, A. Bourdon, R. Rouvoy, L. Seinturier. *International Workshop on Green and Sustainable Software* (GREENS), June 2012, Zurich, Switzerland. pp.21-27.
3637

38+
## Use Cases
39+
PowerAPI is used in a variety of projects to address key challenges of GreenIT:
40+
* [BitWatts](http://bitwatts.powerapi.org) provides process-level power estimation of applications running in virtual machines
41+
* [Web Energy Archive](http://webenergyarchive.com) ranks popular websites based on the energy footpring they imposes to browsers
42+
* [Greenspector](http://greenspector.com) optimises the power consumption of software by identifying potential energy leaks in the source code.
3743

3844
## Acknowledgments
39-
We all stand on the shoulders of giants and get by with a little help from our friends. PowerAPI is written in [Scala](http://www.scala-lang.org) (version 2.11.4 under [3-clause BSD license](http://www.scala-lang.org/license.html)) and built on top of:
40-
* [Akka](http://akka.io) (version 2.3.6 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for asynchronous processing
41-
* [Typesage Config](https://github.com/typesafehub/config) (version 1.2.1 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for reading configuration files.
42-
* [Apache log4j2](http://logging.apache.org/log4j/2.x) (version 2.1 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for logging outside actors.
43-
* [powerspy.scala](https://github.com/Spirals-Team/powerspy.scala) (version 1.0.1 under [AGPL license](http://www.gnu.org/licenses/agpl-3.0.html)), for using the [PowerSpy powermeter](http://www.alciom.com/en/products/powerspy2-en-gb-2.html).
44-
* [BridJ](https://code.google.com/p/bridj/) (version 0.6.2 under [3-clause BSD license](https://github.com/ochafik/nativelibs4java/blob/master/libraries/BridJ/LICENSE)), for system or C calls.
45+
We all stand on the shoulders of giants and get by with a little help from our friends. PowerAPI is written in [Scala](http://www.scala-lang.org) (version 2.11.6 under [3-clause BSD license](http://www.scala-lang.org/license.html)) and built on top of:
46+
* [Akka](http://akka.io) (version 2.3.11 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for asynchronous processing
47+
* [Typesafe Config](https://github.com/typesafehub/config) (version 1.2.1 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for reading configuration files.
48+
* [Apache log4j2](http://logging.apache.org/log4j/2.x) (version 2.3 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for logging outside actors.
49+
* [powerspy.scala](https://github.com/Spirals-Team/powerspy.scala) (version 1.2 under [AGPL license](http://www.gnu.org/licenses/agpl-3.0.html)), for using the [PowerSpy powermeter](http://www.alciom.com/en/products/powerspy2-en-gb-2.html).
50+
* [BridJ](https://code.google.com/p/bridj/) (version 0.7.0 under [3-clause BSD license](https://github.com/ochafik/nativelibs4java/blob/master/libraries/BridJ/LICENSE)), for system or C calls.
4551
* [perfmon2](http://sourceforge.net/p/perfmon2/libpfm4/ci/master/tree) (version 4.6.0 under [MIT license](http://sourceforge.net/p/perfmon2/libpfm4/ci/master/tree/COPYING)), for accessing hardware performance counters.
4652
* [JFreeChart](http://www.jfree.org/jfreechart/) (version 1.0.19 under [LGPL license](https://www.gnu.org/licenses/lgpl.html)), for creation of interactive and animated charts.
4753
* [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.
48-
* [Saddle](http://saddle.github.io) (version 1.3.3 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for data manipulation.
54+
* [Saddle](http://saddle.github.io/) (version 1.3.3 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for data manipulation.
55+
* [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.
4956

5057
# License
5158
This software is licensed under the *GNU Affero General Public License*, quoted below.

build.sbt

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
name := "powerapi"
22

3-
version in ThisBuild := "3.1"
3+
version in ThisBuild := "3.2"
44

5-
scalaVersion in ThisBuild := "2.11.4"
5+
scalaVersion in ThisBuild := "2.11.6"
66

77
scalacOptions in ThisBuild ++= Seq(
88
"-language:reflectiveCalls",
@@ -13,10 +13,8 @@ scalacOptions in ThisBuild ++= Seq(
1313

1414
// Logging
1515
libraryDependencies in ThisBuild ++= Seq(
16-
"org.apache.logging.log4j" % "log4j-api" % "2.1",
17-
"org.apache.logging.log4j" % "log4j-core" % "2.1"
16+
"org.apache.logging.log4j" % "log4j-api" % "2.3",
17+
"org.apache.logging.log4j" % "log4j-core" % "2.3"
1818
)
1919

2020
parallelExecution in (ThisBuild, Test) := false
21-
22-
codacyProjectTokenFile := Some("./codacy-token.txt")

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

+40-29
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,13 @@
2323
package org.powerapi.app
2424

2525
import java.lang.management.ManagementFactory
26-
2726
import org.powerapi.core.target.{Application, All, Process, Target}
2827
import org.powerapi.module.rapl.RAPLModule
2928
import org.powerapi.reporter.{FileDisplay, JFreeChartDisplay, ConsoleDisplay}
30-
import org.powerapi.{PowerMonitoring, PowerMeter, PowerModule}
29+
import org.powerapi.{PowerMonitoring, PowerMeter}
3130
import org.powerapi.core.power._
3231
import org.powerapi.module.cpu.dvfs.CpuDvfsModule
33-
import org.powerapi.module.cpu.simple.CpuSimpleModule
32+
import org.powerapi.module.cpu.simple.{SigarCpuSimpleModule, ProcFSCpuSimpleModule}
3433
import org.powerapi.module.libpfm.{LibpfmHelper, LibpfmCoreProcessModule, LibpfmCoreModule}
3534
import org.powerapi.module.powerspy.PowerSpyModule
3635
import scala.concurrent.duration.DurationInt
@@ -44,7 +43,7 @@ import scala.sys.process.stringSeqToProcess
4443
* @author <a href="mailto:[email protected]">Loïc Huertas</a>
4544
*/
4645
object PowerAPI extends App {
47-
val modulesR = """(cpu-simple|cpu-dvfs|libpfm-core|libpfm-core-process|powerspy|rapl)(,(cpu-simple|cpu-dvfs|libpfm-core|libpfm-core-process|powerspy|rapl))*""".r
46+
val modulesR = """(procfs-cpu-simple|sigar-cpu-simple|cpu-dvfs|libpfm-core|libpfm-core-process|powerspy|rapl)(,(procfs-cpu-simple|sigar-cpu-simple|cpu-dvfs|libpfm-core|libpfm-core-process|powerspy|rapl))*""".r
4847
val aggR = """max|min|geomean|logsum|mean|median|stdev|sum|variance""".r
4948
val durationR = """\d+""".r
5049
val pidR = """(\d+)""".r
@@ -65,19 +64,6 @@ object PowerAPI extends App {
6564
case _ => false
6665
}
6766

68-
implicit def modulesStrToPowerModules(str: String): Seq[PowerModule] = {
69-
(for(module <- str.split(",")) yield {
70-
module match {
71-
case "cpu-simple" => CpuSimpleModule()
72-
case "cpu-dvfs" => CpuDvfsModule()
73-
case "libpfm-core" => LibpfmCoreModule()
74-
case "libpfm-core-process" => LibpfmCoreProcessModule()
75-
case "powerspy" => PowerSpyModule()
76-
case "rapl" => RAPLModule()
77-
}
78-
}).toSeq
79-
}
80-
8167
def validateAgg(str: String): Boolean = str match {
8268
case aggR(_*) => true
8369
case _ => false
@@ -121,16 +107,18 @@ object PowerAPI extends App {
121107
def printHelp(): Unit = {
122108
val str =
123109
"""
124-
|PowerAPI, Spirals Team"
110+
|PowerAPI, Spirals Team
125111
|
126-
|Build a software-defined power meter. Do not forget to configure correctly the modules (see the documentation).
112+
|Build a software-defined power meter. Do not forget to configure correctly the modules.
113+
|You can use different settings per software-defined power meter for some modules by using the optional prefix option.
114+
|Please, refer to the documentation inside the GitHub wiki for further details.
127115
|
128-
|usage: ./powerapi modules [cpu-simple|cpu-dvfs|libpfm-core|libpfm-core-proces|powerspy|rapl,...] \
129-
| monitor --frequency [ms] --targets [pid, ..., app, ...)|all] --agg [max|min|geomean|logsum|mean|median|stdev|sum|variance] --[console,file [filepath],chart] \
116+
|usage: ./powerapi modules [procfs-cpu-simple|sigar-cpu-simple|cpu-dvfs|libpfm-core|libpfm-core-proces|powerspy|rapl,...] *--prefix [name]* \
117+
| monitor --frequency [ms] --targets [pid, ..., app, ...|all] --agg [max|min|geomean|logsum|mean|median|stdev|sum|variance] --[console,file [filepath],chart] \
130118
| duration [s]
131119
|
132-
|example: ./powerapi modules cpu-simple monitor --frequency 1000 --targets firefox --agg max --console monitor --targets chrome --agg max --console \
133-
| modules powerspy monitor --frequency 1000 --targets all --agg max --console \
120+
|example: ./powerapi modules procfs-cpu-simple monitor --frequency 1000 --targets firefox,chrome --agg max --console \
121+
| modules powerspy --prefix powermeter2 monitor --frequency 1000 --targets all --agg max --console \
134122
| duration 30
135123
""".stripMargin
136124

@@ -139,16 +127,21 @@ object PowerAPI extends App {
139127

140128
def cli(options: List[Map[Symbol, Any]], duration: String, args: List[String]): (List[Map[Symbol, Any]], String) = args match {
141129
case Nil => (options, duration)
130+
case "modules" :: value :: "--prefix" :: prefix :: "monitor" :: tail if validateModules(value) => {
131+
val (remainingArgs, monitors) = cliMonitorsSubcommand(List(), Map(), tail.map(_.toString))
132+
cli(options :+ Map('modules -> value, 'prefix -> Some(prefix), 'monitors -> monitors), duration, remainingArgs)
133+
}
142134
case "modules" :: value :: "monitor" :: tail if validateModules(value) => {
143135
val (remainingArgs, monitors) = cliMonitorsSubcommand(List(), Map(), tail.map(_.toString))
144-
cli(options :+ Map('modules -> value, 'monitors -> monitors), duration, remainingArgs)
136+
cli(options :+ Map('modules -> value, 'prefix -> None, 'monitors -> monitors), duration, remainingArgs)
145137
}
146138
case "duration" :: value :: tail if validateDuration(value) => cli(options, value, tail)
147139
case option :: tail => println(s"unknown cli option $option"); sys.exit(1)
148140
}
149141

150142
def cliMonitorsSubcommand(options: List[Map[Symbol, Any]], currentMonitor: Map[Symbol, Any], args: List[String]): (List[String], List[Map[Symbol, Any]]) = args match {
151143
case Nil => (List(), options :+ currentMonitor)
144+
case "modules" :: value :: "--prefix" :: prefix :: "monitor" :: tail if validateModules(value) => (List("modules", value, "--prefix", prefix, "monitor") ++ tail, options :+ currentMonitor)
152145
case "modules" :: value :: "monitor" :: tail if validateModules(value) => (List("modules", value, "monitor") ++ tail, options :+ currentMonitor)
153146
case "duration" :: value :: tail if validateDuration(value) => (List("duration", value) ++ tail, options :+ currentMonitor)
154147
case "monitor" :: tail => cliMonitorsSubcommand(options :+ currentMonitor, Map(), tail)
@@ -167,12 +160,28 @@ object PowerAPI extends App {
167160
}
168161

169162
else {
170-
Seq("bash", "scripts/system.bash").!
163+
if(System.getProperty("os.name").toLowerCase.indexOf("nix") >= 0 || System.getProperty("os.name").toLowerCase.indexOf("nux") >= 0) Seq("bash", "scripts/system.bash").!
171164
val (configuration, duration) = cli(List(), "3600", args.toList)
172165

166+
var libpfmHelper: Option[LibpfmHelper] = None
167+
168+
if(configuration.count(powerMeterConf => powerMeterConf('modules).toString.contains("libpfm")) != 0) {
169+
libpfmHelper = Some(new LibpfmHelper)
170+
libpfmHelper.get.init()
171+
}
172+
173173
for(powerMeterConf <- configuration) {
174-
val modules = powerMeterConf('modules).toString
175-
if(modules.contains("libpfm-core") || modules.contains("libpfm-core-process")) LibpfmHelper.init()
174+
val modules = (for(module <- powerMeterConf('modules).toString.split(",")) yield {
175+
module match {
176+
case "procfs-cpu-simple" => ProcFSCpuSimpleModule()
177+
case "sigar-cpu-simple" => SigarCpuSimpleModule()
178+
case "cpu-dvfs" => CpuDvfsModule()
179+
case "libpfm-core" => LibpfmCoreModule(powerMeterConf('prefix).asInstanceOf[Option[String]], libpfmHelper.get)
180+
case "libpfm-core-process" => LibpfmCoreProcessModule(powerMeterConf('prefix).asInstanceOf[Option[String]], libpfmHelper.get)
181+
case "powerspy" => PowerSpyModule()
182+
case "rapl" => RAPLModule()
183+
}
184+
}).toSeq
176185

177186
val powerMeter = PowerMeter.loadModule(modules: _*)
178187
powerMeters :+= powerMeter
@@ -207,8 +216,10 @@ object PowerAPI extends App {
207216

208217
Thread.sleep(duration.toInt.seconds.toMillis)
209218

210-
val isLibpfmInit = configuration.count(powerMeterConf => powerMeterConf('modules).toString.contains("libpfm-core") || powerMeterConf('modules).toString.contains("libpfm-core-process")) != 0
211-
if(isLibpfmInit) LibpfmHelper.deinit()
219+
libpfmHelper match {
220+
case Some(helper) => helper.deinit()
221+
case _ => {}
222+
}
212223
}
213224

214225
shutdownHookThread.start()

powerapi-core/build.sbt

+13-11
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
1-
import SonatypeKeys._
2-
3-
sonatypeSettings
4-
51
name := "powerapi-core"
62

73
organization := "org.powerapi"
84

5+
resolvers ++= Seq(
6+
"JBoss Thirdparty Uploads" at "https://repository.jboss.org/nexus/content/repositories/thirdparty-uploads/"
7+
)
8+
99
// App
1010
libraryDependencies ++= Seq(
11-
"com.typesafe.akka" %% "akka-actor" % "2.3.6",
11+
"com.typesafe.akka" %% "akka-actor" % "2.3.11",
1212
"com.typesafe" % "config" % "1.2.1",
13-
"fr.inria.powerspy" % "powerspy-core_2.11" % "1.1",
14-
"com.nativelibs4java" % "bridj" % "0.6.2",
13+
"fr.inria.powerspy" % "powerspy-core_2.11" % "1.2",
14+
"com.nativelibs4java" % "bridj" % "0.7.0",
1515
"com.github.scala-incubator.io" %% "scala-io-core" % "0.4.3",
1616
"com.github.scala-incubator.io" %% "scala-io-file" % "0.4.3",
1717
"org.jfree" % "jfreechart" % "1.0.19",
18-
"org.scala-saddle" %% "saddle-core" % "1.3.3"
18+
"org.scala-saddle" %% "saddle-core" % "1.3.3",
19+
"org.hyperic" % "sigar" % "1.6.5.132"
1920
)
2021

2122
// Tests
2223
libraryDependencies ++= Seq(
23-
"com.typesafe.akka" %% "akka-testkit" % "2.3.6" % "test",
24-
"org.scalatest" %% "scalatest" % "2.2.2" % "test"
24+
"com.typesafe.akka" %% "akka-testkit" % "2.3.11" % "test",
25+
"org.scalatest" %% "scalatest" % "2.2.5" % "test",
26+
"org.scalamock" %% "scalamock-scalatest-support" % "3.2.2" % "test"
2527
)
2628

2729
startYear := Some(2014)
@@ -39,7 +41,7 @@ pomExtra := {
3941
<developer>
4042
<id>mcolmant</id>
4143
<name>Maxime Colmant</name>
42-
<url>http://researchers.lille.inria.fr/colmant/</url>
44+
<url>http://mcolmant.github.io/</url>
4345
</developer>
4446
<developer>
4547
<id>rouvoy</id>

powerapi-core/lib/libpfm.jar

-133 Bytes
Binary file not shown.
206 KB
Binary file not shown.
241 KB
Binary file not shown.
229 KB
Binary file not shown.
205 KB
Binary file not shown.
564 KB
Binary file not shown.
483 KB
Binary file not shown.
504 KB
Binary file not shown.
392 KB
Binary file not shown.
252 KB
Binary file not shown.
415 KB
Binary file not shown.
323 KB
Binary file not shown.
264 KB
Binary file not shown.
278 KB
Binary file not shown.
256 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.
176 KB
Binary file not shown.
175 KB
Binary file not shown.
203 KB
Binary file not shown.
237 KB
Binary file not shown.
360 KB
Binary file not shown.
92.6 KB
Binary file not shown.

powerapi-core/lib/sigar-x86-winnt.dll

289 KB
Binary file not shown.

powerapi-core/lib/sigar-x86-winnt.lib

97.1 KB
Binary file not shown.

powerapi-core/src/main/java/org/powerapi/module/libpfm/CUtils.java

+4-6
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* This file is a part of PowerAPI.
55
*
6-
* Copyright (C) 2011-2014 Inria, University of Lille 1.
6+
* Copyright (C) 2011-2015 Inria, University of Lille 1.
77
*
88
* PowerAPI is free software: you can redistribute it and/or modify
99
* it under the terms of the GNU Affero General Public License as
@@ -28,8 +28,6 @@
2828
import org.bridj.BridJ;
2929
import org.bridj.CRuntime;
3030
import org.bridj.Pointer;
31-
32-
import perfmon2.libpfm.LibpfmLibrary;
3331
import perfmon2.libpfm.perf_event_attr;
3432

3533
/**
@@ -47,10 +45,10 @@ public class CUtils {
4745
/**
4846
* perf_event_open maccro (not generated correctly).
4947
*/
50-
public static int perf_event_open(Pointer<perf_event_attr> __hw, int __pid, int __cpu, int __gr, @CLong long __flags) {
51-
return syscall(LibpfmLibrary.__NR_perf_event_open, Pointer.getPeer(__hw), __pid, __cpu, __gr, __flags);
48+
public static int perf_event_open(int __nrPerfEventOpen, Pointer<perf_event_attr> __hw, int __pid, int __cpu, int __gr, @CLong long __flags) {
49+
return syscall(__nrPerfEventOpen, Pointer.getPeer(__hw), __pid, __cpu, __gr, __flags);
5250
}
53-
private native static int syscall(int __cdde, Object... varArgs1);
51+
private native static int syscall(int __code, Object... varArgs1);
5452

5553
/**
5654
* Interact with a given file descriptor. In this case, we use it to enable, disable and reset a file descriptor (so, a counter).

0 commit comments

Comments
 (0)