automotive-dlt
dlt-kpi-process.c
Go to the documentation of this file.
1 /*
2  * @licence app begin@
3  * SPDX license identifier: MPL-2.0
4  *
5  * Copyright (C) 2011-2015, BMW AG
6  *
7  * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
8  *
9  * This Source Code Form is subject to the terms of the
10  * Mozilla Public License (MPL), v. 2.0.
11  * If a copy of the MPL was not distributed with this file,
12  * You can obtain one at http://mozilla.org/MPL/2.0/.
13  *
14  * For further information see http://www.genivi.org/.
15  * @licence end@
16  */
17 
27 #include "dlt-kpi-process.h"
28 
29 #include <pthread.h>
30 #include <unistd.h>
31 
32 DltReturnValue dlt_kpi_read_process_file_to_str(pid_t pid, char **target_str, char *subdir);
33 unsigned long int dlt_kpi_read_process_stat_to_ulong(pid_t pid, unsigned int index);
35 
36 DltReturnValue dlt_kpi_process_update_io_wait(DltKpiProcess *process, unsigned long int time_dif_ms)
37 {
38  if(process == NULL)
39  {
40  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
42  }
43 
44  unsigned long int total_io_wait = dlt_kpi_read_process_stat_to_ulong(process->pid, 42);
45 
46  int cpu_count = dlt_kpi_get_cpu_count();
47 
48  process->io_wait = (total_io_wait - process->last_io_wait) * 1000 / sysconf(_SC_CLK_TCK); // busy milliseconds since last update
49  if(time_dif_ms > 0 && cpu_count > 0)
50  process->io_wait = process->io_wait * 1000 / time_dif_ms / cpu_count; // busy milliseconds per second per CPU
51 
52  process->last_io_wait = total_io_wait;
53 
54  return DLT_RETURN_OK;
55 }
56 
57 DltReturnValue dlt_kpi_process_update_cpu_time(DltKpiProcess *process, unsigned long int time_dif_ms)
58 {
59  if(process == NULL)
60  {
61  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
63  }
64 
65  unsigned long int utime = dlt_kpi_read_process_stat_to_ulong(process->pid, 14);
66  unsigned long int stime = dlt_kpi_read_process_stat_to_ulong(process->pid, 15);
67 
68  unsigned long total_cpu_time = utime + stime;
69 
70  if(process->last_cpu_time > 0 && process->last_cpu_time <= total_cpu_time)
71  {
72  int cpu_count = dlt_kpi_get_cpu_count();
73 
74  process->cpu_time = (total_cpu_time - process->last_cpu_time) * 1000 / sysconf(_SC_CLK_TCK); // busy milliseconds since last update
75  if(time_dif_ms > 0 && cpu_count > 0)
76  process->cpu_time = process->cpu_time * 1000 / time_dif_ms / cpu_count; // busy milliseconds per second per CPU
77  }
78  else
79  process->cpu_time = 0;
80 
81  process->last_cpu_time = total_cpu_time;
82 
83  return DLT_RETURN_OK;
84 }
85 
87 {
88  if(process == NULL)
89  {
90  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
92  }
93 
94  process->rss = dlt_kpi_read_process_stat_to_ulong(process->pid, 24);
95 
96  return DLT_RETURN_OK;
97 }
98 
100 {
101  if(process == NULL)
102  {
103  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
105  }
106 
107  char *buffer, *tok, *last_tok;
108  char *delim = " :\t\n";
109  last_tok = NULL;
110 
111  DltReturnValue ret;
112  if((ret = dlt_kpi_read_process_file_to_str(process->pid, &buffer, "status")) < DLT_RETURN_OK) return ret;
113 
114  process->ctx_switches = 0;
115 
116  tok = strtok(buffer, delim);
117  while(tok != NULL)
118  {
119  if(last_tok != NULL)
120  {
121  if(strcmp(last_tok, "voluntary_ctxt_switches") == 0 || strcmp(last_tok, "nonvoluntary_ctxt_switches") == 0)
122  {
123  char *chk;
124  process->ctx_switches += strtol(tok, &chk, 10);
125 
126  if(*chk != '\0')
127  {
128  fprintf(stderr, "Could not parse ctx_switches info from /proc/%d/status", process->pid);
129  free(buffer);
130  return DLT_RETURN_ERROR;
131  }
132  }
133  }
134 
135  last_tok = tok;
136  tok = strtok(NULL, delim);
137  }
138 
139  free(buffer);
140 
141  return DLT_RETURN_OK;
142 }
143 
145 {
146  if(process == NULL)
147  {
148  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
150  }
151 
152  char *buffer, *tok, *last_tok;
153  char *delim = " :\t\n";
154  last_tok = NULL;
155 
156  DltReturnValue ret;
157  if((ret = dlt_kpi_read_process_file_to_str(process->pid, &buffer, "io")) < DLT_RETURN_OK)
158  return ret;
159 
160  process->io_bytes = 0;
161 
162  tok = strtok(buffer, delim);
163  while(tok != NULL)
164  {
165  if(last_tok != NULL)
166  {
167  if(strcmp(last_tok, "rchar") == 0 || strcmp(last_tok, "wchar") == 0)
168  {
169  char *chk;
170  process->io_bytes += strtoul(tok, &chk, 10);
171 
172  if(*chk != '\0')
173  {
174  fprintf(stderr, "Could not parse io_bytes info from /proc/%d/io", process->pid);
175  free(buffer);
176  return DLT_RETURN_ERROR;
177  }
178  }
179  }
180 
181  last_tok = tok;
182  tok = strtok(NULL, delim);
183  }
184 
185  free(buffer);
186 
187  return DLT_RETURN_OK;
188 }
189 
190 DltReturnValue dlt_kpi_update_process(DltKpiProcess *process, unsigned long int time_dif_ms)
191 {
192 
193  if(process == NULL)
194  {
195  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
197  }
198 
199  dlt_kpi_process_update_io_wait(process, time_dif_ms);
200  dlt_kpi_process_update_cpu_time(process, time_dif_ms);
204 
205  return DLT_RETURN_OK;
206 }
207 
209 {
210  DltKpiProcess *new_process = malloc(sizeof(DltKpiProcess));
211  if(new_process == NULL)
212  {
213  fprintf(stderr, "%s: Out of Memory \n", __func__);
214  return NULL;
215  }
216 
217  memset(new_process, 0, sizeof(DltKpiProcess));
218 
219  new_process->pid = pid;
220  new_process->ppid = (pid_t)dlt_kpi_read_process_stat_to_ulong(pid, 4);
221 
222  dlt_kpi_read_process_file_to_str(pid, &(new_process->command_line), "cmdline");
223  if(new_process->command_line != NULL)
224  if(strlen(new_process->command_line) == 0)
225  {
226  free(new_process->command_line);
227  dlt_kpi_read_process_stat_cmdline(pid, &(new_process->command_line));
228  }
229 
230  dlt_kpi_update_process(new_process, 0);
231 
232  return new_process;
233 }
234 
236 {
237  if(original == NULL)
238  {
239  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
240  return NULL;
241  }
242 
243  // DltKpiProcess *new_process = dlt_kpi_create_process(original->pid);
244  DltKpiProcess *new_process = malloc(sizeof(DltKpiProcess));
245  if(new_process == NULL)
246  {
247  fprintf(stderr, "%s: Out of Memory\n", __func__);
248  return NULL;
249  }
250 
251  memcpy(new_process, original, sizeof(DltKpiProcess));
252 
253  if(original->command_line != NULL)
254  {
255  new_process->command_line = malloc(strlen(original->command_line) + 1);
256  if(new_process->command_line == NULL)
257  {
258  fprintf(stderr, "%s: Out of Memory\n", __func__);
259  free(new_process);
260  return NULL;
261  }
262  strncpy(new_process->command_line, original->command_line, strlen(original->command_line) + 1);
263  }
264  else
265  new_process->command_line = NULL;
266 
267  new_process->next = new_process->prev = NULL;
268 
269  return new_process;
270 }
271 
273 {
274  if(process == NULL)
275  {
276  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
278  }
279 
280  if(process->command_line != NULL)
281  free(process->command_line);
282 
283  free(process);
284 
285  return DLT_RETURN_OK;
286 }
287 
289 {
290  if(process == NULL)
291  {
292  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
294  }
295 
296  printf("[PID %d]\n", process->pid);
297  printf(" > PPID : %d\n", process->ppid);
298  printf(" > CMDLINE : %s\n", process->command_line);
299  printf(" > CPUTIME : %lu (busy ms/s)\n", process->cpu_time);
300  printf(" > RSS : %ld\n", process->rss);
301  printf(" > CTXSWTC : %ld\n", process->ctx_switches);
302  printf(" > IOBYTES : %lu\n", process->io_bytes);
303  printf(" > IOWAIT : %ld (%ld)\n", process->io_wait, process->last_io_wait);
304 
305  return DLT_RETURN_OK;
306 }
307 
308 DltReturnValue dlt_kpi_read_process_file_to_str(pid_t pid, char **target_str, char *subdir)
309 {
310  if(target_str == NULL)
311  {
312  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
313  return DLT_RETURN_ERROR;
314  }
315 
316  *target_str = NULL;
317 
318  if(pid <= 0)
319  {
320  fprintf(stderr, "%s: Invalid Parameter (PID)\n", __func__);
321  return DLT_RETURN_ERROR;
322  }
323 
324  if(subdir == NULL)
325  {
326  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
327  return DLT_RETURN_ERROR;
328  }
329 
330  char filename[BUFFER_SIZE];
331  snprintf(filename, BUFFER_SIZE, "/proc/%d/%s", pid, subdir);
332 
333  return dlt_kpi_read_file_compact(filename, target_str);
334 }
335 
336 unsigned long int dlt_kpi_read_process_stat_to_ulong(pid_t pid, unsigned int index)
337 {
338  if(pid <= 0)
339  {
340  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
341  return 0;
342  }
343 
344  char *buffer = NULL;
345  if(dlt_kpi_read_process_file_to_str(pid, &buffer, "stat") < DLT_RETURN_OK)
346  {
347  // fprintf(stderr, "dlt_kpi_read_process_stat_to_ulong(): Error while reading process stat file. Pid: %d. Requested index: %u\n", pid, index); // can happen if process closed shortly before
348 
349  if(buffer != NULL)
350  free(buffer);
351 
352  return 0;
353  }
354 
355  char *tok = strtok(buffer, " \t\n");
356  unsigned int i = 1, found = 0;
357 
358  while(tok != NULL)
359  {
360  if(i == index)
361  {
362  found = 1;
363  break;
364  }
365  i++;
366  tok = strtok(NULL, " \t\n");
367  }
368 
369  unsigned long int ret = 0;
370 
371  if(found)
372  {
373  char *check = NULL;
374  ret = strtoul(tok, &check, 10);
375  if(*check != '\0')
376  {
377  fprintf(stderr, "dlt_kpi_read_process_stat_to_ulong(): Could not extract token\n");
378  ret = 0;
379  }
380  }
381  else
382  fprintf(stderr, "dlt_kpi_read_process_stat_to_ulong(): Index not found\n");
383 
384  free(buffer);
385 
386  return ret;
387 }
388 
390 {
391  if(pid <= 0)
392  {
393  fprintf(stderr, "%s: Invalid Parameter (PID)\n", __func__);
395  }
396 
397  if(buffer == NULL)
398  {
399  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
401  }
402 
403  char *tmp_buffer = NULL;
404  DltReturnValue tmp = dlt_kpi_read_process_file_to_str(pid, &tmp_buffer, "stat");
405  if(tmp < DLT_RETURN_OK)
406  {
407  if(tmp_buffer != NULL)
408  free(tmp_buffer);
409 
410  return tmp;
411  }
412 
413  char *tok = strtok(tmp_buffer, " \t\n");
414  unsigned int i = 1;
415 
416  while(tok != NULL)
417  {
418  if(i == 2)
419  {
420  break;
421  }
422  i++;
423  tok = strtok(NULL, " \t\n");
424  }
425 
426  if(i == 2)
427  {
428  (*buffer) = malloc(strlen(tok) + 1);
429  strncpy(*buffer, tok, strlen(tok) + 1);
430  }
431  else
432  {
433  fprintf(stderr, "dlt_kpi_read_process_stat_cmdline(): cmdline entry not found\n");
434  return DLT_RETURN_ERROR;
435  }
436 
437  free(tmp_buffer);
438 
439  return DLT_RETURN_OK;
440 }
441 
443 {
444  if(process == NULL || buffer == NULL)
445  {
446  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
448  }
449 
450  snprintf(buffer, maxlen, "%d;%lu;%ld;%ld;%lu;%lu", process->pid, process->cpu_time, process->rss, process->ctx_switches, process->io_bytes, process->io_wait);
451 
452  return DLT_RETURN_OK;
453 }
454 
456 {
457  if(process == NULL || buffer == NULL)
458  {
459  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
461  }
462 
463  snprintf(buffer, maxlen, "%d;%d;%s", process->pid, process->ppid, process->command_line);
464 
465  return DLT_RETURN_OK;
466 }
467 
469 {
470  if(process == NULL || buffer == NULL)
471  {
472  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
474  }
475 
476  snprintf(buffer, maxlen, "%d", process->pid);
477 
478  return DLT_RETURN_OK;
479 }
480 
482 {
483  if(process == NULL || buffer == NULL)
484  {
485  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
487  }
488 
489  snprintf(buffer, maxlen, "%d;%s", process->pid, process->command_line);
490 
491  return DLT_RETURN_OK;
492 }
DltKpiProcess * dlt_kpi_create_process(int pid)
DltReturnValue
Definition: dlt_types.h:86
DltReturnValue dlt_kpi_read_file_compact(char *filename, char **target)
DltReturnValue dlt_kpi_process_update_io_bytes(DltKpiProcess *process)
unsigned long int last_cpu_time
unsigned long int last_io_wait
DltReturnValue dlt_kpi_read_process_stat_cmdline(pid_t pid, char **buffer)
DltReturnValue dlt_kpi_get_msg_process_update(DltKpiProcess *process, char *buffer, int maxlen)
DltReturnValue dlt_kpi_process_update_io_wait(DltKpiProcess *process, unsigned long int time_dif_ms)
DltReturnValue dlt_kpi_get_msg_process_stop(DltKpiProcess *process, char *buffer, int maxlen)
DltKpiProcess * dlt_kpi_clone_process(DltKpiProcess *original)
struct DltKpiProcess * next
unsigned char buffer[BUFFER_SIZE]
Buffer for dlt file transfer. The size is defined by BUFFER_SIZE.
#define BUFFER_SIZE
int dlt_kpi_get_cpu_count()
DltReturnValue dlt_kpi_process_update_cpu_time(DltKpiProcess *process, unsigned long int time_dif_ms)
unsigned long int cpu_time
DltReturnValue dlt_kpi_print_process(DltKpiProcess *process)
DltReturnValue dlt_kpi_update_process(DltKpiProcess *process, unsigned long int time_dif_ms)
DltReturnValue dlt_kpi_free_process(DltKpiProcess *process)
unsigned long int io_wait
unsigned long int io_bytes
struct DltKpiProcess * prev
DltReturnValue dlt_kpi_read_process_file_to_str(pid_t pid, char **target_str, char *subdir)
long int ctx_switches
DltReturnValue dlt_kpi_get_msg_process_new(DltKpiProcess *process, char *buffer, int maxlen)
DltReturnValue dlt_kpi_get_msg_process_commandline(DltKpiProcess *process, char *buffer, int maxlen)
DltReturnValue dlt_kpi_process_update_ctx_switches(DltKpiProcess *process)
DltReturnValue dlt_kpi_process_update_rss(DltKpiProcess *process)
#define NULL
Definition: dlt_common.h:232
unsigned long int dlt_kpi_read_process_stat_to_ulong(pid_t pid, unsigned int index)