Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Reader classes, v3 #250

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.10.12" />
<PackageReference Include="BenchmarkDotNet.Core" Version="0.10.12" />
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
Expand Down
51 changes: 51 additions & 0 deletions MetadataExtractor.Benchmarks/NonSeekableStream.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// 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;
using System.IO;

namespace MetadataExtractor.Benchmarks
{
internal class NonSeekableStream : Stream
{
Stream m_stream;
internal NonSeekableStream(Stream baseStream)
{
m_stream = baseStream;
}

public override bool CanRead => m_stream.CanRead;

public override bool CanSeek => false;

public override bool CanWrite => m_stream.CanWrite;

public override long Length => throw new NotSupportedException();

public override long Position { get => m_stream.Position; set => throw new NotSupportedException(); }

public override void Flush()
{
m_stream.Flush();
}

public override int Read(byte[] buffer, int offset, int count)
{
return m_stream.Read(buffer, offset, count);
}

public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}

public override void SetLength(long value)
{
throw new NotSupportedException();
}

public override void Write(byte[] buffer, int offset, int count)
{
m_stream.Write(buffer, offset, count);
}
}
}
3 changes: 2 additions & 1 deletion MetadataExtractor.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ namespace MetadataExtractor.Benchmarks
{
internal static class Program
{
private static void Main() => BenchmarkRunner.Run<JpegBenchmark>();
//private static void Main() => BenchmarkRunner.Run<JpegBenchmark>();
private static void Main() => BenchmarkRunner.Run<RASBenchmark>();
}

/*
Expand Down
183 changes: 183 additions & 0 deletions MetadataExtractor.Benchmarks/RASBenchmark.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
using System;
using System.IO;

using BenchmarkDotNet.Attributes;

using MetadataExtractor.IO;

namespace MetadataExtractor.Benchmarks
{
[MemoryDiagnoser]
public class RASBenchmark
{
private readonly MemoryStream _stream;

private readonly ReaderInfo _reader;
public RASBenchmark()
{
_stream = new MemoryStream();

// This is the largest JPEG file in this repository
using var fs = File.OpenRead("../../../../MetadataExtractor.Tests/Data/nikonMakernoteType2b.jpg");
fs.CopyTo(_stream);

_reader = new RandomAccessStream(_stream).CreateReader();
}

[Benchmark(Baseline = true)]
public void RASListBenchmark()
{
_stream.Position = 0;

//var reader = new RandomAccessStream(_stream).CreateReader();
RunReader(_reader);
}


/*
[Benchmark]]
public void RASDictionaryBenchmark()
{
_stream.Position = 0;

var reader = new RandomAccessStreamDictionary(_stream).CreateReader();
RunReader(reader);
}

[Benchmark]
public void RASDictionaryNonseekableBenchmark()
{
_stream.Position = 0;

var reader = new RandomAccessStreamDictionary(new NonSeekableStream(_stream)).CreateReader();
RunReader(reader);
}

[Benchmark]
public void RASListNonseekableBenchmark()
{
_stream.Position = 0;

var reader = new RandomAccessStream(new NonSeekableStream(_stream)).CreateReader();
RunReader(reader);
}
*/


[Benchmark]
public void IndexedCapturingReaderBenchmark()
{
_stream.Position = 0;

var reader = new IndexedCapturingReader(_stream, 4096);
RunIndexedReader(reader);
}

[Benchmark]
public void IndexedSeekingReaderBenchmark()
{
_stream.Position = 0;

var reader = new IndexedSeekingReader(_stream);
RunIndexedReader(reader);
}

private void RunReader(ReaderInfo reader)
{
int offset = 4 * 1024 + 10; // skip over at least one buffer, just because

// Nothing mathematical intended here other than jumping around in the file
for (int i = 0; i < 10; i++)
{
var calcoffset2 = GetLongOffset(i, offset, 2);
var calcoffset3 = GetLongOffset(i, offset, 3);


reader.GetInt16(calcoffset2);
reader.GetInt16(calcoffset3);

reader.GetInt24(calcoffset2);
reader.GetInt24(calcoffset3);

reader.GetInt32(calcoffset2);
reader.GetInt32(calcoffset3);

reader.GetBytes(calcoffset2, 128);
reader.GetBytes(calcoffset3, 128);

reader.GetInt64(calcoffset2);
reader.GetInt64(calcoffset3);

for (int j = 0; j < 1000; j++)
{
reader.GetByte(calcoffset2 + j);
reader.GetByte(calcoffset3 + j);
}

reader.GetUInt16(calcoffset2);
reader.GetUInt16(calcoffset3);

reader.GetUInt32(calcoffset2);
reader.GetUInt32(calcoffset3);


//reader.GetUInt64(calcoffset2);
//reader.GetUInt64(calcoffset3);
}
}

private void RunIndexedReader(IndexedReader reader)
{
int offset = 4 * 1024 + 10; // skip over at least one buffer, just because

// Nothing mathematical intended here other than jumping around in the file
for (int i = 0; i < 10; i++)
{
var calcoffset2 = GetIntOffset(i, offset, 2);
var calcoffset3 = GetIntOffset(i, offset, 3);


reader.GetInt16(calcoffset2);
reader.GetInt16(calcoffset3);

reader.GetInt24(calcoffset2);
reader.GetInt24(calcoffset3);

reader.GetInt32(calcoffset2);
reader.GetInt32(calcoffset3);

reader.GetBytes(calcoffset2, 128);
reader.GetBytes(calcoffset3, 128);

reader.GetInt64(calcoffset2);
reader.GetInt64(calcoffset3);

for (int j = 0; j < 1000; j++)
{
reader.GetByte(calcoffset2 + j);
reader.GetByte(calcoffset3 + j);
}

reader.GetUInt16(calcoffset2);
reader.GetUInt16(calcoffset3);

reader.GetUInt32(calcoffset2);
reader.GetUInt32(calcoffset3);


//reader.GetUInt64(calcoffset2);
//reader.GetUInt64(calcoffset3);
}
}

private static long GetLongOffset(int i, long offset, int power)
{
return (long)(i * offset + Math.Pow(power, i));
}

private static int GetIntOffset(int i, long offset, int power)
{
return (int)(i * offset + Math.Pow(power, i));
}
}
}
51 changes: 51 additions & 0 deletions MetadataExtractor.Tests/IO/RAS/NonSeekableStream.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// 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;
using System.IO;

