Marcel Taeumel uploaded a new version of System to project The Trunk:
http://source.squeak.org/trunk/System-mt.1190.mcz ==================== Summary ==================== Name: System-mt.1190 Author: mt Time: 5 November 2020, 4:23:31.287798 pm UUID: 832d3d0e-dc06-a14f-ac49-d7dc709680ea Ancestors: System-mt.1189 Speeds up String >> #translated and locale switching as follows: - Only call #localeChanged(Gently) on classes that implement it, just like #cleanUp: - For the InternalTranslator, make translation-in-all-domains a no-op; 122µs -> 1.3µs - For the GetTextTranslator, make translation-in-all-domains fetch all available .mo files once, then directly enumerate that cache until a result is found; roughly 50µs -> 8µs - Avoid loading all .mo files on #localeChanged(Gently); only do that for translation-in-all-domains =============== Diff against System-mt.1189 =============== Item was added: + ----- Method: GetTextTranslator class>>addUserDefaultLocaleDir: (in category 'translation data layout') ----- + addUserDefaultLocaleDir: dir + "new dir will be put as first" + self userDefaultLocaleDirs addFirst: dir! Item was changed: ----- Method: GetTextTranslator class>>availableLanguageLocaleIDs (in category 'accessing') ----- availableLanguageLocaleIDs "GetTextTranslator availableLanguageLocaleIDs" | ids dirs localeDirForLang directoryNames | ids := Set new. dirs := Set new. + dirs addAll: self localeDirsForDomain. + dirs addAll: self userDefaultLocaleDirs. + dirs addAll: self systemDefaultLocaleDirs. - dirs addAll: LocaleDirsForDomain values. - dirs addAll: self defaultLocaleDirs. dirs do: [:dir | | localesDir | localesDir := FileDirectory on: dir. directoryNames := [localesDir directoryNames] on: InvalidDirectoryError do: [:e | #()]. directoryNames do: [:langDirName | | localeID | localeID := LocaleID posixName: langDirName. localeDirForLang := localesDir directoryNamed: (self langDirNameForLocaleID: localeID). localeDirForLang ifNotNil: [ (localeDirForLang fileNamesMatching: '*.mo') ifNotEmpty: [ids add: localeID]]. localeID hasParent ifTrue: [ localeDirForLang := localesDir directoryNamed: (self langDirNameForLocaleID: localeID parent). localeDirForLang ifNotNil: [ (localeDirForLang fileNamesMatching: '*.mo') ifNotEmpty: [ids add: localeID parent]]]. ]. ]. ^ids! Item was added: + ----- Method: GetTextTranslator class>>cleanUp: (in category 'class initialization') ----- + cleanUp: aggressive + + aggressive ifTrue: [ + UserDefaultLocaleDirs := OrderedCollection new. + LocaleDirsForDomain := Dictionary new].! Item was removed: - ----- Method: GetTextTranslator class>>defaultLocaleDirs (in category 'translation data layout') ----- - defaultLocaleDirs - | dirs | - dirs := OrderedCollection new. - UserDefaultLocaleDirs ifNotNil: [dirs addAll: UserDefaultLocaleDirs]. - dirs addAll: self systemDefaultLocaleDirs. - ^dirs - ! Item was added: + ----- Method: GetTextTranslator class>>findAllMOsForLocaleID: (in category 'private') ----- + findAllMOsForLocaleID: id + + | relativePath path allMONames result | + relativePath := String streamContents: [:stream | + stream + nextPutAll: FileDirectory slash; + nextPutAll: (self langDirNameForLocaleID: id); + nextPutAll: FileDirectory slash]. + allMONames := TextDomainManager allKnownDomains + collect: [:each | each -> (self moNameForDomain: each)]. + result := OrderedCollection new. + self localeDirsDo: [:localeDir | + allMONames do: [:moName | + path := String streamContents: [:s | + s nextPutAll: localeDir; nextPutAll: relativePath; nextPutAll: moName value]. + ([FileDirectory default fileExists: path] on: InvalidDirectoryError do: [false]) + ifTrue: [result add: moName key -> path] ]]. + ^ result! Item was changed: ----- Method: GetTextTranslator class>>findMOForLocaleID:domain: (in category 'private') ----- findMOForLocaleID: id domain: aDomainName + + | relativePath path | + relativePath := String streamContents: [:stream | + stream + nextPutAll: FileDirectory slash; + nextPutAll: (self langDirNameForLocaleID: id); + nextPutAll: FileDirectory slash; + nextPutAll: (self moNameForDomain: aDomainName)]. + self + localeDirsForDomain: aDomainName + do: [:localeDir | + path := localeDir, relativePath. + ([FileDirectory default fileExists: path] on: InvalidDirectoryError do: [false]) + ifTrue: [^ path]]. + ^ nil! - | sepa langSubDir path | - sepa := FileDirectory slash. - langSubDir := self langDirNameForLocaleID: id. - (self localeDirsForDomain: aDomainName) - do: [:each | - path := each , sepa , langSubDir, sepa , (self moNameForDomain: aDomainName). - [(FileDirectory default fileExists: path) - ifTrue: [^path]] on: InvalidDirectoryError do: [:e | ^nil]]. - ^nil.! Item was added: + ----- Method: GetTextTranslator class>>getLocaleDirForDomain: (in category 'translation data layout') ----- + getLocaleDirForDomain: aDomainName + "returns registered localeDirectory for the textdomain. returns nil if not registered" + ^LocaleDirsForDomain at: aDomainName ifAbsent: [nil]! Item was removed: - ----- Method: GetTextTranslator class>>localeDirForDomain: (in category 'translation data layout') ----- - localeDirForDomain: aDomainName - "returns registered localeDirectory for the textdomain. returns nil if not registered" - ^LocaleDirsForDomain at: aDomainName ifAbsent: [nil]! Item was added: + ----- Method: GetTextTranslator class>>localeDirsDo: (in category 'translation data layout') ----- + localeDirsDo: workBlock + "Enumerates all locale directories, regardless of a specific text domain. Begin with domain-specific directories, then user-specific directories, finally system-specific directories." + + self localeDirsForDomain do: workBlock. + self userDefaultLocaleDirs do: workBlock. + self systemDefaultLocaleDirs do: workBlock.! Item was changed: + ----- Method: GetTextTranslator class>>localeDirsForDomain (in category 'accessing') ----- - ----- Method: GetTextTranslator class>>localeDirsForDomain (in category 'private') ----- localeDirsForDomain + + ^ LocaleDirsForDomain values! - ^LocaleDirsForDomain ifNil: [LocaleDirsForDomain := Dictionary new]! Item was removed: - ----- Method: GetTextTranslator class>>localeDirsForDomain: (in category 'translation data layout') ----- - localeDirsForDomain: aDomainName - "returns collection of locale directories for text domain. - This includes user defined one for the domain, user defaults and system defaults" - | dirs dir | - dirs := OrderedCollection new. - dir := self localeDirForDomain: aDomainName. - dir ifNotNil: [dirs add: dir]. - dirs addAll: self defaultLocaleDirs. - ^dirs! Item was added: + ----- Method: GetTextTranslator class>>localeDirsForDomain:do: (in category 'translation data layout') ----- + localeDirsForDomain: aDomainName do: workBlock + "Enumerates all locale directories for the text domain. Begin with domain-specific directories, then user-specific directories, finally system-specific directories." + + (self getLocaleDirForDomain: aDomainName) + ifNotNil: [:dir | workBlock value: dir]. + + self userDefaultLocaleDirs do: workBlock. + self systemDefaultLocaleDirs do: workBlock.! Item was changed: ----- Method: GetTextTranslator class>>privateStartUp (in category 'class initialization') ----- privateStartUp + self setSystemDefaultLocaleDirs. - self setupLocaleDirs. self availableLanguageLocaleIDs do: [ :localeID | NaturalLanguageTranslator translators at: localeID put: (self newForLocaleID: localeID). ]! Item was removed: - ----- Method: GetTextTranslator class>>setLocaleDir:forDoamin: (in category 'translation data layout') ----- - setLocaleDir: path forDoamin: aDomainName - self LocaleDirsForDomain - at: aDomainName - put: path.! Item was added: + ----- Method: GetTextTranslator class>>setLocaleDirForDomain:to: (in category 'translation data layout') ----- + setLocaleDirForDomain: aDomainName to: aPath + + LocaleDirsForDomain at: aDomainName put: aPath.! Item was added: + ----- Method: GetTextTranslator class>>setSystemDefaultLocaleDirs (in category 'translation data layout') ----- + setSystemDefaultLocaleDirs + + | dirs sepa localesDirName | + sepa := FileDirectory slash. + SystemDefaultLocaleDirs := nil. + dirs := self systemDefaultLocaleDirs. + localesDirName := 'locale'. + { Smalltalk imagePath. Smalltalk vmPath } do: [:path | + dirs addIfNotPresent: ((path endsWith: sepa) + ifTrue: [path, localesDirName] + ifFalse: [path, sepa, localesDirName])].! Item was removed: - ----- Method: GetTextTranslator class>>setupLocaleDirs (in category 'translation data layout') ----- - setupLocaleDirs - | dirs sepa localesDirName | - sepa := FileDirectory slash. - SystemDefaultLocaleDirs := nil. - dirs := self systemDefaultLocaleDirs. - localesDirName := 'locale'. - dirs add: (Smalltalk imagePath) , sepa , localesDirName. - dirs add: (Smalltalk vmPath) , sepa , localesDirName. - ^dirs! Item was changed: + ----- Method: GetTextTranslator class>>systemDefaultLocaleDirs (in category 'accessing') ----- - ----- Method: GetTextTranslator class>>systemDefaultLocaleDirs (in category 'translation data layout') ----- systemDefaultLocaleDirs ^SystemDefaultLocaleDirs ifNil: [SystemDefaultLocaleDirs := OrderedCollection new] ! Item was changed: + ----- Method: GetTextTranslator class>>userDefaultLocaleDirs (in category 'accessing') ----- - ----- Method: GetTextTranslator class>>userDefaultLocaleDirs (in category 'translation data layout') ----- userDefaultLocaleDirs ^UserDefaultLocaleDirs ifNil: [UserDefaultLocaleDirs := OrderedCollection new] ! Item was changed: ----- Method: GetTextTranslator>>initialize (in category 'initialize-release') ----- initialize + + super initialize. moFiles := Dictionary new.! Item was removed: - ----- Method: GetTextTranslator>>loadMOFiles (in category 'accessing') ----- - loadMOFiles - TextDomainManager allKnownDomains - do: [:domainName | - self moFileForDomain: domainName - ].! Item was added: + ----- Method: GetTextTranslator>>loadMOFilesForAllDomains (in category 'private') ----- + loadMOFilesForAllDomains + + moFiles := Dictionary new. + moFiles at: #* put: OrderedCollection new. + + (self class findAllMOsForLocaleID: self localeID) do: [:moName | + | moFile | + moFile := MOFile new load: moName value localeID: self localeID. + moFiles at: moName key put: moFile. + (moFiles at: #*) add: moFile]. + + ^ moFiles at: #*! Item was added: + ----- Method: GetTextTranslator>>localeChanged (in category 'language switching') ----- + localeChanged + "Reset cached .mo files. They will be loaded again as needed." + + moFiles := Dictionary new.! Item was removed: - ----- Method: GetTextTranslator>>reloadMOFiles (in category 'accessing') ----- - reloadMOFiles - moFiles := Dictionary new. - self loadMOFiles.! Item was removed: - ----- Method: GetTextTranslator>>setCurrent (in category 'language switching') ----- - setCurrent - "ensure actual contents of MOs is loaded on switching language" - self loadMOFiles! Item was added: + ----- Method: GetTextTranslator>>translateInAllDomains: (in category 'translation') ----- + translateInAllDomains: aString + + | translation | + (self moFiles at: #* ifAbsent: [self loadMOFilesForAllDomains]) + do: [:moFile | + translation := moFile translationFor: aString. + translation == aString ifFalse: [^ translation]]. + ^ aString "no translation found"! Item was added: + ----- Method: InternalTranslator>>translateInAllDomains: (in category 'translation') ----- + translateInAllDomains: aString + "Domains do not matter for the internal translator." + + ^ aString! Item was changed: ----- Method: Locale class>>localeChanged (in category 'notification') ----- localeChanged + + NaturalLanguageTranslator localeChanged. SystemNavigation default allBehaviorsDo: [:b | + (b ~~ self and: [b ~~ NaturalLanguageTranslator]) + ifTrue: [(b class includesSelector: #localeChanged) + ifTrue: [b localeChanged]]].! - b == self ifFalse: [b localeChanged]].! Item was changed: ----- Method: Locale class>>localeChangedGently (in category 'notification') ----- localeChangedGently + + NaturalLanguageTranslator localeChangedGently. + SystemNavigation default allBehaviorsDo: [:b | + (b ~~ self and: [b ~~ NaturalLanguageTranslator]) + ifTrue: [(b class includesSelector: #localeChangedGently) + ifTrue: [b localeChangedGently]]].! - SystemNavigation default allBehaviorsDo: [:b | b == self ifFalse: [b localeChangedGently]].! Item was changed: ----- Method: Locale class>>switchTo:gently: (in category 'accessing') ----- switchTo: locale gently: gentlyFlag "Locale switchTo: (Locale isoLanguage: 'de')" | availableID | availableID := (NaturalLanguageTranslator availableForLocaleID: locale localeID) localeID. Current localeID = availableID ifFalse: [Previous := Current. CurrentPlatform := Current := Locale localeID: availableID. - NaturalLanguageTranslator localeChanged. gentlyFlag ifTrue: [self localeChangedGently] ifFalse: [self localeChanged]]! Item was changed: ----- Method: NaturalLanguageTranslator class>>localeChanged (in category 'accessing') ----- localeChanged "notify some project starts to use this locale. this facility may use the event to load translation data dynamically" + self current localeChanged. - self current setCurrent ! Item was added: + ----- Method: NaturalLanguageTranslator>>localeChanged (in category 'language switching') ----- + localeChanged + "The system's current locale (ID) changed. Make sure to update all lookup caches if your translator needs external resources such as files."! Item was removed: - ----- Method: NaturalLanguageTranslator>>setCurrent (in category 'language switching') ----- - setCurrent - "notify locale of the translator become current" - ! Item was added: + ----- Method: NaturalLanguageTranslator>>translateInAllDomains: (in category 'translation') ----- + translateInAllDomains: aString + + | translation | + TextDomainManager allKnownDomains do: [:domain | + translation := self translate: aString inDomain: domain. + aString == translation ifFalse: [^ translation]]. + ^ aString! Item was changed: ----- Method: String>>translated (in category '*System-Localization') ----- translated + "Note that we cannot call #translatedTo: because the sender context encodes the domain name." + + ^ self - "answer the receiver translated to the default language" - | translation | - translation := self translatedTo: LocaleID current + inDomain: (TextDomainManager domainOfMethod: thisContext sender method)! - inDomain: (TextDomainManager domainOfMethod: thisContext sender method). - self == translation ifTrue: [^self translatedInAllDomains]. - ^translation! Item was removed: - ----- Method: String>>translatedInAllDomains (in category '*System-Localization') ----- - translatedInAllDomains - | translation | - "Transcript show: self printString, ' translatedInAllDomains'; cr." - TextDomainManager allKnownDomains do: [:domain | - translation := self translatedTo: LocaleID current inDomain: domain. - self = translation ifFalse: [^translation] - ]. - ^self! Item was removed: - ----- Method: String>>translatedInAnyDomain (in category '*System-Localization') ----- - translatedInAnyDomain - | translation | - Transcript show: self printString, ' translatedInAnyDomain'; cr. - TextDomainManager allKnownDomains do: [:domain | - translation := self translatedInDomain: domain. - self = translation ifFalse: [^translation]]. - ^self! Item was changed: ----- Method: String>>translatedInDomain: (in category '*System-Localization') ----- translatedInDomain: aDomainName + + ^ self + translatedTo: LocaleID current + inDomain: aDomainName! - | translation | - translation := self translatedTo: LocaleID current inDomain: aDomainName. - self == translation ifTrue: [^self translatedInAllDomains]. - ^translation - ! Item was removed: - ----- Method: String>>translatedInDomain:or: (in category '*System-Localization') ----- - translatedInDomain: aDomainName or: anotherDomainName - | translation | - translation := self translatedTo: LocaleID current inDomain: aDomainName. - self == translation ifTrue: [^self translatedInDomain: anotherDomainName]. - ^translation - ! Item was changed: ----- Method: String>>translatedTo: (in category '*System-Localization') ----- translatedTo: localeID "answer the receiver translated to the given locale id" + + ^ self + translatedTo: localeID + inDomain: (TextDomainManager domainOfMethod: thisContext sender method)! - ^ self translatedTo: localeID inDomain: (TextDomainManager domainOfMethod: thisContext sender method).! Item was changed: ----- Method: String>>translatedTo:inDomain: (in category '*System-Localization') ----- translatedTo: localeID inDomain: aDomainName + "Answer the receiver translated to the given locale id in the textdomain. If no translation can be found, try to lookup all domains for a translation." - "answer the receiver translated to the given locale id in the textdomain" + | translator translation | + translator := NaturalLanguageTranslator availableForLocaleID: localeID. + translation := translator translate: self inDomain: aDomainName. + translation == self ifTrue: [^ translator translateInAllDomains: self]. + ^ translation! - ^ NaturalLanguageTranslator translate: self - toLocaleID: localeID - inDomain: aDomainName! |
Hi all! Here are more detailed benchmarks: Image: 6.0alpha (Update 20067) VM: 202007252116 (32-bit, Windows 10) Translations: 27 .mo files (aka. text domains) -> GetTextTranslator "1) Time to switch locale. Only workspace and docking bar." Locale switchAndInstallFontToID: (LocaleID isoLanguage: 'en'). [Locale switchAndInstallFontToID: (LocaleID isoLanguage: 'de')] timeToRunWithoutGC. "BEFORE: 1577 ms" "AFTER: 1327 ms" "2) Bench fastest lookup path" ['world' translatedInDomain: #Morphic] bench. "BEFORE: '405,000 per second. 2.47 microseconds per run. 4.64 % GC time.'" "AFTER: '433,000 per second. 2.31 microseconds per run. 6.07878 % GC time.'"" "3) Bench try-any-domain fallback." ['world' translated] bench. "BEFORE: '20,300 per second. 49.2 microseconds per run. 11.33773 % GC time.'" "AFTER: '133,000 per second. 7.53 microseconds per run. 8.09838 % GC time.'" "4) No translation found." ['Hello, World!' translated] bench. "BEFORE: '16,200 per second. 61.9 microseconds per run. 13.9772 % GC time.'" "AFTER: '98,600 per second. 10.1 microseconds per run. 7.63847 % GC time.'" **** vvvv Translations: 0 .mo files --> InternalTranslator vvvv ['world' translatedInDomain: #Morphic] bench. "BEFORE: '8,180 per second. 122 microseconds per run. 2.87942 % GC time.'" "AFTER: '760,000 per second. 1.32 microseconds per run. 3.95921 % GC time.'" ['world' translated] bench. "BEFORE: '8,210 per second. 122 microseconds per run. 2.98 % GC time.'" "AFTER: '670,000 per second. 1.49 microseconds per run. 4.62 % GC time.'" ['Hello, World!' translated] bench. "BEFORE: '8,100 per second. 124 microseconds per run. 3.76 % GC time.'" "AFTER: '672,000 per second. 1.49 microseconds per run. 5.48 % GC time.'" Best, Marcel
|
Free forum by Nabble | Edit this page |