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

Commit 2818e4d

Browse files
committed
feature(docker): dockerize the CLI and sampling apps
Use travis for building docker images on tags and publish releases. Closes #77
1 parent a33899f commit 2818e4d

File tree

9 files changed

+287
-20
lines changed

9 files changed

+287
-20
lines changed

.travis.yml

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,34 @@
11
sudo: required
22

3+
services:
4+
- docker
5+
6+
env:
7+
global:
8+
- secure: "BfP5e/OPM62e3ktm4RD2nuBJls2u8zdXg/YjNyght5dpD2vCjL6ZHWhgDM2mNFpzgYPiE3DPsSE7g2ZlsBUJCuK8a7lB5r+OiWFcWkilC1E9QX6OMcDTpEKb5A9InFGcpt0xbjY5+8qaIbaN8TJcdxaxeit0TZEvxeirQa5OOEY=" # COVERALLS_REPO_TOKEN
9+
- secure: "ldIw526YR2Fe6FlfIPlbbOojEeg7etbO4dqiL4TLm00SBhVkKG+DuckhFixVAvAJx1Q1LuVyUPsXaR77OjqiTxSkaH+GbsmR5VIM4qA/kBheD4IiV4wTamg679d+AldRNWcGtLpefgwqlCJ53FcMzUT9TH/MJcbEaOJ5GKW9v+s=" # CODACY_PROJECT_TOKEN
10+
- secure: "MLFJWju96LymkPNIsUeJelNN5J3BK55OV/RXVMONC5kDr4N7T4JyhT6KUa4k+FSJ0S1GTPQMWQQEkWDF1MlZXv5yGwW4h5rN3tt//vqyHk968SyqlhTdygqzx6tO6t3OsfQ2F1AqVWAWsHQckL+VmhEo53VqVXpsqLy9DyLYGjs=" # DOCKER_EMAIL
11+
- secure: "FbLHLKNAtpj7ZVgSobOPgAgdLK3/P4sR6RcaOmpVRsgaqodTPx7VkzGpkf4rOqPwxKU3+96vr0TlIdPRYWAE39Y3gMb1dyZ34+CxsrJ3avJYc2+9NT3kmAuU33Iy1DCo3IEnR7pWVVEyR80ob0c1ASfPAW1JN8DhBRRERpkMyn4=" # DOCKER_USER
12+
- secure: "VLK9NI4yE+hLV8rgjiB0hOfQn1uFO7cEHHL4sEDZKNu1TgvwfTrEWEzMMLvG8pwK/7eG78xfNB489m/Imj7Y52xK6sZuY7Y78Y06mkepZS8PisAJiW59kHWH1Ci84DYHZ0y07NAgvCOSLS9l0ncgLdlGvRboR9KBYDMEWycwEn8=" # DOCKER_PWD
13+
314
cache:
415
directories:
5-
- $HOME/.m2/repository
6-
- $HOME/.sbt
7-
- $HOME/.ivy2
16+
- "$HOME/.m2/repository"
17+
- "$HOME/.sbt"
18+
- "$HOME/.ivy2"
819

920
language: scala
1021

1122
scala:
1223
- 2.11.7
1324

25+
jdk:
26+
- openjdk7
27+
28+
# workaround for openjdk buffer overflow
29+
addons:
30+
hostname: localhost
31+
1432
script:
1533
- sbt compile test:compile
1634
- sbt 'set concurrentRestrictions in Global += Tags.limit(Tags.Test, 1)' "project powerapi-core" coverage test
@@ -20,10 +38,37 @@ before_install:
2038
- wget -O influxdb.deb https://s3.amazonaws.com/influxdb/influxdb_0.10.2-1_amd64.deb
2139
- sudo dpkg -i influxdb.deb
2240
- sudo service influxdb start
23-
- sleep 5; /usr/bin/influx --execute "CREATE USER powerapi WITH PASSWORD 'powerapi' WITH ALL PRIVILEGES"
24-
41+
- sleep 5; /usr/bin/influx --execute "CREATE USER powerapi WITH PASSWORD 'powerapi'
42+
WITH ALL PRIVILEGES"
2543

