123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- /******************************************************************************
- *
- * Copyright (C) 2019 by
- * The Salk Institute for Biological Studies and
- * Pittsburgh Supercomputing Center, Carnegie Mellon University
- *
- * Use of this source code is governed by an MIT-style
- * license that can be found in the LICENSE file or at
- * https://opensource.org/licenses/MIT.
- *
- ******************************************************************************/
- #ifndef SRC4_SCHEDULER_H_
- #define SRC4_SCHEDULER_H_
- #include <deque>
- #include <list>
- #include <mutex>
- #include "base_event.h"
- namespace Json {
- class Value;
- }
- namespace MCell {
- // we should represent the time interval with a precisely
- // represented floating point value
- const double BUCKET_TIME_INTERVAL = 1;
- class Bucket {
- public:
- Bucket(double start_time_) :
- start_time(start_time_) {
- }
- ~Bucket();
- void insert(BaseEvent* event);
- void dump() const;
- double start_time;
- std::list<BaseEvent*> events;
- };
- typedef std::deque<Bucket> BucketDeque;
- class Calendar {
- public:
- Calendar() :
- cached_next_barrier_time(TIME_INVALID) {
- // create at least one item?
- queue.push_back(Bucket(TIME_SIMULATION_START));
- }
- ~Calendar() {
- // implicitly calls destructors of items in queue and
- // deletes all events
- }
- void insert(BaseEvent* event);
- double get_next_time();
- BaseEvent* pop_next();
- void dump() const;
- void to_data_model(Json::Value& mcell_node, const bool only_for_viz) const;
- const BaseEvent* find_next_event_with_type_index(
- const event_type_index_t event_type_index) const;
- void get_all_events_with_type_index(
- const event_type_index_t event_type_index, std::vector<BaseEvent*>& events);
- void get_all_events_with_type_index(
- const event_type_index_t event_type_index, std::vector<const BaseEvent*>& events) const;
- double get_time_up_to_next_barrier(const double current_time, const double max_time_step);
- void print_periodic_stats() const {
- std::cout << "Calendar: queue.size() = " << queue.size() << "\n";
- }
- private:
- // differs from get_next_time - does not clear empty buckets
- // and returns bucket start time, not the next event time
- double get_first_bucket_start_time() {
- assert(queue.size() != 0);
- return queue.front().start_time;
- }
- double event_time_to_bucket_start_time(const double time) {
- // flooring to a multiple of BUCKET_TIME_INTERVAL
- return floor_to_multiple_f(time, BUCKET_TIME_INTERVAL);
- }
- BucketDeque::iterator get_or_create_bucket(const double time);
- void clear_empty_buckets();
- // queue might be empty
- BucketDeque queue;
- // used in get_time_up_to_next_barrier
- double cached_next_barrier_time;
- };
- // Structure used to return information about the event that was just handled
- struct EventExecutionInfo {
- EventExecutionInfo(
- const double time_, const event_type_index_t type_index_, const bool return_from_run_iterations_) :
- time(time_), type_index(type_index_), return_from_run_iterations(return_from_run_iterations_) {
- }
- double time;
- event_type_index_t type_index;
- bool return_from_run_iterations;
- };
- class Scheduler {
- public:
- Scheduler() :
- event_being_executed(nullptr),
- async_event_queue_lock(mtx, std::defer_lock),
- have_async_events_to_schedule(false) {
- }
- // - scheduler becomes owner of the base_event object
- // - event's time must be valid and not be in the past
- void schedule_event(BaseEvent* event);
- // - similar as schedule_event only guarded by a critical section and
- // inserts the event into a separate queue of events,
- // - every method whose outcome might be changed by the events in the async queue
- // must call schedule_events_from_async_queue to schedule these events correctly
- // - events that have event_time == TIME_INVALID will get time for the next iteration
- // so that they are executed in the right order
- void schedule_event_asynchronously(BaseEvent* event);
- // returns the time of next event
- double get_next_event_time(const bool skip_async_events_check = false);
- // returns time of the event that was handled
- EventExecutionInfo handle_next_event();
- // skip events for checkpointing,
- // may take long time if periodic events are scheduled
- void skip_events_up_to_time(const double start_time);
- void dump() const;
- void to_data_model(Json::Value& mcell_node, const bool only_for_viz) const;
- const BaseEvent* find_next_event_with_type_index(
- const event_type_index_t event_type_index) {
- schedule_events_from_async_queue();
- return calendar.find_next_event_with_type_index(event_type_index);
- }
- void get_all_events_with_type_index(
- const event_type_index_t event_type_index, std::vector<BaseEvent*>& events) {
- schedule_events_from_async_queue();
- return calendar.get_all_events_with_type_index(event_type_index, events);
- }
- BaseEvent* get_event_being_executed() {
- return event_being_executed;
- }
- const BaseEvent* get_event_being_executed() const {
- return event_being_executed;
- }
- void print_periodic_stats() const {
- calendar.print_periodic_stats();
- }
- private:
- // checks if there are events in the async queue and schedules them
- // not really const but maintains the consistency of events visible to the outside
- void schedule_events_from_async_queue();
- Calendar calendar;
- // callback might need to query which event is being executed right now
- // is nullptr when no event is running
- BaseEvent* event_being_executed;
- // lock for asynchronous scheduling of events
- std::mutex mtx;
- std::unique_lock<std::mutex> async_event_queue_lock;
- std::vector<BaseEvent*> async_event_queue;
- volatile bool have_async_events_to_schedule; // unguarded flag for fast check whether async_event_queue is empty
- };
- } // namespace mcell
- #endif // SRC4_SCHEDULER_H_
|