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