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,228 +13,102 @@ See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
/**
* @fileoverview Common interfaces for the tensorflow graph visualizer.
*/
module tf {
/**
* 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;
}
/**
* Tracks task progress. Each task being passed a progress tracker needs
* to call the below-defined methods to notify the caller about the gradual
* progress of the task.
*/
export interface ProgressTracker {
updateProgress(incrementValue: number): void;
setMessage(msg: string): 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);
/**
* Tracks task progress. Each task being passed a progress tracker needs
* to call the below-defined methods to notify the caller about the gradual
* progress of the task.
*/
export interface ProgressTracker {
updateProgress(incrementValue: number): void;
setMessage(msg: string): void;
reportError(msg: string, err: Error): void;
}
}
/**
* 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);
});
}
/**
* TensorFlow node definition as defined in the graph proto file.
*/
export interface TFNode {
/** Name of the node */
name: string;
/** List of nodes that are inputs for this node. */
input: string[];
/** The name of the device where the computation will run. */
device: string;
/** The name of the operation associated with this node. */
op: string;
/** List of attributes that describe/modify the operation. */
attr: {key: string, value: Object}[];
}
/**
* 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 stats file definition as defined in the stats proto file.
*/
export interface StepStats {
dev_stats: {device: string, node_stats: NodeStats[]}[];
}
/**
* TensorFlow node definition as defined in the graph proto file.
*/
export interface TFNode {
/** Name of the node */
name: string;
/** List of nodes that are inputs for this node. */
input: string[];
/** The name of the device where the computation will run. */
device: string;
/** The name of the operation associated with this node. */
op: string;
/** List of attributes that describe/modify the operation. */
attr: {key: string, value: Object}[];
}
/**
* TensorFlow stats file definition as defined in the stats proto file.
*/
export interface StepStats {
dev_stats: {device: string, node_stats: NodeStats[]}[];
}
/**
* TensorFlow stats for a node as defined in the stats proto file.
*/
export interface NodeStats {
node_name: string;
// The next 4 properties are currently stored as string in json
// and must be parsed.
all_start_micros: number;
op_start_rel_micros: number;
op_end_rel_micros: number;
all_end_rel_micros: number;
memory: {
allocator_name: string;
total_bytes: number; // Stored as string in json and should be parsed.
peak_bytes: number; // Stored as string in json and should be parsed.
}[];
/** Output sizes recorded for a single execution of a graph node */
output: TFNodeOutput[];
timeline_label: string;
scheduled_micros: string;
thread_id: string;
}
/**
* Description for the output tensor(s) of an operation in the graph.
*/
export interface TFNodeOutput {
slot: number; // Stored as string in json and should be parsed.
tensor_description: {
/** Data type of tensor elements */
dtype: string;
/** Shape of the tensor */
shape: {
/**
* Dimensions of the tensor, such as [{name: 'input', size: 30},
* {name: 'output', size: 40}] for a 30 x 40 2D tensor. The names
* are optional. The order of entries in 'dim' matters: It indicates
* the layout of the values in the tensor in-memory representation.
*/
dim: {
/** Size of the tensor in that dimension */
size: number, // Stored as string in json and should be parsed.
/** Optional name of the tensor dimension */
name?: string
}[];
};
/** Information about the size and allocator used for the data */
allocation_description: {
// The next 2 properties are stored as string in json and
// should be parsed.
/** Total number of bytes requested */
requested_bytes: number;
/** Total number of bytes allocated, if known */
allocated_bytes?: number;
/** Name of the allocator used */
/**
* TensorFlow stats for a node as defined in the stats proto file.
*/
export interface NodeStats {
node_name: string;
// The next 4 properties are currently stored as string in json
// and must be parsed.
all_start_micros: number;
op_start_rel_micros: number;
op_end_rel_micros: number;
all_end_rel_micros: number;
memory: {
allocator_name: string;
total_bytes: number; // Stored as string in json and should be parsed.
peak_bytes: number; // Stored as string in json and should be parsed.
}[];
/** Output sizes recorded for a single execution of a graph node */
output: TFNodeOutput[];
timeline_label: string;
scheduled_micros: string;
thread_id: string;
}
/**
* Description for the output tensor(s) of an operation in the graph.
*/
export interface TFNodeOutput {
slot: number; // Stored as string in json and should be parsed.
tensor_description: {
/** Data type of tensor elements */
dtype: string;
/** Shape of the tensor */
shape: {
/**
* Dimensions of the tensor, such as [{name: 'input', size: 30},
* {name: 'output', size: 40}] for a 30 x 40 2D tensor. The names
* are optional. The order of entries in 'dim' matters: It indicates
* the layout of the values in the tensor in-memory representation.
*/
dim: {
/** Size of the tensor in that dimension */
size: number, // Stored as string in json and should be parsed.
/** Optional name of the tensor dimension */
name?: string
}[];
};
/** Information about the size and allocator used for the data */
allocation_description: {
// The next 2 properties are stored as string in json and
// should be parsed.
/** Total number of bytes requested */
requested_bytes: number;
/** Total number of bytes allocated, if known */
allocated_bytes?: number;
/** Name of the allocator used */
allocator_name: string;
};
};
};
}
}
} // close module tf

