SystemInformation.cxx 148 KB
Newer Older
1
2
3
/*============================================================================
  KWSys - Kitware System Library
  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4

5
6
  Distributed under the OSI-approved BSD License (the "License");
  see accompanying file Copyright.txt for details.
7

8
9
10
11
  This software is distributed WITHOUT ANY WARRANTY; without even the
  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the License for more information.
============================================================================*/
12
13
14

#if defined(_WIN32)
# define NOMINMAX // use our min,max
15
16
17
# if !defined(_WIN32_WINNT) && !(defined(_MSC_VER) && _MSC_VER < 1300)
#  define _WIN32_WINNT 0x0501
# endif
Sebastien Barre's avatar
Sebastien Barre committed
18
19
20
# include <winsock.h> // WSADATA, include before sys/types.h
#endif

21
22
23
24
#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
# define _GNU_SOURCE
#endif

25
26
27
28
29
30
31
32
33
34
35
36
// TODO:
// We need an alternative implementation for many functions in this file
// when USE_ASM_INSTRUCTIONS gets defined as 0.
//
// Consider using these on Win32/Win64 for some of them:
//
// IsProcessorFeaturePresent
// http://msdn.microsoft.com/en-us/library/ms724482(VS.85).aspx
//
// GetProcessMemoryInfo
// http://msdn.microsoft.com/en-us/library/ms683219(VS.85).aspx

37
38
39
#include "kwsysPrivate.h"
#include KWSYS_HEADER(SystemInformation.hxx)
#include KWSYS_HEADER(Process.h)
40

41
42
43
44
45
// Work-around CMake dependency scanning limitation.  This must
// duplicate the above list of headers.
#if 0
# include "SystemInformation.hxx.in"
# include "Process.h.in"
46
47
#endif

48
49
50
#include <iostream>
#include <sstream>
#include <fstream>
Brad King's avatar
Brad King committed
51
52
#include <string>
#include <vector>
53

54
#if defined(_WIN32)
55
# include <windows.h>
56
57
58
# if defined(_MSC_VER) && _MSC_VER >= 1800
#  define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
# endif
59
# include <errno.h>
60
61
62
# if defined(KWSYS_SYS_HAS_PSAPI)
#  include <psapi.h>
# endif
63
# if !defined(siginfo_t)
64
typedef int siginfo_t;
65
66
67
68
69
# endif
#else
# include <sys/types.h>
# include <sys/time.h>
# include <sys/utsname.h> // int uname(struct utsname *buf);
70
# include <sys/resource.h> // getrlimit
71
72
73
74
# include <unistd.h>
# include <signal.h>
# include <fcntl.h>
# include <errno.h> // extern int errno;
75
76
#endif

77
78
79
80
81
#if defined (__CYGWIN__) && !defined(_WIN32)
# include <windows.h>
# undef _WIN32
#endif

82
83
84
85
86
87
88
89
90
91
92
93
#ifdef __FreeBSD__
# include <sys/sysctl.h>
# include <fenv.h>
# include <sys/socket.h>
# include <netdb.h>
# include <netinet/in.h>
# if defined(KWSYS_SYS_HAS_IFADDRS_H)
#  include <ifaddrs.h>
#  define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
# endif
#endif

94
95
96
97
98
#if defined(__OpenBSD__) || defined(__NetBSD__)
# include <sys/param.h>
# include <sys/sysctl.h>
#endif

99
100
101
102
#if defined(KWSYS_SYS_HAS_MACHINE_CPU_H)
# include <machine/cpu.h>
#endif

103
104
105
106
#if defined(__DragonFly__)
# include <sys/sysctl.h>
#endif

107
#ifdef __APPLE__
108
109
110
111
112
113
114
115
116
# include <sys/sysctl.h>
# include <mach/vm_statistics.h>
# include <mach/host_info.h>
# include <mach/mach.h>
# include <mach/mach_types.h>
# include <fenv.h>
# include <sys/socket.h>
# include <netdb.h>
# include <netinet/in.h>
117
118
119
120
# if defined(KWSYS_SYS_HAS_IFADDRS_H)
#  include <ifaddrs.h>
#  define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
# endif
121
122
# if !(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0 >= 1050)
#  undef KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE
123
# endif
124
125
#endif

126
#ifdef __linux
127
128
129
130
# include <fenv.h>
# include <sys/socket.h>
# include <netdb.h>
# include <netinet/in.h>
131
132
133
134
135
136
# if defined(KWSYS_SYS_HAS_IFADDRS_H)
#  include <ifaddrs.h>
#  if !defined(__LSB_VERSION__) /* LSB has no getifaddrs */
#   define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
#  endif
# endif
137
138
139
140
141
142
143
# if defined(KWSYS_CXX_HAS_RLIMIT64)
typedef struct rlimit64 ResourceLimitType;
#  define GetResourceLimit getrlimit64
# else
typedef struct rlimit ResourceLimitType;
#  define GetResourceLimit getrlimit
# endif
144
#elif defined( __hpux )
145
146
# include <sys/param.h>
# include <sys/pstat.h>
147
148
149
# if defined(KWSYS_SYS_HAS_MPCTL_H)
#  include <sys/mpctl.h>
# endif
150
151
#endif

