spin_loop_detector.cc 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // Implements spin loop detection as described by
  2. // T. Li, A. R. Lebeck, and D. J. Sorin.
  3. // "Spin detection hardware for improved management of multithreaded systems."
  4. // IEEE Transactions on Parallel and Distributed Systems (TPDS), 17:508-521, June 2006.
  5. #include "spin_loop_detector.h"
  6. #include "core.h"
  7. #include "performance_model.h"
  8. void SpinLoopDetector::commitBCT(uint64_t eip)
  9. {
  10. // We just executed a backward control transfer (BCT)
  11. // ``A BCT can be a backward conditional taken branch, unconditional branch, or jump instruction.''
  12. // Note: since we keep the SDT as a queue, a BCT's position is not constant so we use explicit ids
  13. // We also have an unbounded RUB so there is no overflow bit
  14. Core *core = m_thread->getCore();
  15. // Find BCT in the SDT
  16. Sdt::iterator entry = m_sdt.begin();
  17. for( ; entry != m_sdt.end(); ++entry)
  18. if (entry->eip == eip)
  19. break;
  20. if (entry == m_sdt.end())
  21. {
  22. // Unknown BCT: add to SDT, increment next SDT entry id, and update mask of valid ids
  23. m_sdt.push_back(SdtEntry(eip, m_sdt_nextid, core->getInstructionCount(), core->getPerformanceModel()->getElapsedTime()));
  24. m_sdt_nextid = (m_sdt_nextid + 1) % SDT_MAX_SIZE;
  25. // Keep only top SDT_MAX_SIZE entries
  26. if (m_sdt.size() > SDT_MAX_SIZE)
  27. m_sdt.pop_front();
  28. m_sdt_bitmask = 0;
  29. for(Sdt::iterator it = m_sdt.begin(); it != m_sdt.end(); ++it)
  30. m_sdt_bitmask |= (1 << it->id);
  31. }
  32. else
  33. {
  34. // Found! Check all RUB entries for our id to check if observable register state
  35. // has changed since the end of last iteration (Spin Condition 1)
  36. uint8_t id = entry->id;
  37. bool spinning = true;
  38. for(Rub::iterator it = m_rub.begin(); it != m_rub.end(); ++it)
  39. {
  40. if (it->second.second & (1 << id))
  41. {
  42. // ``There exists at least one entry in the RUB that corresponds to this SDT entry.
  43. // This means that the observable register state of the thread differs and, thus,
  44. // the thread was not spinning.''
  45. spinning = false;
  46. // Reset RUB entry for our loop id
  47. it->second.second &= ~(1 << id);
  48. }
  49. }
  50. if (spinning)
  51. {
  52. // Spin loop detected !!
  53. core->updateSpinCount(
  54. core->getInstructionCount() - entry->icount,
  55. // This time difference will have been caused by instructions earlier in the queue, not by the instructions
  56. // in this exact spin loop. But, when spinning for a long time, the earlier instructions will be spin loops as well
  57. // so if spin count is large (which is when we care) it should be reasonably accurate.
  58. core->getPerformanceModel()->getElapsedTime() - entry->tcount
  59. );
  60. }
  61. entry->icount = core->getInstructionCount();
  62. entry->tcount = core->getPerformanceModel()->getElapsedTime();
  63. }
  64. }
  65. void SpinLoopDetector::commitNonSilentStore()
  66. {
  67. // ``Whenever the processor commits a non-silent store, it clears the SDT.''
  68. m_sdt.clear();
  69. m_rub.clear();
  70. }
  71. void SpinLoopDetector::commitRegisterWrite(reg_t reg, uint64_t old_value, uint64_t value)
  72. {
  73. // Implements Register Update Buffer (RUB), see Section 3.2, 3rd paragraph
  74. // ``For each instruction it then commits, the processor checks if the instruction's architectural
  75. // (i.e., logical) destination register is already in the RUB.''
  76. if (m_rub.count(reg) == 0)
  77. {
  78. // ``If not, the processor has discovered a new register written by the thread
  79. // It then compares the new value of this register (i.e., the value being committed)
  80. // to its old value (i.e., the value before being overwritten by the commit).''
  81. if (value != old_value)
  82. {
  83. // ``If not equal, the processor adds the register number and its old value to the RUB.''
  84. m_rub[reg] = std::make_pair(old_value, m_sdt_bitmask);
  85. }
  86. }
  87. else
  88. {
  89. // ``If the register is already in the RUB, then the processor compares its new value to its current value in the RUB.''
  90. if (value == m_rub[reg].first)
  91. {
  92. // ``If equal, it deletes this register from the RUB;''
  93. m_rub.erase(reg);
  94. }
  95. // ``otherwise, no action is necessary.''
  96. else
  97. {
  98. // Actually, this happens when the register is already in the RUB for an older loop.
  99. // Unless it's a silent write, update the bitmask to represent all current loop candidates.
  100. if (value != old_value)
  101. m_rub[reg].second |= m_sdt_bitmask;
  102. }
  103. }
  104. }