2644
after_success:
2745
- sbt "project powerapi-core" coverageReport
2846
- sbt "project powerapi-core" codacyCoverage
2947
- sbt "project powerapi-core" coveralls
48+
49+
before_deploy:
50+
- sbt "project powerapi-sampling" universal:packageZipTarball
51+
- sbt "project powerapi-cli" universal:packageZipTarball
52+
- tar -C powerapi-sampling/target/universal -xvf powerapi-sampling/target/universal/powerapi-sampling.tgz
53+
- tar -C powerapi-cli/target/universal -xvf powerapi-cli/target/universal/powerapi-cli.tgz
54+
55+
deploy:
56+
provider: releases
57+
api_key:
58+
secure: IEU1nWNWXW394yjC8/2Ch3naFM18mUmns9q11U0sCWMm9nz7ej4D5crKxCPtIHyHtFlONY1s0udBk6rv3aCVq0UikOysHFiVdPPeJTRCtGptxOb04/pZtq3vITcMzS9+CQc+yV8Y3A2vv15L/30ERMk1fgur+Nb+8vTFfXfzEik=
59+
file:
60+
- "powerapi-sampling/target/universal/powerapi-sampling.tgz"
61+
- "powerapi-cli/target/universal/powerapi-cli.tgz"
62+
skip_cleanup: true
63+
on:
64+
tags: true
65+
repo: Spirals-Team/powerapi
66+
67+
after_deploy:
68+
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PWD
69+
- docker build -f docker/sampling/Dockerfile-sampling -t spirals/powerapi-sampling:$TRAVIS_TAG .
70+
- docker build -f docker/Dockerfile-cli -t spirals/powerapi-cli:$TRAVIS_TAG .
71+
- docker tag spirals/powerapi-sampling:$TRAVIS_TAG spirals/powerapi-sampling:latest
72+
- docker tag spirals/powerapi-cli:$TRAVIS_TAG spirals/powerapi-cli:latest
73+
- docker push spirals/powerapi-sampling
74+
- docker push spirals/powerapi-cli

