Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

sfprocpidstats.c

Go to the documentation of this file.
00001 /*
00002 ** $Id$
00003 **
00004 **  sfprocpidstats.c
00005 **
00006 ** Copyright (C) 2002 Sourcefire,Inc
00007 ** Dan Roelker <droelker@sourcefire.com>
00008 **
00009 ** This program is free software; you can redistribute it and/or modify
00010 ** it under the terms of the GNU General Public License as published by
00011 ** the Free Software Foundation; either version 2 of the License, or
00012 ** (at your option) any later version.
00013 **
00014 ** This program is distributed in the hope that it will be useful,
00015 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 ** GNU General Public License for more details.
00018 **
00019 ** You should have received a copy of the GNU General Public License
00020 ** along with this program; if not, write to the Free Software
00021 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00022 **
00023 **
00024 **  DESCRIPTION
00025 **    This file gets the correct CPU usage for SMP linux machines.
00026 **
00027 */
00028 #include "sfprocpidstats.h"
00029 
00030 #ifdef LINUX_SMP
00031 
00032 #include <stdlib.h>
00033 #include <stdio.h>
00034 #include <linux/param.h>
00035 #include <sys/types.h>
00036 #include <string.h>
00037 #include <math.h>
00038 
00039 #include "util.h"
00040 
00041 #define PROC_STAT       "/proc/stat"
00042 #define PROC_SELF_CPU   "/proc/self/cpu"
00043 #define PROC_SELF_STAT  "/proc/self/stat"
00044 
00045 typedef struct _USERSYS {
00046     u_long user;
00047     u_long sys;
00048     u_long idle;
00049 } USERSYS;
00050 
00051 static int giCPUs = 1;
00052 
00053 static USERSYS *gpStatCPUs = NULL;
00054 static USERSYS *gpStatCPUs_2 = NULL;
00055 
00056 static FILE *proc_stat;
00057 
00058 static int GetProcStatCpu(USERSYS *pStatCPUs, int iCPUs)
00059 {
00060     int iRet;
00061     int iCtr;
00062     u_long ulUser;
00063     u_long ulNice;
00064     u_long ulSys;
00065     u_long ulIdle;
00066     char buf[256];
00067 
00068     rewind(proc_stat);
00069 
00070     /*
00071     **  Read the total CPU usage, don't use right now.
00072     **
00073     **  But we do want to read it if there is only one CPU.
00074     */
00075     if(iCPUs != 1)
00076     {
00077         if(!fgets(buf, sizeof(buf), proc_stat))
00078             return -1;
00079     }
00080 
00081     /*
00082     **  Read the individual CPU usages.  This tells us where
00083     **  sniffing and snorting is occurring.
00084     */
00085     for(iCtr = 0; iCtr < iCPUs; iCtr++)
00086     {
00087         if(!fgets(buf, sizeof(buf), proc_stat))
00088             return -1;
00089 
00090         iRet = sscanf(buf, "%*s %lu %lu %lu %lu",
00091                       &ulUser, &ulNice, &ulSys, &ulIdle);
00092 
00093         if(iRet == EOF || iRet < 4)
00094             return -1;
00095 
00096         pStatCPUs[iCtr].user = ulUser + ulNice;
00097         pStatCPUs[iCtr].sys  = ulSys;
00098         pStatCPUs[iCtr].idle = ulIdle;
00099     }
00100 
00101     return 0;
00102 }
00103 
00104 static int GetCpuNum()
00105 {
00106     int iRet;
00107     int iCPUs = 0;
00108     char acCpuName[10+1];
00109     char buf[256];
00110 
00111     rewind(proc_stat);
00112 
00113     while(1)
00114     {
00115         if(!fgets(buf, sizeof(buf), proc_stat))
00116             return 0;
00117 
00118         iRet = sscanf(buf, "%10s %*u %*u %*u %*u", acCpuName);
00119         if(iRet < 1 || iRet == EOF)
00120         {
00121             return 0;
00122         }
00123 
00124         acCpuName[sizeof(acCpuName)-1] = 0x00;
00125             
00126         if(strncmp(acCpuName, "cpu", 3))
00127         {
00128             break;
00129         }
00130 
00131         iCPUs++;
00132     }
00133 
00134     /*
00135     **  If there are more then one CPU, then we subtract one because
00136     **  the first CPU entry combines all CPUs.  This should be
00137     **  backward compatible with 2.2 not compiled with SMP support.
00138     */
00139     if(iCPUs > 1)
00140         iCPUs--;
00141 
00142     return iCPUs;
00143 }
00144 
00145 int sfInitProcPidStats(SFPROCPIDSTATS *sfProcPidStats)
00146 {
00147     proc_stat = fopen(PROC_STAT, "r");
00148     if(!proc_stat)
00149     {
00150         FatalError("PERFMONITOR ERROR: Can't open %s.", PROC_STAT);
00151     }
00152 
00153     giCPUs = GetCpuNum();
00154     if(giCPUs <= 0)
00155     {
00156         FatalError("PERFMONITOR ERROR: Error reading CPUs from %s.",
00157                    PROC_STAT);
00158     }
00159 
00160     gpStatCPUs   = (USERSYS *)calloc(giCPUs, sizeof(USERSYS));
00161     if(!gpStatCPUs)
00162         FatalError("PERFMONITOR ERROR: Error allocating CPU mem.");
00163 
00164     gpStatCPUs_2 = (USERSYS *)calloc(giCPUs, sizeof(USERSYS));
00165     if(!gpStatCPUs_2)
00166         FatalError("PERFMONITOR ERROR: Error allocating CPU mem.");
00167 
00168     /*
00169     **  Allocate for sfProcPidStats CPUs
00170     */
00171     sfProcPidStats->SysCPUs = (CPUSTAT *)calloc(giCPUs, sizeof(CPUSTAT));
00172     if(!sfProcPidStats->SysCPUs)
00173         FatalError("PERFMONITOR ERROR: Error allocating SysCPU mem.");
00174 
00175     sfProcPidStats->iCPUs = giCPUs;
00176 
00177     if(GetProcStatCpu(gpStatCPUs, giCPUs))
00178         FatalError("PERFMONITOR ERROR: Error while reading '%s'.",
00179                 PROC_STAT);
00180 
00181     fclose(proc_stat);
00182 
00183     return 0;
00184 }
00185 
00186 int sfProcessProcPidStats(SFPROCPIDSTATS *sfProcPidStats)
00187 {
00188     static int iError = 0;
00189     int iCtr;
00190     u_long ulCPUjiffies;
00191 
00192     proc_stat = fopen(PROC_STAT, "r");
00193     if(!proc_stat)
00194     {
00195         if(!iError)
00196         {
00197             ErrorMessage("PERFMONITOR ERROR: Cannot open %s.", PROC_STAT);
00198             iError = 1;
00199         }
00200 
00201         return -1;
00202     }
00203 
00204     if(GetProcStatCpu(gpStatCPUs_2, giCPUs))
00205     {
00206         if(!iError)
00207         {
00208             ErrorMessage("PERFMONITOR ERROR: Error while reading '%s'.",
00209                     PROC_STAT);
00210             iError = 1;
00211         }
00212 
00213         return -1;
00214     }
00215 
00216     fclose(proc_stat);
00217 
00218     /*
00219     **  SysCPUs (The system's CPU usage, like top gives you)
00220     */
00221     for(iCtr = 0; iCtr < giCPUs; iCtr++)
00222     {
00223         ulCPUjiffies = (gpStatCPUs_2[iCtr].user - gpStatCPUs[iCtr].user) +
00224                        (gpStatCPUs_2[iCtr].sys - gpStatCPUs[iCtr].sys) +
00225                        (gpStatCPUs_2[iCtr].idle - gpStatCPUs[iCtr].idle);
00226 
00227         if(gpStatCPUs_2[iCtr].user > gpStatCPUs[iCtr].user)
00228         {
00229             sfProcPidStats->SysCPUs[iCtr].user = (((double)(gpStatCPUs_2[iCtr].user - 
00230                                                  gpStatCPUs[iCtr].user)) /
00231                                                  ulCPUjiffies) * 100.0;
00232             if(sfProcPidStats->SysCPUs[iCtr].user < .01)
00233             {
00234                 sfProcPidStats->SysCPUs[iCtr].user = 0;
00235             }
00236         }
00237         else
00238         {
00239             sfProcPidStats->SysCPUs[iCtr].user = 0;
00240         }
00241 
00242         if(gpStatCPUs_2[iCtr].sys > gpStatCPUs[iCtr].sys)
00243         {
00244             sfProcPidStats->SysCPUs[iCtr].sys = (((double)(gpStatCPUs_2[iCtr].sys - 
00245                                                 gpStatCPUs[iCtr].sys)) /
00246                                                 ulCPUjiffies) * 100.0;
00247             if(sfProcPidStats->SysCPUs[iCtr].sys < .01)
00248             {
00249                 sfProcPidStats->SysCPUs[iCtr].sys = 0;
00250             }
00251         }
00252         else
00253         {
00254             sfProcPidStats->SysCPUs[iCtr].sys = 0;
00255         }
00256 
00257         if(gpStatCPUs_2[iCtr].idle > gpStatCPUs[iCtr].idle)
00258         {
00259             sfProcPidStats->SysCPUs[iCtr].idle = (((double)(gpStatCPUs_2[iCtr].idle - 
00260                                                  gpStatCPUs[iCtr].idle)) /
00261                                                  ulCPUjiffies) * 100.0;
00262             if(sfProcPidStats->SysCPUs[iCtr].idle < .01)
00263             {
00264                 sfProcPidStats->SysCPUs[iCtr].idle = 0;
00265             }
00266         }
00267         else
00268         {
00269             sfProcPidStats->SysCPUs[iCtr].idle = 0;
00270         }
00271 
00272         /*
00273         **  Set statistics for next processing.
00274         */
00275         gpStatCPUs[iCtr].user  = gpStatCPUs_2[iCtr].user;
00276         gpStatCPUs[iCtr].sys   = gpStatCPUs_2[iCtr].sys;
00277         gpStatCPUs[iCtr].idle  = gpStatCPUs_2[iCtr].idle;
00278     }
00279 
00280     return 0;
00281 }
00282 
00283 #endif
00284 

Generated on Sun May 14 14:51:15 2006 by  doxygen 1.4.2