From c9a281fbb352791c5ba290255b6e88671aa47ed7 Mon Sep 17 00:00:00 2001 From: Benjamin Kraft Date: Mon, 11 Sep 2023 14:49:41 +0200 Subject: [PATCH] simulation is on different thread --- CMakeLists.txt | 3 ++- src/GLWidget.cpp | 3 ++- src/MainWindow.cpp | 18 +++++++++++++----- src/MainWindow.h | 4 +++- src/Simulation.cpp | 15 +++++++++++++-- src/Simulation.h | 14 ++++++++++---- src/main.cpp | 29 +++++++++++++++++++++++++++++ 7 files changed, 72 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index edbf303..4aa1aa9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,10 +8,11 @@ set(CMAKE_AUTOUIC ON) find_package(Qt6 COMPONENTS OpenGLWidgets REQUIRED) find_package(Eigen3 REQUIRED) +find_package(OpenMP REQUIRED) file(GLOB_RECURSE SOURCE_FILES src/**.cpp) add_executable(Pendulum WIN32 ${SOURCE_FILES} icons/icons.qrc) include_directories(${EIGEN3_INCLUDE_DIR}) -target_link_libraries(Pendulum Qt6::OpenGLWidgets) +target_link_libraries(Pendulum Qt6::OpenGLWidgets OpenMP::OpenMP_CXX) diff --git a/src/GLWidget.cpp b/src/GLWidget.cpp index 7e81baf..b8553a2 100644 --- a/src/GLWidget.cpp +++ b/src/GLWidget.cpp @@ -33,8 +33,9 @@ void GLWidget::timerEvent(QTimerEvent *e) { void GLWidget::updateFPS() { auto thisFrame = high_resolution_clock::now(); - auto diff = duration_cast(thisFrame - previousFrame).count(); + auto diff = (int)duration_cast(thisFrame - previousFrame).count(); currentFPS = 1000 / (diff == 0 ? 1 : diff); + // std::cout << currentFPS << std::endl; previousFrame = thisFrame; } diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index b64eb2c..53d1cbc 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -14,9 +14,15 @@ #include #include "Pendulum.h" #include "Button.h" +#include +#include +#include MainWindow::MainWindow() { + simulationThread = new QThread(this); simulation = new Simulation; + simulation->moveToThread(simulationThread); + simulationThread->start(); masses = std::vector(MaxSegments); lengths = std::vector(MaxSegments); @@ -291,7 +297,7 @@ QWidget * MainWindow::buildAddUI() { removeBtn->setStyleSheet("background-color: #ffaaaa"); connect(addBtn, &QPushButton::clicked, this, &MainWindow::add); - connect(removeBtn, &QPushButton::clicked, this, &MainWindow::remove); + connect(removeBtn, &QPushButton::clicked, simulation, &Simulation::clearPendula); btnLyt->addWidget(addBtn); btnLyt->addWidget(removeBtn); @@ -420,10 +426,6 @@ void MainWindow::add() { } } -void MainWindow::remove() { - simulation->clearPendula(); -} - void MainWindow::resetSimulationControl() { gravitySlider->setValue(981); timescaleSlider->setValue(100); @@ -433,3 +435,9 @@ void MainWindow::resetSimulationControl() { void MainWindow::toggleSimulation() { simulation->isPlaying = !simulation->isPlaying; } + +void MainWindow::closeEvent(QCloseEvent *e) { + simulationThread->quit(); + simulationThread->wait(); + e->accept(); +} diff --git a/src/MainWindow.h b/src/MainWindow.h index c246cbc..37cd6d2 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -11,11 +11,14 @@ enum Property {Angle, Mass, Length}; class MainWindow : public QWidget { public: explicit MainWindow(); +protected: + void closeEvent(QCloseEvent*) override; private: void buildUI(); QWidget * buildAddUI(); QWidget * buildSimulationUI(); Simulation * simulation; + QThread * simulationThread; GLWidget * glWidget = nullptr; @@ -42,7 +45,6 @@ public slots: void resetLengths(); void normalizeLengths(); void add(); - void remove(); void resetSimulationControl(); void toggleSimulation(); diff --git a/src/Simulation.cpp b/src/Simulation.cpp index eb17304..fd2c3bd 100644 --- a/src/Simulation.cpp +++ b/src/Simulation.cpp @@ -2,12 +2,16 @@ #include "Pendulum.h" #include #include +#include +#include +#include Simulation::Simulation() { timer = new QTimer(this); QTimer::connect(timer, &QTimer::timeout, this, &Simulation::update); timer->setInterval(updateInterval); timer->start(); + lastUpdate = high_resolution_clock::now(); }; void Simulation::draw(QPainter *p, int screenSize) const { @@ -18,6 +22,11 @@ void Simulation::draw(QPainter *p, int screenSize) const { } void Simulation::update() { + auto thisUpdate = high_resolution_clock::now(); + auto ms = (int)duration_cast(thisUpdate - lastUpdate).count(); + // std::cout << ms << std::endl; + lastUpdate = thisUpdate; + if (!isPlaying) return; @@ -25,8 +34,9 @@ void Simulation::update() { h /= substeps; - for (int i = 0; i < substeps; i++) - for (const auto pendulum : pendula) + #pragma omp parallel for + for (const auto pendulum : pendula) + for (int i = 0; i < substeps; i++) pendulum->update(h, gravity); } @@ -35,3 +45,4 @@ void Simulation::clearPendula() { delete p; pendula.clear(); } + diff --git a/src/Simulation.h b/src/Simulation.h index a31a608..e5df659 100644 --- a/src/Simulation.h +++ b/src/Simulation.h @@ -1,6 +1,9 @@ #include #include #include +#include + +using namespace std::chrono; class Pendulum; class QPainter; @@ -12,20 +15,23 @@ public: double size = 50; - double gravity; - double timescale; - int substeps; + double gravity {}; + double timescale {}; + int substeps {}; int updateInterval = 17; bool isPlaying = false; std::vector pendula; - void clearPendula(); QTimer * timer; void draw(QPainter*, int) const; +public slots: + void clearPendula(); private slots: void update(); +private: + time_point lastUpdate; }; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 7621d26..22dfe2e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,11 @@ #include #include #include "MainWindow.h" +#include +#include +#include + +using namespace std::chrono; int main(int argc, char* argv[]) { QApplication app(argc, argv); @@ -12,5 +17,29 @@ int main(int argc, char* argv[]) { MainWindow w; w.show(); + for (int threads = 1; threads <= 16; threads++){ + int num_steps = 100'000; + double step = 1.0 / double(num_steps); + + omp_set_num_threads(threads); + double pi = 0; + auto t = high_resolution_clock ::now(); + #pragma omp parallel + { + int numThreads = omp_get_num_threads(); + int threadId = omp_get_thread_num(); + int i; + double localSum = 0; + for (i = threadId; i < num_steps; i += numThreads){ + double x = (i + 0.5) * step; + localSum += 4.0 / (1.0 + x * x); + } + #pragma omp atomic + pi += localSum * step; + } + std::cout << threads << " " << duration_cast(high_resolution_clock::now() - t).count() << " "; + std::cout << pi << std::endl; + } + return QApplication::exec(); }