152
#ifdef __HAIKU__
153
# include <OS.h>
154
155
#endif

156
157
158
159
160
161
162
163
164
165
166
167
168
#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
# include <execinfo.h>
# if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
#  include <cxxabi.h>
# endif
# if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
#  include <dlfcn.h>
# endif
#else
# undef KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE
# undef KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP
#endif

169
170
171
172
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
173
#include <ctype.h> // int isdigit(int c);
174

175
176
177
178
#if defined(KWSYS_USE_LONG_LONG)
# if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG)
#  define iostreamLongLong(x) (x)
# else
179
#  define iostreamLongLong(x) ((long)(x))
180
181
182
183
184
# endif
#elif defined(KWSYS_USE___INT64)
# if defined(KWSYS_IOS_HAS_OSTREAM___INT64)
#  define iostreamLongLong(x) (x)
# else
185
#  define iostreamLongLong(x) ((long)(x))
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# endif
#else
# error "No Long Long"
#endif

#if defined(KWSYS_CXX_HAS_ATOLL)
# define atoLongLong atoll
#else
# if defined(KWSYS_CXX_HAS__ATOI64)
#  define atoLongLong _atoi64
# elif defined(KWSYS_CXX_HAS_ATOL)
#  define atoLongLong atol
# else
#  define atoLongLong atoi
# endif
#endif

203
#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64) && !defined(__clang__)
204
205
206
207
208
#define USE_ASM_INSTRUCTIONS 1
#else
#define USE_ASM_INSTRUCTIONS 0
#endif

209
#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__clang__)
210
211
212
213
214
215
#include <intrin.h>
#define USE_CPUID_INTRINSICS 1
#else
#define USE_CPUID_INTRINSICS 0
#endif

216
#if USE_ASM_INSTRUCTIONS || USE_CPUID_INTRINSICS || defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID)
217
218
219
220
221
222
# define USE_CPUID 1
#else
# define USE_CPUID 0
#endif

#if USE_CPUID
223
224
225
226
227
228
229
230
231
232

#define CPUID_AWARE_COMPILER

/**
 * call CPUID instruction
 *
 * Will return false if the instruction failed.
 */
static bool call_cpuid(int select, int result[4])
{
233
234
235
236
#if USE_CPUID_INTRINSICS
  __cpuid(result, select);
  return true;
#else
237
  int tmp[4];
238
#if defined(_MSC_VER)
239
240
241
242
243
  // Use SEH to determine CPUID presence
  __try {
    _asm {
#ifdef CPUID_AWARE_COMPILER
      ; we must push/pop the registers <<CPUID>> writes to, as the
244
      ; optimiser does not know about <<CPUID>>, and so does not expect
245
246
247
248
249
250
251
252
      ; these registers to change.
      push eax
      push ebx
      push ecx
      push edx
#endif
      ; <<CPUID>>
      mov eax, select
253
254
255
256
257
258
#ifdef CPUID_AWARE_COMPILER
      cpuid
#else
      _asm _emit 0x0f
      _asm _emit 0xa2
#endif
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
      mov tmp[0 * TYPE int], eax
      mov tmp[1 * TYPE int], ebx
      mov tmp[2 * TYPE int], ecx
      mov tmp[3 * TYPE int], edx

#ifdef CPUID_AWARE_COMPILER
      pop edx
      pop ecx
      pop ebx
      pop eax
#endif
      }
    }
  __except(1)
    {
    return false;
    }

277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
    memcpy(result, tmp, sizeof(tmp));
#elif defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID)
  unsigned int a, b, c, d;
  __asm {
    mov EAX, select;
    cpuid
    mov a, EAX;
    mov b, EBX;
    mov c, ECX;
    mov d, EDX;
  }

  result[0] = a;
  result[1] = b;
  result[2] = c;
  result[3] = d;
#endif

295
296
  // The cpuid instruction succeeded.
  return true;
297
#endif
298
299
300
301
}
#endif


302
303
namespace KWSYS_NAMESPACE
{
304
305
template<typename T>
T min(T a, T b){ return a<b ? a : b; }
306

307
308
extern "C" { typedef void (*SigAction)(int,siginfo_t*,void*); }

309
310
311
//  Define SystemInformationImplementation class
typedef  void (*DELAY_FUNC)(unsigned int uiMS);

312
313
class SystemInformationImplementation
{
314
public:
315
  typedef SystemInformation::LongLong LongLong;
316
317
318
319
320
  SystemInformationImplementation ();
  ~SystemInformationImplementation ();

