adaptive-monitoring-framework
Changes
app-example/pom.xml 2(+1 -1)
app-example/src/main/java/org/springframework/samples/petclinic/ApplicationInitializer.java 4(+3 -1)
tigris/pom.xml 2(+1 -1)
tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/configuration/annotation/TigrisConfiguration.java 2(+2 -0)
Details
app-example/pom.xml 2(+1 -1)
diff --git a/app-example/pom.xml b/app-example/pom.xml
index e08c131..5a0dc51 100644
--- a/app-example/pom.xml
+++ b/app-example/pom.xml
@@ -219,7 +219,7 @@
<dependency>
<groupId>br.ufrgs.inf.prosoft</groupId>
<artifactId>tigris</artifactId>
- <version>0.11.0-SNAPSHOT</version>
+ <version>0.12.0-SNAPSHOT</version>
</dependency>
</dependencies>
diff --git a/app-example/src/main/java/org/springframework/samples/petclinic/ApplicationInitializer.java b/app-example/src/main/java/org/springframework/samples/petclinic/ApplicationInitializer.java
index 8e43593..1de44d4 100644
--- a/app-example/src/main/java/org/springframework/samples/petclinic/ApplicationInitializer.java
+++ b/app-example/src/main/java/org/springframework/samples/petclinic/ApplicationInitializer.java
@@ -10,7 +10,9 @@ import br.ufrgs.inf.prosoft.tigris.sampling.GranularityType;
@TigrisConfiguration(
logRepository = RepositoryType.MEMORY,
staticMetricFile = "petclinic.csv",
- samplingPercentage = 0.5)
+ samplingPercentage = 0.5, adaptiveSamplingRate = true) // adaptive sampling
+// samplingPercentage = 1, adaptiveSamplingRate = false) // full monitoring
+// samplingPercentage = 0, adaptiveSamplingRate = false) // no monitoring
@TigrisCriteria(
criteria = "more frequent '∪' more expensive",
granularity = GranularityType.METHOD,
tigris/pom.xml 2(+1 -1)
diff --git a/tigris/pom.xml b/tigris/pom.xml
index a972e98..2c274d4 100644
--- a/tigris/pom.xml
+++ b/tigris/pom.xml
@@ -6,7 +6,7 @@
<groupId>br.ufrgs.inf.prosoft</groupId>
<artifactId>tigris</artifactId>
- <version>0.11.0-SNAPSHOT</version>
+ <version>0.12.0-SNAPSHOT</version>
<properties>
<aspectj.version>1.8.9</aspectj.version>
diff --git a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/configuration/annotation/TigrisConfiguration.java b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/configuration/annotation/TigrisConfiguration.java
index c59e982..f748de0 100644
--- a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/configuration/annotation/TigrisConfiguration.java
+++ b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/configuration/annotation/TigrisConfiguration.java
@@ -46,4 +46,6 @@ public @interface TigrisConfiguration {
* @return the int
*/
long cycleTimeInMilliseconds() default 3600000; //3600000 milliseconds = 1h
+
+ boolean adaptiveSamplingRate() default false;
}
diff --git a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/monitoring/aspects/TigrisCoordinator.java b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/monitoring/aspects/TigrisCoordinator.java
index e388f8f..c2bfacd 100644
--- a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/monitoring/aspects/TigrisCoordinator.java
+++ b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/monitoring/aspects/TigrisCoordinator.java
@@ -92,7 +92,7 @@ public class TigrisCoordinator implements Runnable {
deniedPattern = Pattern.compile(componentScanConfig.denied());
logger.info("@TigrisConfiguration will trace and cache methods into {} and deny {} package.", allowedPattern.pattern(), deniedPattern.pattern());
- sampling = new Sampling(tigrisConfiguration.samplingPercentage(), tigrisConfiguration.cycleTimeInMilliseconds());
+ sampling = new Sampling(tigrisConfiguration.samplingPercentage(), tigrisConfiguration.cycleTimeInMilliseconds(), tigrisConfiguration.adaptiveSamplingRate());
//TODO when to run it?
samplingAdaptationExecutor.scheduleWithFixedDelay(
sampling, 120000, 450000, TimeUnit.MILLISECONDS);
@@ -189,7 +189,7 @@ public class TigrisCoordinator implements Runnable {
Granularity granularity = new Granularity(tigrisCriteria.granularity(), signature);
- if (sampling.isPerformanceBaselineEnabled()) {
+ if (tigrisConfiguration.adaptiveSamplingRate() && sampling.isPerformanceBaselineEnabled()) {
sampling.addPerformanceBaselineItem(granularity, endTime - startTime);
}
@@ -255,7 +255,13 @@ public class TigrisCoordinator implements Runnable {
logger.info("Selected methods for fine-grained ({}): {}", allowedFineGrained.size(), allowedFineGrained);
//analyze once
-// coarseMonitoringEnabled = false;
+ coarseMonitoringEnabled = false;
+ }
+ if (enabled) {
+ logger.info("Adaptive Sampling Status - Sample traces ({}): {}", sampling.getSample().getTotalItems(),
+ sampling.getSample().getTraceFrequency());
+ logger.info("Adaptive Sampling Status - Population traces ({}): {}", sampling.getPopulation().getTotalItems(),
+ sampling.getPopulation().getTraceFrequency());
}
}
}
\ No newline at end of file
diff --git a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/FrequencyDataSet.java b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/FrequencyDataSet.java
index 71a1fa4..ad3677d 100644
--- a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/FrequencyDataSet.java
+++ b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/FrequencyDataSet.java
@@ -43,4 +43,8 @@ public class FrequencyDataSet {
}
return summaryStatistics;
}
+
+ public Map<Granularity, Integer> getTraceFrequency() {
+ return granularityPopulation;
+ }
}
diff --git a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/PerformanceBaselineDataSet.java b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/PerformanceBaselineDataSet.java
index f0029df..bb9aa55 100644
--- a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/PerformanceBaselineDataSet.java
+++ b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/PerformanceBaselineDataSet.java
@@ -49,6 +49,9 @@ public class PerformanceBaselineDataSet {
public Apdex getApdexResults(Map<Granularity, DescriptiveStatistics> sampledDataSet){
long satisfied = 0, tolerated = 0, n = 0;
for (Granularity granularity : sampledDataSet.keySet()){
+ //TODO is it ok to compare with the overall?
+ //some methods may be really fast and some really huge
+ //should we use getApdexResultsPerEvent?
double meanPlusStd = getOverallAvg() + getOverallStd();
for (double value: sampledDataSet.get(granularity).getValues()) {
if (value < meanPlusStd){
diff --git a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/Sampling.java b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/Sampling.java
index 25ee90a..b4b79b3 100644
--- a/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/Sampling.java
+++ b/tigris/src/main/java/br/ufrgs/inf/prosoft/tigris/sampling/Sampling.java
@@ -17,6 +17,7 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class Sampling implements Runnable {
+ private final boolean adaptiveSamplingRate;
private boolean samplingEnabled = true;
private boolean performanceBaselineEnabled = false;
private double samplingRate; // in percentage, 0 to 1
@@ -36,9 +37,10 @@ public class Sampling implements Runnable {
*/
private double z = 1.96, p = 0.5, e = 0.05;
- public Sampling(double initialSamplingRate, long cycleLengthInMilliseconds) {
+ public Sampling(double initialSamplingRate, long cycleLengthInMilliseconds, boolean adaptiveSamplingRate) {
samplingRate = initialSamplingRate;
decayingPrecision = new ExponentialDecayFunction(1, 0.00001, cycleLengthInMilliseconds);
+ this.adaptiveSamplingRate = adaptiveSamplingRate;
startMonitoringCycle();
}
@@ -53,9 +55,15 @@ public class Sampling implements Runnable {
return false;
}
- boolean decision = samplingEnabled
- && simpleSamplingDecision() // sampling rate evaluation
- && population.getProportion(granularity) >= sample.getProportion(granularity); // sample has not enough items of that granularity compared to the population
+ boolean simpleSamplingDecision = simpleSamplingDecision();
+ boolean decision;
+ if (adaptiveSamplingRate) {
+ decision = samplingEnabled
+ && simpleSamplingDecision // sampling rate evaluation
+ && population.getProportion(granularity) >= sample.getProportion(granularity); // sample has not enough items of that granularity compared to the population
+ } else {
+ decision = simpleSamplingDecision;
+ }
if (decision)
sample.addItem(granularity);
@@ -125,29 +133,28 @@ public class Sampling implements Runnable {
return n_inf / (1 + ((n_inf - 1) / n));
}
- public double getSampleSizeErrorMargin() {
- return getSampleSizeErrorMargin(z);
- }
-
public double getSampleSizeErrorMargin(double precision) {
double e_n_inf = Math.sqrt((Math.pow(precision, 2) * p * (1 - p)) / sample.getTotalItems());
return e_n_inf * Math.sqrt((population.getTotalItems() - sample.getTotalItems()) / (population.getTotalItems() - 1));
}
- public void startMonitoringCycle() {
- startTime = System.currentTimeMillis();
- }
-
public long getMonitoringCycleTime(){
return (System.currentTimeMillis() - startTime);
}
public void endMonitoringCycle() {
this.sampledDataSet = new ConcurrentHashMap<>();
- releaseForAnalysis();
+ logger.info("Adaptive Sampling Monitoring Cycle Finished - Sample traces ({}): {}", getSample().getTotalItems(),
+ getSample().getTraceFrequency());
+ logger.info("Adaptive Sampling Monitoring Cycle Finished - Population traces ({}): {}", getPopulation().getTotalItems(),
+ getPopulation().getTraceFrequency());
startMonitoringCycle();
}
+ private void startMonitoringCycle() {
+ startTime = System.currentTimeMillis();
+ }
+
public boolean shouldCollectPerformanceBaseline() {
return new BinomialDistribution(1, 0.1).sample() == 1;
}
@@ -174,6 +181,10 @@ public class Sampling implements Runnable {
public void run() {
//TODO this is supposed to run from time to time based on triggers? Or every new trace collected?
+ //this method deals with sampling rate adaptation procedures
+ if (!adaptiveSamplingRate)
+ return;
+
if (isReady()) {
logger.info("Sample is ready, releasing for analysis and resetting...");
endMonitoringCycle();
@@ -191,9 +202,6 @@ public class Sampling implements Runnable {
performanceBaselineEnabled = true;
}
- public void releaseForAnalysis() {
- }
-
public boolean isPerformanceBaselineEnabled() {
return performanceBaselineEnabled;
}
@@ -231,4 +239,12 @@ public class Sampling implements Runnable {
//TODO run it every new trace collected?
run();
}
+
+ public FrequencyDataSet getSample() {
+ return sample;
+ }
+
+ public FrequencyDataSet getPopulation() {
+ return population;
+ }
}
diff --git a/tigris/src/test/java/br/ufrgs/inf/prosoft/tigris/SamplingTest.java b/tigris/src/test/java/br/ufrgs/inf/prosoft/tigris/SamplingTest.java
index 26ee2ce..b290bfc 100644
--- a/tigris/src/test/java/br/ufrgs/inf/prosoft/tigris/SamplingTest.java
+++ b/tigris/src/test/java/br/ufrgs/inf/prosoft/tigris/SamplingTest.java
@@ -3,14 +3,28 @@ package br.ufrgs.inf.prosoft.tigris;
import br.ufrgs.inf.prosoft.tigris.sampling.Granularity;
import br.ufrgs.inf.prosoft.tigris.sampling.GranularityType;
import br.ufrgs.inf.prosoft.tigris.sampling.Sampling;
+import org.junit.Assert;
import org.junit.Test;
public class SamplingTest {
@Test
- public void samplingDecision(){
- Sampling sampling = new Sampling(0.5, 100);
- sampling.samplingDecision(new Granularity(GranularityType.METHOD, "function"));
- sampling.samplingDecision(new Granularity(GranularityType.METHOD, "function"));
+ public void samplingDecisionWithNoChance(){
+ Sampling sampling = new Sampling(0, 100, false);
+ for (int i = 0; i < 2000; i++) {
+ Assert.assertFalse(sampling.samplingDecision(new Granularity(GranularityType.METHOD, "function")));
+ }
+ Assert.assertEquals(0, sampling.getSample().getTotalItems());
+ Assert.assertEquals(2000, sampling.getPopulation().getTotalItems());
+ }
+
+ @Test
+ public void samplingDecisionWith100Chance(){
+ Sampling sampling = new Sampling(1, 100, false);
+ for (int i = 0; i < 2000; i++) {
+ Assert.assertTrue(sampling.samplingDecision(new Granularity(GranularityType.METHOD, "function")));
+ }
+ Assert.assertEquals(2000, sampling.getSample().getTotalItems());
+ Assert.assertEquals(2000, sampling.getPopulation().getTotalItems());
}
}