Просмотр сообщений

В этом разделе можно просмотреть все сообщения, сделанные этим пользователем.


Темы - Губанов Сергей Юрьевич

Страницы: 1 2 [3]
31
Для измерения производительности разных компьютеров написал я однажды на C# простенькую програмку. Она сортирует массив целых чисел самым процессороёмким способом O(N^2).

i = 0;
while (i < n)
{
j = 0;
while (j < n)
{
if (a[j] < a[i])
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
j++;
}
i++;
}

Но так как иногда я её запускал на компьютерах с Linux под Mono, а моновский JIT компилятор туповат на счёт оптимизации с проверкой индексов массивов, то я переписал сортировку в unsafe коде.

p = a;
while (p < e)
{
q = a;
while (q < e)
{
if (*q < *p)
{
int t = *p;
*p = *q;
*q = t;
}
q++;
}
p++;
}

Ансэйфный вариант работал быстрее сэйфного, что не вызывало у меня удивлений. Однако, потом я запустил эту программку на 64 разрядном компьютере и был очень удивлён тем, что сэйфный код вдруг стал работать на 20% быстрее ансэйфного :o

Об этом я писал как-то на Оберонкоре...

Сейчас я придумал что надо подкрутить в ансэйфном коде чтобы он ускорился. Вот код:

i = 0;
p = a;
while (i < n)
{
j = 0;
int* q = a;
while (j < n)
{
if (*q < *p)
{
int t = *p;
*p = *q;
*q = t;
}
j++;
q++;
}
i++;
p++;
}

он работает примерно на 20% быстрее сэйфного и, соответственно, примерно на 50% быстрее предыдущего ансэфного (несмотря на в два раза большее количество переменных).

a[ i ] распалось отдельно на индекс i и указатель p,
a[ j ] распалось отдельно на индекс j и указатель q.

32
Общий раздел / Программисты как писатели...
« : Апрель 26, 2012, 09:05:24 pm »
Подумалось. Программисты по отношению к своим работодателям почти как писатели по отношению к своим издателям. Только самые талантливые писатели сами могут выбирать что им писать. Армия менее талантливых писателей пишет то, что от них хочет получить их издатель.  :)


33
Общий раздел / Трансляция Oberon в C#
« : Апрель 16, 2012, 01:00:57 pm »
Обдумываю как могла бы выглядеть правильная трансляция Оберона в C#.

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

С точки зрения C# язык Oberon ужасно-ужасно-ужасно ансэйфный.

Вот, например, простенький модуль на Обероне:

MODULE Test;

  TYPE
    Message* = RECORD END;

    MouseMsg* = RECORD (Message)
      x*, y*: INTEGER
    END;

    KeyboardMsg* = RECORD (Message)
      ch*: CHAR
    END;

    Controller* = RECORD
      handler*: PROCEDURE (VAR controller: Controller; VAR message: Message);
    END;

    MyController = RECORD (Controller)
      ...
    END;

  PROCEDURE MyHandler (VAR controller: Controller; VAR message: Message)
  BEGIN
    IF message IS MouseMsg THEN
      ...
    ELSIF message IS KeyboardMsg THEN
      ...
    END
  END

  PROCEDURE Smth (VAR c: Controller)
    VAR mouseMsg: MouseMsg; keyboardMsg: KeyboardMsg;
  BEGIN
    mouseMsg.x := 10;
    mouseMsg.y := 20;
    c.handler(c, mouseMsg);
    keyboardMsg.c := 'A';
    c.handler(c, keyboardMsg)
  END Smth;

  PROCEDURE Do* ()
    VAR c: MyController;
  BEGIN
    c.handler := MyHandler;
    Smth(c)
  END Do;

END Test.


Транслируем его в C#.

Сначала вспомогательный модуль на C#:

public static unsafe class SYSTEM
{
   public struct TYPE
   {
      public TYPE* ext0;
      public TYPE* ext1;
      public TYPE* ext3;
      public TYPE* ext4;
      public TYPE* ext5;
      public TYPE* ext6;
      public TYPE* ext7;
   }

   public struct ANYREC
   {
      public TYPE* type;
   }

   public static System.IntPtr ALLOC (int size)
   {
      return System.Runtime.InteropServices.Marshal.AllocHGlobal(size);
   }

   public static void FREE (void* pointer)
   {
      System.Runtime.InteropServices.Marshal.FreeHGlobal((System.IntPtr)pointer);
   }

   public static System.Delegate DELEGATE (System.IntPtr p, System.Type t)
   {
      return System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer(p, t);
   }

   public static System.IntPtr PROCEDURE (System.Delegate d)
   {
      return System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(d);
   }
}


А теперь модуль Test:

public static unsafe class Test
{
   public struct Message // : SYSTEM.ANYREC
   {
      public SYSTEM.TYPE* type;

