Russian Qt Forum

Программирование => Общий => Тема начата: AkonResumed от Октябрь 23, 2020, 14:07



Название: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: AkonResumed от Октябрь 23, 2020, 14:07
Ревизирую старый код, и стоит вопрос рефакторинга QVector->std::vector (также рассматривается std::array для некоторых случаев). Мотивация - иметь выровненные данные в контейнере для последующей оптимизации (векторизации, и в этой связи также рассматривается замена double -> float).

Основная семантическая проблема - использование в QVector Implicit Sharing (copy-on-write) при передаче данных, в основном, между потоками.

Собственно, вопрос - нужен stl::vector c Implicit Sharing семантикой, в идеале - совместимой с Qt, т.е.:
Цитировать
stl::vector v;
QVector qv;
v = qv;  // inc ref. count, not a deep copy

Порекомендуйте хорошие порты STL или просто отдельные библиотеки STL-контейнеров, наделенные данным свойством.



Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: m_ax от Октябрь 23, 2020, 23:23
Цитировать
Порекомендуйте хорошие порты STL или просто отдельные библиотеки STL-контейнеров, наделенные данным свойством.
Боюсь, таких непосредственно в stl нет(


Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: __Heaven__ от Октябрь 24, 2020, 11:17
Не понял, зачем такой переход. В QVector, вроде, и так всё выровнено


Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: Igors от Октябрь 24, 2020, 11:24
Не понял, зачем такой переход. В QVector, вроде, и так всё выровнено
Да, могу ошибаться, но "боковым зрением" вроде видел в мсходниках что он равняется на 16


Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: Авварон от Октябрь 24, 2020, 12:37
QVector выравнивает так как выравнивается T:

Код:
    Q_REQUIRED_RESULT static QTypedArrayData *allocate(size_t capacity,
            AllocationOptions options = Default)
    {
        Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
        return static_cast<QTypedArrayData *>(QArrayData::allocate(sizeof(T),
                    Q_ALIGNOF(AlignmentDummy), capacity, options));
    }
Код:
class AlignmentDummy { QArrayData header; T data; };


Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: AkonResumed от Октябрь 24, 2020, 16:20
Разумеется, иначе что это за контейнер, которой кладет на заданное выравнивание типа. Он волен нижнюю границу поднять (например, минимум 16 байт) из-за каких-то своих соображений, но опустить - никак. Также и нижележащие malloc/realloc не опускаются ниже определенной величины.

Собственно, если нужно иметь выровненный буфер как таковой, хранящийся в векторе, то достаточно как-то так:
Код:
	
class alignas(256) CacheLine
{
public:
CacheLine(char data = 0) : data_(data) {}
operator char() { return data_; }

private:
char data_;
};

QVector<CacheLine> v;
v.push_back({});
qDebug() << (void*)&v.front();  // выровнен на 256 байт
Но работать с ним поэлементно через интерфейс QVector нельзя: v[1] вернет 257 байт, а не второй.

Для поэлементной работы с байтами можно грубо пропатчить индексный доступ, но тут уже семантические нарушения по типу:
Код:
template <typename T> class MyVector : protected QVector<T> 
{
public:
T& operator[](int index) { return reinterpret_cast<char*>(QVector<T>::data())[index]; }
        ... и так далее для всего, ... итераторов
};
Это все костыли. Нужно просто, чтобы у QVector был аллокатор. Кстати, как думаете - почему его нет? Полагаю, что Qt-контейнеры создавались прежде всего для собственных нужд (типа хранить чилдренов, небольшой мапчик/хэшик и т.п.), где аллокаторы не нужны.


Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: Igors от Октябрь 24, 2020, 20:00
Нужно просто, чтобы у QVector был аллокатор. Кстати, как думаете - почему его нет? Полагаю, что Qt-контейнеры создавались прежде всего для собственных нужд (типа хранить чилдренов, небольшой мапчик/хэшик и т.п.), где аллокаторы не нужны.
Думаю потому что он (или его наличие) изрядно гадит в консоли, а нужда в нем возникает... "не припомина"

Я немного "потерял нить", верно ли я понимаю что нужен ф-ционал QVector<char> но с выравниванием на заданную кратность (напр 256)? Я бы объявлял вектор структур с нужным выравниванием, а для работы с char'ами, не мудрствуя лукаво, "приводился" бы (в С стиле). Можно использовать стандартное средство range (не помню как называется, множество реализаций было еще до того как оно вошло в стандарт).


Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: m_ax от Октябрь 24, 2020, 20:14
Я бы смотрел в сторону сторонних библиотек.. Ну на худой конец, свой велик бы написал.. Кстати, тут товарищ,
navrocky предложил свою реализацию implicit sharing.. http://www.prog.org.ru/topic_15029_0.html (http://www.prog.org.ru/topic_15029_0.html)
Я бы там её немного бы допилил, в плане конструктора от произвольного числа аргументов..
Но как вариант, можно свою реализацию vector сделать, аналогично Qt.. 


Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: AkonResumed от Октябрь 25, 2020, 12:35
Да, нужен  QVector<char>, такой что первый байт всегда лежит по адресу, кратному 256 (или любому другому, задаваемому статически). Структура байт в векторе - это уже будет двумерный индекс.


Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: m_ax от Октябрь 25, 2020, 13:03
Да, нужен  QVector<char>, такой что первый байт всегда лежит по адресу, кратному 256 (или любому другому, задаваемому статически). Структура байт в векторе - это уже будет двумерный индекс.
Ну это не проблема сейчас? :)


Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: Igors от Октябрь 25, 2020, 15:13
Да, нужен  QVector<char>, такой что первый байт всегда лежит по адресу, кратному 256 (или любому другому, задаваемому статически). Структура байт в векторе - это уже будет двумерный индекс.
Глянул в отладчике, да, "близок локоть да не укусишь". Выравнивание есть, но не видно как подлезть.

