调度

调度

class Reader : public ReaderBase   
	template <typename MessageT>
    bool Reader<MessageT>::Init() {
​````略
      std::function<void(const std::shared_ptr<MessageT>&)> func;
      if (reader_func_ != nullptr) {
        func = [this](const std::shared_ptr<MessageT>& msg) {
          this->Enqueue(msg);
          this->reader_func_(msg);
        };
      } else {
        func = [this](const std::shared_ptr<MessageT>& msg) { this->Enqueue(msg); };
      }
      auto sched = scheduler::Instance();
      croutine_name_ = role_attr_.node_name() + "_" + role_attr_.channel_name();
      auto dv = std::make_shared<data::DataVisitor<MessageT>>(
          role_attr_.channel_id(), pending_queue_size_);
      // Using factory to wrap templates.
      croutine::RoutineFactory factory =
          croutine::CreateRoutineFactory<MessageT>(std::move(func), dv);
      if (!sched->CreateTask(factory, croutine_name_)) {
        AERROR << "Create Task Failed!";
        init_.exchange(false);
        return false;
      }
​````略
    }

  • auto dv = std::make_shared< data::DataVisitor>(
    role_attr_.channel_id(), pending_queue_size_);
template <typename M0>//DataVisito构造函数
class DataVisitor<M0, NullType, NullType, NullType> : public DataVisitorBase
	DataVisitor(uint64_t channel_id, uint32_t queue_size)
          : buffer_(channel_id, new BufferType<M0>(queue_size)) {
        DataDispatcher<M0>::Instance()->AddBuffer(buffer_);
        data_notifier_->AddNotifier(buffer_.channel_id(), notifier_);
      }
  • croutine::RoutineFactory factory =
    croutine::CreateRoutineFactory(std::move(func), dv);
template <typename M0, typename F>
RoutineFactory CreateRoutineFactory(
    F&& f, const std::shared_ptr<data::DataVisitor<M0>>& dv) {
  RoutineFactory factory;
  factory.SetDataVisitor(dv);
  factory.create_routine = [=]() {
    return [=]() {
      std::shared_ptr<M0> msg;
      for (;;) {
        CRoutine::GetCurrentRoutine()->set_state(RoutineState::DATA_WAIT);
        if (dv->TryFetch(msg)) {
          f(msg);
          CRoutine::Yield(RoutineState::READY);
        } else {
          CRoutine::Yield();
        }
      }
    };
  };
  return factory;
}

auto sched = scheduler::Instance();

namespace {
std::atomic<Scheduler*> instance = {nullptr};
std::mutex mutex;
}

Scheduler* Instance() {
  Scheduler* obj = instance.load(std::memory_order_acquire);
  if (obj == nullptr) {
    std::lock_guard<std::mutex> lock(mutex);
    obj = instance.load(std::memory_order_relaxed);
    if (obj == nullptr) {
      std::string policy("classic");
      std::string conf("conf/");
      conf.append(GlobalData::Instance()->ProcessGroup()).append(".conf");
      auto cfg_file = GetAbsolutePath(WorkRoot(), conf);
      apollo::cyber::proto::CyberConfig cfg;
      if (PathExists(cfg_file) && GetProtoFromFile(cfg_file, &cfg)) {
        policy = cfg.scheduler_conf().policy();
      } else {
        AWARN << "Pls make sure schedconf exist and which format is correct.\n";
      }
      if (!policy.compare("classic")) {
        obj = new SchedulerClassic();
      } else if (!policy.compare("choreography")) {
        obj = new SchedulerChoreography();
      } else {
        AWARN << "Invalid scheduler policy: " << policy;
        obj = new SchedulerClassic();
      }
      instance.store(obj, std::memory_order_release);
    }
  }
  return obj;
}

obj = new SchedulerClassic();