  const char * GetVendorString();
  const char * GetVendorID();
Brad King's avatar
Brad King committed
321
322
323
324
325
  std::string GetTypeID();
  std::string GetFamilyID();
  std::string GetModelID();
  std::string GetModelName();
  std::string GetSteppingCode();
326
327
328
  const char * GetExtendedProcessorName();
  const char * GetProcessorSerialNumber();
  int GetProcessorCacheSize();
329
  unsigned int GetLogicalProcessorsPerPhysical();
330
331
332
333
  float GetProcessorClockFrequency();
  int GetProcessorAPICID();
  int GetProcessorCacheXSize(long int);
  bool DoesCPUSupportFeature(long int);
334

335
336
  const char * GetOSName();
  const char * GetHostname();
Brad King's avatar
Brad King committed
337
  int GetFullyQualifiedDomainName(std::string &fqdn);
338
339
340
341
342
343
344
345
346
347
348
349
  const char * GetOSRelease();
  const char * GetOSVersion();
  const char * GetOSPlatform();

  bool Is64Bits();

  unsigned int GetNumberOfLogicalCPU(); // per physical cpu
  unsigned int GetNumberOfPhysicalCPU();

  bool DoesCPUSupportCPUID();

  // Retrieve memory information in megabyte.
350
351
352
  size_t GetTotalVirtualMemory();
  size_t GetAvailableVirtualMemory();
  size_t GetTotalPhysicalMemory();
353
354
  size_t GetAvailablePhysicalMemory();

355
  LongLong GetProcessId();
356
357

  // Retrieve memory information in kib
358
359
360
361
362
363
364
365
  LongLong GetHostMemoryTotal();
  LongLong GetHostMemoryAvailable(const char *envVarName);
  LongLong GetHostMemoryUsed();

  LongLong GetProcMemoryAvailable(
        const char *hostLimitEnvVarName,
        const char *procLimitEnvVarName);
  LongLong GetProcMemoryUsed();
366

367
368
  double GetLoadAverage();

369
370
371
  // enable/disable stack trace signal handler.
  static
  void SetStackTraceOnError(int enable);
372

373
374
  // get current stack
  static
Brad King's avatar
Brad King committed
375
  std::string GetProgramStack(int firstFrame, int wholePath);
376

377
378
379
380
  /** Run the different checks */
  void RunCPUCheck();
  void RunOSCheck();
  void RunMemoryCheck();
381

382
public:
383
  typedef struct tagID
384
385
386
387
388
389
390
    {
    int Type;
    int Family;
    int Model;
    int Revision;
    int ExtendedFamily;
    int ExtendedModel;
Brad King's avatar
Brad King committed
391
392
393
394
    std::string ProcessorName;
    std::string Vendor;
    std::string SerialNumber;
    std::string ModelName;
395
396
    } ID;

397
  typedef struct tagCPUPowerManagement
398
399
400
401
402
403
    {
    bool HasVoltageID;
    bool HasFrequencyID;
    bool HasTempSenseDiode;
    } CPUPowerManagement;

404
  typedef struct tagCPUExtendedFeatures
405
406
407
408
409
410
411
    {
    bool Has3DNow;
    bool Has3DNowPlus;
    bool SupportsMP;
    bool HasMMXPlus;
    bool HasSSEMMX;
    bool SupportsHyperthreading;
412
    unsigned int LogicalProcessorsPerPhysical;
413
414
    int APIC_ID;
    CPUPowerManagement PowerManagement;
415
416
417
    } CPUExtendedFeatures;

  typedef struct CPUtagFeatures
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
    {
    bool HasFPU;
    bool HasTSC;
    bool HasMMX;
    bool HasSSE;
    bool HasSSEFP;
    bool HasSSE2;
    bool HasIA64;
    bool HasAPIC;
    bool HasCMOV;
    bool HasMTRR;
    bool HasACPI;
    bool HasSerial;
    bool HasThermal;
    int CPUSpeed;
    int L1CacheSize;
    int L2CacheSize;
    int L3CacheSize;
    CPUExtendedFeatures ExtendedFeatures;
    } CPUFeatures;
438
439

