Skip to content

Commit

Permalink
Use tile cache in Frame for all tiles
Browse files Browse the repository at this point in the history
  • Loading branch information
Pam Harris committed May 10, 2024
1 parent 4c47ec8 commit 8f0bf53
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 37 deletions.
33 changes: 18 additions & 15 deletions src/Cache/TileCache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,10 @@ TilePtr TileCache::Get(Key key, std::shared_ptr<FileLoader> loader, std::mutex&
return nullptr;
}

TilePtr TileCache::GetCopy(Key key, std::shared_ptr<FileLoader> loader, std::mutex& image_mutex) {
// Load or retrieve tile and return a shared_ptr of a copy to ensure it will not be changed in the cache.
auto tile_ptr = Get(key, loader, image_mutex);
std::vector<float> tile_data;
tile_data.assign(tile_ptr->begin(), tile_ptr->end());
return std::make_shared<std::vector<float>>(tile_data);
void TileCache::Put(Key key, TilePtr tile) {
// Add a tile to the cache
std::unique_lock<std::mutex> guard(_tile_cache_mutex);
AddTile(key, tile);
}

void TileCache::Reset(int32_t z, int32_t stokes, int capacity) {
Expand Down Expand Up @@ -153,15 +151,7 @@ bool TileCache::LoadChunk(Key chunk_key, std::shared_ptr<FileLoader> loader, std

// If the tile is not in the map
if (_map.find(key) == _map.end()) { // add if not found
// Evict oldest tile if necessary
if (_map.size() == _capacity) {
_map.erase(_queue.back().first);
_queue.pop_back();
}

// Insert the new tile
_queue.push_front(std::make_pair(key, t));
_map[key] = _queue.begin();
AddTile(key, t);

} else { // touch the tile
Touch(key);
Expand All @@ -173,3 +163,16 @@ bool TileCache::LoadChunk(Key chunk_key, std::shared_ptr<FileLoader> loader, std

return true;
}

void TileCache::AddTile(Key key, TilePtr tile) {
// Add a tile to the cache without locking. Caller should have locked the cache.
// Evict oldest tile if necessary
if (_map.size() == _capacity) {
_map.erase(_queue.back().first);
_queue.pop_back();
}

// Insert the new tile
_queue.push_front(std::make_pair(key, tile));
_map[key] = _queue.begin();
}
11 changes: 9 additions & 2 deletions src/Cache/TileCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,12 @@ class TileCache {
*/
TilePtr Get(Key key, std::shared_ptr<FileLoader> loader, std::mutex& image_mutex);

/** @brief Retrieve a tile from the cache and return a copy
/** @brief Add a tile to the cache
* @param key The tile key
* @param tile The tile
* @details This function locks the cache because it modifies the cache state.
*/
TilePtr GetCopy(Key key, std::shared_ptr<FileLoader> loader, std::mutex& image_mutex);
void Put(Key key, TilePtr tile);

/** @brief Reset the cache for a new Z coordinate and/or Stokes coordinate, clearing all tiles.
* @param z The new Z coordinate
Expand Down Expand Up @@ -100,6 +101,12 @@ class TileCache {
* @see ChunkKey
*/
bool LoadChunk(Key chunk_key, std::shared_ptr<FileLoader> loader, std::mutex& image_mutex);
/** @brief Add a tile to the cache.
* @param key The tile key
* @param tile The tile
* @details This function does not lock the cache, and assumes that the tile is in the cache.
*/
void AddTile(Key key, TilePtr tile);

/** @brief The current Z coordinate. */
int32_t _z;
Expand Down
42 changes: 22 additions & 20 deletions src/Frame/Frame.cc
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,11 @@ Frame::Frame(uint32_t session_id, std::shared_ptr<FileLoader> loader, const std:
return;
}

// reset the tile cache if the loader will use it
if (_loader->UseTileCache()) {
int tiles_x = (_width - 1) / TILE_SIZE + 1;
int tiles_y = (_height - 1) / TILE_SIZE + 1;
int tile_cache_capacity = std::min(MAX_TILE_CACHE_CAPACITY, 2 * (tiles_x + tiles_y));
_tile_cache.Reset(_z_index, _stokes_index, tile_cache_capacity);
}
// reset the tile cache
int tiles_x = (_width - 1) / TILE_SIZE + 1;
int tiles_y = (_height - 1) / TILE_SIZE + 1;
int tile_cache_capacity = std::min(MAX_TILE_CACHE_CAPACITY, 2 * (tiles_x + tiles_y));
_tile_cache.Reset(_z_index, _stokes_index, tile_cache_capacity);

try {
// Resize stats vectors and load data from image, if the format supports it.
Expand Down Expand Up @@ -345,15 +343,11 @@ bool Frame::SetImageChannels(int new_z, int new_stokes, std::string& message) {
if (!(_loader->UseTileCache() && _loader->HasMip(2)) || IsComputedStokes(_stokes_index)) {
// Reload the full channel cache for loaders which use it
FillImageCache();
} else {
// Don't reload the full channel cache here because we may not need it

if (_loader->UseTileCache()) {
// invalidate / clear the full resolution tile cache
_tile_cache.Reset(_z_index, _stokes_index);
}
}

// invalidate / clear the full resolution tile cache
_tile_cache.Reset(_z_index, _stokes_index);

updated = true;
} else {
message = fmt::format("Channel {} or Stokes {} is invalid in image", new_z, new_stokes);
Expand Down Expand Up @@ -574,16 +568,19 @@ bool Frame::GetRasterTileData(std::shared_ptr<std::vector<float>>& tile_data_ptr
height = std::ceil((float)req_height / mip);

std::vector<float> tile_data;
bool loaded_data(0);
bool loaded_data(0), cached_data(0);
TileCache::Key key(bounds.x_min(), bounds.y_min());

if (mip > 1 && !IsComputedStokes(_stokes_index)) {
// Try to load downsampled data from the image file
loaded_data = _loader->GetDownsampledRasterData(tile_data, _z_index, _stokes_index, bounds, mip, _image_mutex);
} else if (!_image_cache_valid && _loader->UseTileCache()) {
// Load a tile from the tile cache only if this is supported *and* the full image cache isn't populated
tile_data_ptr = _tile_cache.GetCopy(TileCache::Key(bounds.x_min(), bounds.y_min()), _loader, _image_mutex);
if (tile_data_ptr) {
return true;
} else if (!_image_cache_valid) {
// Load a tile from the tile cache if the full image cache isn't populated
auto tile_ptr = _tile_cache.Get(key, _loader, _image_mutex);
if (tile_ptr) {
tile_data.assign(tile_ptr->begin(), tile_ptr->end());
loaded_data = true;
cached_data = true;
}
}

Expand All @@ -592,8 +589,13 @@ bool Frame::GetRasterTileData(std::shared_ptr<std::vector<float>>& tile_data_ptr
loaded_data = GetRasterData(tile_data, bounds, mip, true);
}

// Set return value and cache if not already done
if (loaded_data) {
tile_data_ptr = std::make_shared<std::vector<float>>(tile_data);

if (!cached_data) {
_tile_cache.Put(key, tile_data_ptr);
}
}

return loaded_data;
Expand Down

0 comments on commit 8f0bf53

Please sign in to comment.