Конференция "Начинающим" » странное поведение Case оператора в консольном приложении
 
Ошибка соединения. delphimaster.php on line 737
  • Тимохов Дима © (25.12.16 21:47) [20]

    > Rouse_ ©   (25.12.16 20:13) [18]


    У меня дельфи2007.

    Саш, я загнул про 30%, там была ошибка теста(((
    Но разница все же есть.

    Убрал вообще Random. Дело не в нем.
    Test1 и Test2 - имеют одинаковый асм (смотрел CPU), только, есно, адреса переходов различаются.
    Но Test1 выполняется медленнее на от 5 до 18%. Причем, стабильно. Хоть сто раз запуская (без перекомпиляции или с ней - не важно), а вторая (по порядку в коде процедура) Test2 выполняется быстрее. Причем у меня и в оконном приложении похожая картина.

    Чудеса.

    О мастер анализа асма, поясни, пожалуйста, что за чудеса?


    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);
      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 22:57) [22]

    > Rouse_ ©   (25.12.16 22:23) [21]
    > Хм, это уже интересней, ок с утра гляну

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

    )))
  • DVM © (25.12.16 23:01) [23]

    > Тимохов Дима ©   (25.12.16 21:47) [20]

    Разница есть только в 32 бит приложении (5%), в 64 бит ее либо нет, либо она скачет в пределах +/- 1%
  • Игорь Шевченко © (25.12.16 23:07) [24]
    Вот же делать людям нечего
  • Тимохов Дима © (25.12.16 23:09) [25]

    > Игорь Шевченко ©   (25.12.16 23:07) [24]
    > Вот же делать людям нечего

    Почему? Эксперимент, гипотеза, подтверждение гипотезы. Вполне научный метод.

    Игорь, согласись (ну или не согласись), ведь факт интересный - как может один и тот же код (на уровне асма - ниже, т.е. до опкодов или что там - не опускаюсь, ибо не умею) дает разный результат?
  • DVM © (25.12.16 23:09) [26]

    > Тимохов Дима ©   (25.12.16 21:47) [20]
    >

    А вообще ты неправильно замеряешь время.
    QueryPerformanceFrequency() надо вызывать сразу после действия, а не до.
  • DVM © (25.12.16 23:13) [27]

    > Тимохов Дима ©   (25.12.16 21:47) [20]

    Все эти странности из-за того, что CPU поднимает частоту после (или во время) вызова первой функции и вторая отрабатывает на более высокой частоте, чем первая.
  • Тимохов Дима © (25.12.16 23:16) [28]

    > DVM ©   (25.12.16 23:09) [26]
    >
    > > Тимохов Дима ©   (25.12.16 21:47) [20]
    > >
    >
    > А вообще ты неправильно замеряешь время.
    > QueryPerformanceFrequency() надо вызывать сразу после действия,
    >  а не до.

    это я здесь в примере переставил, чтобы процедуры короче были.
    у меня и так разница есть - не такая устойчивая, но от 2 до 12% бывает.
  • Тимохов Дима © (25.12.16 23:17) [29]

    > DVM ©   (25.12.16 23:13) [27]
    >
    > > Тимохов Дима ©   (25.12.16 21:47) [20]
    >
    > Все эти странности из-за того, что CPU поднимает частоту
    > после (или во время) вызова первой функции и вторая отрабатывает
    > на более высокой частоте, чем первая.

    Век живи - век учись.
    Спасибо. Очень похоже на правду.
  • invis © (26.12.16 02:43) [30]
    Test1 и Test2 - имеют одинаковый асм (смотрел CPU), только, есно, адреса переходов различаются.

    Адреса имеют значение, в интернетах пишут (ссылаясь на мануалы Интел), что рекомендуется выравнивать адрес перехода на 16.
    Но Дельфи этого не делает, иногда случайно попадает, иногда нет. Отсюда и разница.
  • Rouse_ © (26.12.16 11:02) [31]
    Нет никаких странностей, ибо:

    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.


    Вот так все будет нормально с легкой девиацией.
  • DVM © (26.12.16 11:05) [32]

    > Rouse_ ©   (26.12.16 11:02) [31]

    Ну я ж говорю, он неправильно замерял время, у него из-за динамического изменения частоты у всех современных CPU время выполнения некорректно считалось.
  • Rouse_ © (26.12.16 11:35) [33]
    Ну да, я тоже не с первого раза заметил, поэтому и удивился.
  • Rouse_ © (26.12.16 11:36) [34]
    Кстати выяснилось что этот-же код на 64 битах работает в два раза медленней чем на 32-ух. Хотя асм выхлоп ровный без излишеств, а вот это уже печально.
  • Тимохов Дима © (26.12.16 11:48) [35]

    > 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



    Причем, картина стабильная.
  • Rouse_ © (26.12.16 11:57) [36]
    У меня вроде ровно:
    Test1 = 1/1,4481  | Test2 = 1/1,4482 | diff in % = 0,00
    Test1 = 1/1,4439  | Test2 = 1/1,4465 | diff in % = 0,18

  • Тимохов Дима © (26.12.16 12:02) [37]

    > Rouse_ ©   (26.12.16 11:57) [36]
    > У меня вроде ровно:


    В цикле прогнал: среднее значение 8%.

    Видать, особенности моего Intel Core 2 DUO.
    Или компилятор иной.

    Ладно) Забью - практического смысла ноль, видимо, Игорь прав.
  • invis © (26.12.16 14:42) [38]
    Попробуй поменять местами Test1 и Test2 (не вызовы, а сами функции).
  • NoUser © (28.12.16 18:27) [39]

    > [34]

    0041A5D6 81E201000080     and edx,$80000001


    vs
    0000000000427352 41F7F8           idiv r8d


    это без излишеств?


    > [35]
    > Причем, картина стабильная.

    Гипертрейдинг ?
 
Конференция "Начинающим" » странное поведение Case оператора в консольном приложении
Есть новые Нет новых   [118450   +39][b:0.001][p:0.002]