Как аннулировать кеш при бенчмаркинге?

У меня есть этот код, который при замене порядка UsingAs и UsingCast их производительность также свопит.

using System;
using System.Diagnostics;
using System.Linq;

using System.IO;

class Test
{
    const int Size = 30000000;

    static void Main()
    {
        object[] values = new MemoryStream[Size];



        UsingAs(values);
        UsingCast(values);


        Console.ReadLine();
    }

    static void UsingCast(object[] values)
    {
        Stopwatch sw = Stopwatch.StartNew();
        int sum = 0;
        foreach (object o in values)
        {
            if (o is MemoryStream)
            {
                var m = (MemoryStream)o;
                sum += (int)m.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("Cast: {0} : {1}", sum,
                          (long)sw.ElapsedMilliseconds);
    }

    static void UsingAs(object[] values)
    {
        Stopwatch sw = Stopwatch.StartNew();
        int sum = 0;
        foreach (object o in values)
        {

            if (o is MemoryStream)
            {
                var m = o as MemoryStream;
                sum += (int)m.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("As: {0} : {1}", sum,
                          (long)sw.ElapsedMilliseconds);
    }


}

Выходы:

As: 0 : 322
Cast: 0 : 281

При этом...

UsingCast(values);
UsingAs(values);

... Результат:

Cast: 0 : 322
As: 0 : 281

Выполняя только это...

UsingAs(values);

... Результат:

As: 0 : 322

Выполняя только это:

UsingCast(values);

... Результат:

Cast: 0 : 322

Помимо запуска их независимо, как сделать недействительным кеш, чтобы второй тестируемый код не получал кэшированную память первого кода?

Сравнительный анализ, просто понравился тот факт, что современные процессоры делают эту кеширующую магию: -)

[EDIT]

Как рекомендуется попробовать этот более быстрый код (предположительно)...

static void UsingAsAndNullTest(object[] values)
{        
    Stopwatch sw = Stopwatch.StartNew();
    int sum = 0;
    foreach (object o in values)
    {
        var m = o as MemoryStream;
        if (m != null)
        {                
            sum += (int)m.Length;
        }
    }
    sw.Stop();
    Console.WriteLine("As and null test: {0} : {1}", sum,
                      (long)sw.ElapsedMilliseconds);
}

... В результате получается следующее:

As and null test: 0 : 342

Медленнее, чем два кода выше

[EDIT]:

Как посоветовали вручить каждой рутине свою собственную копию...

static void UsingAs(object[] values)
{
    object[] a = values.ToArray();

    Stopwatch sw = Stopwatch.StartNew();
    int sum = 0;
    foreach (object o in a)
    {

        if (o is MemoryStream)
        {
            var m = o as MemoryStream;
            sum += (int)m.Length;
        }
    }
    sw.Stop();
    Console.WriteLine("As: {0} : {1}", sum,
                      (long)sw.ElapsedMilliseconds);
}

static void UsingCast(object[] values)
{
    object[] a = values.ToArray();

    Stopwatch sw = Stopwatch.StartNew();
    int sum = 0;
    foreach (object o in a)
    {
        if (o is MemoryStream)
        {
            var m = (MemoryStream)o;
            sum += (int)m.Length;
        }
    }
    sw.Stop();
    Console.WriteLine("Cast: {0} : {1}", sum,
                      (long)sw.ElapsedMilliseconds);
}

... Выходы:

Cast: 0 : 282
As: 0 : 282

Теперь они имеют одинаковые результаты, благодаря Remus!

Запуск Cast и As независимо, они также дают тот же результат (то есть 282). Теперь о том, почему они становятся быстрее (от 322 до 282 миллисекунд), когда им передают свою собственную копию массива, я ничего не могу сделать из этого:-) Это совсем другая история

Ответы

Ответ 1

Если вы хотите извлечь из изображения кеш L2 и пропуски TLB, тогда просто вызовите второй тест на другой MemoryStream того же размера.