00001
00032 #include "linden_common.h"
00033
00034 #include "llsys.h"
00035
00036 #include <iostream>
00037 #ifdef LL_STANDALONE
00038 # include <zlib.h>
00039 #else
00040 # include "zlib/zlib.h"
00041 #endif
00042
00043 #include "llprocessor.h"
00044
00045 #if LL_WINDOWS
00046 # define WIN32_LEAN_AND_MEAN
00047 # include <winsock2.h>
00048 # include <windows.h>
00049 #elif LL_DARWIN
00050 # include <errno.h>
00051 # include <sys/sysctl.h>
00052 # include <sys/utsname.h>
00053 # include <stdint.h>
00054 #elif LL_LINUX
00055 # include <errno.h>
00056 # include <sys/utsname.h>
00057 # include <unistd.h>
00058 # include <sys/sysinfo.h>
00059 const char MEMINFO_FILE[] = "/proc/meminfo";
00060 const char CPUINFO_FILE[] = "/proc/cpuinfo";
00061 #endif
00062
00063
00064 static const S32 CPUINFO_BUFFER_SIZE = 16383;
00065 LLCPUInfo gSysCPU;
00066
00067 LLOSInfo::LLOSInfo() :
00068 mMajorVer(0), mMinorVer(0), mBuild(0),
00069 mOSString("")
00070 {
00071
00072 #if LL_WINDOWS
00073 OSVERSIONINFOEX osvi;
00074 BOOL bOsVersionInfoEx;
00075
00076
00077 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
00078 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
00079 if(!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) &osvi)))
00080 {
00081
00082 osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
00083 if(!GetVersionEx( (OSVERSIONINFO *) &osvi))
00084 return;
00085 }
00086 mMajorVer = osvi.dwMajorVersion;
00087 mMinorVer = osvi.dwMinorVersion;
00088 mBuild = osvi.dwBuildNumber;
00089
00090 switch(osvi.dwPlatformId)
00091 {
00092 case VER_PLATFORM_WIN32_NT:
00093 {
00094
00095 if(osvi.dwMajorVersion <= 4)
00096 {
00097 mOSString = "Microsoft Windows NT ";
00098 }
00099 else if(osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
00100 {
00101 mOSString = "Microsoft Windows 2000 ";
00102 }
00103 else if(osvi.dwMajorVersion ==5 && osvi.dwMinorVersion == 1)
00104 {
00105 mOSString = "Microsoft Windows XP ";
00106 }
00107 else if(osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
00108 {
00109 if(osvi.wProductType == VER_NT_WORKSTATION)
00110 mOSString = "Microsoft Windows XP x64 Edition ";
00111 else mOSString = "Microsoft Windows Server 2003 ";
00112 }
00113 else if(osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0)
00114 {
00115 if(osvi.wProductType == VER_NT_WORKSTATION)
00116 mOSString = "Microsoft Windows Vista ";
00117 else mOSString = "Microsoft Windows Vista Server ";
00118 }
00119 else
00120 {
00121 HKEY hKey;
00122 WCHAR szProductType[80];
00123 DWORD dwBufLen;
00124 RegOpenKeyEx( HKEY_LOCAL_MACHINE,
00125 L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
00126 0, KEY_QUERY_VALUE, &hKey );
00127 RegQueryValueEx( hKey, L"ProductType", NULL, NULL,
00128 (LPBYTE) szProductType, &dwBufLen);
00129 RegCloseKey( hKey );
00130 if ( lstrcmpi( L"WINNT", szProductType) == 0 )
00131 {
00132 mOSString += "Professional ";
00133 }
00134 else if ( lstrcmpi( L"LANMANNT", szProductType) == 0 )
00135 {
00136 mOSString += "Server ";
00137 }
00138 else if ( lstrcmpi( L"SERVERNT", szProductType) == 0 )
00139 {
00140 mOSString += "Advanced Server ";
00141 }
00142 }
00143
00144 std::string csdversion = utf16str_to_utf8str(osvi.szCSDVersion);
00145
00146 char tmp[MAX_STRING];
00147 if(osvi.dwMajorVersion <= 4)
00148 {
00149 snprintf(
00150 tmp,
00151 sizeof(tmp),
00152 "version %d.%d %s (Build %d)",
00153 osvi.dwMajorVersion,
00154 osvi.dwMinorVersion,
00155 csdversion.c_str(),
00156 (osvi.dwBuildNumber & 0xffff));
00157 }
00158 else
00159 {
00160 snprintf(
00161 tmp,
00162 sizeof(tmp),
00163 "%s (Build %d)",
00164 csdversion.c_str(),
00165 (osvi.dwBuildNumber & 0xffff));
00166 }
00167 mOSString += tmp;
00168 }
00169 break;
00170
00171 case VER_PLATFORM_WIN32_WINDOWS:
00172
00173 if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
00174 {
00175 mOSString = "Microsoft Windows 95 ";
00176 if ( osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B' )
00177 {
00178 mOSString += "OSR2 ";
00179 }
00180 }
00181 if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
00182 {
00183 mOSString = "Microsoft Windows 98 ";
00184 if ( osvi.szCSDVersion[1] == 'A' )
00185 {
00186 mOSString += "SE ";
00187 }
00188 }
00189 if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
00190 {
00191 mOSString = "Microsoft Windows Millennium Edition ";
00192 }
00193 break;
00194 }
00195 #else
00196 struct utsname un;
00197 if(uname(&un) != -1)
00198 {
00199 mOSString.append(un.sysname);
00200 mOSString.append(" ");
00201 mOSString.append(un.release);
00202 mOSString.append(" ");
00203 mOSString.append(un.version);
00204 mOSString.append(" ");
00205 mOSString.append(un.machine);
00206 }
00207 else
00208 {
00209 mOSString.append("Unable to collect OS info");
00210 }
00211 #endif
00212
00213 }
00214
00215 #ifndef LL_WINDOWS
00216
00217 S32 LLOSInfo::getMaxOpenFiles()
00218 {
00219 const S32 OPEN_MAX_GUESS = 256;
00220
00221 #ifdef OPEN_MAX
00222 static S32 open_max = OPEN_MAX;
00223 #else
00224 static S32 open_max = 0;
00225 #endif
00226
00227 if (0 == open_max)
00228 {
00229
00230 errno = 0;
00231 if ( (open_max = sysconf(_SC_OPEN_MAX)) < 0)
00232 {
00233 if (0 == errno)
00234 {
00235
00236 open_max = OPEN_MAX_GUESS;
00237 }
00238 else
00239 {
00240 llerrs << "LLOSInfo::getMaxOpenFiles: sysconf error for _SC_OPEN_MAX" << llendl;
00241 }
00242 }
00243 }
00244 return open_max;
00245 }
00246 #endif
00247
00248 void LLOSInfo::stream(std::ostream& s) const
00249 {
00250 s << mOSString;
00251 }
00252
00253 const std::string& LLOSInfo::getOSString() const
00254 {
00255 return mOSString;
00256 }
00257
00258 const S32 STATUS_SIZE = 8192;
00259
00260
00261 U32 LLOSInfo::getProcessVirtualSizeKB()
00262 {
00263 U32 virtual_size = 0;
00264 #if LL_WINDOWS
00265 #endif
00266 #if LL_LINUX
00267 FILE* status_filep = LLFile::fopen("/proc/self/status", "rb");
00268 S32 numRead = 0;
00269 char buff[STATUS_SIZE];
00270
00271 size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep);
00272 buff[nbytes] = '\0';
00273
00274
00275 char *memp = strstr(buff, "VmSize:");
00276 if (memp)
00277 {
00278 numRead += sscanf(memp, "%*s %u", &virtual_size);
00279 }
00280 fclose(status_filep);
00281 #elif LL_SOLARIS
00282 char proc_ps[LL_MAX_PATH];
00283 sprintf(proc_ps, "/proc/%d/psinfo", (int)getpid());
00284 int proc_fd = -1;
00285 if((proc_fd = open(proc_ps, O_RDONLY)) == -1){
00286 llwarns << "unable to open " << proc_ps << llendl;
00287 return 0;
00288 }
00289 psinfo_t proc_psinfo;
00290 if(read(proc_fd, &proc_psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)){
00291 llwarns << "Unable to read " << proc_ps << llendl;
00292 close(proc_fd);
00293 return 0;
00294 }
00295
00296 close(proc_fd);
00297
00298 virtual_size = proc_psinfo.pr_size;
00299 #endif
00300 return virtual_size;
00301 }
00302
00303
00304 U32 LLOSInfo::getProcessResidentSizeKB()
00305 {
00306 U32 resident_size = 0;
00307 #if LL_WINDOWS
00308 #endif
00309 #if LL_LINUX
00310 FILE* status_filep = LLFile::fopen("/proc/self/status", "rb");
00311 if (status_filep != NULL)
00312 {
00313 S32 numRead = 0;
00314 char buff[STATUS_SIZE];
00315
00316 size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep);
00317 buff[nbytes] = '\0';
00318
00319
00320 char *memp = strstr(buff, "VmRSS:");
00321 if (memp)
00322 {
00323 numRead += sscanf(memp, "%*s %u", &resident_size);
00324 }
00325 fclose(status_filep);
00326 }
00327 #elif LL_SOLARIS
00328 char proc_ps[LL_MAX_PATH];
00329 sprintf(proc_ps, "/proc/%d/psinfo", (int)getpid());
00330 int proc_fd = -1;
00331 if((proc_fd = open(proc_ps, O_RDONLY)) == -1){
00332 llwarns << "unable to open " << proc_ps << llendl;
00333 return 0;
00334 }
00335 psinfo_t proc_psinfo;
00336 if(read(proc_fd, &proc_psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)){
00337 llwarns << "Unable to read " << proc_ps << llendl;
00338 close(proc_fd);
00339 return 0;
00340 }
00341
00342 close(proc_fd);
00343
00344 resident_size = proc_psinfo.pr_rssize;
00345 #endif
00346 return resident_size;
00347 }
00348
00349 LLCPUInfo::LLCPUInfo()
00350 {
00351 std::ostringstream out;
00352 CProcessor proc;
00353 const ProcessorInfo* info = proc.GetCPUInfo();
00354
00355 mHasSSE = info->_Ext.SSE_StreamingSIMD_Extensions;
00356 mHasSSE2 = info->_Ext.SSE2_StreamingSIMD2_Extensions;
00357 mHasAltivec = info->_Ext.Altivec_Extensions;
00358 mCPUMhz = (S32)(proc.GetCPUFrequency(50)/1000000.0);
00359 mFamily.assign( info->strFamily );
00360 mCPUString = "Unknown";
00361
00362 #if LL_WINDOWS || LL_DARWIN || LL_SOLARIS
00363 out << proc.strCPUName;
00364 if (200 < mCPUMhz && mCPUMhz < 10000)
00365 {
00366 out << " (" << mCPUMhz << " MHz)";
00367 }
00368 mCPUString = out.str();
00369
00370 #elif LL_LINUX
00371 std::map< LLString, LLString > cpuinfo;
00372 FILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb");
00373 if(cpuinfo_fp)
00374 {
00375 char line[MAX_STRING];
00376 memset(line, 0, MAX_STRING);
00377 while(fgets(line, MAX_STRING, cpuinfo_fp))
00378 {
00379
00380
00381 char* tabspot = strchr( line, '\t' );
00382 if (tabspot == NULL)
00383 continue;
00384 char* colspot = strchr( tabspot, ':' );
00385 if (colspot == NULL)
00386 continue;
00387 char* spacespot = strchr( colspot, ' ' );
00388 if (spacespot == NULL)
00389 continue;
00390 char* nlspot = strchr( line, '\n' );
00391 if (nlspot == NULL)
00392 nlspot = line + strlen( line );
00393 std::string linename( line, tabspot );
00394 LLString llinename(linename);
00395 LLString::toLower(llinename);
00396 std::string lineval( spacespot + 1, nlspot );
00397 cpuinfo[ llinename ] = lineval;
00398 }
00399 fclose(cpuinfo_fp);
00400 }
00401 # if LL_X86
00402 LLString flags = " " + cpuinfo["flags"] + " ";
00403 LLString::toLower(flags);
00404 mHasSSE = ( flags.find( " sse " ) != std::string::npos );
00405 mHasSSE2 = ( flags.find( " sse2 " ) != std::string::npos );
00406
00407 F64 mhz;
00408 if (LLString::convertToF64(cpuinfo["cpu mhz"], mhz)
00409 && 200.0 < mhz && mhz < 10000.0)
00410 {
00411 mCPUMhz = (S32)llrint(mhz);
00412 }
00413 if (!cpuinfo["model name"].empty())
00414 mCPUString = cpuinfo["model name"];
00415 # endif // LL_X86
00416 #endif // LL_LINUX
00417 }
00418
00419 bool LLCPUInfo::hasAltivec() const
00420 {
00421 return mHasAltivec;
00422 }
00423
00424 bool LLCPUInfo::hasSSE() const
00425 {
00426 return mHasSSE;
00427 }
00428
00429 bool LLCPUInfo::hasSSE2() const
00430 {
00431 return mHasSSE2;
00432 }
00433
00434 S32 LLCPUInfo::getMhz() const
00435 {
00436 return mCPUMhz;
00437 }
00438
00439 std::string LLCPUInfo::getCPUString() const
00440 {
00441 return mCPUString;
00442 }
00443
00444 void LLCPUInfo::stream(std::ostream& s) const
00445 {
00446 #if LL_WINDOWS || LL_DARWIN || LL_SOLARIS
00447
00448 char proc_buf[CPUINFO_BUFFER_SIZE];
00449 CProcessor proc;
00450 if(proc.CPUInfoToText(proc_buf, CPUINFO_BUFFER_SIZE))
00451 {
00452 s << proc_buf;
00453 }
00454 else
00455 {
00456 s << "Unable to collect processor information" << std::endl;
00457 }
00458 #else
00459
00460 FILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb");
00461 if(cpuinfo)
00462 {
00463 char line[MAX_STRING];
00464 memset(line, 0, MAX_STRING);
00465 while(fgets(line, MAX_STRING, cpuinfo))
00466 {
00467 line[strlen(line)-1] = ' ';
00468 s << line;
00469 }
00470 fclose(cpuinfo);
00471 s << std::endl;
00472 }
00473 else
00474 {
00475 s << "Unable to collect processor information" << std::endl;
00476 }
00477 #endif
00478
00479
00480 s << "->mHasSSE: " << (U32)mHasSSE << std::endl;
00481 s << "->mHasSSE2: " << (U32)mHasSSE2 << std::endl;
00482 s << "->mHasAltivec: " << (U32)mHasAltivec << std::endl;
00483 s << "->mCPUMhz: " << mCPUMhz << std::endl;
00484 s << "->mCPUString: " << mCPUString << std::endl;
00485 }
00486
00487 LLMemoryInfo::LLMemoryInfo()
00488 {
00489 }
00490
00491 #if LL_WINDOWS
00492 static U32 LLMemoryAdjustKBResult(U32 inKB)
00493 {
00494
00495
00497
00498
00499
00500
00501
00502
00503 inKB += 1024;
00504
00505 return inKB;
00506 }
00507 #endif
00508
00509 U32 LLMemoryInfo::getPhysicalMemoryKB() const
00510 {
00511 #if LL_WINDOWS
00512 MEMORYSTATUSEX state;
00513 state.dwLength = sizeof(state);
00514 GlobalMemoryStatusEx(&state);
00515
00516 return LLMemoryAdjustKBResult((U32)(state.ullTotalPhys >> 10));
00517
00518 #elif LL_DARWIN
00519
00520 uint64_t phys = 0;
00521 int mib[2] = { CTL_HW, HW_MEMSIZE };
00522
00523 size_t len = sizeof(phys);
00524 sysctl(mib, 2, &phys, &len, NULL, 0);
00525
00526 return (U32)(phys >> 10);
00527
00528 #elif LL_LINUX
00529 U64 phys = 0;
00530 phys = (U64)(getpagesize()) * (U64)(get_phys_pages());
00531 return (U32)(phys >> 10);
00532
00533 #elif LL_SOLARIS
00534 U64 phys = 0;
00535 phys = (U64)(getpagesize()) * (U64)(sysconf(_SC_PHYS_PAGES));
00536 return (U32)(phys >> 10);
00537
00538 #else
00539 return 0;
00540
00541 #endif
00542 }
00543
00544 U32 LLMemoryInfo::getPhysicalMemoryClamped() const
00545 {
00546
00547
00548
00549 U32 phys_kb = getPhysicalMemoryKB();
00550 if (phys_kb >= 4194304 )
00551 {
00552 return U32_MAX;
00553 }
00554 else
00555 {
00556 return phys_kb << 10;
00557 }
00558 }
00559
00560 void LLMemoryInfo::stream(std::ostream& s) const
00561 {
00562 #if LL_WINDOWS
00563 MEMORYSTATUSEX state;
00564 state.dwLength = sizeof(state);
00565 GlobalMemoryStatusEx(&state);
00566
00567 s << "Percent Memory use: " << (U32)state.dwMemoryLoad << '%' << std::endl;
00568 s << "Total Physical KB: " << (U32)(state.ullTotalPhys/1024) << std::endl;
00569 s << "Avail Physical KB: " << (U32)(state.ullAvailPhys/1024) << std::endl;
00570 s << "Total page KB: " << (U32)(state.ullTotalPageFile/1024) << std::endl;
00571 s << "Avail page KB: " << (U32)(state.ullAvailPageFile/1024) << std::endl;
00572 s << "Total Virtual KB: " << (U32)(state.ullTotalVirtual/1024) << std::endl;
00573 s << "Avail Virtual KB: " << (U32)(state.ullAvailVirtual/1024) << std::endl;
00574 #elif LL_DARWIN
00575 uint64_t phys = 0;
00576
00577 size_t len = sizeof(phys);
00578
00579 if(sysctlbyname("hw.memsize", &phys, &len, NULL, 0) == 0)
00580 {
00581 s << "Total Physical KB: " << phys/1024 << std::endl;
00582 }
00583 else
00584 {
00585 s << "Unable to collect memory information";
00586 }
00587 #elif LL_SOLARIS
00588 U64 phys = 0;
00589
00590 phys = (U64)(sysconf(_SC_PHYS_PAGES)) * (U64)(sysconf(_SC_PAGESIZE)/1024);
00591
00592 s << "Total Physical KB: " << phys << std::endl;
00593 #else
00594
00595 FILE* meminfo = LLFile::fopen(MEMINFO_FILE,"rb");
00596 if(meminfo)
00597 {
00598 char line[MAX_STRING];
00599 memset(line, 0, MAX_STRING);
00600 while(fgets(line, MAX_STRING, meminfo))
00601 {
00602 line[strlen(line)-1] = ' ';
00603 s << line;
00604 }
00605 fclose(meminfo);
00606 }
00607 else
00608 {
00609 s << "Unable to collect memory information";
00610 }
00611 #endif
00612 }
00613
00614 std::ostream& operator<<(std::ostream& s, const LLOSInfo& info)
00615 {
00616 info.stream(s);
00617 return s;
00618 }
00619
00620 std::ostream& operator<<(std::ostream& s, const LLCPUInfo& info)
00621 {
00622 info.stream(s);
00623 return s;
00624 }
00625
00626 std::ostream& operator<<(std::ostream& s, const LLMemoryInfo& info)
00627 {
00628 info.stream(s);
00629 return s;
00630 }
00631
00632 BOOL gunzip_file(const char *srcfile, const char *dstfile)
00633 {
00634 char tmpfile[LL_MAX_PATH];
00635 const S32 UNCOMPRESS_BUFFER_SIZE = 32768;
00636 BOOL retval = FALSE;
00637 gzFile src = NULL;
00638 U8 buffer[UNCOMPRESS_BUFFER_SIZE];
00639 FILE *dst = NULL;
00640 S32 bytes = 0;
00641 (void *) strcpy(tmpfile, dstfile);
00642 (void *) strncat(tmpfile, ".t", sizeof(tmpfile) - strlen(tmpfile) -1);
00643 src = gzopen(srcfile, "rb");
00644 if (! src) goto err;
00645 dst = LLFile::fopen(tmpfile, "wb");
00646 if (! dst) goto err;
00647 do
00648 {
00649 bytes = gzread(src, buffer, UNCOMPRESS_BUFFER_SIZE);
00650 size_t nwrit = fwrite(buffer, sizeof(U8), bytes, dst);
00651 if (nwrit < (size_t) bytes)
00652 {
00653 llerrs << "Short write on " << tmpfile << llendl;
00654 }
00655 } while(gzeof(src) == 0);
00656 fclose(dst);
00657 dst = NULL;
00658 if (LLFile::rename(tmpfile, dstfile) == -1) goto err;
00659 retval = TRUE;
00660 err:
00661 if (src != NULL) gzclose(src);
00662 if (dst != NULL) fclose(dst);
00663 return retval;
00664 }
00665
00666 BOOL gzip_file(const char *srcfile, const char *dstfile)
00667 {
00668 const S32 COMPRESS_BUFFER_SIZE = 32768;
00669 char tmpfile[LL_MAX_PATH];
00670 BOOL retval = FALSE;
00671 U8 buffer[COMPRESS_BUFFER_SIZE];
00672 gzFile dst = NULL;
00673 FILE *src = NULL;
00674 S32 bytes = 0;
00675 (void *) strcpy(tmpfile, dstfile);
00676 (void *) strncat(tmpfile, ".t", sizeof(tmpfile) - strlen(tmpfile) -1);
00677 dst = gzopen(tmpfile, "wb");
00678 if (! dst) goto err;
00679 src = LLFile::fopen(srcfile, "rb");
00680 if (! src) goto err;
00681
00682 do
00683 {
00684 bytes = (S32)fread(buffer, sizeof(U8), COMPRESS_BUFFER_SIZE,src);
00685 gzwrite(dst, buffer, bytes);
00686 } while(feof(src) == 0);
00687 gzclose(dst);
00688 dst = NULL;
00689 #if LL_WINDOWS
00690
00691 LLFile::remove(dstfile);
00692 #endif
00693 if (LLFile::rename(tmpfile, dstfile) == -1) goto err;
00694 retval = TRUE;
00695 err:
00696 if (src != NULL) fclose(src);
00697 if (dst != NULL) gzclose(dst);
00698 return retval;
00699 }