Russian Qt Forum
Ноябрь 23, 2024, 00:02 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2] 3 4 5   Вниз
  Печать  
Автор Тема: Хранение "хвостиков"  (Прочитано 24773 раз)
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #15 : Сентябрь 22, 2015, 11:44 »

Ну ладно, см. аттач. Рез-ты

test1 =  0.121
test2 =  13.464
test3 =  8.072


Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #16 : Сентябрь 22, 2015, 13:10 »

Ну ладно, см. аттач. Рез-ты

test1 =  0.121
test2 =  13.464
test3 =  8.072
И что Вы хотели этим сказать?  Улыбающийся
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #17 : Сентябрь 22, 2015, 13:36 »

Лёгкое изменение теста (немного нагрузки и плюшек буста), то результаты уже не так разнятся:

Код
Bash
elapsed time: 400 msec
elapsed time: 1405 msec
elapsed time: 5797 msec
 

Сам тест:
Код
C++ (Qt)
template <class R>
struct getter : public boost::static_visitor<R>
{
   getter(size_t i) : index(i) {}
 
   template <class V>
   R operator()(V & v) const
   {
       return v[index];
   }
 
   R operator()(R v) const
   {
       if (index) throw std::out_of_range("out of range");
       return v;
   }
 
private:
   size_t index;
};
 
template <class R, class V>
R& get(size_t i, V & v)
{
   return boost::apply_visitor(getter<R&>(i), v);
}
 
 
 
const int TEST_COUNT = 50 * 1024 * 1024;
 
struct CData {
   float val;
};
 
struct CData2 {
   boost::variant<std::vector<float>, float> vec;
// или boost::variant<std::vector<float>, std::array<float, MAGIC_BUF>> vec;
// Или написать свою обёртку над таким вариантом, которая внешне была аналогична обычному вектору, например.
};
 
struct CData3 {
   QList<float> vec;
};
 
 
template <class F>
void run(F f)
{
   auto start = std::chrono::high_resolution_clock::now();
   f();
   auto stop = std::chrono::high_resolution_clock::now();
 
   auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(stop-start).count();
 
   std::cout << "elapsed time: " << elapsed << " msec" << std::endl;
}
 
int main()
{
   std::mt19937 gen;
   std::uniform_real_distribution<float> dist(0.0f, 1.0f);
 
   run([&]()
   {
 
       CData * data = new CData[TEST_COUNT];
           for (int i = 0; i < TEST_COUNT; ++i)
               data[i].val = dist(gen);
           delete [] data;
   });
 
   run([&]
   {
       CData2 * data2 = new CData2[TEST_COUNT];
           for (int i = 0; i < TEST_COUNT; ++i) {
               data2[i].vec = dist(gen);
           }
 
           delete [] data2;
   });
 
   run([&]{
       CData3 * data3 = new CData3[TEST_COUNT];
           for (int i = 0; i < TEST_COUNT; ++i)
               data3[i].vec.push_back(dist(gen));
           delete [] data3;
   });
 
   return 0;
}
 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #18 : Сентябрь 22, 2015, 13:56 »

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

Можно сделать темплейт и определить через него пулы на 1, 2 и 3 элемента (например).
А объект с данными будет содержать указатель на конкретный элемент в нужном пуле.
Либо сделать один пул, который является вектором флотов и имеет на каждый флот флаг "занят"-"свободен", например, через битовую маску. Тогда нужный объект должен будет найти в пуле первые N свободных подряд идущих элементов и заюзать их. Но тут поиск нужен и т.д., имхо несколько пулов лучше.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
xokc
Птица говорун
*****
Offline Offline

Сообщений: 976



Просмотр профиля
« Ответ #19 : Сентябрь 22, 2015, 14:02 »

Немного оффтопну. Вот никого не "воротит" от такого?
Код
C++ (Qt)
auto start = std::chrono::high_resolution_clock::now();
f();
auto stop = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(stop-start).count();
std::cout << "elapsed time: " << elapsed << " msec" << std::endl;
 
И это ещё спасибо "auto", без него бы оно ещё страшнее стало.
Сравните с
Код
C++ (Qt)
QElapsedTimer t;
t.start();
f();
std::cout << "elapsed time: " << t.elapsed() << " msec" << std::endl;
 
Записан
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #20 : Сентябрь 22, 2015, 14:09 »

И что Вы хотели этим сказать?  Улыбающийся

что QList быстрее
Записан
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #21 : Сентябрь 22, 2015, 14:12 »

мне также не ясно - зачем тащить std и буст в qt проект, если в qt есть все из них (имею ввиду то что уже есть)
мы же не заменяем qstring на std::string
Записан
kamre
Частый гость
***
Offline Offline

Сообщений: 233


Просмотр профиля
« Ответ #22 : Сентябрь 22, 2015, 14:15 »

Вроде бы какие-то реализации для std::string для коротких строк используют inplace буфер, а для больших указатель на память, выделяемую в куче. Вот здесь что-то очень похожее можно использовать.