docker/Dockerfile-cli

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
FROM alpine:latest
2+
3+
ENV POWERAPI_PACKAGE powerapi-cli
4+
ENV LIBPFM_PACKAGE libpfm-4.6.0
5+
6+
ENV INSTALL_PACKAGES ca-certificates linux-headers libc-dev make gcc patch
7+
ENV RUNTIME_PACKAGES bluez bluez-dev openjdk7-jre bash procps
8+
9+
COPY docker/libpfm/config.mk.patch /root/
10+
COPY ${POWERAPI_PACKAGE}/target/universal/${POWERAPI_PACKAGE}/ /root/${POWERAPI_PACKAGE}/
11+
12+
VOLUME /conf
13+
14+
RUN apk update && apk upgrade && apk add $INSTALL_PACKAGES $RUNTIME_PACKAGES && \
15+
wget https://circle-artifacts.com/gh/andyshinn/alpine-pkg-glibc/6/artifacts/0/home/ubuntu/alpine-pkg-glibc/packages/x86_64/glibc-2.21-r2.apk && apk --allow-untrusted add glibc-2.21-r2.apk && rm -f glibc-2.21-r2.apk && \
16+
wget http://downloads.sourceforge.net/project/perfmon2/libpfm4/${LIBPFM_PACKAGE}.tar.gz && tar -C /root -xzvf ${LIBPFM_PACKAGE}.tar.gz && patch -d /root/$LIBPFM_PACKAGE -p1 < /root/config.mk.patch && (cd /root/$LIBPFM_PACKAGE; make lib; make install) && rm -rf /root/config.mk.patch /root/$LIBPFM_PACKAGE ${LIBPFM_PACKAGE}.tar.gz && \
17+
rm -rf /root/${POWERAPI_PACKAGE}/conf && ln -s /conf/ /root/${POWERAPI_PACKAGE}/conf && \
18+
apk del glibc $INSTALL_PACKAGES && \
19+
rm -rf /var/cache/apk/*
20+
21+
WORKDIR /root/$POWERAPI_PACKAGE
22+
23+
ENTRYPOINT ["./bin/powerapi"]

docker/README.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
## Docker version of PowerAPI
2+
3+
Lightweight docker images of PowerAPI packaged as docker images.
4+
5+
You have first to create a [data volume](https://docs.docker.com/engine/userguide/containers/dockervolumes/#creating-and-mounting-a-data-volume-container) to store the configuration files (`conf` directory) for PowerAPI.
6+
It will include all parameters needed to PowerAPI for configuring its internal components.
7+
The different parameters to set up are described inside the [Wiki](https://github.com/Spirals-Team/powerapi/wiki).
8+
9+
We assume that two data volumes `powerapi-cli-conf` and `powerapi-sampling-conf` are created on the host system.
10+
11+
### PowerAPI: CLI
12+
13+
This image is used to run automatically a various choices of software-defined power meters.
14+
15+
#### Usage
16+
17+
Show the help text:
18+
19+
```
20+
docker run --rm --privileged --net=host --pid=host \
21+
--volumes-from powerapi-cli-conf \
22+
spirals/powerapi-cli
23+
```
24+
25+
The `--privileged` option is used to get the root access to the host machine,
26+
the `--net=host` option is mandatory to be able to use the PowerSPY bluetooth power meter inside a container,
27+
and the `--pid=host` is required to be able to get an access to the running apps of the host machine.
28+
29+
A classic example with the `ProcFS` module can be:
30+
31+
powerapi.conf:
32+
33+
```
34+
powerapi.cpu.tdp = 35
35+
```
36+
37+
Associated docker command:
38+
39+
```
40+
docker run --rm --privileged --net=host --pid=host \
41+
--volumes-from powerapi-cli-conf \
42+
spirals/powerapi-cli \
43+
modules procfs-cpu-simple monitor --frequency 1000 --all --console
44+
```
45+
46+
### PowerAPI: Sampling
47+
48+
This image is used to build a CPU power model.
49+
50+
#### Usage
51+
52+
Launch the sampling:
53+
54+
```
55+
docker run --rm --privileged --net=host --pid=host \
56+
--volumes-from powerapi-sampling-conf \
57+
spirals/powerapi-sampling
58+
```
59+
60+
Example of a sampling configuration file:
61+
62+
sampling.conf:
63+
64+
```
65+
powerspy.mac = "00:0B:CE:07:1E:9B"
66+
67+
powerapi.cpu.topology = [
68+
{ core = 0, indexes = [0, 4] }
69+
{ core = 1, indexes = [1, 5] }
70+
{ core = 2, indexes = [2, 6] }
71+
{ core = 3, indexes = [3, 7] }
72+
]
73+
74+
powerapi.sampling.dvfs = true
75+
powerapi.sampling.turbo = true
76+
77+
powerapi.cycles-polynom-regression.cpu-base-frequency = 0.133
78+
powerapi.cycles-polynom-regression.cpu-max-frequency = 2.66
79+
powerapi.cycles-polynom-regression.unhalted-cycles-event = "CPU_CLK_UNHALTED:THREAD_P"
80+
powerapi.cycles-polynom-regression.ref-cycles-event = "CPU_CLK_UNHALTED:REF_P"
81+
82+
interval = 1s
83+
powerapi.actors.timeout = 15s
84+
powerapi.sampling.interval = ${interval}
85+
powerspy.interval = ${interval}
86+
powerapi.sampling.steps = [100, 25]
87+
powerapi.sampling.step-duration = 10
88+
```

docker/libpfm/config.mk.patch

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
--- a/config.mk
2+
+++ b/config.mk
3+
@@ -194,7 +194,7 @@ endif
4+
CC?=gcc
5+
LIBS=
6+
INSTALL=install
7+
-LDCONFIG=ldconfig
8+
+LDCONFIG=/usr/glibc/usr/bin/ldconfig
9+
LN?=ln -sf
10+
PFMINCDIR=$(TOPDIR)/include
11+
PFMLIBDIR=$(TOPDIR)/lib
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
FROM alpine:latest
2+
3+
ENV POWERAPI_PACKAGE powerapi-sampling
4+
ENV LIBPFM_PACKAGE libpfm-4.6.0
5+
6+
ENV INSTALL_PACKAGES ca-certificates linux-headers libc-dev make gcc patch
7+
ENV RUNTIME_PACKAGES bluez bluez-dev openjdk7-jre bash util-linux cpulimit procps
8+
9+
COPY docker/libpfm/config.mk.patch /root/
10+
COPY docker/sampling/run.sh /root/
11+
COPY ${POWERAPI_PACKAGE}/target/universal/${POWERAPI_PACKAGE}/ /root/${POWERAPI_PACKAGE}/
12+
13+
VOLUME /conf
14+
15+
RUN apk update && apk upgrade && apk add $INSTALL_PACKAGES $RUNTIME_PACKAGES && \
16+
wget https://circle-artifacts.com/gh/andyshinn/alpine-pkg-glibc/6/artifacts/0/home/ubuntu/alpine-pkg-glibc/packages/x86_64/glibc-2.21-r2.apk && apk --allow-untrusted add glibc-2.21-r2.apk && rm -f glibc-2.21-r2.apk && \
17+
wget http://downloads.sourceforge.net/project/perfmon2/libpfm4/${LIBPFM_PACKAGE}.tar.gz && tar -C /root -xzvf ${LIBPFM_PACKAGE}.tar.gz && patch -d /root/$LIBPFM_PACKAGE -p1 < /root/config.mk.patch && (cd /root/$LIBPFM_PACKAGE; make lib; make install) && rm -rf /root/config.mk.patch /root/$LIBPFM_PACKAGE ${LIBPFM_PACKAGE}.tar.gz && \
18+
wget http://people.seas.harvard.edu/~apw/stress/stress-1.0.4.tar.gz && tar -C /root -xzvf stress-1.0.4.tar.gz && (cd /root/stress-1.0.4; ./configure; make; make install) && rm -rf /root/stress-1.0.4 && \
19+
rm -rf /${POWERAPI_PACKAGE}/conf && ln -s /conf/ /root/${POWERAPI_PACKAGE}/conf && \
20+
apk del glibc $INSTALL_PACKAGES && \
21+
rm -rf /var/cache/apk/*
22+
23+
WORKDIR /root
24+
25+
ENTRYPOINT ["./run.sh"]

docker/sampling/run.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/usr/bin/env bash
2+
3+
cd powerapi-sampling && ./bin/sampling --all results/sampling results/processing results/computing
4+
5+
echo ""
6+
echo "Here is your CPU power model to use with PowerAPI"
7+
echo ""
8+
cat results/computing/libpfm-formula.conf
9+
echo ""

powerapi-core/src/main/scala/org/powerapi/core/MonitorActors.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import org.powerapi.core.ClockChannel.{startClock, stopClock, subscribeClockTick
3535
import org.powerapi.core.MonitorChannel.{MonitorAggregator, MonitorFrequency, MonitorStart, MonitorStop, MonitorStopAll, formatMonitorChildName, publishMonitorTick, setAggregator, setFrequency, stopMonitor, subscribeMonitorsChannel}
3636
import org.powerapi.core.power._
3737
import org.powerapi.core.target.Target
38+
import org.powerapi.core.TickChannel.{subscribeTick, unsubscribeTick}
3839
import org.powerapi.module.FormulaChannel.stopFormula
3940
import org.powerapi.module.PowerChannel.{AggregatePowerReport, RawPowerReport, render, subscribeAggPowerReport, subscribeRawPowerReport, unsubscribeRawPowerReport, unsubscribeAggPowerReport}
4041
import org.powerapi.module.SensorChannel.stopSensor
@@ -62,6 +63,11 @@ trait MonitorConfiguration extends Configuration {
6263
*/
6364
class MonitorChild(eventBus: MessageBus, muid: UUID, targets: Set[Target]) extends ActorComponent {
6465

66+
override def preStart(): Unit = {
67+
subscribeTick(muid)(eventBus)(self)
68+
super.preStart()
69+
}
70+
6571
def receive: Actor.Receive = starting orElse default
6672

6773
def starting: Actor.Receive = {
@@ -75,7 +81,7 @@ class MonitorChild(eventBus: MessageBus, muid: UUID, targets: Set[Target]) exten
7581
case tick: Tick => produceMessages(tick)
7682
case powerReport: RawPowerReport => aggregate(aggR, powerReport, aggregator)
7783
case msg: MonitorAggregator if msg.muid == muid => setAggregator(aggR, msg.aggregator)
78-
case msg: MonitorFrequency if msg.muid == muid => setMonitorFrequency(aggR, aggregator, msg.frequency)
84+
case msg: MonitorFrequency if msg.muid == muid => unsubscribeTick(msg.muid)(eventBus)(self); setMonitorFrequency(aggR, aggregator, msg.frequency)
7985
case msg: MonitorStop if msg.muid == muid => stop()
8086
case _: MonitorStopAll => stop()
8187
}

powerapi-core/src/main/scala/org/powerapi/core/Tick.scala

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,16 @@
2222
*/
2323
package org.powerapi.core
2424

25+
import java.util.UUID
26+
27+
import akka.actor.ActorRef
28+
2529
/**
2630
* Base trait for Tick messages.
2731
*
2832
* @author <a href="mailto:maxime.colmant@gmail.com">Maxime Colmant</a>
2933
*/
30-
trait Tick {
34+
trait Tick extends Message {
3135
/**
3236
* Subject used for routing the message.
3337
*/
@@ -38,3 +42,38 @@ trait Tick {
3842
*/
3943
def timestamp: Long
4044
}
45+
46+
/**
47+
* Tick channel.
48+
*
49+
* @author <a href="mailto:maxime.colmant@gmail.com">Maxime Colmant</a>
50+
*/
51+
object TickChannel extends Channel {
52+
53+
type M = Tick
54+
55+
/**
56+
* Used to subscribe/unsubscribe to Tick on the right topic.
57+
*/
58+
def subscribeTick(muid: UUID): MessageBus => ActorRef => Unit = {
59+
subscribe(tickTopic(muid))
60+
}
61+
62+
def unsubscribeTick(muid: UUID): MessageBus => ActorRef => Unit = {
63+
unsubscribe(tickTopic(muid))
64+
}
65+
66+
/**
67+
* Used to format the topic used to interact with the MonitorChild actors.
68+
*/
69+
def tickTopic(muid: UUID): String = {
70+
s"tick:$muid"
71+
}
72+
73+
/**
74+
* Used to publish a Tick message built externally on the right topic.
75+
*/
76+
def publishTick(tick: Tick): MessageBus => Unit = {
77+
publish(tick)
78+
}
79+
}

0 commit comments

Comments
 (0)