Tomographer  v5.0
Tomographer C++ Framework Documentation
pymultiproc.h
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) 2016 ETH Zurich, Institute for Theoretical Physics, Philippe Faist
7  * Copyright (c) 2017 Caltech, Institute for Quantum Information and Matter, Philippe Faist
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a copy
10  * of this software and associated documentation files (the "Software"), to deal
11  * in the Software without restriction, including without limitation the rights
12  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  * copies of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27 
28 #ifndef PYMULTIPROC_H
29 #define PYMULTIPROC_H
30 
31 #include <string>
32 
33 #include <tomographerpy/common.h>
34 
35 #include <tomographer/mhrw.h>
36 #include <tomographer/mhrwtasks.h>
37 
38 #include <tomographerpy/pymhrw.h>
39 
40 
41 namespace tpy {
42 
43 
52 struct TOMOGRAPHER_EXPORT WorkerStatusReport
53 {
55  int worker_id;
56 
58  py::float_ fraction_done;
59 
61  py::str msg;
62 
64  py::dict data;
65 };
66 
73 struct TOMOGRAPHER_EXPORT FullStatusReport {
75  : num_completed(-1), num_total_runs(-1), elapsed(0.0),
76  workers(), total_fraction_done(), human_report()
77  {
78  }
79 
81  py::int_ num_completed;
83  py::int_ num_total_runs;
85  py::float_ elapsed;
86 
90  py::list workers; // list of [WorkerStatusReport or None (for idle)]
91 
93  py::float_ total_fraction_done;
94 
96  py::str human_report;
97 };
98 
99 
109 template<typename TaskType>
110 struct TOMOGRAPHER_EXPORT PyStatusReportAddWorkerDataFields
111 {
115  static inline void addDataFields(py::dict & , const typename TaskType::StatusReportType & ) { }
116 };
117 
125 template<typename CData, typename Rng>
126 struct TOMOGRAPHER_EXPORT PyStatusReportAddWorkerDataFields< Tomographer::MHRWTasks::MHRandomWalkTask<CData, Rng> >
127 {
129  static inline void addDataFields(py::dict & d, const TaskStatusReportType & wr) {
130  d["mhrw_params"] = tpy::MHRWParams(
131  pyMHWalkerParamsToDictInvoke(wr.mhrw_params.mhwalker_params),
132  wr.mhrw_params.n_sweep,
133  wr.mhrw_params.n_therm,
134  wr.mhrw_params.n_run);
135  d["acceptance_ratio"] = wr.acceptance_ratio;
136  d["kstep"] = wr.kstep;
137  d["n_total_iters"] = wr.n_total_iters;
138  }
139 };
140 
149 template<typename TaskType, typename IntType = int>
152  )
153 {
155  r.num_completed = report.num_completed;
156  r.num_total_runs = report.num_total_runs;
157  r.elapsed = report.elapsed;
159  r.human_report = report.getHumanReport();
160  r.workers = py::list();
161  for (std::size_t k = 0; k < report.workers_reports.size(); ++k) {
162  if (!report.workers_running[k]) {
163  r.workers.append(py::none());
164  continue;
165  }
166  // and prepare the report object
167  const auto& rr = report.workers_reports[k];
168  tpy::WorkerStatusReport wreport;
169  // generic worker status report fields
170  wreport.worker_id = (int)k;
171  wreport.fraction_done = rr.fraction_done;
172  wreport.msg = rr.msg;
173  // fields specific to MHRWValueHistogramTasks
175  // add this report
176  r.workers.append(wreport);
177  }
178  return r;
179 }
180 
181 
200 template<typename TaskDispatcher>
201 inline void setTasksStatusReportPyCallback(TaskDispatcher & tasks, py::object progress_fn,
202  int progress_interval_ms, bool require_gil_acquisition = false)
203 {
204  typedef typename TaskDispatcher::TaskType TaskType;
205 
206  //
207  // NOTE: always set a progress report handler, even if progress_fn is None. Indeed, we
208  // use this callback to e.g. check for keyboard interrupt signals.
209  //
210 
211  auto fn = [progress_fn](const typename TaskDispatcher::FullStatusReportType & report) {
212 
213  if (PyErr_Occurred() != NULL || PyErr_CheckSignals() == -1) {
214  //fprintf(stderr, "DEBUG:: error set, throwing\n") ;
215  throw py::error_already_set();
216  }
217  // call the python progress callback:
218  if (!progress_fn.is_none()) {
219  auto r = preparePyTaskStatusReport<TaskType>(report);
220  //fprintf(stderr, "DEBUG:: about to call py callback\n") ;
221  progress_fn(py::cast(r));
222  if (PyErr_Occurred() != NULL || PyErr_CheckSignals() == -1) {
223  fprintf(stderr, "DEBUG:: error set, throwing\n") ;
224  throw py::error_already_set();
225  }
226  //fprintf(stderr, "DEBUG:: py callback done\n") ;
227  }
228  };
229 
230  auto fn_with_gil = [fn](const typename TaskDispatcher::FullStatusReportType & report) {
231  py::gil_scoped_acquire gil_acquire;
232  fn(report);
233  };
234 
235  if (require_gil_acquisition) {
236  tasks.setStatusReportHandler(fn_with_gil);
237  } else {
238  tasks.setStatusReportHandler(fn);
239  }
240  tasks.requestPeriodicStatusReport(progress_interval_ms);
241 }
242 
243 
244 } // namespace tpy
245 
246 
247 
248 
249 
250 
251 #endif
IterCountIntType kstep
the current iteration number
Definition: mhrw.h:1101
double acceptance_ratio
the current acceptance ratio of the random walk (see Tomographer::MHRandomWalk::acceptanceRatio() ) ...
Definition: mhrw.h:1116
py::float_ fraction_done
Fraction of the job done for this worker (0.0 to 1.0)
Definition: pymultiproc.h:58
Base namespace for the Tomographer project.
Definition: densellh.h:45
py::int_ num_total_runs
Total number of tasks which have been or will be run.
Definition: pymultiproc.h:83
py::dict data
Additional task-specific data; see also PyStatusReportAddWorkerDataFields.
Definition: pymultiproc.h:64
int worker_id
Unique identifier of the worker.
Definition: pymultiproc.h:55
std::vector< TaskStatusReportType, typename Tools::NeedOwnOperatorNew< TaskStatusReportType >::AllocatorType > workers_reports
List with the raw report submitted from each individual thread.
Definition: multiproc.h:122
std::vector< bool > workers_running
List specifying for each worker (e.g. a spawned thread) whether it is active or not.
Definition: multiproc.h:110
TaskCountIntType num_completed
Number of completed tasks.
Definition: multiproc.h:97
std::string getHumanReport() const
Produce a text-based human-readable short representation of the status report.
Definition: multiproc.h:154
py::float_ elapsed
Elapsed time in seconds since the launching of the tasks.
Definition: pymultiproc.h:85
Multiprocessing tasks interface (see Multiprocessing Task Interfaces) for parallel Metropolis-Hasting...
Complete status report for multiple tasks running in parallel.
Definition: pymultiproc.h:73
IterCountIntType n_total_iters
the total number of iterations required for this random walk
Definition: mhrw.h:1124
Tomographer::MHRWParams< py::object, CountIntType > MHRWParams
The Tomographer::MHRWParams type exposed to Python (the MHWalkerParam can be represented by any Pytho...
Definition: pymhrw.h:44
C++ utility to populate the data field of a WorkerStatusReport for a given TaskType.
Definition: pymultiproc.h:110
py::dict pyMHWalkerParamsToDictInvoke(const MHWalkerParams &p)
Helper for converting any MHWalkerParams into a dictionary, using automatic template parameter deduct...
Definition: pymhrw.h:95
double totalFractionDone() const
The total fraction of the job completed.
Definition: multiproc.h:137
py::int_ num_completed
Number of tasks which have already completed.
Definition: pymultiproc.h:81
tpy::FullStatusReport preparePyTaskStatusReport(const Tomographer::MultiProc::FullStatusReport< typename TaskType::StatusReportType, IntType > &report)
Utility to prepare a Python status report (FullStatusReport) from a task&#39;s status report...
Definition: pymultiproc.h:150
static void addDataFields(py::dict &, const typename TaskType::StatusReportType &)
Add fields to the given dict, from a status report sent in by a TaskType. The default implementation ...
Definition: pymultiproc.h:115
py::float_ total_fraction_done
Total fraction of work done, as a fraction between 0 and 1.
Definition: pymultiproc.h:93
Status Report structure representing the status of a MHRandomWalk.
Definition: mhrw.h:1084
TaskCountIntType num_total_runs
Total number of tasks to perform.
Definition: multiproc.h:100
py::str human_report
Complete, human-readable summary of the current status of everything.
Definition: pymultiproc.h:96
void setTasksStatusReportPyCallback(TaskDispatcher &tasks, py::object progress_fn, int progress_interval_ms, bool require_gil_acquisition=false)
Set up status reporting for a task dispatcher, using a Python callback for status reports...
Definition: pymultiproc.h:201
py::list workers
A Python list of worker status; either a WorkerStatusReport, or py::none() if the worker is idle...
Definition: pymultiproc.h:90
Routines for performing a Metropolis-Hastings random walk.
Report of the status of a single worker.
Definition: pymultiproc.h:52
C++ Classes and Utilities for Python Modules.
Definition: common.h:85
MHRWParamsType mhrw_params
the parameters of the random walk
Definition: mhrw.h:1111
double elapsed
Number of seconds elapsed since launching the tasks.
Definition: multiproc.h:127
py::str msg
Human-readable message summarizing the status of this worker.
Definition: pymultiproc.h:61
A complete status report, abstract version.
Definition: multiproc.h:85