| // Copyright 2015 The Bazel Authors. All rights reserved. | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //    http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 | package com.google.devtools.build.lib.profiler; | 
 |  | 
 | import static com.google.common.truth.Truth.assertThat; | 
 | import static org.junit.Assert.assertEquals; | 
 | import static org.junit.Assert.assertFalse; | 
 | import static org.junit.Assert.assertSame; | 
 |  | 
 | import com.google.devtools.build.lib.profiler.Profiler.ProfiledTaskKinds; | 
 | import com.google.devtools.build.lib.profiler.chart.AggregatingChartCreator; | 
 | import com.google.devtools.build.lib.profiler.chart.Chart; | 
 | import com.google.devtools.build.lib.profiler.chart.ChartBar; | 
 | import com.google.devtools.build.lib.profiler.chart.ChartBarType; | 
 | import com.google.devtools.build.lib.profiler.chart.ChartColumn; | 
 | import com.google.devtools.build.lib.profiler.chart.ChartCreator; | 
 | import com.google.devtools.build.lib.profiler.chart.ChartLine; | 
 | import com.google.devtools.build.lib.profiler.chart.ChartRow; | 
 | import com.google.devtools.build.lib.profiler.chart.ChartVisitor; | 
 | import com.google.devtools.build.lib.profiler.chart.Color; | 
 | import com.google.devtools.build.lib.profiler.chart.DetailedChartCreator; | 
 | import com.google.devtools.build.lib.testutil.FoundationTestCase; | 
 | import com.google.devtools.build.lib.testutil.Scratch; | 
 | import com.google.devtools.build.lib.testutil.Suite; | 
 | import com.google.devtools.build.lib.testutil.TestSpec; | 
 | import com.google.devtools.build.lib.util.BlazeClock; | 
 | import com.google.devtools.build.lib.vfs.Path; | 
 |  | 
 | import org.junit.Test; | 
 | import org.junit.runner.RunWith; | 
 | import org.junit.runners.JUnit4; | 
 |  | 
 | import java.util.List; | 
 |  | 
 | /** | 
 |  * Unit tests for the profiler chart generation. | 
 |  */ | 
 | @TestSpec(size = Suite.MEDIUM_TESTS) | 
 | @RunWith(JUnit4.class) | 
 | public class ProfilerChartTest extends FoundationTestCase { | 
 |   private static final int COMMON_CHART_TYPES = ProfilePhase.values().length; | 
 |   private static final int DETAILED_CHART_TYPES = ProfilerTask.values().length; | 
 |   private static final int AGGREGATED_CHART_TYPES = 4; | 
 |   private static final int AGGREGATED_CHART_NO_VFS_TYPES = 3; | 
 |  | 
 |   @Test | 
 |   public void testChartCreators() throws Exception { | 
 |     Runnable run = new Runnable() { | 
 |       @Override | 
 |       public void run() { | 
 |         Profiler.instance().startTask(ProfilerTask.ACTION, "action"); | 
 |         Profiler.instance().completeTask(ProfilerTask.ACTION); | 
 |       } | 
 |     }; | 
 |     int threads = 4; // there is one extra thread due due the event that finalizes the profiler | 
 |     ProfileInfo info = createProfileInfo(run, threads - 1); | 
 |     ChartCreator aggregatingCreator = new AggregatingChartCreator(info, true); | 
 |     Chart aggregatedChart = aggregatingCreator.create(); | 
 |     assertEquals(threads, aggregatedChart.getRowCount()); | 
 |     assertThat(aggregatedChart.getSortedRows().get(0).getBars()).hasSize(1); | 
 |  | 
 |     ChartCreator detailedCreator = new DetailedChartCreator(info); | 
 |     Chart detailedChart = detailedCreator.create(); | 
 |     assertThat(detailedChart.getSortedTypes()).hasSize(COMMON_CHART_TYPES + DETAILED_CHART_TYPES); | 
 |     assertEquals(threads, detailedChart.getRowCount()); | 
 |     assertThat(detailedChart.getSortedRows().get(0).getBars()).hasSize(1); | 
 |   } | 
 |  | 
 |   @Test | 
 |   public void testAggregatingChartCreator() throws Exception { | 
 |     Runnable run = new Runnable() { | 
 |       @Override | 
 |       public void run() { | 
 |         Profiler profiler = Profiler.instance(); | 
 |         profiler.startTask(ProfilerTask.ACTION, "action"); // Stays | 
 |         task(profiler, ProfilerTask.REMOTE_EXECUTION, "remote execution"); // Removed | 
 |         task(profiler, ProfilerTask.ACTION_CHECK, "check"); // Removed | 
 |         task(profiler, ProfilerTask.ACTION_LOCK, "lock"); // Stays | 
 |         profiler.completeTask(ProfilerTask.ACTION); | 
 |         task(profiler, ProfilerTask.INFO, "info"); // Stays | 
 |         task(profiler, ProfilerTask.VFS_STAT, "stat"); // Stays, if showVFS | 
 |         task(profiler, ProfilerTask.WAIT, "wait"); // Stays | 
 |       } | 
 |     }; | 
 |     ProfileInfo info = createProfileInfo(run, 1); | 
 |  | 
 |     ChartCreator aggregatingCreator = new AggregatingChartCreator(info, true); | 
 |     Chart aggregatedChart = aggregatingCreator.create(); | 
 |     assertThat(aggregatedChart.getSortedTypes()) | 
 |         .hasSize(COMMON_CHART_TYPES + AGGREGATED_CHART_TYPES); | 
 |     assertThat(aggregatedChart.getSortedRows().get(0).getBars()).hasSize(5); | 
 |  | 
 |     ChartCreator aggregatingNoVfsCreator = new AggregatingChartCreator(info, false); | 
 |     Chart aggregatedNoVfsChart = aggregatingNoVfsCreator.create(); | 
 |     assertThat(aggregatedNoVfsChart.getSortedTypes()) | 
 |         .hasSize(COMMON_CHART_TYPES + AGGREGATED_CHART_NO_VFS_TYPES); | 
 |     assertThat(aggregatedNoVfsChart.getSortedRows().get(0).getBars()).hasSize(4); | 
 |  | 
 |     ChartCreator detailedCreator = new DetailedChartCreator(info); | 
 |     Chart detailedChart = detailedCreator.create(); | 
 |     assertThat(detailedChart.getSortedTypes()) | 
 |         .hasSize(COMMON_CHART_TYPES + ProfilerTask.values().length); | 
 |     assertThat(detailedChart.getSortedRows().get(0).getBars()).hasSize(7); | 
 |   } | 
 |  | 
 |   @Test | 
 |   public void testChart() throws Exception { | 
 |     Chart chart = new Chart(); | 
 |  | 
 |     ChartBarType type3 = chart.createType("name3", Color.GREEN); | 
 |     ChartBarType type2 = chart.createType("name2", Color.RED); | 
 |     ChartBarType type1 = chart.createType("name1", Color.BLACK); | 
 |     List<ChartBarType> types = chart.getSortedTypes(); | 
 |     assertThat(types).hasSize(3); | 
 |     assertEquals(type1.getName(), types.get(0).getName()); | 
 |     assertEquals(type1.getColor(), types.get(0).getColor()); | 
 |     assertEquals(type2.getName(), types.get(1).getName()); | 
 |     assertEquals(type2.getColor(), types.get(1).getColor()); | 
 |     assertEquals(type3.getName(), types.get(2).getName()); | 
 |     assertEquals(type3.getColor(), types.get(2).getColor()); | 
 |  | 
 |     assertSame(type3, chart.lookUpType("name3")); | 
 |     assertSame(type2, chart.lookUpType("name2")); | 
 |     assertSame(type1, chart.lookUpType("name1")); | 
 |  | 
 |     assertSame(Chart.UNKNOWN_TYPE, chart.lookUpType("wergl")); | 
 |     types = chart.getSortedTypes(); | 
 |     assertThat(types).hasSize(4); | 
 |  | 
 |     chart.addBar(1, 2, 3, type1, "label1"); | 
 |     chart.addBar(2, 3, 4, type2, "label2"); | 
 |     chart.addBar(2, 4, 5, type3, "label3"); | 
 |     chart.addBar(3, 3, 4, type2, "label4"); | 
 |     chart.addBar(3, 4, 5, type3, "label5"); | 
 |     chart.addBar(3, 5, 6, type3, "label6"); | 
 |  | 
 |     assertEquals(6, chart.getMaxStop()); | 
 |     assertEquals(3, chart.getRowCount()); | 
 |  | 
 |     List<ChartRow> rows = chart.getSortedRows(); | 
 |     assertThat(rows).hasSize(3); | 
 |     assertThat(rows.get(0).getBars()).hasSize(1); | 
 |     assertThat(rows.get(1).getBars()).hasSize(2); | 
 |     assertThat(rows.get(2).getBars()).hasSize(3); | 
 |  | 
 |     ChartBar bar = rows.get(0).getBars().get(0); | 
 |     assertEquals(2, bar.getStart()); | 
 |     assertEquals(3, bar.getStop()); | 
 |     assertSame(type1, bar.getType()); | 
 |     assertEquals("label1", bar.getLabel()); | 
 |   } | 
 |  | 
 |   @Test | 
 |   public void testChartRows() throws Exception { | 
 |     ChartRow row1 = new ChartRow("1", 0); | 
 |     ChartRow row2 = new ChartRow("2", 1); | 
 |     ChartRow row3 = new ChartRow("3", 1); | 
 |  | 
 |     assertEquals("1", row1.getId()); | 
 |     assertEquals(0, row1.getIndex()); | 
 |  | 
 |     assertEquals(-1, row1.compareTo(row2)); | 
 |     assertEquals(1, row2.compareTo(row1)); | 
 |     assertEquals(0, row2.compareTo(row3)); | 
 |  | 
 |     row1.addBar(new ChartBar(row1, 1, 2, new ChartBarType("name1", Color.BLACK), false, "label1")); | 
 |     row1.addBar(new ChartBar(row1, 2, 3, new ChartBarType("name2", Color.RED), false, "label2")); | 
 |  | 
 |     assertThat(row1.getBars()).hasSize(2); | 
 |     assertEquals("label1", row1.getBars().get(0).getLabel()); | 
 |     assertEquals("label2", row1.getBars().get(1).getLabel()); | 
 |   } | 
 |  | 
 |   @Test | 
 |   public void testChartBarTypes() throws Exception { | 
 |     ChartBarType type1 = new ChartBarType("name1", Color.BLACK); | 
 |     ChartBarType type2 = new ChartBarType("name2", Color.RED); | 
 |     ChartBarType type3 = new ChartBarType("name2", Color.GREEN); | 
 |  | 
 |     assertEquals(-1, type1.compareTo(type2)); | 
 |     assertEquals(1, type2.compareTo(type1)); | 
 |     assertEquals(0, type2.compareTo(type3)); | 
 |  | 
 |     assertEquals(type3, type2); | 
 |     assertFalse(type1.equals(type3)); | 
 |     assertFalse(type1.equals(type2)); | 
 |  | 
 |     assertEquals(type3.hashCode(), type2.hashCode()); | 
 |     assertFalse(type1.hashCode() == type2.hashCode()); | 
 |     assertFalse(type1.hashCode() == type3.hashCode()); | 
 |   } | 
 |  | 
 |   @Test | 
 |   public void testChartBar() throws Exception { | 
 |     ChartRow row1 = new ChartRow("1", 0); | 
 |     ChartBarType type = new ChartBarType("name1", Color.BLACK); | 
 |     ChartBar bar1 = new ChartBar(row1, 1, 2, type, false, "label1"); | 
 |     assertEquals(row1, bar1.getRow()); | 
 |     assertEquals(1, bar1.getStart()); | 
 |     assertEquals(2, bar1.getStop()); | 
 |     assertSame(type, bar1.getType()); | 
 |     assertEquals("label1", bar1.getLabel()); | 
 |   } | 
 |  | 
 |   @Test | 
 |   public void testVisitor() throws Exception { | 
 |     Chart chart = new Chart(); | 
 |     ChartBarType type3 = chart.createType("name3", Color.GREEN); | 
 |     ChartBarType type2 = chart.createType("name2", Color.RED); | 
 |     ChartBarType type1 = chart.createType("name1", Color.BLACK); | 
 |     chart.addBar(1, 2, 3, type1, "label1"); | 
 |     chart.addBar(2, 3, 4, type2, "label2"); | 
 |     chart.addBar(2, 4, 5, type3, "label3"); | 
 |     chart.addBar(3, 3, 4, type2, "label4"); | 
 |     chart.addBar(3, 4, 5, type3, "label5"); | 
 |     chart.addBar(3, 5, 6, type3, "label6"); | 
 |  | 
 |     TestingChartVisitor visitor = new TestingChartVisitor(); | 
 |     chart.accept(visitor); | 
 |     assertEquals(1, visitor.beginChartCount); | 
 |     assertEquals(1, visitor.endChartCount); | 
 |     assertEquals(3, visitor.rowCount); | 
 |     assertEquals(6, visitor.barCount); | 
 |     assertEquals(0, visitor.columnCount); | 
 |     assertEquals(0, visitor.lineCount); | 
 |   } | 
 |  | 
 |   private ProfileInfo createProfileInfo(Runnable runnable, int noOfRows) throws Exception { | 
 |     Scratch scratch = new Scratch(); | 
 |     Path cacheDir = scratch.dir("/tmp"); | 
 |     Path cacheFile = cacheDir.getRelative("profile1.dat"); | 
 |     Profiler profiler = Profiler.instance(); | 
 |     profiler.start(ProfiledTaskKinds.ALL, cacheFile.getOutputStream(), "basic test", false, | 
 |         BlazeClock.instance(), BlazeClock.instance().nanoTime()); | 
 |  | 
 |     // Write from multiple threads to generate multiple rows in the chart. | 
 |     for (int i = 0; i < noOfRows; i++) { | 
 |       Thread t = new Thread(runnable); | 
 |       t.start(); | 
 |       t.join(); | 
 |     } | 
 |  | 
 |     profiler.stop(); | 
 |     return ProfileInfo.loadProfile(cacheFile); | 
 |   } | 
 |  | 
 |   private void task(final Profiler profiler, ProfilerTask task, String name) { | 
 |     profiler.startTask(task, name); | 
 |     try { | 
 |       Thread.sleep(100); | 
 |     } catch (InterruptedException e) { | 
 |       // ignore | 
 |     } | 
 |     profiler.completeTask(task); | 
 |   } | 
 |  | 
 |   private static final class TestingChartVisitor implements ChartVisitor { | 
 |     private int rowCount; | 
 |     private int endChartCount; | 
 |     private int barCount; | 
 |     private int beginChartCount; | 
 |     private int columnCount; | 
 |     private int lineCount; | 
 |  | 
 |     @Override | 
 |     public void visit(Chart chart) { | 
 |       beginChartCount++; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public void endVisit(Chart chart) { | 
 |       endChartCount++; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public void visit(ChartRow chartRow) { | 
 |       rowCount++; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public void visit(ChartBar chartBar) { | 
 |       barCount++; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public void visit(ChartColumn chartColumn) { | 
 |       columnCount++; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public void visit(ChartLine chartLine) { | 
 |       lineCount++; | 
 |     } | 
 |   } | 
 | } |