Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет kouzdra ([info]kouzdra)
@ 2008-04-29 14:22:00


Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Entry tags:Компутерщина

Тут наткнулся на очередного энтузиаста С++ с незамутненным вполне сознанием. Ну интереса ради написал три тестика - точнее один - на трех языках:

создание и сортировка (причина выбора теста была в упоминании std::sort в контексте Ну не нужно и все. И списки сортировать без библиотечных функций не нужно) массива из 2 млн строк, представляющих собой числа от 0 до 2_000_000 в дес.записи:

C++:

void test () {
   vector v (2000000);
   char buf [20];
   for (int i = 0; i != v.size (); ++ i)
   {
     sprintf (buf, "%d", i);
     v [i] = string (buf);
   }
   sort (v.begin (), v.end (), less_equal ());
//   for (int i = 0; i != v.size (); ++ i)
//      cout << v [i] << "\n";
}


O'Caml:
let (+>) x f = f x
let s = Array.init 2_000_000 string_of_int      
let _ = Array.fast_sort compare s      
(*let _ = s +> Array.to_list +> String.concat ", " +> Printf.printf "[%s]\n"*)      


Java:
	public static void main(String[] args) {
		final String [] v = new String [2000000];
		for (int i = 0; i < v.length; i++) v[i] = Integer.toString(i);
		Arrays.sort(v);
//		for (String aV : v) System.out.println("s = " + aV);
	}


Результаты оказались ожидаемыми - С++ с O'Caml одинаковы по скорости, программа на O'Caml потребила 36MB памяти против 54MB на С++, Жаба порвала С++ как бобик тряпку - инициализация - массива раза в полтора быстрее, сортировка - раза в 3.

Смотреть код и память у Жабы - занятие то, еще на код O'Caml и C++ я посмотрел:
O'Caml - 84 вполне естественных строчки на асме, С++ - 2895 строчек (без отладочной информации).

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

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


Какая из этого мораль - да очень простая - полезно иногда немного по сторонам смотреть, ну и еще одна - если Вы совершенно точно не знаете, почему вам не подходит Жаба - не лезьте в С++ - просто потратите кучу времени совершенно зря.


(Читать комментарии) - (Добавить комментарий)


[info]ppkk
2008-04-30 23:08 (ссылка)
Куча и без того динамическая, а максимальный размер при виртуальной памяти знать нужно.
???

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-04-30 23:48 (ссылка)
Ведь не хочется, чтобы замусоренная куча сначала была отсвоплена, а потом в ней началась сборка мусора?

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]kouzdra
2008-04-30 23:54 (ссылка)
Честно говоря O'Caml и бемовский коллектор как-то без этих ужасов обходятся.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-05-01 00:38 (ссылка)
Наверно, более разумные умолчания. Можно еще попытаться медитировать на вынюковые счетчики производительности, но как-то это сомнительно.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]kouzdra
2008-05-01 11:24 (ссылка)
Да нет - просто у них нет лимита - они действительно могут сожрать всю память - но по крайней мере ocamlевый расширяет кучу только если она оказывается заполнена слишком сильно (там есть параметр - заполненность кучи - Gc.space_overhead) -

http://caml.inria.fr/pub/docs/manual-ocaml/libref/Gc.html

которым можно управлять, как и прочими параметрами Gc - причем можно их менять на ходу. Жабий GC после общения с ocaml'евским у меня честно говоря вызывает изрядное раздражение - у тех давно уже и инкрементальный сборщик нормально работал.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-05-01 13:05 (ссылка)
У меня размер кучи управляется диапазонами по размеру, доле живых объектов (примерно соответствует твоему параметру) и доле времени исполнения программы, проведенной в сборщике мусора. Размер меняется только после большой сборки мусора. Диапазоны там для гистерезиса, чтобы не гуляло туда-сюда на границе. И все равно работает не очень хорошо - иногда пухнет слишком быстро, иногда наоборот. Подозреваю, что по существу все эти параметры нужны для предсказания будущего по короткому прошлому, а для моего алгоритма и типичных приложений оно нифига предсказываться не желает. Вместо гладкости явно лезут периодические свойства остатков (типа, размер младшего поколения поделить на аппетит тела цикла).

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

Но -Xmx явно скоро умрет. Для нового сборщика G1 в нем мало смысла.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]ppkk
2008-05-02 00:34 (ссылка)
G1
А когда оно будет?

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-05-02 03:10 (ссылка)
В серверном варианте уж больше года как есть.

(Ответить) (Уровень выше)