namespace MetadataExtractor.Tests.IO
{
internal class NonSeekableStream : Stream
{
Stream m_stream;
internal NonSeekableStream(Stream baseStream)
{
m_stream = baseStream;
}

public override bool CanRead => m_stream.CanRead;

public override bool CanSeek => false;

public override bool CanWrite => m_stream.CanWrite;

public override long Length => throw new NotSupportedException();

public override long Position { get => m_stream.Position; set => throw new NotSupportedException(); }

public override void Flush()
{
m_stream.Flush();
}

public override int Read(byte[] buffer, int offset, int count)
{
return m_stream.Read(buffer, offset, count);
}

public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}

public override void SetLength(long value)
{
throw new NotSupportedException();
}

public override void Write(byte[] buffer, int offset, int count)
{
m_stream.Write(buffer, offset, count);
}
}
}
27 changes: 27 additions & 0 deletions MetadataExtractor.Tests/IO/RAS/RasByteArrayReaderTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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;
using MetadataExtractor.IO;
using Xunit;

namespace MetadataExtractor.Tests.IO
{
/// <summary>Unit tests for <see cref="RandomAccessStream"/> with indexed reading on a byte array.</summary>
/// <author>Drew Noakes https://drewnoakes.com</author>
/// <author>Kevin Mott https://github.com/kwhopper</author>
public sealed class RasByteArrayReaderTest : RasIndexedTestBase
{
protected override ReaderInfo CreateReader(params byte[] bytes)
{
return ReaderInfo.CreateFromArray(bytes);
}

[Fact]
public void ConstructWithNullBufferThrows()
{
// ReSharper disable once AssignNullToNotNullAttribute
Assert.Throws<ArgumentNullException>(() => CreateReader(null!));
}

}
}
27 changes: 27 additions & 0 deletions MetadataExtractor.Tests/IO/RAS/RasIndexedCapturingReaderTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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;
using System.IO;
using MetadataExtractor.IO;
using Xunit;

namespace MetadataExtractor.Tests.IO
{
/// <summary>Unit tests for <see cref="RandomAccessStream"/> with indexed reading on a MemoryStream.</summary>
/// <author>Drew Noakes https://drewnoakes.com</author>
/// <author>Kevin Mott https://github.com/kwhopper</author>
public sealed class RasIndexedCapturingReaderTest : RasIndexedTestBase
{
[Fact]
public void ConstructWithNullBufferThrows()
{
// ReSharper disable once AssignNullToNotNullAttribute
Assert.Throws<ArgumentNullException>(() => ReaderInfo.CreateFromStream(null!));
}

protected override ReaderInfo CreateReader(params byte[] bytes)
{
return ReaderInfo.CreateFromStream(new MemoryStream(bytes));
}
}
}
Loading