Re[5]: почему так медленно?
От: alexzzzz  
Дата: 11.06.19 16:24
Оценка:
Здравствуйте, CodeMonkey, Вы писали:

CM>Не 2/3, а 32% согласно профайлеру. Разницу в разы это не объясняет.


У меня заходит за 60%.

A>>Получается, рантайм NET Framework такой умный, что знает, что Windows отдаёт процессу уже занулённые страницы, поэтому самостоятельно массив нулями не инициализирует.

CM>Не такой и умный, если это просаживает производительность.

Так наоборот же. Рантайм не тратит время на то, что и так было сделано. В таком же тесте классов ошибок страниц в 1,5 раза больше, потому что памяти требуется больше. У классов они просто не включались в измерения, а у структур включались.

  C#
using System;
using System.Diagnostics;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        var num = 10_000_000;
        var processName = Process.GetCurrentProcess().ProcessName;
        var pageFaultsCounter = new PerformanceCounter("Process", "Page Faults/sec", processName);

        {
            var data = new TestClass[num];
            Console.WriteLine($"1) {pageFaultsCounter.RawValue} page faults");

            //PrintGCollections();
            for (var i = 0; i < data.Length; i++)
            {
                data[i] = new TestClass();
            }
            //PrintGCollections();
            Console.WriteLine($"2) {pageFaultsCounter.RawValue} page faults");

            var watch = Stopwatch.StartNew();
            for (var i = 0; i < data.Length; i++)
            {
                data[i].Number0 = 10;
                data[i].Number1 = 20;
            }
            watch.Stop();
            Console.WriteLine($"3) {pageFaultsCounter.RawValue} page faults");
            Console.WriteLine(watch.Elapsed.TotalSeconds);
        }

        {
            var data = new TestStruct[num];
            Console.WriteLine($"1) {pageFaultsCounter.RawValue} page faults");

            Array.Clear(data, 0, data.Length);
            Console.WriteLine($"2) {pageFaultsCounter.RawValue} page faults");

            var watch = Stopwatch.StartNew();
            for (var i = 0; i < data.Length; i++)
            {
                data[i].Number0 = 10;
                data[i].Number1 = 20;
            }
            watch.Stop();
            Console.WriteLine($"3) {pageFaultsCounter.RawValue} page faults");
            Console.WriteLine(watch.Elapsed.TotalSeconds);
        }
    }

    private static void PrintGCollections()
    {
        Console.WriteLine("GC: " + string.Join(", ", Enumerable.Range(0, GC.MaxGeneration + 1).Select(GC.CollectionCount)));
    }

    struct TestStruct
    {
        public long Number0;
        public long Number1;
        public long Temp0;
        public long Temp1;
        public long Temp2;
        public long Temp3;
        public long Temp4;
        public long Temp5;
        public long Temp6;
        public long Temp7;
    }

    class TestClass
    {
        public long Number0;
        public long Number1;
        public long Temp0;
        public long Temp1;
        public long Temp2;
        public long Temp3;
        public long Temp4;
        public long Temp5;
        public long Temp6;
        public long Temp7;
    }
}

1) 36837 page faults
2) 345167 page faults
3) 345640 page faults
0,1460079
1) 350326 page faults
2) 546109 page faults
3) 546580 page faults
0,1018719


Структуры стабильно быстрее.
Отредактировано 11.06.2019 16:28 alexzzzz . Предыдущая версия . Еще …
Отредактировано 11.06.2019 16:28 alexzzzz . Предыдущая версия .
Re[6]: почему так медленно?
От: Sharov Россия  
Дата: 11.06.19 16:30
Оценка:
Здравствуйте, alexzzzz, Вы писали:

A>Так наоборот же. Рантайм не тратит время на то, что и так было сделано. В таком же тесте классов ошибок страниц в 1,5 раза больше, потому что памяти требуется больше. У классов они просто не включались в измерения, а у структур включались.



A>}[/cs][/cut]

A>
1) 36837 page faults
A>2) 345167 page faults
A>3) 345640 page faults
A>0,1460079
A>1) 350326 page faults
A>2) 546109 page faults
A>3) 546580 page faults
A>0,1018719


А не меньше? А то цифры показывают другое?
Кодом людям нужно помогать!
Re[6]: почему так медленно?
От: CodeMonkey  
Дата: 11.06.19 16:38
Оценка:
Здравствуйте, alexzzzz, Вы писали:

A>У классов они просто не включались в измерения, а у структур включались.


Почему это не включались?
Re[7]: почему так медленно?
От: alexzzzz  
Дата: 11.06.19 16:54
Оценка: 12 (1)
Здравствуйте, Sharov, Вы писали:

S>А не меньше? А то цифры показывают другое?


Не. Цифры показывают количество ошибок, накопленное со старта процесса. Тут интересны скачки. Инициализация массива объектов добавила примерно 300 тысяч ошибок, инициализация массива структур ― примерно 200 тысяч.

PS
Строго говоря, счётчик показывает количество ошибок в секунду (Page Faults/sec), но так как вся работа занимает меньше секунды, то можно считать, что это накопленное количество ошибок со старта процесса.
Отредактировано 09.07.2019 8:34 alexzzzz . Предыдущая версия .
Re[7]: почему так медленно?
От: alexzzzz  
Дата: 11.06.19 17:04
Оценка:
Здравствуйте, CodeMonkey, Вы писали:

A>>У классов они просто не включались в измерения, а у структур включались.

CM>Почему это не включались?

Ну у karbofos42 так в тесте получилось: http://rsdn.org/forum/dotnet/7466200.1
Автор: karbofos42
Дата: 09.06.19


У классов все ошибки происходят в первом цикле в строке
data[i] = new TestClass();

