crossplatform.ru

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


  Ответ в Создание быстродействующего распределителя памяти
Введите ваше имя
Подтвердите код

Введите в поле код из 6 символов, отображенных в виде изображения. Если вы не можете прочитать код с изображения, нажмите на изображение для генерации нового кода.
 

Опции сообщения
 Включить смайлы?
Иконки сообщения
(Опционально)
                                
                                
  [ Без иконки ]
 


Последние 10 сообщений [ в обратном порядке ]
AD Дата 13.7.2009, 17:30
  Итак, сделал вырезку некоторых файлов из boost и добавил в свой проект.
Распределителем памяти сделал fast_pool_allocator. Скорость значительно улучшилась. Есть еще тормоза при загрузке 50 и более файлов, но это уже несмертельно и не так долго.
Вот версия, с которой буду "жить" некоторое время. Потом оптимизирую отрисовку - должно улучшить результаты! :)
Reading Logs
#include "boost/pool/pool_alloc.hpp"

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

public:
    LOGRECORD(const boost::fast_pool_allocator<PARAMVALUE>& only_once_allocator =
                boost::fast_pool_allocator<PARAMVALUE>(), size_t size = 0): name_file(""),
                params(size, PARAMVALUE(), only_once_allocator) {}
    LOGRECORD(const LOGRECORD& l): name_file(l.name_file), phase(l.phase),
                                   params(l.params.size(), PARAMVALUE(), l.params.get_allocator())
    { std::copy(l.params.begin(), l.params.end(), params.begin()); }
    LOGRECORD& operator=(const LOGRECORD& l);
    PARAMVALUE GetLat(QVector<ParamDescr*>* descr) const;
    PARAMVALUE GetLon(QVector<ParamDescr*>* descr) const;
    PARAMVALUE GetDateTime(QVector<ParamDescr*>* descr) const;
    PARAMVALUE GetParamValue(QVector<ParamDescr*>* descr, const std::string& name, const Suint& addr) const;
    PARAMVALUE GetParamValue(QVector<ParamDescr*>* descr, const std::string& name) const;
    PARAMVALUE GetParamValue(QVector<ParamDescr*>* descr, const Suint& addr, std::string& instance);
};

class LogReader: public QObject
    {
        Q_OBJECT

    private:
        QVector<uint> m_vBlock;                    ///< вектор прочитанных слов
        QFile* _file;                            ///< указатель на файл загрузки (лог-файл)
        char* files_buff;                        ///< буфер, в который будут считываться все данные из файлов
        qint64 bytes_read;                        ///< реальное количество прочитанных данных
        int records_count;                        ///< количество записей в лог-файле
        boost::fast_pool_allocator<PARAMVALUE> alloc;///< распределитель памяти

    public:
        QVector<ParamDescr*> rec_descr;            ///< вектор параметров из файла описания (файла загрузки)
        TLV* mainWindow;                        ///< указатель на объект главного окна

    private:
        bool parseBlock(LOGRECORD& t);
        void ChangeDateTime(LOGRECORD& t);
        void FillCompParams(LOGRECORD& t);
        void selectPhase(ParamDescr* descrParam, int index, LOGRECORD& t);
        void selectPhase(LOGRECORD& t);
        void fillHlpLog(const LOGRECORD& t, uint index);
        void compareTimeMark(QVector<LOGRECORD>& log, time_t& before_read);
        void lastCompare(QVector<LOGRECORD>& log, const time_t& before_read);

    public:
        LogReader(std::string FileName, TLV* main): mainWindow(main), records_count(0), _file(new QFile()),
                                        files_buff(0), bytes_read(0) { _file -> setName(FileName.c_str()); }
        LogReader(const char* FileName, TLV* main): mainWindow(main), records_count(0), _file(new QFile()),
                                        files_buff(0), bytes_read(0) { _file -> setName(FileName); }
        ~LogReader() { shutdown(); }
    ///// ................................................... ////////
        void setBytesRead(qint64 n) { bytes_read = n; }
        qint64 bytesRead() const { return bytes_read; }
        bool tRead();
        bool parseBuffer();
    };