class SchedulerClassic  SchedulerClassic构造函数
	SchedulerClassic::SchedulerClassic() {
      // get sched config
      std::string conf("conf/");
      conf.append(GlobalData::Instance()->ProcessGroup()).append(".conf");
      auto cfg_file = GetAbsolutePath(WorkRoot(), conf);

      apollo::cyber::proto::CyberConfig cfg;
      if (PathExists(cfg_file) && GetProtoFromFile(cfg_file, &cfg)) {
        classic_conf_ = cfg.scheduler_conf().classic_conf();
        for (auto& group : classic_conf_.groups()) {
          auto& group_name = group.name();
          for (auto task : group.tasks()) {
            task.set_group_name(group_name);
            cr_confs_[task.name()] = task;
          }
        }
      } else {
        // if do not set default_proc_num in scheduler conf
        // give a default value
        uint32_t proc_num = 2;
        auto& global_conf = GlobalData::Instance()->Config();
        if (global_conf.has_scheduler_conf() &&
            global_conf.scheduler_conf().has_default_proc_num()) {
          proc_num = global_conf.scheduler_conf().default_proc_num();
        }
        task_pool_size_ = proc_num;

        auto sched_group = classic_conf_.add_groups();
        sched_group->set_name(DEFAULT_GROUP_NAME);
        sched_group->set_processor_num(proc_num);
      }

      CreateProcessor();
    }

