scheduler.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /******************************************************************************
  2. *
  3. * Copyright (C) 2019 by
  4. * The Salk Institute for Biological Studies and
  5. * Pittsburgh Supercomputing Center, Carnegie Mellon University
  6. *
  7. * Use of this source code is governed by an MIT-style
  8. * license that can be found in the LICENSE file or at
  9. * https://opensource.org/licenses/MIT.
  10. *
  11. ******************************************************************************/
  12. #include "scheduler.h"
  13. #include "generated/gen_names.h"
  14. namespace MCell {
  15. void Bucket::insert(BaseEvent* event) {
  16. // check right away if the event belongs to the end
  17. if (events.empty() || cmp_lt(events.back()->event_time, event->event_time, SCHEDULER_COMPARISON_EPS)) {
  18. events.push_back(event);
  19. }
  20. else {
  21. // go through the list and put our item to the right time and right order
  22. auto it = events.begin();
  23. // find the right time
  24. while (it != events.end() && cmp_lt((*it)->event_time, event->event_time, SCHEDULER_COMPARISON_EPS)) {
  25. it++;
  26. }
  27. // find the right ordering among events with the same event_time
  28. while (it != events.end() && cmp_eq((*it)->event_time, event->event_time, SCHEDULER_COMPARISON_EPS)
  29. && (*it)->type_index <= event->type_index) {
  30. // if we already found events with our type, check secondary ordering
  31. if ((*it)->type_index == event->type_index && event->needs_secondary_ordering()) {
  32. assert((*it)->needs_secondary_ordering());
  33. // do we belong in front of the current event?
  34. if (event->get_secondary_ordering_value() < (*it)->get_secondary_ordering_value()) {
  35. // yes, terminate search
  36. break;
  37. }
  38. }
  39. it++;
  40. }
  41. events.insert(it, event);
  42. }
  43. }
  44. Bucket::~Bucket() {
  45. for (auto it = events.begin(); it != events.end(); it++) {
  46. // delete remaining events, usually there should be none
  47. delete *it;
  48. }
  49. }
  50. void Bucket::dump() const {
  51. for (const BaseEvent* event: events) {
  52. event->dump();
  53. }
  54. }
  55. // insert a new item with time event->event_time, create bucket if needed
  56. void Calendar::insert(BaseEvent* event) {
  57. // update barrier cache if needed
  58. if (event->is_barrier() && event->event_time < cached_next_barrier_time) {
  59. cached_next_barrier_time = event->event_time;
  60. }
  61. // align time to multiple of one if the value is close to it
  62. // required for example for custom time step where 0.1 * 10 must be equal to 1
  63. double rounded_time = round_f(event->event_time);
  64. if (cmp_eq(round_f(event->event_time), event->event_time, SCHEDULER_COMPARISON_EPS)) {
  65. event->event_time = rounded_time;
  66. }
  67. double bucket_start_time = event_time_to_bucket_start_time(event->event_time);
  68. if (queue.empty()) {
  69. // no items yet - simply create new bucket and insert our event there
  70. queue.push_back( Bucket(bucket_start_time) );
  71. queue.front().insert(event);
  72. }
  73. else {
  74. // we first need to find out whether we already have a bucket for this event
  75. double first_start_time = get_first_bucket_start_time();
  76. release_assert(bucket_start_time - first_start_time >= 0 && "cannot schedule to the past"); // some eps?
  77. size_t buckets_from_first = (bucket_start_time - first_start_time) / BUCKET_TIME_INTERVAL;
  78. if (buckets_from_first < queue.size()) {
  79. // bucket exists
  80. queue[buckets_from_first].insert(event);
  81. }
  82. else {
  83. // we need to create new buckets
  84. size_t missing_buckets = buckets_from_first - queue.size() + 1;
  85. if (missing_buckets > SCHEDULER_MAX_BUCKETS_TO_FUTURE) {
  86. errs() << "An event such as " << API::NAME_CLASS_COUNT << " or " << API::NAME_CLASS_VIZ_OUTPUT <<
  87. " is scheduled too far into the future (" << missing_buckets << " time steps). " <<
  88. "This would require too much memory, please adjust its period with attribute " << API::NAME_EVERY_N_TIMESTEPS << "." <<
  89. " (event type index " << event->type_index << ")\n";
  90. exit(1);
  91. }
  92. double next_time = queue.back().start_time + BUCKET_TIME_INTERVAL;
  93. for (size_t i = 0; i < missing_buckets; i++) {
  94. queue.push_back(Bucket(next_time));
  95. next_time += BUCKET_TIME_INTERVAL;
  96. }
  97. assert(buckets_from_first < queue.size());
  98. queue[buckets_from_first].insert(event);
  99. }
  100. }
  101. }
  102. void Calendar::clear_empty_buckets() {
  103. while (queue.front().events.empty()) {
  104. queue.pop_front();
  105. }
  106. }
  107. BaseEvent* Calendar::pop_next() {
  108. clear_empty_buckets();
  109. BaseEvent* next_event = queue.front().events.front();
  110. queue.front().events.pop_front();
  111. return next_event;
  112. }
  113. double Calendar::get_next_time() {
  114. clear_empty_buckets();
  115. assert(!queue.empty() && !queue.front().events.empty());
  116. BaseEvent* next_event = queue.front().events.front();
  117. return next_event->event_time;
  118. }
  119. void Calendar::dump() const {
  120. for (const Bucket& bucket: queue) {
  121. bucket.dump();
  122. }
  123. }
  124. void Calendar::to_data_model(Json::Value& mcell_node, const bool only_for_viz) const {
  125. for (const Bucket& bucket: queue) {
  126. for (const BaseEvent* event: bucket.events) {
  127. if (only_for_viz && event->type_index != EVENT_TYPE_INDEX_MOL_OR_RXN_COUNT) {
  128. // include only visualization-related events
  129. continue;
  130. }
  131. event->to_data_model(mcell_node);
  132. }
  133. }
  134. }
  135. const BaseEvent* Calendar::find_next_event_with_type_index(
  136. const event_type_index_t event_type_index) const {
  137. for (const Bucket& bucket: queue) {
  138. for (const BaseEvent* event: bucket.events) {
  139. if (event->type_index == event_type_index) {
  140. return event;
  141. }
  142. }
  143. }
  144. return nullptr;
  145. }
  146. void Calendar::get_all_events_with_type_index(
  147. const event_type_index_t event_type_index,
  148. std::vector<BaseEvent*>& events
  149. ) {
  150. for (const Bucket& bucket: queue) {
  151. for (BaseEvent* event: bucket.events) {
  152. if (event->type_index == event_type_index) {
  153. events.push_back(event);
  154. }
  155. }
  156. }
  157. }
  158. void Calendar::get_all_events_with_type_index(
  159. const event_type_index_t event_type_index,
  160. std::vector<const BaseEvent*>& events
  161. ) const {
  162. for (const Bucket& bucket: queue) {
  163. for (BaseEvent* event: bucket.events) {
  164. if (event->type_index == event_type_index) {
  165. events.push_back(event);
  166. }
  167. }
  168. }
  169. }
  170. // returns max_time_step if no barrier is scheduled for interval
  171. // current_time .. current_time+max_time_step
  172. // if such a barrier exists, returns barrier time - current_time
  173. double Calendar::get_time_up_to_next_barrier(
  174. const double current_time, const double max_time_step) {
  175. if (cached_next_barrier_time != TIME_INVALID &&
  176. current_time < cached_next_barrier_time
  177. ) {
  178. return std::min(cached_next_barrier_time - current_time, max_time_step);
  179. }
  180. // go through the whole schedule and find the first barrier
  181. cached_next_barrier_time = TIME_FOREVER;
  182. // expecting that there are only events that are scheduled
  183. // for the future
  184. bool found = false;
  185. for (const Bucket& bucket: queue) {
  186. for (const BaseEvent* event: bucket.events) {
  187. if (event->is_barrier()) {
  188. assert(event->event_time >= current_time);
  189. cached_next_barrier_time = event->event_time;
  190. found = true;
  191. break;
  192. }
  193. }
  194. if (found) {
  195. break;
  196. }
  197. }
  198. return std::min(cached_next_barrier_time - current_time, max_time_step);
  199. }
  200. void Scheduler::schedule_event(BaseEvent* event) {
  201. release_assert(event->event_time != TIME_INVALID);
  202. calendar.insert(event);
  203. }
  204. void Scheduler::schedule_event_asynchronously(BaseEvent* event) {
  205. // may be called multiple times at the same moment e.g. when
  206. // adding a checkpointing event based on some timer in Python
  207. async_event_queue_lock.lock();
  208. have_async_events_to_schedule = true;
  209. async_event_queue.push_back(event);
  210. async_event_queue_lock.unlock();
  211. }
  212. void Scheduler::schedule_events_from_async_queue() {
  213. if (!have_async_events_to_schedule) {
  214. return;
  215. }
  216. async_event_queue_lock.lock();
  217. for (BaseEvent* e: async_event_queue) {
  218. if (e->event_time == TIME_INVALID) {
  219. // real asynchronous event,
  220. // schedule correctly for an upcoming iteration while making sure
  221. // that all the events from the current iteration are finished so that
  222. // the event_type_index is correctly followed
  223. e->event_time = floor_f(get_next_event_time(true) + 1);
  224. }
  225. schedule_event(e);
  226. }
  227. async_event_queue.clear();
  228. have_async_events_to_schedule = false;
  229. async_event_queue_lock.unlock();
  230. }
  231. double Scheduler::get_next_event_time(const bool skip_async_events_check) {
  232. if (!skip_async_events_check) {
  233. schedule_events_from_async_queue();
  234. }
  235. return calendar.get_next_time();
  236. }
  237. // pop next scheduled event and run its step method
  238. EventExecutionInfo Scheduler::handle_next_event() {
  239. // first check if there are any
  240. schedule_events_from_async_queue();
  241. BaseEvent* event = calendar.pop_next();
  242. assert(event != NULL && "Empty event queue - at least end simulation event should be present");
  243. double event_time = event->event_time;
  244. if (event->may_be_blocked_by_barrier_and_needs_set_time_step()) {
  245. double max_time_step = calendar.get_time_up_to_next_barrier(
  246. event->event_time, event->get_max_time_up_to_next_barrier());
  247. event->set_barrier_time_for_next_execution(max_time_step);
  248. }
  249. #ifdef DEBUG_SCHEDULER
  250. event->dump("");
  251. #endif
  252. event_being_executed = event;
  253. event->step();
  254. event_being_executed = nullptr;
  255. event_type_index_t type_index = event->type_index;
  256. bool return_from_run_iterations = event->return_from_run_n_iterations_after_execution();
  257. // schedule itself for the next period or just delete
  258. double next_time;
  259. bool to_schedule = event->update_event_time_for_next_scheduled_time();
  260. if (to_schedule) {
  261. calendar.insert(event);
  262. }
  263. else {
  264. delete event;
  265. }
  266. return EventExecutionInfo(event_time, type_index, return_from_run_iterations);
  267. }
  268. void Scheduler::skip_events_up_to_time(const double start_time) {
  269. // need to deal with imprecisions, e.g. 0.0000005 * 10^6 ~= 5.0000000000008
  270. while (calendar.get_next_time() < start_time - EPS) {
  271. BaseEvent* event = calendar.pop_next();
  272. bool to_schedule = event->update_event_time_for_next_scheduled_time();
  273. if (to_schedule) {
  274. calendar.insert(event);
  275. }
  276. else {
  277. delete event;
  278. }
  279. }
  280. }
  281. void Scheduler::dump() const {
  282. calendar.dump();
  283. }
  284. void Scheduler::to_data_model(Json::Value& mcell_node, const bool only_for_viz) const {
  285. // go through all events and run their conversion,
  286. // for many events, the conversion does nothing
  287. calendar.to_data_model(mcell_node, only_for_viz);
  288. }
  289. } // namespace mcell