Friday, December 21, 2012

Quickie - QtGui.js - Now Even Liverer :)

Another quick update to my series of blogs about trying to get Qt ported over to the wonderful Emscripten, so that a Qt + C++ app can be compiled to Javascript and HTML5, and so run in a browser.

When last we met, I was having a few issues with QGraphicsView, which I eventually pinned down to Emscripten's occasional mishandling of combinations of doubles and 64-bit ints. I submitted a bug report, and received a lightning-fast fix, so now QGraphicsView seems to be working perfectly :)

Another problematic issue was with older versions of Chromium often "freezing" for long periods of time (accompanied by a large spike in memory consumption), which I hypothesised was due to the large amount of local variables declared in certain methods. As a result, I forked out some of Emscripten's nice parallel-optimisation code and wrote a few optimisations that worked around the issue by using Emscripten's (currently disabled upstream) "registerize" pass plus a bit of code that "tucks" variables into the smallest block where they are used. This doesn't fix the problem, but it does make it much, much less severe (i.e. freezes are less frequent, last for a shorter time, and consume less memory). Bleeding edge Chrome suffers much less from this issue, as well as being much faster and memory-efficient when crunching through piles of Javascript, so I recommend to use that with the demos if you can :)

A third issue was with the sheer size of the resulting Javascript produced (~34MB or so). Closure would have reduced this considerably, but unfortunately was buggy with emscripten-qt and always generated broken code :( So I've added a very simple, brute-force global name-mangling system that reduces this to about 16MB (gzip'ing, as my webserver hopefully does when you request a demo in your browser, reduces this to ~4MB or so, which is not *too* bad). The mangling is hilariously slow and hackish (it currently takes about 10 minutes to run!) and really downright dangerous (I'm frankly amazed it works at all!) but it should be relatively easy to implement efficiently and safely after I return from my Christmas break :)

Here are a handful of demos: make sure you have plenty of RAM free if you are using anything other than a recent Chrome :)

Chip
Colliding Mice
Elastic Nodes
Embedded Dialogs

(Note that, sadly, Konqueror/ Rekonq won't work with emscripten-qt, presumably due to lack of typed array support(?))

The next things to work on are a small helper library for making asynchronous dialogs slightly more convenient to use, and less-sketchy keyboard support (you'll notice that you can't currently type any punctuation, and selecting text with the keyboard is not quite right). After that, I'll upload more of the Emscripten-ised Qt examples and then get back to working on Kate's Vi mode :)

I've added a bunch more documentation (plus a few more screenshots!) here.

Thursday, November 29, 2012

Quickie - Qt*Gui*.js - It (Mostly) Lives :)

A quick update to my previous blogs about trying to get Qt ported over to the wonderful Emscripten, so that a Qt + C++ app can be compiled to Javascript and HTML5, and so run in a browser. When last we met, I had QtCore ported, and was starting to look at making QtGui work, using QWS. I quote:
Qt's QWS, at a cursory glance, seems like it does a *huge* amount of stuff for you, mainly leaving the tasks of flushing pixels to screen (using Canvas's "putImageData" method, in this case) and providing it with mouse and key events. I'm sure that there's a whole host of little devils lurking in the details, though :)
I was right on both counts - QWS is awesome, and fundamentally there is very little that one needs to do, but I certainly have been beset my devils along the way :) I'm pleased to report that I've (mostly) got it working, with some caveats.
Humble Beginnings
Slightly-Less-Humble Not-Quite Beginnings
That's More Like It

So now we have Qt's QGraphicsWidget based "chips" demo running in a browser, with only very minimal changes! But here come those caveats:

1) At certain angles and sizes, the "chips" will stop rendering entirely. I haven't begun to look into this yet, but the "embedded dialogs" has this even worse - none of the graphics scene is drawn at all :/ If I were to guess, I'd guess that there is some floating point issue cropping up somewhere.

2) Currently, Google's "Closure" compiler - which Emscripten optionally uses to compress the Javascript to acceptable levels - is generating incorrect code that will bomb out at runtime. When it works, I would estimate that it would compress the "chips" demo down from its massive 100MB(!) (unoptimised build) / 38MB (optimised build) to a less massive 12MB. Any gzip'ing done by the web server should then bring this down to a more svelte ~500k or so. Hopefully :) I haven't begun to try to diagnose this yet. Having "Closure" work correctly is nice beyond the bandwidth cost as it reduces the start-up time and (I think) the peak memory usage.

