Slicer custom application deployment to many computers

@jcfr @pieper @lassoan @superlib

Good Morning. I’m starting to think about how to deploy SlicerQR to 25,000 PCs across the Mayo Enterprise. After building the package, it consists of over 7000 files at a total size of over 700MB. It would be seriously frowned-upon to propose deploying it to 25,000 PCs. So, my question is: Would there be any disadvantages to placing the installation in 1 place on a file share and have the users execute SlicerQR from a folder there? Would there be conflicts with sharing? Once the app is loaded into local memory, what are potential problems with a common launch path?

Hello @jcfr, @superlib

Could you grant @Liqin access to the SlicerQR repository? She is the technical specialist for this project and will need to begin reading through and understanding the code ASAP. Thank you.

Probably this could be reduced to about half size by removing parts that are not needed, but I guess it would not change things significantly.

Running Slicer from a shared network drive would have many advantages (for example, it would be much easier to handle automatic updates), but it would be very bad if users would need to download the viewer from scratch for viewing data.

A good solution could be to install just a launcher on each computer, which would be responsible for automatically copying of Slicer files from the shared folder to a local cache and launch it when needed (no installation is needed, Slicer can run from any writeable folder). The launcher would be a small standalone application (if built with static Qt then it would be a few MB, if built with dynamically-linked Qt then it would be a few ten MB). If someone does not need the 3D viewer then the full Slicer would never be copied to the computer. The launcher could show download progress, handle automatic updates (check if the locally cached version is the same as in the shared folder and offer to upgrade), custom URLs (so that Slicer could be launched from a werb browser) and file associations (e.g., Slicer could be launched when the user wants to open a .dcm, .nrrd, … file).

Hey @lassoan,

I’m a bit confused. Please allow me to clarify.

Currently, I can run the SlicerQR slicelet from a fileserver. I copied the folder tree to a folder on the file server and mapped it to drive S:. When I, launch SlicerQR like this…

S:
cd SlicerQREADS
SlicerQReads.exe --python-code "folder='S:\SlicerQREADS\TestImages'; import os; slicer.util.loadVolume(folder + '/' + os.listdir(folder)[0], {'singleFile': False})"

This works fine without copying the files locally.

Will this be OK for 25000 potential users? Actually, probably about 5000 simultaneous users max.

Simply running from a read-only shared location has these disadvantages:

  • Launching Slicer can take much longer if the files have to be fetched each time from a remote server
  • Users cannot install extensions that dynamically download and install additional Python packages

If you don’t allow your users to install extensions and startup time is not critical (or your network is very fast and/or local file caching works very efficiently) then these limitations might not be a problem for you.

Size of the Slicer installation is comparable with size of a patient image, so if your servers can already handle image download requests from 5000 users then I would assume that they can handle Slicer downloads as well. However, this download is clearly a burden that could be avoided by setting up local caching. If you don’t want to create a custom launcher/downloader then you can check what caching is available at the operating system level. It may be possible to set up local caching of a shared network folder (maybe even persistent cache, which is kept when the computer is restarted) or you may leverage other file sharing services (sharepoint, onedrive, etc.) that your organization already uses.

Cool! Thanks @lassoan ! :slight_smile:

Here are few approach we could evaluate:

  • statically link loadable module into the application
  • statically integrate PythonQt module that are currently dynamically loaded
  • statically link against external dependency like ITK, VTK, DCMTK, …
  • harden the current python integrate into C++ and remove the use of python

That said, before investing resources to support this, we should consider:

  • @lassoan comment regarding size of images vs size of the application
  • performing additional bench-marking for startup time and define which target time we aim (Initial profiling by @pieper concluded that shared library loading was at fault)

This is turning into a very interesting topic, since it’s not unusual for custom apps to be concerned about the size of the distribution, startup time, and “time to first image”, so Doug’s project will have extra side benefits.

I wouldn’t suggest this for every computer, but for heavy users who want instant display one could leave the app running so it could respond instantly. It could even auto-start at login (to be used with care, since this kind of auto-run can really bog down the login process).

@spycolyf can you give us any benchmarks about other apps that are distributed to the 25,000 Mayo computers? How big are the installations? How fast do they start up?

1 Like

@lassoan @pieper @jcfr,

Sorry for the delay, I had to meet with Mayo legal about its involvement in opensource software. Bottom line, to indicate on the repository GitHub page and documentation that it’s a Mayo collaboration and that “Mayo is a contributor” to any opensource project is totally fine and the use of the QREADS brand is approved as well.