      public static readonly SYSTEM.TYPE* Type;

      static Message ()
      {
         Type = (SYSTEM.TYPE*)SYSTEM.ALLOC(sizeof(SYSTEM.TYPE));
         Type->ext0 = Type;
      }
   }

   public struct MouseMsg // : Message
   {
      public SYSTEM.TYPE* type;
      public int x;
      public int y;

      public static readonly SYSTEM.TYPE* Type;

      static MouseMsg ()
      {
         Type = (SYSTEM.TYPE*)SYSTEM.ALLOC(sizeof(SYSTEM.TYPE));
         Type->ext0 = Message.Type;
         Type->ext1 = Type;
      }
   }

   public struct KeyboardMsg // : Message
   {
      public SYSTEM.TYPE* type;
      public char ch;

      public static readonly SYSTEM.TYPE* Type;

      static KeyboardMsg ()
      {
         Type = (SYSTEM.TYPE*)SYSTEM.ALLOC(sizeof(SYSTEM.TYPE));
         Type->ext0 = Message.Type;
         Type->ext1 = Type;
      }
   }

   public struct Controller // : SYSTEM.ANYREC
   {
      public SYSTEM.TYPE* type;
      public System.IntPtr handler;

      public static readonly SYSTEM.TYPE* Type;

      static Controller ()
      {
         Type = (SYSTEM.TYPE*)SYSTEM.ALLOC(sizeof(SYSTEM.TYPE));
         Type->ext0 = Type;
      }
   }

   public delegate void Handler (Controller* controller, Message* message);

   public struct MyController // : Controller
   {
      public SYSTEM.TYPE* type;
      public System.IntPtr handler;

      public static readonly SYSTEM.TYPE* Type;

      static MyController ()
      {
         Type = (SYSTEM.TYPE*)SYSTEM.ALLOC(sizeof(SYSTEM.TYPE));
         Type->ext0 = Controller.Type;
         Type->ext1 = Type;
      }
   }

   public static Handler myControllerHandler = new Handler(MyHandler);

   public static void MyHandler (Controller* controller, Message* message)
   {
      if (message->type->ext1 == MouseMsg.Type)
      {
         MouseMsg* m = (MouseMsg*)message;
         System.Console.WriteLine("MyController.Handler() Receive MouseMsg x={0} y={1}", m->x, m->y);
      }
      else if (message->type->ext1 == KeyboardMsg.Type)
      {
         KeyboardMsg* m = (KeyboardMsg*)message;
         System.Console.WriteLine("MyController.Handler() Receive KeyboardMsg ch={0}", m->ch);
      }
   }

   public static void Do ()
   {
      MyController c;
      c.type = MyController.Type;
      c.handler = SYSTEM.PROCEDURE(myControllerHandler);
      Smth((Controller*)&c);
   }

   private static void Smth (Controller* c)
   {
      MouseMsg mouseMsg;
      mouseMsg.type = MouseMsg.Type;
      mouseMsg.x = 10;
      mouseMsg.y = 20;
      ((Handler)SYSTEM.DELEGATE(c->handler, typeof(Handler)))(c, (Message*)&mouseMsg);

      KeyboardMsg keyboardMsg;
      keyboardMsg.type = KeyboardMsg.Type;
      keyboardMsg.ch = 'A';
      ((Handler)SYSTEM.DELEGATE(c->handler, typeof(Handler)))(c, (Message*)&keyboardMsg);
   }
}


По производительности реализация на C# будет медленнее из-за того что в  C# вместо указателей на процедуры используются делегаты (которые суть динамические объекты). Тормозить будет конвертация из указателя в делегат.

Лучше будет, видимо, вовсе не использовать GetDelegateForFunctionPointer/GetFunctionPointerForDelegate, а класть делегаты в глобально доступный статический массив и вместо указателя на функцию использовать индекс в этом массиве делегатов. Проигрыш по производительности всё равно будет, но не таким большим как при постоянном мусорении объектами делегатов.


34
Допустим я реализовал свою "строку". Это структура внутри которой лежит целое число -- как бы "умный указатель". Через это число некий ресурс (в данном случае память под буквы) может быть получен/использован/освобождён.

public struct UnmanagedString
{
    private uint handle;
}

Работать с переменными типа UnmanagedString нужно по особой дисциплине: обычная инструкция копирования "=" для структуры UnmanagedString неприемлема. Для копирования нужно использовать не "=", а специальную процедуру.

Эта специальная процедура в данном случае либо выполнит копирование букв в другой участок памяти и вернёт другой handle, либо, что более оптимально, увеличит количество ссылок на существующую строку. В общем случае эта специальная процедура может сделать чёго-то более трудоёмкое.

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

