"Fossies" - the Fresh Open Source Software Archive

Member "procmeter3-3.6+svn387/modules/stat-cpu.c" (24 Dec 2010, 18223 Bytes) of package /linux/misc/procmeter3-3.6+svn387.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "stat-cpu.c" see the Fossies "Dox" file reference documentation.

    1 /***************************************
    2   $Header: /home/amb/CVS/procmeter3/modules/stat-cpu.c,v 1.13 2008-05-05 18:45:36 amb Exp $
    3 
    4   ProcMeter - A system monitoring program for Linux - Version 3.5b.
    5 
    6   Low level system statistics for CPU usage.
    7   ******************/ /******************
    8   Written by Andrew M. Bishop
    9 
   10   This file Copyright 1998-2008 Andrew M. Bishop
   11   It may be distributed under the GNU Public License, version 2, or
   12   any higher version.  See section COPYING of the GNU Public license
   13   for conditions under which this file may be redistributed.
   14   ***************************************/
   15 
   16 
   17 #include <stdio.h>
   18 #include <stdlib.h>
   19 #include <string.h>
   20 
   21 #include "procmeter.h"
   22 
   23 #define CPU         0
   24 #define CPU_USER    1
   25 #define CPU_NICE    2
   26 #define CPU_SYS     3
   27 #define CPU_IDLE    4
   28 #define CPU_IOWAIT  5
   29 #define CPU_IRQ     6
   30 #define CPU_SOFTIRQ 7
   31 #define CPU_STEAL   8
   32 
   33 #define N_OUTPUTS_24 5
   34 #define N_OUTPUTS_26 9
   35 
   36 /* The interface information.  */
   37 
   38 /*+ The normal outputs +*/
   39 ProcMeterOutput _outputs[N_OUTPUTS_26]=
   40 {
   41  /*+ The total cpu output +*/
   42  {
   43   /* char  name[];          */ "CPU",
   44   /* char *description;     */ "The total fraction of the time that the CPU is busy.",
   45   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
   46   /* short interval;        */ 1,
   47   /* char  text_value[];    */ "0 %",
   48   /* long  graph_value;     */ 0,
   49   /* short graph_scale;     */ 20,
   50   /* char  graph_units[];   */ "(%d%%)"
   51  },
   52  /*+ The user cpu output +*/
   53  {
   54   /* char  name[];          */ "CPU_User",
   55   /* char *description;     */ "The fraction of the time that the CPU is processing user level code (applications).",
   56   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
   57   /* short interval;        */ 1,
   58   /* char  text_value[];    */ "0 %",
   59   /* long  graph_value;     */ 0,
   60   /* short graph_scale;     */ 20,
   61   /* char  graph_units[];   */ "(%d%%)"
   62  },
   63  /*+ The nice cpu output +*/
   64  {
   65   /* char  name[];          */ "CPU_Nice",
   66   /* char *description;     */ "The fraction of the time that the CPU is running processes that run at a lowered priority.",
   67   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
   68   /* short interval;        */ 1,
   69   /* char  text_value[];    */ "0 %",
   70   /* long  graph_value;     */ 0,
   71   /* short graph_scale;     */ 20,
   72   /* char  graph_units[];   */ "(%d%%)"
   73  },
   74  /*+ The system cpu output +*/
   75  {
   76   /* char  name[];          */ "CPU_System",
   77   /* char *description;     */ "The fraction of the time that the CPU is processing system level code (kernel).",
   78   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
   79   /* short interval;        */ 1,
   80   /* char  text_value[];    */ "0 %",
   81   /* long  graph_value;     */ 0,
   82   /* short graph_scale;     */ 20,
   83   /* char  graph_units[];   */ "(%d%%)"
   84  },
   85  /*+ The idle cpu output +*/
   86  {
   87   /* char  name[];          */ "CPU_Idle",
   88   /* char *description;     */ "The fraction of the time that the CPU is idle.",
   89   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
   90   /* short interval;        */ 1,
   91   /* char  text_value[];    */ "0 %",
   92   /* long  graph_value;     */ 0,
   93   /* short graph_scale;     */ 20,
   94   /* char  graph_units[];   */ "(%d%%)"
   95  },
   96  /*+ The iowait cpu output +*/
   97  {
   98   /* char  name[];          */ "CPU_IOWait",
   99   /* char *description;     */ "The fraction of the time that the CPU is waiting for IO.",
  100   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  101   /* short interval;        */ 1,
  102   /* char  text_value[];    */ "0 %",
  103   /* long  graph_value;     */ 0,
  104   /* short graph_scale;     */ 20,
  105   /* char  graph_units[];   */ "(%d%%)"
  106  },
  107  /*+ The irq cpu output +*/
  108  {
  109   /* char  name[];          */ "CPU_IRQ",
  110   /* char *description;     */ "The fraction of the time that the CPU is waiting for IRQs.",
  111   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  112   /* short interval;        */ 1,
  113   /* char  text_value[];    */ "0 %",
  114   /* long  graph_value;     */ 0,
  115   /* short graph_scale;     */ 20,
  116   /* char  graph_units[];   */ "(%d%%)"
  117  },
  118  /*+ The softirq cpu output +*/
  119  {
  120   /* char  name[];          */ "CPU_SoftIRQ",
  121   /* char *description;     */ "The fraction of the time that the CPU is ???.",
  122   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  123   /* short interval;        */ 1,
  124   /* char  text_value[];    */ "0 %",
  125   /* long  graph_value;     */ 0,
  126   /* short graph_scale;     */ 20,
  127   /* char  graph_units[];   */ "(%d%%)"
  128  },
  129  /*+ The steal cpu output +*/
  130  {
  131   /* char  name[];          */ "CPU_Steal",
  132   /* char *description;     */ "The fraction of the time that the CPU is ???.",
  133   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  134   /* short interval;        */ 1,
  135   /* char  text_value[];    */ "0 %",
  136   /* long  graph_value;     */ 0,
  137   /* short graph_scale;     */ 20,
  138   /* char  graph_units[];   */ "(%d%%)"
  139  }
  140 };
  141 
  142 /*+ The outputs with multiple CPUs +*/
  143 ProcMeterOutput _smp_outputs[N_OUTPUTS_26]=
  144 {
  145  /*+ The total cpu output +*/
  146  {
  147   /* char  name[];          */ "CPU%d",
  148   /* char *description;     */ "The total fraction of the time that the CPU number %d is busy.",
  149   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  150   /* short interval;        */ 1,
  151   /* char  text_value[];    */ "0 %",
  152   /* long  graph_value;     */ 0,
  153   /* short graph_scale;     */ 20,
  154   /* char  graph_units[];   */ "(%d%%)"
  155  },
  156  /*+ The user cpu output +*/
  157  {
  158   /* char  name[];          */ "CPU%d_User",
  159   /* char *description;     */ "The fraction of the time that the CPU number %d is processing user level code (applications).",
  160   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  161   /* short interval;        */ 1,
  162   /* char  text_value[];    */ "0 %",
  163   /* long  graph_value;     */ 0,
  164   /* short graph_scale;     */ 20,
  165   /* char  graph_units[];   */ "(%d%%)"
  166  },
  167  /*+ The nice cpu output +*/
  168  {
  169   /* char  name[];          */ "CPU%d_Nice",
  170   /* char *description;     */ "The fraction of the time that the CPU number %d is running processes that run at a lowered priority.",
  171   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  172   /* short interval;        */ 1,
  173   /* char  text_value[];    */ "0 %",
  174   /* long  graph_value;     */ 0,
  175   /* short graph_scale;     */ 20,
  176   /* char  graph_units[];   */ "(%d%%)"
  177  },
  178  /*+ The system cpu output +*/
  179  {
  180   /* char  name[];          */ "CPU%d_System",
  181   /* char *description;     */ "The fraction of the time that the CPU number %d is processing system level code (kernel).",
  182   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  183   /* short interval;        */ 1,
  184   /* char  text_value[];    */ "0 %",
  185   /* long  graph_value;     */ 0,
  186   /* short graph_scale;     */ 20,
  187   /* char  graph_units[];   */ "(%d%%)"
  188  },
  189  /*+ The idle cpu output +*/
  190  {
  191   /* char  name[];          */ "CPU%d_Idle",
  192   /* char *description;     */ "The fraction of the time that the CPU number %d is idle.",
  193   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  194   /* short interval;        */ 1,
  195   /* char  text_value[];    */ "0 %",
  196   /* long  graph_value;     */ 0,
  197   /* short graph_scale;     */ 20,
  198   /* char  graph_units[];   */ "(%d%%)"
  199  },
  200  /*+ The iowait cpu output +*/
  201  {
  202   /* char  name[];          */ "CPU%d_IOWait",
  203   /* char *description;     */ "The fraction of the time that the CPU number %d is waiting for IO.",
  204   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  205   /* short interval;        */ 1,
  206   /* char  text_value[];    */ "0 %",
  207   /* long  graph_value;     */ 0,
  208   /* short graph_scale;     */ 20,
  209   /* char  graph_units[];   */ "(%d%%)"
  210  },
  211  /*+ The irq cpu output +*/
  212  {
  213   /* char  name[];          */ "CPU%d_IRQ",
  214   /* char *description;     */ "The fraction of the time that the CPU number %d is waiting for IRQs.",
  215   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  216   /* short interval;        */ 1,
  217   /* char  text_value[];    */ "0 %",
  218   /* long  graph_value;     */ 0,
  219   /* short graph_scale;     */ 20,
  220   /* char  graph_units[];   */ "(%d%%)"
  221  },
  222  /*+ The softirq cpu output +*/
  223  {
  224   /* char  name[];          */ "CPU%d_SoftIRQ",
  225   /* char *description;     */ "The fraction of the time that the CPU number %d is ???.",
  226   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  227   /* short interval;        */ 1,
  228   /* char  text_value[];    */ "0 %",
  229   /* long  graph_value;     */ 0,
  230   /* short graph_scale;     */ 20,
  231   /* char  graph_units[];   */ "(%d%%)"
  232  },
  233  /*+ The steal cpu output +*/
  234  {
  235   /* char  name[];          */ "CPU%d_Steal",
  236   /* char *description;     */ "The fraction of the time that the CPU number %d is ???.",
  237   /* char  type;            */ PROCMETER_GRAPH|PROCMETER_TEXT|PROCMETER_BAR,
  238   /* short interval;        */ 1,
  239   /* char  text_value[];    */ "0 %",
  240   /* long  graph_value;     */ 0,
  241   /* short graph_scale;     */ 20,
  242   /* char  graph_units[];   */ "(%d%%)"
  243  }
  244 };
  245 
  246 
  247 /*+ The extra outputs with multiple CPUs +*/
  248 ProcMeterOutput *smp_outputs=NULL;
  249 
  250 /*+ The outputs. +*/
  251 ProcMeterOutput **outputs=NULL;
  252 
  253 /*+ The module. +*/
  254 ProcMeterModule module=
  255 {
  256  /* char name[];            */ "Stat-CPU",
  257  /* char *description;      */ "CPU usage statistics. [From /proc/stat]",
  258 };
  259 
  260 
  261 /* The line buffer */
  262 static char *line=NULL;
  263 static size_t length=0;
  264 
  265 /* The current and previous values read from the file */
  266 static unsigned long long *current,*previous,values[2][N_OUTPUTS_26];
  267 static unsigned long long *smp_current,*smp_previous,*smp_values[2]={NULL,NULL};
  268 
  269 /*+ The number of CPUs (or 0 for only 1!). +*/
  270 static int ncpus=0;
  271 
  272 /*+ A flag to indicate that this is kernel v2.6 and has 8 CPU counters. +*/
  273 static int kernel_26=0;
  274 
  275 
  276 /*++++++++++++++++++++++++++++++++++++++
  277   Load the module.
  278 
  279   ProcMeterModule *Load Returns the module information.
  280   ++++++++++++++++++++++++++++++++++++++*/
  281 
  282 ProcMeterModule *Load(void)
  283 {
  284  return(&module);
  285 }
  286 
  287 
  288 /*++++++++++++++++++++++++++++++++++++++
  289   Initialise the module, creating the outputs as required.
  290 
  291   ProcMeterOutput **Initialise Returns a NULL terminated list of outputs.
  292 
  293   char *options The options string for the module from the .procmeterrc file.
  294   ++++++++++++++++++++++++++++++++++++++*/
  295 
  296 ProcMeterOutput **Initialise(char *options)
  297 {
  298  FILE *f;
  299  int n=0;
  300 
  301  outputs=(ProcMeterOutput**)malloc(sizeof(ProcMeterOutput*));
  302  outputs[0]=NULL;
  303 
  304  current=values[0];
  305  previous=values[1];
  306 
  307  /* Verify the statistics from /proc/stat */
  308 
  309  f=fopen("/proc/stat","r");
  310  if(!f)
  311     fprintf(stderr,"ProcMeter(%s): Could not open '/proc/stat'.\n",__FILE__);
  312  else
  313    {
  314     if(!fgets_realloc(&line,&length,f)) /* cpu */
  315        fprintf(stderr,"ProcMeter(%s): Could not read '/proc/stat'.\n",__FILE__);
  316     else
  317       {
  318        unsigned long long d1,d2,d3,d4,d5,d6,d7,d8;
  319 
  320        if(sscanf(line,"cpu %llu %llu %llu %llu %llu %llu %llu %llu",&d1,&d2,&d3,&d4,&d5,&d6,&d7,&d8)==8)
  321           kernel_26=1;
  322 
  323        if(kernel_26 || sscanf(line,"cpu %llu %llu %llu %llu",&d1,&d2,&d3,&d4)==4)
  324          {
  325           int i,n_outputs;
  326 
  327           if(kernel_26)
  328              n_outputs=N_OUTPUTS_26;
  329           else
  330              n_outputs=N_OUTPUTS_24;
  331 
  332           /* cpu or disk or page */
  333           while(fgets_realloc(&line,&length,f) && line[0]=='c' && line[1]=='p' && line[2]=='u') /* kernel version > ~2.1.84 */
  334             {
  335              int ncpu;
  336 
  337              if((kernel_26 && sscanf(line,"cpu%d %llu %llu %llu %llu %llu %llu %llu %llu",&ncpu,&d1,&d2,&d3,&d4,&d5,&d6,&d7,&d8)==9) ||
  338                 sscanf(line,"cpu%d %llu %llu %llu %llu",&ncpu,&d1,&d2,&d3,&d4)==5)
  339                {
  340                 ncpus++;
  341 
  342                 smp_values[0]=(unsigned long long*)realloc((void*)smp_values[0],ncpus*N_OUTPUTS_26*sizeof(unsigned long long));
  343                 smp_values[1]=(unsigned long long*)realloc((void*)smp_values[1],ncpus*N_OUTPUTS_26*sizeof(unsigned long long));
  344                 smp_current=smp_values[0]; smp_previous=smp_values[1];
  345 
  346                 smp_outputs=(ProcMeterOutput*)realloc((void*)smp_outputs,ncpus*n_outputs*sizeof(ProcMeterOutput));
  347 
  348                 for(i=0;i<n_outputs;i++)
  349                   {
  350                    smp_outputs[i+ncpu*n_outputs]=_smp_outputs[i];
  351                    snprintf(smp_outputs[i+ncpu*n_outputs].name, PROCMETER_NAME_LEN+1, _smp_outputs[i].name, ncpu);
  352                    smp_outputs[i+ncpu*n_outputs].description=(char*)malloc(strlen(_smp_outputs[i].description)+8);
  353                    sprintf(smp_outputs[i+ncpu*n_outputs].description,_smp_outputs[i].description,ncpu);
  354                   }
  355                }
  356              else
  357                 fprintf(stderr,"ProcMeter(%s): Unexpected 'cpu%d' line in '/proc/stat'.\n"
  358                                "    expected: 'cpu%d %%llu %%llu %%llu %%llu'\n"
  359                                "          or: 'cpu%d %%llu %%llu %%llu %%llu %%llu %%llu %%llu %%llu'\n"
  360                                "    found:    %s",__FILE__,ncpu,ncpu,ncpu,line);
  361             }
  362 
  363           outputs=(ProcMeterOutput**)realloc((void*)outputs,(1+n_outputs+ncpus*n_outputs)*sizeof(ProcMeterOutput*));
  364 
  365           for(i=0;i<n_outputs;i++)
  366              outputs[n++]=&_outputs[i];
  367 
  368           for(i=0;i<ncpus*n_outputs;i++)
  369              outputs[n++]=&smp_outputs[i];
  370 
  371           for(i=0;i<N_OUTPUTS_26;i++)
  372              current[i]=previous[i]=0;
  373 
  374           for(i=0;i<ncpus*N_OUTPUTS_26;i++)
  375              smp_current[i]=smp_previous[i]=0;
  376 
  377           outputs[n]=NULL;
  378          }
  379        else
  380           fprintf(stderr,"ProcMeter(%s): Unexpected 'cpu' line in '/proc/stat'.\n"
  381                          "    expected: 'cpu %%llu %%llu %%llu %%llu'\n"
  382                          "          or: 'cpu %%llu %%llu %%llu %%llu %%llu %%llu %%llu %%llu'\n"
  383                          "    found:    %s",__FILE__,line);
  384       }
  385 
  386     fclose(f);
  387    }
  388 
  389  return(outputs);
  390 }
  391 
  392 
  393 /*++++++++++++++++++++++++++++++++++++++
  394   Perform an update on one of the statistics.
  395 
  396   int Update Returns 0 if OK, else -1.
  397 
  398   time_t now The current time.
  399 
  400   ProcMeterOutput *output The output that the value is wanted for.
  401   ++++++++++++++++++++++++++++++++++++++*/
  402 
  403 int Update(time_t now,ProcMeterOutput *output)
  404 {
  405  static time_t last=0;
  406  int i,n_outputs;
  407 
  408  /* Get the statistics from /proc/stat */
  409 
  410  if(now!=last)
  411    {
  412     FILE *f;
  413     unsigned long long *temp;
  414 
  415     temp=current;
  416     current=previous;
  417     previous=temp;
  418 
  419     temp=smp_current;
  420     smp_current=smp_previous;
  421     smp_previous=temp;
  422 
  423     f=fopen("/proc/stat","r");
  424     if(!f)
  425        return(-1);
  426 
  427     fgets_realloc(&line,&length,f); /* cpu */
  428     sscanf(line,"cpu %llu %llu %llu %llu %llu %llu %llu %llu",&current[CPU_USER],&current[CPU_NICE],&current[CPU_SYS],&current[CPU_IDLE],
  429                                                               &current[CPU_IOWAIT],&current[CPU_IRQ],&current[CPU_SOFTIRQ],&current[CPU_STEAL]);
  430 
  431     current[CPU]=current[CPU_USER]+current[CPU_NICE]+current[CPU_SYS];
  432     if(kernel_26)
  433        current[CPU]+=current[CPU_IOWAIT]+current[CPU_IRQ]+current[CPU_SOFTIRQ]+current[CPU_STEAL];
  434 
  435     /* cpu or disk or page */
  436     while(fgets_realloc(&line,&length,f) && line[0]=='c' && line[1]=='p' && line[2]=='u') /* kernel version > ~2.1.84 */
  437       {
  438        int ncpu,offset;
  439        unsigned long long cpu_user,cpu_nice,cpu_sys,cpu_idle,cpu_iowait,cpu_irq,cpu_softirq,cpu_steal;
  440 
  441        sscanf(line,"cpu%d %llu %llu %llu %llu %llu %llu %llu %llu",&ncpu,&cpu_user,&cpu_nice,&cpu_sys,&cpu_idle,
  442                                                                    &cpu_iowait,&cpu_irq,&cpu_softirq,&cpu_steal);
  443 
  444        offset=ncpu*N_OUTPUTS_26;
  445 
  446        smp_current[CPU_USER   +offset]=cpu_user;
  447        smp_current[CPU_NICE   +offset]=cpu_nice;
  448        smp_current[CPU_SYS    +offset]=cpu_sys;
  449        smp_current[CPU_IDLE   +offset]=cpu_idle;
  450        smp_current[CPU_IOWAIT +offset]=cpu_iowait;
  451        smp_current[CPU_IRQ    +offset]=cpu_irq;
  452        smp_current[CPU_SOFTIRQ+offset]=cpu_softirq;
  453        smp_current[CPU_STEAL  +offset]=cpu_steal;
  454 
  455        smp_current[CPU+offset]=smp_current[CPU_USER+offset]+smp_current[CPU_NICE+offset]+smp_current[CPU_SYS+offset];
  456        if(kernel_26)
  457           smp_current[CPU+offset]+=smp_current[CPU_IOWAIT+offset]+smp_current[CPU_IRQ+offset]+smp_current[CPU_SOFTIRQ+offset]+smp_current[CPU_STEAL+offset];
  458       }
  459 
  460     fclose(f);
  461 
  462     last=now;
  463    }
  464 
  465  if(kernel_26)
  466     n_outputs=N_OUTPUTS_26;
  467  else
  468     n_outputs=N_OUTPUTS_24;
  469 
  470  for(i=0;i<n_outputs;i++)
  471     if(output==&_outputs[i])
  472       {
  473        unsigned long long tot;
  474        double value;
  475 
  476        tot=current[CPU]+current[CPU_IDLE]-previous[CPU]-previous[CPU_IDLE];
  477 
  478        if(tot)
  479           value=100.0*(double)(current[i]-previous[i]+0.5)/(double)tot;
  480        else
  481           value=0.0;
  482        if(value>100.0)
  483           value=100.0;
  484        else if(value<0.0)
  485           value=0.0;
  486 
  487        output->graph_value=PROCMETER_GRAPH_FLOATING(value/output->graph_scale);
  488        sprintf(output->text_value,"%.0f %%",value);
  489 
  490        return(0);
  491       }
  492 
  493  for(i=0;i<ncpus*n_outputs;i++)
  494     if(output==&smp_outputs[i])
  495       {
  496        int ncpu=i/n_outputs,offset=ncpu*N_OUTPUTS_26;
  497        unsigned long long tot;
  498        double value;
  499 
  500        tot=smp_current[CPU+offset]+smp_current[CPU_IDLE+offset]-smp_previous[CPU+offset]-smp_previous[CPU_IDLE+offset];
  501 
  502        if(tot)
  503           value=100.0*(double)(smp_current[i]-smp_previous[i]+0.5)/(double)tot;
  504        else
  505           value=0.0;
  506        if(value>100.0)
  507           value=100.0;
  508        else if(value<0.0)
  509           value=0.0;
  510 
  511        output->graph_value=PROCMETER_GRAPH_FLOATING(value/output->graph_scale);
  512        sprintf(output->text_value,"%.0f %%",value);
  513 
  514        return(0);
  515       }
  516 
  517  return(-1);
  518 }
  519 
  520 
  521 /*++++++++++++++++++++++++++++++++++++++
  522   Tidy up and prepare to have the module unloaded.
  523   ++++++++++++++++++++++++++++++++++++++*/
  524 
  525 void Unload(void)
  526 {
  527  if(ncpus)
  528    {
  529     int i,n_outputs;
  530 
  531     if(kernel_26)
  532        n_outputs=N_OUTPUTS_26;
  533     else
  534        n_outputs=N_OUTPUTS_24;
  535 
  536     for(i=0;i<ncpus*n_outputs;i++)
  537        free(smp_outputs[i].description);
  538 
  539     free(smp_outputs);
  540 
  541     free(smp_values[0]);
  542     free(smp_values[1]);
  543    }
  544 
  545  free(outputs);
  546 
  547  if(line)
  548     free(line);
  549 }