Типы данных

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Re: Типы данных

Сообщение vitaly_l » 13.03.2018 14:02:29

MylnikovDm писал(а):Поэтому во втором случае у вас ассемблерный код по определению должен быть больше.

Нет они по командам - одинаковые, разница в одной команде. Inc и Move, а всё остальное одинаково (за исключением создания и удаления). Создание и удаление - я отбрасываю, т.к. это не серьёзное и мало-весомое отличие.
ElectroGuard писал(а):Никто же не мешает сделать прямой указатель на динамический массив.

Пример покажите пожалуйста, чтобы исключить недопонимание художников в программировании.
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: Типы данных

Сообщение MylnikovDm » 13.03.2018 15:40:45

Нет они по командам - одинаковые, разница в одной команде. Inc и Move, а всё остальное одинаково (за исключением создания и удаления).


Давайте посчитаем.

arr^ := b; - переводится в три команды процессора:
mov 0x42c000, %edx - записываем значение указателя arr с адреса 0x42c000 в регистр edx - чтение в регистр из памяти
mov 0x42c010, %al - записываем значение переменной b с адреса 0x42c010 в регистр al - чтение в регистр из памяти
mov %al, (%edx) - записываем значение регистра al (переменная b) в ячейку памяти по адресу в регистре edx (arr^) - запись из регистра в память

inc(arr); - смещаем указатель
addl 0x01, 0x42c000 - прямое прибавление 1 к значению в ячейке памяти 0x42c000, то есть, тут на самом деле происходит чтение и запись в одной команде.

Итого получаем три чтения из памяти в регистр и две записи из регистра в память

Теперь рассмотрим второй вариант.

arr[b] := b;
mov 0x42c000, %eax - записываем значение указателя arr с адреса 0x42c000 в регистр eax - чтение в регистр из памяти
movzbl 0x42c010, %edx - записываем значение переменной b с адреса 0x42c010 в регистр edx c дополнением нулями до 64 бит - чтение в регистр из памяти
mov 0x42c010, %al - записываем значение переменной b с адреса 0x42c010 в регистр al - чтение в регистр из памяти
mov %сl, (%eax, %edx, 1) - записываем значение регистра cl (переменная b) в ячейку памяти по адресу в регистрaх eax+edx (arr[b]) - запись из регистра в память

Получаем три чтения из памяти в регистр и одну запись из регистра в память.

И, что интересно, в случае с массивом получается на одну операцию записи в память меньше. Все остальные команды обработки цикла в обоих случаях одинаковые.

Но в целом ассемблерный код как-то не особо порадовал. Оптимизация как таковая отсутствует. Регистровые переменные не используются, идёт постоянная загрузка данных, которые уже и так находятся в регистрах процессора. Зачем?
MylnikovDm
постоялец
 
Сообщения: 103
Зарегистрирован: 15.02.2007 21:26:10
Откуда: Челябинск

Re: Типы данных

Сообщение serbod » 13.03.2018 16:47:39

MylnikovDm а зачем лезть во внутреннюю структуру, когда можно взять указатель на первый элемент? А дальше через арифметику указателей можно любой элемент прочитать. С риском выстрелить в ногу, но зато очень быстро.

Код: Выделить всё
var p: Pointer; // или PByte, для удобства
var arr: array of Byte;
var str: string;

p := @arr[0];

p := s[1];  // будет больно, если s = ''
p := PChar(s); // а так будет норм


Добавлено спустя 3 минуты 8 секунд:
MylnikovDm писал(а):Оптимизация как таковая отсутствует.

Возможно, для удобства отладки.
Аватара пользователя
serbod
постоялец
 
Сообщения: 449
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

Re: Типы данных

Сообщение vitaly_l » 13.03.2018 18:03:44

MylnikovDm писал(а):arr^ := b; - переводится в три команды процессора:
mov 0x42c000, %edx - записываем значение указателя arr с адреса 0x42c000 в регистр edx - чтение в регистр из памяти
mov 0x42c010, %al - записываем значение переменной b с адреса 0x42c010 в регистр al - чтение в регистр из памяти
mov %al, (%edx) - записываем значение регистра al (переменная b) в ячейку памяти по адресу в регистре edx (arr^) - запись из регистра в память

