summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/H5C.c235
-rw-r--r--src/H5Cpkg.h17
2 files changed, 149 insertions, 103 deletions
diff --git a/src/H5C.c b/src/H5C.c
index e753da4..03d7b7a 100644
--- a/src/H5C.c
+++ b/src/H5C.c
@@ -438,6 +438,10 @@ H5C_create(size_t max_cache_size,
((cache_ptr->epoch_markers)[i]).type = &H5C__epoch_marker_class;
}
+ cache_ptr->entries_loaded_counter = 0;
+ cache_ptr->entries_inserted_counter = 0;
+ cache_ptr->entries_relocated_counter = 0;
+
if ( H5C_reset_cache_hit_rate_stats(cache_ptr) != SUCCEED ) {
/* this should be impossible... */
@@ -2417,6 +2421,9 @@ H5C_protect(H5F_t * f,
*/
H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, NULL)
+ /* Update entries loaded in cache counter */
+ cache_ptr->entries_loaded_counter++;
+
/* Record that the entry was loaded, to trigger a notify callback later */
/* (After the entry is fully added to the cache) */
was_loaded = TRUE;
@@ -3224,10 +3231,10 @@ H5C_unprotect(H5F_t * f,
/* Delete the entry from the skip list on destroy */
flush_flags |= H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG;
+ HDassert(((!was_clean) || dirtied) == entry_ptr->in_slist);
if(H5C__flush_single_entry(f, dxpl_id, entry_ptr, flush_flags) < 0)
HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Can't flush entry")
-
- }
+ } /* end if */
#ifdef H5_HAVE_PARALLEL
else if(clear_entry) {
@@ -5146,22 +5153,22 @@ static herr_t
H5C_flush_invalidate_ring(const H5F_t * f, hid_t dxpl_id, H5C_ring_t ring,
unsigned flags)
{
- H5C_t * cache_ptr;
+ H5C_t *cache_ptr;
hbool_t restart_slist_scan;
- int32_t protected_entries = 0;
- int32_t i;
- int32_t cur_ring_pel_len;
- int32_t old_ring_pel_len;
- unsigned cooked_flags;
- unsigned evict_flags;
- H5SL_node_t * node_ptr = NULL;
- H5C_cache_entry_t * entry_ptr = NULL;
- H5C_cache_entry_t * next_entry_ptr = NULL;
+ int32_t protected_entries = 0;
+ int32_t i;
+ int32_t cur_ring_pel_len;
+ int32_t old_ring_pel_len;
+ unsigned cooked_flags;
+ unsigned evict_flags;
+ H5SL_node_t *node_ptr = NULL;
+ H5C_cache_entry_t *entry_ptr = NULL;
+ H5C_cache_entry_t *next_entry_ptr = NULL;
#if H5C_DO_SANITY_CHECKS
int64_t initial_slist_len = 0;
size_t initial_slist_size = 0;
#endif /* H5C_DO_SANITY_CHECKS */
- herr_t ret_value = SUCCEED;
+ herr_t ret_value = SUCCEED;
FUNC_ENTER_NOAPI(FAIL)
@@ -5407,77 +5414,92 @@ H5C_flush_invalidate_ring(const H5F_t * f, hid_t dxpl_id, H5C_ring_t ring,
*
* Writes to disk are possible here.
*/
- for(i = 0; i < H5C__HASH_TABLE_LEN; i++) {
- next_entry_ptr = cache_ptr->index[i];
- while(next_entry_ptr != NULL) {
- entry_ptr = next_entry_ptr;
- HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
- HDassert(entry_ptr->ring >= ring);
+ /* reset the counters so that we can detect insertions, loads,
+ * and moves caused by the pre_serialize and serialize calls.
+ */
+ cache_ptr->entries_loaded_counter = 0;
+ cache_ptr->entries_inserted_counter = 0;
+ cache_ptr->entries_relocated_counter = 0;
- next_entry_ptr = entry_ptr->ht_next;
- HDassert((next_entry_ptr == NULL) ||
- (next_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC));
+ next_entry_ptr = cache_ptr->il_head;
+ while(next_entry_ptr != NULL) {
+ entry_ptr = next_entry_ptr;
+ HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(entry_ptr->ring >= ring);
- if(((!entry_ptr->flush_me_last) ||
- ((entry_ptr->flush_me_last) &&
- (cache_ptr->num_last_entries >= cache_ptr->slist_len))) &&
- (entry_ptr->flush_dep_nchildren == 0) &&
- (entry_ptr->ring == ring)) {
+ next_entry_ptr = entry_ptr->il_next;
+ HDassert((next_entry_ptr == NULL) ||
+ (next_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC));
- if(entry_ptr->is_protected) {
- /* we have major problems -- but lets flush and
- * destroy everything we can before we flag an
- * error.
- */
- protected_entries++;
- if(!entry_ptr->in_slist)
- HDassert(!(entry_ptr->is_dirty));
- } else if(!(entry_ptr->is_pinned)) {
-
- /* if *entry_ptr is dirty, it is possible
- * that one or more other entries may be
- * either removed from the cache, loaded
- * into the cache, or moved to a new location
- * in the file as a side effect of the flush.
- *
- * It's also possible that removing a clean
- * entry will remove the last child of a proxy
- * entry, allowing it to be removed also and
- * invalidating the next_entry_ptr.
- *
- * If either of these happen, and one of the target
- * or proxy entries happens to be the next entry in
- * the hash bucket, we could either find ourselves
- * either scanning a non-existant entry, scanning
- * through a different bucket, or skipping an entry.
- *
- * Neither of these are good, so restart the
- * the scan at the head of the hash bucket
- * after the flush if we detect that the next_entry_ptr
- * becomes invalid.
- *
- * This is not as inefficient at it might seem,
- * as hash buckets typically have at most two
- * or three entries.
- */
- cache_ptr->entry_watched_for_removal = next_entry_ptr;
- if(H5C__flush_single_entry(f, dxpl_id, entry_ptr, (cooked_flags | H5C__DURING_FLUSH_FLAG | H5C__FLUSH_INVALIDATE_FLAG | H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG)) < 0)
- HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Entry flush destroy failed.")
-
- /* Check for the next entry getting removed */
- if(NULL != next_entry_ptr && NULL == cache_ptr->entry_watched_for_removal) {
- /* update stats for hash bucket scan restart here.
- * -- JRM
- */
- next_entry_ptr = cache_ptr->index[i];
- H5C__UPDATE_STATS_FOR_INDEX_SCAN_RESTART(cache_ptr)
- } /* end if */
- else
- cache_ptr->entry_watched_for_removal = NULL;
+ if((!entry_ptr->flush_me_last || (entry_ptr->flush_me_last && cache_ptr->num_last_entries >= cache_ptr->slist_len))
+ && entry_ptr->flush_dep_nchildren == 0 && entry_ptr->ring == ring) {
+ if(entry_ptr->is_protected) {
+ /* we have major problems -- but lets flush and
+ * destroy everything we can before we flag an
+ * error.
+ */
+ protected_entries++;
+ if(!entry_ptr->in_slist)
+ HDassert(!(entry_ptr->is_dirty));
+ } /* end if */
+ else if(!(entry_ptr->is_pinned)) {
+ /* if *entry_ptr is dirty, it is possible
+ * that one or more other entries may be
+ * either removed from the cache, loaded
+ * into the cache, or moved to a new location
+ * in the file as a side effect of the flush.
+ *
+ * It's also possible that removing a clean
+ * entry will remove the last child of a proxy
+ * entry, allowing it to be removed also and
+ * invalidating the next_entry_ptr.
+ *
+ * If either of these happen, and one of the target
+ * or proxy entries happens to be the next entry in
+ * the hash bucket, we could either find ourselves
+ * either scanning a non-existant entry, scanning
+ * through a different bucket, or skipping an entry.
+ *
+ * Neither of these are good, so restart the
+ * the scan at the head of the hash bucket
+ * after the flush if we detect that the next_entry_ptr
+ * becomes invalid.
+ *
+ * This is not as inefficient at it might seem,
+ * as hash buckets typically have at most two
+ * or three entries.
+ */
+ cache_ptr->entry_watched_for_removal = next_entry_ptr;
+
+ if(H5C__flush_single_entry(f, dxpl_id, entry_ptr, (cooked_flags | H5C__DURING_FLUSH_FLAG | H5C__FLUSH_INVALIDATE_FLAG | H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG)) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Entry flush destroy failed.")
+
+ /* Restart the index list scan if necessary. Must
+ * do this if the next entry is evicted, and also if
+ * one or more entries are inserted, loaded, or moved
+ * as these operations can result in part of the scan
+ * being skipped -- which can cause a spurious failure
+ * if this results in the size of the pinned entry
+ * failing to decline during the pass.
+ */
+ if((NULL != next_entry_ptr && NULL == cache_ptr->entry_watched_for_removal)
+ || (cache_ptr->entries_loaded_counter > 0)
+ || (cache_ptr->entries_inserted_counter > 0)
+ || (cache_ptr->entries_relocated_counter > 0)) {
+
+ next_entry_ptr = cache_ptr->il_head;
+
+ cache_ptr->entries_loaded_counter = 0;
+ cache_ptr->entries_inserted_counter = 0;
+ cache_ptr->entries_relocated_counter = 0;
+
+ H5C__UPDATE_STATS_FOR_INDEX_SCAN_RESTART(cache_ptr)
} /* end if */
+ else
+ cache_ptr->entry_watched_for_removal = NULL;
} /* end if */
- } /* end while loop scanning hash table bin */
+ } /* end if */
} /* end for loop scanning hash table */
/* We can't do anything if entries are pinned. The
@@ -5488,32 +5510,33 @@ H5C_flush_invalidate_ring(const H5F_t * f, hid_t dxpl_id, H5C_ring_t ring,
* of pinned entries from pass to pass. If it stops
* shrinking before it hits zero, we scream and die.
*/
- old_ring_pel_len = cur_ring_pel_len;
+ old_ring_pel_len = cur_ring_pel_len;
entry_ptr = cache_ptr->pel_head_ptr;
cur_ring_pel_len = 0;
while(entry_ptr != NULL) {
HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
HDassert(entry_ptr->ring >= ring);
- if(entry_ptr->ring == ring)
+ if(entry_ptr->ring == ring)
cur_ring_pel_len++;
entry_ptr = entry_ptr->next;
} /* end while */
- if((cur_ring_pel_len > 0) && (cur_ring_pel_len >= old_ring_pel_len)) {
+ /* Check if the number of pinned entries in the ring is positive, and
+ * it is not declining. Scream and die if so.
+ */
+ if(cur_ring_pel_len > 0 && cur_ring_pel_len >= old_ring_pel_len) {
/* Don't error if allowed to have pinned entries remaining */
- if(evict_flags)
+ if(evict_flags)
HGOTO_DONE(TRUE)
- /* The number of pinned entries in the ring is positive, and
- * it is not declining. Scream and die.
- */
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Pinned entry count not decreasing, cur_ring_pel_len = %d, old_ring_pel_len = %d, ring = %d", (int)cur_ring_pel_len, (int)old_ring_pel_len, (int)ring)
} /* end if */
HDassert(protected_entries == cache_ptr->pl_len);
- if((protected_entries > 0) && (protected_entries == cache_ptr->index_len))
+
+ if(protected_entries > 0 && protected_entries == cache_ptr->index_len)
HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "Only protected entries left in cache, protected_entries = %d", (int)protected_entries)
} /* main while loop */
@@ -5719,7 +5742,7 @@ H5C_flush_ring(H5F_t *f, hid_t dxpl_id, H5C_ring_t ring, unsigned flags)
if(!flush_marked_entries || entry_ptr->flush_marker)
HDassert(entry_ptr->ring >= ring);
- /* advance node pointer now, before we delete its target
+ /* Advance node pointer now, before we delete its target
* from the slist.
*/
node_ptr = H5SL_next(node_ptr);
@@ -5728,19 +5751,26 @@ H5C_flush_ring(H5F_t *f, hid_t dxpl_id, H5C_ring_t ring, unsigned flags)
if(NULL == next_entry_ptr)
HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "next_entry_ptr == NULL ?!?!")
+ HDassert(next_entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
+ HDassert(next_entry_ptr->is_dirty);
+ HDassert(next_entry_ptr->in_slist);
+
+ if(!flush_marked_entries || next_entry_ptr->flush_marker)
+ HDassert(next_entry_ptr->ring >= ring);
+
HDassert(entry_ptr != next_entry_ptr);
} /* end if */
else
next_entry_ptr = NULL;
- if(((!flush_marked_entries) || (entry_ptr->flush_marker)) &&
- ((!entry_ptr->flush_me_last) ||
- (entry_ptr->flush_me_last &&
- ((cache_ptr->num_last_entries >= cache_ptr->slist_len) ||
- (flush_marked_entries && entry_ptr->flush_marker)))) &&
- ( ( entry_ptr->flush_dep_nchildren == 0 ) ||
- ( entry_ptr->flush_dep_ndirty_children == 0 ) ) &&
- (entry_ptr->ring == ring)) {
+ if((!flush_marked_entries || entry_ptr->flush_marker)
+ && (!entry_ptr->flush_me_last ||
+ (entry_ptr->flush_me_last
+ && (cache_ptr->num_last_entries >= cache_ptr->slist_len
+ || (flush_marked_entries && entry_ptr->flush_marker))))
+ && (entry_ptr->flush_dep_nchildren == 0
+ || entry_ptr->flush_dep_ndirty_children == 0)
+ && entry_ptr->ring == ring) {
if(entry_ptr->is_protected) {
/* we probably have major problems -- but lets
* flush everything we can before we decide
@@ -5930,7 +5960,7 @@ H5C__flush_single_entry(const H5F_t *f, hid_t dxpl_id, H5C_cache_entry_t *entry_
#endif /* H5C_DO_SANITY_CHECKS */
if(entry_ptr->is_protected) {
- HDassert(!entry_ptr->is_protected);
+ HDassert(!entry_ptr->is_protected);
/* Attempt to flush a protected entry -- scream and die. */
HGOTO_ERROR(H5E_CACHE, H5E_PROTECT, FAIL, "Attempt to flush a protected entry.")
@@ -6117,11 +6147,11 @@ H5C__flush_single_entry(const H5F_t *f, hid_t dxpl_id, H5C_cache_entry_t *entry_
HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag cleared")
/* Propagate the clean flag up the flush dependency chain if appropriate */
- HDassert(entry_ptr->flush_dep_ndirty_children == 0);
- if(entry_ptr->flush_dep_nparents > 0)
- if(H5C__mark_flush_dep_clean(entry_ptr) < 0)
- HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Can't propagate flush dep clean flag")
- } /* end if */
+ HDassert(entry_ptr->flush_dep_ndirty_children == 0);
+ if(entry_ptr->flush_dep_nparents > 0)
+ if(H5C__mark_flush_dep_clean(entry_ptr) < 0)
+ HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Can't propagate flush dep clean flag")
+ } /* end if */
} /* end else */
/* reset the flush_in progress flag */
@@ -7836,7 +7866,8 @@ H5C__generate_image(const H5F_t *f, H5C_t *cache_ptr, H5C_cache_entry_t *entry_p
* for a move
*/
if(serialize_flags & H5C__SERIALIZE_MOVED_FLAG) {
- H5C__UPDATE_STATS_FOR_MOVE(cache_ptr, entry_ptr);
+ /* Update stats and entries relocated counter */
+ H5C__UPDATE_STATS_FOR_MOVE(cache_ptr, entry_ptr)
/* We must update cache data structures for the change in address */
if(entry_ptr->addr == old_addr) {
diff --git a/src/H5Cpkg.h b/src/H5Cpkg.h
index e30ca8d..0782b09 100644
--- a/src/H5Cpkg.h
+++ b/src/H5Cpkg.h
@@ -656,7 +656,8 @@ if ( ( ( ( (head_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) && \
((cache_ptr)->cache_flush_moves[(entry_ptr)->type->id])++; \
if ( entry_ptr->flush_in_progress ) \
((cache_ptr)->entry_flush_moves[(entry_ptr)->type->id])++; \
- (((cache_ptr)->moves)[(entry_ptr)->type->id])++;
+ (((cache_ptr)->moves)[(entry_ptr)->type->id])++; \
+ (cache_ptr)->entries_relocated_counter++;
#define H5C__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, new_size)\
if ( cache_ptr->flush_in_progress ) \
@@ -782,6 +783,7 @@ if ( ( ( ( (head_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) && \
((cache_ptr)->max_size)[(entry_ptr)->type->id] ) \
((cache_ptr)->max_size)[(entry_ptr)->type->id] \
= (entry_ptr)->size; \
+ cache_ptr->entries_inserted_counter++; \
}
#define H5C__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit) \
@@ -866,6 +868,7 @@ if ( ( ( ( (head_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) && \
(cache_ptr)->max_slist_len = (cache_ptr)->slist_len; \
if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size ) \
(cache_ptr)->max_slist_size = (cache_ptr)->slist_size; \
+ cache_ptr->entries_inserted_counter++; \
}
#define H5C__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit) \
@@ -4057,6 +4060,15 @@ typedef struct H5C_tag_info_t {
* this field will be reset every automatic resize epoch.
*
*
+ * entries_loaded_counter: Number of entries loaded into the cache
+ * since the last time this field was reset.
+ *
+ * entries_inserted_counter: Number of entries inserted into the cache
+ * since the last time this field was reset.
+ *
+ * entries relocated_counter: Number of entries whose base address has
+ * been changed since the last time this field was reset.
+ *
* Statistics collection fields:
*
* When enabled, these fields are used to collect statistics as described
@@ -4439,6 +4451,9 @@ struct H5C_t {
int64_t cache_hits;
int64_t cache_accesses;
+ int64_t entries_loaded_counter;
+ int64_t entries_inserted_counter;
+ int64_t entries_relocated_counter;
#if H5C_COLLECT_CACHE_STATS
/* stats fields */
int64_t hits[H5C__MAX_NUM_TYPE_IDS + 1];