libmsngr  1.1
 All Data Structures Files Functions Variables Enumerations Enumerator Macros Groups
msngr_procstats.c
Go to the documentation of this file.
1 /*******************************************************************************
2 *
3 * COPYRIGHT (C) 2010 Battelle Memorial Institute. All Rights Reserved.
4 *
5 ********************************************************************************
6 *
7 * Author:
8 * name: Brian Ermold
9 * phone: (509) 375-2277
10 * email: brian.ermold@pnl.gov
11 *
12 ********************************************************************************
13 *
14 * REPOSITORY INFORMATION:
15 * $Revision: 6688 $
16 * $Author: ermold $
17 * $Date: 2011-05-16 19:03:08 +0000 (Mon, 16 May 2011) $
18 *
19 ********************************************************************************
20 *
21 * NOTE: DOXYGEN is used to generate documentation for this file.
22 *
23 *******************************************************************************/
24 
25 /** @file msngr_procstats.c
26  * Process Stats Functions.
27  */
28 
29 #include <string.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <sys/times.h>
34 
35 #include "messenger.h"
36 
37 #if SOLARIS
38 #include <procfs.h>
39 #endif
40 
41 /**
42  * @defgroup PROCESS_STATS Process Stats
43  */
44 /*@{*/
45 
46 /*******************************************************************************
47  * Private Data and Functions
48  */
49 /** @privatesection */
50 
51 static ProcStats gProcStats;
52 
53 #if SOLARIS
54 
55 /**
56  * PRIVATE: Get stats from the /proc/pid/usage file.
57  *
58  * @param pid - process id
59  *
60  * @return
61  * - 1 if successful
62  * - 0 if an error occurred
63  */
64 static int _get_prusage(pid_t pid)
65 {
66  char prusage_file[64];
67  prusage_t pru;
68  int fd;
69  int nread;
70  double run_time;
71 
72  memset((void *)&pru, 0, sizeof(prusage_t));
73 
74  sprintf(prusage_file, "/proc/%ld/usage", (long)pid);
75 
76  fd = open(prusage_file, O_RDONLY);
77 
78  if (fd < 0) {
79 
80  snprintf(gProcStats.errstr, MAX_STATS_ERROR,
81  "Could not open process usage file: %s\n"
82  " -> %s\n", prusage_file, strerror(errno));
83 
84  return(0);
85  }
86 
87  nread = read(fd, &pru, sizeof(prusage_t));
88 
89  if (nread == -1) {
90 
91  snprintf(gProcStats.errstr, MAX_STATS_ERROR,
92  "Could not read process usage file: %s\n"
93  " -> %s\n", prusage_file, strerror(errno));
94 
95  close (fd);
96  return(0);
97  }
98  else if (nread != sizeof(prusage_t)) {
99 
100  snprintf(gProcStats.errstr, MAX_STATS_ERROR,
101  "Could not read process usage file: %s\n"
102  " -> bytes read (%d) does not match expected size (%d)\n",
103  prusage_file, nread, sizeof(prusage_t));
104 
105  close (fd);
106  return(0);
107  }
108 
109  close (fd);
110 
111  if (pru.pr_ioch > gProcStats.total_rw_io) {
112  gProcStats.total_rw_io = (unsigned long)pru.pr_ioch;
113  }
114 
115  run_time = (double)pru.pr_rtime.tv_sec
116  + ((double)pru.pr_rtime.tv_nsec/1e9);
117 
118  if (run_time > gProcStats.run_time) {
119  gProcStats.run_time = run_time;
120  }
121 
122  return(1);
123 }
124 
125 /**
126  * PRIVATE: Get stats from the /proc/pid/psinfo file.
127  *
128  * @param pid - process id
129  *
130  * @return
131  * - 1 if successful
132  * - 0 if an error occurred
133  */
134 static int _get_psinfo(pid_t pid)
135 {
136  char psinfo_file[64];
137  psinfo_t psi;
138  int fd;
139  int nread;
140 
141  memset((void *)&psi, 0, sizeof(psinfo_t));
142 
143  sprintf(psinfo_file, "/proc/%ld/psinfo", (long)pid);
144 
145  fd = open(psinfo_file, O_RDONLY);
146 
147  if (fd < 0) {
148 
149  snprintf(gProcStats.errstr, MAX_STATS_ERROR,
150  "Could not open process info file: %s\n"
151  " -> %s\n", psinfo_file, strerror(errno));
152 
153  return(0);
154  }
155 
156  nread = read(fd, &psi, sizeof(psinfo_t));
157 
158  if (nread == -1) {
159 
160  snprintf(gProcStats.errstr, MAX_STATS_ERROR,
161  "Could not read process info file: %s\n"
162  " -> %s\n", psinfo_file, strerror(errno));
163 
164  close (fd);
165  return(0);
166  }
167  else if (nread != sizeof(psinfo_t)) {
168 
169  snprintf(gProcStats.errstr, MAX_STATS_ERROR,
170  "Could not read process info file: %s\n"
171  " -> bytes read (%d) does not match expected size (%d)\n",
172  psinfo_file, nread, sizeof(psinfo_t));
173 
174  close (fd);
175  return(0);
176  }
177 
178  close (fd);
179 
180  strncpy(gProcStats.exe_name, psi.pr_fname, 127);
181 
182  if (psi.pr_size > gProcStats.image_size) {
183  gProcStats.image_size = (unsigned int)psi.pr_size;
184  }
185 
186  if (psi.pr_rssize > gProcStats.rss_size) {
187  gProcStats.rss_size = (unsigned int)psi.pr_rssize;
188  }
189 
190  return(1);
191 }
192 
193 #else
194 #if LINUX
195 
196 /**
197  * PRIVATE: Get stats from the /proc/pid/status file.
198  *
199  * @param pid - process id
200  *
201  * @return
202  * - 1 if successful
203  * - 0 if an error occurred
204  */
205 static int _get_process_status(pid_t pid)
206 {
207  char status_file[64];
208  char line[512];
209  FILE *fp;
210  unsigned int image_size;
211  unsigned int rss_size;
212 
213  sprintf(status_file, "/proc/%d/status", pid);
214 
215  fp = fopen(status_file, "r");
216 
217  if (!fp) {
218 
219  snprintf(gProcStats.errstr, MAX_STATS_ERROR,
220  "Could not open process status file: %s\n"
221  " -> %s\n", status_file, strerror(errno));
222 
223  return(0);
224  }
225 
226  while (fgets(line, 512, fp) != NULL) {
227 
228  if (strstr(line, "Name")) {
229  sscanf(line, "%*s %s", gProcStats.exe_name);
230  }
231  else if (strstr(line, "VmSize")) {
232  sscanf(line, "%*s %u", &image_size);
233  if (gProcStats.image_size < image_size) {
234  gProcStats.image_size = image_size;
235  }
236  }
237  else if (strstr(line, "VmRSS")) {
238  sscanf(line, "%*s %u", &rss_size);
239  if (gProcStats.rss_size < rss_size) {
240  gProcStats.rss_size = rss_size;
241  }
242  }
243  }
244 
245  if (ferror(fp)) {
246 
247  snprintf(gProcStats.errstr, MAX_STATS_ERROR,
248  "Could not read process status file: %s\n"
249  " -> %s\n", status_file, strerror(errno));
250 
251  fclose(fp);
252  return(0);
253  }
254 
255  fclose(fp);
256 
257  return(1);
258 }
259 
260 #endif /* LINUX */
261 #endif /* SOLARIS */
262 
263 /*******************************************************************************
264  * Public Functions
265  */
266 /** @publicsection */
267 
268 /**
269  * Get process stats.
270  *
271  * The return value of this function points to the internal ProcStats
272  * structure and must not be modified or freed by the calling process.
273  *
274  * @return pointer to the internal ProcStats structure
275  */
277 {
278  pid_t pid = getpid();
279  double ticks_per_sec = (double)sysconf(_SC_CLK_TCK);
280  double clock_ticks;
281  struct tms tms_buf;
282 
283  /* Clear the error message */
284 
285  gProcStats.errstr[0] = '\0';
286 
287  /* Get total CPU time */
288 
289  if (times(&tms_buf) != (clock_t)-1) {
290 
291  clock_ticks = tms_buf.tms_utime /* user time */
292  + tms_buf.tms_stime /* system time */
293  + tms_buf.tms_cutime /* user time of children */
294  + tms_buf.tms_cstime; /* system time of children */
295 
296  gProcStats.cpu_time = clock_ticks / ticks_per_sec;
297  }
298 
299  /* Get stats */
300 
301 #if SOLARIS
302  _get_prusage(pid);
303  _get_psinfo(pid);
304 #else
305 #if LINUX
306  _get_process_status(pid);
307 #endif
308 #endif
309 
310  return(&gProcStats);
311 }
312 
313 /**
314  * Print process stats.
315  *
316  * This function will print the current process information for:
317  *
318  * - Executable File Name
319  * - Process Image Size
320  * - Resident Set Size
321  * - Total CPU Time
322  * - Total Read/Write IO
323  * - Run Time
324  *
325  * @param fp - pointer to output file stream
326  */
327 void procstats_print(FILE *fp)
328 {
329  ProcStats *proc_stats = procstats_get();
330 
331  if (proc_stats->errstr[0] != '\0') {
332  fprintf(fp, "%s\n", proc_stats->errstr);
333  }
334 
335  fprintf(fp,
336  "Executable File Name: %s\n"
337  "Process Image Size: %u Kbytes\n"
338  "Resident Set Size: %u Kbytes\n"
339  "Total CPU Time: %g seconds\n",
340  proc_stats->exe_name,
341  proc_stats->image_size,
342  proc_stats->rss_size,
343  proc_stats->cpu_time);
344 
345  if (proc_stats->total_rw_io > 0) {
346  fprintf(fp,
347  "Total Read/Write IO: %lu bytes\n",
348  proc_stats->total_rw_io);
349  }
350 
351  if (proc_stats->run_time > 0) {
352  fprintf(fp,
353  "Run Time: %.2f seconds\n",
354  proc_stats->run_time);
355  }
356 }
357 
358 /*@}*/