/// Выбор этапа полета
    void LogReader::selectPhase(ParamDescr* descrParam, int index, LOGRECORD& t)
    {
        if(descrParam -> Name() != "phaseoperation") return;
        int n = t.params[index].value;
        if(n < phaseList.size() && !phaseList.isEmpty())
        {
            t.phase[true] = phaseList[n][(mainWindow) ? mainWindow -> Language() : true];
            t.phase[false] = phaseList[n][(mainWindow) ? !mainWindow -> Language() : false];
        }
    }

    /// Выбор этапа полета - если нет совпадений имен
    void LogReader::selectPhase(LOGRECORD& t)
    {
        if(t.phase.isEmpty() && !phaseList.isEmpty())
        {
            bool f = (mainWindow) ? mainWindow -> Language() : true;
            t.phase[f] = phaseList[0][f];
            t.phase[!f] = phaseList[0][!f];
        }
    }

    /// Разбор одной записи
    bool LogReader::parseBlock(LOGRECORD& t)
    {
        struct VARS {
            bool flag;
            uint var;
            VARS(): flag(false), var(0) {}
        } vars[ADDR_LIMIT];

        t.name_file = strippedName(_file -> fileName());

        int i = 0, block_size = m_vBlock.size();
        for(int j=0; j<block_size; ++j)
        {
            uint index = m_vBlock[j] % ADDR_LIMIT;
            vars[index].flag = true;
            vars[index].var = m_vBlock[j];
        }

        paramI end(rec_descr.end());
        for(paramI iter=rec_descr.begin(); iter!=end; ++iter, ++i)
        {
            uint addr_index = (*iter) -> Address();
            if(addr_index < ADDR_LIMIT)
                if(vars[addr_index].flag)
                    t.params[i] = (*iter) -> GetValue(vars[addr_index].var);
            selectPhase((*iter), i, t);
        }
        selectPhase(t);

        return true;
    }

    /// Заполнение вычислимых параметров
    void LogReader::FillCompParams(LOGRECORD& t)
    {
        if(mainWindow -> iniReader() -> indexComputeParam() < 0) return;
        for(int i=mainWindow -> iniReader() -> indexComputeParam(); i<rec_descr.size(); ++i)
        {
            CompParamDescr* p = dynamic_cast<CompParamDescr*> (rec_descr[i]);
            ElemFormul formul(p -> formulList());
            COMPUTE* element = formul.calculateFormul(&t, &rec_descr);
            if(element != 0)
            {
                t.params[i].value = element -> GetValue();
                t.params[i].status = PS_OK;
                t.params[i].evn = 0;
            }
        }
    }

    /// Заполнение вектора-получателя частями прочитанных данных
    void LogReader::fillVec(QVector<LOGRECORD>& sender) { mainWindow -> addData(sender); }

    /// Запись значений времени и даты
    void LogReader::ChangeDateTime(LOGRECORD& t)
    {
        int time_index = mainWindow -> iniReader() -> indexTimeParam(),
            date_index = mainWindow -> iniReader() -> indexDateParam();
        TimeParamDescr* dt_time = dynamic_cast<TimeParamDescr*> (rec_descr[time_index]);
        DateParamDescr* dt_date = dynamic_cast<DateParamDescr*> (rec_descr[date_index]);
        tm c_time = dt_time -> TCTime(), c_date = dt_date -> TCDate();
        TimeDateParamDescr tmd(c_time, c_date);
        t.params[time_index] = tmd.GetValue(0);
        t.params[date_index] = tmd.GetValue(0);
    }

    /// Заполнение hlp_log
    void LogReader::fillHlpLog(const LOGRECORD& t, uint index)
    {
        if(index == 0)
            mainWindow -> hlp_log.append(VEC_PARTNER(index, t.name_file, t.phase));
        else if(index > 0 && mainWindow -> hlp_log.size() != 0)
        {
            if(mainWindow -> hlp_log.last().name != t.name_file ||
                mainWindow -> hlp_log.last().phase != t.phase)
                mainWindow -> hlp_log.append(VEC_PARTNER(index, t.name_file, t.phase));

        }
    }

    /// Сравнение временных меток
    void LogReader::compareTimeMark(QVector<LOGRECORD>& log, time_t& before_read)
    {
        time_t contin_read;
        time(&contin_read);
        time_t delta = contin_read - before_read;
        if(delta > 2)
        {
            before_read = contin_read;
            fillVec(log);
            log.clear();
        }
    }

    /// Сравнение временных меток, если чтение файла завершилось раньше, чем через 3 секунды
    void LogReader::lastCompare(QVector<LOGRECORD>& log, const time_t& before_read)
    {
        if(!log.size()) return;
        fillVec(log);
        log.clear();
    }