3) Much more annoyingly, and something that swallowed up all of the last two days - you will often get huge memory spikes in Chrome and long (~30s) hangs where the browser asks if you want to kill the page or not. It eventually recovers and drops the memory usage back down, but this is still unacceptable. This has had me completely baffled, to the point where I was engaged in "Magical Thinking" about what could be causing it - especially as it *doesn't* seems to occur with an unoptimised build (I think it is builds that have been run through "Relooper" in particular that are causing the problem, but will need to experiment further).

Using the Chrome profiling tools, it seems that the QStyle/ QPlastiqueStyle draw*Control methods always swallow up the lions share of the CPU during these episodes. Looking at the generated code, I see that there are over a thousand(!) local Javascript variables and "constants" (constant during that particular invocation, that is) being declared and initialised - indiscriminately - at the top of the method, and if this method is running several times in quick succession - as it is - it's possible that Chrome is quickly racking up memory usage then doing a lengthly garbage collection. This is all speculation on my part, though (there's that "magical thinking" again!) and needs further investigation.

A potentially worthwhile optimisation here would be to tuck some of these invocation-constants into the case statements where they are actually used, which should generally speed things up and reduce memory consumption. I'm still baffled as to why this doesn't happen when Relooper is used, though. Firefox doesn't seem to suffer from this, but is in general much slower.

So, in general, I'm cautiously optimistic about this. I won't be linking directly to demo pages due to their current massive sizes, but here are links to compress versions that you can play with. One is completely unoptimised and hence very slow, but doesn't hang Chrome, whereas the other is a lot faster but occasionally does :/

Chips Unoptimised

Chips Optimised

(zip file containing both - ~17MB download)

The actual patches to chips were tiny: just the standard job of making sure that all local variables in main() that need to persist for the lifetime of the app are allocated on the heap, not the stack (in Emscripten apps - well, Javascript in general, really - there is no possibility of local event processing loops like we use when we call QApplication::exec() - so QApplication::exec() will exit immediately, and then so will main())

I'm going to spend the rest of today a) resting and b) making a project page & documentation so that other people can play with it. If anyone has any questions in the meantime, please ask away :)

PS - it also no longer works with Konqueror or Rekonq, sadly: I thought I could get away with not using typed arrays - which Konqueror and Rekong don't appear to support(?) - but it looks Qt really does need them.

Update:I'm adding some documentation here, but it's still very incomplete and I'm too tired right now to add to it :)

Update2:Looks like my hunch about the hangs being due to large numbers of local variables might have been correct - I've "tucked" a few hundred local variables from some of the problematic functions into smaller scopes using a Vim macro, and, while it still hangs in Chromium from time to time, it is far less severe. Find it here!

Monday, November 19, 2012

Quickie - QtCore.js Progress Update

A quick follow-up to my previous blog here. In a nutshell - I'm experimenting with using Emscripten to try and compile Qt+C++ apps to Javascript and HTML5, so that they can be run in a browser (with some limitations).

Well, looks like I got lazy again ;) But having just restarted working on this, I now have QFile support working, and more importantly, a limited "event loop" which now means I can use QTimer, queued connections, posting events etc. This represents a big chunk of QtCore, and although I wasn't in any doubt that they would work, it's nice to see that all the moc+signal+slot stuff works seamlessly :)

