public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements
@ 2021-01-04 15:42 Laszlo Ersek
  2021-01-04 15:42 ` [PATCH 1/8] ShellPkg/Comp: add file buffering Laszlo Ersek
                   ` (9 more replies)
  0 siblings, 10 replies; 15+ messages in thread
From: Laszlo Ersek @ 2021-01-04 15:42 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Anthony Perard, Ard Biesheuvel, Jordan Justen, Julien Grall,
	Leif Lindholm, Peter Grehan, Philippe Mathieu-Daudé, Ray Ni,
	Rebecca Cran, Sami Mujawar, Zhichao Gao

Repo:   https://pagure.io/lersek/edk2.git
Branch: shell_usability_improvements

This series addresses various usability shortcomings that I've recently
run into, while working with large directory trees on FAT and/or
virtio-fs in the UEFI shell.

* add file buffering to the COMP command
  https://bugzilla.tianocore.org/show_bug.cgi?id=3123

* ArmVirtPkg, OvmfPkg: set PcdShellFileOperationSize to 0x20000
  https://bugzilla.tianocore.org/show_bug.cgi?id=3125

* Shell: pathname / filename sorting
  https://bugzilla.tianocore.org/show_bug.cgi?id=3151

* ArmVirtPkg, OvmfPkg: disable list length checks in NOOPT and DEBUG
  builds
  https://bugzilla.tianocore.org/show_bug.cgi?id=3152

Beyond testing the series locally, I've also heavily subjected it to
local CI runs, including ECC (relevant for ShellPkg).

Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Julien Grall <julien@xen.org>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Peter Grehan <grehan@freebsd.org>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rebecca Cran <rebecca@bsdio.com>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Zhichao Gao <zhichao.gao@intel.com>

Thanks
Laszlo

Laszlo Ersek (8):
  ShellPkg/Comp: add file buffering
  OvmfPkg: raise PcdShellFileOperationSize to 128KB
  ArmVirtPkg: raise PcdShellFileOperationSize to 128KB
  ShellPkg/ShellCommandLib: add ShellSortFileList()
  ShellPkg/Ls: sort output by FileName in non-SFO mode
  ShellPkg/ShellProtocol: sort files by FullName in
    RemoveDupInFileList()
  OvmfPkg: disable list length checks in NOOPT and DEBUG builds
  ArmVirtPkg: disable list length checks in NOOPT and DEBUG builds

 ArmVirtPkg/ArmVirt.dsc.inc                                                 |   2 +-
 ArmVirtPkg/ArmVirtQemu.dsc                                                 |   1 +
 ArmVirtPkg/ArmVirtQemuKernel.dsc                                           |   1 +
 OvmfPkg/AmdSev/AmdSevX64.dsc                                               |   1 +
 OvmfPkg/Bhyve/BhyveX64.dsc                                                 |   1 +
 OvmfPkg/OvmfPkgIa32.dsc                                                    |   3 +
 OvmfPkg/OvmfPkgIa32X64.dsc                                                 |   3 +
 OvmfPkg/OvmfPkgX64.dsc                                                     |   3 +
 OvmfPkg/OvmfXen.dsc                                                        |   1 +
 ShellPkg/Application/Shell/ShellProtocol.c                                 |  16 +
 ShellPkg/Include/Library/ShellCommandLib.h                                 |  81 +++++
 ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c                 | 312 ++++++++++++++++++++
 ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h                 |  19 ++
 ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf               |   1 +
 ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c                         | 127 +++++++-
 ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf |   1 +
 ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c                           |  14 +
 ShellPkg/ShellPkg.dsc                                                      |   1 +
 18 files changed, 584 insertions(+), 4 deletions(-)


