From 4e375707392e4f9085e2d2342e41aee9d4df2b0a Mon Sep 17 00:00:00 2001 From: BobCF Date: Thu, 8 Nov 2018 18:16:25 +0800 Subject: [PATCH] BaseTools: Optimize string concatenation https://bugzilla.tianocore.org/show_bug.cgi?id=1288 This patch is one of build tool performance improvement series patches. This patch is going to use join function instead of string += string2 statement. Current code use string += string2 in a loop to combine a string. while creating a string list in a loop and using "".join(stringlist) after the loop will be much faster. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: BobCF Cc: Liming Gao Cc: Jaben Carsey Reviewed-by: Liming Gao Reviewed-by: Jaben Carsey --- BaseTools/Source/Python/AutoGen/StrGather.py | 39 +++++++++++++------ BaseTools/Source/Python/Common/Misc.py | 21 +++++----- .../Source/Python/Workspace/InfBuildData.py | 4 +- .../Python/Workspace/WorkspaceCommon.py | 11 ++---- 4 files changed, 44 insertions(+), 31 deletions(-) diff --git a/BaseTools/Source/Python/AutoGen/StrGather.py b/BaseTools/Source/Python/AutoGen/StrGather.py index 361d499076..d34a9e9447 100644 --- a/BaseTools/Source/Python/AutoGen/StrGather.py +++ b/BaseTools/Source/Python/AutoGen/StrGather.py @@ -137,7 +137,7 @@ def AscToHexList(Ascii): # @retval Str: A string of .h file content # def CreateHFileContent(BaseName, UniObjectClass, IsCompatibleMode, UniGenCFlag): - Str = '' + Str = [] ValueStartPtr = 60 Line = COMMENT_DEFINE_STR + ' ' + LANGUAGE_NAME_STRING_NAME + ' ' * (ValueStartPtr - len(DEFINE_STR + LANGUAGE_NAME_STRING_NAME)) + DecToHexStr(0, 4) + COMMENT_NOT_REFERENCED Str = WriteLine(Str, Line) @@ -166,12 +166,12 @@ def CreateHFileContent(BaseName, UniObjectClass, IsCompatibleMode, UniGenCFlag): Line = COMMENT_DEFINE_STR + ' ' + Name + ' ' * (ValueStartPtr - len(DEFINE_STR + Name)) + DecToHexStr(Token, 4) + COMMENT_NOT_REFERENCED UnusedStr = WriteLine(UnusedStr, Line) - Str = ''.join([Str, UnusedStr]) + Str.extend( UnusedStr) Str = WriteLine(Str, '') if IsCompatibleMode or UniGenCFlag: Str = WriteLine(Str, 'extern unsigned char ' + BaseName + 'Strings[];') - return Str + return "".join(Str) ## Create a complete .h file # @@ -187,7 +187,7 @@ def CreateHFileContent(BaseName, UniObjectClass, IsCompatibleMode, UniGenCFlag): def CreateHFile(BaseName, UniObjectClass, IsCompatibleMode, UniGenCFlag): HFile = WriteLine('', CreateHFileContent(BaseName, UniObjectClass, IsCompatibleMode, UniGenCFlag)) - return HFile + return "".join(HFile) ## Create a buffer to store all items in an array # @@ -211,7 +211,7 @@ def CreateArrayItem(Array, Width = 16): MaxLength = Width Index = 0 Line = ' ' - ArrayItem = '' + ArrayItem = [] for Item in Array: if Index < MaxLength: @@ -223,7 +223,7 @@ def CreateArrayItem(Array, Width = 16): Index = 1 ArrayItem = Write(ArrayItem, Line.rstrip()) - return ArrayItem + return "".join(ArrayItem) ## CreateCFileStringValue # @@ -238,7 +238,7 @@ def CreateCFileStringValue(Value): Value = [StringBlockType] + Value Str = WriteLine('', CreateArrayItem(Value)) - return Str + return "".join(Str) ## GetFilteredLanguage # @@ -440,7 +440,7 @@ def CreateCFileContent(BaseName, UniObjectClass, IsCompatibleMode, UniBinBuffer, # AllStr = Write(AllStr, Str) - return AllStr + return "".join(AllStr) ## Create end of .c file # @@ -467,7 +467,7 @@ def CreateCFile(BaseName, UniObjectClass, IsCompatibleMode, FilterInfo): CFile = '' CFile = WriteLine(CFile, CreateCFileContent(BaseName, UniObjectClass, IsCompatibleMode, None, FilterInfo)) CFile = WriteLine(CFile, CreateCFileEnd()) - return CFile + return "".join(CFile) ## GetFileList # @@ -574,13 +574,30 @@ def GetStringFiles(UniFilList, SourceFileList, IncludeList, IncludePathList, Ski # Write an item # def Write(Target, Item): - return ''.join([Target, Item]) + if isinstance(Target,str): + Target = [Target] + if not Target: + Target = [] + if isinstance(Item,list): + Target.extend(Item) + else: + Target.append(Item) + return Target # # Write an item with a break line # def WriteLine(Target, Item): - return ''.join([Target, Item, '\n']) + if isinstance(Target,str): + Target = [Target] + if not Target: + Target = [] + if isinstance(Item, list): + Target.extend(Item) + else: + Target.append(Item) + Target.append('\n') + return Target # This acts like the main() function for the script, unless it is 'import'ed into another # script. diff --git a/BaseTools/Source/Python/Common/Misc.py b/BaseTools/Source/Python/Common/Misc.py index 2354f392f2..84f3f16ee6 100644 --- a/BaseTools/Source/Python/Common/Misc.py +++ b/BaseTools/Source/Python/Common/Misc.py @@ -778,7 +778,7 @@ class TemplateString(object): ## Constructor def __init__(self, Template=None): - self.String = '' + self.String = [] self.IsBinary = False self._Template = Template self._TemplateSectionList = self._Parse(Template) @@ -788,7 +788,7 @@ class TemplateString(object): # @retval string The string replaced # def __str__(self): - return self.String + return "".join(self.String) ## Split the template string into fragments per the ${BEGIN} and ${END} flags # @@ -836,9 +836,12 @@ class TemplateString(object): def Append(self, AppendString, Dictionary=None): if Dictionary: SectionList = self._Parse(AppendString) - self.String += "".join(S.Instantiate(Dictionary) for S in SectionList) + self.String.append( "".join(S.Instantiate(Dictionary) for S in SectionList)) else: - self.String += AppendString + if isinstance(AppendString,list): + self.String.extend(AppendString) + else: + self.String.append(AppendString) ## Replace the string template with dictionary of placeholders # @@ -1744,10 +1747,7 @@ class PathClass(object): # @retval True The two PathClass are the same # def __eq__(self, Other): - if isinstance(Other, type(self)): - return self.Path == Other.Path - else: - return self.Path == str(Other) + return self.Path == str(Other) ## Override __cmp__ function # @@ -1757,10 +1757,7 @@ class PathClass(object): # @retval -1 The first PathClass is less than the second PathClass # @retval 1 The first PathClass is Bigger than the second PathClass def __cmp__(self, Other): - if isinstance(Other, type(self)): - OtherKey = Other.Path - else: - OtherKey = str(Other) + OtherKey = str(Other) SelfKey = self.Path if SelfKey == OtherKey: diff --git a/BaseTools/Source/Python/Workspace/InfBuildData.py b/BaseTools/Source/Python/Workspace/InfBuildData.py index d10cfea40d..99bbecfd1f 100644 --- a/BaseTools/Source/Python/Workspace/InfBuildData.py +++ b/BaseTools/Source/Python/Workspace/InfBuildData.py @@ -614,7 +614,9 @@ class InfBuildData(ModuleBuildClassObject): Instance = Record[1] if Instance: Instance = NormPath(Instance, self._Macros) - RetVal[Lib] = Instance + RetVal[Lib] = Instance + else: + RetVal[Lib] = None return RetVal ## Retrieve library names (for Edk.x style of modules) diff --git a/BaseTools/Source/Python/Workspace/WorkspaceCommon.py b/BaseTools/Source/Python/Workspace/WorkspaceCommon.py index 8d8a3e2789..55d01fa4b2 100644 --- a/BaseTools/Source/Python/Workspace/WorkspaceCommon.py +++ b/BaseTools/Source/Python/Workspace/WorkspaceCommon.py @@ -128,13 +128,10 @@ def GetModuleLibInstances(Module, Platform, BuildDatabase, Arch, Target, Toolcha for LibraryClassName in M.LibraryClasses: if LibraryClassName not in LibraryInstance: # override library instance for this module - if LibraryClassName in Platform.Modules[str(Module)].LibraryClasses: - LibraryPath = Platform.Modules[str(Module)].LibraryClasses[LibraryClassName] - else: - LibraryPath = Platform.LibraryClasses[LibraryClassName, ModuleType] - if LibraryPath is None or LibraryPath == "": - LibraryPath = M.LibraryClasses[LibraryClassName] - if LibraryPath is None or LibraryPath == "": + LibraryPath = Platform.Modules[str(Module)].LibraryClasses.get(LibraryClassName,Platform.LibraryClasses[LibraryClassName, ModuleType]) + if LibraryPath is None: + LibraryPath = M.LibraryClasses.get(LibraryClassName) + if LibraryPath is None: if FileName: EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, "Instance of library class [%s] is not found" % LibraryClassName, -- 2.39.2