до запуска таймера.
Отредактировано 11.06.2019 17:05 alexzzzz . Предыдущая версия .
Re[8]: почему так медленно?
От: CodeMonkey  
Дата: 11.06.19 17:15
Оценка:
Здравствуйте, alexzzzz, Вы писали:

A>Ну у karbofos42 так в тесте получилось: http://rsdn.org/forum/dotnet/7466200.1
Автор: karbofos42
Дата: 09.06.19


A>У классов все ошибки происходят в первом цикле в строке

A>
data[i] = new TestClass();

A>до запуска таймера.

А в моих замерах — включалось.
Re[9]: почему так медленно?
От: alexzzzz  
Дата: 11.06.19 20:39
Оценка: 6 (1)
Здравствуйте, CodeMonkey, Вы писали:

CM>А в моих замерах — включалось.


У тебя 150-160 пусков GC, которому требуется постоянно увеличивать кучу, помечать объекты живыми, перекидывать их из поколения в поколение (хотя сами объекты в памяти вроде не перемещаются). Процессорному кэшу при этом тоже вряд ли хорошо. Объектов в пике 10 миллионов.

Массив структур же достаточно один раз линейно пробежать. Половина времени тратится на soft page faults, вторая половина на собственно запись полей.

Скачал на попробовать dotTrace. Режим Sampling показывает, что внутри GC от запуска к запуску проводится 60-80% времени. На пользовательский код приходится что-то типа 15% времени.

В Mono оригинальный тест с классами работает на полсекунды быстрее, чем в NET Framework, хотя GC в Mono запускается >220 раз.
Отредактировано 11.06.2019 20:40 alexzzzz . Предыдущая версия .
Re[10]: почему так медленно?
От: CodeMonkey  
Дата: 12.06.19 15:03
Оценка:
Здравствуйте, alexzzzz, Вы писали:

A>Скачал на попробовать dotTrace. Режим Sampling показывает, что внутри GC от запуска к запуску проводится 60-80% времени. На пользовательский код приходится что-то типа 15% времени.


Ага, у меня он самый. В этом режиме показывает 46% на сборку мусора и еще 33% какой-то Special. Что это за зверь?
Re: почему так медленно?
От: alexzzzz  
Дата: 12.06.19 16:58
Оценка:
Цикл с классами:



Первый call создаёт объект.
Второй call пишет его в массив. Пишет как-то слишком сложно. Подозреваю, что происходит какая-то проверка типов. Была мысль про ARRAY COVARIANCE: NOT JUST UGLY, BUT SLOW TOO, но решение из статьи заметно на скорость не повлияло.

Цикл со структурами:

Отредактировано 12.06.2019 19:08 alexzzzz . Предыдущая версия . Еще …
Отредактировано 12.06.2019 19:05 alexzzzz . Предыдущая версия .
Re[2]: почему так медленно?
От: CodeMonkey  
Дата: 12.06.19 18:46
Оценка: :)
Здравствуйте, alexzzzz, Вы писали:

"You IP is blacklisted...."

A>Второй call пишет его в массив. Пишет как-то слишком сложно. Подозреваю, что происходит какая-то проверка типов.


Скорее всего, это write barrier. Который здесь пока никто не упоминал
Re[3]: почему так медленно?
От: alexzzzz  
Дата: 12.06.19 19:57
Оценка:
Здравствуйте, CodeMonkey, Вы писали:

CM>Скорее всего, это write barrier. Который здесь пока никто не упоминал


Непохоже. Там проверки на выход на границы массива, ещё какие-то проверки, запись в массив и, кажется, ещё какая-то проверка.
Отредактировано 12.06.2019 19:59 alexzzzz . Предыдущая версия .
Re[4]: почему так медленно?
От: CodeMonkey  
Дата: 12.06.19 20:17
Оценка:
Здравствуйте, alexzzzz, Вы писали:

A>Там проверки на выход на границы массива, ещё какие-то проверки, запись в массив и, кажется, ещё какая-то проверка.


Нет, это не то.
Re: почему так медленно?
От: itmanager85  
Дата: 13.06.19 00:32
Оценка: 1 (1) -1 :)
Здравствуйте, CodeMonkey, Вы писали:

CM>Получается:


CM>1.6395053

CM>0.2299897

CM>Откуда здесь разница аж в 8 раз?


аххаха, смешно чувак открыл для себя что выделение памяти — не бесплатная операция .. (а тем более создание экземляра класса) ..

вкратце, в первом случае ты изначально выделил место под массив указателей на объекты класса, а потом выделяешь память (в цикле) — под каждый объект класса и присваиваешь указателю .. (ссылку на него)

очевидно что это дикий жир (в т.ч. требующий вызова системных функций и т.д.) — по сравнению с тем чтобы просто выделить память под массив (одним куском) и лупить (в цикле) туда пару значений переменных ..


вот тут показательный пример уже привели
http://rsdn.org/forum/dotnet/7467268.1
Автор: alexzzzz
Дата: 10.06.19
Отредактировано 13.06.2019 0:34 itmanager85 . Предыдущая версия .
Re[2]: почему так медленно?
От: itmanager85  
Дата: 13.06.19 07:04
Оценка: +1 -1 :)
Здравствуйте, itmanager85, Вы писали:

CodeMonkey, и за что же минус позвольте полюбопытствовать — или как то подгадить хочется а по сути возразить и нечего ?
Re: почему так медленно?
От: vvv848165@ya.ru  
Дата: 28.06.19 09:00
Оценка: :)
Здравствуйте, CodeMonkey, Вы писали:

new TestClass

new вызывает GC сборщик мусора до выделения памяти и обходит все переменные
Если б ты его распараллелил то разница была бы больше чем в 100 раз...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.