diff --git a/core/include/Data/ArrayData.h b/core/include/Data/ArrayData.h index c466119..4ccc414 100644 --- a/core/include/Data/ArrayData.h +++ b/core/include/Data/ArrayData.h @@ -1,8 +1,9 @@ #ifndef SCIQLOP_ARRAYDATA_H #define SCIQLOP_ARRAYDATA_H +#include +#include #include - /** * @brief The ArrayData class represents a dataset for a data series. * @@ -22,10 +23,22 @@ public: template > explicit ArrayData(int nbColumns) : m_Data{1, QVector{}} { + QWriteLocker locker(&m_Lock); m_Data[0].resize(nbColumns); } /** + * Ctor for a unidimensional ArrayData + * @param nbColumns the number of values the ArrayData will hold + */ + explicit ArrayData(const ArrayData &other) + { + QReadLocker otherLocker(&other.m_Lock); + QWriteLocker locker(&m_Lock); + m_Data = other.m_Data; + } + + /** * Sets a data at a specified index. The index has to be valid to be effective * @param index the index to which the data will be set * @param data the data to set @@ -34,6 +47,7 @@ public: template > void setData(int index, double data) noexcept { + QWriteLocker locker(&m_Lock); if (index >= 0 && index < m_Data.at(0).size()) { m_Data[0].replace(index, data); } @@ -44,8 +58,9 @@ public: * @remarks this method is only available for a unidimensional ArrayData */ template > - const QVector &data() const noexcept + QVector data() const noexcept { + QReadLocker locker(&m_Lock); return m_Data[0]; } @@ -54,8 +69,9 @@ public: * @remarks this method is only available for a unidimensional ArrayData */ template > - const QVector &data(double tStart, double tEnd) const noexcept + QVector data(double tStart, double tEnd) const noexcept { + QReadLocker locker(&m_Lock); return m_Data.at(tStart); } @@ -63,20 +79,30 @@ public: template > void merge(const ArrayData<1> &arrayData) { + QWriteLocker locker(&m_Lock); if (!m_Data.empty()) { + QReadLocker otherLocker(&arrayData.m_Lock); m_Data[0] += arrayData.data(); } } template > - int size() + int size() const { + QReadLocker locker(&m_Lock); return m_Data[0].size(); } + void clear() + { + QWriteLocker locker(&m_Lock); + m_Data.clear(); + } + private: QVector > m_Data; + mutable QReadWriteLock m_Lock; }; #endif // SCIQLOP_ARRAYDATA_H diff --git a/core/include/Data/DataSeries.h b/core/include/Data/DataSeries.h index e94b9c4..936df33 100644 --- a/core/include/Data/DataSeries.h +++ b/core/include/Data/DataSeries.h @@ -6,9 +6,10 @@ #include +#include +#include #include - Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeries) Q_LOGGING_CATEGORY(LOG_DataSeries, "DataSeries") @@ -38,12 +39,19 @@ public: /// @sa IDataSeries::valuesUnit() Unit valuesUnit() const override { return m_ValuesUnit; } + void clear() + { + m_XAxisData->clear(); + m_ValuesData->clear(); + } + /// @sa IDataSeries::merge() void merge(IDataSeries *dataSeries) override { if (auto dimDataSeries = dynamic_cast *>(dataSeries)) { m_XAxisData->merge(*dimDataSeries->xAxisData()); m_ValuesData->merge(*dimDataSeries->valuesData()); + dimDataSeries->clear(); } else { qCWarning(LOG_DataSeries()) @@ -51,6 +59,10 @@ public: } } + virtual void lockRead() { m_Lock.lockForRead(); } + virtual void lockWrite() { m_Lock.lockForWrite(); } + virtual void unlock() { m_Lock.unlock(); } + protected: /// Protected ctor (DataSeries is abstract) explicit DataSeries(std::shared_ptr > xAxisData, const Unit &xAxisUnit, @@ -88,6 +100,8 @@ private: Unit m_XAxisUnit; std::shared_ptr > m_ValuesData; Unit m_ValuesUnit; + + QReadWriteLock m_Lock; }; #endif // SCIQLOP_DATASERIES_H diff --git a/core/include/Data/IDataSeries.h b/core/include/Data/IDataSeries.h index af1b2b2..4fc0ff9 100644 --- a/core/include/Data/IDataSeries.h +++ b/core/include/Data/IDataSeries.h @@ -51,6 +51,10 @@ public: virtual void merge(IDataSeries *dataSeries) = 0; virtual std::unique_ptr clone() const = 0; + + virtual void lockRead() = 0; + virtual void lockWrite() = 0; + virtual void unlock() = 0; }; // Required for using shared_ptr in signals/slots diff --git a/core/src/Variable/Variable.cpp b/core/src/Variable/Variable.cpp index 17795a3..2a2ba89 100644 --- a/core/src/Variable/Variable.cpp +++ b/core/src/Variable/Variable.cpp @@ -3,6 +3,9 @@ #include #include +#include +#include + Q_LOGGING_CATEGORY(LOG_Variable, "Variable") struct Variable::VariablePrivate { @@ -57,6 +60,7 @@ void Variable::setDateTime(const SqpDateTime &dateTime) noexcept void Variable::setDataSeries(std::shared_ptr dataSeries) noexcept { + qCDebug(LOG_Variable()) << "Variable::setDataSeries" << QThread::currentThread()->objectName(); if (!dataSeries) { /// @todo ALX : log return; @@ -67,8 +71,11 @@ void Variable::setDataSeries(std::shared_ptr dataSeries) noexcept impl->m_DataSeries = dataSeries->clone(); } else { + dataSeries->lockWrite(); + impl->m_DataSeries->lockWrite(); impl->m_DataSeries->merge(dataSeries.get()); - + impl->m_DataSeries->unlock(); + dataSeries->unlock(); emit updated(); } } diff --git a/core/src/Variable/VariableCacheController.cpp b/core/src/Variable/VariableCacheController.cpp index 7c42f2d..526fc9e 100644 --- a/core/src/Variable/VariableCacheController.cpp +++ b/core/src/Variable/VariableCacheController.cpp @@ -3,6 +3,7 @@ #include "Variable/Variable.h" #include +#include Q_LOGGING_CATEGORY(LOG_VariableCacheController, "VariableCacheController") struct VariableCacheController::VariableCacheControllerPrivate { @@ -32,6 +33,8 @@ VariableCacheController::VariableCacheController(QObject *parent) void VariableCacheController::addDateTime(std::shared_ptr variable, const SqpDateTime &dateTime) { + qCDebug(LOG_VariableCacheController()) << "VariableCacheController::addDateTime" + << QThread::currentThread()->objectName(); if (variable) { auto findVariableIte = impl->m_VariableToSqpDateTimeListMap.find(variable); if (findVariableIte == impl->m_VariableToSqpDateTimeListMap.end()) { @@ -81,6 +84,9 @@ QVector VariableCacheController::provideNotInCacheDateTimeList(std::shared_ptr variable, const SqpDateTime &dateTime) { + qCDebug(LOG_VariableCacheController()) + << "VariableCacheController::provideNotInCacheDateTimeList" + << QThread::currentThread()->objectName(); auto notInCache = QVector{}; // This algorithm is recursif. The idea is to localise the start time then the end time in the @@ -101,6 +107,8 @@ VariableCacheController::provideNotInCacheDateTimeList(std::shared_ptr QVector VariableCacheController::dateCacheList(std::shared_ptr variable) const noexcept { + qCDebug(LOG_VariableCacheController()) << "VariableCacheController::dateCacheList" + << QThread::currentThread()->objectName(); try { return impl->m_VariableToSqpDateTimeListMap.at(variable); } diff --git a/core/src/Variable/VariableController.cpp b/core/src/Variable/VariableController.cpp index 53b92cf..0e58f7e 100644 --- a/core/src/Variable/VariableController.cpp +++ b/core/src/Variable/VariableController.cpp @@ -152,6 +152,8 @@ void VariableController::createVariable(const QString &name, void VariableController::onDateTimeOnSelection(const SqpDateTime &dateTime) { + qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection" + << QThread::currentThread()->objectName(); auto selectedRows = impl->m_VariableSelectionModel->selectedRows(); for (const auto &selectedRow : qAsConst(selectedRows)) { @@ -166,6 +168,8 @@ void VariableController::onDateTimeOnSelection(const SqpDateTime &dateTime) void VariableController::onRequestDataLoading(std::shared_ptr variable, const SqpDateTime &dateTime) { + qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading" + << QThread::currentThread()->objectName(); // we want to load data of the variable for the dateTime. // First we check if the cache contains some of them. // For the other, we ask the provider to give them. diff --git a/gui/src/SqpApplication.cpp b/gui/src/SqpApplication.cpp index e53fdde..c79f0f7 100644 --- a/gui/src/SqpApplication.cpp +++ b/gui/src/SqpApplication.cpp @@ -18,6 +18,14 @@ public: m_VariableController{std::make_unique()}, m_VisualizationController{std::make_unique()} { + QThread::currentThread()->setObjectName("MainThread"); + m_DataSourceController->moveToThread(&m_DataSourceControllerThread); + m_DataSourceControllerThread.setObjectName("DataSourceControllerThread"); + m_VariableController->moveToThread(&m_VariableControllerThread); + m_VariableControllerThread.setObjectName("VariableControllerThread"); + m_VisualizationController->moveToThread(&m_VisualizationControllerThread); + m_VisualizationControllerThread.setObjectName("VisualizationControllerThread"); + // /////////////////////////////// // // Connections between controllers // // /////////////////////////////// // @@ -34,9 +42,6 @@ public: m_VisualizationController.get(), SIGNAL(variableAboutToBeDeleted(std::shared_ptr)), Qt::DirectConnection); - m_DataSourceController->moveToThread(&m_DataSourceControllerThread); - m_VariableController->moveToThread(&m_VariableControllerThread); - m_VisualizationController->moveToThread(&m_VisualizationControllerThread); // Additionnal init m_VariableController->setTimeController(m_TimeController.get()); diff --git a/gui/src/Visualization/VisualizationGraphHelper.cpp b/gui/src/Visualization/VisualizationGraphHelper.cpp index b80cb8f..afd2e62 100644 --- a/gui/src/Visualization/VisualizationGraphHelper.cpp +++ b/gui/src/Visualization/VisualizationGraphHelper.cpp @@ -5,12 +5,16 @@ #include -#include - Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper") namespace { +class SqpDataContainer : public QCPGraphDataContainer { +public: + void appendGraphDataUnsorted(const QCPGraphData &data) { mData.append(data); } +}; + + /// Format for datetimes on a axis const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss"); @@ -33,35 +37,36 @@ QSharedPointer axisTicker(bool isTimeAxis) void updateScalarData(QCPAbstractPlottable *component, ScalarSeries &scalarSeries, const SqpDateTime &dateTime) { - QElapsedTimer timer; - timer.start(); + qCDebug(LOG_VisualizationGraphHelper()) << "TORM: updateScalarData" + << QThread::currentThread()->objectName(); if (auto qcpGraph = dynamic_cast(component)) { // Clean the graph // NAIVE approch - const auto &xData = scalarSeries.xAxisData()->data(); - const auto &valuesData = scalarSeries.valuesData()->data(); - const auto count = xData.count(); - qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points in cache" << xData.count(); - auto xValue = QVector(count); - auto vValue = QVector(count); - - int n = 0; - for (auto i = 0; i < count; ++i) { - const auto x = xData[i]; - if (x >= dateTime.m_TStart && x <= dateTime.m_TEnd) { - xValue[n] = x; - vValue[n] = valuesData[i]; - ++n; + scalarSeries.lockRead(); + { + const auto xData = scalarSeries.xAxisData()->data(); + const auto valuesData = scalarSeries.valuesData()->data(); + const auto count = xData.count(); + qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points in cache" + << xData.count(); + + auto dataContainer = qcpGraph->data(); + dataContainer->clear(); + auto sqpDataContainer = QSharedPointer::create(); + qcpGraph->setData(sqpDataContainer); + + for (auto i = 0; i < count; ++i) { + const auto x = xData[i]; + if (x >= dateTime.m_TStart && x <= dateTime.m_TEnd) { + sqpDataContainer->appendGraphDataUnsorted(QCPGraphData(x, valuesData[i])); + } } + sqpDataContainer->sort(); + qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points displayed" + << sqpDataContainer->size(); } + scalarSeries.unlock(); - xValue.resize(n); - vValue.resize(n); - - qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points displayed" - << xValue.count(); - - qcpGraph->setData(xValue, vValue); // Display all data component->rescaleAxes(); diff --git a/gui/src/Visualization/VisualizationGraphWidget.cpp b/gui/src/Visualization/VisualizationGraphWidget.cpp index d96af5b..5af7fa8 100644 --- a/gui/src/Visualization/VisualizationGraphWidget.cpp +++ b/gui/src/Visualization/VisualizationGraphWidget.cpp @@ -79,7 +79,6 @@ void VisualizationGraphWidget::addVariable(std::shared_ptr variable) connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated())); } - void VisualizationGraphWidget::addVariableUsingGraph(std::shared_ptr variable) { @@ -178,7 +177,8 @@ void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1) { - qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged"); + qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged") + << QThread::currentThread()->objectName(); for (auto it = impl->m_VariableToPlotMultiMap.cbegin(); it != impl->m_VariableToPlotMultiMap.cend(); ++it) { diff --git a/gui/src/Visualization/qcustomplot.cpp b/gui/src/Visualization/qcustomplot.cpp index 809e1f3..a9f6699 100644 --- a/gui/src/Visualization/qcustomplot.cpp +++ b/gui/src/Visualization/qcustomplot.cpp @@ -18570,7 +18570,7 @@ void QCPLegend::setIconSize(const QSize &size) } /*! \overload -*/ + */ void QCPLegend::setIconSize(int width, int height) { mIconSize.setWidth(width); diff --git a/plugins/mockplugin/src/CosinusProvider.cpp b/plugins/mockplugin/src/CosinusProvider.cpp index 0f4ae0b..8bb61dc 100644 --- a/plugins/mockplugin/src/CosinusProvider.cpp +++ b/plugins/mockplugin/src/CosinusProvider.cpp @@ -6,6 +6,7 @@ #include #include +#include Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider") @@ -39,6 +40,8 @@ CosinusProvider::retrieveData(const DataProviderParameters ¶meters) const void CosinusProvider::requestDataLoading(const QVector &dateTimeList) { + qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataLoading" + << QThread::currentThread()->objectName(); // NOTE: Try to use multithread if possible for (const auto &dateTime : dateTimeList) { auto scalarSeries = this->retrieveData(DataProviderParameters{dateTime});