File: interruptable_progress_monitor.hpp

package info (click to toggle)
r-cran-rcppprogress 0.4.2-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 216 kB
  • sloc: cpp: 490; sh: 13; makefile: 2
file content (202 lines) | stat: -rw-r--r-- 4,762 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/*
 * interruptable_progress_monitor.hpp
 *
 * A class that monitors the progress of computations:
 *   - can display a progress bar
 *   - can handle user interrupt (R user level) or programmatic abort
 *   - can be used in OpenMP loops
 *
 * Author: karl.forner@gmail.com
 *
 */
#ifndef _RcppProgress_INTERRUPTABLE_PROGRESS_MONITOR_HPP
#define _RcppProgress_INTERRUPTABLE_PROGRESS_MONITOR_HPP

#include "interrupts.hpp"
#include "progress_bar.hpp"
//#include "fetch_raw_gwas_bar.hpp"

#ifdef _OPENMP
#include <omp.h>
#endif

class InterruptableProgressMonitor {
public: // ====== LIFECYCLE =====

	/**
	 * Main constructor
	 *
	 * @param max the expected number of tasks to perform
	 * @param display_progress whether to display a progress bar in the console
	 * @param pb    the ProgressBar instance to use
	 */
	InterruptableProgressMonitor(
	  unsigned long max,
	  bool display_progress,
	  ProgressBar& pb
  ) : _progress_bar(pb)
{
		reset(max, display_progress);
		if (is_display_on()) {
		  _progress_bar.display();
		}
	}

	~InterruptableProgressMonitor() {
		if (is_display_on() && !is_aborted()) _progress_bar.end_display();
	}

public: // ===== ACCESSORS/SETTERS =====
	void set_display_status(bool on) { _display_progress = on; 	}
	bool is_display_on() const { return _display_progress; }
	unsigned long get_max() const { return _max; }
	bool is_aborted() const { return _abort; }


public: // ===== PBLIC MAIN INTERFACE =====
	/**
	 * increment the current progress.
	 *
	 * Iff called by the master thread, it will also update the display if needed
	 *
	 * @param amount the number of newly performed tasks to report
	 *
	 * @return false iff the computation is aborted
	 */
	bool increment(unsigned long amount=1) {
		if ( is_aborted() )
			return false;
		return is_master() ? update_master(_current + amount) : atomic_increment(amount);
	}

	/**
	 * set the current progress indicator
	 *
	 * Iff called by the master thread, it will also update the display if needed
	 *
	 * @param current the total number of performed tasks so far (by all threads)
	 *
	 * @return false iff the computation is aborted
	 */
	bool update(unsigned long current) {
		if ( is_aborted() )
			return false;
		return is_master() ? update_master(current) : atomic_update(current);
	}

	/**
	 * check that the no interruption has been requested and return the current status
	 *
	 * Iff called by the master thread, it will check for R-user level interruption.
	 *
	 * @return true iff the computation is aborted
	 */
	bool check_abort() {
		if ( is_aborted() )
			return true;

		if ( is_master() )  {
			check_user_interrupt_master();
		}
		return is_aborted();
	}

	/**
	 * request computation abortion
	 */
	void abort() {
#ifdef _OPENMP
#pragma omp critical
#endif
		_abort = true;

	}

	/**
	 * return true iff the thread is the master.
	 * In case of non-OpenMP loop, always return true
	 */
	bool is_master() const {
#ifdef _OPENMP
		return omp_get_thread_num() == 0;
#else
		return true;
#endif
	}

public: // ===== methods for MASTER thread =====

	/**
	 * set the current progress indicator and update the progress bar display if needed.
	 *
	 *
	 * @param current the total number of performed tasks
	 *
	 * @return false iff the computation is aborted
	 */
	bool update_master(unsigned long current) {
		_current = current;
		if (is_display_on()) _progress_bar.update(progress(current));
		return ! is_aborted();
	}

	void check_user_interrupt_master() {
		if ( !is_aborted() && checkInterrupt() ) {
			abort();
		}
	}

public: // ===== methods for non-MASTER threads =====

	bool atomic_increment(unsigned long amount=1) {
#ifdef _OPENMP
#pragma omp atomic
#endif
		_current+=amount;
		return ! is_aborted();
	}

	bool atomic_update(unsigned long current) {
#ifdef _OPENMP
#pragma omp critical
#endif
		_current=current;
		return ! is_aborted();
	}

protected: // ==== other instance methods =====
	// convert current value to [0-1] progress
	double progress(unsigned long current) {
		return double(current) / double(_max);
	}

	/**
	 * reset the monitor.
	 *
	 * Currently not really useful
	 *
	 * @param max the expected number of tasks to perform
	 * @param display_progress whether to display a progress bar in the console
	 *
	 */
	void reset(unsigned long max = 1, bool display_progress = true) {
		_max = max;
		if ( _max <= 0 )
			_max = 1;
		_current = 0;
		_display_progress = display_progress;
		_abort = false;
	}


private: // ===== INSTANCE VARIABLES ====
  ProgressBar& _progress_bar;
	unsigned long _max; 			// the nb of tasks to perform
	unsigned long _current; 		// the current nb of tasks performed

	bool _abort;					// whether the process should abort
	bool _display_progress;			// whether to display the progress bar

};

#endif