From 1471a387b3e4af4543a1eef6ecff4510eea9ccb7 Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Fri, 29 Aug 2014 15:22:50 +0200 Subject: [PATCH] Add details of persisters in profiling output to ease understanding --- .../batch/phases/PersisterExecutionEvent.java | 50 ++++++++++++++ .../batch/phases/PersistersPhaseEvent.java | 51 ++++++++++++++ .../org/sonar/batch/phases/PhaseExecutor.java | 7 +- .../java/org/sonar/batch/phases/Phases.java | 2 +- .../event/PersisterExecutionHandler.java | 45 +++++++++++++ .../phases/event/PersistersPhaseHandler.java | 50 ++++++++++++++ .../batch/phases/event/package-info.java | 23 +++++++ .../profiling/PhasesSumUpTimeProfiler.java | 33 +++++++++- .../PhasesSumUpTimeProfilerTest.java | 66 +++++++++++++++++++ 9 files changed, 321 insertions(+), 6 deletions(-) create mode 100644 sonar-batch/src/main/java/org/sonar/batch/phases/PersisterExecutionEvent.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/phases/PersistersPhaseEvent.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/phases/event/PersisterExecutionHandler.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/phases/event/PersistersPhaseHandler.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/phases/event/package-info.java diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/PersisterExecutionEvent.java b/sonar-batch/src/main/java/org/sonar/batch/phases/PersisterExecutionEvent.java new file mode 100644 index 00000000000..cb6574591c7 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/PersisterExecutionEvent.java @@ -0,0 +1,50 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.phases; + +import org.sonar.batch.index.ScanPersister; +import org.sonar.batch.phases.event.PersisterExecutionHandler; + +class PersisterExecutionEvent extends AbstractPhaseEvent + implements PersisterExecutionHandler.PersisterExecutionEvent { + + private final ScanPersister persister; + + PersisterExecutionEvent(ScanPersister persister, boolean start) { + super(start); + this.persister = persister; + } + + @Override + public ScanPersister getPersister() { + return persister; + } + + @Override + public void dispatch(PersisterExecutionHandler handler) { + handler.onPersisterExecution(this); + } + + @Override + public Class getType() { + return PersisterExecutionHandler.class; + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/PersistersPhaseEvent.java b/sonar-batch/src/main/java/org/sonar/batch/phases/PersistersPhaseEvent.java new file mode 100644 index 00000000000..c2074effcda --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/PersistersPhaseEvent.java @@ -0,0 +1,51 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.phases; + +import org.sonar.batch.index.ScanPersister; +import org.sonar.batch.phases.event.PersistersPhaseHandler; + +import java.util.List; + +class PersistersPhaseEvent extends AbstractPhaseEvent + implements PersistersPhaseHandler.PersistersPhaseEvent { + + private final List persisters; + + PersistersPhaseEvent(List persisters, boolean start) { + super(start); + this.persisters = persisters; + } + + public List getPersisters() { + return persisters; + } + + @Override + protected void dispatch(PersistersPhaseHandler handler) { + handler.onPersistersPhase(this); + } + + @Override + protected Class getType() { + return PersistersPhaseHandler.class; + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/PhaseExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/phases/PhaseExecutor.java index 5fc37a64dfd..c08312ce36c 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/phases/PhaseExecutor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/PhaseExecutor.java @@ -138,14 +138,15 @@ public final class PhaseExecutor { private void executePersisters() { LOGGER.info("Store results in database"); - String persistersStep = "Persisters"; - eventBus.fireEvent(new BatchStepEvent(persistersStep, true)); + eventBus.fireEvent(new PersistersPhaseEvent(Lists.newArrayList(persisters), true)); for (ScanPersister persister : persisters) { LOGGER.debug("Execute {}", persister.getClass().getName()); + eventBus.fireEvent(new PersisterExecutionEvent(persister, true)); persister.persist(); + eventBus.fireEvent(new PersisterExecutionEvent(persister, false)); } - eventBus.fireEvent(new BatchStepEvent(persistersStep, false)); + eventBus.fireEvent(new PersistersPhaseEvent(Lists.newArrayList(persisters), false)); } private void updateStatusJob() { 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 44b817907af..4ce24c70a6b 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,7 @@ import java.util.Set; public class Phases { public static enum Phase { - MAVEN("Maven"), INIT("Initializers"), SENSOR("Sensors"), DECORATOR("Decorators"), POSTJOB("Post-Jobs"); + MAVEN("Maven"), INIT("Initializers"), SENSOR("Sensors"), DECORATOR("Decorators"), PERSISTER("Persisters"), POSTJOB("Post-Jobs"); private final String label; diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/event/PersisterExecutionHandler.java b/sonar-batch/src/main/java/org/sonar/batch/phases/event/PersisterExecutionHandler.java new file mode 100644 index 00000000000..7df8dae4ade --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/event/PersisterExecutionHandler.java @@ -0,0 +1,45 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.phases.event; + +import org.sonar.api.batch.events.EventHandler; +import org.sonar.batch.index.ScanPersister; + +public interface PersisterExecutionHandler extends EventHandler { + + /** + * This interface is not intended to be implemented by clients. + */ + interface PersisterExecutionEvent { + + ScanPersister getPersister(); + + boolean isStart(); + + boolean isEnd(); + + } + + /** + * Called before and after execution of {@link ScanPersister}. + */ + void onPersisterExecution(PersisterExecutionEvent event); + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/event/PersistersPhaseHandler.java b/sonar-batch/src/main/java/org/sonar/batch/phases/event/PersistersPhaseHandler.java new file mode 100644 index 00000000000..087755bacab --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/event/PersistersPhaseHandler.java @@ -0,0 +1,50 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.phases.event; + +import org.sonar.api.batch.events.EventHandler; +import org.sonar.batch.index.ScanPersister; + +import java.util.List; + +public interface PersistersPhaseHandler extends EventHandler { + + /** + * This interface is not intended to be implemented by clients. + */ + interface PersistersPhaseEvent { + + /** + * @return list of Persisters in the order of execution + */ + List getPersisters(); + + boolean isStart(); + + boolean isEnd(); + + } + + /** + * Called before and after execution of all {@link ScanPersister}s. + */ + void onPersistersPhase(PersistersPhaseEvent event); + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/event/package-info.java b/sonar-batch/src/main/java/org/sonar/batch/phases/event/package-info.java new file mode 100644 index 00000000000..6aefbe5b6bb --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/event/package-info.java @@ -0,0 +1,23 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.batch.phases.event; + +import javax.annotation.ParametersAreNonnullByDefault; 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 index c2eec6f34a5..42d61fb4f64 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/profiling/PhasesSumUpTimeProfiler.java +++ b/sonar-batch/src/main/java/org/sonar/batch/profiling/PhasesSumUpTimeProfiler.java @@ -25,12 +25,23 @@ import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.batch.Decorator; -import org.sonar.api.batch.events.*; +import org.sonar.api.batch.events.DecoratorExecutionHandler; +import org.sonar.api.batch.events.DecoratorsPhaseHandler; +import org.sonar.api.batch.events.InitializerExecutionHandler; +import org.sonar.api.batch.events.InitializersPhaseHandler; +import org.sonar.api.batch.events.MavenPhaseHandler; +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.api.utils.System2; import org.sonar.api.utils.TimeUtils; import org.sonar.batch.events.BatchStepHandler; import org.sonar.batch.phases.Phases; +import org.sonar.batch.phases.event.PersisterExecutionHandler; +import org.sonar.batch.phases.event.PersistersPhaseHandler; import javax.annotation.Nullable; @@ -43,7 +54,8 @@ import static org.sonar.batch.profiling.AbstractTimeProfiling.sortByDescendingTo import static org.sonar.batch.profiling.AbstractTimeProfiling.truncate; public class PhasesSumUpTimeProfiler implements ProjectAnalysisHandler, SensorExecutionHandler, DecoratorExecutionHandler, PostJobExecutionHandler, DecoratorsPhaseHandler, - SensorsPhaseHandler, PostJobsPhaseHandler, MavenPhaseHandler, InitializersPhaseHandler, InitializerExecutionHandler, BatchStepHandler { + SensorsPhaseHandler, PostJobsPhaseHandler, MavenPhaseHandler, InitializersPhaseHandler, InitializerExecutionHandler, BatchStepHandler, PersistersPhaseHandler, + PersisterExecutionHandler { static final Logger LOG = LoggerFactory.getLogger(PhasesSumUpTimeProfiler.class); private static final int TEXT_RIGHT_PAD = 60; @@ -137,6 +149,23 @@ public class PhasesSumUpTimeProfiler implements ProjectAnalysisHandler, SensorEx } } + public void onPersistersPhase(PersistersPhaseEvent event) { + if (event.isStart()) { + currentModuleProfiling.addPhaseProfiling(Phases.Phase.PERSISTER); + } else { + currentModuleProfiling.getProfilingPerPhase(Phases.Phase.PERSISTER).stop(); + } + } + + public void onPersisterExecution(PersisterExecutionEvent event) { + PhaseProfiling profiling = currentModuleProfiling.getProfilingPerPhase(Phases.Phase.PERSISTER); + if (event.isStart()) { + profiling.newItemProfiling(event.getPersister()); + } else { + profiling.getProfilingPerItem(event.getPersister()).stop(); + } + } + public void onDecoratorExecution(DecoratorExecutionEvent event) { PhaseProfiling profiling = currentModuleProfiling.getProfilingPerPhase(Phases.Phase.DECORATOR); if (event.isStart()) { 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 index bb8096f8a83..ad19f8fd1c9 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/profiling/PhasesSumUpTimeProfilerTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/profiling/PhasesSumUpTimeProfilerTest.java @@ -44,7 +44,10 @@ import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.api.utils.System2; import org.sonar.batch.events.BatchStepEvent; +import org.sonar.batch.index.ScanPersister; import org.sonar.batch.phases.Phases.Phase; +import org.sonar.batch.phases.event.PersisterExecutionHandler; +import org.sonar.batch.phases.event.PersistersPhaseHandler; import java.util.Arrays; import java.util.Collections; @@ -77,6 +80,7 @@ public class PhasesSumUpTimeProfilerTest { assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.INIT).getProfilingPerItem(new FakeInitializer()).totalTime()).isEqualTo(7L); assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.SENSOR).getProfilingPerItem(new FakeSensor()).totalTime()).isEqualTo(10L); assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator1()).totalTime()).isEqualTo(20L); + assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.PERSISTER).getProfilingPerItem(new FakeScanPersister()).totalTime()).isEqualTo(40L); assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.POSTJOB).getProfilingPerItem(new FakePostJob()).totalTime()).isEqualTo(30L); assertThat(profiler.currentModuleProfiling.getProfilingPerBatchStep("Free memory").totalTime()).isEqualTo(9L); @@ -98,6 +102,7 @@ public class PhasesSumUpTimeProfilerTest { assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.SENSOR).getProfilingPerItem(new FakeSensor()).totalTime()).isEqualTo(10L); assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator1()).totalTime()).isEqualTo(20L); assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator2()).totalTime()).isEqualTo(10L); + assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.PERSISTER).getProfilingPerItem(new FakeScanPersister()).totalTime()).isEqualTo(40L); assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.POSTJOB).getProfilingPerItem(new FakePostJob()).totalTime()).isEqualTo(30L); assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.MAVEN).totalTime()).isEqualTo(12L); @@ -105,6 +110,7 @@ public class PhasesSumUpTimeProfilerTest { assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.SENSOR).getProfilingPerItem(new FakeSensor()).totalTime()).isEqualTo(30L); assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator1()).totalTime()).isEqualTo(60L); assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator2()).totalTime()).isEqualTo(30L); + assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.PERSISTER).getProfilingPerItem(new FakeScanPersister()).totalTime()).isEqualTo(120L); assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.POSTJOB).getProfilingPerItem(new FakePostJob()).totalTime()).isEqualTo(90L); } @@ -153,6 +159,7 @@ public class PhasesSumUpTimeProfilerTest { initializerPhase(profiler); sensorPhase(profiler); decoratorPhase(profiler); + persistersPhase(profiler); postJobPhase(profiler); batchStep(profiler); // End of moduleA @@ -230,6 +237,19 @@ public class PhasesSumUpTimeProfilerTest { profiler.onSensorsPhase(sensorsEvent(false)); } + private void persistersPhase(PhasesSumUpTimeProfiler profiler) throws InterruptedException { + ScanPersister persister = new FakeScanPersister(); + // Start of persister phase + profiler.onPersistersPhase(persistersEvent(true)); + // Start of a ScanPersister + profiler.onPersisterExecution(persisterEvent(persister, true)); + clock.sleep(40); + // End of a ScanPersister + profiler.onPersisterExecution(persisterEvent(persister, false)); + // End of persister phase + profiler.onPersistersPhase(persistersEvent(false)); + } + private void postJobPhase(PhasesSumUpTimeProfiler profiler) throws InterruptedException { PostJob postJob = new FakePostJob(); // Start of sensor phase @@ -323,6 +343,26 @@ public class PhasesSumUpTimeProfilerTest { }; } + private PersisterExecutionHandler.PersisterExecutionEvent persisterEvent(final ScanPersister persister, final boolean start) { + return new PersisterExecutionHandler.PersisterExecutionEvent() { + + @Override + public boolean isStart() { + return start; + } + + @Override + public boolean isEnd() { + return !start; + } + + @Override + public ScanPersister getPersister() { + return persister; + } + }; + } + private SensorsPhaseEvent sensorsEvent(final boolean start) { return new SensorsPhaseHandler.SensorsPhaseEvent() { @@ -398,6 +438,26 @@ public class PhasesSumUpTimeProfilerTest { }; } + private PersistersPhaseHandler.PersistersPhaseEvent persistersEvent(final boolean start) { + return new PersistersPhaseHandler.PersistersPhaseEvent() { + + @Override + public boolean isStart() { + return start; + } + + @Override + public boolean isEnd() { + return !start; + } + + @Override + public List getPersisters() { + return null; + } + }; + } + private DecoratorsPhaseHandler.DecoratorsPhaseEvent decoratorsEvent(final boolean start) { return new DecoratorsPhaseHandler.DecoratorsPhaseEvent() { @@ -486,4 +546,10 @@ public class PhasesSumUpTimeProfilerTest { public void executeOn(Project project, SensorContext context) { } } + + public class FakeScanPersister implements ScanPersister { + @Override + public void persist() { + } + } } -- 2.39.5