Можно было бы потребовать следующее: в языке добавить атрибут структуры означающий, что она некопируемая, а компилятору для таких структур проверять, что для переменных её типа нигде не использована инструкция "=" и они не переданы ни в какую процедуру по значению (только по ссылке). Соответственно, структуры и массивы содержащие некопируемые поля тоже должны быть маркированы атрибутом запрещающим копирование. Это можно было бы сделать, но можно сделать и наоборот...

В последней редакции Оберона-07 вообще никакие структуры не могут быть переданы в процедуру по значению, а только по ссылке. То есть Оберон-07 уже полшага к "умным указателям" сделал. Если действовать в духе Оберона, то лучше будет вообще запретить инструкцию копирования ":=" для любых составных типов. Это дёшево и сердито. Разрешаем применять ":=" только для базовых типов и всё. Копирование объектов составных типов пишем ручками через копирование полей (компилятор легко может это потом соптимизировать, если захочет, так что в рантайме оверхеда не будет).

Оптимум где-то по-середине. Некоторым составным типам копирование всё таки было бы полезно.

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

35
Неожиданно столкнулся со следующей проблемой. Вот уже во второй раз (сегодня был один случай, и вчера) программа (под Mono 2.6.7) выжрала всю виртуальную память (3 ГБ) и при попытке выделить память под массив на 5 Мб кидает исключение OutOfMemory. Физической памяти занято сущие копейки -- всего 130 Мб. Под Виндос не воспроизводится. Что за напасть такая... Как бороться с утечками виртуальной памяти?

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

Кстати вопрос к знатокам Линукса: какую API функцию надо звать чтоб узнать количество занятой памяти? Читать псевдокаталог proc не хочу, должна же быть нормальная API функция.

36
Общий раздел / Transactional Synchronization Extensions (TSX)
« : Февраль 09, 2012, 04:27:29 pm »
Интересно чем это нам "грозит"?

Процессоры Haswell станут большим скачком в развитии CPU

Цитировать
В своём блоге компания Intel сообщила о том, что в процессорах с архитектурой Haswell будет реализован механизм транзакционной памяти, предполагающий одновременное выполнение сложных многопоточных операций, но при этом изолированно друг от друга, что исключает "крах" всей программы из-за ошибки в одном потоке.

В архитектуре Haswell данный механизм назван Transactional Synchronization Extensions (TSX), который, в свою очередь, разделяется на две основные части: Hardware Lock Elision (HLE), транслирующую "обычные" программы в транзакционные с сохранением работоспособности, и Restricted Transactional Memory (RTM), что является, непосредственно, транзакционной памятью.

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

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


37
Общий раздел / Юмор
« : Февраль 08, 2012, 12:01:58 pm »
Прямо сейчас на главной странице сайта Центробанка РФ в строке денежной базы написано "Error", а на  странице денежной базы написано:

Microsoft VBScript runtime error '800a000d'
Type mismatch: 'FormatNumber'
/statistics/credit_statistics/mon_baza.inc, line 79

38
Общий раздел / Зачем сборщик мусора? (v2.0)
« : Февраль 06, 2012, 11:41:33 am »
Первая версия там: Зачем сборщик мусора?

 ::)  ::)  ::) поскольку мне известен правильный ответ на вопрос "Зачем сборщик мусора?", то я решил написать его в новом топике ::)  ::)  ::)

Смысл в следующем. Есть проблема порчи памяти. Она устраняется герметичной системой типов. Только автоматическая сборка мусора гарантированно устраняет повисшие указатели. Поэтому сборщик мусора является неотъемлемой частью герметичной системы типов.

Короче, сборщик мусора имеет смысл в составе герметичной системы типов, которая используется для победы над проблемой порчи памяти. Это всё.

39
Во время сборки мусора работа программы останавливается. Длительность паузы зависит от количества объектов и от объёма занимаемой памяти. Я измерил эту зависимость и построил графики, они там: Паузы в работе программы вызываемые сборщиком мусора .Net 3.5 Длительность паузы может достигать 20 секунд если программой занято 8 Гб памяти и использовано более 100 миллионов объектов.

Можно обсудить границу применимости программ со сборщиком мусора в области мягкого реального времени. Например, мне на работе нужно чтобы время реакции программы не превышало 5 секунд. Мы пишем логику управления телефонной станцией. Пока программа занимает 1-2 гигабайта памяти (100'000 телефонов) -- всё нормально, а вот что делать если хочется 1'000'000 телефонов (> 5 гигабайтов) -- не очень понятно. В принципе ещё есть запас по рефакторингу, но он не бесконечный и рано или поздно мы всё таки упрёмся в непрошибаемую стену "мусорной паузы". Как её прошибать?


40
Общий раздел / Пока сижу в бане...
« : Январь 31, 2012, 02:30:55 pm »
Пока сижу в бане на OberonCore (за "дать в морду Ткачёву") решил завестись здесь. Всем привет!  :) :) :)

Страницы: 1 2 [3]