aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-batch
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2013-04-16 16:46:35 +0200
committerJulien HENRY <julien.henry@sonarsource.com>2013-04-16 16:49:13 +0200
commitd8d846936cb37aafccb672074e3b8ee1d995f608 (patch)
treef0c7446b68cad9d2f89b32a5624d683eb9fb0624 /sonar-batch
parentfb7248d86bc6b540567a2dcc8ee9cad6a615e254 (diff)
downloadsonarqube-d8d846936cb37aafccb672074e3b8ee1d995f608.tar.gz
sonarqube-d8d846936cb37aafccb672074e3b8ee1d995f608.zip
SONAR-4147 Support a new profiling option "sonar.profiling.log=true"
Diffstat (limited to 'sonar-batch')
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/phases/Phases.java13
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/phases/PostJobExecutionEvent.java50
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/phases/PostJobPhaseEvent.java51
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/phases/PostJobsExecutor.java13
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/phases/SensorsExecutor.java2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/profiling/AbstractTimeProfiling.java93
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/profiling/ItemProfiling.java34
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/profiling/ModuleProfiling.java64
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/profiling/PhaseProfiling.java106
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/profiling/PhasesSumUpTimeProfiler.java162
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/profiling/package-info.java24
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java79
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapContainerTest.java8
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/phases/PostJobsExecutorTest.java5
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/profiling/PhasesSumUpTimeProfilerTest.java360
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/scan/ProjectScanContainerTest.java23
17 files changed, 1046 insertions, 43 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java
index d7459b0e7a7..b2314ee7053 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java
@@ -76,7 +76,7 @@ public final class Batch {
}
private void startBatch() {
- List all = Lists.newArrayList(components);
+ List<Object> all = Lists.newArrayList(components);
all.add(new BootstrapProperties(bootstrapProperties));
if (projectReactor != null) {
all.add(projectReactor);
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/Phases.java b/sonar-batch/src/main/java/org/sonar/batch/phases/Phases.java
index 2ccb0da0d05..6694153325e 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/phases/Phases.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/phases/Phases.java
@@ -27,7 +27,18 @@ import java.util.Set;
public class Phases {
public static enum Phase {
- MAVEN, INIT, SENSOR, DECORATOR, POSTJOB
+ MAVEN("Maven"), INIT("Initializers"), SENSOR("Sensors"), DECORATOR("Decorators"), POSTJOB("Post-Jobs");
+
+ private final String label;
+
+ private Phase(String label) {
+ this.label = label;
+ }
+
+ @Override
+ public String toString() {
+ return label;
+ }
}
private final Set<Phase> enabled = Sets.newHashSet();
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/PostJobExecutionEvent.java b/sonar-batch/src/main/java/org/sonar/batch/phases/PostJobExecutionEvent.java
new file mode 100644
index 00000000000..05eb06718f6
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/phases/PostJobExecutionEvent.java
@@ -0,0 +1,50 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.phases;
+
+import org.sonar.api.batch.PostJob;
+import org.sonar.api.batch.events.PostJobExecutionHandler;
+
+class PostJobExecutionEvent extends AbstractPhaseEvent<PostJobExecutionHandler>
+ implements org.sonar.api.batch.events.PostJobExecutionHandler.PostJobExecutionEvent {
+
+ private final PostJob postJob;
+
+ PostJobExecutionEvent(PostJob postJob, boolean start) {
+ super(start);
+ this.postJob = postJob;
+ }
+
+ @Override
+ public PostJob getPostJob() {
+ return postJob;
+ }
+
+ @Override
+ public void dispatch(PostJobExecutionHandler handler) {
+ handler.onPostJobExecution(this);
+ }
+
+ @Override
+ public Class getType() {
+ return PostJobExecutionHandler.class;
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/PostJobPhaseEvent.java b/sonar-batch/src/main/java/org/sonar/batch/phases/PostJobPhaseEvent.java
new file mode 100644
index 00000000000..1dc88497501
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/phases/PostJobPhaseEvent.java
@@ -0,0 +1,51 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.phases;
+
+import org.sonar.api.batch.PostJob;
+import org.sonar.api.batch.events.PostJobsPhaseHandler;
+
+import java.util.List;
+
+class PostJobPhaseEvent extends AbstractPhaseEvent<PostJobsPhaseHandler>
+ implements org.sonar.api.batch.events.PostJobsPhaseHandler.PostJobsPhaseEvent {
+
+ private final List<PostJob> postJobs;
+
+ PostJobPhaseEvent(List<PostJob> postJobs, boolean start) {
+ super(start);
+ this.postJobs = postJobs;
+ }
+
+ public List<PostJob> getPostJobs() {
+ return postJobs;
+ }
+
+ @Override
+ protected void dispatch(PostJobsPhaseHandler handler) {
+ handler.onPostJobsPhase(this);
+ }
+
+ @Override
+ protected Class getType() {
+ return PostJobsPhaseHandler.class;
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/PostJobsExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/phases/PostJobsExecutor.java
index ee89e9ac2da..5a1736552c4 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/phases/PostJobsExecutor.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/phases/PostJobsExecutor.java
@@ -19,6 +19,7 @@
*/
package org.sonar.batch.phases;
+import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -29,9 +30,10 @@ import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.maven.DependsUponMavenPlugin;
import org.sonar.api.batch.maven.MavenPluginHandler;
import org.sonar.api.resources.Project;
-import org.sonar.batch.scan.maven.MavenPluginExecutor;
+import org.sonar.batch.events.EventBus;
import org.sonar.batch.local.DryRunExporter;
import org.sonar.batch.scan.filesystem.DefaultModuleFileSystem;
+import org.sonar.batch.scan.maven.MavenPluginExecutor;
import java.util.Collection;
@@ -43,20 +45,25 @@ public class PostJobsExecutor implements BatchComponent {
private final DefaultModuleFileSystem fs;
private final MavenPluginExecutor mavenExecutor;
private final DryRunExporter localModeExporter;
+ private final EventBus eventBus;
public PostJobsExecutor(BatchExtensionDictionnary selector, Project project, DefaultModuleFileSystem fs, MavenPluginExecutor mavenExecutor,
- DryRunExporter localModeExporter) {
+ DryRunExporter localModeExporter, EventBus eventBus) {
this.selector = selector;
this.project = project;
this.fs = fs;
this.mavenExecutor = mavenExecutor;
this.localModeExporter = localModeExporter;
+ this.eventBus = eventBus;
}
public void execute(SensorContext context) {
Collection<PostJob> postJobs = selector.select(PostJob.class, project, true);
+
+ eventBus.fireEvent(new PostJobPhaseEvent(Lists.newArrayList(postJobs), true));
execute(context, postJobs);
exportLocalModeResults(context);
+ eventBus.fireEvent(new PostJobPhaseEvent(Lists.newArrayList(postJobs), false));
}
private void execute(SensorContext context, Collection<PostJob> postJobs) {
@@ -64,8 +71,10 @@ public class PostJobsExecutor implements BatchComponent {
for (PostJob postJob : postJobs) {
LOG.info("Executing post-job {}", postJob.getClass());
+ eventBus.fireEvent(new PostJobExecutionEvent(postJob, true));
executeMavenPlugin(postJob);
postJob.executeOn(project, context);
+ eventBus.fireEvent(new PostJobExecutionEvent(postJob, false));
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/SensorsExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/phases/SensorsExecutor.java
index 9428884f068..47f1eff8e2a 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/phases/SensorsExecutor.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/phases/SensorsExecutor.java
@@ -66,9 +66,9 @@ public class SensorsExecutor implements BatchComponent {
for (Sensor sensor : sensors) {
// SONAR-2965 In case the sensor takes too much time we close the session to not face a timeout
session.commitAndClose();
- executeMavenPlugin(sensor);
eventBus.fireEvent(new SensorExecutionEvent(sensor, true));
+ executeMavenPlugin(sensor);
sensor.analyse(project, context);
eventBus.fireEvent(new SensorExecutionEvent(sensor, false));
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/profiling/AbstractTimeProfiling.java b/sonar-batch/src/main/java/org/sonar/batch/profiling/AbstractTimeProfiling.java
new file mode 100644
index 00000000000..5ff269a69ac
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/profiling/AbstractTimeProfiling.java
@@ -0,0 +1,93 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.profiling;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public abstract class AbstractTimeProfiling {
+
+ private final long startTime;
+
+ private long totalTime;
+
+ public AbstractTimeProfiling() {
+ this.startTime = System.currentTimeMillis();
+ }
+
+ public long startTime() {
+ return startTime;
+ }
+
+ public void stop() {
+ this.totalTime = System.currentTimeMillis() - startTime;
+ }
+
+ public long totalTime() {
+ return totalTime;
+ }
+
+ public String totalTimeAsString() {
+ if (totalTime < 1000) {
+ return String.format("%sms", totalTime);
+ }
+ else {
+ long sec = totalTime / 1000;
+ // long remainingMs = totalTime - (sec * 1000);
+ if (sec < 60) {
+ return String.format("%ss", sec);
+ }
+ else {
+ long min = sec / 60;
+ long remainingSec = sec - (min * 60);
+ if (remainingSec > 0) {
+ return String.format("%smin %ss", min, remainingSec);
+ }
+ else {
+ return String.format("%smin", min);
+ }
+ }
+ }
+ }
+
+ public void setTotalTime(long totalTime) {
+ this.totalTime = totalTime;
+ }
+
+ protected void add(AbstractTimeProfiling other) {
+ this.setTotalTime(this.totalTime() + other.totalTime());
+ }
+
+ protected <G extends AbstractTimeProfiling> List<G> sortByDescendingTotalTime(Collection<G> unsorted) {
+ List<G> result = new ArrayList<G>(unsorted.size());
+ result.addAll(unsorted);
+ Collections.sort(result, new Comparator<G>() {
+ @Override
+ public int compare(G o1, G o2) {
+ return Long.valueOf(o2.totalTime()).compareTo(o1.totalTime());
+ }
+ });
+ return result;
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/profiling/ItemProfiling.java b/sonar-batch/src/main/java/org/sonar/batch/profiling/ItemProfiling.java
new file mode 100644
index 00000000000..18998ab6b10
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/profiling/ItemProfiling.java
@@ -0,0 +1,34 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.profiling;
+
+public class ItemProfiling extends AbstractTimeProfiling {
+
+ private final String itemName;
+
+ public ItemProfiling(String itemName) {
+ this.itemName = itemName;
+ }
+
+ public String itemName() {
+ return itemName;
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/profiling/ModuleProfiling.java b/sonar-batch/src/main/java/org/sonar/batch/profiling/ModuleProfiling.java
new file mode 100644
index 00000000000..40c00be5050
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/profiling/ModuleProfiling.java
@@ -0,0 +1,64 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.profiling;
+
+import org.sonar.batch.phases.Phases;
+import org.sonar.batch.phases.Phases.Phase;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public class ModuleProfiling extends AbstractTimeProfiling {
+
+ private Map<Phases.Phase, PhaseProfiling> profilingPerPhase = new HashMap<Phases.Phase, PhaseProfiling>();
+
+ public PhaseProfiling getProfilingPerPhase(Phase phase) {
+ return profilingPerPhase.get(phase);
+ }
+
+ public void addPhaseProfiling(Phase phase) {
+ profilingPerPhase.put(phase, PhaseProfiling.create(phase));
+ }
+
+ public void dump() {
+ for (PhaseProfiling phaseProfiling : sortByDescendingTotalTime(profilingPerPhase.values())) {
+ System.out.println(" * " + phaseProfiling.phase() + " execution time: " + phaseProfiling.totalTimeAsString());
+ }
+ for (Phase phase : Phases.Phase.values()) {
+ if (profilingPerPhase.containsKey(phase)) {
+ System.out.println("");
+ System.out.println(" * " + phase + " execution time breakdown");
+ getProfilingPerPhase(phase).dump();
+ }
+ }
+ }
+
+ public void merge(ModuleProfiling other) {
+ super.add(other);
+ for (Entry<Phases.Phase, PhaseProfiling> entry : other.profilingPerPhase.entrySet()) {
+ if (!this.profilingPerPhase.containsKey(entry.getKey())) {
+ this.addPhaseProfiling(entry.getKey());
+ }
+ this.getProfilingPerPhase(entry.getKey()).merge(entry.getValue());
+ }
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/profiling/PhaseProfiling.java b/sonar-batch/src/main/java/org/sonar/batch/profiling/PhaseProfiling.java
new file mode 100644
index 00000000000..5ed818970f2
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/profiling/PhaseProfiling.java
@@ -0,0 +1,106 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.profiling;
+
+import org.sonar.batch.phases.Phases.Phase;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public class PhaseProfiling extends AbstractTimeProfiling {
+
+ private final Phase phase;
+
+ private Map<String, ItemProfiling> profilingPerItem = new HashMap<String, ItemProfiling>();
+
+ public PhaseProfiling(Phase phase) {
+ this.phase = phase;
+ }
+
+ public static PhaseProfiling create(Phase phase) {
+ return new PhaseProfiling(phase);
+ }
+
+ public Phase phase() {
+ return phase;
+ }
+
+ public ItemProfiling getProfilingPerItem(Object item) {
+ String stringOrSimpleName = toStringOrSimpleName(item);
+ return profilingPerItem.get(stringOrSimpleName);
+ }
+
+ public void newItemProfiling(Object item) {
+ String stringOrSimpleName = toStringOrSimpleName(item);
+ profilingPerItem.put(stringOrSimpleName, new ItemProfiling(stringOrSimpleName));
+ }
+
+ public void newItemProfiling(String itemName) {
+ profilingPerItem.put(itemName, new ItemProfiling(itemName));
+ }
+
+ public void merge(PhaseProfiling other) {
+ super.add(other);
+ for (Entry<String, ItemProfiling> entry : other.profilingPerItem.entrySet()) {
+ if (!this.profilingPerItem.containsKey(entry.getKey())) {
+ newItemProfiling(entry.getKey());
+ }
+ this.getProfilingPerItem(entry.getKey()).add(entry.getValue());
+ }
+ }
+
+ public void dump() {
+ for (ItemProfiling itemProfiling : truncateList(sortByDescendingTotalTime(profilingPerItem.values()))) {
+ System.out.println(" o " + itemProfiling.itemName() + ": " + itemProfiling.totalTimeAsString());
+ }
+ }
+
+ /**
+ * Try to use toString if it is not the default {@link Object#toString()}. Else use {@link Class#getSimpleName()}
+ * @param o
+ * @return
+ */
+ private String toStringOrSimpleName(Object o) {
+ String toString = o.toString();
+ if (toString == null || toString.startsWith(o.getClass().getName())) {
+ return o.getClass().getSimpleName();
+ }
+ return toString;
+ }
+
+ private List<ItemProfiling> truncateList(List<ItemProfiling> sortedFullList) {
+ int maxSize = 10;
+ List<ItemProfiling> result = new ArrayList<ItemProfiling>(maxSize);
+ int i = 0;
+ for (ItemProfiling item : sortedFullList) {
+ if (i++ >= maxSize || item.totalTime() == 0) {
+ return result;
+ }
+ else {
+ result.add(item);
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/profiling/PhasesSumUpTimeProfiler.java b/sonar-batch/src/main/java/org/sonar/batch/profiling/PhasesSumUpTimeProfiler.java
new file mode 100644
index 00000000000..88f3c0de6dd
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/profiling/PhasesSumUpTimeProfiler.java
@@ -0,0 +1,162 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.profiling;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Lists;
+import org.sonar.api.batch.Decorator;
+import org.sonar.api.batch.events.DecoratorExecutionHandler;
+import org.sonar.api.batch.events.DecoratorsPhaseHandler;
+import org.sonar.api.batch.events.PostJobExecutionHandler;
+import org.sonar.api.batch.events.PostJobsPhaseHandler;
+import org.sonar.api.batch.events.ProjectAnalysisHandler;
+import org.sonar.api.batch.events.SensorExecutionHandler;
+import org.sonar.api.batch.events.SensorsPhaseHandler;
+import org.sonar.api.resources.Project;
+import org.sonar.batch.phases.Phases;
+
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+
+public class PhasesSumUpTimeProfiler implements ProjectAnalysisHandler, SensorExecutionHandler, DecoratorExecutionHandler, PostJobExecutionHandler, DecoratorsPhaseHandler,
+ SensorsPhaseHandler, PostJobsPhaseHandler {
+
+ @VisibleForTesting
+ ModuleProfiling currentModuleProfiling;
+ @VisibleForTesting
+ ModuleProfiling totalProfiling = new ModuleProfiling();
+ private DecoratorsProfiler decoratorsProfiler;
+
+ @Override
+ public void onProjectAnalysis(ProjectAnalysisEvent event) {
+ Project module = event.getProject();
+ if (event.isStart()) {
+ decoratorsProfiler = new DecoratorsProfiler();
+ currentModuleProfiling = new ModuleProfiling();
+ }
+ else {
+ currentModuleProfiling.stop();
+ System.out.println("\n -------- Profiling for module " + module.getName() + " --------\n");
+ currentModuleProfiling.dump();
+ System.out.println("\n -------- End of profiling for module " + module.getName() + " --------\n");
+ totalProfiling.merge(currentModuleProfiling);
+ if (module.isRoot() && !module.getModules().isEmpty()) {
+ totalProfiling.stop();
+ System.out.println("\n ======== Profiling for total execution ========\n");
+ totalProfiling.dump();
+ System.out.println("\n ======== End of profiling for total execution ========\n");
+ }
+ }
+ }
+
+ public void onSensorsPhase(SensorsPhaseEvent event) {
+ if (event.isStart()) {
+ currentModuleProfiling.addPhaseProfiling(Phases.Phase.SENSOR);
+ }
+ else {
+ currentModuleProfiling.getProfilingPerPhase(Phases.Phase.SENSOR).stop();
+ }
+ }
+
+ public void onSensorExecution(SensorExecutionEvent event) {
+ PhaseProfiling profiling = currentModuleProfiling.getProfilingPerPhase(Phases.Phase.SENSOR);
+ if (event.isStart()) {
+ profiling.newItemProfiling(event.getSensor());
+ } else {
+ profiling.getProfilingPerItem(event.getSensor()).stop();
+ }
+ }
+
+ public void onDecoratorExecution(DecoratorExecutionEvent event) {
+ PhaseProfiling profiling = currentModuleProfiling.getProfilingPerPhase(Phases.Phase.DECORATOR);
+ if (event.isStart()) {
+ if (profiling.getProfilingPerItem(event.getDecorator()) == null) {
+ profiling.newItemProfiling(event.getDecorator());
+ }
+ decoratorsProfiler.start(event.getDecorator());
+ } else {
+ decoratorsProfiler.stop();
+ }
+ }
+
+ public void onDecoratorsPhase(DecoratorsPhaseEvent event) {
+ if (event.isStart()) {
+ currentModuleProfiling.addPhaseProfiling(Phases.Phase.DECORATOR);
+ }
+ else {
+ for (Decorator decorator : decoratorsProfiler.getDurations().keySet()) {
+ currentModuleProfiling.getProfilingPerPhase(Phases.Phase.DECORATOR)
+ .getProfilingPerItem(decorator).setTotalTime(decoratorsProfiler.getDurations().get(decorator));
+ }
+ currentModuleProfiling.getProfilingPerPhase(Phases.Phase.DECORATOR).stop();
+ }
+ }
+
+ public void onPostJobsPhase(PostJobsPhaseEvent event) {
+ if (event.isStart()) {
+ currentModuleProfiling.addPhaseProfiling(Phases.Phase.POSTJOB);
+ }
+ else {
+ currentModuleProfiling.getProfilingPerPhase(Phases.Phase.POSTJOB).stop();
+ }
+ }
+
+ public void onPostJobExecution(PostJobExecutionEvent event) {
+ PhaseProfiling profiling = currentModuleProfiling.getProfilingPerPhase(Phases.Phase.POSTJOB);
+ if (event.isStart()) {
+ profiling.newItemProfiling(event.getPostJob());
+ } else {
+ profiling.getProfilingPerItem(event.getPostJob()).stop();
+ }
+ }
+
+ static class DecoratorsProfiler {
+ List<Decorator> decorators = Lists.newArrayList();
+ Map<Decorator, Long> durations = new IdentityHashMap<Decorator, Long>();
+ long startTime;
+ Decorator currentDecorator;
+
+ DecoratorsProfiler() {
+ }
+
+ void start(Decorator decorator) {
+ this.startTime = System.currentTimeMillis();
+ this.currentDecorator = decorator;
+ }
+
+ void stop() {
+ final Long cumulatedDuration;
+ if (durations.containsKey(currentDecorator)) {
+ cumulatedDuration = durations.get(currentDecorator);
+ } else {
+ decorators.add(currentDecorator);
+ cumulatedDuration = 0L;
+ }
+ durations.put(currentDecorator, cumulatedDuration + (System.currentTimeMillis() - startTime));
+ }
+
+ public Map<Decorator, Long> getDurations() {
+ return durations;
+ }
+
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/profiling/package-info.java b/sonar-batch/src/main/java/org/sonar/batch/profiling/package-info.java
new file mode 100644
index 00000000000..6c52d959784
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/profiling/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.batch.profiling;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
index e6d7cdd5003..ed9c5bba0c5 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
@@ -20,7 +20,9 @@
package org.sonar.batch.scan;
import org.sonar.api.BatchExtension;
+import org.sonar.api.CoreProperties;
import org.sonar.api.batch.InstantiationStrategy;
+import org.sonar.api.config.Settings;
import org.sonar.api.platform.ComponentContainer;
import org.sonar.api.resources.Project;
import org.sonar.batch.DefaultFileLinesContextFactory;
@@ -31,12 +33,22 @@ import org.sonar.batch.bootstrap.ExtensionInstaller;
import org.sonar.batch.bootstrap.ExtensionMatcher;
import org.sonar.batch.bootstrap.ExtensionUtils;
import org.sonar.batch.bootstrap.MetricProvider;
-import org.sonar.batch.index.*;
+import org.sonar.batch.index.DefaultIndex;
+import org.sonar.batch.index.DefaultPersistenceManager;
+import org.sonar.batch.index.DefaultResourcePersister;
+import org.sonar.batch.index.DependencyPersister;
+import org.sonar.batch.index.EventPersister;
+import org.sonar.batch.index.LinkPersister;
+import org.sonar.batch.index.MeasurePersister;
+import org.sonar.batch.index.MemoryOptimizer;
+import org.sonar.batch.index.SnapshotCache;
+import org.sonar.batch.index.SourcePersister;
import org.sonar.batch.issue.DeprecatedViolations;
import org.sonar.batch.issue.IssueCache;
import org.sonar.batch.issue.IssuePersister;
import org.sonar.batch.issue.ScanIssueActions;
import org.sonar.batch.phases.GraphPersister;
+import org.sonar.batch.profiling.PhasesSumUpTimeProfiler;
import org.sonar.batch.scan.maven.FakeMavenPluginExecutor;
import org.sonar.batch.scan.maven.MavenPluginExecutor;
import org.sonar.batch.scan.source.SourceDataPersister;
@@ -59,44 +71,47 @@ public class ProjectScanContainer extends ComponentContainer {
addBatchComponents();
fixMavenExecutor();
addBatchExtensions();
+ Settings settings = getComponentByType(Settings.class);
+ if (settings != null && settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)) {
+ add(PhasesSumUpTimeProfiler.class);
+ }
}
private void addBatchComponents() {
add(
- DefaultResourceCreationLock.class,
- DefaultPersistenceManager.class,
- DependencyPersister.class,
- EventPersister.class,
- LinkPersister.class,
- MeasurePersister.class,
- MemoryOptimizer.class,
- DefaultResourcePersister.class,
- SourcePersister.class,
- DefaultNotificationManager.class,
- MetricProvider.class,
- ProjectConfigurator.class,
- DefaultIndex.class,
- DefaultFileLinesContextFactory.class,
- ProjectLock.class,
- LastSnapshots.class,
- SnapshotCache.class,
+ DefaultResourceCreationLock.class,
+ DefaultPersistenceManager.class,
+ DependencyPersister.class,
+ EventPersister.class,
+ LinkPersister.class,
+ MeasurePersister.class,
+ MemoryOptimizer.class,
+ DefaultResourcePersister.class,
+ SourcePersister.class,
+ DefaultNotificationManager.class,
+ MetricProvider.class,
+ ProjectConfigurator.class,
+ DefaultIndex.class,
+ DefaultFileLinesContextFactory.class,
+ ProjectLock.class,
+ LastSnapshots.class,
+ SnapshotCache.class,
- ScanIssueActions.class,
- DeprecatedViolations.class,
- IssueCache.class,
- IssuePersister.class,
+ ScanIssueActions.class,
+ DeprecatedViolations.class,
+ IssueCache.class,
+ IssuePersister.class,
- TestPlanPerspectiveLoader.class,
- TestablePerspectiveLoader.class,
- TestPlanBuilder.class,
- TestableBuilder.class,
- ScanGraph.create(),
- GraphPersister.class,
+ TestPlanPerspectiveLoader.class,
+ TestablePerspectiveLoader.class,
+ TestPlanBuilder.class,
+ TestableBuilder.class,
+ ScanGraph.create(),
+ GraphPersister.class,
- SyntaxHighlightingCache.class,
- SymbolDataCache.class,
- SourceDataPersister.class
- );
+ SyntaxHighlightingCache.class,
+ SymbolDataCache.class,
+ SourceDataPersister.class);
}
private void fixMavenExecutor() {
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapContainerTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapContainerTest.java
index db3a4d21bfe..347ff07f085 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapContainerTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BootstrapContainerTest.java
@@ -62,11 +62,11 @@ public class BootstrapContainerTest {
PluginMetadata metadata = mock(PluginMetadata.class);
FakePlugin plugin = new FakePlugin();
BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class);
- when(pluginRepository.getPluginsByMetadata()).thenReturn(ImmutableMap.<PluginMetadata, Plugin>of(
- metadata, plugin
- ));
+ when(pluginRepository.getPluginsByMetadata()).thenReturn(ImmutableMap.<PluginMetadata, Plugin> of(
+ metadata, plugin
+ ));
- BootstrapContainer container = spy(BootstrapContainer.create(Lists.newArrayList(pluginRepository)));
+ BootstrapContainer container = spy(BootstrapContainer.create(Lists.<Object> newArrayList(pluginRepository)));
doNothing().when(container).executeTask();
container.doAfterStart();
diff --git a/sonar-batch/src/test/java/org/sonar/batch/phases/PostJobsExecutorTest.java b/sonar-batch/src/test/java/org/sonar/batch/phases/PostJobsExecutorTest.java
index 4f23c04a2c9..5b1472b2c88 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/phases/PostJobsExecutorTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/phases/PostJobsExecutorTest.java
@@ -25,9 +25,10 @@ import org.sonar.api.batch.BatchExtensionDictionnary;
import org.sonar.api.batch.PostJob;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.resources.Project;
-import org.sonar.batch.scan.maven.MavenPluginExecutor;
+import org.sonar.batch.events.EventBus;
import org.sonar.batch.local.DryRunExporter;
import org.sonar.batch.scan.filesystem.DefaultModuleFileSystem;
+import org.sonar.batch.scan.maven.MavenPluginExecutor;
import java.util.Arrays;
@@ -48,7 +49,7 @@ public class PostJobsExecutorTest {
@Before
public void setUp() {
- executor = new PostJobsExecutor(selector, project, mock(DefaultModuleFileSystem.class), mavenPluginExecutor, localModeExporter);
+ executor = new PostJobsExecutor(selector, project, mock(DefaultModuleFileSystem.class), mavenPluginExecutor, localModeExporter, mock(EventBus.class));
}
@Test
diff --git a/sonar-batch/src/test/java/org/sonar/batch/profiling/PhasesSumUpTimeProfilerTest.java b/sonar-batch/src/test/java/org/sonar/batch/profiling/PhasesSumUpTimeProfilerTest.java
new file mode 100644
index 00000000000..e5b586979a0
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/profiling/PhasesSumUpTimeProfilerTest.java
@@ -0,0 +1,360 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.profiling;
+
+import org.junit.Test;
+import org.sonar.api.batch.Decorator;
+import org.sonar.api.batch.DecoratorContext;
+import org.sonar.api.batch.PostJob;
+import org.sonar.api.batch.Sensor;
+import org.sonar.api.batch.SensorContext;
+import org.sonar.api.batch.events.DecoratorExecutionHandler;
+import org.sonar.api.batch.events.DecoratorsPhaseHandler;
+import org.sonar.api.batch.events.PostJobExecutionHandler;
+import org.sonar.api.batch.events.PostJobsPhaseHandler;
+import org.sonar.api.batch.events.ProjectAnalysisHandler;
+import org.sonar.api.batch.events.ProjectAnalysisHandler.ProjectAnalysisEvent;
+import org.sonar.api.batch.events.SensorExecutionHandler;
+import org.sonar.api.batch.events.SensorExecutionHandler.SensorExecutionEvent;
+import org.sonar.api.batch.events.SensorsPhaseHandler;
+import org.sonar.api.batch.events.SensorsPhaseHandler.SensorsPhaseEvent;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Resource;
+import org.sonar.batch.phases.Phases.Phase;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class PhasesSumUpTimeProfilerTest {
+
+ @Test
+ public void testSimpleProject() throws InterruptedException {
+ PhasesSumUpTimeProfiler profiler = new PhasesSumUpTimeProfiler();
+ final Project project = mockProject("project", true);
+ when(project.getModules()).thenReturn(Collections.<Project> emptyList());
+
+ fakeAnalysis(profiler, project);
+
+ assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.SENSOR).getProfilingPerItem(new FakeSensor()).totalTime()).isIn(delta(10L, 5));
+ assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator1()).totalTime()).isIn(delta(20L, 5));
+ assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.POSTJOB).getProfilingPerItem(new FakePostJob()).totalTime()).isIn(delta(30L, 5));
+
+ }
+
+ @Test
+ public void testMultimoduleProject() throws InterruptedException {
+ PhasesSumUpTimeProfiler profiler = new PhasesSumUpTimeProfiler();
+ final Project project = mockProject("project root", true);
+ final Project moduleA = mockProject("moduleA", false);
+ final Project moduleB = mockProject("moduleB", false);
+ when(project.getModules()).thenReturn(Arrays.asList(moduleA, moduleB));
+
+ fakeAnalysis(profiler, moduleA);
+ fakeAnalysis(profiler, moduleB);
+ fakeAnalysis(profiler, project);
+
+ assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.SENSOR).getProfilingPerItem(new FakeSensor()).totalTime()).isIn(delta(10L, 5));
+ assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator1()).totalTime()).isIn(delta(20L, 5));
+ assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator2()).totalTime()).isIn(delta(10L, 5));
+ assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.POSTJOB).getProfilingPerItem(new FakePostJob()).totalTime()).isIn(delta(30L, 5));
+
+ assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.SENSOR).getProfilingPerItem(new FakeSensor()).totalTime()).isIn(delta(30L, 5));
+ assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator1()).totalTime()).isIn(delta(60L, 10));
+ assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator2()).totalTime()).isIn(delta(30L, 5));
+ assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.POSTJOB).getProfilingPerItem(new FakePostJob()).totalTime()).isIn(delta(90L, 10));
+ }
+
+ @Test
+ public void testDisplayTimings() {
+ AbstractTimeProfiling profiling = new AbstractTimeProfiling() {
+ };
+
+ profiling.setTotalTime(5);
+ assertThat(profiling.totalTimeAsString()).isEqualTo("5ms");
+
+ profiling.setTotalTime(5 * 1000 + 12);
+ assertThat(profiling.totalTimeAsString()).isEqualTo("5s");
+
+ profiling.setTotalTime(5 * 60 * 1000 + 12 * 1000);
+ assertThat(profiling.totalTimeAsString()).isEqualTo("5min 12s");
+
+ profiling.setTotalTime(5 * 60 * 1000);
+ assertThat(profiling.totalTimeAsString()).isEqualTo("5min");
+ }
+
+ private Object[] delta(long value, int delta) {
+ Long[] result = new Long[2 * delta + 1];
+ int index = 0;
+ for (long i = value - delta; i <= value + delta; i++) {
+ result[index++] = i;
+ }
+ return result;
+ }
+
+ private Project mockProject(String name, boolean isRoot) {
+ final Project project = mock(Project.class);
+ when(project.isRoot()).thenReturn(isRoot);
+ when(project.getName()).thenReturn(name);
+ return project;
+ }
+
+ private void fakeAnalysis(PhasesSumUpTimeProfiler profiler, final Project module) throws InterruptedException {
+ // Start of moduleA
+ profiler.onProjectAnalysis(projectEvent(module, true));
+ sensorPhase(profiler);
+ decoratorPhase(profiler);
+ postJobPhase(profiler);
+ // End of moduleA
+ profiler.onProjectAnalysis(projectEvent(module, false));
+ }
+
+ private void decoratorPhase(PhasesSumUpTimeProfiler profiler) throws InterruptedException {
+ Decorator decorator1 = new FakeDecorator1();
+ Decorator decorator2 = new FakeDecorator2();
+ // Start of decorator phase
+ profiler.onDecoratorsPhase(decoratorsEvent(true));
+ // Start of decorator 1
+ profiler.onDecoratorExecution(decoratorEvent(decorator1, true));
+ Thread.sleep(10);
+ // End of decorator 1
+ profiler.onDecoratorExecution(decoratorEvent(decorator1, false));
+ // Start of decorator 2
+ profiler.onDecoratorExecution(decoratorEvent(decorator2, true));
+ Thread.sleep(5);
+ // End of decorator 2
+ profiler.onDecoratorExecution(decoratorEvent(decorator2, false));
+ // Start of decorator 1
+ profiler.onDecoratorExecution(decoratorEvent(decorator1, true));
+ Thread.sleep(10);
+ // End of decorator 1
+ profiler.onDecoratorExecution(decoratorEvent(decorator1, false));
+ // Start of decorator 2
+ profiler.onDecoratorExecution(decoratorEvent(decorator2, true));
+ Thread.sleep(5);
+ // End of decorator 2
+ profiler.onDecoratorExecution(decoratorEvent(decorator2, false));
+ // End of decorator phase
+ profiler.onDecoratorsPhase(decoratorsEvent(false));
+ }
+
+ private void sensorPhase(PhasesSumUpTimeProfiler profiler) throws InterruptedException {
+ Sensor sensor = new FakeSensor();
+ // Start of sensor phase
+ profiler.onSensorsPhase(sensorsEvent(true));
+ // Start of a Sensor
+ profiler.onSensorExecution(sensorEvent(sensor, true));
+ Thread.sleep(10);
+ // End of a Sensor
+ profiler.onSensorExecution(sensorEvent(sensor, false));
+ // End of sensor phase
+ profiler.onSensorsPhase(sensorsEvent(false));
+ }
+
+ private void postJobPhase(PhasesSumUpTimeProfiler profiler) throws InterruptedException {
+ PostJob postJob = new FakePostJob();
+ // Start of sensor phase
+ profiler.onPostJobsPhase(postJobsEvent(true));
+ // Start of a Sensor
+ profiler.onPostJobExecution(postJobEvent(postJob, true));
+ Thread.sleep(30);
+ // End of a Sensor
+ profiler.onPostJobExecution(postJobEvent(postJob, false));
+ // End of sensor phase
+ profiler.onPostJobsPhase(postJobsEvent(false));
+ }
+
+ private SensorExecutionEvent sensorEvent(final Sensor sensor, final boolean start) {
+ return new SensorExecutionHandler.SensorExecutionEvent() {
+
+ @Override
+ public boolean isStart() {
+ return start;
+ }
+
+ @Override
+ public boolean isEnd() {
+ return !start;
+ }
+
+ @Override
+ public Sensor getSensor() {
+ return sensor;
+ }
+ };
+ }
+
+ private DecoratorExecutionHandler.DecoratorExecutionEvent decoratorEvent(final Decorator decorator, final boolean start) {
+ return new DecoratorExecutionHandler.DecoratorExecutionEvent() {
+
+ @Override
+ public boolean isStart() {
+ return start;
+ }
+
+ @Override
+ public boolean isEnd() {
+ return !start;
+ }
+
+ @Override
+ public Decorator getDecorator() {
+ return decorator;
+ }
+ };
+ }
+
+ private PostJobExecutionHandler.PostJobExecutionEvent postJobEvent(final PostJob postJob, final boolean start) {
+ return new PostJobExecutionHandler.PostJobExecutionEvent() {
+
+ @Override
+ public boolean isStart() {
+ return start;
+ }
+
+ @Override
+ public boolean isEnd() {
+ return !start;
+ }
+
+ @Override
+ public PostJob getPostJob() {
+ return postJob;
+ }
+ };
+ }
+
+ private SensorsPhaseEvent sensorsEvent(final boolean start) {
+ return new SensorsPhaseHandler.SensorsPhaseEvent() {
+
+ @Override
+ public boolean isStart() {
+ return start;
+ }
+
+ @Override
+ public boolean isEnd() {
+ return !start;
+ }
+
+ @Override
+ public List<Sensor> getSensors() {
+ return null;
+ }
+ };
+ }
+
+ private PostJobsPhaseHandler.PostJobsPhaseEvent postJobsEvent(final boolean start) {
+ return new PostJobsPhaseHandler.PostJobsPhaseEvent() {
+
+ @Override
+ public boolean isStart() {
+ return start;
+ }
+
+ @Override
+ public boolean isEnd() {
+ return !start;
+ }
+
+ @Override
+ public List<PostJob> getPostJobs() {
+ return null;
+ }
+ };
+ }
+
+ private DecoratorsPhaseHandler.DecoratorsPhaseEvent decoratorsEvent(final boolean start) {
+ return new DecoratorsPhaseHandler.DecoratorsPhaseEvent() {
+
+ @Override
+ public boolean isStart() {
+ return start;
+ }
+
+ @Override
+ public boolean isEnd() {
+ return !start;
+ }
+
+ @Override
+ public List<Decorator> getDecorators() {
+ return null;
+ }
+ };
+ }
+
+ private ProjectAnalysisEvent projectEvent(final Project project, final boolean start) {
+ return new ProjectAnalysisHandler.ProjectAnalysisEvent() {
+ @Override
+ public boolean isStart() {
+ return start;
+ }
+
+ @Override
+ public boolean isEnd() {
+ return !start;
+ }
+
+ @Override
+ public Project getProject() {
+ return project;
+ }
+ };
+ }
+
+ public class FakeSensor implements Sensor {
+ @Override
+ public void analyse(Project project, SensorContext context) {
+ }
+
+ public boolean shouldExecuteOnProject(Project project) {
+ return true;
+ }
+ }
+
+ public class FakeDecorator1 implements Decorator {
+ public void decorate(Resource resource, DecoratorContext context) {
+ }
+
+ public boolean shouldExecuteOnProject(Project project) {
+ return true;
+ }
+ }
+
+ public class FakeDecorator2 implements Decorator {
+ public void decorate(Resource resource, DecoratorContext context) {
+ }
+
+ public boolean shouldExecuteOnProject(Project project) {
+ return true;
+ }
+ }
+
+ public class FakePostJob implements PostJob {
+ @Override
+ public void executeOn(Project project, SensorContext context) {
+ }
+ }
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectScanContainerTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectScanContainerTest.java
index 3ec36cd3313..9cd35fd0c8d 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectScanContainerTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectScanContainerTest.java
@@ -21,11 +21,14 @@ package org.sonar.batch.scan;
import org.junit.Test;
import org.sonar.api.BatchExtension;
+import org.sonar.api.CoreProperties;
import org.sonar.api.ServerExtension;
import org.sonar.api.batch.InstantiationStrategy;
+import org.sonar.api.config.Settings;
import org.sonar.api.platform.ComponentContainer;
import org.sonar.api.task.TaskExtension;
import org.sonar.batch.bootstrap.ExtensionInstaller;
+import org.sonar.batch.profiling.PhasesSumUpTimeProfiler;
import org.sonar.batch.scan.maven.MavenPluginExecutor;
import static org.fest.assertions.Assertions.assertThat;
@@ -55,6 +58,26 @@ public class ProjectScanContainerTest {
}
@Test
+ public void should_activate_profiling() {
+ ComponentContainer parentContainer = new ComponentContainer();
+ Settings settings = new Settings();
+ parentContainer.add(settings);
+ ProjectScanContainer container = new ProjectScanContainer(parentContainer);
+ container.add(mock(ExtensionInstaller.class));
+ container.doBeforeStart();
+
+ assertThat(container.getComponentsByType(PhasesSumUpTimeProfiler.class)).hasSize(0);
+
+ settings.setProperty(CoreProperties.PROFILING_LOG_PROPERTY, "true");
+
+ container = new ProjectScanContainer(parentContainer);
+ container.add(mock(ExtensionInstaller.class));
+ container.doBeforeStart();
+
+ assertThat(container.getComponentsByType(PhasesSumUpTimeProfiler.class)).hasSize(1);
+ }
+
+ @Test
public void should_add_only_batch_extensions() {
ProjectScanContainer.BatchExtensionFilter filter = new ProjectScanContainer.BatchExtensionFilter();