]> git.proxmox.com Git - mirror_edk2.git/commitdiff
UefiCpuPkg/PiSmmCpuDxeSmm: Improve the performance of GetFreeToken()
authorRay Ni <niruiyu@users.noreply.github.com>
Fri, 10 Apr 2020 02:51:26 +0000 (10:51 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Mon, 13 Apr 2020 03:13:36 +0000 (03:13 +0000)
Today's GetFreeToken() runs at the algorithm complexity of O(n)
where n is the size of the token list.

The change introduces a new global variable FirstFreeToken and it
always points to the first free token. So the algorithm complexity
of GetFreeToken() decreases from O(n) to O(1).

The improvement matters when some SMI code uses StartupThisAP()
service for each of the AP such that the algorithm complexity
becomes O(n) * O(m) where m is the AP count.

As next steps,
1. PROCEDURE_TOKEN.Used field can be optimized out because
all tokens before FirstFreeToken should have "Used" set while all
after FirstFreeToken should have "Used" cleared.
2. ResetTokens() can be optimized to only reset tokens before
FirstFreeToken.

v2: add missing line in InitializeDataForMmMp.
v3: update copyright year to 2020.

Signed-off-by: Ray Ni <ray.ni@intel.com>
Reviewed-by: Eric Dong <eric.dong@intel.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>
UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h

index c285a70ebb9ab079822c959f6f7e0a8750018822..93cac5e4fa93235e5d294ea65055bca98e8ed69b 100644 (file)
@@ -453,6 +453,11 @@ ResetTokens (
 \r
     Link = GetNextNode (&gSmmCpuPrivate->TokenList, Link);\r
   }\r
+\r
+  //\r
+  // Reset the FirstFreeToken to the beginning of token list upon exiting SMI.\r
+  //\r
+  gSmmCpuPrivate->FirstFreeToken = GetFirstNode (&gSmmCpuPrivate->TokenList);\r
 }\r
 \r
 /**\r
@@ -1060,23 +1065,21 @@ IsTokenInUse (
 /**\r
   Allocate buffer for the SPIN_LOCK and PROCEDURE_TOKEN.\r
 \r
+  @return First token of the token buffer.\r
 **/\r