base-commit: 0785c619a58a450091d2bf6755591012533b80b8
-- 
2.19.1.3.g30247aa5d201


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/8] ShellPkg/Comp: add file buffering
  2021-01-04 15:42 [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements Laszlo Ersek
@ 2021-01-04 15:42 ` Laszlo Ersek
  2021-01-11  1:24   ` Gao, Zhichao
  2021-01-04 15:42 ` [PATCH 2/8] OvmfPkg: raise PcdShellFileOperationSize to 128KB Laszlo Ersek
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 15+ messages in thread
From: Laszlo Ersek @ 2021-01-04 15:42 UTC (permalink / raw)
  To: edk2-devel-groups-io; +Cc: Philippe Mathieu-Daudé, Ray Ni, Zhichao Gao

The COMP shell command compares two files byte for byte. In order to
retrieve the bytes to compare, it currently invokes
gEfiShellProtocol->ReadFile() on both files, using a single-byte buffer
every time. This is very inefficient; the underlying
EFI_FILE_PROTOCOL.Read() function may be costly.

Read both file operands in chunks of "PcdShellFileOperationSize" bytes.
Draw bytes for comparison from the internal read-ahead buffers.

Some ad-hoc measurements on my laptop, using OVMF, and the 4KB default of
"PcdShellFileOperationSize":

- When comparing two identical 1MB files that are served by EnhancedFatDxe
  on top of VirtioScsiDxe, this patch brings no noticeable improvement;
  the comparison completes in <1s both before and after.

- When comparing two identical 1MB files served by VirtioFsDxe, the
  comparison time improves from 2 minutes 25 seconds to <1s.

Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Zhichao Gao <zhichao.gao@intel.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3123
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf |   1 +
 ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c                         | 127 +++++++++++++++++++-
 2 files changed, 125 insertions(+), 3 deletions(-)

diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf b/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf
index ed94477a0642..74ad5facf6b1 100644
--- a/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf
+++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf
@@ -113,6 +113,7 @@ [LibraryClasses]
   BcfgCommandLib
 
 [Pcd]
+  gEfiShellPkgTokenSpaceGuid.PcdShellFileOperationSize        ## CONSUMES
   gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask              ## CONSUMES
 
 [Protocols]
diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c
index 0a5d13f01c7b..0df0b3149369 100644
--- a/ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c
+++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c
@@ -21,6 +21,16 @@ typedef enum {
   InPrevDiffPoint
 } READ_STATUS;
 
+//
+// Buffer type, for reading both file operands in chunks.
+//
+typedef struct {
+  UINT8 *Data;     // dynamically allocated buffer
+  UINTN Allocated; // the allocated size of Data
+  UINTN Next;      // next position in Data to fetch a byte at
+  UINTN Left;      // number of bytes left in Data for fetching at Next
+} FILE_BUFFER;
+
 /**
   Function to print differnt point data.
 
@@ -76,6 +86,106 @@ PrintDifferentPoint(
   ShellPrintEx (-1, -1, L"*\r\n");
 }
 
+/**
+  Initialize a FILE_BUFFER.
+
+  @param[out] FileBuffer  The FILE_BUFFER to initialize. On return, the caller
+                          is responsible for checking FileBuffer->Data: if
+                          FileBuffer->Data is NULL on output, then memory
+                          allocation failed.
+**/
+STATIC
+VOID
+FileBufferInit (
+  OUT FILE_BUFFER *FileBuffer
+  )
+{
+  FileBuffer->Allocated = PcdGet32 (PcdShellFileOperationSize);
+  FileBuffer->Data      = AllocatePool (FileBuffer->Allocated);
+  FileBuffer->Left      = 0;
+}
+
+/**
+  Uninitialize a FILE_BUFFER.
+
+  @param[in,out] FileBuffer  The FILE_BUFFER to uninitialize. The caller is
+                             responsible for making sure FileBuffer was first
+                             initialized with FileBufferInit(), successfully or
+                             unsuccessfully.
+**/
+STATIC
+VOID
+FileBufferUninit (
+  IN OUT FILE_BUFFER *FileBuffer
+  )
+{
+  SHELL_FREE_NON_NULL (FileBuffer->Data);
+}
+
+/**
+  Read a byte from a SHELL_FILE_HANDLE, buffered with a FILE_BUFFER.
+
+  @param[in] FileHandle      The SHELL_FILE_HANDLE to replenish FileBuffer
+                             from, if needed.
+
+  @param[in,out] FileBuffer  The FILE_BUFFER to read a byte from. If FileBuffer
+                             is empty on entry, then FileBuffer is refilled
+                             from FileHandle, before outputting a byte from
+                             FileBuffer to Byte. The caller is responsible for
+                             ensuring that FileBuffer was successfully
+                             initialized with FileBufferInit().
+
+  @param[out] BytesRead      On successful return, BytesRead is set to 1 if the
+                             next byte from FileBuffer has been stored to Byte.
+                             On successful return, BytesRead is set to 0 if
+                             FileBuffer is empty, and FileHandle is at EOF.
+                             When an error is returned, BytesRead is not set.
+
+  @param[out] Byte           On output, the next byte from FileBuffer. Only set
+                             if (a) EFI_SUCCESS is returned and (b) BytesRead
+                             is set to 1 on output.
+
+  @retval EFI_SUCCESS  BytesRead has been set to 0 or 1. In the latter case,
+                       Byte has been set as well.
+
+  @return              Error codes propagated from
+                       gEfiShellProtocol->ReadFile().
+**/
+STATIC
+EFI_STATUS
+FileBufferReadByte (
+  IN     SHELL_FILE_HANDLE FileHandle,
+  IN OUT FILE_BUFFER       *FileBuffer,
+     OUT UINTN             *BytesRead,
+     OUT UINT8             *Byte
+  )
+{
+  UINTN      ReadSize;
+  EFI_STATUS Status;
+
+  if (FileBuffer->Left == 0) {
+    ReadSize = FileBuffer->Allocated;
+    Status = gEfiShellProtocol->ReadFile (FileHandle, &ReadSize,
+                                  FileBuffer->Data);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+    if (ReadSize == 0) {
+      *BytesRead = 0;
+      return EFI_SUCCESS;
+    }
+    FileBuffer->Next = 0;
+    FileBuffer->Left = ReadSize;
+  }
+
+  *BytesRead = 1;
+  *Byte      = FileBuffer->Data[FileBuffer->Next];
+
+  FileBuffer->Next++;
+  FileBuffer->Left--;
+  return EFI_SUCCESS;
+}
+
 /**
   Function for 'comp' command.
 
@@ -107,6 +217,8 @@ ShellCommandRunComp (
   UINT8               OneByteFromFile2;
   UINT8               *DataFromFile1;
   UINT8               *DataFromFile2;
+  FILE_BUFFER         FileBuffer1;
+  FILE_BUFFER         FileBuffer2;
   UINTN               InsertPosition1;
   UINTN               InsertPosition2;
   UINTN               DataSizeFromFile1;
@@ -234,10 +346,15 @@ ShellCommandRunComp (
       if (ShellStatus == SHELL_SUCCESS) {
         DataFromFile1 = AllocateZeroPool ((UINTN)DifferentBytes);
         DataFromFile2 = AllocateZeroPool ((UINTN)DifferentBytes);
-        if (DataFromFile1 == NULL || DataFromFile2 == NULL) {
+        FileBufferInit (&FileBuffer1);
+        FileBufferInit (&FileBuffer2);
+        if (DataFromFile1 == NULL || DataFromFile2 == NULL ||
+            FileBuffer1.Data == NULL || FileBuffer2.Data == NULL) {
           ShellStatus = SHELL_OUT_OF_RESOURCES;
           SHELL_FREE_NON_NULL (DataFromFile1);
           SHELL_FREE_NON_NULL (DataFromFile2);
+          FileBufferUninit (&FileBuffer1);
+          FileBufferUninit (&FileBuffer2);
         }
       }
 
@@ -247,9 +364,11 @@ ShellCommandRunComp (
           DataSizeFromFile2 = 1;
           OneByteFromFile1 = 0;
           OneByteFromFile2 = 0;
-          Status = gEfiShellProtocol->ReadFile (FileHandle1, &DataSizeFromFile1, &OneByteFromFile1);
+          Status = FileBufferReadByte (FileHandle1, &FileBuffer1,
+                     &DataSizeFromFile1, &OneByteFromFile1);
           ASSERT_EFI_ERROR (Status);
-          Status = gEfiShellProtocol->ReadFile (FileHandle2, &DataSizeFromFile2, &OneByteFromFile2);
+          Status = FileBufferReadByte (FileHandle2, &FileBuffer2,
+                     &DataSizeFromFile2, &OneByteFromFile2);
           ASSERT_EFI_ERROR (Status);
 
           TempAddress++;
@@ -346,6 +465,8 @@ ShellCommandRunComp (
 
         SHELL_FREE_NON_NULL (DataFromFile1);
         SHELL_FREE_NON_NULL (DataFromFile2);
+        FileBufferUninit (&FileBuffer1);
+        FileBufferUninit (&FileBuffer2);
 
         if (DiffPointNumber == 0) {
           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_COMP_FOOTER_PASS), gShellDebug1HiiHandle);
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 2/8] OvmfPkg: raise PcdShellFileOperationSize to 128KB
  2021-01-04 15:42 [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements Laszlo Ersek
  2021-01-04 15:42 ` [PATCH 1/8] ShellPkg/Comp: add file buffering Laszlo Ersek
@ 2021-01-04 15:42 ` Laszlo Ersek
  2021-01-04 15:42 ` [PATCH 3/8] ArmVirtPkg: " Laszlo Ersek
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Laszlo Ersek @ 2021-01-04 15:42 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Jordan Justen, Philippe Mathieu-Daudé

Some UEFI shell commands read and write files in chunks. The chunk size is
given by "PcdShellFileOperationSize", whose default in
"ShellPkg/ShellPkg.dec" is 4KB (0x1000).

The virtio-fs daemon of QEMU advertizes a 128KB maximum buffer size by
default, for the FUSE_WRITE operation.

By raising PcdShellFileOperationSize 32-fold, the number of FUSE write
requests shrinks proportionately, when writing large files. And when a
Virtio Filesystem is not used, a 128KB chunk size is still not
particularly wasteful.

Some ad-hoc measurements on my laptop, using OVMF:

- The time it takes to copy a ~270MB file from a Virtio Filesystem to the
  same Virtio Filesystem improves from ~9 seconds to ~1 second.

- The time it takes to compare two identical ~270MB files on the same
  Virtio Filesystem improves from ~11 seconds to ~3 seconds.

Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3125
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/OvmfPkgIa32.dsc    | 2 ++
 OvmfPkg/OvmfPkgIa32X64.dsc | 2 ++
 OvmfPkg/OvmfPkgX64.dsc     | 2 ++
 3 files changed, 6 insertions(+)

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 26a013ec353e..cd0acf021459 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -560,6 +560,8 @@ [PcdsFixedAtBuild]
   #
 !include NetworkPkg/NetworkPcds.dsc.inc
 
+  gEfiShellPkgTokenSpaceGuid.PcdShellFileOperationSize|0x20000
+
 !if $(SMM_REQUIRE) == TRUE
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackSize|0x4000
 !endif
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 10579fe46c5b..3bf493bdb08f 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -566,6 +566,8 @@ [PcdsFixedAtBuild.X64]
   #
 !include NetworkPkg/NetworkPcds.dsc.inc
 
+  gEfiShellPkgTokenSpaceGuid.PcdShellFileOperationSize|0x20000
+
 !if $(SMM_REQUIRE) == TRUE
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackSize|0x4000
 !endif
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index c9235e48ad62..cebdbc9faabe 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -564,6 +564,8 @@ [PcdsFixedAtBuild]
   #
 !include NetworkPkg/NetworkPcds.dsc.inc
 
+  gEfiShellPkgTokenSpaceGuid.PcdShellFileOperationSize|0x20000
+
 !if $(SMM_REQUIRE) == TRUE
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackSize|0x4000
 !endif
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 3/8] ArmVirtPkg: raise PcdShellFileOperationSize to 128KB
  2021-01-04 15:42 [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements Laszlo Ersek
  2021-01-04 15:42 ` [PATCH 1/8] ShellPkg/Comp: add file buffering Laszlo Ersek
  2021-01-04 15:42 ` [PATCH 2/8] OvmfPkg: raise PcdShellFileOperationSize to 128KB Laszlo Ersek
@ 2021-01-04 15:42 ` Laszlo Ersek
  2021-01-04 15:42 ` [PATCH 4/8] ShellPkg/ShellCommandLib: add ShellSortFileList() Laszlo Ersek
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Laszlo Ersek @ 2021-01-04 15:42 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Leif Lindholm, Philippe Mathieu-Daudé

Some UEFI shell commands read and write files in chunks. The chunk size is
given by "PcdShellFileOperationSize", whose default in
"ShellPkg/ShellPkg.dec" is 4KB (0x1000).

The virtio-fs daemon of QEMU advertizes a 128KB maximum buffer size by
default, for the FUSE_WRITE operation.

By raising PcdShellFileOperationSize 32-fold, the number of FUSE write
requests shrinks proportionately, when writing large files. And when a
Virtio Filesystem is not used, a 128KB chunk size is still not
particularly wasteful.

Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3125
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 ArmVirtPkg/ArmVirtQemu.dsc       | 1 +
 ArmVirtPkg/ArmVirtQemuKernel.dsc | 1 +
 2 files changed, 2 insertions(+)

diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
index ef5d6dbeaddc..b8bc08d73921 100644
--- a/ArmVirtPkg/ArmVirtQemu.dsc
+++ b/ArmVirtPkg/ArmVirtQemu.dsc
@@ -204,6 +204,7 @@ [PcdsFixedAtBuild.common]
 !endif
 
   gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|3
+  gEfiShellPkgTokenSpaceGuid.PcdShellFileOperationSize|0x20000
 
 [PcdsFixedAtBuild.AARCH64]
   # Clearing BIT0 in this PCD prevents installing a 32-bit SMBIOS entry point,
diff --git a/ArmVirtPkg/ArmVirtQemuKernel.dsc b/ArmVirtPkg/ArmVirtQemuKernel.dsc
index f8f5f7f4b94b..2ef86f96688f 100644
--- a/ArmVirtPkg/ArmVirtQemuKernel.dsc
+++ b/ArmVirtPkg/ArmVirtQemuKernel.dsc
@@ -174,6 +174,7 @@ [PcdsFixedAtBuild.common]
 !endif
 
   gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|3
+  gEfiShellPkgTokenSpaceGuid.PcdShellFileOperationSize|0x20000
 
 [PcdsPatchableInModule.common]
   # we need to provide a resolution for this PCD that supports PcdSet64()
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 4/8] ShellPkg/ShellCommandLib: add ShellSortFileList()
  2021-01-04 15:42 [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements Laszlo Ersek
                   ` (2 preceding siblings ...)
  2021-01-04 15:42 ` [PATCH 3/8] ArmVirtPkg: " Laszlo Ersek
@ 2021-01-04 15:42 ` Laszlo Ersek
  2021-01-13  3:03   ` Gao, Zhichao
  2021-01-04 15:42 ` [PATCH 5/8] ShellPkg/Ls: sort output by FileName in non-SFO mode Laszlo Ersek
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 15+ messages in thread
From: Laszlo Ersek @ 2021-01-04 15:42 UTC (permalink / raw)
  To: edk2-devel-groups-io; +Cc: Philippe Mathieu-Daudé, Ray Ni, Zhichao Gao

Introduce the ShellSortFileList() function, for sorting an
EFI_SHELL_FILE_INFO list, by FileName or by FullName.

Duplicates can be kept in the same list, or separated out to a new list.
In either case, the relative order between duplicates does not change (the
sorting is stable).

For the sorting, use OrderedCollectionLib rather than SortLib:

- The PerformQuickSort() function from the latter has quadratic worst-case
  time complexity, plus it is implemented recursively (see
  "MdeModulePkg/Library/UefiSortLib/UefiSortLib.c"). It can also not
  return an error on memory allocation failure.

- In comparison, the Red-Black Tree instance of OrderedCollectionLib sorts
  in O(n*log(n)) worst-case time, contains no recursion with the default
  PcdValidateOrderedCollection=FALSE setting, and the OrderedCollectionLib
  class APIs return errors appropriately.

The OrderedCollectionLib APIs do not permit duplicates natively, but by
using lists as collection entries, stable sorting of duplicates can be
achieved.

Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Zhichao Gao <zhichao.gao@intel.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3151
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 ShellPkg/ShellPkg.dsc                                        |   1 +
 ShellPkg/Include/Library/ShellCommandLib.h                   |  81 +++++
 ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf |   1 +
 ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h   |  19 ++
 ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c   | 312 ++++++++++++++++++++
 5 files changed, 414 insertions(+)

diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc
index c42bc9464a0f..a8b6de334284 100644
--- a/ShellPkg/ShellPkg.dsc
+++ b/ShellPkg/ShellPkg.dsc
@@ -47,6 +47,7 @@ [LibraryClasses.common]
   ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf
   ShellCEntryLib|ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf
   HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf
+  OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrderedCollectionRedBlackTreeLib.inf
 
   PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
   BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf
diff --git a/ShellPkg/Include/Library/ShellCommandLib.h b/ShellPkg/Include/Library/ShellCommandLib.h
index 63fcac82a2de..bc1afed5e7f5 100644
--- a/ShellPkg/Include/Library/ShellCommandLib.h
+++ b/ShellPkg/Include/Library/ShellCommandLib.h
@@ -714,4 +714,85 @@ CatSDumpHex (
   IN UINTN   DataSize,
   IN VOID    *UserData
   );
+
+//
+// Determines the ordering operation for ShellSortFileList().
+//
+typedef enum {
+  //
+  // Sort the EFI_SHELL_FILE_INFO objects by the FileName field, in increasing
+  // order, using gUnicodeCollation->StriColl().
+  //
+  ShellSortFileListByFileName,
+  //
+  // Sort the EFI_SHELL_FILE_INFO objects by the FullName field, in increasing
+  // order, using gUnicodeCollation->StriColl().
+  //
+  ShellSortFileListByFullName,
+  ShellSortFileListMax
+} SHELL_SORT_FILE_LIST;
+
+/**
+  Sort an EFI_SHELL_FILE_INFO list, optionally moving duplicates to a separate
+  list.
+
+  @param[in,out] FileList  The list of EFI_SHELL_FILE_INFO objects to sort.
+
+                           If FileList is NULL on input, then FileList is
+                           considered an empty, hence already sorted, list.
+
+                           Otherwise, if (*FileList) is NULL on input, then
+                           EFI_INVALID_PARAMETER is returned.
+
+                           Otherwise, the caller is responsible for having
+                           initialized (*FileList)->Link with
+                           InitializeListHead(). No other fields in the
+                           (**FileList) head element are accessed by this
+                           function.
+
+                           On output, (*FileList) is sorted according to Order.
+                           If Duplicates is NULL on input, then duplicate
+                           elements are preserved, sorted stably, on
+                           (*FileList). If Duplicates is not NULL on input,
+                           then duplicates are moved (stably sorted) to the
+                           new, dynamically allocated (*Duplicates) list.
+
+  @param[out] Duplicates   If Duplicates is NULL on input, (*FileList) will be
+                           a monotonically ordered list on output, with
+                           duplicates stably sorted.
+
+                           If Duplicates is not NULL on input, (*FileList) will
+                           be a strictly monotonically oredered list on output,
+                           with duplicates separated (stably sorted) to
+                           (*Duplicates). All fields except Link will be
+                           zero-initialized in the (**Duplicates) head element.
+                           If no duplicates exist, then (*Duplicates) is set to
+                           NULL on output.
+
+  @param[in] Order         Determines the comparison operation between
+                           EFI_SHELL_FILE_INFO objects.
+
+  @retval EFI_INVALID_PARAMETER  (UINTN)Order is greater than or equal to
+                                 (UINTN)ShellSortFileListMax. Neither the
+                                 (*FileList) nor the (*Duplicates) list has
+                                 been modified.
+
+  @retval EFI_INVALID_PARAMETER  (*FileList) was NULL on input. Neither the
+                                 (*FileList) nor the (*Duplicates) list has
+                                 been modified.
+
+  @retval EFI_OUT_OF_RESOURCES   Memory allocation failed. Neither the
+                                 (*FileList) nor the (*Duplicates) list has
+                                 been modified.
+
+  @retval EFI_SUCCESS            Sorting successful, including the case when
+                                 FileList is NULL on input.
+**/
+EFI_STATUS
+EFIAPI
+ShellSortFileList (
+  IN OUT EFI_SHELL_FILE_INFO  **FileList,
+     OUT EFI_SHELL_FILE_INFO  **Duplicates OPTIONAL,
+  IN     SHELL_SORT_FILE_LIST Order
+  );
 #endif //_SHELL_COMMAND_LIB_
diff --git a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf
index a1b5601c96b6..08ca7cb78842 100644
--- a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf
+++ b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf
@@ -42,6 +42,7 @@ [LibraryClasses]
   ShellLib
   HiiLib
   HandleParsingLib
+  OrderedCollectionLib
 
 [Protocols]
   gEfiUnicodeCollation2ProtocolGuid                       ## CONSUMES
diff --git a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h
index 8ecc2f6bf5a2..0ca291e4f9bf 100644
--- a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h
+++ b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h
@@ -39,6 +39,7 @@
 #include <Library/HiiLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiLib.h>
+#include <Library/OrderedCollectionLib.h>
 
 typedef struct{
   LIST_ENTRY                  Link;
@@ -60,6 +61,24 @@ typedef struct {
   CHAR16            *Path;
 } SHELL_COMMAND_FILE_HANDLE;
 
+//
+// Collects multiple EFI_SHELL_FILE_INFO objects that share the same name.
+//
+typedef struct {
+  //
+  // A string that compares equal to either the FileName or the FullName fields
+  // of all EFI_SHELL_FILE_INFO objects on SameNameList, according to
+  // gUnicodeCollation->StriColl(). The string is not dynamically allocated;
+  // instead, it *aliases* the FileName or FullName field of the
+  // EFI_SHELL_FILE_INFO object that was first encountered with this name.
+  //
+  CONST CHAR16 *Alias;
+  //
+  // A list of EFI_SHELL_FILE_INFO objects whose FileName or FullName fields
+  // compare equal to Alias, according to gUnicodeCollation->StriColl().
+  //
+  LIST_ENTRY SameNameList;
+} SHELL_SORT_UNIQUE_NAME;
 
 #endif //_UEFI_COMMAND_LIB_INTERNAL_HEADER_
 
diff --git a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
index 345808a1eac6..b06d22592d33 100644
--- a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
+++ b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
@@ -1909,3 +1909,315 @@ CatSDumpHex (
 
   return RetVal;
 }
+
+/**
+  ORDERED_COLLECTION_USER_COMPARE function for SHELL_SORT_UNIQUE_NAME objects.
+
+  @param[in] Unique1AsVoid  The first SHELL_SORT_UNIQUE_NAME object (Unique1),
+                            passed in as a pointer-to-VOID.
+
+  @param[in] Unique2AsVoid  The second SHELL_SORT_UNIQUE_NAME object (Unique2),
+                            passed in as a pointer-to-VOID.
+
+  @retval <0  If Unique1 compares less than Unique2.
+
+  @retval  0  If Unique1 compares equal to Unique2.
+
+  @retval >0  If Unique1 compares greater than Unique2.
+**/
+STATIC
+INTN
+EFIAPI
+UniqueNameCompare (
+  IN CONST VOID *Unique1AsVoid,
+  IN CONST VOID *Unique2AsVoid
+  )
+{
+  CONST SHELL_SORT_UNIQUE_NAME *Unique1;
+  CONST SHELL_SORT_UNIQUE_NAME *Unique2;
+
+  Unique1 = Unique1AsVoid;
+  Unique2 = Unique2AsVoid;
+
+  //
+  // We need to cast away CONST for EFI_UNICODE_COLLATION_STRICOLL.
+  //
+  return gUnicodeCollation->StriColl (
+                              gUnicodeCollation,
+                              (CHAR16 *)Unique1->Alias,
+                              (CHAR16 *)Unique2->Alias
+                              );
+}
+
+/**
+  ORDERED_COLLECTION_KEY_COMPARE function for SHELL_SORT_UNIQUE_NAME objects.
+
+  @param[in] UniqueAliasAsVoid  The CHAR16 string UniqueAlias, passed in as a
+                                pointer-to-VOID.
+
+  @param[in] UniqueAsVoid       The SHELL_SORT_UNIQUE_NAME object (Unique),
+                                passed in as a pointer-to-VOID.
+
+  @retval <0  If UniqueAlias compares less than Unique->Alias.
+
+  @retval  0  If UniqueAlias compares equal to Unique->Alias.
+
+  @retval >0  If UniqueAlias compares greater than Unique->Alias.
+**/
+STATIC
+INTN
+EFIAPI
+UniqueNameAliasCompare (
+  IN CONST VOID *UniqueAliasAsVoid,
+  IN CONST VOID *UniqueAsVoid
+  )
+{
+  CONST CHAR16                 *UniqueAlias;
+  CONST SHELL_SORT_UNIQUE_NAME *Unique;
+
+  UniqueAlias = UniqueAliasAsVoid;
+  Unique      = UniqueAsVoid;
+
+  //
+  // We need to cast away CONST for EFI_UNICODE_COLLATION_STRICOLL.
+  //
+  return gUnicodeCollation->StriColl (
+                              gUnicodeCollation,
+                              (CHAR16 *)UniqueAlias,
+                              (CHAR16 *)Unique->Alias
+                              );
+}
+
+/**
+  Sort an EFI_SHELL_FILE_INFO list, optionally moving duplicates to a separate
+  list.
+
+  @param[in,out] FileList  The list of EFI_SHELL_FILE_INFO objects to sort.
+
+                           If FileList is NULL on input, then FileList is
+                           considered an empty, hence already sorted, list.
+
+                           Otherwise, if (*FileList) is NULL on input, then
+                           EFI_INVALID_PARAMETER is returned.
+
+                           Otherwise, the caller is responsible for having
+                           initialized (*FileList)->Link with
+                           InitializeListHead(). No other fields in the
+                           (**FileList) head element are accessed by this
+                           function.
+
+                           On output, (*FileList) is sorted according to Order.
+                           If Duplicates is NULL on input, then duplicate
+                           elements are preserved, sorted stably, on
+                           (*FileList). If Duplicates is not NULL on input,
+                           then duplicates are moved (stably sorted) to the
+                           new, dynamically allocated (*Duplicates) list.
+
+  @param[out] Duplicates   If Duplicates is NULL on input, (*FileList) will be
+                           a monotonically ordered list on output, with
+                           duplicates stably sorted.
+
+                           If Duplicates is not NULL on input, (*FileList) will
+                           be a strictly monotonically oredered list on output,
+                           with duplicates separated (stably sorted) to
+                           (*Duplicates). All fields except Link will be
+                           zero-initialized in the (**Duplicates) head element.
+                           If no duplicates exist, then (*Duplicates) is set to
+                           NULL on output.
+
+  @param[in] Order         Determines the comparison operation between
+                           EFI_SHELL_FILE_INFO objects.
+
+  @retval EFI_INVALID_PARAMETER  (UINTN)Order is greater than or equal to
+                                 (UINTN)ShellSortFileListMax. Neither the
+                                 (*FileList) nor the (*Duplicates) list has
+                                 been modified.
+
+  @retval EFI_INVALID_PARAMETER  (*FileList) was NULL on input. Neither the
+                                 (*FileList) nor the (*Duplicates) list has
+                                 been modified.
+
+  @retval EFI_OUT_OF_RESOURCES   Memory allocation failed. Neither the
+                                 (*FileList) nor the (*Duplicates) list has
+                                 been modified.
+
+  @retval EFI_SUCCESS            Sorting successful, including the case when
+                                 FileList is NULL on input.
+**/
+EFI_STATUS
+EFIAPI
+ShellSortFileList (
+  IN OUT EFI_SHELL_FILE_INFO  **FileList,
+     OUT EFI_SHELL_FILE_INFO  **Duplicates OPTIONAL,
+  IN     SHELL_SORT_FILE_LIST Order
+  )
+{
+  LIST_ENTRY               *FilesHead;
+  ORDERED_COLLECTION       *Sort;
+  LIST_ENTRY               *FileEntry;
+  EFI_SHELL_FILE_INFO      *FileInfo;
+  SHELL_SORT_UNIQUE_NAME   *Unique;
+  EFI_STATUS               Status;
+  EFI_SHELL_FILE_INFO      *Dupes;
+  LIST_ENTRY               *NextFileEntry;
+  CONST CHAR16             *Alias;
+  ORDERED_COLLECTION_ENTRY *SortEntry;
+  LIST_ENTRY               *TargetFileList;
+  ORDERED_COLLECTION_ENTRY *NextSortEntry;
+  VOID                     *UniqueAsVoid;
+
+  if ((UINTN)Order >= (UINTN)ShellSortFileListMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (FileList == NULL) {
+    //
+    // FileList is considered empty, hence already sorted, with no duplicates.
+    //
+    if (Duplicates != NULL) {
+      *Duplicates = NULL;
+    }
+    return EFI_SUCCESS;
+  }
+
+  if (*FileList == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  FilesHead = &(*FileList)->Link;
+
+  //
+  // Collect all the unique names.
+  //
+  Sort = OrderedCollectionInit (UniqueNameCompare, UniqueNameAliasCompare);
+  if (Sort == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  BASE_LIST_FOR_EACH (FileEntry, FilesHead) {
+    FileInfo = (EFI_SHELL_FILE_INFO *)FileEntry;
+
+    //
+    // Try to record the name of this file as a unique name.
+    //
+    Unique = AllocatePool (sizeof (*Unique));
+    if (Unique == NULL) {
+      Status = EFI_OUT_OF_RESOURCES;
+      goto UninitSort;
+    }
+    Unique->Alias = ((Order == ShellSortFileListByFileName) ?
+                     FileInfo->FileName :
+                     FileInfo->FullName);
+    InitializeListHead (&Unique->SameNameList);
+
+    Status = OrderedCollectionInsert (Sort, NULL, Unique);
+    if (EFI_ERROR (Status)) {
+      //
+      // Only two errors are possible: memory allocation failed, or this name
+      // has been encountered before. In either case, the
+      // SHELL_SORT_UNIQUE_NAME object being constructed has to be released.
+      //
+      FreePool (Unique);
+      //
+      // Memory allocation failure is fatal, while having seen the same name
+      // before is normal.
+      //
+      if (Status == EFI_OUT_OF_RESOURCES) {
+        goto UninitSort;
+      }
+      ASSERT (Status == EFI_ALREADY_STARTED);
+    }
+  }
+
+  //
+  // If separation of duplicates has been requested, allocate the list for
+  // them.
+  //
+  if (Duplicates != NULL) {
+    Dupes = AllocateZeroPool (sizeof (*Dupes));
+    if (Dupes == NULL) {
+      Status = EFI_OUT_OF_RESOURCES;
+      goto UninitSort;
+    }
+    InitializeListHead (&Dupes->Link);
+  }
+
+  //
+  // No memory allocation beyond this point; thus, no chance to fail. We can
+  // now migrate the EFI_SHELL_FILE_INFO objects from (*FileList) to Sort.
+  //
+  BASE_LIST_FOR_EACH_SAFE (FileEntry, NextFileEntry, FilesHead) {
+    FileInfo = (EFI_SHELL_FILE_INFO *)FileEntry;
+    //
+    // Look up the SHELL_SORT_UNIQUE_NAME that matches FileInfo's name.
+    //
+    Alias = ((Order == ShellSortFileListByFileName) ?
+             FileInfo->FileName :
+             FileInfo->FullName);
+    SortEntry = OrderedCollectionFind (Sort, Alias);
+    ASSERT (SortEntry != NULL);
+    Unique = OrderedCollectionUserStruct (SortEntry);
+    //
+    // Move FileInfo from (*FileList) to the end of the list of files whose
+    // names all compare identical to FileInfo's name.
+    //
+    RemoveEntryList (&FileInfo->Link);
+    InsertTailList (&Unique->SameNameList, &FileInfo->Link);
+  }
+
+  //
+  // All EFI_SHELL_FILE_INFO objects originally in (*FileList) have been
+  // distributed to Sort. Now migrate them back to (*FileList), advancing in
+  // unique name order.
+  //
+  for (SortEntry = OrderedCollectionMin (Sort);
+       SortEntry != NULL;
+       SortEntry = OrderedCollectionNext (SortEntry)) {
+    Unique = OrderedCollectionUserStruct (SortEntry);
+    //
+    // The first FileInfo encountered for each unique name goes back on
+    // (*FileList) unconditionally. Further FileInfo instances for the same
+    // unique name -- that is, duplicates -- are either returned to (*FileList)
+    // or separated, dependent on the caller's request.
+    //
+    TargetFileList = FilesHead;
+    BASE_LIST_FOR_EACH_SAFE (FileEntry, NextFileEntry, &Unique->SameNameList) {
+      RemoveEntryList (FileEntry);
+      InsertTailList (TargetFileList, FileEntry);
+      if (Duplicates != NULL) {
+        TargetFileList = &Dupes->Link;
+      }
+    }
+  }
+
+  //
+  // We're done. If separation of duplicates has been requested, output the
+  // list of duplicates -- and free that list at once, if it's empty (i.e., if
+  // no duplicates have been found).
+  //
+  if (Duplicates != NULL) {
+    if (IsListEmpty (&Dupes->Link)) {
+      FreePool (Dupes);
+      *Duplicates = NULL;
+    } else {
+      *Duplicates = Dupes;
+    }
+  }
+  Status = EFI_SUCCESS;
+
+  //
+  // Fall through.
+  //
+UninitSort:
+  for (SortEntry = OrderedCollectionMin (Sort);
+       SortEntry != NULL;
+       SortEntry = NextSortEntry) {
+    NextSortEntry = OrderedCollectionNext (SortEntry);
+    OrderedCollectionDelete (Sort, SortEntry, &UniqueAsVoid);
+    Unique = UniqueAsVoid;
+    ASSERT (IsListEmpty (&Unique->SameNameList));
+    FreePool (Unique);
+  }
+  OrderedCollectionUninit (Sort);
+
+  return Status;
+}
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 5/8] ShellPkg/Ls: sort output by FileName in non-SFO mode
  2021-01-04 15:42 [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements Laszlo Ersek
                   ` (3 preceding siblings ...)
  2021-01-04 15:42 ` [PATCH 4/8] ShellPkg/ShellCommandLib: add ShellSortFileList() Laszlo Ersek
@ 2021-01-04 15:42 ` Laszlo Ersek
  2021-01-13  3:04   ` Gao, Zhichao
  2021-01-04 15:42 ` [PATCH 6/8] ShellPkg/ShellProtocol: sort files by FullName in RemoveDupInFileList() Laszlo Ersek
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 15+ messages in thread
From: Laszlo Ersek @ 2021-01-04 15:42 UTC (permalink / raw)
  To: edk2-devel-groups-io; +Cc: Philippe Mathieu-Daudé, Ray Ni, Zhichao Gao

Sorting the LS output in non-SFO mode by FileName is best demonstrated
with two examples.

(1a) Before:

> FS2:\> dir -r apps
> Directory of: FS2:\apps\
> 01/01/1970  01:00 <DIR> r           0  .
> 12/22/2020  17:53 <DIR>         4,096  X64
> 12/22/2020  17:53 <DIR>         4,096  AARCH64
> 01/01/1970  01:00 <DIR> r           0  ..
> 12/22/2020  17:53 <DIR>         4,096  IA32
>           0 File(s)           0 bytes
>           5 Dir(s)
> Directory of: FS2:\apps\X64\
> 12/22/2020  17:52              18,752  DumpDynPcd.efi
> 12/22/2020  17:52              34,240  SmiHandlerProfileInfo.efi
> 01/01/1970  01:00 <DIR> r           0  .
> 12/22/2020  17:52              11,456  VariableInfo.efi
> 12/22/2020  17:52              26,304  MemoryProfileInfo.efi
> 12/22/2020  17:53             126,656  AcpiViewApp.efi
> 12/22/2020  17:53              38,784  Cpuid.efi
> 01/01/1970  01:00 <DIR> r           0  ..
>           6 File(s)     256,192 bytes
>           2 Dir(s)
> Directory of: FS2:\apps\AARCH64\
> 12/22/2020  17:52              32,768  DumpDynPcd.efi
> 01/01/1970  01:00 <DIR> r           0  .
> 12/22/2020  17:52              20,480  VariableInfo.efi
> 12/22/2020  17:52              40,960  MemoryProfileInfo.efi
> 12/22/2020  17:53             139,264  AcpiViewApp.efi
> 01/01/1970  01:00 <DIR> r           0  ..
>           4 File(s)     233,472 bytes
>           2 Dir(s)
> Directory of: FS2:\apps\IA32\
> 12/22/2020  17:52              17,344  DumpDynPcd.efi
> 12/22/2020  17:52              30,720  SmiHandlerProfileInfo.efi
> 01/01/1970  01:00 <DIR> r           0  .
> 12/22/2020  17:52              10,880  VariableInfo.efi
> 12/22/2020  17:52              24,192  MemoryProfileInfo.efi
> 12/22/2020  17:53             105,536  AcpiViewApp.efi
> 12/22/2020  17:53              36,096  Cpuid.efi
> 01/01/1970  01:00 <DIR> r           0  ..
>           6 File(s)     224,768 bytes
>           2 Dir(s)

(1b) After:

> FS2:\> dir -r apps
> Directory of: FS2:\apps\
> 01/01/1970  01:00 <DIR> r           0  .
> 01/01/1970  01:00 <DIR> r           0  ..
> 12/22/2020  17:53 <DIR>         4,096  AARCH64
> 12/22/2020  17:53 <DIR>         4,096  IA32
> 12/22/2020  17:53 <DIR>         4,096  X64
>           0 File(s)           0 bytes
>           5 Dir(s)
> Directory of: FS2:\apps\X64\
> 01/01/1970  01:00 <DIR> r           0  .
> 01/01/1970  01:00 <DIR> r           0  ..
> 12/22/2020  17:53             126,656  AcpiViewApp.efi
> 12/22/2020  17:53              38,784  Cpuid.efi
> 12/22/2020  17:52              18,752  DumpDynPcd.efi
> 12/22/2020  17:52              26,304  MemoryProfileInfo.efi
> 12/22/2020  17:52              34,240  SmiHandlerProfileInfo.efi
> 12/22/2020  17:52              11,456  VariableInfo.efi
>           6 File(s)     256,192 bytes
>           2 Dir(s)
> Directory of: FS2:\apps\AARCH64\
> 01/01/1970  01:00 <DIR> r           0  .
> 01/01/1970  01:00 <DIR> r           0  ..
> 12/22/2020  17:53             139,264  AcpiViewApp.efi
> 12/22/2020  17:52              32,768  DumpDynPcd.efi
> 12/22/2020  17:52              40,960  MemoryProfileInfo.efi
> 12/22/2020  17:52              20,480  VariableInfo.efi
>           4 File(s)     233,472 bytes
>           2 Dir(s)
> Directory of: FS2:\apps\IA32\
> 01/01/1970  01:00 <DIR> r           0  .
> 01/01/1970  01:00 <DIR> r           0  ..
> 12/22/2020  17:53             105,536  AcpiViewApp.efi
> 12/22/2020  17:53              36,096  Cpuid.efi
> 12/22/2020  17:52              17,344  DumpDynPcd.efi
> 12/22/2020  17:52              24,192  MemoryProfileInfo.efi
> 12/22/2020  17:52              30,720  SmiHandlerProfileInfo.efi
> 12/22/2020  17:52              10,880  VariableInfo.efi
>           6 File(s)     224,768 bytes
>           2 Dir(s)

(2a) Before:

> FS2:\> dir apps\*\*.efi
> Directory of: FS2:\apps\*\
> 12/22/2020  17:52              18,752  DumpDynPcd.efi
> 12/22/2020  17:52              34,240  SmiHandlerProfileInfo.efi
> 12/22/2020  17:52              11,456  VariableInfo.efi
> 12/22/2020  17:52              26,304  MemoryProfileInfo.efi
> 12/22/2020  17:53             126,656  AcpiViewApp.efi
> 12/22/2020  17:53              38,784  Cpuid.efi
> 12/22/2020  17:52              32,768  DumpDynPcd.efi
> 12/22/2020  17:52              20,480  VariableInfo.efi
> 12/22/2020  17:52              40,960  MemoryProfileInfo.efi
> 12/22/2020  17:53             139,264  AcpiViewApp.efi
> 12/22/2020  17:52              17,344  DumpDynPcd.efi
> 12/22/2020  17:52              30,720  SmiHandlerProfileInfo.efi
> 12/22/2020  17:52              10,880  VariableInfo.efi
> 12/22/2020  17:52              24,192  MemoryProfileInfo.efi
> 12/22/2020  17:53             105,536  AcpiViewApp.efi
> 12/22/2020  17:53              36,096  Cpuid.efi
>          16 File(s)     714,432 bytes
>           0 Dir(s)

(2b) After:

> FS2:\> dir apps\*\*.efi
> Directory of: FS2:\apps\*\
> 12/22/2020  17:53             126,656  AcpiViewApp.efi
> 12/22/2020  17:53             139,264  AcpiViewApp.efi
> 12/22/2020  17:53             105,536  AcpiViewApp.efi
> 12/22/2020  17:53              38,784  Cpuid.efi
> 12/22/2020  17:53              36,096  Cpuid.efi
> 12/22/2020  17:52              18,752  DumpDynPcd.efi
> 12/22/2020  17:52              32,768  DumpDynPcd.efi
> 12/22/2020  17:52              17,344  DumpDynPcd.efi
> 12/22/2020  17:52              26,304  MemoryProfileInfo.efi
> 12/22/2020  17:52              40,960  MemoryProfileInfo.efi
> 12/22/2020  17:52              24,192  MemoryProfileInfo.efi
> 12/22/2020  17:52              34,240  SmiHandlerProfileInfo.efi
> 12/22/2020  17:52              30,720  SmiHandlerProfileInfo.efi
> 12/22/2020  17:52              11,456  VariableInfo.efi
> 12/22/2020  17:52              20,480  VariableInfo.efi
> 12/22/2020  17:52              10,880  VariableInfo.efi
>          16 File(s)     714,432 bytes
>           0 Dir(s)

(In example (2), note that the sorting is stable; that is, whatever order
is established between identical FileNames by ShellOpenFileMetaArg(), it
is preserved by ShellSortFileList().)

Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Zhichao Gao <zhichao.gao@intel.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3151
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c
index da2b1acab47c..8b97926d7f47 100644
--- a/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c
+++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c
@@ -489,6 +489,20 @@ PrintLsOutput(
       PrintSfoVolumeInfoTableEntry(ListHead);
     }
 
+    if (!Sfo) {
+      //
+      // Sort the file list by FileName, stably.
+      //
+      // If the call below fails, then the EFI_SHELL_FILE_INFO list anchored to
+      // ListHead will not be changed in any way.
+      //
+      ShellSortFileList (
+        &ListHead,
+        NULL,                       // Duplicates
+        ShellSortFileListByFileName
+        );
+    }
+
     for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link), LongestPath = 0
         ; !IsNull(&ListHead->Link, &Node->Link)
         ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 6/8] ShellPkg/ShellProtocol: sort files by FullName in RemoveDupInFileList()
  2021-01-04 15:42 [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements Laszlo Ersek
                   ` (4 preceding siblings ...)
  2021-01-04 15:42 ` [PATCH 5/8] ShellPkg/Ls: sort output by FileName in non-SFO mode Laszlo Ersek
@ 2021-01-04 15:42 ` Laszlo Ersek
  2021-01-13  3:04   ` Gao, Zhichao
  2021-01-04 15:42 ` [PATCH 7/8] OvmfPkg: disable list length checks in NOOPT and DEBUG builds Laszlo Ersek
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 15+ messages in thread
From: Laszlo Ersek @ 2021-01-04 15:42 UTC (permalink / raw)
  To: edk2-devel-groups-io; +Cc: Philippe Mathieu-Daudé, Ray Ni, Zhichao Gao

The current implementation of EfiShellRemoveDupInFileList():
- has quadratic time complexity, as a disadvantage, and
- needs no dynamic memory, as an advantage.

Because the UEFI Shell Spec requires
EFI_SHELL_PROTOCOL.RemoveDupInFileList() to succeed at all times, keep the
current method as a fallback (it cannot fail due to needing no dynamic
memory).

However, as a higher priority option, call the new ShellSortFileList()
function at first, separating out and releasing duplicates.
(ShellSortFileList() can fail due to EFI_OUT_OF_RESOURCES.)

Beyond improving the runtime of EfiShellRemoveDupInFileList(), this change
has the extremely desirable effect that the ShellOpenFileMetaArg()
function in the ShellPkg/Library/UefiShellLib instance will produce file
lists that are sorted by FullName.

Consequently, when used with wildcards, the ATTRIB, CP, FOR, LOAD,
LOADPCIROM, LS, MV, RM, TOUCH, TYPE commands will process files in
FullName order. (LS in recursive mode uses wildcards internally.)

Before:

> FS2:\> dir -r -sfo apps
> [...]
> FileInfo,"FS2:\apps\"
> FileInfo,"FS2:\apps\X64"
> FileInfo,"FS2:\apps\AARCH64"
> FileInfo,"FS2:\"
> FileInfo,"FS2:\apps\IA32"
> FileInfo,"FS2:\apps\X64\DumpDynPcd.efi"
> FileInfo,"FS2:\apps\X64\SmiHandlerProfileInfo.efi"
> FileInfo,"FS2:\apps\X64\"
> FileInfo,"FS2:\apps\X64\VariableInfo.efi"
> FileInfo,"FS2:\apps\X64\MemoryProfileInfo.efi"
> FileInfo,"FS2:\apps\X64\AcpiViewApp.efi"
> FileInfo,"FS2:\apps\X64\Cpuid.efi"
> FileInfo,"FS2:\apps\"
> FileInfo,"FS2:\apps\AARCH64\DumpDynPcd.efi"
> FileInfo,"FS2:\apps\AARCH64\"
> FileInfo,"FS2:\apps\AARCH64\VariableInfo.efi"
> FileInfo,"FS2:\apps\AARCH64\MemoryProfileInfo.efi"
> FileInfo,"FS2:\apps\AARCH64\AcpiViewApp.efi"
> FileInfo,"FS2:\apps\"
> FileInfo,"FS2:\apps\IA32\DumpDynPcd.efi"
> FileInfo,"FS2:\apps\IA32\SmiHandlerProfileInfo.efi"
> FileInfo,"FS2:\apps\IA32\"
> FileInfo,"FS2:\apps\IA32\VariableInfo.efi"
> FileInfo,"FS2:\apps\IA32\MemoryProfileInfo.efi"
> FileInfo,"FS2:\apps\IA32\AcpiViewApp.efi"
> FileInfo,"FS2:\apps\IA32\Cpuid.efi"
> FileInfo,"FS2:\apps\"

After:

> FS2:\> dir -r -sfo apps
> [...]
> FileInfo,"FS2:\"
> FileInfo,"FS2:\apps\"
> FileInfo,"FS2:\apps\AARCH64"
> FileInfo,"FS2:\apps\IA32"
> FileInfo,"FS2:\apps\X64"
> FileInfo,"FS2:\apps\"
> FileInfo,"FS2:\apps\AARCH64\"
> FileInfo,"FS2:\apps\AARCH64\AcpiViewApp.efi"
> FileInfo,"FS2:\apps\AARCH64\DumpDynPcd.efi"
> FileInfo,"FS2:\apps\AARCH64\MemoryProfileInfo.efi"
> FileInfo,"FS2:\apps\AARCH64\VariableInfo.efi"
> FileInfo,"FS2:\apps\"
> FileInfo,"FS2:\apps\IA32\"
> FileInfo,"FS2:\apps\IA32\AcpiViewApp.efi"
> FileInfo,"FS2:\apps\IA32\Cpuid.efi"
> FileInfo,"FS2:\apps\IA32\DumpDynPcd.efi"
> FileInfo,"FS2:\apps\IA32\MemoryProfileInfo.efi"
> FileInfo,"FS2:\apps\IA32\SmiHandlerProfileInfo.efi"
> FileInfo,"FS2:\apps\IA32\VariableInfo.efi"
> FileInfo,"FS2:\apps\"
> FileInfo,"FS2:\apps\X64\"
> FileInfo,"FS2:\apps\X64\AcpiViewApp.efi"
> FileInfo,"FS2:\apps\X64\Cpuid.efi"
> FileInfo,"FS2:\apps\X64\DumpDynPcd.efi"
> FileInfo,"FS2:\apps\X64\MemoryProfileInfo.efi"
> FileInfo,"FS2:\apps\X64\SmiHandlerProfileInfo.efi"
> FileInfo,"FS2:\apps\X64\VariableInfo.efi"

Regarding LS in non-SFO mode, the stability of ShellSortFileList() shows.
The ShellSortFileList() call added to LS in the previous patch re-sorts
the output of ShellOpenFileMetaArg(); and so this patch improves the
ordering between identical FileNames:

Before:

> FS2:\> dir -r apps
> Directory of: FS2:\apps\
> 01/01/1970  01:00 <DIR> r           0  .
> 01/01/1970  01:00 <DIR> r           0  ..
> 12/22/2020  17:53 <DIR>         4,096  AARCH64
> 12/22/2020  17:53 <DIR>         4,096  IA32
> 12/22/2020  17:53 <DIR>         4,096  X64
>           0 File(s)           0 bytes
>           5 Dir(s)
> Directory of: FS2:\apps\X64\
> 01/01/1970  01:00 <DIR> r           0  .
> 01/01/1970  01:00 <DIR> r           0  ..
> 12/22/2020  17:53             126,656  AcpiViewApp.efi
> 12/22/2020  17:53              38,784  Cpuid.efi
> 12/22/2020  17:52              18,752  DumpDynPcd.efi
> 12/22/2020  17:52              26,304  MemoryProfileInfo.efi
> 12/22/2020  17:52              34,240  SmiHandlerProfileInfo.efi
> 12/22/2020  17:52              11,456  VariableInfo.efi
>           6 File(s)     256,192 bytes
>           2 Dir(s)
> Directory of: FS2:\apps\AARCH64\
> 01/01/1970  01:00 <DIR> r           0  .
> 01/01/1970  01:00 <DIR> r           0  ..
> 12/22/2020  17:53             139,264  AcpiViewApp.efi
> 12/22/2020  17:52              32,768  DumpDynPcd.efi
> 12/22/2020  17:52              40,960  MemoryProfileInfo.efi
> 12/22/2020  17:52              20,480  VariableInfo.efi
>           4 File(s)     233,472 bytes
>           2 Dir(s)
> Directory of: FS2:\apps\IA32\
> 01/01/1970  01:00 <DIR> r           0  .
> 01/01/1970  01:00 <DIR> r           0  ..
> 12/22/2020  17:53             105,536  AcpiViewApp.efi
> 12/22/2020  17:53              36,096  Cpuid.efi
> 12/22/2020  17:52              17,344  DumpDynPcd.efi
> 12/22/2020  17:52              24,192  MemoryProfileInfo.efi
> 12/22/2020  17:52              30,720  SmiHandlerProfileInfo.efi
> 12/22/2020  17:52              10,880  VariableInfo.efi
>           6 File(s)     224,768 bytes
>           2 Dir(s)
>
> FS2:\> dir apps\*\*.efi
> Directory of: FS2:\apps\*\
> 12/22/2020  17:53             126,656  AcpiViewApp.efi
> 12/22/2020  17:53             139,264  AcpiViewApp.efi
> 12/22/2020  17:53             105,536  AcpiViewApp.efi
> 12/22/2020  17:53              38,784  Cpuid.efi
> 12/22/2020  17:53              36,096  Cpuid.efi
> 12/22/2020  17:52              18,752  DumpDynPcd.efi
> 12/22/2020  17:52              32,768  DumpDynPcd.efi
> 12/22/2020  17:52              17,344  DumpDynPcd.efi
> 12/22/2020  17:52              26,304  MemoryProfileInfo.efi
> 12/22/2020  17:52              40,960  MemoryProfileInfo.efi
> 12/22/2020  17:52              24,192  MemoryProfileInfo.efi
> 12/22/2020  17:52              34,240  SmiHandlerProfileInfo.efi
> 12/22/2020  17:52              30,720  SmiHandlerProfileInfo.efi
> 12/22/2020  17:52              11,456  VariableInfo.efi
> 12/22/2020  17:52              20,480  VariableInfo.efi
> 12/22/2020  17:52              10,880  VariableInfo.efi
>          16 File(s)     714,432 bytes
>           0 Dir(s)

After:

> FS2:\> dir -r apps
> Directory of: FS2:\apps\
> 01/01/1970  01:00 <DIR> r           0  .
> 01/01/1970  01:00 <DIR> r           0  ..
> 12/22/2020  17:53 <DIR>         4,096  AARCH64
> 12/22/2020  17:53 <DIR>         4,096  IA32
> 12/22/2020  17:53 <DIR>         4,096  X64
>           0 File(s)           0 bytes
>           5 Dir(s)
> Directory of: FS2:\apps\AARCH64\
> 01/01/1970  01:00 <DIR> r           0  .
> 01/01/1970  01:00 <DIR> r           0  ..
> 12/22/2020  17:53             139,264  AcpiViewApp.efi
> 12/22/2020  17:52              32,768  DumpDynPcd.efi
> 12/22/2020  17:52              40,960  MemoryProfileInfo.efi
> 12/22/2020  17:52              20,480  VariableInfo.efi
>           4 File(s)     233,472 bytes
>           2 Dir(s)
> Directory of: FS2:\apps\IA32\
> 01/01/1970  01:00 <DIR> r           0  .
> 01/01/1970  01:00 <DIR> r           0  ..
> 12/22/2020  17:53             105,536  AcpiViewApp.efi
> 12/22/2020  17:53              36,096  Cpuid.efi
> 12/22/2020  17:52              17,344  DumpDynPcd.efi
> 12/22/2020  17:52              24,192  MemoryProfileInfo.efi
> 12/22/2020  17:52              30,720  SmiHandlerProfileInfo.efi
> 12/22/2020  17:52              10,880  VariableInfo.efi
>           6 File(s)     224,768 bytes
>           2 Dir(s)
> Directory of: FS2:\apps\X64\
> 01/01/1970  01:00 <DIR> r           0  .
> 01/01/1970  01:00 <DIR> r           0  ..
> 12/22/2020  17:53             126,656  AcpiViewApp.efi
> 12/22/2020  17:53              38,784  Cpuid.efi
> 12/22/2020  17:52              18,752  DumpDynPcd.efi
> 12/22/2020  17:52              26,304  MemoryProfileInfo.efi
> 12/22/2020  17:52              34,240  SmiHandlerProfileInfo.efi
> 12/22/2020  17:52              11,456  VariableInfo.efi
>           6 File(s)     256,192 bytes
>           2 Dir(s)
>
> FS2:\> dir apps\*\*.efi
> Directory of: FS2:\apps\*\
> 12/22/2020  17:53             139,264  AcpiViewApp.efi
> 12/22/2020  17:53             105,536  AcpiViewApp.efi
> 12/22/2020  17:53             126,656  AcpiViewApp.efi
> 12/22/2020  17:53              36,096  Cpuid.efi
> 12/22/2020  17:53              38,784  Cpuid.efi
> 12/22/2020  17:52              32,768  DumpDynPcd.efi
> 12/22/2020  17:52              17,344  DumpDynPcd.efi
> 12/22/2020  17:52              18,752  DumpDynPcd.efi
> 12/22/2020  17:52              40,960  MemoryProfileInfo.efi
> 12/22/2020  17:52              24,192  MemoryProfileInfo.efi
> 12/22/2020  17:52              26,304  MemoryProfileInfo.efi
> 12/22/2020  17:52              30,720  SmiHandlerProfileInfo.efi
> 12/22/2020  17:52              34,240  SmiHandlerProfileInfo.efi
> 12/22/2020  17:52              20,480  VariableInfo.efi
> 12/22/2020  17:52              10,880  VariableInfo.efi
> 12/22/2020  17:52              11,456  VariableInfo.efi
>          16 File(s)     714,432 bytes
>           0 Dir(s)

Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Zhichao Gao <zhichao.gao@intel.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3151
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 ShellPkg/Application/Shell/ShellProtocol.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/ShellPkg/Application/Shell/ShellProtocol.c b/ShellPkg/Application/Shell/ShellProtocol.c
index 4e639fe35e4f..e79c39058b3e 100644
--- a/ShellPkg/Application/Shell/ShellProtocol.c
+++ b/ShellPkg/Application/Shell/ShellProtocol.c
@@ -1855,6 +1855,8 @@ EfiShellRemoveDupInFileList(
   IN EFI_SHELL_FILE_INFO **FileList
   )
 {
+  EFI_STATUS          Status;
+  EFI_SHELL_FILE_INFO *Duplicates;
   EFI_SHELL_FILE_INFO *ShellFileListItem;
   EFI_SHELL_FILE_INFO *ShellFileListItem2;
   EFI_SHELL_FILE_INFO *TempNode;
@@ -1862,6 +1864,20 @@ EfiShellRemoveDupInFileList(
   if (FileList == NULL || *FileList == NULL) {
     return (EFI_INVALID_PARAMETER);
   }
+
+  Status = ShellSortFileList (
+             FileList,
+             &Duplicates,
+             ShellSortFileListByFullName
+             );
+  if (!EFI_ERROR (Status)) {
+    EfiShellFreeFileList (&Duplicates);
+    return EFI_SUCCESS;
+  }
+  //
+  // Fall back to the slow method that needs no extra memory, and so cannot
+  // fail.
+  //
   for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link)
       ; !IsNull(&(*FileList)->Link, &ShellFileListItem->Link)
       ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem->Link)
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 7/8] OvmfPkg: disable list length checks in NOOPT and DEBUG builds
  2021-01-04 15:42 [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements Laszlo Ersek
                   ` (5 preceding siblings ...)
  2021-01-04 15:42 ` [PATCH 6/8] ShellPkg/ShellProtocol: sort files by FullName in RemoveDupInFileList() Laszlo Ersek
@ 2021-01-04 15:42 ` Laszlo Ersek
  2021-01-04 15:42 ` [PATCH 8/8] ArmVirtPkg: " Laszlo Ersek
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Laszlo Ersek @ 2021-01-04 15:42 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Anthony Perard, Ard Biesheuvel, Jordan Justen, Julien Grall,
	Leif Lindholm, Peter Grehan, Philippe Mathieu-Daudé,
	Rebecca Cran, Sami Mujawar

In NOOPT and DEBUG builds, if "PcdMaximumLinkedListLength" is nonzero,
then several LIST_ENTRY *node* APIs in BaseLib compare the *full* list
length against the PCD.

This turns the time complexity of node-level APIs from constant to linear,
and that of full-list manipulations from linear to quadratic.

As an example, consider the EFI_SHELL_FILE_INFO list, which is a data
structure that's widely used in the UEFI shell. I randomly extracted 5000
files from "/usr/include" on my laptop, spanning 1095 subdirectories out
of 1538, and then ran "DIR -R" in the UEFI shell on this tree. These are
the wall-clock times:

           PcdMaximumLinkedListLength  PcdMaximumLinkedListLength
           =1,000,000                  =0
           --------------------------  ---------------------------
FAT        4 min 31 s                        18 s
virtio-fs  5 min 13 s                  1 min 33 s

Checking list lengths against an arbitrary maximum (default: 1,000,000)
seems useless even in NOOPT and DEBUG builds, while the cost is
significant; so set the PCD to 0.

Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Julien Grall <julien@xen.org>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Peter Grehan <grehan@freebsd.org>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Cc: Rebecca Cran <rebecca@bsdio.com>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3152
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/AmdSev/AmdSevX64.dsc | 1 +
 OvmfPkg/Bhyve/BhyveX64.dsc   | 1 +
 OvmfPkg/OvmfPkgIa32.dsc      | 1 +
 OvmfPkg/OvmfPkgIa32X64.dsc   | 1 +
 OvmfPkg/OvmfPkgX64.dsc       | 1 +
 OvmfPkg/OvmfXen.dsc          | 1 +
 6 files changed, 6 insertions(+)

diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
index bb7697eb324b..c1b3d27885b0 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -437,6 +437,7 @@ [PcdsFixedAtBuild]
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1
   gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
   gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
+  gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|0
 !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
diff --git a/OvmfPkg/Bhyve/BhyveX64.dsc b/OvmfPkg/Bhyve/BhyveX64.dsc
index b93fe30ae4e0..acf8f17ade12 100644
--- a/OvmfPkg/Bhyve/BhyveX64.dsc
+++ b/OvmfPkg/Bhyve/BhyveX64.dsc
@@ -429,6 +429,7 @@ [PcdsFixedAtBuild]
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1
   gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
   gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
+  gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|0
 !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index cd0acf021459..7cce8944e496 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -476,6 +476,7 @@ [PcdsFixedAtBuild]
   gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
 !endif
   gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
+  gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|0
 !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 3bf493bdb08f..8d21dc0ed7b6 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -480,6 +480,7 @@ [PcdsFixedAtBuild]
   gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
 !endif
   gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
+  gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|0
 !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index cebdbc9faabe..103af2fea7a5 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -480,6 +480,7 @@ [PcdsFixedAtBuild]
   gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
 !endif
   gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
+  gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|0
 !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index 12b7a87ee877..c15835d9d23c 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -356,6 +356,7 @@ [PcdsFixedAtBuild]
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1
   gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
   gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x10
+  gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|0
 !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
-- 
2.19.1.3.g30247aa5d201



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 8/8] ArmVirtPkg: disable list length checks in NOOPT and DEBUG builds
  2021-01-04 15:42 [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements Laszlo Ersek
                   ` (6 preceding siblings ...)
  2021-01-04 15:42 ` [PATCH 7/8] OvmfPkg: disable list length checks in NOOPT and DEBUG builds Laszlo Ersek
@ 2021-01-04 15:42 ` Laszlo Ersek
  2021-01-04 16:12 ` [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements Ard Biesheuvel
  2021-01-08  8:34 ` [edk2-devel] " Laszlo Ersek
  9 siblings, 0 replies; 15+ messages in thread
From: Laszlo Ersek @ 2021-01-04 15:42 UTC (permalink / raw)
  To: edk2-devel-groups-io
  Cc: Ard Biesheuvel, Julien Grall, Leif Lindholm,
	Philippe Mathieu-Daudé, Sami Mujawar

In NOOPT and DEBUG builds, if "PcdMaximumLinkedListLength" is nonzero,
then several LIST_ENTRY *node* APIs in BaseLib compare the *full* list
length against the PCD.

This turns the time complexity of node-level APIs from constant to linear,
and that of full-list manipulations from linear to quadratic.

(See some example OVMF numbers in the previous patch.)

Checking list lengths against an arbitrary maximum -- default value, and
current ArmVirtPkg setting: 1,000,000 -- seems useless even in NOOPT and
DEBUG builds, while the cost is significant; so set the PCD to 0.

Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Cc: Julien Grall <julien@xen.org>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3152
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 ArmVirtPkg/ArmVirt.dsc.inc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ArmVirtPkg/ArmVirt.dsc.inc b/ArmVirtPkg/ArmVirt.dsc.inc
index 9ec92930472d..d9abadbe708c 100644
--- a/ArmVirtPkg/ArmVirt.dsc.inc
+++ b/ArmVirtPkg/ArmVirt.dsc.inc
@@ -290,7 +290,7 @@ [PcdsFeatureFlag.AARCH64]
 [PcdsFixedAtBuild.common]
   gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength|1000000
   gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength|1000000
-  gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|1000000
+  gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|0
   gEfiMdePkgTokenSpaceGuid.PcdSpinLockTimeout|10000000
   gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|320
 
-- 
2.19.1.3.g30247aa5d201


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements
  2021-01-04 15:42 [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements Laszlo Ersek
                   ` (7 preceding siblings ...)
  2021-01-04 15:42 ` [PATCH 8/8] ArmVirtPkg: " Laszlo Ersek
@ 2021-01-04 16:12 ` Ard Biesheuvel
  2021-01-08  8:34 ` [edk2-devel] " Laszlo Ersek
  9 siblings, 0 replies; 15+ messages in thread
From: Ard Biesheuvel @ 2021-01-04 16:12 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel-groups-io
  Cc: Anthony Perard, Jordan Justen, Julien Grall, Leif Lindholm,
	Peter Grehan, Philippe Mathieu-Daudé, Ray Ni, Rebecca Cran,
	Sami Mujawar, Zhichao Gao

On 1/4/21 4:42 PM, Laszlo Ersek wrote:
> Repo:   https://pagure.io/lersek/edk2.git
> Branch: shell_usability_improvements
> 
> This series addresses various usability shortcomings that I've recently
> run into, while working with large directory trees on FAT and/or
> virtio-fs in the UEFI shell.
> 
> * add file buffering to the COMP command
>   https://bugzilla.tianocore.org/show_bug.cgi?id=3123
> 
> * ArmVirtPkg, OvmfPkg: set PcdShellFileOperationSize to 0x20000
>   https://bugzilla.tianocore.org/show_bug.cgi?id=3125
> 
> * Shell: pathname / filename sorting
>   https://bugzilla.tianocore.org/show_bug.cgi?id=3151
> 
> * ArmVirtPkg, OvmfPkg: disable list length checks in NOOPT and DEBUG
>   builds
>   https://bugzilla.tianocore.org/show_bug.cgi?id=3152
> 
> Beyond testing the series locally, I've also heavily subjected it to
> local CI runs, including ECC (relevant for ShellPkg).
> 
> Cc: Anthony Perard <anthony.perard@citrix.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Julien Grall <julien@xen.org>
> Cc: Leif Lindholm <leif@nuviainc.com>
> Cc: Peter Grehan <grehan@freebsd.org>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Rebecca Cran <rebecca@bsdio.com>
> Cc: Sami Mujawar <sami.mujawar@arm.com>
> Cc: Zhichao Gao <zhichao.gao@intel.com>
> 
> Thanks
> Laszlo
> 
> Laszlo Ersek (8):
>   ShellPkg/Comp: add file buffering
>   OvmfPkg: raise PcdShellFileOperationSize to 128KB
>   ArmVirtPkg: raise PcdShellFileOperationSize to 128KB
>   ShellPkg/ShellCommandLib: add ShellSortFileList()
>   ShellPkg/Ls: sort output by FileName in non-SFO mode
>   ShellPkg/ShellProtocol: sort files by FullName in
>     RemoveDupInFileList()
>   OvmfPkg: disable list length checks in NOOPT and DEBUG builds
>   ArmVirtPkg: disable list length checks in NOOPT and DEBUG builds
> 

Where needed,

Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>

-- 
Ard.

>  ArmVirtPkg/ArmVirt.dsc.inc                                                 |   2 +-
>  ArmVirtPkg/ArmVirtQemu.dsc                                                 |   1 +
>  ArmVirtPkg/ArmVirtQemuKernel.dsc                                           |   1 +
>  OvmfPkg/AmdSev/AmdSevX64.dsc                                               |   1 +
>  OvmfPkg/Bhyve/BhyveX64.dsc                                                 |   1 +
>  OvmfPkg/OvmfPkgIa32.dsc                                                    |   3 +
>  OvmfPkg/OvmfPkgIa32X64.dsc                                                 |   3 +
>  OvmfPkg/OvmfPkgX64.dsc                                                     |   3 +
>  OvmfPkg/OvmfXen.dsc                                                        |   1 +
>  ShellPkg/Application/Shell/ShellProtocol.c                                 |  16 +
>  ShellPkg/Include/Library/ShellCommandLib.h                                 |  81 +++++
>  ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c                 | 312 ++++++++++++++++++++
>  ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h                 |  19 ++
>  ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf               |   1 +
>  ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c                         | 127 +++++++-
>  ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf |   1 +
>  ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c                           |  14 +
>  ShellPkg/ShellPkg.dsc                                                      |   1 +
>  18 files changed, 584 insertions(+), 4 deletions(-)
> 
> 
> base-commit: 0785c619a58a450091d2bf6755591012533b80b8
> 


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements
  2021-01-04 15:42 [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements Laszlo Ersek
                   ` (8 preceding siblings ...)
  2021-01-04 16:12 ` [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements Ard Biesheuvel
@ 2021-01-08  8:34 ` Laszlo Ersek
  9 siblings, 0 replies; 15+ messages in thread
From: Laszlo Ersek @ 2021-01-08  8:34 UTC (permalink / raw)
  To: edk2-devel-groups-io, Ray Ni, Zhichao Gao
  Cc: Anthony Perard, Ard Biesheuvel, Jordan Justen, Julien Grall,
	Leif Lindholm, Peter Grehan, Philippe Mathieu-Daudé,
	Rebecca Cran, Sami Mujawar

Zhichao, Ray,

can you please start reviewing the ShellPkg patches in this series? (#1,
#4, #5, #6.)

Thanks,
Laszlo

On 01/04/21 16:42, Laszlo Ersek wrote:
> Repo:   https://pagure.io/lersek/edk2.git
> Branch: shell_usability_improvements
> 
> This series addresses various usability shortcomings that I've recently
> run into, while working with large directory trees on FAT and/or
> virtio-fs in the UEFI shell.
> 
> * add file buffering to the COMP command
>   https://bugzilla.tianocore.org/show_bug.cgi?id=3123
> 
> * ArmVirtPkg, OvmfPkg: set PcdShellFileOperationSize to 0x20000
>   https://bugzilla.tianocore.org/show_bug.cgi?id=3125
> 
> * Shell: pathname / filename sorting
>   https://bugzilla.tianocore.org/show_bug.cgi?id=3151
> 
> * ArmVirtPkg, OvmfPkg: disable list length checks in NOOPT and DEBUG
>   builds
>   https://bugzilla.tianocore.org/show_bug.cgi?id=3152
> 
> Beyond testing the series locally, I've also heavily subjected it to
> local CI runs, including ECC (relevant for ShellPkg).
> 
> Cc: Anthony Perard <anthony.perard@citrix.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Julien Grall <julien@xen.org>
> Cc: Leif Lindholm <leif@nuviainc.com>
> Cc: Peter Grehan <grehan@freebsd.org>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Rebecca Cran <rebecca@bsdio.com>
> Cc: Sami Mujawar <sami.mujawar@arm.com>
> Cc: Zhichao Gao <zhichao.gao@intel.com>
> 
> Thanks
> Laszlo
> 
> Laszlo Ersek (8):
>   ShellPkg/Comp: add file buffering
>   OvmfPkg: raise PcdShellFileOperationSize to 128KB
>   ArmVirtPkg: raise PcdShellFileOperationSize to 128KB
>   ShellPkg/ShellCommandLib: add ShellSortFileList()
>   ShellPkg/Ls: sort output by FileName in non-SFO mode
>   ShellPkg/ShellProtocol: sort files by FullName in
>     RemoveDupInFileList()
>   OvmfPkg: disable list length checks in NOOPT and DEBUG builds
>   ArmVirtPkg: disable list length checks in NOOPT and DEBUG builds
> 
>  ArmVirtPkg/ArmVirt.dsc.inc                                                 |   2 +-
>  ArmVirtPkg/ArmVirtQemu.dsc                                                 |   1 +
>  ArmVirtPkg/ArmVirtQemuKernel.dsc                                           |   1 +
>  OvmfPkg/AmdSev/AmdSevX64.dsc                                               |   1 +
>  OvmfPkg/Bhyve/BhyveX64.dsc                                                 |   1 +
>  OvmfPkg/OvmfPkgIa32.dsc                                                    |   3 +
>  OvmfPkg/OvmfPkgIa32X64.dsc                                                 |   3 +
>  OvmfPkg/OvmfPkgX64.dsc                                                     |   3 +
>  OvmfPkg/OvmfXen.dsc                                                        |   1 +
>  ShellPkg/Application/Shell/ShellProtocol.c                                 |  16 +
>  ShellPkg/Include/Library/ShellCommandLib.h                                 |  81 +++++
>  ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c                 | 312 ++++++++++++++++++++
>  ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h                 |  19 ++
>  ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf               |   1 +
>  ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c                         | 127 +++++++-
>  ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf |   1 +
>  ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c                           |  14 +
>  ShellPkg/ShellPkg.dsc                                                      |   1 +
>  18 files changed, 584 insertions(+), 4 deletions(-)
> 
> 
> base-commit: 0785c619a58a450091d2bf6755591012533b80b8
> 


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/8] ShellPkg/Comp: add file buffering
  2021-01-04 15:42 ` [PATCH 1/8] ShellPkg/Comp: add file buffering Laszlo Ersek
@ 2021-01-11  1:24   ` Gao, Zhichao
  0 siblings, 0 replies; 15+ messages in thread
From: Gao, Zhichao @ 2021-01-11  1:24 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel-groups-io; +Cc: Philippe Mathieu-Daudé, Ni, Ray

Reviewed-by: Zhichao Gao <zhichao.gao@intel.com>

Thanks,
Zhichao

> -----Original Message-----
> From: Laszlo Ersek <lersek@redhat.com>
> Sent: Monday, January 4, 2021 11:42 PM
> To: edk2-devel-groups-io <devel@edk2.groups.io>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>; Ni, Ray <ray.ni@intel.com>;
> Gao, Zhichao <zhichao.gao@intel.com>
> Subject: [PATCH 1/8] ShellPkg/Comp: add file buffering
> 
> The COMP shell command compares two files byte for byte. In order to retrieve
> the bytes to compare, it currently invokes
> gEfiShellProtocol->ReadFile() on both files, using a single-byte buffer
> every time. This is very inefficient; the underlying
> EFI_FILE_PROTOCOL.Read() function may be costly.
> 
> Read both file operands in chunks of "PcdShellFileOperationSize" bytes.
> Draw bytes for comparison from the internal read-ahead buffers.
> 
> Some ad-hoc measurements on my laptop, using OVMF, and the 4KB default of
> "PcdShellFileOperationSize":
> 
> - When comparing two identical 1MB files that are served by EnhancedFatDxe
>   on top of VirtioScsiDxe, this patch brings no noticeable improvement;
>   the comparison completes in <1s both before and after.
> 
> - When comparing two identical 1MB files served by VirtioFsDxe, the
>   comparison time improves from 2 minutes 25 seconds to <1s.
> 
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Zhichao Gao <zhichao.gao@intel.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3123
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
> 
> ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.in
> f |   1 +
>  ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c                         | 127
> +++++++++++++++++++-
>  2 files changed, 125 insertions(+), 3 deletions(-)
> 
> diff --git
> a/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib
> .inf
> b/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib
> .inf
> index ed94477a0642..74ad5facf6b1 100644
> ---
> a/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib
> .inf
> +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1Command
> +++ sLib.inf
> @@ -113,6 +113,7 @@ [LibraryClasses]
>    BcfgCommandLib
> 
>  [Pcd]
> +  gEfiShellPkgTokenSpaceGuid.PcdShellFileOperationSize        ## CONSUMES
>    gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask              ## CONSUMES
> 
>  [Protocols]
> diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c
> b/ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c
> index 0a5d13f01c7b..0df0b3149369 100644
> --- a/ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c
> +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/Comp.c
> @@ -21,6 +21,16 @@ typedef enum {
>    InPrevDiffPoint
>  } READ_STATUS;
> 
> +//
> +// Buffer type, for reading both file operands in chunks.
> +//
> +typedef struct {
> +  UINT8 *Data;     // dynamically allocated buffer
> +  UINTN Allocated; // the allocated size of Data
> +  UINTN Next;      // next position in Data to fetch a byte at
> +  UINTN Left;      // number of bytes left in Data for fetching at Next
> +} FILE_BUFFER;
> +
>  /**
>    Function to print differnt point data.
> 
> @@ -76,6 +86,106 @@ PrintDifferentPoint(
>    ShellPrintEx (-1, -1, L"*\r\n");
>  }
> 
> +/**
> +  Initialize a FILE_BUFFER.
> +
> +  @param[out] FileBuffer  The FILE_BUFFER to initialize. On return, the caller
> +                          is responsible for checking FileBuffer->Data: if
> +                          FileBuffer->Data is NULL on output, then memory
> +                          allocation failed.
> +**/
> +STATIC
> +VOID
> +FileBufferInit (
> +  OUT FILE_BUFFER *FileBuffer
> +  )
> +{
> +  FileBuffer->Allocated = PcdGet32 (PcdShellFileOperationSize);
> +  FileBuffer->Data      = AllocatePool (FileBuffer->Allocated);
> +  FileBuffer->Left      = 0;
> +}
> +
> +/**
> +  Uninitialize a FILE_BUFFER.
> +
> +  @param[in,out] FileBuffer  The FILE_BUFFER to uninitialize. The caller is
> +                             responsible for making sure FileBuffer was first
> +                             initialized with FileBufferInit(), successfully or
> +                             unsuccessfully.
> +**/
> +STATIC
> +VOID
> +FileBufferUninit (
> +  IN OUT FILE_BUFFER *FileBuffer
> +  )
> +{
> +  SHELL_FREE_NON_NULL (FileBuffer->Data); }
> +
> +/**
> +  Read a byte from a SHELL_FILE_HANDLE, buffered with a FILE_BUFFER.
> +
> +  @param[in] FileHandle      The SHELL_FILE_HANDLE to replenish FileBuffer
> +                             from, if needed.
> +
> +  @param[in,out] FileBuffer  The FILE_BUFFER to read a byte from. If FileBuffer
> +                             is empty on entry, then FileBuffer is refilled
> +                             from FileHandle, before outputting a byte from
> +                             FileBuffer to Byte. The caller is responsible for
> +                             ensuring that FileBuffer was successfully
> +                             initialized with FileBufferInit().
> +
> +  @param[out] BytesRead      On successful return, BytesRead is set to 1 if the
> +                             next byte from FileBuffer has been stored to Byte.
> +                             On successful return, BytesRead is set to 0 if
> +                             FileBuffer is empty, and FileHandle is at EOF.
> +                             When an error is returned, BytesRead is not set.
> +
> +  @param[out] Byte           On output, the next byte from FileBuffer. Only set
> +                             if (a) EFI_SUCCESS is returned and (b) BytesRead
> +                             is set to 1 on output.
> +
> +  @retval EFI_SUCCESS  BytesRead has been set to 0 or 1. In the latter case,
> +                       Byte has been set as well.
> +
> +  @return              Error codes propagated from
> +                       gEfiShellProtocol->ReadFile().
> +**/
> +STATIC
> +EFI_STATUS
> +FileBufferReadByte (
> +  IN     SHELL_FILE_HANDLE FileHandle,
> +  IN OUT FILE_BUFFER       *FileBuffer,
> +     OUT UINTN             *BytesRead,
> +     OUT UINT8             *Byte
> +  )
> +{
> +  UINTN      ReadSize;
> +  EFI_STATUS Status;
> +
> +  if (FileBuffer->Left == 0) {
> +    ReadSize = FileBuffer->Allocated;
> +    Status = gEfiShellProtocol->ReadFile (FileHandle, &ReadSize,
> +                                  FileBuffer->Data);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +    if (ReadSize == 0) {
> +      *BytesRead = 0;
> +      return EFI_SUCCESS;
> +    }
> +    FileBuffer->Next = 0;
> +    FileBuffer->Left = ReadSize;
> +  }
> +
> +  *BytesRead = 1;
> +  *Byte      = FileBuffer->Data[FileBuffer->Next];
> +
> +  FileBuffer->Next++;
> +  FileBuffer->Left--;
> +  return EFI_SUCCESS;
> +}
> +
>  /**
>    Function for 'comp' command.
> 
> @@ -107,6 +217,8 @@ ShellCommandRunComp (
>    UINT8               OneByteFromFile2;
>    UINT8               *DataFromFile1;
>    UINT8               *DataFromFile2;
> +  FILE_BUFFER         FileBuffer1;
> +  FILE_BUFFER         FileBuffer2;
>    UINTN               InsertPosition1;
>    UINTN               InsertPosition2;
>    UINTN               DataSizeFromFile1;
> @@ -234,10 +346,15 @@ ShellCommandRunComp (
>        if (ShellStatus == SHELL_SUCCESS) {
>          DataFromFile1 = AllocateZeroPool ((UINTN)DifferentBytes);
>          DataFromFile2 = AllocateZeroPool ((UINTN)DifferentBytes);
> -        if (DataFromFile1 == NULL || DataFromFile2 == NULL) {
> +        FileBufferInit (&FileBuffer1);
> +        FileBufferInit (&FileBuffer2);
> +        if (DataFromFile1 == NULL || DataFromFile2 == NULL ||
> +            FileBuffer1.Data == NULL || FileBuffer2.Data == NULL) {
>            ShellStatus = SHELL_OUT_OF_RESOURCES;
>            SHELL_FREE_NON_NULL (DataFromFile1);
>            SHELL_FREE_NON_NULL (DataFromFile2);
> +          FileBufferUninit (&FileBuffer1);
> +          FileBufferUninit (&FileBuffer2);
>          }
>        }
> 
> @@ -247,9 +364,11 @@ ShellCommandRunComp (
>            DataSizeFromFile2 = 1;
>            OneByteFromFile1 = 0;
>            OneByteFromFile2 = 0;
> -          Status = gEfiShellProtocol->ReadFile (FileHandle1, &DataSizeFromFile1,
> &OneByteFromFile1);
> +          Status = FileBufferReadByte (FileHandle1, &FileBuffer1,
> +                     &DataSizeFromFile1, &OneByteFromFile1);
>            ASSERT_EFI_ERROR (Status);
> -          Status = gEfiShellProtocol->ReadFile (FileHandle2, &DataSizeFromFile2,
> &OneByteFromFile2);
> +          Status = FileBufferReadByte (FileHandle2, &FileBuffer2,
> +                     &DataSizeFromFile2, &OneByteFromFile2);
>            ASSERT_EFI_ERROR (Status);
> 
>            TempAddress++;
> @@ -346,6 +465,8 @@ ShellCommandRunComp (
> 
>          SHELL_FREE_NON_NULL (DataFromFile1);
>          SHELL_FREE_NON_NULL (DataFromFile2);
> +        FileBufferUninit (&FileBuffer1);
> +        FileBufferUninit (&FileBuffer2);
> 
>          if (DiffPointNumber == 0) {
>            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_COMP_FOOTER_PASS),
> gShellDebug1HiiHandle);
> --
> 2.19.1.3.g30247aa5d201
> 


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/8] ShellPkg/ShellCommandLib: add ShellSortFileList()
  2021-01-04 15:42 ` [PATCH 4/8] ShellPkg/ShellCommandLib: add ShellSortFileList() Laszlo Ersek
@ 2021-01-13  3:03   ` Gao, Zhichao
  0 siblings, 0 replies; 15+ messages in thread
From: Gao, Zhichao @ 2021-01-13  3:03 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel-groups-io; +Cc: Philippe Mathieu-Daudé, Ni, Ray

Reviewed-by: Zhichao Gao <zhichao.gao@intel.com>

Thanks,
Zhichao

> -----Original Message-----
> From: Laszlo Ersek <lersek@redhat.com>
> Sent: Monday, January 4, 2021 11:43 PM
> To: edk2-devel-groups-io <devel@edk2.groups.io>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>; Ni, Ray <ray.ni@intel.com>;
> Gao, Zhichao <zhichao.gao@intel.com>
> Subject: [PATCH 4/8] ShellPkg/ShellCommandLib: add ShellSortFileList()
> 
> Introduce the ShellSortFileList() function, for sorting an EFI_SHELL_FILE_INFO list,
> by FileName or by FullName.
> 
> Duplicates can be kept in the same list, or separated out to a new list.
> In either case, the relative order between duplicates does not change (the
> sorting is stable).
> 
> For the sorting, use OrderedCollectionLib rather than SortLib:
> 
> - The PerformQuickSort() function from the latter has quadratic worst-case
>   time complexity, plus it is implemented recursively (see
>   "MdeModulePkg/Library/UefiSortLib/UefiSortLib.c"). It can also not
>   return an error on memory allocation failure.
> 
> - In comparison, the Red-Black Tree instance of OrderedCollectionLib sorts
>   in O(n*log(n)) worst-case time, contains no recursion with the default
>   PcdValidateOrderedCollection=FALSE setting, and the OrderedCollectionLib
>   class APIs return errors appropriately.
> 
> The OrderedCollectionLib APIs do not permit duplicates natively, but by using lists
> as collection entries, stable sorting of duplicates can be achieved.
> 
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Zhichao Gao <zhichao.gao@intel.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3151
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  ShellPkg/ShellPkg.dsc                                        |   1 +
>  ShellPkg/Include/Library/ShellCommandLib.h                   |  81 +++++
>  ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf |   1 +
>  ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h   |  19 ++
>  ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c   | 312
> ++++++++++++++++++++
>  5 files changed, 414 insertions(+)
> 
> diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc index
> c42bc9464a0f..a8b6de334284 100644
> --- a/ShellPkg/ShellPkg.dsc
> +++ b/ShellPkg/ShellPkg.dsc
> @@ -47,6 +47,7 @@ [LibraryClasses.common]
> 
> ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.i
> nf
>    ShellCEntryLib|ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf
> 
> HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.in
> f
> +
> + OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeL
> + ib/BaseOrderedCollectionRedBlackTreeLib.inf
> 
> 
> PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCo
> ffGetEntryPointLib.inf
> 
> BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCom
> mandLib.inf
> diff --git a/ShellPkg/Include/Library/ShellCommandLib.h
> b/ShellPkg/Include/Library/ShellCommandLib.h
> index 63fcac82a2de..bc1afed5e7f5 100644
> --- a/ShellPkg/Include/Library/ShellCommandLib.h
> +++ b/ShellPkg/Include/Library/ShellCommandLib.h
> @@ -714,4 +714,85 @@ CatSDumpHex (
>    IN UINTN   DataSize,
>    IN VOID    *UserData
>    );
> +
> +//
> +// Determines the ordering operation for ShellSortFileList().
> +//
> +typedef enum {
> +  //
> +  // Sort the EFI_SHELL_FILE_INFO objects by the FileName field, in
> +increasing
> +  // order, using gUnicodeCollation->StriColl().
> +  //
> +  ShellSortFileListByFileName,
> +  //
> +  // Sort the EFI_SHELL_FILE_INFO objects by the FullName field, in
> +increasing
> +  // order, using gUnicodeCollation->StriColl().
> +  //
> +  ShellSortFileListByFullName,
> +  ShellSortFileListMax
> +} SHELL_SORT_FILE_LIST;
> +
> +/**
> +  Sort an EFI_SHELL_FILE_INFO list, optionally moving duplicates to a
> +separate
> +  list.
> +
> +  @param[in,out] FileList  The list of EFI_SHELL_FILE_INFO objects to sort.
> +
> +                           If FileList is NULL on input, then FileList is
> +                           considered an empty, hence already sorted, list.
> +
> +                           Otherwise, if (*FileList) is NULL on input, then
> +                           EFI_INVALID_PARAMETER is returned.
> +
> +                           Otherwise, the caller is responsible for having
> +                           initialized (*FileList)->Link with
> +                           InitializeListHead(). No other fields in the
> +                           (**FileList) head element are accessed by this
> +                           function.
> +
> +                           On output, (*FileList) is sorted according to Order.
> +                           If Duplicates is NULL on input, then duplicate
> +                           elements are preserved, sorted stably, on
> +                           (*FileList). If Duplicates is not NULL on input,
> +                           then duplicates are moved (stably sorted) to the
> +                           new, dynamically allocated (*Duplicates) list.
> +
> +  @param[out] Duplicates   If Duplicates is NULL on input, (*FileList) will be
> +                           a monotonically ordered list on output, with
> +                           duplicates stably sorted.
> +
> +                           If Duplicates is not NULL on input, (*FileList) will
> +                           be a strictly monotonically oredered list on output,
> +                           with duplicates separated (stably sorted) to
> +                           (*Duplicates). All fields except Link will be
> +                           zero-initialized in the (**Duplicates) head element.
> +                           If no duplicates exist, then (*Duplicates) is set to
> +                           NULL on output.
> +
> +  @param[in] Order         Determines the comparison operation between
> +                           EFI_SHELL_FILE_INFO objects.
> +
> +  @retval EFI_INVALID_PARAMETER  (UINTN)Order is greater than or equal to
> +                                 (UINTN)ShellSortFileListMax. Neither the
> +                                 (*FileList) nor the (*Duplicates) list has
> +                                 been modified.
> +
> +  @retval EFI_INVALID_PARAMETER  (*FileList) was NULL on input. Neither the
> +                                 (*FileList) nor the (*Duplicates) list has
> +                                 been modified.
> +
> +  @retval EFI_OUT_OF_RESOURCES   Memory allocation failed. Neither the
> +                                 (*FileList) nor the (*Duplicates) list has
> +                                 been modified.
> +
> +  @retval EFI_SUCCESS            Sorting successful, including the case when
> +                                 FileList is NULL on input.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ShellSortFileList (
> +  IN OUT EFI_SHELL_FILE_INFO  **FileList,
> +     OUT EFI_SHELL_FILE_INFO  **Duplicates OPTIONAL,
> +  IN     SHELL_SORT_FILE_LIST Order
> +  );
>  #endif //_SHELL_COMMAND_LIB_
> diff --git a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf
> b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf
> index a1b5601c96b6..08ca7cb78842 100644
> --- a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf
> +++ b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf
> @@ -42,6 +42,7 @@ [LibraryClasses]
>    ShellLib
>    HiiLib
>    HandleParsingLib
> +  OrderedCollectionLib
> 
>  [Protocols]
>    gEfiUnicodeCollation2ProtocolGuid                       ## CONSUMES
> diff --git a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h
> b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h
> index 8ecc2f6bf5a2..0ca291e4f9bf 100644
> --- a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h
> +++ b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h
> @@ -39,6 +39,7 @@
>  #include <Library/HiiLib.h>
>  #include <Library/UefiBootServicesTableLib.h>
>  #include <Library/UefiLib.h>
> +#include <Library/OrderedCollectionLib.h>
> 
>  typedef struct{
>    LIST_ENTRY                  Link;
> @@ -60,6 +61,24 @@ typedef struct {
>    CHAR16            *Path;
>  } SHELL_COMMAND_FILE_HANDLE;
> 
> +//
> +// Collects multiple EFI_SHELL_FILE_INFO objects that share the same name.
> +//
> +typedef struct {
> +  //
> +  // A string that compares equal to either the FileName or the
> +FullName fields
> +  // of all EFI_SHELL_FILE_INFO objects on SameNameList, according to
> +  // gUnicodeCollation->StriColl(). The string is not dynamically
> +allocated;
> +  // instead, it *aliases* the FileName or FullName field of the
> +  // EFI_SHELL_FILE_INFO object that was first encountered with this name.
> +  //
> +  CONST CHAR16 *Alias;
> +  //
> +  // A list of EFI_SHELL_FILE_INFO objects whose FileName or FullName
> +fields
> +  // compare equal to Alias, according to gUnicodeCollation->StriColl().
> +  //
> +  LIST_ENTRY SameNameList;
> +} SHELL_SORT_UNIQUE_NAME;
> 
>  #endif //_UEFI_COMMAND_LIB_INTERNAL_HEADER_
> 
> diff --git a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
> b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
> index 345808a1eac6..b06d22592d33 100644
> --- a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
> +++ b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
> @@ -1909,3 +1909,315 @@ CatSDumpHex (
> 
>    return RetVal;
>  }
> +
> +/**
> +  ORDERED_COLLECTION_USER_COMPARE function for
> SHELL_SORT_UNIQUE_NAME objects.
> +
> +  @param[in] Unique1AsVoid  The first SHELL_SORT_UNIQUE_NAME object
> (Unique1),
> +                            passed in as a pointer-to-VOID.
> +
> +  @param[in] Unique2AsVoid  The second SHELL_SORT_UNIQUE_NAME object
> (Unique2),
> +                            passed in as a pointer-to-VOID.
> +
> +  @retval <0  If Unique1 compares less than Unique2.
> +
> +  @retval  0  If Unique1 compares equal to Unique2.
> +
> +  @retval >0  If Unique1 compares greater than Unique2.
> +**/
> +STATIC
> +INTN
> +EFIAPI
> +UniqueNameCompare (
> +  IN CONST VOID *Unique1AsVoid,
> +  IN CONST VOID *Unique2AsVoid
> +  )
> +{
> +  CONST SHELL_SORT_UNIQUE_NAME *Unique1;
> +  CONST SHELL_SORT_UNIQUE_NAME *Unique2;
> +
> +  Unique1 = Unique1AsVoid;
> +  Unique2 = Unique2AsVoid;
> +
> +  //
> +  // We need to cast away CONST for EFI_UNICODE_COLLATION_STRICOLL.
> +  //
> +  return gUnicodeCollation->StriColl (
> +                              gUnicodeCollation,
> +                              (CHAR16 *)Unique1->Alias,
> +                              (CHAR16 *)Unique2->Alias
> +                              );
> +}
> +
> +/**
> +  ORDERED_COLLECTION_KEY_COMPARE function for
> SHELL_SORT_UNIQUE_NAME objects.
> +
> +  @param[in] UniqueAliasAsVoid  The CHAR16 string UniqueAlias, passed in as a
> +                                pointer-to-VOID.
> +
> +  @param[in] UniqueAsVoid       The SHELL_SORT_UNIQUE_NAME object
> (Unique),
> +                                passed in as a pointer-to-VOID.
> +
> +  @retval <0  If UniqueAlias compares less than Unique->Alias.
> +
> +  @retval  0  If UniqueAlias compares equal to Unique->Alias.
> +
> +  @retval >0  If UniqueAlias compares greater than Unique->Alias.
> +**/
> +STATIC
> +INTN
> +EFIAPI
> +UniqueNameAliasCompare (
> +  IN CONST VOID *UniqueAliasAsVoid,
> +  IN CONST VOID *UniqueAsVoid
> +  )
> +{
> +  CONST CHAR16                 *UniqueAlias;
> +  CONST SHELL_SORT_UNIQUE_NAME *Unique;
> +
> +  UniqueAlias = UniqueAliasAsVoid;
> +  Unique      = UniqueAsVoid;
> +
> +  //
> +  // We need to cast away CONST for EFI_UNICODE_COLLATION_STRICOLL.
> +  //
> +  return gUnicodeCollation->StriColl (
> +                              gUnicodeCollation,
> +                              (CHAR16 *)UniqueAlias,
> +                              (CHAR16 *)Unique->Alias
> +                              );
> +}
> +
> +/**
> +  Sort an EFI_SHELL_FILE_INFO list, optionally moving duplicates to a
> +separate
> +  list.
> +
> +  @param[in,out] FileList  The list of EFI_SHELL_FILE_INFO objects to sort.
> +
> +                           If FileList is NULL on input, then FileList is
> +                           considered an empty, hence already sorted, list.
> +
> +                           Otherwise, if (*FileList) is NULL on input, then
> +                           EFI_INVALID_PARAMETER is returned.
> +
> +                           Otherwise, the caller is responsible for having
> +                           initialized (*FileList)->Link with
> +                           InitializeListHead(). No other fields in the
> +                           (**FileList) head element are accessed by this
> +                           function.
> +
> +                           On output, (*FileList) is sorted according to Order.
> +                           If Duplicates is NULL on input, then duplicate
> +                           elements are preserved, sorted stably, on
> +                           (*FileList). If Duplicates is not NULL on input,
> +                           then duplicates are moved (stably sorted) to the
> +                           new, dynamically allocated (*Duplicates) list.
> +
> +  @param[out] Duplicates   If Duplicates is NULL on input, (*FileList) will be
> +                           a monotonically ordered list on output, with
> +                           duplicates stably sorted.
> +
> +                           If Duplicates is not NULL on input, (*FileList) will
> +                           be a strictly monotonically oredered list on output,
> +                           with duplicates separated (stably sorted) to
> +                           (*Duplicates). All fields except Link will be
> +                           zero-initialized in the (**Duplicates) head element.
> +                           If no duplicates exist, then (*Duplicates) is set to
> +                           NULL on output.
> +
> +  @param[in] Order         Determines the comparison operation between
> +                           EFI_SHELL_FILE_INFO objects.
> +
> +  @retval EFI_INVALID_PARAMETER  (UINTN)Order is greater than or equal to
> +                                 (UINTN)ShellSortFileListMax. Neither the
> +                                 (*FileList) nor the (*Duplicates) list has
> +                                 been modified.
> +
> +  @retval EFI_INVALID_PARAMETER  (*FileList) was NULL on input. Neither the
> +                                 (*FileList) nor the (*Duplicates) list has
> +                                 been modified.
> +
> +  @retval EFI_OUT_OF_RESOURCES   Memory allocation failed. Neither the
> +                                 (*FileList) nor the (*Duplicates) list has
> +                                 been modified.
> +
> +  @retval EFI_SUCCESS            Sorting successful, including the case when
> +                                 FileList is NULL on input.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ShellSortFileList (
> +  IN OUT EFI_SHELL_FILE_INFO  **FileList,
> +     OUT EFI_SHELL_FILE_INFO  **Duplicates OPTIONAL,
> +  IN     SHELL_SORT_FILE_LIST Order
> +  )
> +{
> +  LIST_ENTRY               *FilesHead;
> +  ORDERED_COLLECTION       *Sort;
> +  LIST_ENTRY               *FileEntry;
> +  EFI_SHELL_FILE_INFO      *FileInfo;
> +  SHELL_SORT_UNIQUE_NAME   *Unique;
> +  EFI_STATUS               Status;
> +  EFI_SHELL_FILE_INFO      *Dupes;
> +  LIST_ENTRY               *NextFileEntry;
> +  CONST CHAR16             *Alias;
> +  ORDERED_COLLECTION_ENTRY *SortEntry;
> +  LIST_ENTRY               *TargetFileList;
> +  ORDERED_COLLECTION_ENTRY *NextSortEntry;
> +  VOID                     *UniqueAsVoid;
> +
> +  if ((UINTN)Order >= (UINTN)ShellSortFileListMax) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (FileList == NULL) {
> +    //
> +    // FileList is considered empty, hence already sorted, with no duplicates.
> +    //
> +    if (Duplicates != NULL) {
> +      *Duplicates = NULL;
> +    }
> +    return EFI_SUCCESS;
> +  }
> +
> +  if (*FileList == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  FilesHead = &(*FileList)->Link;
> +
> +  //
> +  // Collect all the unique names.
> +  //
> +  Sort = OrderedCollectionInit (UniqueNameCompare,
> + UniqueNameAliasCompare);  if (Sort == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  BASE_LIST_FOR_EACH (FileEntry, FilesHead) {
> +    FileInfo = (EFI_SHELL_FILE_INFO *)FileEntry;
> +
> +    //
> +    // Try to record the name of this file as a unique name.
> +    //
> +    Unique = AllocatePool (sizeof (*Unique));
> +    if (Unique == NULL) {
> +      Status = EFI_OUT_OF_RESOURCES;
> +      goto UninitSort;
> +    }
> +    Unique->Alias = ((Order == ShellSortFileListByFileName) ?
> +                     FileInfo->FileName :
> +                     FileInfo->FullName);
> +    InitializeListHead (&Unique->SameNameList);
> +
> +    Status = OrderedCollectionInsert (Sort, NULL, Unique);
> +    if (EFI_ERROR (Status)) {
> +      //
> +      // Only two errors are possible: memory allocation failed, or this name
> +      // has been encountered before. In either case, the
> +      // SHELL_SORT_UNIQUE_NAME object being constructed has to be released.
> +      //
> +      FreePool (Unique);
> +      //
> +      // Memory allocation failure is fatal, while having seen the same name
> +      // before is normal.
> +      //
> +      if (Status == EFI_OUT_OF_RESOURCES) {
> +        goto UninitSort;
> +      }
> +      ASSERT (Status == EFI_ALREADY_STARTED);
> +    }
> +  }
> +
> +  //
> +  // If separation of duplicates has been requested, allocate the list
> + for  // them.
> +  //
> +  if (Duplicates != NULL) {
> +    Dupes = AllocateZeroPool (sizeof (*Dupes));
> +    if (Dupes == NULL) {
> +      Status = EFI_OUT_OF_RESOURCES;
> +      goto UninitSort;
> +    }
> +    InitializeListHead (&Dupes->Link);
> +  }
> +
> +  //
> +  // No memory allocation beyond this point; thus, no chance to fail.
> + We can  // now migrate the EFI_SHELL_FILE_INFO objects from (*FileList) to
> Sort.
> +  //
> +  BASE_LIST_FOR_EACH_SAFE (FileEntry, NextFileEntry, FilesHead) {
> +    FileInfo = (EFI_SHELL_FILE_INFO *)FileEntry;
> +    //
> +    // Look up the SHELL_SORT_UNIQUE_NAME that matches FileInfo's name.
> +    //
> +    Alias = ((Order == ShellSortFileListByFileName) ?
> +             FileInfo->FileName :
> +             FileInfo->FullName);
> +    SortEntry = OrderedCollectionFind (Sort, Alias);
> +    ASSERT (SortEntry != NULL);
> +    Unique = OrderedCollectionUserStruct (SortEntry);
> +    //
> +    // Move FileInfo from (*FileList) to the end of the list of files whose
> +    // names all compare identical to FileInfo's name.
> +    //
> +    RemoveEntryList (&FileInfo->Link);
> +    InsertTailList (&Unique->SameNameList, &FileInfo->Link);  }
> +
> +  //
> +  // All EFI_SHELL_FILE_INFO objects originally in (*FileList) have
> + been  // distributed to Sort. Now migrate them back to (*FileList),
> + advancing in  // unique name order.
> +  //
> +  for (SortEntry = OrderedCollectionMin (Sort);
> +       SortEntry != NULL;
> +       SortEntry = OrderedCollectionNext (SortEntry)) {
> +    Unique = OrderedCollectionUserStruct (SortEntry);
> +    //
> +    // The first FileInfo encountered for each unique name goes back on
> +    // (*FileList) unconditionally. Further FileInfo instances for the same
> +    // unique name -- that is, duplicates -- are either returned to (*FileList)
> +    // or separated, dependent on the caller's request.
> +    //
> +    TargetFileList = FilesHead;
> +    BASE_LIST_FOR_EACH_SAFE (FileEntry, NextFileEntry, &Unique-
> >SameNameList) {
> +      RemoveEntryList (FileEntry);
> +      InsertTailList (TargetFileList, FileEntry);
> +      if (Duplicates != NULL) {
> +        TargetFileList = &Dupes->Link;
> +      }
> +    }
> +  }
> +
> +  //
> +  // We're done. If separation of duplicates has been requested, output
> + the  // list of duplicates -- and free that list at once, if it's
> + empty (i.e., if  // no duplicates have been found).
> +  //
> +  if (Duplicates != NULL) {
> +    if (IsListEmpty (&Dupes->Link)) {
> +      FreePool (Dupes);
> +      *Duplicates = NULL;
> +    } else {
> +      *Duplicates = Dupes;
> +    }
> +  }
> +  Status = EFI_SUCCESS;
> +
> +  //
> +  // Fall through.
> +  //
> +UninitSort:
> +  for (SortEntry = OrderedCollectionMin (Sort);
> +       SortEntry != NULL;
> +       SortEntry = NextSortEntry) {
> +    NextSortEntry = OrderedCollectionNext (SortEntry);
> +    OrderedCollectionDelete (Sort, SortEntry, &UniqueAsVoid);
> +    Unique = UniqueAsVoid;
> +    ASSERT (IsListEmpty (&Unique->SameNameList));
> +    FreePool (Unique);
> +  }
> +  OrderedCollectionUninit (Sort);
> +
> +  return Status;
> +}
> --
> 2.19.1.3.g30247aa5d201
> 


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 5/8] ShellPkg/Ls: sort output by FileName in non-SFO mode
  2021-01-04 15:42 ` [PATCH 5/8] ShellPkg/Ls: sort output by FileName in non-SFO mode Laszlo Ersek
@ 2021-01-13  3:04   ` Gao, Zhichao
  0 siblings, 0 replies; 15+ messages in thread
From: Gao, Zhichao @ 2021-01-13  3:04 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel-groups-io; +Cc: Philippe Mathieu-Daudé, Ni, Ray

Reviewed-by: Zhichao Gao <zhichao.gao@intel.com>

Thanks,
Zhichao

> -----Original Message-----
> From: Laszlo Ersek <lersek@redhat.com>
> Sent: Monday, January 4, 2021 11:43 PM
> To: edk2-devel-groups-io <devel@edk2.groups.io>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>; Ni, Ray <ray.ni@intel.com>;
> Gao, Zhichao <zhichao.gao@intel.com>
> Subject: [PATCH 5/8] ShellPkg/Ls: sort output by FileName in non-SFO mode
> 
> Sorting the LS output in non-SFO mode by FileName is best demonstrated with
> two examples.
> 
> (1a) Before:
> 
> > FS2:\> dir -r apps
> > Directory of: FS2:\apps\
> > 01/01/1970  01:00 <DIR> r           0  .
> > 12/22/2020  17:53 <DIR>         4,096  X64
> > 12/22/2020  17:53 <DIR>         4,096  AARCH64
> > 01/01/1970  01:00 <DIR> r           0  ..
> > 12/22/2020  17:53 <DIR>         4,096  IA32
> >           0 File(s)           0 bytes
> >           5 Dir(s)
> > Directory of: FS2:\apps\X64\
> > 12/22/2020  17:52              18,752  DumpDynPcd.efi
> > 12/22/2020  17:52              34,240  SmiHandlerProfileInfo.efi
> > 01/01/1970  01:00 <DIR> r           0  .
> > 12/22/2020  17:52              11,456  VariableInfo.efi
> > 12/22/2020  17:52              26,304  MemoryProfileInfo.efi
> > 12/22/2020  17:53             126,656  AcpiViewApp.efi
> > 12/22/2020  17:53              38,784  Cpuid.efi
> > 01/01/1970  01:00 <DIR> r           0  ..
> >           6 File(s)     256,192 bytes
> >           2 Dir(s)
> > Directory of: FS2:\apps\AARCH64\
> > 12/22/2020  17:52              32,768  DumpDynPcd.efi
> > 01/01/1970  01:00 <DIR> r           0  .
> > 12/22/2020  17:52              20,480  VariableInfo.efi
> > 12/22/2020  17:52              40,960  MemoryProfileInfo.efi
> > 12/22/2020  17:53             139,264  AcpiViewApp.efi
> > 01/01/1970  01:00 <DIR> r           0  ..
> >           4 File(s)     233,472 bytes
> >           2 Dir(s)
> > Directory of: FS2:\apps\IA32\
> > 12/22/2020  17:52              17,344  DumpDynPcd.efi
> > 12/22/2020  17:52              30,720  SmiHandlerProfileInfo.efi
> > 01/01/1970  01:00 <DIR> r           0  .
> > 12/22/2020  17:52              10,880  VariableInfo.efi
> > 12/22/2020  17:52              24,192  MemoryProfileInfo.efi
> > 12/22/2020  17:53             105,536  AcpiViewApp.efi
> > 12/22/2020  17:53              36,096  Cpuid.efi
> > 01/01/1970  01:00 <DIR> r           0  ..
> >           6 File(s)     224,768 bytes
> >           2 Dir(s)
> 
> (1b) After:
> 
> > FS2:\> dir -r apps
> > Directory of: FS2:\apps\
> > 01/01/1970  01:00 <DIR> r           0  .
> > 01/01/1970  01:00 <DIR> r           0  ..
> > 12/22/2020  17:53 <DIR>         4,096  AARCH64
> > 12/22/2020  17:53 <DIR>         4,096  IA32
> > 12/22/2020  17:53 <DIR>         4,096  X64
> >           0 File(s)           0 bytes
> >           5 Dir(s)
> > Directory of: FS2:\apps\X64\
> > 01/01/1970  01:00 <DIR> r           0  .
> > 01/01/1970  01:00 <DIR> r           0  ..
> > 12/22/2020  17:53             126,656  AcpiViewApp.efi
> > 12/22/2020  17:53              38,784  Cpuid.efi
> > 12/22/2020  17:52              18,752  DumpDynPcd.efi
> > 12/22/2020  17:52              26,304  MemoryProfileInfo.efi
> > 12/22/2020  17:52              34,240  SmiHandlerProfileInfo.efi
> > 12/22/2020  17:52              11,456  VariableInfo.efi
> >           6 File(s)     256,192 bytes
> >           2 Dir(s)
> > Directory of: FS2:\apps\AARCH64\
> > 01/01/1970  01:00 <DIR> r           0  .
> > 01/01/1970  01:00 <DIR> r           0  ..
> > 12/22/2020  17:53             139,264  AcpiViewApp.efi
> > 12/22/2020  17:52              32,768  DumpDynPcd.efi
> > 12/22/2020  17:52              40,960  MemoryProfileInfo.efi
> > 12/22/2020  17:52              20,480  VariableInfo.efi
> >           4 File(s)     233,472 bytes
> >           2 Dir(s)
> > Directory of: FS2:\apps\IA32\
> > 01/01/1970  01:00 <DIR> r           0  .
> > 01/01/1970  01:00 <DIR> r           0  ..
> > 12/22/2020  17:53             105,536  AcpiViewApp.efi
> > 12/22/2020  17:53              36,096  Cpuid.efi
> > 12/22/2020  17:52              17,344  DumpDynPcd.efi
> > 12/22/2020  17:52              24,192  MemoryProfileInfo.efi
> > 12/22/2020  17:52              30,720  SmiHandlerProfileInfo.efi
> > 12/22/2020  17:52              10,880  VariableInfo.efi
> >           6 File(s)     224,768 bytes
> >           2 Dir(s)
> 
> (2a) Before:
> 
> > FS2:\> dir apps\*\*.efi
> > Directory of: FS2:\apps\*\
> > 12/22/2020  17:52              18,752  DumpDynPcd.efi
> > 12/22/2020  17:52              34,240  SmiHandlerProfileInfo.efi
> > 12/22/2020  17:52              11,456  VariableInfo.efi
> > 12/22/2020  17:52              26,304  MemoryProfileInfo.efi
> > 12/22/2020  17:53             126,656  AcpiViewApp.efi
> > 12/22/2020  17:53              38,784  Cpuid.efi
> > 12/22/2020  17:52              32,768  DumpDynPcd.efi
> > 12/22/2020  17:52              20,480  VariableInfo.efi
> > 12/22/2020  17:52              40,960  MemoryProfileInfo.efi
> > 12/22/2020  17:53             139,264  AcpiViewApp.efi
> > 12/22/2020  17:52              17,344  DumpDynPcd.efi
> > 12/22/2020  17:52              30,720  SmiHandlerProfileInfo.efi
> > 12/22/2020  17:52              10,880  VariableInfo.efi
> > 12/22/2020  17:52              24,192  MemoryProfileInfo.efi
> > 12/22/2020  17:53             105,536  AcpiViewApp.efi
> > 12/22/2020  17:53              36,096  Cpuid.efi
> >          16 File(s)     714,432 bytes
> >           0 Dir(s)
> 
> (2b) After:
> 
> > FS2:\> dir apps\*\*.efi
> > Directory of: FS2:\apps\*\
> > 12/22/2020  17:53             126,656  AcpiViewApp.efi
> > 12/22/2020  17:53             139,264  AcpiViewApp.efi
> > 12/22/2020  17:53             105,536  AcpiViewApp.efi
> > 12/22/2020  17:53              38,784  Cpuid.efi
> > 12/22/2020  17:53              36,096  Cpuid.efi
> > 12/22/2020  17:52              18,752  DumpDynPcd.efi
> > 12/22/2020  17:52              32,768  DumpDynPcd.efi
> > 12/22/2020  17:52              17,344  DumpDynPcd.efi
> > 12/22/2020  17:52              26,304  MemoryProfileInfo.efi
> > 12/22/2020  17:52              40,960  MemoryProfileInfo.efi
> > 12/22/2020  17:52              24,192  MemoryProfileInfo.efi
> > 12/22/2020  17:52              34,240  SmiHandlerProfileInfo.efi
> > 12/22/2020  17:52              30,720  SmiHandlerProfileInfo.efi
> > 12/22/2020  17:52              11,456  VariableInfo.efi
> > 12/22/2020  17:52              20,480  VariableInfo.efi
> > 12/22/2020  17:52              10,880  VariableInfo.efi
> >          16 File(s)     714,432 bytes
> >           0 Dir(s)
> 
> (In example (2), note that the sorting is stable; that is, whatever order is
> established between identical FileNames by ShellOpenFileMetaArg(), it is
> preserved by ShellSortFileList().)
> 
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Zhichao Gao <zhichao.gao@intel.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3151
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
> 
> diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c
> b/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c
> index da2b1acab47c..8b97926d7f47 100644
> --- a/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c
> +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c
> @@ -489,6 +489,20 @@ PrintLsOutput(
>        PrintSfoVolumeInfoTableEntry(ListHead);
>      }
> 
> +    if (!Sfo) {
> +      //
> +      // Sort the file list by FileName, stably.
> +      //
> +      // If the call below fails, then the EFI_SHELL_FILE_INFO list anchored to
> +      // ListHead will not be changed in any way.
> +      //
> +      ShellSortFileList (
> +        &ListHead,
> +        NULL,                       // Duplicates
> +        ShellSortFileListByFileName
> +        );
> +    }
> +
>      for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link),
> LongestPath = 0
>          ; !IsNull(&ListHead->Link, &Node->Link)
>          ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node-
> >Link)
> --
> 2.19.1.3.g30247aa5d201
> 


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 6/8] ShellPkg/ShellProtocol: sort files by FullName in RemoveDupInFileList()
  2021-01-04 15:42 ` [PATCH 6/8] ShellPkg/ShellProtocol: sort files by FullName in RemoveDupInFileList() Laszlo Ersek
@ 2021-01-13  3:04   ` Gao, Zhichao
  0 siblings, 0 replies; 15+ messages in thread
From: Gao, Zhichao @ 2021-01-13  3:04 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel-groups-io; +Cc: Philippe Mathieu-Daudé, Ni, Ray

Reviewed-by: Zhichao Gao <zhichao.gao@intel.com>

Thanks,
Zhichao

> -----Original Message-----
> From: Laszlo Ersek <lersek@redhat.com>
> Sent: Monday, January 4, 2021 11:43 PM
> To: edk2-devel-groups-io <devel@edk2.groups.io>
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>; Ni, Ray <ray.ni@intel.com>;
> Gao, Zhichao <zhichao.gao@intel.com>
> Subject: [PATCH 6/8] ShellPkg/ShellProtocol: sort files by FullName in
> RemoveDupInFileList()
> 
> The current implementation of EfiShellRemoveDupInFileList():
> - has quadratic time complexity, as a disadvantage, and
> - needs no dynamic memory, as an advantage.
> 
> Because the UEFI Shell Spec requires
> EFI_SHELL_PROTOCOL.RemoveDupInFileList() to succeed at all times, keep the
> current method as a fallback (it cannot fail due to needing no dynamic memory).
> 
> However, as a higher priority option, call the new ShellSortFileList() function at
> first, separating out and releasing duplicates.
> (ShellSortFileList() can fail due to EFI_OUT_OF_RESOURCES.)
> 
> Beyond improving the runtime of EfiShellRemoveDupInFileList(), this change has
> the extremely desirable effect that the ShellOpenFileMetaArg() function in the
> ShellPkg/Library/UefiShellLib instance will produce file lists that are sorted by
> FullName.
> 
> Consequently, when used with wildcards, the ATTRIB, CP, FOR, LOAD,
> LOADPCIROM, LS, MV, RM, TOUCH, TYPE commands will process files in
> FullName order. (LS in recursive mode uses wildcards internally.)
> 
> Before:
> 
> > FS2:\> dir -r -sfo apps
> > [...]
> > FileInfo,"FS2:\apps\"
> > FileInfo,"FS2:\apps\X64"
> > FileInfo,"FS2:\apps\AARCH64"
> > FileInfo,"FS2:\"
> > FileInfo,"FS2:\apps\IA32"
> > FileInfo,"FS2:\apps\X64\DumpDynPcd.efi"
> > FileInfo,"FS2:\apps\X64\SmiHandlerProfileInfo.efi"
> > FileInfo,"FS2:\apps\X64\"
> > FileInfo,"FS2:\apps\X64\VariableInfo.efi"
> > FileInfo,"FS2:\apps\X64\MemoryProfileInfo.efi"
> > FileInfo,"FS2:\apps\X64\AcpiViewApp.efi"
> > FileInfo,"FS2:\apps\X64\Cpuid.efi"
> > FileInfo,"FS2:\apps\"
> > FileInfo,"FS2:\apps\AARCH64\DumpDynPcd.efi"
> > FileInfo,"FS2:\apps\AARCH64\"
> > FileInfo,"FS2:\apps\AARCH64\VariableInfo.efi"
> > FileInfo,"FS2:\apps\AARCH64\MemoryProfileInfo.efi"
> > FileInfo,"FS2:\apps\AARCH64\AcpiViewApp.efi"
> > FileInfo,"FS2:\apps\"
> > FileInfo,"FS2:\apps\IA32\DumpDynPcd.efi"
> > FileInfo,"FS2:\apps\IA32\SmiHandlerProfileInfo.efi"
> > FileInfo,"FS2:\apps\IA32\"
> > FileInfo,"FS2:\apps\IA32\VariableInfo.efi"
> > FileInfo,"FS2:\apps\IA32\MemoryProfileInfo.efi"
> > FileInfo,"FS2:\apps\IA32\AcpiViewApp.efi"
> > FileInfo,"FS2:\apps\IA32\Cpuid.efi"
> > FileInfo,"FS2:\apps\"
> 
> After:
> 
> > FS2:\> dir -r -sfo apps
> > [...]
> > FileInfo,"FS2:\"
> > FileInfo,"FS2:\apps\"
> > FileInfo,"FS2:\apps\AARCH64"
> > FileInfo,"FS2:\apps\IA32"
> > FileInfo,"FS2:\apps\X64"
> > FileInfo,"FS2:\apps\"
> > FileInfo,"FS2:\apps\AARCH64\"
> > FileInfo,"FS2:\apps\AARCH64\AcpiViewApp.efi"
> > FileInfo,"FS2:\apps\AARCH64\DumpDynPcd.efi"
> > FileInfo,"FS2:\apps\AARCH64\MemoryProfileInfo.efi"
> > FileInfo,"FS2:\apps\AARCH64\VariableInfo.efi"
> > FileInfo,"FS2:\apps\"
> > FileInfo,"FS2:\apps\IA32\"
> > FileInfo,"FS2:\apps\IA32\AcpiViewApp.efi"
> > FileInfo,"FS2:\apps\IA32\Cpuid.efi"
> > FileInfo,"FS2:\apps\IA32\DumpDynPcd.efi"
> > FileInfo,"FS2:\apps\IA32\MemoryProfileInfo.efi"
> > FileInfo,"FS2:\apps\IA32\SmiHandlerProfileInfo.efi"
> > FileInfo,"FS2:\apps\IA32\VariableInfo.efi"
> > FileInfo,"FS2:\apps\"
> > FileInfo,"FS2:\apps\X64\"
> > FileInfo,"FS2:\apps\X64\AcpiViewApp.efi"
> > FileInfo,"FS2:\apps\X64\Cpuid.efi"
> > FileInfo,"FS2:\apps\X64\DumpDynPcd.efi"
> > FileInfo,"FS2:\apps\X64\MemoryProfileInfo.efi"
> > FileInfo,"FS2:\apps\X64\SmiHandlerProfileInfo.efi"
> > FileInfo,"FS2:\apps\X64\VariableInfo.efi"
> 
> Regarding LS in non-SFO mode, the stability of ShellSortFileList() shows.
> The ShellSortFileList() call added to LS in the previous patch re-sorts the output of
> ShellOpenFileMetaArg(); and so this patch improves the ordering between
> identical FileNames:
> 
> Before:
> 
> > FS2:\> dir -r apps
> > Directory of: FS2:\apps\
> > 01/01/1970  01:00 <DIR> r           0  .
> > 01/01/1970  01:00 <DIR> r           0  ..
> > 12/22/2020  17:53 <DIR>         4,096  AARCH64
> > 12/22/2020  17:53 <DIR>         4,096  IA32
> > 12/22/2020  17:53 <DIR>         4,096  X64
> >           0 File(s)           0 bytes
> >           5 Dir(s)
> > Directory of: FS2:\apps\X64\
> > 01/01/1970  01:00 <DIR> r           0  .
> > 01/01/1970  01:00 <DIR> r           0  ..
> > 12/22/2020  17:53             126,656  AcpiViewApp.efi
> > 12/22/2020  17:53              38,784  Cpuid.efi
> > 12/22/2020  17:52              18,752  DumpDynPcd.efi
> > 12/22/2020  17:52              26,304  MemoryProfileInfo.efi
> > 12/22/2020  17:52              34,240  SmiHandlerProfileInfo.efi
> > 12/22/2020  17:52              11,456  VariableInfo.efi
> >           6 File(s)     256,192 bytes
> >           2 Dir(s)
> > Directory of: FS2:\apps\AARCH64\
> > 01/01/1970  01:00 <DIR> r           0  .
> > 01/01/1970  01:00 <DIR> r           0  ..
> > 12/22/2020  17:53             139,264  AcpiViewApp.efi
> > 12/22/2020  17:52              32,768  DumpDynPcd.efi
> > 12/22/2020  17:52              40,960  MemoryProfileInfo.efi
> > 12/22/2020  17:52              20,480  VariableInfo.efi
> >           4 File(s)     233,472 bytes
> >           2 Dir(s)
> > Directory of: FS2:\apps\IA32\
> > 01/01/1970  01:00 <DIR> r           0  .
> > 01/01/1970  01:00 <DIR> r           0  ..
> > 12/22/2020  17:53             105,536  AcpiViewApp.efi
> > 12/22/2020  17:53              36,096  Cpuid.efi
> > 12/22/2020  17:52              17,344  DumpDynPcd.efi
> > 12/22/2020  17:52              24,192  MemoryProfileInfo.efi
> > 12/22/2020  17:52              30,720  SmiHandlerProfileInfo.efi
> > 12/22/2020  17:52              10,880  VariableInfo.efi
> >           6 File(s)     224,768 bytes
> >           2 Dir(s)
> >
> > FS2:\> dir apps\*\*.efi
> > Directory of: FS2:\apps\*\
> > 12/22/2020  17:53             126,656  AcpiViewApp.efi
> > 12/22/2020  17:53             139,264  AcpiViewApp.efi
> > 12/22/2020  17:53             105,536  AcpiViewApp.efi
> > 12/22/2020  17:53              38,784  Cpuid.efi
> > 12/22/2020  17:53              36,096  Cpuid.efi
> > 12/22/2020  17:52              18,752  DumpDynPcd.efi
> > 12/22/2020  17:52              32,768  DumpDynPcd.efi
> > 12/22/2020  17:52              17,344  DumpDynPcd.efi
> > 12/22/2020  17:52              26,304  MemoryProfileInfo.efi
> > 12/22/2020  17:52              40,960  MemoryProfileInfo.efi
> > 12/22/2020  17:52              24,192  MemoryProfileInfo.efi
> > 12/22/2020  17:52              34,240  SmiHandlerProfileInfo.efi
> > 12/22/2020  17:52              30,720  SmiHandlerProfileInfo.efi
> > 12/22/2020  17:52              11,456  VariableInfo.efi
> > 12/22/2020  17:52              20,480  VariableInfo.efi
> > 12/22/2020  17:52              10,880  VariableInfo.efi
> >          16 File(s)     714,432 bytes
> >           0 Dir(s)
> 
> After:
> 
> > FS2:\> dir -r apps
> > Directory of: FS2:\apps\
> > 01/01/1970  01:00 <DIR> r           0  .
> > 01/01/1970  01:00 <DIR> r           0  ..
> > 12/22/2020  17:53 <DIR>         4,096  AARCH64
> > 12/22/2020  17:53 <DIR>         4,096  IA32
> > 12/22/2020  17:53 <DIR>         4,096  X64
> >           0 File(s)           0 bytes
> >           5 Dir(s)
> > Directory of: FS2:\apps\AARCH64\
> > 01/01/1970  01:00 <DIR> r           0  .
> > 01/01/1970  01:00 <DIR> r           0  ..
> > 12/22/2020  17:53             139,264  AcpiViewApp.efi
> > 12/22/2020  17:52              32,768  DumpDynPcd.efi
> > 12/22/2020  17:52              40,960  MemoryProfileInfo.efi
> > 12/22/2020  17:52              20,480  VariableInfo.efi
> >           4 File(s)     233,472 bytes
> >           2 Dir(s)
> > Directory of: FS2:\apps\IA32\
> > 01/01/1970  01:00 <DIR> r           0  .
> > 01/01/1970  01:00 <DIR> r           0  ..
> > 12/22/2020  17:53             105,536  AcpiViewApp.efi
> > 12/22/2020  17:53              36,096  Cpuid.efi
> > 12/22/2020  17:52              17,344  DumpDynPcd.efi
> > 12/22/2020  17:52              24,192  MemoryProfileInfo.efi
> > 12/22/2020  17:52              30,720  SmiHandlerProfileInfo.efi
> > 12/22/2020  17:52              10,880  VariableInfo.efi
> >           6 File(s)     224,768 bytes
> >           2 Dir(s)
> > Directory of: FS2:\apps\X64\
> > 01/01/1970  01:00 <DIR> r           0  .
> > 01/01/1970  01:00 <DIR> r           0  ..
> > 12/22/2020  17:53             126,656  AcpiViewApp.efi
> > 12/22/2020  17:53              38,784  Cpuid.efi
> > 12/22/2020  17:52              18,752  DumpDynPcd.efi
> > 12/22/2020  17:52              26,304  MemoryProfileInfo.efi
> > 12/22/2020  17:52              34,240  SmiHandlerProfileInfo.efi
> > 12/22/2020  17:52              11,456  VariableInfo.efi
> >           6 File(s)     256,192 bytes
> >           2 Dir(s)
> >
> > FS2:\> dir apps\*\*.efi
> > Directory of: FS2:\apps\*\
> > 12/22/2020  17:53             139,264  AcpiViewApp.efi
> > 12/22/2020  17:53             105,536  AcpiViewApp.efi
> > 12/22/2020  17:53             126,656  AcpiViewApp.efi
> > 12/22/2020  17:53              36,096  Cpuid.efi
> > 12/22/2020  17:53              38,784  Cpuid.efi
> > 12/22/2020  17:52              32,768  DumpDynPcd.efi
> > 12/22/2020  17:52              17,344  DumpDynPcd.efi
> > 12/22/2020  17:52              18,752  DumpDynPcd.efi
> > 12/22/2020  17:52              40,960  MemoryProfileInfo.efi
> > 12/22/2020  17:52              24,192  MemoryProfileInfo.efi
> > 12/22/2020  17:52              26,304  MemoryProfileInfo.efi
> > 12/22/2020  17:52              30,720  SmiHandlerProfileInfo.efi
> > 12/22/2020  17:52              34,240  SmiHandlerProfileInfo.efi
> > 12/22/2020  17:52              20,480  VariableInfo.efi
> > 12/22/2020  17:52              10,880  VariableInfo.efi
> > 12/22/2020  17:52              11,456  VariableInfo.efi
> >          16 File(s)     714,432 bytes
> >           0 Dir(s)
> 
> Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Zhichao Gao <zhichao.gao@intel.com>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3151
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  ShellPkg/Application/Shell/ShellProtocol.c | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/ShellPkg/Application/Shell/ShellProtocol.c
> b/ShellPkg/Application/Shell/ShellProtocol.c
> index 4e639fe35e4f..e79c39058b3e 100644
> --- a/ShellPkg/Application/Shell/ShellProtocol.c
> +++ b/ShellPkg/Application/Shell/ShellProtocol.c
> @@ -1855,6 +1855,8 @@ EfiShellRemoveDupInFileList(
>    IN EFI_SHELL_FILE_INFO **FileList
>    )
>  {
> +  EFI_STATUS          Status;
> +  EFI_SHELL_FILE_INFO *Duplicates;
>    EFI_SHELL_FILE_INFO *ShellFileListItem;
>    EFI_SHELL_FILE_INFO *ShellFileListItem2;
>    EFI_SHELL_FILE_INFO *TempNode;
> @@ -1862,6 +1864,20 @@ EfiShellRemoveDupInFileList(
>    if (FileList == NULL || *FileList == NULL) {
>      return (EFI_INVALID_PARAMETER);
>    }
> +
> +  Status = ShellSortFileList (
> +             FileList,
> +             &Duplicates,
> +             ShellSortFileListByFullName
> +             );
> +  if (!EFI_ERROR (Status)) {
> +    EfiShellFreeFileList (&Duplicates);
> +    return EFI_SUCCESS;
> +  }
> +  //
> +  // Fall back to the slow method that needs no extra memory, and so
> + cannot  // fail.
> +  //
>    for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link)
>        ; !IsNull(&(*FileList)->Link, &ShellFileListItem->Link)
>        ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link,
> &ShellFileListItem->Link)
> --
> 2.19.1.3.g30247aa5d201
> 


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2021-01-13  3:04 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-01-04 15:42 [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements Laszlo Ersek
2021-01-04 15:42 ` [PATCH 1/8] ShellPkg/Comp: add file buffering Laszlo Ersek
2021-01-11  1:24   ` Gao, Zhichao
2021-01-04 15:42 ` [PATCH 2/8] OvmfPkg: raise PcdShellFileOperationSize to 128KB Laszlo Ersek
2021-01-04 15:42 ` [PATCH 3/8] ArmVirtPkg: " Laszlo Ersek
2021-01-04 15:42 ` [PATCH 4/8] ShellPkg/ShellCommandLib: add ShellSortFileList() Laszlo Ersek
2021-01-13  3:03   ` Gao, Zhichao
2021-01-04 15:42 ` [PATCH 5/8] ShellPkg/Ls: sort output by FileName in non-SFO mode Laszlo Ersek
2021-01-13  3:04   ` Gao, Zhichao
2021-01-04 15:42 ` [PATCH 6/8] ShellPkg/ShellProtocol: sort files by FullName in RemoveDupInFileList() Laszlo Ersek
2021-01-13  3:04   ` Gao, Zhichao
2021-01-04 15:42 ` [PATCH 7/8] OvmfPkg: disable list length checks in NOOPT and DEBUG builds Laszlo Ersek
2021-01-04 15:42 ` [PATCH 8/8] ArmVirtPkg: " Laszlo Ersek
2021-01-04 16:12 ` [PATCH 0/8] ShellPkg, ArmVirtPkg, OvmfPkg: shell usability improvements Ard Biesheuvel
2021-01-08  8:34 ` [edk2-devel] " Laszlo Ersek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox