Move tensorflow graph visualizer utility functions to a util.ts file under a tf.graph.util namespace.

Change: 121883015
This commit is contained in:
A. Unique TensorFlower 2016-05-09 14:17:48 -08:00 committed by TensorFlower Gardener
parent 6e02bf0299
commit d4f83e1c64
10 changed files with 418 additions and 362 deletions

View File

@ -13,152 +13,26 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
==============================================================================*/ ==============================================================================*/
module tf {
/** /**
* Recommended delay (ms) when running an expensive task asynchronously * @fileoverview Common interfaces for the tensorflow graph visualizer.
* that gives enough time for the progress bar to update its UI.
*/ */
const ASYNC_TASK_DELAY = 20;
export function time<T>(msg: string, task: () => T) { module tf {
let start = Date.now(); /**
let result = task();
/* tslint:disable */
console.log(msg, ':', Date.now() - start, 'ms');
/* tslint:enable */
return result;
}
/**
* Tracks task progress. Each task being passed a progress tracker needs * Tracks task progress. Each task being passed a progress tracker needs
* to call the below-defined methods to notify the caller about the gradual * to call the below-defined methods to notify the caller about the gradual
* progress of the task. * progress of the task.
*/ */
export interface ProgressTracker { export interface ProgressTracker {
updateProgress(incrementValue: number): void; updateProgress(incrementValue: number): void;
setMessage(msg: string): void; setMessage(msg: string): void;
reportError(msg: string, err: Error): void; reportError(msg: string, err: Error): void;
}
/**
* Creates a tracker that sets the progress property of the
* provided polymer component. The provided component must have
* a property called 'progress' that is not read-only. The progress
* property is an object with a numerical 'value' property and a
* string 'msg' property.
*/
export function getTracker(polymerComponent: any) {
return {
setMessage: function(msg) {
polymerComponent.set(
'progress', {value: polymerComponent.progress.value, msg: msg});
},
updateProgress: function(value) {
polymerComponent.set('progress', {
value: polymerComponent.progress.value + value,
msg: polymerComponent.progress.msg
});
},
reportError: function(msg: string, err) {
// Log the stack trace in the console.
console.error(err.stack);
// And send a user-friendly message to the UI.
polymerComponent.set(
'progress',
{value: polymerComponent.progress.value, msg: msg, error: true});
},
};
}
/**
* Creates a tracker for a subtask given the parent tracker, the total progress
* of the subtask and the subtask message. The parent task should pass a
* subtracker to its subtasks. The subtask reports its own progress which
* becames relative to the main task.
*/
export function getSubtaskTracker(parentTracker: ProgressTracker,
impactOnTotalProgress: number, subtaskMsg: string): ProgressTracker {
return {
setMessage: function(progressMsg) {
// The parent should show a concatenation of its message along with
// its subtask tracker message.
parentTracker.setMessage(subtaskMsg + ': ' + progressMsg);
},
updateProgress: function(incrementValue) {
// Update the parent progress relative to the child progress.
// For example, if the sub-task progresses by 30%, and the impact on the
// total progress is 50%, then the task progresses by 30% * 50% = 15%.
parentTracker
.updateProgress(incrementValue * impactOnTotalProgress / 100);
},
reportError: function(msg: string, err: Error) {
// The parent should show a concatenation of its message along with
// its subtask error message.
parentTracker.reportError(subtaskMsg + ': ' + msg, err);
} }
};
}
/** /**
* Runs an expensive task and return the result.
*/
export function runTask<T>(msg: string, incProgressValue: number,
task: () => T, tracker: ProgressTracker): T {
// Update the progress message to say the current running task.
tracker.setMessage(msg);
// Run the expensive task with a delay that gives enough time for the
// UI to update.
try {
var result = tf.time(msg, task);
// Update the progress value.
tracker.updateProgress(incProgressValue);
// Return the result to be used by other tasks.
return result;
} catch (e) {
// Errors that happen inside asynchronous tasks are
// reported to the tracker using a user-friendly message.
tracker.reportError('Failed ' + msg, e);
}
}
/**
* Runs an expensive task asynchronously and returns a promise of the result.
*/
export function runAsyncTask<T>(msg: string, incProgressValue: number,
task: () => T, tracker: ProgressTracker): Promise<T> {
return new Promise((resolve, reject) => {
// Update the progress message to say the current running task.
tracker.setMessage(msg);
// Run the expensive task with a delay that gives enough time for the
// UI to update.
setTimeout(function() {
try {
var result = tf.time(msg, task);
// Update the progress value.
tracker.updateProgress(incProgressValue);
// Return the result to be used by other tasks.
resolve(result);
} catch (e) {
// Errors that happen inside asynchronous tasks are
// reported to the tracker using a user-friendly message.
tracker.reportError('Failed ' + msg, e);
}
}, ASYNC_TASK_DELAY);
});
}
/**
* Returns a query selector with escaped special characters that are not
* allowed in a query selector.
*/
export function escapeQuerySelector(querySelector: string): string {
return querySelector.replace(/([:.\[\],/\\\(\)])/g, '\\$1');
}
/**
* TensorFlow node definition as defined in the graph proto file. * TensorFlow node definition as defined in the graph proto file.
*/ */
export interface TFNode { export interface TFNode {
/** Name of the node */ /** Name of the node */
name: string; name: string;
/** List of nodes that are inputs for this node. */ /** List of nodes that are inputs for this node. */
@ -169,19 +43,19 @@ export interface TFNode {
op: string; op: string;
/** List of attributes that describe/modify the operation. */ /** List of attributes that describe/modify the operation. */
attr: {key: string, value: Object}[]; attr: {key: string, value: Object}[];
} }
/** /**
* TensorFlow stats file definition as defined in the stats proto file. * TensorFlow stats file definition as defined in the stats proto file.
*/ */
export interface StepStats { export interface StepStats {
dev_stats: {device: string, node_stats: NodeStats[]}[]; dev_stats: {device: string, node_stats: NodeStats[]}[];
} }
/** /**
* TensorFlow stats for a node as defined in the stats proto file. * TensorFlow stats for a node as defined in the stats proto file.
*/ */
export interface NodeStats { export interface NodeStats {
node_name: string; node_name: string;
// The next 4 properties are currently stored as string in json // The next 4 properties are currently stored as string in json
// and must be parsed. // and must be parsed.
@ -199,12 +73,12 @@ export interface NodeStats {
timeline_label: string; timeline_label: string;
scheduled_micros: string; scheduled_micros: string;
thread_id: string; thread_id: string;
} }
/** /**
* Description for the output tensor(s) of an operation in the graph. * Description for the output tensor(s) of an operation in the graph.
*/ */
export interface TFNodeOutput { export interface TFNodeOutput {
slot: number; // Stored as string in json and should be parsed. slot: number; // Stored as string in json and should be parsed.
tensor_description: { tensor_description: {
/** Data type of tensor elements */ /** Data type of tensor elements */
@ -236,5 +110,5 @@ export interface TFNodeOutput {
allocator_name: string; allocator_name: string;
}; };
}; };
} }
} // close module tf } // close module tf

View File

@ -855,7 +855,10 @@ export function build(rawNodes: tf.TFNode[], params: BuildParams,
*/ */
let nodeNames = new Array<string>(rawNodes.length); let nodeNames = new Array<string>(rawNodes.length);
return runAsyncTask('Normalizing names', 30, () => { return tf.graph.util
.runAsyncTask(
'Normalizing names', 30,
() => {
let opNodes = new Array<OpNode>(rawNodes.length); let opNodes = new Array<OpNode>(rawNodes.length);
let index = 0; let index = 0;
_.each(rawNodes, rawNode => { _.each(rawNodes, rawNode => {
@ -885,16 +888,20 @@ export function build(rawNodes: tf.TFNode[], params: BuildParams,
opNodes.splice(index); opNodes.splice(index);
nodeNames.splice(index); nodeNames.splice(index);
return opNodes; return opNodes;
}, tracker).then((opNodes) => { },
tracker)
.then((opNodes) => {
// Create the graph data structure from the graphlib library. // Create the graph data structure from the graphlib library.
return runAsyncTask('Building the data structure', 70, () => { return tf.graph.util.runAsyncTask(
let normalizedNameDict = mapStrictHierarchy(nodeNames, 'Building the data structure', 70, () => {
embeddingNodeNames); let normalizedNameDict =
mapStrictHierarchy(nodeNames, embeddingNodeNames);
let graph = new SlimGraph; let graph = new SlimGraph;
// Add the nodes to the graph. // Add the nodes to the graph.
_.each(opNodes, opNode => { _.each(opNodes, opNode => {
let normalizedName = normalizedNameDict[opNode.name] || opNode.name; let normalizedName =
normalizedNameDict[opNode.name] || opNode.name;
graph.nodes[normalizedName] = opNode; graph.nodes[normalizedName] = opNode;
// Check if the node has out-embeddings. If yes, add them to the // Check if the node has out-embeddings. If yes, add them to the
// node. // node.
@ -909,20 +916,26 @@ export function build(rawNodes: tf.TFNode[], params: BuildParams,
opNode.name = normalizedName; opNode.name = normalizedName;
}); });
// Visit each node's inputs to add the edges to the graph. If the input // Visit each node's inputs to add the edges to the graph. If the
// is an in-embedding, then add it to the node's in-embeddings instead. // input
// is an in-embedding, then add it to the node's in-embeddings
// instead.
_.each(opNodes, opNode => { _.each(opNodes, opNode => {
_.each(opNode.inputs, (input, i) => { _.each(opNode.inputs, (input, i) => {
let inputName = input.name; let inputName = input.name;
if (inputName in inEmbedding) { if (inputName in inEmbedding) {
let inEmbedNode = inEmbedding[inputName]; let inEmbedNode = inEmbedding[inputName];
opNode.inEmbeddings.push(inEmbedNode); opNode.inEmbeddings.push(inEmbedNode);
// Move the inputs of the in-embedding node into incoming edges of // Move the inputs of the in-embedding node into incoming
// the main node. E.g. the control dependency of a constant node // edges of
// should be moved to the op node where the constant is embedded. // the main node. E.g. the control dependency of a constant
// node
// should be moved to the op node where the constant is
// embedded.
for (let embedInput of inEmbedNode.inputs) { for (let embedInput of inEmbedNode.inputs) {
addEdgeToGraph(graph, addEdgeToGraph(
normalizedNameDict[embedInput.name] || embedInput.name, graph, normalizedNameDict[embedInput.name] ||
embedInput.name,
opNode, embedInput.isControlDependency, params, i); opNode, embedInput.isControlDependency, params, i);
} }
} else if (inputName in outEmbedding) { } else if (inputName in outEmbedding) {
@ -930,12 +943,14 @@ export function build(rawNodes: tf.TFNode[], params: BuildParams,
// the main node where the out-embedding points to. // the main node where the out-embedding points to.
let outEmbedNode = outEmbedding[inputName]; let outEmbedNode = outEmbedding[inputName];
for (let embedInput of outEmbedNode.inputs) { for (let embedInput of outEmbedNode.inputs) {
addEdgeToGraph(graph, addEdgeToGraph(
normalizedNameDict[embedInput.name] || embedInput.name, graph, normalizedNameDict[embedInput.name] ||
embedInput.name,
opNode, input.isControlDependency, params, i); opNode, input.isControlDependency, params, i);
} }
} else { } else {
addEdgeToGraph(graph, normalizedNameDict[inputName] || inputName, addEdgeToGraph(
graph, normalizedNameDict[inputName] || inputName,
opNode, input.isControlDependency, params, i); opNode, input.isControlDependency, params, i);
} }
}); });

View File

@ -400,7 +400,8 @@ export function build(graph: tf.graph.SlimGraph, params: HierarchyParams,
tracker: ProgressTracker): Promise<Hierarchy|void> { tracker: ProgressTracker): Promise<Hierarchy|void> {
let h = new HierarchyImpl(); let h = new HierarchyImpl();
let seriesNames: { [name: string]: string } = {}; let seriesNames: { [name: string]: string } = {};
return runAsyncTask( return tf.graph.util
.runAsyncTask(
'Adding nodes', 20, 'Adding nodes', 20,
() => { () => {
// Get all the possible device names. // Get all the possible device names.
@ -415,7 +416,7 @@ export function build(graph: tf.graph.SlimGraph, params: HierarchyParams,
}, },
tracker) tracker)
.then(() => { .then(() => {
return runAsyncTask('Detect series', 20, () => { return tf.graph.util.runAsyncTask('Detect series', 20, () => {
if (params.seriesNodeMinSize > 0) { if (params.seriesNodeMinSize > 0) {
groupSeries( groupSeries(
h.root, h, seriesNames, params.seriesNodeMinSize, h.root, h, seriesNames, params.seriesNodeMinSize,
@ -424,12 +425,13 @@ export function build(graph: tf.graph.SlimGraph, params: HierarchyParams,
}, tracker); }, tracker);
}) })
.then(() => { .then(() => {
return runAsyncTask('Adding edges', 30, () => { return tf.graph.util.runAsyncTask('Adding edges', 30, () => {
addEdges(h, graph, seriesNames); addEdges(h, graph, seriesNames);
}, tracker); }, tracker);
}) })
.then(() => { .then(() => {
return runAsyncTask('Finding similar subgraphs', 30, () => { return tf.graph.util.runAsyncTask(
'Finding similar subgraphs', 30, () => {
h.templates = template.detect(h, params.verifyTemplate); h.templates = template.detect(h, params.verifyTemplate);
}, tracker); }, tracker);
}) })

View File

@ -53,13 +53,18 @@ export function fetchPbTxt(filepath: string): Promise<string> {
* Fetches the metadata file, parses it and returns a promise of the result. * Fetches the metadata file, parses it and returns a promise of the result.
*/ */
export function fetchAndParseMetadata(path: string, tracker: ProgressTracker) { export function fetchAndParseMetadata(path: string, tracker: ProgressTracker) {
return runTask('Reading metadata pbtxt', 40, () => { return tf.graph.util
.runTask(
'Reading metadata pbtxt', 40,
() => {
if (path == null) { if (path == null) {
return Promise.resolve(null); return Promise.resolve(null);
} }
return fetchPbTxt(path).then(text => new Blob([text])); return fetchPbTxt(path).then(text => new Blob([text]));
}, tracker).then((blob: Blob) => { },
return runTask('Parsing metadata.pbtxt', 60, () => { tracker)
.then((blob: Blob) => {
return tf.graph.util.runTask('Parsing metadata.pbtxt', 60, () => {
return blob != null ? parseStatsPbTxt(blob) : null; return blob != null ? parseStatsPbTxt(blob) : null;
}, tracker); }, tracker);
}); });
@ -70,11 +75,16 @@ export function fetchAndParseMetadata(path: string, tracker: ProgressTracker) {
*/ */
export function fetchAndParseGraphData(path: string, pbTxtFile: Blob, export function fetchAndParseGraphData(path: string, pbTxtFile: Blob,
tracker: ProgressTracker) { tracker: ProgressTracker) {
return runTask('Reading graph pbtxt', 40, () => { return tf.graph.util
.runTask(
'Reading graph pbtxt', 40,
() => {
return pbTxtFile ? Promise.resolve(pbTxtFile) : return pbTxtFile ? Promise.resolve(pbTxtFile) :
fetchPbTxt(path).then(text => new Blob([text])); fetchPbTxt(path).then(text => new Blob([text]));
}, tracker).then(blob => { },
return runTask('Parsing graph.pbtxt', 60, () => { tracker)
.then(blob => {
return tf.graph.util.runTask('Parsing graph.pbtxt', 60, () => {
return parseGraphPbTxt(blob); return parseGraphPbTxt(blob);
}, tracker); }, tracker);
}); });

View File

@ -544,7 +544,7 @@ export function getFillForNode(templateIndex, colorBy,
return colorParams.UNKNOWN; return colorParams.UNKNOWN;
} }
let id = renderInfo.node.name; let id = renderInfo.node.name;
let escapedId = tf.escapeQuerySelector(id); let escapedId = tf.graph.util.escapeQuerySelector(id);
let gradientDefs = d3.select('svg#svg defs #linearGradients'); let gradientDefs = d3.select('svg#svg defs #linearGradients');
let linearGradient = gradientDefs.select('linearGradient#' + escapedId); let linearGradient = gradientDefs.select('linearGradient#' + escapedId);
// If the linear gradient is not there yet, create it. // If the linear gradient is not there yet, create it.

View File

@ -0,0 +1,154 @@
/* Copyright 2015 Google Inc. 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.
==============================================================================*/
/**
* @fileoverview Utility functions for the tensorflow graph visualizer.
*/
module tf.graph.util {
/**
* Recommended delay (ms) when running an expensive task asynchronously
* that gives enough time for the progress bar to update its UI.
*/
const ASYNC_TASK_DELAY = 20;
export function time<T>(msg: string, task: () => T) {
let start = Date.now();
let result = task();
/* tslint:disable */
console.log(msg, ':', Date.now() - start, 'ms');
/* tslint:enable */
return result;
}
/**
* Creates a tracker that sets the progress property of the
* provided polymer component. The provided component must have
* a property called 'progress' that is not read-only. The progress
* property is an object with a numerical 'value' property and a
* string 'msg' property.
*/
export function getTracker(polymerComponent: any) {
return {
setMessage: function(msg) {
polymerComponent.set(
'progress', {value: polymerComponent.progress.value, msg: msg});
},
updateProgress: function(value) {
polymerComponent.set('progress', {
value: polymerComponent.progress.value + value,
msg: polymerComponent.progress.msg
});
},
reportError: function(msg: string, err) {
// Log the stack trace in the console.
console.error(err.stack);
// And send a user-friendly message to the UI.
polymerComponent.set(
'progress',
{value: polymerComponent.progress.value, msg: msg, error: true});
},
};
}
/**
* Creates a tracker for a subtask given the parent tracker, the total
* progress
* of the subtask and the subtask message. The parent task should pass a
* subtracker to its subtasks. The subtask reports its own progress which
* becames relative to the main task.
*/
export function getSubtaskTracker(
parentTracker: ProgressTracker, impactOnTotalProgress: number,
subtaskMsg: string): ProgressTracker {
return {
setMessage: function(progressMsg) {
// The parent should show a concatenation of its message along with
// its subtask tracker message.
parentTracker.setMessage(subtaskMsg + ': ' + progressMsg);
},
updateProgress: function(incrementValue) {
// Update the parent progress relative to the child progress.
// For example, if the sub-task progresses by 30%, and the impact on the
// total progress is 50%, then the task progresses by 30% * 50% = 15%.
parentTracker.updateProgress(
incrementValue * impactOnTotalProgress / 100);
},
reportError: function(msg: string, err: Error) {
// The parent should show a concatenation of its message along with
// its subtask error message.
parentTracker.reportError(subtaskMsg + ': ' + msg, err);
}
};
}
/**
* Runs an expensive task and return the result.
*/
export function runTask<T>(
msg: string, incProgressValue: number, task: () => T,
tracker: ProgressTracker): T {
// Update the progress message to say the current running task.
tracker.setMessage(msg);
// Run the expensive task with a delay that gives enough time for the
// UI to update.
try {
let result = tf.graph.util.time(msg, task);
// Update the progress value.
tracker.updateProgress(incProgressValue);
// Return the result to be used by other tasks.
return result;
} catch (e) {
// Errors that happen inside asynchronous tasks are
// reported to the tracker using a user-friendly message.
tracker.reportError('Failed ' + msg, e);
}
}
/**
* Runs an expensive task asynchronously and returns a promise of the result.
*/
export function runAsyncTask<T>(
msg: string, incProgressValue: number, task: () => T,
tracker: ProgressTracker): Promise<T> {
return new Promise((resolve, reject) => {
// Update the progress message to say the current running task.
tracker.setMessage(msg);
// Run the expensive task with a delay that gives enough time for the
// UI to update.
setTimeout(function() {
try {
let result = tf.graph.util.time(msg, task);
// Update the progress value.
tracker.updateProgress(incProgressValue);
// Return the result to be used by other tasks.
resolve(result);
} catch (e) {
// Errors that happen inside asynchronous tasks are
// reported to the tracker using a user-friendly message.
tracker.reportError('Failed ' + msg, e);
}
}, ASYNC_TASK_DELAY);
});
}
/**
* Returns a query selector with escaped special characters that are not
* allowed in a query selector.
*/
export function escapeQuerySelector(querySelector: string): string {
return querySelector.replace(/([:.\[\],/\\\(\)])/g, '\\$1');
}
}

View File

@ -3,17 +3,18 @@
<link rel="import" href="../tf-imports/graphlib.html"> <link rel="import" href="../tf-imports/graphlib.html">
<link rel="import" href="../tf-imports/lodash.html"> <link rel="import" href="../tf-imports/lodash.html">
<script src="lib/colors.js"></script>
<script src="lib/common.js"></script> <script src="lib/common.js"></script>
<script src="lib/externs.js"></script> <script src="lib/externs.js"></script>
<script src="lib/graph.js"></script> <script src="lib/graph.js"></script>
<script src="lib/parser.js"></script>
<script src="lib/hierarchy.js"></script> <script src="lib/hierarchy.js"></script>
<script src="lib/layout.js"></script>
<script src="lib/parser.js"></script>
<script src="lib/render.js"></script> <script src="lib/render.js"></script>
<script src="lib/template.js"></script>
<script src="lib/scene/scene.js"></script>
<script src="lib/scene/annotation.js"></script> <script src="lib/scene/annotation.js"></script>
<script src="lib/scene/contextmenu.js"></script>
<script src="lib/scene/edge.js"></script> <script src="lib/scene/edge.js"></script>
<script src="lib/scene/node.js"></script> <script src="lib/scene/node.js"></script>
<script src="lib/scene/contextmenu.js"></script> <script src="lib/scene/scene.js"></script>
<script src="lib/layout.js"></script> <script src="lib/template.js"></script>
<script src="lib/colors.js"></script> <script src="lib/util.js"></script>

View File

@ -66,7 +66,7 @@ Polymer({
value: 0, value: 0,
msg: '' msg: ''
}); });
var tracker = tf.getTracker(this); var tracker = tf.graph.util.getTracker(this);
tf.graph.parser.fetchAndParseMetadata(path, tracker) tf.graph.parser.fetchAndParseMetadata(path, tracker)
.then(function(stats) { .then(function(stats) {
this._setOutStats(stats); this._setOutStats(stats);
@ -78,7 +78,7 @@ Polymer({
value: 0, value: 0,
msg: '' msg: ''
}); });
var tracker = tf.getTracker(this); var tracker = tf.graph.util.getTracker(this);
var hierarchyParams = { var hierarchyParams = {
verifyTemplate: true, verifyTemplate: true,
// If a set of numbered op nodes has at least this number of nodes // If a set of numbered op nodes has at least this number of nodes
@ -91,7 +91,7 @@ Polymer({
seriesMap: {}, seriesMap: {},
}; };
this._setOutHierarchyParams(hierarchyParams); this._setOutHierarchyParams(hierarchyParams);
var dataTracker = tf.getSubtaskTracker(tracker, 30, 'Data'); var dataTracker = tf.graph.util.getSubtaskTracker(tracker, 30, 'Data');
tf.graph.parser.fetchAndParseGraphData(path, pbTxtFile, dataTracker) tf.graph.parser.fetchAndParseGraphData(path, pbTxtFile, dataTracker)
.then(function(graph) { .then(function(graph) {
// Build the flat graph (consists only of Op nodes). // Build the flat graph (consists only of Op nodes).
@ -119,12 +119,12 @@ Polymer({
outEmbeddingTypes: ['^[a-zA-Z]+Summary$'], outEmbeddingTypes: ['^[a-zA-Z]+Summary$'],
refEdges: refEdges refEdges: refEdges
}; };
var graphTracker = tf.getSubtaskTracker(tracker, 20, 'Graph'); var graphTracker = tf.graph.util.getSubtaskTracker(tracker, 20, 'Graph');
return tf.graph.build(graph, buildParams, graphTracker); return tf.graph.build(graph, buildParams, graphTracker);
}) })
.then(function(graph) { .then(function(graph) {
this._setOutGraph(graph); this._setOutGraph(graph);
var hierarchyTracker = tf.getSubtaskTracker(tracker, 50, var hierarchyTracker = tf.graph.util.getSubtaskTracker(tracker, 50,
'Namespace hierarchy'); 'Namespace hierarchy');
return tf.graph.hierarchy.build(graph, hierarchyParams, hierarchyTracker); return tf.graph.hierarchy.build(graph, hierarchyParams, hierarchyTracker);
}.bind(this)) }.bind(this))

View File

@ -569,12 +569,12 @@ Polymer({
/** Main method for building the scene */ /** Main method for building the scene */
_build: function(renderHierarchy) { _build: function(renderHierarchy) {
this.templateIndex = renderHierarchy.hierarchy.getTemplateIndex(); this.templateIndex = renderHierarchy.hierarchy.getTemplateIndex();
tf.time('tf-graph-scene (layout):', function() { tf.graph.util.time('tf-graph-scene (layout):', function() {
// layout the scene for this meta / series node // layout the scene for this meta / series node
tf.graph.layout.layoutScene(renderHierarchy.root, this); tf.graph.layout.layoutScene(renderHierarchy.root, this);
}.bind(this)); }.bind(this));
tf.time('tf-graph-scene (build scene):', function() { tf.graph.util.time('tf-graph-scene (build scene):', function() {
tf.graph.scene.buildGroup(d3.select(this.$.root), renderHierarchy.root, this); tf.graph.scene.buildGroup(d3.select(this.$.root), renderHierarchy.root, this);
tf.graph.scene.addGraphClickListener(this.$.svg, this); tf.graph.scene.addGraphClickListener(this.$.svg, this);
}.bind(this)); }.bind(this));

View File

@ -113,7 +113,7 @@ Polymer({
} }
}, },
_buildRenderHierarchy: function(graphHierarchy) { _buildRenderHierarchy: function(graphHierarchy) {
tf.time('new tf.graph.render.Hierarchy', function() { tf.graph.util.time('new tf.graph.render.Hierarchy', function() {
if (graphHierarchy.root.type !== tf.graph.NodeType.META) { if (graphHierarchy.root.type !== tf.graph.NodeType.META) {
// root must be metanode but sometimes Polymer's dom-if has not // root must be metanode but sometimes Polymer's dom-if has not
// remove tf-graph element yet in <tf-node-info> // remove tf-graph element yet in <tf-node-info>
@ -265,8 +265,8 @@ Polymer({
value: 0, value: 0,
msg: '' msg: ''
}); });
var tracker = tf.getTracker(this); var tracker = tf.graph.util.getTracker(this);
var hierarchyTracker = tf.getSubtaskTracker(tracker, 100, var hierarchyTracker = tf.graph.util.getSubtaskTracker(tracker, 100,
'Namespace hierarchy'); 'Namespace hierarchy');
tf.graph.hierarchy.build(this.basicGraph, this.hierarchyParams, hierarchyTracker) tf.graph.hierarchy.build(this.basicGraph, this.hierarchyParams, hierarchyTracker)
.then(function(graphHierarchy) { .then(function(graphHierarchy) {