Re[4]: BOOST, .NET, String.Split и производительность…
От: McSeem2 США http://www.antigrain.com
Дата: 16.09.06 20:07
Оценка: -1
Здравствуйте, FR, Вы писали:

FR>кстати профайлер говорит что процентов 20 времени сидит в ntdll.dll на примерно таком коде:


[. . .]

FR>Похоже синхронизация неплохо отъедает производительность. Вообще в ntdll.dll сидит 49% времени в основном в строковых функциях и кусочках похожих тому что выше.


Во-во. Я тоже с этим сталкивался — isspace на винде отъедал больше половины всего времени работы парсера. Так что язык здесь ни при чем вообще.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[3]: [Benchmark] DMD быстрее всех updated
От: Андрей Хропов Россия  
Дата: 16.09.06 20:28
Оценка:
Здравствуйте, FR, Вы писали:

FR>Здравствуйте, Андрей Хропов, Вы писали:


АХ>>5) Python+Psyco — 4.12 (не ускорил!)


FR>Psyco не любит когда код в основном теле модуля надо его в функцию засунуть, тогда чуть ускорит:


Ммм, да, почесав затылок, вспомнил что он вроде пофункционально оптимизирует.
И у меня теперь ускорил даже совсем не чуть а почти в 2 раза
Теперь обновленная таблица с твоим вариантом выглядит как:

(Athlon XP 1700+ @ 1.5 GHZ + 512Mb DDR266)
:

1) DMD — 0.775 сек
2) GDC — 0.905 сек
3) С#/Nemerle — 1.1 сек
4) Python+Psyco — 2 сек
5) Python — 3.48 сек
6) GCC + Boost — 22.5 сек
7) MS VC++ + Boost — 35 сек

Интересно, а что будет если использовать внутри цикла в C++ вариант python через boost.python .
Поможет ли это реанимировать boost (в смысле будет ли быстрее чем 35 сек)?
Re: BOOST, .NET, String.Split и производительность…
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 16.09.06 20:34
Оценка: :))
Здравствуйте, 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++.
Re[3]: [Benchmark] DMD быстрее всех
От: Андрей Хропов Россия  
Дата: 16.09.06 20:40
Оценка:
Здравствуйте, 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 и производительность…
От: Андрей Хропов Россия  
Дата: 16.09.06 20:58
Оценка:
Здравствуйте, 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 и производительность…
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 16.09.06 21:28
Оценка: +1
Здравствуйте, Андрей Хропов, Вы писали:

АХ>Так все оптимизации выкручены по максимуму. Значение аргумента 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 и производительность…
От: VladD2 Российская Империя www.nemerle.org
Дата: 17.09.06 00:22
Оценка: -5 :))
Здравствуйте, Denis2005, Вы писали:

D>Зачем мне питон, когда такой пример под .NET отрабатывает за 0.6 сек, и код даже короче (на C#_, чем в приведенном примере.


От это ты зря здесь сказал. Сейчас подтянутся eao197 с ГВ и после короткой но продолжительной бесебы в тебе найдут массу недостатков.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: BOOST, .NET, String.Split и производительность…
От: VladD2 Российская Империя www.nemerle.org
Дата: 17.09.06 00:22
Оценка: -3
Здравствуйте, McSeem2, Вы писали:

MS>Во-во. Я тоже с этим сталкивался — isspace на винде отъедал больше половины всего времени работы парсера. Так что язык здесь ни при чем вообще.


Естественно. Причем библиотеки. Только вот когда любители С++ начинают пенесометрией по скорости заниматься они как-то забывают, что в программе многое от библиотек зависит и все время приводят вручную оптимизированный код. А пожизни в программах может быть уйма вот таких проблемочек которые в купе вырастают в торомоза. Так что лучший друг производительности по прежнему не С++, а профайлер.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: [Benchmark] DMD быстрее всех
От: VladD2 Российская Империя www.nemerle.org
Дата: 17.09.06 00:22
Оценка:
Здравствуйте, Андрей Хропов, Вы писали:

А где же Оберон?
А то прийдет сами знаете кто и ему даже про синтксический оверхэд будет невозможно поговорить! А вать такй случай предствылч:

АХ>
АХ>#include <vector>
АХ>#include <string>
АХ>#include <iostream>
АХ>#include <boost/algorithm/string/split.hpp>
АХ>#include <boost/algorithm/string/classification.hpp>

АХ>#include <windows.h> // for GetTickCount

АХ>using namespace std;
АХ>using namespace boost::algorithm;

АХ>int main()
АХ>{
АХ>  DWORD start = GetTickCount();
    
АХ>  int res = 0;
АХ>  for(int i = 0; i < 1000000; i++)
АХ>  {
АХ>    // так корректней сравнивать, ведь в др программах мы размер не указывали
АХ>    // + по моим тестам почти не повлияло на скорость
АХ>    vector<string> tokens; 
АХ>    split(tokens, "123 345 asdf 23453 asdfas", is_any_of(" "));
АХ>    res += tokens.size();
АХ>  }

АХ>  DWORD stop = GetTickCount();

АХ>  cout << "res is " << res << ',' << stop - start << " ms elapsed\n";
  
АХ>  return 0;
АХ>}
АХ>
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: [Benchmark] DMD быстрее всех
От: VladD2 Российская Империя www.nemerle.org
Дата: 17.09.06 00:22
Оценка: +3 :))) :))) :)))
Здравствуйте, Андрей Хропов, Вы писали:

