Related changes: * Refactored part of cli/profile_analyzer_cli.py to new file lib/profiling.py. * Improve the way in which filtering is done for file path and line number. * Add unit test for the "lp" and "ps" commands under tf.while_loops. * Add op type to the "lp" table. Also add the ability to sort the rows by op type. * Let the length of the all-"-" divider scale automatically with screen with in the curses UI. PiperOrigin-RevId: 156502357
109 lines
3.6 KiB
Python
109 lines
3.6 KiB
Python
# Copyright 2017 The TensorFlow 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.
|
|
# ==============================================================================
|
|
"""Data structures and algorithms for profiling information."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import print_function
|
|
|
|
import os
|
|
|
|
|
|
class ProfileDatum(object):
|
|
"""Profile data point."""
|
|
|
|
def __init__(self,
|
|
device_name,
|
|
node_exec_stats,
|
|
file_path,
|
|
line_number,
|
|
func_name,
|
|
op_type):
|
|
"""Constructor.
|
|
|
|
Args:
|
|
device_name: (string) name of the device.
|
|
node_exec_stats: `NodeExecStats` proto.
|
|
file_path: path to the source file involved in creating the op.
|
|
line_number: line number in the file involved in creating the op.
|
|
func_name: name of the function that the line belongs to.
|
|
op_type: (string) Operation type.
|
|
"""
|
|
self.device_name = device_name
|
|
self.node_exec_stats = node_exec_stats
|
|
self.file_path = file_path
|
|
self.line_number = line_number
|
|
self.func_name = func_name
|
|
if self.file_path:
|
|
self.file_line_func = "%s:%d(%s)" % (
|
|
os.path.basename(self.file_path), self.line_number, self.func_name)
|
|
else:
|
|
self.file_line_func = ""
|
|
self.op_type = op_type
|
|
self.start_time = self.node_exec_stats.all_start_micros
|
|
self.op_time = (self.node_exec_stats.op_end_rel_micros -
|
|
self.node_exec_stats.op_start_rel_micros)
|
|
|
|
@property
|
|
def exec_time(self):
|
|
"""Op execution time plus pre- and post-processing."""
|
|
return self.node_exec_stats.all_end_rel_micros
|
|
|
|
|
|
class AggregateProfile(object):
|
|
"""Profile summary data for aggregating a number of ProfileDatum."""
|
|
|
|
def __init__(self, profile_datum):
|
|
"""Constructor.
|
|
|
|
Args:
|
|
profile_datum: (`ProfileDatum`) an instance of `ProfileDatum` to
|
|
initialize this object with.
|
|
"""
|
|
|
|
self.total_op_time = profile_datum.op_time
|
|
self.total_exec_time = profile_datum.exec_time
|
|
device_and_node = "%s:%s" % (profile_datum.device_name,
|
|
profile_datum.node_exec_stats.node_name)
|
|
self._node_to_exec_count = {device_and_node: 1}
|
|
|
|
def add(self, profile_datum):
|
|
"""Accumulate a new instance of ProfileDatum.
|
|
|
|
Args:
|
|
profile_datum: (`ProfileDatum`) an instance of `ProfileDatum` to
|
|
accumulate to this object.
|
|
"""
|
|
|
|
self.total_op_time += profile_datum.op_time
|
|
self.total_exec_time += profile_datum.exec_time
|
|
device_and_node = "%s:%s" % (profile_datum.device_name,
|
|
profile_datum.node_exec_stats.node_name)
|
|
|
|
device_and_node = "%s:%s" % (profile_datum.device_name,
|
|
profile_datum.node_exec_stats.node_name)
|
|
if device_and_node in self._node_to_exec_count:
|
|
self._node_to_exec_count[device_and_node] += 1
|
|
else:
|
|
self._node_to_exec_count[device_and_node] = 1
|
|
|
|
@property
|
|
def node_count(self):
|
|
return len(self._node_to_exec_count)
|
|
|
|
@property
|
|
def node_exec_count(self):
|
|
return sum(self._node_to_exec_count.values())
|