/// Чтение файла загрузки
    bool LogReader::tRead()
    {
        if(!open()) return false;        ///< открываем файл с логом

        if(_file -> size() > FBUFF_SIZE - bytes_read)
            return false;
        qint64 really_read = _file -> read(&files_buff[bytes_read], _file -> size());
        assert(really_read == _file -> size());
        bytes_read += really_read;

        shutdown();                        ///< закрываем файл с логом

        return true;
    }

    /// Разбор прочитанного буфера
    bool LogReader::parseBuffer()
    {
        uint var = 1e+6, index = 0;
        int i = 0;
        bool bBlock = false, buff_ready = false;
        LOGRECORD unit(alloc, rec_descr.size());
        QVector<LOGRECORD> log(0, unit);
        time_t before_read;        time(&before_read);

        for(uint* p=reinterpret_cast<uint*>(files_buff); i<(bytes_read / sizeof(var)); ++p, ++i)
        {
            var = *p;
            Suint adr = var % 256;
            /// Определение начала/конца одной записи и записывание ее в вектор
            switch(adr)
            {
            case 0000:
                m_vBlock.clear();
                bBlock = true;
            break;
            case 0001:
                if(bBlock)
                {
                    log.append(unit);
                    parseBlock(log.last());
                    ChangeDateTime(log.last());
                    if(mainWindow -> iniReader() -> indexComputeParam() > 0)
                        FillCompParams(log.last());
                    fillHlpLog(log.last(), index);
                    buff_ready = true;
                    compareTimeMark(log, before_read);
                    ++index;
                }
                bBlock = false;
            break;
            default:
                if(bBlock) m_vBlock.append((uint)var);
            }
        }
        lastCompare(log, before_read);

        return buff_ready;
    }

Если есть замечания, пишите, постараюсь учесть. Может быть, кому-то еще и пригодится то, что в этой теме было описано. :)

Да.... Огромное спасибо Tonal(у), Владу, BRE за помощь! Без вас я бы не смог так улучшить код! :)
Влад Дата 13.7.2009, 11:59
 
Цитата
bcp
Usage:
bcp --list [options] module-list
bcp --list-short [options] module-list
bcp --report [options] module-list html-file
bcp [options] module-list output-path

Options:
--boost=path sets the location of the boost tree to path
--scan treat the module list as a list of (possibly non-boost)
files to scan for boost dependencies
--cvs only copy files under cvs version control
--unix-lines make sure that all copied files use Unix style line endings

module-list: a list of boost files or library names to copy
html-file: the name of a html file to which the report will be written
output-path: the path to which files will be copied
AD Дата 13.7.2009, 11:40
 
Цитата(Tonal @ 1.7.2009, 11:44) *
Вот и смотри как там работают с памятью.
А подключить действительно просто - бустовский пул не требует подключения библиотек - только хедеров и пути к ним. :)