View File

@ -855,100 +855,115 @@ export function build(rawNodes: tf.TFNode[], params: BuildParams,
*/
let nodeNames = new Array<string>(rawNodes.length);
return runAsyncTask('Normalizing names', 30, () => {
let opNodes = new Array<OpNode>(rawNodes.length);
let index = 0;
_.each(rawNodes, rawNode => {
let opNode = new OpNodeImpl(rawNode);
if (isInEmbeddedPred(opNode)) {
embeddingNodeNames.push(opNode.name);
inEmbedding[opNode.name] = opNode;
return;
}
return tf.graph.util
.runAsyncTask(
'Normalizing names', 30,
() => {
let opNodes = new Array<OpNode>(rawNodes.length);
let index = 0;
_.each(rawNodes, rawNode => {
let opNode = new OpNodeImpl(rawNode);
if (isInEmbeddedPred(opNode)) {
embeddingNodeNames.push(opNode.name);
inEmbedding[opNode.name] = opNode;
return;
}
if (isOutEmbeddedPred(opNode)) {
embeddingNodeNames.push(opNode.name);
outEmbedding[opNode.name] = opNode;
_.each(opNode.inputs, input => {
let inputName = input.name;
outEmbeddings[inputName] = outEmbeddings[inputName] || [];
outEmbeddings[inputName].push(opNode);
});
return;
}
// The node is not an embedding, so add it to the names and nodes
// lists.
opNodes[index] = opNode;
nodeNames[index] = opNode.name;
index++;
});
opNodes.splice(index);
nodeNames.splice(index);
return opNodes;
}, tracker).then((opNodes) => {
// Create the graph data structure from the graphlib library.
return runAsyncTask('Building the data structure', 70, () => {
let normalizedNameDict = mapStrictHierarchy(nodeNames,
embeddingNodeNames);
let graph = new SlimGraph;
if (isOutEmbeddedPred(opNode)) {
embeddingNodeNames.push(opNode.name);
outEmbedding[opNode.name] = opNode;
_.each(opNode.inputs, input => {
let inputName = input.name;
outEmbeddings[inputName] = outEmbeddings[inputName] || [];
outEmbeddings[inputName].push(opNode);
});
return;
}
// The node is not an embedding, so add it to the names and nodes
// lists.
opNodes[index] = opNode;
nodeNames[index] = opNode.name;
index++;
});
opNodes.splice(index);
nodeNames.splice(index);
return opNodes;
},
tracker)
.then((opNodes) => {
// Create the graph data structure from the graphlib library.
return tf.graph.util.runAsyncTask(
'Building the data structure', 70, () => {
let normalizedNameDict =
mapStrictHierarchy(nodeNames, embeddingNodeNames);
let graph = new SlimGraph;
// Add the nodes to the graph.
_.each(opNodes, opNode => {
let normalizedName = normalizedNameDict[opNode.name] || opNode.name;
graph.nodes[normalizedName] = opNode;
// Check if the node has out-embeddings. If yes, add them to the
// node.
if (opNode.name in outEmbeddings) {
opNode.outEmbeddings = outEmbeddings[opNode.name];
// Normalize the names of the out-embeddings.
_.each(opNode.outEmbeddings, node => {
node.name = normalizedNameDict[node.name] || node.name;
});
}
// Update the name of the node.
opNode.name = normalizedName;
// Add the nodes to the graph.
_.each(opNodes, opNode => {
let normalizedName =
normalizedNameDict[opNode.name] || opNode.name;
graph.nodes[normalizedName] = opNode;
// Check if the node has out-embeddings. If yes, add them to the
// node.
if (opNode.name in outEmbeddings) {
opNode.outEmbeddings = outEmbeddings[opNode.name];
// Normalize the names of the out-embeddings.
_.each(opNode.outEmbeddings, node => {
node.name = normalizedNameDict[node.name] || node.name;
});
}
// Update the name of the node.
opNode.name = normalizedName;
});
// Visit each node's inputs to add the edges to the graph. If the
// input
// is an in-embedding, then add it to the node's in-embeddings
// instead.
_.each(opNodes, opNode => {
_.each(opNode.inputs, (input, i) => {
let inputName = input.name;
if (inputName in inEmbedding) {
let inEmbedNode = inEmbedding[inputName];
opNode.inEmbeddings.push(inEmbedNode);
// Move the inputs of the in-embedding node into incoming
// edges of
// 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) {
addEdgeToGraph(
graph, normalizedNameDict[embedInput.name] ||
embedInput.name,
opNode, embedInput.isControlDependency, params, i);
}
} else if (inputName in outEmbedding) {
// Move the inputs of the out-embedding node into inputs of
// the main node where the out-embedding points to.
let outEmbedNode = outEmbedding[inputName];
for (let embedInput of outEmbedNode.inputs) {
addEdgeToGraph(
graph, normalizedNameDict[embedInput.name] ||
embedInput.name,
opNode, input.isControlDependency, params, i);
}
} else {
addEdgeToGraph(
graph, normalizedNameDict[inputName] || inputName,
opNode, input.isControlDependency, params, i);
}
});
});
// Normalize the names of in-embeddings.
_.each(inEmbedding, (node, name) => {
node.name = normalizedNameDict[node.name] || node.name;
});
return graph;
}, tracker);
});
// Visit each node's inputs to add the edges to the graph. If the input
// is an in-embedding, then add it to the node's in-embeddings instead.
_.each(opNodes, opNode => {
_.each(opNode.inputs, (input, i) => {
let inputName = input.name;
if (inputName in inEmbedding) {
let inEmbedNode = inEmbedding[inputName];
opNode.inEmbeddings.push(inEmbedNode);
// Move the inputs of the in-embedding node into incoming edges of
// 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) {
addEdgeToGraph(graph,
normalizedNameDict[embedInput.name] || embedInput.name,
opNode, embedInput.isControlDependency, params, i);
}
} else if (inputName in outEmbedding) {
// Move the inputs of the out-embedding node into inputs of
// the main node where the out-embedding points to.
let outEmbedNode = outEmbedding[inputName];
for (let embedInput of outEmbedNode.inputs) {
addEdgeToGraph(graph,
normalizedNameDict[embedInput.name] || embedInput.name,
opNode, input.isControlDependency, params, i);
}
} else {
addEdgeToGraph(graph, normalizedNameDict[inputName] || inputName,
opNode, input.isControlDependency, params, i);
}
});
});
// Normalize the names of in-embeddings.
_.each(inEmbedding, (node, name) => {
node.name = normalizedNameDict[node.name] || node.name;
});
return graph;
}, tracker);
});
};
/**

View File

@ -400,22 +400,23 @@ export function build(graph: tf.graph.SlimGraph, params: HierarchyParams,
tracker: ProgressTracker): Promise<Hierarchy|void> {
let h = new HierarchyImpl();
let seriesNames: { [name: string]: string } = {};
return runAsyncTask(
'Adding nodes', 20,
() => {
// Get all the possible device names.
let deviceNames = {};
_.each(graph.nodes, (node, nodeName) => {
if (node.device != null) {
deviceNames[node.device] = true;
}
});
h.devices = _.keys(deviceNames);
addNodes(h, graph);
},
tracker)
return tf.graph.util
.runAsyncTask(
'Adding nodes', 20,
() => {
// Get all the possible device names.
let deviceNames = {};
_.each(graph.nodes, (node, nodeName) => {
if (node.device != null) {
deviceNames[node.device] = true;
}
});
h.devices = _.keys(deviceNames);
addNodes(h, graph);
},
tracker)
.then(() => {
return runAsyncTask('Detect series', 20, () => {
return tf.graph.util.runAsyncTask('Detect series', 20, () => {
if (params.seriesNodeMinSize > 0) {
groupSeries(
h.root, h, seriesNames, params.seriesNodeMinSize,
@ -424,14 +425,15 @@ export function build(graph: tf.graph.SlimGraph, params: HierarchyParams,
}, tracker);
})
.then(() => {
return runAsyncTask('Adding edges', 30, () => {
return tf.graph.util.runAsyncTask('Adding edges', 30, () => {
addEdges(h, graph, seriesNames);
}, tracker);
})
.then(() => {
return runAsyncTask('Finding similar subgraphs', 30, () => {
h.templates = template.detect(h, params.verifyTemplate);
}, tracker);
return tf.graph.util.runAsyncTask(
'Finding similar subgraphs', 30, () => {
h.templates = template.detect(h, params.verifyTemplate);
}, tracker);
})
.then(() => { return h; });
};

View File

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

View File

@ -544,7 +544,7 @@ export function getFillForNode(templateIndex, colorBy,
return colorParams.UNKNOWN;
}
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 linearGradient = gradientDefs.select('linearGradient#' + escapedId);
// 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/lodash.html">
<script src="lib/colors.js"></script>
<script src="lib/common.js"></script>
<script src="lib/externs.js"></script>
<script src="lib/graph.js"></script>
<script src="lib/parser.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/template.js"></script>
<script src="lib/scene/scene.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/node.js"></script>
<script src="lib/scene/contextmenu.js"></script>
<script src="lib/layout.js"></script>
<script src="lib/colors.js"></script>
<script src="lib/scene/scene.js"></script>
<script src="lib/template.js"></script>
<script src="lib/util.js"></script>

View File

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

View File

@ -569,12 +569,12 @@ Polymer({
/** Main method for building the scene */
_build: function(renderHierarchy) {
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
tf.graph.layout.layoutScene(renderHierarchy.root, 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.addGraphClickListener(this.$.svg, this);
}.bind(this));

View File

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