32 Replies Latest reply on Feb 11, 2015 3:36 AM by mcollinge

    Redundant code issues - Performance Increase - Cost Saving!!!

    mrowbory

      While I was investigating a duplication of stylesheets by a custom theme, I came back to the question of why there is so much redundant code in the main page.

       

      It seems that nearly 350kb of a 450kb page is duplication, predominantly from i18 references, but also from a number of other large javascript blocks that really should not be in the main page.

       

      Moving these to one of the other resource files would provide a massive performance boost.

       

      Currently every page I visit has to re-download and parse all of this code before it can start rendering the page.  No wonder the page loads still seem very slow even with Akamai.

       

      Imagine if this was cacheable!

       

      For example, when I visit the first page it downloads 450kb in total.  The subsequent 9 pages would require only 100kb each page for a total of 1350kb.

       

      In it's current form I'm downloading a total of 3.5MB! (I know that http compression reduces the actual size, but you are still talking 90kb per page instead of 16kb)

       

      I really think this would make the pages load a lot snappier - especially on slow browsers and connections, but think of the bandwidth savings.  I imagine the processor utilisation would drop significantly as the web servers stop having to compress and send out such huge page files for every request.


      If all this extra code was loaded on another connection, the page will return and start drawing itself much more quickly!

       

      I can't even imagine what the ROI for this fix would be given the amount of traffic Jive serves.

       

      You could reduce page sizes to a third, and probably at least double the amount of page transactions the servers could support.

       

      If it was me, I'd make this above an S0 priority to fix.

       

      I'm being selfish really,  I'd just love the Jive community (and ours) to respond faster than a few seconds for most pages. 

       

       

      Some details from my analysis:

       

      Does this need to be in the main page? 4.8k saving

       

        /* Kongregate Asychronous JavaScript Loader

       

      Why is this repeated 16 times? Also there are two large blocks of javascript above it that could be removed from the page.

       

        if(typeof(tinyMCE) != "undefined"

       

      Next there are a load of jive.rte.macros.push commands, could be another 10kb saving.

       

      Then there are a few massive blocks totalling about 350kb - relating to jive.i18n.addMsgs

       

      Also why is the onbaording.css file loaded on every page, it's only used in the getting started guide.

       

      It would really be prudent to try and consolidate all the css files as well...!

       

      Further Testing

      I did some further testing, saving off the overview page, and loading it up to the server as html, one with the code inline, and one with the code saved out to a jive-tes-js.js file.

       

      Test 1 - All in-line code:

      You can see in this case it was 341ms for the file to load.

      jive-test-1-1.png

      Test 2 - js as separate file which can be cached:

      You can see the significant difference in download time, and size.   The key thing here, is now all subsequent files are also much smaller and can re-use the same js.

      jive-test-2.png

       

      Bootnote.

      I have been using Jive since version 2.5 and I have to say that each major version has become a step change worse in performance and page size.  A look at the latest page structure would give even an amateur performance analyst a heart attack.  I really hope that something can be done to improve it.

       

      To me it's a no-brainer, with a small amount of clever work you could dramatically improve performance across the board.  It seems crazy to pay a fortune for Akamai when the issues can be fixed so easily.

        • Re: Redundant code issues - Performance Increase - Cost Saving!!!
          jrenaud

          It's easy to criticize something looking at it from the outside, but I have to agree: looking at how Jive's pages are assembled in the browser, I'm really left with the impression that page load performance could greatly benefit from a cleanup. It currently feels like every minor issue or task has been handled by adding another layer of code over the existing one, through every subsequent releases.

           

          Now, it may be easier to say than to do, but the speed and responsiveness of the interface as perceived by the users in my community is an issue often coming up when discussion with them, or at least often at the very limit of what is considered "correct" by them.

            • RE: Redundant code issues - Performance Increase - Cost Saving!!!
              mrowbory

              I agree it can be easy to criticise, and I don‘t do it lightly.

               

              I have been working/coding Jive products for the last 5 years now though, and it does upset me that this situation is getting worse rather than better.

               

              Jive‘s core asset is a web based product, so for them to not tackle such 101 fundamental issues is simply not good enough.

               

              Making a web page perform well is tough, but it is so worth doing. The nature of the internet means that no amount of memory or hardware can speed your site up, yet programming the page properly could dramatically increase  performance, reduce load on your hardware, reduce bandwidth costs. 

               

              The speed itself gives a marked increase in productivity which surely should be a good selling point!  I know that if Jive coded the site well then I wouldn‘t need to rely on the expense of a CDN like Akamai so there are massive cost implications here.

                • Re: Redundant code issues - Performance Increase - Cost Saving!!!
                  czurcher

                  Even with a CDN, if you have a large global site the impact on performance due to bloated or redundant code cannot be underestimated. Every version of the Jive platform we have rolled out here at Premier Farnell for our element14 community, our own internal developers have had to customize to do some of this cleanup to optimize our page load times. It is disappointing that it looks like we're going to have to devote time, effort (and customize again!) in this version.

              • Re: Redundant code issues - Performance Increase - Cost Saving!!!
                it2000

                Anyhow the v6 pages are more static and thus better cacheable. For example the avatar and points are loaded asynchronously. But there is still a lot to optimize.

                • Re: Redundant code issues - Performance Increase - Cost Saving!!!
                  steve_heine

                  any clue what they've done on www.saphana.com/

                  This instance has great performance

                   

                  SAP HANA One Platform on AWS | SAP HANA

                  • Re: Redundant code issues - Performance Increase - Cost Saving!!!

                    Martin, thank you for taking the time to investigate performance issues and for reporting your findings.  As an engineer I always find feedback useful and you make some good suggestions.  I know that you have brought up concerns about performance before.  I think that we have made substantial performance improvements that I hope you will find reassuring.  More on that further down.

                     

                    The code that we put in inline scripts is generally stuff that is difficult to cache.  For example, i18n strings are mostly stable but they can change when a new theme is applied.  And we have to support the phrase substitutions feature, which can cause any string to be changed with the flip of an admin setting.  So we can't just put a 10 year expiration time on those strings like we do with most of the JavaScript. But you are right that we would be much better off if those strings were loaded separately and cached.  And in fact we have discussed a plan that could let us do that which might get into an upcoming release.  We just have to implement that plan with accommodations for theming, phrase substitutions, and so on.

                     

                    The duplication of the undefined check for tinyMCE is unnecessary - that is a good point.  I will file an ticket to work on that.

                     

                    There is some thinking behind putting the Kongregate Asynchronous JavaScript Loader inline.  That is the component that is responsible for deferred code loading; it fetches code that will be needed some time in the future in a way that does not block page load.  When there is deferred code that we know needs to be loaded we want to start downloading it as soon as possible to minimize total latency.  But in practice having the script inline may not be helping much.  If we were putting all of our external script tags at the end of the body tag I think that inlining the loader would be advantageous.  But we are not quite there yet.  There is a good chance that I will take your advice and move the loader into an external script.

                     

                    I think that the onboarding stylesheet is loaded everywhere because the getting started feature does make appearances in a few different places. But we do have a procedure for loading stylesheets asynchronously in such cases.  I will file another ticket to see that that gets looked at.

                     

                    I agree about consolidating CSS files.  That is another item that has been our list of desired optimizations for some time.  There is a wrinkle though: due to an unfortunate design decision in Internet Explorer if any stylesheet contains more than 4095 selectors all of the subsequent selectors and rules are ignored.  Recently jive.css hit that limit and we actually had to split it into two parts; which is of course the opposite of what we want to do.  But the other stylesheets that we are using are not as big and we should be able to combine those down to a smaller number of files.

                     

                    It would be great if we could make each page cacheable.  In fact that is another idea that we have discussed and would like to implement.  But that is not going to be a simple change.  There are a lot of pieces of dynamic data that go into each page when it is rendered and many of those are expected to be up-to-the-second which prevents us from setting expiration times of any substantial duration.  We might not get much benefit from Etags either since an Etag would have to be based on whatever piece of data has changed most recently.  It is likely the result would be that a given Etag would not stay fresh long enough to be useful and the caching benefit would be outweighed by the cost of generating and checking Etags.  To make a real improvement we will have to decouple highly-dynamic page state from less dynamic content.  It will probably be some time before we can get to a point where we can put caching headers on HTML responses themselves.  In the meantime as you point out we can work on making each page smaller.

                     

                    I want you to know that we do care about performance and we are working on it.  As you point out there is plenty of stuff that we can improve. There are also a lot of improvements that we have already made.  In 7.0 in particular - the code that is currently running our cloud offering - we have made serious efforts to improve page load times.  And I expect do to more before the 7.0 on-premise release.

                     

                    We have a system in place now that runs automated performance tests on development builds and new releases so that we can keep track of how each set of new features affects performance.  We are using this tool to try to make sure that each release is at least as fast as the previous version.  For example, here is a report on page load times for the search results page as measured in Chrome 21:

                     

                    search-results-performance-chrome-21.png

                     

                    The two entries on the left are releases: 6.0.0.0 and the current cloud release respectively.  The other four entries are builds of the Jive code that is currently in development.

                     

                    There are two main strategies that we have been pushing during 7.0 development: moving script tags to the end of the body tag so that content renders before script download and execution delays take place; and deferring code loading to reduce the total amount of code that is executed during page load.

                     

                    In 6.0 we applied the first strategy to a selection of pages including the activity stream and the inbox.  On those pages only a minimal amount of code is loaded via script tags in the head tag.  The rest of the code is loaded by script tags at the end of the body.  The result is a big reduction in the time it takes for the page content to become visible so that you can read what is on the page while JavaScript initialization takes place.  In 7.0 we applied the same strategy to every page.  You can see the impact of that change in the graph above: the "visible" time was reduced by nearly 200 ms.  At that point you can see and click on search results.  We saw similar improvements to visible times across the board after implementing this strategy.

                     

                    I chose to show benchmarks from the search results page because that graph shows off the benefit of moving script tags down.  Since that change was already made to the activity stream and inbox in 6.0 and I don't have a 5.0 vs. 6.0 comparison handy the graphs from those pages don't properly reflect the improvement.

                     

                    The other metric shown, the "responsive" time, is the time at which all JavaScript included with the page has been downloaded, parsed, executed, and initialized - including the time taken to run all callbacks after the document "ready" event.  At that time the page is fully interactive. The second strategy of deferring code is intended to decrease the responsive time.  The idea is that there is code that is needed to power features on a given page but that does not have to be executed right away or that may not be needed every time the page is loaded.  For example the JavaScript code for the onboarding feature may be called from a number of different places but will only be invoked rarely once a user has settled in.  So we do not download that code until the user actually interacts with an onboarding feature.

                     

                    Converting code to deferred loading is something that we have to do on a feature-by-feature basis as opposed to the global switch for moving script tags to the end of the body tag.  We have made a start on applying this strategy but it will take time to convert every feature that could benefit.  You can see from the graph we have seen some positive results already.  We expect to take that further in upcoming work.

                     

                    You'll notice that the load times in that graph are quite a bit faster than what you measured in the Webkit inspector.  Part of that is because the performance tests we are running do not send requests out over a network so bandwidth and latency are not figured in.  I am very aware of that discrepancy and of the fact that reducing download sizes and number of requests made will have benefits that do not necessarily reflect on synthetic benchmarks.  Another factor is that the instance that you are testing against appears to load extra code from plugins or customizations.  It happens that we also made improvements in 7.0 to combine plugin code into a smaller number of script files.

                     

                    Though bandwidth is an important factor, I believe that the time taken to parse and execute scripts is a bigger factor in the current codebase. Consider that in the timelines that you posted there is a script file that is loaded from cache and yet its bar still runs for hundreds of milliseconds.  Your change to speed up the HTML download time reduces the time until the DOMContentLoaded event (a.k.a. the document ready event) from 1.36 s to 1.12 s, a change of 0.24 s or 18%.  That is a substantial improvement and is certainly nothing for me to turn my nose up at.  But you have almost entirely eliminated network delay yet 80% of the original load time remains.  I think that most of that time is taken up by script parsing and script execution.  For that reason my main focus is on removing or deferring as much JavaScript code as possible.