[info]ppkk
2008-05-02 00:30 (ссылка)
Честно говоря, это, по-моему, означает, что надо собирать мусор, когда приходит пора использовать жёсткий диск (естественно, с установкой, чтобы не производить её повторно слишком быстро). Я неправильно понимаю сущность сборки мусора, или её свойство в том, что она может происходить в любой момент?

Ответ только сделал ситуацию непонятнее.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-05-02 03:15 (ссылка)
ОС, однако, не извещает приложение о свопинге. И вообще в системе много процессов, каждый из которых может хотеть память.

В жабе сборка может происходить только при отведении памяти. Спецификация вольнее - везде. где может быть брошено исключение OutOfMemory, - но так программ никто не пишет.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]ppkk
2008-05-02 10:43 (ссылка)
(следующий комментарий учтён)

ОС, однако, не извещает приложение о свопинге.
Но отследить, какие страницы сброшены на медленную память ведь можно?
Да и заблокировать страницы против их сброса на медленную память тоже можно.
Если для Явы самое страшное — возможное торможение из-за возможного переноса в медленную память, то можно выделять память "по понятиям" (типа меньшего из 32 Мб и 10% свободной) и блокировать её от сброса, когда памяти не хватит, — собрать мусор, если собралось немного, — выделить ещё памяти, когда проснётся совесть, начать выделять память без блокировки сброса в медленную.

В общем, лучше бы медленнее сортировали строки.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-05-02 11:19 (ссылка)
По-моему, лучше бы умолчательные параметры устанавливали в более разумные.

(Ответить) (Уровень выше)


[info]qwerty
2008-05-02 03:21 (ссылка)
Насчет мест сборки мусора вру - в принципе, где угодно, на самом же деле только когда все нитки в GC-safe поинтах, которые определяются реализацией.

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

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]ppkk
2008-05-02 10:12 (ссылка)
А, ну я тогда правильно предполагал: в остальных местах тоже можно, только придётся не просто остановить программу, но и как-то нетривиально её перестраивать.

По-хорошему алгоритм и параметры по умолчанию должны быть такими, чтобы о них не нужно было знать.
Проблеме с вылетом из-за нехватки памяти приложений, которые не снабжены тем, о чём я изначально написал (в Окнах: установщиком, обёрткой в виде .exe файла, который следит за тем, что установлена правильная версия JRE и вызывает исполнение с правильными параметрами), очень много лет.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-05-02 11:17 (ссылка)
Собственно, а почему бы вам такую программу не написать? Код жабы, кажется, уже открыт. Теоретически возможно к нему приложить любую программу с открытым кодом под GPL2. Если программа окажется полезной. народ за нее проголосует и станет вместе с жабой распространять. Передать пожелание я могу, но сильно сомневаюсь, что на него откликнутся. Оно, вероятно, полезное, но не интересное :-) Я сам десктопных жаб не пишу. Моя мобильная стандарта CLDC 1.1. Максимальный размер кучи у нее по умолчанию 1 МБ.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]ppkk
2008-05-02 11:54 (ссылка)
Собственно, а почему бы вам такую программу не написать? Код жабы, кажется, уже открыт. Теоретически возможно к нему приложить любую программу с открытым кодом под GPL2. Если программа окажется полезной. народ за нее проголосует и станет вместе с жабой распространять. Передать пожелание я могу, но сильно сомневаюсь, что на него откликнутся. Оно, вероятно, полезное, но не интересное :-)

Я очень рад, что скорее всего не откликнутся. Я добра Яве не желаю, развивать её не хочу, не то, что собственным трудом, так даже полезными советами. Не считал бы очевидным, не писал бы и предложений:)

А вот сортировку TStringList во Фри Паскале улучшить, наверное, соберусь: её разработчики ФП, скорее всего, тоже считают полезной, но неинтересной:)

По-моему, лучше бы умолчательные параметры устанавливали в более разумные.
Они не могут быть разумными. Это не типичная программа на Яве, но какому-нибудь преобразователю картинок может легко потребоваться от 128*160=20480 б до нескольких гигабайт. (С учётом почти популярности подсчёта статистики использования цветов в картинке на языке PHP, это не так уж глупо.)

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-05-02 12:09 (ссылка)
Ну, почему не может? Установить максимум в 2 ГБ и держать liveness в некотором диапазоне (60-80%, например). Если становится больше высшей границы, кучу расширять, например, умножая ее размер на некоторый больший единицы коэффициент, но не более, чем до предела. Если меньше низшей границы, соответственно, наоборот. Начинать с нижнего предела размера, каковой установить, скажем, в 4 МБ. Единственный недостаток - сжирающее всю кучу приложение помрет не быстро, а долго и мучительно свопя.

(Ответить) (Уровень выше)

