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/tsl/platform/logger.h" |
17 | |
18 | #include "absl/base/call_once.h" |
19 | #include "absl/synchronization/notification.h" |
20 | #include "tensorflow/tsl/platform/env.h" |
21 | #include "tensorflow/tsl/platform/logging.h" |
22 | |
23 | namespace tsl { |
24 | namespace { |
25 | |
26 | class DefaultLogger : public Logger { |
27 | private: |
28 | void DoLogProto(google::protobuf::Any* proto) override {} |
29 | void DoFlush() override {} |
30 | }; |
31 | |
32 | } // namespace |
33 | |
34 | Logger::FactoryFunc Logger::singleton_factory_ = []() -> Logger* { |
35 | return new DefaultLogger(); |
36 | }; |
37 | |
38 | struct LoggerSingletonContainer { |
39 | // Used to kick off the construction of a new thread that will asynchronously |
40 | // construct a Logger. |
41 | absl::once_flag start_initialization_thread_flag; |
42 | |
43 | // The constructed logger, if there is one. |
44 | Logger* logger; |
45 | |
46 | // The initializing thread notifies `logger_initialized` after storing the |
47 | // constructed logger to `logger`. |
48 | absl::Notification logger_initialized; |
49 | |
50 | // The thread used to construct the Logger instance asynchronously. |
51 | std::unique_ptr<Thread> initialization_thread; |
52 | |
53 | // Used to kick off the joining and destruction of `initialization_thread`. |
54 | absl::once_flag delete_initialization_thread_flag; |
55 | }; |
56 | |
57 | LoggerSingletonContainer* GetLoggerSingletonContainer() { |
58 | static LoggerSingletonContainer* container = new LoggerSingletonContainer; |
59 | return container; |
60 | } |
61 | |
62 | struct AsyncSingletonImpl { |
63 | static void InitializationThreadFn() { |
64 | LoggerSingletonContainer* container = GetLoggerSingletonContainer(); |
65 | container->logger = Logger::singleton_factory_(); |
66 | container->logger_initialized.Notify(); |
67 | } |
68 | |
69 | static void StartInitializationThread(LoggerSingletonContainer* container) { |
70 | Thread* thread = |
71 | Env::Default()->StartThread(ThreadOptions{}, "logger-init-thread" , |
72 | AsyncSingletonImpl::InitializationThreadFn); |
73 | container->initialization_thread.reset(thread); |
74 | } |
75 | }; |
76 | |
77 | /*static*/ Logger* Logger::GetSingleton() { |
78 | // Call the async version to kick off the initialization thread if necessary. |
79 | (void)Logger::GetSingletonAsync(); |
80 | |
81 | // And wait for the thread to finish. |
82 | LoggerSingletonContainer* container = GetLoggerSingletonContainer(); |
83 | absl::call_once(container->delete_initialization_thread_flag, |
84 | [container]() { container->initialization_thread.reset(); }); |
85 | |
86 | return container->logger; |
87 | } |
88 | |
89 | /*static*/ Logger* Logger::GetSingletonAsync() { |
90 | LoggerSingletonContainer* container = GetLoggerSingletonContainer(); |
91 | absl::call_once(container->start_initialization_thread_flag, |
92 | AsyncSingletonImpl::StartInitializationThread, container); |
93 | |
94 | if (container->logger_initialized.HasBeenNotified()) { |
95 | // Wait for the initializing thread to finish to reclaim resources. |
96 | absl::call_once( |
97 | container->delete_initialization_thread_flag, |
98 | [container]() { container->initialization_thread.reset(); }); |
99 | return container->logger; |
100 | } else { |
101 | return nullptr; |
102 | } |
103 | } |
104 | } // namespace tsl |
105 | |