Вот из MSVC 2012:
Код:
	enum
{ // length of internal buffer, [1, 16]
_BUF_SIZE = 16 / sizeof (value_type) < 1 ? 1
: 16 / sizeof (value_type)};
enum
{ // roundup mask for allocated buffers, [0, 15]
_ALLOC_MASK = sizeof (value_type) <= 1 ? 15
: sizeof (value_type) <= 2 ? 7
: sizeof (value_type) <= 4 ? 3
: sizeof (value_type) <= 8 ? 1 : 0};

value_type *_Myptr()
{ // determine current pointer to buffer for mutable string
return (this->_BUF_SIZE <= this->_Myres
? _STD addressof(*this->_Bx._Ptr)
: this->_Bx._Buf);
}

const value_type *_Myptr() const
{ // determine current pointer to buffer for nonmutable string
return (this->_BUF_SIZE <= this->_Myres
? _STD addressof(*this->_Bx._Ptr)
: this->_Bx._Buf);
}

union _Bxty
{ // storage for small buffer or pointer to larger one
value_type _Buf[_BUF_SIZE];
pointer _Ptr;
char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;

size_type _Mysize; // current length of string
size_type _Myres; // current storage reserved for string
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #23 : Сентябрь 22, 2015, 14:18 »

Ворвусь в тему. QVarLengthArray спасет отца. Краткость - сестра.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #24 : Сентябрь 22, 2015, 14:35 »

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

Можно сделать темплейт и определить через него пулы на 1, 2 и 3 элемента (например).
А объект с данными будет содержать указатель на конкретный элемент в нужном пуле.
Либо сделать один пул, который является вектором флотов и имеет на каждый флот флаг "занят"-"свободен", например, через битовую маску. Тогда нужный объект должен будет найти в пуле первые N свободных подряд идущих элементов и заюзать их. Но тут поиск нужен и т.д., имхо несколько пулов лучше.
Это ничего нового не вносит. Понятно что проблема актуальна/возникает когда хвостиков "много" (мульены), а тогда темплейты создают неприятные проблемы с контейнером.

Код
C++ (Qt)
struct CData2 {
   boost::variant<std::vector<float>, float> vec;
// или boost::variant<std::vector<float>, std::array<float, MAGIC_BUF>> vec;
// Или написать свою обёртку над таким вариантом, которая внешне была аналогична обычному вектору, например.
};
 
Субъетивно, но существенно - эдак все время может быть потрачено на изучение буста (да чего там, и задача может быть забыта). Когда же это будет на бусте (если будет) - не исключено что рез-т окажется не так уж хорош как ожидалось.

Ну вот допустим я захотел хранить 0, 1, 2, 3, 4 флота напрямую (до 16 байт), а для большего числа эл-тов уже вектор. Длинноватая сопля получается в определении такого boost::variant и длинновато его инициализировать зная текущее число эл-тов.

А главное - проблем с памятью это не решит. Какой бы ни был вумный boost::variant, а данные он будет хранить в куче (иначе это не variant).  Ведь можно и просто так
Код
C++ (Qt)
int count;
float * data;   // и просто new[] и delete[]
Не вижу чем (в данном случае) это хуже boost::variant, скорее лучше

На мой взгляд самое естественное - хранить данные в др контейнере, (правда неясно в каком и как). Странно что никто не предложил ничего из этой оперы
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #25 : Сентябрь 22, 2015, 14:48 »

Ворвусь в тему. QVarLengthArray спасет отца. Краткость - сестра.
Логика "пользователя Qt": какой класс из букваря похож? Ага, вот этот - ну все, берем  Улыбающийся
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #26 : Сентябрь 22, 2015, 15:00 »

Ну, контейнер (пул) объективно решит проблему частых аллокаций-деаллокаций. Производительность это подымет. Тогда надо так и делать:

int count;
float * data;

где data будет указывать на count элементов в пуле. Пулы, кстати, можно создавать тоже в рантайме Улыбающийся В зависимости от кол-ва элементов "хвоста". Это, конечно, не упростит имплементацию, но фурычить будет шустрее.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #27 : Сентябрь 22, 2015, 15:32 »

Цитировать
На мой взгляд самое естественное - хранить данные в др контейнере, (правда неясно в каком и как).

std::valarray. С ним получаются самые лучшие результаты:
Код
Bash
elapsed time: 393 msec
elapsed time: 800 msec std::valarray
elapsed time: 5659 msec QList
 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #28 : Сентябрь 22, 2015, 15:41 »

Цитировать
На мой взгляд самое естественное - хранить данные в др контейнере, (правда неясно в каком и как).

std::valarray. С ним получаются самые лучшие результаты:
Так а что valarray, куда его лепить-то?
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #29 : Сентябрь 22, 2015, 15:49 »

Цитировать
Так а что valarray, куда его лепить-то?

Ай, нет.. прошу прощения, опечатался там в коде, поэтому такие времена получились.. 
« Последнее редактирование: Сентябрь 22, 2015, 15:59 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Страниц: 1 [2] 3 4 5   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.163 секунд. Запросов: 23.