Ну а если "не по теме" :)? Верную ли цель Вы ставите (выровненный QVector<char>) и стоит ли ее добиваться? С точки зрения "минимум переделок" - скорее всего да. Но если все делать чисто/кошерно (к чему Вы так явно стремитесь) - то скорее нет. Ведь операции с QVector<char>, хотя бы push_back, erase и.т.п. никак не поддерживают целостность выравниваемых структур.


Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: Авварон от Октябрь 25, 2020, 15:16
почему нельзя выделить чуть больше и использовать для доступа выровненный span<char>?


Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: m_ax от Октябрь 25, 2020, 15:27
почему нельзя выделить чуть больше и использовать для доступа выровненный span<char>?

Не понял, а как он с QVector такой финт может произвести? Или я не догоняю?)


Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: Авварон от Октябрь 25, 2020, 16:13
Ну типа не использовать не выровненное начало вектора, а начинать с нужным (выровненным) оффсетом. А span "мимикрирует" под вектор что позволяет АПИ сохранить более менее. Понятно, что все мутабельные операции типа append() мимо.


Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: m_ax от Октябрь 25, 2020, 16:26
Ну типа не использовать не выровненное начало вектора, а начинать с нужным (выровненным) оффсетом. А span "мимикрирует" под вектор что позволяет АПИ сохранить более менее. Понятно, что все мутабельные операции типа append() мимо.

Спасибо, более-менее дошло)


Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: AkonResumed от Октябрь 25, 2020, 18:26
Да, нужен  QVector<char>, такой что первый байт всегда лежит по адресу, кратному 256 (или любому другому, задаваемому статически). Структура байт в векторе - это уже будет двумерный индекс.
Глянул в отладчике, да, "близок локоть да не укусишь". Выравнивание есть, но не видно как подлезть.

Ну а если "не по теме" :)? Верную ли цель Вы ставите (выровненный QVector<char>) и стоит ли ее добиваться? С точки зрения "минимум переделок" - скорее всего да. Но если все делать чисто/кошерно (к чему Вы так явно стремитесь) - то скорее нет. Ведь операции с QVector<char>, хотя бы push_back, erase и.т.п. никак не поддерживают целостность выравниваемых структур.
Нужно, чтобы начало вектора было выровнено, далее программист сам решает, как ему обрабатывать данные в середине. Т.е., он будет читать их кусками по 256 байт, если конкретный обработчик требует выравнивания.

С невыровненным началом - неудобно, size()/begin()/operator[],... уже непосредственно неприменимы.



Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: Igors от Октябрь 31, 2020, 10:28
Нужно, чтобы начало вектора было выровнено, далее программист сам решает, как ему обрабатывать данные в середине. Т.е., он будет читать их кусками по 256 байт, если конкретный обработчик требует выравнивания.
Ну все-таки данные "первичны", поэтому если требование 256 установлено/принято, то и контейнер должен содержать такие структуры, с тем чтобы все операции удаления/вставки сохраняли целостность данных. А для других обработчиков соскочить на DataView (забыл как называется). Мне это кажется более идейным


Название: Re: STL-compatible контейнеры с семантикой Qt's Implicit Sharing
Отправлено: AkonResumed от Ноябрь 10, 2020, 22:28
Согласен с вашей логикой. По сути требования два: для определенной (математической) обработки - это выравнивание на 256 байт, для наполнения и общей обработки (типа заменить элемент) - это буфер char-ов (QVector<char>).