simulation is on different thread

main
Benjamin Kraft 1 year ago
parent a3d04d3086
commit c9a281fbb3
  1. 3
      CMakeLists.txt
  2. 3
      src/GLWidget.cpp
  3. 18
      src/MainWindow.cpp
  4. 4
      src/MainWindow.h
  5. 15
      src/Simulation.cpp
  6. 14
      src/Simulation.h
  7. 29
      src/main.cpp

@ -8,10 +8,11 @@ set(CMAKE_AUTOUIC ON)
find_package(Qt6 COMPONENTS OpenGLWidgets REQUIRED) find_package(Qt6 COMPONENTS OpenGLWidgets REQUIRED)
find_package(Eigen3 REQUIRED) find_package(Eigen3 REQUIRED)
find_package(OpenMP REQUIRED)
file(GLOB_RECURSE SOURCE_FILES src/**.cpp) file(GLOB_RECURSE SOURCE_FILES src/**.cpp)
add_executable(Pendulum WIN32 ${SOURCE_FILES} icons/icons.qrc) add_executable(Pendulum WIN32 ${SOURCE_FILES} icons/icons.qrc)
include_directories(${EIGEN3_INCLUDE_DIR}) include_directories(${EIGEN3_INCLUDE_DIR})
target_link_libraries(Pendulum Qt6::OpenGLWidgets) target_link_libraries(Pendulum Qt6::OpenGLWidgets OpenMP::OpenMP_CXX)

@ -33,8 +33,9 @@ void GLWidget::timerEvent(QTimerEvent *e) {
void GLWidget::updateFPS() { void GLWidget::updateFPS() {
auto thisFrame = high_resolution_clock::now(); auto thisFrame = high_resolution_clock::now();
auto diff = duration_cast<milliseconds>(thisFrame - previousFrame).count(); auto diff = (int)duration_cast<milliseconds>(thisFrame - previousFrame).count();
currentFPS = 1000 / (diff == 0 ? 1 : diff); currentFPS = 1000 / (diff == 0 ? 1 : diff);
// std::cout << currentFPS << std::endl;
previousFrame = thisFrame; previousFrame = thisFrame;
} }

@ -14,9 +14,15 @@
#include <QCoreApplication> #include <QCoreApplication>
#include "Pendulum.h" #include "Pendulum.h"
#include "Button.h" #include "Button.h"
#include <QThread>
#include <QCloseEvent>
#include <QTimer>
MainWindow::MainWindow() { MainWindow::MainWindow() {
simulationThread = new QThread(this);
simulation = new Simulation; simulation = new Simulation;
simulation->moveToThread(simulationThread);
simulationThread->start();
masses = std::vector<double>(MaxSegments); masses = std::vector<double>(MaxSegments);
lengths = std::vector<double>(MaxSegments); lengths = std::vector<double>(MaxSegments);
@ -291,7 +297,7 @@ QWidget * MainWindow::buildAddUI() {
removeBtn->setStyleSheet("background-color: #ffaaaa"); removeBtn->setStyleSheet("background-color: #ffaaaa");
connect(addBtn, &QPushButton::clicked, this, &MainWindow::add); 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(addBtn);
btnLyt->addWidget(removeBtn); btnLyt->addWidget(removeBtn);
@ -420,10 +426,6 @@ void MainWindow::add() {
} }
} }
void MainWindow::remove() {
simulation->clearPendula();
}
void MainWindow::resetSimulationControl() { void MainWindow::resetSimulationControl() {
gravitySlider->setValue(981); gravitySlider->setValue(981);
timescaleSlider->setValue(100); timescaleSlider->setValue(100);
@ -433,3 +435,9 @@ void MainWindow::resetSimulationControl() {
void MainWindow::toggleSimulation() { void MainWindow::toggleSimulation() {
simulation->isPlaying = !simulation->isPlaying; simulation->isPlaying = !simulation->isPlaying;
} }
void MainWindow::closeEvent(QCloseEvent *e) {
simulationThread->quit();
simulationThread->wait();
e->accept();
}

@ -11,11 +11,14 @@ enum Property {Angle, Mass, Length};
class MainWindow : public QWidget { class MainWindow : public QWidget {
public: public:
explicit MainWindow(); explicit MainWindow();
protected:
void closeEvent(QCloseEvent*) override;
private: private:
void buildUI(); void buildUI();
QWidget * buildAddUI(); QWidget * buildAddUI();
QWidget * buildSimulationUI(); QWidget * buildSimulationUI();
Simulation * simulation; Simulation * simulation;
QThread * simulationThread;
GLWidget * glWidget = nullptr; GLWidget * glWidget = nullptr;
@ -42,7 +45,6 @@ public slots:
void resetLengths(); void resetLengths();
void normalizeLengths(); void normalizeLengths();
void add(); void add();
void remove();
void resetSimulationControl(); void resetSimulationControl();
void toggleSimulation(); void toggleSimulation();

@ -2,12 +2,16 @@
#include "Pendulum.h" #include "Pendulum.h"
#include <QPainter> #include <QPainter>
#include <QTimer> #include <QTimer>
#include <QThread>
#include <omp.h>
#include <iostream>
Simulation::Simulation() { Simulation::Simulation() {
timer = new QTimer(this); timer = new QTimer(this);
QTimer::connect(timer, &QTimer::timeout, this, &Simulation::update); QTimer::connect(timer, &QTimer::timeout, this, &Simulation::update);
timer->setInterval(updateInterval); timer->setInterval(updateInterval);
timer->start(); timer->start();
lastUpdate = high_resolution_clock::now();
}; };
void Simulation::draw(QPainter *p, int screenSize) const { void Simulation::draw(QPainter *p, int screenSize) const {
@ -18,6 +22,11 @@ void Simulation::draw(QPainter *p, int screenSize) const {
} }
void Simulation::update() { void Simulation::update() {
auto thisUpdate = high_resolution_clock::now();
auto ms = (int)duration_cast<milliseconds>(thisUpdate - lastUpdate).count();
// std::cout << ms << std::endl;
lastUpdate = thisUpdate;
if (!isPlaying) if (!isPlaying)
return; return;
@ -25,8 +34,9 @@ void Simulation::update() {
h /= substeps; h /= substeps;
for (int i = 0; i < substeps; i++) #pragma omp parallel for
for (const auto pendulum : pendula) for (const auto pendulum : pendula)
for (int i = 0; i < substeps; i++)
pendulum->update(h, gravity); pendulum->update(h, gravity);
} }
@ -35,3 +45,4 @@ void Simulation::clearPendula() {
delete p; delete p;
pendula.clear(); pendula.clear();
} }

@ -1,6 +1,9 @@
#include <vector> #include <vector>
#include <cstdint> #include <cstdint>
#include <QObject> #include <QObject>
#include <chrono>
using namespace std::chrono;
class Pendulum; class Pendulum;
class QPainter; class QPainter;
@ -12,20 +15,23 @@ public:
double size = 50; double size = 50;
double gravity; double gravity {};
double timescale; double timescale {};
int substeps; int substeps {};
int updateInterval = 17; int updateInterval = 17;
bool isPlaying = false; bool isPlaying = false;
std::vector<Pendulum *> pendula; std::vector<Pendulum *> pendula;
void clearPendula();
QTimer * timer; QTimer * timer;
void draw(QPainter*, int) const; void draw(QPainter*, int) const;
public slots:
void clearPendula();
private slots: private slots:
void update(); void update();
private:
time_point<system_clock> lastUpdate;
}; };

@ -1,6 +1,11 @@
#include <QApplication> #include <QApplication>
#include <QSurfaceFormat> #include <QSurfaceFormat>
#include "MainWindow.h" #include "MainWindow.h"
#include <omp.h>
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
QApplication app(argc, argv); QApplication app(argc, argv);
@ -12,5 +17,29 @@ int main(int argc, char* argv[]) {
MainWindow w; MainWindow w;
w.show(); 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<microseconds>(high_resolution_clock::now() - t).count() << " ";
std::cout << pi << std::endl;
}
return QApplication::exec(); return QApplication::exec();
} }

Loading…
Cancel
Save