GUI events slow down long computations
-
@JonB the 'begin' variable also increases by 4096 each time. so the pattern goes:
begin: 0... size: 4096
begin: 4096.. size: 8192
begin: 8192... size: 12288 etc..
it increases at the bottom of the plot function, begin += 4096 :)edit: the plot is correct and what is expected from my txt file, just reeeeaallly slow when buttons are pressed (presumably from the processEvents(); function in the loop)
@engsml said in GUI events slow down long computations:
the 'begin' variable also increases by 4096 each time.
Oh, you mean that's your variable you don't show but increment yourself. I was thinking it was some kind of
std::list::begin
iterator on the list of points.Your plot would not have gone wrong, just it would contain loads of "duplicate" points. But I take the point about the buttons being the issue.
-
@JonB the 'begin' variable also increases by 4096 each time. so the pattern goes:
begin: 0... size: 4096
begin: 4096.. size: 8192
begin: 8192... size: 12288 etc..
it increases at the bottom of the plot function, begin += 4096 :)edit: the plot is correct and what is expected from my txt file, just reeeeaallly slow when buttons are pressed (presumably from the processEvents(); function in the loop)
@engsml said in GUI events slow down long computations:
just reeeeaallly slow when buttons are pressed (presumably from the processEvents(); function in the loop)
I do think you ought explain what a button actually does? The whole point is that the
processEvents()
allows whatever code for on clicked to actually run, so of course if it does much stuff it's going to slow things down. If a button's click does basically nothing, then the overhead is much smaller. If you just click a button (rather than keep clicking it) which does nothing, it shouldn't take any more time than if you don't click a button (but still haveprocessEvents()
in the code), if you're saying it does? -
@engsml said in GUI events slow down long computations:
just reeeeaallly slow when buttons are pressed (presumably from the processEvents(); function in the loop)
I do think you ought explain what a button actually does? The whole point is that the
processEvents()
allows whatever code for on clicked to actually run, so of course if it does much stuff it's going to slow things down. If a button's click does basically nothing, then the overhead is much smaller. If you just click a button (rather than keep clicking it) which does nothing, it shouldn't take any more time than if you don't click a button (but still haveprocessEvents()
in the code), if you're saying it does?@JonB The buttons mainly do stuff like scroll left or right, set the range to autoscale the plot, zoom in/out and save a screenshot. All the methods are found in the QChart API and only have about 1 line of code each.
I can imagine the overlaps plot twice (i.e when begin is 4096 but also the end of the last loop when size was 4096) but I am not too sure if there are other duplicates. Am I missing something?
-
@JonB The buttons mainly do stuff like scroll left or right, set the range to autoscale the plot, zoom in/out and save a screenshot. All the methods are found in the QChart API and only have about 1 line of code each.
I can imagine the overlaps plot twice (i.e when begin is 4096 but also the end of the last loop when size was 4096) but I am not too sure if there are other duplicates. Am I missing something?
@engsml
Don't worry about what I said about duplicates. I'll assume your code is correct there. I just misunderstood what yourbegin
was.I'm still not sure just what your expectation/experience is. If you press a button to change how the chart looks (like scrolling or zooming or whatever), every time you click it will do so. That will interrupt your adding of new points till the action is finished, so naturally the final, overall plot time will end up being longer. Would you not expect that?
But if you do not click a button, but do have the
processEvents()
in there, the only extra thing that is happening is that the chart is getting redrawn (points added) as it goes along. Which will also be slower overall than not redrawing till the whole thing is finished.I still say you are calling
processEvents()
too frequently. You should use a batch size. If you say 4096 makes it too unresponsive, at least try 10% of that (400, 100, whatever) rather than calling it for every single point appended. -
@engsml
Don't worry about what I said about duplicates. I'll assume your code is correct there. I just misunderstood what yourbegin
was.I'm still not sure just what your expectation/experience is. If you press a button to change how the chart looks (like scrolling or zooming or whatever), every time you click it will do so. That will interrupt your adding of new points till the action is finished, so naturally the final, overall plot time will end up being longer. Would you not expect that?
But if you do not click a button, but do have the
processEvents()
in there, the only extra thing that is happening is that the chart is getting redrawn (points added) as it goes along. Which will also be slower overall than not redrawing till the whole thing is finished.I still say you are calling
processEvents()
too frequently. You should use a batch size. If you say 4096 makes it too unresponsive, at least try 10% of that (400, 100, whatever) rather than calling it for every single point appended.@JonB Thanks for your help! I included this code snippet in my for loop (I created a variable to help track each 10th element). It seems to run much faster. I'll test it out a bit more and see what the 'magic number' is. Thanks so much again for all your help.
if(currentIndex % 10 == 0) { QCoreApplication::processEvents(); }
-
@JonB Thanks for your help! I included this code snippet in my for loop (I created a variable to help track each 10th element). It seems to run much faster. I'll test it out a bit more and see what the 'magic number' is. Thanks so much again for all your help.
if(currentIndex % 10 == 0) { QCoreApplication::processEvents(); }
-
@engsml
Yep, that's 1 in 10. Like I suggested, I'd be looking for more like 1 in 100 or 1 in 400 as being frequent enough. (I'm surprised that 4096 is too "lumpy" in the first place.)@JonB Yeah it seems 100 is a good number where it still remains fast and responsive. I'm pretty surprised too! My file is about 300,000 coordinates which is probably a lot less data than most large scale programs. I would've assumed Qt and C++ are quicker at processing it.
-
@JonB Yeah it seems 100 is a good number where it still remains fast and responsive. I'm pretty surprised too! My file is about 300,000 coordinates which is probably a lot less data than most large scale programs. I would've assumed Qt and C++ are quicker at processing it.
@engsml
300k points-odd is still a lot of points, though having no experience I don't know what to expect. I don't suppose your average end-user will notice each one of those. If you only add 1 in 10 of them you callprocessEvents()
10 times fewer for the same responsiveness. So if you have a lot of points you could sample or average and it would all be a lot quicker. Though that's probably very naughty :) -
@engsml
300k points-odd is still a lot of points, though having no experience I don't know what to expect. I don't suppose your average end-user will notice each one of those. If you only add 1 in 10 of them you callprocessEvents()
10 times fewer for the same responsiveness. So if you have a lot of points you could sample or average and it would all be a lot quicker. Though that's probably very naughty :) -
@JonB That's definitely a good point. I'll have to play around with the UX when I get everything working properly in the end :)
-
@engsml
Hang on a minute. Let's look at your code, please:int arrSize = 4096; //for incrementing in intervals for(int i = 0; i < arr.size(); i += arrSize) //Plots in increments of 4096 plot(arr, (i + 4096));
This passes first 0+4096, then 4096+4096, then 8192+4096, then....
void myClass::plot(QVector<QPointF> arr, int size) for(int i = begin; i < size; i++){
arr
is always the original array. I presume (I'm not C++)begin
is always 0.size
is bigger (by 4096) every timeplot
is called.Aren't you (re-)plotting more & more points --- specifically, all points from 0 up to where you have progressed to --- every time you call
plot()
in your batches?? Or am I going loopy?Hi,
@JonB said in GUI events slow down long computations:
void myClass::plot(QVector<QPointF> arr, int size)
for(int i = begin; i < size; i++){arr is always the original array. I presume (I'm not C++) begin is always 0. size is bigger (by 4096) every time plot is called.
Nope, it's a copy, if you want to avoid useless copies, pass const references i.e.
void myClass::plot(const QVector<QPointF> &arr)
.In the case you only want to process items between two elements of the vector then pass the start and end iterator within your arrays.
-
@engsml
I see there is a https://doc.qt.io/qt-5.9/qxyseries.html#append-2 which takes aQList<QPointF>
. It may or may not be more efficient than you adding points one-at-a-time. Might be worth a try?@JonB I tried that, but it still caused the GUI to become unresponsive. I also tried a similar approach where I passed a QVector<QPointF> and did series->replace(); and that was also too slow for the function to handle. It seems the data is just too large for these functions. I considered passing the array in intervals instead of all at once for these functions, but ultimately decided it was already very similar to the function I already have.
-
@engsml
Since you allowprocessEvents()
after each single point append, I would expect you would see the chart repaint for every point. (Without that you would only see the whole chart at the end, in one single go.) This may be pretty as an animation, but it's bound to be slower (I would have thought) than making it so it only paints once on conclusion, or at least only between "batches" of new points. Depends what you want.It is true that if you have computation-heavy code you should really do that in a distinct thread from the UI thread, to retain responsiveness. However, the catch is that accessing the
QChart
/QSeries
can only be done from the UI thread which created it. That means yourseries->append()
call.One usually arranges for the computation thread to send a signal to the UI thread for the points it wants added to the chart. But in your case I don't see any actual heavy-duty computation going on, you seem to have all the coordinates you want already in some array. So you don't actually want to do any more than append the point, and I don't see that a separate thread is useful to you....
@JonB In my case i use this function for processing the graph points which is used for graph plotting to the chartview in QML.This function is called approximately 1/10th of the second continously
void Link::haversine(double lat5, double lon5, double lat2, double lon2) { QtConcurrent::run([=, this]()mutable { // Captures all variables by value //QMutexLocker locker(&mutex23); //first_method(lat5,lon5,lat2,lon2); lat5 = qDegreesToRadians(lat5); lon5 = qDegreesToRadians(lon5); lat2 = qDegreesToRadians(lat2); lon2 = qDegreesToRadians(lon2); dlat = lat2 - lat5; dlon = lon2 - lon5; // Haversine formula components a = qPow(qSin(dlat / 2.0), 2) + qCos(lat1) * qCos(lat2) * qPow(qSin(dlon / 2.0), 2); c = 2.0 * qAsin(qSqrt(a)); c = earth_radius * c; graph_x = c*1000 ;//- tare_main_distance; graph_y = env_depth; graph_points(graph_x,graph_y,yaw1,pitch1); emit new_data(); }); }
Will it slow down the GUI whe prolong running of the software.If it is how to minimally solve it?
-
@JonB In my case i use this function for processing the graph points which is used for graph plotting to the chartview in QML.This function is called approximately 1/10th of the second continously
void Link::haversine(double lat5, double lon5, double lat2, double lon2) { QtConcurrent::run([=, this]()mutable { // Captures all variables by value //QMutexLocker locker(&mutex23); //first_method(lat5,lon5,lat2,lon2); lat5 = qDegreesToRadians(lat5); lon5 = qDegreesToRadians(lon5); lat2 = qDegreesToRadians(lat2); lon2 = qDegreesToRadians(lon2); dlat = lat2 - lat5; dlon = lon2 - lon5; // Haversine formula components a = qPow(qSin(dlat / 2.0), 2) + qCos(lat1) * qCos(lat2) * qPow(qSin(dlon / 2.0), 2); c = 2.0 * qAsin(qSqrt(a)); c = earth_radius * c; graph_x = c*1000 ;//- tare_main_distance; graph_y = env_depth; graph_points(graph_x,graph_y,yaw1,pitch1); emit new_data(); }); }
Will it slow down the GUI whe prolong running of the software.If it is how to minimally solve it?
@Vijaykarthikeyan
I know nothing about QML. My reaction to your code:- Behaviour/timing depends on what
graph_points()
andnew_data()
do. - If
graph_points()
"updates the UI" (and that counts for chartview in QML) are you sure you are allowed to do it from a separate thread? - Code seems to do a couple of trivial calculations and produce a single point to add. Is this really worth doing in in its thread?
- Doing anything like this just 10 times per second must surely be trivial and not lead to performance problems?
- If anything this thread is about "batching" updates of multiple points rather than updating with a single point.
- Does your approach achieve anything time-wise over the time taken ultimately for the call to
[Q]XYSeries::append(single-point)
? - Have you timed your code over some non-thread simple implementation to see whether it has any advantage?
- Behaviour/timing depends on what
-
graph points() is the function to be called to log/save the calculated value in a text file.
New_data() is the signal which is emitted in this function has to be received in QML side.
I surfed through the website.They are saying the Math library operations will slow down the performance.That's why I'm using concurrent run.
I doubted at the Batch processing because i'm developing real time application in which batch processing introduce a little bit delay
I wish to develop the UI in QML that's why i avoid the Qt c++ gui.when not implenmented in concurrent run, it is introducing some delay