CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ZombieKillerService.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: FWCore/Services
4 // Class : ZombieKillerService
5 //
6 // Implementation:
7 // [Notes on implementation]
8 //
9 // Original Author: Chris Jones
10 // Created: Sat, 22 Mar 2014 16:25:47 GMT
11 //
12 
13 // system include files
14 #include <atomic>
15 #include <thread>
16 #include <mutex>
17 #include <condition_variable>
18 #include <exception>
19 
20 // user include files
25 
26 namespace edm {
28  public:
30 
31  static void fillDescriptions(ConfigurationDescriptions& descriptions);
32 
33  private:
34  const unsigned int m_checkThreshold;
35  const unsigned int m_secsBetweenChecks;
36  std::thread m_watchingThread;
37  std::condition_variable m_jobDoneCondition;
39  bool m_jobDone;
40  std::atomic<bool> m_stillAlive;
41  std::atomic<unsigned int> m_numberChecksWhenNotAlive;
42 
43  void notAZombieYet();
44  void checkForZombie();
45  void startThread();
46  void stopThread();
47  };
48 } // namespace edm
49 
50 using namespace edm;
51 
52 inline bool isProcessWideService(ZombieKillerService const*) { return true; }
53 
54 //
55 // constants, enums and typedefs
56 //
57 
58 //
59 // static data member definitions
60 //
61 
62 //
63 // constructors and destructor
64 //
66  : m_checkThreshold(iPSet.getUntrackedParameter<unsigned int>("numberOfAllowedFailedChecksInARow")),
67  m_secsBetweenChecks(iPSet.getUntrackedParameter<unsigned int>("secondsBetweenChecks")),
68  m_jobDone(false),
69  m_stillAlive(true),
70  m_numberChecksWhenNotAlive(0) {
71  iRegistry.watchPostBeginJob([this]() { startThread(); });
72  iRegistry.watchPostEndJob([this]() { stopThread(); });
73 
74  iRegistry.watchPreSourceRun([this](RunIndex) { notAZombieYet(); });
75  iRegistry.watchPostSourceRun([this](RunIndex) { notAZombieYet(); });
76 
77  iRegistry.watchPreSourceLumi([this](LuminosityBlockIndex) { notAZombieYet(); });
78  iRegistry.watchPostSourceLumi([this](LuminosityBlockIndex) { notAZombieYet(); });
79 
80  iRegistry.watchPreSourceEvent([this](StreamID) { notAZombieYet(); });
81  iRegistry.watchPostSourceEvent([this](StreamID) { notAZombieYet(); });
82 
83  iRegistry.watchPreModuleBeginStream([this](StreamContext const&, ModuleCallingContext const&) { notAZombieYet(); });
84  iRegistry.watchPostModuleBeginStream([this](StreamContext const&, ModuleCallingContext const&) { notAZombieYet(); });
85 
86  iRegistry.watchPreModuleEndStream([this](StreamContext const&, ModuleCallingContext const&) { notAZombieYet(); });
87  iRegistry.watchPostModuleEndStream([this](StreamContext const&, ModuleCallingContext const&) { notAZombieYet(); });
88 
89  iRegistry.watchPreModuleEndJob([this](ModuleDescription const&) { notAZombieYet(); });
90  iRegistry.watchPostModuleEndJob([this](ModuleDescription const&) { notAZombieYet(); });
91  iRegistry.watchPreModuleEvent([this](StreamContext const&, ModuleCallingContext const&) { notAZombieYet(); });
92  iRegistry.watchPostModuleEvent([this](StreamContext const&, ModuleCallingContext const&) { notAZombieYet(); });
93 
95  [this](StreamContext const&, ModuleCallingContext const&) { notAZombieYet(); });
97  [this](StreamContext const&, ModuleCallingContext const&) { notAZombieYet(); });
98 
99  iRegistry.watchPreModuleStreamEndRun([this](StreamContext const&, ModuleCallingContext const&) { notAZombieYet(); });
100  iRegistry.watchPostModuleStreamEndRun([this](StreamContext const&, ModuleCallingContext const&) { notAZombieYet(); });
101 
103  [this](StreamContext const&, ModuleCallingContext const&) { notAZombieYet(); });
105  [this](StreamContext const&, ModuleCallingContext const&) { notAZombieYet(); });
106 
107  iRegistry.watchPreModuleStreamEndLumi([this](StreamContext const&, ModuleCallingContext const&) { notAZombieYet(); });
109  [this](StreamContext const&, ModuleCallingContext const&) { notAZombieYet(); });
110 
112  [this](GlobalContext const&, ModuleCallingContext const&) { notAZombieYet(); });
114  [this](GlobalContext const&, ModuleCallingContext const&) { notAZombieYet(); });
115 
116  iRegistry.watchPreModuleGlobalEndRun([this](GlobalContext const&, ModuleCallingContext const&) { notAZombieYet(); });
117  iRegistry.watchPostModuleGlobalEndRun([this](GlobalContext const&, ModuleCallingContext const&) { notAZombieYet(); });
118 
120  [this](GlobalContext const&, ModuleCallingContext const&) { notAZombieYet(); });
122  [this](GlobalContext const&, ModuleCallingContext const&) { notAZombieYet(); });
123 
124  iRegistry.watchPreModuleGlobalEndLumi([this](GlobalContext const&, ModuleCallingContext const&) { notAZombieYet(); });
126  [this](GlobalContext const&, ModuleCallingContext const&) { notAZombieYet(); });
127 }
128 
129 // ZombieKillerService::ZombieKillerService(const ZombieKillerService& rhs)
130 // {
131 // // do actual copying here;
132 // }
133 
134 //ZombieKillerService::~ZombieKillerService()
135 //{
136 //}
137 
138 //
139 // assignment operators
140 //
141 // const ZombieKillerService& ZombieKillerService::operator=(const ZombieKillerService& rhs)
142 // {
143 // //An exception safe implementation is
144 // ZombieKillerService temp(rhs);
145 // swap(rhs);
146 //
147 // return *this;
148 // }
149 
150 //
151 // member functions
152 //
155  m_stillAlive = true;
156 }
157 
159  if (not m_stillAlive) {
162  edm::LogError("JobStuck") << "Too long since the job has last made progress.";
163  std::terminate();
164  } else {
165  edm::LogWarning("JobProgressing") << "It has been " << m_numberChecksWhenNotAlive * m_secsBetweenChecks
166  << " seconds since job seen progressing";
167  }
168  }
169  m_stillAlive = false;
170 }
171 
173  m_watchingThread = std::thread([this]() {
174  std::unique_lock<std::mutex> lock(m_jobDoneMutex);
175  while (not m_jobDoneCondition.wait_for(
176  lock, std::chrono::seconds(m_secsBetweenChecks), [this]() -> bool { return m_jobDone; })) {
177  //we timed out
178  checkForZombie();
179  }
180  });
181 }
182 
183 void ZombieKillerService::stopThread() {
184  {
185  std::lock_guard<std::mutex> guard(m_jobDoneMutex);
186  m_jobDone = true;
187  }
188  m_jobDoneCondition.notify_all();
189  m_watchingThread.join();
190 }
191 
194  desc.addUntracked<unsigned int>("secondsBetweenChecks", 60)
195  ->setComment("Number of seconds to wait between checking if progress has been made.");
196  desc.addUntracked<unsigned int>("numberOfAllowedFailedChecksInARow", 3)
197  ->setComment("Number of allowed checks in a row with no progress.");
198  descriptions.add("ZombieKillerService", desc);
199 }
200 
201 //
202 // const member functions
203 //
204 
205 //
206 // static member functions
207 //
208 
void watchPostModuleGlobalEndLumi(PostModuleGlobalEndLumi::slot_type const &iSlot)
void watchPreModuleGlobalBeginRun(PreModuleGlobalBeginRun::slot_type const &iSlot)
static void fillDescriptions(ConfigurationDescriptions &descriptions)
double seconds()
ParameterDescriptionBase * addUntracked(U const &iLabel, T const &value)
void watchPostEndJob(PostEndJob::slot_type const &iSlot)
void watchPostModuleEndStream(PostModuleEndStream::slot_type const &iSlot)
void watchPreModuleEvent(PreModuleEvent::slot_type const &iSlot)
static std::mutex mutex
Definition: Proxy.cc:8
void watchPostModuleEvent(PostModuleEvent::slot_type const &iSlot)
const unsigned int m_checkThreshold
void watchPostModuleGlobalBeginLumi(PostModuleGlobalBeginLumi::slot_type const &iSlot)
void watchPostModuleStreamEndLumi(PostModuleStreamEndLumi::slot_type const &iSlot)
void watchPostModuleStreamBeginRun(PostModuleStreamBeginRun::slot_type const &iSlot)
void watchPostSourceEvent(PostSourceEvent::slot_type const &iSlot)
void watchPreModuleBeginStream(PreModuleBeginStream::slot_type const &iSlot)
Log< level::Error, false > LogError
void watchPreModuleGlobalEndRun(PreModuleGlobalEndRun::slot_type const &iSlot)
void watchPostSourceRun(PostSourceRun::slot_type const &iSlot)
void watchPreSourceLumi(PreSourceLumi::slot_type const &iSlot)
void watchPreModuleEndJob(PreModuleEndJob::slot_type const &iSlot)
void watchPreSourceRun(PreSourceRun::slot_type const &iSlot)
void watchPreModuleGlobalBeginLumi(PreModuleGlobalBeginLumi::slot_type const &iSlot)
void watchPostModuleStreamEndRun(PostModuleStreamEndRun::slot_type const &iSlot)
void watchPreModuleStreamBeginLumi(PreModuleStreamBeginLumi::slot_type const &iSlot)
#define DEFINE_FWK_SERVICE(type)
Definition: ServiceMaker.h:96
void watchPostModuleBeginStream(PostModuleBeginStream::slot_type const &iSlot)
bool isProcessWideService(ZombieKillerService const *)
std::atomic< unsigned int > m_numberChecksWhenNotAlive
void watchPostSourceLumi(PostSourceLumi::slot_type const &iSlot)
void watchPostModuleGlobalEndRun(PostModuleGlobalEndRun::slot_type const &iSlot)
void watchPostModuleStreamBeginLumi(PostModuleStreamBeginLumi::slot_type const &iSlot)
void watchPreModuleStreamEndLumi(PreModuleStreamEndLumi::slot_type const &iSlot)
void watchPreModuleStreamBeginRun(PreModuleStreamBeginRun::slot_type const &iSlot)
void add(std::string const &label, ParameterSetDescription const &psetDescription)
void watchPreModuleEndStream(PreModuleEndStream::slot_type const &iSlot)
const unsigned int m_secsBetweenChecks
std::atomic< bool > m_stillAlive
void watchPreModuleStreamEndRun(PreModuleStreamEndRun::slot_type const &iSlot)
ZombieKillerService(edm::ParameterSet const &, edm::ActivityRegistry &)
void watchPostModuleGlobalBeginRun(PostModuleGlobalBeginRun::slot_type const &iSlot)
void watchPreSourceEvent(PreSourceEvent::slot_type const &iSlot)
Log< level::Warning, false > LogWarning
void watchPostModuleEndJob(PostModuleEndJob::slot_type const &iSlot)
void watchPreModuleGlobalEndLumi(PreModuleGlobalEndLumi::slot_type const &iSlot)
std::condition_variable m_jobDoneCondition
void watchPostBeginJob(PostBeginJob::slot_type const &iSlot)
convenience function for attaching to signal