00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
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
00041
00042
00043 XrdCmsMeter XrdCms::Meter;
00044
00045
00046
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
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
00092
00093
00094 XrdCmsMeter::~XrdCmsMeter()
00095 {
00096 if (monpgm) free(monpgm);
00097 if (montid) XrdSysThread::Kill(montid);
00098 }
00099
00100
00101
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
00122
00123
00124 int XrdCmsMeter::FreeSpace(int &tot_util)
00125 {
00126 long long fsavail;
00127
00128
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
00138
00139 cfsMutex.Lock();
00140 fsavail = dsk_maxf;
00141 tot_util= dsk_util;
00142 cfsMutex.UnLock();
00143
00144
00145
00146 if (fsavail >> 31LL) fsavail = 0x7fffffff;
00147
00148
00149
00150 return static_cast<int>(fsavail);
00151 }
00152
00153
00154
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
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;
00176 dsk_lpn = vsInfo.Large >> 20LL;
00177 }
00178
00179
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
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
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
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
00222
00223
00224 int XrdCmsMeter::Monitor(char *pgm, int itv)
00225 {
00226 char *mp, pp;
00227 int rc;
00228
00229
00230
00231 mp = monpgm = strdup(pgm);
00232 while(*mp && *mp != ' ') mp++;
00233 pp = *mp; *mp ='\0';
00234
00235
00236
00237 if (access(monpgm, X_OK))
00238 {Say.Emsg("Meter", errno, "find executable", monpgm);
00239 return -1;
00240 }
00241
00242
00243
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
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
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
00285
00286 if (!Virtual && montid && (time(0) - rep_tod > monint*2)) myMeter.Drain();
00287
00288
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
00299
00300 return maxfree;
00301 }
00302
00303
00304
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
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
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
00367
00368
00369 unsigned int XrdCmsMeter::TotalSpace(unsigned int &minfree)
00370 {
00371 long long fstotal, fsminfr;
00372
00373
00374
00375 if (Virtual)
00376 {if (Virtual == peerFS) {minfree = 0; return 0x7fffffff;}
00377 if (VirtUpdt) UpdtSpace();
00378 }
00379
00380
00381
00382 cfsMutex.Lock();
00383 fstotal = dsk_tot;
00384 fsminfr = MinFree;
00385 cfsMutex.UnLock();
00386
00387
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
00396
00397 return static_cast<unsigned int>(fstotal);
00398 }
00399
00400
00401
00402
00403
00404
00405
00406
00407 void XrdCmsMeter::calcSpace()
00408 {
00409 EPNAME("calcSpace")
00410 XrdOssVSInfo vsInfo;
00411 int old_util, rc;
00412 long long fsutil;
00413
00414
00415
00416
00417 if ((rc = Config.ossFS->StatVS(&vsInfo, 0, 1)))
00418 Say.Emsg("Meter", rc, "calculate file system space");
00419
00420
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
00427
00428 cfsMutex.Lock();
00429 old_util = dsk_util;
00430 dsk_maxf = vsInfo.LFree >> 20LL;
00431 dsk_free = vsInfo.Free >> 20LL;
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
00440
00441
00442
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
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
00485
00486
00487 void XrdCmsMeter::UpdtSpace()
00488 {
00489 static const SMask_t allNodes(~0);
00490 SpaceData mySpace;
00491
00492
00493
00494 Cluster.Space(mySpace, allNodes);
00495
00496
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;
00505 MinFree = mySpace.wMinF;
00506 VirtUpdt = 0;
00507 cfsMutex.UnLock();
00508 }