crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

6 страниц V  « < 3 4 5 6 >  
Ответить в данную темуНачать новую тему
> Создание быстродействующего распределителя памяти, для std::vector или замена глобальных операций выделения памяти
Влад
  опции профиля:
сообщение 1.7.2009, 16:07
Сообщение #41


Участник
**

Группа: Участник
Сообщений: 146
Регистрация: 20.3.2009
Из: Санкт-Петербург
Пользователь №: 627

Спасибо сказали: 46 раз(а)




Репутация:   8  


Цитата(AD @ 30.6.2009, 15:59) *
Влад, исходя из твоих слов, следует заменить глобальные new и delete!

Нет. Тут фича в том, что new и delete можно перегрузить для конкретного класса - именно того, который тормозит.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 1.7.2009, 16:10
Сообщение #42


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Цитата(Влад @ 1.7.2009, 17:07) *
Нет. Тут фича в том, что new и delete можно перегрузить для конкретного класса - именно того, который тормозит.

Да, видимо, придется! :(
Еще раз проверил, все-таки притормаживает на выделении памяти!
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 1.7.2009, 16:49
Сообщение #43


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Цитата(AD @ 1.7.2009, 17:10) *
Да, видимо, придется! :(

А чем думаешь их заменить? В чем смысл?

Цитата(AD @ 1.7.2009, 17:10) *
Еще раз проверил, все-таки притормаживает на выделении памяти!

Попробуй задать в алокаторе такой размер, что бы все элементы гарантированно помещались в один chunk. И посмотри результаты в профилировщике. Странно все как-то.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 1.7.2009, 17:14
Сообщение #44


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


У меня видоизменилась несколько структура, потому приведу ее еще раз:
/// Структура для хранения всех значений параметров в логе
struct LOGRECORD
{
public:
    std::vector<PARAMVALUE, pool_alloc<PARAMVALUE> > params;    ///< массив параметров
    QMap<bool, QString> phase;                ///< название этапа полета
    QString name_file;                        ///< имя лог-файла для данной записи

public:
    LOGRECORD(size_t size = 0): params(size), name_file("") {}
    LOGRECORD(const LOGRECORD& l): params(l.params), phase(l.phase), name_file(l.name_file) {}
/// anything
};

/// Функции чтения из файла
/// Чтение файла загрузки
    bool LogReader::tRead()
    {
        uint var = (uint)1E+6, index = 0;
        bool bBlock = false, file_read = false;
        QVector<LOGRECORD> log;
        time_t before_read, contin_read;        time(&before_read);

        while(_file -> read((char*)&var, sizeof(var)) > 0)
        {
            Suint adr = var % 256;
            /// Определение начала/конца одной записи и записывание ее в вектор
            switch(adr)
            {
            case 0000:
                m_vBlock.clear();
                bBlock = true;
            break;
            case 0001:
                if(bBlock)
                {
                    log.append(LOGRECORD(rec_descr.size()));
                    parseBlock(log.last());

                    file_read = true;
                    /// Сравнение временных меток
                    time(&contin_read);
                    time_t delta = contin_read - before_read;
                    if(delta > 3)
                    {
                        before_read = contin_read;
                        fillVec(log);
                        log.last().params.clear();
                        log.clear();
                    }
                    ++index;
                }
                bBlock = false;
            break;
            default:
                if(bBlock) m_vBlock.append((uint)var);
            }
        }
        if(log.size()) { fillVec(log); log.clear(); }

        /// Закрываем файл с логом
        shutdown();
        return file_read;
    }

/// Разбор одной записи
    bool LogReader::parseBlock(LOGRECORD& t)
    {
        t.name_file = strippedName(_file -> fileName());
        int size1 = m_vBlock.size(), size2 = rec_descr.size();
        QTextStream out(&traceFile);
        out << "m_vBlock.size() = " << size1 << "          rec_descr.size() = " << size2 << endl;
        /*for(QVector<uint>::iterator iter=m_vBlock.begin(); iter!=m_vBlock.end(); ++iter)
        {
            uint var = *iter;
            Suint adr = var % 256;
            register int i = 0;
            for(paramI jter=rec_descr.begin(); jter!=rec_descr.end(); ++jter, ++i)
            {
                if(adr == (*jter) -> Address())
                {
                    t.params[i] = (*jter) -> GetValue(var);
                    t.params[i].evn = 0;
                }
            }
        }*/

        return true;
    }


Видно, что два вложенных цикла, на которых, по идее могли быть тормоза закомментированы (пока!) и все-равно чувствительная длительность по времени!

Сообщение отредактировал AD - 1.7.2009, 17:18
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 1.7.2009, 17:57
Сообщение #45


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Заметил такую странную вещь:
Указал CHUNK_SIZE = 2^20 (два в 20 степени). Все произошло моментально. Расскоментировал код, загрузка стала производиться довольно долго, а вот уже само отображение крайне шустрое (хотя раньше и при отображении были тормоза)! Буду продолжать искать длительные операции.
Сейчас сделал CHUNK_SIZE = 2^13 (в 20 степени - все-таки не есть хорошо - чуть всю операционку не сожрало! :))
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Tonal
  опции профиля:
сообщение 2.7.2009, 8:04
Сообщение #46


Активный участник
***

Группа: Участник
Сообщений: 452
Регистрация: 6.12.2007
Из: Новосибирск
Пользователь №: 34

Спасибо сказали: 69 раз(а)




Репутация:   17  


Может всё же так:
...
    struct Chunk
    {
        Chunk* next;
        char memory[chunk_size * sizeof(T)];
    };
...

Тогда размер Chunk::memory будет всегда кратен количеству элементов - не будут пропадать попусту невлезшие кусочки. :)
Ну и размер chunk_size я бы поставил как среднее rec_descr.size() * 100, например. :)

