/* * Unix SMB/CIFS implementation. * Performance Counter Daemon * * Copyright (C) Marcin Krzysztof Porwit 2005 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "perf.h" void init_cpudata_desc(PERF_DATA_BLOCK *data) { init_perf_counter(&(data->cpuInfo.cpuObjDesc), &(data->cpuInfo.cpuObjDesc), get_counter_id(data), "Processor", "The Processor object consists of counters that describe the behavior of the CPU.", 0, PERF_OBJECT); init_perf_counter(&(data->cpuInfo.userCPU), &(data->cpuInfo.cpuObjDesc), get_counter_id(data), "\% User CPU Utilization", "\% User CPU Utilization is the percentage of the CPU used by processes executing user code.", PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT, PERF_COUNTER); init_perf_counter(&(data->cpuInfo.systemCPU), &(data->cpuInfo.cpuObjDesc), get_counter_id(data), "\% System CPU Utilization", "\% System CPU Utilization is the percentage of the CPU used by processes doing system calls.", PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT, PERF_COUNTER); init_perf_counter(&(data->cpuInfo.niceCPU), &(data->cpuInfo.cpuObjDesc), get_counter_id(data), "\% Nice CPU Utilization", "\% Nice CPU Utilization is the percentage of the CPU used by processes running in nice mode.", PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_NOSHOW, PERF_COUNTER); init_perf_counter(&(data->cpuInfo.idleCPU), &(data->cpuInfo.cpuObjDesc), get_counter_id(data), "\% Idle CPU", "\% Idle CPU is the percentage of the CPU not doing any work.", PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_NOSHOW, PERF_COUNTER); return; } void get_cpuinfo(PERF_DATA_BLOCK *data) { int num, i; unsigned int cpuid; char buf[PROC_BUF]; static FILE *fp = NULL; if(!fp) { if(!(fp = fopen("/proc/stat", "r"))) { perror("get_cpuinfo: fopen"); exit(1); } } rewind(fp); fflush(fp); /* Read in the first line and discard it -- that has the CPU summary */ if(!fgets(buf, sizeof(buf), fp)) { perror("get_cpuinfo: fgets"); exit(1); } for(i = 0; i < data->cpuInfo.numCPUs; i++) { if(!fgets(buf, sizeof(buf), fp)) { perror("get_cpuinfo: fgets"); exit(1); } num = sscanf(buf, "cpu%u %Lu %Lu %Lu %Lu", &cpuid, &data->cpuInfo.data[i].user, &data->cpuInfo.data[i].nice, &data->cpuInfo.data[i].system, &data->cpuInfo.data[i].idle); if(i != cpuid) { perror("get_cpuinfo: /proc/stat inconsistent?"); exit(1); } /* Alternate way of doing things: struct tms buffer; data->PerfTime100nSec = times(&buffer); */ data->PerfTime100nSec += data->cpuInfo.data[i].user + data->cpuInfo.data[i].nice + data->cpuInfo.data[i].system + data->cpuInfo.data[i].idle; } data->PerfTime100nSec /= data->cpuInfo.numCPUs; return; } void init_cpu_data(PERF_DATA_BLOCK *data) { data->cpuInfo.data = calloc(data->cpuInfo.numCPUs, sizeof(*data->cpuInfo.data)); if(!data->cpuInfo.data) { perror("init_cpu_data: out of memory"); exit(1); } init_cpudata_desc(data); get_cpuinfo(data); return; } void output_cpu_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt) { output_perf_desc(data->cpuInfo.cpuObjDesc, rt); output_perf_desc(data->cpuInfo.userCPU, rt); output_perf_desc(data->cpuInfo.niceCPU, rt); output_perf_desc(data->cpuInfo.systemCPU, rt); output_perf_desc(data->cpuInfo.idleCPU, rt); if(data->cpuInfo.numCPUs > 1) output_num_instances(data->cpuInfo.cpuObjDesc, data->cpuInfo.numCPUs + 1, rt); return; } void output_cpuinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags) { int i; char buf[NAME_LEN]; output_perf_counter(data->cpuInfo.userCPU, data->cpuInfo.data[0].user, rt, tdb_flags); output_perf_counter(data->cpuInfo.systemCPU, data->cpuInfo.data[0].system, rt, tdb_flags); output_perf_counter(data->cpuInfo.niceCPU, data->cpuInfo.data[0].nice, rt, tdb_flags); output_perf_counter(data->cpuInfo.idleCPU, data->cpuInfo.data[0].idle, rt, tdb_flags); if(data->cpuInfo.numCPUs > 1) { for(i = 0; i < data->cpuInfo.numCPUs; i++) { memset(buf, 0, NAME_LEN); sprintf(buf, "cpu%d", i); output_perf_instance(data->cpuInfo.cpuObjDesc.index, i, (void *)&(data->cpuInfo.data[i]), sizeof(data->cpuInfo.data[i]), buf, rt, tdb_flags); } memset(buf, 0, NAME_LEN); sprintf(buf, "_Total"); output_perf_instance(data->cpuInfo.cpuObjDesc.index, i, (void *)&(data->cpuInfo.data[i]), sizeof(data->cpuInfo.data[i]), buf, rt, tdb_flags); } return; }