-
Компилятор D7. в большом цикле выполнятся оператор Case всегда выполняется за ~150сек
Randomize;
for i := 0 to 2147483647 do begin
case Random(20) of
1:;
.....
20:;
end;
end; а если сместить чуть метки, примерно так:
Randomize;
for i := 0 to 2147483647 do begin
case Random(20,40) of
20:;
.....
40:;
end;
end; то такой код (с другим диапазоном меток) начинает выполняться быстрее, всегда ~90 сек. Причем данный эффект наблюдатся только в консольном приложении, в оконном два примера работают одинаково. Может есть опции компилятора для разной трансляции case?
-
> Random(20,40)
я вот уже плохо помню, но разве это не RandomRange? которая немного не Random(20)
-
> kilkennycat © (24.12.16 20:01) [1]
Это условно, писалось в посте от руки
-
У меня только одна бредовая идея приходит на ум из этих результатов.
Что когда диапазон маленький те от 1..20 поиск нужного ключа идет перебором, а когда значения поболее от 20..40, то поиск ключа идет бинарным поиском.
-
Уверен, что распределение равномерное в 0-20 и в 20-40. А у тебя разное количество меток к тому же, т.е. в первом случае каждое 20 значение не попадает ни на одну метку.
-
> Уверен, что распределение равномерное в 0-20 и в 20-40
на 100%, я просто нумерацию начал не с 0, а с 20, а в метках код остался прежним.
-
> Гена © (24.12.16 20:10) [2] > Это условно, писалось в посте от руки
ну круто, чё. меряешь время-то неусловно, вопрос задаешь неусловно, а что меряешь, какой код - условно.
> а когда значения поболее от 20..40,
о возникает вопрос, как сделал от 20. если RandomRange, то это уже модуль Math
а вообще, дизасм в помощь.
-
> а вообще, дизасм в помощь.
Это б если я был умный а не учился на первом курсе.
Вобщем, кому интересно напишите в чем же дело.
Беру, просто перетосовую беспорядочно метки в Case т.е. не по порядку от 1..20, а 20,5,3,17 итд и результат выполнения становиться быстрей т.е те же ~90 сек второго примера, а не ~150 как если бы метки ишли по порядку.
Получается компилятор генерирует разный код.
-
А и еще один прикол: догружаю case кучей пустых меток вида 100:; те варианты выбора которые несут нагрузку (как помните их 20 шт) разбрасываю среди этих вариантов и опять ~90, хотя казалось бы вариантов стало в 5 раз больше и работать должно в 5 раз медленнее, а работает наоборот быстрее.
Наверно точно в одном случая компилятор принимает решение искать метки перебором, а когда их больше - бинарным поиском
-
> Гена © (24.12.16 19:48)
С кейсом много чюдесов. Объяснить тебе смогут все деталях только те, кто разбирается в асме. Я, к сожалению, не разбираюсь...
-
Смотря какой case, маленький джампами организован, большой через датамап, тут лучше асм листинг смотреть, у меня такого поведения не воспроизвелось
-
> у меня такого поведения не воспроизвелось
Так только в консоли, в оконных "не балуется"
-
Экзешники архивом выложи, завтра или в пн гляну под IDA что там у тебя чудит, желательно с map файлами
-
> Это б если я был умный а не учился на первом курсе.
)))
вот-вот, универы нынче зло!
Ставишь точку останова (BreakPoint) , потом Ctrl+Alt+D, потом смотришь асм сам и нам показываешь.
-
> Гена © (25.12.16 00:18) [11] > > > > у меня такого поведения не воспроизвелось > > Так только в консоли, в оконных "не балуется" >
Не вижу разницы для компилятора в этих случаях. Разница может быть только в настройках конкретных проектов.
-
> Германн © (25.12.16 02:01) [14] > Не вижу разницы для компилятора в этих случаях. > Разница может быть только в настройках конкретных проектов.
Вот я бы небыл столь категоричен, знаешь сколько раз я уже натыкался на глюки компилятора? Вполне возможно что это один из таких вариантов. (Хотя, D7 - блин только обратил внимание, я то на берлине проверял)
-
> глюки компилятора
необязательно глюки. вот компиль xc8 иногда один и тот же код какой-то функции оптимизирует по-разному, только из-за того, что где-то совершенно далеко изменился размер переменной, которая к этой функции и отношения-то прямого не имеет. Мне так вместо простейшего сдвига такую хренотень замутил, что я не сразу-то и понял, че творится. При этом всё работает, конечно. Правда, не так :)
-
> Rouse_ © (25.12.16 00:07) [10] > Смотря какой case, маленький джампами организован, большой > через датамап, тут лучше асм листинг смотреть, у меня такого > поведения не воспроизвелось
Розыч, а у меня воспроизвелось. Только наоборот: у меня другие рандомы, правда (не думаю, что важно). Разница во времени процентов 20-30%. Чудеса.
-
> Тимохов Дима © (25.12.16 16:45) [17] > Розыч, а у меня воспроизвелось. Только наоборот: у меня > другие рандомы, правда (не думаю, что важно). Разница во > времени процентов 20-30%. Чудеса.
Ну скинь свой вариант, у меня оба варианта кода за 5 секунд (5.7) проходят. Я специально семерку с образа поднял и протестил именно в консоли.
-
> kilkennycat © (25.12.16 14:10) [16] > Мне так вместо простейшего сдвига такую хренотень замутил, > что я не сразу-то и понял, че творится. При этом всё работает, > конечно. Правда, не так :)
Это скорее всего как раз прыжок через датамап (а вот с ним могут быть чудеса - на 2005 гарантированно воспроизводился один из вариантов, пока не пофиксили). На кодецентрале там даже большое обсуждение было.
-
> Rouse_ © (25.12.16 20:13) [18]
У меня дельфи2007. Саш, я загнул про 30%, там была ошибка теста((( Но разница все же есть. Убрал вообще Random. Дело не в нем. Test1 и Test2 - имеют одинаковый асм (смотрел CPU), только, есно, адреса переходов различаются. Но Test1 выполняется медленнее на от 5 до 18%. Причем, стабильно. Хоть сто раз запуская (без перекомпиляции или с ней - не важно), а вторая (по порядку в коде процедура) Test2 выполняется быстрее. Причем у меня и в оконном приложении похожая картина. Чудеса. О мастер анализа асма, поясни, пожалуйста, что за чудеса?
program Project1;
uses
SysUtils, Windows;
const
cCount = 500000000;
var
r: Integer;
f, b, a: TLargeInteger;
d1, d2: Extended;
s1, s2: String;
procedure Test1;
var i: Integer;
begin
QueryPerformanceCounter(b);
for i := 0 to cCount do
case i mod 2 of
0: Inc(r);
1: Dec(r);
end;
QueryPerformanceCounter(a);
d1 := (a-b)/f;
s1 := IntToStr(R)+'/'+FormatFloat('0.0000', d1);
end;
procedure Test2;
var i: Integer;
begin
QueryPerformanceCounter(b);
for i := 0 to cCount do
case i mod 2 of
0: Inc(r);
1: Dec(r);
end;
QueryPerformanceCounter(a);
d2 := (a-b)/f;
s2 := IntToStr(R)+'/'+FormatFloat('0.0000', d2);
end;
begin
QueryPerformanceFrequency(f);
r := 0; Test2;
r := 0; Test1;
Writeln('Test1 = '+s1+' | Test2 = '+s2+' | diff in % = '+FormatFloat('0.00', (d2-d1)/d1*100));
Readln;
end.
-
Хм, это уже интересней, ок с утра гляну
-
> Rouse_ © (25.12.16 22:23) [21] > Хм, это уже интересней, ок с утра гляну
Саш, ты извиняй, если что. Это же конференция для Начинающих - значит мне можно и потупить немного.
)))
-
> Тимохов Дима © (25.12.16 21:47) [20]
Разница есть только в 32 бит приложении (5%), в 64 бит ее либо нет, либо она скачет в пределах +/- 1%
-
Вот же делать людям нечего
-
> Игорь Шевченко © (25.12.16 23:07) [24] > Вот же делать людям нечего
Почему? Эксперимент, гипотеза, подтверждение гипотезы. Вполне научный метод.
Игорь, согласись (ну или не согласись), ведь факт интересный - как может один и тот же код (на уровне асма - ниже, т.е. до опкодов или что там - не опускаюсь, ибо не умею) дает разный результат?
-
> Тимохов Дима © (25.12.16 21:47) [20] >
А вообще ты неправильно замеряешь время. QueryPerformanceFrequency() надо вызывать сразу после действия, а не до.
-
> Тимохов Дима © (25.12.16 21:47) [20]
Все эти странности из-за того, что CPU поднимает частоту после (или во время) вызова первой функции и вторая отрабатывает на более высокой частоте, чем первая.
-
> DVM © (25.12.16 23:09) [26] > > > Тимохов Дима © (25.12.16 21:47) [20] > > > > А вообще ты неправильно замеряешь время. > QueryPerformanceFrequency() надо вызывать сразу после действия, > а не до.
это я здесь в примере переставил, чтобы процедуры короче были. у меня и так разница есть - не такая устойчивая, но от 2 до 12% бывает.
-
> DVM © (25.12.16 23:13) [27] > > > Тимохов Дима © (25.12.16 21:47) [20] > > Все эти странности из-за того, что CPU поднимает частоту > после (или во время) вызова первой функции и вторая отрабатывает > на более высокой частоте, чем первая.
Век живи - век учись. Спасибо. Очень похоже на правду.
-
Test1 и Test2 - имеют одинаковый асм (смотрел CPU), только, есно, адреса переходов различаются.
Адреса имеют значение, в интернетах пишут (ссылаясь на мануалы Интел), что рекомендуется выравнивать адрес перехода на 16. Но Дельфи этого не делает, иногда случайно попадает, иногда нет. Отсюда и разница.
-
Нет никаких странностей, ибо:
program Project1;
{$APPTYPE CONSOLE} {$O+} uses SysUtils, Windows; const cCount = 500000000; var r: Integer; f, b, a: TLargeInteger; d1, d2: Extended; s1, s2: String;
procedure Test1; var i: Integer; begin QueryPerformanceCounter(b); for i := 0 to cCount do case i mod 2 of 0: Inc(r); 1: Dec(r); end; QueryPerformanceCounter(a); QueryPerformanceFrequency(f); d1 := (a-b)/f; s1 := IntToStr(R)+'/'+FormatFloat('0.0000', d1); end;
procedure Test2; var i: Integer; begin QueryPerformanceCounter(b); for i := 0 to cCount do case i mod 2 of 0: Inc(r); 1: Dec(r); end; QueryPerformanceCounter(a); QueryPerformanceFrequency(f); d2 := (a-b)/f; s2 := IntToStr(R)+'/'+FormatFloat('0.0000', d2); end;
begin r := 0; Test1; r := 0; Test2; Writeln('Test1 = '+s1+' | Test2 = '+s2+' | diff in % = '+FormatFloat('0.00', (d2-d1)/d1*100)); r := 0; Test2; r := 0; Test1; Writeln('Test1 = '+s1+' | Test2 = '+s2+' | diff in % = '+FormatFloat('0.00', (d2-d1)/d1*100)); Readln; end.
Вот так все будет нормально с легкой девиацией.
-
> Rouse_ © (26.12.16 11:02) [31]
Ну я ж говорю, он неправильно замерял время, у него из-за динамического изменения частоты у всех современных CPU время выполнения некорректно считалось.
-
Ну да, я тоже не с первого раза заметил, поэтому и удивился.
-
Кстати выяснилось что этот-же код на 64 битах работает в два раза медленней чем на 32-ух. Хотя асм выхлоп ровный без излишеств, а вот это уже печально.
-
> Rouse_ © (26.12.16 11:35) [33] > Ну да, я тоже не с первого раза заметил, поэтому и удивился. >
Да я в примере тут вынес QueryPerformanceFrequency, чтобы код короче был. Конечно, замеряю всегда QueryPerformanceFrequency после QueryPerformanceCounter (справку читал). Розыч, твой код - не сказал бы, чтобы легкая девиация была. Test1 = 1/1,3297 | Test2 = 1/1,4811 | diff in % = 11,39
Test1 = 1/1,3866 | Test2 = 1/1,5992 | diff in % = 15,34 Причем, картина стабильная.
-
У меня вроде ровно: Test1 = 1/1,4481 | Test2 = 1/1,4482 | diff in % = 0,00
Test1 = 1/1,4439 | Test2 = 1/1,4465 | diff in % = 0,18
-
> Rouse_ © (26.12.16 11:57) [36] > У меня вроде ровно:
В цикле прогнал: среднее значение 8%.
Видать, особенности моего Intel Core 2 DUO. Или компилятор иной.
Ладно) Забью - практического смысла ноль, видимо, Игорь прав.
-
Попробуй поменять местами Test1 и Test2 (не вызовы, а сами функции).
-
> [34]
0041A5D6 81E201000080 and edx,$80000001 vs 0000000000427352 41F7F8 idiv r8d это без излишеств? > [35] > Причем, картина стабильная.
Гипертрейдинг ?
|