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.

209 lines
5.4KB

  1. #pragma once
  2. #ifdef ARCH_WIN
  3. #include <windows.h>
  4. #endif
  5. #ifdef ARCH_LIN
  6. #include <sys/resource.h>
  7. #include <sys/types.h>
  8. #include <sys/time.h>
  9. #include <unistd.h>
  10. #include <sys/syscall.h>
  11. #include <errno.h>
  12. #endif
  13. class ThreadPriority
  14. {
  15. public:
  16. /**
  17. * Attempts to boost priority of current thread, but not all
  18. * the way to a "realtime" priority. In genera, should not require
  19. * admin rights.
  20. */
  21. static bool boostNormal();
  22. /**
  23. * Attempts to boost priority of current thread all the way to
  24. * a "realtime" priority. Will require admin rights
  25. */
  26. static bool boostRealtime();
  27. static void restore();
  28. #ifdef ARCH_WIN
  29. static bool boostRealtimeWindows();
  30. #endif
  31. private:
  32. static bool boostNormalPthread();
  33. static bool boostRealtimePthread();
  34. static void restorePthread();
  35. #ifdef ARCH_LIN
  36. static bool boostNormalLinux();
  37. #endif
  38. };
  39. #ifdef ARCH_WIN
  40. inline bool ThreadPriority::boostRealtimeWindows()
  41. {
  42. HANDLE h = GetCurrentProcess();
  43. auto x = GetPriorityClass(h);
  44. printf("cur priority class = %lx, realtime=%x", x, REALTIME_PRIORITY_CLASS);
  45. SetPriorityClass(h, HIGH_PRIORITY_CLASS);
  46. printf("set pri class to %x is now %lx\n", HIGH_PRIORITY_CLASS, GetPriorityClass(h));
  47. bool b = SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  48. int y = GetThreadPriority(GetCurrentThread());
  49. printf("set pri ret %d, is now %d want %d err=%ld\n",
  50. b,
  51. y,
  52. THREAD_PRIORITY_TIME_CRITICAL, GetLastError());
  53. fflush(stdout);
  54. return y == THREAD_PRIORITY_TIME_CRITICAL;
  55. }
  56. #endif
  57. // Inside Visual Studio test we don't try to link in PThreads,
  58. // So they can't be used here. But they will work on all command line
  59. // test builds, including Windows.
  60. #if !defined(_MSC_VER) || defined(_VSCODE)
  61. inline bool ThreadPriority::boostNormal()
  62. {
  63. #ifdef ARCH_LIN
  64. return boostNormalLinux();
  65. #else
  66. return boostNormalPthread();
  67. #endif
  68. }
  69. inline bool ThreadPriority::boostRealtime()
  70. {
  71. #ifdef ARCH_WIN
  72. return boostRealtimeWindows();
  73. #else
  74. return boostRealtimePthread();
  75. #endif
  76. }
  77. inline void ThreadPriority::restore()
  78. {
  79. restorePthread();
  80. }
  81. inline void ThreadPriority::restorePthread()
  82. {
  83. const pthread_t threadHandle = pthread_self();
  84. struct sched_param params;
  85. params.sched_priority = 0; // Note that on mac, this is not the default.
  86. // fix this.
  87. const int newPolicy = SCHED_OTHER;
  88. int x = pthread_setschedparam(threadHandle, newPolicy, &params);
  89. if (x != 0) {
  90. printf("failed to set reset sched %d\n", x);
  91. }
  92. }
  93. /**
  94. * Linux doesn't support pthread priorities, so
  95. * we use the common hack of setting niceness.
  96. */
  97. #ifdef ARCH_LIN
  98. inline bool ThreadPriority::boostNormalLinux()
  99. {
  100. pid_t tid = syscall(SYS_gettid);
  101. const int priority = -20;
  102. int ret = setpriority(PRIO_PROCESS, tid, priority);
  103. if (ret != 0) {
  104. printf("set pri failed, errno = %d\n", errno);
  105. printf("EACCESS=%d\n", EACCES);
  106. }
  107. printf("priority now %d\n", getpriority(PRIO_PROCESS, tid));
  108. return ret == 0;
  109. }
  110. #endif
  111. inline bool ThreadPriority::boostNormalPthread()
  112. {
  113. struct sched_param params;
  114. const pthread_t threadHandle = pthread_self();
  115. int initPolicy = -10;
  116. pthread_getschedparam(threadHandle, &initPolicy, &params);
  117. printf("in boost, policy was %d, pri was %d otherp=%d\n", initPolicy, params.sched_priority, SCHED_OTHER);
  118. const int initPriority = params.sched_priority;
  119. const int newPolicy = SCHED_OTHER;
  120. const int maxPriority = sched_get_priority_max(newPolicy);
  121. #if 1
  122. {
  123. printf("for OTHER, pri range = %d,%d\n",
  124. sched_get_priority_min(newPolicy),
  125. sched_get_priority_max(newPolicy));
  126. }
  127. #endif
  128. if (maxPriority <= initPriority) {
  129. // Linux seems to only offer one priority for SCHED_OTHER;
  130. printf("SCHED_OTHER only supports priority %d\n", maxPriority);
  131. return false;
  132. }
  133. params.sched_priority = maxPriority;
  134. int x = pthread_setschedparam(threadHandle, newPolicy, &params);
  135. if (x != 0) {
  136. printf("failed to set pri %d for SCHED_OTHER. error= %d\n", maxPriority, x);
  137. }
  138. fflush(stdout);
  139. return x == 0;
  140. }
  141. inline bool ThreadPriority::boostRealtimePthread()
  142. {
  143. struct sched_param params;
  144. const pthread_t threadHandle = pthread_self();
  145. const int newPolicy = SCHED_RR;
  146. const int maxPriority = sched_get_priority_max(newPolicy);
  147. const int minPriority = sched_get_priority_min(newPolicy);
  148. #if 0
  149. if ((maxPriority <= 0) || (minPriority < 0)) {
  150. printf("algorithm doesn't work with rt %d, %d\n", minPriority, maxPriority);
  151. return false;
  152. }
  153. #endif
  154. // use the mean of min and max. These should all be higher than "non realtime"
  155. // on mac the mean was not as good as elevating as other, to let's try max/
  156. //const int newPriority = (maxPriority + minPriority) / 2;
  157. const int newPriority = maxPriority;
  158. printf("realtime min = %d max = %d will use %d\n", minPriority, maxPriority, newPriority);
  159. params.sched_priority = newPriority;
  160. int x = pthread_setschedparam(threadHandle, newPolicy, &params);
  161. if (x != 0) {
  162. printf("failed to set pri %d for SCHED_RR. error= %d\n", newPriority, x);
  163. }
  164. return x == 0;
  165. }
  166. #else
  167. inline bool ThreadPriority::boostNormal()
  168. {
  169. return true;
  170. }
  171. inline bool ThreadPriority::boostRealtime()
  172. {
  173. return true;
  174. }
  175. inline void ThreadPriority::restore()
  176. {
  177. }
  178. #endif