Three things I did to tackle Mockingbird performance issues

I posted an update to Mockingbird earlier today that should make loading large projects much faster.  Most of what I did is probably fairly obvious, but I thought I should share what I did anyway for any Cappuccino newbies looking to help the performance of their app.

1. Use the Safari profiler

The first step to optimization is to always, ALWAYS profile your app.  The things slowing you down will often surprise you, and the guys at 280North have done an amazing job to make Safari's profile very usable with Cappuccino.  You can read more about what they've done here.  After using the profiler, I found a few easy ways to speed things up, but no matter what I did, some of the larger projects were still giving me slow script errors on Firefox.  It was at this point that I realized that if I could somehow break up the work that's being done up front when a new project is loaded, things would work out much better.  And then I remembered that I could...

2. Use Javascript's setTimeout method to break up a large chunk of work

The main issue with loading large projects up front is that each page was being recreated serially in one go.  Instead of doing this, I used setTimeout to load each page, and then give the browser a break between each page load.  My function was basically something like:

- (void)loadPageFunction { window.setTimeout(function() { [self loadPageFunction]; }, 0); }

This way, the browser doesn't think that loading all the pages is one giant chunk of work and, so, for large projects, unless the project has a really crazed page, the browser shouldn't complain.

But then, I noticed one more odd thing - whenever I loaded a project after already having a large project, things ran much more slowly.  After using the profiler to see what was going on, I noticed that my app was spending a lot of time cleaning up notifications from the old project.  After some investigation, I found out that the implementation for - [CPNotificationCenter removeObserver:] is way slower than explicitly removing your observer for each notification using - [CPNotificationtCenter removeObserver:name:object:], and I was using the former everywhere.  So, I decided to change these to...

3. Use - [CPNotificationtCenter removeObserver:name:object:] instead of - [CPNotificationCenter removeObserver:]

One of the problems with Javascript is its lack of weak references, which becomes an issue with singletons like CPNotificationCenter's defaultCenter.  I've tried fairly hard to make sure I always remove my observers wherever I set them up, but I'm pretty sure there are still leaks in there somewhere.  These leaks don't really affect performance until you use a - [CPNotificationCenter removeObserver:] call since this will end up iterating through all your notifications (so if you have many, that becomes a problem).  This is, however, a hack around a more fundamental problem - either we need to figure out a way to implement some kind of weak referencing system in Objective-J or, (the easier route), make it easier to not use the default notification center to handle notifications.  A lot of classes internal to the framework use the default notification center for messaging, but it would definitely be a lot easier for me to just trash the notification center whenever I open a new project (still not perfect, I know, but I think better than what currently happens).  

Loading mentions Retweet
Filed under  //  Cappuccino  
Comments (4)
Posted 20 days ago

Exporting Cappuccino views to HTML

On the way to implementing PDF export, I needed to be able to transform Mockingbird pages into static HTML.  So, I added a simple category to CPView.  This category creates a cloned DOMElement of the CPView's DOMElement that has the canvas elements converted to PNG images.  I then use XMLSerializer to serialize and send this data to my server.  You can get the gist of it here - http://gist.github.com/253272 .

This uses Nihilogic's Canvas2Image library, which requires base64.j .  The one problem with this code is it won't work in IE since it requires a canvas-enabled browser.

In the meantime, hope this can help someone else trying to do something similar =).

Loading mentions Retweet
Comments (0)
Posted 1 month ago

A small step towards better text support in Cappuccino

Though Cappuccino has treated me very well so far, text support in Cappuccino is still an area that needs much improvement.  Many newcomers still ask about multiline text support, and so far, the solution has been the minimal implementation of CPTextView located here.  I've been using this for a while, but recently ran into a few problems, and decided to make it just a little less hacked together =).

First, the code: http://gist.github.com/222291

EDIT: The above code works with Cappuccino's current master branch.  If you are using Jake, this should work: http://gist.github.com/239696

This code is a bit of an amalgam of code from CPTextField and the old CPTextView.  I've tried to make it a bit more cross-browser compatible and have added support for tabbing.  I've also changed the behavior to be based roughly on the behavior Ross Boucher implemented for CPTextField as described here.  I implement the same delegate methods, except that for CPTextView, the action fires on escape instead of return.  Note that this is not actually the behavior of CPTextView in Cocoa, so if you want to override this behavior, I've made sure to let CPTextView be easily overridable.  There are no file-scoped functions - you can just override the private methods _keyUpFunction, _keyDownFunction, _keyPressFunction and _blurFunction. 

