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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Подкачка данных переменной длины  (Прочитано 7924 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Июль 08, 2010, 15:54 »

Добрый день

Рассмотрим сначала простой и понятный случай. Есть имедж размером M x N, пусть например значение каждого пикселя соответствует высоте над уровнем моря. Имедж может быть велик (или имеем много имеджей), поэтому не храним его весь в памяти а подкачиваем его с диска. Псевдокод

Код
C++ (Qt)
float Image::GetPixel( int x, int y )
{
// номер страницы в файле подкачки
 int pageNo = (y / mPixelPageY) * mNumPageX + x / mPixelPageX;  
 
// загрузили страницу
 if (!mPage[pageNo].IsLoaded())
   LoadPage(pageNo, mBaseOffsetInFile + pageNo * mPageSizeBytes);
 
// координаты пикселя внутри страницы
 x %= mPixelPageX;
 y %= mPixelPageY;
 
// данные
 return mPage[pageNo].mData[y * mPixelPageX + x];
}
 
   

Теперь более сложный случай: каждому пикселю соответствует последовательность значений переменной длины. Для оного всего 1 значение, для другого 10, для какого-то и все 20 (пусть и редко). Как организовать подкачку в этом случае? Есть мысли?

Спасибо
Записан
niXman
Гость
« Ответ #1 : Июль 09, 2010, 01:10 »

1. т.е. Image::GetPixel() должна возвращать массив?
2. Image::GetPixel() может дергаться из нескольких потоков?
3. кол-во вызывающих ее потоков?
4. Image::GetPixel() живет в отдельном потоке?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Июль 09, 2010, 12:18 »

1. т.е. Image::GetPixel() должна возвращать массив?
Указатель на константный
Код
C++ (Qt)
const float * Image::GetComplexPixel( int iX, int iY, int * oNumPix );
 

2. Image::GetPixel() может дергаться из нескольких потоков?
да

3. кол-во вызывающих ее потоков?
равно числу ядер процессора

4. Image::GetPixel() живет в отдельном потоке?
да
« Последнее редактирование: Июль 09, 2010, 12:25 от Igors » Записан
niXman
Гость
« Ответ #3 : Июль 09, 2010, 15:21 »

Цитировать
Указатель на константный
а как же вы узнаете размер? он же у вас разный Подмигивающий
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Июль 09, 2010, 15:27 »

а как же вы узнаете размер? он же у вас разный Подмигивающий
Для этого oNumPix
Записан
niXman
Гость
« Ответ #5 : Июль 09, 2010, 19:31 »

а как же вы узнаете размер? он же у вас разный Подмигивающий
Для этого oNumPix
ааа, так вы метод изменили. не заметил.

Цитировать
Указатель на константный
1. если указатель - значит память для него нужно выделять динамически. но когда освобождать память? метод(код) который ее выделяет, этого знать не может. а тот кто ее получит, удалить не сможет из-за того что константный.
2. если указатель - можно возвращать адрес локального массива. но тогда никакой многопоточности.

я вижу решение таким:
нужен "некий класс"(с ссылкой на контейнер который им владеет) с перегруженным operator()(который вернет запись, и удалит себя из контейнера в котором живет), возвращающий, к примеру, std::pair<boost::uint32_t, float[32]>
boost::uint32_t - содержит размер актуальных данных.
float[32] - автоматический массив максимально возможного размера. выделение динамической памяти - дорогая операция.
для чего нужен "некий класс"? - И для того, чтоб реализовать упреждющее чтение Подмигивающий
допустим, хранение очереди состоящей из std::pair<boost::uint32_t, float[32]> типов размером, к примеру, в 10000 единиц, будет занимать около 35кб. очень не много, но производительность вырастит ощутимо.

раз уж метод может дергаться из нескольких потоков, то наверняка нужна нешуточная производительность. потому, читать по одной записи не рационально.
еще вариант для оптимизации - не удалять из очереди "использованные" записи. а, к примеру, использовать записи типа boost::tuple<boost::uint32_t, float[32], bool>. где bool - признак состояния записи(занята/свободна). это даст ощутимый прирост производительности.

вроде правильно объяснил. остальное реализация.
« Последнее редактирование: Июль 09, 2010, 19:59 от niXman » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Июль 09, 2010, 20:56 »

1. если указатель - значит память для него нужно выделять динамически. но когда освобождать память? метод(код) который ее выделяет, этого знать не может. а тот кто ее получит, удалить не сможет из-за того что константный.
Это не имеет отношения к теме, но заметим что константный указатель удалять можно (мне это всегда казалось неестественным).

Удаление происходит в ф-ции LoadPage. При каждой загрузке страницы увеличиваем размер используемой памяти (в байтах). Если этот размер превышает установленный предел, то наименее используемые страницы освобождаются и размер уменьшается.

2. если указатель - можно возвращать адрес локального массива. но тогда никакой многопоточности.
Сделать это thread-safe интересно и нужно, но пока я спрашиваю как вообще организовать подкачку для таких данных.

я вижу решение таким:
нужен "некий класс"(с ссылкой на контейнер который им владеет) с перегруженным operator()(который вернет запись, и удалит себя из контейнера в котором живет), возвращающий, к примеру, std::pair<boost::uint32_t, float[32]>
boost::uint32_t - содержит размер актуальных данных.
Кончайте пьянку с контейнерами и бустами, думайте самостоятельно
Записан
niXman
Гость
« Ответ #7 : Июль 09, 2010, 21:17 »

Цитировать
Кончайте пьянку с контейнерами и бустами
велоизобретательством занимаетесь. никакой рациональности и профф подхода.

Цитировать
думайте самостоятельно
зачем вы Qt используете? думайте самостоятельно. напишите свою версию Подмигивающий
« Последнее редактирование: Июль 09, 2010, 22:15 от niXman » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Июль 10, 2010, 02:50 »

велоизобретательством занимаетесь. никакой рациональности и профф подхода.
В чем же по-Вашему эти рациональность и подход? Свести данные к постоянной длине, зарезервировав по максимуму? Это ход мысли начинающего "Во блин, это new потом еще надо delete... Да ну его нафиг, просто объявлю переменную массив побольше чтобы за глаза хватило". Ваше предложение float[32] - точно такое же, знание множества классов никак не меняет сути.

В STL. boost или еще где есть стандартные подходы для решения этой (или подобной) задачи? Расскажите, я с удовольствием послушаю и скажу "спасибо, я этого не знал", неважно подойдет мне это по скорости или нет. А пускать пузыри с float[32] нечего  Улыбающийся
Записан
niXman
Гость
« Ответ #9 : Июль 10, 2010, 06:01 »

Цитировать
ход мысли начинающего "Во блин, это new потом еще надо delete... Да ну его нафиг, просто объявлю переменную массив побольше чтобы за глаза хватило"
попробуйте почитать настоящие книжки, настоящих экспертов. а не никому не известных афтараф, шлееф, к примеру. которые используют new из-за того, что не знают что с++ поддерживает автоматические переменные, доступ к которым производится быстрее, из-за меньшего уровня косвенности Подмигивающий эх..

Цитировать
Ваше предложение float[32]
Цитировать
А пускать пузыри с float[32] нечего
и это "говорит" человек, пишущий код, выделяющий 8Гб памяти?
или в статье по проектированию с использованием шаблонов, спрашивает, "кто такие команды"?
 Смеющийся
детский сад, да и только...
« Последнее редактирование: Июль 10, 2010, 06:16 от niXman » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Июль 12, 2010, 16:19 »

Ничего  "супер-сложного" не спрашивалось. Я напр. вижу такой вариант
Код
C++ (Qt)
#define VPAGE_PIX_X 32
#define VPAGE_PIX_Y 32
#define VPAGE_PIXELS (VPAGE_PIX_X * VPAGE_PIX_Y)
 
class CVPage {
struct CPoint {
int mCount;
float mData[1];
};
 
struct CData {
const float * GetPixel( int iX, int iY, int * oNumPix ) const
{
int offset = mLookup[iY * VPAGE_PIX_X + iX];
if (offset < 0) { // empty point
*oNumPix = 0;
return 0;
}
CPoint * pt = (CPoint *)(mBase + offset);
*oNumPix = pt->mCount;
return pt->mData;
}
 
int mLookup[VPAGE_PIXELS];
char mBase[1];
};
 
public:
CVPage( void );
 
const float * GetPixel( int iX, int iY, int * oNumPix ) const
{
return mData->GetPixel(iX, iY, oNumPix);
}
 
void * Alloc( void )
{
mData = (CData *) malloc(mLoadSize);
return mData;
}
 
void Free( void )
{
if (mData) {
free(mData);
mData = 0;
}
}
 
private:
long long     mFilePos;
unsigned int mLoadSize;
CData *      mData;
volatile int   mSpin;
};
 
Возможно, это "не совсем в духе С++"  Улыбающийся  Поэтому мне было бы интересно посмотреть/сравнить с др. реализациями. Также как разыгрывать mSpin - есть о чем подумать. А на флуд "нашей малышь" не стоит обращать внимания  Улыбающийся
« Последнее редактирование: Июль 12, 2010, 16:23 от Igors » Записан
niXman
Гость
« Ответ #11 : Июль 12, 2010, 16:57 »

первое что на ум пришло:
Цитировать
Некоторые C++ программисты используют boost, некоторые о нем только слышали, некоторые - нет. Так вот, последние 2 категории - тупиковая ветвь развития (о тех, кому не позволяет железо или компилятор я не говорю), как правило, такие люди даже не доросли до стандартной библиотеки, а их стиль программирования можно назвать “Си с классами”.
отсюда: http://rakafon.blogspot.com/2009/04/boost-boost-c.html
в точности, и не первый раз, подтверждает сказанное Улыбающийся
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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