Re[2]: тест с матрицами
От: Pavel Dvorkin Россия  
Дата: 30.09.05 11:50
Оценка:
Здравствуйте, Serginio1, Вы писали:

S> Что то вроде такого (ghjie ghjotybz pf jib,rb). Это же можно применть и для джагед массивов

S> for(i = 0; i < nSize; i++)
S> {
S> for(j = 0; j < nSize; j++)
S> {
S> temp = 0;
S> fixed(float* aa=&а[i],float* bb=&b[0,j])
S> {
S> for( k = 0; k < nSize; k++, аа++, b+=nSize)
S> temp += *aa * *b;
S> }
S> c[i,j] = temp;
S> }
S> }

Компилятор на твой код ругается нещадно. Не принимает

fixed(float* aa=&а[i],float* bb=&b[0,j])

Когда я ее разделил на

fixed(float* aa=&а[i])
fixed(float* bb=&b[0,j])

начал ругаться на число индексов у b (и он прав здесь) и т.д. Если сможешь — исправь и оттранслируй сам
With best regards
Pavel Dvorkin
Re[3]: тест с матрицами
От: HotDog Швейцария www.denebspace.com
Дата: 30.09.05 12:04
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

VD>>Кстати, твой код на моей машине показывает 16 секунд. Так что более чем на треть чем на твоей плюсовый.

PD>Кстати, просьба ко всем, кто это читает и имеет 10 минут свободного времени. Пропустите мой тест (самый первую программу на С# из http://www.rsdn.ru/Forum/Message.aspx?mid=1408480&amp;only=1
Автор: Pavel Dvorkin
Дата: 29.09.05
) и сообщите время, ну и характерстики PC.


Первый пример работает 36 секунд (только я там int i,j,k,nSize = 10; на int i,j,k,nSize = 1000; поменял)
Второй (оптимизированый) работает 26 секунд.

FW 1.1

комп пентюх IV, 3.2 GHz, 1 гиг памяти.
Re[3]: тест с матрицами
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 30.09.05 12:14
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:


PD>Компилятор на твой код ругается нещадно. Не принимает


PD>fixed(float* aa=&а[i],float* bb=&b[0,j])


PD>Когда я ее разделил на


PD>fixed(float* aa=&а[i])

PD> fixed(float* bb=&b[0,j])

PD>начал ругаться на число индексов у b (и он прав здесь) и т.д. Если сможешь — исправь и оттранслируй сам

К сожалению под рукой нет студии
для float [,] а,в;
Ругаться должен на float* aa=&а[i]

fixed(float* aa=&а[i,0],float* bb=&b[0,j])
... << RSDN@Home 1.1.4 stable rev. 510>>
и солнце б утром не вставало, когда бы не было меня
Re[4]: тест с матрицами
От: Pavel Dvorkin Россия  
Дата: 30.09.05 12:29
Оценка:
Здравствуйте, HotDog, Вы писали:

HD>Первый пример работает 36 секунд (только я там int i,j,k,nSize = 10; на int i,j,k,nSize = 1000; поменял)


Да, я там не заметил эту ошибку.

HD>Второй (оптимизированый) работает 26 секунд.


HD>FW 1.1


HD>комп пентюх IV, 3.2 GHz, 1 гиг памяти.


Странно. Не можешь прислать EXE на мэйл (есть в личных данных). У меня 1.6 GHz, 768 Мб. Должно быть медленнее, но настолько ?
With best regards
Pavel Dvorkin
Re[4]: тест с матрицами
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 30.09.05 12:35
Оценка:
Здравствуйте, Serginio1, Вы писали:


S> для float [][] а,в;

