Show a column with the location of a skylark function in HTML profiling statistics.
--
MOS_MIGRATED_REVID=102143715
diff --git a/src/main/java/com/google/devtools/build/lib/profiler/chart/SkylarkStatistics.java b/src/main/java/com/google/devtools/build/lib/profiler/chart/SkylarkStatistics.java
index 054a775..9db8516 100644
--- a/src/main/java/com/google/devtools/build/lib/profiler/chart/SkylarkStatistics.java
+++ b/src/main/java/com/google/devtools/build/lib/profiler/chart/SkylarkStatistics.java
@@ -49,14 +49,6 @@
}
/**
- * @param variable
- * @return An approximation of whether the argument is valid as a JavaScript variable.
- */
- private static boolean isValidJsVariable(String variable) {
- return variable.matches("^[\\w_].*");
- }
-
- /**
* For each Skylark function compute a {@link TasksStatistics} object from the execution times of
* all corresponding {@link Task}s from either {@link #userFunctionTasks} or
* {@link #builtinFunctionTasks}. Fills fields {@link #userFunctionStats} and
@@ -124,10 +116,6 @@
out.println(" document.querySelector('#builtin-close').onclick = function() {");
out.println(" document.querySelector('#builtin-histogram').style.display = 'none';");
out.println(" };");
-
- printDrawTableJs(dataVar, tableVar, "user");
- printDrawTableJs(dataVar, tableVar, "builtin");
-
out.println("};");
out.println("var options = {");
@@ -144,10 +132,12 @@
out.printf(" var selection = %s[category].getSelection();\n", tableVar);
out.println(" if (selection.length < 1) return;");
out.println(" var item = selection[0];");
- out.printf(" var func = %s[category].getValue(item.row, 0);\n", dataVar);
- out.println(" var histData = histogramData[category][func];");
+ out.printf(" var loc = %s[category].getValue(item.row, 0);\n", dataVar);
+ out.printf(" var func = %s[category].getValue(item.row, 1);\n", dataVar);
+ out.println(" var key = loc + '#' + func;");
+ out.println(" var histData = histogramData[category][key];");
out.println(" var fnOptions = JSON.parse(JSON.stringify(options));");
- out.println(" fnOptions.title = func;");
+ out.println(" fnOptions.title = loc + ' - ' + func;");
out.println(" var chartDiv = document.getElementById(category+'-chart');");
out.println(" var chart = new google.visualization.Histogram(chartDiv);");
out.println(" var histogramDiv = document.getElementById(category+'-histogram');");
@@ -158,15 +148,6 @@
out.println("</script>");
}
- private void printDrawTableJs(String dataVar, String tableVar, String category) {
- out.printf(
- " %s.%s.draw(%s.%s, {showRowNumber: true, width: '100%%', height: '100%%'});\n",
- tableVar,
- category,
- dataVar,
- category);
- }
-
private void printHistogramData() {
out.println(" histogramData = {");
printHistogramData(builtinFunctionTasks, "builtin");
@@ -175,12 +156,9 @@
}
private void printHistogramData(ListMultimap<String, Task> tasks, String category) {
- out.printf(" \"%s\": {\n", category);
+ out.printf(" '%s': {\n", category);
for (String function : tasks.keySet()) {
- if (!isValidJsVariable(function)) {
- continue;
- }
- out.printf(" \"%s\": google.visualization.arrayToDataTable(\n", function);
+ out.printf(" '%s': google.visualization.arrayToDataTable(\n", function);
out.print(" [['duration']");
for (Task task : tasks.get(function)) {
out.printf(",[%f]", task.duration / 1000000.);
@@ -197,44 +175,58 @@
String tableVar,
long totalNanos) {
String tmpVar = category + dataVar;
- out.printf(" var %s = new google.visualization.DataTable();\n", tmpVar);
- out.printf(" %s.addColumn('string', 'Function');\n", tmpVar);
- out.printf(" %s.addColumn('number', 'count');\n", tmpVar);
- out.printf(" %s.addColumn('number', 'min (ms)');\n", tmpVar);
- out.printf(" %s.addColumn('number', 'mean (ms)');\n", tmpVar);
- out.printf(" %s.addColumn('number', 'median (ms)');\n", tmpVar);
- out.printf(" %s.addColumn('number', 'max (ms)');\n", tmpVar);
- out.printf(" %s.addColumn('number', 'standard deviation (ms)');\n", tmpVar);
- out.printf(" %s.addColumn('number', 'total (ms)');\n", tmpVar);
- out.printf(" %s.addColumn('number', 'relative total (%%)');\n", tmpVar);
- out.printf(" %s.addRows([\n", tmpVar);
- for (TasksStatistics stats : statsList) {
- if (!isValidJsVariable(stats.name)) {
- continue;
- }
- double relativeTotal = (double) stats.totalNanos / totalNanos;
- out.printf(
- " ['%s', %d, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, {v:%.4f, f:'%.4f %%'}],\n",
- stats.name,
- stats.count,
- stats.minimumMillis(),
- stats.meanMillis(),
- stats.medianMillis(),
- stats.maximumMillis(),
- stats.standardDeviationMillis,
- stats.totalMillis(),
- relativeTotal,
- relativeTotal * 100);
- }
- out.println(" ]);");
- out.printf(" %s.%s = %s;\n", dataVar, category, tmpVar);
out.printf(" var statsDiv = document.getElementById('%s_function_stats');\n", category);
- out.printf(" %s.%s = new google.visualization.Table(statsDiv);\n", tableVar, category);
- out.printf(
- " google.visualization.events.addListener(%s.%s, 'select', selectHandler('%s'));\n",
- tableVar,
- category,
- category);
+ if (statsList.isEmpty()) {
+ out.println(" statsDiv.innerHTML = '<i>No relevant function calls to display. Some minor"
+ + " builtin functions may have been ignored because their names could not be used as"
+ + " variables in JavaScript.</i>'");
+ } else {
+ out.printf(" var %s = new google.visualization.DataTable();\n", tmpVar);
+ out.printf(" %s.addColumn('string', 'Location');\n", tmpVar);
+ out.printf(" %s.addColumn('string', 'Function');\n", tmpVar);
+ out.printf(" %s.addColumn('number', 'count');\n", tmpVar);
+ out.printf(" %s.addColumn('number', 'min (ms)');\n", tmpVar);
+ out.printf(" %s.addColumn('number', 'mean (ms)');\n", tmpVar);
+ out.printf(" %s.addColumn('number', 'median (ms)');\n", tmpVar);
+ out.printf(" %s.addColumn('number', 'max (ms)');\n", tmpVar);
+ out.printf(" %s.addColumn('number', 'standard deviation (ms)');\n", tmpVar);
+ out.printf(" %s.addColumn('number', 'total (ms)');\n", tmpVar);
+ out.printf(" %s.addColumn('number', 'relative total (%%)');\n", tmpVar);
+ out.printf(" %s.addRows([\n", tmpVar);
+ for (TasksStatistics stats : statsList) {
+ double relativeTotal = (double) stats.totalNanos / totalNanos;
+ String[] split = stats.name.split("#");
+ String location = split[0];
+ String name = split[1];
+ out.printf(
+ " ['%s', '%s', %d, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, {v:%.4f, f:'%.4f %%'}],\n",
+ location,
+ name,
+ stats.count,
+ stats.minimumMillis(),
+ stats.meanMillis(),
+ stats.medianMillis(),
+ stats.maximumMillis(),
+ stats.standardDeviationMillis,
+ stats.totalMillis(),
+ relativeTotal,
+ relativeTotal * 100);
+ }
+ out.println(" ]);");
+ out.printf(" %s.%s = %s;\n", dataVar, category, tmpVar);
+ out.printf(" %s.%s = new google.visualization.Table(statsDiv);\n", tableVar, category);
+ out.printf(
+ " google.visualization.events.addListener(%s.%s, 'select', selectHandler('%s'));\n",
+ tableVar,
+ category,
+ category);
+ out.printf(
+ " %s.%s.draw(%s.%s, {showRowNumber: true, width: '100%%', height: '100%%'});\n",
+ tableVar,
+ category,
+ dataVar,
+ category);
+ }
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/BuiltinFunction.java b/src/main/java/com/google/devtools/build/lib/syntax/BuiltinFunction.java
index 9fcf9a4..a7547de 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/BuiltinFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/BuiltinFunction.java
@@ -19,12 +19,14 @@
import com.google.devtools.build.lib.profiler.ProfilerTask;
import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor.HackHackEitherList;
import com.google.devtools.build.lib.syntax.SkylarkType.SkylarkFunctionType;
+
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.NoSuchElementException;
import java.util.concurrent.ExecutionException;
+
import javax.annotation.Nullable;
/**
@@ -187,7 +189,10 @@
} catch (IllegalAccessException e) {
throw badCallException(loc, e, args);
} finally {
- Profiler.instance().logSimpleTask(startTime, ProfilerTask.SKYLARK_BUILTIN_FN, getName());
+ Profiler.instance().logSimpleTask(
+ startTime,
+ ProfilerTask.SKYLARK_BUILTIN_FN,
+ this.getClass().getName() + "#" + getName());
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/UserDefinedFunction.java b/src/main/java/com/google/devtools/build/lib/syntax/UserDefinedFunction.java
index 3e37c00..f50e6ee 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/UserDefinedFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/UserDefinedFunction.java
@@ -14,8 +14,10 @@
package com.google.devtools.build.lib.syntax;
import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.events.Location.LineAndColumn;
import com.google.devtools.build.lib.profiler.Profiler;
import com.google.devtools.build.lib.profiler.ProfilerTask;
+import com.google.devtools.build.lib.vfs.PathFragment;
/**
* The actual function registered in the environment. This function is defined in the
@@ -73,12 +75,39 @@
real.registerStatement(lastStatement);
throw real;
} finally {
- Profiler.instance().logSimpleTask(startTimeProfiler, ProfilerTask.SKYLARK_USER_FN, getName());
+ Profiler.instance().logSimpleTask(
+ startTimeProfiler,
+ ProfilerTask.SKYLARK_USER_FN,
+ getLocationPathAndLine() + "#" + getName());
}
return Runtime.NONE;
}
/**
+ * Returns the location (filename:line) of the BaseFunction's definition.
+ *
+ * <p>If such a location is not defined, this method returns an empty string.
+ */
+ private String getLocationPathAndLine() {
+ if (location == null) {
+ return "";
+ }
+
+ StringBuilder builder = new StringBuilder();
+ PathFragment path = location.getPath();
+ if (path != null) {
+ builder.append(path.getPathString());
+ }
+
+ LineAndColumn position = location.getStartLineAndColumn();
+ if (position != null) {
+ builder.append(":").append(position.getLine());
+ }
+ return builder.toString();
+ }
+
+
+ /**
* Creates a new environment for the execution of this function.
*/
@Override