LINUX.ORG.RU

Сравнение производительности Qt и Cairo


2

0

Зак Русин провел сравнение производительности векторной графики в Qt и Cairo. Тест состоит из рендеринга трех сложных полигонов: text path, маленький полигон с большим количеством вершин на одной линии, огромный полигон с количеством вершин порядка 100000.

Измерялось количество кадров в секунду, использовались версии Cairo 1.2.5 (XRender и Glitz), Amanith из svn, Qt 4.3 (XRender и OpenGL) на Pentium4 3.2ГГц, 1Гб, NVIDIA 6600 с драйвером 1.0-9625.

Все тесты использовали антиалиасинг, и были предприняты усилия, чтобы поставить библиотеки в равные условия. Результаты очень интересны:

* Qt быстрее Cairo в XRender в 5-7 раз
* Qt(OpenGL) быстрее Qt(XRender) в 5-7 раз, но упирается в производительность GPU при 80000+ вершин
* Cairo(Glitz) показывает одинаковую производительность с Cairo(XRender)
* Ни Amanith, ни Cairo(XRender) не могут справится с последним полигоном в 100000 вершин.
* С большим полигоном Cairo(Glitz) отображает 0.2 кадра в секунду, а Qt переваливает за 10 fps.
* Qt(XRender) на порядок превосходит по производительности и Cairo(Glitz), и Amanith, хотя последние работают с OpenGL ускорением, а первый без него.


Выводы: Qt на голову выше других библиотек, а в OpenGL настолько быстр, что сравнивать с чем либо ещё просто нечестно.


PS от автора новости: Остается надеяться, что OpenSource позволит авторам Cairo "подсмотреть" построение тесселятора и рендерера, чтобы сократить разрыв до приемлемых значений.

>>> Подробности

★★★★★

Проверено: Shaman007 ()

Ответ на: комментарий от anonymous

> можете считать что конструктор это псевдофункция в которой vtbl не доступна, это очень определенная вещь (в яве же на стеке лежат необъекты :)

ВАУ! Это сильный ход! Если б просто vtbl не было и виртуальные вызовы ломались (exceptions тосе) - это и то было бы логичнее.

> почему вы решили что на стеке будет лежать вышестоящий конструктор ?

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

svu ★★★★★
()
Ответ на: комментарий от svu

выша ошибка это предположение о существовании некоторого магического "реального класса"

я и предложил вам написать assert что бы вы поняли насколько это магично

anonymous
()
Ответ на: комментарий от svu

> ВАУ! Это сильный ход! Если б просто vtbl не было и виртуальные вызовы ломались (exceptions тосе) - это и то было бы логичнее.

не могу сказать очень точно, но реально оно так
вызов конструкторов не вложен друг в друга, конструктор предка вызывается до блока конструктора потомка, а не в нем

anonymous
()
Ответ на: комментарий от anonymous

> с неопределенность данных вы согласились ...

Да, но не с неопределенностью кода.

> не знаю как можно думать о том, что можно знать определенно.

Ну щаз. Класс A определил финальный метод XX(), вызывающий виртуальный метод YY(). Дочерний класс B вызвал XX в конструкторе B(). Должен ли автор реализации класса B знать о том мелком факте реализации А, что XX() вызывает YY()? Как автор А мог планировать такую ситуацию?

svu ★★★★★
()
Ответ на: комментарий от anonymous

При чем тут магия? Все, что я хочу - это имя класса создаваемого _конечного_ объекта. Называйте его реальным или нереальным - как Вам угодно.

svu ★★★★★
()
Ответ на: комментарий от svu

меня интересует ситуация когда A в конструкторе вызывает свой определенный метод YY, но вы ничего не можете сказать вызовется ли реально A::XXX или какой либо другой метод

это и есть неопределенность, если вы не можете сказать мне точно

anonymous
()
Ответ на: комментарий от anonymous

> вызов конструкторов не вложен друг в друга, конструктор предка вызывается до блока конструктора потомка, а не в нем

Я давно это подозревал - но это не важно. Важно, чтобы при вызове _первого_ же, самого базового, конструктора vtbl был уже окончательно сформирован. Точнее, слово "важно" неправильно - но это один из возможных и вполне валидных подходов. Именно он в жабе и есть. И, если верить dave, что ключевое слово override является реализацией виртуальности в С# - значит, и там тоже.

svu ★★★★★
()
Ответ на: комментарий от svu

магия в том что вы _не можете_ написать assert
мы говорим вроде бы как о некоторой определенной вещи
но описать формально ее не можем

anonymous
()
Ответ на: комментарий от anonymous

В этом случае, извините, для Вас вся идея с виртуальностью - одна большая неточность. Никогда нельзя заранее сказать, что вызовется при вызове виртуального метода. Но этот контекст "неточности" довольно странен. Я под неточностью подразумеваю - отсутствие гарантий на то, что для одного и того же объекта вызовется одна и та же реализация.

