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