From f2c74468185652da74c0dafbc9a687223c25baeb Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Tue, 6 Feb 2024 23:18:50 +1100 Subject: [PATCH] Reduce overhead reading byte/sbyte arrays from IndexedReader Traces gathered over the test suite show: - ~2.7% CPU spent in `IndexedReader.GetByte(int)` - ~0.4% CPU spent in `IndexedReader.GetSByte(int)` Looking at the main callers shows loops in `TiffReader` that call these methods in loops. This approach accrues overhead per-byte due to bounds checking and virtual dispatch. Instead, use the `Span` overload of `GetBytes` that performs the bounds checking once, then copies data in a single call. It may be possible to give a similar treatment to the handling of other TIFF format codes, though they're not currently showing up on traces and would be more complex to implement due to byte-ordering issues (`byte` and `sbyte` being immune from those). --- MetadataExtractor/Formats/Tiff/TiffReader.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/MetadataExtractor/Formats/Tiff/TiffReader.cs b/MetadataExtractor/Formats/Tiff/TiffReader.cs index 78ab8c90c..ce1c776d7 100644 --- a/MetadataExtractor/Formats/Tiff/TiffReader.cs +++ b/MetadataExtractor/Formats/Tiff/TiffReader.cs @@ -1,5 +1,7 @@ // Copyright (c) Drew Noakes and contributors. All Rights Reserved. Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. +using System.Runtime.InteropServices; + namespace MetadataExtractor.Formats.Tiff { /// @@ -384,8 +386,8 @@ private static void ProcessTag(ITiffHandler handler, int tagId, int tagValueOffs else { var array = new sbyte[componentCount]; - for (var i = 0; i < componentCount; i++) - array[i] = reader.GetSByte(tagValueOffset + i); + var bytes = MemoryMarshal.Cast(array); + reader.GetBytes(tagValueOffset, bytes); handler.SetInt8SArray(tagId, array); } break; @@ -399,8 +401,7 @@ private static void ProcessTag(ITiffHandler handler, int tagId, int tagValueOffs else { var array = new byte[componentCount]; - for (var i = 0; i < componentCount; i++) - array[i] = reader.GetByte(tagValueOffset + i); + reader.GetBytes(tagValueOffset, array); handler.SetInt8UArray(tagId, array); } break;