Почему мое приложение C ++ быстрее, чем мое приложение C (использующее ту же библиотеку) на Core i7 - PullRequest
6 голосов
/ 13 января 2010

У меня есть библиотека, написанная на C, и у меня есть 2 приложения, написанные на C ++ и C. Эта библиотека является коммуникационной библиотекой, поэтому один из вызовов API выглядит следующим образом:

int source_send( source_t* source, const char* data );

В приложении C код выглядит примерно так:

source_t* source = source_create();
for( int i = 0; i < count; ++i )
    source_send( source, "test" );

Где, как это делает приложение C ++:

struct Source
{
    Source()
    {
        _source = source_create();
    }

    bool send( const std::string& data )
    {
        source_send( _source, data.c_str() );
    }

    source_t* _source;
};

int main()
{
    Source* source = new Source();
    for( int i = 0; i < count; ++i )
        source->send( "test" );
}

На Intel Core i7 код C ++ производит почти ровно на 50% больше сообщений в секунду. В то время как на Intel Core 2 Duo он выдает почти одинаковое количество сообщений в секунду. (Ядро i7 имеет 4 ядра с 2 процессорными потоками в каждом)

Мне любопытно, какое волшебство аппаратное обеспечение выполняет, чтобы осуществить это. У меня есть некоторые теории, но я думал, что получу реальный ответ:)

Редактировать: Дополнительная информация из комментариев

Компилятор - это визуальный C ++, так что это окно Windows (оба)

Реализация коммуникационной библиотеки создает новый поток для отправки сообщений. Source_create - это то, что создает этот поток.

Ответы [ 5 ]

7 голосов
/ 13 января 2010

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

Следующее, что я хотел бы сделать, это проверить генерируемый код сборки. Если вы используете набор инструментов GNU, у вас есть несколько способов сделать это.

Вы можете попросить gcc и g ++ вывести код сборки через аргумент командной строки -S. Убедитесь, что, кроме добавления этого аргумента, вы используете те же аргументы командной строки, что и для обычной компиляции.

Второй вариант - загрузить вашу программу с помощью gdb и использовать команду disas.

Удачи.

Обновление

Вы можете делать то же самое с помощью Microsoft Toolchain.

Чтобы вывести компилятор на выходную сборку, вы можете использовать / FA или / FAs . Первый должен выводить сборку только тогда, когда второй будет смешивать сборку и источник (что должно облегчить отслеживание).

Что касается использования отладчика, после запуска отладчика в Visual Studio перейдите к «Отладка | Windows | Разборка» (проверено в Visual Studio 2005, другие версии могут отличаться).

2 голосов
/ 13 января 2010

Не видя полного кода или сборки, я думаю, что компилятор c ++ для вас встроен. Одна из прелестей компиляторов c ++ - это возможность встроить практически все, что угодно для скорости, и хорошо известно, что компиляторы microsoft безвозмездно встраивают почти до точки необоснованного раздувания конечных исполняемых файлов.

1 голос
/ 13 января 2010

Первое, что я бы порекомендовал сделать, - это профилировать обе версии и посмотреть, есть ли заметные различия.

Является ли версия C копированием чего-либо излишне (это может быть тонкая или не очень тонкая оптимизация, такая как оптимизация возвращаемого значения).

Это должно отображаться в хорошем профилировщике, если у вас более высокий уровень VS SKU, профилировщик на основе выборки там хорош, если вы ищете хороший бесплатный профилировщик, анализатор производительности Windows невероятно мощный для Vista и выше Вот пошаговое руководство по использованию опции стекирования

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

Я бы проследил за этим с помощью профиля, если бы не было чего-то явно очевидного (например, дополнительной копии).

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

-Rick

0 голосов
/ 13 января 2010

Просто дикая догадка: если вы компилируете исходный код библиотеки вместе со своим приложением, а функции C API не объявлены extern "C", то, возможно, версия C ++ использует другое и как-то более быстрое соглашение о вызовах?

Кроме того, если вы компилируете исходный код библиотеки вместе со своим приложением, то, возможно, компилятор C ++ компилирует исходный код библиотеки как C ++ и чем-то лучше его оптимизирует, чем ваш компилятор C?

0 голосов
/ 13 января 2010

Core i7 с гипер-резьбой - у вас включен HT?

Может быть, код C ++ каким-то образом скомпилирован, чтобы использовать преимущества HT, а код C - нет. Как выглядит диспетчер задач, когда вы запускаете свой код? Равномерно распределить нагрузку на количество ядер или несколько ядер?

...