svu ★★★★★
()
Ответ на: комментарий от anonymous

> ну так напишите assert

В плюсах - боюсь, не справлюсь (не передавая класс в явном виде в от потомков к предкам). В жабке - легко. Что хотите сказать-то?

svu ★★★★★
()
Ответ на: комментарий от svu

в жабке напишите, но без рефлексии правда, интересно посмотреть
можете и с рефлексией, то-же интересно

я хочу сказать, что в данный момент мне интересно увидеть этот код :)

anonymous
()
Ответ на: комментарий от svu

> Я под неточностью подразумеваю - отсутствие гарантий на то, что для одного и того же объекта вызовется одна и та же реализация.

когда конструируется объект, существуют только предки и этот самый объект, никакой не точности нет
для ___одного и того же___ объекта вызовется __одна и та же реализация___.

anonymous
()
Ответ на: комментарий от svu

>> Никогда нельзя заранее сказать, что вызовется при вызове виртуального метода. Но этот контекст "неточности" довольно странен.

вообще-то я просто проиллюстрировал фразу из сановского туториала
на яву :) так что этот "контекст "неточности"" не мной придуман

anonymous
()
Ответ на: комментарий от anonymous

Конечно, только с рефлексией и буду
(без новомодных ассертов, со старым добрым RuntimeException):

$ cat a.java b.java 
public class a {
  public a() {
    if (getClass().getName().equals("b"))
      throw new RuntimeException("WTF!");
  }
}

public class b extends a {
  public static void main (String args[]) {
    b B = new b();
  }
}

svu ★★★★★
()
Ответ на: комментарий от svu

$ java b
Exception in thread "main" java.lang.RuntimeException: WTF!
        at a.<init>(a.java:4)
        at b.main(b.java:3)

svu ★★★★★
()
Ответ на: комментарий от svu

> Конечно, только с рефлексией и буду
:)

ну давайте уж дальше XP ....

мой шаг:
я написал реализацию class_name () { return "b"; }

все работает !!!!!! :))))

ваш шаг ?

anonymous
()
Ответ на: комментарий от anonymous

> когда конструируется объект, существуют только предки и этот самый объект, никакой не точности нет

Java думает иначе. Еще раз - есть разные подходы, и у каждого свои недостатки.

svu ★★★★★
()
Ответ на: комментарий от svu

вы написали:

struct A {
A () {
assert(!strcmp(class_name(), "B"));
}
};

struct B: public A {
B () {
}
};

B b;

я написал:

struct A {
const char* class_name () { return "B";}
A () {
assert(strcmp(class_name(), "B");
}
};

struct B: public A {
B () {
}
};

B b;

все валидно, все работает превосходно
по XP следующий ваш ход сломать этот тест

anonymous
()
Ответ на: комментарий от anonymous

Ваш тест просто невалиден, с т.зр. жабы. Вы не можете переопределить getClass() - он final (да еще и native:). Поэтому "обмануть" не получится. А в плюсы мой тест не переводится - именно потому что class_name в конструкторе класса А всегда вызывается из класса А. Так что я не очень понимаю, что именно я должен сломать.

svu ★★★★★
()
Ответ на: комментарий от anonymous

Что значит "неправильно"? Смотря чего Вы хотите.

ОК, давайте формально. Мои требования:

1. Для объекта класса А метод class_name должен возвращать "А"

2. Для объекта класса B он должен возвращать "B".

Если у меня есть код:

А а = new A();
B b = new B();

На выходе я должен получить:

A
B

При этом cout << должен вызываться только внутри конструктора класса А.
У класса А есть только один конструктор - который не принимает
параметров (и не использует глобальные переменные).

Вы можете выдать мне такой код на плюсах?

svu ★★★★★
()
Ответ на: комментарий от svu

вы просто не знакомы с XP

суть:
я не переопределял getClass(), я просто утверждаю, что моя class_name
возвращает имя "конечного" класса
вам нужно написать код который говорит, что я ошибаюсь
можно на яве :))))

anonymous
()
Ответ на: комментарий от svu

> Что значит "неправильно"? Смотря чего Вы хотите.
> ОК, давайте формально. Мои требования:

формально, значит кодом
я очень мало прошу :), не расписать же математическое выражение для этого :))))

anonymous
()
Ответ на: комментарий от anonymous

я просто хочу сказать, что метод getClass
не возможно написать на с++, как невозможно его написать и на java
это данность, привнесенная извне
самое смешное, что вы не можете проверить, правильное ли значение возвращает метод getClass

anonymous
()
Ответ на: комментарий от anonymous

