Line data Source code
1 : /* 2 : * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved. 3 : * Copyright Contributors to the OpenSDN project 4 : */ 5 : #include <boost/bind/bind.hpp> 6 : #include "logging.h" 7 : #include "io/event_manager.h" 8 : #include "timer_impl.h" 9 : #include "time_util.h" 10 : #include "task.h" 11 : #include "task_monitor.h" 12 : #include "task_tbbkeepawake.h" 13 : 14 : using namespace boost::placeholders; 15 : 16 : #define kPollIntervalMultiplier 2 17 : #define kInactivityMultiplier 50 18 : 19 10 : TaskMonitor::TaskMonitor(TaskScheduler *scheduler, 20 : uint64_t tbb_keepawake_time_msec, 21 : uint64_t inactivity_time_msec, 22 10 : uint64_t poll_interval_msec) : 23 10 : scheduler_(scheduler), cancelled_(false), timer_impl_(nullptr), 24 10 : inactivity_time_usec_(inactivity_time_msec * 1000), 25 10 : poll_interval_msec_(poll_interval_msec), 26 10 : tbb_keepawake_time_msec_(tbb_keepawake_time_msec), 27 10 : last_activity_(ClockMonotonicUsec()), 28 10 : last_enqueue_count_(0), last_done_count_(0), poll_count_(0) { 29 10 : } 30 : 31 10 : TaskMonitor::~TaskMonitor() { 32 10 : } 33 : 34 7 : void TaskMonitor::UpdateTimers() { 35 : // Ensure polling interval for monitor is atleast 2*keep-awake-time 36 : // It ensures when monitor is invoked, there is some job enqueued 37 : // and executed 38 7 : if ((tbb_keepawake_time_msec_ * kPollIntervalMultiplier) > poll_interval_msec_) { 39 5 : poll_interval_msec_ = 40 5 : kPollIntervalMultiplier * tbb_keepawake_time_msec_; 41 : } 42 : 43 : // Ensure monitor timeout is atleast 50 * poll-interval 44 7 : if ((poll_interval_msec_ * kInactivityMultiplier * 1000) > 45 7 : inactivity_time_usec_) { 46 6 : inactivity_time_usec_ = 47 6 : poll_interval_msec_ * kInactivityMultiplier * 1000; 48 : } 49 7 : return; 50 : } 51 : 52 2 : void TaskMonitor::Start(EventManager *evm) { 53 2 : if (inactivity_time_usec_ == 0 || poll_interval_msec_ == 0) 54 0 : return; 55 : 56 2 : UpdateTimers(); 57 2 : timer_impl_.reset(new TimerImpl(*evm->io_service())); 58 2 : Restart(); 59 2 : return; 60 : } 61 : 62 2 : void TaskMonitor::Terminate() { 63 2 : cancelled_ = true; 64 2 : } 65 : 66 2 : void TaskMonitor::Restart() { 67 2 : boost::system::error_code ec; 68 2 : timer_impl_->expires_from_now(poll_interval_msec_, ec); 69 2 : if (ec) { 70 0 : assert(0); 71 : } 72 2 : timer_impl_->async_wait(boost::bind(&TaskMonitor::Run, this, 73 : boost::asio::placeholders::error)); 74 2 : } 75 : 76 22 : bool TaskMonitor::Monitor(uint64_t t, uint64_t enqueue_count, 77 : uint64_t done_count) { 78 : // New tasks were spawned by TBB. Treat as activity seen 79 22 : if (done_count != last_done_count_) { 80 9 : last_done_count_ = done_count; 81 9 : last_enqueue_count_ = enqueue_count; 82 9 : last_activity_ = t; 83 9 : return true; 84 : } 85 : 86 : // No change in done_count_. Now validate enqueue_count. 87 : // Note: We cannot match enqueue_count_ and done_count_. Both these numbers 88 : // are updated by multiple threads and are not atomic numbers. As a result 89 : // they can potentially be out-of-sync 90 : // 91 : // If no new tasks are enqueued, then assume there is no more tasks 92 : // to run. Treat it similar to seeing activity 93 13 : if (enqueue_count == last_enqueue_count_) { 94 7 : last_done_count_ = done_count; 95 7 : last_enqueue_count_ = enqueue_count; 96 7 : last_activity_ = t; 97 7 : return true; 98 : } 99 : 100 : // Enqueues are happening, check if inactivity exceeds configured time 101 6 : return ((t - last_activity_) <= inactivity_time_usec_); 102 : } 103 : 104 0 : void TaskMonitor::Run(const boost::system::error_code &ec) { 105 0 : poll_count_++; 106 : 107 : // ASIO API aborted. Just restart ASIO timer again 108 0 : if (ec && ec.value() == boost::asio::error::operation_aborted) { 109 0 : Restart(); 110 0 : return; 111 : } 112 : 113 0 : if (cancelled_) 114 0 : return; 115 : 116 0 : if (Monitor(ClockMonotonicUsec(), scheduler_->enqueue_count(), 117 0 : scheduler_->done_count())) { 118 0 : Restart(); 119 0 : return; 120 : } 121 0 : LOG(ERROR, "!!!! ERROR !!!! Task Monitor failed"); 122 0 : assert(0); 123 : }