New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[server] parallel map rendering #3886
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a general consideration that does not only apply to this particular PR which I think is a very good job!
I think that in the server we should try to stick to the 12 factors philosophy for the server configuration: pass all configuration through environment variables.
I think it's ok to have the configuration in the settings but I'd prefer if the settings could also be overridden by environment variables.
My suggestion is to add a new environment variables for each new configuration parameter and use the settings as a fallback in case the enviroment var is not set.
Ideally, we should be able to configure the server completely from the environment.
* reading qsettings. | ||
* @note added in QGIS 3.0 | ||
*/ | ||
class QgsMapRendererJobProxy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe worth moving QgsMapRendererJobProxy
into it's own file?
I am not sure this is the right approach. If I understand correctly, the proxy is introduced just to work around the fact that python cannot be used from multiple threads at the same time. In QGIS application however we do not have this problem, so I believe the issue comes from the fact that the server python support just does not release the python interpreter lock, so that other threads can run python code. So in summary I think we do not need renderer job proxy, we just need to fix python support in the server. |
Actually, the proxy is just here to hide the parallel/sequential render job configuration. It's the new function But I can take a look on how QGIS application does. |
Ideally just like in rendering in QgsMapCanvas, the only difference between parallel/sequential rendering job should be whether one uses QgsMapRendererParallelJob or QgsMapRendererSequentialJob. Everything else should be the same, otherwise we are risking rendering bugs that are hard to track down. For access control, it would be worthwhile to write a test to ensure that it's working correctly with parallel/sequential jobs without extra workarounds. |
As soon as this PR is merger, I will run a performance test and will share you on qgis-dev ML! |
9f4310d
to
e512679
Compare
@elpaso Thank you for your comment!
I added a QgsServerSettings class to centralize and manage the priority between environment variable and global settings. I only did it with two new environment variables : QGIS_SERVER_PARALLEL_RENDERING and QGIS_SERVER_MAX_THREADS. If you think it's a good idea, I can extend the behaviour with others variables too. |
@pblottiere thanks for implementation! |
It looks good. Does it log in the QGIS log that one setting has been overwrite by the environment ? This is very useful for debugging. |
@yjacolin Testing that in your benchmark tool could help tracking if we really gain what expected, and if we don't face issues with multiple concurrent access. On my tests with only one user, I found really good performance improvements. In the other way, there is still something more CPU consuming in server context than in desktop, since I just ear the CPU fan blowing for the same request :) Maybe the png issue you tracked? |
92714a5
to
dc6b794
Compare
Can the singleton introduced here be avoided? We are trying not to add anymore to the code - see qgis/qgis4.0_api#42 |
whatwhatwhat?! @pblottiere @vmora @mhugo hey the singleton killer team, is Nyall right? We might do something here :) |
@haubourg Yes, @nyalldawson is perfectly right. The settings management class was initially just a proposition, so I made it simple. But if we want to keep this idea, indeed, the singleton has to be removed :) |
07f8b00
to
4395d59
Compare
I looked into the issue causing the parallel render job to hang. Actually, without the changes I made to resolve filtering expressions in the main thread, the server hangs only when these conditions are met: And these conditions are typically encountered during tests. But everything is working well when the server runs "for real", so the python support in the server seems OK. I think it's due to the In short, the server hangs when a Python instance is using a QgsServer that calls C++ threads that call Python classes (thanks to an inherited class and a SIP binding). I do not have a clue on how it can be resolved. However, in any case, it seems more reasonable to avoid this configuration by always resolving filtering expressions in main thread (not time consuming since we just want to retrieve a string).
Moreover, to avoid differences between parallel and sequential rendering, filtering expressions are always resolved in the main thread. Thus, everything is exactly the same except we use QgsMapRendererParallelJob in one case and QgsMapRendererSequentialJob in another. Thanks a lot for your comments. Tell me what you think. |
I have updated the QgsServerSettings class to manage these environment variables:
A |
There's no more singleton! |
4395d59
to
f7729b3
Compare
@pblottiere looks good to me! |
@pblottiere @elpaso This certainly should be merged before #3866 because qgswmsserver files has been removed from the server code unit and it it will be a bit messy if you try to merge into removed files ! I will manage to port the changes to wms server before the merging of #3866. |
@dmarteau if you're agree, I will merge. |
@pblottiere there are some errors and warnings to fixe! |
@rldhont I'm gonna take a look. |
@pblottiere I revert the merge |
@rldhont |
@pblottiere I have tried to merge your code into #3866: there is a lot of conflicts and it's somewhat painful to rebase. I'm going to try the other way and see if it is cleaner: so there will only need to migrate changes to wmsserver. |
@pblottiere Merging your code into #3866 was somewhat painful, I'm going to try the other way. |
@pblottiere after the merge here are the errors. https://dash.orfeo-toolbox.org/viewBuildError.php?type=0&buildid=257417 |
No more warnings on master! |
@pblottiere @elpaso @rldhont: I have managed to merge #3886 onto #3866 which is much easier than the opposite. The result is here https://github.com/dmarteau/QGIS/tree/pblottiere-servermultithread. The code compiles and test are passed. |
@dmarteau |
@pblottiere I think this is because you missed a rebase with master. |
@pblottiere #3866 has been merged, so you have to update this PR. |
@pblottiere: look at https://github.com/dmarteau/QGIS/tree/pblottiere-servermultithread, may be you will find most of the rebasing done here. |
I mainly took your work for rebasing. Everything seems OK but I still got the next error from Travis "The job exceeded the maximum time limit for jobs, and has been terminated". I'll restart the build later. |
This PR allows to activate the parallel map rendering in QGIS Server.
By default, global QGIS QSettings are used to switch between parallel and sequential rendering.
But the QGIS_OPTIONS_PATH environment variable can be defined before spawning the server and the $QGIS_OPTIONS_PATH/QGIS/QGIS3.ini file is then read to retrieve rendering configuration.
For example:
Filtering expressions coming with QgsAccessControl can now be resolved before the rendering step. Thus, when the parallel map rendering is activated, filtering epressions are resolved within the main thread. Otherwise, the server hangs when multiple C++ threads are calling the same Python instance.
Let me know what you think.