I'll now start working on the GUI part. Qt's QWS, at a cursory glance, seems like it does a *huge* amount of stuff for you, mainly leaving the tasks of flushing pixels to screen (using Canvas's "putImageData" method, in this case) and providing it with mouse and key events. I'm sure that there's a whole host of little devils lurking in the details, though :)

Konqueror and Rekonq now work (I suppose they don't support the typed arrays which are Emscripten's default); the current test example can be found here: it is 2.3MB, but if your browser (and my webserver) support gzip, then it should be about a 280k download. Gobbles quite a bit of RAM, though :/

Source code for the example:

timer-qt.cpp
timer-qt.h

Tuesday, November 6, 2012

Quickie - QtCore.js proof-of-concept

Wow - long time, no blog. I've recently being doing some work on Kate's Vim mode and should really be continuing to work on that (I'll blog about it when I have something more substantial to report), but got side-tracked when I heard about the remarkable Emscripten project, and starting pondering whether I could get Qt to work on it.

For the uninitiated - Emscripten leverages the awesome LLVM and clang projects to take code compiled using clang - usually C/C++, but presumably any language which clang can compile and for which there is an Emscripten-ified library/ runtime available - and converts it into Javascript. After about 15 hours of work, I finally have Qt4 QtCore Emscripten-ified sufficiently well to print a simple, QString-based "Hello, world!". Warning: This is a big (13MB!) webpage, which will require a decent amount of RAM:

Hello, QtCore.js!

The original C++ source is the trivially simple one from here.

It doesn't seem to work in Konqueror/ Rekonq at the moment, but then, very few of the official demos work there, either. I haven't looked into why, yet.

There's a lot left to do - obviously, one of the major issues is that I haven't even looked at QtGui yet, and I haven't implemented the QtCore.js approximation of the event loop - but it should be a fun mini-project :) I'm not sure how far I'll take it, though - the resulting Javascript is impractically huge (although currently I don't think I'm applying any of Emscriptens - or maybe even llvm's - optimisations, yet) and that's just for QtCore. Plus, there are some limitations that are the result of using Javascript - no QThread support, for a start (and HTML5's web workers offer no help, here) and also it will almost certainly be impossible to have local event loops, meaning that any app that uses the *::exec methods for their pop up menus, message boxes, network activity etc will have to be re-worked to use the asyncronous versions instead.

If anyone's interested, I'm blog again in a few days time, if I've made any progress. If any Trolls want to give me some hints on how to get QtGui + plus a simple window system up-and-running using HTML5 Canvases, that would be hugely appreciated :)

Quick update: I turned the optimisations on, and it shrunk to a much more reasonable 1.8MB :)

Wednesday, December 31, 2008

Khrooty4Daily - Highly Experimental!

Experiment - Khrooty4Daily

Not much feedback here (but thanks to those wo did reply :)), but, hey - let's give it a go anyway!

I've cleaned up and uploaded a copy of Khrooty4Daily which you can find here. A few notes before people download it:


  • I'm going in completely blind here, and have no idea if this will work across distros - it could easily simple fail for most people at the first hurdle.

  • A chroot is not as insulated as a VM - in particular, processes started in the chroot are not separated from those started outside the chroot.

  • Again unlike a VM, it's possible for apps in a chrooted environment to e.g. crash/ lockup your X session.

  • Based on John's blog here, it seems at least possible that the chrooted KDE4Daily session won't run concurrently with an existing KDE4 session, which is a big shame, if true.

  • I have some difficulty unmounting /dev/ from the chroot, apparently necessitating a reboot if I want to delete the chroot. Important Note: Under no circumstances should you attempt to delete the chroot without properly unmounting it!



Potential doom and gloom aside (I prefer to err on the side of caution :)), it would be great if at least a handful of people - preferably spanning a goodly range of distros - could download and try it and report their findings here :) As mentioned, I've not tried this before outside of Kubuntu 8.04, so if any step fails for you, please post here.

So, from the top, open a shell and navigate to where you want the chroot to be. You will need root access. Download it:

wget "http://home.kde.org/~kde4daily/Khrooty4Daily4.2-experimental.tar.bz2"

Check the md5sum:

md5sum Khrooty4Daily4.2-experimental.tar.bz2
dad7d49fe39e416ff36f3ab59bf23229 Khrooty4Daily4.2-experimental.tar.bz2

Extract *as root* (should take up <2.5 GB). The "p" flag is important, here: we want things that should have root ownership (e.g. kcheckpass) to have root ownership.

tar -xjpf Khrooty4Daily4.2-experimental.tar.bz2

Quick spot-check that the permissions are OK:

ls -l kde4daily-chroot/usr/bin/kcheckpass
-rwsr-sr-x 1 root root 14934 2008-12-06 10:33 kde4daily-chroot/usr/bin/kcheckpass

