Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
3.4 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: determine CPU speed under linux
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <sys/types.h>
  10. #include <sys/sysctl.h>
  11. #include <sys/time.h>
  12. #include <unistd.h>
  13. #include <tier0/platform.h>
  14. #include <errno.h>
  15. #define rdtsc(x) \
  16. __asm__ __volatile__ ("rdtsc" : "=A" (x))
  17. class TimeVal
  18. {
  19. public:
  20. TimeVal() {}
  21. TimeVal& operator=(const TimeVal &val) { m_TimeVal = val.m_TimeVal; }
  22. inline double operator-(const TimeVal &left)
  23. {
  24. uint64 left_us = (uint64) left.m_TimeVal.tv_sec * 1000000 + left.m_TimeVal.tv_usec;
  25. uint64 right_us = (uint64) m_TimeVal.tv_sec * 1000000 + m_TimeVal.tv_usec;
  26. uint64 diff_us = left_us - right_us;
  27. return diff_us/1000000;
  28. }
  29. timeval m_TimeVal;
  30. };
  31. // Compute the positive difference between two 64 bit numbers.
  32. static inline uint64 diff(uint64 v1, uint64 v2)
  33. {
  34. uint64 d = v1 - v2;
  35. if (d >= 0) return d; else return -d;
  36. }
  37. #ifdef OSX
  38. uint64 GetCPUFreqFromPROC()
  39. {
  40. int mib[2] = {CTL_HW, HW_CPU_FREQ};
  41. uint64 frequency = 0;
  42. size_t len = sizeof(frequency);
  43. if (sysctl(mib, 2, &frequency, &len, NULL, 0) == -1)
  44. return 0;
  45. return frequency;
  46. }
  47. #else
  48. uint64 GetCPUFreqFromPROC()
  49. {
  50. double mhz = 0;
  51. char line[1024], *s, search_str[] = "cpu MHz";
  52. FILE *fp;
  53. /* open proc/cpuinfo */
  54. if ((fp = fopen("/proc/cpuinfo", "r")) == NULL)
  55. {
  56. return 0;
  57. }
  58. /* ignore all lines until we reach MHz information */
  59. while (fgets(line, 1024, fp) != NULL)
  60. {
  61. if (strstr(line, search_str) != NULL)
  62. {
  63. /* ignore all characters in line up to : */
  64. for (s = line; *s && (*s != ':'); ++s);
  65. /* get MHz number */
  66. if (*s && (sscanf(s+1, "%lf", &mhz) == 1))
  67. break;
  68. }
  69. }
  70. if (fp!=NULL) fclose(fp);
  71. return (uint64)(mhz*1000000);
  72. }
  73. #endif
  74. uint64 CalculateCPUFreq()
  75. {
  76. #ifdef LINUX
  77. char const *pFreq = getenv("CPU_MHZ");
  78. if ( pFreq )
  79. {
  80. uint64 retVal = 1000000;
  81. return retVal * atoi( pFreq );
  82. }
  83. #endif
  84. // Compute the period. Loop until we get 3 consecutive periods that
  85. // are the same to within a small error. The error is chosen
  86. // to be +/- 0.02% on a P-200.
  87. const uint64 error = 40000;
  88. const int max_iterations = 600;
  89. int count;
  90. uint64 period, period1 = error * 2, period2 = 0, period3 = 0;
  91. for (count = 0; count < max_iterations; count++)
  92. {
  93. TimeVal start_time, end_time;
  94. uint64 start_tsc, end_tsc;
  95. gettimeofday (&start_time.m_TimeVal, 0);
  96. rdtsc (start_tsc);
  97. usleep (5000); // sleep for 5 msec
  98. gettimeofday (&end_time.m_TimeVal, 0);
  99. rdtsc (end_tsc);
  100. period3 = (end_tsc - start_tsc) / (end_time - start_time);
  101. if (diff (period1, period2) <= error &&
  102. diff (period2, period3) <= error &&
  103. diff (period1, period3) <= error)
  104. break;
  105. period1 = period2;
  106. period2 = period3;
  107. }
  108. if (count == max_iterations)
  109. {
  110. return GetCPUFreqFromPROC(); // fall back to /proc
  111. }
  112. // Set the period to the average period measured.
  113. period = (period1 + period2 + period3) / 3;
  114. // Some Pentiums have broken TSCs that increment very
  115. // slowly or unevenly.
  116. if (period < 10000000)
  117. {
  118. return GetCPUFreqFromPROC(); // fall back to /proc
  119. }
  120. return period;
  121. }