New issue
Advanced search Search tips

Issue 784229 link

Starred by 1 user

Issue metadata

Status: Available
Owner: ----
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux , Windows , Chrome , Mac
Pri: 3
Type: Bug



Sign in to add a comment

base::i18n::BreakIterator::Init() is slow. Breaking rules are not cached. Impacts browser startup, typing in the omnibox, notification bubbles, bookmarks in autocomplete, ...

Project Member Reported by tapted@chromium.org, Nov 13 2017

Issue description

Chrome Version       : 64.0.3260.2

Follow-up to  Issue 780670 

https://uma.googleplex.com/p/chrome/callstacks?sid=0373251115cd153fd1279a7aa0747c9f

In those charts, calls to base::i18n::BreakIterator::Init() take up an _average_ of 25ms on all browser startups sampled. But you can see the major contributing posted tasks should only be happening for a small number of users, so I'm guessing the real performance cost for users encountering this is much higher. 

After the fix in  Issue 780670 , (in descending order of impact) the triggers above are coming from
 - Text Layout required in the session crashed bubble
 - Text Layout required for a posted task to PlatformNotificationServiceImpl::DisplayPersistentNotification()  (invoking WebNotificationTray::ShowPopups)
 - Textfield::SetText(..) via the autocomplete matcher changing the omnibox text and requiring a cursor position
 - Browser navigation changing the omnibox text
 - Typing a character into the omnibox (triggers 3 calls)
 - Clicking in the omnibox

While investigating  Issue 780670  I observed:
 - The first call to BreakIterator::Init() may take 100+ milliseconds due to disk reads, later calls are also "slow" (don't have a clear number)
 - every bookmark calls BreakIterator::Init() when it's added to autocomplete results. For me, over 1000 times. But in a worker thread.

And,
"""
it looks like The code in BreakIterator::createInstance is *always* picking the "slow path", and recompiling the break rules every time we need an iterator. It's probably not 87ms once the rule dictionary is cached in memory, but there's prob

But there are strategies for avoiding this. We can update base::i18n::BreakIterator either to initialize ICU's BreakIterator "service" so that BreakIterator::createInstance can use the fast path, or possibly just have one UBreakIterator stashed in the ui::ResourceBundle that we call ubrk_safeClone and ubrk_setText on whenever we need a new base::i18n::BreakIterator.

But it doesn't look like we're making any attempts to *disable* ICU's BreakIterator service. It just reaches code at


static inline UBool
hasService(void)
{
    return !gInitOnce.isReset() && getService() != NULL;
}

getService() lazily creates a service, but `!gInitOnce.isReset()` is always false, so it never tries.


Seems we need to trigger a call to BreakIterator::registerInstance at least once (and thereafter it auto-create if the locale changes? - that third_party/icu code is weird). Of course.. calling BreakIterator::registerInstance() during startup isn't going to remove the 87ms *startup* performance regression. But we should be able to lazily register something.


I actually get dozens of calls to BreakIterator::makeInstance when I start chrome - 1199 to be precise fact.  They seem to come from bookmarks code:

    frame #12: 0x000000011bc90997 libbase_i18n.dylib`base::i18n::BreakIterator::Init(this=0x000070000e516b60) at break_iterator.cc:73
    frame #13: 0x0000000101af6aa5 libchrome_dll.dylib`query_parser::QueryParser::ParseQueryImpl(this=0x000070000e516e90, query=0x000070000e516e78, matching_algorithm=DEFAULT, root=0x000070000e516c38) at query_parser.cc:412
    frame #14: 0x0000000101af7f7d libchrome_dll.dylib`query_parser::QueryParser::ParseQueryWords(this=0x000070000e516e90, query=0x000070000e516e78, matching_algorithm=DEFAULT, words=0x000070000e516e98 size=0) at query_parser.cc:351
    frame #15: 0x00000001083536fd libchrome_dll.dylib`bookmarks::TitledUrlIndex::ExtractQueryWords(this=0x000000013652b3c0, query=0x000070000e516f88) at titled_url_index.cc:229
    frame #16: 0x0000000108353232 libchrome_dll.dylib`bookmarks::TitledUrlIndex::Add(this=0x000000013652b3c0, node=0x000000015ce178d0) at titled_url_index.cc:60
    frame #17: 0x000000010833e4e7 libchrome_dll.dylib`bookmarks::(anonymous namespace)::AddBookmarksToIndex(details=0x000000013652b8a0, node=0x000000015ce178d0) at bookmark_storage.cc:47
    frame #18: 0x000000010833e533 libchrome_dll.dylib`bookmarks::(anonymous namespace)::AddBookmarksToIndex(details=0x000000013652b8a0, node=0x000000013652b4e0) at bookmark_storage.cc:50
    frame #19: 0x000000010833cb12 libchrome_dll.dylib`bookmarks::(anonymous namespace)::LoadCallback(
"""
 
Screen Shot 2017-11-13 at 2.05.50 pm.png
541 KB View Download
Lazily creating a BreakIterator will likely only help a little.  Best would be to be put uses, where possible, on a background thread.

Various parts of the omnibox system need indices to in order generate suggestions.  These need to be created shortly after startup.

For example, the in-memory URL index uses break iterator heavily.  It's created on the HistoryDB thread shortly after startup.  Happily, this happens on the history DB thread.
https://cs.chromium.org/chromium/src/components/omnibox/browser/in_memory_url_index.cc?l=277-284

Likewise, there's an index of bookmarks for searching.
https://cs.chromium.org/chromium/src/components/bookmarks/browser/bookmark_storage.cc?l=105-107
I'm not sure what thread this is on; according to the earlier report, it's on "a worker thread."  We can probably separate the the "load bookmarks" code from the "index bookmarks" code, and invoke the latter slightly later, if that helps...

I'm not sure about the top three triggers (two text layout, one text field one).
Labels: Performance-Browser
Bulk adding Performance-Browser label for bugs identified with the UMA Sampling Profiler.
Project Member

Comment 3 by sheriffbot@chromium.org, Jan 7

Labels: Hotlist-Recharge-Cold
Status: Untriaged (was: Available)
This issue has been Available for over a year. If it's no longer important or seems unlikely to be fixed, please consider closing it out. If it is important, please re-triage the issue.

Sorry for the inconvenience if the bug really should have been left as Available.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
Status: Available (was: Untriaged)
This is still important to us, but I think we should take action in the descending order of impact as described in c#0:

 - Text Layout required in the session crashed bubble
 - Text Layout required for a posted task to PlatformNotificationServiceImpl::DisplayPersistentNotification()  (invoking WebNotificationTray::ShowPopups)
 - Textfield::SetText(..) via the autocomplete matcher changing the omnibox text and requiring a cursor position
 - Browser navigation changing the omnibox text
 - Typing a character into the omnibox (triggers 3 calls)
 - Clicking in the omnibox

So for now it's a P3 from my perspective for the omnibox team until we are the 'sore thumb' sticking out.

Sign in to add a comment