Skip to content

Instantly share code, notes, and snippets.

@thargy
Created September 23, 2016 07:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thargy/5a025aaae1924e5525afa3be053e0d16 to your computer and use it in GitHub Desktop.
Save thargy/5a025aaae1924e5525afa3be053e0d16 to your computer and use it in GitHub Desktop.
Test Memory Mapped File (C#)
<Query Kind="Program">
<Reference>&lt;RuntimeDirectory&gt;\System.Runtime.InteropServices.dll</Reference>
<Namespace>Microsoft.Win32.SafeHandles</Namespace>
<Namespace>System.IO.MemoryMappedFiles</Namespace>
<Namespace>System.Runtime.InteropServices</Namespace>
</Query>
void Main()
{
for (int i = 0; i < 3; i++)
{
Test(100000, 32);
"".Dump();
Test(50000, 1024);
"".Dump();
Test(3000, 32*1024);
"".Dump();
}
}
void Test(int loops, long bufferSize, long size = (long)1024*1024*1024*16)
{
long t1,t2,t3,t4,t5;
string worldFile = Path.GetTempFileName();
//worldFile.Dump();
try
{
using (FileStream f = File.Create(worldFile))
{
// Try to mark file as sparse, if this fails then we allocate 16GB.
if (!MarkAsSparseFile(f))
"Failed to create world as sparse file.".Dump();
// Set file length
f.SetLength(size);
f.Close();
}
byte[] buffer = new byte[bufferSize];
byte[] buffer2 = new byte[bufferSize];
Stopwatch s= new Stopwatch();
GC.Collect();
GC.WaitForFullGCComplete();
Array.Copy(buffer, buffer2, buffer.Length);
s.Start();
for (int i = 0; i < loops; i++)
Array.Copy(buffer, buffer2, buffer.Length);
s.Stop();
t1 = s.ElapsedTicks;
string.Format("{0} bytes array copy total: {1} ms. {2} ms x {3}",
bufferSize,
s.Elapsed.TotalMilliseconds,
s.Elapsed.TotalMilliseconds/loops,
loops).Dump();
using (MemoryMappedFile m = MemoryMappedFile.CreateFromFile(worldFile))
{
GC.Collect();
GC.WaitForFullGCComplete();
using (MemoryMappedViewStream a = m.CreateViewStream(1000, buffer.Length, MemoryMappedFileAccess.Read))
{
a.Read(buffer, 0, buffer.Length);
s.Restart();
for (int i = 0; i < loops; i++)
{
a.Seek(0, SeekOrigin.Begin);
a.Read(buffer, 0, buffer.Length);
}
}
s.Stop();
t2 = s.ElapsedTicks;
string.Format("{0} bytes single view stream copy total: {1} ms. {2} ms x {3}",
bufferSize,
s.Elapsed.TotalMilliseconds,
s.Elapsed.TotalMilliseconds/loops,
loops).Dump();
}
using (MemoryMappedFile m = MemoryMappedFile.CreateFromFile(worldFile))
{
GC.Collect();
GC.WaitForFullGCComplete();
using (MemoryMappedViewStream a = m.CreateViewStream(1000, buffer.Length, MemoryMappedFileAccess.Read))
{
a.Read(buffer, 0, buffer.Length);
}
s.Restart();
for (int i = 0; i < loops; i++)
{
using (MemoryMappedViewStream a = m.CreateViewStream(1000, buffer.Length, MemoryMappedFileAccess.Read))
{
a.Read(buffer, 0, buffer.Length);
}
}
s.Stop();
t3 = s.ElapsedTicks;
string.Format("{0} bytes multiple view stream copy total: {1} ms. {2} ms x {3}",
bufferSize,
s.Elapsed.TotalMilliseconds,
s.Elapsed.TotalMilliseconds/loops,
loops).Dump();
}
using (MemoryMappedFile m = MemoryMappedFile.CreateFromFile(worldFile))
{
GC.Collect();
GC.WaitForFullGCComplete();
using (MemoryMappedViewAccessor a = m.CreateViewAccessor(1000, buffer.Length))
{
a.ReadArray(0, buffer,0, buffer.Length);
s.Restart();
for (int i = 0; i < loops; i++)
{
a.ReadArray(0, buffer,0, buffer.Length);
}
}
s.Stop();
t4 = s.ElapsedTicks;
string.Format("{0} bytes single accessor copy total: {1} ms. {2} ms x {3}",
bufferSize,
s.Elapsed.TotalMilliseconds,
s.Elapsed.TotalMilliseconds/loops,
loops).Dump();
}
using (MemoryMappedFile m = MemoryMappedFile.CreateFromFile(worldFile))
{
GC.Collect();
GC.WaitForFullGCComplete();
using (MemoryMappedViewAccessor a = m.CreateViewAccessor(1000, buffer.Length))
{
a.ReadArray(0, buffer,0, buffer.Length);
}
s.Restart();
for (int i = 0; i < loops; i++)
{
using (MemoryMappedViewAccessor a = m.CreateViewAccessor(1000, buffer.Length))
{
a.ReadArray(0, buffer,0, buffer.Length);
}
}
s.Stop();
t5 = s.ElapsedTicks;
string.Format("{0} bytes multiple accessor copy total: {1} ms. {2} ms x {3}",
bufferSize,
s.Elapsed.TotalMilliseconds,
s.Elapsed.TotalMilliseconds/loops,
loops).Dump();
}
"".Dump();
string.Format("single vs/array: {0:F3}", (double)t2/t1).Dump();
string.Format("multi vs/array: {0:F3}", (double)t3/t1).Dump();
string.Format("multi vs/single vs: {0:F3}", (double)t3/t2).Dump();
"".Dump();
string.Format("single ac/array: {0:F3}", (double)t4/t1).Dump();
string.Format("multi ac/array: {0:F3}", (double)t5/t1).Dump();
string.Format("multi vs/single vs: {0:F3}", (double)t4/t5).Dump();
"".Dump();
string.Format("single ac/single vs: {0:F3}", (double)t4/t2).Dump();
string.Format("multi ac/multi vs: {0:F3}", (double)t5/t3).Dump();
new string('-',80).Dump();
} finally {
File.Delete(worldFile);
//File.Exists(worldFile).Dump();
}
}
// Define other methods and classes here
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool DeviceIoControl(
SafeFileHandle hDevice,
int dwIoControlCode,
IntPtr InBuffer,
int nInBufferSize,
IntPtr OutBuffer,
int nOutBufferSize,
ref int pBytesReturned,
[In] ref NativeOverlapped lpOverlapped
);
public static bool MarkAsSparseFile(FileStream fileStream)
{
int bytesReturned = 0;
NativeOverlapped lpOverlapped = new NativeOverlapped();
return DeviceIoControl(
fileStream.SafeFileHandle,
590020, //FSCTL_SET_SPARSE,
IntPtr.Zero,
0,
IntPtr.Zero,
0,
ref bytesReturned,
ref lpOverlapped);
}
@thargy
Copy link
Author

thargy commented Sep 23, 2016

For full details on using this Gist, visit Memory mapped file performance on thargy.com

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment