Tomographer  v1.0a
Tomographer C++ Framework Documentation
signal_status_report.h
Go to the documentation of this file.
1 /* This file is part of the Tomographer project, which is distributed under the
2  * terms of the MIT license.
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2015 ETH Zurich, Institute for Theoretical Physics, Philippe Faist
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  */
26 
27 
28 #ifndef SIGNAL_STATUS_REPORT
29 #define SIGNAL_STATUS_REPORT
30 
40 #include <signal.h>
41 
42 #include <cstdio>
43 #include <ctime>
44 
45 #include <chrono>
46 
47 
48 namespace Tomographer
49 {
50 namespace Tools
51 {
52 
56 {
57  SignalHandler() { }
58  virtual ~SignalHandler() { }
59 
60  virtual void handle_signal(int) = 0;
61 };
62 
63 
66 template<typename TaskDispatcher, typename Logger, typename TimerClock = std::chrono::system_clock>
68 {
69  SigHandlerTaskDispatcherStatusReporter(TaskDispatcher * tasks_, Logger & logger_)
70  : tasks(tasks_), logger(logger_), time_start()
71  {
72  tasks->set_status_report_handler(
73  [this](const typename TaskDispatcher::FullStatusReportType& report) {
74  logger.debug("SigHandlerStatusReporter/lambda", "intermediate progress report lambda called");
75  this->intermediate_progress_report(report);
76  });
77  }
78 
79  TaskDispatcher * tasks;
80  Logger & logger;
81 
82  typename TimerClock::time_point time_start;
83 
84  virtual void handle_signal(int /*sig*/)
85  {
86  tasks->request_status_report();
87  }
88 
92  void intermediate_progress_report(const typename TaskDispatcher::FullStatusReportType& report)
93  {
94  std::string elapsed = fmt_duration(TimerClock::now() - time_start);
95  fprintf(stderr,
96  "\n"
97  "=========================== Intermediate Progress Report ============================\n"
98  " (hit Ctrl+C quickly again to interrupt)\n"
99  " Total Completed Runs: %d/%d: %5.2f%%\n"
100  " %s total elapsed\n"
101  "Current Run(s) information (threads working/spawned %d/%d):\n",
102  report.num_completed, report.num_total_runs,
103  (double)report.num_completed/report.num_total_runs*100.0,
104  elapsed.c_str(), report.num_active_working_threads,
105  report.num_threads
106  );
107  // calculate padding needed to align results
108  // typedef typename OMPTaskDispatcher::TaskStatusReportType TaskStatusReportType;
109  // auto elem = std::max_element(report.tasks_reports.begin(), report.tasks_reports.end(),
110  // [](const TaskStatusReportType& a, const TaskStatusReportType& b) -> bool {
111  // return a.msg.size() < b.msg.size();
112  // });
113  // std::size_t maxmsgwid = (*elem).msg.size();
114  for (int k = 0; k < report.num_threads; ++k) {
115  std::string msg = report.tasks_running[k] ? report.tasks_reports[k].msg : std::string("<idle>");
116  // if (msg.size() < maxmsgwid) {
117  // msg.insert(0, maxmsgwid - msg.size(), ' ');
118  // }
119  fprintf(stderr, "=== Thread #%2d: %s\n", k, msg.c_str());
120  }
121  fprintf(stderr,
122  "=====================================================================================\n\n");
123  };
124 
125 };
126 
127 template<typename TaskDispatcher, typename LoggerT>
128 SigHandlerTaskDispatcherStatusReporter<TaskDispatcher, LoggerT>
129 makeSigHandlerTaskDispatcherStatusReporter(TaskDispatcher * tasks, LoggerT & logger)
130 {
131  // yes, RVO better kick in
132  return SigHandlerTaskDispatcherStatusReporter<TaskDispatcher, LoggerT>(tasks, logger);
133 }
134 
135 
136 
137 
138 #ifndef SIG_STATUS_REPORT_REPEAT_EXIT_DELAY
139 #define SIG_STATUS_REPORT_REPEAT_EXIT_DELAY 2
140 #endif
141 
142 namespace tomo_internal {
143  static std::time_t last_sig_hit_time = 0;
144  static SignalHandler * signal_handler = NULL;
145 
146  void signal_dispatch_fn(int signal)
147  {
148  std::fprintf(stderr, "\n*** interrupt\n");
149  std::time_t now;
150  time(&now);
151  if ( (now - tomo_internal::last_sig_hit_time) < SIG_STATUS_REPORT_REPEAT_EXIT_DELAY ) {
152  // two interrupts within two seconds --> exit
153  std::fprintf(stderr, "\n*** Exit\n");
154  ::exit(1);
155  return;
156  }
157  tomo_internal::last_sig_hit_time = now;
158 
159  if (signal_handler != NULL) {
160  signal_handler->handle_signal(signal);
161  } else {
162  fprintf(stderr, "Warning: sig_handle: no signal handler set (got signal %d)\n", signal);
163  }
164  }
165 }
166 
167 
177 template<typename SigHandler>
178 void installSignalStatusReportHandler(int signum, SigHandler * sobj)
179 {
180  tomo_internal::signal_handler = sobj;
181  signal(signum, tomo_internal::signal_dispatch_fn);
182 }
183 
184 
185 } // namespace Tools
186 } // namespace Tomographer
187 
188 
189 #endif
Base namespace for the Tomographer project.
Definition: dmmhrw.h:51
STL class.
void intermediate_progress_report(const typename TaskDispatcher::FullStatusReportType &report)
Format a nice intermediate progress report.
An abstract signal handler, in class form.
void installSignalStatusReportHandler(int signum, SigHandler *sobj)
Installs the given signal handler to catch the signal signum.
A generic handler which requests a status report from an OMPTaskDispatcher.
T c_str(T...args)
std::string fmt_duration(double seconds)
Format a number of seconds into a human-readable string.
Definition: fmt.h:170
T fprintf(T...args)