The Gaudi Framework  master (181af51f)
Loading...
Searching...
No Matches
ProcessDescriptor.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
11#ifndef __APPLE__
12static const long TICK_TO_100NSEC = 100000;
13#endif // not __APPLE__
14
15namespace System {
43}
44
45#include <cstdio>
46#include <errno.h>
47#include <fcntl.h>
48#include <iostream>
49#include <libgen.h>
50#include <sstream>
51#include <string>
52#include <sys/signal.h>
53#include <sys/syscall.h>
54#include <sys/times.h>
55#include <sys/types.h>
56#include <unistd.h>
57#ifndef __APPLE__
58# include <sys/procfs.h>
59#endif
60#include <cstdio>
61#include <sys/resource.h>
62#include <sys/time.h>
63
64/* Format of the Linux proc/stat (man 5 proc, kernel 2.6.35):
65 pid %d The process ID.
66
67 comm %s The filename of the executable, in parentheses. This is visible
68 whether or not the executable is swapped out.
69
70 state %c One character from the string "RSDZTW" where R is running, S is
71 sleeping in an interruptible wait, D is waiting in uninterruptible
72 disk sleep, Z is zombie, T is traced or stopped (on a signal), and
73 W is paging.
74
75 ppid %d The PID of the parent.
76
77 pgrp %d The process group ID of the process.
78
79 session %d The session ID of the process.
80
81 tty_nr %d The controlling terminal of the process. (The minor device number
82 is contained in the combination of bits 31 to 20 and 7 to 0; the
83 major device number is in bits 15 t0 8.)
84
85 tpgid %d The ID of the foreground process group of the controlling terminal
86 of the process.
87
88 flags %u (%lu before Linux 2.6.22)
89 The kernel flags word of the process. For bit meanings, see the
90 PF_* defines in <linux/sched.h>. Details depend on the kernel
91 version.
92
93 minflt %lu The number of minor faults the process has made which have not
94 required loading a memory page from disk.
95
96 cminflt %lu The number of minor faults that the process's waited-for children
97 have made.
98
99 majflt %lu The number of major faults the process has made which have
100 required loading a memory page from disk.
101
102 cmajflt %lu The number of major faults that the process's waited-for children
103 have made.
104
105 utime %lu Amount of time that this process has been scheduled in user mode,
106 measured in clock ticks (divide by sysconf(_SC_CLK_TCK). This
107 includes guest time, guest_time (time spent running a virtual CPU,
108 see below), so that applications that are not aware of the guest
109 time field do not lose that time from their calculations.
110
111 stime %lu Amount of time that this process has been scheduled in kernel
112 mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK).
113
114 cutime %ld Amount of time that this process's waited-for children have been
115 scheduled in user mode, measured in clock ticks (divide by
116 sysconf(_SC_CLK_TCK). (See also times(2).) This includes guest
117 time, cguest_time (time spent running a virtual CPU, see below).
118
119 cstime %ld Amount of time that this process's waited-for children have been
120 scheduled in kernel mode, measured in clock ticks (divide by
121 sysconf(_SC_CLK_TCK).
122
123 priority %ld
124 (Explanation for Linux 2.6) For processes running a real-time
125 scheduling policy (policy below; see sched_setscheduler(2)), this
126 is the negated scheduling priority, minus one; that is, a number
127 in the range -2 to -100, corresponding to real-time priorities 1
128 to 99. For processes running under a non-real-time scheduling
129 policy, this is the raw nice value (setpriority(2)) as represented
130 in the kernel. The kernel stores nice values as numbers in the
131 range 0 (high) to 39 (low), corresponding to the user-visible nice
132 range of -20 to 19.
133
134 Before Linux 2.6, this was a scaled value based on the scheduler
135 weighting given to this process.
136
137 nice %ld The nice value (see setpriority(2)), a value in the range 19 (low
138 priority) to -20 (high priority).
139
140 num_threads %ld
141 Number of threads in this process (since Linux 2.6). Before ker‐
142 nel 2.6, this field was hard coded to 0 as a placeholder for an
143 earlier removed field.
144
145 itrealvalue %ld
146 The time in jiffies before the next SIGALRM is sent to the process
147 due to an interval timer. Since kernel 2.6.17, this field is no
148 longer maintained, and is hard coded as 0.
149
150 starttime %llu (was %lu before Linux 2.6)
151 The time in jiffies the process started after system boot.
152
153 vsize %lu Virtual memory size in bytes.
154
155 rss %ld Resident Set Size: number of pages the process has in real memory.
156 This is just the pages which count towards text, data, or stack
157 space. This does not include pages which have not been demand-
158 loaded in, or which are swapped out.
159
160 rsslim %lu Current soft limit in bytes on the rss of the process; see the
161 description of RLIMIT_RSS in getpriority(2).
162
163 startcode %lu
164 The address above which program text can run.
165
166 endcode %lu The address below which program text can run.
167
168 startstack %lu
169 The address of the start (i.e., bottom) of the stack.
170
171 kstkesp %lu The current value of ESP (stack pointer), as found in the kernel
172 stack page for the process.
173
174 kstkeip %lu The current EIP (instruction pointer).
175
176 signal %lu The bitmap of pending signals, displayed as a decimal number.
177 Obsolete, because it does not provide information on real-time
178 signals; use /proc/[pid]/status instead.
179
180 blocked %lu The bitmap of blocked signals, displayed as a decimal number.
181 Obsolete, because it does not provide information on real-time
182 signals; use /proc/[pid]/status instead.
183
184 sigignore %lu
185 The bitmap of ignored signals, displayed as a decimal number.
186 Obsolete, because it does not provide information on real-time
187 signals; use /proc/[pid]/status instead.
188
189 sigcatch %lu
190 The bitmap of caught signals, displayed as a decimal number.
191 Obsolete, because it does not provide information on real-time
192 signals; use /proc/[pid]/status instead.
193
194 wchan %lu This is the "channel" in which the process is waiting. It is the
195 address of a system call, and can be looked up in a namelist if
196 you need a textual name. (If you have an up-to-date
197 /etc/psdatabase, then try ps -l to see the WCHAN field in action.)
198
199 nswap %lu Number of pages swapped (not maintained).
200
201 cnswap %lu Cumulative nswap for child processes (not maintained).
202
203 exit_signal %d (since Linux 2.1.22)
204 Signal to be sent to parent when we die.
205
206 processor %d (since Linux 2.2.8)
207 CPU number last executed on.
208
209 rt_priority %u (since Linux 2.5.19; was %lu before Linux 2.6.22)
210 Real-time scheduling priority, a number in the range 1 to 99 for
211 processes scheduled under a real-time policy, or 0, for non-real-
212 time processes (see sched_setscheduler(2)).
213
214 policy %u (since Linux 2.5.19; was %lu before Linux 2.6.22)
215 Scheduling policy (see sched_setscheduler(2)). Decode using the
216 SCHED_* constants in linux/sched.h.
217
218 delayacct_blkio_ticks %llu (since Linux 2.6.18)
219 Aggregated block I/O delays, measured in clock ticks (centisec‐
220 onds).
221
222 guest_time %lu (since Linux 2.6.24)
223 Guest time of the process (time spent running a virtual CPU for a
224 guest operating system), measured in clock ticks (divide by
225 sysconf(_SC_CLK_TCK).
226
227 cguest_time %ld (since Linux 2.6.24)
228 Guest time of the process's children, measured in clock ticks
229 (divide by sysconf(_SC_CLK_TCK).
230*/
232 int pid;
233 char comm[400];
234 char state;
235 int ppid;
236 int pgrp;
238 int tty;
239 int tpgid;
240 unsigned long flags;
241 unsigned long minflt;
242 unsigned long cminflt;
243 unsigned long majflt;
244 unsigned long cmajflt;
245 unsigned long utime;
246 unsigned long stime;
247 long cutime;
248 long cstime;
250 long nice;
253 unsigned long long starttime;
254 unsigned long vsize;
255 long rss;
256 unsigned long rlim;
257 unsigned long startcode;
258 unsigned long endcode;
259 unsigned long startstack;
260 unsigned long kstkesp;
261 unsigned long kstkeip;
262 unsigned long signal;
263 unsigned long blocked;
264 unsigned long sigignore;
265 unsigned long sigcatch;
266 unsigned long wchan;
267};
268
269#ifdef __APPLE__
270// static long pg_size = 0;
271#else
272static long pg_size = sysconf( _SC_PAGESIZE ); // getpagesize();
273#endif
274void readProcStat( long pid, linux_proc& pinfo ) {
275
276 ssize_t cnt;
277 int fd;
278 char buf[512];
279
280 std::ostringstream ost;
281
282 ost << "/proc/" << pid << "/stat";
283 std::string fname = ost.str();
284 if ( ( fd = open( fname.c_str(), O_RDONLY ) ) < 0 ) {
285 std::cerr << "Failed to open " << ost.str() << std::endl;
286 return;
287 }
288
289 lseek( fd, 0, SEEK_SET );
290 if ( ( cnt = read( fd, buf, sizeof( buf ) - 1 ) ) < 0 ) {
291 std::cout << "LINUX Read of Proc file failed:" << std::endl;
292 close( fd );
293 return;
294 }
295
296 // Format
297 if ( cnt > 0 ) {
298 buf[cnt] = '\0';
299 sscanf(
300 buf,
301 // 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 20 1 2 3 4 5 6 7 8 9
302 // 30 1 2 3 4 5
303 "%d %400s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu "
304 "%lu %lu %lu %lu %lu %lu %lu",
305 &pinfo.pid, pinfo.comm, &pinfo.state, &pinfo.ppid, &pinfo.pgrp, &pinfo.session, &pinfo.tty, &pinfo.tpgid,
306 &pinfo.flags, &pinfo.minflt, &pinfo.cminflt, &pinfo.majflt, &pinfo.cmajflt, &pinfo.utime, &pinfo.stime,
307 &pinfo.cutime, &pinfo.cstime, &pinfo.priority, &pinfo.nice, &pinfo.num_threads, &pinfo.itrealvalue,
308 &pinfo.starttime, &pinfo.vsize, &pinfo.rss, &pinfo.rlim, &pinfo.startcode, &pinfo.endcode, &pinfo.startstack,
309 &pinfo.kstkesp, &pinfo.kstkeip, &pinfo.signal, &pinfo.blocked, &pinfo.sigignore, &pinfo.sigcatch,
310 &pinfo.wchan );
311 }
312 close( fd );
313}
314
315// static long s_myPid = ::getpid();
316// In order to properly support e.g. fork() calls, we cannot keep a copy of the pid!
317
318#ifndef __APPLE__
319static inline long processID( long pid ) { return ( pid > 0 ) ? pid : ( ::getpid() ); }
320#endif // not __APPLE__
321
322#include "ProcessDescriptor.h"
324#include <GaudiKernel/System.h>
325
327 if ( pid > 0 ) {
328 if ( pid != ::getpid() ) {
329 // Note: the return type of getpid is pid_t, which is int on 64bit machines too
330 m_handle = reinterpret_cast<void*>( static_cast<long>( ::getpid() ) );
331 m_needRelease = true;
332 return;
333 }
334 }
336 m_needRelease = false;
337}
338
342
344 if ( info == 0 ) return 0;
345 long status = 1;
346
347 if ( fetch == IO ) {
348#if defined( __linux )
349 linux_proc prc;
350 readProcStat( processID( pid ), prc );
351 rusage usage;
352 getrusage( RUSAGE_SELF, &usage );
353 info->ReadOperationCount = usage.ru_inblock;
354 info->WriteOperationCount = usage.ru_oublock;
355 info->OtherOperationCount = 0;
356 info->ReadTransferCount = usage.ru_inblock;
357 info->WriteTransferCount = usage.ru_oublock;
358 info->OtherTransferCount = 0;
359#else // All Other
360 if ( pid ) {}
361#endif // End ALL OS
362 }
363 return status;
364}
365
367 if ( info == 0 ) return 0;
368 long status = 1;
369
370 if ( fetch == Quota ) {
371#if defined( __linux ) // Linux
372 // rusage usage;
373 // getrusage(RUSAGE_SELF, &usage);
374 rlimit lim;
375
376 getrlimit( RLIMIT_DATA, &lim );
377 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
378 info->PeakPagedPoolUsage = lim.rlim_cur;
379 info->PagedPoolUsage = lim.rlim_cur;
380 info->PagedPoolLimit = lim.rlim_max;
381
382 getrlimit( RLIMIT_STACK, &lim );
383 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
384 info->PeakNonPagedPoolUsage = lim.rlim_cur;
385 info->NonPagedPoolUsage = lim.rlim_cur;
386 info->NonPagedPoolLimit = lim.rlim_max;
387
388 linux_proc prc;
389 readProcStat( processID( pid ), prc );
390 info->PeakPagefileUsage = prc.rss * pg_size;
391 info->PagefileUsage = prc.rss * pg_size;
392 info->PagefileLimit = 0xFFFFFFFF;
393#elif defined( __APPLE__ )
394 if ( pid ) {}
395#else // All Other
396 if ( pid ) {}
397#endif // End ALL OS
398 }
399
400 return status;
401}
402
403long System::ProcessDescriptor::query( [[maybe_unused]] long pid, InfoType fetch, long* info ) {
404
405 if ( info == 0 ) return 0;
406 long status = 1;
407
408 switch ( fetch ) {
409 case PriorityBoost:
410 // Not applicable
411 status = 0;
412 *info = 0;
413 status = ( status == 0 ) ? 1 : 0;
414 break;
415 default:
416 status = -1;
417 *info = -1;
418 break;
419 }
420 return status;
421}
422
424 if ( info == 0 ) return 0;
425 long status = 1;
426
427 if ( fetch == Memory ) {
428#if defined( __linux ) // Linux
429 const ssize_t bufsize = 1024;
430 char buf[bufsize];
431 pid = processID( pid );
432 sprintf( buf, "/proc/%ld/statm", pid );
433 long size, resident, share, trs, lrs, drs, dt;
434 int fd = open( buf, O_RDONLY );
435 ssize_t nread = read( fd, buf, bufsize );
436 close( fd );
437 if ( nread < bufsize && nread >= 0 ) buf[nread] = '\0';
438 fd = sscanf( buf, "%ld %ld %ld %ld %ld %ld %ld", &size, &resident, &share, &trs, &drs, &lrs, &dt );
439 linux_proc prc;
440 readProcStat( pid, prc );
441 info->PeakVirtualSize = prc.vsize;
442 info->VirtualSize = prc.vsize;
443 info->PeakWorkingSetSize = resident * pg_size;
444 info->WorkingSetSize = resident * pg_size;
445 info->QuotaPeakPagedPoolUsage = share * pg_size;
446 info->QuotaPagedPoolUsage = share * pg_size;
447 info->QuotaNonPagedPoolUsage = ( trs + drs ) * pg_size; // drs = data/stack size
448 info->QuotaPeakNonPagedPoolUsage = ( trs + drs ) * pg_size; // trs = VmExe size
449 info->PageFaultCount = prc.majflt + prc.minflt;
450 info->PagefileUsage = prc.vsize - resident * pg_size;
451 info->PeakPagefileUsage = prc.vsize - resident * pg_size;
452#elif defined( __APPLE__ )
453 if ( pid ) {}
454#else // All Other
455 if ( pid ) {}
456#endif // End ALL OS
457 }
458 return status;
459}
460
462 if ( info == 0 ) return 0;
463 long status = 1;
464
465 if ( fetch == Quota ) {
466#if defined( __linux ) // Linux
467 // On linux all this stuff typically is not set
468 // (ie. rlim_max=RLIM_INFINITY...)
469
470 if ( pid > 0 && pid != ::getpid() ) return 0; // only possible for myself
471
472 rlimit lim;
473 getrlimit( RLIMIT_DATA, &lim );
474 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
475 info->PagedPoolLimit = lim.rlim_max;
476
477 getrlimit( RLIMIT_STACK, &lim );
478 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
479 info->NonPagedPoolLimit = lim.rlim_max;
480 info->MinimumWorkingSetSize = 0;
481
482 getrlimit( RLIMIT_RSS, &lim );
483 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
484 info->MaximumWorkingSetSize = lim.rlim_max;
485
486 getrlimit( RLIMIT_AS, &lim );
487 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
488 info->PagefileLimit = lim.rlim_max;
489
490 getrlimit( RLIMIT_CPU, &lim );
491 if ( lim.rlim_max == RLIM_INFINITY ) lim.rlim_max = 0xFFFFFFFF;
492 info->TimeLimit = lim.rlim_max;
493#elif defined( __APPLE__ )
494 if ( pid ) {}
495#else // All Other
496 if ( pid ) {}
497#endif // End ALL OS
498 }
499 return status;
500}
501
503 if ( info == 0 ) return 0;
504 long status = 1;
505
506 if ( fetch == ProcessBasics ) {
507#if defined( __linux ) // Linux
508 linux_proc prc;
509 pid = processID( pid );
510 readProcStat( pid, prc );
511 info->ExitStatus = 0;
512 info->PebBaseAddress = (PPEB)prc.startcode;
513 info->BasePriority = 2 * 15 - prc.priority;
514 // std::cout << "Base Priority=" << info->BasePriority << "|"
515 // << prc.priority << std::endl;
516 info->AffinityMask = prc.flags;
517 // std::cout << "Flags =" << info->AffinityMask << "|"
518 // << prc.flags << std::endl;
519 info->UniqueProcessId = pid;
521#else // All Other
522 if ( pid ) {}
523#endif // End ALL OS
524 }
525 return status;
526}
527
529 if ( info == 0 ) return 0;
530 long status = 1;
531
532 if ( fetch == Times ) {
533#if defined( __linux ) // Linux
534 static long long prc_start = 0;
535 bool myself = pid <= 0 || pid == ::getpid(); // avoid unnecessary calls to getpid if pid<0
536 if ( myself && prc_start == 0 ) { // called only once to set prc_start
537 linux_proc prc;
538 readProcStat( processID( pid ), prc );
539 // prc.startup is in ticks since system start, need to offset for absolute time
540 tms tmsb;
541 static long long offset =
542 100 * static_cast<long long>( time( nullptr ) ) - static_cast<long long>( times( &tmsb ) );
543 prc_start = ( prc.starttime + offset ) * TICK_TO_100NSEC;
544 }
545
546 if ( myself ) { // myself
547 tms tmsb;
548 times( &tmsb );
549 info->UserTime = tmsb.tms_utime * TICK_TO_100NSEC;
550 info->KernelTime = tmsb.tms_stime * TICK_TO_100NSEC;
551 info->CreateTime = prc_start;
552 } else { // other process
553 linux_proc prc;
554 readProcStat( processID( pid ), prc );
555 tms tmsb;
556 static long long offset =
557 100 * static_cast<long long>( time( nullptr ) ) - static_cast<long long>( times( &tmsb ) );
558
559 tms t;
560 times( &t );
561 info->UserTime = t.tms_utime * TICK_TO_100NSEC;
562 info->KernelTime = t.tms_stime * TICK_TO_100NSEC;
563 info->CreateTime = ( prc.starttime + offset ) * TICK_TO_100NSEC;
564 }
565 info->ExitTime = 0;
566
567 status = 1;
568
569#elif defined( __APPLE__ )
570 if ( pid ) {}
571// FIXME (MCl): Make an alternative function get timing on OSX
572// times() seems to cause a segmentation fault
573#else // no /proc file system: assume sys_start for the first call
574 tms tmsb;
575 static clock_t sys_start = times( 0 );
576 static long long offset = 100 * long long( time( 0 ) ) - sys_start;
577 clock_t now = times( &tmsb );
578 info->CreateTime = offset + now;
579 info->UserTime = tmsb.tms_utime;
580 info->KernelTime = tmsb.tms_stime;
581 info->CreateTime *= TICK_TO_100NSEC;
582 info->UserTime *= TICK_TO_100NSEC;
583 info->KernelTime *= TICK_TO_100NSEC;
584 info->ExitTime = 0;
585 status = 1;
586#endif
587 }
588
589 return status;
590}
void readProcStat(long pid, linux_proc &pinfo)
long query(long pid, InfoType fetch, PROCESS_BASIC_INFORMATION *info)
void usage(const std::string &argv0)
Note: OS specific details for environment resolution.
Definition Environment.h:25
@ ProcessDefaultHardErrorMode
@ ProcessEnableAlignmentFaultFixup
@ ProcessPooledUsageAndLimits
GAUDI_API ProcessHandle processHandle()
Handle to running process.
InfoType
Enumeration for fetching information.
Definition SystemBase.h:15
@ PriorityBoost
Definition SystemBase.h:15
@ ProcessBasics
Definition SystemBase.h:15
struct _PEB * PPEB
Basic Process Information NtQueryInformationProcess using ProcessBasicInfo.
Process I/O Counters NtQueryInformationProcess using ProcessIoCounters.
unsigned long WriteOperationCount
unsigned long OtherOperationCount
unsigned long ReadOperationCount
Process/Thread System and User Time NtQueryInformationProcess using ProcessTimes NtQueryInformationTh...
Process Pooled Quota Usage and Limits NtQueryInformationProcess using ProcessPooledUsageAndLimits.
Process Quotas NtQueryInformationProcess using ProcessQuotaLimits NtQueryInformationProcess using Pro...
unsigned long PagedPoolLimit
unsigned long MaximumWorkingSetSize
unsigned long MinimumWorkingSetSize
unsigned long NonPagedPoolLimit
unsigned long PagefileLimit
Process Virtual Memory Counters NtQueryInformationProcess using ProcessVmCounters.
unsigned long PeakPagefileUsage
unsigned long QuotaPeakNonPagedPoolUsage
unsigned long QuotaNonPagedPoolUsage
unsigned long PeakWorkingSetSize
unsigned long QuotaPagedPoolUsage
unsigned long VirtualSize
unsigned long PagefileUsage
unsigned long WorkingSetSize
unsigned long PageFaultCount
unsigned long PeakVirtualSize
unsigned long QuotaPeakPagedPoolUsage
unsigned long utime
unsigned long flags
unsigned long rlim
unsigned long vsize
unsigned long endcode
unsigned long startcode
unsigned long blocked
unsigned long signal
unsigned long cmajflt
unsigned long startstack
unsigned long majflt
unsigned long minflt
unsigned long stime
unsigned long long starttime
unsigned long sigcatch
unsigned long sigignore
unsigned long kstkeip
unsigned long kstkesp
unsigned long wchan
unsigned long cminflt