DPsim
OpenMPLevelScheduler.cpp
1 /* Copyright 2017-2021 Institute for Automation of Complex Power Systems,
2  * EONERC, RWTH Aachen University
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7  *********************************************************************************/
8 
9 #include <dpsim/OpenMPLevelScheduler.h>
10 #include <omp.h>
11 
12 #include <iostream>
13 
14 using namespace CPS;
15 using namespace DPsim;
16 
17 OpenMPLevelScheduler::OpenMPLevelScheduler(Int threads,
18  String outMeasurementFile)
19  : mOutMeasurementFile(outMeasurementFile) {
20  if (threads >= 0)
21  mNumThreads = threads;
22  else
23  mNumThreads = omp_get_num_threads();
24 }
25 
26 void OpenMPLevelScheduler::createSchedule(const Task::List &tasks,
27  const Edges &inEdges,
28  const Edges &outEdges) {
29  Task::List ordered;
30 
31  Scheduler::topologicalSort(tasks, inEdges, outEdges, ordered);
32  Scheduler::levelSchedule(ordered, inEdges, outEdges, mLevels);
33 
34  if (!mOutMeasurementFile.empty())
35  Scheduler::initMeasurements(tasks);
36 }
37 
38 void OpenMPLevelScheduler::step(Real time, Int timeStepCount) {
39  long i, level = 0;
40  std::chrono::steady_clock::time_point start, end;
41 
42  if (!mOutMeasurementFile.empty()) {
43 #pragma omp parallel shared(time, timeStepCount) private(level, i, start, end) \
44  num_threads(mNumThreads)
45  for (level = 0; level < static_cast<long>(mLevels.size()); level++) {
46  {
47 #pragma omp for schedule(static)
48  for (i = 0; i < static_cast<long>(mLevels[level].size()); i++) {
49  start = std::chrono::steady_clock::now();
50  mLevels[level][i]->execute(time, timeStepCount);
51  end = std::chrono::steady_clock::now();
52  updateMeasurement(mLevels[level][i].get(), end - start);
53  }
54  }
55  }
56  } else {
57 #pragma omp parallel shared(time, timeStepCount) private(level, i) \
58  num_threads(mNumThreads)
59  for (level = 0; level < static_cast<long>(mLevels.size()); level++) {
60  {
61 #pragma omp for schedule(static)
62  for (i = 0; i < static_cast<long>(mLevels[level].size()); i++) {
63  mLevels[level][i]->execute(time, timeStepCount);
64  }
65  }
66  }
67  }
68 }
69 
71  if (!mOutMeasurementFile.empty()) {
72  writeMeasurements(mOutMeasurementFile);
73  }
74 }
void step(Real time, Int timeStepCount)
Performs a single simulation step.
void stop()
Called on simulation stop to reliably clean up e.g. running helper threads.
void writeMeasurements(CPS::String filename)
Write measurement data to file.
Definition: Scheduler.cpp:32
void topologicalSort(const CPS::Task::List &tasks, const Edges &inEdges, const Edges &outEdges, CPS::Task::List &sortedTasks)
Simple topological sort, filtering out tasks that do not need to be executed.
Definition: Scheduler.cpp:120
static void levelSchedule(const CPS::Task::List &tasks, const Edges &inEdges, const Edges &outEdges, std::vector< CPS::Task::List > &levels)
Definition: Scheduler.cpp:190
std::unordered_map< CPS::Task::Ptr, std::deque< CPS::Task::Ptr > > Edges
Definition: Scheduler.h:31
void updateMeasurement(CPS::Task *task, TaskTime time)
Definition: Scheduler.cpp:28