Bug 31266

Summary: [Qt] QWebSettings::setMaximumPagesInCache(int pages) does not enable the Page Cache
Product: WebKit Reporter: Andras Becsi <abecsi>
Component: WebKit QtAssignee: Nobody <webkit-unassigned>
Status: RESOLVED FIXED    
Severity: Normal CC: abecsi, commit-queue, hausmann, kenneth, tonikitoo, vestbo, zecke
Priority: P3 Keywords: Qt
Version: 528+ (Nightly build)   
Hardware: PC   
OS: Linux   
Attachments:
Description Flags
proposed patch for further discussion
none
proposed patch
hausmann: review-
simlified patch
hausmann: review-
also change DRT to set the cache globally none

Description Andras Becsi 2009-11-09 11:20:49 PST
Created attachment 42772 [details]
proposed patch for further discussion

Calling setMaximumPagesInCache(somePositiveInt) does not enable the Page Cache (http://webkit.org/blog/427/webkit-page-cache-i-the-basics/) which is disabled by default in QtWebKit.
Further more QWebSettings::setMaximumPagesInCache(int pages) is static, so calling d->settings-setUsesPageCache(true) if pages>0 is not an option.
To support page caching in a comparative way and quality as the other ports do, we would need a nice cross platform way to measure the available system memory and calculate the page cache capacity in a similar way as the Mac and Win ports do:

Eg.: WebKit/win/WebView.cpp:502:
        // Page cache capacity (in pages)
        // (Research indicates that value / page drops substantially after 3 pages.)
        if (memSize >= 2048)
            pageCacheCapacity = 5;
        else if (memSize >= 1024)
            pageCacheCapacity = 4;
        else if (memSize >= 512)
            pageCacheCapacity = 3;
        else if (memSize >= 256)
            pageCacheCapacity = 2;
        else
            pageCacheCapacity = 1;

But in embedded devices memory is a precious resource, so there may be situations where caching has to be disabled completely. 
So we would have to guess somehow which setting would be best, or leave the whole decision to the programmer? 

The attached patch tries the second approach and adds methods to qwebsetting and documents the usage and co-relation to setMaximumPagesInCache().
 
It would be nice to get some input on that issue.
Comment 1 Kenneth Rohde Christiansen 2009-11-09 11:25:33 PST
Well, the heuristics could be implemented by the browser or app using WebKit.
Remember QtWebKit is not just for creating browsers :-), so I think the current
API is OK.

setMaximumPagesInCache was introduced before 4.6 right?
Comment 2 Andras Becsi 2009-11-09 11:28:46 PST
(In reply to comment #1)
> Well, the heuristics could be implemented by the browser or app using WebKit.
> Remember QtWebKit is not just for creating browsers :-), so I think the current
> API is OK.
> 
> setMaximumPagesInCache was introduced before 4.6 right?
Yes I think so.
Comment 3 Andras Becsi 2009-11-09 11:51:41 PST
(In reply to comment #2)
> (In reply to comment #1)
> > Well, the heuristics could be implemented by the browser or app using WebKit.
> > Remember QtWebKit is not just for creating browsers :-), so I think the current
> > API is OK.

Further investigation showed that in qwebsettings.cpp:91:QWebSettingsPrivate::apply()) the attributes QHash (which is a member of QWebSettingsPrivate) is completely empty in approx. 5900 layout tests (from 6100 running), and has maximally 1 element in the other ~200, so it seems that updating the whole QWebSettings enum every time apply() is called might be a performance regression.

> > 
> > setMaximumPagesInCache was introduced before 4.6 right?
> Yes I think so.
Comment 4 Antonio Gomes 2009-11-09 11:55:28 PST
cool.