Пардон, что лезу в разговор
[info]mc6312.livejournal.com
2008-05-02 17:27 (ссылка)
> сортировку TStringList во Фри Паскале улучшить
Там не в самой сортировке дело, там сравнение строк тормозное до изумления.
Ради эксперимента вместо TStringList.Sort попробовал TStringList.CustomSort(SortProc), где вместо SortProc была стянутая из дельфей ассемблерная процедура, результат:
Sort: 13.58 sec.
CustomSort: 3.92 sec.
в 3.5 раза быстрее...

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: Пардон, что лезу в разговор
[info]ppkk
2008-05-02 19:10 (ссылка)
Интересно.

В принципе, я не без этой мысли: иначе про TList написал бы.

Но Дельфы тоже тормозят: выше я писал, что "стандартным методом" у ФП время ~25 секунд, у Дельф — ~23, так что и в Дельфах SortProc не очень освоен.

А процедура встроенная (inline)? Как я понимаю, "быстро" могут работать только встроенные процедуры и процедуры из модуля system.

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: Пардон, что лезу в разговор
[info]mc6312.livejournal.com
2008-05-02 20:58 (ссылка)
У фрипаскаля внутри TList.Sort целые дебри:
Procedure TStringList.Sort;
begin
CustomSort(@StringListAnsiCompare);
end;

function StringListAnsiCompare(List: TStringList; Index1, Index: Integer): Integer;
begin
Result := List.DoCompareText(List.FList^[Index1].FString,
List.FList^[Index].FString);
end;

Function TStringList.DoCompareText(const s1,s2 : string) : PtrInt;
begin
// могли бы процедурную переменную для функции сравнения завести, нафига каждый раз
// if-then?
if FCaseSensitive // почему-то по умолчанию оно false, и вызывается проверка не учитывающая регистр
then result:=AnsiCompareStr(s1,s2)
else result:=AnsiCompareText(s1,s2);
end;

function Win32AnsiCompareText(const S1, S2: string): PtrInt;
begin
// при этом она (под win32) просто вызывает функцию API, которая довольно нетороплива
// емнимс, они это передрали у дельфей
result:=CompareString(LOCALE_USER_DEFAULT,NORM_IGNORECASE,pchar(s1),length(s1),
pchar(s2),length(s2))-2;
end;

если TStringList.CaseSensitive=true, то все равно используется аналогичная обертка системной CompareString, только без флага NORM_IGNORECASE, естественно, оба варианта одинаково тормозят.

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: Пардон, что лезу в разговор
[info]ppkk
2008-05-02 21:55 (ссылка)
// емнимс, они это передрали у дельфей
Просто вызов соответствующей системной функции, по-моему, нельзя считать передиранием. БОльшая часть sysutils под Окнами, кажется, — вызов соответствующих функций ОС.

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

И поэтому я упомянул "быструю сортировку", чтобы не обещать зарабатывать геморрой.

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: Пардон, что лезу в разговор
[info]mc6312.livejournal.com
2008-05-02 22:07 (ссылка)
> отслеживать возможное изменение кодировки

А зачем отслеживать? Маловероятно, что она изменится за время работы процесса (если это не серверное чего-нибудь, да и там тоже). При старте программы создаются таблицы для перевода в верхний регистр (в случае Win32 - с помощью CharUpperBuff, например) и т.п. для текущей кодировки, и далее они используются для регистро-независимого сравнения и т.п.

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: Пардон, что лезу в разговор
[info]ppkk
2008-05-02 22:42 (ссылка)
Да, именно так, только, по-моему, отслеживать надо (не хочется накосячить), и это в принципе несложно (просто хранить с найденными значениями и название кодировки, и каждый раз проверять, не сменилась ли она).

А поддержка неоднобайтовых кодировок — не понимаю, что с ней во Фри Паскале.

И что с поддержкой UTF-8, для которой метод не годится (но которая даже в Окнах имеет номер и название как кодировка).

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: Пардон, что лезу в разговор
[info]mc6312.livejournal.com
2008-05-03 00:25 (ссылка)
Widestrings (UTF-16) во фрипаскале есть. Функции для преобразования utf-8/utf-16/utf-32 друг в друга тоже есть. Функции сравнения строк для widestrings тоже есть. Что у них внутри еще не смотрел.

(Ответить) (Уровень выше)

Re: Пардон, что лезу в разговор
[info]ppkk
2008-05-02 20:24 (ссылка)
Про сортировку я ещё имел в виду, что "быстрая сортировка" лично мне не нравится: нужны ловкости для снижения вероятности квадратичного времени и т.п. Какой-нибудь вариант сортировки кучей, что-нибудь такое, может быть лучше.

(Ответить) (Уровень выше)


(Читать комментарии) -