Closed
Bug 417444
Opened 17 years ago
Closed 17 years ago
load in other font family names lazily
Categories
(Core :: Graphics, defect, P3)
Tracking
()
RESOLVED
FIXED
People
(Reporter: jtd, Assigned: jtd)
References
Details
(Keywords: perf)
Attachments
(2 files, 3 obsolete files)
(deleted),
text/plain
|
Details | |
(deleted),
patch
|
roc
:
review+
roc
:
superreview+
|
Details | Diff | Splinter Review |
On the Mac, over 95% of the time in InitFontList is spent reading in other font family names, primarily localized family names. As these aren't needed for most Latin-based languages, we should be able to get away with loading them lazily when the first font family name lookup miss occurs. This will shift the bulk of the time spent reading these in out of the startup time.
These can be read in gradually using the work done for bug 416946.
Assignee | ||
Comment 1•17 years ago
|
||
Move the reading in of other font names out of gfxQuartzFontCache::InitFontList and into a separate procedure that is called only when these names are absolutely needed. The initialization occurs after startup in gfxQuartzFontCache::FindFamily when a font lookup miss occurs.
Assignee | ||
Updated•17 years ago
|
Flags: blocking1.9?
Priority: -- → P3
Assignee | ||
Updated•17 years ago
|
Status: NEW → ASSIGNED
Updated•17 years ago
|
Flags: blocking1.9? → blocking1.9+
Assignee | ||
Comment 2•17 years ago
|
||
Dumped using font info logging enabled with a debug build:
export NSPR_LOG_FILE=fontlist.log
export NSPR_LOG_MODULES=fontInfoLog:5
Data for each face read in at startup, with weight and traits (see NSFontManager docs). On my system, 554 total font faces, only 62 other family names, 16 of these are Hiragino xxx names.
Assignee | ||
Updated•17 years ago
|
Attachment #303947 -
Attachment mime type: application/octet-stream → text/plain
Assignee | ||
Comment 3•17 years ago
|
||
Instead of reading in other font family names (primarily localized names) at startup, defer this until absolutely needed when a lookup miss occurs. By avoiding this, we shift a large amount of the time spent in InitFontList to when the data is actually needed. This information is still needed even in cases where no localized names are needed since we can't distinguish between a localized name and a name of a font that doesn't exist (e.g. a Windows font like Arial Unicode MS).
Attachment #303947 -
Attachment is obsolete: true
Attachment #303952 -
Flags: superreview?(roc)
Attachment #303952 -
Flags: review?(roc)
+ PRBool mOtherFamilyNamesInitialized;
PRPackedBool in structs
+ PRBool mOtherFamilyNamesInitialized;
ditto
+ if (mOtherFamilyNamesInitialized) return;
We generally put the "return" on its own line
+ // if other family names exist, iterate through other faces
+ if ([otherFamilyNames count] != 0) {
So the assumption here is that if the "normal" face has only one name, then all faces have only that name? It sounds reasonable, but maybe it could be more clearly documented. I guess we're using it already anyway.
Are there ever enough names that the linear search through the array for duplicate names becomes a problem? Would it be simpler and faster to just pass aOtherFamilyFunctor into ReadOtherFamilyNamesForFace, and have it return true if it found any?
+ // to avoid full search of font name tables, seed the other names table with localized names from
+ // some of the prefs fonts which are accessed via their localized names. changes in the pref fonts will only cause
+ // a font lookup miss earlier. this is a simple optimization, it's not required for correctness
Would it make sense to actually iterate through all the pref fonts here? Is that something you're planning to do later?
+ // lookup in other family names list (mostly localized names)
+ if (mOtherFamilyNames.Get(key, &familyEntry)) {
return familyEntry;
}
+
+ // name not found and other family names not yet fully initialized so
+ // initialize the rest of the list and try again. this is done lazily
+ // since reading name table entries is expensive
+ if (!mOtherFamilyNamesInitialized) {
+ InitOtherFamilyNames();
+ if (mOtherFamilyNames.Get(key, &familyEntry)) {
+ return familyEntry;
+ }
+ }
If mOtherFamilyNamesInitialized is false, how can mOtherFamilyNames return anything? Couldn't we simplify this so we check mOtherFamilyNamesInitialized first, call InitOtherFamilyNames if necessary, and then unconditionally lookup mOtherFamilyNames?
+ nsDataHashtable<nsStringHashKey, nsRefPtr<MacOSFamilyEntry> > mOtherFamilyNames;
Why not nsRefPtrHashtable? Then you don't need these extra assignments to nsRefPtr locals when you put something into the hashtable.
Assignee | ||
Comment 5•17 years ago
|
||
(In reply to comment #4)
> Are there ever enough names that the linear search through the array for
> duplicate names becomes a problem?
The most extreme example would be some instances of Adobe font families like Minion Pro that have a large number of faces with extra family names in each, but this is generally the rare case. In the majority of cases we're dealing with a single localized family name. See attached fontinfo listing for examples of other family names that show up.
> + // to avoid full search of font name tables, seed the other names table
> with localized names from
> + // some of the prefs fonts which are accessed via their localized names.
> changes in the pref fonts will only cause
> + // a font lookup miss earlier. this is a simple optimization, it's not
> required for correctness
>
> Would it make sense to actually iterate through all the pref fonts here? Is
> that something you're planning to do later?
Yes, I think that might make sense but the simplest way to do this for now is just to prime mOtherFamilyNames with pref fonts that use localized names.
> + // name not found and other family names not yet fully initialized so
> + // initialize the rest of the list and try again. this is done lazily
> + // since reading name table entries is expensive
> + if (!mOtherFamilyNamesInitialized) {
> + InitOtherFamilyNames();
> + if (mOtherFamilyNames.Get(key, &familyEntry)) {
> + return familyEntry;
> + }
> + }
>
> If mOtherFamilyNamesInitialized is false, how can mOtherFamilyNames return
> anything? Couldn't we simplify this so we check mOtherFamilyNamesInitialized
> first, call InitOtherFamilyNames if necessary, and then unconditionally lookup
> mOtherFamilyNames?
mOtherFamilyNamesInitialized is only set to true when the name tables for *all* fonts have been read in. By explicitly calling ReadOtherFamilyNamesForFamily for a few pref font families that use localized names we avoid the need to read in all name tables until we hit a page that causes a name lookup miss. This effectively shifts the need to do this work well past startup.
I'll set up a new patch tomorrow with the other changes you suggested.
One thing to keep in mind is that thanks to Session Restore, it's reasonably common for users to hit a lot of Web pages immediately after startup, some of which could have weird glyphs.
Assignee | ||
Comment 7•17 years ago
|
||
(In reply to comment #6)
> One thing to keep in mind is that thanks to Session Restore, it's reasonably
> common for users to hit a lot of Web pages immediately after startup, some of
> which could have weird glyphs.
No doubt. The main thing here is simply to move the reading of the font name tables out of the startup process, but if session restore is involved then that increases the chance that a font lookup miss will occur, necessitating the reading of font name tables. Note that weird glyphs are fine, it's weird font names that will necessitate pulling in the font name tables.
Assignee | ||
Updated•17 years ago
|
Attachment #303947 -
Attachment is obsolete: false
Assignee | ||
Updated•17 years ago
|
Attachment #303235 -
Attachment is obsolete: true
Assignee | ||
Comment 8•17 years ago
|
||
With changes based on comment #4.
Attachment #303952 -
Attachment is obsolete: true
Attachment #304132 -
Flags: superreview?(roc)
Attachment #304132 -
Flags: review?(roc)
Attachment #303952 -
Flags: superreview?(roc)
Attachment #303952 -
Flags: review?(roc)
> Are there ever enough names that the linear search through the array for
> duplicate names becomes a problem? Would it be simpler and faster to just pass
> aOtherFamilyFunctor into ReadOtherFamilyNamesForFace, and have it return true
> if it found any?
You don't seem to have addressed this? You're passing in the functor but you're still maintaining and searching otherFamilyNames which I think you don't actually need?
Assignee | ||
Comment 10•17 years ago
|
||
(In reply to comment #9)
> > Are there ever enough names that the linear search through the array for
> > duplicate names becomes a problem? Would it be simpler and faster to just pass
> > aOtherFamilyFunctor into ReadOtherFamilyNamesForFace, and have it return true
> > if it found any?
>
> You don't seem to have addressed this? You're passing in the functor but you're
> still maintaining and searching otherFamilyNames which I think you don't
> actually need?
Passing the otherFamilyNames array is needed to avoid adding the same other family name in multiple times. Consider Hiragino Kaku Gothic Pro as an example, there are two faces with different weights. Each contains *both* "Hiragino Kaku Gothic Pro" and "ヒラギノ角ゴ Pro", the same name in Japanese. Without keeping the otherFamilyNames array around, you'd be adding the Japanese name in twice when ReadOtherFamilyNamesForFace was called for each of the faces.
What's wrong with that? If you want the first face added to win in mOtherFamilyNames, just do a Get before you do a Put and don't Put if there was already an entry for that name.
Assignee | ||
Comment 12•17 years ago
|
||
Eliminated the otherFamilyNames array. I didn't add the code in call ReadOtherFamilyNamesForFamily with family names supplied by a pref, that's lower priority work right now. There's some pref handling work that needs to get done for 390901, so I think I'll work on including the code in a patch for that bug.
Attachment #304132 -
Attachment is obsolete: true
Attachment #304407 -
Flags: superreview?(roc)
Attachment #304407 -
Flags: review?(roc)
Attachment #304132 -
Flags: superreview?(roc)
Attachment #304132 -
Flags: review?(roc)
Comment on attachment 304407 [details] [diff] [review]
patch, v.0.4, read in other font family names lazily
This could be sped up more in two ways:
-- gfxQuartzFontCache::AddOtherFamilyName could take an NSString* parameter for aOtherFamilyName, which we convert to an nsAutoString just once, lowercasing it at the same time.
-- Using nsTHashtable you could avoid the need to do a Get and a Put in the same function. You would just do a Put to get the current entry for the key and bail out if it was already occupied.
Only worth worrying about if those code points show up in profiles.
Attachment #304407 -
Flags: superreview?(roc)
Attachment #304407 -
Flags: superreview+
Attachment #304407 -
Flags: review?(roc)
Attachment #304407 -
Flags: review+
Assignee | ||
Comment 14•17 years ago
|
||
Makes sense. Name tables are fairly sparse, most fonts don't have localized family names so adding names isn't the time consuming part of this process (although many fonts localize the *full* name to include the localization of style descriptions like Bold).
Checked in.
Status: ASSIGNED → RESOLVED
Closed: 17 years ago
Resolution: --- → FIXED
Comment 15•17 years ago
|
||
There was 1 cycle with this in - a 4% Ts win.
The relanding shaved 1000ms (6.67%) off of Ts on boxset, Camino's perf box, so folks with older/slower/PPC machines should see a slightly nicer startup win :D
Assignee | ||
Comment 17•17 years ago
|
||
(In reply to comment #16)
> The relanding shaved 1000ms (6.67%) off of Ts on boxset, Camino's perf box, so
> folks with older/slower/PPC machines should see a slightly nicer startup win :D
Even more so for those folks with a large number of fonts on their machine!
You need to log in
before you can comment on or make changes to this bug.
Description
•