Line data Source code
1 : /*
2 : * Utilj.cc
3 : *
4 : * Created on: Nov 4, 2010
5 : * Author: jjacobs
6 : */
7 :
8 : #include <cstdarg>
9 : #include <cstdio>
10 : #include <cstring>
11 : #include <errno.h>
12 :
13 : #include <casacore/casa/aips.h>
14 : #include <casacore/casa/aipstype.h>
15 : #include <casacore/casa/BasicSL/String.h>
16 : #include <casacore/casa/Utilities/CountedPtr.h>
17 : #include <sys/time.h>
18 : #include <execinfo.h>
19 : #include <algorithm>
20 : #include <math.h>
21 : #include <fstream>
22 : #include <unistd.h>
23 : #include <sys/time.h>
24 : #include <sys/resource.h>
25 :
26 : using std::max;
27 : using std::min;
28 :
29 : using namespace casacore;
30 : using namespace std;
31 :
32 : #include "UtilJ.h"
33 :
34 : using namespace casacore;
35 : namespace casa {
36 :
37 : namespace utilj {
38 :
39 : // Leave a tag to allow manual verification of build setting
40 :
41 : #if defined (CASA_THREAD_NEUTRAL)
42 : String CasaThreadNeutral = "CasaThreadNeutral:YES";
43 : #else
44 : String CasaThreadNeutral = "CasaThreadNeutral:NO";
45 : #endif // defined (CASA_THREAD_NEUTRAL)
46 :
47 : String
48 0 : formatV (const String & formatString, va_list vaList)
49 : {
50 : char buffer [4096];
51 0 : int nPrinted = vsnprintf (buffer, sizeof (buffer), formatString.c_str(), vaList);
52 :
53 0 : if (nPrinted >= (int) sizeof (buffer) - 1){
54 0 : buffer [sizeof (buffer) - 2] = '|'; // mark as truncated
55 : }
56 :
57 0 : return buffer;
58 : }
59 :
60 : /*String
61 : format (const char * formatString, ...)
62 : {
63 :
64 : // Return a String object created using the printf-like format string
65 : // and the provided arguments. If the text is truncated because the
66 : // internal buffer is too small, the last character will be a pipe "|".
67 :
68 : va_list vaList;
69 :
70 : va_start (vaList, formatString);
71 :
72 : String result = formatV (formatString, vaList);
73 :
74 : va_end (vaList);
75 :
76 : return result;
77 : }*/
78 :
79 :
80 : Bool
81 0 : getEnv (const String & name, const Bool & defaultValue)
82 : {
83 0 : char * value = getenv (name.c_str());
84 :
85 0 : if (value == NULL){
86 0 : return defaultValue;
87 : }
88 : else{
89 0 : String stringValue = value;
90 0 : stringValue.downcase();
91 0 : Bool truthValue = true;
92 :
93 0 : if (stringValue == "false" ||
94 0 : stringValue == "f" ||
95 0 : stringValue == "0" ||
96 0 : stringValue == "no"){
97 :
98 0 : truthValue = false;
99 : }
100 :
101 0 : return truthValue;
102 0 : }
103 : }
104 :
105 : Int
106 0 : getEnv (const String & name, const Int & defaultValue)
107 : {
108 0 : char * value = getenv (name.c_str());
109 :
110 0 : if (value == NULL){
111 0 : return defaultValue;
112 : }
113 : else{
114 :
115 : char * next;
116 0 : long longValue = strtol (value, & next, 10);
117 :
118 : // If all of the value characters weren't consumed, assume
119 : // an error occurred and use the default value.
120 :
121 0 : if (* next != '\0')
122 0 : longValue = defaultValue;
123 :
124 0 : return longValue;
125 : }
126 : }
127 :
128 :
129 : String
130 0 : getTimestamp ()
131 : {
132 : // Get a possibly decent resolution time value
133 :
134 : struct timeval now;
135 0 : gettimeofday (& now, NULL);
136 :
137 : // Convert from UTC to local time
138 :
139 0 : struct tm localNow = * localtime (& now.tv_sec);
140 :
141 : // Output the seconds portion of the time in the format
142 : // hh:mm:ss
143 :
144 : char buffer [128];
145 0 : strftime (buffer, sizeof(buffer), "%X", & localNow);
146 :
147 : // Add on the higher resolution portion (if any) of the time
148 : // as milliseconds
149 :
150 : char buffer2 [128];
151 :
152 0 : snprintf (buffer2, sizeof(buffer2), "%s.%03d", buffer, (int) now.tv_usec/1000);
153 :
154 : // Return the final result in the format "hh:mm:ss.ttt"
155 :
156 0 : return buffer2;
157 : }
158 :
159 : Bool
160 0 : isEnvDefined (const String & name)
161 : {
162 0 : char * value = getenv (name.c_str());
163 :
164 0 : return value != NULL;
165 : }
166 :
167 : void
168 0 : printBacktrace (ostream & os, const String & prefix)
169 : {
170 : void * stack [512];
171 0 : int nUsed = backtrace (stack, 512);
172 0 : char ** trace = backtrace_symbols (stack, nUsed);
173 0 : if (! prefix.empty()){
174 0 : os << prefix << endl;
175 : }
176 0 : os << "*** Stack trace (use c++filt to demangle):" << endl;
177 0 : for (int i = 0; i < nUsed; i++){
178 0 : os << trace[i] << endl;
179 : }
180 0 : os.flush();
181 0 : delete trace;
182 0 : }
183 :
184 : AipsError
185 0 : repackageAipsError (AipsError & error, const String & message, const String & file, Int line, const String & func)
186 : {
187 0 : ostringstream os;
188 :
189 0 : AipsError tmp (message, file, line);
190 0 : os << func << ": " << tmp.what() << "\n " << error.what();
191 :
192 0 : return AipsError (os.str());
193 0 : }
194 :
195 : long
196 0 : round (Double d)
197 : {
198 0 : Double sign = (d < 0) ? -1.0 : 1.0;
199 :
200 0 : d += 0.5 * sign;
201 :
202 0 : long result = (long) d;
203 :
204 0 : return result;
205 : }
206 :
207 :
208 : void
209 0 : sleepMs (Int milliseconds)
210 : {
211 : struct timespec t, tRemaining;
212 0 : t.tv_sec = milliseconds / 1000;
213 0 : t.tv_nsec = (milliseconds - t.tv_sec) * 1000000;
214 :
215 : // Because nanosleep can be interrupted by a signal, it is necessary
216 : // to continue the wait if errno is EINTR. When interrupted, nanosleep
217 : // copies the amount of time remaining in the wait into tRemaining; so
218 : // the remainder of one interation becomes the wait value proper on the
219 : // next iteration.
220 :
221 : Bool done;
222 : do {
223 0 : done = nanosleep (& t, & tRemaining) == 0 || errno != EINTR;
224 0 : t = tRemaining;
225 0 : } while (! done);
226 :
227 0 : }
228 :
229 : vector<String>
230 0 : split (const String & string, const String & splitter, Bool ignoreConsecutiveSplitters)
231 : {
232 0 : vector<String> result;
233 :
234 0 : Int start = 0;
235 :
236 : while (true){
237 :
238 0 : Int matchStart = string.find (splitter, start);
239 :
240 0 : if (matchStart == (int) String::npos){
241 :
242 : // No match: put rest of string into the result
243 :
244 0 : String text = string.substr (start);
245 :
246 0 : if (! text.empty()){
247 :
248 0 : result.push_back (string.substr (start));
249 : }
250 :
251 0 : break;
252 0 : }
253 :
254 0 : String text = string.substr (start, matchStart - start);
255 :
256 0 : if (! (text.empty() && ignoreConsecutiveSplitters)){
257 :
258 : // If the text is nonempty or we're not ignored consecutive
259 : // occurrences of splitters, then push text onto the result.
260 :
261 0 : result.push_back (text);
262 : }
263 :
264 0 : start = matchStart + splitter.length();
265 0 : }
266 :
267 0 : return result;
268 0 : }
269 :
270 : void
271 0 : toStdError (const String & m, const String & prefix)
272 : {
273 0 : cerr << prefix << m << endl;
274 0 : cerr.flush();
275 0 : }
276 :
277 :
278 : void
279 0 : throwIf (bool condition, const String & message, const String & file, Int line, const String & func)
280 : {
281 :
282 : // If the condition is met then throw an AipsError
283 :
284 0 : if (condition) {
285 0 : String m = func + ": " + message;
286 0 : AipsErrorTrace e (m.c_str(), file.c_str(), line);
287 :
288 : # if defined (NDEBUG)
289 : toStdError (e.what());
290 : # endif
291 :
292 0 : throw e;
293 0 : }
294 0 : }
295 :
296 : void
297 0 : throwIfError (int errorCode, const String & prefix, const String & file, Int line, const String & func)
298 : {
299 : // If the provided error code is not equal to success (0) then
300 : // throw an AipsError using the provided suffix and then details
301 : // of the error.
302 :
303 0 : if (errorCode != 0) {
304 0 : AipsErrorTrace e (String::format ("%s: %s (errno=%d):%s", func.c_str(), prefix.c_str(),
305 0 : errorCode, strerror (errorCode)), file.c_str(), line);
306 :
307 : # if defined (NDEBUG)
308 : toStdError (e.what());
309 : # endif
310 :
311 0 : throw e;
312 0 : }
313 0 : }
314 :
315 : DeltaThreadTimes
316 0 : ThreadTimes::operator- (const ThreadTimes & tEarlier) const
317 : {
318 0 : return DeltaThreadTimes (this->elapsed() - tEarlier.elapsed(),
319 0 : this->cpu() - tEarlier.cpu());
320 : }
321 :
322 : DeltaThreadTimes &
323 0 : DeltaThreadTimes::operator+= (const DeltaThreadTimes & other)
324 : {
325 0 : cpu_p += other.cpu();
326 0 : elapsed_p += other.elapsed();
327 0 : n_p += 1;
328 :
329 0 : if (doStats_p){
330 0 : cpuSsq_p += other.cpu() * other.cpu();
331 0 : cpuMin_p = min (cpuMin_p, other.cpu());
332 0 : cpuMax_p = max (cpuMax_p, other.cpu());
333 0 : elapsedSsq_p += other.elapsed() * other.elapsed();
334 0 : elapsedMin_p = min (elapsedMin_p, other.elapsed());
335 0 : elapsedMax_p = max (elapsedMax_p, other.elapsed());
336 : }
337 :
338 0 : return * this;
339 : }
340 :
341 :
342 : String
343 0 : DeltaThreadTimes::formatAverage (const String & floatFormat,
344 : Double scale,
345 : const String & units) const // to convert to ms
346 : {
347 : String realFormat = String::format ("(el=%s,cp=%s,%%4.1f%%%%) %s",
348 0 : floatFormat.c_str(), floatFormat.c_str(), units.c_str());
349 0 : Int n = n_p != 0 ? n_p : 1;
350 0 : Double c = cpu_p / n * scale;
351 0 : Double e = elapsed_p / n * scale;
352 0 : Double p = c / e * 100;
353 :
354 0 : String result = String::format (realFormat.c_str(), e, c, p);
355 :
356 0 : return result;
357 0 : }
358 :
359 : String
360 0 : DeltaThreadTimes::formatStats (const String & floatFormat,
361 : Double scale,
362 : const String & units) const // to convert to ms
363 : {
364 : String realFormat = String::format ("(el=%s {%s-%s,%s}, cp=%s {%s-%s,%s}, %%4.1f%%%%) %s",
365 : floatFormat.c_str(),
366 : floatFormat.c_str(),
367 : floatFormat.c_str(),
368 : floatFormat.c_str(),
369 : floatFormat.c_str(),
370 : floatFormat.c_str(),
371 : floatFormat.c_str(),
372 : floatFormat.c_str(),
373 0 : units.c_str());
374 0 : Int n = n_p != 0 ? n_p : 1;
375 0 : Double c = cpu_p / n * scale;
376 0 : Double cS = sqrt (cpuSsq_p / n_p - c * c);
377 0 : Double e = elapsed_p / n * scale;
378 0 : Double eS = sqrt (elapsedSsq_p / n_p - e * e);
379 0 : Double p = c / e * 100;
380 :
381 0 : String result = String::format (realFormat.c_str(), e, elapsedMin_p, elapsedMax_p, eS,
382 0 : c, cpuMin_p, cpuMax_p, cS, p);
383 :
384 0 : return result;
385 0 : }
386 :
387 0 : AipsErrorTrace::AipsErrorTrace ( const String &msg, const String &filename, uInt lineNumber,
388 0 : Category c)
389 0 : : AipsError (msg, filename, lineNumber, c)
390 : {
391 : void * stack [512];
392 0 : int n = backtrace (stack, 512);
393 0 : char ** trace = backtrace_symbols (stack, n);
394 :
395 0 : message += "\nStack trace (use c++filt to demangle):\n";
396 0 : for (int i = 0; i < n; i++){
397 0 : message += trace[i] + String ("\n");
398 : }
399 0 : free (trace);
400 0 : }
401 :
402 :
403 :
404 0 : MemoryStatistics::MemoryStatistics ()
405 : {
406 : char buffer [128];
407 :
408 0 : pid_t pid = getpid ();
409 :
410 0 : sprintf (buffer, "/proc/%d/statm", pid);
411 :
412 0 : filename_p = buffer;
413 :
414 0 : pageSize_p = getpagesize ();
415 :
416 0 : bytesPerMb_p = 1024 * 1024.0;
417 0 : }
418 :
419 : double
420 0 : MemoryStatistics::getVmInMB() const
421 : {
422 0 : return getVmInBytes () / bytesPerMb_p;
423 : }
424 :
425 : int64_t
426 0 : MemoryStatistics::getVmInBytes() const
427 : {
428 0 : return vmPages_p * pageSize_p;
429 : }
430 :
431 : double
432 0 : MemoryStatistics::getRssInMB() const
433 : {
434 0 : return getRssInBytes () / bytesPerMb_p;
435 : }
436 :
437 : int64_t
438 0 : MemoryStatistics::getRssInBytes() const
439 : {
440 0 : return rssPages_p * pageSize_p;
441 : }
442 :
443 :
444 : void
445 0 : MemoryStatistics::update ()
446 : {
447 0 : ifstream is (filename_p.c_str());
448 :
449 0 : is >> vmPages_p >> rssPages_p;
450 :
451 0 : is.close ();
452 0 : }
453 :
454 0 : IoStatistics::IoStatistics ()
455 : {
456 0 : Int pid = getpid();
457 0 : ostringstream os;
458 :
459 0 : statFile_p = String::format ("/proc/%d/io", pid);
460 :
461 0 : capture ();
462 0 : }
463 :
464 : IoStatistics
465 0 : IoStatistics::operator- (const IoStatistics & other) const
466 : {
467 0 : IoStatistics result;
468 0 : result.nBytesRead_p = nBytesRead_p - other.nBytesRead_p;
469 0 : result.nBytesWritten_p = nBytesWritten_p - other.nBytesWritten_p;
470 0 : result.nReads_p = nReads_p - other.nReads_p;
471 0 : result.nWrites_p = nWrites_p - other.nWrites_p;
472 :
473 0 : return result;
474 : }
475 :
476 : IoStatistics
477 0 : IoStatistics::operator+ (const IoStatistics & other) const
478 : {
479 0 : IoStatistics result;
480 :
481 0 : result.nBytesRead_p = nBytesRead_p + other.nBytesRead_p;
482 0 : result.nBytesWritten_p = nBytesWritten_p + other.nBytesWritten_p;
483 0 : result.nReads_p = nReads_p + other.nReads_p;
484 0 : result.nWrites_p = nWrites_p + other.nWrites_p;
485 :
486 0 : return result;
487 : }
488 :
489 : IoStatistics
490 0 : IoStatistics::operator* (Double f) const
491 : {
492 0 : IoStatistics result;
493 :
494 0 : result.nBytesRead_p = nBytesRead_p * f;
495 0 : result.nBytesWritten_p = nBytesWritten_p * f;
496 0 : result.nReads_p = nReads_p * f;
497 0 : result.nWrites_p = nWrites_p * f;
498 :
499 0 : return result;
500 : }
501 :
502 : IoStatistics
503 0 : IoStatistics::operator/ (const IoStatistics & other) const
504 : {
505 0 : IoStatistics result;
506 :
507 0 : result.nBytesRead_p = nBytesRead_p / other.nBytesRead_p;
508 0 : result.nBytesWritten_p = nBytesWritten_p / other.nBytesWritten_p;
509 0 : result.nReads_p = nReads_p / other.nReads_p;
510 0 : result.nWrites_p = nWrites_p / other.nWrites_p;
511 :
512 0 : return result;
513 : }
514 :
515 :
516 : void
517 0 : IoStatistics::capture ()
518 : {
519 0 : ifstream is (statFile_p.c_str());
520 :
521 0 : ThrowIf (! is.good(), String::format ("Failed to open %s file", statFile_p.c_str()));
522 :
523 0 : String tag;
524 :
525 0 : is >> tag;
526 0 : ThrowIf (tag != "rchar:",
527 : String::format ("Expected 'rchar:', got '%s'", tag.c_str()));
528 0 : is >> nBytesRead_p;
529 :
530 0 : is >> tag;
531 0 : ThrowIf (tag != "wchar:",
532 : String::format ("Expected 'wchar:', got '%s'", tag.c_str()));
533 0 : is >> nBytesWritten_p;
534 :
535 :
536 0 : is >> tag;
537 0 : ThrowIf (tag != "syscr:",
538 : String::format ("Expected 'syscr:', got '%s'", tag.c_str()));
539 0 : is >> nReads_p;
540 :
541 :
542 0 : is >> tag;
543 0 : ThrowIf (tag != "syscw:",
544 : String::format ("Expected 'syscw:', got '%s'", tag.c_str()));
545 0 : is >> nWrites_p;
546 :
547 0 : is.close();
548 0 : }
549 :
550 : Double
551 0 : IoStatistics::getBytesRead () const
552 : {
553 0 : return nBytesRead_p;
554 : }
555 :
556 : Double
557 0 : IoStatistics::getBytesWritten () const
558 : {
559 0 : return nBytesWritten_p;
560 : }
561 :
562 : Double
563 0 : IoStatistics::getNReads () const
564 : {
565 0 : return nReads_p;
566 : }
567 :
568 : Double
569 0 : IoStatistics::getNWrites () const
570 : {
571 0 : return nWrites_p;
572 : }
573 :
574 : String
575 0 : IoStatistics::report (float scale, const String & scaleTag) const
576 : {
577 0 : IoStatistics t = (* this) * scale;
578 :
579 : return String::format ("read: %.3f %sB, %.3f %sOps; write: %.3f %sB, %.3f %sOps",
580 : t.nBytesRead_p, scaleTag.c_str(), t.nReads_p, scaleTag.c_str(),
581 0 : t.nBytesWritten_p, scaleTag.c_str(), t.nWrites_p, scaleTag.c_str());
582 :
583 :
584 0 : }
585 : } // end namespace utilj
586 :
587 : using namespace casacore;
588 : } // end namespace casa
|