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 #include <utility>
20
21 #include "absl/memory/memory.h"
22 #include "tensorflow/core/platform/errors.h"
23 #include "tensorflow/core/platform/logging.h"
24 #include "tensorflow/core/platform/mutex.h"
25 #include "tensorflow/core/platform/platform.h"
26 #include "tensorflow/core/platform/status.h"
27 #include "tensorflow/core/platform/types.h"
28 #include "tensorflow/core/profiler/lib/profiler_interface.h"
29 #include "tensorflow/core/profiler/profiler_options.pb.h"
30 #include "tensorflow/core/profiler/protobuf/xplane.pb.h"
31 #include "tensorflow/core/protobuf/config.pb.h"
32 #include "tensorflow/core/protobuf/error_codes.pb.h"
33
34 #if !defined(IS_MOBILE_PLATFORM)
35 #include "tensorflow/core/profiler/convert/post_process_single_host_xplane.h"
36 #include "tensorflow/core/profiler/lib/profiler_factory.h"
37 #include "tensorflow/core/profiler/lib/profiler_lock.h"
38 #include "tensorflow/core/profiler/utils/time_utils.h"
39 #endif
40
41 namespace tensorflow {
42 namespace {
43
GetOptions(const ProfileOptions & opts)44 ProfileOptions GetOptions(const ProfileOptions& opts) {
45 if (opts.version()) return opts;
46 ProfileOptions options = ProfilerSession::DefaultOptions();
47 options.set_include_dataset_ops(opts.include_dataset_ops());
48 return options;
49 }
50
51 }; // namespace
52
Create(const ProfileOptions & options)53 /*static*/ std::unique_ptr<ProfilerSession> ProfilerSession::Create(
54 const ProfileOptions& options) {
55 return absl::WrapUnique(new ProfilerSession(options));
56 }
57
Status()58 tensorflow::Status ProfilerSession::Status() {
59 mutex_lock l(mutex_);
60 return status_;
61 }
62
CollectDataInternal(profiler::XSpace * space)63 Status ProfilerSession::CollectDataInternal(profiler::XSpace* space) {
64 mutex_lock l(mutex_);
65 TF_RETURN_IF_ERROR(status_);
66 #if !defined(IS_MOBILE_PLATFORM)
67 LOG(INFO) << "Profiler session collecting data.";
68 for (auto& profiler : profilers_) {
69 profiler->Stop().IgnoreError();
70 }
71
72 for (auto& profiler : profilers_) {
73 profiler->CollectData(space).IgnoreError();
74 }
75
76 if (active_) {
77 // Allow another session to start.
78 profiler::ReleaseProfilerLock();
79 active_ = false;
80 }
81 #endif
82 return Status::OK();
83 }
84
CollectData(profiler::XSpace * space)85 Status ProfilerSession::CollectData(profiler::XSpace* space) {
86 #if !defined(IS_MOBILE_PLATFORM)
87 TF_RETURN_IF_ERROR(CollectDataInternal(space));
88 PostProcessSingleHostXSpace(space, start_time_ns_);
89 #endif
90 return Status::OK();
91 }
92
ProfilerSession(const ProfileOptions & options)93 ProfilerSession::ProfilerSession(const ProfileOptions& options)
94 #if defined(IS_MOBILE_PLATFORM)
95 : active_(false),
96 status_(tensorflow::Status(
97 error::UNIMPLEMENTED,
98 "Profiler is unimplemented for mobile platforms.")),
99 #else
100 : active_(profiler::AcquireProfilerLock()),
101 #endif
102 options_(GetOptions(options)) {
103 #if !defined(IS_MOBILE_PLATFORM)
104 if (!active_) {
105 status_ = tensorflow::Status(error::ALREADY_EXISTS,
106 "Another profiler session is active.");
107 return;
108 }
109
110 LOG(INFO) << "Profiler session initializing.";
111 // Sleep until it is time to start profiling.
112 if (options_.start_timestamp_ns() > 0) {
113 int64_t sleep_duration_ns =
114 options_.start_timestamp_ns() - profiler::GetCurrentTimeNanos();
115 if (sleep_duration_ns < 0) {
116 LOG(WARNING) << "Profiling is late by " << -sleep_duration_ns
117 << " nanoseconds and will start immediately.";
118 } else {
119 LOG(INFO) << "Delaying start of profiler session by "
120 << sleep_duration_ns;
121 profiler::SleepForNanos(sleep_duration_ns);
122 }
123 }
124
125 LOG(INFO) << "Profiler session started.";
126 start_time_ns_ = profiler::GetCurrentTimeNanos();
127 CreateProfilers(options_, &profilers_);
128 status_ = Status::OK();
129
130 for (auto& profiler : profilers_) {
131 DCHECK(profiler != nullptr);
132 auto start_status = profiler->Start();
133 if (!start_status.ok()) {
134 LOG(WARNING) << "Encountered error while starting profiler: "
135 << start_status.ToString();
136 }
137 }
138 #endif
139 }
140
~ProfilerSession()141 ProfilerSession::~ProfilerSession() {
142 #if !defined(IS_MOBILE_PLATFORM)
143 LOG(INFO) << "Profiler session tear down.";
144 for (auto& profiler : profilers_) {
145 profiler->Stop().IgnoreError();
146 }
147
148 if (active_) {
149 // Allow another session to start.
150 profiler::ReleaseProfilerLock();
151 }
152 #endif
153 }
154
155 } // namespace tensorflow
156