1/*
2 KSysGuard, the KDE System Guard
3
4 Copyright (c) 2000-2001 Chris Schlaeger <cs@kde.org>
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of version 2 of the GNU General Public
8 License as published by the Free Software Foundation.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
19*/
20
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <fcntl.h>
24#include <unistd.h>
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <ctype.h>
29#include <time.h>
30
31#include "Command.h"
32#include "ksysguardd.h"
33
34#include "cpuinfo.h"
35
36static int CpuInfoOK = 0;
37static int numProcessors = 0; /* Total number of physical processors */
38static int HighNumProcessors = 0; /* Highest # number of physical processors ever seen */
39static int numCores = 0; /* Total # of cores */
40static int HighNumCores = 0; /* Highest # of cores ever seen */
41static float* Clocks = 0; /* Array with one entry per core */
42
43#define CPUINFOBUFSIZE (32 * 1024)
44static char CpuInfoBuf[ CPUINFOBUFSIZE ];
45static int Dirty = 0;
46static struct SensorModul *CpuInfoSM;
47
48static void processCpuInfo( void )
49{
50 char format[ 32 ];
51 char tag[ 32 ];
52 char value[ 256 ];
53 char* cibp = CpuInfoBuf;
54
55 /* coreUniqueId is not per processor; it is a counter of the number of cores encountered
56 * by the parse thus far */
57 int coreUniqueId = 0;
58
59 /* Reset global variables */
60 numCores = 0;
61 numProcessors = 0;
62
63 if ( !CpuInfoOK )
64 return;
65
66 sprintf( format, "%%%d[^:]: %%%d[^\n]\n", (int)sizeof( tag ) - 1,
67 (int)sizeof( value ) - 1 );
68
69 while ( sscanf( cibp, format, tag, value ) == 2 ) {
70 char* p;
71
72 tag[ sizeof( tag ) - 1 ] = '\0';
73 value[ sizeof( value ) - 1 ] = '\0';
74
75 /* remove trailing whitespaces */
76 p = tag + strlen( tag ) - 1;
77 /* remove trailing whitespaces */
78 while ( ( *p == ' ' || *p == '\t' ) && p > tag )
79 *p-- = '\0';
80
81 if ( strcmp( tag, "processor" ) == 0 ) {
82 if ( sscanf( value, "%d", &coreUniqueId ) == 1 ) {
83 if ( coreUniqueId >= HighNumCores ) {
84 /* Found a new processor core. Maybe even a new processor. (We'll check later) */
85 char cmdName[ 24 ];
86
87 /* Each core has a clock speed. Allocate one per core found. */
88 Clocks = (float*) realloc( Clocks, (coreUniqueId+1) * sizeof( float ) );
89 memset(Clocks + HighNumCores, 0, (coreUniqueId +1 - HighNumCores) * sizeof( float ));
90
91 HighNumCores = coreUniqueId + 1;
92
93 snprintf( cmdName, sizeof( cmdName ) - 1, "cpu/cpu%d/clock", coreUniqueId );
94 registerMonitor( cmdName, "float", printCPUxClock, printCPUxClockInfo,
95 CpuInfoSM );
96 }
97 }
98 } else if ( strcmp( tag, "cpu MHz" ) == 0 ) {
99 if (HighNumCores > coreUniqueId) {
100 /* The if statement above *should* always be true, but there's no harm in being safe. */
101 sscanf( value, "%f", &Clocks[ coreUniqueId ] );
102 }
103 } else if ( strcmp( tag, "core id" ) == 0 ) {
104 /* the core id is per processor */
105 int curCore;
106
107 if ( (sscanf( value, "%d", &curCore ) == 1) && curCore == 0 ) {
108 /* core id is back at 0. We just found a new processor. */
109 numProcessors++;
110
111 if (numProcessors > HighNumProcessors)
112 HighNumProcessors = numProcessors;
113 }
114 }
115 /* Move cibp to beginning of next line, if there is one. */
116 cibp = strchr( cibp, '\n' );
117 if ( cibp )
118 cibp++;
119 else
120 cibp = CpuInfoBuf + strlen( CpuInfoBuf );
121 }
122
123 numCores = coreUniqueId + 1;
124
125 Dirty = 0;
126}
127
128/*
129================================ public part =================================
130*/
131
132void initCpuInfo( struct SensorModul* sm )
133{
134 CpuInfoSM = sm;
135
136 if ( updateCpuInfo() < 0 )
137 return;
138
139 registerMonitor( "system/processors", "integer", printNumCpus, printNumCpusInfo,
140 CpuInfoSM );
141 registerMonitor( "system/cores", "integer", printNumCores, printNumCoresInfo,
142 CpuInfoSM );
143
144 processCpuInfo();
145
146 registerMonitor( "cpu/system/AverageClock", "float", printCPUClock, printCPUClockInfo,
147 CpuInfoSM );
148}
149
150void exitCpuInfo( void )
151{
152 CpuInfoOK = -1;
153
154 free( Clocks );
155}
156
157int updateCpuInfo( void )
158{
159 size_t n;
160 int fd;
161
162 if ( CpuInfoOK < 0 )
163 return -1;
164
165 if ( ( fd = open( "/proc/cpuinfo", O_RDONLY ) ) < 0 ) {
166 if ( CpuInfoOK != 0 )
167 print_error( "Cannot open file \'/proc/cpuinfo\'!\n"
168 "The kernel needs to be compiled with support\n"
169 "for /proc file system enabled!\n" );
170 CpuInfoOK = -1;
171 return -1;
172 }
173
174 n = 0;
175 for(;;) {
176 ssize_t len = read( fd, CpuInfoBuf + n, CPUINFOBUFSIZE - 1 - n );
177 if( len < 0 ) {
178 print_error( "Failed to read file \'/proc/cpuinfo\'!\n" );
179 CpuInfoOK = -1;
180 close( fd );
181 return -1;
182 }
183 n += len;
184 if( len == 0 ) /* reading finished */
185 break;
186 if( n == CPUINFOBUFSIZE - 1 ) {
187 log_error( "Internal buffer too small to read \'/proc/cpuinfo\'" );
188 CpuInfoOK = 0;
189 close( fd );
190 return -1;
191 }
192 }
193
194 close( fd );
195 CpuInfoOK = 1;
196 CpuInfoBuf[ n ] = '\0';
197 Dirty = 1;
198
199 return 0;
200}
201
202void printCPUxClock( const char* cmd )
203{
204 int id;
205
206 if ( Dirty )
207 processCpuInfo();
208
209 sscanf( cmd + 7, "%d", &id );
210 output( "%f\n", Clocks[ id ] );
211}
212
213void printCPUClock( const char* cmd )
214{
215 int id;
216 float clock = 0;
217 cmd = cmd; /*Silence warning*/
218
219 if ( Dirty ) {
220 processCpuInfo();
221 }
222
223 for ( id = 0; id < HighNumCores; id++ ) {
224 clock += Clocks[ id ];
225 }
226 clock /= HighNumCores;
227 output( "%f\n", clock );
228}
229
230void printCPUxClockInfo( const char* cmd )
231{
232 int id;
233
234 sscanf( cmd + 7, "%d", &id );
235 output( "CPU%d Clock Frequency\t0\t0\tMHz\n", id );
236}
237
238void printCPUClockInfo( const char* cmd )
239{
240 cmd = cmd; /*Silence warning*/
241 output( "CPU Clock Frequency\t0\t0\tMHz\n" );
242}
243
244void printNumCpus( const char* cmd )
245{
246 (void) cmd;
247
248 if ( Dirty )
249 processCpuInfo();
250
251 output( "%d\n", numProcessors );
252}
253
254void printNumCpusInfo( const char* cmd )
255{
256 (void) cmd;
257
258 output( "Number of physical CPUs\t0\t0\t\n" );
259}
260
261void printNumCores( const char* cmd )
262{
263 (void) cmd;
264
265 if ( Dirty )
266 processCpuInfo();
267
268 output( "%d\n", numCores );
269}
270
271void printNumCoresInfo( const char* cmd )
272{
273 (void) cmd;
274
275 output( "Total number of processor cores\t0\t0\t\n" );
276}
277