Хочу попробовать подключить boost(овский) pool_allocator. Как там с помощью-какой-то утилиты мне собрать нужные пути? Сможете помочь? Буду благодарен.
AD Дата 9.7.2009, 17:10
  Сделал так: вначале чтение всех файлов. Пихаем прочитанное в буфер. А затем уже ходим по буферу и распарсиваем.
Reading files
/// Цикл по всем выбранным лог-файлам
void RThread::run()
{
    countRecords(); ///< подсчет количества записей в файлах
    logger -> initializeBuffer(Reader::FBUFF_SIZE);
    logger -> setBytesRead(0);
    read_count = flist.size();
    if(flist.size())
    {
        foreach(QString fname, flist)
        {
            if(stopped) break;
            logger -> setFileName(fname);
            if(logger -> tRead()) --read_count;
        }
        logger -> parseBuffer();
    }
    if(read_count == 0) --read_count;
    logger -> destroyBuffer();
    exec();
}

/// Чтение файла загрузки
    bool LogReader::tRead()
    {
        if(!open()) return false;        ///< открываем файл с логом

        if(_file -> size() > FBUFF_SIZE - bytes_read)
            return false;
        qint64 really_read = _file -> read(&files_buff[bytes_read], _file -> size());
        assert(really_read == _file -> size());
        bytes_read += really_read;

        shutdown();                        ///< закрываем файл с логом

        return true;
    }

    /// Разбор прочитанного буфера
    bool LogReader::parseBuffer()
    {
        uint var = 1e+6, index = 0;
        int i = 0;
        bool bBlock = false, buff_ready = false;
        QVector<LOGRECORD> log(0, LOGRECORD());
        time_t before_read;        time(&before_read);

        for(uint* p=reinterpret_cast<uint*>(files_buff); i < (bytes_read / sizeof(var)); ++p, ++i)
        {
            var = *p;
            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());
                    fillHlpLog(log.last(), index);
                    buff_ready = true;
                    compareTimeMark(log, before_read);
                    ++index;
                }
                bBlock = false;
            break;
            default:
                if(bBlock) m_vBlock.append((uint)var);
            }
        }
        lastCompare(log, before_read);

        return buff_ready;
    }


Как и предполагалось, это разделение не решило основную проблему - притормаживание.
Пока что, так как при всех собственных распределителях памяти программа падает при выделении большого количества файлов оставил (пока!) стандартный распределитель памяти. Притормаживает в функции parseBlock(), на строках params.resize()
Вот полный код функции:
/// Разбор одной записи
    bool LogReader::parseBlock(LOGRECORD& t)
    {
        t.params.resize(rec_descr.size());
        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;
                }
                selectPhase(*jter, i, t);
            }
        }
        selectPhase(t);

        return true;
    }
AD Дата 8.7.2009, 12:12
  Так... Ну теперь я совсем не понимаю, почему при загрузке нескольких файлов такие задержки! (Посмотрел в профилировщике) :shock:
При этом программа зависает, забирая 99% процессорного времени.


Тормоза на функции allocate!
Не могу понять, где в ней в принципе, кроме grow, могут быть тормоза. В grow после корректного создания конструкторов LOGRECORD теперь заходит довольно редко!

Код, слегка изменил. Вот так:
/// функция allocate из класса virtalloc
pointer allocate(size_type elements, virtalloc<void>::const_pointer hint=0)
    {
        assert(elements);

        Link* prev  = m_pHead;
        Link* first = m_pHead;
        Link* last  = m_pHead;

        size_t size = elements * m_elemSize;
        int count   = elements - 1;

        // check if we have enough free space to
        // store a continuous sequence of objects
        while(last && last -> next && count)
        {
            if(size_t((char*)last -> next -(char*)last) != m_elemSize)
            {                        
                prev  = last;
                first = last -> next;
                count = elements - 1;
            }
            else --count;
            last = last -> next;
        }
        if(!count && last)
        {
             // space found in current chunk
            if(first != m_pHead)
            {
                Link* p = last;
                while(p -> next) p = p -> next;
                p -> next = m_pHead;
                prev -> next = 0;
            }
            m_pHead = last -> next;
        }
        else // no free space => allocate one more chunk
        {
            grow(size, m_pHead);
            first = m_pHead;
            m_pHead = ((Link*)((char*)first +size-m_elemSize)) -> next;
        }
        return (pointer) first;
    }


