A library for working with phylogenetic and population genetic data.
v0.32.0
resource_logger.hpp
Go to the documentation of this file.
1 #ifndef GENESIS_UTILS_CORE_RESOURCE_LOGGER_H_
2 #define GENESIS_UTILS_CORE_RESOURCE_LOGGER_H_
3 
4 /*
5  Genesis - A toolkit for working with phylogenetic data.
6  Copyright (C) 2014-2024 Lucas Czech
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21  Contact:
22  Lucas Czech <lucas.czech@sund.ku.dk>
23  University of Copenhagen, Globe Institute, Section for GeoGenetics
24  Oster Voldgade 5-7, 1350 Copenhagen K, Denmark
25 */
26 
41 
42 #include <atomic>
43 #include <chrono>
44 #include <condition_variable>
45 #include <fstream>
46 #include <functional>
47 #include <iostream>
48 #include <mutex>
49 #include <memory>
50 #include <sstream>
51 #include <thread>
52 #include <vector>
53 
54 namespace genesis {
55 namespace utils {
56 
57 // =================================================================================================
58 // Resource Logger
59 // =================================================================================================
60 
62 {
63 public:
64 
65  using OutputSink = std::function<void(const std::string&)>;
66 
67  // -------------------------------------------------------------------------
68  // Constructors and Rule of Five
69  // -------------------------------------------------------------------------
70 
71  ResourceLogger( std::chrono::duration<int> interval )
72  : interval_(interval)
73  , running_(false)
74  {}
75 
76  ResourceLogger( std::chrono::duration<int> interval, std::string const& log_file )
77  : ResourceLogger( interval )
78  {
79  log_to_file( log_file );
80  start();
81  }
82 
84  {
85  stop();
86  }
87 
88  ResourceLogger( ResourceLogger const& ) = delete;
89  ResourceLogger( ResourceLogger&& ) = delete;
90 
91  ResourceLogger& operator= ( ResourceLogger const& ) = delete;
93 
94  // -------------------------------------------------------------------------
95  // Member Functions
96  // -------------------------------------------------------------------------
97 
98  void start()
99  {
100  // Do nothing if we are already running, as otherwise
101  // another logging thread would be spawned.
102  if( running_ ) {
103  return;
104  }
105  running_ = true;
106  logging_thread_ = std::thread( &ResourceLogger::logging_worker_thread_, this );
107  }
108 
109  void stop()
110  {
111  {
112  std::lock_guard<std::mutex> lock(logging_mutex_);
113  if( !running_ ) {
114  return;
115  }
116  running_ = false;
117  }
118  logging_cv_.notify_all();
119  if( logging_thread_.joinable() ) {
120  logging_thread_.join();
121  }
122  }
123 
124  void set_interval( std::chrono::duration<int> new_interval )
125  {
126  {
127  std::lock_guard<std::mutex> lock(logging_mutex_);
128  interval_ = new_interval;
129  }
130  logging_cv_.notify_all();
131  }
132 
133  void log_to_sink( OutputSink sink, bool write_header = true )
134  {
135  // Write the header, and add it for logging.
136  if( write_header ) {
137  sink( make_header_() );
138  }
139  std::unique_lock<std::mutex> lock( sink_mutex_ );
140  output_sinks_.push_back(sink);
141  }
142 
143  void log_to_file( std::string const& log_file, bool write_header = true )
144  {
145  auto target = std::make_shared<std::ofstream>();
146  file_output_stream( log_file, *target );
147  log_to_sink(
148  [target]( std::string const& message ){
149  (*target) << message << std::endl;
150  },
151  write_header
152  );
153  }
154 
155  void log_to_stdout( bool write_header = false )
156  {
157  log_to_sink(
158  []( std::string const& message ) {
159  std::cout << message << std::endl;
160  },
161  write_header
162  );
163  }
164 
165  void log_to_stderr( bool write_header = false )
166  {
167  log_to_sink(
168  []( std::string const& message ) {
169  std::cerr << message << std::endl;
170  },
171  write_header
172  );
173  }
174 
175  // -------------------------------------------------------------------------
176  // Internal Members
177  // -------------------------------------------------------------------------
178 
179 private:
180 
181  std::string make_header_()
182  {
183  return "date\ttime\tfiles\tmem\tcpu\ttasks";
184  }
185 
186  std::string make_log_message_()
187  {
188  // TODO make this a functional instead, so that users can provide any form of logging they want. rename the class into TimedLogger or something, then, provide a default implementation of this here, so that we still have an easy to use ResourceLogger based on that.
189 
190  std::stringstream ss;
191  ss << current_date() << "\t" << current_time();
192  ss << "\t" << info_process_current_file_count();
194  ss << "\t" << info_process_current_cpu_usage() << "%";
195  if( Options::get().global_thread_pool() ) {
196  ss << "\t" << Options::get().global_thread_pool()->pending_tasks_count();
197  } else {
198  ss << "\t0";
199  }
200  // ss << "\n";
201  return ss.str();
202  }
203 
204  void log_message_to_sinks_()
205  {
206  auto const message = make_log_message_();
207  std::unique_lock<std::mutex> lock( sink_mutex_ );
208  for( auto& sink : output_sinks_ ) {
209  sink( message );
210  }
211  }
212 
213  void logging_worker_thread_()
214  {
215  // Log one intial time, as otherwise the logging thread will first
216  // wait for the time interval to pass before making the first log.
217  log_message_to_sinks_();
218 
219  // Run while the atomic var is active, then exit.
220  while( true ) {
221  // Wait for either the time interval, or check that we are still running.
222  // This avoids blocking at the end of the program, when the thread needs to join,
223  // but is in sleep.
224  std::unique_lock<std::mutex> lock(logging_mutex_);
225  if( logging_cv_.wait_for( lock, interval_, [this] { return !running_; })) {
226  break;
227  }
228 
229  // Now we have waited, so make a log.
230  log_message_to_sinks_();
231  }
232  }
233 
234  // -------------------------------------------------------------------------
235  // Data Members
236  // -------------------------------------------------------------------------
237 
238  std::chrono::duration<int> interval_;
239  std::atomic<bool> running_;
240 
241  std::thread logging_thread_;
242  std::mutex logging_mutex_;
243  std::condition_variable logging_cv_;
244 
245  std::mutex sink_mutex_;
246  std::vector<OutputSink> output_sinks_;
247 
248 };
249 
250 } // namespace utils
251 } // namespace genesis
252 
253 #endif // include guard
genesis::utils::current_date
std::string current_date()
Returns the current date as a string in the format "2014-12-31".
Definition: date_time.cpp:68
date_time.hpp
Provides functions for date and time access.
genesis::utils::ResourceLogger::set_interval
void set_interval(std::chrono::duration< int > new_interval)
Definition: resource_logger.hpp:124
output_stream.hpp
genesis::utils::info_process_current_cpu_usage
double info_process_current_cpu_usage(bool all_cores, bool percent)
Return the CPU usage of the current process.
Definition: info.cpp:1891
genesis::utils::ResourceLogger::ResourceLogger
ResourceLogger(std::chrono::duration< int > interval)
Definition: resource_logger.hpp:71
genesis::utils::Options::global_thread_pool
std::shared_ptr< ThreadPool > global_thread_pool() const
Return a global thread pool to be used for parallel computations.
Definition: options.hpp:268
genesis::utils::ResourceLogger::stop
void stop()
Definition: resource_logger.hpp:109
std.hpp
Provides some valuable additions to STD.
genesis::utils::current_time
std::string current_time()
Returns the current time as a string in the format "13:37:42".
Definition: date_time.cpp:88
genesis::utils::info_process_current_memory_usage
size_t info_process_current_memory_usage()
Return the memory currently used by the current process, in bytes.
Definition: info.cpp:1876
genesis::utils::ResourceLogger::~ResourceLogger
~ResourceLogger()
Definition: resource_logger.hpp:83
string.hpp
Provides some commonly used string utility functions.
genesis::utils::ResourceLogger::ResourceLogger
ResourceLogger(std::chrono::duration< int > interval, std::string const &log_file)
Definition: resource_logger.hpp:76
logging.hpp
Provides easy and fast logging functionality.
genesis::utils::ResourceLogger::operator=
ResourceLogger & operator=(ResourceLogger const &)=delete
genesis::utils::file_output_stream
void file_output_stream(std::string const &file_name, std::ofstream &out_stream, std::ios_base::openmode mode=std::ios_base::out, bool create_dirs=true)
Helper function to obtain an output stream to a file.
Definition: output_stream.hpp:72
info.hpp
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
genesis::utils::ResourceLogger::OutputSink
std::function< void(const std::string &)> OutputSink
Definition: resource_logger.hpp:65
genesis::utils::ResourceLogger::log_to_stdout
void log_to_stdout(bool write_header=false)
Definition: resource_logger.hpp:155
genesis::utils::to_string_byte_format
std::string to_string_byte_format(size_t value)
Produce a human readable formatting of a size in bytes, using the appropriate suffix.
Definition: string.cpp:1047
options.hpp
genesis::utils::info_process_current_file_count
size_t info_process_current_file_count()
Return the number of files (i.e., file descriptors) that the current process (the process calling thi...
Definition: info.cpp:1213
genesis::utils::ResourceLogger::log_to_file
void log_to_file(std::string const &log_file, bool write_header=true)
Definition: resource_logger.hpp:143
genesis::utils::ResourceLogger::log_to_stderr
void log_to_stderr(bool write_header=false)
Definition: resource_logger.hpp:165
genesis::utils::ResourceLogger::start
void start()
Definition: resource_logger.hpp:98
genesis::utils::Options::get
static Options & get()
Returns a single instance of this class.
Definition: options.hpp:68
genesis::utils::ResourceLogger::log_to_sink
void log_to_sink(OutputSink sink, bool write_header=true)
Definition: resource_logger.hpp:133
genesis::utils::ResourceLogger
Definition: resource_logger.hpp:61