я просто хочу сказать, что метод getClass
не возможно написать на с++, как невозможно его написать и на java
это данность, привнесенная извне
самое смешное, что вы не можете проверить, правильное ли значение возвращает метод getClass

anonymous
()
Ответ на: комментарий от anonymous

Ваш сlass_name не возвращает имя конечного класса. Для проверки этого достаточно создать еще одного потомка класса А.

svu ★★★★★
()
Ответ на: комментарий от anonymous

Вместо getClass().getName() можно использовать любой другой виртуальный метод - от этого ничего не изменится.

Что такое "правильное значение" - я не знаю (это зависит от спеков). Все, что я хочу - это разные значения для разных производных классов - и чтобы эти значения были доступны в конструкторе базового класса. Чего ж проще-то?

svu ★★★★★
()
Ответ на: комментарий от anonymous

> вам нужно написать код который говорит, что я ошибаюсь

Формально, это вот такой код:

public class C extends A {
public C() {}
}

svu ★★★★★
()
Ответ на: комментарий от anonymous

Внутри конструктора A этот assert смысла не имеет (потому что любые проверки на этом уровне можно обмануть). assert имеет смысл сделать только в коде, который реально создает объекты.

svu ★★★★★
()
Ответ на: комментарий от svu

"любые проверки можно обмануть" - разумеется, если Вы ставите запрет на пользование боговдохновенным getClass().

svu ★★★★★
()
Ответ на: комментарий от svu

> Внутри конструктора A этот assert смысла не имеет (потому что любые проверки на этом уровне можно обмануть). assert имеет смысл сделать только в коде, который реально создает объекты.
> "любые проверки можно обмануть" - разумеется, если Вы ставите запрет на пользование боговдохновенным getClass().

вот, видите забавность ситуации :)
фактически единственным определением "конечного" класса внутри конструктора является - тот клас который возвращает getClass
поэтому я и просил дать определение "конечного" класса, в плюсах у меня нет getClass и сам термин "конечный" класс становиться бессмысленным. Тут даже не обмануть, суть в том, что тут возможно единственное заключение: assert(class_name() == getClass().name()) и никакого другого, в этом и магичность getClass.
в общем вы поставили в принципе невыполнимую задачу, но если ее переформулировать: распечатать трэйс имен создаваемых объектов, то почему бы и нет :)

anonymous
()
Ответ на: комментарий от anonymous

> поэтому я и просил дать определение "конечного" класса

Ах вот оно что! Определение конечного класса нельзя дать, не выходя из контекста конструктора. Оно определяется только во внешнем контексте создания объекта (там, где делается new B()). Но я хочу, чтобы у меня действия конструктора зависели от этого контекста. И жабка это обеспечивает.

> в общем вы поставили в принципе невыполнимую задачу

А как же жаба-то справляется? Просто она при вызове конструктора считает нормальным использовать (неявно доступную) информацию из внешнего контекста. И что? Если это всем удобно?

> распечатать трэйс имен создаваемых объектов, то почему бы и нет :)

Ура! Только не весь трейс - а именно имя класса самого распоследнего потомка? Путем одной строки в базовом классе. Дык и как это сделать в плюсах?

svu ★★★★★
()
Ответ на: комментарий от svu

> Но я хочу, чтобы у меня действия конструктора зависели от этого контекста. И жабка это обеспечивает.

вы друг друга нашли :)

> А как же жаба-то справляется?

никак, просто кто-то, когда-то притянул это за уши

> Просто она при вызове конструктора считает нормальным использовать (неявно доступную) информацию из внешнего контекста. И что? Если это всем удобно?

я могу ввести любое количество лишних сущностей
а надо ?

> Ура! Только не весь трейс - а именно имя класса самого распоследнего потомка? Путем одной строки в базовом классе. Дык и как это сделать в плюсах?

если честно, времени нет, но способы таковы
1) воспользоваться дебажной информацией, все равно этот трэйс вне дебага мне не нужен, что кстати плюсовые отладчики и делают
2) воспользоваться буферизованным объектным выводом, работать будет но с задержкой, буферизованный же
3) подменить оператор new, трюк, но, пока, самый простой вариант
может еще есть .....

anonymous
()
Ответ на: комментарий от anonymous

PS
я выполнил задачу: распечатать трэйс имен создаваемых объектов

сами понимаете, что печатать имя класса самого распоследнего потомка
из конструктора невозможно, то что вы делаете в яве, это печатаете
результат работы getClass. с таким же успехом я могу сказать, что в моей реализации я делаю просто std::cout << class_name () и доказать что я не прав вы не сможете.

anonymous
()
Ответ на: комментарий от anonymous

> я могу ввести любое количество лишних сущностей

Лишняя они и нет - это вопрос схоластический. А вот то, что это бывает удобно - это факт.

