Project
Loading...
Searching...
No Matches
GeneratorFileOrCmd.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
13
16// For fifo's and system call
17#include <cstdlib>
18#include <sys/types.h> // POSIX only
19#include <sys/stat.h> // POSIX only
20#include <csignal>
21#include <sys/wait.h>
22#include <cstdio>
23// For filesystem operations
24#include <filesystem>
25// Waits
26#include <thread>
27// Log messages
28#include <fairlogger/Logger.h>
29#include <SimConfig/SimConfig.h>
30
31namespace
32{
33std::string ltrim(const std::string& s, const std::string& what = "\" ' ")
34{
35 auto start = s.find_first_not_of(what);
36 if (start == std::string::npos) {
37 return "";
38 }
39
40 return s.substr(start);
41}
42
43std::string rtrim(const std::string& s, const std::string& what = "\"' ")
44{
45 auto end = s.find_last_not_of(what);
46 return s.substr(0, end + 1);
47}
48
49std::string trim(const std::string& s, const std::string& what = "\"' ")
50{
51 return rtrim(ltrim(s, what), what);
52}
53} // namespace
54
55namespace o2
56{
57namespace eventgen
58{
59// -----------------------------------------------------------------
61 const conf::SimConfig& config)
62{
63 setFileNames(param.fileNames);
64 setCmd(param.cmd);
65 setOutputSwitch(trim(param.outputSwitch));
66 setSeedSwitch(trim(param.seedSwitch));
67 setBmaxSwitch(trim(param.bMaxSwitch));
68 setNEventsSwitch(trim(param.nEventsSwitch));
69 setBackgroundSwitch(trim(param.backgroundSwitch));
70 setSeed(config.getStartSeed());
71 setNEvents(config.getNEvents());
72 setBmax(config.getBMax());
73}
74// -----------------------------------------------------------------
75// Switches are permanently set to default values
77 const conf::SimConfig& config)
78{
79 setFileNames(param.fileNames);
80 setCmd(param.cmd);
81 setOutputSwitch(">");
82 setSeedSwitch("-s");
83 setBmaxSwitch("-b");
84 setNEventsSwitch("-n");
86 setSeed(config.getStartSeed());
87 setNEvents(config.getNEvents());
88 setBmax(config.getBMax());
89}
90// -----------------------------------------------------------------
91void GeneratorFileOrCmd::setFileNames(const std::string& filenames)
92{
93 std::stringstream s(filenames);
94 std::string f;
95 while (std::getline(s, f, ',')) {
96 mFileNames.push_back(f);
97 }
98}
99// -----------------------------------------------------------------
101{
102 std::string fileName = mFileNames.front();
103 std::stringstream s;
104 s << mCmd << " ";
105 if (not mSeedSwitch.empty() and mSeedSwitch != "none") {
106 s << mSeedSwitch << " " << mSeed << " ";
107 }
108 if (not mNEventsSwitch.empty() and mNEventsSwitch != "none") {
109 s << mNEventsSwitch << " " << mNEvents << " ";
110 }
111 if (not mBmaxSwitch.empty() and mBmax >= 0 and mBmaxSwitch != "none") {
112 s << mBmaxSwitch.c_str() << " " << mBmax << " ";
113 }
114
115 s << mOutputSwitch << " " << fileName << " "
117 return s.str();
118}
119// -----------------------------------------------------------------
120bool GeneratorFileOrCmd::executeCmdLine(const std::string& cmd)
121{
122 LOG(info) << "Command line to execute: \"" << cmd << "\"";
123 // Fork a new process
124 pid_t pid = fork();
125 if (pid == -1) {
126 LOG(fatal) << "Failed to fork process: " << std::strerror(errno);
127 return false;
128 }
129
130 if (pid == 0) {
131 // Child process
132 setsid();
133 execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)nullptr);
134 // If execl returns, there was an error, otherwise following lines will not be executed
135 LOG(fatal) << "Failed to execute command: " << std::strerror(errno);
136 _exit(EXIT_FAILURE);
137 } else {
138 // Parent process
139 setCmdPid(pid);
140 LOG(info) << "Child spawned process group is running with PID: " << mCmdPid;
141 }
142 return true;
143}
144// -----------------------------------------------------------------
145bool GeneratorFileOrCmd::terminateCmd(unsigned int graceMillis)
146{
147 if (mCmdPid == -1) {
148 LOG(info) << "No command is currently running";
149 return false;
150 }
151
152 // Let the command finish by itself if it is about to: killing the process
153 // group first would deprive an intermediate shell of the chance to reap the
154 // actual generator, and with it this process of the generator's CPU time,
155 // which only reaches RUSAGE_CHILDREN through that reap.
156 constexpr unsigned int pollMillis = 10;
157 for (unsigned int waited = 0; waited < graceMillis; waited += pollMillis) {
158 int status;
159 pid_t reaped = waitpid(mCmdPid, &status, WNOHANG);
160 if (reaped == mCmdPid) {
161 LOG(info) << "Command with process ID " << mCmdPid << " exited by itself";
162 mCmdPid = -1;
163 return true;
164 }
165 if (reaped == -1) {
166 break; // not our child (any more): let the kill path report it
167 }
168 std::this_thread::sleep_for(std::chrono::milliseconds(pollMillis));
169 }
170
171 LOG(info) << "Terminating process ID group " << mCmdPid;
172 if (kill(-mCmdPid, SIGKILL) == -1) {
173 LOG(fatal) << "Failed to kill process: " << std::strerror(errno);
174 return false;
175 }
176
177 // Wait for the process to terminate
178 int status;
179 if (waitpid(mCmdPid, &status, 0) == -1) {
180 LOG(fatal) << "Failed to wait for process termination: " << std::strerror(errno);
181 return false;
182 }
183
184 mCmdPid = -1; // Reset the process ID
185 return true;
186}
187// -----------------------------------------------------------------
188bool GeneratorFileOrCmd::makeTemp(const bool& fromName)
189{
190 if (fromName) {
191 if (mFileNames.empty()) {
192 LOG(fatal) << "No file names to make temporary file from";
193 return false;
194 } else if (mFileNames.size() > 1) {
195 LOG(warning) << "More than one file name to make temporary file from";
196 LOG(warning) << "Using the first one: " << mFileNames.front();
197 LOG(warning) << "Removing all the others";
198 mFileNames.erase(++mFileNames.begin(), mFileNames.end());
199 } else {
200 LOG(debug) << "Making temporary file from: " << mFileNames.front();
201 }
202 std::ofstream ofs(mFileNames.front().c_str());
203 if (!ofs) {
204 LOG(fatal) << "Failed to create temporary file: " << mFileNames.front();
205 return false;
206 }
207 mTemporary = std::string(mFileNames.front());
208 ofs.close();
209 } else {
210 mFileNames.clear();
211 char buf[] = "generatorFifoXXXXXX";
212 auto fp = mkstemp(buf);
213 if (fp < 0) {
214 LOG(fatal) << "Failed to make temporary file: "
215 << std::strerror(errno);
216 return false;
217 }
218 mTemporary = std::string(buf);
219 mFileNames.push_back(mTemporary);
220 close(fp);
221 }
222 return true;
223}
224// -----------------------------------------------------------------
226{
227 if (mTemporary.empty()) {
228 LOG(info) << "Temporary file name empty, nothing to remove";
229 return false;
230 }
231
232 // Get the file we're reading from
233 std::filesystem::path p(mTemporary);
234
235 // Check if the file exists
236 if (not std::filesystem::exists(p)) {
237 LOG(info) << "Temporary file " << p << " does not exist";
238 return true;
239 }
240
241 // Remove temporary file
242 std::error_code ec;
243 std::filesystem::remove(p, ec);
244 if (ec) {
245 LOG(warn) << "When removing " << p << ": " << ec.message();
246 }
247
248 // Ignore errors when removing the temporary file
249 return true;
250}
251// -----------------------------------------------------------------
253{
254 // First remove the temporary file if it exists,
255 // otherwise we may not be able to make the FIFO
256 removeTemp();
257
258 std::string fileName = mFileNames.front();
259
260 int ret = mkfifo(fileName.c_str(), 0600);
261 if (ret != 0) {
262 LOG(fatal) << "Failed to make fifo \"" << fileName << "\": "
263 << std::strerror(errno);
264 return false;
265 }
266
267 return true;
268}
269// -----------------------------------------------------------------
271{
272 try {
273 for (auto& f : mFileNames) {
274 auto c = std::filesystem::canonical(std::filesystem::path(f));
275 f = c.c_str();
276 }
277 } catch (std::exception& e) {
278 LOG(error) << e.what();
279 return false;
280 }
281 return true;
282}
283// -----------------------------------------------------------------
284void GeneratorFileOrCmd::waitForData(const std::string& filename) const
285{
286 using namespace std::chrono_literals;
287
288 // Get the file we're reading from
289 std::filesystem::path p(filename);
290
291 LOG(debug) << "Waiting for data on " << p;
292
293 // Wait until child process creates the file
294 while (not std::filesystem::exists(p)) {
295 std::this_thread::sleep_for(mWait * 1ms);
296 }
297
298 // Wait until we have more data in the file than just the file
299 // header
300 while (std::filesystem::file_size(p) <= 256) {
301 std::this_thread::sleep_for(mWait * 1ms);
302 }
303
304 // Give the child process 1 second to post the data to the file
305 LOG(debug) << "Got data in " << p << ", sleeping for a while";
306 std::this_thread::sleep_for(mWait * 2ms);
307}
308
309} /* namespace eventgen */
310} /* namespace o2 */
std::ostringstream debug
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error s
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char e
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs and
char error[CURL_ERROR_SIZE]
Utility functions for MC particles.
uint16_t pid
Definition RawData.h:2
uint32_t c
Definition RawData.h:2
ULong_t getStartSeed() const
Definition SimConfig.h:171
float getBMax() const
Definition SimConfig.h:162
unsigned int getNEvents() const
Definition SimConfig.h:157
GLuint GLuint end
Definition glcorearb.h:469
GLdouble f
Definition glcorearb.h:310
GLenum GLfloat param
Definition glcorearb.h:271
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition glcorearb.h:2514
std::string trim(std::string const &str)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string filename()
void setCmdPid(const pid_t cmdPid)
void setBackgroundSwitch(const std::string &opt)
void setSeedSwitch(const std::string &opt)
void setFileNames(const std::string &filenames)
void setup(const GeneratorFileOrCmdParam &param, const conf::SimConfig &config)
std::list< std::string > mFileNames
void setSeed(unsigned long seed)
void setNEventsSwitch(const std::string &opt)
void setOutputSwitch(const std::string &opt)
virtual bool terminateCmd(unsigned int graceMillis=0)
void setCmd(const std::string &cmd)
virtual std::string makeCmdLine() const
virtual void waitForData(const std::string &filename) const
virtual bool executeCmdLine(const std::string &cmd)
virtual bool makeTemp(const bool &)
void setBmaxSwitch(const std::string &opt)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"