tc_timeprovider.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /**
  2. * Tencent is pleased to support the open source community by making Tars available.
  3. *
  4. * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
  5. *
  6. * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
  7. * in compliance with the License. You may obtain a copy of the License at
  8. *
  9. * https://opensource.org/licenses/BSD-3-Clause
  10. *
  11. * Unless required by applicable law or agreed to in writing, software distributed
  12. * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  13. * CONDITIONS OF ANY KIND, either express or implied. See the License for the
  14. * specific language governing permissions and limitations under the License.
  15. */
  16. #include "util/tc_timeprovider.h"
  17. #include "util/tc_logger.h"
  18. #include <cmath>
  19. namespace tars
  20. {
  21. TC_TimeProvider* TC_TimeProvider::g_tp = NULL;
  22. TC_TimeProvider* TC_TimeProvider::getInstance()
  23. {
  24. static std::once_flag flag;
  25. std::call_once(flag, []()
  26. {
  27. g_tp = new TC_TimeProvider();
  28. g_tp->start();
  29. });
  30. return g_tp;
  31. }
  32. TC_TimeProvider::~TC_TimeProvider()
  33. {
  34. }
  35. #if TARGET_PLATFORM_IOS || TARGET_PLATFORM_LINUX
  36. //直接从寄存器获取开机上电以来的周期(和主频有关系)
  37. //如果微处理器的主频是1MHZ的话,那么tsc就会在1秒内增加1000000
  38. uint64_t TC_TimeProvider::GetCycleCount()
  39. {
  40. //__inline __attribute__((always_inline)) uint64_t rdtsc() {
  41. #if defined(__i386__)
  42. int64_t ret;
  43. __asm__ volatile ("rdtsc" : "=A" (ret) );
  44. return ret;
  45. #elif defined(__x86_64__) || defined(__amd64__)
  46. uint32_t lo, hi;
  47. __asm__ __volatile__("rdtsc" : "=a" (lo), "=d" (hi));
  48. return (((uint64_t)hi << 32) | lo);
  49. #elif defined(__aarch64__)
  50. uint64_t cntvct;
  51. asm volatile ("isb; mrs %0, cntvct_el0; isb; " : "=r" (cntvct) :: "memory");
  52. return cntvct;
  53. #else
  54. #warning No high-precision counter available for your OS/arch
  55. return 0;
  56. #endif
  57. /*
  58. uint32_t high, low;
  59. __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high));
  60. uint64_t current_tsc = ((uint64_t)high << 32) | low;
  61. return current_tsc;
  62. */
  63. }
  64. /*
  65. #define rdtsc(low,high) \
  66. __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
  67. uint64_t current_tsc = ((uint64_t)high << 32) | low;
  68. */
  69. #else
  70. uint64_t TC_TimeProvider::GetCycleCount()
  71. {
  72. LARGE_INTEGER tmp;
  73. QueryPerformanceCounter(&tmp);
  74. return tmp.QuadPart;
  75. }
  76. #endif
  77. void TC_TimeProvider::getNow(timeval *tv)
  78. {
  79. #if TARGET_PLATFORM_IOS || TARGET_PLATFORM_LINUX
  80. int idx = _buf_idx;
  81. *tv = _t[idx];
  82. if(fabs(_cpu_cycle - 0) < 0.0001 && _use_tsc)
  83. {
  84. addTimeOffset(*tv, idx);
  85. }
  86. else
  87. {
  88. TC_Common::gettimeofday(*tv);
  89. }
  90. #else
  91. TC_Common::gettimeofday(*tv);
  92. #endif
  93. }
  94. uint64_t TC_TimeProvider::getNowMs()
  95. {
  96. struct timeval tv;
  97. getNow(&tv);
  98. return tv.tv_sec * (int64_t)1000 + tv.tv_usec / 1000;
  99. }
  100. void TC_TimeProvider::run()
  101. {
  102. memset(_tsc, 0x00, sizeof(_tsc));
  103. while (!_terminate)
  104. {
  105. timeval& tt = _t[!_buf_idx];
  106. TC_Common::gettimeofday(tt);
  107. setTsc(tt);
  108. _buf_idx = !_buf_idx;
  109. std::this_thread::sleep_for(std::chrono::milliseconds(10));
  110. }
  111. }
  112. void TC_TimeProvider::terminate()
  113. {
  114. _terminate = true;
  115. if(joinable())
  116. {
  117. join();
  118. }
  119. }
  120. // double TC_TimeProvider::cpuMHz()
  121. // {
  122. // if (_cpu_cycle != 0)
  123. // return 1.0 / _cpu_cycle;
  124. // return 0;
  125. // }
  126. void TC_TimeProvider::setTsc(timeval& tt)
  127. {
  128. uint64_t current_tsc = GetCycleCount();
  129. uint64_t& last_tsc = _tsc[!_buf_idx];
  130. timeval& last_tt = _t[_buf_idx];
  131. static bool first = true;
  132. if (first)
  133. {
  134. //第一次进来
  135. first = false;
  136. _cpu_cycle = 0;
  137. last_tsc = current_tsc;
  138. }
  139. else
  140. {
  141. //计算两次之间的间隔(us)
  142. time_t sptime = (tt.tv_sec - last_tt.tv_sec) * 1000 * 1000 + (tt.tv_usec - last_tt.tv_usec);
  143. //时间间隔/cpu计数次数, 得到cpu一次的周期时间
  144. _cpu_cycle = (double)sptime / (current_tsc - _tsc[_buf_idx]);
  145. last_tsc = current_tsc;
  146. }
  147. }
  148. void TC_TimeProvider::addTimeOffset(timeval& tt, const int &idx)
  149. {
  150. int64_t current_tsc = (int64_t)GetCycleCount();
  151. int64_t t = (int64_t)(current_tsc - (int64_t)_tsc[idx]);
  152. //根据cpu的技术次数*周期时间得到时间间隔(us)
  153. time_t offset = (t * _cpu_cycle);
  154. //偏差超过1s就认为是有问题的!
  155. if (t < -1000 || offset > 1000000)
  156. {
  157. cerr<< "TC_TimeProvider add_time_offset error,correct it by use gettimeofday. offset:" << offset <<"|current_tsc:"<<current_tsc<<"|last_tsc:"<<_tsc[idx]<<"|t:" << t <<endl;
  158. _use_tsc = false;
  159. TC_Common::gettimeofday(tt);
  160. return;
  161. }
  162. // cout << "addTimeOffset:" << offset << ", " << _cpu_cycle << ", t:" << t << endl;
  163. tt.tv_usec += offset;
  164. while (tt.tv_usec >= 1000000) { tt.tv_usec -= 1000000; tt.tv_sec++;}
  165. }
  166. }