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
|