Re: GraphicsView performance problems
Well...[CUT BECAUSE SOMETHING WEIRD IS GOING ON...it seems to be as if drawing the lines one by one is faster...but somehow that is rather unbelievable on second thought]...
Another method of getting rid of spurious mallocs is to reuse Pens and Brushes...
I guess i will not repost all of the code for these little changes...
Does anyone has access to a profiler on windows/mac? I would like to know if those changes that were good for linux (ellipses, rect -> painterpath) lines drawn one by one, is also good for these palatforms ;-)
Re: GraphicsView performance problems
Quote:
Originally Posted by
camel
Well, after some more testing I found out that it is cheaper (in the drawBackground) method to draw the lines one by one, than to regenerate a new painterpath everytime.
Another method of getting rid of spurious mallocs is to reuse Pens and Brushes...
I guess i will not repost all of the code for these little changes...
Does anyone has access to a profiler on windows/mac? I would like to know if those changes that were good for linux (ellipses, rect -> painterpath) lines drawn one by one, is also good for these palatforms ;-)
Yeah exactly I too would like to know opinion on windows especially. Did anyone notice performance difference between windows and linux when you select and move all items ?
Re: GraphicsView performance problems
Quote:
Originally Posted by
Gopala Krishna
[2] 25.0 0.01 0.00 GridScene::drawBackground(QPainter*, QRectF const&) [2]
0.00 0.00 36506/36506 GridScene::setupArray(QVarLengthArray<QLineF, 100>&, QRectF const&) [12]
0.00 0.00 36506/36506 GridScene::drawLines(QPainter*, QVarLengthArray<QLineF, 100>&) [13]
That looks really weird.
The reason probably once again that the time is spent inside of Qt-Code and not yours, so sadly that does not help.
Or it could have been inlined, again not really helpfull :-/
Have you tried valgrind/callgrind and KCacheGrind as a profiler? It is rather nice :-)
Re: GraphicsView performance problems
Quote:
Originally Posted by
camel
That looks really weird.
The reason probably once again that the time is spent inside of Qt-Code and not yours, so sadly that does not help.
These figures are wrong. All functions from inside Qt should be counted on behalf of the functions calling them and here all functions have nothing but zeros. The application needs to run longer.
Quote:
Or it could have been inlined, again not really helpfull :-/
Yes, that's possible, especially if they were implemented inside the class header and optimisations were enabled.
You must be sure to disable inlining optimisations. You can use -fno-inline to disable inlining.
Re: GraphicsView performance problems
Yup! you both are right. Anyway I am recompiling Qt tomorrow. I'll surely post after I do that. In the meanwhile I'd like to inform you people that I have never used cachegrind. Is that better than gprof ? If yes how should I use that ?
Re: GraphicsView performance problems
Did you try my last modification? Did it change anything for you?
Quote:
Originally Posted by
Gopala Krishna
Yup! you both are right. Anyway I am recompiling Qt tomorrow. I'll surely post after I do that. In the meanwhile I'd like to inform you people that I have never used cachegrind. Is that better than gprof ? If yes how should I use that ?
You do not need to compile anything special (besides DEBUG of course ;-)
Then call
Quote:
$valgrind --tool=callgrind ./YOUR_APP
this will produce a file called callgrind.out.PID_OF_PROCESS
then you can call
Quote:
$kcachegrind callgrind.out.PID_OF_PROCESS
http://kcachegrind.sourceforge.net/cgi-bin/show.cgi
Re: GraphicsView performance problems
I have modified my application which uses QGraphicsView framework to draw a grid simmilar to yours and I implemented it in a worst possible way:
Code:
painter->setPen(p);
for(int row=10+((int)(rect.top())/10)*10; row<rect.bottom(); row+=10){
for(int col = 10+((int)(rect.left())/10)*10; col<rect.right(); col+=10)
painter->drawPoint(col, row);
}
}
Profiling info (compiled with -fno-inline -ggdb -pg) looks like this:
Code:
% cumulative self self total
time seconds seconds calls us/call us/call name
33.33 0.02 0.02 1547664 0.01 0.01 QRectF::right() const
33.33 0.04 0.02 SpecScene::drawBackground(QPainter*, QRectF const&)
16.67 0.05 0.01 1527572 0.01 0.01 QPainter::drawPoint(int, int)
As you see 33% of the application time is spent in drawBackground and half of it is used to calculate QRectF::right() (which makes sense as it gets calculated in each iteration of the loop) and pretty much is used to actually draw the points.
Code:
index % time self children called name
<spontaneous>
[1] 83.3 0.02 0.03 SpecScene::drawBackground(QPainter*, QRectF const&) [1]
0.02 0.00 1547627/1547664 QRectF::right() const [2]
0.01 0.00 1527572/1527572 QPainter::drawPoint(int, int) [3]
0.00 0.00 20635/20651 QRectF::bottom() const [35]
0.00 0.00 20055/20055 QRectF::left() const [36]
0.00 0.00 580/580 QRectF::top() const [93]
0.00 0.00 1/702 QColor::QColor(int, int, int, int) [92]
As you see it is actually more time consuming to calculate the rectangle coords than to draw points!
Some facts:
- I use Qt4.2.2 on i686 Linux,
- I didn't use antialiasing,
- I didn't use scaling (so I have an identity matrix when it comes to viewport-window transformations),
- scene size was about 1200x1000,
- I didn't compile Qt with profiling information (so I guess it's not required after all),
- I got detailed info about both mine and Qt methods,
- the result is pretty fast.
I got a pretty good result, but I didn't suffer from viewport-window transformations which might be your case if you scale the view. I didn't use antialiasing for my view, as points are points - they don't suffer from the aliasing effect. I could easily improve the implementation by calculating rectangle coordinates once per drawBackground() which should reduce the execution effort by half.
It is up to you to do the interpretation of the results. My impression is that it is not really drawBackground() which causes the slowdown - maybe it is just called too often by other parts of the system? Maybe you abuse update()?
Re: GraphicsView performance problems
Quote:
Originally Posted by
camel
Did you try my last modification? Did it change anything for you?
You do not need to compile anything special (besides DEBUG of course ;-)
Then call
this will produce a file called callgrind.out.PID_OF_PROCESS
then you can call
http://kcachegrind.sourceforge.net/cgi-bin/show.cgi
Thanks ! Here is the output as attachment
EDIT: My quota of attachment is almost over. I'll update a bit later.
Re: GraphicsView performance problems
Quote:
Originally Posted by
wysota
I have modified my application which uses QGraphicsView framework to draw a grid simmilar to yours and I implemented it in a worst possible way:
Profiling info (compiled with -fno-inline -ggdb -pg) looks like this:
Code:
% cumulative self self total
time seconds seconds calls us/call us/call name
33.33 0.02 0.02 1547664 0.01 0.01 QRectF::right() const
33.33 0.04 0.02 SpecScene::drawBackground(QPainter*, QRectF const&)
16.67 0.05 0.01 1527572 0.01 0.01 QPainter::drawPoint(int, int)
Well, if you disable inlining, no wonder right() is expensive. calling a function 1.5 Million times just takes its time...inlining is there for a reason ;-)
So I would not call this run very exemplary... :-)
Re: GraphicsView performance problems
just a note:
If you like to profile further into the drawing part,
you need to call:
Quote:
valgrind --tool=callgrind --seperate-callers=5 --seperate-recs=10 ./YOUR_APP
Otherwise you will get "cycles", which is not very helpfull in this task..
BUT: this takes up much more memory to analyze later...
Re: GraphicsView performance problems
Hi,
well I just love to play with this... ;-)
Here is another (and much faster) way to write the drawBackground function...with the added niceness that it helps avoiding the color errors ;-)
You might want to check if this survives zooming etc.
Code:
{
const int gridSize = 25;
if (backgroundCache.isNull()) {
backgroundCache
= QPixmap(gridSize, gridSize
);
const int middle = gridSize / 2;
QPainter backgroundPainter
(&backgroundCache
);
backgroundPainter.setRenderHints(painter->renderHints());
backgroundPainter.
fillRect(QRect(0,
0, gridSize, gridSize
),
QBrush(Qt
::white));
backgroundPainter.setPen(backgroundPen);
backgroundPainter.setBrush(backgroundBrush);
backgroundPainter.drawLine(0, middle, gridSize, middle);
backgroundPainter.drawLine(middle, 0, middle, gridSize);
}
const int realLeft = static_cast<int>(std::floor(rect.left()));
const int realRight = static_cast<int>(std::ceil(rect.right()));
const int realTop = static_cast<int>(std::floor(rect.top()));
const int realBottom = static_cast<int>(std::ceil(rect.bottom()));
const int firstLeftGridLine = realLeft - (realLeft % gridSize);
const int firstTopGridLine = realTop - (realTop % gridSize);
for (int x = firstLeftGridLine; x < realRight; x += gridSize) {
for (int y = firstTopGridLine; y < realBottom; y += gridSize) {
painter->drawPixmap(x, y, backgroundCache);
}
}
}
Have a nice day :-)
Re: GraphicsView performance problems
Quote:
Originally Posted by
camel
just a note:
If you like to profile further into the drawing part,
you need to call:
Otherwise you will get "cycles", which is not very helpfull in this task..
BUT: this takes up much more memory to analyze later...
I get the following error
Quote:
valgrind: Bad option '--seperate-callers=5'; aborting.
I am trying to analyse the code as it is now. I am getting lost here and there but kcachegrind is a cool tool. Needs some time to get used to it. Thanks for helping me till now. I'll continue with this tomorrow.
Re: GraphicsView performance problems
Quote:
Originally Posted by
camel
Well, if you disable inlining, no wonder right() is expensive. calling a function 1.5 Million times just takes its time...inlining is there for a reason ;-)
So I would not call this run very exemplary... :-)
It means that QRectF::right() takes longer than QPainter::drawPoint() and right() is not a very complex method :)
After getting rid of the right() and bottom() calls inside the loop the result of profiling is as follows:
Code:
50.00 0.06 0.06 SpecScene::drawBackground(QPainter*, QRectF const&)
25.00 0.09 0.03 1460235 0.02 0.02 QPoint::QPoint(int, int)
16.67 0.11 0.02 1454915 0.01 0.03 QPainter::drawPoint(int, int)
The QPoint constructor is called by QPainter::drawPoint, so we can forget about it. The whole method takes over 90% of the whole application time and gives a total of less than 0.1s. That's not much :)
It is important to see what the bottleneck is instead of shooting blind. No matter how much you optimise QPainter::drawLines() if it's not the bottleneck, you won't get a decent improvement.
In my opinion it would be much simpler and faster to simply apply a backgroundBrush with the grid to the scene and forget about points and lines. You wouldn't get any painter paths then, no floating point operations. The only thing that could slow down the process is the matrix transformation, so try to avoid it.
Re: GraphicsView performance problems
Quote:
Originally Posted by
Gopala Krishna
I get the following error
valgrind: Bad option '--seperate-callers=5'; aborting.
I think they changed the option names during 3.1 and 3.2 (which I use)
try:
valgrind --tool=callgrind --fn-caller=5 --fn-recursion=10 ./YOUR_APP
Re: GraphicsView performance problems
Quote:
Originally Posted by
camel
Hi,
well I just love to play with this... ;-)
Here is another way to write the drawBackground function...with the added niceness that it helps avoiding the color errors ;-)
You might want to check if this survives zooming etc.
Have a nice day :-)
Not bad idea! :) That problem solved !!! Thanks a lot.
Now the next problem is performance ! :(
A good day to you too :)
Re: GraphicsView performance problems
Quote:
Originally Posted by
wysota
It is important to see what the bottleneck is instead of shooting blind. No matter how much you optimise
QPainter::drawLines() if it's not the bottleneck, you won't get a decent improvement.
That is why I look into my KCachgrind and follow the callgraph and sources ;-)
The problem is not drawPoints, as that does not do much.
The problem with drawLines and friends is that it often (with antialiasing) first creates a painterpath from those lines and then paints them. This takes time, not least because of memory allocation.
This is why I said use painterpaths directly.
Optimizing the returnvalue of boundingrect and shape is so easy (and makes the code much nicer in my opinion) so that I would not even consider it a optimization, its just nicer programming. (besides helping during run-time of course ;-)
Quote:
Originally Posted by
wysota
In my opinion it would be much simpler and faster to simply apply a backgroundBrush with the grid to the scene and forget about points and lines. You wouldn't get any painter paths then, no floating point operations. The only thing that could slow down the process is the matrix transformation, so try to avoid it.
I cuncur there, see my last post about the drawbackground function.
To use a background brush would be the logical next step ;-)
Re: GraphicsView performance problems
Quote:
Originally Posted by
camel
The problem with drawLines and friends is that it often (with antialiasing) first creates a painterpath from those lines and then paints them. This takes time, not least because of memory allocation.
This is why I said use painterpaths directly.
If you disable antialiasing, there is a possibility that painter paths will not be used. And there is no point in having antialiasing enabled for drawing horizontal or vertical lines, as these don't suffer from the aliasing effect. You can safely temporarily disable antialiasing while painting those.
Code:
bool isAA
= painter
->renderHints
() & QPainter::Antialiasing;
painter
->setRenderHint
(QPainter::Antialiasing,
false);
painter->drawLines(...);
painter
->setRenderHint
(QPainter::Antialiasing, isAA
);
Another possibility of painter paths being active is that there is scaling involved. But while zooming in, the number of lines needed to draw should decrease. While zooming out on the other hand you can draw fewer lines as too many of them will clutter the scene anyway.
You can also store the path in a member variable and then only draw the path on the painter. But I think using a background brush will be much faster, especially with smooth scaling disabled.
Re: GraphicsView performance problems
Quote:
Originally Posted by
wysota
In my opinion it would be much simpler and faster to simply apply a backgroundBrush with the grid to the scene and forget about points and lines.
Well I tried even this. That is not the problem. First of all the main problem is while moving "many items" together. For example in the above eg the performance goes down if you select all resistors and move - thats about 80 items at a time!!! (20 resistors,40 nodes, 20 text items) . Here to get sufficient performance the area to be updated should be selected appropriately and efficiently so that the scene is updated least number of times.
Further I have a question - is the the bsp indexing causing these performance problems ?
Further I would like to inform that I am not using any matrix transformations. All these are just on regular matrix.
Re: GraphicsView performance problems
Quote:
Originally Posted by
wysota
If you disable antialiasing, there is a possibility that painter paths will not be used. And there is no point in having antialiasing enabled for drawing horizontal or vertical lines, as these don't suffer from the aliasing effect. You can safely temporarily disable antialiasing while painting those.
The problem being of course that the lines look differenty ;-)
But some people might see that as an advantage in this case.
Quote:
Originally Posted by
wysota
Another possibility of painter paths being active is that there is scaling involved. But while zooming in, the number of lines needed to draw should decrease. While zooming out on the other hand you can draw fewer lines as too many of them will clutter the scene anyway.
You can also store the path in a member variable and then only draw the path on the painter. But I think using a background brush will be much faster, especially with smooth scaling disabled.
In this case the brush is faster. Storing the path in a member variable is not possible in this case, as the lines to draw will change wildly during repaints, and I am not sure how efficient it would be to crop out the rest if you draw all possible lines.
For the other items, I did just that, storing the path. which works out quite well. I might be possible to also use pixmaps here, but that is probably rather a space/time tradeoff... :-)
Re: GraphicsView performance problems
Quote:
Originally Posted by
Gopala Krishna
First of all the main problem is while moving "many items" together.
So the problem is not within drawBackground....
Quote:
Further I have a question - is the the bsp indexing causing these performance problems ?
Yes, you should disable the bsp indexing while moving many items at once and enable it again afterwards. Every time you move an item, the tree may need to be rebuilt. Multiply that by the number of items and number of moves you perform...
Quote:
Further I would like to inform that I am not using any matrix transformations. All these are just on regular matrix.
If you use zooming, then you are using matrix transformations. You are using them anyway as I'm almost 100% sure viewport-window conversion and/or the transformation matrix is used to obtain local coordinate system for items :)