MADNESS 0.10.1
thread.h
Go to the documentation of this file.
1/*
2 This file is part of MADNESS.
3
4 Copyright (C) 2007,2010 Oak Ridge National Laboratory
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 For more information please contact:
21
22 Robert J. Harrison
23 Oak Ridge National Laboratory
24 One Bethel Valley Road
25 P.O. Box 2008, MS-6367
26
27 email: harrisonrj@ornl.gov
28 tel: 865-241-3937
29 fax: 865-572-0680
30*/
31
32#ifndef MADNESS_WORLD_THREAD_H__INCLUDED
33#define MADNESS_WORLD_THREAD_H__INCLUDED
34
35/**
36 \file thread.h
37 \brief Implements Dqueue, Thread, ThreadBase and ThreadPool.
38 \ingroup threads
39*/
40
44#include <atomic>
45#include <vector>
46#include <cstddef>
47#include <cstdio>
48#include <pthread.h>
49
50#include <functional>
51#include <type_traits>
52#include <typeinfo>
53#include <new>
54
55//////////// Parsec Related Begin ////////////////////
56#ifdef HAVE_PARSEC
57#include "parsec.h"
58#endif
59//////////// Parsec Related End ////////////////////
60
61#ifdef MADNESS_TASK_PROFILING
62#include <execinfo.h> // for backtrace_symbols
63#ifndef USE_LIBIBERTY
64#include <cxxabi.h> // for abi::__cxa_demangle
65#else
66extern "C" {
67 extern char * cplus_demangle (const char *mangled, int options);
68#define DMGL_NO_OPTS 0 /* For readability... */
69}
70#endif
71#include <sstream> // for std::istringstream
72#include <cstring> // for strchr & strrchr
73#endif // MADNESS_TASK_PROFILING
74
75#ifdef HAVE_INTEL_TBB
76#include <tbb/task_arena.h>
77#ifndef TBB_PREVIEW_GLOBAL_CONTROL
78# define TBB_PREVIEW_GLOBAL_CONTROL 1
79#endif
80# include <tbb/global_control.h>
81#endif
82
83
84#ifndef _SC_NPROCESSORS_CONF
85// Old macs don't have necessary support thru sysconf to determine the
86// no. of processors so must use sysctl
87#include <sys/types.h>
88#include <sys/sysctl.h>
89#endif
90
91namespace madness {
92
93 // Forward decls.
94 class Barrier;
95 class ThreadPool;
96 class WorldTaskQueue;
97 class AtomicInt;
98 void error(const char *msg);
99
100 /// purges tasks from this thread (if any) so that it's safe to make blocking calls from it
101 /// @note this is only needed for the Pthreads backend
102 inline void thread_purge();
103
105 static const size_t maxncpu = 1024;
106 bool print;
107 size_t ncpu = 0;
108 bool do_bind = true;
109 size_t cpus[maxncpu];
110 std::atomic<size_t> nextcpu = 0;
111 static thread_local bool bound;
112
113 public:
114
115 ThreadBinder(bool print = false) : print(print) {
116#ifndef ON_A_MAC
117 ncpu = 0;
118 cpu_set_t mask;
119 sched_getaffinity(0, sizeof(mask), &mask);
120 for (size_t i=0; i<maxncpu; i++) {
121 if (CPU_ISSET(int(i),&mask)) {
123 cpus[ncpu++] = i;
124 }
125 }
126 if (print) {
127 std::cout << "ncpu: " << get_ncpu() << std::endl;
128 for (size_t i=0; i<get_ncpu(); i++) {
129 std::cout << get_cpus()[i] << " " ;
130 }
131 std::cout << std::endl;
132 }
133 nextcpu = ncpu/2;
134#endif
135 if (this->print) { };
136 }
137
138 void set_do_bind(bool value) {do_bind = value;}
139
140 const size_t* get_cpus() const { return cpus; }
141
142 size_t get_ncpu() const { return ncpu; }
143
144 void bind() {
145#ifndef ON_A_MAC
146 if (do_bind && !bound) { // In TBB this is called by each task, so check do_bind first
147 bound = true;
148 cpu_set_t mask;
149 CPU_ZERO(&mask);
150 size_t cpu = cpus[nextcpu++ % ncpu];
151 CPU_SET(cpu, &mask);
152 sched_setaffinity(0, sizeof(mask), &mask);
153 if (print) std::cout << "bound thread to " << cpu << std::endl;
154 }
155#endif
156 }
157 };
158
159 extern ThreadBinder binder;
160
161 /// \addtogroup threads
162 /// @{
163
164 /// Simplified thread wrapper to hide pthread complexity.
165
166 /// If the thread is using any of the object state, you cannot
167 /// delete the object until the thread has terminated.
168 ///
169 /// The cleanest solution is to put the object on the heap and
170 /// have the run method `delete this` at its end.
172 friend class ThreadPool;
173
174 static pthread_key_t thread_key; ///< Thread id key.
175
176 /// \todo Brief description needed.
177
178 /// \todo Descriptions needed.
179 /// \param[in,out] self Description needed.
180 /// \return Description needed.
181 static void* main(void* self);
182
183 int pool_num; ///< Stores index of thread in pool or -1.
184 pthread_t id; ///< \todo Brief description needed.
185
186 /// \todo Brief description needed.
187 static void init_thread_key() {
188 const int rc = pthread_key_create(&thread_key, nullptr);
189 if(rc != 0)
190 MADNESS_EXCEPTION("pthread_key_create failed", rc);
191 }
192
193 /// \todo Brief description needed.
194 static void delete_thread_key() {
195 pthread_key_delete(thread_key);
196 }
197
198 /// Sets the index of this thread within the pool.
199
200 /// \todo Verify documentation.
201 /// \param[in] i The index of this thread.
203 pool_num = i;
204 }
205
206#if defined(HAVE_IBMBGQ) and defined(HPM)
207 static const int hpm_thread_id_all = -10; ///< \todo Brief description needed.
208 static const int hpm_thread_id_main = -2; ///< \todo Brief description needed.
209 static bool main_instrumented; ///< \todo Brief description needed.
210 static bool all_instrumented; ///< \todo Brief description needed.
211 static int hpm_thread_id; ///< \todo Brief description needed.
212#endif
213
214 public:
215
216 /// Default constructor.
217
218 /// Sets up the thread; however, \c start() must be invoked to
219 /// actually begin the thread.
221
222 virtual ~ThreadBase() { }
223
224 /// Function to be executed by the thread.
225
226 /// Override this to do work.
227 virtual void run() = 0;
228
229 /// Start the thread running.
230 void start();
231
232 /// A thread can call this to terminate its execution.
233 static void exit() {
234 pthread_exit(0);
235 }
236
237 /// Get the pthread id of this thread (if running).
238 const pthread_t& get_id() const {
239 return id;
240 }
241
242 /// Get index of this thread in \c ThreadPool.
243
244 /// \return (0,...,nthread-1) or -1 if not in the \c ThreadPool.
246 return pool_num;
247 }
248
249 /// Cancel this thread.
250 int cancel() const {
251 return pthread_cancel(get_id());
252 }
253
254
255 /// Get number of actual hardware processors.
256
257 /// \return The number of hardward processors.
258 static int num_hw_processors();
259
260 /// \todo Brief description needed.
261
262 /// \todo Descriptions needed.
263 /// \return Description needed.
265 return static_cast<ThreadBase*>(pthread_getspecific(thread_key));
266 }
267
268#if defined(HAVE_IBMBGQ) and defined(HPM)
269 /// \todo Brief description needed.
270
271 /// \todo Descriptions needed.
272 /// \param[in] hpm_thread_id Description needed.
273 static void set_hpm_thread_env(int hpm_thread_id);
274#endif
275 }; // class ThreadBase
276
277 /// Simplified thread wrapper to hide pthread complexity.
278 class Thread : public ThreadBase {
279 void* (*f)(void *); ///< The function called for executing this thread. \todo should we replace this by a std::function?
280 void* args; ///< The arguments passed to this thread for execution.
281
282 /// Invokes the function for this thread.
283 void run() {
284 f(args);
285 }
286
287 public:
288 /// Default constructor.
289
290 /// \c start() must be invoked to actually execute the thread.
291 Thread() : f(nullptr), args(nullptr) { }
292
293 /// Create a thread and start it running `f(args)`.
294
295 /// \param[in] f The function to be called.
296 /// \param[in,out] args The arguments to the function.
297 Thread(void* (*f)(void *), void* args=nullptr)
298 : f(f), args(args) {
300 }
301
302 /// Start the thread by running `f(args)`.
303
304 /// \param[in] f The function to be called.
305 /// \param[in,out] args The arguments to the function.
306 void start(void* (*f)(void *), void* args=nullptr) {
307 this->f = f;
308 this->args = args;
310 }
311
312 virtual ~Thread() = default;
313 }; // class Thread
314
315
316 /// Contains attributes of a task.
317
318 /// The current attributes are:
319 /// - \c generator : Setting this hints that a task will produce
320 /// additional tasks and is used by the scheduler to
321 /// increase/throttle parallelism. The default is false.
322 /// - \c stealable : Setting this indicates that a task may be
323 /// migrated to another process for dynamic load balancing. The
324 /// default value is false.
325 /// - \c highpriority : indicates a high priority task. The default
326 /// value is false.
327 /// - \c nthread : indicates number of threads. 0 threads is interpreted
328 /// as 1 thread for backward compatibility and ease of specifying
329 /// defaults. The default value is 0 (==1).
331 unsigned long flags; ///< Byte-string storing the specified attributes.
332
333 public:
334 static const unsigned long NTHREAD = 0xff; ///< Mask for nthread byte.
335 static const unsigned long GENERATOR = 1ul<<8; ///< Mask for generator bit.
336 static const unsigned long STEALABLE = GENERATOR<<1; ///< Mask for stealable bit.
337 static const unsigned long HIGHPRIORITY = GENERATOR<<2; ///< Mask for priority bit.
338
339 /// Sets the attributes to the desired values.
340
341 /// `flags`, if unspecified sets all attributes to their default
342 /// values.
343 /// \param[in] flags The attribute values.
344 explicit TaskAttributes(unsigned long flags = 0)
345 : flags(flags) {}
346
347 /// Copy constructor.
348
349 /// \param[in] attr The attributes to copy.
351 : flags(attr.flags) {}
352
353 virtual ~TaskAttributes() {}
354
355 /// Test if the generator attribute is true.
356
357 /// \return True if this task is a generator, false otherwise.
358 bool is_generator() const {
359 return flags&GENERATOR;
360 }
361
362 /// Test if the stealable attribute is true.
363
364 /// \return True if this task is stealable, false otherwise.
365 bool is_stealable() const {
366 return flags&STEALABLE;
367 }
368
369 /// Test if the high priority attribute is true.
370
371 /// \return True if this task is a high priority, false otherwise.
372 bool is_high_priority() const {
373 return flags&HIGHPRIORITY;
374 }
375
376 /// Sets the generator attribute.
377
378 /// \param[in] generator_hint The new value for the generator attribute.
379 TaskAttributes& set_generator(bool generator_hint) {
380 if (generator_hint)
381 flags |= GENERATOR;
382 else
383 flags &= ~GENERATOR;
384 return *this;
385 }
386
387 /// Sets the stealable attribute.
388
389 /// \param[in] stealable The new value for the stealable attribute.
390 TaskAttributes& set_stealable(bool stealable) {
391 if (stealable) flags |= STEALABLE;
392 else flags &= ~STEALABLE;
393 return *this;
394 }
395
396 /// Sets the high priority attribute.
397
398 /// \param[in] hipri The new value for the high priority attribute.
400 if (hipri)
402 else
403 flags &= ~HIGHPRIORITY;
404 return *this;
405 }
406
407 /// Set the number of threads.
408
409 /// \attention Are you sure this is what you want to call? Only call
410 /// this for a \c TaskAttributes that is \em not a base class of a task
411 /// object.
412 /// \p If you are trying to set the number of threads in an \em existing
413 /// task you should call \c TaskInterface::set_nthread() instead. No
414 /// doubt there is some virtual/protected/something voodoo to prevent
415 /// you from doing harm.
416 ///
417 /// \todo Perhaps investigate a way to make this function only accessible
418 /// from the intended functions (using the so-called voodoo)?
419 ///
420 /// \param[in] nthread The new number of threads.
421 void set_nthread(int nthread) {
422 MADNESS_ASSERT(nthread>=0 && nthread<256);
423 flags = (flags & (~NTHREAD)) | (nthread & NTHREAD);
424 }
425
426 /// Get the number of threads.
427
428 /// \return The number of threads.
429 int get_nthread() const {
430 int n = flags & NTHREAD;
431 if (n == 0)
432 n = 1;
433 return n;
434 }
435
436 /// Serializes the attributes for I/O.
437
438 /// tparam Archive The archive type.
439 /// \param[in,out] ar The archive.
440 template <typename Archive>
441 void serialize(Archive& ar) {
442 ar & flags;
443 }
444
445 /// \todo Brief description needed.
446
447 /// \todo Descriptions needed.
448 /// \return Description needed.
451 }
452
453 /// \todo Brief description needed.
454
455 /// \todo Descriptions needed.
456 /// \return Description needed.
459 }
460
461 /// \todo Brief description needed.
462
463 /// \todo Descriptions needed.
464 /// \return Description needed.
465 static TaskAttributes multi_threaded(int nthread) {
467 t.set_nthread(nthread);
468 return t;
469 }
470 };
471
472 /// Used to pass information about the thread environment to a user's task.
474 const int _nthread; ///< Number of threads collaborating on task.
475 const int _id; ///< ID of this thread (0,...,nthread-1).
476 Barrier* _barrier; ///< Pointer to the shared barrier, `null` if there is only a single thread.
477
478 public:
479 /// Constructor collecting necessary environmental information.
480
481 /// \todo Verify this documentation.
482 /// \param[in] nthread The number of threads collaborating on this task.
483 /// \param[in] id The ID of this thread.
484 /// \param[in] barrier Pointer to the shared barrier.
488
489#if HAVE_INTEL_TBB
490 /// Constructor collecting necessary environmental information.
491
492 /// \todo Verify this documentation.
493 /// \param[in] nthread The number of threads collaborating on this task.
494 /// \param[in] id The ID of this thread.
495 ///
496 /// \todo I cannot get the TaskThreadEnv to work with Barrier.
497 /// Need to figure out why.
499 : _nthread(nthread), _id(id), _barrier(nullptr)
501#endif
502
503 /// Get the number of threads collaborating on this task.
504
505 /// \return The number of threads.
506 int nthread() const {
507 return _nthread;
508 }
509
510 /// Get the ID of this thread.
511
512 /// \return The ID of this thread.
513 int id() const {
514 return _id;
515 }
516
517 /// \todo Brief description needed.
518
519 /// \todo Descriptions needed.
520 /// \return Description needed.
521 bool barrier() const {
522 if (_nthread == 1)
523 return true;
524 else {
526 return _barrier->enter(_id);
527 }
528 }
529 };
530
531
532#ifdef MADNESS_TASK_PROFILING
533
534 namespace profiling {
535
536 /// Task event class.
537
538 /// This class is used to record the task trace information, including
539 /// submit, start, and stop times, as well as identification information.
540 class TaskEvent {
541 private:
542 double times_[3]; ///< Task trace times: { submit, start, stop }.
543 std::pair<void*, unsigned short> id_; ///< Task identification information.
544 unsigned short threads_; ///< Number of threads used by the task.
545
546 /// Print demangled symbol name.
547
548 /// Add the demangled symbol name to \c os. If demangling fails,
549 /// the unmodified symbol name is used instead. If symbol is NULL,
550 /// "UNKNOWN" is used instead. A tab character is added after the
551 /// symbol name.
552 /// \param[in,out] os The output stream.
553 /// \param[in] symbol The symbol to add to the stream.
554 static void print_demangled(std::ostream& os, const char* symbol) {
555 // Get the demagled symbol name
556 if(symbol) {
557 int status = 0;
558#ifndef USE_LIBIBERTY
559 const char* name = abi::__cxa_demangle(symbol, 0, 0, &status);
560#else
561 char* name = cplus_demangle(symbol, DMGL_NO_OPTS);
562#endif
563 // Append the demangled symbol name to the output stream
564 if(status == 0) {
565 os << name << "\t";
566 free((void*)name);
567 } else {
568 os << symbol << "\t";
569 }
570 } else {
571 os << "UNKNOWN\t";
572 }
573 }
574
575 /// Get name of the function pointer.
576
577 /// \return The mangled function name.
578 std::string get_name() const {
579
580 // Get the backtrace symbol for the function address,
581 // which contains the function name.
582 void* const * func_ptr = const_cast<void* const *>(& id_.first);
583 char** bt_sym = backtrace_symbols(func_ptr, 1);
584
585 // Extract the mangled function name from the backtrace
586 // symbol.
587 std::string mangled_name;
588
589#ifdef ON_A_MAC
590 // Format of bt_sym is:
591 // <frame #> <file name> <address> <mangled name> + <function offset>
592 std::istringstream iss(bt_sym[0]);
593 long frame;
594 std::string file, address;
595 iss >> frame >> file >> address >> mangled_name;
596#else // Assume Linux
597 // Format of bt_sym is:
598 // <file>(<mangled name>+<function offset>) [<address>]
599 const char* first = strchr(bt_sym[0],'(');
600 if(first) {
601 ++first;
602 const char* last = strrchr(first,'+');
603 if(last)
604 mangled_name.assign(first, (last - first) - 1);
605 }
606#endif // ON_A_MAC
607
608 // Free the backtrace buffer
609 free(bt_sym);
610
611 return mangled_name;
612 }
613
614 public:
615
616 // Only default constructors are needed.
617
618 /// Record the start time of the task and collect task information.
619
620 /// \param[in,out] id The task identifier (a function pointer or const char*)
621 /// and an integer to differentiate the different types.
622 /// \param[in] threads The number of threads this task uses.
623 /// \param[in] submit_time The time that the task was submitted to the
624 /// task queue.
625 void start(const std::pair<void*, unsigned short>& id,
626 const unsigned short threads, const double submit_time)
627 {
628 id_ = id;
629 threads_ = threads;
630 times_[0] = submit_time;
631 times_[1] = wall_time();
632 }
633
634 /// Record the stop time of the task.
635 void stop() {
636 times_[2] = wall_time();
637 }
638
639 /// Output the task data using a tab-separated list.
640
641 /// Output information includes
642 /// - the ID pointer
643 /// - the function, member function, and object type name
644 /// - the number of threads used by the task
645 /// - the submit time
646 /// - the start time
647 /// - the stop time.
648 ///
649 /// \param[in,out] os The output stream.
650 /// \param[in] te The task event to be output.
651 /// \return The \c os reference.
652 friend std::ostream& operator<<(std::ostream& os, const TaskEvent& te) {
653 // Add address to output stream
654 os << std::hex << std::showbase << te.id_.first <<
655 std::dec << std::noshowbase << "\t";
656
657 // Print the name
658 switch(te.id_.second) {
659 case 1:
660 {
661 const std::string mangled_name = te.get_name();
662
663 // Print the demangled name
664 if(! mangled_name.empty())
665 print_demangled(os, mangled_name.c_str());
666 else
667 os << "UNKNOWN\t";
668 }
669 break;
670 case 2:
671 print_demangled(os, static_cast<const char*>(te.id_.first));
672 break;
673 default:
674 os << "UNKNOWN\t";
675 }
676
677 // Print:
678 // # of threads, submit time, start time, stop time
679 os << te.threads_;
680 const std::streamsize precision = os.precision();
681 os.precision(6);
682 os << std::fixed << "\t" << te.times_[0]
683 << "\t" << te.times_[1] << "\t" << te.times_[2];
684 os.precision(precision);
685 return os;
686 }
687
688 }; // class TaskEvent
689
690 /// Task event list base class.
691
692 /// This base class allows the data to be stored in a linked list.
694 private:
695 TaskEventListBase* next_; ///< The next task event in the list.
696
699
700 public:
701
702 /// Default constructor.
704 : next_(nullptr) { }
705
706 /// Virtual destructor.
707 virtual ~TaskEventListBase() = default;
708
709 /// Get the next event list in the linked list.
710
711 /// \return The next event list.
713 return next_;
714 }
715
716 /// Insert \c list after this list.
717
718 /// \param[in] list The list to be inserted.
720 if(next_)
721 list->next_ = next_;
722 next_ = list;
723 }
724
725 /// Output a task event list to an output stream.
726
727 /// \param[in,out] os The ouptut stream.
728 /// \param[in] tel The task event list to be output.
729 /// \return The modified output stream.
730 friend inline std::ostream& operator<<(std::ostream& os, const TaskEventListBase& tel) {
731 return tel.print_events(os);
732 }
733
734 private:
735
736 /// Print the events.
737 virtual std::ostream& print_events(std::ostream&) const = 0;
738
739 }; // class TaskEventList
740
741 /// A list of task events.
742
743 /// This object is used by the thread pool to record task data.
745 private:
746 unsigned int n_; ///< The number of events recorded.
747 std::unique_ptr<TaskEvent[]> events_; ///< The event array.
748
749 TaskEventList(const TaskEventList&) = delete;
751
752 public:
753
754 /// Default constructor.
755
756 /// \param[in] nmax The maximum number of task events.
757 /// \todo Should nmax be stored? I think it used to be a template
758 /// parameter (N), which is no longer present.
759 TaskEventList(const unsigned int nmax) :
760 TaskEventListBase(), n_(0ul), events_(new TaskEvent[nmax])
761 { }
762
763 /// Virtual destructor.
764 virtual ~TaskEventList() = default;
765
766 /// Get a new event from this list.
767
768 /// \warning This function can only be called \c nmax times. It is
769 /// the caller's resonsibility to ensure that it is not called too
770 /// many times.
771 /// \return The new event from the list.
773 return events_.get() + (n_++);
774 }
775
776 private:
777
778 /// Print events recorded in this list.
779
780 /// \param[in,out] os The output stream.
781 /// \return The modified output stream.
782 virtual std::ostream& print_events(std::ostream& os) const {
783 const int thread_id = ThreadBase::this_thread()->get_pool_thread_index();
784 for(std::size_t i = 0; i < n_; ++i)
785 os << thread_id << "\t" << events_[i] << std::endl;
786 return os;
787 }
788
789 }; // class TaskEventList
790
791 /// This class collects and prints task profiling data.
792
793 /// \note Each thread has its own \c TaskProfiler object, so only one
794 /// thread will ever operate on this object at a time and all operations
795 /// are inheirently thread safe.
797 private:
798 TaskEventListBase* head_; ///< The head of the linked list of data.
799 TaskEventListBase* tail_; ///< The tail of the linked list of data.
800
801 static Mutex output_mutex_; ///< Mutex used to lock the output file.
802
803 TaskProfiler(const TaskProfiler&) = delete;
805
806 public:
807 /// The output file name.
808
809 /// This variable is initialized by \c ThreadPool::begin and is
810 /// assigned the value given by the environment variable
811 /// `MAD_TASKPROFILER_NAME`.
812 static const char* output_file_name_;
813
814 public:
815 /// Default constructor.
817 : head_(nullptr), tail_(nullptr)
818 { }
819
820 /// Destructor.
822 // Cleanup linked list
823 TaskEventListBase* next = nullptr;
824 while(head_ != nullptr) {
825 next = head_->next();
826 delete head_;
827 head_ = next;
828 }
829 }
830
831 /// Create a new task event list.
832
833 /// \param[in] nmax The maximum number of elements that the list
834 /// can contain.
835 /// \return A new task event list.
836 TaskEventList* new_list(const std::size_t nmax) {
837 // Create a new event list
838 TaskEventList* list = new TaskEventList(nmax);
839
840 // Append the list to the tail of the linked list
841 if(head_ != nullptr) {
842 tail_->insert(list);
843 tail_ = list;
844 } else {
845 head_ = list;
846 tail_ = list;
847 }
848 return list;
849 }
850
851 /// Write the profile data to file.
852
853 /// The data is cleared after it is written to the file, so this
854 /// function may be called more than once.
855 ///
856 /// \warning This function should only be called from the thread
857 /// that owns it, otherwise data will likely be corrupted.
858 ///
859 /// \note This function is thread safe, in that it may be called by
860 /// different objects in different threads simultaneously.
861 void write_to_file();
862 }; // class TaskProfiler
863
864 } // namespace profiling
865
866#endif // MADNESS_TASK_PROFILING
867
868
869 /// Lowest level task interface.
870
871 /// The pool invokes \c run_multi_threaded(), which does any necessary
872 /// setup for multiple threads, and then invokes the user's \c run() method.
874 {
875 friend class ThreadPool;
876
877 private:
878
879#ifdef MADNESS_TASK_PROFILING
880 profiling::TaskEvent* task_event_; ///< \todo Description needed.
881 double submit_time_; ///< \todo Description needed.
882 std::pair<void*, unsigned short> id_; ///< \todo Description needed.
883
884 /// \todo Brief description needed.
885
886 /// \todo Descriptions needed.
887 /// \param[in,out] task_event Description needed.
888 void set_event(profiling::TaskEvent* task_event) {
889 task_event_ = task_event;
890 }
891
892 /// Collect info on the task and record the submit time.
893 void submit() {
895 this->get_id(id_);
896 }
897#endif // MADNESS_TASK_PROFILING
898
899 /// Object that is used to convert function and member function pointers into `void*`.
900
901 /// \note This is technically not supported by the C++ standard but
902 /// it will likely not cause any issues here (famous last words?).
903 /// \todo Descriptions needed.
904 /// \tparam T Description needed.
905 template <typename T>
907 T in; ///< \todo Description needed.
908 void* out; ///< \todo Description needed.
909 };
910
911 protected:
912
913 /// \todo Brief description needed.
914
915 /// \todo Descriptions needed.
916 /// \tparam fnT Description needed.
917 /// \param[in,out] id Description needed.
918 /// \param[in] fn Description needed.
919 /// \return Description needed.
920 template <typename fnT>
921 static typename std::enable_if<detail::function_traits<fnT>::value ||
923 make_id(std::pair<void*,unsigned short>& id, fnT fn) {
925 poop.in = fn;
926 id.first = poop.out;
927 id.second = 1ul;
928 }
929
930 /// \todo Brief description needed.
931
932 /// \todo Descriptions needed. What is the purpose of the second argument?
933 /// \tparam fnobjT Description needed.
934 /// \param[in,out] id Description needed.
935 template <typename fnobjT>
936 static typename std::enable_if<!(detail::function_traits<fnobjT>::value ||
938 make_id(std::pair<void*,unsigned short>& id, const fnobjT&) {
939 id.first = reinterpret_cast<void*>(const_cast<char*>(typeid(fnobjT).name()));
940 id.second = 2ul;
941 }
942
943 private:
944
945 /// \todo Brief description needed.
946
947 /// \todo Descriptions needed.
948 /// \param[in,out] id Description needed.
949 virtual void get_id(std::pair<void*,unsigned short>& id) const {
950 id.first = nullptr;
951 id.second = 0ul;
952 }
953
954#ifndef HAVE_INTEL_TBB
955
956 Barrier* barrier; ///< Barrier, only allocated for multithreaded tasks.
957 AtomicInt count; ///< Used to count threads as they start.
958
959 /// Number of queue entries still referring to this task.
960 ///
961 /// A multithreaded task is enqueued once per requested thread, so the
962 /// task outlives the barrier: it may only be destroyed once every one of
963 /// those entries has been taken off the queue and handled. Tying
964 /// destruction to the barrier instead lets the last thread out free the
965 /// task while copies of its pointer are still queued, and the allocator
966 /// then hands the same address to the next task -- two generations live
967 /// at one address, `count` restarted by the new constructor, duplicate
968 /// participant ids, and a barrier waiting forever for an id that was
969 /// never issued.
970 AtomicInt nqueued;
971
972 /// Returns true for the one thread that should invoke the destructor.
973
974 /// \return True for the one thread that should invoke the destructor.
975 bool run_multi_threaded() {
976 // As a thread enters this routine it increments the shared counter
977 // to generate a unique id without needing any thread-local storage.
978 // A downside is this does not preserve any relationships between thread
979 // numbering and the architecture ... more work ahead.
980 int nthread = get_nthread();
981 if (nthread == 1) {
982#ifdef MADNESS_TASK_PROFILING
983 task_event_->start(id_, nthread, submit_time_);
984#endif // MADNESS_TASK_PROFILING
985 run(TaskThreadEnv(1,0,0));
986#ifdef MADNESS_TASK_PROFILING
987 task_event_->stop();
988#endif // MADNESS_TASK_PROFILING
989 return true;
990 }
991 else {
992 int id = count++;
993 std::atomic<bool> barrier_flag{false};
994 barrier->register_thread(id, &barrier_flag);
995
996#ifdef MADNESS_TASK_PROFILING
997 if(id == 0)
998 task_event_->start(id_, nthread, submit_time_);
999#endif // MADNESS_TASK_PROFILING
1000
1001 run(TaskThreadEnv(nthread, id, barrier));
1002
1003#ifdef MADNESS_TASK_PROFILING
1004 const bool cleanup = barrier->enter(id);
1005 if(cleanup) task_event_->stop();
1006 return cleanup;
1007#else
1008 return barrier->enter(id);
1009#endif // MADNESS_TASK_PROFILING
1010 }
1011 }
1012
1013 public:
1014
1015 /// Default constructor.
1017 : TaskAttributes()
1018 , barrier(nullptr)
1019#if HAVE_PARSEC
1020 , parsec_task(ParsecRuntime::task(is_high_priority(), this))
1021#endif
1022 {
1023 count = 0;
1024 nqueued = 1;
1025 }
1026
1027 /// Constructor setting the specified task attributes.
1028
1029 /// \param[in] attr The task attributes.
1030 explicit PoolTaskInterface(const TaskAttributes& attr)
1031 : TaskAttributes(attr)
1032 , barrier(attr.get_nthread()>1 ? new Barrier(attr.get_nthread()) : 0)
1033#if HAVE_PARSEC
1034 , parsec_task(ParsecRuntime::task(is_high_priority(), this))
1035#endif
1036 {
1037 count = 0;
1038 nqueued = 1;
1039 }
1040
1041 /// Set the number of queue entries that refer to this task.
1042
1043 /// Called by ThreadPool::add() before the task is enqueued.
1044 /// \param[in] n The number of entries about to be pushed.
1045 void set_nqueued(int n) { nqueued = n; }
1046
1047 /// Release one queue entry once it has been handled.
1048
1049 /// \return True if this was the last outstanding entry, i.e. the caller
1050 /// now owns the task and must destroy it.
1051 bool release_nqueued() { return nqueued.dec_and_test(); }
1052
1053 /// Destructor.
1054 /// \todo Should we either use a unique_ptr for barrier or check that barrier != nullptr here?
1055 virtual ~PoolTaskInterface() {
1056#if HAVE_PARSEC
1057 *(reinterpret_cast<PoolTaskInterface**>(&(parsec_task->locals[0]))) = nullptr;
1058 ParsecRuntime::delete_parsec_task(parsec_task);
1059 parsec_task = nullptr;
1060#endif
1061 delete barrier;
1062 }
1063
1064 /// Call this to reset the number of threads before the task is submitted.
1065
1066 /// Once a task has been constructed, /c TaskAttributes::set_nthread()
1067 /// is insufficient because a multithreaded task includes a barrier
1068 /// that needs to know the number of threads.
1069 ///
1070 /// \param[in] nthread The new number of threads.
1071 void set_nthread(int nthread) {
1072 if (nthread != get_nthread()) {
1074 delete barrier;
1075 if (nthread > 1)
1076 barrier = new Barrier(nthread);
1077 else
1078 barrier = 0;
1079 }
1080 }
1081#if HAVE_PARSEC
1082 //////////// Parsec Related Begin ////////////////////
1083 parsec_task_t *parsec_task;
1084 //////////// Parsec Related End ///////////////////
1085#endif
1086
1087#else
1088
1089 public:
1090
1091 /// Default constructor.
1094
1095 /// \todo Brief description needed.
1096
1097 /// \todo Descriptions needed.
1098 /// \param[in] attr Description needed.
1099 explicit PoolTaskInterface(const TaskAttributes& attr) :
1100 TaskAttributes(attr)
1101 {
1102 }
1103
1104 /// Destructor.
1105 virtual ~PoolTaskInterface() = default;
1106
1107 /// Call this to reset the number of threads before the task is submitted
1108
1109 /// Once a task has been constructed /c TaskAttributes::set_nthread()
1110 /// is insufficient because a multithreaded task includes a
1111 /// barrier that needs to know the number of threads.
1112 void set_nthread(int nthread) {
1113 if (nthread != get_nthread())
1115 }
1116
1117 /// \todo Brief description needed.
1118
1119 /// \todo Descriptions needed.
1120 /// \return Description needed.
1121 void execute() {
1122 const int nthread = get_nthread();
1123 run( TaskThreadEnv(nthread, 0) );
1124 }
1125
1126#endif // HAVE_INTEL_TBB
1127
1128 /// Override this method to implement a multi-threaded task.
1129
1130 /// \c info.nthread() will be the number of threads collaborating on this task.
1131 ///
1132 /// \c info.id() will be the index of the current thread \c id=0,...,nthread-1.
1133 ///
1134 /// \c info.barrier() will be a barrier for all of the threads, and returns
1135 /// true for the last thread to enter the barrier (other threads get false).
1136 ///
1137 /// \todo Description needed.
1138 /// \param[in] info Description needed.
1139
1140
1141 virtual void run(const TaskThreadEnv& info) = 0;
1142
1143 };
1144
1145 /// A no-operation task used for various purposes.
1147 public:
1148 /// Execution function that does nothing.
1149 void run(const TaskThreadEnv& /*info*/) {}
1150
1151 /// Destructor.
1152 virtual ~PoolTaskNull() {}
1153
1154 private:
1155 /// \todo Brief description needed.
1156
1157 /// \todo Description needed.
1158 /// \param[in,out] id Description needed.
1159 virtual void get_id(std::pair<void*,unsigned short>& id) const {
1161 }
1162 };
1163
1164 /// \c ThreadPool thread object.
1165
1166 /// This class holds thread local data for thread pool threads. It can be
1167 /// accessed via \c ThreadBase::this_thread().
1168 class ThreadPoolThread : public Thread {
1169 private:
1170 // Thread local data for thread pool
1171#ifdef MADNESS_TASK_PROFILING
1172 profiling::TaskProfiler profiler_; ///< \todo Description needed.
1173#endif // MADNESS_TASK_PROFILING
1174
1175 public:
1177 virtual ~ThreadPoolThread() = default;
1178
1179#ifdef MADNESS_TASK_PROFILING
1180 /// Task profiler accessor.
1181
1182 /// \todo Description needed.
1183 /// \return Description needed.
1187#endif // MADNESS_TASK_PROFILING
1188 };
1189
1190 /// A singleton pool of threads for dynamic execution of tasks.
1191
1192 /// \attention You must instantiate the pool while running with just one
1193 /// thread.
1195 public:
1196 // non-copyable and non-movable
1197 ThreadPool(const ThreadPool&) = delete;
1199 void operator=(const ThreadPool&) = delete;
1200 void operator=(ThreadPool&&) = delete;
1201
1202 /// Get the number of threads from the environment.
1203
1204 /// \return The number of threads.
1205 static int default_nthread();
1206
1207 private:
1208 friend class WorldTaskQueue;
1209
1210 // Thread pool data
1211 ThreadPoolThread *threads; ///< Array of threads.
1212 ThreadPoolThread main_thread; ///< Placeholder for main thread tls.
1213 DQueue<PoolTaskInterface*> queue; ///< Queue of tasks.
1214 int nthreads; ///< Number of threads.
1215 volatile bool finish; ///< Set to true when time to stop.
1216 AtomicInt nfinished; ///< Thread pool exit counter.
1217
1218 // Static data
1219 static ThreadPool* instance_ptr; ///< Singleton pointer.
1220 static const int nmax = 128; ///< Number of task a worker thread will pop from the task queue
1221 static double await_timeout; ///< Waiter timeout.
1222
1223#if defined(HAVE_IBMBGQ) and defined(HPM)
1224 static unsigned int main_hpmctx; ///< HPM context for main thread.
1225#endif
1226 /// The constructor is private to enforce the singleton model.
1227
1228 /// \todo Description needed.
1229 /// \param[in] nthread Description needed.
1230 ThreadPool(int nthread=-1);
1231
1232 /// Run the next task.
1233
1234 /// \todo Verify and complete this documentation.
1235 /// \param[in] wait Block of true.
1236 /// \param[in,out] this_thread Description needed.
1237 /// \return True if a task was run.
1238 bool run_task(bool wait, ThreadPoolThread* this_thread) {
1239#if HAVE_INTEL_TBB
1240 MADNESS_EXCEPTION("run_task should not be called when using Intel TBB", 1);
1241#else
1242
1243 if (!wait && queue.empty()) return false;
1244 std::pair<PoolTaskInterface*,bool> t = queue.pop_front(wait);
1245#ifdef MADNESS_TASK_PROFILING
1246 profiling::TaskEventList* event_list =
1247 this_thread->profiler().new_list(1);
1248#endif // MADNESS_TASK_PROFILING
1249 // Task pointer might be zero due to stealing
1250 if (t.second && t.first) {
1251#ifdef MADNESS_TASK_PROFILING
1252 t.first->set_event(event_list->event());
1253#endif // MADNESS_TASK_PROFILING
1254 // Same ownership rule as run_tasks(): the task belongs to
1255 // whichever thread handles its last queue entry, not to
1256 // whichever leaves the barrier last.
1257 PoolTaskInterface* const task = t.first;
1258 task->run_multi_threaded(); // What we are here to do
1259 if (task->release_nqueued()) delete task;
1260 }
1261 return t.second;
1262#endif
1263 }
1264
1265 /// \todo Brief description needed.
1266
1267 /// \todo Descriptions needed.
1268 /// \param[in] wait Description needed.
1269 /// \param[in,out] this_thread Description needed.
1270 /// \return Description needed.
1271 bool run_tasks(bool wait, ThreadPoolThread* const this_thread) {
1272#if HAVE_INTEL_TBB
1273// if (!wait && tbb_task_list->empty()) return false;
1274// tbb::task* t = &tbb_task_list->pop_front();
1275// if (t) {
1276// tbb_parent_task->increment_ref_count();
1277// tbb_parent_task->enqueue(*t);
1278// }
1279
1280// wait = (tbb_parent_task->ref_count() >= 1) ? false : true;
1281// return wait;
1282
1283 MADNESS_EXCEPTION("run_tasks should not be called when using Intel TBB", 1);
1284#else
1285
1286 PoolTaskInterface* taskbuf[nmax];
1287 int ntask = queue.pop_front(nmax, taskbuf, wait);
1288#ifdef MADNESS_TASK_PROFILING
1289 profiling::TaskEventList* event_list =
1290 this_thread->profiler().new_list(ntask);
1291#endif // MADNESS_TASK_PROFILING
1292 for (int i=0; i<ntask; ++i) {
1293 if (taskbuf[i]) { // Task pointer might be zero due to stealing
1294#ifdef MADNESS_TASK_PROFILING
1295 taskbuf[i]->set_event(event_list->event());
1296#endif // MADNESS_TASK_PROFILING
1297 PoolTaskInterface* const task = taskbuf[i];
1298 task->run_multi_threaded(); // returns true for the last thread
1299 // out of the barrier -- informational
1300 // only; it does not confer ownership
1301 if (task->release_nqueued()) delete task;
1302 }
1303 }
1304#if HAVE_PARSEC
1305 ////////////////// Parsec Related Begin //////////////////
1306 if(0 == ntask) {
1307 ntask = parsec_runtime->test();
1308 }
1309 ///////////////// Parsec Related End ////////////////////
1310#endif
1311 return (ntask>0);
1312#endif
1313 }
1314
1315 /// \todo Brief description needed.
1316
1317 /// \todo Description needed.
1318 /// \param[in,out] thread Description needed.
1319 void thread_main(ThreadPoolThread* const thread);
1320
1321 /// Forwards the thread to bound member function.
1322
1323 /// \todo Descriptions needed.
1324 /// \param[in] v Description needed.
1325 /// \return Description needed.
1326 static void* pool_thread_main(void *v);
1327
1328 public:
1329 /// Return a pointer to the only instance, constructing as necessary.
1330
1331 /// \return A pointer to the only instance.
1333#ifndef MADNESS_ASSERTIONS_DISABLE
1334 if(! instance_ptr) {
1335 std::cerr << "!!! ERROR: The thread pool has not been initialized.\n"
1336 << "!!! ERROR: Call madness::initialize before submitting tasks to the task queue.\n";
1337 MADNESS_EXCEPTION("ThreadPool::instance_ptr is NULL", 0);
1338 }
1339#endif
1340 return instance_ptr;
1341 }
1342
1344#if !(defined(HAVE_INTEL_TBB) || defined(HAVE_PARSEC))
1345 queue.lock_and_flush_prebuf();
1346#endif
1347 }
1348
1349#if HAVE_PARSEC
1350 ////////////////// Parsec Related Begin //////////////////
1351 static ParsecRuntime *parsec_runtime;
1352 ///////////////// Parsec Related End ////////////////////
1353#endif
1354
1355#if HAVE_INTEL_TBB
1356 static std::unique_ptr<tbb::global_control> tbb_control; ///< \todo Description needed.
1357 static std::unique_ptr<tbb::task_arena> tbb_arena;
1358#endif
1359
1360 /// Please invoke while in a single-threaded environment.
1361
1362 /// \todo Verify documentation.
1363 /// \param[in] nthread The number of threads.
1364 static void begin(int nthread=-1);
1365
1366 /// \todo Description needed.
1367 static void end();
1368
1369 /// Add a new task to the pool.
1370
1371 /// \todo Description needed.
1372 /// \param[in,out] task Description needed.
1374#ifdef MADNESS_TASK_PROFILING
1375 task->submit();
1376#endif // MADNESS_TASK_PROFILING
1377
1378#if HAVE_PARSEC
1379 //////////// Parsec Related Begin ////////////////////
1380 parsec_runtime->schedule(task);
1381 //////////// Parsec Related End ////////////////////
1382#elif HAVE_INTEL_TBB
1383//#ifdef MADNESS_CAN_USE_TBB_PRIORITY
1384// if(task->is_high_priority())
1385// tbb::task::enqueue(*task, tbb::priority_high);
1386// else
1387//#endif // MADNESS_CAN_USE_TBB_PRIORITY
1388 tbb_arena->enqueue(
1389 //use unique_ptr to automatically delete task ptr
1390 [task_p = std::unique_ptr<PoolTaskInterface>(task)] () noexcept {
1391 //exceptions are not expected here, as nobody will catch them for enqueued tasks
1392 task_p->execute();
1393 });
1394#else
1395 if (!task) MADNESS_EXCEPTION("ThreadPool: inserting a NULL task pointer", 1);
1396 int task_threads = task->get_nthread();
1397 // One reference per queue entry, established before the task becomes
1398 // visible to the pool. The task is destroyed by whichever thread
1399 // handles the last entry, not by whichever leaves the barrier last:
1400 // those are the same thread in the common case, but not always, and
1401 // getting it wrong frees the task while copies of its pointer are
1402 // still queued.
1403 task->set_nqueued(task_threads);
1404 // Currently multithreaded tasks must be shoved on the end of the q
1405 // to avoid a race condition as multithreaded task is starting up
1406 if (task->is_high_priority() && (task_threads == 1)) {
1407 instance()->queue.push_front(task);
1408 }
1409 else {
1410 instance()->queue.push_back(task, task_threads);
1411 }
1412#endif // HAVE_INTEL_TBB
1413 }
1414
1415 /// \todo Brief description needed.
1416
1417 /// \todo Descriptions needed.
1418 /// \tparam opT Description needed.
1419 /// \param[in,out] op Description needed.
1420 template <typename opT>
1421 void scan(opT& op) {
1422 queue.scan(op);
1423 }
1424
1425 /// Add a vector of tasks to the pool.
1426
1427 /// \param[in] tasks Vector of tasks to add to the pool.
1428 static void add(const std::vector<PoolTaskInterface*>& tasks) {
1429#if HAVE_INTEL_TBB
1430 MADNESS_EXCEPTION("Do not add tasks to the madness task queue when using Intel TBB.", 1);
1431#else
1432 typedef std::vector<PoolTaskInterface*>::const_iterator iteratorT;
1433 for (iteratorT it=tasks.begin(); it!=tasks.end(); ++it) {
1434 add(*it);
1435 }
1436#endif
1437 }
1438
1439 /// An otherwise idle thread can all this to run a task.
1440
1441 /// \return True if a task was run.
1442 static bool run_task() {
1443#ifdef HAVE_INTEL_TBB
1444 return false;
1445#else
1446
1447#ifdef MADNESS_TASK_PROFILING
1448 ThreadPoolThread* const thread = static_cast<ThreadPoolThread*>(ThreadBase::this_thread());
1449#else
1450 ThreadPoolThread* const thread = nullptr;
1451#endif // MADNESS_TASK_PROFILING
1452
1453 return instance()->run_tasks(false, thread);
1454#endif // HAVE_INTEL_TBB
1455 }
1456
1457 /// Returns the number of threads in the pool.
1458
1459 /// \return The number of threads in the pool.
1460 static std::size_t size() {
1461 return instance()->nthreads;
1462 }
1463
1464 /// Returns the number of tasks in the queue.
1465
1466 /// \return The number of tasks in the queue.
1467 static std::size_t queue_size() {
1468 return instance()->queue.size();
1469 }
1470
1471 /// Returns queue statistics.
1472
1473 /// \return Queue statistics.
1474 static const DQStats& get_stats();
1475
1476 /// Access the pool thread array
1477 /// \return ptr to the pool thread array, its size is given by \c size()
1479 return const_cast<const ThreadPoolThread*>(instance()->threads);
1480 }
1481
1482 /// Gracefully wait for a condition to become true, executing any tasks in the queue.
1483
1484 /// Probe should be an object that, when called, returns the status.
1485 /// \todo Descriptions needed/need verification.
1486 /// \tparam Probe Type of the probe.
1487 /// \param[in] probe The probe.
1488 /// \param[in] dowork Do work while waiting - default is true
1489 /// \param[in] sleep Sleep instead of spin while waiting (e.g., to avoid pounding on MPI) - default is false
1490 template <typename Probe>
1491 static void await(const Probe& probe, bool dowork = true, bool sleep = false) {
1492 if (!probe()) {
1493 double start = cpu_time();
1494 const double timeout = await_timeout;
1495 int counter = 0;
1496
1497 // if dowork=false must manually purge threal-local tasks to ensure progress
1498 if (!dowork) thread_purge();
1499
1500 MutexWaiter waiter;
1501 while (!probe()) {
1502
1503 const bool working = (dowork ? ThreadPool::run_task() : false);
1504 const double current_time = cpu_time();
1505
1506 if (working) { // Reset timeout logic
1507 waiter.reset();
1508 start = current_time;
1509 counter = 0;
1510 } else {
1511 if(((current_time - start) > timeout) && (timeout > 1.0)) { // Check for timeout
1512 std::cerr << "!!MADNESS: Hung queue?" << std::endl;
1513 if (counter++ > 3) {
1514 const long bufsize=256;
1515 char errstr[bufsize];
1516 snprintf(errstr,bufsize, "ThreadPool::await() timed out after %.1lf seconds", timeout);
1517 throw madness::MadnessException(errstr, 0, 1,
1518 __LINE__, __FUNCTION__,
1519 __FILE__);
1520 }
1521 }
1522 if (sleep) {
1523 // THIS NEEDS TO BECOME AN EXTERNAL PARAMETER
1524 // Problem is exacerbated when running with many
1525 // (e.g., 512 or more) send/recv buffers, and
1526 // also with many threads. More outstanding
1527 // requests means each call into MPI takes
1528 // longer and more threads means more calls in
1529 // spots where all threads are messaging. Old
1530 // code was OK on dancer.icl.utk.edu with just
1531 // 32 bufs and 20 threads, but 512 bufs caused
1532 // intermittent hangs I think due to something
1533 // not being able to make progress or general
1534 // confusion (this with MPICH) ... maybe using a
1535 // fair mutex somewhere would help.
1536 //
1537 // 100us is a long time ... will try 10us. mmm ... perhaps need 100 at least on dancer with 17 threads per node
1538 myusleep(100);
1539 }
1540 else {
1541 waiter.wait();
1542 }
1543 }
1544 }
1545 } // if !probe()
1546 }
1547
1548 /// Destructor.
1550#if HAVE_PARSEC
1551 ////////////////// Parsec related Begin /////////////////
1552 delete parsec_runtime;
1553 ////////////////// Parsec related End /////////////////
1554#elif HAVE_INTEL_TBB
1555#else
1556 delete[] threads;
1557#endif
1558 }
1559
1560 /// \sa madness::threadpool_wait_policy
1561 static void set_wait_policy(
1562 WaitPolicy policy,
1563 int sleep_duration_in_microseconds = 0) {
1564#if !HAVE_INTEL_TBB && !HAVE_PARSEC
1565 instance()->queue.set_wait_policy(policy,
1566 sleep_duration_in_microseconds);
1567#endif
1568 }
1569
1570 };
1571
1572 // clang-format off
1573 /// Controls how aggressively ThreadPool holds on to the OS threads
1574 /// while waiting for work. Currently useful only for Pthread pool when it's using spinlocks;
1575 /// NOT used for TBB or PaRSEC.
1576 /// \param policy specifies how to wait for work;
1577 /// - WaitPolicy::Busy -- threads are kept busy (default); recommended when intensive work is only performed by MADNESS threads
1578 /// - WaitPolicy::Yield -- thread yields; recommended when intensive work is performed primarily by non-MADNESS threads
1579 /// - WaitPolicy::Sleep -- thread sleeps for \p sleep_duration_in_microseconds ; recommended when intensive work is performed by MADNESS nd non-MADNESS threads
1580 /// \param sleep_duration_in_microseconds if `policy==WaitPolicy::Sleep` this specifies the duration of sleep, in microseconds
1581 // clang-format on
1583 int sleep_duration_in_microseconds = 0) {
1584 ThreadPool::set_wait_policy(policy, sleep_duration_in_microseconds);
1585 }
1586
1587 /// @}
1588
1589 inline void thread_purge() {
1590#if !(defined(HAVE_PARSEC) || defined(HAVE_INTEL_TBB))
1593#endif
1594 }
1595
1596 template<class F, class... Args>
1597 constexpr decltype(auto) blocking_invoke(F&& f, Args&&... args)
1598 noexcept(std::is_nothrow_invocable_v<F, Args...>) {
1599 thread_purge();
1600 return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
1601 }
1602
1603 template<class R, class F, class... Args>
1604 constexpr R blocking_invoke_r(F&& f, Args&&... args)
1605 noexcept(std::is_nothrow_invocable_v<F, Args...>) {
1606 thread_purge();
1607#if __cplusplus < 202302L
1608 if constexpr (std::is_void_v<R>)
1609 std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
1610 else
1611 return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
1612#else
1613 return std::invoke_r<R>(std::forward<F>(f), std::forward<Args>(args)...);
1614#endif
1615 }
1616
1617} // namespace madness
1618
1619#endif // MADNESS_WORLD_THREAD_H__INCLUDED
simple class for testing the solver
Definition derivatives.cc:60
An integer with atomic set, get, read+increment, read+decrement, and decrement+test operations.
Definition atomicint.h:126
bool dec_and_test()
Decrements the counter and returns true if the new value is zero,.
Definition atomicint.h:297
Definition worldmutex.h:730
void register_thread(int id, std::atomic< bool > *pflag)
Each thread calls this once before first use.
Definition worldmutex.h:749
bool enter(const int id)
Each thread calls this with its id (0,..,nthread-1) to enter the barrier.
Definition worldmutex.h:760
A thread safe, fast but simple doubled-ended queue.
Definition dqueue.h:80
Base class for exceptions thrown in MADNESS.
Definition madness_exception.h:66
Definition worldmutex.h:128
void wait()
Definition worldmutex.cc:103
void reset()
Definition worldmutex.h:143
Mutex using pthread mutex operations.
Definition worldmutex.h:150
Lowest level task interface.
Definition thread.h:874
double submit_time_
Definition thread.h:881
void execute()
Definition thread.h:1121
virtual ~PoolTaskInterface()=default
Destructor.
static std::enable_if<!(detail::function_traits< fnobjT >::value||detail::memfunc_traits< fnobjT >::value)>::type make_id(std::pair< void *, unsigned short > &id, const fnobjT &)
Definition thread.h:938
profiling::TaskEvent * task_event_
Definition thread.h:880
PoolTaskInterface()
Default constructor.
Definition thread.h:1092
virtual void run(const TaskThreadEnv &info)=0
Override this method to implement a multi-threaded task.
PoolTaskInterface(const TaskAttributes &attr)
Definition thread.h:1099
std::pair< void *, unsigned short > id_
Definition thread.h:882
void set_event(profiling::TaskEvent *task_event)
Definition thread.h:888
void submit()
Collect info on the task and record the submit time.
Definition thread.h:893
static std::enable_if< detail::function_traits< fnT >::value||detail::memfunc_traits< fnT >::value >::type make_id(std::pair< void *, unsigned short > &id, fnT fn)
Definition thread.h:923
virtual void get_id(std::pair< void *, unsigned short > &id) const
Definition thread.h:949
void set_nthread(int nthread)
Call this to reset the number of threads before the task is submitted.
Definition thread.h:1112
A no-operation task used for various purposes.
Definition thread.h:1146
void run(const TaskThreadEnv &)
Execution function that does nothing.
Definition thread.h:1149
virtual ~PoolTaskNull()
Destructor.
Definition thread.h:1152
virtual void get_id(std::pair< void *, unsigned short > &id) const
Definition thread.h:1159
Contains attributes of a task.
Definition thread.h:330
TaskAttributes & set_highpriority(bool hipri)
Sets the high priority attribute.
Definition thread.h:399
TaskAttributes(const TaskAttributes &attr)
Copy constructor.
Definition thread.h:350
bool is_generator() const
Test if the generator attribute is true.
Definition thread.h:358
static TaskAttributes hipri()
Definition thread.h:457
TaskAttributes & set_generator(bool generator_hint)
Sets the generator attribute.
Definition thread.h:379
static const unsigned long GENERATOR
Mask for generator bit.
Definition thread.h:335
static const unsigned long STEALABLE
Mask for stealable bit.
Definition thread.h:336
bool is_stealable() const
Test if the stealable attribute is true.
Definition thread.h:365
TaskAttributes(unsigned long flags=0)
Sets the attributes to the desired values.
Definition thread.h:344
static const unsigned long NTHREAD
Mask for nthread byte.
Definition thread.h:334
void set_nthread(int nthread)
Set the number of threads.
Definition thread.h:421
static TaskAttributes generator()
Definition thread.h:449
bool is_high_priority() const
Test if the high priority attribute is true.
Definition thread.h:372
TaskAttributes & set_stealable(bool stealable)
Sets the stealable attribute.
Definition thread.h:390
static TaskAttributes multi_threaded(int nthread)
Definition thread.h:465
void serialize(Archive &ar)
Serializes the attributes for I/O.
Definition thread.h:441
unsigned long flags
Byte-string storing the specified attributes.
Definition thread.h:331
int get_nthread() const
Get the number of threads.
Definition thread.h:429
static const unsigned long HIGHPRIORITY
Mask for priority bit.
Definition thread.h:337
virtual ~TaskAttributes()
Definition thread.h:353
Used to pass information about the thread environment to a user's task.
Definition thread.h:473
int id() const
Get the ID of this thread.
Definition thread.h:513
TaskThreadEnv(int nthread, int id, Barrier *barrier)
Constructor collecting necessary environmental information.
Definition thread.h:485
TaskThreadEnv(int nthread, int id)
Constructor collecting necessary environmental information.
Definition thread.h:498
bool barrier() const
Definition thread.h:521
Barrier * _barrier
Pointer to the shared barrier, null if there is only a single thread.
Definition thread.h:476
const int _nthread
Number of threads collaborating on task.
Definition thread.h:474
int nthread() const
Get the number of threads collaborating on this task.
Definition thread.h:506
const int _id
ID of this thread (0,...,nthread-1).
Definition thread.h:475
Simplified thread wrapper to hide pthread complexity.
Definition thread.h:171
virtual void run()=0
Function to be executed by the thread.
int pool_num
Stores index of thread in pool or -1.
Definition thread.h:183
void set_pool_thread_index(int i)
Sets the index of this thread within the pool.
Definition thread.h:202
static void exit()
A thread can call this to terminate its execution.
Definition thread.h:233
ThreadBase()
Default constructor.
Definition thread.h:220
const pthread_t & get_id() const
Get the pthread id of this thread (if running).
Definition thread.h:238
static pthread_key_t thread_key
Thread id key.
Definition thread.h:174
static ThreadBase * this_thread()
Definition thread.h:264
int cancel() const
Cancel this thread.
Definition thread.h:250
pthread_t id
Definition thread.h:184
static void delete_thread_key()
Definition thread.h:194
static int num_hw_processors()
Get number of actual hardware processors.
Definition thread.cc:174
void start()
Start the thread running.
Definition thread.cc:158
virtual ~ThreadBase()
Definition thread.h:222
static void init_thread_key()
Definition thread.h:187
int get_pool_thread_index() const
Get index of this thread in ThreadPool.
Definition thread.h:245
Definition thread.h:104
bool do_bind
Definition thread.h:108
void bind()
Definition thread.h:144
size_t get_ncpu() const
Definition thread.h:142
ThreadBinder(bool print=false)
Definition thread.h:115
size_t cpus[maxncpu]
Definition thread.h:109
std::atomic< size_t > nextcpu
Definition thread.h:110
const size_t * get_cpus() const
Definition thread.h:140
bool print
Definition thread.h:106
static const size_t maxncpu
Definition thread.h:105
static thread_local bool bound
Definition thread.h:111
void set_do_bind(bool value)
Definition thread.h:138
size_t ncpu
Definition thread.h:107
ThreadPool thread object.
Definition thread.h:1168
ThreadPoolThread()
Definition thread.h:1176
profiling::TaskProfiler profiler_
Definition thread.h:1172
profiling::TaskProfiler & profiler()
Task profiler accessor.
Definition thread.h:1184
virtual ~ThreadPoolThread()=default
A singleton pool of threads for dynamic execution of tasks.
Definition thread.h:1194
static void add(PoolTaskInterface *task)
Add a new task to the pool.
Definition thread.h:1373
int nthreads
Number of threads.
Definition thread.h:1214
static std::unique_ptr< tbb::task_arena > tbb_arena
Definition thread.h:1357
static bool run_task()
An otherwise idle thread can all this to run a task.
Definition thread.h:1442
static void add(const std::vector< PoolTaskInterface * > &tasks)
Add a vector of tasks to the pool.
Definition thread.h:1428
ThreadPool(ThreadPool &&)=delete
void operator=(ThreadPool &&)=delete
volatile bool finish
Set to true when time to stop.
Definition thread.h:1215
ThreadPool(const ThreadPool &)=delete
static void set_wait_policy(WaitPolicy policy, int sleep_duration_in_microseconds=0)
Definition thread.h:1561
static int default_nthread()
Get the number of threads from the environment.
Definition thread.cc:325
static const DQStats & get_stats()
Returns queue statistics.
Definition thread.cc:466
static void end()
Definition thread.cc:437
AtomicInt nfinished
Thread pool exit counter.
Definition thread.h:1216
void operator=(const ThreadPool &)=delete
static ThreadPool * instance_ptr
Singleton pointer.
Definition thread.h:1219
ThreadPoolThread * threads
Array of threads.
Definition thread.h:1211
void thread_main(ThreadPoolThread *const thread)
Definition thread.cc:349
~ThreadPool()
Destructor.
Definition thread.h:1549
void scan(opT &op)
Definition thread.h:1421
void flush_prebuf()
Definition thread.h:1343
static void begin(int nthread=-1)
Please invoke while in a single-threaded environment.
Definition thread.cc:379
static ThreadPool * instance()
Return a pointer to the only instance, constructing as necessary.
Definition thread.h:1332
static double await_timeout
Waiter timeout.
Definition thread.h:1221
DQueue< PoolTaskInterface * > queue
Queue of tasks.
Definition thread.h:1213
bool run_tasks(bool wait, ThreadPoolThread *const this_thread)
Definition thread.h:1271
static std::size_t queue_size()
Returns the number of tasks in the queue.
Definition thread.h:1467
ThreadPoolThread main_thread
Placeholder for main thread tls.
Definition thread.h:1212
static const int nmax
Number of task a worker thread will pop from the task queue.
Definition thread.h:1220
bool run_task(bool wait, ThreadPoolThread *this_thread)
Run the next task.
Definition thread.h:1238
static void * pool_thread_main(void *v)
Forwards the thread to bound member function.
Definition thread.cc:374
static void await(const Probe &probe, bool dowork=true, bool sleep=false)
Gracefully wait for a condition to become true, executing any tasks in the queue.
Definition thread.h:1491
static std::unique_ptr< tbb::global_control > tbb_control
Definition thread.h:1356
static const ThreadPoolThread * get_threads()
Definition thread.h:1478
static std::size_t size()
Returns the number of threads in the pool.
Definition thread.h:1460
Simplified thread wrapper to hide pthread complexity.
Definition thread.h:278
void start(void *(*f)(void *), void *args=nullptr)
Start the thread by running f(args).
Definition thread.h:306
virtual ~Thread()=default
Thread(void *(*f)(void *), void *args=nullptr)
Create a thread and start it running f(args).
Definition thread.h:297
Thread()
Default constructor.
Definition thread.h:291
void run()
Invokes the function for this thread.
Definition thread.h:283
void * args
The arguments passed to this thread for execution.
Definition thread.h:280
void *(* f)(void *)
The function called for executing this thread.
Definition thread.h:279
Multi-threaded queue to manage and run tasks.
Definition world_task_queue.h:319
Task event list base class.
Definition thread.h:693
virtual ~TaskEventListBase()=default
Virtual destructor.
TaskEventListBase * next_
The next task event in the list.
Definition thread.h:695
friend std::ostream & operator<<(std::ostream &os, const TaskEventListBase &tel)
Output a task event list to an output stream.
Definition thread.h:730
TaskEventListBase & operator=(const TaskEventListBase &)=delete
TaskEventListBase * next() const
Get the next event list in the linked list.
Definition thread.h:712
virtual std::ostream & print_events(std::ostream &) const =0
Print the events.
TaskEventListBase()
Default constructor.
Definition thread.h:703
void insert(TaskEventListBase *list)
Insert list after this list.
Definition thread.h:719
TaskEventListBase(const TaskEventListBase &)=delete
A list of task events.
Definition thread.h:744
TaskEvent * event()
Get a new event from this list.
Definition thread.h:772
TaskEventList & operator=(const TaskEventList &)=delete
TaskEventList(const unsigned int nmax)
Default constructor.
Definition thread.h:759
virtual std::ostream & print_events(std::ostream &os) const
Print events recorded in this list.
Definition thread.h:782
unsigned int n_
The number of events recorded.
Definition thread.h:746
TaskEventList(const TaskEventList &)=delete
virtual ~TaskEventList()=default
Virtual destructor.
std::unique_ptr< TaskEvent[]> events_
The event array.
Definition thread.h:747
Task event class.
Definition thread.h:540
std::string get_name() const
Get name of the function pointer.
Definition thread.h:578
friend std::ostream & operator<<(std::ostream &os, const TaskEvent &te)
Output the task data using a tab-separated list.
Definition thread.h:652
void start(const std::pair< void *, unsigned short > &id, const unsigned short threads, const double submit_time)
Record the start time of the task and collect task information.
Definition thread.h:625
static void print_demangled(std::ostream &os, const char *symbol)
Print demangled symbol name.
Definition thread.h:554
unsigned short threads_
Number of threads used by the task.
Definition thread.h:544
void stop()
Record the stop time of the task.
Definition thread.h:635
double times_[3]
Task trace times: { submit, start, stop }.
Definition thread.h:542
std::pair< void *, unsigned short > id_
Task identification information.
Definition thread.h:543
This class collects and prints task profiling data.
Definition thread.h:796
TaskEventListBase * head_
The head of the linked list of data.
Definition thread.h:798
TaskProfiler()
Default constructor.
Definition thread.h:816
void write_to_file()
Write the profile data to file.
Definition thread.cc:213
~TaskProfiler()
Destructor.
Definition thread.h:821
TaskEventList * new_list(const std::size_t nmax)
Create a new task event list.
Definition thread.h:836
TaskProfiler & operator=(const TaskProfiler &)=delete
TaskEventListBase * tail_
The tail of the linked list of data.
Definition thread.h:799
TaskProfiler(const TaskProfiler &)=delete
static const char * output_file_name_
The output file name.
Definition thread.h:812
static Mutex output_mutex_
Mutex used to lock the output file.
Definition thread.h:801
static const double R
Definition csqrt.cc:46
const std::size_t bufsize
Definition derivatives.cc:16
real_function_3d mask
Definition dirac-hatom.cc:27
Implements DQueue.
void threadpool_wait_policy(WaitPolicy policy, int sleep_duration_in_microseconds=0)
Definition thread.h:1582
static const double v
Definition hatom_sf_dirac.cc:20
Tensor< double > op(const Tensor< double > &x)
Definition kain.cc:508
#define MADNESS_CHECK(condition)
Check a condition — even in a release build the condition is always evaluated so it can have side eff...
Definition madness_exception.h:182
#define MADNESS_EXCEPTION(msg, value)
Macro for throwing a MADNESS exception.
Definition madness_exception.h:119
#define MADNESS_ASSERT(condition)
Assert a condition that should be free of side-effects since in release builds this might be a no-op.
Definition madness_exception.h:134
Namespace for all elements and tools of MADNESS.
Definition DFConvergence.h:9
WaitPolicy
wait policies supported by ConditionVariable/DQueue/ThreadPool
Definition worldmutex.h:511
static double cpu_time()
Returns the cpu time in seconds relative to an arbitrary origin.
Definition timers.h:128
ThreadBinder binder
Definition thread.cc:71
void thread_purge()
Definition thread.h:1589
static void myusleep(unsigned int us)
Sleep or spin for specified number of microseconds.
Definition timers.h:186
bool is_madness_thread()
Definition thread_info.h:70
NDIM & f
Definition mra.h:2668
void error(const char *msg)
Definition world.cc:147
double wall_time()
Returns the wall time in seconds relative to an arbitrary origin.
Definition timers.cc:48
std::string type(const PairType &n)
Definition PNOParameters.h:18
constexpr R blocking_invoke_r(F &&f, Args &&... args) noexcept(std::is_nothrow_invocable_v< F, Args... >)
Definition thread.h:1604
constexpr decltype(auto) blocking_invoke(F &&f, Args &&... args) noexcept(std::is_nothrow_invocable_v< F, Args... >)
Definition thread.h:1597
std::string name(const FuncType &type, const int ex=-1)
Definition ccpairfunction.h:28
Definition dqueue.h:59
Function traits in the spirit of boost function traits.
Definition function_traits.h:13
Member function traits in the spirit of boost function traits.
Definition function_traits.h:21
static double current_time
Definition tdse1d.cc:160
int task(int i)
Definition test_runtime.cpp:4
int main()
Definition test_workflow_builders.cpp:14
const char * status[2]
Definition testperiodic.cc:43
Implements thread introspection for Pthreads backend.
Object that is used to convert function and member function pointers into void*.
Definition thread.h:906