Здравствуйте, FR, Вы писали:
FR>кстати профайлер говорит что процентов 20 времени сидит в ntdll.dll на примерно таком коде:
[. . .]
FR>Похоже синхронизация неплохо отъедает производительность. Вообще в ntdll.dll сидит 49% времени в основном в строковых функциях и кусочках похожих тому что выше.
Во-во. Я тоже с этим сталкивался — isspace на винде отъедал больше половины всего времени работы парсера. Так что язык здесь ни при чем вообще.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, FR, Вы писали:
FR>Здравствуйте, Андрей Хропов, Вы писали:
АХ>>5) Python+Psyco — 4.12 (не ускорил!)
FR>Psyco не любит когда код в основном теле модуля надо его в функцию засунуть, тогда чуть ускорит:
Ммм, да, почесав затылок, вспомнил что он вроде пофункционально оптимизирует.
И у меня теперь ускорил даже совсем не чуть а почти в 2 раза
Теперь обновленная таблица с твоим вариантом выглядит как:
Интересно, а что будет если использовать внутри цикла в C++ вариант python через boost.python .
Поможет ли это реанимировать boost (в смысле будет ли быстрее чем 35 сек)?
Re: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
D>Честно говоря, результаты меня обескуражили…
D>Время работы: 20 секунд. (и это при полной оптимизации и отключенными проверками !?!) D>Может есть что сказать приверженцам BOOST-а, и по возможности объяснить где "кривые руки"?
По моему беглому взгляду на реализацию split-а показалось, что дело в реализации is_any_of. В частности, в том, что при каждом обращении к split объект-предикат, который скрывается за is_any_of конструируется заново. И более того, где-то там внутри этот предикат передается в подчиненные функции и сохраняется во вспомогательных объектах по значению.
Образно говоря, происходит что-то похожее на нижеследующий код:
#include <algorithm>
#include <string>
#include <set>
template< class Finder >
class Finder_Holder
{
private :
Finder finder_;
public :
Finder_Holder( Finder finder )
: finder_( finder )
{}
void
operator()( char c ) { finder_( c ); }
};
class Finder
{
private :
std::set< char > tokens_;
public :
Finder( std::string tokens )
: tokens_( tokens.begin(), tokens.end() )
{}
bool
operator()( char c )
{
return tokens_.end() == tokens_.find( c );
}
};
Finder_Holder< Finder >
is_any_of( const std::string & value )
{
return Finder_Holder< Finder >( Finder( value ) );
}
template< class Predicate >
void
do_something( const std::string & s, Predicate pred )
{
std::for_each( s.begin(), s.end(), pred );
}
void
test()
{
for( int i = 0; i != 1000000; ++i )
do_something( "123 345 asdf 23453 asdfas", is_any_of( " " ) );
}
int
main()
{
test();
return 0;
}
Обратите внимание на то, что в do_something объект pred передается по значению. А is_any_of возвращает объект Finder_Holder так же по значению.
В результате этот код у меня работает за время:
bash-3.1$ time t1.exe
real 0m5.172s
user 0m0.031s
sys 0m0.000s
(cl -O2 -EHsc)
Если же сделать так. чтобы по максимуму сохранять ссылки на объекты:
#include <algorithm>
#include <string>
#include <set>
template< class Finder >
class Finder_Holder
{
private :
const Finder & finder_;
public :
Finder_Holder( const Finder & finder )
: finder_( finder )
{}
void
operator()( char c ) const { finder_( c ); }
};
class Finder
{
private :
std::set< char > tokens_;
public :
Finder( const std::string & tokens )
: tokens_( tokens.begin(), tokens.end() )
{}
bool
operator()( char c ) const
{
return tokens_.end() == tokens_.find( c );
}
};
Finder_Holder< Finder >
is_any_of( const std::string & value )
{
return Finder_Holder< Finder >( Finder( value ) );
}
template< class Predicate >
void
do_something( const std::string & s, const Predicate & pred )
{
std::for_each( s.begin(), s.end(), pred );
}
void
test()
{
const Finder_Holder< Finder > pred = is_any_of( " " );
for( int i = 0; i != 1000000; ++i )
do_something( "123 345 asdf 23453 asdfas", pred );
}
int
main()
{
test();
return 0;
}
то получается время:
bash-3.1$ time t2.exe
real 0m0.406s
user 0m0.015s
sys 0m0.015s
при тех же опциях компилятора.
Очень похоже, что именно из-за проблем с is_any_of и наблюдаются тормоза в твоем случае.
А любителям boost-ов я бы напомнил: KISS
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, CreatorCray, Вы писали:
CC>Здравствуйте, Андрей Хропов, Вы писали:
АХ>>6) GCC + Boost — 22.5 сек АХ>>7) MS VC++ + Boost — 35 сек CC>А добавьте ка пунктик C++ + самописный split CC>Бо что то мне кажется что тут надо в "консерватории" что то подправить
Странно почему boost себя так плохо показывает.
Его вроде далеко не новички пишут, да и peer review у них вроде есть.
Надо идти к ним на форум ругаться
А то прям стыд и срам какой-то.
А так напиши универсальный split и запости сюда результаты.
Re[2]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, Denis2005, Вы писали:
D>>Честно говоря, результаты меня обескуражили…
D>>Время работы: 20 секунд. (и это при полной оптимизации и отключенными проверками !?!) D>>Может есть что сказать приверженцам BOOST-а, и по возможности объяснить где "кривые руки"?
E>По моему беглому взгляду на реализацию split-а показалось, что дело в реализации is_any_of. В частности, в том, что при каждом обращении к split объект-предикат, который скрывается за is_any_of конструируется заново. И более того, где-то там внутри этот предикат передается в подчиненные функции и сохраняется во вспомогательных объектах по значению.
Так все оптимизации выкручены по максимуму. Значение аргумента is_any_of известно во время компиляции.
Все это должно заинлайниться до констант. Или этого не происходит, почему?
P.S. Я смотрю у тебя Linux или BSD. Если не лень и стоят компиляторы других языков, то прогони проги из моего бенчмарка.
Наблюдаются ли те же временные пропорции?
Re[3]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Андрей Хропов, Вы писали:
АХ>Так все оптимизации выкручены по максимуму. Значение аргумента is_any_of известно во время компиляции. АХ>Все это должно заинлайниться до констант. Или этого не происходит, почему?
Судя по всему не происходит. Да и с чего бы происходить, если аргумент is_any_of неявно приводится к std::string (который может требовать у себя в конструкторе обращения к new), затем is_any_of возвращает какой-то объект, в котором еще что-то требует обращения к new, затем это еще к чему-то обращается и т.д. и т.п. Если есть желание, можешь сам расписать на бумаге цепочку вызовов внутри split-а, посмотри, в какие дебри это тебя заведет.
И вообще, я бы не стал надеятся на то, что компилятор умнее программиста и своими опримизирующими фокусами выправит кривизну рук разработчика.
АХ>P.S. Я смотрю у тебя Linux или BSD. Если не лень и стоят компиляторы других языков, то прогони проги из моего бенчмарка.
У меня WinXP + Cygwin. Да и лень
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[3]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
D>Зачем мне питон, когда такой пример под .NET отрабатывает за 0.6 сек, и код даже короче (на C#_, чем в приведенном примере.
От это ты зря здесь сказал. Сейчас подтянутся eao197 с ГВ и после короткой но продолжительной бесебы в тебе найдут массу недостатков.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: BOOST, .NET, String.Split и производительность…
Здравствуйте, McSeem2, Вы писали:
MS>Во-во. Я тоже с этим сталкивался — isspace на винде отъедал больше половины всего времени работы парсера. Так что язык здесь ни при чем вообще.
Естественно. Причем библиотеки. Только вот когда любители С++ начинают пенесометрией по скорости заниматься они как-то забывают, что в программе многое от библиотек зависит и все время приводят вручную оптимизированный код. А пожизни в программах может быть уйма вот таких проблемочек которые в купе вырастают в торомоза. Так что лучший друг производительности по прежнему не С++, а профайлер.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Андрей Хропов, Вы писали:
АХ>Странно почему boost себя так плохо показывает. АХ>Его вроде далеко не новички пишут, да и peer review у них вроде есть.
У них задачи другие. Они мозг тренируют.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Андрей Хропов, Вы писали:
CC>>А добавьте ка пунктик C++ + самописный split CC>>Бо что то мне кажется что тут надо в "консерватории" что то подправить АХ>Странно почему boost себя так плохо показывает.
Это у них бывает. Похоже народ о производительности не очень то задумывается... АХ>А так напиши универсальный split и запости сюда результаты.
Появится время и острая потребность — займусь
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[6]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
VD>Естественно. Причем библиотеки.
VD>Только вот когда любители С++ начинают пенесометрией по скорости заниматься они как-то забывают, что в программе многое от библиотек зависит и все время приводят вручную оптимизированный код.
Дык библиотеки то в первую очередь надо оптимизировать. К примеру большую часть CRT можно (и нужно) переписывать с нуля с учетом производительности. Потому как тормозная она...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[3]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
E>>А любителям boost-ов я бы напомнил: KISS
VD>Ты прочти свое сообщение и подумай кому бы еще о KISS напомнить.
И кому?
Если хочешь позлословить по поводу приведенного мной кода, то это всего лишь популярное изложение части деталей реализации boost::algorithms::is_any_of. К реализации которого я не имею никакого отношения.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[5]: BOOST, .NET, String.Split и производительность…
АХ>Интересно, а что будет если использовать внутри цикла в C++ вариант python через boost.python . АХ>Поможет ли это реанимировать boost (в смысле будет ли быстрее чем 35 сек)?
Мерять надо, в принципе накладные расходы на вызов (python — C++) относительно небольшие (у меня миллион вызовов примерно секунда), так что скорее всего будет быстрее
Re[2]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, Denis2005, Вы писали:
D>>Честно говоря, результаты меня обескуражили…
D>>Время работы: 20 секунд. (и это при полной оптимизации и отключенными проверками !?!) D>>Может есть что сказать приверженцам BOOST-а, и по возможности объяснить где "кривые руки"?
E>По моему беглому взгляду на реализацию split-а показалось, что дело в реализации is_any_of. В частности, в том, что при каждом обращении к split объект-предикат, который скрывается за is_any_of конструируется заново. И более того, где-то там внутри этот предикат передается в подчиненные функции и сохраняется во вспомогательных объектах по значению.
Попробовал с самописным предикатом:
#include <iostream>
#include <vector>
#include <boost/algorithm/string/split.hpp>
using namespace std;
using boost::algorithm::split;
inline bool is_space(char c)
{
return c == ' ';
}
int main(int argc, char *argv[])
{
int r = 0;
vector<string> tokens(5);
for(int i = 0; i < 1000000; i++)
{
split(tokens, "123 345 asdf 23453 asdfas", is_space);
r += tokens.size();
}
return 0;
}
результаты(первый с boost::algorithm::is_any_of)
vc71 | 33.2 и 9.7
vc71 + STLport-4.6 | 24.9 и 9.9
gcc3.2 | 10.8 и 3.5
gcc догнал скрипты
Re[2]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
D>Здравствуйте, eao197, Вы писали:
E>>По моему беглому взгляду на реализацию split-а показалось, что дело в реализации is_any_of.
D>Даже если написать примитивный предикат:
D>bool char_is_space(const char c) D>{ D> return c == ' '; D>}
D>то заместо ~20 сек., получаем ~5 сек., на VC++ 8.0.
угу в бусте явно что-то перемудрили, даже вот такой кошмар:
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
int main(int argc, char *argv[])
{
int r = 0;
vector<string> tokens(5);
for(int i = 0; i < 1000000; i++)
{
istringstream istr("123 345 asdf 23453 asdfas");
string word;
int k = 0;
while(!istr.eof())
{
istr >> word;
tokens[k++] = word;
}
r += k;
}
cout << r << endl;
return 0;
}
работает в 8 раз быстрее чем бустовский вариант (vc71 + STLport-4.6)
Здравствуйте, Андрей Хропов, Вы писали:
АХ>Странно почему boost себя так плохо показывает. АХ>Его вроде далеко не новички пишут, да и peer review у них вроде есть. АХ>Надо идти к ним на форум ругаться АХ>А то прям стыд и срам какой-то.
АХ>А так напиши универсальный split и запости сюда результаты.
Вот такой не универсальный и наколенный вариант
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void split(vector<string> &out, const char *text, bool (*pred)(char))
{
out.erase(out.begin(), out.end());
const char *begin_word = text;
for(; *text; ++text)
{
const char c = *text;
if(pred(c))
{
out.push_back(string(begin_word, text - begin_word));
begin_word = text + 1;
}
}
if(text != begin_word)
out.push_back(string(begin_word, text - begin_word));
}
inline bool is_space(char c)
{
return c == ' ';
}
int main(int argc, char *argv[])
{
int r = 0;
vector<string> tokens(5);
for(int i = 0; i < 1000000; i++)
{
split(tokens, "123 345 asdf 23453 asdfas", is_space);
r += tokens.size();
}
cout << r << endl;
/*for(int i = 0; i < tokens.size(); ++i)
{
cout << tokens[i] << endl;
}*/return 0;
}
уже не оставляет шансов бусту(почти в 30 раз для vc8). Вообще надо разобратся как они умудрились такое тормозное сделать.