-VOID\r
+LIST_ENTRY *\r
 AllocateTokenBuffer (\r
   VOID\r
   )\r
 {\r
   UINTN               SpinLockSize;\r
   UINT32              TokenCountPerChunk;\r
-  UINTN               ProcTokenSize;\r
   UINTN               Index;\r
-  PROCEDURE_TOKEN     *ProcToken;\r
   SPIN_LOCK           *SpinLock;\r
   UINT8               *SpinLockBuffer;\r
-  UINT8               *ProcTokenBuffer;\r
+  PROCEDURE_TOKEN     *ProcTokens;\r
 \r
   SpinLockSize = GetSpinLockProperties ();\r
-  ProcTokenSize = sizeof (PROCEDURE_TOKEN);\r
 \r
   TokenCountPerChunk = FixedPcdGet32 (PcdCpuSmmMpTokenCountPerChunk);\r
   ASSERT (TokenCountPerChunk != 0);\r
@@ -1092,49 +1095,22 @@ AllocateTokenBuffer (
   SpinLockBuffer = AllocatePool (SpinLockSize * TokenCountPerChunk);\r
   ASSERT (SpinLockBuffer != NULL);\r
 \r
-  ProcTokenBuffer = AllocatePool (ProcTokenSize * TokenCountPerChunk);\r
-  ASSERT (ProcTokenBuffer != NULL);\r
+  ProcTokens = AllocatePool (sizeof (PROCEDURE_TOKEN) * TokenCountPerChunk);\r
+  ASSERT (ProcTokens != NULL);\r
 \r
   for (Index = 0; Index < TokenCountPerChunk; Index++) {\r
     SpinLock = (SPIN_LOCK *)(SpinLockBuffer + SpinLockSize * Index);\r
     InitializeSpinLock (SpinLock);\r
 \r
-    ProcToken = (PROCEDURE_TOKEN *)(ProcTokenBuffer + ProcTokenSize * Index);\r
-    ProcToken->Signature = PROCEDURE_TOKEN_SIGNATURE;\r
-    ProcToken->SpinLock = SpinLock;\r
-    ProcToken->Used = FALSE;\r
-    ProcToken->RunningApCount = 0;\r
+    ProcTokens[Index].Signature      = PROCEDURE_TOKEN_SIGNATURE;\r
+    ProcTokens[Index].SpinLock       = SpinLock;\r
+    ProcTokens[Index].Used           = FALSE;\r
+    ProcTokens[Index].RunningApCount = 0;\r
 \r
-    InsertTailList (&gSmmCpuPrivate->TokenList, &ProcToken->Link);\r
+    InsertTailList (&gSmmCpuPrivate->TokenList, &ProcTokens[Index].Link);\r
   }\r
-}\r
 \r
-/**\r
-  Find first free token in the allocated token list.\r
-\r
-  @retval    return the first free PROCEDURE_TOKEN.\r
-\r
-**/\r
-PROCEDURE_TOKEN *\r
-FindFirstFreeToken (\r
-  VOID\r
-  )\r
-{\r
-  LIST_ENTRY        *Link;\r
-  PROCEDURE_TOKEN   *ProcToken;\r
-\r
-  Link = GetFirstNode (&gSmmCpuPrivate->TokenList);\r
-  while (!IsNull (&gSmmCpuPrivate->TokenList, Link)) {\r
-    ProcToken = PROCEDURE_TOKEN_FROM_LINK (Link);\r
-\r
-    if (!ProcToken->Used) {\r
-      return ProcToken;\r
-    }\r
-\r
-    Link = GetNextNode (&gSmmCpuPrivate->TokenList, Link);\r
-  }\r
-\r
-  return NULL;\r
+  return &ProcTokens[0].Link;\r
 }\r
 \r
 /**\r
@@ -1154,12 +1130,15 @@ GetFreeToken (
 {\r
   PROCEDURE_TOKEN  *NewToken;\r
 \r
-  NewToken = FindFirstFreeToken ();\r
-  if (NewToken == NULL) {\r
-    AllocateTokenBuffer ();\r
-    NewToken = FindFirstFreeToken ();\r
+  //\r
+  // If FirstFreeToken meets the end of token list, enlarge the token list.\r
+  // Set FirstFreeToken to the first free token.\r
+  //\r
+  if (gSmmCpuPrivate->FirstFreeToken == &gSmmCpuPrivate->TokenList) {\r
+    gSmmCpuPrivate->FirstFreeToken = AllocateTokenBuffer ();\r
   }\r
-  ASSERT (NewToken != NULL);\r
+  NewToken = PROCEDURE_TOKEN_FROM_LINK (gSmmCpuPrivate->FirstFreeToken);\r
+  gSmmCpuPrivate->FirstFreeToken = GetNextNode (&gSmmCpuPrivate->TokenList, gSmmCpuPrivate->FirstFreeToken);\r
 \r
   NewToken->Used = TRUE;\r
   NewToken->RunningApCount = RunningApsCount;\r
@@ -1781,7 +1760,7 @@ InitializeDataForMmMp (
 \r
   InitializeListHead (&gSmmCpuPrivate->TokenList);\r
 \r
-  AllocateTokenBuffer ();\r
+  gSmmCpuPrivate->FirstFreeToken = AllocateTokenBuffer ();\r
 }\r
 \r
 /**\r
index fe7e8b0323b82095faa8b48582e0680a1035fc4c..c9b3b739f37c5074a8c3f43286754857ff73ed66 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 Agent Module to load other modules to deploy SMM Entry Vector for X86 CPU.\r
 \r
-Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.<BR>\r
 Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
 \r
 SPDX-License-Identifier: BSD-2-Clause-Patent\r
@@ -255,6 +255,7 @@ typedef struct {
 \r
   PROCEDURE_WRAPPER               *ApWrapperFunc;\r
   LIST_ENTRY                      TokenList;\r
+  LIST_ENTRY                      *FirstFreeToken;\r
 } SMM_CPU_PRIVATE_DATA;\r
 \r
 extern SMM_CPU_PRIVATE_DATA  *gSmmCpuPrivate;\r