> если честно, времени нет, но способы таковы

Согласитесь, но все эти способы весьма извратны (а первый еще и зависит от компилятора, что совсем некрасиво). Кстати, хотелось бы посмотреть в коде (когда у Вас будет время) на трюк с подменой new. Только Вы помните условия - весь код должен быть только в базовом классе?

svu ★★★★★
()
Ответ на: комментарий от svu

> Лишняя они и нет - это вопрос схоластический.

ну если идти таким путем, все есть схоластика

> А вот то, что это бывает удобно - это факт.

не знаю, за всю жизнь ни разу не понадобилось (это факт).
мне вообще-то не интересен сам факт создания объекта, мне интересен контекст создания и корректнось создания

> Согласитесь, но все эти способы весьма извратны

вообще-то, есть такая штука - aspectc++, там все решается системно :)

> (а первый еще и зависит от компилятора, что совсем некрасиво).

но удобно :)))))))))))))))))))))))))))))))
любую вещь можно оправдать удобством

> Только Вы помните условия - весь код должен быть только в базовом классе?

вы не слышите или не хотите услышать что я говорю

> Кстати, хотелось бы посмотреть в коде (когда у Вас будет время) на трюк с подменой new.

#define new .... :))))))))))))))))

4-ый способ
специально для вас сделать патч для компилятора c++ что-бы в нем был метод getClass. :))))))))))

PS.
если вы хотите что-бы я сказал - это не возможно в c++
пожалуста - это не возможно в c++ :))))))))))
это недостаток ? с таким же успехом я могу сказать - приведите мне способ изменить методику аллокации/деаллокации памяти для объектов и способ ручного удаления объекта .....,
как сделать так что-бы объект уничтожался немедленно при покидании стекового фрэйма, атоматически !!!! ? мне например очень удобно иметь такую возможность (без шуток, очень удобная штука)
просто если мы начнем сейчас меряться пиписьками, то добъемся только одного - женщины будут смеяться :)

PPS
все хватит !

anonymous
()
Ответ на: комментарий от anonymous

> мне вообще-то не интересен сам факт создания объекта, мне интересен контекст создания и корректнось создания

Это понятно. Непонятно только, почему Вы настаиваете именно на таком прочтении "контекста создания". Точнее, это понятно - но с этим не согласно;)

> пожалуста - это не возможно в c++ :))))))))))

Ура! "Зарработало!" (с) "Простоквашино" ;)

> приведите мне способ изменить методику аллокации/деаллокации памяти для объектов и способ ручного удаления объекта .....,

Да, в языке, где нет понятия "памяти" и "аллокации" - разумеется, никак.

>PPS все хватит !

Вроде, уже договорились до всего чего надо. Остальное оставим додумывать читателям флейма;)

svu ★★★★★
()
Ответ на: комментарий от Syncro

Ничего не могу понять. Один и тот же код, в Windows - нормально, в Linux - еле перерисовывается. Для примера - код из Tutorial'a...
Код:

#include <QApplication>
#include <QPushButton>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QPushButton hello("Hello world!");
    hello.resize(100, 30);
    hello.show();
    return app.exec();
}

Если этот диалог развернуть на весь экран и понажимать на кнопке - реакция на экране где то через секунду. Или просто Resize этого диалога делать - кадр за кадром... Вообщем еле ворочается. Release - тоже самое, может чуток побыстрее. Ничего не понимаю. Остальные программы в Linux шустро работают (FireFox, Thunderbird, Eclipse...), и при resize да и так - даже быстрее чем в винде Smile. OpenGL тоже летает (Quake 3)! Тормозят только собранные программы...
OS: Kernel: 2.6.18, Slackware 11, KDE 3.5.4, GCC 3.4.6, драйвер NVIDIA 1.0-8776
Sempron 2500, GeForce FX5700 128MB, 1Gb...
Подскажите куда смотреть?

anonymous
()
Ответ на: комментарий от anonymous

qt 4 что ли? Не знаю, у меня все нормально, правда qt 3-я

anonymous
()

ИМХО Qt производительнее на медленных компьютерах.

Где ГТК вообще не работает (то есть отрисовывает медленнее чем человек пишет/что-то делает), Qt летает.

wieker ★★
()
Ответ на: комментарий от wieker

> ИМХО Qt производительнее на медленных компьютерах.

> Где ГТК вообще не работает (то есть отрисовывает медленнее чем человек пишет/что-то делает), Qt летает.

Действительно, в своё время куте на слабой тачке именно из-за этого и снёс, что гтк работала шустрее. Так что своё имхо оставьте при себе.

anonymous
()
Ответ на: комментарий от klalafuda

> если плохой программист на C - это еще не так страшно, то для C++ это как обезьяна с гранатой.

Скорее справедливо обратное утверждение

propheta
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.