YARP
Yet Another Robot Platform
SystemInfo.cpp
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3  * SPDX-FileCopyrightText: 2006-2010 RobotCub Consortium
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <yarp/os/SystemInfo.h>
8 
9 #include <yarp/os/Os.h>
11 
12 #include <cstdio>
13 #include <cstdlib>
14 #include <cstring>
15 
16 using namespace yarp::os;
17 
18 #if defined(__linux__)
19 # include <arpa/inet.h>
20 # include <ifaddrs.h>
21 # include <linux/if.h>
22 # include <netinet/in.h>
23 # include <pwd.h>
24 # include <sys/ioctl.h>
25 # include <sys/socket.h>
26 # include <sys/statvfs.h>
27 # include <sys/types.h>
28 # include <sys/utsname.h>
29 # include <unistd.h>
30 
31 extern char** environ;
32 
33 #elif defined(__APPLE__)
34 # include <mach/mach.h>
35 # include <pwd.h>
36 # include <sstream>
37 # include <sys/mount.h>
38 # include <sys/param.h>
39 # include <sys/sysctl.h>
40 # include <sys/types.h>
41 # include <unistd.h>
42 
43 namespace {
44 
45 YARP_OS_LOG_COMPONENT(SYSTEMINFO, "yarp.os.SystemInfo")
46 
47 } // namespace
48 
49 #endif
50 
51 #if defined(_WIN32)
52 # include <Lmcons.h>
53 # include <comdef.h> // for using bstr_t class
54 # include <psapi.h>
55 # include <shlobj.h>
56 # include <windows.h>
57 //#define _WIN32_DCOM
58 # include <wbemidl.h>
59 # if (defined(WINVER)) && (WINVER >= 0x0502)
60 # include <pdh.h>
61 # include <pdhmsg.h>
62 # pragma comment(lib, "pdh.lib")
63 # pragma comment(lib, "psapi.lib") // for get proocess name for pid
64 # pragma comment(lib, "wbemuuid.lib") // for get process arguments from pid
65 # endif
66 
67 # include <yarp/os/PeriodicThread.h>
68 # include <yarp/os/Semaphore.h>
69 
70 # include <vector>
71 
72 
73 static void enableCpuLoadCollector();
74 static void disableCpuLoadCollector();
75 
76 #endif
77 
78 #if defined(__linux__)
79 SystemInfo::capacity_t getMemEntry(const char* tag, const char* bufptr)
80 {
81  char* tail;
83  size_t len = strlen(tag);
84  while (bufptr != nullptr) {
85  if (*bufptr == '\n') {
86  bufptr++;
87  }
88  if (strncmp(tag, bufptr, len) == 0) {
89  retval = strtol(bufptr + len, &tail, 10);
90  if (tail == bufptr + len) {
91  return -1;
92  }
93  return retval;
94  }
95  bufptr = strchr(bufptr, '\n');
96  }
97  return -1;
98 }
99 
100 
101 bool getCpuEntry(const char* tag, const char* buff, std::string& value)
102 {
103  if (strlen(buff) <= strlen(tag)) {
104  return false;
105  }
106 
107  if (strncmp(buff, tag, strlen(tag)) != 0) {
108  return false;
109  }
110 
111  const char* pos1 = strchr(buff, ':');
112  if (pos1 == nullptr) {
113  return false;
114  }
115 
116  while ((*pos1 != '\0') && ((*pos1 == ' ') || (*pos1 == ':') || (*pos1 == '\t'))) {
117  pos1++;
118  }
119  const char* pos2 = buff + strlen(buff) - 1;
120  while ((*pos2 != ':') && ((*pos2 == ' ') || (*pos2 == '\n'))) {
121  pos2--;
122  }
123  if (pos2 < pos1) {
124  return false;
125  }
126  value = std::string(pos1, pos2 - pos1 + 1);
127  return true;
128 }
129 #endif
130 
131 
132 #if defined(_WIN32)
133 class CpuLoadCollector : public yarp::os::PeriodicThread
134 {
135 public:
136  CpuLoadCollector() :
138  {
139  firstRun = true;
140  load.cpuLoad1 = 0.0;
141  load.cpuLoad5 = 0.0;
142  load.cpuLoad15 = 0.0;
143  load.cpuLoadInstant = (int)0;
144  }
145 
146  ~CpuLoadCollector()
147  {
148  }
149 
150  void run()
151  {
152  sem.wait();
153  load.cpuLoadInstant = (int)phdCpuLoad();
154  samples.push_back(load.cpuLoadInstant);
155  if (samples.size() > 180)
156  samples.erase(samples.begin());
157 
158  std::vector<int>::reverse_iterator rti;
159  int sum = 0;
160  int n = 0;
161  for (rti = samples.rbegin(); rti < samples.rend(); ++rti) {
162  sum += (*rti);
163  n++;
164  // every 1min
165  if (n < 12)
166  load.cpuLoad1 = (double)(sum / n) / 100.0;
167  // every 5min
168  if (n < 60)
169  load.cpuLoad5 = (double)(sum / n) / 100.0;
170  // every 15min
171  load.cpuLoad15 = (double)(sum / n) / 100.0;
172  }
173  sem.post();
174  }
175 
176  SystemInfo::LoadInfo getCpuLoad()
177  {
178  sem.wait();
179  SystemInfo::LoadInfo ld = load;
180  sem.post();
181  return ld;
182  }
183 
184  //bool threadInit()
185  //void threadRelease()
186 private:
187 # if (defined(WINVER)) && (WINVER >= 0x0502)
188  double phdCpuLoad()
189  {
190  DWORD ret;
191  if (firstRun) {
192  phdStatus = PdhOpenQuery(nullptr, 0, &hPhdQuery);
193  if (phdStatus != ERROR_SUCCESS)
194  return 0;
195 
196  PdhAddCounter(hPhdQuery, TEXT("\\Processor(_Total)\\% Processor Time"), 0, &phdCounter);
197  PdhCollectQueryData(hPhdQuery);
198  firstRun = false;
199  return 0;
200  }
201 
202  phdStatus = PdhCollectQueryData(hPhdQuery);
203  if (phdStatus != ERROR_SUCCESS)
204  return 0;
205  phdStatus = PdhGetFormattedCounterValue(phdCounter,
206  PDH_FMT_DOUBLE | PDH_FMT_NOCAP100,
207  &ret,
208  &phdFmtValue);
209  if (phdStatus != ERROR_SUCCESS)
210  return 0;
211  return phdFmtValue.doubleValue;
212  }
213 # else
214  double phdCpuLoad()
215  {
216  return 0.0;
217  }
218 # endif
219 
220 private:
221 # if (defined(WINVER)) && (WINVER >= 0x0502)
222  PDH_STATUS phdStatus;
223  HQUERY hPhdQuery;
224  PDH_FMT_COUNTERVALUE phdFmtValue;
225  HCOUNTER phdCounter;
226 # endif
227  bool firstRun;
229  std::vector<int> samples;
231 };
232 
233 static CpuLoadCollector* globalLoadCollector = nullptr;
234 
235 void enableCpuLoadCollector()
236 {
237  if (globalLoadCollector == nullptr) {
238  globalLoadCollector = new CpuLoadCollector();
239  globalLoadCollector->start();
240  }
241 }
242 
243 void disableCpuLoadCollector()
244 {
245  if (globalLoadCollector) {
246  globalLoadCollector->stop();
247  delete globalLoadCollector;
248  globalLoadCollector = nullptr;
249  }
250 }
251 
252 #endif
253 
254 
256 {
257  MemoryInfo memory;
258  memory.totalSpace = 0;
259  memory.freeSpace = 0;
260 
261 #if defined(_WIN32)
262  MEMORYSTATUSEX statex;
263  statex.dwLength = sizeof(statex);
264  if (GlobalMemoryStatusEx(&statex)) {
265  memory.totalSpace = (capacity_t)(statex.ullTotalPhys / 1048576); //in Mb
266  memory.freeSpace = (capacity_t)(statex.ullAvailPhys / 1048576); //in Mb
267  }
268 #endif
269 
270 #if defined(__linux__)
271  char buffer[128];
272  FILE* procmem = fopen("/proc/meminfo", "r");
273  if (procmem != nullptr) {
274  while (fgets(buffer, 128, procmem) != nullptr) {
275  capacity_t ret;
276  if ((ret = getMemEntry("MemTotal:", buffer)) > 0) {
277  memory.totalSpace = ret / 1024;
278  }
279 
280  if ((ret = getMemEntry("MemFree:", buffer)) > 0) {
281  memory.freeSpace = ret / 1024;
282  }
283  }
284  fclose(procmem);
285  }
286 #elif defined(__APPLE__)
287 
288  vm_size_t page_size;
289  mach_port_t mach_port;
290  mach_msg_type_number_t count;
291  vm_statistics64_data_t vm_stats;
292 
293  mach_port = mach_host_self();
294  count = HOST_VM_INFO64_COUNT;
295  if (KERN_SUCCESS == host_page_size(mach_port, &page_size) && KERN_SUCCESS == host_statistics64(mach_port, HOST_VM_INFO, (host_info64_t)&vm_stats, &count)) {
296  //These seem to return the # of pages
297  natural_t activePages = vm_stats.active_count + vm_stats.wire_count;
298  natural_t inactivePages = vm_stats.inactive_count + vm_stats.free_count;
299  natural_t totalPages = activePages + inactivePages;
300 
301  int64_t total = totalPages * page_size;
302  int64_t freeSpace = inactivePages * page_size;
303 
304  memory.totalSpace = total / 1024;
305  memory.freeSpace = freeSpace / 1024;
306  }
307 
308 #endif
309 
310 
311  return memory;
312 }
313 
314 
316 {
317  StorageInfo storage;
318  storage.totalSpace = 0;
319  storage.freeSpace = 0;
320 
321 #if defined(_WIN32)
322 
323  DWORD dwSectorsPerCluster = 0, dwBytesPerSector = 0;
324  DWORD dwFreeClusters = 0, dwTotalClusters = 0;
325  std::string strHome = getUserInfo().homeDir;
326  if (strHome.empty())
327  strHome = "C:\\";
328  if (GetDiskFreeSpaceA(strHome.c_str(), &dwSectorsPerCluster, &dwBytesPerSector, &dwFreeClusters, &dwTotalClusters)) {
329  storage.freeSpace = (capacity_t)((dwFreeClusters / 1048576.0) * dwSectorsPerCluster * dwBytesPerSector);
330  storage.totalSpace = (capacity_t)((dwTotalClusters) / 1048576.0 * dwSectorsPerCluster * dwBytesPerSector);
331  }
332 #endif
333 
334 #if defined(__linux__)
335  std::string strHome = getUserInfo().homeDir;
336  if (strHome.empty()) {
337  strHome = "/home";
338  }
339 
340  struct statvfs vfs;
341  if (statvfs(strHome.c_str(), &vfs) == 0) {
342  storage.totalSpace = (int)(vfs.f_blocks * vfs.f_bsize / (1048576)); // in MB
343  storage.freeSpace = (int)(vfs.f_bavail * vfs.f_bsize / (1048576)); // in MB
344  }
345 
346 #endif
347 
348 #if defined(__APPLE__)
349  std::string strHome = getUserInfo().homeDir;
350  if (strHome.empty())
351  strHome = "/";
352 
353  struct statfs vfs;
354  if (statfs(strHome.c_str(), &vfs) == 0) {
355  storage.totalSpace = (int)(vfs.f_blocks * vfs.f_bsize / (1048576)); // in MB
356  storage.freeSpace = (int)(vfs.f_bavail * vfs.f_bsize / (1048576)); // in MB
357  }
358 #endif
359 
360  return storage;
361 }
362 
363 /*
364 SystemInfo::NetworkInfo SystemInfo::getNetworkInfo()
365 {
366  NetworkInfo network;
367 
368 #if defined(__linux__)
369 
370  struct ifaddrs * ifAddrStruct=nullptr;
371  struct ifaddrs * ifa=nullptr;
372  void * tmpAddrPtr=nullptr;
373 
374  getifaddrs(&ifAddrStruct);
375  for (ifa = ifAddrStruct; ifa != nullptr; ifa = ifa->ifa_next)
376  {
377  if (ifa ->ifa_addr->sa_family == AF_INET)
378  {
379  // is a valid IP4 Address
380  tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
381  char addressBuffer[INET_ADDRSTRLEN];
382  const char* ret = inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
383  if (ret && (strcmp(ifa->ifa_name, "eth0") == 0))
384  network.ip4 = addressBuffer;
385  }
386  else if (ifa->ifa_addr->sa_family == AF_INET6)
387  {
388  // is a valid IP6 Address
389  tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
390  char addressBuffer[INET6_ADDRSTRLEN];
391  const char* ret = inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
392  if (ret && (strcmp(ifa->ifa_name, "eth0") == 0))
393  network.ip6 = addressBuffer;
394  }
395  }
396 
397  if (ifAddrStruct)
398  freeifaddrs(ifAddrStruct);
399 
400  // getting mac addrress
401  struct ifreq ifr;
402  struct ifreq *IFR;
403  struct ifconf ifc;
404  char buf[1024];
405  int s;
406  bool found = false;
407 
408  if ( (s = socket(AF_INET, SOCK_DGRAM, 0)) == -1 )
409  return network;
410 
411  ifc.ifc_len = sizeof(buf);
412  ifc.ifc_buf = buf;
413  ioctl(s, SIOCGIFCONF, &ifc);
414  IFR = ifc.ifc_req;
415  for (int i = ifc.ifc_len/sizeof(struct ifreq); --i >= 0; IFR++)
416  {
417  strcpy(ifr.ifr_name, IFR->ifr_name);
418  if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0)
419  {
420  if (!(ifr.ifr_flags & IFF_LOOPBACK))
421  {
422  if (ioctl(s, SIOCGIFHWADDR, &ifr) == 0)
423  {
424  found = true;
425  break;
426  }
427  }
428  }
429  }
430  close(s);
431 
432  if (found)
433  {
434  unsigned char addr[6];
435  char mac[32];
436  bcopy(ifr.ifr_hwaddr.sa_data, addr, 6);
437  sprintf(mac, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
438  addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
439  network.mac = mac;
440  }
441 
442 #endif
443  return network;
444 }
445 */
446 
447 
449 {
450  ProcessorInfo processor;
451  processor.cores = 0;
452  processor.frequency = 0.0;
453  processor.family = 0;
454  processor.modelNumber = 0;
455  processor.siblings = 0;
456 
457 #if defined(_WIN32)
458  SYSTEM_INFO sysinf;
459  GetSystemInfo(&sysinf);
460  switch (sysinf.wProcessorArchitecture) {
461  case PROCESSOR_ARCHITECTURE_AMD64: {
462  processor.architecture = "X64";
463  break;
464  }
465  case PROCESSOR_ARCHITECTURE_IA64: {
466  processor.architecture = "Intel Itanium-based";
467  break;
468  }
469  case PROCESSOR_ARCHITECTURE_INTEL: {
470  processor.architecture = "X86";
471  break;
472  }
473  default:
474  processor.architecture = "Unknown";
475  };
476  processor.siblings = sysinf.dwNumberOfProcessors;
477  processor.modelNumber = sysinf.dwProcessorType;
478  switch (sysinf.dwProcessorType) {
479  case PROCESSOR_INTEL_386: {
480  processor.model = "PROCESSOR_INTEL_386";
481  break;
482  }
483  case PROCESSOR_INTEL_486: {
484  processor.model = "PROCESSOR_INTEL_486";
485  break;
486  }
487  case PROCESSOR_INTEL_PENTIUM: {
488  processor.model = "PROCESSOR_INTEL_PENTIUM";
489  break;
490  }
491  case PROCESSOR_INTEL_IA64: {
492  processor.model = "PROCESSOR_INTEL_IA64";
493  break;
494  }
495  case PROCESSOR_AMD_X8664: {
496  processor.model = "PROCESSOR_AMD_X8664";
497  break;
498  }
499  };
500 
501  DWORD dwMHz;
502  DWORD BufSize = sizeof(DWORD);
503  HKEY hKey;
504  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
505  "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
506  0,
507  KEY_READ,
508  &hKey)
509  == ERROR_SUCCESS) {
510  RegQueryValueEx(hKey, "~MHz", nullptr, nullptr, (LPBYTE)&dwMHz, &BufSize);
511  processor.frequency = (double)dwMHz;
512  RegCloseKey(hKey);
513  }
514 
515  // TODO: this should be fixed to obtain correct number of physical cores
516  processor.cores = 1;
517 
518 #endif
519 
520 #if defined(__linux__)
521  char buffer[128];
522  FILE* proccpu = fopen("/proc/cpuinfo", "r");
523  if (proccpu != nullptr) {
524  while (fgets(buffer, 128, proccpu) != nullptr) {
525  std::string value;
526  if (getCpuEntry("model", buffer, value) && !getCpuEntry("model name", buffer, value)) {
527  processor.modelNumber = atoi(value.c_str());
528  }
529  if (getCpuEntry("model name", buffer, value)) {
530  processor.model = value;
531  }
532  if (getCpuEntry("vendor_id", buffer, value)) {
533  processor.vendor = value;
534  }
535  if (getCpuEntry("cpu family", buffer, value)) {
536  processor.family = atoi(value.c_str());
537  }
538  if (getCpuEntry("cpu cores", buffer, value)) {
539  processor.cores = atoi(value.c_str());
540  }
541  if (getCpuEntry("siblings", buffer, value)) {
542  processor.siblings = atoi(value.c_str());
543  }
544  if (getCpuEntry("cpu MHz", buffer, value)) {
545  processor.frequency = atof(value.c_str());
546  }
547  }
548  fclose(proccpu);
549  }
550 
551  struct utsname uts;
552  if (uname(&uts) == 0) {
553  processor.architecture = uts.machine;
554  }
555 #elif defined(__APPLE__)
556  // std::string architecture;
557 
558  int mib[] = {CTL_HW, HW_CPU_FREQ};
559  int64_t value = 0;
560  size_t length = sizeof(value);
561 
562  if (!sysctl(mib, 2, &value, &length, nullptr, 0)) {
563  processor.frequency = value / 1e+6; //this is in Hz. What is the expected frequency?
564  }
565 
566  if (!sysctlbyname("hw.logicalcpu", &value, &length, nullptr, 0)) {
567  processor.cores = value; //this is the number of cores
568  //or cpus: hw.physicalcpu
569  }
570 
571  char buff[513];
572  size_t buffLen = 512;
573  if (!sysctlbyname("machdep.cpu.vendor", buff, &buffLen, nullptr, 0)) {
574  processor.vendor = buff; //this is the number of cores
575  //or cpus: hw.physicalcpu
576  }
577  buffLen = 512;
578  if (!sysctlbyname("machdep.cpu.brand_string", buff, &buffLen, nullptr, 0)) {
579  processor.model = buff; //this is the number of cores
580  //or cpus: hw.physicalcpu
581  }
582  if (!sysctlbyname("machdep.cpu.family", &value, &length, nullptr, 0)) {
583  processor.family = value; //this is the number of cores
584  //or cpus: hw.physicalcpu
585  }
586  if (!sysctlbyname("machdep.cpu.model", &value, &length, nullptr, 0)) {
587  processor.modelNumber = value; //this is the number of cores
588  //or cpus: hw.physicalcpu
589  }
590 
591 
592 #endif
593  return processor;
594 }
595 
596 
598 {
599  PlatformInfo platform;
600 
601 #if defined(_WIN32)
602  platform.name = "Windows";
603  OSVERSIONINFOEX osver;
604  osver.dwOSVersionInfoSize = sizeof(osver);
605  if (GetVersionEx((LPOSVERSIONINFO)&osver)) {
606  char buff[64];
607  sprintf(buff, "%d.%d", osver.dwMajorVersion, osver.dwMinorVersion);
608  platform.release = buff;
609  platform.codename = buff;
610  if ((osver.dwMajorVersion == 10) && (osver.dwMinorVersion == 0) && (osver.wProductType == VER_NT_WORKSTATION)) {
611  platform.distribution = "10";
612  } else if ((osver.dwMajorVersion == 10) && (osver.dwMinorVersion == 0) && (osver.wProductType != VER_NT_WORKSTATION)) {
613  platform.distribution = "Server 2016";
614  } else if ((osver.dwMajorVersion == 6) && (osver.dwMinorVersion == 2) && (osver.wProductType == VER_NT_WORKSTATION)) {
615  platform.distribution = "8.1";
616  } else if ((osver.dwMajorVersion == 6) && (osver.dwMinorVersion == 3) && (osver.wProductType != VER_NT_WORKSTATION)) {
617  platform.distribution = "Server 2012 R2";
618  } else if ((osver.dwMajorVersion == 6) && (osver.dwMinorVersion == 2) && (osver.wProductType == VER_NT_WORKSTATION)) {
619  platform.distribution = "8";
620  } else if ((osver.dwMajorVersion == 6) && (osver.dwMinorVersion == 2) && (osver.wProductType != VER_NT_WORKSTATION)) {
621  platform.distribution = "Server 2012";
622  } else if ((osver.dwMajorVersion == 6) && (osver.dwMinorVersion == 1) && (osver.wProductType == VER_NT_WORKSTATION)) {
623  platform.distribution = "7";
624  } else if ((osver.dwMajorVersion == 6) && (osver.dwMinorVersion == 1) && (osver.wProductType != VER_NT_WORKSTATION)) {
625  platform.distribution = "Server 2008 R2";
626  } else if ((osver.dwMajorVersion == 6) && (osver.dwMinorVersion == 0) && (osver.wProductType == VER_NT_WORKSTATION)) {
627  platform.distribution = "Vista";
628  } else if ((osver.dwMajorVersion == 6) && (osver.dwMinorVersion == 0) && (osver.wProductType != VER_NT_WORKSTATION)) {
629  platform.distribution = "Server 2008";
630  } else if ((osver.dwMajorVersion == 5) && (osver.dwMinorVersion == 2)) {
631  platform.distribution = "Server 2003";
632  // } else if ((osver.dwMajorVersion == 5) && (osver.dwMinorVersion == 2) && (osver.wSuiteMask & VER_SUITE_WH_SERVER)) {
633  // platform.distribution = "Home Server";
634  // } else if ((osver.dwMajorVersion == 5) && (osver.dwMinorVersion == 2) && (GetSystemMetrics(SM_SERVERR2) != 0)) {
635  // platform.distribution = "Server 2003 R2";
636  } else if ((osver.dwMajorVersion == 5) && (osver.dwMinorVersion == 2) && (osver.wProductType == VER_NT_WORKSTATION)) /* &&(osver.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)*/ {
637  platform.distribution = "XP Professional x64 Edition";
638  } else if ((osver.dwMajorVersion == 5) && (osver.dwMinorVersion == 1)) {
639  platform.distribution = "XP";
640  } else if ((osver.dwMajorVersion == 5) && (osver.dwMinorVersion == 0)) {
641  platform.distribution = "2000";
642  }
643  }
644 
645  const char* a = GetEnvironmentStrings();
646  size_t prev = 0;
647  for (size_t i = 0;; i++) {
648  if (a[i] == '\0') {
649  std::string tmpVariable(a + prev, a + i);
650  size_t equalsSign = tmpVariable.find("=");
651  if (equalsSign != std::string::npos && equalsSign != 0) // among environment variables there are DOS-related ones that start with a =
652  {
653  platform.environmentVars.put(tmpVariable.substr(0, equalsSign), tmpVariable.substr(equalsSign + 1));
654  }
655  prev = i + 1;
656  if (a[i + 1] == '\0') {
657  break;
658  }
659  }
660  }
661 
662 #endif
663 
664 #if defined(__linux__)
665  struct utsname uts;
666  if (uname(&uts) == 0) {
667  platform.name = uts.sysname;
668  platform.kernel = uts.release;
669  } else {
670  platform.name = "Linux";
671  }
672 
673  char buffer[128];
674  FILE* release = popen("lsb_release -ric", "r");
675  if (release != nullptr) {
676  while (fgets(buffer, 128, release) != nullptr) {
677  std::string value;
678  if (getCpuEntry("Distributor ID", buffer, value)) {
679  platform.distribution = value;
680  }
681  if (getCpuEntry("Release", buffer, value)) {
682  platform.release = value;
683  }
684  if (getCpuEntry("Codename", buffer, value)) {
685  platform.codename = value;
686  }
687  }
688  pclose(release);
689  }
690 
691  char* varChar = *environ;
692 
693  for (int i = 0; varChar != nullptr; i++) {
694  std::string tmpVariable(varChar);
695  size_t equalsSign = tmpVariable.find('=');
696  if (equalsSign != std::string::npos) {
697  platform.environmentVars.put(tmpVariable.substr(0, equalsSign), tmpVariable.substr(equalsSign + 1));
698  }
699  varChar = *(environ + i);
700  }
701 #endif
702 
703 #if defined(__APPLE__)
704 
705  char buff[513];
706  size_t buffLen = 512;
707  if (!sysctlbyname("kern.ostype", buff, &buffLen, nullptr, 0)) {
708  platform.name = buff;
709  }
710 
711  if (!sysctlbyname("kern.osrelease", buff, &buffLen, nullptr, 0)) {
712  platform.release = buff;
713  }
714 
715 #endif
716  return platform;
717 }
718 
719 
721 {
722  UserInfo user;
723  user.userID = 0;
724 
725 #if defined(_WIN32)
726  char path[MAX_PATH + 1];
727  if (SHGetFolderPathA(nullptr, CSIDL_PROFILE, nullptr, 0, path) == S_OK)
728  user.homeDir = path;
729 
730  char username[UNLEN + 1];
731  DWORD nsize = UNLEN + 1;
732  if (GetUserName(username, &nsize)) {
733  user.userName = username;
734  user.realName = username;
735  }
736 #endif
737 
738 #if defined(__linux__) || defined(__APPLE__)
739  struct passwd* pwd = getpwuid(getuid());
740  user.userID = getuid();
741  if (pwd != nullptr) {
742  user.userName = pwd->pw_name;
743  user.realName = pwd->pw_gecos;
744  user.homeDir = pwd->pw_dir;
745  }
746 #endif
747  return user;
748 }
749 
750 
752 {
753  LoadInfo load;
754  load.cpuLoad1 = 0.0;
755  load.cpuLoad5 = 0.0;
756  load.cpuLoad15 = 0.0;
757  load.cpuLoadInstant = 0;
758 
759 #if defined(_WIN32)
760  if (globalLoadCollector) {
761  load = globalLoadCollector->getCpuLoad();
762  int siblings = getProcessorInfo().siblings;
763  if (siblings > 1) {
764  load.cpuLoad1 *= siblings;
765  load.cpuLoad5 *= siblings;
766  load.cpuLoad15 *= siblings;
767  }
768  }
769 #endif
770 
771 #if defined(__linux__)
772  FILE* procload = fopen("/proc/loadavg", "r");
773  if (procload != nullptr) {
774  char buff[128];
775  int ret = fscanf(procload, "%lf %lf %lf %s", &(load.cpuLoad1), &(load.cpuLoad5), &(load.cpuLoad15), buff);
776  if (ret > 0) {
777  char* tail = strchr(buff, '/');
778  if ((tail != nullptr) && (tail != buff)) {
779  load.cpuLoadInstant = (int)(strtol(buff, &tail, 0) - 1);
780  }
781  }
782  fclose(procload);
783  }
784 #endif
785 
786 #if defined(__APPLE__)
787 
788  mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
789  host_cpu_load_info_data_t cpu_load;
790 
791  if (KERN_SUCCESS == host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info64_t)&cpu_load, &count)) {
792  //How to map this information into yarp structure?
793  natural_t total = 0;
794  for (int i = 0; i < CPU_STATE_MAX; ++i) {
795  total += cpu_load.cpu_ticks[i];
796  }
797 
798  load.cpuLoad1 = 100.0 * cpu_load.cpu_ticks[CPU_STATE_USER] / total;
799  }
800 #endif
801  return load;
802 }
803 
804 
806 {
807  // If not specified, get information for current process
808  if (pid == 0) {
809  pid = yarp::os::getpid();
810  }
811 
813  info.pid = -1; // invalid
814  info.schedPolicy = -1;
815  info.schedPriority = -1;
816 #if defined(__linux__)
817  FILE* file;
818  char cmdline[256] = {0};
819  char filename[256];
820  sprintf(filename, "/proc/%d/cmdline", pid);
821  file = fopen(filename, "r");
822  if (file != nullptr) {
823  char* p = fgets(cmdline, sizeof(cmdline) / sizeof(*cmdline), file);
824  fclose(file);
825  if (p != nullptr) {
826  while (*p != 0) {
827  p += strlen(p);
828  if (*(p + 1) != 0) {
829  *p = ' ';
830  }
831  p++;
832  }
833  info.pid = pid;
834  // split the cmdline to find the arguments
835  info.name = cmdline;
836  size_t index = info.name.find(' ');
837  if (index != std::string::npos) {
838  info.name = info.name.substr(0, index);
839  info.arguments = cmdline;
840  info.arguments = info.arguments.substr(index + 1);
841  }
842  }
843  }
844 
845  // scheduling params
846  struct sched_param param;
847  if (sched_getparam(pid, &param) == 0) {
848  info.schedPriority = param.__sched_priority;
849  }
850  info.schedPolicy = sched_getscheduler(pid);
851 
852 #elif defined(_WIN32)
853  HANDLE hnd = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
854  if (hnd) {
855  TCHAR filename[MAX_PATH];
856  if (GetModuleBaseName(hnd, 0, filename, MAX_PATH)) {
857  info.name = filename;
858  info.pid = pid;
859  }
860  CloseHandle(hnd);
861  }
862  // reterieving arguments
863  HRESULT hr = 0;
864  IWbemLocator* WbemLocator = nullptr;
865  IWbemServices* WbemServices = nullptr;
866  IEnumWbemClassObject* EnumWbem = nullptr;
867 
868  //initializate the Windows security
869  hr = CoInitializeEx(0, COINIT_MULTITHREADED);
870  hr = CoInitializeSecurity(nullptr, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE, nullptr);
871  hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&WbemLocator);
872  if (WbemLocator != nullptr) {
873  //connect to the WMI
874  hr = WbemLocator->ConnectServer(L"ROOT\\CIMV2", nullptr, nullptr, 0, 0, 0, 0, &WbemServices);
875  if (WbemServices != nullptr) {
876  //Run the WQL Query
877  hr = WbemServices->ExecQuery(L"WQL", L"SELECT ProcessId, CommandLine FROM Win32_Process", WBEM_FLAG_FORWARD_ONLY, nullptr, &EnumWbem);
878  // Iterate over the enumerator
879  if (EnumWbem != nullptr) {
880  IWbemClassObject* result = nullptr;
881  ULONG returnedCount = 0;
882 
883  while ((hr = EnumWbem->Next(WBEM_INFINITE, 1, &result, &returnedCount)) == S_OK) {
884  VARIANT ProcessId;
885  VARIANT CommandLine;
886 
887  // access the properties
888  hr = result->Get(L"ProcessId", 0, &ProcessId, 0, 0);
889  hr = result->Get(L"CommandLine", 0, &CommandLine, 0, 0);
890  if (!(CommandLine.vt == VT_NULL) && ProcessId.uintVal == (unsigned int)pid) {
891  // covert BSTR to std::string
892  int res = WideCharToMultiByte(CP_UTF8, 0, CommandLine.bstrVal, -1, nullptr, 0, nullptr, nullptr);
893  info.arguments.resize(res);
894  WideCharToMultiByte(CP_UTF8, 0, CommandLine.bstrVal, -1, &info.arguments[0], res, nullptr, nullptr);
895  size_t idx = info.arguments.find(' ');
896  if (idx == info.arguments.npos) {
897  info.arguments.clear();
898  } else {
899  info.arguments = info.arguments.substr(idx + 2); // it seems windows adds two spaces after the program name
900  }
901  info.pid = pid;
902  VariantClear(&ProcessId);
903  VariantClear(&CommandLine);
904  break;
905  }
906  result->Release();
907  } // end while
908 
909  EnumWbem->Release();
910  } // end if EnumWbem
911 
912  WbemServices->Release();
913  } // end if WbemServices
914 
915  WbemLocator->Release();
916  } // end if WbemLocator
917 
918  CoUninitialize();
919 #elif defined(__APPLE__)
920  kinfo_proc procInfo;
921  size_t length = sizeof(procInfo);
922 
923  int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
924 
925  if (!sysctl(mib, 4, &procInfo, &length, nullptr, 0)) {
926  info.name = procInfo.kp_proc.p_comm;
927  info.pid = procInfo.kp_proc.p_pid;
928 
929  //Some info here: https://gist.github.com/nonowarn/770696
930  mib[1] = KERN_PROCARGS;
931  mib[2] = pid;
932  char* proc_argv;
933  size_t argv_len;
934  //getting length of execute string
935  int result = sysctl(mib, 3, nullptr, &argv_len, nullptr, 0);
936  if (result != 0) {
937  yCError(SYSTEMINFO, "sysctl: %d, %s", errno, strerror(errno));
938  return info;
939  }
940 
941  //now getting the string
942  proc_argv = (char*)malloc(sizeof(char) * argv_len);
943  result = sysctl(mib, 3, proc_argv, &argv_len, nullptr, 0);
944  if (result != 0) {
945  yCError(SYSTEMINFO, "sysctl: %d, %s", errno, strerror(errno));
946  free(proc_argv);
947  return info;
948  }
949 
950  //looking for '\0', i.e. NULL char
951  //skip first string which is the executable
952  size_t index = 0;
953  while (index < argv_len && proc_argv[index] != '\0') {
954  index++;
955  }
956  index++;
957  //now we have to split the remaining string
958  //Note: this is not easy. We don't know the format
959  //See: http://lists.apple.com/archives/darwin-kernel/2012/Mar/msg00025.html
960  //for example, I get both arguments and environment variables
961 
962  std::stringstream arguments;
963  while (index < argv_len) {
964  if (proc_argv[index] == '\0' && index != argv_len - 1) {
965  arguments << " ";
966  } else {
967  arguments << proc_argv[index];
968  }
969  index++;
970  }
971 
972  free(proc_argv);
973  info.arguments = arguments.str();
974  }
975 
976 #endif
977  return info;
978 }
int16_t * samples
bool ret
void * HANDLE
An abstraction for a periodic thread.
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition: Property.cpp:1015
A class for thread synchronization and mutual exclusion.
Definition: Semaphore.h:26
static MemoryInfo getMemoryInfo()
getMemoryInfo
Definition: SystemInfo.cpp:255
static ProcessInfo getProcessInfo(int pid=0)
gets the operating system process information given by its PID.
Definition: SystemInfo.cpp:805
static PlatformInfo getPlatformInfo()
getPlatformInfo
Definition: SystemInfo.cpp:597
static UserInfo getUserInfo()
getUserInfo
Definition: SystemInfo.cpp:720
static LoadInfo getLoadInfo()
getLoadInfo
Definition: SystemInfo.cpp:751
static StorageInfo getStorageInfo()
getStorageInfo
Definition: SystemInfo.cpp:315
static ProcessorInfo getProcessorInfo()
getProcessorInfo
Definition: SystemInfo.cpp:448
#define yCError(component,...)
Definition: LogComponent.h:154
#define YARP_OS_LOG_COMPONENT(name, name_string)
Definition: LogComponent.h:34
An interface to the operating system, including Port based communication.
int getpid()
Portable wrapper for the getppid() function.
Definition: Os.cpp:91
ShouldUseSystemClock
Definition: Time.h:20
The LoadInfo struct holds the current cpu load information.
Definition: SystemInfo.h:69
The MemoryInfo struct holds the system memory information.
Definition: SystemInfo.h:34
The PlatformInfo struct holds the operating system information.
Definition: SystemInfo.h:81
yarp::os::Property environmentVars
Definition: SystemInfo.h:87
The ProcessInfo struct provides the operating system process information.
Definition: SystemInfo.h:113
The ProcessorInfo struct holds the processor information.
Definition: SystemInfo.h:53
The StorageInfo struct holds the system storage information.
Definition: SystemInfo.h:44
The UserInfo struct holds the current user information.
Definition: SystemInfo.h:94