hce-node application  1.4.3
HCE Hierarchical Cluster Engine node application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
DRCEResourceExtractor.cpp
Go to the documentation of this file.
1 #include <sys/resource.h>
2 #include <sys/statvfs.h>
3 #include <utility>
4 #include <unistd.h>
5 #include <string.h>
6 #include <errno.h>
7 #include <fstream>
8 #include <sstream>
9 #include <dirent.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <time.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 
16 #include <Poco/TemporaryFile.h>
17 #include <Poco/Logger.h>
18 #include <Poco/Message.h>
19 
20 #include "DRCEAsyncTasksQueue.hpp"
22 #include "DRCEMessageConst.hpp"
23 #include "DRCEError.hpp"
24 #include "DRCEReadProcessData.hpp"
25 #include "DRCEResourceUsage.hpp"
26 
27 namespace HCE
28 {
29 namespace drce
30 {
31 //-----------------------------------------------------------------------------
33 : diskSize(0), diskUsed(0), diskFree(0), diskUsedPercent(0.0), diskFreePercent(0.0), externalDiskSize(0)
34 {
35  try
36  {
37  update();
38  }
39  catch(Poco::Exception& e)
40  {
41  Poco::Logger::root().log(Poco::Message(drce_const::moduleName, "DiskSpaceExtractor "+e.message(), Poco::Message::Priority::PRIO_ERROR));
42  }
43 }
44 //-----------------------------------------------------------------------------
45 void DiskSpaceExtractor::setDiskSize(size_t diskSize_)
46 {
47  externalDiskSize = diskSize_;
48 }
49 //-----------------------------------------------------------------------------
50 void DiskSpaceExtractor::update(void) throw (Poco::Exception)
51 {
52  Poco::TemporaryFile temporaryFile;
53  temporaryFile.createFile();
54  const std::string fileName = temporaryFile.path();
55 
56  struct statvfs64 buf={0};
57 
58  if (statvfs64(fileName.c_str(), &buf) != 0)
59  throw Poco::Exception(std::string("DiskSpaceExtractor::update: ")+strerror(errno));
60 
61  size_t blksize = buf.f_bsize;
62  size_t blocks = buf.f_blocks;
63  size_t freeblks = buf.f_bfree;
64 
65  if (externalDiskSize)
66  diskSize = externalDiskSize;
67  else
68  diskSize = blocks * blksize;
69 
70  diskFree = freeblks * blksize;
71  diskUsed = diskSize - diskFree;
72 
73  diskUsedPercent = static_cast<double>(diskUsed*100)/diskSize;
74  diskFreePercent = static_cast<double>(diskFree*100)/diskSize;
75 }
76 //-----------------------------------------------------------------------------
77 //-----------------------------------------------------------------------------
78 size_t DiskSpaceExtractor::getDiskUsageBytes(pid_t pid)
79 {
80  size_t diskUsage = 0;
81  char buf[PATH_MAX] = {0};
82  struct dirent* entry = nullptr;
83 
84  snprintf(buf, PATH_MAX, "/proc/%i/fd/", pid);
85 
86  DIR* dir = opendir(buf);
87  if (dir)
88  {
89  while ((entry = readdir(dir)) != nullptr)
90  {
91  if (entry->d_name != std::string(".") && entry->d_name != std::string(".."))
92  {
93  diskUsage += getFileSize(std::string(buf)+"/"+entry->d_name);
94  }
95  }
96  closedir(dir);
97  }
98  return diskUsage;
99 }
100 //-----------------------------------------------------------------------------
101 size_t DiskSpaceExtractor::getFileSize(const std::string& filename)
102 {
103  size_t result = 0;
104  struct stat buff = {0};
105 
106  if (stat (filename.c_str(), &buff) == 0)
107  {
108  result = buff.st_size;
109  }
110  return result;
111 }
112 //-----------------------------------------------------------------------------
113 size_t DiskSpaceExtractor::getDiskUsage(const std::vector<pid_t>& ids)
114 {
115  size_t diskUsage = 0;
116 
117  for (size_t i=0;i<ids.size();++i)
118  {
119  diskUsage += getDiskUsageBytes(ids[i]);
120  }
121  return diskUsage;
122 }
123 //-----------------------------------------------------------------------------
124 //-----------------------------------------------------------------------------
125 void CpuUsageExtractor::getCpuData(pid_t pid, std::pair<unsigned long int, unsigned long int>& p)
126 {
127  const unsigned int count = 14;
128  char path[PATH_MAX]={0};
129  char pId[PATH_MAX]={0};
130  snprintf(path, PATH_MAX, "%s%d%s", "/proc/", pid, "/stat");
131 
132  FILE* fp = fopen(path, "r");
133  if (fp)
134  {
135  for(unsigned int i = 1; i < count; ++i)
136  {
137  fscanf(fp, "%s", pId);
138  }
139 
140  fscanf(fp, "%ld%ld", &p.first, &p.second);
141  fclose(fp);
142  }
143 }
144 //-----------------------------------------------------------------------------
145 /*
146  * calculates the elapsed CPU usage for list of processes
147  */
148 double CpuUsageExtractor::getCpuUsage(const std::vector<pid_t>& ids)
149 {
150  const double defaultUsage = 100.0;
151  const unsigned int SLPTIME = 200000;
152 
153  std::vector<std::pair<unsigned long int, unsigned long int> > cpuPrevData, cpuData;
154 
155  for (size_t i=0;i<ids.size();++i)
156  {
157  std::pair<unsigned long int, unsigned long int> data;
158  getCpuData(ids[i], data);
159  cpuPrevData.push_back(data);
160  }
161 
162  usleep(SLPTIME);
163 
164  for (size_t i=0;i<ids.size();++i)
165  {
166  std::pair<unsigned long int, unsigned long int> data;
167  getCpuData(ids[i], data);
168  cpuData.push_back(data);
169  }
170 
171  unsigned long int q(0), r(0);
172 
173  for (size_t i=0;i<cpuData.size();++i)
174  {
175  if ((cpuData[i].first) && (cpuPrevData[i].first))
176  q += abs(cpuData[i].first-cpuPrevData[i].first);
177 
178  if ((cpuData[i].second) && (cpuPrevData[i].second))
179  r += abs(cpuData[i].second-cpuPrevData[i].second);
180  }
181 
182  double result = defaultUsage;
183  long int frec = sysconf(_SC_CLK_TCK);
184  if (frec > 0)
185  {
186  result = ((q + r)*100.0/((double)0.2*frec));
187  }
188  return result;
189 }
190 //-----------------------------------------------------------------------------
192 : cpuUsage(0.0),/* lastBusy(0), lastWork(0),*/ iowait(0.0)/*, lastIOWait(0), lastSum(0)*/
193 {
194  update();
195 }
196 //-----------------------------------------------------------------------------
198 {
199  memset(&oldCpu, 0, sizeof(oldCpu));
200  updateUsage();
201  usleep(SLPTIME);
202  updateUsage();
203 }
204 //-----------------------------------------------------------------------------
205 void CpuUsageExtractor::updateUsage(void)
206 {
207  std::ifstream ifs("/proc/stat");
208  if (ifs.is_open())
209  {
210  std::string line;
211  while(getline(ifs, line))
212  {
213  if (line.compare(0, 4, "cpu ")==0)
214  {
215  unsigned long long nice(0), irq(0), softirq(0);
216 
217  int items = sscanf(line.c_str(),
218  "cpu %20llu %20llu %20llu %20llu %20llu %20llu %20llu",
219  &newCpu.user, &nice,
220  &newCpu.system,
221  &newCpu.idle,
222  &newCpu.iowait,
223  &irq, &softirq);
224 
225  newCpu.user += nice;
226  if (items == 4)
227  newCpu.iowait = 0;
228  if (items == 7)
229  newCpu.system += irq + softirq;
230  break;
231  }
232  }
233  ifs.close();
234  }
235 
236  struct cpu_info cpu;
237 
238  cpu.user = newCpu.user - oldCpu.user;
239  cpu.system = newCpu.system - oldCpu.system;
240  cpu.idle = newCpu.idle - oldCpu.idle;
241  cpu.iowait = newCpu.iowait - oldCpu.iowait;
242  double total = static_cast<double>(cpu.user + cpu.system + cpu.idle + cpu.iowait)/100.0;
243 
244  cpuUsage = static_cast<double>(cpu.user/total)+static_cast<double>(cpu.system/total);
245  iowait = static_cast<double>(cpu.iowait/total);
246 
247  oldCpu = newCpu;
248 }
249 //-----------------------------------------------------------------------------
251 {
252  update();
253 }
254 //-----------------------------------------------------------------------------
256 {
257  std::ifstream ifs("/proc/loadavg");
258  if (ifs.is_open())
259  {
260  std::string line;
261  while(getline(ifs, line))
262  {
263  sscanf(line.c_str(),"%lf %lf %lf", &loadAverage[0], &loadAverage[1], &loadAverage[2]);
264  }
265  ifs.close();
266  }
267 }
268 //-----------------------------------------------------------------------------
270 {
271  double value = 0.0;
272  if (index < SZ)
273  {
274  value = loadAverage[index];
275  }
276  return value;
277 }
278 //-----------------------------------------------------------------------------
279 //-----------------------------------------------------------------------------
281 : memTotal(0), memFree(0), buffers(0), cached(0), swapTotal(0), swapFree(0), vmallocTotal(0), vmallocUsed(0)
282 {
283 }
284 //-----------------------------------------------------------------------------
286 : memTotal(0), memFree(0), buffers(0), cached(0), swapTotal(0), swapFree(0), vmallocTotal(0), vmallocUsed(0)
287 {
288  *this = std::forward<MemInfo>(rhs);
289 }
290 //-----------------------------------------------------------------------------
292 {
293  if (this != &rhs)
294  {
295  memTotal = std::move(rhs.memTotal);
296  memFree = std::move(rhs.memFree);
297  buffers = std::move(rhs.buffers);
298  cached = std::move(rhs.cached);
299  swapTotal = std::move(rhs.swapTotal);
300  swapFree = std::move(rhs.swapFree);
301  vmallocTotal = std::move(rhs.vmallocTotal);
302  vmallocUsed = std::move(rhs.vmallocUsed);
303  }
304  return *this;
305 }
306 //-----------------------------------------------------------------------------
307 //-----------------------------------------------------------------------------
309 : vramUsed(0), rramUsed(0), vramFree(0), rramFree(0), vramUsedPercent(0.0), rramUsedPercent(0.0), vramFreePercent(0.0), rramFreePercent(0.0),
310  externalVramTotal(0), externalRramTotal(0)
311 {
312  update();
313 }
314 //-----------------------------------------------------------------------------
315 void MemoryExtractor::setVramTotal(size_t vramTotal_)
316 {
317  externalVramTotal = vramTotal_;
318 }
319 //-----------------------------------------------------------------------------
320 void MemoryExtractor::setRramTotal(size_t rramTotal_)
321 {
322  externalRramTotal = rramTotal_;
323 }
324 //-----------------------------------------------------------------------------
326 {
327  MemoryExtractor::MemInfo memInfo = getMemoryInfo();
328 
329  if (externalRramTotal)
330  memInfo.memTotal = externalRramTotal;
331 
332  rramFree = (memInfo.memTotal-memInfo.cached-memInfo.buffers)*1024;
333  rramUsed = memInfo.memTotal*1024-rramFree;
334 
335  size_t vmemTotal = (externalVramTotal)?externalVramTotal:(memInfo.swapTotal+memInfo.memTotal);
336  vramFree = (vmemTotal-memInfo.vmallocUsed)*1024;
337  vramUsed = memInfo.vmallocUsed*1024;
338 
339  rramFreePercent = static_cast<double>(rramFree*100)/(memInfo.memTotal*1024);
340  rramUsedPercent = static_cast<double>(rramUsed*100)/(memInfo.memTotal*1024);
341 
342  vramFreePercent = static_cast<double>(vramFree*100)/(vmemTotal*1024);
343  vramUsedPercent = static_cast<double>(vramUsed*100)/(vmemTotal*1024);
344 
345  vramTotal = vmemTotal*1024;
346  rramTotal = memInfo.memTotal*1024;
347 }
348 //-----------------------------------------------------------------------------
349 MemoryExtractor::MemInfo MemoryExtractor::getMemoryInfo(void)
350 {
351  MemoryExtractor::MemInfo memInfo;
352 
353  std::ifstream ifs("/proc/meminfo");
354  if (ifs.is_open())
355  {
356  std::string line;
357  while(getline(ifs, line))
358  {
359  if (line.find("MemTotal")!=std::string::npos)
360  sscanf(line.c_str(), "MemTotal: %zu", &(memInfo.memTotal));
361 
362  if (line.find("MemFree")!=std::string::npos)
363  sscanf(line.c_str(), "MemFree: %zu", &(memInfo.memFree));
364 
365  if (line.find("Buffers")!=std::string::npos)
366  sscanf(line.c_str(), "Buffers: %zu", &(memInfo.buffers));
367 
368  if (line.find("Cached")!=std::string::npos)
369  sscanf(line.c_str(), "Cached: %zu", &(memInfo.cached));
370 
371  if (line.find("SwapTotal")!=std::string::npos)
372  sscanf(line.c_str(), "SwapTotal: %zu", &(memInfo.swapTotal));
373 
374  if (line.find("SwapFree")!=std::string::npos)
375  sscanf(line.c_str(), "SwapFree: %zu", &(memInfo.swapFree));
376 
377  if (line.find("VmallocTotal")!=std::string::npos)
378  sscanf(line.c_str(), "VmallocTotal: %zu", &(memInfo.vmallocTotal));
379 
380  if (line.find("VmallocUsed")!=std::string::npos)
381  sscanf(line.c_str(), "VmallocUsed: %zu", &(memInfo.vmallocUsed));
382  }
383  ifs.close();
384  }
385  return memInfo;
386 }
387 //-----------------------------------------------------------------------------
388 //-----------------------------------------------------------------------------
390 : cpu(0.0), vram(0), rram(0), threads(0), disk(0)
391 {
392 }
393 //-----------------------------------------------------------------------------
395 : cpu(0.0), vram(0), rram(0), threads(0), disk(0)
396 {
397  *this = rhs;
398 }
399 //-----------------------------------------------------------------------------
401 : cpu(0.0), vram(0), rram(0), threads(0), disk(0)
402 {
403  *this = std::forward<FieldsArray>(rhs);
404 }
405 //-----------------------------------------------------------------------------
407 {
408  if (this != &rhs)
409  {
410  cpu = rhs.cpu;
411  vram = rhs.vram;
412  rram = rhs.rram;
413  threads = rhs.threads;
414  disk = rhs.disk;
415  }
416  return *this;
417 }
418 //-----------------------------------------------------------------------------
420 {
421  if (this != &rhs)
422  {
423  cpu = std::move(rhs.cpu);
424  vram = std::move(rhs.vram);
425  rram = std::move(rhs.rram);
426  threads = std::move(rhs.threads);
427  disk = std::move(rhs.disk);
428  }
429  return *this;
430 }
431 //-----------------------------------------------------------------------------
433 {
434  cpu = 0.0;
435  vram = 0;
436  rram = 0;
437  threads = 0;
438  disk = 0;
439 }
440 //-----------------------------------------------------------------------------
441 //-----------------------------------------------------------------------------
443 {
444  std::vector<pid_t> ids = DRCEReadProcessData::getAllProcessIds(asyncTask.pid);
445 
447 
448  for (size_t i=0;i<ids.size();++i)
449  {
451 
453  fieldsArray.vram += processData.vram;
454  fieldsArray.rram += processData.rram;
455 
457  fieldsArray.threads += processData.threads;
458  }
460  fieldsArray.cpu = CpuUsageExtractor::getCpuUsage(ids);
462  fieldsArray.disk = DiskSpaceExtractor::getDiskUsage(ids);
463 
464  if (fieldsArray.cpu > 1000 || fieldsArray.threads > 100)
465  {
466  std::cout << "taskId: " << asyncTask.taskId << " pid: "<< asyncTask.pid << " count: " << ids.size() << std::endl;
467  std::cout << "Children: ";
468  for (size_t i=0;i<ids.size();++i)
469  std::cout << ids[i] << " ";
470  std::cout << std::endl;
471  std::cout << "cpu: " << fieldsArray.cpu << " vram: " << fieldsArray.vram << " rram: "<< fieldsArray.rram << " threads: " << fieldsArray.threads << std::endl;
472  }
473 
474  return fieldsArray;
475 }
476 //-----------------------------------------------------------------------------
479 //-----------------------------------------------------------------------------
480 ResourceUsageExtractor::ResourceUsageExtractor(void)
481 : cpuUsageExtractor(), diskSpaceExtractor(), memoryExtractor(), loadAverageExtractor(), maxThreadsCount(0), maxProcessesCount(0)
482 {
483 }
484 //-----------------------------------------------------------------------------
486 {
487  Poco::Mutex::ScopedLock lock(mutex);
488  if(!pHandler)
490  return *pHandler;
491 }
492 //-----------------------------------------------------------------------------
494 {
495  Poco::Mutex::ScopedLock lock(mutex);
496  if(pHandler)
497  {
498  delete pHandler;
499  pHandler=nullptr;
500  }
501 }
502 //-----------------------------------------------------------------------------
504 {
505  Poco::Mutex::ScopedLock lock(mutex);
510 }
511 //-----------------------------------------------------------------------------
512 ResourceUsage ResourceUsageExtractor::extract(void) throw (Poco::Exception)
513 {
514  Poco::Mutex::ScopedLock lock(mutex);
515  ResourceUsage resourceUsage;
516 
517  resourceUsage.cpu = cpuUsageExtractor.getCpuUsage();
518  resourceUsage.iowait = cpuUsageExtractor.getIOWait();
519 
520  resourceUsage.diskUsed = diskSpaceExtractor.getDiskUsed();
522 
523  resourceUsage.vramUsed = memoryExtractor.getVramUsed();
525  resourceUsage.rramUsed = memoryExtractor.getRramUsed();
527 
529 
530  DRCEReadProcessData::getInstance().getProcessAndThreads(resourceUsage.processes, resourceUsage.threads);
531 
532  long sz = sysconf(_SC_PAGESIZE);
533  if (sz<0)
534  throw Poco::Exception(std::string("ResourceUsageExtractor::extract: ")+strerror(errno));
535 
536 // printf("Page size = %ld bytes \n", sz);
537 
538  size_t stacksize = 0;
539  pthread_attr_t attr;
540  pthread_attr_init(&attr);
541  pthread_attr_getstacksize(&attr, &stacksize);
542 // printf("Thread stack size = %zu bytes \n", stacksize);
543  stacksize /= 1024;
544 // printf("Thread stack size = %zu Kb \n", stacksize);
545 
546  size_t totalRamPages = (memoryExtractor.getRramTotal()/sz);
547 // printf("Total ram pages = %zu\n", totalRamPages);
548 
549  size_t maxThreads = (maxThreadsCount)?maxThreadsCount:(totalRamPages/(8*stacksize/sz));
550 // printf("Max threads = %zu\n", maxThreads);
551 
552 // std::cout << "getMaxProcesses(): " << getMaxProcesses() << std::endl;
553 // std::cout << "getMaxThreads(): " << getMaxThreads() << std::endl;
554 
555  resourceUsage.threadsPercent = static_cast<double>(resourceUsage.threads*100)/maxThreads;
556 
557  double numberThreads = static_cast<double>(memoryExtractor.getVramTotal())/(stacksize*1024*1024*1024);
558 // printf("Number of threads = %f\n", numberThreads);
559 
560  double maxProcesses = (maxProcessesCount)?maxProcessesCount:(static_cast<double>(maxThreads) / numberThreads);
561 // printf("Max Processes = %f\n", maxProcesses);
562 
563  resourceUsage.processesPercent = static_cast<double>(resourceUsage.processes*100)/maxProcesses;
564 
565  //TODO in future, here can be necessary refactoring
566  return resourceUsage;
567 }
568 //-----------------------------------------------------------------------------
570 {
571  Poco::Mutex::ScopedLock lock(mutex);
572  return cpuUsageExtractor;
573 }
574 //-----------------------------------------------------------------------------
576 {
577  Poco::Mutex::ScopedLock lock(mutex);
578  return diskSpaceExtractor;
579 }
580 //-----------------------------------------------------------------------------
582 {
583  Poco::Mutex::ScopedLock lock(mutex);
584  return memoryExtractor;
585 }
586 //-----------------------------------------------------------------------------
588 {
589  Poco::Mutex::ScopedLock lock(mutex);
590  return loadAverageExtractor;
591 }
592 //-----------------------------------------------------------------------------
593 void ResourceUsageExtractor::setMaxThreadsCount(size_t maxThreadsCount_)
594 {
595  Poco::Mutex::ScopedLock lock(mutex);
596  maxThreadsCount=maxThreadsCount_;
597 }
598 //-----------------------------------------------------------------------------
600 {
601  Poco::Mutex::ScopedLock lock(mutex);
602  return maxThreadsCount;
603 }
604 //-----------------------------------------------------------------------------
605 void ResourceUsageExtractor::setMaxProcessesCount(size_t maxProcessesCount_)
606 {
607  Poco::Mutex::ScopedLock lock(mutex);
608  maxProcessesCount=maxProcessesCount_;
609 }
610 //-----------------------------------------------------------------------------
612 {
613  Poco::Mutex::ScopedLock lock(mutex);
614  return maxProcessesCount;
615 }
616 //-----------------------------------------------------------------------------
617 void ResourceUsageExtractor::setMaxDiskSize(size_t maxDiskSize_)
618 {
619  Poco::Mutex::ScopedLock lock(mutex);
620  diskSpaceExtractor.setDiskSize(maxDiskSize_);
621 }
622 //-----------------------------------------------------------------------------
624 {
625  Poco::Mutex::ScopedLock lock(mutex);
627 }
628 //-----------------------------------------------------------------------------
629 void ResourceUsageExtractor::setMaxVramSize(size_t maxVramSize_)
630 {
631  Poco::Mutex::ScopedLock lock(mutex);
632  memoryExtractor.setVramTotal(maxVramSize_);
633 }
634 //-----------------------------------------------------------------------------
636 {
637  Poco::Mutex::ScopedLock lock(mutex);
638  return memoryExtractor.getVramTotal();
639 }
640 //-----------------------------------------------------------------------------
641 void ResourceUsageExtractor::setMaxRramSize(size_t maxRramSize_)
642 {
643  Poco::Mutex::ScopedLock lock(mutex);
644  memoryExtractor.setRramTotal(maxRramSize_);
645 }
646 //-----------------------------------------------------------------------------
648 {
649  Poco::Mutex::ScopedLock lock(mutex);
650  return memoryExtractor.getRramTotal();
651 }
652 //-----------------------------------------------------------------------------
653 //-----------------------------------------------------------------------------
654 } // end namespace drce
655 } // end namespace HCE