r4490: Add experimental cache support in 2D tiled image

URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox ChangeLog: 2009-09-16 Fabien Freling <fabien.freling@lrde.epita.fr> Add experimental cache support in 2D tiled image. * fabien/mln/core/image/cache.hh: Implement cache management. * fabien/mln/core/image/page.hh: Implement page management. * fabien/mln/core/image/tiled2d.hh: Add cache management. * fabien/tests/core/image/Makefile: Minor update. * fabien/tests/core/image/tiled2d.cc: Minor update. --- mln/core/image/cache.hh | 159 ++++++++++++++++++++++++++++++++++++++++++++ mln/core/image/page.hh | 155 ++++++++++++++++++++++++++++++++++++++++++ mln/core/image/tiled2d.hh | 37 ++++++---- tests/core/image/Makefile | 2 tests/core/image/tiled2d.cc | 7 + 5 files changed, 345 insertions(+), 15 deletions(-) Index: trunk/milena/sandbox/fabien/tests/core/image/tiled2d.cc =================================================================== --- trunk/milena/sandbox/fabien/tests/core/image/tiled2d.cc (revision 4489) +++ trunk/milena/sandbox/fabien/tests/core/image/tiled2d.cc (revision 4490) @@ -43,10 +43,13 @@ mln_piter_(tiled2d<rgb8>) p(tiled_ima.domain()); for_all(p) - if (p.col() % 16 == 0) + if (p.row() % 7 == 0) + { + //std::cout << tiled_ima(p); tiled_ima(p) = literal::green; - //std::cout << tiled_ima(p) << std::endl; + //std::cout << " -> " << tiled_ima(p) << std::endl; //mln_assertion(tiled_ima(p) == ima(p)); + } /*for_all(p) if (p.col() % 16 == 0) Index: trunk/milena/sandbox/fabien/tests/core/image/Makefile =================================================================== --- trunk/milena/sandbox/fabien/tests/core/image/Makefile (revision 4489) +++ trunk/milena/sandbox/fabien/tests/core/image/Makefile (revision 4490) @@ -3,5 +3,7 @@ LIBS = `Magick++-config --cppflags --cxxflags --ldflags --libs` INC = -I../../../ -I../../../../../ +all: tiled2d + tiled2d: tiled2d.cc ${CXX} ${CXXFLAGS} ${INC} $^ -o tiled2d Index: trunk/milena/sandbox/fabien/mln/core/image/cache.hh =================================================================== --- trunk/milena/sandbox/fabien/mln/core/image/cache.hh (revision 0) +++ trunk/milena/sandbox/fabien/mln/core/image/cache.hh (revision 4490) @@ -0,0 +1,159 @@ +// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef MLN_CORE_IMAGE_CACHE_HH +# define MLN_CORE_IMAGE_CACHE_HH + +/// \file +/// Definition of the basic mln::cache class. + +#include <mln/util/array.hh> + +#include <mln/core/image/page.hh> + + +namespace mln +{ + + template <typename D, typename V> + class cache + { + public: + + // Constructor + cache(D domain, std::streampos pos, unsigned ncols, std::fstream* f); + ~cache(); + + void set_number_pages(unsigned number_pages); + V read(mln_psite(D) p); + void write(const mln_psite(D)& p, const V& value); + + protected: + + util::array<page<D, V>* > pages_; + unsigned number_pages_; + + // Image info. + D domain_; + std::streampos pos_; + unsigned ncols_; + std::fstream* f_; + }; + + +# ifndef MLN_INCLUDE_ONLY + + + template <typename D, typename V> + inline + cache<D, V>::cache(D domain, std::streampos pos, unsigned ncols, std::fstream* f) + { + this->number_pages_ = 1; + + this->domain_ = domain; + this->pos_ = pos; + this->ncols_ = ncols; + this->f_ = f; + } + + template <typename D, typename V> + inline + cache<D, V>::~cache() + { + for (unsigned i = 0; i < this->pages_.nelements(); ++i) + delete this->pages_[i]; + this->pages_.clear(); + } + + template <typename D, typename V> + inline + void + cache<D, V>::set_number_pages(unsigned number_pages) + { + if (number_pages < this->number_pages_) + { + // FIXME: Prune pages array. + } + this->number_pages_ = number_pages; + } + + template <typename D, typename V> + inline + V + cache<D, V>::read(mln_psite(D) p) + { + for (unsigned i = 0; i < this->pages_.nelements(); ++i) + { + if (this->pages_[i]->has(p)) + return this->pages_[i]->read(p); + } + + // If we have not found a valid page, we just add one. + // FIXME: We should test that we have room for a new page. + page<D, V>* new_page = new page<D, V>(this->domain_, + p, + this->pos_, + this->ncols_, + this->f_); + this->pages_.append(new_page); + return new_page->read(p); + } + + template <typename D, typename V> + inline + void + cache<D, V>::write(const mln_psite(D)& p, const V& value) + { + bool found = false; + for (unsigned i = 0; !found && i < this->pages_.nelements(); ++i) + { + if (this->pages_[i]->has(p)) + { + this->pages_[i]->write(p, value); + found = true; + } + } + + if (!found) + { + // If we have not found a valid page, we just add one. + // FIXME: We should test that we have room for a new page. + page<D, V>* new_page = new page<D, V>(this->domain_, + p, + this->pos_, + this->ncols_, + this->f_); + this->pages_.append(new_page); + new_page->write(p, value); + } + } + + +# endif // ! MLN_INCLUDE_ONLY + +} // end of namespace mln + + +#endif // ! MLN_CORE_IMAGE_CACHE_HH Index: trunk/milena/sandbox/fabien/mln/core/image/tiled2d.hh =================================================================== --- trunk/milena/sandbox/fabien/mln/core/image/tiled2d.hh (revision 4489) +++ trunk/milena/sandbox/fabien/mln/core/image/tiled2d.hh (revision 4490) @@ -39,6 +39,8 @@ # include <mln/fun/i2v/all_to.hh> # include <mln/value/proxy.hh> +# include <mln/core/image/cache.hh> + namespace mln @@ -63,6 +65,7 @@ std::string file_; bool loaded_; T value_; + cache<box2d, T>* cache_; box2d b_; // theoretical box unsigned bdr_; @@ -323,8 +326,11 @@ data< tiled2d<T> >::deallocate_() { if (this->loaded_) + { + delete this->cache_; this->f_->close(); } + } template <typename T> inline @@ -428,13 +434,18 @@ { this_->data_->f_ = new std::fstream(this->data_->file_.c_str()); this_->data_->loaded_ = true; + this_->data_->cache_ = new cache<box2d, T>(this_->data_->b_, + this_->data_->pos_, + this_->ncols(), + this_->data_->f_); } - std::streampos offset = this_->data_->pos_; + /*std::streampos offset = this_->data_->pos_; offset += (this_->ncols() * p.row() + p.col()) * sizeof(T); this_->data_->f_->seekg(offset); this_->data_->f_->get((char*)(&this_->data_->value_), sizeof(T) + 1); // FIXME: I don't know why // I have to add +1. - return this_->data_->value_; + return this_->data_->value_;*/ + return this_->data_->cache_->read(p); } template <typename T> @@ -442,15 +453,17 @@ void tiled2d<T>::write_(const point2d& p, const T& value) { - if (!this->data_->loaded_) + mln::tiled2d<T>* this_ = const_cast<mln::tiled2d<T>* >(this); // Trust me, I have to do this(_). + if (!this_->data_->loaded_) { - this->data_->f_ = new std::fstream(this->data_->file_.c_str()); - this->data_->loaded_ = true; + this_->data_->f_ = new std::fstream(this->data_->file_.c_str()); + this_->data_->loaded_ = true; + this_->data_->cache_ = new cache<box2d, T>(this_->data_->b_, + this_->data_->pos_, + this_->ncols(), + this_->data_->f_); } - std::streampos offset = this->data_->pos_; - offset += (this->ncols() * p.row() + p.col()) * sizeof(T); - this->data_->f_->seekp(offset); - this->data_->f_->write((char*)(&value), sizeof(T)); + this_->data_->cache_->write(p, value); } @@ -462,8 +475,7 @@ tiled2d<T>::at_(unsigned row, unsigned col) const { mln_precondition(this->has(point2d(row, col))); - //FIXME: use the cache Luke. - return this->data_->value_; + return this->data_->cache_(point2d(row, col)); } template <typename T> @@ -472,8 +484,7 @@ tiled2d<T>::at_(unsigned row, unsigned col) { mln_precondition(this->has(point2d(row, col))); - //FIXME: use the cache Luke. - return this->data_->value_; + return this->data_->cache_(point2d(row, col)); } template <typename T> Index: trunk/milena/sandbox/fabien/mln/core/image/page.hh =================================================================== --- trunk/milena/sandbox/fabien/mln/core/image/page.hh (revision 0) +++ trunk/milena/sandbox/fabien/mln/core/image/page.hh (revision 4490) @@ -0,0 +1,155 @@ +// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef MLN_CORE_IMAGE_PAGE_HH +# define MLN_CORE_IMAGE_PAGE_HH + +/// \file +/// Definition of the basic mln::page class. + +# include <fstream> + +# include <mln/util/array.hh> + + +namespace mln +{ + + template <typename D, typename V> + class page + { + public: + + // Constructor & destructor. + page(D domain, mln_psite(D) p, std::streampos pos, unsigned ncols, std::fstream* f); + ~page(); + + bool has(mln_psite(D) p); + V read(mln_psite(D) p); + void write(const mln_psite(D)& p, const V& value); + void flush(); + + // Debug. + void print_buffer(); + + protected: + + D domain_; + D range_; + V* buffer_; + std::fstream* f_; + std::streampos offset_; + unsigned buffer_size_; + }; + + +# ifndef MLN_INCLUDE_ONLY + + + template <typename D, typename V> + inline + page<D, V>::page(D domain, mln_psite(D) p, std::streampos pos, unsigned ncols, std::fstream* f) + { + // Defining layout for a line. + this->range_.pmin() = p; + this->range_.pmin().col() = domain.pmin().col(); + this->range_.pmax() = p; + this->range_.pmax().col() = domain.pmax().col(); + + this->buffer_ = new V[ncols]; + + this->domain_ = domain; + this->f_ = f; + this->buffer_size_ = ncols; + + this->offset_ = pos; + this->offset_ += (ncols * p.row()) * sizeof(V); + f->seekg(this->offset_); + f->get((char*)(buffer_), buffer_size_ * sizeof(V)); + } + + template <typename D, typename V> + inline + page<D, V>::~page() + { + this->flush(); + delete this->buffer_; + } + + template <typename D, typename V> + inline + bool + page<D, V>::has(mln_psite(D) p) + { + return p.col() >= this->range_.pmin().col() && + p.col() <= this->range_.pmax().col() && + p.row() >= this->range_.pmin().row() && + p.row() <= this->range_.pmax().row(); + } + + template <typename D, typename V> + inline + V + page<D, V>::read(mln_psite(D) p) + { + return buffer_[p.col() - this->range_.pmin().col()]; + } + + template <typename D, typename V> + inline + void + page<D, V>::write(const mln_psite(D)& p, const V& value) + { + buffer_[p.col() - this->range_.pmin().col()] = value; + } + + template <typename D, typename V> + inline + void + page<D, V>::flush() + { + this->f_->seekg(this->offset_); + this->f_->write((char*)(buffer_), buffer_size_ * sizeof(V)); + } + + + // Debug. + + template <typename D, typename V> + inline + void + page<D, V>::print_buffer() + { + for (unsigned i = 0; i < this->buffer_size_; ++i) + std::cout << "buffer[" << i << "] = " << this->buffer_[i] << std::endl; + } + + +# endif // ! MLN_INCLUDE_ONLY + +} // end of namespace mln + + +#endif // ! MLN_CORE_IMAGE_PAGE_HH
participants (1)
-
Fabien Freling