/* * @licence app begin@ * SPDX license identifier: MPL-2.0 * * Copyright (C) 2011-2015, BMW AG * * This file is part of GENIVI Project DLT - Diagnostic Log and Trace. * * This Source Code Form is subject to the terms of the * Mozilla Public License (MPL), v. 2.0. * If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. * * For further information see http://www.genivi.org/. * @licence end@ */ /*! * \author Sven Hassler * * \copyright Copyright © 2011-2015 BMW AG. \n * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/. * * \file dlt-kpi-process.c */ #include "dlt-kpi-process.h" #include #include DltReturnValue dlt_kpi_read_process_file_to_str(pid_t pid, char **target_str, char *subdir); unsigned long int dlt_kpi_read_process_stat_to_ulong(pid_t pid, unsigned int index); DltReturnValue dlt_kpi_read_process_stat_cmdline(pid_t pid, char **buffer); DltReturnValue dlt_kpi_process_update_io_wait(DltKpiProcess *process, unsigned long int time_dif_ms) { if (process == NULL) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return DLT_RETURN_WRONG_PARAMETER; } unsigned long int total_io_wait = dlt_kpi_read_process_stat_to_ulong(process->pid, 42); int cpu_count = dlt_kpi_get_cpu_count(); process->io_wait = (total_io_wait - process->last_io_wait) * 1000 / sysconf(_SC_CLK_TCK); /* busy milliseconds since last update */ if ((time_dif_ms > 0) && (cpu_count > 0)) process->io_wait = process->io_wait * 1000 / time_dif_ms / cpu_count; /* busy milliseconds per second per CPU */ process->last_io_wait = total_io_wait; return DLT_RETURN_OK; } DltReturnValue dlt_kpi_process_update_cpu_time(DltKpiProcess *process, unsigned long int time_dif_ms) { if (process == NULL) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return DLT_RETURN_WRONG_PARAMETER; } unsigned long int utime = dlt_kpi_read_process_stat_to_ulong(process->pid, 14); unsigned long int stime = dlt_kpi_read_process_stat_to_ulong(process->pid, 15); unsigned long total_cpu_time = utime + stime; if ((process->last_cpu_time > 0) && (process->last_cpu_time <= total_cpu_time)) { int cpu_count = dlt_kpi_get_cpu_count(); process->cpu_time = (total_cpu_time - process->last_cpu_time) * 1000 / sysconf(_SC_CLK_TCK); /* busy milliseconds since last update */ if ((time_dif_ms > 0) && (cpu_count > 0)) process->cpu_time = process->cpu_time * 1000 / time_dif_ms / cpu_count; /* busy milliseconds per second per CPU */ } else { process->cpu_time = 0; } process->last_cpu_time = total_cpu_time; return DLT_RETURN_OK; } DltReturnValue dlt_kpi_process_update_rss(DltKpiProcess *process) { if (process == NULL) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return DLT_RETURN_WRONG_PARAMETER; } process->rss = dlt_kpi_read_process_stat_to_ulong(process->pid, 24); return DLT_RETURN_OK; } DltReturnValue dlt_kpi_process_update_ctx_switches(DltKpiProcess *process) { if (process == NULL) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return DLT_RETURN_WRONG_PARAMETER; } char *buffer, *tok, *last_tok; char *delim = " :\t\n"; last_tok = NULL; DltReturnValue ret; if ((ret = dlt_kpi_read_process_file_to_str(process->pid, &buffer, "status")) < DLT_RETURN_OK) return ret; process->ctx_switches = 0; tok = strtok(buffer, delim); while (tok != NULL) { if (last_tok != NULL) { if ((strcmp(last_tok, "voluntary_ctxt_switches") == 0) || (strcmp(last_tok, "nonvoluntary_ctxt_switches") == 0)) { char *chk; process->ctx_switches += strtol(tok, &chk, 10); if (*chk != '\0') { fprintf(stderr, "Could not parse ctx_switches info from /proc/%d/status", process->pid); free(buffer); return DLT_RETURN_ERROR; } } } last_tok = tok; tok = strtok(NULL, delim); } free(buffer); return DLT_RETURN_OK; } DltReturnValue dlt_kpi_process_update_io_bytes(DltKpiProcess *process) { if (process == NULL) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return DLT_RETURN_WRONG_PARAMETER; } char *buffer, *tok, *last_tok; char *delim = " :\t\n"; last_tok = NULL; DltReturnValue ret; if ((ret = dlt_kpi_read_process_file_to_str(process->pid, &buffer, "io")) < DLT_RETURN_OK) return ret; process->io_bytes = 0; tok = strtok(buffer, delim); while (tok != NULL) { if (last_tok != NULL) { if ((strcmp(last_tok, "rchar") == 0) || (strcmp(last_tok, "wchar") == 0)) { char *chk; process->io_bytes += strtoul(tok, &chk, 10); if (*chk != '\0') { fprintf(stderr, "Could not parse io_bytes info from /proc/%d/io", process->pid); free(buffer); return DLT_RETURN_ERROR; } } } last_tok = tok; tok = strtok(NULL, delim); } free(buffer); return DLT_RETURN_OK; } DltReturnValue dlt_kpi_update_process(DltKpiProcess *process, unsigned long int time_dif_ms) { if (process == NULL) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return DLT_RETURN_WRONG_PARAMETER; } dlt_kpi_process_update_io_wait(process, time_dif_ms); dlt_kpi_process_update_cpu_time(process, time_dif_ms); dlt_kpi_process_update_rss(process); dlt_kpi_process_update_ctx_switches(process); dlt_kpi_process_update_io_bytes(process); return DLT_RETURN_OK; } DltKpiProcess *dlt_kpi_create_process(int pid) { DltKpiProcess *new_process = malloc(sizeof(DltKpiProcess)); if (new_process == NULL) { fprintf(stderr, "%s: Out of Memory \n", __func__); return NULL; } memset(new_process, 0, sizeof(DltKpiProcess)); new_process->pid = pid; new_process->ppid = (pid_t)dlt_kpi_read_process_stat_to_ulong(pid, 4); dlt_kpi_read_process_file_to_str(pid, &(new_process->command_line), "cmdline"); if (new_process->command_line != NULL) if (strlen(new_process->command_line) == 0) { free(new_process->command_line); dlt_kpi_read_process_stat_cmdline(pid, &(new_process->command_line)); } dlt_kpi_update_process(new_process, 0); return new_process; } DltKpiProcess *dlt_kpi_clone_process(DltKpiProcess *original) { if (original == NULL) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return NULL; } /* DltKpiProcess *new_process = dlt_kpi_create_process(original->pid); */ DltKpiProcess *new_process = malloc(sizeof(DltKpiProcess)); if (new_process == NULL) { fprintf(stderr, "%s: Out of Memory\n", __func__); return NULL; } memcpy(new_process, original, sizeof(DltKpiProcess)); if (original->command_line != NULL) { new_process->command_line = malloc(strlen(original->command_line) + 1); if (new_process->command_line == NULL) { fprintf(stderr, "%s: Out of Memory\n", __func__); free(new_process); return NULL; } strncpy(new_process->command_line, original->command_line, strlen(original->command_line) + 1); } else { new_process->command_line = NULL; } new_process->next = new_process->prev = NULL; return new_process; } DltReturnValue dlt_kpi_free_process(DltKpiProcess *process) { if (process == NULL) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return DLT_RETURN_WRONG_PARAMETER; } if (process->command_line != NULL) free(process->command_line); free(process); return DLT_RETURN_OK; } DltReturnValue dlt_kpi_print_process(DltKpiProcess *process) { if (process == NULL) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return DLT_RETURN_WRONG_PARAMETER; } printf("[PID %d]\n", process->pid); printf(" > PPID : %d\n", process->ppid); printf(" > CMDLINE : %s\n", process->command_line); printf(" > CPUTIME : %lu (busy ms/s)\n", process->cpu_time); printf(" > RSS : %ld\n", process->rss); printf(" > CTXSWTC : %ld\n", process->ctx_switches); printf(" > IOBYTES : %lu\n", process->io_bytes); printf(" > IOWAIT : %ld (%ld)\n", process->io_wait, process->last_io_wait); return DLT_RETURN_OK; } DltReturnValue dlt_kpi_read_process_file_to_str(pid_t pid, char **target_str, char *subdir) { if (target_str == NULL) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return DLT_RETURN_ERROR; } *target_str = NULL; if (pid <= 0) { fprintf(stderr, "%s: Invalid Parameter (PID)\n", __func__); return DLT_RETURN_ERROR; } if (subdir == NULL) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return DLT_RETURN_ERROR; } char filename[BUFFER_SIZE]; snprintf(filename, BUFFER_SIZE, "/proc/%d/%s", pid, subdir); return dlt_kpi_read_file_compact(filename, target_str); } unsigned long int dlt_kpi_read_process_stat_to_ulong(pid_t pid, unsigned int index) { if (pid <= 0) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return 0; } char *buffer = NULL; if (dlt_kpi_read_process_file_to_str(pid, &buffer, "stat") < DLT_RETURN_OK) { /* 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 */ if (buffer != NULL) free(buffer); return 0; } char *tok = strtok(buffer, " \t\n"); unsigned int i = 1, found = 0; while (tok != NULL) { if (i == index) { found = 1; break; } i++; tok = strtok(NULL, " \t\n"); } unsigned long int ret = 0; if (found) { char *check = NULL; ret = strtoul(tok, &check, 10); if (*check != '\0') { fprintf(stderr, "dlt_kpi_read_process_stat_to_ulong(): Could not extract token\n"); ret = 0; } } else { fprintf(stderr, "dlt_kpi_read_process_stat_to_ulong(): Index not found\n"); } free(buffer); return ret; } DltReturnValue dlt_kpi_read_process_stat_cmdline(pid_t pid, char **buffer) { if (pid <= 0) { fprintf(stderr, "%s: Invalid Parameter (PID)\n", __func__); return DLT_RETURN_WRONG_PARAMETER; } if (buffer == NULL) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return DLT_RETURN_WRONG_PARAMETER; } char *tmp_buffer = NULL; DltReturnValue tmp = dlt_kpi_read_process_file_to_str(pid, &tmp_buffer, "stat"); if (tmp < DLT_RETURN_OK) { if (tmp_buffer != NULL) free(tmp_buffer); return tmp; } char *tok = strtok(tmp_buffer, " \t\n"); unsigned int i = 1; while (tok != NULL) { if (i == 2) break; i++; tok = strtok(NULL, " \t\n"); } if (i == 2) { (*buffer) = malloc(strlen(tok) + 1); strncpy(*buffer, tok, strlen(tok) + 1); } else { fprintf(stderr, "dlt_kpi_read_process_stat_cmdline(): cmdline entry not found\n"); return DLT_RETURN_ERROR; } free(tmp_buffer); return DLT_RETURN_OK; } DltReturnValue dlt_kpi_get_msg_process_update(DltKpiProcess *process, char *buffer, int maxlen) { if ((process == NULL) || (buffer == NULL)) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return DLT_RETURN_WRONG_PARAMETER; } 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); return DLT_RETURN_OK; } DltReturnValue dlt_kpi_get_msg_process_new(DltKpiProcess *process, char *buffer, int maxlen) { if ((process == NULL) || (buffer == NULL)) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return DLT_RETURN_WRONG_PARAMETER; } snprintf(buffer, maxlen, "%d;%d;%s", process->pid, process->ppid, process->command_line); return DLT_RETURN_OK; } DltReturnValue dlt_kpi_get_msg_process_stop(DltKpiProcess *process, char *buffer, int maxlen) { if ((process == NULL) || (buffer == NULL)) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return DLT_RETURN_WRONG_PARAMETER; } snprintf(buffer, maxlen, "%d", process->pid); return DLT_RETURN_OK; } DltReturnValue dlt_kpi_get_msg_process_commandline(DltKpiProcess *process, char *buffer, int maxlen) { if ((process == NULL) || (buffer == NULL)) { fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__); return DLT_RETURN_WRONG_PARAMETER; } snprintf(buffer, maxlen, "%d;%s", process->pid, process->command_line); return DLT_RETURN_OK; }