Anyway, about the startup times, are you asking about benchmarks for imaging apps in particular? The main QREADS competitor image viewers are Visage and ResMD. MPR is embedded into those apps. My goal with QREADS is to make SlicerQREADS seem as if is a part of QREADS. When the user right-mouse clicks on a CT scan image for example, a menu pops up and then they select SlicerQREADS. My goal is to make the user experience a seamless transition from QREADS to SlicerQREADS as though SlicerQREADS is a popup from the QREADS menu item selection. If we can get it to come up in 10 seconds, that would be within the range of acceptability.

That’s very helpful as a target. Some of the things Jc mentioned can certainly help towards this. It may also be possible to start scrolling the axials as they arrive and then snap to MPR once the volume is complete (or something similar so the user doesn’t just see a blank screen and get bored).

Also glad you cleared with legal. Mayo has a great tradition of contributions to open source but it’s always good to confirm.

Warm start (starting Slicer if it was launched recently) takes about 10 seconds on my computer but cold startup can take 2-3x more. We may be able to reduce the cold startup time to around 10 seconds, but it would be probably more comfortable to keep Slicer open after it is started because the user would still need to wait for DICOM loading.

The wait time for the user might be also reduced if Slicer startup overlaps with the network transfer of the images.

Images will be stored locally by the time the user selects the SlicerQREADS menu item on the image menu. And of course it depends on the size of the series. So, I’d like to pursue keeping slicer up after the first use. So, how would the user experience work? Would it minimize after pushing the close button and restore when the QREADS menu item is selected again? If so, how would QREADS communicate with SlicerQREADS while it’s stays open? Some type of inter-process communication?

Yes, Slicer could just close its windows and go into background mode with a port open so that it could get awaked by, say, an http request with parameters about where to load the data and optionally what view to display. Then it would open its windows back up. For heavy users Slicer could be started at login so even their first request is serviced quickly.

@pieper @lassoan @jcfr

Sounds wonderful Steve! Is this a current Slicer feature? I’d like to try it before my presentation to the Apps Oversight Committee on March 4th if possible.

Thanks

It’s “sort of” a current feature in the sense that there are existing prototypes and everything needed can be accomplished with a minimal amount python to customize behavior. There are several options and you’d want to decide what would work best.

A working example is demoed in this video. There’s some preamble about how the teamplay system works where the study is selected, etc. Then when the Slicer button is pressed, the teamplay app creates a json file with the information about the study to load together with the security tokens and it posts it to a url. This triggers a slicer instance to read and display the corresponding study.

If you are working on the user’s local machine, where you can have direct access to the URL and the data, you could use SlicerWeb with the repl (read-eval-print-loop) endpoint, which allows arbitrary code execution.

For example:

curl -X POST localhost:2016/slicer/repl --data "import SampleData; SampleData.SampleDataLogic().downloadMRHead(); slicer.app.layoutManager().setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutOneUpYellowSliceView)"

Makes this image appear:

You can post any slicer python commands, e.g. to show/hide the main window, load or unload data, switch layout or modules, etc. (obviously don’t expose this port to the internet!)

@pieper @jcfr @lassoan

Thanks Steve, So could you help me with getting SlicerQREADS to do this, or help me to understand that example? It’s very cryptic to me. How can I get SlicerQREADS to do this?

It shouldn’t be too hard to get this approach going, but I don’t know about the QREADS side of the equation. What language is it written in? The example uses a linux command line utility but any http package could be used, so my assumption would be you can add a button that sends an http request. Do you know if/how it can do that?

On the Slicer side you just need to define the operations you want, like show/hide main window, set layout, load and display dicom data, close scene and hide window. Then it’s just a matter of sending those python commands via the http request.

While controlling Slicer via web requests would be certainly an elegant and flexible solution, if it is not easy to integrate a http library into QREADS or hospital IT policies does not let an application to open a listening port then there are other options.

A very simple solution is to use files to communicate. QREADS could ask Slicer to load an image by creating a json file in a designated folder. Slicer can set up a QFileSystemWatcher (or use a timer and check for folder changes manually once in every few seconds) and if there is a new file there then read and process it.

@lassoan @pieper @jcfr Well that’s just it. I don’t know if the web request method is the way to go or not. I am a user experience guy with little web experience, and that’s all that matters to me in the end. I should get one of my experts in this conversation. I do know that QREADS is written in JAVA and is heavily client-server architected and the client communicates with the server via http and https. So, web requests are in. But would this be as fast as local installation, and could Slicer reside on the QREADS server? I will need to get my QRERADS server experts involved.

Calling web requests should not be an issue then. It should be possible to create a listening socket in Slicer that only accept local connections and that will not require firewall exceptions. So, QREADS sending commands to Slicer view web requests should work well.