print-manager is now low latency and low CPU demanding
First of all I really want to say a big: Thank You!
For all of you who donated to my fund raising campaign, the goal was reached pretty fast and there was also people sending the money without PayPal, if you are still willing to do the contribution there’s still 5 days left, and if you can’t make a donation I already appreciate the good feedback I receive, you CAN still send patches fill bugs, translate there are lots of ways of contributing.
Back to the topic…
It all started last week when I was trying to hunt down a ghost, yes a ghost!! You don’t believe me? Take a look:
If you runned our new plasmoid for a while, I don’t know how much time is needed, if suspend/resume has any interference in it, but it turns out a ghost job and printer will show up… Debugging this is really hard because when I put the plasmoid the ghost is not there, so I don’t know how to reproduce it quickly, but I know the cause.
Let me first tell how all print-manager worked before this change
CUPS is like an HTTP server, you create IPP requests, send, and get back a response. So when the application/plasma data-engine started I asked the server for all printers, then I asked for all jobs. This process is a bit CPU consuming because it has to convert Qt types (QString, QStringList..) to C types but also adding then with the proper CUPS flags (ie say a boolean var is bool), and do the opposite when we get a response.
Now when the UI needs to refresh I actually had to do all of that using a timer every 1,5 second, plus update the model/plasma data-engine, and even check if anything changed to avoid refreshing the UI which is increases the CPU usage.
Because of the ghost problem I remembered seeing some DBus interface on printer-applet, so taking a look at the code I found “com.redhat.PrinterSpooler” Interface. Using dbus-monitor I was able to create a new printers data-engine to test how it would work, and turned out that this was a very good change, now instead of refreshing all printers using a timer, I could not only refresh the list when something changed but also only ask CUPS the printer I was interested in.
So say if you click on pause printer immediately a signal is emitted and the UI will refresh, thus creating a very low latency. Now not happy enough I had to do the same with the print jobs, but I found out that “com.redhat.PrinterSpooler” didn’t provide enough signals. Say I cancel a job using http://localhost:631 no signal is emitted resulting on the print-queue thinking the job is still active, you can find this bug on printer-applet.
I decided to try the Gnome Control Center printers module, and yes the bug was there too, so I decided to contact the RedHat guy (Tim Waugh) to see if we could get another CUPS patch, and it turns out that “com.redhat.PrinterSpooler” was not used long ago, and there was a new “org.cups.cupsd.Notifier” interface, which for my surprise Gnome printers module used.
The new interface is quite different from the old one, instead of just waiting for a signal to arrive, we have to actually register which signals we want to listen, and CUPS returns a subscription ID, this ID has to be renewed from time to time (but surely is much less work than getting all your jobs and printers from time to time).
Reading the CUPS patch that makes this working I found out why the Gnome thing wasn’t working, it didn’t registered to the needed events, so now not only KDE print stuff works better but also Gnome’s :P
If you read all of the above you are still curious about the ghost, aren’t you?
Well as I said I don’t know when it happens but I sort of know why, the old data-engine had “Printers”, “ActiveJobs”, “AllJobs” entries which didn’t had any valid data, but where used to probe data-engine to update it’s entries. So for some reason these invalid sources showed up on the listing, I even tried to use a DataModel filter but it didn’t resolve.
With the usage of DBus I dropped two features, listing all jobs or completed jobs. The problem is that these lists tend to be too big, and plasmoids start to get slow to fill the data, also to get rid of the ghost entry I removed the invalid entries so there’s no way of telling the data-engine what do you want. The alternative would be to have more two data-engines, but 99,9% of the users will care only about the active jobs which this will fit the need perfectly (the QWidget GUI is also available providing this feature).
To end this post, I have a nice screenshot:
As you can see I’ve changed the plasmoid to use switches to pause/resume printer.
Make sure you make uninstall before testing the new version since the old data-engine was removed.
UPDATE: The above screenshot with a plasmoid smaller and printers grayed when disabled: