1/*
2 *  Unix SMB/CIFS implementation.
3 *  Performance Counter Daemon
4 *
5 *  Copyright (C) Marcin Krzysztof Porwit    2005
6 *
7 *  This program is free software; you can redistribute it and/or modify
8 *  it under the terms of the GNU General Public License as published by
9 *  the Free Software Foundation; either version 2 of the License, or
10 *  (at your option) any later version.
11 *
12 *  This program is distributed in the hope that it will be useful,
13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *  GNU General Public License for more details.
16 *
17 *  You should have received a copy of the GNU General Public License
18 *  along with this program; if not, write to the Free Software
19 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include "perf.h"
23
24void init_cpudata_desc(PERF_DATA_BLOCK *data)
25{
26    init_perf_counter(&(data->cpuInfo.cpuObjDesc),
27		      &(data->cpuInfo.cpuObjDesc),
28		      get_counter_id(data),
29		      "Processor",
30		      "The Processor object consists of counters that describe the behavior of the CPU.",
31		      0,
32		      PERF_OBJECT);
33    init_perf_counter(&(data->cpuInfo.userCPU),
34		      &(data->cpuInfo.cpuObjDesc),
35		      get_counter_id(data),
36		      "\% User CPU Utilization",
37		      "\% User CPU Utilization is the percentage of the CPU used by  processes executing user code.",
38		      PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT,
39		      PERF_COUNTER);
40    init_perf_counter(&(data->cpuInfo.systemCPU),
41		      &(data->cpuInfo.cpuObjDesc),
42		      get_counter_id(data),
43		      "\% System CPU Utilization",
44		      "\% System CPU Utilization is the percentage of the CPU used by processes doing system calls.",
45		      PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT,
46		      PERF_COUNTER);
47    init_perf_counter(&(data->cpuInfo.niceCPU),
48		      &(data->cpuInfo.cpuObjDesc),
49		      get_counter_id(data),
50		      "\% Nice CPU Utilization",
51		      "\% Nice CPU Utilization is the percentage of the CPU used by processes running in nice mode.",
52		      PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_NOSHOW,
53		      PERF_COUNTER);
54    init_perf_counter(&(data->cpuInfo.idleCPU),
55		      &(data->cpuInfo.cpuObjDesc),
56		      get_counter_id(data),
57		      "\% Idle CPU",
58		      "\% Idle CPU is the percentage of the CPU not doing any work.",
59		      PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_NOSHOW,
60		      PERF_COUNTER);
61
62    return;
63}
64
65void get_cpuinfo(PERF_DATA_BLOCK *data)
66{
67    int num, i;
68    unsigned int cpuid;
69    char buf[PROC_BUF];
70    static FILE *fp = NULL;
71
72    if(!fp)
73    {
74	if(!(fp = fopen("/proc/stat", "r")))
75	{
76	    perror("get_cpuinfo: fopen");
77	    exit(1);
78	}
79    }
80
81    rewind(fp);
82    fflush(fp);
83
84    /* Read in the first line and discard it -- that has the CPU summary */
85    if(!fgets(buf, sizeof(buf), fp))
86    {
87	perror("get_cpuinfo: fgets");
88	exit(1);
89    }
90    for(i = 0; i < data->cpuInfo.numCPUs; i++)
91    {
92	if(!fgets(buf, sizeof(buf), fp))
93	{
94	    perror("get_cpuinfo: fgets");
95	    exit(1);
96	}
97	num = sscanf(buf, "cpu%u %Lu %Lu %Lu %Lu",
98		     &cpuid,
99		     &data->cpuInfo.data[i].user,
100		     &data->cpuInfo.data[i].nice,
101		     &data->cpuInfo.data[i].system,
102		     &data->cpuInfo.data[i].idle);
103	if(i != cpuid)
104	{
105	    perror("get_cpuinfo: /proc/stat inconsistent?");
106	    exit(1);
107	}
108	/*
109	  Alternate way of doing things:
110	  struct tms buffer;
111	  data->PerfTime100nSec = times(&buffer);
112	*/
113	data->PerfTime100nSec += data->cpuInfo.data[i].user +
114	    data->cpuInfo.data[i].nice +
115	    data->cpuInfo.data[i].system +
116	    data->cpuInfo.data[i].idle;
117    }
118    data->PerfTime100nSec /= data->cpuInfo.numCPUs;
119    return;
120}
121
122void init_cpu_data(PERF_DATA_BLOCK *data)
123{
124    data->cpuInfo.data = calloc(data->cpuInfo.numCPUs, sizeof(*data->cpuInfo.data));
125    if(!data->cpuInfo.data)
126    {
127	perror("init_cpu_data: out of memory");
128	exit(1);
129    }
130
131    init_cpudata_desc(data);
132
133    get_cpuinfo(data);
134
135    return;
136}
137
138void output_cpu_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt)
139{
140    output_perf_desc(data->cpuInfo.cpuObjDesc, rt);
141    output_perf_desc(data->cpuInfo.userCPU, rt);
142    output_perf_desc(data->cpuInfo.niceCPU, rt);
143    output_perf_desc(data->cpuInfo.systemCPU, rt);
144    output_perf_desc(data->cpuInfo.idleCPU, rt);
145    if(data->cpuInfo.numCPUs > 1)
146	    output_num_instances(data->cpuInfo.cpuObjDesc, data->cpuInfo.numCPUs + 1, rt);
147
148    return;
149}
150
151void output_cpuinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
152{
153    int i;
154    char buf[NAME_LEN];
155
156    output_perf_counter(data->cpuInfo.userCPU,
157			data->cpuInfo.data[0].user,
158			rt, tdb_flags);
159    output_perf_counter(data->cpuInfo.systemCPU,
160			data->cpuInfo.data[0].system,
161			rt, tdb_flags);
162    output_perf_counter(data->cpuInfo.niceCPU,
163			data->cpuInfo.data[0].nice,
164			rt, tdb_flags);
165    output_perf_counter(data->cpuInfo.idleCPU,
166			data->cpuInfo.data[0].idle,
167			rt, tdb_flags);
168    if(data->cpuInfo.numCPUs > 1)
169      {
170	      for(i = 0; i < data->cpuInfo.numCPUs; i++)
171	      {
172		      memset(buf, 0, NAME_LEN);
173		      sprintf(buf, "cpu%d", i);
174		      output_perf_instance(data->cpuInfo.cpuObjDesc.index,
175					   i,
176					   (void *)&(data->cpuInfo.data[i]),
177					   sizeof(data->cpuInfo.data[i]),
178					   buf, rt, tdb_flags);
179	      }
180
181	      memset(buf, 0, NAME_LEN);
182	      sprintf(buf, "_Total");
183	      output_perf_instance(data->cpuInfo.cpuObjDesc.index,
184				   i,
185				   (void *)&(data->cpuInfo.data[i]),
186				   sizeof(data->cpuInfo.data[i]),
187				   buf, rt, tdb_flags);
188      }
189    return;
190}
191