Да, ты ведь профилируешь релизную сборку, я надеюсь?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 2.7.2009, 9:11
Сообщение #47


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Цитата(Tonal @ 2.7.2009, 9:04) *
Да, ты ведь профилируешь релизную сборку, я надеюсь?

На счет профилировки хотел посоветоваться! Не помню как мне один раз удалось спрофилировать программу, но больше не удавалось. Причина следующая: файлы, которые генерирует MOC типа ui_tlv.h я создаю еще cpp, переношу туда setupUi, retranslateUi! Делаю это потому что кое-что изменяю в этих функциях! Так проблема в том, что при включенном профайлере компилятор каждый пересобирает проект, соответственно h-файлы все время пересоздаются и выдается куча ошибок. При попытке просто скомпилировать, он снова пересобирает проект. Есть способ победить эту штуку?

Вот видоизменил распределитель.
Пока не видны изменения в скорости: :(
allocator
#ifndef SPECIFIC_ALLOCATOR_INL
#define SPECIFIC_ALLOCATOR_INL

#include <memory>
#include <cassert>

#define CHUNK_SIZE 2048

/// Собственный распределитель памяти
template <typename T> class pool_alloc: public std::allocator<T>
{
private:
    static const difference_type chunk_size = CHUNK_SIZE;
    struct Link { Link* next; };
    struct Chunk
    {
        Chunk* next;
        char memory[chunk_size * ((sizeof(T) <= 0) ? 1 : sizeof(T))];
    };
    Link* head;
    Chunk* chunks;
    static const size_type elem_size = (sizeof(T) < sizeof(Link*)) ? sizeof(Link*) : sizeof(T);
    static const size_type num_elem = chunk_size / elem_size;

private:
    void grow(bool special = false)            ///< увеличиваем пулл
    {
        Chunk* n = new Chunk;
        n -> next = chunks;
        chunks = n;

        char* start = n -> memory;
        char* last = &n -> memory[(num_elem - 1) * elem_size];
        for(char* p=start; p<last; p+=elem_size)
            reinterpret_cast<Link*> (p) -> next = reinterpret_cast<Link*> (p + elem_size);
        reinterpret_cast<Link*> (last) -> next = (special) ? head : 0;
        head = reinterpret_cast<Link*> (start);
    }

public:
    pool_alloc() throw(): head(0), chunks(0) {}
    pointer allocate(size_type n)            ///< выделяем память под n элементов типа T
    {
        if(n * elem_size > chunk_size) throw std::bad_alloc();
        if(!head) grow();
        else if(n != 1) grow(true);
        Link* p = head;
        while(n--) head = head -> next;
        return reinterpret_cast<pointer> (p);
    }
    void deallocate(pointer p, size_type n) ///< возвращаем память в пулл
    {
        char* end = (char*)(p) + n;
        for(char* q=(char*)p; q<end; q+=elem_size)
            reinterpret_cast<Link*> (q) -> next = reinterpret_cast<Link*> (q + elem_size);
        reinterpret_cast<Link*> (end - elem_size) -> next = head;
        head = reinterpret_cast<Link*> (p);
    }
    ~pool_alloc() throw()
    {
        Chunk* n = chunks;
        while(n)
        {
            Chunk* p = n;
            n = n -> next;
            delete p;
        }
    }
    template <typename Other> struct rebind
    { typedef pool_alloc<Other> other; };
    template <typename Other> pool_alloc(const pool_alloc<Other>& p) throw() { head = 0, chunks = 0; }
    template <typename Other> pool_alloc<T>& operator=(const pool_alloc<Other>&)
    { head = 0; chunks = 0; return *this; }
    pool_alloc(const pool_alloc<T>& p) throw() { head = 0, chunks = 0; }
};

#endif // SPECIFIC_ALLOCATOR_INL


Сообщение отредактировал AD - 2.7.2009, 10:50
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 2.7.2009, 10:51
Сообщение #48


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Так.... совсем интересно. При загрузке большого количества логов программа терпит молный крах.

Пока попробую тогда реализовать вариант с массивами, описанный в code 2!
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Влад
  опции профиля:
сообщение 2.7.2009, 13:38
Сообщение #49


Участник
**

Группа: Участник
Сообщений: 146
Регистрация: 20.3.2009
Из: Санкт-Петербург
Пользователь №: 627

Спасибо сказали: 46 раз(а)




Репутация:   8  


Видел: http://rsdn.ru/forum/cpp.applied/930448.aspx ?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 3.7.2009, 12:00
Сообщение #50


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Так, получилось ускорение с помощью массивов (пока что достаточное, но не необходимое)!
На следующей неделе все-таки доразбираюсь с распределителем памяти и постараюсь перевести решение для векторов.
Код следующий:
// h-file
/// Класс для хранения лог-файла
    class LogReader: public QObject
    {
        Q_OBJECT

    protected:
        QVector<uint> m_vBlock;                    ///< вектор прочитанных слов
        QFile* _file;                            ///< указатель на файл загрузки (лог-файл)
        char* _pm_buff;        ///< буфер памяти, который выделяется для распределения между массивами параметров
        int _pm_buff_count;                        ///< счетчик для корректного выделения памяти

private:
        bool parseBlock(LOGRECORD& t);

public:
            bool tRead();
};



cpp-code
// cpp-file

/// Чтение файла загрузки
    bool LogReader::tRead()
    {
        uint var = (uint)1E+6, index = 0;
        bool bBlock = false, file_read = false;
        QVector<LOGRECORD> log;
        time_t before_read, contin_read;        time(&before_read);

        while(_file -> read((char*)&var, sizeof(var)) > 0)
        {
            Suint adr = var % 256;
            /// Определение начала/конца одной записи и записывание ее в вектор
            switch(adr)
            {
            case 0000:
                m_vBlock.clear();
                bBlock = true;
            break;
            case 0001:
                if(bBlock)
                {
                    log.append(LOGRECORD());
                    parseBlock(log.last());
                    ChangeDateTime(log.last());
                    if(mainWindow -> iniReader() -> indexComputeParam() > 0)
                        FillCompParams(log.last());

                                        /// Сравнение временных меток
                    time(&contin_read);
                    time_t delta = contin_read - before_read;
                    if(delta > 3)
                    {
                        before_read = contin_read;
                        fillVec(log);
                        log.clear();
                    }
                    ++index;
                                  }
                              bBlock = false;
            break;
            default:
                if(bBlock) m_vBlock.append((uint)var);

if(log.size()) { fillVec(log); log.clear(); }

        /// Закрываем файл с логом
        shutdown();
        return true;
}

/// Разбор одной записи
    bool LogReader::parseBlock(LOGRECORD& t)
    {
        if(_pm_buff_count >= BUFF_SIZE) _pm_buff_count = 0;
        if(!_pm_buff_count)
            _pm_buff = new char[rec_descr.size() * BUFF_SIZE * sizeof(PARAMVALUE)],
            memset(_pm_buff, 0, rec_descr.size() * BUFF_SIZE * sizeof(PARAMVALUE));
        t.params = reinterpret_cast<PARAMVALUE*> (_pm_buff + _pm_buff_count * rec_descr.size()
                                    * sizeof(PARAMVALUE));
        ++_pm_buff_count;
        t.name_file = strippedName(_file -> fileName());
        for(QVector<uint>::iterator iter=m_vBlock.begin(); iter!=m_vBlock.end(); ++iter)
        {
            uint var = *iter;
            Suint adr = var % 256;
            register int i = 0;
            for(paramI jter=rec_descr.begin(); jter!=rec_descr.end(); ++jter, ++i)
            {
                if(adr == (*jter) -> Address())
                {
                    t.params[i] = (*jter) -> GetValue(var);
                    t.params[i].evn = 0;
                }
                           //// anything
                        }
                }
                     /// anything

                   return true;
           }


Именно строки для ускорения кода - вот:
if(_pm_buff_count >= BUFF_SIZE) _pm_buff_count = 0;
        if(!_pm_buff_count)
            _pm_buff = new char[rec_descr.size() * BUFF_SIZE * sizeof(PARAMVALUE)],
            memset(_pm_buff, 0, rec_descr.size() * BUFF_SIZE * sizeof(PARAMVALUE));
        t.params = reinterpret_cast<PARAMVALUE*> (_pm_buff + _pm_buff_count * rec_descr.size()
                                    * sizeof(PARAMVALUE));
        ++_pm_buff_count;


Еще раз повторюсь, что с помощью векторов я все-таки постараюсь сделать корректный код, но чуть позже!

СПАСИБО ВСЕМ ЗА ПОМОЩЬ! Еще, возможно, обращусь! :)

Сообщение отредактировал AD - 3.7.2009, 12:04
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

6 страниц V  « < 3 4 5 6 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 15.1.2025, 7:17