Tuesday, September 15, 2009

Flex Compiler Integration Optimization

This is a continuation of the FLEX Integration Series - please refer to the previous posts for more details:

  1. Building FLEX Integration with SHP
  2. FLEX Compiler Integration with SHP

Now we'll cover how to optimize the integration for performance.

The easiest way to determine whether a new compilation is necessary is by comparing the timestamp of the source code vs the timestamp of the object code - even the venerable make utilize this simple check.

So what we need to do is to determine the timestamp of the shp script that we call mxml, and then compare it against the flash video file.  Since mxmlc compilation time is long, if the timestamp of the shp source script has a later timestamp than the flash video, it is very safe to assume that the source script have been changed.

Determining the Timestamp 

PLT Scheme offers (this-expression-source-directory) and (this-expression-source-file-name) to help determine the location.  But as those are macros and applies to the location of their presence, they are not exactly helpful to our cause unless we want to write them out everytime we have to use mxml like this:


(mxml (this-expression-source-directory) path ...)  
We want the value to be automatically available rather than manually available, so we'll have to improve our SHP handler.


(define __PATH__ (make-parameter (shp-handler-path ($server)))) ;; looks like C macro... 
 (define (evaluate-script path)

  (evaluate-terms (file->values path) path))


(define (evaluate-terms terms path)
  (require-modules! terms) ;; first register the required modules 
  ;; then we filter out the required statement and evaluate the rest of the terms as a proc. 
  (eval `(lambda ,(terms->args terms) 
           (parameterize ((__PATH__ path))
             . ,(terms->exps terms)))
        handler-namespace))
Now we have the path available within the SHP script scope, and we can use it to check the timestamp.



Comparing the Timestamp

To check the timestamp we just need to make sure the path of the flash video also exists:

(define (mxml path #:id (id #f) #:height (height 400) #:width (width 400) 
              . widgets)
  (define (helper)
      (let ((app (apply mx:app widgets)))
        (call-with-output-file 
            (mxml-path path)
          (lambda (out)
            (display (mxml->string app) out))
          #:exists 'replace)
        (compile! path) ;; 
        (flash (string-append path ".swf") #:id id #:height height #:width width)))
  (if (file-exists? (flash-path (string-append path ".swf")))
      (if (> (mtime (__PATH__)) (mtime (flash-path (string-append path ".swf")))) ;; we need to compile... 
          (helper)
          (flash (string-append path ".swf") #:id id #:height height #:width width))
      (helper)))
Now the flash video will only get recompiled if the script changes.

Note on Premature Optimization

So far the development of SHP has followed the principle of resisting premature optimization (for example - we have not focused on caching the script compilations yet), one to see how far we can go, and another there isn't much needs yet.  However, mxmlc is really, really slow for compilation.  You'll get frustrated from having to wait for the flash to compile just from accidentally refreshing the page.  Hence this is one of the very first optimizations we do.


We are close to making bzlib/flexer available - we just need to flesh out the mxml API for the common widgets. Stay tuned.

No comments:

Post a Comment