АХ>Странно почему boost себя так плохо показывает.

АХ>Его вроде далеко не новички пишут, да и peer review у них вроде есть.

У них задачи другие. Они мозг тренируют.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: BOOST, .NET, String.Split и производительность…
От: VladD2 Российская Империя www.nemerle.org
Дата: 17.09.06 00:22
Оценка:
Здравствуйте, eao197, Вы писали:

E>А любителям boost-ов я бы напомнил: KISS


Ты прочти свое сообщение и подумай кому бы еще о KISS напомнить.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: [Benchmark] DMD быстрее всех
От: CreatorCray  
Дата: 17.09.06 01:22
Оценка:
Здравствуйте, Андрей Хропов, Вы писали:

CC>>А добавьте ка пунктик C++ + самописный split

CC>>Бо что то мне кажется что тут надо в "консерватории" что то подправить
АХ>Странно почему boost себя так плохо показывает.
Это у них бывает. Похоже народ о производительности не очень то задумывается...
АХ>А так напиши универсальный split и запости сюда результаты.
Появится время и острая потребность — займусь
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: BOOST, .NET, String.Split и производительность…
От: CreatorCray  
Дата: 17.09.06 01:22
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Естественно. Причем библиотеки.


VD>Только вот когда любители С++ начинают пенесометрией по скорости заниматься они как-то забывают, что в программе многое от библиотек зависит и все время приводят вручную оптимизированный код.

Дык библиотеки то в первую очередь надо оптимизировать. К примеру большую часть CRT можно (и нужно) переписывать с нуля с учетом производительности. Потому как тормозная она...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: BOOST, .NET, String.Split и производительность…
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 17.09.06 05:17
Оценка:
Здравствуйте, VladD2, Вы писали:

E>>А любителям boost-ов я бы напомнил: KISS


VD>Ты прочти свое сообщение и подумай кому бы еще о KISS напомнить.


И кому?

Если хочешь позлословить по поводу приведенного мной кода, то это всего лишь популярное изложение части деталей реализации boost::algorithms::is_any_of. К реализации которого я не имею никакого отношения.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[5]: BOOST, .NET, String.Split и производительность…
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 17.09.06 07:03
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Так что язык здесь ни при чем вообще.


C# вроде как под той же виндой тестируют с той же самой ntdll.dll
... << RSDN@Home 1.2.0 alpha rev. 654>>
Re[4]: [Benchmark] DMD быстрее всех updated
От: FR  
Дата: 17.09.06 07:54
Оценка:
Здравствуйте, Андрей Хропов, Вы писали:


АХ>Интересно, а что будет если использовать внутри цикла в C++ вариант python через boost.python .

АХ>Поможет ли это реанимировать boost (в смысле будет ли быстрее чем 35 сек)?

Мерять надо, в принципе накладные расходы на вызов (python — C++) относительно небольшие (у меня миллион вызовов примерно секунда), так что скорее всего будет быстрее
Re[2]: BOOST, .NET, String.Split и производительность…
От: FR  
Дата: 17.09.06 07:54
Оценка:
Здравствуйте, 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 Россия  
Дата: 17.09.06 08:27
Оценка:
Здравствуйте, eao197, Вы писали:

E>По моему беглому взгляду на реализацию split-а показалось, что дело в реализации is_any_of.


Даже если написать примитивный предикат:

bool char_is_space(const char c)
{
return c == ' ';
}

то заместо ~20 сек., получаем ~5 сек., на VC++ 8.0.
Re[3]: BOOST, .NET, String.Split и производительность…
От: FR  
Дата: 17.09.06 09:26
Оценка: 2 (1)
Здравствуйте, 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)
Re[4]: [Benchmark] DMD быстрее всех
От: FR  
Дата: 17.09.06 10:08
Оценка:
Здравствуйте, Андрей Хропов, Вы писали:

АХ>Странно почему 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). Вообще надо разобратся как они умудрились такое тормозное сделать.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.