XrdCmsMeter.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                        X r d C m s M e t e r . c c                         */
00004 /*                                                                            */
00005 /* (c) 2007 by the Board of Trustees of the Leland Stanford, Jr., University  */
00006 /*                            All Rights Reserved                             */
00007 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00008 /*              DE-AC02-76-SFO0515 with the Department of Energy              */
00009 /******************************************************************************/
00010 
00011 //         $Id: XrdCmsMeter.cc 35287 2010-09-14 21:19:35Z ganis $
00012 
00013 // Original Version: 1.22 2007/08/30 00:42:39 abh
00014 
00015 const char *XrdCmsMeterCVSID = "$Id: XrdCmsMeter.cc 35287 2010-09-14 21:19:35Z ganis $";
00016   
00017 #include <errno.h>
00018 #include <fcntl.h>
00019 #include <signal.h>
00020 #include <stdio.h>
00021 #include <string.h>
00022 #include <time.h>
00023 #include <unistd.h>
00024 #include <sys/stat.h>
00025 #include <sys/types.h>
00026 #include <sys/wait.h>
00027 
00028 #include "XrdCms/XrdCmsCluster.hh"
00029 #include "XrdCms/XrdCmsConfig.hh"
00030 #include "XrdCms/XrdCmsMeter.hh"
00031 #include "XrdCms/XrdCmsNode.hh"
00032 #include "XrdCms/XrdCmsState.hh"
00033 #include "XrdCms/XrdCmsTrace.hh"
00034 #include "XrdOss/XrdOss.hh"
00035 #include "XrdSys/XrdSysPlatform.hh"
00036 
00037 using namespace XrdCms;
00038  
00039 /******************************************************************************/
00040 /*                               G l o b a l s                                */
00041 /******************************************************************************/
00042 
00043        XrdCmsMeter   XrdCms::Meter;
00044 
00045 /******************************************************************************/
00046 /*            E x t e r n a l   T h r e a d   I n t e r f a c e s             */
00047 /******************************************************************************/
00048 
00049 void *XrdCmsMeterRun(void *carg)
00050       {XrdCmsMeter *mp = (XrdCmsMeter *)carg;
00051        return mp->Run();
00052       }
00053 
00054 void *XrdCmsMeterRunFS(void *carg)
00055       {XrdCmsMeter *mp = (XrdCmsMeter *)carg;
00056        return mp->RunFS();
00057       }
00058 
00059 /******************************************************************************/
00060 /*                           C o n s t r u c t o r                            */
00061 /******************************************************************************/
00062 
00063 XrdCmsMeter::XrdCmsMeter() : myMeter(&Say)
00064 {
00065     Running  = 0;
00066     dsk_calc = 0;
00067     fs_nums  = 0;
00068     noSpace  = 0;
00069     MinFree  = 0;
00070     HWMFree  = 0;
00071     dsk_lpn  = 0;
00072     dsk_tot  = 0;
00073     dsk_free = 0;
00074     dsk_maxf = 0;
00075     lastFree = 0;
00076     lastUtil = 0;
00077     monpgm   = 0;
00078     monint   = 0;
00079     montid   = 0;
00080     rep_tod  = time(0);
00081     xeq_load = 0;
00082     cpu_load = 0;
00083     mem_load = 0;
00084     pag_load = 0;
00085     net_load = 0;
00086     Virtual  = 0;
00087     VirtUpdt = 1;
00088 }
00089   
00090 /******************************************************************************/
00091 /*                            D e s t r u c t o r                             */
00092 /******************************************************************************/
00093   
00094 XrdCmsMeter::~XrdCmsMeter()
00095 {
00096    if (monpgm) free(monpgm);
00097    if (montid) XrdSysThread::Kill(montid);
00098 }
00099   
00100 /******************************************************************************/
00101 /*                              c a l c L o a d                               */
00102 /******************************************************************************/
00103 
00104 int XrdCmsMeter::calcLoad(int pcpu, int pio, int pload, int pmem, int ppag)
00105 {
00106    return   (Config.P_cpu  * pcpu /100)
00107           + (Config.P_io   * pio  /100)
00108           + (Config.P_load * pload/100)
00109           + (Config.P_mem  * pmem /100)
00110           + (Config.P_pag  * ppag /100);
00111 }
00112 
00113 /******************************************************************************/
00114 
00115 int XrdCmsMeter::calcLoad(int nowload, int pdsk)
00116 {
00117    return   (Config.P_dsk  * pdsk /100) + nowload;
00118 }
00119 
00120 /******************************************************************************/
00121 /*                             F r e e S p a c e                              */
00122 /******************************************************************************/
00123   
00124 int XrdCmsMeter::FreeSpace(int &tot_util)
00125 {
00126    long long fsavail;
00127 
00128 // If we are a virtual filesystem, do virtual stats
00129 //
00130    if (Virtual)
00131       {if (Virtual == peerFS) {tot_util = 0; return 0x7fffffff;}
00132        if (VirtUpdt) UpdtSpace();
00133        tot_util = lastUtil;
00134        return lastFree;
00135       }
00136 
00137 // The values are calculated periodically so use the last available ones
00138 //
00139    cfsMutex.Lock();
00140    fsavail = dsk_maxf;
00141    tot_util= dsk_util;
00142    cfsMutex.UnLock();
00143 
00144 // Now adjust the values to fit
00145 //
00146    if (fsavail >> 31LL) fsavail = 0x7fffffff;
00147 
00148 // Return amount available
00149 //
00150    return static_cast<int>(fsavail);
00151 }
00152 
00153 /******************************************************************************/
00154 /*                                  I n i t                                   */
00155 /******************************************************************************/
00156   
00157 void  XrdCmsMeter::Init()
00158 {
00159     XrdOssVSInfo vsInfo;
00160     pthread_t monFStid;
00161     char buff[1024], sfx1, sfx2, sfx3;
00162     long maxfree, totfree, totDisk;
00163     int rc;
00164 
00165 // Get initial free space
00166 //
00167         if ((rc = Config.ossFS->StatVS(&vsInfo, 0, 1)))
00168            {Say.Emsg("Meter", rc, "calculate file system space");
00169             noSpace = 1;
00170            }
00171    else if (!(fs_nums = vsInfo.Extents))
00172            {Say.Emsg("Meter", "Warning! No writable filesystems found.");
00173             noSpace = 1;
00174            }
00175    else    {dsk_tot = vsInfo.Total >> 20LL; // in MB
00176             dsk_lpn = vsInfo.Large >> 20LL;
00177            }
00178 
00179 // Check if we should bother to continue
00180 //
00181    if (noSpace)
00182       {if (!Config.asSolo()) CmsState.Update(XrdCmsState::Space, 0);
00183        Say.Emsg("Meter", "Write access and staging prohibited.");
00184        return;
00185       }
00186 
00187 // Set values (disk space values are in megabytes)
00188 // 
00189     if (Config.DiskMinP) MinFree = dsk_lpn * Config.DiskMinP / 100;
00190     if (Config.DiskMin > MinFree) MinFree  = Config.DiskMin;
00191     MinStype= Scale(MinFree, MinShow);
00192     if (Config.DiskHWMP) HWMFree = dsk_lpn * Config.DiskHWMP / 100;
00193     if (Config.DiskHWM > HWMFree) HWMFree  = Config.DiskHWM;
00194     HWMStype= Scale(HWMFree, HWMShow);
00195     dsk_calc = (Config.DiskAsk < 5 ? 5 : Config.DiskAsk);
00196 
00197 // Calculate the initial free space and start the FS monitor thread
00198 //
00199    calcSpace();
00200    if ((noSpace = (dsk_maxf < MinFree)) && !Config.asSolo())
00201       CmsState.Update(XrdCmsState::Space, 0);
00202    if ((rc = XrdSysThread::Run(&monFStid, XrdCmsMeterRunFS, (void *)this, 0,
00203       "FS meter"))) Say.Emsg("Meter", rc, "start filesystem meter.");
00204 
00205 // Document what we have
00206 //
00207    sfx1 = Scale(dsk_maxf, maxfree);
00208    sfx2 = Scale(dsk_tot,  totDisk);
00209    sfx3 = Scale(dsk_free, totfree);
00210    sprintf(buff,"Found %d filesystem(s); %ld%cB total (%d%% util);"
00211                 " %ld%cB free (%ld%cB max)", fs_nums, totDisk, sfx2,
00212                 dsk_util, totfree, sfx3, maxfree, sfx1);
00213    Say.Emsg("Meter", buff);
00214    if (noSpace)
00215       {sprintf(buff, "%ld%cB minimum", MinShow, MinStype);
00216        Say.Emsg("Meter", "Warning! Available space <", buff);
00217       }
00218 }
00219 
00220 /******************************************************************************/
00221 /*                               M o n i t o r                                */
00222 /******************************************************************************/
00223   
00224 int XrdCmsMeter::Monitor(char *pgm, int itv)
00225 {
00226    char *mp, pp;
00227    int rc;
00228 
00229 // Isolate the program name
00230 //
00231    mp = monpgm = strdup(pgm);
00232    while(*mp && *mp != ' ') mp++;
00233    pp = *mp; *mp ='\0';
00234 
00235 // Make sure the program is executable by us
00236 //
00237    if (access(monpgm, X_OK))
00238       {Say.Emsg("Meter", errno, "find executable", monpgm);
00239        return -1;
00240       }
00241 
00242 // Start up the program. We don't really need to serialize Restart() because
00243 // Monitor() is a one-time call (otherwise unpredictable results may occur).
00244 //
00245    *mp = pp; monint = itv;
00246    if ((rc = XrdSysThread::Run(&montid, XrdCmsMeterRun, (void *)this, 0,
00247       "Perf meter"))) Say.Emsg("Meter", rc, "start performance meter.");
00248    Running = 1;
00249    return 0;
00250 }
00251 
00252 /******************************************************************************/
00253 /*                                R e c o r d                                 */
00254 /******************************************************************************/
00255   
00256 void XrdCmsMeter::Record(int pcpu, int pnet, int pxeq,
00257                          int pmem, int ppag, int pdsk)
00258 {
00259    int temp;
00260 
00261    repMutex.Lock();
00262    temp = cpu_load + cpu_load/2;
00263    cpu_load = (cpu_load + (pcpu > temp ? temp : pcpu))/2;
00264    temp = net_load + net_load/2;
00265    net_load = (net_load + (pnet > temp ? temp : pnet))/2;
00266    temp = xeq_load + xeq_load/2;
00267    xeq_load = (xeq_load + (pxeq > temp ? temp : pxeq))/2;
00268    temp = mem_load + mem_load/2;
00269    mem_load = (mem_load + (pmem > temp ? temp : pmem))/2;
00270    temp = pag_load + pag_load/2;
00271    pag_load = (pag_load + (ppag > temp ? temp : ppag))/2;
00272    repMutex.UnLock();
00273 }
00274  
00275 /******************************************************************************/
00276 /*                                R e p o r t                                 */
00277 /******************************************************************************/
00278   
00279 int XrdCmsMeter::Report(int &pcpu, int &pnet, int &pxeq, 
00280                         int &pmem, int &ppag, int &pdsk)
00281 {
00282    int maxfree;
00283 
00284 // Force restart the monitor program if it hasn't reported within 2 intervals
00285 //
00286    if (!Virtual && montid && (time(0) - rep_tod > monint*2)) myMeter.Drain();
00287 
00288 // Format a usage line
00289 //
00290    repMutex.Lock();
00291    maxfree = FreeSpace(pdsk);
00292    if (!Running && !Virtual) pcpu = pnet = pmem = ppag = pxeq = 0;
00293       else {pcpu = cpu_load; pnet = net_load; pmem = mem_load; 
00294             ppag = pag_load; pxeq = xeq_load;
00295            }
00296    repMutex.UnLock();
00297 
00298 // All done
00299 //
00300    return maxfree;
00301 }
00302 
00303 /******************************************************************************/
00304 /*                                   R u n                                    */
00305 /******************************************************************************/
00306   
00307 void *XrdCmsMeter::Run()
00308 {
00309    const struct timespec rqtp = {30, 0};
00310    int i, myLoad, prevLoad = -1;
00311    char *lp = 0;
00312 
00313 // Execute the program (keep restarting and keep reading the output)
00314 //
00315    while(1)
00316         {if (myMeter.Exec(monpgm) == 0)
00317              while((lp = myMeter.GetLine()))
00318                   {repMutex.Lock();
00319                    i = sscanf(lp, "%d %d %d %d %d",
00320                        &xeq_load, &cpu_load, &mem_load, &pag_load, &net_load);
00321                    rep_tod = time(0);
00322                    repMutex.UnLock();
00323                    if (i != 5) break;
00324                    myLoad = calcLoad(cpu_load,net_load,xeq_load,mem_load,pag_load);
00325                    if (prevLoad >= 0)
00326                       {prevLoad = prevLoad - myLoad;
00327                        if (prevLoad < 0) prevLoad = -prevLoad;
00328                        if (prevLoad > Config.P_fuzz) XrdCmsNode::Report_Usage(0);
00329                       }
00330                    prevLoad = myLoad;
00331                   }
00332          if (lp) Say.Emsg("Meter","Perf monitor returned invalid output:",lp);
00333             else Say.Emsg("Meter","Perf monitor died.");
00334          nanosleep(&rqtp, 0);
00335          Say.Emsg("Meter", "Restarting monitor:", monpgm);
00336         }
00337    return (void *)0;
00338 }
00339 
00340 /******************************************************************************/
00341 /*                                 r u n F S                                  */
00342 /******************************************************************************/
00343   
00344 void *XrdCmsMeter::RunFS()
00345 {
00346    const struct timespec rqtp = {dsk_calc, 0};
00347    int noNewSpace;
00348    int mlim = 60/dsk_calc, nowlim = 0;
00349   
00350    while(1)
00351         {nanosleep(&rqtp, 0);
00352          calcSpace();
00353          noNewSpace = dsk_maxf < (noSpace ? HWMFree : MinFree);
00354          if (noSpace != noNewSpace)
00355             {SpaceMsg(noNewSpace);
00356              noSpace = noNewSpace;
00357              if (!Config.asSolo()) CmsState.Update(XrdCmsState::Space,!noSpace);
00358             }
00359             else if (noSpace && !nowlim) SpaceMsg(noNewSpace);
00360          nowlim = (nowlim ? nowlim-1 : mlim);
00361         }
00362    return (void *)0;
00363 }
00364   
00365 /******************************************************************************/
00366 /*                            T o t a l S p a c e                             */
00367 /******************************************************************************/
00368 
00369 unsigned int XrdCmsMeter::TotalSpace(unsigned int &minfree)
00370 {
00371    long long fstotal, fsminfr;
00372 
00373 // If we are a virtual filesystem, do virtual stats
00374 //
00375    if (Virtual)
00376       {if (Virtual == peerFS) {minfree = 0; return 0x7fffffff;}
00377        if (VirtUpdt) UpdtSpace();
00378       }
00379 
00380 // The values are calculated periodically so use the last available ones
00381 //
00382    cfsMutex.Lock();
00383    fstotal = dsk_tot;
00384    fsminfr = MinFree;
00385    cfsMutex.UnLock();
00386 
00387 // Now adjust the values to fit
00388 //
00389    if (fsminfr >> 31LL) minfree = 0x7fffffff;
00390       else              minfree = static_cast<unsigned int>(fsminfr);
00391    fstotal = fstotal >> 10LL;
00392    if (fstotal == 0) fstotal = 1;
00393       else if (fstotal >> 31LL) fstotal = 0x7fffffff;
00394 
00395 // Return amount available
00396 //
00397    return static_cast<unsigned int>(fstotal);
00398 }
00399   
00400 /******************************************************************************/
00401 /*                       P r i v a t e   M e t h o d s                        */
00402 /******************************************************************************/
00403 /******************************************************************************/
00404 /*                             c a l c S p a c e                              */
00405 /******************************************************************************/
00406   
00407 void XrdCmsMeter::calcSpace()
00408 {
00409    EPNAME("calcSpace")
00410    XrdOssVSInfo vsInfo;
00411    int       old_util, rc;
00412    long long fsutil;
00413 
00414 // Get free space statistics. On error, all fields will be zero, which is
00415 // what we really want to kill space allocation.
00416 //
00417    if ((rc = Config.ossFS->StatVS(&vsInfo, 0, 1)))
00418       Say.Emsg("Meter", rc, "calculate file system space");
00419 
00420 // Calculate the disk utilization (note that dsk_tot is in MB)
00421 //
00422    fsutil = (dsk_tot ? 100-(((vsInfo.Free >> 20LL)*100)/dsk_tot) : 100);
00423    if (fsutil < 0) fsutil = 0;
00424       else if (fsutil > 100) fsutil = 100;
00425 
00426 // Update the stats and release the lock
00427 //
00428    cfsMutex.Lock();
00429    old_util = dsk_util;
00430    dsk_maxf = vsInfo.LFree >> 20LL; // In MB
00431    dsk_free = vsInfo.Free  >> 20LL; // In MB
00432    dsk_util = static_cast<int>(fsutil);
00433    cfsMutex.UnLock();
00434    if (old_util != dsk_util)
00435       DEBUG("New fs info; maxfree=" <<dsk_maxf <<"MB utilized=" <<dsk_util <<"%");
00436 }
00437 
00438 /******************************************************************************/
00439 /*                                 S c a l e                                  */
00440 /******************************************************************************/
00441   
00442 // Note: Input quantity is always in megabytes!
00443 
00444 char XrdCmsMeter::Scale(long long inval, long &outval)
00445 {
00446     const char sfx[] = {'M', 'G', 'T', 'P'};
00447     unsigned int i;
00448 
00449     for (i = 0; i < sizeof(sfx)-1 && inval > 1024; i++) inval = inval/1024;
00450 
00451     outval = static_cast<long>(inval);
00452     return sfx[i];
00453 }
00454  
00455 /******************************************************************************/
00456 /*                              S p a c e M s g                               */
00457 /******************************************************************************/
00458 
00459 void XrdCmsMeter::SpaceMsg(int why)
00460 {
00461    const char *What;
00462    char sfx, buff[1024];
00463    long maxfree;
00464 
00465    sfx = Scale(dsk_maxf, maxfree);
00466 
00467    if (why)
00468       {What = "Insufficient space; ";
00469        if (noSpace)
00470           sprintf(buff, "%ld%cB available < %ld%cB high watermark",
00471                                 maxfree, sfx, HWMShow, HWMStype);
00472           else
00473           sprintf(buff, "%ld%cB available < %ld%cB minimum",
00474                                 maxfree, sfx, MinShow, MinStype);
00475       } else {
00476        What = "  Sufficient space; ";
00477        sprintf(buff, "%ld%cB available > %ld%cB high watermak",
00478                                 maxfree, sfx, HWMShow, HWMStype);
00479       }
00480       Say.Emsg("Meter", What, buff);
00481 }
00482 
00483 /******************************************************************************/
00484 /*                             U p d t S p a c e                              */
00485 /******************************************************************************/
00486   
00487 void XrdCmsMeter::UpdtSpace()
00488 {
00489    static const SMask_t allNodes(~0);
00490    SpaceData mySpace;
00491 
00492 // Get new space values for the cluser
00493 //
00494    Cluster.Space(mySpace, allNodes);
00495 
00496 // Update out local information
00497 //
00498    cfsMutex.Lock();
00499    if (mySpace.wFree > mySpace.sFree)
00500       {lastFree = mySpace.wFree; lastUtil = mySpace.wUtil;
00501       } else {
00502        lastFree = mySpace.sFree; lastUtil = mySpace.sUtil;
00503       }
00504    dsk_tot = static_cast<long long>(mySpace.Total)<<10LL; // In MB
00505    MinFree = mySpace.wMinF;
00506    VirtUpdt = 0;
00507    cfsMutex.UnLock();
00508 }

Generated on Tue Jul 5 14:46:30 2011 for ROOT_528-00b_version by  doxygen 1.5.1