Skip to content

Commit

Permalink
Merge pull request #2 from Spirals-Team/develop
Browse files Browse the repository at this point in the history
Updates informations & libraries, adds more tools to get informations about the project
  • Loading branch information
mcolmant committed Jun 3, 2015
2 parents 1a1f7ee + de6bb9e commit 1001604
Show file tree
Hide file tree
Showing 26 changed files with 174 additions and 347 deletions.
14 changes: 5 additions & 9 deletions .travis.yml
@@ -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_d4bcb24b4a82_key -iv $encrypted_d4bcb24b4a82_iv
-in secrets.tar.enc -out secrets.tar -d
- tar xvf secrets.tar
- sbt clean "project bitwatts-core" coverage test
after_success:
- sbt coverageReport
- sbt coverageAggregate
- sbt codacyCoverage
- sbt "project bitwatts-core" coverageReport
- sbt "project bitwatts-core" codacyCoverage
- sbt "project bitwatts-core" coveralls
11 changes: 8 additions & 3 deletions README.md
@@ -1,6 +1,10 @@
# BitWatts

[![Join the chat at https://gitter.im/Spirals-Team/bitwatts](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Spirals-Team/bitwatts?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

[![Build Status](https://travis-ci.org/Spirals-Team/bitwatts.svg)](https://travis-ci.org/Spirals-Team/bitwatts)
[![Codacy Badge](https://www.codacy.com/project/badge/688093bb28514036ae4cd9ac0fb78868)](https://www.codacy.com/public/maximecolmant/bitwatts)
[![Coverage Status](https://coveralls.io/repos/Spirals-Team/bitwatts/badge.svg)](https://coveralls.io/r/Spirals-Team/bitwatts)
[![Codacy Badge](https://www.codacy.com/project/badge/d2e5e4f39ff248439b1968d45aa45811)](https://www.codacy.com/app/mcolmant/bitwatts)

BitWatts is an extension of [PowerAPI](https://github.com/Spirals-Team/powerapi) for building software-defined power meters inside virtualized environments.
To have more details on what is a software-defined power meter, please consult: http://powerapi.org.
Expand All @@ -27,15 +31,16 @@ When submitting code, please make every effort to follow existing conventions an

## Acknowledgments
We all stand on the shoulders of giants and get by with a little help from our friends. BitWatts 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:
* [PowerAPI](https://github.com/Spirals-Team/powerapi) (version 3.0 under [AGPL license](http://www.gnu.org/licenses/agpl-3.0.html)), for using a software-defined power meter
* [PowerAPI](https://github.com/Spirals-Team/powerapi) (version 3.2 under [AGPL license](http://www.gnu.org/licenses/agpl-3.0.html)), for using a software-defined power meter
* [JUnixSocket](https://code.google.com/p/junixsocket/) (version 1.3 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for using unix domain sockets (quick time accesses)
* [Apache Thrift](https://thrift.apache.org/) (version 0.9.2 under [Apache 2 license](http://www.apache.org/licenses/LICENSE-2.0)), for scalable cross-language services
* [JeroMQ](https://github.com/zeromq/jeromq) (version 0.3.4 under [LGPL3 license](https://github.com/zeromq/jeromq/blob/master/COPYING.LESSER)), for using libzmq in native java.
* [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.

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

Copyright (C) 2011-2014 Inria, University of Lille 1.
Copyright (C) 2011-2015 Inria, University of Lille 1, University of Neuchâtel.

BitWatts is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

Expand Down
Expand Up @@ -3,7 +3,8 @@
*
* This file is a part of BitWatts.
*
* Copyright (C) 2011-2014 Inria, University of Lille 1.
* Copyright (C) 2011-2015 Inria, University of Lille 1,
* University of Neuchâtel.
*
* BitWatts is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
Expand All @@ -25,14 +26,15 @@ package org.powerapi.bitwatts.app
import java.lang.management.ManagementFactory

import org.powerapi.bitwatts.reporter.{ThriftDisplay, VirtioDisplay}
import org.powerapi.core.LinuxHelper
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.bitwatts.module.virtio.VirtioModule
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.{ProcFSCpuSimpleModule, SigarCpuSimpleModule}
import org.powerapi.module.libpfm.{LibpfmHelper, LibpfmCoreProcessModule, LibpfmCoreModule}
import org.powerapi.module.powerspy.PowerSpyModule
import scala.concurrent.duration.DurationInt
Expand All @@ -44,9 +46,10 @@ import scala.sys.process.stringSeqToProcess
* @author <a href="mailto:maxime.colmant@gmail.com">Maxime Colmant</a>
*/
object BitWatts extends App {
val modulesR = """(cpu-simple|cpu-dvfs|libpfm-core|libpfm-core-process|powerspy|rapl|virtio)(,(cpu-simple|cpu-dvfs|libpfm-core|libpfm-core-process|powerspy|rapl|virtio))*""".r
val modulesR = """(procfs-cpu-simple|sigar-cpu-simple|cpu-dvfs|libpfm-core|libpfm-core-process|powerspy|rapl|virtio)(,(procfs-cpu-simple|sigar-cpu-simple|cpu-dvfs|libpfm-core|libpfm-core-process|powerspy|rapl|virtio))*""".r
val aggR = """max|min|geomean|logsum|mean|median|stdev|sum|variance""".r
val numbersR = """(\d+)""".r
val durationR = """\d+""".r
val pidR = """(\d+)""".r
val appR = """(.+)""".r
val thriftR = """(.+),([0-9]+),(.+),(.+)""".r

Expand All @@ -65,20 +68,6 @@ object BitWatts 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()
case "virtio" => VirtioModule()
}
}).toSeq
}

def validateAgg(str: String): Boolean = str match {
case aggR(_*) => true
case _ => false
Expand All @@ -99,7 +88,7 @@ object BitWatts extends App {
}

def validateDuration(str: String): Boolean = str match {
case numbersR(_*) => true
case durationR(_*) => true
case _ => false
}

Expand All @@ -113,7 +102,7 @@ object BitWatts extends App {
target match {
case "" => Process(ManagementFactory.getRuntimeMXBean.getName.split("@")(0).toInt)
case "all" => All
case numbersR(pid) => Process(pid.toInt)
case pidR(pid) => Process(pid.toInt)
case appR(app) => Application(app)
}
}).toSeq
Expand All @@ -127,12 +116,14 @@ object BitWatts extends App {
def printHelp(): Unit = {
val str =
"""
|BitWatts Spirals Team / University of Neuchatel"
|BitWatts, Spirals Team / University of Neuchatel"
|
|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: ./bitwatts modules [cpu-simple|cpu-dvfs|libpfm-core|libpfm-core-process|powerspy|rapl|virtio, ...] \
| monitor --frequency [ms] --targets [pid, ..., app, ...)|all] --agg [max|min|geomean|logsum|mean|median|stdev|sum|variance] --[console,file [filepath],chart,virtio [filepath], thrift [ip,port,sender,topic] ...]] \
|usage: ./bitwatts modules [procfs-cpu-simple|sigar-cpu-simple|cpu-dvfs|libpfm-core|libpfm-core-proces|powerspy|rapl|virtio,...] *--prefix [name]* \
| monitor --frequency [ms] --targets [pid, ..., app, ...|all] --agg [max|min|geomean|logsum|mean|median|stdev|sum|variance] --[console,file [filepath],chart,virtio [filepath],thrift [ip,port,sender,topic]] \
| duration [s]
|
|example: ./bitwatts modules libpfm-core-process monitor --frequency 1000 --targets 2355 --agg max --virtio /tmp/port2 \
Expand All @@ -146,16 +137,21 @@ object BitWatts 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 @@ -176,12 +172,31 @@ object BitWatts 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
// Currently, our solution was only tested on Linux
val linuxHelper = new LinuxHelper

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()
case "virtio" => VirtioModule(powerMeterConf('prefix).asInstanceOf[Option[String]], linuxHelper)
}
}).toSeq

val powerMeter = PowerMeter.loadModule(modules: _*)
powerMeters :+= powerMeter
Expand Down Expand Up @@ -229,8 +244,10 @@ object BitWatts 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
8 changes: 4 additions & 4 deletions bitwatts-core/build.sbt
Expand Up @@ -2,14 +2,14 @@ name := "bitwatts-core"

// App
libraryDependencies ++= Seq(
"org.powerapi" % "powerapi-core_2.11" % "3.1",
"org.powerapi" % "powerapi-core_2.11" % "3.2",
"org.apache.thrift" % "libthrift" % "0.9.2",
"org.zeromq" % "jeromq" % "0.3.4"
)

// Tests
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-testkit" % "2.3.6" % "test",
"org.scalatest" %% "scalatest" % "2.2.2" % "test",
"org.scalamock" %% "scalamock-scalatest-support" % "3.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"
)

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Expand Up @@ -3,7 +3,8 @@
*
* This file is a part of BitWatts.
*
* Copyright (C) 2011-2014 Inria, University of Lille 1.
* Copyright (C) 2011-2015 Inria, University of Lille 1,
* University of Neuchâtel.
*
* BitWatts is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
Expand Down
Expand Up @@ -3,7 +3,8 @@
*
* This file is a part of BitWatts.
*
* Copyright (C) 2011-2014 Inria, University of Lille 1.
* Copyright (C) 2011-2015 Inria, University of Lille 1,
* University of Neuchâtel.
*
* BitWatts is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
Expand Down
Expand Up @@ -3,7 +3,8 @@
*
* This file is a part of BitWatts.
*
* Copyright (C) 2011-2014 Inria, University of Lille 1.
* Copyright (C) 2011-2015 Inria, University of Lille 1,
* University of Neuchâtel.
*
* BitWatts is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
Expand All @@ -23,15 +24,17 @@
package org.powerapi.bitwatts.module.virtio

import org.powerapi.PowerModule
import org.powerapi.core.LinuxHelper
import org.powerapi.core.OSHelper

class VirtioModule(port: Int) extends PowerModule {
lazy val underlyingSensorsClasses = Seq((classOf[VirtioSensor], Seq(new LinuxHelper, port)))
class VirtioModule(osHelper: OSHelper, port: Int) extends PowerModule {
lazy val underlyingSensorsClasses = Seq((classOf[VirtioSensor], Seq(osHelper, port)))
lazy val underlyingFormulaeClasses = Seq((classOf[VirtioFormula], Seq()))
}

object VirtioModule extends VirtioSensorConfiguration {
def apply(): VirtioModule = {
new VirtioModule(port)
object VirtioModule {
def apply(prefixConf: Option[String] = None, osHelper: OSHelper): VirtioModule = {
val virtioSensorConf = new VirtioSensorConfiguration(prefixConf)

new VirtioModule(osHelper, virtioSensorConf.port)
}
}

0 comments on commit 1001604

Please sign in to comment.