if (!sched->CreateTask(factory, croutine_name_)) {

class Scheduler
    bool Scheduler::CreateTask(const RoutineFactory& factory,
                               const std::string& name) {
      return CreateTask(factory.create_routine(), name, factory.GetDataVisitor());
    }

return CreateTask(factory.create_routine(), name, factory.GetDataVisitor());

class Scheduler
    
    /*
   //func=factory.create_routine = [=]() {
    return [=]() {
      std::shared_ptr<M0> msg;
      for (;;) {
        CRoutine::GetCurrentRoutine()->set_state(RoutineState::DATA_WAIT);
        if (dv->TryFetch(msg)) {
          f(msg);
          CRoutine::Yield(RoutineState::READY);
        } else {
          CRoutine::Yield();
        }
      }
    };
  };
  
  name=croutine_name_ = role_attr_.node_name() + "_" + role_attr_.channel_name();
    */
    bool Scheduler::CreateTask(std::function<void()>&& func,
                               const std::string& name,
                               std::shared_ptr<DataVisitorBase> visitor) {
      if (unlikely(stop_.load())) {
        ADEBUG << "scheduler is stoped, cannot create task!";
        return false;
      }

      //根据node名称创建任务ID
      auto task_id = GlobalData::RegisterTaskName(name);

      auto cr = std::make_shared<CRoutine>(func);
      cr->set_id(task_id);
      cr->set_name(name);

      //分发协程任务
      if (!DispatchTask(cr)) {
        return false;
      }
      //注册唤醒任务
      if (visitor != nullptr) {
        visitor->RegisterNotifyCallback([this, task_id, name]() {
          if (unlikely(stop_.load())) {
            return;
          }
          this->NotifyProcessor(task_id);
        });
      }
      return true;
    }

auto cr = std::make_shared(func);

class CRoutine构造函数
	CRoutine::CRoutine(const std::function<void()> &func) : func_(func) {
      std::call_once(pool_init_flag, [&]() {
        auto routine_num = 100;
        auto &global_conf = common::GlobalData::Instance()->Config();
        if (global_conf.has_scheduler_conf() &&
            global_conf.scheduler_conf().has_routine_num()) {
          routine_num = global_conf.scheduler_conf().routine_num();
        }
        context_pool.reset(new base::CCObjectPool<RoutineContext>(routine_num));
      });

      context_ = context_pool->GetObject();
      if (context_ == nullptr) {
        AWARN << "Maximum routine context number exceeded! Please check "
                 "[routine_num] in config file.";
        context_.reset(new RoutineContext());
      }

      MakeContext(CRoutineEntry, this, context_.get());
      state_ = RoutineState::READY;
      updated_.test_and_set(std::memory_order_release);
    }

context_pool.reset(new base::CCObjectPool(routine_num));

class CCObjectPool  
	struct Node {
        T object;
        Node *next;
      };

      struct alignas(2 * sizeof(Node *)) Head {
        uintptr_t count;
        Node *node;
      };

	template <typename T>
    CCObjectPool<T>::CCObjectPool(uint32_t size) : capacity_(size) {
      node_arena_ = static_cast<Node *>(CheckedCalloc(capacity_, sizeof(Node)));
      FOR_EACH(i, 0, capacity_ - 1) { node_arena_[i].next = node_arena_ + 1 + i; }
      node_arena_[capacity_ - 1].next = nullptr;
      free_head_.store({0, node_arena_}, std::memory_order_relaxed);
    }

context_ = context_pool->GetObject();

class CCObjectPool     
	template <typename T>
    std::shared_ptr<T> CCObjectPool<T>::GetObject() {
      Head free_head;
      if (unlikely(!FindFreeHead(&free_head))) {
        return nullptr;
      }
      auto self = this->shared_from_this();
      return std::shared_ptr<T>(reinterpret_cast<T *>(free_head.node),
                                [self](T *object) { self->ReleaseObject(object); });
    }

MakeContext(CRoutineEntry, this, context_.get());

void CRoutineEntry(void *arg) {
  CRoutine *r = static_cast<CRoutine *>(arg);
  r->Run();
  CRoutine::Yield(RoutineState::FINISHED);
}

/*
constexpr size_t STACK_SIZE = 8 * 1024 * 1024;
constexpr size_t REGISTERS_SIZE = 56;
*/
void MakeContext(const func &f1, const void *arg, RoutineContext *ctx) {
  ctx->sp = ctx->stack + STACK_SIZE - 2 * sizeof(void *) - REGISTERS_SIZE;
  std::memset(ctx->sp, 0, REGISTERS_SIZE);
  char *sp = ctx->stack + STACK_SIZE - 2 * sizeof(void *);
  *reinterpret_cast<void **>(sp) = reinterpret_cast<void *>(f1);
  sp -= sizeof(void *);
  *reinterpret_cast<void **>(sp) = const_cast<void *>(arg);
}

if (!DispatchTask(cr)) {
return false;
}

其中cr为:

auto cr = std::make_shared(func);
cr->set_id(task_id); // auto task_id = GlobalData::RegisterTaskName(name);
cr->set_name(name); //name=croutine_name_ = role_attr_.node_name() + "" + role_attr.channel_name();

class SchedulerClassic : public Scheduler
	bool SchedulerClassic::DispatchTask(const std::shared_ptr<CRoutine>& cr) {
      // we use multi-key mutex to prevent race condition
      // when del && add cr with same crid
      if (likely(id_cr_wl_.find(cr->id()) == id_cr_wl_.end())) {
        {
          std::lock_guard<std::mutex> wl_lg(cr_wl_mtx_);
          if (id_cr_wl_.find(cr->id()) == id_cr_wl_.end()) {
            id_cr_wl_[cr->id()];
          }
        }
      }
      std::lock_guard<std::mutex> lg(id_cr_wl_[cr->id()]);

      {
        WriteLockGuard<AtomicRWLock> lk(id_cr_lock_);
        if (id_cr_.find(cr->id()) != id_cr_.end()) {
          return false;
        }
        id_cr_[cr->id()] = cr;
      }

      if (cr_confs_.find(cr->name()) != cr_confs_.end()) {
        ClassicTask task = cr_confs_[cr->name()];
        cr->set_priority(task.prio());
        cr->set_group_name(task.group_name());
      } else {
        // croutine that not exist in conf
        cr->set_group_name(classic_conf_.groups(0).name());
      }

      // Check if task prio is reasonable.
      if (cr->priority() >= MAX_PRIO) {
        AWARN << cr->name() << " prio is greater than MAX_PRIO[ << " << MAX_PRIO
              << "].";
        cr->set_priority(MAX_PRIO - 1);
      }

      // Enqueue task.
      {
        WriteLockGuard<AtomicRWLock> lk(
            ClassicContext::rq_locks_[cr->group_name()].at(cr->priority()));
        ClassicContext::cr_group_[cr->group_name()].at(cr->priority())
            .emplace_back(cr);
      }

      PerfEventCache::Instance()->AddSchedEvent(SchedPerf::RT_CREATE, cr->id(),
                                                cr->processor_id());
      ClassicContext::Notify(cr->group_name());
      return true;
    }

ClassicContext::Notify(cr->group_name());

class  ClassicContext        
	void ClassicContext::Notify(const std::string& group_name) {
      cv_wq_[group_name].notify_one();
    }	
scheduler_conf {
  policy: "classic"
  classic_conf {
    groups: [
      {
        name: "group1"
        processor_num: 16
        affinity: "range"
        cpuset: "0-7,16-23"
        processor_policy: "SCHED_OTHER"
        processor_prio: 0
        tasks: [
          {
            name: "ABC"
            prio: 2
          },{
            name: "XYZ"
            prio: 1
          }
        ]
      },{
        name: "group2"
        processor_num: 16 
        affinity: "1to1"
        cpuset: "8-15,24-31"
        processor_policy: "SCHED_OTHER"
        processor_prio: 0
        tasks: [
          {
            name: "MMN"
            prio: 0
          },{
            name: "NXX"
            prio: 1
          }
        ]
      }
    ]
  }
}

CreateProcessor();

class SchedulerClassic   
	void SchedulerClassic::CreateProcessor() {
      for (auto& group : classic_conf_.groups()) {
        auto& group_name = group.name();
        auto proc_num = group.processor_num();
        if (task_pool_size_ == 0) {
          task_pool_size_ = proc_num;
        }

        auto& affinity = group.affinity();
        auto& processor_policy = group.processor_policy();
        auto processor_prio = group.processor_prio();
        std::vector<int> cpuset;
        ParseCpuset(group.cpuset(), &cpuset);

        ClassicContext::cr_group_[group_name];
        ClassicContext::rq_locks_[group_name];
        ClassicContext::mtx_wq_[group_name];
        ClassicContext::cv_wq_[group_name];

        for (uint32_t i = 0; i < proc_num; i++) {
          auto ctx = std::make_shared<ClassicContext>();
          ctx->SetGroupName(group_name);
          pctxs_.emplace_back(ctx);

          auto proc = std::make_shared<Processor>();
          proc->BindContext(ctx);
          proc->SetAffinity(cpuset, affinity, i);
          proc->SetSchedPolicy(processor_policy, processor_prio);
          processors_.emplace_back(proc);
        }
      }
    }

proc->BindContext(ctx);

class Processor   
	void Processor::BindContext(const std::shared_ptr<ProcessorContext> &context) {
      context_ = context;
      std::call_once(thread_flag_,
                     [this]() { thread_ = std::thread(&Processor::Run, this); });
    }

std::call_once(thread_flag_,
this { thread_ = std::thread(&Processor::Run, this); });

class Processor    
	void Processor::Run() {
      tid_.store(static_cast<int>(syscall(SYS_gettid)));

      while (likely(running_)) {
        if (likely(context_ != nullptr)) {
          auto croutine = context_->NextRoutine();
          if (croutine) {
            croutine->Resume();
            croutine->Release();
          } else {
            context_->Wait();
          }
        } else {
          std::unique_lock<std::mutex> lk(mtx_ctx_);
          cv_ctx_.wait_for(lk, std::chrono::milliseconds(10));
        }
      }
    }

auto croutine = context_->NextRoutine();

class ClassicContext    
	std::shared_ptr<CRoutine> ClassicContext::NextRoutine() {
      if (unlikely(stop_)) {
        return nullptr;
      }

      for (int i = MAX_PRIO - 1; i >= 0; --i) {
        ReadLockGuard<AtomicRWLock> lk(rq_locks_[group_name_].at(i));
        for (auto& cr : cr_group_[group_name_].at(i)) {
          if (!cr->Acquire()) {
            continue;
          }

          if (cr->UpdateState() == RoutineState::READY) {
            PerfEventCache::Instance()->AddSchedEvent(SchedPerf::NEXT_RT, cr->id(),
                                                      cr->processor_id());
            return cr;
          }

          if (unlikely(cr->state() == RoutineState::SLEEP)) {
            if (!need_sleep_ || wake_time_ > cr->wake_time()) {
              need_sleep_ = true;
              wake_time_ = cr->wake_time();
            }
          }

          cr->Release();
        }
      }

      return nullptr;
    }

croutine->Resume();

class  CRoutine    
	RoutineState CRoutine::Resume() {
      if (unlikely(force_stop_)) {
        state_ = RoutineState::FINISHED;
        return state_;
      }

      if (unlikely(state_ != RoutineState::READY)) {
        AERROR << "Invalid Routine State!";
        return state_;
      }

      current_routine_ = this;
      PerfEventCache::Instance()->AddSchedEvent(
          SchedPerf::SWAP_IN, id_, processor_id_, static_cast<int>(state_));
      SwapContext(GetMainStack(), GetStack());
      PerfEventCache::Instance()->AddSchedEvent(
          SchedPerf::SWAP_OUT, id_, processor_id_, static_cast<int>(state_));
      current_routine_ = nullptr;
      return state_;
    }

SwapContext(GetMainStack(), GetStack());

inline void SwapContext(char** src_sp, char** dest_sp) {
  ctx_swap(reinterpret_cast<void**>(src_sp), reinterpret_cast<void**>(dest_sp));
}

extern "C" {
extern void ctx_swap(void**, void**) asm("ctx_swap");
};

extern void ctx_swap(void**, void**) asm(“ctx_swap”);

void CRoutineEntry(void *arg) {
  CRoutine *r = static_cast<CRoutine *>(arg);
  r->Run();
  CRoutine::Yield(RoutineState::FINISHED);
}

/*
constexpr size_t STACK_SIZE = 8 * 1024 * 1024;
constexpr size_t REGISTERS_SIZE = 56;
*/
void MakeContext(const func &f1, const void *arg, RoutineContext *ctx) {
  ctx->sp = ctx->stack + STACK_SIZE - 2 * sizeof(void *) - REGISTERS_SIZE;
  std::memset(ctx->sp, 0, REGISTERS_SIZE);
  char *sp = ctx->stack + STACK_SIZE - 2 * sizeof(void *);
  *reinterpret_cast<void **>(sp) = reinterpret_cast<void *>(f1);
  sp -= sizeof(void *);
  *reinterpret_cast<void **>(sp) = const_cast<void *>(arg);
}

.globl ctx_swap
.type  ctx_swap, @function
ctx_swap:
      pushq %rdi
      pushq %r12
      pushq %r13
      pushq %r14
      pushq %r15
      pushq %rbx
      pushq %rbp
      movq %rsp, (%rdi)

      movq (%rsi), %rsp
      popq %rbp
      popq %rbx
      popq %r15
      popq %r14
      popq %r13
      popq %r12
      popq %rdi
      ret

croutine->Release();

class CRoutine   
	inline void CRoutine::Release() {
      return lock_.clear(std::memory_order_release);
    }

//注册唤醒任务
if (visitor != nullptr) {
visitor->RegisterNotifyCallback([ this, task_id, name ] ( ) {
if (unlikely(stop_.load())) {
return;
}
this->NotifyProcessor(task_id);
});
}

class DataVisitorBase    
	void RegisterNotifyCallback(std::function<void()>&& callback) {
        notifier_->callback = callback;
      }

this->NotifyProcessor(task_id);

class SchedulerClassic    
	bool SchedulerClassic::NotifyProcessor(uint64_t crid) {
      if (unlikely(stop_)) {
        return true;
      }

      {
        ReadLockGuard<AtomicRWLock> lk(id_cr_lock_);
        if (id_cr_.find(crid) != id_cr_.end()) {
          auto cr = id_cr_[crid];
          if (cr->state() == RoutineState::DATA_WAIT) {
            cr->SetUpdateFlag();
          }

          ClassicContext::Notify(cr->group_name());
          return true;
        }
      }
      return false;
    }

ClassicContext::Notify(cr->group_name());

class ClassicContext    
	void ClassicContext::Notify(const std::string& group_name) {
      cv_wq_[group_name].notify_one();//context_->Wait();在函数Processor::Run()中
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海洋2416

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值