# 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. # ============================================================================== """TensorFlow 2.0 Profiler for both Eager Mode and Graph Mode. The profiler has two mode: - Programmatic Mode: start(), stop() and Profiler class. It will perform when calling start() or create Profiler class and will stop when calling stop() or destroying Profiler class. - On-demand Mode: start_profiler_server(). It will perform profiling when receive profiling request. NOTE: Only one active profiler session is allowed. Use of simultaneous Programmatic Mode and On-demand Mode is undefined and will likely fail. NOTE: The Keras TensorBoard callback will automatically perform sampled profiling. Before enabling customized profiling, set the callback flag "profile_batches=[]" to disable automatic sampled profiling. customized profiling. """ import datetime import os import threading from tensorflow.python.client import _pywrap_events_writer from tensorflow.python.eager import context from tensorflow.python.framework import errors from tensorflow.python.platform import gfile from tensorflow.python.platform import tf_logging as logging from tensorflow.python.profiler.internal import _pywrap_profiler from tensorflow.python.util import compat from tensorflow.python.util.deprecation import deprecated _profiler = None _profiler_lock = threading.Lock() _run_num = 0 # This suffix should be kept in sync with kProfileEmptySuffix in # tensorflow/core/profiler/rpc/client/capture_profile.cc. _EVENT_FILE_SUFFIX = '.profile-empty' class ProfilerAlreadyRunningError(Exception): pass class ProfilerNotRunningError(Exception): pass @deprecated('2020-07-01', 'use `tf.profiler.experimental.start` instead.') def start(options=None): """Start profiling. Args: options: profiler options. Raises: ProfilerAlreadyRunningError: If another profiling session is running. """ global _profiler with _profiler_lock: if _profiler is not None: raise ProfilerAlreadyRunningError('Another profiler is running.') if context.default_execution_mode == context.EAGER_MODE: context.ensure_initialized() _profiler = _pywrap_profiler.ProfilerSession() try: _profiler.start('', options if options is not None else {}) except errors.AlreadyExistsError: logging.warning('Another profiler session is running which is probably ' 'created by profiler server. Please avoid using profiler ' 'server and profiler APIs at the same time.') raise ProfilerAlreadyRunningError('Another profiler is running.') @deprecated('2020-07-01', 'use `tf.profiler.experimental.stop` instead.') def stop(): """Stop current profiling session and return its result. Returns: A binary string of tensorflow.tpu.Trace. User can write the string to file for offline analysis by tensorboard. Raises: ProfilerNotRunningError: If there is no active profiling session. """ global _profiler global _run_num with _profiler_lock: if _profiler is None: raise ProfilerNotRunningError( 'Cannot stop profiling. No profiler is running.') if context.default_execution_mode == context.EAGER_MODE: context.context().executor.wait() result = _profiler.stop() _profiler = None _run_num += 1 return result @deprecated( '2020-07-01', '`tf.python.eager.profiler` has deprecated, use `tf.profiler` instead.' ) def maybe_create_event_file(logdir): """Create an empty event file if not already exists. This event file indicates that we have a plugins/profile/ directory in the current logdir. Args: logdir: log directory. """ for file_name in gfile.ListDirectory(logdir): if file_name.endswith(_EVENT_FILE_SUFFIX): return # TODO(b/127330388): Use summary_ops_v2.create_file_writer instead. event_writer = _pywrap_events_writer.EventsWriter( compat.as_bytes(os.path.join(logdir, 'events'))) event_writer.InitWithSuffix(compat.as_bytes(_EVENT_FILE_SUFFIX)) @deprecated( '2020-07-01', '`tf.python.eager.profiler` has deprecated, use `tf.profiler` instead.' ) def save(logdir, result): """Save profile result to TensorBoard logdir. Args: logdir: log directory read by TensorBoard. result: profiling result returned by stop(). """ plugin_dir = os.path.join( logdir, 'plugins', 'profile', datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')) gfile.MakeDirs(plugin_dir) maybe_create_event_file(logdir) with gfile.Open(os.path.join(plugin_dir, 'local.trace'), 'wb') as f: f.write(result) @deprecated('2020-07-01', 'use `tf.profiler.experimental.server.start`.') def start_profiler_server(port): """Start a profiler grpc server that listens to given port. The profiler server will keep the program running even the training finishes. Please shutdown the server with CTRL-C. It can be used in both eager mode and graph mode. The service defined in tensorflow/core/profiler/profiler_service.proto. Please use tensorflow/contrib/tpu/profiler/capture_tpu_profile to capture tracable file following https://cloud.google.com/tpu/docs/cloud-tpu-tools#capture_trace Args: port: port profiler server listens to. """ if context.default_execution_mode == context.EAGER_MODE: context.ensure_initialized() _pywrap_profiler.start_server(port) @deprecated('2020-07-01', 'use `tf.profiler.experimental.Profile` instead.') class Profiler(object): """Context-manager eager profiler api. Example usage: ```python with Profiler("/path/to/logdir"): # do some work ``` """ def __init__(self, logdir): self._logdir = logdir def __enter__(self): start() def __exit__(self, typ, value, tb): result = stop() save(self._logdir, result)