Re[5]: Агащазкакже
От: xvost Германия http://www.jetbrains.com/company/people/Pasynkov_Eugene.html
Дата: 25.04.05 05:51
Оценка:
Здравствуйте, VladD2, Вы писали:

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

VD>Вообще-то более чем возможно. Просто оптимизатор халявит.

Вот кусок кода:


class C
{
  private ArrayList myList;
  public C(ArrayList list) {myList = list;}
  public void foo() {myList.Add(1);}
}

......
ArrayList list = new ArrayList (collection);
C c = new C(list);
for (int i=0; i<list.Count(); i++)
  c.foo();


И как тут оптимизатор будет думать????
list.Count() не является инвариантом в этом цикле
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Re[6]: Агащазкакже
От: qxWork Голландия http://www.jetbrains.com/company/people/Coox_Sergey.html
Дата: 25.04.05 06:06
Оценка:
X>Вот кусок кода:


X>
X>class C
X>{
X>  private ArrayList myList;
X>  public C(ArrayList list) {myList = list;}
X>  public void foo() {myList.Add(1);}
X>}

X>......
X>ArrayList list = new ArrayList (collection);
X>C c = new C(list);
X>for (int i=0; i<list.Count(); i++)
X>  c.foo();
X>


X>И как тут оптимизатор будет думать????

X>list.Count() не является инвариантом в этом цикле

Это следствие отсутствия в .NET модификатора const. С++ оптимизатор лего справляется с конструкциями вида:
class C {
  int Count() const;
  void foo() const; 
}

void Foo( C &c ) {
  
  for( int i=0; i<c.Count(); ++i ) {
    c.foo();
  }
}

Более того, если добавить в класс C mutable поле и модифицировать его внутри foo, то можно наблюдать интересный эффект

Возвращаясь к опримизатору IL, кое-что он все-таки оптимизит, например, утверждается, что код
int []a = new int[100];
for( int i=0; i<a.Length; ++i ) {
  a[i] = i;
}


работает быстрее, чем
int []a = new int[100];
int nItems = a.Length;
for( int i=0; i<nItems; ++i ) {
  a[i] = i;
}


вследствие того, что оптимизатор удаляет проверки границ массива. Убил бы )
Re[3]: Оптимизация кода
От: SiAVoL Россия  
Дата: 25.04.05 07:05
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Спасибо. Просто мне кажется где-то пробегала такая тема,

А>что вот такой код
А>
А>ArrayList ar = new ArrayList();
А>for(int i = 0; i < ar.Count; i++)
А>{
А>   ar[i] = ...;
А>}
А>


А>будет компилятором оптимизирован в такой


А>
А>ArrayList ar = new ArrayList();
А>int count = ar.Count;
А>for(int i = 0; i < count; i++)
А>{
А>   ar[i] = ...;
А>}
А>


А>Дык вот в IL-е ничего подобного я не заметил. Идет как и положено постоянно ображение к get_Count()