template<class T> class allocator_wrapper
{
    typedef virtalloc<T> Allocator;

public:
    typedef typename Allocator::size_type size_type;
    typedef typename Allocator::difference_type difference_type;
    typedef typename Allocator::pointer pointer;
    typedef typename Allocator::const_pointer const_pointer;
    typedef typename Allocator::reference reference;
    typedef typename Allocator::const_reference const_reference;
    typedef typename Allocator::value_type value_type;
    template <class U> struct rebind { typedef allocator_wrapper<U> other; };

private:
    Allocator* m_allocator;

public:
    allocator_wrapper(Allocator* allocator = 0): m_allocator(allocator) {}
    pointer address(reference x) const { return &x; }
    const_pointer address(const_reference x) const { return &x; }
    pointer allocate(size_type elements, virtalloc<void>::const_pointer hint=0)
    { return (m_allocator) ? m_allocator -> allocate(elements, hint) : 0; }
    void deallocate(void* pBlk, size_type elements)
    { if(m_allocator) m_allocator -> deallocate(pBlk, elements); }
    size_type max_size() const throw() { return size_t(-1) / sizeof(T); }
    void construct(pointer p, const T& val) { ::new((void*)p) T(val); }
    void destroy(pointer p) { p -> ~T(); }
};


class LogReader: public QObject
    {
        Q_OBJECT

    private:
        QVector<uint> m_vBlock;                    ///< вектор прочитанных слов
        QFile* _file;                            ///< указатель на файл загрузки (лог-файл)
        virtalloc<PARAMVALUE> alloc;            ///< распределитель памяти
///////////////////////////////////////
};

/// Чтение файла загрузки
    bool LogReader::tRead()
    {
        uint var = (uint)1E+6, index = 0;
        bool bBlock = false, file_read = false;
        LOGRECORD unit(allocator_wrapper<PARAMVALUE>(&alloc), rec_descr.size());
        QVector<LOGRECORD> log(0, unit);
        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(unit);
                    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.clear();
                    }
                    ++index;
                }
                bBlock = false;
            break;
            default:
                if(bBlock) m_vBlock.append((uint)var);
            }
        }
        if(log.size()) { fillVec(log); log.clear(); }

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


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

public:
    LOGRECORD(const allocator_wrapper<PARAMVALUE>& only_once_allocator = allocator_wrapper<PARAMVALUE>(),
                size_t size = 0): params(size, PARAMVALUE(), only_once_allocator), name_file("") {}
    LOGRECORD(const LOGRECORD& l): params(l.params.size(), PARAMVALUE(), l.params.get_allocator()),
                                    phase(l.phase), name_file(l.name_file)
    { for(register int i=0; i<l.params.size(); ++i) params[i] = l.params.at(i); }
////////////////////////////////////////////////////////////////////////////////////////////////
};


Буду благодарен, если подскажите в чем еще проблемы могут быть.
AD Дата 7.7.2009, 11:07
  Буду очень благодарен за любую помощь. Очень требуется - так как самому тяжело найти решение проблемы.

Выяснил, что выделение памяти происходит для каждого элемента, причем функция grow вызывается при добавлении одного элемента даже по несколько раз. Видимо, надо изменить саму технологию добавления? нет? Сейчас это происходит так:
/// Структура для хранения всех значений параметров в логе
struct LOGRECORD
{
public:
    std::vector<PARAMVALUE, virtalloc<PARAMVALUE> > params;    ///< массив параметров
/////////////////////////////////////////
/////////////////////////////////////////
};