We now need to mount /sys, /proc and /dev in the correct places in the chroot - please refer to the warning about /dev, above. Again *as root*:

mount -o bind /proc kde4daily-chroot/proc
mount -o bind /sys kde4daily-chroot/sys
mount -o bind /dev kde4daily-chroot/dev

If all has gone well, you are now ready to chroot into your new Khrooty4Daily environment! *As root*, do:

chroot kde4daily-chroot /bin/bash

You will now be running as the root user inside your Khrooty4Daily chroot. You might want to change the password of kde4daily at this point. Let's switch to our kde4daily user:

su - kde4daily

The command-prompt should be red.


The story so far ...


Let's do a quick update:

kde4daily-update

Ok, now to try starting up a GUI session. I believe it's possible to run apps from the chroot transparently inside your current X session, or give Khrooty4Daily a full-blown X session of it's own or even, I would guess, to eventually add it as a selectable option to KDM, but I don't really feel comfortable with that, so I'll just use Xephyr for now. Install Xephyr from your distros packages, and start it up. I'll use screen :1 as I only have one display - you might need to use a different number. There may or may not be xhost authorisation required - please let me know :) Let's use a 1024x600 screen. *Outside* of your chrooted session, launch Xephyr:

Xephyr -screen 1024x600 :1

Now from within your chrooted session, do

export DISPLAY=localhost:1
startkde

The localhost appears to be necessary. The :1 should obviously match the :n you used when launching Xephyr. All being well, Khrooty4Daily should launch in your Xephyr window!


Success!


Obviously, if something has gone wrong before you get to this point, please let me know. If not, let's do something daring - let's compile Amarok!

In your Khrooty4Daily session, open up a Konsole and navigate to the KDE4DAILY_SOURCE_DIR (this is just a convention - you can bung it anywhere you want, but it's simpler this way for the time being.)

cd $KDE4DAILY_SOURCE_DIR

Amarok lives in the multimedia (extragear) module (http://websvn.kde.org/trunk/extragear/multimedia/). Due to the way the KDE build system is arranged, we'll have to check out and run cmake on the whole module, although we'll only be actually compiling Amarok itself. Check out the source; we'll put it into a directory called extragear-multimedia to differentiate it from ordinary multimedia:

svn co svn://anonsvn.kde.org/home/kde/trunk/extragear/multimedia extragear-multimedia

Let's make a corresponding build dir for doing out-of-source builds. Again, I'll use $KDE4DAILY_BUILD_DIR by convention:

mkdir $KDE4DAILY_BUILD_DIR/extragear-multimedia
cd $KDE4DAILY_BUILD_DIR/extragear-multimedia

Khrooty4Daily provides the cmakekde command as described on techbase, but this command implicitly does a make && make install on the whole module, whereas we want to do cmake on the whole module, but only make && make install inside the amarok dir. So I provided the onlycmakekde command. This is roughly analogous to the "./configure" step of autotools:

onlycmakekde $KDE4DAILY_SOURCE_DIR/extragear-multimedia

Ordinarily you'd have to hunt around for dependencies at this stage, but Khrooty4Daily is jam-packed with them :)


Almost too easy ...


Now we just need to compile amarok. Make yourself a nice cup of tea during this step - you've earned it! If you have a multi-core CPU, you might want to tweak the "make" parameters.

cd amarok
make VERBOSE=1 && make install

If all goes well (it did at the time of writing), Amarok should be installed and ready to launch! I can't get the Xine backend to work (almost certainly my fault) so I have to change the backend to GStreamer in The Multimedia section of System Settings.


Switching to the GStreamer Backend



Kind of!



Groovy!


Funky Music not included :)

To exit the chroot, simply

exit


from the chroot session until you get back to the shell on the host machine that you entered the chroot from. It doesn't appear to be necessary to unmount your /proc, /sys and /dev unless you're fed up with the chroot and want to delete it, so I always leave mine mounted. If and when you do decide to delete khrooty4daily, you will need to unmount it. From the directory containing khrooty4daily, and as root:

umount kde4daily-chroot/proc
umount kde4daily-chroot/sys
umount kde4daily-chroot/dev

As mentioned, the unmount of /dev might fail. DO NOT attempt to delete kde4daily-chroot until it has been cleanly unmounted! You may need to reboot in order to achieve this. When you are 100% sure that it is no longer mounted, simply delete the kde4daily-chroot directory - this step will need to be performed as root, so it's best to do it from the command-line.

And that's it! Assuming everything went OK, and you haven't followed the instructions too blindy and deleted khrooty4daily, you can check out source for other modules or apps from kde-apps.org and compile them, hack on them, install kdevelop3 from the repositories or kdevelop4 from SVN, whatever floats your coding boat, and get stuck in. Maybe sign up for Klassroom, or help out with the million and one other tasks that could all use an extra pair of hands :)