унсейв выглядит так

 for(i = 0; i < nSize; i++)
{
for(j = 0; j < nSize; j++)
{
temp = 0;
fixed(float* aa=а[i])
{
for( k = 0; k < nSize; k++, аа++)
 fixed(float* bb=b[k]
 {
temp += *aa * bb[j];
}
}
c[i,j] = temp;
}
}
... << RSDN@Home 1.1.4 stable rev. 510>>
и солнце б утром не вставало, когда бы не было меня
Re[3]: тест с матрицами
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.09.05 16:47
Оценка: 56 (5) +1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>А что такое райт-барьера, если не секрет ?


Не сикрет, но этот вопрос требует серьезного объяснения.

На пальцах...

Для того чтобы при сборе мусора небыло заметных на глаз задержек (ведь графы объектов могут быть любого размера) сборщик мусора делит управляемый хип на три подхипа:
1. Нулевое поколение — объекты которые только что порождены.
2. Первое поколение — объекты которые прошли первую сборку мусора и при этом на них остались ссылки.
3. Второе поколение — объекты которые прошли 2 или более сборки мусора.

Третье поголнеие — это долгоживующие объекты. Нулевое очень короткоживующие. Из нулевого поколения объекты или попадают в 1 и затем во второе, или быстренько умирают. В большинстве приложений 90% и более процентов обектов нулевого поколения помирают не переходя в первое поколения. Ну, а первое поколение является своеобразным буфером непозволяющим залетать во второе поколение случайным объектом.

Сборка нулевого поколения происходит очень быстро. Это поколение можно назвать вторым стеком (точнее выделение памяти из него несколько медленее выделения памяти в стеке, но все же бизок к тому).

При сборке нулевого поколения очень важно не анализировать первое и темболее второе поколение. Именно это позволяет собирать нулевое поколение очень быстро. Но тут возникает одна проблема. На объекты из нулевого поколения может быть сделана ссылка из других поколений. А это означает, что прийдется стрить полный граф объектов анализируя все поколения. Чтобы этого не делать в любой код модифицирующий ссылки вставляется вызов метода проверящий к какому поколения отностися объект. Если объект из нулевого поколения, а ссылка делается внутри хипа непренадлежащего к нулевому поколению, то такая ссылка помещатся в специальный список так называемых корней поколения. Этот списк и анализируется при сборке мусора нулевого поколения.

Таким образом модификация указателей в дотнете долеко не бесплатная операция. А происходить она может не только при применение знака "=". Как раз в случае вызова x[y][z] может образовываться временная переменная перед записю в котрую тоже может быть вставлен код райт-барьера (барьера записи).

VD>>Так что перепиши свой алгоритм, чтобы проходил массив последовательно.


PD>Влад, то, что этот алгоритм можно переписать, чтобы массив b проходился последовательно, я прекрасно понимаю. Его еще несколькими способами можно переписать. Не в этом вопрос, а в том, что я на ровном месте обнаружил несколько необычную зависимость.


Это не очень ровное место. Этот алгоритм плох и для неуправляемого кода. Тут уже играет свою роль архитектура современных микропроцессоров. А для управляемого кода это вообще худший случай.

PD> А не всегда алгоритм можно так переписать. К примеру, нахождение собственных чисел и собственных векторов так легко не перепишется...


Ты меня извини, но у тебя какие-то доисторические подходы к вопросам производительности.

Важно не то, что ты можешь написать не эффективный код. Важно, то что ты можешь написать эффективный код! Пиши программу как получается. Если производительности достаточно, то вообще ни о чем не думай. Если нет, то на технике где ее недостоточно проведи тесты с помощью профайлера. Выяви узкие места и переписывай их вплть до ансэйва или применения неуправляемых языков.

В итоге:
1. Ты будеть создавать рпиложения значительно быстрее. Ведь ты не заморачиваешся на оптмизациях.
2. Твои приложения небудет напичканы ненужными оптимизациями, а значит будут более читабельными и будут легче подаваться развитию и/или рефакторингу.
3. Твои приложения будт более безопастными, так как управляемы код с применением защищающих от ошибок языков вроде C# снижают вероятность появления ошибок и упрощяют их писк если они все же появляются.
4. Твоей код будет более переносимым, так как большинство оптимизаций так или иначе увеличивают зависимость от платформы.

Так что конечно если ты знашь про грабли и их лего обойти, то это сделать несомненно нужно. Но заморачиваться на это не стоит. Это неверный подход.

PD>for(j = 0; j < nSize; j++)


PD>писать что-то вроде


PD>for(j = 0; j < a[j].Length; j++)


Да. Более тог "a[j]" лучше вынести из цикла. Это же инвариант, но джит с большой вероятностью его не выкинит.

PD>А что это даст ?


К сожалению JIT-дотнета на сегодня довольно туп и обладает только небольшим количеством довольно примитивных оптимизаторов. Я бы сказал, что он стоит примерно на уровне VC6 за вычетом проблем связанных с самой архитектурой дотнета (вызов интерфейсов, затраты на упровление памятью (тот самый райт-барьер) и т.п.).

Так вот у дижито совершенно точно есть оптимизация проверки "index < array.Length". Он определяет что index используется для доступа к элементам массива array и выкидывает дополнительную проверку выхода за пределы массива. Если же в цикле стоит проверка переменной, то у него не хватает ума понять что в этой переменной находися длинна массива и джит вставляет проверку выхода за предылв массива внутри цикла. То есть получается дуюлирование проверки.

Кстатит, именно по этому фикл где используется один индекс для доступа к двум массивам в дотнете принципиально будет чуть боленнен чем в анменеджед коде. Ведь проверка осуществляется только для одного массива.

Все это несомненно просто упращенная реализация джита. Я просто уверен, что в будущем оптимизации джита дойдут до тех же высток которых сегодня достигли оптимизирующие компиляторы С++ и им подобные, но на это могут уйти годы. Ведь оптимизации в джитах значительно более сложно сделать, так как есть куча факторов которые могут нарушить среду вычислений.

Однако джиты потенциально могут делать куда больший объем оптимизаций нежели анменеджед-компиляторы. Ведь:
1. При запуске программы джиту доступен весь код приложения. Можно сказать, что для джита (и пре джита, компилятора при инсталляции или ngen.exe) нет ДЛЛ-ей! Он может воспринималь приложение как единое целое, а значит он может выкидывать вырожденные виртуальные вызовы. Переписывать код не вризая преходы между модулями.
2. Джит и преджит запускаются на конкретом компьютереа, а значит могут использовать инфомрацию о его компонентах. Например, генерировать код под конретный процессор или даже под их количество (распараллеливая некоторые уастки кода). Он может оптимизировать распределение памяти исходя из объемов установленной оперативной памтия и т.п.
3. Модули оптимизации могут интегрироваться в джит сторонними производителями, так что программа однажды скомпилированная может ускориться просто из-за исполнения на более соврешенном джите.

В МС-Ресерч ведутся ряд исследований посвященных оптимизации управляемого кода и вообще оптимизаций. Так стоти почитать о Бартоке (оптимизирующем компиляторе C# написанном на C# и порождающем машинный код), и о Фениксе (фрэймворке для постороения потимизирующиго бэкэнда для компиляторов, джитов, для профелирования кода и для прочих модификации промежуточного кода.

PD>Ну , с такими аргументами я спорить не могу. ИМХО где-то у нас на полке старая 386 машина пылится. Пойду сейчас, найду ее , и если она работает, зафурычу этот алгоритм в DOS на BC++ 3.1, вот тогда уж точно C# победит с фантастическим отрывом!


Да, я тому, что зачастую проще выкинуть 2-4 лишних сотен на более быструю машину, чем 2-4 килобакса на зарплаты программистов.

PD>А если серьезнее — странно. Какая у тебя машина ?


AMD 64 3500+ (2 Ггц) + 1 Гиг памяти.

Правда, я еще твой тест запустил на втором фрэймворке. Может это повлияло...

А ты то на чем запускал?

...

Для сравнения запустил тот же код на VC++ 8.0 получилось 13 секунд. Так что не все такк страшно, как казлось.

В дебаге вообще 17 секунд, так что можно считать, что МС таки доводит джит до уровня С++-ного компилятора.

PD>Кстати, просьба ко всем, кто это читает и имеет 10 минут свободного времени. Пропустите мой тест (самый первую программу на С# из http://www.rsdn.ru/Forum/Message.aspx?mid=1408480&amp;only=1
Автор: Pavel Dvorkin
Дата: 29.09.05
) и сообщите время, ну и характерстики PC. А то, может, у меня что-то с FrameWork не в порядке (с машиной — не может быть, тест С++ проходит нормально), а я тут глубокомысленные выводы делаю


Поставь второй.

VD>>Ты как раз нашел случай, где ансэйф может нихило помочь.


PD>Влад, если можешь — объясни, как тут unsafe применить.


Где-то рядом я тут давал ссылку на свой код реализующий альфаблэндинг. Том очень похожая идея.

Если в двух словах, то заменяешь матрицу на плоский массив, пиниль массив, получаешь таким образом указатель, и дальще возишся с этим указателем эмулируя на нем матрицу. В итоге получашь код близкий по характеристикам к С, т.е. Такой же быстрый, но и такой же опасный. Единственное, что радует реально ансэйф нужет только при перемножении. Остальные части тебе практически ничего не дадут. Это батлнэк.

PD> Я уже несколько человек просил, никто не отзывается. Только не модифицируй алгоритм, т.е. матрица b по строкам. Я не могу понять, как это сделать. Рихтер утверждает, что указатели можно применять к массивам простых типов, а здесь, черт побери, массив массивов!


Ну, массив-масссиво — это тоже два массива. Но в твоем случае просто не нужно использовать массив массивов. Лучше или взять чистую матирцу и получить указатель на ее начало, или сэмулировать матрицу на плоском массиве (это и рподемонстрировано в тесте с альфаблэндом).
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: тест с матрицами
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.09.05 16:47
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

VD>>Кстати, привел бы код продольного прохода... Думаю его можно еще ускорить.


PD>Не понял. На С# я все коды привел. На С++, что ли — для прямоугольной матрицы ?


Вот тут
Автор: Pavel Dvorkin
Дата: 29.09.05
ты привел результаты более быстрых вариантов. Я говорю, о том, что если нимного поколдавать, то возможно и их можно ускорить.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: тест с матрицами
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.09.05 16:47
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

HD>>Первый пример работает 36 секунд (только я там int i,j,k,nSize = 10; на int i,j,k,nSize = 1000; поменял)


PD>Да, я там не заметил эту ошибку.


HD>>Второй (оптимизированый) работает 26 секунд.


Я когда первый раз запустил, тоже улыбнулся... подумал, что ты на ХТ его гонял. Потом сравнил с сишным и увидел 10 вместо тысячи...
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: тест с матрицами
От: Alexey Axyonov Украина  
Дата: 30.09.05 19:39
Оценка:
PD>А если серьезнее — странно. Какая у тебя машина ?
PD>Кстати, просьба ко всем, кто это читает и имеет 10 минут свободного времени. Пропустите мой тест (самый первую программу на С# из http://www.rsdn.ru/Forum/Message.aspx?mid=1408480&amp;only=1
Автор: Pavel Dvorkin
Дата: 29.09.05
) и сообщите время, ну и характерстики PC. А то, может, у меня что-то с FrameWork не в порядке (с машиной — не может быть, тест С++ проходит нормально), а я тут глубокомысленные выводы делаю


1 вариант — 17.6 сек.
вариант с
temp += a[i][k] * b[j][к];
— 3 сек.

вариант с [,] — 15.6 сек

VS2005 RC

Athlon 64 3500+, 1 GB RAM
... << RSDN@Home 1.2.0 alpha rev. 618>>
Re[4]: тест с матрицами
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 01.10.05 16:52
Оценка:
Здравствуйте, VladD2, Вы писали:


VD>Таким образом модификация указателей в дотнете долеко не бесплатная операция. А происходить она может не только при применение знака "=". Как раз в случае вызова x[y][z] может образовываться временная переменная перед записю в котрую тоже может быть вставлен код райт-барьера (барьера записи).


Согласен. При чем при вызове x[y][z] с изменяющейся z это происходит один раз за цикл.
Издержки 1.1, т.к. по сути никакого райт-барьера не должно быть, но ...
и солнце б утром не вставало, когда бы не было меня
Re[4]: тест с матрицами
От: Pavel Dvorkin Россия  
Дата: 02.10.05 05:02
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Pavel Dvorkin, Вы писали:


PD>>А что такое райт-барьера, если не секрет ?


VD>Не сикрет, но этот вопрос требует серьезного объяснения.


VD>На пальцах...


<skipped>

Понятно. Я об этом знал, не знал только, что это называется райт-барьером. Но коль уж этот вопрос здесь возник, задам еще один вопрос.

У Рихтера довольно ясно все это изложено, но об одном он то ли умалчивает, то ли я невнимательно прочита, а книги под рукой нет.

Что же все-таки происходит со 2 поколением ? В нем сборка мусора производится или нет ? И если производится, то когда ?
И второе. Рихтер пишет, что большие объекты (кажется, более 80 Кб) выделяются из особой кучи, которая никогда не дефрагментируется, и попадают сразу во 2 поколение.
Что значит не дефрагментируется ? Поскольку, как он объясняет, в куче .Net нет классического списка пустых блоков, то что же там будет ? К примеру (глупый, конечно, пример) создаю я большие объект на 100 Кб, штук 10, потом четные освобождаю, и создаю еще 10 объектов по 110 Кбайт. Они что, за пределами первого экстента будут, а дырки не будут заполнены ? В C++ это именно так, но там дырки настоящие, и если создать объект на 90 Кбайт — он в дырке устроится. А здесь что ?

VD>Это не очень ровное место. Этот алгоритм плох и для неуправляемого кода.


Я бы сказал — хуже. В 3 раза, на моей машине.


VD>Ты меня извини, но у тебя какие-то доисторические подходы к вопросам производительности.


Ну что же, я далеко не молод, так что воззрения на этот счет у меня классические

VD>Важно не то, что ты можешь написать не эффективный код. Важно, то что ты можешь написать эффективный код! Пиши программу как получается. Если производительности достаточно, то вообще ни о чем не думай. Если нет, то на технике где ее недостоточно проведи тесты с помощью профайлера. Выяви узкие места и переписывай их вплть до ансэйва или применения неуправляемых языков.


Я это все прекрасно понимаю, Но не в этом же вопрос. Более того, доведись мне писать, я матрицу как следует и расположу, даже если вообще ничего про .Net знать не буду.
А точка зрения моя такова, что писать надо сразу как следует. Впрочем, я об этом подробнее напишу в Философии, я уже свое сообщение подготовил, остается его немного доделать. Так что подожди

VD>3. Твои приложения будт более безопастными, так как управляемы код с применением защищающих от ошибок языков вроде C# снижают вероятность появления ошибок и упрощяют их писк если они все же появляются.


На эту тему можно бы тоже подискутировать. От чего защищают ? От выхода индекса за пределы массива, мемори ликов или от разыменования null и т.д. — да, не спорю. А от использования + вместо — в формуле ? От сложеняи килограммов с метрами вместо умножения ? От алгоритмической ошибки ? От логической ошибки ?
А каков процент ошибок типа мемори ликов и т.д по сравнению с ошибками логики или реализации ?
Кстати, мемори лики, ресурс лики, нулевые указатели и выход индекса у меня Bouds Checker прекрасно ловит.

VD>4. Твоей код будет более переносимым, так как большинство оптимизаций так или иначе увеличивают зависимость от платформы.


Да не об оптимизации же речь идет, а о стиле программирования ! Никак ты меня понять не хочешь!



VD>Так вот у дижито совершенно точно есть оптимизация проверки "index < array.Length". Он определяет что index используется для доступа к элементам массива array и выкидывает дополнительную проверку выхода за пределы массива. Если же в цикле стоит проверка переменной, то у него не хватает ума понять что в этой переменной находися длинна массива и джит вставляет проверку выхода за предылв массива внутри цикла. То есть получается дуюлирование проверки.


Понял, спасибо.


VD>Все это несомненно просто упращенная реализация джита. Я просто уверен, что в будущем оптимизации джита дойдут до тех же высток которых сегодня достигли оптимизирующие компиляторы С++ и им подобные, но на это могут уйти годы.


Вот на этот счет я сомневаюсь. Потому что есть одна причина, и ее не обойдешь. Оптимизирующий компилятор с C++ может этой оптимизацией хоть 10 минут заниматься. Если у меня проект будет полчаса компилироваться, я восторга не выскажу, но вытерплю (кстати, проект, в котором я участвовал, компилировался минут 15). А вот у JIT такого времени никогда не будет.

>Ведь оптимизации в джитах значительно более сложно сделать, так как есть куча факторов которые могут нарушить среду вычислений.


Тем более.

VD>Однако джиты потенциально могут делать куда больший объем оптимизаций нежели анменеджед-компиляторы. Ведь:

VD>1. При запуске программы джиту доступен весь код приложения. Можно сказать, что для джита (и пре джита, компилятора при инсталляции или ngen.exe) нет ДЛЛ-ей! Он может воспринималь приложение как единое целое, а значит он может выкидывать вырожденные виртуальные вызовы. Переписывать код не вризая преходы между модулями.

Теоретически рассуждение совершенно безупречное, а пркатически если он вздумает это делать при компиляции каждой строки — кошмар будет. Если же он будет компилироват весь IL-код модуля/сборки/домена, то это просто будет перенос компиляции к клиенту . Тогда почему бы не откомпилировать заранее ?


VD>2. Джит и преджит запускаются на конкретом компьютереа, а значит могут использовать инфомрацию о его компонентах. Например, генерировать код под конретный процессор или даже под их количество (распараллеливая некоторые уастки кода).


С этим согласен, но это было бы существенно, если бы мы имели с десяток платформ. А их всего-то пока 3 — x86,IA64, x86-64. Не такая уж проблема откомпилировать 3 разных релиза.

>Он может оптимизировать распределение памяти исходя из объемов установленной оперативной памтия и т.п.


Интересная мысль.

VD>3. Модули оптимизации могут интегрироваться в джит сторонними производителями, так что программа однажды скомпилированная может ускориться просто из-за исполнения на более соврешенном джите.


Поживем — увидим.

VD>В МС-Ресерч ведутся ряд исследований посвященных оптимизации управляемого кода и вообще оптимизаций. Так стоти почитать о Бартоке (оптимизирующем компиляторе C# написанном на C# и порождающем машинный код)


А вот это действительно мне интересно. ИМХО если бы реализовать C# со всеми ее идеями и Net FrameWork в компилированном виде, без IL — замечательная штука могла бы получиться.
Ссылку не кинешь ? Но ведь это уход от IL и переход к классической компиляции, нет ?



PD>>Ну , с такими аргументами я спорить не могу. ИМХО где-то у нас на полке старая 386 машина пылится. Пойду сейчас, найду ее , и если она работает, зафурычу этот алгоритм в DOS на BC++ 3.1, вот тогда уж точно C# победит с фантастическим отрывом!


VD>Да, я тому, что зачастую проще выкинуть 2-4 лишних сотен на более быструю машину, чем 2-4 килобакса на зарплаты программистов.


При одном условии. Что этот программист пишет программу для одной машины . А вот когда для тысяч — то это еще вопрос. А когда нет никакой возможности на железо влиять — тем более.

PD>>А если серьезнее — странно. Какая у тебя машина ?


VD>AMD 64 3500+ (2 Ггц) + 1 Гиг памяти.


Посмотри мои ответы в тест с матрицами-2. Такое впечатление, что какой-то здесь барьер на 2GHz. Глупо, конечно, такое предполагать...

VD>Правда, я еще твой тест запустил на втором фрэймворке. Может это повлияло...


Может...

VD>Для сравнения запустил тот же код на VC++ 8.0 получилось 13 секунд. Так что не все такк страшно, как казлось.


Я полне допускаю, что что-то у меня не так. Првада, у GlebZ то же, что и у меня. а у других то же, что и у тебя. Черт знает что.


VD>Поставь второй.


А он к Studio 7.1 прикручивается ?

VD>Где-то рядом я тут давал ссылку на свой код реализующий альфаблэндинг. Том очень похожая идея.


VD>Если в двух словах, то заменяешь матрицу на плоский массив,


Как с плоским массивом делать — я и сам понимаю. Кстати, он ведь сразу во 2 поколение попадет, там как-никак 4 Мб при размере 1000.

>пиниль массив, получаешь таким образом указатель, и дальще возишся с этим указателем эмулируя на нем матрицу.


Это я еще лет 15 назад умел делать

А с массивом массивов — не решается, как я понял ? Спрашиваю не потому. что мне очень хочется именно его использовать, а просто в плане изучения языка.
With best regards
Pavel Dvorkin
Re[3]: тест с матрицами
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 02.10.05 05:49
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:


PD>А что такое райт-барьера, если не секрет ?


Посмотри
http://www.rsdn.ru/Forum/?mid=630648
Автор: Serginio1
Дата: 06.05.04


http://www.rsdn.ru/Forum/?mid=630648
Автор: Serginio1
Дата: 06.05.04


http://www.rsdn.ru/Forum/?mid=1039377
Автор: Serginio1
Дата: 22.02.05


http://www.rsdn.ru/Forum/?mid=1039377
Автор: Serginio1
Дата: 22.02.05


Кстати во многих случаях fixed не панацея при частом его использоавании т.к. добавляются дополнительные проблемы пофиксации объекта.
и солнце б утром не вставало, когда бы не было меня
Re[5]: тест с матрицами
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 02.10.05 06:09
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Что же все-таки происходит со 2 поколением ? В нем сборка мусора производится или нет ? И если производится, то когда ?

PD>И второе. Рихтер пишет, что большие объекты (кажется, более 80 Кб) выделяются из особой кучи, которая никогда не дефрагментируется, и попадают сразу во 2 поколение.
PD>Что значит не дефрагментируется ? Поскольку, как он объясняет, в куче .Net нет классического списка пустых блоков, то что же там будет ? К примеру (глупый, конечно, пример) создаю я большие объект на 100 Кб, штук 10, потом четные освобождаю, и создаю еще 10 объектов по 110 Кбайт. Они что, за пределами первого экстента будут, а дырки не будут заполнены ? В C++ это именно так, но там дырки настоящие, и если создать объект на 90 Кбайт — он в дырке устроится. А здесь что ?

Я тебе уже ссылочку давал
http://rsdn.ru/Forum/Message.aspx?mid=701354&amp;only=1
Автор: Serginio1
Дата: 30.06.04

Стоят на месте как вкопанные, что относится и к фиксированным объектам. И дырки остаются.
Но память то у нас виртуальная . Физических адресов обычно хватает.
и солнце б утром не вставало, когда бы не было меня
Re[5]: тест с матрицами
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.10.05 21:24
Оценка: 14 (2)
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Что же все-таки происходит со 2 поколением ? В нем сборка мусора производится или нет ?


Производится. Но не во всем хипе. Ко второму поколению относятся два хипа. Один — обычных в который попадают объекты относительно маленького размера. Врать не буду, размер не помню. Можно поискать по форуму эта цифра звучала не раз. Второй — LOH (лоховый, значич, по нашему ). Расшифровывается как Large Objects Heap — т.е. куча для объектов большого размера. Устроена она аналогично куче виндовс. Дефрагментация LOH не производится. Вместо этого она управляется аналогично С-шной куче. Маленькие стоящие рядом блоки объеденяются.

PD> И если производится, то когда ?


Сборка мусора второго поколения производится когда дотнет решит, что это нужно и можно сделать. Точный алгоритм тут неизвестен, но судя по наюлюдениям делается это как можно редко и по-возможности в моменты кода процессор незагружен. В грамотно написанно приложении за час может проходить от 1-20 сборок второго поколения.

В LOH производится только пометка областей как освобожденных, а остальной части хипа второго поколения производится пометка и укопмакчивание хипа. При пометке создется список живых объектов. При укомпакцичании эти объекты сдвигаются (их тела копируются) к началу кучи так чтобы между объектами небыло пустых областей. К сожалению добиться этого можно невсегда. Иногда во время сборки мусора объекты могут быть заблокированны (например, в сдедствии действий "помошников" пытающихся оптимизировать скорость работы за счет небезопастного кода). В этом случае заблокированные объекты не сдвигаются, а рантайм тратит больше времени на сбрку второго поколения и выделение памяти. Так что нужно стараться меньше заниматься ручным управлением памятью.

PD>И второе. Рихтер пишет, что большие объекты (кажется, более 80 Кб) выделяются из особой кучи, которая никогда не дефрагментируется, и попадают сразу во 2 поколение.


Так и есть. Об этом я уже сказал выше. Но "никогда не дефрагментируются" не значит "не освобождаются". Просто прицип управления памятью немного другой. Свободные блоки исползуются пвторно как в С-шной куче.

Однозначно можно сказать, что приложение возящаесе с LOH внешне потребляет больше памяти, так как LOH обычно не уменьшается. Но на самом деле это все фигня, так как куски большого объема просто попадают в своп.

PD>Что значит не дефрагментируется ? Поскольку, как он объясняет, в куче .Net нет классического списка пустых блоков, то что же там будет ?


В LOH как раз есть списки пустых блоков (или что-то их заменяющее). Просто их вычисление происходит не при явном освобождении памяти, как в С-подобных хипах, а при вычислении достижимых объектов второго поколения (а вернее всех поколений). Формула проста. Свободные блоки — это все блоки за вычетом занятых.

PD> К примеру (глупый, конечно, пример) создаю я большие объект на 100 Кб, штук 10, потом четные освобождаю, и создаю еще 10 объектов по 110 Кбайт.


Гы. Вот тут уже ошибка в логике. Ты не можешь освободить объект. Ты можешь толко "забыть" про него, т.е. потерять все ссылки на него. Но это не означает, что ЖЦ сочтет его сразу же мертвым. Во-первых, для этого ЖЦ должен собрать мусор во втором поколении (т.п. во всех поколениях), а это как я уже говорил довольно редкая операция в правильно написанном менеджед-приложении. А, во-вторых, объект может иметь финалайзер, что приведет к тому, что объект останется живым даже после первой сборки мусора, так как на него будет ссылка в очереди финализации (она тоже считается корнем ЖЦ).

Таким образом говорить "потом ... освобождаю" нельзя! Даже если ссылок больше нет ЖЦ може по прежнему считать, что память занята и выделить новый участок памяти.

PD> Они что, за пределами первого экстента будут, а дырки не будут заполнены ?


Да. И, как я уже сказал, все даже намного печальнее. Но тут вступает в работу виртуальная память виндовс. Дотнетные приложения не зря резервируют десятки мегабайт виртулки при старте. Ведь если приложение не использует физическую память (явно не пишет в нее и не читает из нее), а системе нехватает реальной (физической) памяти, то винда такие блоки скинет на винт и переиспользует память. По этому LOH живет по приципу "рост прежде всего". Ну, и чтобы небыло роста памяти самым разумным является не занимать кучи огромных объектов.

Собственно не так-то просто занять огромный объект. Ведь в дотнете все потенциально болшие структуры имеют ссылочную природу. Так что большой может быть только массив (особенно вэлью-типов). Появляются такие массивы обычно при считывании в память файлов большого объема. Так что если есть желание сэкономить память, то имеет смысл использовать потоковое чтение, а не залповое в массивы. Однако заморчиваться на это не стоит. При наличии некоторого объема оперативки все это не имеет значения. Виртуалка справляетс очень неплохо. В конце концов все относительно. С-шный (а стало быть и Виндовый) хип ведут себя так же. Ну, разве что понятие "освободить память" в них детерминировано.

PD> В C++ это именно так, но там дырки настоящие, и если создать объект на 90 Кбайт — он в дырке устроится. А здесь что ?


В С++, а точнее в традиционных С++-ных хипах — это так для любых динамически создаваемых объектов. К тому же в С++ намного проще получить огромные объекты, так как в них частой практикой является использование встроенных массивов. В дотнете же 99% объектов (% относительно количества, а не объема занимаемой памяти) живут не просто в обычных хипах, они обычно хивут в нулевом и первом хипе.

Есть даже понятие "хороший паттерн испльзования памяти". Так приложения с хорошим паттерном работают довольно быстро и не в них влияние сборщика мусора на глаз заметить невозможно (даже если это очень интерактивные приложения вроде 3D-игр или тексовых процессоров). Приложения с "плохим паттерном" — это приложения в которых затраты на сборку мусора превышают 10%, и в которых очень часто собирается мусор 2-го поголения.

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

Хорошим примером антипаттерна использования памяти является создание объектов-оберток (или враперов). Представим объемный граф объектов над которым нужно произвести некотурую операцию. Представим так же что у объектов этого графа (точнее их классов) интерфейс не совпадает с требуемым для этой операции. Стандартным решением в этом случае будет создание объекта-посредника преобразующего интерфейс объектов из графа в требуемый. Можно создавать такие объекты непосредственно перед вызовом операции и забывать про них сразу после нее (обнулять ссылки на них), а можно создав однажды оберточный объект "прикопать" его на будующее (сохранить ссылку). Так вот большинство С-шников думая, что стоимость создания/уничтожения объекта относительно велика, то что размер объекта относительно мал, и то что операции могут производиться не один раз могут принять решение "прикапывать" обертки. Но как раз это и может стать проблемой если объем объектов велик. Ведь если их не прикапывать, то переодически будет производиться сборка нулевого поколения. При этом почти все оно буедет состоять из мертвых объектов-оберток, что приведет ктому что ЖЦ практически не будет тратить время на их утилизацию. К тому же объем памяти нулевого поколения подстраивается рантаймом под размер кэша процессора, а стало быт работа в нем значительно быстрее нежели в других хипах. Кэширование приводит к тому, что обертки уезжают во второе поколение, что приводит к копированию объектов (ведь при перемещении между поколениями объеты физически копируются) и к тому, что постояно будет просхдить сброс кэша.

В итоге решение принятое в целях оптимизации может дать обратный эффект.

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

Одако все это очень зибко и лучше вообе не делать предположений, а лечить явные томоза. Дотнет оптимизирован на довольно профанское (с точки зрения матерого С-шника) отношения к памяти. Он проектировался в рассчете на среднего программиста, а не на гуру выжимателя битов из байтов.

VD>>Это не очень ровное место. Этот алгоритм плох и для неуправляемого кода.


PD>Я бы сказал — хуже. В 3 раза, на моей машине.


Вы хотите поговорить об этом? :с)

Я уже в самом начале сказал, что вопросы оптимизации — это очень не простые вопросы затрагивающие массу тонких моментов. Процессор тут тоже тонкое место. Как видишь твоей процессор и мой уже показывают разные результаты. Причем ни в коем случае нельзя делать выводы, что дотнет оптимизирован под АМД 64. Во-первых, есть операции (например, работа с плавающей точкой) где П4 под дотнетом работает быстрее чем АМД, а, во-вторых, те же PM порой "рвут" куда более гигорцовых конкурентов и от Интела и от АМД.

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

Так что просто дотнет в виду того, что боки памяти в нем содержат дополнительную внутренюю информацию просто быстрее нарывается на эти проблемы, ну и в том, что P4 имеют настолько бездарную архитектуру, что сбросы кэша в них приводят к катастрофическим последствиям для производительности.

Ты же пыташся делать какие-то обобщения. А это в корне не верно. Это частный случай. В других случаях все может оказаться с точностью до наоборот.

VD>>Ты меня извини, но у тебя какие-то доисторические подходы к вопросам производительности.


PD>Ну что же, я далеко не молод, так что воззрения на этот счет у меня классические


Отнюдь. Почитай, например, вот эту Оптимизация – ваш злейший враг
Автор(ы): Dr. Joseph M. Newcomer
Дата: 19.03.2005
В этом эссе доктор Ньюкамер делится своим опытом и соображениями по поводу преждевременной, несвоевременной или неактуальной оптимизации, призывая программистов избежать подобных ошибок.
статью. Ее написал куда более старый человек. Он то уж точно учился на более замшелых принципах, но его подход в корне отличается от твого. Просто он осознал его неверность и принял другую точку зрения. И я согласен с ним. Хотя я в этой области варюсь всего 15 лет (кстати, достаточно чтобы встречать в штыки все новое).

PD>Я это все прекрасно понимаю, Но не в этом же вопрос. Более того, доведись мне писать, я матрицу как следует и расположу, даже если вообще ничего про .Net знать не буду.


Тогда в чем причина твоих возмущений?

PD>А точка зрения моя такова, что писать надо сразу как следует.


Дык что же ты написал алгоритм как попало если знал, что и в анменеджед мире на современных процессорах это плохая реализация?

PD> Впрочем, я об этом подробнее напишу в Философии, я уже свое сообщение подготовил, остается его немного доделать. Так что подожди


ОК. Почитаем. Боюсь это снова будут возмущения на пустом месте.

PD>На эту тему можно бы тоже подискутировать. От чего защищают ?


От ошибок. Например, в твоих С++-ных тестах память занимается, но не освобождается. Для теста наплевать и забыть, а для реального приложения боьшая проблема. И не надо говорить, что ты это специально... там ровно три строчки кода нужно дописать. К тому же когда ты их напишь окажется, что еще бывают исключения и все сложнее.

PD> От...


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

PD>Кстати, мемори лики, ресурс лики, нулевые указатели и выход индекса у меня Bouds Checker прекрасно ловит.


Не рассказывай это тем кто с Баунд Чекером просидел несколько месяцев безвылазно, а потом ловил вылеты в релизе.

PD>Да не об оптимизации же речь идет, а о стиле программирования ! Никак ты меня понять не хочешь!


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

VD>>Все это несомненно просто упращенная реализация джита. Я просто уверен, что в будущем оптимизации джита дойдут до тех же высток которых сегодня достигли оптимизирующие компиляторы С++ и им подобные, но на это могут уйти годы.


PD>Вот на этот счет я сомневаюсь. Потому что есть одна причина, и ее не обойдешь. Оптимизирующий компилятор с C++ может этой оптимизацией хоть 10 минут заниматься.


Может. Но:
1. Практика показывает, что релиз-версии VC (один из лучших оптимизирующих компиляторов) собирает быстрее отладочных. Так что затраты на создание отладочной информации оказываютя куда большими.
2. Уже есть технология пред-компиляции, так называемый преджит. Она позволяет заниматься компиляцией при инсталляции приложения на машину или по отдельному запросу. Во втором фрэймворке преджит развит и уже позволяет производить прекомпиляцию нескольких сборок как единой сущьсти (что позволяет делать межсборочные оптимизации), а так же позвоялет производить фоновую прекомпиляцию (при этом инсталлятор или приложение запускающее прекомпилцию помещает задания на прекомпиляцию в очередь и получает управление обратно, а прекомпиляция производится в фоновом режиме службой ОС). Таким образом уже сделаны нужные шаги к тому, чтобы твои опасения были напрасными. Жаль, что на сегодня от преджита толку не много. Скорость прилоежния праткически не отличается от джит-компиляции. Но то что такие шаги делаются, коворит о намерениях идти по этому пути. В МС и МС-Ресерч ведь не идеоты работают.
3. Джит может производить динамическое профилирование исполняемого файла и создавать подсказки на будующее. При повторном запуске джит может выбрать отдельную стратегию компиляции для отдельных функций. Более того. Джит может динамически перекомпилировать некоторые фнкции. Именно так и поступает джит из реализации Явы от Сана.

В общем, ты просто не обладашь достаточным количеством информации. Так что не стоит делать выводы.

PD> Если у меня проект будет полчаса компилироваться, я восторга не выскажу, но вытерплю (кстати, проект, в котором я участвовал, компилировался минут 15).


В релизе? А в дебаге сколько? Думаю, знашь что в дебаге оптимизации выключается (в VC и большинстве компиляторов для Виндовс и Линукс)? Странно, паравда, что дебажный как минимум не компилируетя быстрее?

А вот дотнетные проекты компилируются намного быстрее. И дело тут не в оптимизации. Дело тут в том, что С++ это бездарно спроектированный язык. Он унаследовал от С самые худшие вещи и привнес еще множество вещей еще больше замедляющих компиляцию. Главная проблема С++ — это отсуствие модульности. В стандарте плюсов вообще не оговоривается никакое представление модулей. Вместо модулей в С++ используются неандертальские текстовые включения файлов (инклюды)! Вот на возню с ними и на возню с шаблонами которые до уровня AST то и то сложно разобрать и уходит основное время при компиляции. А оптимизация там как раз время занимает не так уж и много. Например, в VC 7.1 и выше есть опция "Оптимизация всего приложения". При включения этой опции компилятор компилирует код в специальный промежуточный (кстати, очень похожий на МСИЛ из дотнета) код, а оптимизацией занимается линкер! Так вот при этом линковка проходит довольно шустро даже на окромных проектах.

PD> А вот у JIT такого времени никогда не будет.


См. выше. Ты заблуждаешся.

>>Ведь оптимизации в джитах значительно более сложно сделать, так как есть куча факторов которые могут нарушить среду вычислений.


PD>Тем более.


Не тем более, а именно из-за этого. И как понимашь, сложность != невозможноть. Просто на это нужно время. С научной точки зрения все вопросы давно решены. Сейчас слово за реализацией.

PD>Теоретически рассуждение совершенно безупречное,


Практически во втром фрэймворке это уже можно делать.

PD> а пркатически если он вздумает это делать при компиляции каждой строки — кошмар будет. Если же он будет компилироват весь IL-код модуля/сборки/домена, то это просто будет перенос компиляции к клиенту .


МСИЛ — это и есть перенос последней стадии компиляции на машину клиента. Собственно потенциальные бенефиты от этого и явивились дополнительным стимулом перехода от машинного кода к МСИЛ-у. Как ты понимашь, большинство сервисов можно было бы обеспечить и без МСИЛ-а. Та же метаинформация может прилагаться и к машинному коду. МСИЛ обеспечиват именно что возмоность вмешаться в процесс построения машинного кода непосредственно на машине клиента. Это позоляет и прозводить оптимизации под конкретный процессор, и встраивать в код проверки безопастности. Без этойвозможности CAS (Code Access Sequrity) был бы невозможен в принципе, так как проверки занимают время, да и их можно подделать. А так сам рантайм принимает решение какие проверки и как вставлять.

PD> Тогда почему бы не откомпилировать заранее?


Все причины я описал. Компиляция до стадии промежуточного кода и так делается заранее. А последняя стадия компиляции позволяет достичь большого количества бенифитов. В общем, люди думают о будующем.


PD>С этим согласен, но это было бы существенно, если бы мы имели с десяток платформ. А их всего-то пока 3 — x86,IA64, x86-64. Не такая уж проблема откомпилировать 3 разных релиза.


1. Дотнет уже сейчас запускается на добром десятке процесоров с разной архитектурой. Это и Итаниумы, и PC, и разные процессоры для КПК и смартфонов. К тому же платформа есть платформа. Она предоставляет возможность. Что же это плохо?
2. Даже x86 процессоры имеют разную реализацию и для них можно и нужно использовать разные способы оптимизации. Как видишь, даже объем кода влияет на выбор стратегии. Так что это не лишнее.
3. Со временем появятся модули оптимизации от внешних производителей. Я почти уверен, что приозводителеи процессоров сами займутся созданием оных. А стало быть такая возможность — это еще и возможность выбора опимизатора конечным пользователем. О таком и мечтать недавно никто не мог.

VD>>3. Модули оптимизации могут интегрироваться в джит сторонними производителями, так что программа однажды скомпилированная может ускориться просто из-за исполнения на более соврешенном джите.


PD>Поживем — увидим.


Однозначно. Но почитать про принципы можно уже сейчас — Phoenix.

PD>А вот это действительно мне интересно. ИМХО если бы реализовать C# со всеми ее идеями и Net FrameWork в компилированном виде, без IL — замечательная штука могла бы получиться.


На самом деле это интересно только для одного случаях — создания ОС на C#. Барток компилирует тот же МСИЛ в маш.код для того, чтобы на нем можно было создать загрузчик ОС. Сама же ОС как раз является заместителем дотнета и для запуска приложений в ней уже не требуется извращений.

PD>Ссылку не кинешь ? Но ведь это уход от IL и переход к классической компиляции, нет ?


http://research.microsoft.com/act/
http://channel9.msdn.com/ShowPost.aspx?PostID=68302

Ссылка на Феникс выше.


PD>Посмотри мои ответы в тест с матрицами-2. Такое впечатление, что какой-то здесь барьер на 2GHz. Глупо, конечно, такое предполагать...


Нет. Барьер тут на границах кэша. Просто П4 имеют разные объемы кэша в разных моделях. http://www.sisoftware.net/sandra поможет тебе определить объем кэша.

VD>>Правда, я еще твой тест запустил на втором фрэймворке. Может это повлияло...


PD>Может...


Похоже он тут не причем. Пробовал на 1.1 разница почти никакой.

VD>>Для сравнения запустил тот же код на VC++ 8.0 получилось 13 секунд. Так что не все такк страшно, как казлось.


PD>Я полне допускаю, что что-то у меня не так. Првада, у GlebZ то же, что и у меня. а у других то же, что и у тебя. Черт знает что.


Ага. Процессор плохо реагирующий на сброс кэша и кэш малого объема. Я тут запустил тест на P4 3.0 Ггц. Правда там память на 400 шине, но у PM 1.7 шина тоже вроде 400-ая (если не хуже), но 2 метра кэша.

Так вот на 2000 результат следучщий:
12.5 минут на фрэймворке (правда фрэймворк более старый, что гипотетически тоже может повлияеть).
2.7 минуты на С++ (162 сек.).
То есть разница в 4.5 раза. Конечно не 14, про что ты рассказывал, но тут уже наверно влияет вылет за кэш и С++-ного теста.
На 1000 результат C#:
59 секунд (считай минута)
C++:
13 сек.
То есть разница в те же 4.5 раза.

В случае матрицы на 500 элементов в обоих случаях получается 1 секунда. В общем, и думать не очем. Разница в кэше.

VD>>Поставь второй.


PD>А он к Studio 7.1 прикручивается ?


Нет. Но встает пареллельно и можно компилировать проекты из командной строки. Но похоже для этого теста он ничего не даст.

PD>Как с плоским массивом делать — я и сам понимаю. Кстати, он ведь сразу во 2 поколение попадет, там как-никак 4 Мб при размере 1000.


А какая разница? Одно занятие 4 метров беде практически молниеносным. Ты же него не в цикле занимат будешь?

>>пиниль массив, получаешь таким образом указатель, и дальще возишся с этим указателем эмулируя на нем матрицу.


PD>Это я еще лет 15 назад умел делать


Ну, "пинить" 15 лет назад — это вряд ли. А работа с указателями несомненно 1 в 1 как в С.

PD>А с массивом массивов — не решается, как я понял ? Спрашиваю не потому. что мне очень хочется именно его использовать, а просто в плане изучения языка.


Каждый массив у тебя будет прибавлять минимум 8 лишних байт. В сумме они могут (а точнее точно) вывести массивы за пределы кэша раньше чем сишные. Если же ты займешь единый блок памяти, то таких проблем не будет. Ансэйф с указателями избавить от проблем с контролем выхода за границы массва (но создаст возможность испортить память). Так что получишь код даже быстрее чем с массивом указателей на С, так как блоки памяти будут рспологаться компактнее.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: тест с матрицами
От: Pavel Dvorkin Россия  
Дата: 03.10.05 04:15
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Здравствуйте, Serginio1, Вы писали:



S>> для float [][] а,в;

S>унсейв выглядит так

S>
S> for(i = 0; i < nSize; i++)
S>{
S>for(j = 0; j < nSize; j++)
S>{
S>temp = 0;
S>fixed(float* aa=а[i])
S>{
S>for( k = 0; k < nSize; k++, аа++)
S> fixed(float* bb=b[k]
S> {
S>temp += *aa * bb[j];
S>}
S>}
S>c[i,j] = temp;
S>}
S>}
S>


Увы,...

fixed(float* aa=a[i])
{
for( k = 0; k < nSize; k++, aa++)

Cannot assign to 'aa because it is read-only
With best regards
Pavel Dvorkin
Re[6]: тест с матрицами
От: Pavel Dvorkin Россия  
Дата: 03.10.05 06:21
Оценка:
Здравствуйте, VladD2, Вы писали:


VD>Производится. Но не во всем хипе. Ко второму поколению относятся два хипа. Один — обычных в который попадают объекты относительно маленького размера. Врать не буду, размер не помню. Можно поискать по форуму эта цифра звучала не раз. Второй — LOH (лоховый, значич, по нашему ). Расшифровывается как Large Objects Heap — т.е. куча для объектов большого размера. Устроена она аналогично куче виндовс. Дефрагментация LOH не производится. Вместо этого она управляется аналогично С-шной куче. Маленькие стоящие рядом блоки объеденяются.



PD>> И если производится, то когда ?


VD>Сборка мусора второго поколения производится когда дотнет решит, что это нужно и можно сделать. Точный алгоритм тут неизвестен, но судя по наюлюдениям делается это как можно редко и по-возможности в моменты кода процессор незагружен. В грамотно написанно приложении за час может проходить от 1-20 сборок второго поколения.


Понятно. Т.е. это рассчитано действительно на среднюю" ситуацию. В случае нехорошей ситуации будет плохо. Как , впрочем, и в С++.
Только вот на такой вопрос еще ответь. В C++ это объединение делается немедленно при free/delete. А здесь в отдельном потоке, когда еще будет..., да еще 2 поколение. Может ведь получиться, что я успею объекты насоздавать и "освободить" (не придирайся к слову , а они не будут уничтожены и куча разрастется до неприличия. Если за час 1-20 сборок мусора-то всего... Я ведь за час спокойно могу тысячи и более больших объектов создать и "освободить".



VD>В LOH производится только пометка областей как освобожденных, а остальной части хипа второго поколения производится пометка и укопмакчивание хипа. При пометке создется список живых объектов. При укомпакцичании эти объекты сдвигаются (их тела копируются) к началу кучи так чтобы между объектами небыло пустых областей.


А Рихтер утверждает, что никакого копирования и укомпачивания там нет...



VD>Однозначно можно сказать, что приложение возящаесе с LOH внешне потребляет больше памяти, так как LOH обычно не уменьшается. Но на самом деле это все фигня, так как куски большого объема просто попадают в своп.


Хм... Тебе не доводилось попадать в ситуацию, когда нет больше достаточно большого куска адресного пространства . Мне доводилось. Именно из-за кучи C++. Она там по адресному простанству фрагментирована. Кстати, здесь, я полагаю, тоже ?


PD>> К примеру (глупый, конечно, пример) создаю я большие объект на 100 Кб, штук 10, потом четные освобождаю, и создаю еще 10 объектов по 110 Кбайт.


VD>Гы. Вот тут уже ошибка в логике. Ты не можешь освободить объект. Ты можешь толко "забыть" про него, т.е. потерять все ссылки на него.


Я это давно понимаю. Найди хорошее слово для этой операции (только одно) и я буду его использовать вместо "освободить". Писать каждый раз "потерять все ссылки на него" — не хочу. Забыть — слишком жаргонно.

PD>> Они что, за пределами первого экстента будут, а дырки не будут заполнены ?


VD>Да. И, как я уже сказал, все даже намного печальнее. Но тут вступает в работу виртуальная память виндовс. Дотнетные приложения не зря резервируют десятки мегабайт виртулки при старте. Ведь если приложение не использует физическую память (явно не пишет в нее и не читает из нее), а системе нехватает реальной (физической) памяти, то винда такие блоки скинет на винт и переиспользует память. По этому LOH живет по приципу "рост прежде всего". Ну, и чтобы небыло роста памяти самым разумным является не занимать кучи огромных объектов.


А это, сорри, от задачи зависит. Кстати, ты же мне рекомендуешь использовать в моем матричном тесте a[,], а он туда именно и попадет, в отличие от a[][]. А потом бывают задачи, в которых стартуют с массива размера N, а потом, если не получилось, берут 2N, 4N и т.д...

VD>Собственно не так-то просто занять огромный объект. Ведь в дотнете все потенциально болшие структуры имеют ссылочную природу. Так что большой может быть только массив (особенно вэлью-типов). Появляются такие массивы обычно при считывании в память файлов большого объема. Так что если есть желание сэкономить память, то имеет смысл использовать потоковое чтение, а не залповое в массивы. Однако заморчиваться на это не стоит. При наличии некоторого объема оперативки все это не имеет значения. Виртуалка справляетс очень неплохо. В конце концов все относительно. С-шный (а стало быть и Виндовый) хип ведут себя так же. Ну, разве что понятие "освободить память" в них детерминировано.


Вот именно. Не откладывается, а немедленно исполняется. Поэтому освобожденные блоки сливаются гарантировано тут же и дают новй сравнительно большой блок, который и будет использован. А здесь, пусть память и вытеснена Windows, а объект все еще живой, и не потому, что я его не похоронил ("освободил"), а потому, что могильщик через полчаса придет


VD>В С++, а точнее в традиционных С++-ных хипах — это так для любых динамически создаваемых объектов. К тому же в С++ намного проще получить огромные объекты, так как в них частой практикой является использование встроенных массивов.


Ты имеешь в виду глобальные и статические, т.е. (.data) ?



VD>В итоге решение принятое в целях оптимизации может дать обратный эффект.


<skipped>

VD>Кстати, правильное решение в данном случае будет попытаться вообще отказаться от оберточного объекта и попытаться решить проблему другим способом (изменить интерфейс самих объектов или заменить объетк-оберкту на функцию преобрзователь). Ну, и если обертка все таки нужна, то создавать их денамически и не кэшировать.


Хороший пример, согласен.

VD>Одако все это очень зибко и лучше вообе не делать предположений, а лечить явные томоза. Дотнет оптимизирован на довольно профанское (с точки зрения матерого С-шника) отношения к памяти.


Вот с этим точно согласен

VD>Так что просто дотнет в виду того, что боки памяти в нем содержат дополнительную внутренюю информацию просто быстрее нарывается на эти проблемы, ну и в том, что P4 имеют настолько бездарную архитектуру,


Другого нет

>что сбросы кэша в них приводят к катастрофическим последствиям для производительности.


VD>Ты же пыташся делать какие-то обобщения. А это в корне не верно. Это частный случай. В других случаях все может оказаться с точностью до наоборот.


Вполне.

VD>Отнюдь. Почитай, например, вот эту Оптимизация – ваш злейший враг
Автор(ы): Dr. Joseph M. Newcomer
Дата: 19.03.2005
В этом эссе доктор Ньюкамер делится своим опытом и соображениями по поводу преждевременной, несвоевременной или неактуальной оптимизации, призывая программистов избежать подобных ошибок.
статью. Ее написал куда более старый человек. Он то уж точно учился на более замшелых принципах, но его подход в корне отличается от твого. Просто он осознал его неверность и принял другую точку зрения. И я согласен с ним. Хотя я в этой области варюсь всего 15 лет (кстати, достаточно чтобы встречать в штыки все новое).


Да не встречаю я в штыки все новое. Все — не встречаю.

PD>>А точка зрения моя такова, что писать надо сразу как следует.


VD>Дык что же ты написал алгоритм как попало если знал, что и в анменеджед мире на современных процессорах это плохая реализация?


Исследовал, насколько плохая. Я именно и хочу знать, что где плохо. Чтобы потом не нарваться на это плохо там, где решение не будет столь очевидным.


VD>Это действительно отдельная тема и развивать ее здесь не стоит. По этому поводу скжу только, что все прогрессивная общественность на сегодня понимаеть правильность движения к более безопастным и более автоматическим технологиям.


Это уже на сов. пропаганду похоже. Вся прогрессивная общественность. А те, кто с этим не согласны — реакционеры и т.п.


PD>>Кстати, мемори лики, ресурс лики, нулевые указатели и выход индекса у меня Bouds Checker прекрасно ловит.


VD>Не рассказывай это тем кто с Баунд Чекером просидел несколько месяцев безвылазно, а потом ловил вылеты в релизе.


Я с ними общался . И сам тоже искал.

PD>>Да не об оптимизации же речь идет, а о стиле программирования ! Никак ты меня понять не хочешь!


VD>Я тебя не непонять не хочу. Я просто категорически не согласен с твоим подходом.


Как говорит один мой знакомый, зафиксируем разногласия


PD>>Вот на этот счет я сомневаюсь. Потому что есть одна причина, и ее не обойдешь. Оптимизирующий компилятор с C++ может этой оптимизацией хоть 10 минут заниматься.


VD>Может. Но:

VD>2. Уже есть технология пред-компиляции, так называемый преджит. Она позволяет заниматься компиляцией при инсталляции приложения на машину или по отдельному запросу.

А это есть перенос процесса компиляции на target машину и проведение ее там с учетом ее специфики (память, процессор и т.д.). Сама идея вполне разумная, ничего против не имею. Прада, надо еще учесть, что машине могут апгрейд сделать, так что не только при инсталяции придется. Но это детали.




PD>> Если у меня проект будет полчаса компилироваться, я восторга не выскажу, но вытерплю (кстати, проект, в котором я участвовал, компилировался минут 15).


VD>В релизе? А в дебаге сколько? Думаю, знашь что в дебаге оптимизации выключается


Знаю. Я бы даже сказал, не отключается, а антиоптимизация выполняется. Т.е вот в таком коде

a=b+c;
d=a;

после первого оператора будет что-то вроде

mov a,eax

а второй начнется с

mov eax,a

И это правильно.


>(в VC и большинстве компиляторов для Виндовс и Линукс)? Странно, паравда, что дебажный как минимум не компилируетя быстрее?


Ничего странного. Там pdb файлы строятся. Отключи их построение, будет быстрее.

VD>А вот дотнетные проекты компилируются намного быстрее. И дело тут не в оптимизации. Дело тут в том, что С++ это бездарно спроектированный язык. Он унаследовал от С самые худшие вещи и привнес еще множество вещей еще больше замедляющих компиляцию. Главная проблема С++ — это отсуствие модульности. В стандарте плюсов вообще не оговоривается никакое представление модулей. Вместо модулей в С++ используются неандертальские текстовые включения файлов (инклюды)!


Ну как-то несерьезно это слышать, ей богу. При чем здесь инклюды ? Это же просто способ вставки описаний. В них же кода нет (не считая темплейтов)! А для модульности есть библиотеки, статические, DLL. Можешь, конечно сказать, что это не С++ а Windows. Говори, я не против. Суть не меняется от этого.




VD>Не тем более, а именно из-за этого. И как понимашь, сложность != невозможноть. Просто на это нужно время. С научной точки зрения все вопросы давно решены.


C научной точки зрения и NP-полные задачи решаются. Только времени на них не хватает


VD>Так вот на 2000 результат следучщий:

VD>12.5 минут на фрэймворке (правда фрэймворк более старый, что гипотетически тоже может повлияеть).
VD>2.7 минуты на С++ (162 сек.).
VD>То есть разница в 4.5 раза. Конечно не 14, про что ты рассказывал, но тут уже наверно влияет вылет за кэш и С++-ного теста.
VD>На 1000 результат C#:
VD>59 секунд (считай минута)
VD>C++:
VD>13 сек.
VD>То есть разница в те же 4.5 раза.

VD>В случае матрицы на 500 элементов в обоих случаях получается 1 секунда. В общем, и думать не очем. Разница в кэше.


Я все же не вполне понимаю, при чем тут кэш. Объем данных (float'ов) в обоих случаях один и тот же. Надо их перезагружать в кэше — так ведь и для C++ так же перезагружать надо. Чего в C++ точно нет — это оверхеда на класс Array для каждой строки матрицы b. Ты хочешь сказат, что этот оверхед и вызывает 4 кратную разницу ? Т.е. при доступе с b[k][j] считывается в кэш, условно говоря, b[k], и при этом каждый раз, конечно, разное, так как цикл по k ? Тогда почему эффект сказывается и при больших nSize (5000), где, по твоему уверению, кэш "зашкаливает" и результаты должны быть близкими.


VD>Нет. Но встает пареллельно и можно компилировать проекты из командной строки. Но похоже для этого теста он ничего не даст.


Подожду релиза VS2005

PD>>Как с плоским массивом делать — я и сам понимаю. Кстати, он ведь сразу во 2 поколение попадет, там как-никак 4 Мб при размере 1000.


VD>А какая разница? Одно занятие 4 метров беде практически молниеносным. Ты же него не в цикле занимат будешь?


В этой задаче — нет
With best regards
Pavel Dvorkin
Re[7]: тест с матрицами
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.10.05 00:30
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Понятно. Т.е. это рассчитано действительно на среднюю" ситуацию. В случае нехорошей ситуации будет плохо. Как , впрочем, и в С++.


Дык мы сами творцы всех ситуаций.

PD>Только вот на такой вопрос еще ответь. В C++ это объединение делается немедленно при free/delete. А здесь в отдельном потоке, когда еще будет..., да еще 2 поколение. Может ведь получиться, что я успею объекты насоздавать и "освободить" (не придирайся к слову , а они не будут уничтожены и куча разрастется до неприличия. Если за час 1-20 сборок мусора-то всего... Я ведь за час спокойно могу тысячи и более больших объектов создать и "освободить".


Если ты начнеш орудовать кучей огромных объектов, то сборка второго поколения конечна будет производиться куда чаще чем раз в час. Ведь одним из критериев для ее запуска является рост памяти и подход к контрольным точкам. ЖЦ ведь не ждет когда израсходуется вся память.

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

Но есть одно "но". В рельных приложениях заем огромных блоков делается крайне редко, а живут они обычно долго. Такова уж логика. Мелкие объекты живут мало, большие долго. Ну, глупо ведь открывать фотошопный файл на 100 метров только для того чтбы один раз его отобразить. Скорее всего или будет открыт тамбнэйл но на секунду, или весь файл, но на долго.

VD>>В LOH производится только пометка областей как освобожденных, а остальной части хипа второго поколения производится пометка и укопмакчивание хипа. При пометке создется список живых объектов. При укомпакцичании эти объекты сдвигаются (их тела копируются) к началу кучи так чтобы между объектами небыло пустых областей.


PD>А Рихтер утверждает, что никакого копирования и укомпачивания там нет...


Где там? В LOH есть объеденение блоков. В обычном хипе второго поколения копирование и укомпакчивание. Скорее всего ты его не так понял. Если бы этого не было, то хип второго поколения быстро бы фрагментировался бы и начал бы терять память. Объекты ведь в нем мелкие.

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

PD>Хм... Тебе не доводилось попадать в ситуацию, когда нет больше достаточно большого куска адресного пространства .


В дотнене не доводилось. Еще раз повторяю, что в рельной жизни огромные куски памяти занимаются редко и надолго. Так что этой проблемы нет в следствии дизайна приложений.

PD> Мне доводилось. Именно из-за кучи C++. Она там по адресному простанству фрагментирована. Кстати, здесь, я полагаю, тоже ?


Что значит по "адресному простанству"? Еще раз повторяю, что дотнет пытается занимать виртулку у системы блоками. Причем довольно большими. Если блок кончается, то занимается еще один (скорее всего больший по размеру). Так что проблемы могут начаться только если начать занимать гигабайты памяти, а это уже особый случаи и тут по любому прийдется покумекать. Памяти то пока не терабайты .

PD>Я это давно понимаю. Найди хорошее слово для этой операции (только одно) и я буду его использовать вместо "освободить". Писать каждый раз "потерять все ссылки на него" — не хочу. Забыть — слишком жаргонно.


А не нужно на этом делать акцент. Объект считается мертвым когда на него нет ссылок. А убивать или освобождать его не нужно. Так что говори "метрвый объект", или "объект умер".

PD>А это, сорри, от задачи зависит. Кстати, ты же мне рекомендуешь использовать в моем матричном тесте a[,], а он туда именно и попадет, в отличие от a[][]. А потом бывают задачи, в которых стартуют с массива размера N, а потом, если не получилось, берут 2N, 4N и т.д...


Я ничего не рекламирую. А то что один массив (ну, два... три) занимаемый один раз и живущий все время алгоритма ляжет в LOH — ну, и хрен с ним. Наоборот не будет скакать по поколениям занимая время на копирование. Под то LOH и проектировали.

PD>Вот именно. Не откладывается, а немедленно исполняется. Поэтому освобожденные блоки сливаются гарантировано тут же и дают новй сравнительно большой блок, который и будет использован. А здесь, пусть память и вытеснена Windows, а объект все еще живой,


Блин, сколько раз повторять? Живой — это логическое понятие. Не освобождается память из под объекто! Это нужно в голове держать. Живые объекты живут. Мертвые логически исчезают когда исчезает последняя ссылка. Надо отвыкать от ручного распределения. Это другая парадигма и ей мешают старые привычки и знания.

PD> и не потому, что я его не похоронил ("освободил"), а потому, что могильщик через полчаса придет


Да пофигу. Для виртулки память которую можно вытолкнуть == давно не используемой. Так что неиспользуемый большой объект по любому будет вытолкнут при нехватке памяти. А если ОС памяти хватает, то и думать не о чем. Ну, будет использоваться та память которая в обычно приложении будет просто незадействована, ну, и что?

VD>>В С++, а точнее в традиционных С++-ных хипах — это так для любых динамически создаваемых объектов. К тому же в С++ намного проще получить огромные объекты, так как в них частой практикой является использование встроенных массивов.


PD>Ты имеешь в виду глобальные и статические, т.е. (.data) ?


Нет, я имею в виду объекты создаваемые через new, но имеющие большие размеры. Ну, или через разые там malloc/VirtualAlloc. А аналога статической памяти в дотнете вообще нет. Даже статические поля и те динамически размещатся.

VD>>Одако все это очень зибко и лучше вообе не делать предположений, а лечить явные томоза. Дотнет оптимизирован на довольно профанское (с точки зрения матерого С-шника) отношения к памяти.


PD>Вот с этим точно согласен


Только еще нужно поняь, что это как раз здорово. Так как это позволят не тратить время на отслеживаение "правильности" действий, и сосредоточиться на решаемой задаче.

VD>>Так что просто дотнет в виду того, что боки памяти в нем содержат дополнительную внутренюю информацию просто быстрее нарывается на эти проблемы, ну и в том, что P4 имеют настолько бездарную архитектуру,


PD>Другого нет


У кого как.
Я вот собрал только один П4 и остался им недоволен. Остальные машины или АМД, или PM (ноут).

VD>>Это действительно отдельная тема и развивать ее здесь не стоит. По этому поводу скжу только, что все прогрессивная общественность на сегодня понимаеть правильность движения к более безопастным и более автоматическим технологиям.


PD>Это уже на сов. пропаганду похоже. Вся прогрессивная общественность. А те, кто с этим не согласны — реакционеры и т.п.


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

PD>А это есть перенос процесса компиляции на target машину и проведение ее там с учетом ее специфики (память, процессор и т.д.). Сама идея вполне разумная, ничего против не имею. Прада, надо еще учесть, что машине могут апгрейд сделать, так что не только при инсталяции придется. Но это детали.


А преджит как бы не привязан к инсталляции. Если в те кто все это реализуют дальновидны, то дума, они сделали проверку процессора и перекомпиляцию всех заданий. Хотя как я уже говорил — это все скорее задел на будующее. На сегодня преджит реального ускорения не дает. Только более быструю загрузку.

PD>Знаю. Я бы даже сказал, не отключается, а антиоптимизация выполняется. Т.е вот в таком коде


Не делает он никакой "антиоптимизации". Просто не делает оптимизаций. Вот и все. Оптимизации это отдельные процедуры прогоняемые по внутренеему представлению.

>>(в VC и большинстве компиляторов для Виндовс и Линукс)? Странно, паравда, что дебажный как минимум не компилируетя быстрее?


PD>Ничего странного. Там pdb файлы строятся. Отключи их построение, будет быстрее.


Я знаю как быстрее и компактнее, причем с ПДБ и т.п. Нужно просто не использовать С++. Тогда н будет гигобайтных побочных файлов и компиляция будет в секунны (а то и доли секунд) проходить.

VD>>А вот дотнетные проекты компилируются намного быстрее. И дело тут не в оптимизации. Дело тут в том, что С++ это бездарно спроектированный язык. Он унаследовал от С самые худшие вещи и привнес еще множество вещей еще больше замедляющих компиляцию. Главная проблема С++ — это отсуствие модульности. В стандарте плюсов вообще не оговоривается никакое представление модулей. Вместо модулей в С++ используются неандертальские текстовые включения файлов (инклюды)!


PD>Ну как-то несерьезно это слышать, ей богу. При чем здесь инклюды ? Это же просто способ вставки описаний. В них же кода нет (не считая темплейтов)!


Гы — "кода нет". А на "не считая темплейтов" два раз гы и еще один гы-гы.
Именно инглюды создают все тормоза С++. А шаблоны их умножают многократно. И прекомпилируемые заголовки — это мертвому припарка.

А несерьзно — это твои рассуждения слушать.

PD>А для модульности есть библиотеки, статические, DLL.


А, ну, да. Библиотеки статические. Сто раз гы-гы. На сегодня почти все библиотеки С++ — это горы шаблонов. И в библиотеки их не запихнуть.

Что до ДЛЛ — это это тоже неандертальство с кромальенством. Хотя они вообще к С++ отношения не имеют, но их без хэадеров или другой текстовой фигни использовать нельзя. Да и скорость их вызовов не вше чем у КОМ-объектов.

Другое дело в дотнете. В ДЛЛ-ках МСИЛ и метаинформация. Компилятор видя обращение к другой сборке просто делает прямой вызов и все. Оверхэд нулевой. Хэадеры не требуются. Сборки можно хоть в рантайме подгружать.

PD> Можешь, конечно сказать, что это не С++ а Windows. Говори, я не против. Суть не меняется от этого.


Я могу сказать, что и ДЛЛ в чистом виде, и С++-ая идеология модулей, к коей ДЛЛ отношения не имет — это все дремучий прошлый век. Никуда не годные технологии доживающие свои времена.

Думаю, что даже для С++ сделают рано или поздно модульность. Но будет это не скоро, так как в комитете по стандартизации С++ сидят старперы.

В общем, что трепаться. Сравни скорость компиляции С++-ного проекта и дотнетного. Даже если дотнетных создан с использованием МС++ он один фиг собирается куда быстрее С++-ного. И дело тут именно в том, что в дотнете есть модульность, а С++ дебелизм в виде инклюдов. С этим даже наш главный фанат плюсов ПК не спорит.

PD>Я все же не вполне понимаю, при чем тут кэш. Объем данных (float'ов) в обоих случаях один и тот же. Надо их перезагружать в кэше — так ведь и для C++ так же перезагружать надо.


Не, у каждого массива еще довесок в 16 байт (8 на объект и 4 длинна и т.п.), а может и болше. Плюс черт его знает, что там ЖЦ делает при распредлении массивов. Может он их в некоторый массив в другой хип засовывает...

PD> Чего в C++ точно нет — это оверхеда на класс Array для каждой строки матрицы b.


В дотнете тоже нет. Работа идет не с классом, а с встроенной сущьностью.

PD> Ты хочешь сказат, что этот оверхед и вызывает 4 кратную разницу?


Ну, при большем кэше разница 25 процентов. А при размере массива до 500 ее вообще нет. Как еще это объяснить? А на 5000 разница меньше 2 раз даже на P4.

PD> Т.е. при доступе с b[k][j] считывается в кэш, условно говоря, b[k], и при этом каждый раз, конечно, разное, так как цикл по k ? Тогда почему эффект сказывается и при больших nSize (5000), где, по твоему уверению, кэш "зашкаливает" и результаты должны быть близкими.


При 5000 эффект далеко не тот. Да и чем больше длинна подмассивов, тем больше вероятность перезагрузки кэша при "[j]".

PD>Подожду релиза VS2005


Ну, тогда до революции будешь ждать.

PD>В этой задаче — нет


А где нужно занимать 4-х метровые массивы со скростью пулемета? И какая машина это вообще выдержит?
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: тест с матрицами
От: Pavel Dvorkin Россия  
Дата: 04.10.05 05:07
Оценка:
Здравствуйте, VladD2, Вы писали:


VD>Дык мы сами творцы всех ситуаций.





PD>>А Рихтер утверждает, что никакого копирования и укомпачивания там нет...


VD>Где там?


В LOH.

>В LOH есть объеденение блоков. В обычном хипе второго поколения копирование и укомпакчивание. Скорее всего ты его не так понял.


Я думаю, что и его и тебя я правильно понял. В LOH укомпакчивания нет, так ?


PD>> Мне доводилось. Именно из-за кучи C++. Она там по адресному простанству фрагментирована. Кстати, здесь, я полагаю, тоже ?


VD>Что значит по "адресному простанству"? Еще раз повторяю, что дотнет пытается занимать виртулку у системы блоками. Причем довольно большими.


Это и значит. Т.е. не лежит в непрерывном диапазоне виртуальных адресов.

PD>>Я это давно понимаю. Найди хорошее слово для этой операции (только одно) и я буду его использовать вместо "освободить". Писать каждый раз "потерять все ссылки на него" — не хочу. Забыть — слишком жаргонно.


VD>А не нужно на этом делать акцент. Объект считается мертвым когда на него нет ссылок. А убивать или освобождать его не нужно. Так что говори "метрвый объект", или "объект умер".


Принято


PD>>Вот именно. Не откладывается, а немедленно исполняется. Поэтому освобожденные блоки сливаются гарантировано тут же и дают новй сравнительно большой блок, который и будет использован. А здесь, пусть память и вытеснена Windows, а объект все еще живой,


VD>Блин, сколько раз повторять? Живой — это логическое понятие. Не освобождается память из под объекто! Это нужно в голове держать. Живые объекты живут. Мертвые логически исчезают когда исчезает последняя ссылка. Надо отвыкать от ручного распределения. Это другая парадигма и ей мешают старые привычки и знания.


Не надо мне сто раз повторять, я все это давно понял. Еще раз объясняю, что я хочу узнать, на твоем языке . Объект мертв (в твоем смысле, т.е.исчезла последняя ссылка). Но память, отведенная под него, еще не освобождена GC. Он это сделает потом. А пока что я новые объекты создаю. Их в эту память (занятую мерьвым объектом) поместить нельзя, т.к. GC его еще не убрал. Вот это меня и смущает. Если я успею насоздавать быстрее, чем он успеет мертвые объекты похоронить, то память будет расти, и, может быть, весьма сильно.

VD>Да пофигу. Для виртулки память которую можно вытолкнуть == давно не используемой. Так что неиспользуемый большой объект по любому будет вытолкнут при нехватке памяти. А если ОС памяти хватает, то и думать не о чем. Ну, будет использоваться та память которая в обычно приложении будет просто незадействована, ну, и что?


Ничего. Кроме тог, что запуск следующего приложения или переключение на другое растянутся надолго. Так как при его запуске/перключении именно это вытеснение в своп и начнется, а раньше не произойдет — памяти-то много было. Посмотри у Руссиновича алгоритмы работы NT с working set. Система может даже выделить процессу больше, чем запрошенный им максимальный working set. И он это все потребит. И свопинга не будет. А потом произойдет переключение на MS Word, и вот тут-то и начнут только страницы отбирать.




PD>>А это есть перенос процесса компиляции на target машину и проведение ее там с учетом ее специфики (память, процессор и т.д.). Сама идея вполне разумная, ничего против не имею. Прада, надо еще учесть, что машине могут апгрейд сделать, так что не только при инсталяции придется. Но это детали.


VD>А преджит как бы не привязан к инсталляции. Если в те кто все это реализуют дальновидны, то дума, они сделали проверку процессора и перекомпиляцию всех заданий. Хотя как я уже говорил — это все скорее задел на будующее. На сегодня преджит реального ускорения не дает. Только более быструю загрузку.


Нет, с идеей "докомпиляции" я согласен. Вообще, скажем так — доводка программы на target машине — очень разумно.

PD>>Знаю. Я бы даже сказал, не отключается, а антиоптимизация выполняется. Т.е вот в таком коде


VD>Не делает он никакой "антиоптимизации". Просто не делает оптимизаций. Вот и все. Оптимизации это отдельные процедуры прогоняемые по внутренеему представлению.


Я имел в виду, что ни один программист на ассемблере столь неэффективный код писать никогда не будет

VD>Я знаю как быстрее и компактнее, причем с ПДБ и т.п. Нужно просто не использовать С++.




Зачем такая агрессивность, я все же не пойму. Нравится тебе C#, а другим Visual Basic — ну и что ? А так, у меня впечатление такое, что назначь тебя министром информатики — первый приказ был бы о запрещении C++.

PD>>Ну как-то несерьезно это слышать, ей богу. При чем здесь инклюды ? Это же просто способ вставки описаний. В них же кода нет (не считая темплейтов)!


VD>Гы — "кода нет". А на "не считая темплейтов" два раз гы и еще один гы-гы.

VD>Именно инглюды создают все тормоза С++. А шаблоны их умножают многократно. И прекомпилируемые заголовки — это мертвому припарка.

Я думаю, на эту тему дискутировать не стоит — только флейм получится. Кому нравится арбуз, а кому свиной хрящик


PD>> Можешь, конечно сказать, что это не С++ а Windows. Говори, я не против. Суть не меняется от этого.


VD>Я могу сказать, что и ДЛЛ в чистом виде, и С++-ая идеология модулей, к коей ДЛЛ отношения не имет — это все дремучий прошлый век. Никуда не годные технологии доживающие свои времена.


Честно говоря, даже как-то страшно это слышать. До сих пор с такой нетерпимостью только в политике сталкиваться приходилось.



VD>В общем, что трепаться. Сравни скорость компиляции С++-ного проекта и дотнетного. Даже если дотнетных создан с использованием МС++ он один фиг собирается куда быстрее С++-ного.


Я уже писал — время компиляции меня мало интересует. Меня больше время работы интересует.


VD>Не, у каждого массива еще довесок в 16 байт (8 на объект и 4 длинна и т.п.), а может и болше. Плюс черт его знает, что там ЖЦ делает при распредлении массивов. Может он их в некоторый массив в другой хип засовывает...


Вот это мне и не нравится = черт его знает, кто там и где без моего ведома делает.
With best regards
Pavel Dvorkin
Re[6]: тест с матрицами
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 04.10.05 14:55
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, Serginio1, Вы писали:


S>>Здравствуйте, Serginio1, Вы писали:



а так
S>>> для float [][] а,в;
S>>унсейв выглядит так

S>>
S>> for(i = 0; i < nSize; i++)
S>>{
S>>for(j = 0; j < nSize; j++)
S>>{
S>>temp = 0;
S>>fixed(float* aa=а[i][0])
S>>{
S>>for( k = 0; k < nSize; k++, аа++)
S>> fixed(float* bb=b[k][0])
S>> {
S>>temp += *aa * bb[j];
S>>}
S>>}
S>>c[i,j] = temp;
S>>}
S>>}
S>>
и солнце б утром не вставало, когда бы не было меня
Re[9]: тест с матрицами
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.10.05 15:48
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Я думаю, что и его и тебя я правильно понял. В LOH укомпакчивания нет, так ?


Тогда в чем вопросы? Мы вроде друг другу не противоричим. Думаю, ты все же меня не так понял. Когда я говорит об укомпакчивании, то говорил о обычном хипе второго поколения, а ты воспринял эти слова на счет LOH.

VD>>Что значит по "адресному простанству"? Еще раз повторяю, что дотнет пытается занимать виртулку у системы блоками. Причем довольно большими.


PD>Это и значит. Т.е. не лежит в непрерывном диапазоне виртуальных адресов.


Хоть кол на голове теши. Выделенное жирным прочти еще раз. Естественно, то занять сразу всю память в системе нельзя. Но большие блоки подразумевают, что адресов достаточно чтобы небыло проблем.

...
PD>Принято

Похоже, что все же не очень.

PD>Не надо мне сто раз повторять, я все это давно понял.


Да, вот со стороны не заметно.

PD> Еще раз объясняю, что я хочу узнать, на твоем языке . Объект мертв (в твоем смысле, т.е.исчезла последняя ссылка). Но память, отведенная под него, еще не освобождена GC. Он это сделает потом.


Ну, я же гворю нихрена не понял.

Неосвобождается никакая память никогда. В принципе!
Память считается свободной стазу как объект умер. Просто хип получае фракментированным и ЖЦ требуется произвести вычисление графа живых объектов, чтобы перенести их в другой хип, сдвинуть в этом (если это второе поколение). И только в LOH он занимается отметкой блоков которые "освободились".

PD> А пока что я новые объекты создаю. Их в эту память (занятую мерьвым объектом) поместить нельзя, т.к. GC его еще не убрал. Вот это меня и смущает. Если я успею насоздавать быстрее, чем он успеет мертвые объекты похоронить, то память будет расти, и, может быть, весьма сильно.


Знашь, я устал повтоярь. По этому скажу последний раз. Все очень просто. Большие объекты никто не занимает тоннами в цикле. Так что такой проблемы не существует. Для маленьких объектов не существует понятия памяти занятой мертвыми объектами, по этому их можно создавать хоть миллион. Для них важно чтобы они не перелизали в другие поколения. Так что нет такой проблемы. Есть другая проблема. Фрэймворк в целях оптимизации занимает довольно много памяти про запас. И хотя эта пмять один хрен свободна, но отдельных товарщей это сильно смущает. Этим товарищам советуют запустить фрэймворк в осбтановке ограниченных ресурсов. При это он начинает расходовать память значительно экономнее. Првда и работает менее эффективно.

VD>>Да пофигу. Для виртулки память которую можно вытолкнуть == давно не используемой. Так что неиспользуемый большой объект по любому будет вытолкнут при нехватке памяти. А если ОС памяти хватает, то и думать не о чем. Ну, будет использоваться та память которая в обычно приложении будет просто незадействована, ну, и что?


PD>Ничего. Кроме тог, что запуск следующего приложения или переключение на другое растянутся надолго.


Это твои догадки не имеющие ничего общего с действительносью, так как и свопинг происходит в таких условиях довольно шутстро, и дотнет начинает умерять апетит при нехватке памяти.

PD> Так как при его запуске/перключении именно это вытеснение в своп и начнется, а раньше не произойдет — памяти-то много было. Посмотри у Руссиновича алгоритмы работы NT с working set. Система может даже выделить процессу больше, чем запрошенный им максимальный working set. И он это все потребит. И свопинга не будет. А потом произойдет переключение на MS Word, и вот тут-то и начнут только страницы отбирать.


1. Это рассуждения про десктоп системы. В серверных приложениях все несколько иначе.
2. Один хрен визуально никаких тормозов не наблюдается. Можешь провести эксперемент. Возми любое дотнетное (а можно и нет) приложение отожравшее много (по-твоему) памяти и минимизируй его. Увидишь, что его ворксет сильно сократится, хотя никаких тормозов ты не заметишь.

PD>Я имел в виду, что ни один программист на ассемблере столь неэффективный код писать никогда не будет


Естественно. Программист — человек. И он принципиально не будет без особого на то смысла пихать что-то в память. А генератор код — это программа и как раз она то будет рубить по алгоритму. И чтобы этот алгоритм стал "умнее" нужно не мало усилий приложить.

PD>Зачем такая агрессивность, я все же не пойму. Нравится тебе C#, а другим Visual Basic — ну и что ? А так, у меня впечатление такое, что назначь тебя министром информатики — первый приказ был бы о запрещении C++.


C++ мне не нравится по объективным причинам. В данном разговоре в основном по причине отсутствия поддержки модльности. У Жлэбэйсика, кстати, таких проблем никогда не было. А агрессивности особой нет. Есть скорее зларадство. Вообще C++ — это мой любимый язык в прошлом в котором я не перестаю разочаровываться по сей день. Хотя и по сей день некоторые его особенности мне нравятся.

PD>Я думаю, на эту тему дискутировать не стоит — только флейм получится. Кому нравится арбуз, а кому свиной хрящик


А что здесь разговаривать то? Компиляция 8 проектов С++ с общим объемом исходников 3.5 метра занимала у нас 15 минут на довольно современной технике. И это на одном из самых быстрых компиляторов — VC. На Intel C++ это вообще вылевалось в часы. Сегодня Янус с практически тем же объемом исходников на C# (а они точно компактнее плюсовых) компилируется за 2 секунды!

PD>Честно говоря, даже как-то страшно это слышать. До сих пор с такой нетерпимостью только в политике сталкиваться приходилось.


Да, никакой нетерпимости тут нет. Это трезвая оценка фактов. Я прошел путь от полностью монолитных систем, через ДДЛ, КОМ и в конце концов пришел к дотнетным сборкам. Могу отвественно заявить, что ничего лучше сборок я не видел. А ДЛЛ, по сравнению с ними, просто каменный век. По сути сборки и есть ДЛЛ-и или ЕХЕ-шники, но схожего в них толко PE-формат. Далее это земля и небо. Наличие метаинформации описывающей все внутри сборки, возможности подписывать содержимое сборки, хранение промежуточного кода вместо исполнимого, использование реляционной модели для хранения метаинформации и ресурсов... и против всего этого банальные разделы с маш.кодом и список экспортируемых функций без малейшего намека на описание.

PD>Вот это мне и не нравится = черт его знает, кто там и где без моего ведома делает.


А тебе нравится, что в С++ виртуальный объект тоже черт знает что хранит? А то что указатели могут быть байт эдак по 16 и более?

Тут это хотя бы документировано.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.