There's still obviously a lot lacking in the code.  For one, I didn't really adhere strictly to the Cocoa API for CPTextView when writing this.  Additionally, autoscrolling doesn't work, entering text is fairly slow after scrollbars appear, and I would like to implement mouse tracking so that clicking on the CPTextView's scroll bar doesn't fire the blur method for the CPTextView.  But this is doing the job for now on Mockingbird.

Loading mentions Retweet
Filed under  //  Cappuccino   Objective-J  
Comments (0)
Posted 3 months ago

Some new friends

You may see me posting sometimes with divia at http://lispservice.posterous.com/ .

Loading mentions Retweet
Comments (0)
Posted 11 months ago

Installing Weblocks

These are the steps I followed to get Weblocks working on OS X 10.5 (Leopard). Note that you should have Mercurial, CVS, and Darcs installed.

  1. Install SBCL with multithread support. The multi-threaded part is important and not enabled by default, and not doing it will result in a page that gives you an obscure error message that reads:
    Socket error in "bind": EADDRINUSE (Address already in use)
    To install SBCL with multithread support do the following:
    1. Download the source for SBCL from http://www.sbcl.org/platform-table.html
    2. After unarchiving the source, in the root directory of the source, create a file called customize-target-features.lisp
    3. In that file add the following to enable threads when building SBCL:
      (lambda (features)
             (flet ((enable (x)
                      (pushnew x features))
                    (disable (x)
                      (setf features (remove x features))))
              ;;; Threading support, available only on x86/x86-64 Linux, x86 Solaris
              ;;; and x86 Mac OS X (experimental).
              (enable :sb-thread))) 
      
    4. Compile SBCL with "sh make.sh" from your shell (this takes a while)
    5. Install SBCL with sh install.sh
  2. Get the Weblocks source with
    hg clone http://www.bitbucket.org/skypher/weblocks-stable/.
    
    You will need Mercurial.
  3. Add commands in your .sbclrc file to require asdf, asdf-install, and push your Weblocks source into the ASDF central registry. This file should be located in your home directory. If it does not exist you will need to create it. For me, the file looks like this:
    (require 'asdf)
    (require 'asdf-install)
    (push #p"/Users/saikat/Development/Source/weblocks/" asdf:*central-registry*)
    
  4. Install ASDF-System-Connections. This wasn't listed anywhere but a lot of the libraries that Weblocks depends on complained if I didn't have this installed. This step may not be necessary - I haven't tried without it. I couldn't get ASDF-System-Connections to install by just doing (asdf-install:install :asdf-system-connections). I downloaded the source and installed it using asdf-install. To do this, get the source as a gzipped tar file from here. Then use asdf-install to install it from your local directory as described here
  5. Install all the dependencies listed here. Some notes about this before you begin:
    1. Before installing hunchentoot, I had to install cl-json, metatilities-base, and cl+ssl by hand (asdf-install by name failed on these). For cl-json, I got the source from here. You will need darcs to get it. For metatalities-base, I did this in my shell to get the source:
      $ wget http://common-lisp.net/project/metatilities-base/metatilities-base.tar.gz
      
      For cl+ssl, I got the source from here. You will need CVS to get it. Then I installed all of these using ASDF as is described in step 4.
    2. If you get the following message at any point during the install process you should just CONTINUE (0):
      debugger invoked on a ASDF-INSTALL::KEY-NOT-TRUSTED:
      GPG warns that the key id 0xNIL () is not fully trusted
      
      Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.
      
      restarts (invokable by number or by possibly-abbreviated name):
        0: [CONTINUE     ] Install the package anyway
        1: [SKIP-GPG-CHECK] Don't check GPG signature for this package
        2: [RETRY        ] Retry installation
        3: [ABORT        ] Exit debugger, returning to top level.
      
      (ASDF-INSTALL::VERIFY-GPG-SIGNATURE/STRING
       "-----BEGIN PGP SIGNATURE-----
      
    3. SBCL-port fails to compile. When this happens, simply ACCEPT it (the option that tells you to accept it as if it worked).

You should now be able to follow the instructions in the user's manual to start up weblocks.

Loading mentions Retweet
Filed under  //  Lisp   Weblocks  
Comments (3)
Posted 1 year ago

Hello, world.

We might write some stuff about Lisp, Weblocks, startups, pirates, ninjas, or puns.  Or maybe not.  Who knows what might happen.

Loading mentions Retweet
Comments (0)
Posted 1 year ago