Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
worker.cxx
Go to the documentation of this file.
1/*
2 * Project: RooFit
3 * Authors:
4 * PB, Patrick Bos, Netherlands eScience Center, p.bos@esciencecenter.nl
5 * IP, Inti Pelupessy, Netherlands eScience Center, i.pelupessy@esciencecenter.nl
6 *
7 * Copyright (c) 2021, CERN
8 *
9 * Redistribution and use in source and binary forms,
10 * with or without modification, are permitted according to the terms
11 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
12 */
13
15
23
24#include <string>
25#include <unistd.h> // getpid, pid_t
26#include <cassert>
27#include <cerrno> // EINTR
28#include <csignal> // sigprocmask etc
29
30namespace RooFit {
31namespace MultiProcess {
32
33static bool worker_loop_running = false;
34
39
40/// \brief The worker processes' event loop
41///
42/// Asks the queue process for tasks, polls for incoming messages from other
43/// processes and handles them.
45{
46 assert(JobManager::instance()->process_manager().is_worker());
49
50 // use a flag to not ask twice
51 bool dequeue_acknowledged = true;
52
54 std::size_t mw_sub_index;
55
56 std::tie(poller, mw_sub_index) = JobManager::instance()->messenger().create_worker_poller();
57
58 // The SIGTERM handler was set in the ProcessManager after forking to the queue and worker
59 // processes; it wakes up any poll through the self-pipe, so no signal blocking is needed here.
61 try { // watch for error from poll (which is called inside receive functions) caused by SIGTERM from master
62
63 // try to dequeue a task
64 if (dequeue_acknowledged) { // don't ask twice
65 JobManager::instance()->messenger().send_from_worker_to_queue(W2Q::dequeue);
67 }
68
69 // wait for handshake from queue or update from the master-worker channel
70 auto poll_result = poller.poll(-1);
71 // because the poller may now have a waiting update from master over the master-worker
72 // channel, but the queue channel could be first in the poll_result vector, and during
73 // handling of a new task it is possible we need to already receive the updated state,
74 // we have to then flip this boolean so that in the for loop when we reach the
75 // master-worker channel's result, we can skip it (otherwise we will hang there,
76 // because no more updated state will be coming):
77 bool skip_sub = false;
78 // then process incoming messages from the channels
79 for (auto readable_index : poll_result) {
80 // message comes from the master-worker channel (first element):
82 if (!skip_sub) {
83 auto job_id = JobManager::instance()->messenger().receive_from_master_on_worker<std::size_t>();
84 JobManager::get_job_object(job_id)->update_state();
85 }
86 } else { // from queue channel
87 message_q2w = JobManager::instance()->messenger().receive_from_queue_on_worker<Q2W>();
88 switch (message_q2w) {
91 break;
92 }
95 auto job_id = JobManager::instance()->messenger().receive_from_queue_on_worker<std::size_t>();
96 auto state_id = JobManager::instance()->messenger().receive_from_queue_on_worker<State>();
97 auto task_id = JobManager::instance()->messenger().receive_from_queue_on_worker<Task>();
98
99 // while loop, because multiple jobs may have updated state coming
100 while (state_id != JobManager::get_job_object(job_id)->get_state_id()) {
101 skip_sub = true;
102 auto job_id_for_state =
103 JobManager::instance()->messenger().receive_from_master_on_worker<std::size_t>();
105 }
106 if (RooFit::MultiProcess::Config::getTimingAnalysis()) ProcessTimer::start_timer("worker:eval_task:" + std::to_string(task_id));
107 JobManager::get_job_object(job_id)->evaluate_task(task_id);
108 if (RooFit::MultiProcess::Config::getTimingAnalysis()) ProcessTimer::end_timer("worker:eval_task:" + std::to_string(task_id));
109 JobManager::get_job_object(job_id)->send_back_task_result_from_worker(task_id);
110
111 break;
112 }
113 }
114 }
115 }
116
117 } catch (ppoll_error_t &) {
118 // SIGTERM received (benign signal interruptions are retried inside
119 // Channel::wait), so exit the loop
120 break;
121 }
122 }
123
126
127 worker_loop_running = false;
128}
129
130} // namespace MultiProcess
131} // namespace RooFit
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
static bool getTimingAnalysis()
Definition Config.cxx:87
static JobManager * instance()
static Job * get_job_object(std::size_t job_object_id)
Waits for input on a set of registered Channels.
Definition Poller.h:34
static void start_timer(std::string section_name)
static void end_timer(std::string section_name)
Thrown when a blocking wait on a Channel is interrupted, e.g.
Definition Channel.h:31
void worker_loop()
The worker processes' event loop.
Definition worker.cxx:44
bool is_worker_loop_running()
Definition worker.cxx:35
std::size_t Task
Definition types.h:22
static bool worker_loop_running
Definition worker.cxx:33
std::size_t State
Definition types.h:23
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
Definition CodegenImpl.h:73