inc(arr); - смещаем указатель
addl 0x01, 0x42c000 - прямое прибавление 1 к значению в ячейке памяти 0x42c000, то есть, тут на самом деле происходит чтение и запись в одной команде.

Итого получаем три чтения из памяти в регистр и две записи из регистра в память

Теперь рассмотрим второй вариант.

arr[b] := b;
mov 0x42c000, %eax - записываем значение указателя arr с адреса 0x42c000 в регистр eax - чтение в регистр из памяти
movzbl 0x42c010, %edx - записываем значение переменной b с адреса 0x42c010 в регистр edx c дополнением нулями до 64 бит - чтение в регистр из памяти
mov 0x42c010, %al - записываем значение переменной b с адреса 0x42c010 в регистр al - чтение в регистр из памяти
mov %сl, (%eax, %edx, 1) - записываем значение регистра cl (переменная b) в ячейку памяти по адресу в регистрaх eax+edx (arr[b]) - запись из регистра в память

Получаем три чтения из памяти в регистр и одну запись из регистра в память.

Вы хотите сказать что, SetLength - работает быстрее чем GetMem?
Точнее из ваших слов, получается что, перебор цикла: SetLength - работает быстрее чем перебор цикла GetMem?
Что-то мне в это с трудом верится.

.
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: Типы данных

Сообщение MylnikovDm » 13.03.2018 19:04:00

Вы хотите сказать что, SetLength - работает быстрее чем GetMem?
Точнее из ваших слов, получается что, перебор цикла: SetLength - работает быстрее чем перебор цикла GetMem?
Что-то мне в это с трудом верится.

А тут не надо верить мне или не верить. Просто возьмите и сами проанализируйте ассемблерный листинг, который вы же тут и опубликовали, посчитайте количество обращений к памяти и сами убедитесь, что в приведённом вами варианте компиляции обращение через указатель и его инкремент работает медленнее, чем через массив и индекс. При этом экономия возникает за счёт того, что индекс смещается отдельными командами вне команд обращения к элементу, поэтому запись его значения не происходит, а в случае с инкрементом указателя происходит дополнительная запись значения обратно в память.
На самом деле, если эти варианты оптимизировать на ассемблере, то оба варианта можно значительно ускорить за счёт использования регистровых переменных. Но компилятор FreePascal этого не делает. Возможно потому, что отключена оптимизация для режима отладки.

Да, насколько я сейчас понимаю логику работы компилятора, статический массив с индексом будет работать примерно также, как динамический массив с SetLength. То есть, тут дело не столько в SetLength, сколько в в способе адресации элемента массива, поскольку для случая элемент массива по индексу в процессоре есть специальный вариант команды с адресацией через два регистра, в одном из которых базовый адрес, а во втором смещение на нужный элемент.
MylnikovDm
постоялец
 
Сообщения: 103
Зарегистрирован: 15.02.2007 21:26:10
Откуда: Челябинск

Re: Типы данных

Сообщение Mirage » 14.03.2018 00:09:22

Как относится SetLength vs GetMem к адресации? Тем более, что аналогом SetLength является не GetMem, а ReallocMem.
И для динамического массива ничто не мешает взять адрес первого элемента: @a[0] и работать с ним как с указателем.
Другое дело, что неплохо было бы чтобы компилятор научился переводить обращения по индексу работу с указателями...
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Типы данных

Сообщение MylnikovDm » 14.03.2018 01:35:31

И для динамического массива ничто не мешает взять адрес первого элемента: @a[0] и работать с ним как с указателем.

Из того ассемблерного когда, листинг которого был опубликован, следует, что именно работа через индекс в массиве оказывается быстрее, чем работа через указатель с инкрементом. А так-то да, можно выдернуть адрес любого элемента массива и работать с ним напрямую. Но если писать такой код, то тогда непонятно, а на кой вам вообще FreePascal? Писали бы уже сразу на ассемблере и работали непосредственно с указателями. :D
MylnikovDm
постоялец
 
Сообщения: 103
Зарегистрирован: 15.02.2007 21:26:10
Откуда: Челябинск