Good hunting!

Monday, December 29, 2008

Khrooty4Daily - Interest? Potential Difficulties?

Phew! It's been quite a few months since my last blog, and lots of stuff has happened - I finally got my PhD, so now I can work on KDE without any guilt, and as a result I've gotten my SVN account so that I can wreak some havoc(K)!

From my last blog:

"Anyway, that's all for now - I hope to blog about some non-KDE4Daily-related stuff in the near future :)"

Well, it looks like I suck, but hopefully soon I'll be able to blog about some of the (small amount of) upstream work I've been doing on trying to bring back some of the file management features to Konqueror that went missing during the port to KDE3 to KDE4, and hopefully, eventually, improve on them. Konqui fans - look out for a Konqui4 File Management - State of the Union that I'll be putting together with ppenz within the next month or so!

As for this blog: I've noticed, on IRC and the forums, that many people seem to be having problems getting a KDE development environment set up. Since KDE4Daily releases track the most recent Kubuntu release, and I couldn't be bothered to update my 8.04 Desktop and Laptop to 8.10, this time around KDE4Daily was entirely developed and tested within a self-contained chroot nicknamed, appropriately enough, Khrooty4Daily. It could of course have been performed within a VM, but chroots have a few advantages (and disadvantages) compare to VMs that make it more appropriate for development, IMO: not least, the comparative ease of transferring files to and from the host machine; sharing the hosts RAM; and of course running at native speed which is much more pleasant for compiling and debugging.


Khrooty4Daily offers an easy way to check out and compile KDE sources: all of the cmake stuff is there, the .bashrc macros are present and correct, there's a full and up-to-date KDE install ready to be run, tested and hacked on, and there is a very rich set of package dependencies provided which will allow you to compile pretty much anything from SVN with as many of the optional features as I could satisfy the requirements for. So I was toying with the idea of cleaning and tarring it up and providing it to the community, but since it's going to be a very large blob (probably someone between 1-1.5GB compressed as a rough estimate) that will take me ages to prepare and upload, I thought I'd scope out the level of interest for such a beast. Who thinks they would find this useful? It's not quite as completely insulated and self-contained as a VM, but it still provides a nice way of getting things running on your machine that you can just untar when you begin and rm -rf when you're done.

And also, I appeal to LazyWeb: what are the potential difficulties in providing a chroot environment? Will it work with all x86 distros? Since the root password for all Khrooty4Daily installs is the same and we are going to be mounting /dev/, /sys/ etc onto it, are there any security issues that people need to be aware of? Descriptions of any hitches at all that people have run into with using chroots would be much appreciated as I've only been able to test it in a Kubuntu 8.04 host so far!

Friday, July 4, 2008

KDE4Daily Quickies: Goes Native; Lightly Traces Backs; Decides Our Fate in a Microsecond

Hello Planet - many thanks to jriddell for adding me :)

My name is Simon St James, and some of you may have heard of a project I run called KDE4Daily. This is largely running independently of me, now, so I'm looking into doing some "upstream" KDE development in the not too distant future, probably after the release of 4.1. Writing some docs for Plasma (I've never written docs before, so this will be a nice challenge) and helping out ppenz with his long, long list of Dolphin/ Konqueror TODOs will probably be the first thing I inflict on you all :)

Anyway, here's a trio of news snippets about KDE4Daily that I've been sitting on before getting syndicated:

Goes Native

