1 /* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #include "tensorflow/core/profiler/lib/profiler_session.h"
17 
18 #include <memory>
19 
20 #include "absl/memory/memory.h"
21 #include "tensorflow/core/platform/errors.h"
22 #include "tensorflow/core/platform/logging.h"
23 #include "tensorflow/core/platform/mutex.h"
24 #include "tensorflow/core/platform/platform.h"
25 #include "tensorflow/core/platform/status.h"
26 #include "tensorflow/core/platform/types.h"
27 #include "tensorflow/core/profiler/lib/profiler_interface.h"
28 #include "tensorflow/core/profiler/profiler_options.pb.h"
29 #include "tensorflow/core/profiler/protobuf/xplane.pb.h"
30 #include "tensorflow/core/protobuf/config.pb.h"
31 #include "tensorflow/core/protobuf/error_codes.pb.h"
32 
33 #if !defined(IS_MOBILE_PLATFORM)
34 #include "tensorflow/core/profiler/convert/post_process_single_host_xplane.h"
35 #include "tensorflow/core/profiler/lib/profiler_factory.h"
36 #include "tensorflow/core/profiler/lib/profiler_lock.h"
37 #include "tensorflow/core/profiler/utils/time_utils.h"
38 #endif
39 
40 namespace tensorflow {
41 namespace {
42 
GetOptions(const ProfileOptions & opts)43 ProfileOptions GetOptions(const ProfileOptions& opts) {
44   if (opts.version()) return opts;
45   ProfileOptions options = ProfilerSession::DefaultOptions();
46   options.set_include_dataset_ops(opts.include_dataset_ops());
47   return options;
48 }
49 
50 };  // namespace
51 
Create(const ProfileOptions & options)52 /*static*/ std::unique_ptr<ProfilerSession> ProfilerSession::Create(
53     const ProfileOptions& options) {
54   return absl::WrapUnique(new ProfilerSession(GetOptions(options)));
55 }
56 
Status()57 tensorflow::Status ProfilerSession::Status() {
58   mutex_lock l(mutex_);
59   return status_;
60 }
61 
CollectData(profiler::XSpace * space)62 Status ProfilerSession::CollectData(profiler::XSpace* space) {
63   mutex_lock l(mutex_);
64   TF_RETURN_IF_ERROR(status_);
65 #if !defined(IS_MOBILE_PLATFORM)
66   LOG(INFO) << "Profiler session collecting data.";
67   for (auto& profiler : profilers_) {
68     profiler->Stop().IgnoreError();
69   }
70 
71   for (auto& profiler : profilers_) {
72     profiler->CollectData(space).IgnoreError();
73   }
74 
75   if (active_) {
76     // Allow another session to start.
77     profiler::ReleaseProfilerLock();
78     active_ = false;
79   }
80 
81   PostProcessSingleHostXSpace(space, start_time_ns_);
82 #endif
83 
84   return Status::OK();
85 }
86 
CollectData(RunMetadata * run_metadata)87 Status ProfilerSession::CollectData(RunMetadata* run_metadata) {
88   mutex_lock l(mutex_);
89   TF_RETURN_IF_ERROR(status_);
90 #if !defined(IS_MOBILE_PLATFORM)
91   for (auto& profiler : profilers_) {
92     profiler->Stop().IgnoreError();
93   }
94 
95   for (auto& profiler : profilers_) {
96     profiler->CollectData(run_metadata).IgnoreError();
97   }
98 
99   if (active_) {
100     // Allow another session to start.
101     profiler::ReleaseProfilerLock();
102     active_ = false;
103   }
104 #endif
105 
106   return Status::OK();
107 }
108 
ProfilerSession(ProfileOptions options)109 ProfilerSession::ProfilerSession(ProfileOptions options)
110 #if defined(IS_MOBILE_PLATFORM)
111     : active_(false),
112       status_(tensorflow::Status(
113           error::UNIMPLEMENTED,
114           "Profiler is unimplemented for mobile platforms.")),
115 #else
116     : active_(profiler::AcquireProfilerLock()),
117 #endif
118       options_(std::move(options)) {
119 #if !defined(IS_MOBILE_PLATFORM)
120   if (!active_) {
121     status_ = tensorflow::Status(error::UNAVAILABLE,
122                                  "Another profiler session is active.");
123     return;
124   }
125 
126   LOG(INFO) << "Profiler session initializing.";
127   // Sleep until it is time to start profiling.
128   if (options_.start_timestamp_ns() > 0) {
129     int64 sleep_duration_ns =
130         options_.start_timestamp_ns() - profiler::GetCurrentTimeNanos();
131     if (sleep_duration_ns < 0) {
132       LOG(WARNING) << "Profiling is late by " << -sleep_duration_ns
133                    << " nanoseconds and will start immediately.";
134     } else {
135       LOG(INFO) << "Delaying start of profiler session by "
136                 << sleep_duration_ns;
137       profiler::SleepForNanos(sleep_duration_ns);
138     }
139   }
140 
141   LOG(INFO) << "Profiler session started.";
142   start_time_ns_ = profiler::GetCurrentTimeNanos();
143   CreateProfilers(options_, &profilers_);
144   status_ = Status::OK();
145 
146   for (auto& profiler : profilers_) {
147     auto start_status = profiler->Start();
148     if (!start_status.ok()) {
149       LOG(WARNING) << "Encountered error while starting profiler: "
150                    << start_status.ToString();
151     }
152   }
153 #endif
154 }
155 
~ProfilerSession()156 ProfilerSession::~ProfilerSession() {
157 #if !defined(IS_MOBILE_PLATFORM)
158   LOG(INFO) << "Profiler session tear down.";
159   for (auto& profiler : profilers_) {
160     profiler->Stop().IgnoreError();
161   }
162 
163   if (active_) {
164     // Allow another session to start.
165     profiler::ReleaseProfilerLock();
166   }
167 #endif
168 }
169 }  // namespace tensorflow
170