буквально только сегодня прочитал в блоге Brad Abrams`а (здесь) про оптимизацию такого случая.
Если вкратце, то первый вариант будет работать даже медленнее чем второй. Происходит из-за того что JIT должен проводить проверку выхода за пределы массива. Так вот во втором случае он распознает паттерн перебора массива и проверку производит только один раз. А во втором на каждой итерации.
Мораль такова, не стоит пытаться перехитрить оптимизатор, писать надо естесственным образом, а уж он разберется что к чему. К тому же он постоянно развивается. Например в том же блоге написано, что и первый вариант со временем тоже возможно будет распознаваться.
... << RSDN@Home 1.1.4 beta 5 rev. 0>>
Re[6]: Агащазкакже
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.04.05 11:43
Оценка:
Здравствуйте, xvost, Вы писали:

X>
X>class C
X>{
X>  private ArrayList myList;
X>  public C(ArrayList list) {myList = list;}
X>  public void foo() {myList.Add(1);}
X>}

X>......
X>ArrayList list = new ArrayList (collection);
X>C c = new C(list);
X>for (int i=0; i<list.Count(); i++)
X>  c.foo();
X>


X>И как тут оптимизатор будет думать????

X>list.Count() не является инвариантом в этом цикле

Тут — никак. Но это не означает, что невозможно распозновать случае которые не вызывают модифицирующие методы. Особенно это полезно для встроенных коллекций которые используются очень часто. Подобная оптимизация могла бы неплохо ускорить код приложений.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Агащазкакже
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.04.05 11:43
Оценка:
Здравствуйте, qxWork, Вы писали:

W>Это следствие отсутствия в .NET модификатора const.


Подобный модификатор дотнету не нужен. В дотнете можно читать IL. Это позволяет определить наличие побочных эффектов без дополнительной помощь. К сожалению разработчики дотнета не озаботились подобными проблемами. Но в будущем, я уверен, до этого обязательно дойдет дело.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Оптимизация кода
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.04.05 11:43
Оценка:
Здравствуйте, Igor Trofimov, Вы писали:

VD>>И тем не менее при наличии хорошего оптимизатора подобная оптимизация возможна. К сожалению, подобные оптимизации не делаются даже с массивами и в foreach-ах. А уж там им ни что не препятствует.


iT>здесь


Предпочитаю практику .

Ниже приведен набор тестов для второго фрэймворка.

1. Тест List<int> с выносом длинны в перемнную.
            Console.WriteLine("Framework Version: " + Environment.Version);

            const int count = 10000;
            List<int> array = new List<int>(count);

            for (int i = 0; i < count; i++)
                array.Add(i % 20);

            Console.WriteLine("Start");

            int start = Environment.TickCount;

            int sum = 0;

            int len = array.Count;

            for (int k = 0; k < 100000; k++)
                for (int i = 0; i < len; i++)
                    sum += array[i];

            Console.WriteLine("Time is {0}, sum = {1}", 
                Environment.TickCount - start, sum);

Результат:
Framework Version: 2.0.50215.44
Start
Time is 2719, sum = 910065408

2. Тест List<int> с проверкой длинны внутри цикла.
            Console.WriteLine("Framework Version: " + Environment.Version);

            const int count = 10000;
            List<int> array = new List<int>(count);

            for (int i = 0; i < count; i++)
                array.Add(i % 20);

            Console.WriteLine("Start");

            int start = Environment.TickCount;

            int sum = 0;

            for (int k = 0; k < 100000; k++)
                for (int i = 0; i < array.Count; i++)
                    sum += array[i];

            Console.WriteLine("Time is {0}, sum = {1}", 
                Environment.TickCount - start, sum);

Framework Version: 2.0.50215.44
Start
Time is 2250, sum = 910065408

3. С копрированием в масси и проверкой длинны массива внутри цикла.
            Console.WriteLine("Framework Version: " + Environment.Version);

            const int count = 10000;
            List<int> array1 = new List<int>(count);

            for (int i = 0; i < count; i++)
                array1.Add(i % 20);

            Console.WriteLine("Start");

            int start = Environment.TickCount;

            int sum = 0;

            int len = array1.Count;
            int[] array = array1.ToArray();

            for (int k = 0; k < 100000; k++)
                for (int i = 0; i < array.Length; i++)
                    sum += array[i];

            Console.WriteLine("Time is {0}, sum = {1}", 
                Environment.TickCount - start, sum);

Framework Version: 2.0.50215.44
Start
Time is 1359, sum = 910065408

4. С копрированием в масси и выносом длинны в переменную.
            Console.WriteLine("Framework Version: " + Environment.Version);

            const int count = 10000;
            List<int> array1 = new List<int>(count);

            for (int i = 0; i < count; i++)
                array1.Add(i % 20);

            Console.WriteLine("Start");

            int start = Environment.TickCount;

            int sum = 0;

            int len = array1.Count;
            int[] array = array1.ToArray();

            for (int k = 0; k < 100000; k++)
                for (int i = 0; i < len; i++)
                    sum += array[i];

            Console.WriteLine("Time is {0}, sum = {1}", 
                Environment.TickCount - start, sum);

Framework Version: 2.0.50215.44
Start
Time is 1359, sum = 910065408

5. На чистом массиве с выносом длинны в переменную:
            Console.WriteLine("Framework Version: " + Environment.Version);

            const int count = 10000;
            int [] array = new int[count];

            for (int i = 0; i < count; i++)
                array[i] = i % 20;

            Console.WriteLine("Start");

            int start = Environment.TickCount;

            int sum = 0;

            int len = array.Length;

            for (int k = 0; k < 100000; k++)
                for (int i = 0; i < len; i++)
                    sum += array[i];

            Console.WriteLine("Time is {0}, sum = {1}", 
                Environment.TickCount - start, sum);

Framework Version: 2.0.50215.44
Start
Time is 1344, sum = 910065408

6. На чистом массиве с проверкой длинны в цикле:
            Console.WriteLine("Framework Version: " + Environment.Version);

            const int count = 10000;
            int [] array = new int[count];

            for (int i = 0; i < count; i++)
                array[i] = i % 20;

            Console.WriteLine("Start");

            int start = Environment.TickCount;

            int sum = 0;

            int len = array.Length;

            for (int k = 0; k < 100000; k++)
                for (int i = 0; i < array.Length; i++)
                    sum += array[i];

            Console.WriteLine("Time is {0}, sum = {1}", 
                Environment.TickCount - start, sum);

Framework Version: 2.0.50215.44
Start
Time is 906, sum = 910065408


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

Однако все это такие милиметры, что ловить их в большинстве случаев смысла не имеет.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Агащазкакже
От: Аноним  
Дата: 25.04.05 12:45
Оценка:
интересно, как это нет const??? или что то другое под этим подразумеваеться?
--------------------------------
Авто-подпись — дешевый понт!


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[8]: Агащазкакже
От: qxWork Голландия http://www.jetbrains.com/company/people/Coox_Sergey.html
Дата: 25.04.05 12:52
Оценка:
W>>Это следствие отсутствия в .NET модификатора const.
VD>Подобный модификатор дотнету не нужен. В дотнете можно читать IL. Это позволяет определить наличие побочных эффектов без дополнительной помощь. К сожалению разработчики дотнета не озаботились подобными проблемами. Но в будущем, я уверен, до этого обязательно дойдет дело.
К сожалению, анализ IL очень дорог, чтобы его использовать в оптимизации. Использовать слово const значительно проще и быстрее, да и код становится читабельнее в разы.
Re[8]: Агащазкакже
От: qxWork Голландия http://www.jetbrains.com/company/people/Coox_Sergey.html
Дата: 25.04.05 12:53
Оценка:
YNN>интересно, как это нет const??? или что то другое под этим подразумеваеться?
Модификатора const у методов и параметров действительно нет в .NET
Re[9]: Агащазкакже
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.04.05 15:06
Оценка:
Здравствуйте, qxWork, Вы писали:

W>К сожалению, анализ IL очень дорог, чтобы его использовать в оптимизации. Использовать слово const значительно проще и быстрее, да и код становится читабельнее в разы.


Ну, на счет читабельности С++-ного кода я бы лучше помолчал.

А что до родоговизны... Он один фиг читается. Иначе все инлайнинги и т.п. были бы просто не возвожны. К тому же метод можно один раз ататически анализировать и добавлять ему атрибут. А в дальнейшем анализировать только его.

В общем, это более чем реально. Но создатели дотнета не сделали этого. Будем надеяться что только пока.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.