/// Чтение файла загрузки
    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()));
                                        ///////////////////////////
                                 }
                        default:
                if(bBlock) m_vBlock.append((uint)var);
            }
        }
        if(log.size()) { fillVec(log); log.clear(); }

        /// Закрываем файл с логом
        shutdown();
        return file_read;
    }
AD Дата 6.7.2009, 17:36
  Сделал распределитель памяти следующий:
allocator
#ifndef SPECIFIC_ALLOCATOR_INL
#define SPECIFIC_ALLOCATOR_INL

#include <memory>
#include <cassert>

#include <QObject>
#ifdef Q_WS_WIN
    #pragma once
    #include <windows.h>
#endif

#define ALLOC_PAGE ((64 * 1024) - sizeof(Chunk))

template <class T> class virtalloc;

template <>
class virtalloc<void>
{
public:
    typedef size_t      size_type;
    typedef ptrdiff_t   difference_type;
    typedef void*       pointer;
    typedef const void* const_pointer;
    typedef void        value_type;
    template <class U>  struct rebind { typedef virtalloc<U> other; };
};

/*                   STRUCTURE OF THE MEMORY POOL
                                    
<-----------  Chunk0 ----------- ->  <-----------  Chunk1 ----------- ->
|                                  |                                  |
+----------------------------------+----------------------------------+
| obj0 | obj1 | obj2 | .... | objN |objN+1|objN+2| none | none | none |
+----------------------------------+----------------------------------+
^                                  ^             ^   |  ^   |  ^   |  
|       stored objects             |             |   |__|   |__|   + -> 0
|                                  |             |  
                           m_pChunks       m_pHead   Link*  Link*  Link*
*/
template <class T> class virtalloc
{
private:
    struct Link
    {
    public:
        Link* next;

    public:
        Link(): next(0) {}
        ~Link() { if(next) { delete next; next = 0; } }
    };
    struct Chunk
    {
    public:
        Chunk*    next;
        char    block[0];

    public:
        static void* operator new(size_t size, size_t block)
        { return ::VirtualAlloc(0, size + block, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); }
        static void operator delete(void* p)
        { ::VirtualFree(p, 0, MEM_RELEASE); }
    };
    class ElementSize
    {
    public:
        ElementSize() { size = 0; }
        void set_once(size_t s)
        {
            assert(sizeof(T) <= s);
            if(!size) size = s;
            assert(size == s);
        }
        operator size_t()
        {            
            if(!size)  size = sizeof(T) < sizeof(Link*) ? sizeof(Link*) : sizeof(T);
            return size;
        }
    private:
        size_t  size;
    };
    
    ElementSize        m_elemSize;
    Chunk*             m_pChunks;
    Link*              m_pHead;
    
public:
    typedef size_t     size_type;
    typedef ptrdiff_t  difference_type;
    typedef T*         pointer;
    typedef const T*   const_pointer;
    typedef T&         reference;
    typedef const T&   const_reference;
    typedef T          value_type;
    template <class U> struct rebind { typedef virtalloc<U> other; };

    virtalloc() throw(): m_pChunks(0), m_pHead(0) {}
    template <class U> virtalloc(const virtalloc<U>&) throw(): m_pChunks(0), m_pHead(0) {}
    ~virtalloc() throw()
    {
        while(m_pChunks)
        {
            Chunk* p  = m_pChunks;
            m_pChunks = m_pChunks -> next;
            delete p;
        }
    }
    pointer address(reference x) const { return &x; }    
    const_pointer address(const_reference x) const { return &x; }
    pointer allocate(size_type elements, virtalloc<void>::const_pointer hint=0)
    {
        assert(elements);

        Link* prev  = m_pHead;
        Link* first = m_pHead;
        Link* last  = m_pHead;

        size_t size = elements * m_elemSize;
        int count   = elements - 1;

        // check if we have enough free space to
        // store a continuous sequence of objects
        while(last && last -> next && count)
        {
            if(size_t((char*)last -> next -(char*)last) != m_elemSize)
            {                        
                prev  = last;
                first = last -> next;
                count = elements - 1;
            }
            else --count;
            last = last -> next;
        }
        if(!count && last)
        {
             // space found in current chunk
            if(first != m_pHead)
            {
                Link* p = last;
                while(p -> next) p = p -> next;
                p -> next = m_pHead;
                prev -> next = 0;
            }
            m_pHead = last -> next;
        }
        else // no free space => allocate one more chunk
        {
            grow(size, m_pHead);
            first = m_pHead;
            m_pHead = ((Link*)((char*)first +size-m_elemSize)) -> next;
        }
        return (pointer) first;
    }
    char* _Charalloc(size_type bytes)
    {
        m_elemSize.set_once(bytes);
        return (char*) allocate(1);
    }
    void deallocate(pointer pBlk, size_type elements)
    {
        if(!pBlk || !elements)
            return;
        
        Link* p = (Link*) pBlk;
        for(size_type n=1; n<elements; ++n)
        {
            p -> next = (Link*)((char*)p + m_elemSize);
            p = p -> next;
        }
        p -> next = m_pHead;
        m_pHead = p;        
    }
    void deallocate(void* pBlk, size_type elements)
    { deallocate(static_cast<pointer>(pBlk), elements); }
    size_type max_size() const throw()
    { return size_t(-1) / sizeof(T); }
    void construct(pointer p, const T& val)
    { ::new((void*)p) T(val); }  
    void destroy(pointer p) { p -> ~T(); }

private:    
    void grow(size_t size, Link* tail=0)
    {        
        size = (size / ALLOC_PAGE + (size % ALLOC_PAGE ? 1:0)) * ALLOC_PAGE;

        Chunk* chunk = new(size) Chunk;
        chunk -> next  = m_pChunks;
        m_pChunks    = chunk;
        
        char* first  = chunk -> block;
        char* last   = &first[(size / m_elemSize - 1) * m_elemSize];

        for(char* p=first; p<last; p+=m_elemSize)
            ((Link*)p) -> next = (Link*)(p+m_elemSize);

        ((Link*)last) -> next = tail;
        m_pHead = (Link*)first;
    }
};

