boost::shared_ptr, GC и тормоза

топ 100 блогов love5an26.03.2011 Я на самом деле очень сильно удивлен тем, что очень много людей даже примерно не представляют себе, сколько оверхеда вносят счетчики ссылок, и насколько они менее эффективны, чем нормальный сборщик мусора.

Не перестают меня удивлять и заявления о том, что де, раз в C++ есть boost, с его shared_ptr и прочим, то проблема сборки мусора для C++ фактически решена.

Ладно уж, не будем о том, что счетчики ссылок неспособны разрешить циклические зависимости, просто сравним ту самую производительность, за которую писатели на C++ так трясутся.

Тест, который я придумал, очень прост, но в то же время очень показателен.

Заключается он в следующем:
Создаем вектор на 'length' элементов, заполняем его указателями на структуры, подобные лисповым cons-ячейкам, и 'n' раз прогоняем цикл, в котором создаем копию этого вектора, а старый удаляем(элементы при этом мы не копируем, а копируем только указатели на них). Указатели, в C++, естественно, используем "умные".
В качестве противника C++, то есть в качестве языка, в реализациях которого присутствует нормальный GC, я взял Common Lisp, если конкретно - SBCL.


Для варианта на Common Lisp получился вот такой код:

(declaim (optimize (speed 3) (safety 0)))

(defun copy-vector (vector)
  (declare (type simple-vector vector))
  (let* ((length (length vector))
         (new-vector (make-array length)))
    (dotimes (i length)
      (setf (svref new-vector i) (svref vector i)))
    new-vector))

(defun test (n length)
  (declare (type fixnum length n))
  (let ((vector (make-array length)))
    (dotimes (i length)
      (setf (svref vector i) (cons nil nil)))
    (dotimes (i n)
      (setf vector (copy-vector vector)))))

(defun main (&aux (n (second sb-ext:*posix-argv*))
                  (length (third sb-ext:*posix-argv*)))
  (when (> (length sb-ext:*posix-argv*) 3)
    (write-line "Usage test_sbcl [ n [ length ] ]")
    (sb-ext:quit :unix-status 1))
  (let ((n (or (and n (parse-integer n))
               1000000))
        (length (or (and length (parse-integer length))
                    100)))
    (declare (type fixnum n length))
    (test n length))
  (sb-ext:gc :full t))

(sb-ext:save-lisp-and-die "test_sbcl.exe"
                          :executable t
                          :toplevel #'main)


Обращаю внимание(чтобы не было возмущений на тему того, что в лиспе, в отличие от варианта на C++, память не освобождается), что в конце функции main я все-таки вызываю сборщик мусора SBCL, в параметром :full t, что означает, что он проводит "полную" сборку мусора, освобождая все объекты, которые только можно.

Для C++ получилось вот так:

#include 
#include 
#include 
#include 

struct Cons
{
    void* car;
    void* cdr;
    Cons(void* _car, void* _cdr)
    {
        car = _car;
        cdr = _cdr;
    }
};

typedef boost::shared_ptr ConsPtr;
typedef std::vector ConsPtrVector;
typedef boost::shared_ptr ConsPtrVectorPtr;

ConsPtrVectorPtr CopyVector(ConsPtrVectorPtr vec)
{
    int length = (*vec).size();
    ConsPtrVectorPtr copy(new ConsPtrVector(length));
    for(int i = 0; i<= 0)
            {
                std::cout << "Invalid parameter: " << argv[1] << std::endl;
                return 1;
            }
            break;
        case 3:
            if((n = atoi(argv[1])) <= 0)
            {
                std::cout << "Invalid parameter: " << argv[1] << std::endl;
                return 1;
            }
            if((length = atoi(argv[2])) <= 0)
            {
                std::cout << "Invalid parameter: " << argv[2] << std::endl;
                return 1;
            }
            break;
        default:
            std::cout << "Usage: test_cpp [ n [ length ] ]" << std::endl;
            return 1;
    }
    Test(n, length);
    return 0;
}


Собирается вариант на лиспе вот такой командой:
sbcl --script test.lisp

А вариант на C++, соответственно, вот такой:
g++ -O3 -o test_cpp.exe -I/d/boost_1_46_1/ test.cpp
(я использую MSYS и GCC из mingw32)

Результаты, если честно, меня удивили. Ну то есть, я предполагал, что вариант со счетчиком ссылок будет медленнее, но чтобы настолько!
boost::shared_ptr, GC и тормоза
Как видно, программа на лиспе, с его сборщиком мусора, отрабатывает быстрее аж более чем в 4.5 раза(~0.6 секунд против ~2.8 секунд для C++). И это еще учитывая что CL - высокоуровневый язык с динамической типизацией, и учитывая всю инициализацию, которую проводит рантайм лисп-системы при запуске.

Ну ладно, думаю, всем известно что GC идеально подходит для множества выделений мелких объектов(а в том варианте цикл прогоняется 1000000 раз, с размером вектора в 100 элементов), надо посмотреть как C++ себя покажет при работе с крупным массивом.
boost::shared_ptr, GC и тормоза
Ну что сказать - отрыв в 3.2 раза(~1.7 секунд против ~5.4) это, конечно, не в 4.5, но где-то рядом :)

Результат, в принципе, становится понятным из ассемблерного кода.
Ну то есть, в случае с SBCL я предполагал, что он мне там нагенерирует, примерно:
http://paste.lisp.org/display/120909
А вот лапшу, в которую вылился код на C++ - я разобрать так и не смог:
http://paste.lisp.org/display/120910
Кто-то еще говорит, что он понимает, во что превратится его код после обработки оптимизирующим компилятором?

Оставить комментарий

Архив записей в блогах:
Итак, дорогие сообщники и участницы проекта! Сегодня мы начинаем голосование за героинь нашего он-лайн проекта "Стильная Я". Под катом фотографии участниц с рассказом на тему того, почему они хотят измениться. Для того, чтобы проголосовать за ...
Очередной креатив от деградатов по линии мира цистерн. Как говорится, просто оставлю это здесь... ...
  о заговоре против русско-китайского мира будет рассказано ниже, а пока о чучьханьском вирусе.   Итак около 80-90 тысяч человек заразились, из них уже около 3 тысяч ушло в лучший мир, то есть смертность среди тех, кого лечат, достигает около 3х процентов. Если вирус ...
Гомосексуалисты становятся главными героями не только российской политики. Президент Зимбабве Роберт Мугабе, который находится у власти последнюю четверть века, в преддверии выборов сравнил представителей ЛГБТ-сообщества с животными и пригрозил им смертной казнью. Он также высказался с ...
Вы ходите в сапогах и в красной рубахе навыпуск, подпоясанный шелковым шнурком, и вы добрый. Вы можете так держать. Вы внимательно дослушали сказку до конца. Вы съели всю кашу. Вы купили водки больше, чем вам дали денег. Вы уже полдня не курите. 16 августа 1998 года вы на все ...