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

Commit

Permalink
Merge pull request #69 from Spirals-Team/develop
Browse files Browse the repository at this point in the history
Merge branch "develop" into "master" (Milestone 3.2)
  • Loading branch information
rouvoy committed Jun 2, 2015
2 parents c8a9d0b + 47049c9 commit 1b9e8f6
Show file tree
Hide file tree
Showing 264 changed files with 8,063 additions and 17,478 deletions.
14 changes: 5 additions & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
language: scala
scala:
- 2.11.4
- 2.11.6
script:
- sbt clean coverage test
before_install:
- openssl aes-256-cbc -K $encrypted_48ebb0d1c0b9_key -iv $encrypted_48ebb0d1c0b9_iv
-in secrets.tar.enc -out secrets.tar -d
- tar xvf secrets.tar
- sbt clean "project powerapi-core" coverage test
after_success:
- sbt coverageReport
- sbt coverageAggregate
- sbt codacyCoverage
- sbt "project powerapi-core" coverageReport
- sbt "project powerapi-core" codacyCoverage
- sbt "project powerapi-core" coveralls
27 changes: 17 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<img src="https://rawgit.com/Spirals-Team/powerapi/master/resources/logo/PowerAPI-logo.png" alt="Powerapi" width="300px">

[![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)

[![OSS Licence](http://img.shields.io/badge/license-AGPLv3-532553.svg)](https://www.gnu.org/licenses/agpl-3.0.html)
[![Build Status](https://travis-ci.org/Spirals-Team/powerapi.svg)](https://travis-ci.org/Spirals-Team/powerapi)
[![Codacy Badge](https://www.codacy.com/project/badge/e0b0e331ca414250a7240b6be74aaa7b)](https://www.codacy.com/public/maximecolmant/powerapi)

[![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)
[![Coverage Status](https://coveralls.io/repos/Spirals-Team/powerapi/badge.svg)](https://coveralls.io/r/Spirals-Team/powerapi)
[![Codacy Badge](https://www.codacy.com/project/badge/31f7762213c340fbb5fe1463a5b871d4)](https://www.codacy.com/app/mcolmant/powerapi)

PowerAPI is a middleware toolkit for building software-defined power meters.
Software-defined power meters are configurable software libraries that can estimate the power consumption of software in real-time.
Expand Down Expand Up @@ -34,18 +35,24 @@ When submitting code, please make every effort to follow existing conventions an
* **[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.
* **[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.

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

## Acknowledgments
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:
* [Akka](http://akka.io) (version 2.3.6 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for asynchronous processing
* [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.
* [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.
* [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).
* [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.
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:
* [Akka](http://akka.io) (version 2.3.11 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for asynchronous processing
* [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.
* [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.
* [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).
* [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.
* [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.
* [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.
* [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.
* [Saddle](http://saddle.github.io) (version 1.3.3 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for data manipulation.
* [Saddle](http://saddle.github.io/) (version 1.3.3 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for data manipulation.
* [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.

# License
This software is licensed under the *GNU Affero General Public License*, quoted below.
Expand Down
10 changes: 4 additions & 6 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name := "powerapi"

version in ThisBuild := "3.1"
version in ThisBuild := "3.2"

scalaVersion in ThisBuild := "2.11.4"
scalaVersion in ThisBuild := "2.11.6"

scalacOptions in ThisBuild ++= Seq(
"-language:reflectiveCalls",
Expand All @@ -13,10 +13,8 @@ scalacOptions in ThisBuild ++= Seq(

// Logging
libraryDependencies in ThisBuild ++= Seq(
"org.apache.logging.log4j" % "log4j-api" % "2.1",
"org.apache.logging.log4j" % "log4j-core" % "2.1"
"org.apache.logging.log4j" % "log4j-api" % "2.3",
"org.apache.logging.log4j" % "log4j-core" % "2.3"
)

parallelExecution in (ThisBuild, Test) := false

codacyProjectTokenFile := Some("./codacy-token.txt")
69 changes: 40 additions & 29 deletions powerapi-cli/src/main/scala/org/powerapi/app/PowerAPI.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,13 @@
package org.powerapi.app

import java.lang.management.ManagementFactory

import org.powerapi.core.target.{Application, All, Process, Target}
import org.powerapi.module.rapl.RAPLModule
import org.powerapi.reporter.{FileDisplay, JFreeChartDisplay, ConsoleDisplay}
import org.powerapi.{PowerMonitoring, PowerMeter, PowerModule}
import org.powerapi.{PowerMonitoring, PowerMeter}
import org.powerapi.core.power._
import org.powerapi.module.cpu.dvfs.CpuDvfsModule
import org.powerapi.module.cpu.simple.CpuSimpleModule
import org.powerapi.module.cpu.simple.{SigarCpuSimpleModule, ProcFSCpuSimpleModule}
import org.powerapi.module.libpfm.{LibpfmHelper, LibpfmCoreProcessModule, LibpfmCoreModule}
import org.powerapi.module.powerspy.PowerSpyModule
import scala.concurrent.duration.DurationInt
Expand All @@ -44,7 +43,7 @@ import scala.sys.process.stringSeqToProcess
* @author <a href="mailto:[email protected]">Loïc Huertas</a>
*/
object PowerAPI extends App {
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
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
val aggR = """max|min|geomean|logsum|mean|median|stdev|sum|variance""".r
val durationR = """\d+""".r
val pidR = """(\d+)""".r
Expand All @@ -65,19 +64,6 @@ object PowerAPI extends App {
case _ => false
}

implicit def modulesStrToPowerModules(str: String): Seq[PowerModule] = {
(for(module <- str.split(",")) yield {
module match {
case "cpu-simple" => CpuSimpleModule()
case "cpu-dvfs" => CpuDvfsModule()
case "libpfm-core" => LibpfmCoreModule()
case "libpfm-core-process" => LibpfmCoreProcessModule()
case "powerspy" => PowerSpyModule()
case "rapl" => RAPLModule()
}
}).toSeq
}

def validateAgg(str: String): Boolean = str match {
case aggR(_*) => true
case _ => false
Expand Down Expand Up @@ -121,16 +107,18 @@ object PowerAPI extends App {
def printHelp(): Unit = {
val str =
"""
|PowerAPI, Spirals Team"
|PowerAPI, Spirals Team
|
|Build a software-defined power meter. Do not forget to configure correctly the modules (see the documentation).
|Build a software-defined power meter. Do not forget to configure correctly the modules.
|You can use different settings per software-defined power meter for some modules by using the optional prefix option.
|Please, refer to the documentation inside the GitHub wiki for further details.
|
|usage: ./powerapi modules [cpu-simple|cpu-dvfs|libpfm-core|libpfm-core-proces|powerspy|rapl,...] \
| monitor --frequency [ms] --targets [pid, ..., app, ...)|all] --agg [max|min|geomean|logsum|mean|median|stdev|sum|variance] --[console,file [filepath],chart] \
|usage: ./powerapi modules [procfs-cpu-simple|sigar-cpu-simple|cpu-dvfs|libpfm-core|libpfm-core-proces|powerspy|rapl,...] *--prefix [name]* \
| monitor --frequency [ms] --targets [pid, ..., app, ...|all] --agg [max|min|geomean|logsum|mean|median|stdev|sum|variance] --[console,file [filepath],chart] \
| duration [s]
|
|example: ./powerapi modules cpu-simple monitor --frequency 1000 --targets firefox --agg max --console monitor --targets chrome --agg max --console \
| modules powerspy monitor --frequency 1000 --targets all --agg max --console \
|example: ./powerapi modules procfs-cpu-simple monitor --frequency 1000 --targets firefox,chrome --agg max --console \
| modules powerspy --prefix powermeter2 monitor --frequency 1000 --targets all --agg max --console \
| duration 30
""".stripMargin

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

def cli(options: List[Map[Symbol, Any]], duration: String, args: List[String]): (List[Map[Symbol, Any]], String) = args match {
case Nil => (options, duration)
case "modules" :: value :: "--prefix" :: prefix :: "monitor" :: tail if validateModules(value) => {
val (remainingArgs, monitors) = cliMonitorsSubcommand(List(), Map(), tail.map(_.toString))
cli(options :+ Map('modules -> value, 'prefix -> Some(prefix), 'monitors -> monitors), duration, remainingArgs)
}
case "modules" :: value :: "monitor" :: tail if validateModules(value) => {
val (remainingArgs, monitors) = cliMonitorsSubcommand(List(), Map(), tail.map(_.toString))
cli(options :+ Map('modules -> value, 'monitors -> monitors), duration, remainingArgs)
cli(options :+ Map('modules -> value, 'prefix -> None, 'monitors -> monitors), duration, remainingArgs)
}
case "duration" :: value :: tail if validateDuration(value) => cli(options, value, tail)
case option :: tail => println(s"unknown cli option $option"); sys.exit(1)
}

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

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

var libpfmHelper: Option[LibpfmHelper] = None

if(configuration.count(powerMeterConf => powerMeterConf('modules).toString.contains("libpfm")) != 0) {
libpfmHelper = Some(new LibpfmHelper)
libpfmHelper.get.init()
}

for(powerMeterConf <- configuration) {
val modules = powerMeterConf('modules).toString
if(modules.contains("libpfm-core") || modules.contains("libpfm-core-process")) LibpfmHelper.init()
val modules = (for(module <- powerMeterConf('modules).toString.split(",")) yield {
module match {
case "procfs-cpu-simple" => ProcFSCpuSimpleModule()
case "sigar-cpu-simple" => SigarCpuSimpleModule()
case "cpu-dvfs" => CpuDvfsModule()
case "libpfm-core" => LibpfmCoreModule(powerMeterConf('prefix).asInstanceOf[Option[String]], libpfmHelper.get)
case "libpfm-core-process" => LibpfmCoreProcessModule(powerMeterConf('prefix).asInstanceOf[Option[String]], libpfmHelper.get)
case "powerspy" => PowerSpyModule()
case "rapl" => RAPLModule()
}
}).toSeq

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

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

val isLibpfmInit = configuration.count(powerMeterConf => powerMeterConf('modules).toString.contains("libpfm-core") || powerMeterConf('modules).toString.contains("libpfm-core-process")) != 0
if(isLibpfmInit) LibpfmHelper.deinit()
libpfmHelper match {
case Some(helper) => helper.deinit()
case _ => {}
}
}

shutdownHookThread.start()
Expand Down
24 changes: 13 additions & 11 deletions powerapi-core/build.sbt
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
import SonatypeKeys._

sonatypeSettings

name := "powerapi-core"

organization := "org.powerapi"

resolvers ++= Seq(
"JBoss Thirdparty Uploads" at "https://repository.jboss.org/nexus/content/repositories/thirdparty-uploads/"
)

// App
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-actor" % "2.3.6",
"com.typesafe.akka" %% "akka-actor" % "2.3.11",
"com.typesafe" % "config" % "1.2.1",
"fr.inria.powerspy" % "powerspy-core_2.11" % "1.1",
"com.nativelibs4java" % "bridj" % "0.6.2",
"fr.inria.powerspy" % "powerspy-core_2.11" % "1.2",
"com.nativelibs4java" % "bridj" % "0.7.0",
"com.github.scala-incubator.io" %% "scala-io-core" % "0.4.3",
"com.github.scala-incubator.io" %% "scala-io-file" % "0.4.3",
"org.jfree" % "jfreechart" % "1.0.19",
"org.scala-saddle" %% "saddle-core" % "1.3.3"
"org.scala-saddle" %% "saddle-core" % "1.3.3",
"org.hyperic" % "sigar" % "1.6.5.132"
)

// Tests
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-testkit" % "2.3.6" % "test",
"org.scalatest" %% "scalatest" % "2.2.2" % "test"
"com.typesafe.akka" %% "akka-testkit" % "2.3.11" % "test",
"org.scalatest" %% "scalatest" % "2.2.5" % "test",
"org.scalamock" %% "scalamock-scalatest-support" % "3.2.2" % "test"
)

startYear := Some(2014)
Expand All @@ -39,7 +41,7 @@ pomExtra := {
<developer>
<id>mcolmant</id>
<name>Maxime Colmant</name>
<url>http://researchers.lille.inria.fr/colmant/</url>
<url>http://mcolmant.github.io/</url>
</developer>
<developer>
<id>rouvoy</id>
Expand Down
Binary file modified powerapi-core/lib/libpfm.jar
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-amd64-freebsd-6.so
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-amd64-linux.so
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-amd64-solaris.so
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-arm-linux.so
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-ia64-hpux-11.sl
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-ia64-linux.so
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-pa-hpux-11.sl
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-ppc-aix-5.so
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-ppc-linux.so
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-ppc64-aix-5.so
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-ppc64-linux.so
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-s390x-linux.so
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-sparc-solaris.so
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-sparc64-solaris.so
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-x86-freebsd-5.so
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-x86-freebsd-6.so
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-x86-linux.so
Binary file not shown.
Binary file added powerapi-core/lib/libsigar-x86-solaris.so
Binary file not shown.
Binary file added powerapi-core/lib/sigar-amd64-winnt.dll
Binary file not shown.
Binary file added powerapi-core/lib/sigar-amd64-winnt.lib
Binary file not shown.
Binary file added powerapi-core/lib/sigar-x86-winnt.dll
Binary file not shown.
Binary file added powerapi-core/lib/sigar-x86-winnt.lib
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*
* This file is a part of PowerAPI.
*
* Copyright (C) 2011-2014 Inria, University of Lille 1.
* Copyright (C) 2011-2015 Inria, University of Lille 1.
*
* PowerAPI is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
Expand All @@ -28,8 +28,6 @@
import org.bridj.BridJ;
import org.bridj.CRuntime;
import org.bridj.Pointer;

import perfmon2.libpfm.LibpfmLibrary;
import perfmon2.libpfm.perf_event_attr;

/**
Expand All @@ -47,10 +45,10 @@ public class CUtils {
/**
* perf_event_open maccro (not generated correctly).
*/
public static int perf_event_open(Pointer<perf_event_attr> __hw, int __pid, int __cpu, int __gr, @CLong long __flags) {
return syscall(LibpfmLibrary.__NR_perf_event_open, Pointer.getPeer(__hw), __pid, __cpu, __gr, __flags);
public static int perf_event_open(int __nrPerfEventOpen, Pointer<perf_event_attr> __hw, int __pid, int __cpu, int __gr, @CLong long __flags) {
return syscall(__nrPerfEventOpen, Pointer.getPeer(__hw), __pid, __cpu, __gr, __flags);
}
private native static int syscall(int __cdde, Object... varArgs1);
private native static int syscall(int __code, Object... varArgs1);

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

0 comments on commit 1b9e8f6

Please sign in to comment.