template <class T>
bool operator ==(const virtalloc<T>&, const virtalloc<T>&) throw()
{ return true; }

template <class T>
bool operator !=(const virtalloc<T>&, const virtalloc<T>&) throw()
{ return false; }

#endif // SPECIFIC_ALLOCATOR_INL

Распределитель работает. Но работает ну очень медленно! Собственно код чтения остался тот, что я приводил до того, как снова перешел к массивам!
Скачал тестовую версию VTune посмотрел на что уходит время. Основная нагрузка на функцию grow(). Что сделать, чтобы не было такой убийственно-долгой загрузки (даже пары-тройки файлов)?
Где еще исправить и что?

Вот результаты работы профилировщика:
[attachment=697:intelVTune_results.JPG]

А вот работа профилировщика при коде, который был приведен в прошлом посте, т.е. при работе с массивами:
[attachment=698:intelVTu...ts_array.JPG]

P.S. В обоих случаях я загружал один и тот же файл (один!)!
AD Дата 3.7.2009, 12:00
  Так, получилось ускорение с помощью массивов (пока что достаточное, но не необходимое)!
На следующей неделе все-таки доразбираюсь с распределителем памяти и постараюсь перевести решение для векторов.
Код следующий:
// 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;


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

СПАСИБО ВСЕМ ЗА ПОМОЩЬ! Еще, возможно, обращусь! :)
Влад Дата 2.7.2009, 13:38
  Видел: http://rsdn.ru/forum/cpp.applied/930448.aspx ?
AD Дата 2.7.2009, 10:51
  Так.... совсем интересно. При загрузке большого количества логов программа терпит молный крах.

Пока попробую тогда реализовать вариант с массивами, описанный в code 2!
Просмотр темы полностью (откроется в новом окне)
RSS Текстовая версия Сейчас: 29.4.2024, 7:36