scheduler_big_small.cc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. #include "scheduler_big_small.h"
  2. #include "simulator.h"
  3. #include "config.hpp"
  4. #include "thread.h"
  5. #include "performance_model.h"
  6. #include "core_manager.h"
  7. #include "misc/tags.h"
  8. #include "rng.h"
  9. // Example random big-small scheduler using thread affinity
  10. //
  11. // The hardware consists of B big cores and S small cores
  12. // This scheduler selects B threads that have affinity to (all) big cores,
  13. // while the other threads have affinity to the small cores.
  14. // Periodically, or when threads on a big core stall/end,
  15. // new threads are promoted to run on the big core(s)
  16. //
  17. // This scheduler uses only setThreadAffinity(), and leaves all messy
  18. // low-level details that govern thread stalls etc. to the implementation
  19. // of SchedulerPinnedBase
  20. SchedulerBigSmall::SchedulerBigSmall(ThreadManager *thread_manager)
  21. : SchedulerPinnedBase(thread_manager, SubsecondTime::NS(Sim()->getCfg()->getInt("scheduler/big_small/quantum")))
  22. , m_debug_output(Sim()->getCfg()->getBool("scheduler/big_small/debug"))
  23. , m_last_reshuffle(SubsecondTime::Zero())
  24. , m_rng(rng_seed(42))
  25. {
  26. // Figure out big and small cores, and create affinity masks for the set of big cores and the set of small cores, respectively
  27. m_num_big_cores = 0;
  28. CPU_ZERO(&m_mask_big);
  29. CPU_ZERO(&m_mask_small);
  30. for (core_id_t coreId = 0; coreId < (core_id_t) Sim()->getConfig()->getApplicationCores(); coreId++)
  31. {
  32. bool isBig = Sim()->getTagsManager()->hasTag("core", coreId, "big");
  33. if (isBig)
  34. {
  35. ++m_num_big_cores;
  36. CPU_SET(coreId, &m_mask_big);
  37. }
  38. else
  39. {
  40. CPU_SET(coreId, &m_mask_small);
  41. }
  42. }
  43. }
  44. void SchedulerBigSmall::threadSetInitialAffinity(thread_id_t thread_id)
  45. {
  46. // All threads start out on the small core(s)
  47. moveToSmall(thread_id);
  48. }
  49. void SchedulerBigSmall::threadStall(thread_id_t thread_id, ThreadManager::stall_type_t reason, SubsecondTime time)
  50. {
  51. // When a thread on the big core stalls, promote another thread to the big core(s)
  52. if (m_debug_output)
  53. std::cout << "[SchedulerBigSmall] thread " << thread_id << " stalled" << std::endl;
  54. if (m_thread_isbig[thread_id])
  55. {
  56. // Pick a new thread to run on the big core(s)
  57. pickBigThread();
  58. // Move this thread to the small core(s)
  59. moveToSmall(thread_id);
  60. }
  61. // Call threadStall() in parent class
  62. SchedulerPinnedBase::threadStall(thread_id, reason, time);
  63. if (m_debug_output)
  64. printState();
  65. }
  66. void SchedulerBigSmall::threadExit(thread_id_t thread_id, SubsecondTime time)
  67. {
  68. // When a thread on the big core ends, promote another thread to the big core(s)
  69. if (m_debug_output)
  70. std::cout << "[SchedulerBigSmall] thread " << thread_id << " ended" << std::endl;
  71. if (m_thread_isbig[thread_id])
  72. {
  73. // Pick a new thread to run on the big core(s)
  74. pickBigThread();
  75. }
  76. // Call threadExit() in parent class
  77. SchedulerPinnedBase::threadExit(thread_id, time);
  78. if (m_debug_output)
  79. printState();
  80. }
  81. void SchedulerBigSmall::periodic(SubsecondTime time)
  82. {
  83. bool print_state = false;
  84. if (time > m_last_reshuffle + m_quantum)
  85. {
  86. // First move all threads back to the small cores
  87. for(thread_id_t thread_id = 0; thread_id < (thread_id_t)Sim()->getThreadManager()->getNumThreads(); ++thread_id)
  88. {
  89. if (m_thread_isbig[thread_id])
  90. moveToSmall(thread_id);
  91. }
  92. // Now promote as many threads to the big core pool as there are big cores
  93. for(UInt64 i = 0; i < std::min(m_num_big_cores, Sim()->getThreadManager()->getNumThreads()); ++i)
  94. {
  95. pickBigThread();
  96. }
  97. m_last_reshuffle = time;
  98. print_state = true;
  99. }
  100. // Call periodic() in parent class
  101. SchedulerPinnedBase::periodic(time);
  102. if (print_state && m_debug_output)
  103. printState();
  104. }
  105. void SchedulerBigSmall::moveToSmall(thread_id_t thread_id)
  106. {
  107. threadSetAffinity(INVALID_THREAD_ID, thread_id, sizeof(m_mask_small), &m_mask_small);
  108. m_thread_isbig[thread_id] = false;
  109. }
  110. void SchedulerBigSmall::moveToBig(thread_id_t thread_id)
  111. {
  112. threadSetAffinity(INVALID_THREAD_ID, thread_id, sizeof(m_mask_big), &m_mask_big);
  113. m_thread_isbig[thread_id] = true;
  114. }
  115. void SchedulerBigSmall::pickBigThread()
  116. {
  117. // Randomly select one thread to promote from the small to the big core pool
  118. // First build a list of all eligible cores
  119. std::vector<thread_id_t> eligible;
  120. for(thread_id_t thread_id = 0; thread_id < (thread_id_t)Sim()->getThreadManager()->getNumThreads(); ++thread_id)
  121. {
  122. if (m_thread_isbig[thread_id] == false && m_threads_runnable[thread_id])
  123. {
  124. eligible.push_back(thread_id);
  125. }
  126. }
  127. if (eligible.size() > 0)
  128. {
  129. // Randomly select a thread from our list
  130. thread_id_t thread_id = eligible[rng_next(m_rng) % eligible.size()];
  131. moveToBig(thread_id);
  132. if (m_debug_output)
  133. std::cout << "[SchedulerBigSmall] thread " << thread_id << " promoted to big core" << std::endl;
  134. }
  135. }