i'd block qt 4.6 on it, since it make an important feature (pageCache) to actually work.
Comment 5 Simon Hausmann 2009-11-11 00:56:58 PST
We cannot add new functions to Qt 4.6 anymore.
Comment 6 Simon Hausmann 2009-11-11 01:02:27 PST
Oops, the last comment was incomplete. But as it said, we cannot add new functions to Qt 4.6 anymore :(

You are right that it seems that we are currently not enabling the page cache in WebCore::Settings. I'm not sure if that was introduced afterwards or if it's been missing since then.

My guts feeling is that it's probably best for now to keep it a global setting, i.e. to enable the page cache in all settings objects if there is a maximum set for pages in the page cache. Similarly we should disable it if the maximum is 0.

That can be done without adding new API and I think it gives us a sensible default. The only thing we're missing is the ability to turn off the page cache _per QWebPage_, but it is debatable whether that makes sense in the first place.

It is however a feature we can also introduce later on.
Comment 7 Andras Becsi 2009-11-11 01:08:12 PST
(In reply to comment #6)
> Oops, the last comment was incomplete. But as it said, we cannot add new
> functions to Qt 4.6 anymore :(
> 
> You are right that it seems that we are currently not enabling the page cache
> in WebCore::Settings. I'm not sure if that was introduced afterwards or if it's
> been missing since then.
> 
> My guts feeling is that it's probably best for now to keep it a global setting,
> i.e. to enable the page cache in all settings objects if there is a maximum set
> for pages in the page cache. Similarly we should disable it if the maximum is
> 0.
> 
> That can be done without adding new API and I think it gives us a sensible
> default. The only thing we're missing is the ability to turn off the page cache
> _per QWebPage_, but it is debatable whether that makes sense in the first
> place.
> 
> It is however a feature we can also introduce later on.

I understand and that's why I am experimenting with the globalSettings singleton now which can be reached to enable and disable the page cache in setMaximumPagesInCache as needed. This could work out. Shortly I will add a new attachment.
Comment 8 Andras Becsi 2009-11-11 07:41:14 PST
Created attachment 42961 [details]
proposed patch

Without adding a new QWebSetting enum value it did not enable the global cache, so I needed to add one, but there are no new functions so no API change.
There are two known tests which are skipped because of Page Cache. As implemented they do not time-out and crash any more, but revealed another bug which causes a JS console message:

"CONSOLE MESSAGE: ReferenceError: Trying to access object from destroyed plug-in."

which is a different issue, and tonikitoo will hopefully comfirm that my patch is actually making Page Cache to work.
Comment 9 Simon Hausmann 2009-11-11 07:51:30 PST
(In reply to comment #8)
> Created an attachment (id=42961) [details]
> proposed patch
> 
> Without adding a new QWebSetting enum value it did not enable the global cache,
> so I needed to add one, but there are no new functions so no API change.

Unfortunately adding a new enum is an API change (although admitadely not on a binary level).

Can't we simply enable the cache if there is a maximum set and disable it if the maximum is zero?
Comment 10 Antonio Gomes 2009-11-11 08:29:40 PST
> but revealed another bug which causes a JS console message:
> 
> "CONSOLE MESSAGE: ReferenceError: Trying to access object from destroyed
> plug-in."
> 
> which is a different issue, and tonikitoo will hopefully comfirm that my patch
> is actually making Page Cache to work.

I can confirm it made pageCache to work. In a layout test I am doing I was getting "onLoad" called for back/forward navigations. W/ the patch in I am getting it called once and then just pageShow/Hide.

About the CONSOLE MESSAGE, I am able to reproduce it too even w/ JIT off.
Comment 11 Andras Becsi 2009-11-11 08:34:46 PST
(In reply to comment #9)
> (In reply to comment #8)
> > Created an attachment (id=42961) [details] [details]
> > proposed patch
> > 
> > Without adding a new QWebSetting enum value it did not enable the global cache,
> > so I needed to add one, but there are no new functions so no API change.
> 
> Unfortunately adding a new enum is an API change (although admitadely not on a
> binary level).
> 
> Can't we simply enable the cache if there is a maximum set and disable it if
> the maximum is zero?

Well, I experimented with it for two days now and the only way we can access the platform independent global Settings object now is through QWebSettings::globalSettings()->d which is a QWebSettingsPrivate* and has a WebCore::Settings* member named settings. I tried to set the page cache directly with QWebSettings::globalSettings()->d->settings->setUsesPage(qMax(0, pages)) but this caused DRT to crash on tests which want to override the usage of the cache, because setMaximumPagesInCache is static and the settings member of the singleton didn't get initialized. So I suppose settings was not meant to be called directly but indirectly through d->apply(). This probably will need a refactoring soon since it seems to be much of hiding which might cause performance issues. 
I will try to work around this for Qt 4.6, it will probably be ugly but policy is policy.
After release I will try to refactor this apply in a more elegant way.
Comment 12 Andras Becsi 2009-11-11 08:35:36 PST
(In reply to comment #10)
> > but revealed another bug which causes a JS console message:
> > 
> > "CONSOLE MESSAGE: ReferenceError: Trying to access object from destroyed
> > plug-in."
> > 
> > which is a different issue, and tonikitoo will hopefully comfirm that my patch
> > is actually making Page Cache to work.
> 
> I can confirm it made pageCache to work. In a layout test I am doing I was
> getting "onLoad" called for back/forward navigations. W/ the patch in I am
> getting it called once and then just pageShow/Hide.
> 
> About the CONSOLE MESSAGE, I am able to reproduce it too even w/ JIT off.

Thank you very much for testing.
Comment 13 Simon Hausmann 2009-11-11 13:05:21 PST
(In reply to comment #11)
> (In reply to comment #9)
> > (In reply to comment #8)
> > > Created an attachment (id=42961) [details] [details] [details]
> > > proposed patch
> > > 
> > > Without adding a new QWebSetting enum value it did not enable the global cache,
> > > so I needed to add one, but there are no new functions so no API change.
> > 
> > Unfortunately adding a new enum is an API change (although admitadely not on a
> > binary level).
> > 
> > Can't we simply enable the cache if there is a maximum set and disable it if
> > the maximum is zero?
> 
> Well, I experimented with it for two days now and the only way we can access
> the platform independent global Settings object now is through
> QWebSettings::globalSettings()->d which is a QWebSettingsPrivate* and has a
> WebCore::Settings* member named settings. I tried to set the page cache
> directly with QWebSettings::globalSettings()->d->settings->setUsesPage(qMax(0,
> pages)) but this caused DRT to crash on tests which want to override the usage
> of the cache, because setMaximumPagesInCache is static and the settings member
> of the singleton didn't get initialized. So I suppose settings was not meant to
> be called directly but indirectly through d->apply(). This probably will need a
> refactoring soon since it seems to be much of hiding which might cause
> performance issues. 
> I will try to work around this for Qt 4.6, it will probably be ugly but policy
> is policy.
> After release I will try to refactor this apply in a more elegant way.

Thanks Andras!

I agree it's ugly. I would suggest in apply() to simply look at WebCore::pageCache()->capacity() to decide whether to enable or disable the page cache in the WebCore::Settings object.

Then you can call apply() from setMaximumPagesInCache.
Comment 14 Simon Hausmann 2009-11-11 13:06:33 PST
Comment on attachment 42961 [details]
proposed patch

r- due to the earlier comments. For now we should enable/disable the cache only depending on the maximumPagesInCache value, i.e. the cache capacity.
Comment 15 Andras Becsi 2009-11-11 14:06:04 PST
Created attachment 42998 [details]
simlified patch

Antonio, could you please test this one if it works in your test? It works on the pagehide tests here, if somebody reviews it you can also land it, or I will set the cq+ tomorrow.
Thanks for the hint, Simon. I had a similar concept but this is simpler and not-so-ugly as I thougth :)
Comment 16 Antonio Gomes 2009-11-13 03:55:43 PST
(In reply to comment #15)
> Created an attachment (id=42998) [details]
> simlified patch
> 
> Antonio, could you please test this one if it works in your test? 

thx, bbandix. It works for me too.
Comment 17 Andras Becsi 2009-11-13 04:07:10 PST
(In reply to comment #16)
> (In reply to comment #15)
> > Created an attachment (id=42998) [details] [details]
> > simlified patch
> > 
> > Antonio, could you please test this one if it works in your test? 
> 
> thx, bbandix. It works for me too.

Thanks for testing.
Comment 18 Simon Hausmann 2009-11-13 04:19:32 PST
Comment on attachment 42998 [details]
simlified patch

The patch looks good to me, except for this piece:

> +    settings()->setMaximumPagesInCache(0); // reset to default
>  }
[...]  
> +    else if (name == "WebKitUsesPageCachePreferenceKey")
> +        settings->setMaximumPagesInCache(value.toInt());
>  }

setMaximumPagesInCache is a class method of QWebSettings, so the code should read

QWebSettings::setMaximumPagesInCache()

It is currently not possible to specify this per settings object after all, only globally.
Comment 19 Andras Becsi 2009-11-13 05:19:57 PST
Created attachment 43151 [details]
also change DRT to set the cache globally
Comment 20 WebKit Commit Bot 2009-11-13 05:49:37 PST
Comment on attachment 43151 [details]
also change DRT to set the cache globally

Clearing flags on attachment: 43151

Committed r50938: <http://trac.webkit.org/changeset/50938>
Comment 21 WebKit Commit Bot 2009-11-13 05:49:43 PST
All reviewed patches have been landed.  Closing bug.