Re: Типы данных

Сообщение vitaly_l » 14.03.2018 18:20:40

Mirage писал(а):аналогом SetLength является не GetMem, а ReallocMem


Если сделать:
ReallocMem(somePointer, 0);
somePointer:=nil;

так можно освобождать память?

Это будет равнозначно освобождению памяти как в SetLength(arr,0); ?
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: Типы данных

Сообщение Mirage » 14.03.2018 21:27:25

MylnikovDm писал(а):Из того ассемблерного когда, листинг которого был опубликован, следует, что именно работа через индекс в массиве оказывается быстрее, чем работа через указатель с инкрементом.


Чет сомнительно. Да и из листинга это не может следовать - только их тестов.

MylnikovDm писал(а):Но если писать такой код, то тогда непонятно, а на кой вам вообще FreePascal? Писали бы уже сразу на ассемблере и работали непосредственно с указателями.


Никто не предлагает так писать весь код. Только в тех немногих местах, где критична производительность.

vitaly_l писал(а):Это будет равнозначно освобождению памяти как в SetLength(arr,0); ?


Да, это освободит память.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Типы данных

Сообщение MylnikovDm » 15.03.2018 00:11:41

Чет сомнительно. Да и из листинга это не может следовать - только их тестов.

??? То есть, вы действительно считаете, что если у вас физически происходит на одну запись в память из регистра процессора больше, то при натурных тестах вы можете получить противоположный результат?
MylnikovDm
постоялец
 
Сообщения: 103
Зарегистрирован: 15.02.2007 21:26:10
Откуда: Челябинск

Re: Типы данных

Сообщение Mirage » 15.03.2018 01:49:21

Это код без оптимизации видимо, раз указатель в памяти держится.
В нормальном коде указатель будет в регистре и доступ к памяти будет только при записи собственно по указателю.
Как и в случае с обращением по индексу. Просто в этом случае надо еще вычислить указатель по базовому смещению и индексу.
Так что обращение по указателю должно быть быстрее, чем по индексу. Но будет ли это заметно быстрее покажут только тесты.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Типы данных

Сообщение MylnikovDm » 15.03.2018 13:33:30

В нормальном коде указатель будет в регистре и доступ к памяти будет только при записи собственно по указателю.

В нормальном коде на ассемблере можно много чего написать по другому, чтобы оно работало быстрее. Но мы тут вроде обсуждали какие конструкции FreePascal лучше использовать при написании программ именно на FreePascal, а не на ассемблере. И пока вы конкретными фактами (листингом дизассемблера) не подтвердите, что компилятор FreePascal умеет генерировать другой, более эффективный код, это всё словоблудие и обсуждать тут нечего.

При этом вы правы в том, что на практике сравнивать быстродействие того или иного реального варианта кода следует именно с помощью тестов. Но в реальном коде весьма редко встречаются такие примитивные задачи, которая была использована в обсуждаемом примере. Да и настройки оптимизатора у компилятора тоже могут быть разные. Можно стараться повысить быстродействие программы, а можно пытаться сократить размер получаемого кода. И вовсе не факт, что вариант, который оказался быстрее в первом случае, окажется быстрее и во втором случае тоже.
MylnikovDm
постоялец
 
Сообщения: 103
Зарегистрирован: 15.02.2007 21:26:10
Откуда: Челябинск

Re: Типы данных

Сообщение bormant » 15.03.2018 18:47:54

Ежели что, у компилятора есть ключи оптимизации, влияющие на вид конечного кода, одна и та же последовательность паскалевых операторов способна давать разный ассемблерный код. Поэтому есть смысл проверить кодогенерацию при разных -On.
Аватара пользователя
bormant
постоялец
 
Сообщения: 407
Зарегистрирован: 21.03.2012 11:26:01

Re: Типы данных

Сообщение Mirage » 15.03.2018 19:42:04

Не думаю, что надо проверять способность компилятора размещать интенсивно используемые в цикле переменные в регистрах. Если бы он этого не умел, то интерес разве что академический представлял. :D
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Пред.

Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5

Рейтинг@Mail.ru