/* * This file is part of rasdaman community. * * Rasdaman community 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, either version 3 of the License, or * (at your option) any later version. * * Rasdaman community 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 rasdaman community. If not, see . * * Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / rasdaman GmbH. * * For more information please see * or contact Peter Baumann via . / /** * SOURCE: alignedtiling.cc * * MODULE: rasodmg * CLASS: r_AlignedTiling, r_DefaultTiling * * COMMENTS: * None */ #include #include #include #include #include "rasodmg/alignedtiling.hh" #include "raslib/rmdebug.hh" #include "raslib/rminit.hh" #ifdef __VISUALC__ #include #else #include #endif const char* r_Aligned_Tiling::description = "tile configuration or tile dimension and tile size (in bytes) (ex: \"[0:9,0:9];100\" or \"2;100\")"; r_Aligned_Tiling::r_Aligned_Tiling(const char* encoded) throw (r_Error) : r_Dimension_Tiling(0, 0) { if(!encoded) { RMInit::logOut << "r_Aligned_Tiling::r_Aligned_Tiling(" << (encoded?encoded: "NULL") << ")" << std::endl; throw r_Error(TILINGPARAMETERNOTCORRECT); } r_Bytes tileS=0, lenToConvert=0; r_Minterval* tileConf=NULL; r_Dimension tileD=0; bool state=false; //false for "tileconf;tilesize", true for "tiledim,tilesize" const char *pStart=NULL, *pRes=NULL, *pEnd=NULL; char *pToConvert=NULL; pStart=encoded; pEnd=pStart+strlen(pStart); pRes=strstr(pStart, TCOLON); if(!pRes) { RMInit::logOut << "r_Aligned_Tiling::r_Aligned_Tiling(" << encoded << "): Error decoding tile configuration from tilingparams." << std::endl; throw r_Error(TILINGPARAMETERNOTCORRECT); } //deal with first param lenToConvert=pRes-pStart; pToConvert = new char[lenToConvert+1]; memcpy(pToConvert,pStart,lenToConvert); pToConvert[lenToConvert]='\0'; if(*pToConvert == *LSQRBRA) { try { tileConf=new r_Minterval(pToConvert); } catch(r_Error& err) { RMInit::logOut << "r_Aligned_Tiling::r_Aligned_Tiling(" << encoded << "): Error decoding tile configuration \"" << pToConvert << "\" from tileparams." << std::endl; RMInit::logOut << "Error " << err.get_errorno() << " : " << err.what() << std::endl; delete [] pToConvert; throw r_Error(TILINGPARAMETERNOTCORRECT); } } else { tileD=strtol(pToConvert, (char**)NULL, DefaultBase); if (!tileD) { RMInit::logOut << "r_Aligned_Tiling::r_Aligned_Tiling(" << encoded << "): Error decoding tile dimension \"" << pToConvert << "\" from tileparams." << std::endl; delete[] pToConvert; throw r_Error(TILINGPARAMETERNOTCORRECT); } if (tileD < 0) { RMInit::logOut << "r_Aligned_Tiling::r_Aligned_Tiling(" << encoded << "): Error decoding tile dimension \"" << pToConvert << "\" from tileparams." << std::endl; RMInit::logOut << "Dimension is negative." << std::endl; delete[] pToConvert; throw r_Error(TILINGPARAMETERNOTCORRECT); } } //skip COLON delete[] pToConvert; if(pRes != (pEnd-1)) pRes++; else { RMInit::logOut << "r_Aligned_Tiling::r_Aligned_Tiling(" << encoded << "): Error decoding tiling, end of stream." << std::endl; throw r_Error(TILINGPARAMETERNOTCORRECT); } //deal with second param tileS=strtol(pRes,(char**) NULL, DefaultBase); if (!tileS) { RMInit::logOut << "r_Aligned_Tiling::r_Aligned_Tiling(" << encoded << "): Error decoding tile size \"" << pRes << "\"." << std::endl; if(tileConf) delete tileConf; throw r_Error(TILINGPARAMETERNOTCORRECT); } if (tileS < 0) { RMInit::logOut << "r_Aligned_Tiling::r_Aligned_Tiling(" << encoded << "): Error decoding tile size \"" << pRes << "\", is negative." << std::endl; if(tileConf) delete tileConf; throw r_Error(TILINGPARAMETERNOTCORRECT); } //detect state if(tileConf) { tile_config = *tileConf; dimension = tile_config.dimension(); tile_size = tileS; delete tileConf; } else { tile_config = r_Minterval(tileD); dimension = tileD; tile_size = tileS; } } r_Aligned_Tiling::r_Aligned_Tiling(r_Dimension dim, r_Bytes ts) throw (r_Error) : r_Dimension_Tiling(dim, ts), tile_config(dim) { /// Default tile configuration - equal sides for(r_Dimension i = 0; i < dim ; i++) tile_config << r_Sinterval((r_Range)0, (r_Range)1); } r_Aligned_Tiling::r_Aligned_Tiling(const r_Minterval& tc, r_Bytes ts) throw (r_Error) : r_Dimension_Tiling(tc.dimension(), ts), tile_config(tc) { } r_Tiling* r_Aligned_Tiling::clone() const { r_Aligned_Tiling* newAT = new r_Aligned_Tiling(tile_config, tile_size); return newAT; } r_Aligned_Tiling::~r_Aligned_Tiling() { tile_config.r_deactivate(); } const r_Minterval& r_Aligned_Tiling::get_tile_config() const { return tile_config; } r_Minterval r_Aligned_Tiling::compute_tile_domain(const r_Minterval& dom, r_Bytes cell_size) const { RMDBGENTER(3, RMDebug::module_rasodmg, "r_Aligned_Tiling", "compute_tile_domain(" << dom << ", " << cell_size << ")") // Minimum optimal tile size. Below this value, the waste will be too big. r_Bytes optMinTileSize = get_min_opt_tile_size(); // number of cells per tile according to storage options r_Area numCellsTile = tile_size / cell_size; // For final result. r_Minterval tileDomain(dimension); int startIx = -1; for (r_Dimension i = 0; i < dimension ; i++) { if (tile_config[i].is_low_fixed() == 0 || tile_config[i].is_high_fixed() == 0) startIx = i; } if (startIx >= 0) // Some limits are nonfixed { unsigned long size = cell_size; int i; for(i = startIx; i >=0 ; i--) // treat the non fixed limits first { r_Range l, h; // If any of the limits is non-fixed along this direction, tiles // will extend from one side to the other along this direction. if ((tile_config[i].is_low_fixed() == 0) || (tile_config[i].is_high_fixed() == 0)) { l = dom[i].low(); h = dom[i].high(); /* Alternative interpretation of tile_config with non fixed limits For the time being is useless because the splittile algorithm doesn't take into account the origin of the tile if (tile_config[i].is_low_fixed() == 0) l = contentsDomain[i].low(); else l = tile_config[i].low(); if (tileconfig[i].is_high_fixed() == 0) h = contentsDomain[i].high(); else h = tile_config[i].high(); */ if(size * (h - l + 1) > tile_size) { h = tile_size/size + l - 1; } size = size * (h - l + 1); tileDomain[i] = r_Sinterval(r_Range(l) ,r_Range(h)); } } for(i = dimension-1; i >=0 ; i--) // treat fixed limits now { r_Range l, h; // If any of the limits is non-fixed along this direction, tiles // will extend from one side to the other along this direction. if ((tile_config[i].is_low_fixed() != 0) && (tile_config[i].is_high_fixed() != 0)) { l = tile_config[i].low(); h = tile_config[i].high(); if(size * (h - l + 1) > tile_size) { h = tile_size/size + l - 1; } size = size * (h - l + 1); tileDomain[i] = r_Sinterval(r_Range(l) ,r_Range(h)); } } RMDBGEXIT(2, RMDebug::module_rasodmg, "r_Aligned_Tiling", "calculateTileDomain result : " << tileDomain < get_min_opt_tile_size() && sizeTileConfig < tile_size) { RMDBGEXIT(2, RMDebug::module_rasodmg, "r_Aligned_Tiling", "calculateTileDomain result : " << tile_config) return tile_config; } else { float sizeFactor = (float) numCellsTile / numCellsTileConfig; float f = float (1/ float(dimension)); float dimFactor = (float)pow(sizeFactor, f); RMDBGMIDDLE(2, RMDebug::module_rasodmg, "r_Aligned_Tiling", "dim factor == " << dimFactor) unsigned long l, h; unsigned long newWidth; // extending the bound of each r_Sinterval of tile_config by // using the factor dimFactor for (int i = 0; i < dimension ; i++) { l = tile_config[i].low(); h = tile_config[i].high(); newWidth = (unsigned long) ((h - l + 1) * dimFactor); if (newWidth < 1) newWidth = 1; tileDomain << r_Sinterval(r_Range(l), r_Range(l + newWidth - 1)); } // Approximate the resulting tile size to the target one: /* r_Minterval tmpTileDomain = get_opt_size(tileDomain, cell_size); tileDomain = tmpTileDomain; */ /* unsigned long sz = tileDomain.cell_count() * cell_size; RMDBGOUT(2,"cell_size " << cell_size << " tileDomain "<< tileDomain << std::endl) RMDBGOUT(2,"cell_count == " << tileDomain.cell_count() << " sz == " << sz << std::endl) unsigned long newSz = sz; for(i = dimension-1; i >= 0 && newSz < tile_size ; i--) { RMDBGOUT(2, "inside the cycle " << std::endl) unsigned long deltaSz = cell_size; for (int j = 0 ; j < dimension ; j++) if (j != i) deltaSz *= (tileDomain[j].high()-tileDomain[j].low()+1); h = tileDomain[i].high(); if (deltaSz + newSz <= tile_size) { tileDomain[i].set_high(r_Range(h + 1)); newSz += deltaSz; } } */ if (tileDomain.cell_count() * cell_size > tile_size) RMDBGMIDDLE(2, RMDebug::module_rasodmg, "Error in r_Aligned_Tiling", "calculateTileDomain() " << std::endl); if (tileDomain.cell_count() * cell_size < optMinTileSize) RMDBGMIDDLE(2, RMDebug::module_rasodmg, "r_Aligned_Tiling", "calculateTileDomain() result non optimal " << std::endl); RMDBGEXIT(2, RMDebug::module_rasodmg, "r_Aligned_Tiling", "calculateTileDomain result : " << tileDomain << std::endl) // cout << "return 3"<* r_Aligned_Tiling::compute_tiles(const r_Minterval& obj_domain, r_Bytes cell_size) const throw (r_Error) { std::vector* result = new std::vector; r_Dimension dim = tile_config.dimension(); r_Minterval bigDom = obj_domain; r_Minterval tileDom = compute_tile_domain(obj_domain, cell_size); // cout << "r_Aligned_Tiling::compute_tiles() " << tileDom << std::endl; r_Minterval currDom(tileDom.dimension()); r_Point cursor(tileDom.dimension()); r_Point tileSize; r_Point origin; int done = 0; // initialize cursor for(dim = 0; dim < cursor.dimension(); dim++) cursor[dim] = 0; // calculate size of Tiles tileSize = tileDom.get_extent(); // origin of bigTile origin = bigDom.get_origin(); // initialize currDom for(dim=0; dim < cursor.dimension(); dim++) currDom << r_Sinterval((r_Range) (origin[dim]), (r_Range) (origin[dim] + tileSize[dim] - 1)); // resets tileDom to lower left side of bigTile tileDom = currDom; // intersect with bigTile currDom.intersection_with(bigDom); // iterate with smallTile over bigTile while(!done) { currDom.intersection_with(bigDom); // create new smallTile r_Minterval smallTile(dim); smallTile = currDom; // insert tile in set result->push_back(smallTile); // increment cursor, start with highest dimension long i = cursor.dimension() - 1; cursor[(unsigned int)i] += tileSize[(unsigned int)i]; // move cursor currDom = tileDom.create_translation(cursor); while(!(currDom.intersects_with(bigDom))) { cursor[(unsigned int)i] = 0; i--; if(i < 0) { done = 1; break; } cursor[(unsigned int)i] += tileSize[(unsigned int)i]; // move cursor currDom = tileDom.create_translation(cursor); } } return result; } r_Minterval r_Aligned_Tiling::get_opt_size(const r_Minterval& tileDomain, r_Bytes cellSize) const { unsigned long tileSize = get_tile_size(); unsigned long newSize = tileDomain.cell_count() * cellSize; r_Minterval result = tileDomain; r_Dimension dim = tileDomain.dimension(); int* ixArr = new int[dim]; int* tmpIxArr = new int[dim]; r_Minterval tmpResult = result; int j; for (j = 0; j < dim; j++) ixArr[j] = j; for(j = dim - 1; j >=0 && newSize < tileSize ; j--) { int i=0; unsigned long h, wd; unsigned minWidthIx = 0; unsigned long minWidth = tileDomain[0].high()-tileDomain[0].low()+1; for(int k = j; k >=0 ; k--) { i = ixArr[k]; h = result[i].high() + 1; wd = result[i].high() - result[i].low() + 1; if (wd < minWidth) { minWidth = wd; minWidthIx = i; } } int tmpIx = ixArr[j]; ixArr[minWidthIx] = tmpIx; tmpResult[minWidthIx].set_high(r_Range(h)); newSize = tmpResult.cell_count() * cellSize; if (newSize > tileSize) { for(i = dim-1; i >=0 ; i--) { h = result[i].high() + 1; wd = result[i].high() - result[i].low() + 1; if (wd < minWidth) { minWidth = wd; minWidthIx = i; } } } result[minWidthIx].set_high(r_Range(h)); newSize = result.cell_count() * cellSize; if (newSize > tileSize) { result[minWidthIx].set_high(r_Range(h - 1)); } } delete[] ixArr; return result; } r_Tiling_Scheme r_Aligned_Tiling::get_tiling_scheme() const { return r_AlignedTiling; } r_Bytes r_Aligned_Tiling::get_min_opt_tile_size() const { return (get_tile_size() - get_tile_size()/10); } char* r_Aligned_Tiling::get_string_representation() const { unsigned int bufferSize = 25; // should be enough! // allocate buffer and initialize string stream char* buffer = new char[bufferSize]; std::ostrstream domainStream(buffer, bufferSize); // write into string stream print_status(domainStream); domainStream << std::ends; // allocate memory taking the final string char* returnString = strdup(buffer); // delete buffer delete[] buffer; return returnString; } void r_Aligned_Tiling::print_status(std::ostream& os) const { os << "r_Aligned_Tiling[ "; r_Dimension_Tiling::print_status(os); os << " tile configuration = "<< tile_config <<" ]"; } /* std::ostream& operator<<(std::ostream& s, const r_Aligned_Tiling& at) { at.print_status(s); return s; } */ /* std::vector* r_Default_Tiling::compute_tiles(const r_Minterval& obj_domain, long cell_size) const { std::vector* result = new std::vector; RMDBGENTER(4, RMDebug::module_rasodmg, "r_Default_Tiling", "compute_tiles") r_Minterval bigDom = obj_domain; r_Minterval tileDom(bigDom.dimension()); // compute the domain of the small tiles // tiles are n-dimensional cubes with edge length n-th root of max tile size //old implementations: //long edgeLength = (long)floor(exp((1/(double)tileDom.dimension())* // log(RMInit::tileSize/mar->get_type_length()))); //long edgeLength = (long)floor(exp((1/(double)tileDom.dimension())* // log(get_tile_size()/cell_size))); RMDBGMIDDLE(4, RMDebug::module_rasodmg, "r_Default_Tiling", "tile size == " << get_tile_size()) long edgeLength = (long) floor(pow(get_tile_size()/cell_size, 1/(double)tileDom.dimension())); r_Dimension dim; for(dim=0; dimpush_back(smallTile); // increment cursor, start with highest dimension long i = cursor.dimension() - 1; cursor[(unsigned int)i] += tileSize[(unsigned int)i]; // move cursor currDom = tileDom.create_translation(cursor); while(!(currDom.intersects_with(bigDom))) { cursor[(unsigned int)i] = 0; i--; if(i < 0) { done = 1; break; } cursor[(unsigned int)i] += tileSize[(unsigned int)i]; // move cursor currDom = tileDom.create_translation(cursor); } } RMDBGEXIT(4, RMDebug::module_rasodmg, "r_Default_Tiling", "compute_tiles") return result; } */