Мне записали библиотеку в 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 это производит почти точно ту же сумму сообщений в секунду. (Core i7 имеет 4 ядра с 2 потоками обработки каждый),
Мне любопытно, какое волшебство аппаратные средства выполняют для осуществления этого. У меня есть некоторые теории, но я думал, что получу реальный ответ :)
Править: Дополнительная информация из комментариев
Компилятор является Visual C++, таким образом, это, окна упаковывают (они оба)
Реализация коммуникационной библиотеки создает новый поток для пересылки сообщений. source_create - то, что создает этот поток.
От изучения вашего исходного кода, я не вижу причину, почему код C ++ должен быть быстрее.
Следующее, что я бы сделал, это проверить код монтажа, который генерируется. Если вы используете инструментарий GNU, у вас есть пара способов сделать это.
Вы можете задать GCC и G ++ для вывода кода сборки через аргумент командной строки
. Убедитесь, что другие затем добавляют этот аргумент, вы используете то же самое общие аргументы командной строки, которые вы делаете для регулярного компиляции.
Второй вариант - загрузить программу с GDB и использовать команду
.
Удачи.
Обновление
Вы можете сделать то же самое с Microsoft Toolchain.
Чтобы получить компилятор в узел вывода, вы можете использовать либо / FA или / FAS . Первый должен выводить сборку только в то время как второй будет смешивать сборку и источник (что должно облегчить следовать).
Что касается использования отладчика, после того, как вы получите отладчик, запущенный в Visual Studio, перейдите к «Debug | Windows | разборка» (проверено на Visual Studio 2005, другие версии могут отличаться).
Вы должны на самом деле задать нам реальный вопрос: -) Вам очевидно, почему вы считаете это необходимым, но это почти наверняка не . На самом деле, это почти всегда плохая идея.
Почему вы думаете, что вам нужно сделать это?
Я обычно нахожу, что это потому, что разработчики хотят удалить или не удалить объект в зависимости от того, где он был выделен, но это то, что обычно следует оставить клиенту вашего кода, а не самому вашему коду.
Обновление:
Извиняйтесь, вы, вероятно, нашли одну из немногих областей, в которых то, что вы спрашиваете, имеет смысл. В идеале необходимо переопределить все операторы выделения и отмены выделения памяти, чтобы отслеживать, что создается и удаляется из кучи.
Однако я не уверен, что это простой вопрос перехвата нового/удаления для класса, так как могут возникнуть ситуации, когда delete
не вызывается и, поскольку mark/sweep зависит от количества ссылок, необходимо иметь возможность перехватывать назначения указателей, чтобы он работал правильно.
Думали ли вы о том, как с этим справиться?
Классический пример:
myobject *x = new xclass();
x = 0;
не приведет к вызову удаления.
Как вы также обнаружите, что указатель на один из экземпляров находится в стеке? Перехват новых и удаление может позволить вам сохранить, является ли сам объект стеком или на основе кучи, но я в проигрыше относительно того, как вы скажете, где будет назначен указатель, особенно с кодом типа:
myobject *x1 = new xclass(); // yes, calls new.
myobject *x2 = x; // no, it doesn't.
-121--1282603- Хакерский способ:
struct Detect {
Detect() {
int i;
check(&i);
}
private:
void check(int *i) {
int j;
if ((i < &j) == ((void*)this < (void*)&j))
std::cout << "Stack" << std::endl;
else
std::cout << "Heap" << std::endl;
}
};
Если объект был создан в стеке, он должен жить где-то в направлении переменных стека внешних функций. Куча обычно растет с другой стороны, так что стопка и куча встречались бы где-то посередине.
(Существуют системы, в которых это не работает)
-121--1282616-Не видя полный код или сборку, я думаю, что компилятор c++ встроен для вас. Одной из красот компиляторов c++ является возможность встроить почти что угодно для скорости, а компиляторы Microsoft хорошо известны, чтобы безвозмездно встроить почти до точки необоснованного вздутия конечных исполняемых файлов.
Первое, что я бы порекомендовал сделать - профилировать обе версии и посмотреть, нет ли заметных отличий.
Является ли версия на C копированием чего-то ненужного (это может быть тонкая или не очень тонкая оптимизация, например, оптимизация возвращаемого значения).
Это должно проявиться в хорошем профайлере, если у вас есть VS SKU более высокого уровня, профилировщик на основе сэмплов - это хорошо, если вы ищете хороший бесплатный профайлер, то Windows Performance Analyzer невероятно мощный для Vista, и вот - вот обзор использования опции стековой ходьбы
Первое, что я бы, вероятно, сделал сам - это вломился в отладчик и осмотрел бы разборку для каждой из них, чтобы увидеть, не заметны ли они различия. Обратите внимание, что в компиляторе есть опция выплюнуть asm в текстовый файл.
Я бы проследил за этим с профилем, если бы не было чего-то явно очевидного (например, дополнительной копии).
Еще одна вещь, если вы беспокоитесь о том, что гиперпотоки будут мешать, сродни этому процессу с ядром, отличным от HT. Вы можете сделать это либо через менеджер задач в GUI, либо через SetThreadAffinityMask.
-Rick
.CORE I7 - это гиперпоток - у вас есть HT?
Может быть, код C ++ как-то скомпилирован для воспользовавшись преимуществами HT, тогда как код C не делает. Как выглядит диспетчер задач, когда вы запускаете свой код? Равномерно распределить нагрузку по количеству ядер, или несколько ядер максимально выделены?
Просто дикое предположение: если вы собираете источник библиотеки вместе с вашим приложением, а функции API C API не объявлены Extern «C», то, возможно, версия C ++ использует версию C ++ Разные и как-то быстрее призвать конвенцию ??
Кроме того, если вы собираете источник библиотеки вместе с вашим приложением, то, возможно, компилятор C ++ составляют свой источник библиотеки в виде C ++ и как-то лучше на оптимизации вашего компилятора?