  enum Manufacturer
440
    {
441
    AMD, Intel, NSC, UMC, Cyrix, NexGen, IDT, Rise, Transmeta, Sun, IBM,
442
    Motorola, HP, UnknownManufacturer
443
444
    };

445
protected:
446
  // For windows
447
448
449
450
451
452
453
454
455
456
457
458
  bool RetrieveCPUFeatures();
  bool RetrieveCPUIdentity();
  bool RetrieveCPUCacheDetails();
  bool RetrieveClassicalCPUCacheDetails();
  bool RetrieveCPUClockSpeed();
  bool RetrieveClassicalCPUClockSpeed();
  bool RetrieveCPUExtendedLevelSupport(int);
  bool RetrieveExtendedCPUFeatures();
  bool RetrieveProcessorSerialNumber();
  bool RetrieveCPUPowerManagement();
  bool RetrieveClassicalCPUIdentity();
  bool RetrieveExtendedCPUIdentity();
459

460
  // Processor information
461
462
463
464
465
466
467
  Manufacturer  ChipManufacturer;
  CPUFeatures   Features;
  ID            ChipID;
  float         CPUSpeedInMHz;
  unsigned int  NumberOfLogicalCPU;
  unsigned int  NumberOfPhysicalCPU;

468
  int CPUCount(); // For windows
469
  unsigned char LogicalCPUPerPhysicalCPU();
470
  unsigned char GetAPICId(); // For windows
471
  bool IsHyperThreadingSupported();
472
  static LongLong GetCyclesDifference(DELAY_FUNC, unsigned int); // For windows
473

474
  // For Linux and Cygwin, /proc/cpuinfo formats are slightly different
475
  bool RetreiveInformationFromCpuInfoFile();
Brad King's avatar
Brad King committed
476
  std::string ExtractValueFromCpuInfoFile(std::string buffer,
Bill Hoffman's avatar
Bill Hoffman committed
477
                                          const char* word, size_t init=0);
478

479
  bool QueryLinuxMemory();
480
  bool QueryCygwinMemory();
481

482
483
484
  static void Delay (unsigned int);
  static void DelayOverhead (unsigned int);

Brad King's avatar
Brad King committed
485
  void FindManufacturer(const std::string &family = "");
486
487
488

  // For Mac
  bool ParseSysCtl();
Brad King's avatar
Brad King committed
489
490
491
492
  int CallSwVers(const char *arg, std::string &ver);
  void TrimNewline(std::string&);
  std::string ExtractValueFromSysCtl(const char* word);
  std::string SysCtlBuffer;
493
494

  // For Solaris
495
496
  bool QuerySolarisMemory();
  bool QuerySolarisProcessor();
Brad King's avatar
Brad King committed
497
498
  std::string ParseValueFromKStat(const char* arguments);
  std::string RunProcess(std::vector<const char*> args);
499

500
501
502
  //For Haiku OS
  bool QueryHaikuInfo();

503
504
505
506
  //For QNX
  bool QueryQNXMemory();
  bool QueryQNXProcessor();

507
508
509
510
  //For OpenBSD, FreeBSD, NetBSD, DragonFly
  bool QueryBSDMemory();
  bool QueryBSDProcessor();

511
  //For HP-UX
512
  bool QueryHPUXMemory();
513
514
  bool QueryHPUXProcessor();

515
516
517
  //For Microsoft Windows
  bool QueryWindowsMemory();

518
519
520
  //For AIX
  bool QueryAIXMemory();

521
  bool QueryProcessorBySysconf();
522
523
  bool QueryProcessor();

524
  // Evaluate the memory information.
525
  bool QueryMemoryBySysconf();
526
  bool QueryMemory();
527
528
529
530
  size_t TotalVirtualMemory;
  size_t AvailableVirtualMemory;
  size_t TotalPhysicalMemory;
  size_t AvailablePhysicalMemory;
531

Bill Hoffman's avatar
Bill Hoffman committed
532
  size_t CurrentPositionInFile;
533
534
535