A few people have asked whether it would be possible for Kubuntu 8.04 users (which forms the base of KDE4Daily) would be able to run KDE4 natively, and I'm pleased to note that the answer is "yes". Here it is running in Xephyr; I've also run it in its own X session, but this is slightly trickier.

The technique is based on the rough idea sketched out near the end of this document,
and in essence consists of making a new user called "kde4daily"; scraping out the scripts and the install from the VM image and dumping them into /home/kde4daily on your PC; installing the non-KDE package dependencies; starting up Xephyr and startkde'ing. Everything seems to work as expected: updates work the same as usual; kwin_composite worked in OpenGL mode when I ran it in its own X session, and XRender mode inside Xephyr; backtrace generation works with a little effort; etc.

I'm not quite sure what to do with it, though: some of the packages may or may not be something people particularly want on their desktop at the moment (e.g. mysqld for Akonadi server - actually, lazyweb - are there any security issues one needs to be aware of if one installs mysqld?), and of course, a native install can crash your X server if things go badly. On the plus side, the entirety of KDE4Daily is bunged into a single folder (except for the external package dependencies) so it can be easily removed if you decide you don't want it :) If people are interested in doing this, I'll see if I can put together a semi-official guide, but I'm fairly busy at the moment. Let me know :)

Lightly Traces Backs

This is a little long and technical, so I'll postpone it till the end.

Decides Our Fate in a Microsecond

As I've been planning for a while, now, human decisions have now been removed from the build process and it operates purely on a "If it compiles, ship it!" basis, which means I can bugger off at the weekend, say, or get run over by a bus, without (hopefully) everything screeching to a halt :) You can track the progress of builds here:

http://etotheipiplusone.com/kde4daily/buildprogress.html

It also operates as a "Dashboard Jr", and will display in angry red any compiler errors it encounters before re-trying again in a few hours.

Lightly Traces Backs (for real, this time)

One of the showstoppers for the initial release of KDE4Daily was getting proper, detailed backtraces working in a reasonably bandwidth efficient manner (both for you, the end user, and me, who has a very slow upload bandwidth shared with his housemates). The vast, vast volumes of debug info generated each build make this rather difficult, though, so in a rush, I knocked together a system that separates all the debugging info, binary diffs it against the last uploaded version, and uploads these much smaller diffs. In your KDE4Daily install, a request for a backtrace from DrKonqui via gdb will download the required pieces of debug info and re-assemble them, before offering them up to gdb for the formation of a nice, detailed backtrace. This process is rather slow, as you can imagine, but there was plenty of room for improvement, and I've spent quite a lot of time on trying to fix this.

The attempt was three-pronged: firstly, I got rid of the lazy and inefficient implementation that simply loaded the whole re-assembled debug data into memory before giving it to gdb in favour of a much more memory efficient buffer-and-stream solution. Secondly, I allow some of the debugging data to be pre-fetched during the kde4daily-update process when there is plenty of free memory (this functionality is only available on my harddrive at the moment). And thirdly, I delved deep into the guts of gdb to make it considerably more efficient when loading symbols for backtraces - with stock gdb, creating a backtrace (including Qt stack frames) for Konqueror took about 500MB of memory; with my patch, it peaks at about 200M, and generally hovers around 80MB or so. The patched gdb is called gdb-fast-bt-hack and handles all DrKonqui backtrace requests.

The basic effect of the patch is to allow a special mode, signified by passing the flag "--backtrace-only", that loads *only* the pieces of debugging needed for creating the stack frame, and unloads them when it has extracted the required stack frames. So not only does it take much less peak memory, but it also requests less pieces of debug data, which is expensive in the KDE4Daily system. Note that this will likely only work well if the debug info has been separated from the main executables/ libraries.

If you like horrifying hacks, you can find the patch here:

backtrace_only_gdb.diff

When gdb is attached, and if --backtrace-only has been passed to it, you can call "bt" and "bt" only (and only once!) to generate the backtrace.

Sadly, the time savings aren't as dramatic as I had expected in the VM - it seems I'm hitting some operations that are about an order of magnitude slower in the VM than in a real install. But it took me a whole weekend to do it so you're going to hear about it whether you like it or not ;)

Anyway, that's all for now - I hope to blog about some non-KDE4Daily-related stuff in the near future :)