  // Operating System information
  bool QueryOSInformation();
Brad King's avatar
Brad King committed
536
537
538
539
540
  std::string OSName;
  std::string Hostname;
  std::string OSRelease;
  std::string OSVersion;
  std::string OSPlatform;
541
};
542

543

544
SystemInformation::SystemInformation()
545
546
547
548
{
  this->Implementation = new SystemInformationImplementation;
}

549
SystemInformation::~SystemInformation()
550
551
552
553
554
555
556
557
{
  delete this->Implementation;
}

const char * SystemInformation::GetVendorString()
{
  return this->Implementation->GetVendorString();
}
558

559
560
561
562
const char * SystemInformation::GetVendorID()
{
  return this->Implementation->GetVendorID();
}
563

Brad King's avatar
Brad King committed
564
std::string SystemInformation::GetTypeID()
565
566
567
{
  return this->Implementation->GetTypeID();
}
568

Brad King's avatar
Brad King committed
569
std::string SystemInformation::GetFamilyID()
570
571
572
{
  return this->Implementation->GetFamilyID();
}
573

Brad King's avatar
Brad King committed
574
std::string SystemInformation::GetModelID()
575
576
577
{
  return this->Implementation->GetModelID();
}
578

Brad King's avatar
Brad King committed
579
std::string SystemInformation::GetModelName()
580
581
582
583
{
  return this->Implementation->GetModelName();
}

Brad King's avatar
Brad King committed
584
std::string SystemInformation::GetSteppingCode()
585
586
587
{
  return this->Implementation->GetSteppingCode();
}
588

589
590
591
592
const char * SystemInformation::GetExtendedProcessorName()
{
  return this->Implementation->GetExtendedProcessorName();
}
593

594
595
596
597
const char * SystemInformation::GetProcessorSerialNumber()
{
  return this->Implementation->GetProcessorSerialNumber();
}
598

599
600
601
602
int SystemInformation::GetProcessorCacheSize()
{
  return this->Implementation->GetProcessorCacheSize();
}
603

604
unsigned int SystemInformation::GetLogicalProcessorsPerPhysical()
605
606
607
{
  return this->Implementation->GetLogicalProcessorsPerPhysical();
}
608

609
610
611
612
float SystemInformation::GetProcessorClockFrequency()
{
  return this->Implementation->GetProcessorClockFrequency();
}
613

614
615
616
617
int SystemInformation::GetProcessorAPICID()
{
  return this->Implementation->GetProcessorAPICID();
}
618

619
620
621
622
int SystemInformation::GetProcessorCacheXSize(long int l)
{
  return this->Implementation->GetProcessorCacheXSize(l);
}
623

624
625
626
627
628
bool SystemInformation::DoesCPUSupportFeature(long int i)
{
  return this->Implementation->DoesCPUSupportFeature(i);
}

Brad King's avatar
Brad King committed
629
std::string SystemInformation::GetCPUDescription()
630
{
631
  std::ostringstream oss;
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
  oss
    << this->GetNumberOfPhysicalCPU()
    << " core ";
  if (this->GetModelName().empty())
    {
    oss
      << this->GetProcessorClockFrequency()
      << " MHz "
      << this->GetVendorString()
      << " "
      << this->GetExtendedProcessorName();
    }
  else
    {
    oss << this->GetModelName();
    }

  // remove extra spaces
Brad King's avatar
Brad King committed
650
  std::string tmp=oss.str();
651
  size_t pos;
Brad King's avatar
Brad King committed
652
  while( (pos=tmp.find("  "))!=std::string::npos)
653
654
655
656
657
658
659
    {
    tmp.replace(pos,2," ");
    }

  return tmp;
}

660
661
662
663
const char * SystemInformation::GetOSName()
{
  return this->Implementation->GetOSName();
}
664

665
666
667
668
const char * SystemInformation::GetHostname()
{
  return this->Implementation->GetHostname();
}
669

Brad King's avatar
Brad King committed
670
std::string SystemInformation::GetFullyQualifiedDomainName()
671
{
Brad King's avatar
Brad King committed
672
  std::string fqdn;
673
  this->Implementation->GetFullyQualifiedDomainName(fqdn);
674
675
676
  return fqdn;
}

677
678
679
680
const char * SystemInformation::GetOSRelease()
{
  return this->Implementation->GetOSRelease();
}
681

682
683
684
685
const char * SystemInformation::GetOSVersion()
{
  return this->Implementation->GetOSVersion();
}
686

687
688
689
690
691
const char * SystemInformation::GetOSPlatform()
{
  return this->Implementation->GetOSPlatform();
}

692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
int SystemInformation::GetOSIsWindows()
{
#if defined(_WIN32)
  return 1;
#else
  return 0;
#endif
}

int SystemInformation::GetOSIsLinux()
{
#if defined(__linux)
  return 1;
#else
  return 0;
#endif
}

int SystemInformation::GetOSIsApple()
{
#if defined(__APPLE__)
  return 1;
#else
  return 0;
#endif
}

Brad King's avatar
Brad King committed
719
std::string SystemInformation::GetOSDescription()
720
{
721
  std::ostringstream oss;
722
723
724
725
726
727
728
729
730
731
  oss
    << this->GetOSName()
    << " "
    << this->GetOSRelease()
    << " "
    << this->GetOSVersion();

  return oss.str();
}

732
733
734
735
736
737
738
739
740
bool SystemInformation::Is64Bits()
{
  return this->Implementation->Is64Bits();
}

unsigned int SystemInformation::GetNumberOfLogicalCPU() // per physical cpu
{
  return this->Implementation->GetNumberOfLogicalCPU();
}
741

742
743
744
745
746
747
748
749
750
751
752
unsigned int SystemInformation::GetNumberOfPhysicalCPU()
{
  return this->Implementation->GetNumberOfPhysicalCPU();
}

bool SystemInformation::DoesCPUSupportCPUID()
{
  return this->Implementation->DoesCPUSupportCPUID();
}

// Retrieve memory information in megabyte.
753
size_t SystemInformation::GetTotalVirtualMemory()
754
755
756
{
  return this->Implementation->GetTotalVirtualMemory();
}
757

758
size_t SystemInformation::GetAvailableVirtualMemory()
759
760
761
{
  return this->Implementation->GetAvailableVirtualMemory();
}
762

763
size_t SystemInformation::GetTotalPhysicalMemory()
764
765
766
767
{
  return this->Implementation->GetTotalPhysicalMemory();
}

768
size_t SystemInformation::GetAvailablePhysicalMemory()
769
770
771
772
{
  return this->Implementation->GetAvailablePhysicalMemory();
}

Brad King's avatar
Brad King committed
773
std::string SystemInformation::GetMemoryDescription(
774
775
      const char *hostLimitEnvVarName,
      const char *procLimitEnvVarName)
776
{
777
  std::ostringstream oss;
778
  oss
779
780
781
782
783
784
785
786
    << "Host Total: "
    << iostreamLongLong(this->GetHostMemoryTotal())
    << " KiB, Host Available: "
    << iostreamLongLong(this->GetHostMemoryAvailable(hostLimitEnvVarName))
    << " KiB, Process Available: "
    << iostreamLongLong(
         this->GetProcMemoryAvailable(hostLimitEnvVarName,procLimitEnvVarName))
    << " KiB";
787
788
789
  return oss.str();
}

790
791
// host memory info in units of KiB.
SystemInformation::LongLong SystemInformation::GetHostMemoryTotal()
792
{
793
  return this->Implementation->GetHostMemoryTotal();
794
795
}

796
797
SystemInformation::LongLong
SystemInformation::GetHostMemoryAvailable(const char *hostLimitEnvVarName)
798
{
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
  return this->Implementation->GetHostMemoryAvailable(hostLimitEnvVarName);
}

SystemInformation::LongLong SystemInformation::GetHostMemoryUsed()
{
  return this->Implementation->GetHostMemoryUsed();
}

// process memory info in units of KiB.
SystemInformation::LongLong
SystemInformation::GetProcMemoryAvailable(
        const char *hostLimitEnvVarName,
        const char *procLimitEnvVarName)
{
  return this->Implementation->GetProcMemoryAvailable(
          hostLimitEnvVarName,
          procLimitEnvVarName);
}

SystemInformation::LongLong SystemInformation::GetProcMemoryUsed()
{
  return this->Implementation->GetProcMemoryUsed();
821
822
}

823
824
825
826
827
double SystemInformation::GetLoadAverage()
{
  return this->Implementation->GetLoadAverage();
}

828
SystemInformation::LongLong SystemInformation::GetProcessId()
829
830
831
832
833
834
835
836
837
{
  return this->Implementation->GetProcessId();
}

void SystemInformation::SetStackTraceOnError(int enable)
{
  SystemInformationImplementation::SetStackTraceOnError(enable);
}

Brad King's avatar
Brad King committed
838
std::string SystemInformation::GetProgramStack(int firstFrame, int wholePath)
839
840
841
842
{
  return SystemInformationImplementation::GetProgramStack(firstFrame, wholePath);
}

843
844
845
/** Run the different checks */
void SystemInformation::RunCPUCheck()
{
846
  this->Implementation->RunCPUCheck();
847
}
848

849
850
void SystemInformation::RunOSCheck()
{
851
  this->Implementation->RunOSCheck();
852
}
853

854
855
void SystemInformation::RunMemoryCheck()
{
856
  this->Implementation->RunMemoryCheck();
857
858
859
860
861
862
}


// --------------------------------------------------------------
// SystemInformationImplementation starts here

863
#define STORE_TLBCACHE_INFO(x,y)  x = (x < (y)) ? (y) : x
864
865
866
867
#define TLBCACHE_INFO_UNITS      (15)
#define CLASSICAL_CPU_FREQ_LOOP    10000000
#define RDTSC_INSTRUCTION      _asm _emit 0x0f _asm _emit 0x31

868
869
870
871
#define MMX_FEATURE            0x00000001
#define MMX_PLUS_FEATURE       0x00000002
#define SSE_FEATURE            0x00000004
#define SSE2_FEATURE           0x00000008
872
#define AMD_3DNOW_FEATURE      0x00000010
873
874
875
876
877
878
879
#define AMD_3DNOW_PLUS_FEATURE 0x00000020
#define IA64_FEATURE           0x00000040
#define MP_CAPABLE             0x00000080
#define HYPERTHREAD_FEATURE    0x00000100
#define SERIALNUMBER_FEATURE   0x00000200
#define APIC_FEATURE           0x00000400
#define SSE_FP_FEATURE         0x00000800
880
#define SSE_MMX_FEATURE        0x00001000
881
882
#define CMOV_FEATURE           0x00002000
#define MTRR_FEATURE           0x00004000
883
884
885
#define L1CACHE_FEATURE        0x00008000
#define L2CACHE_FEATURE        0x00010000
#define L3CACHE_FEATURE        0x00020000
886
887
888
889
890
#define ACPI_FEATURE           0x00040000
#define THERMALMONITOR_FEATURE 0x00080000
#define TEMPSENSEDIODE_FEATURE 0x00100000
#define FREQUENCYID_FEATURE    0x00200000
#define VOLTAGEID_FREQUENCY    0x00400000
891
892
893
894
895
896
897
898
899

// Status Flag
#define HT_NOT_CAPABLE           0
#define HT_ENABLED               1
#define HT_DISABLED              2
#define HT_SUPPORTED_NOT_ENABLED 3
#define HT_CANNOT_DETECT         4

// EDX[28]  Bit 28 is set if HT is supported
900
#define HT_BIT             0x10000000
901
902
903

// EAX[11:8] Bit 8-11 contains family processor ID.
#define FAMILY_ID          0x0F00
904
#define PENTIUM4_ID        0x0F00
905
// EAX[23:20] Bit 20-23 contains extended family processor ID
906
#define EXT_FAMILY_ID      0x0F00000
907
// EBX[23:16] Bit 16-23 in ebx contains the number of logical
908
909
#define NUM_LOGICAL_BITS   0x00FF0000
// processors per physical processor when execute cpuid with
910
// eax set to 1
911
912
// EBX[31:24] Bits 24-31 (8 bits) return the 8-bit unique
#define INITIAL_APIC_ID_BITS  0xFF000000
913
914
915
// initial APIC ID for the processor this code is running on.
// Default value = 0xff if HT is not supported

916
917
// Hide implementation details in an anonymous namespace.
namespace {
918
// *****************************************************************************
919
#if defined(__linux) || defined(__APPLE__)
920
int LoadLines(
921
      FILE *file,
Brad King's avatar
Brad King committed
922
      std::vector<std::string> &lines)
923
924
925
926
927
{
  // Load each line in the given file into a the vector.
  int nRead=0;
  const int bufSize=1024;
  char buf[bufSize]={'\0'};
928
929
930
931
932
933
934
935
936
937
938
  while (!feof(file) && !ferror(file))
    {
    errno=0;
    if (fgets(buf,bufSize,file) == 0)
      {
      if (ferror(file) && (errno==EINTR))
        {
        clearerr(file);
        }
      continue;
      }
939
940
941
942
943
944
    char *pBuf=buf;
    while(*pBuf)
      {
      if (*pBuf=='\n') *pBuf='\0';
      pBuf+=1;
      }
945
946
947
948
    lines.push_back(buf);
    ++nRead;
    }
  if (ferror(file))
949
950
951
    {
    return 0;
    }
952
953
954
  return nRead;
}

955
# if defined(__linux)
956
957
958
// *****************************************************************************
int LoadLines(
      const char *fileName,
Brad King's avatar
Brad King committed
959
      std::vector<std::string> &lines)
960
961
962
{
  FILE *file=fopen(fileName,"r");
  if (file==0)
963
    {
964
    return 0;
965
    }
966
967
  int nRead=LoadLines(file,lines);
  fclose(file);
968
969
  return nRead;
}
970
# endif
971
972
973
974

// ****************************************************************************
template<typename T>
int NameValue(
Brad King's avatar
Brad King committed
975
976
      std::vector<std::string> &lines,
      std::string name, T &value)
977
978
979
980
{
  size_t nLines=lines.size();
  for (size_t i=0; i<nLines; ++i)
    {
981
    size_t at=lines[i].find(name);
Brad King's avatar
Brad King committed
982
    if (at==std::string::npos)
983
      {
984
      continue;
985
      }
986
    std::istringstream is(lines[i].substr(at+name.size()));
987
988
    is >> value;
    return 0;
989
990
991
    }
  return -1;
}
992
#endif
993

994
#if defined(__linux)
995
996
997
998
999
1000
// ****************************************************************************
template<typename T>
int GetFieldsFromFile(
      const char *fileName,
      const char **fieldNames,
      T *values)
1001
{
Brad King's avatar
Brad King committed
1002
  std::vector<std::string> fields;
1003
1004
1005
1006
  if (!LoadLines(fileName,fields))
    {
    return -1;
    }
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
  int i=0;
  while (fieldNames[i]!=NULL)
    {
    int ierr=NameValue(fields,fieldNames[i],values[i]);
    if (ierr)
      {
      return -(i+2);
      }
    i+=1;
    }
  return 0;
}

// ****************************************************************************
template<typename T>
1022
1023
int GetFieldFromFile(
      const char *fileName,
1024
1025
1026
      const char *fieldName,
      T &value)
{
1027
  const char *fieldNames[2]={fieldName,NULL};
1028
  T values[1]={T(0)};
1029
  int ierr=GetFieldsFromFile(fileName,fieldNames,values);
1030
1031
  if (ierr)
    {
1032
1033
1034
1035
1036
    return ierr;
    }
  value=values[0];
  return 0;
}
1037
#endif
1038
1039

// ****************************************************************************
1040
#if defined(__APPLE__)
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
template<typename T>
int GetFieldsFromCommand(
      const char *command,
      const char **fieldNames,
      T *values)
{
  FILE *file=popen(command,"r");
  if (file==0)
    {
    return -1;
    }
Brad King's avatar
Brad King committed
1052
  std::vector<std::string> fields;
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
  int nl=LoadLines(file,fields);
  pclose(file);
  if (nl==0)
    {
    return -1;
    }
  int i=0;
  while (fieldNames[i]!=NULL)
    {
    int ierr=NameValue(fields,fieldNames[i],values[i]);
    if (ierr)
      {
      return -(i+2);
      }
    i+=1;
1068
1069
1070
    }
  return 0;
}
1071
#endif
1072

1073
// ****************************************************************************
1074
#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
1075
1076
1077
1078
1079
1080
void StacktraceSignalHandler(
      int sigNo,
      siginfo_t *sigInfo,
      void * /*sigContext*/)
{
#if defined(__linux) || defined(__APPLE__)
1081
  std::ostringstream oss;
1082
  oss
1083
1084
     << std::endl
     << "=========================================================" << std::endl
1085
     << "Process id " << getpid() << " ";
1086
1087
  switch (sigNo)
    {
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
    case SIGINT:
      oss << "Caught SIGINT";
      break;

    case SIGTERM:
      oss << "Caught SIGTERM";
      break;

    case SIGABRT:
      oss << "Caught SIGABRT";
      break;

1100
    case SIGFPE:
1101
1102
1103
1104
1105
      oss
        << "Caught SIGFPE at "
        << (sigInfo->si_addr==0?"0x":"")
        << sigInfo->si_addr
        <<  " ";
1106
1107
      switch (sigInfo->si_code)
        {
1108
# if defined(FPE_INTDIV)
1109
        case FPE_INTDIV:
1110
          oss << "integer division by zero";
1111
          break;
1112
# endif
1113

1114
# if defined(FPE_INTOVF)
1115
        case FPE_INTOVF:
1116
          oss << "integer overflow";
1117
          break;
1118
# endif
1119
1120

        case FPE_FLTDIV:
1121
          oss << "floating point divide by zero";
1122
1123
1124
          break;

        case FPE_FLTOVF:
1125
          oss << "floating point overflow";
1126
1127
1128
          break;

        case FPE_FLTUND:
1129
          oss << "floating point underflow";
1130
1131
1132
          break;

        case FPE_FLTRES:
1133
          oss << "floating point inexact result";
1134
1135
1136
          break;

        case FPE_FLTINV:
1137
          oss << "floating point invalid operation";
1138
1139
          break;

1140
#if defined(FPE_FLTSUB)
1141
        case FPE_FLTSUB:
1142
          oss << "floating point subscript out of range";
1143
          break;
1144
#endif
1145
1146

        default:
1147
          oss << "code " << sigInfo->si_code;
1148
1149
1150
1151
1152
          break;
        }
      break;

    case SIGSEGV:
1153
1154
1155
1156
1157
      oss
        << "Caught SIGSEGV at "
        << (sigInfo->si_addr==0?"0x":"")
        << sigInfo->si_addr
        <<  " ";
1158
1159
1160
      switch (sigInfo->si_code)
        {
        case SEGV_MAPERR:
1161
          oss << "address not mapped to object";
1162
1163
1164
          break;

        case SEGV_ACCERR:
1165
          oss << "invalid permission for mapped object";
1166
1167
1168
          break;

        default:
1169
          oss << "code " << sigInfo->si_code;
1170
1171
1172
1173
1174
          break;
        }
      break;

    case SIGBUS:
1175
1176
1177
1178
1179
      oss
        << "Caught SIGBUS at "
        << (sigInfo->si_addr==0?"0x":"")
        << sigInfo->si_addr
        <<  " ";
1180
1181
1182
      switch (sigInfo->si_code)
        {
        case BUS_ADRALN:
1183
          oss << "invalid address alignment";
1184
1185
          break;

1186
# if defined(BUS_ADRERR)
Burlen Loring's avatar