Change the way cache hits and misses are tracked to avoid counting blind page writes as misses and count the results of partial page writes. Report cache hit rate in status.
This commit is contained in:
parent
e02dae5e0b
commit
b4dbc6d7fa
|
@ -297,6 +297,10 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"page_cache":{
|
||||
"log_hit_rate":0.5,
|
||||
"storage_hit_rate":0.5
|
||||
},
|
||||
"messages":[
|
||||
{
|
||||
"reasons":[
|
||||
|
|
|
@ -319,6 +319,10 @@ const KeyRef JSONSchemas::statusSchema = LiteralStringRef(R"statusSchema(
|
|||
}
|
||||
]
|
||||
},
|
||||
"page_cache":{
|
||||
"log_hit_rate":0.5,
|
||||
"storage_hit_rate":0.5
|
||||
},
|
||||
"messages":[
|
||||
{
|
||||
"reasons":[
|
||||
|
|
|
@ -67,8 +67,6 @@ struct EvictablePageCache : ReferenceCounted<EvictablePageCache> {
|
|||
EvictablePageCache() : pageSize(0), maxPages(0), cacheEvictionType(RANDOM) {}
|
||||
|
||||
explicit EvictablePageCache(int pageSize, int64_t maxSize) : pageSize(pageSize), maxPages(maxSize / pageSize), cacheEvictionType(evictionPolicyStringToEnum(FLOW_KNOBS->CACHE_EVICTION_POLICY)) {
|
||||
cacheHits.init(LiteralStringRef("EvictablePageCache.CacheHits"));
|
||||
cacheMisses.init(LiteralStringRef("EvictablePageCache.CacheMisses"));
|
||||
cacheEvictions.init(LiteralStringRef("EvictablePageCache.CacheEvictions"));
|
||||
}
|
||||
|
||||
|
@ -82,7 +80,6 @@ struct EvictablePageCache : ReferenceCounted<EvictablePageCache> {
|
|||
} else {
|
||||
lruPages.push_back(*page); // new page is considered the most recently used (placed at LRU tail)
|
||||
}
|
||||
++cacheMisses;
|
||||
}
|
||||
|
||||
void updateHit(EvictablePage* page) {
|
||||
|
@ -91,7 +88,6 @@ struct EvictablePageCache : ReferenceCounted<EvictablePageCache> {
|
|||
lruPages.erase(List::s_iterator_to(*page));
|
||||
lruPages.push_back(*page);
|
||||
}
|
||||
++cacheHits;
|
||||
}
|
||||
|
||||
void try_evict() {
|
||||
|
@ -126,8 +122,6 @@ struct EvictablePageCache : ReferenceCounted<EvictablePageCache> {
|
|||
List lruPages;
|
||||
int pageSize;
|
||||
int64_t maxPages;
|
||||
Int64MetricHandle cacheHits;
|
||||
Int64MetricHandle cacheMisses;
|
||||
Int64MetricHandle cacheEvictions;
|
||||
const CacheEvictionType cacheEvictionType;
|
||||
};
|
||||
|
@ -278,6 +272,8 @@ private:
|
|||
Int64MetricHandle countFileCacheWrites;
|
||||
Int64MetricHandle countFileCacheReadsBlocked;
|
||||
Int64MetricHandle countFileCacheWritesBlocked;
|
||||
Int64MetricHandle countFileCachePageReadsHit;
|
||||
Int64MetricHandle countFileCachePageReadsMissed;
|
||||
Int64MetricHandle countFileCachePageReadsMerged;
|
||||
Int64MetricHandle countFileCacheReadBytes;
|
||||
|
||||
|
@ -286,28 +282,33 @@ private:
|
|||
Int64MetricHandle countCacheWrites;
|
||||
Int64MetricHandle countCacheReadsBlocked;
|
||||
Int64MetricHandle countCacheWritesBlocked;
|
||||
Int64MetricHandle countCachePageReadsHit;
|
||||
Int64MetricHandle countCachePageReadsMissed;
|
||||
Int64MetricHandle countCachePageReadsMerged;
|
||||
Int64MetricHandle countCacheReadBytes;
|
||||
|
||||
AsyncFileCached( Reference<IAsyncFile> uncached, const std::string& filename, int64_t length, Reference<EvictablePageCache> pageCache )
|
||||
AsyncFileCached( Reference<IAsyncFile> uncached, const std::string& filename, int64_t length, Reference<EvictablePageCache> pageCache )
|
||||
: uncached(uncached), filename(filename), length(length), prevLength(length), pageCache(pageCache), currentTruncate(Void()), currentTruncateSize(0) {
|
||||
if( !g_network->isSimulated() ) {
|
||||
countFileCacheWrites.init( LiteralStringRef("AsyncFile.CountFileCacheWrites"), filename);
|
||||
countFileCacheReads.init( LiteralStringRef("AsyncFile.CountFileCacheReads"), filename);
|
||||
countFileCacheWritesBlocked.init( LiteralStringRef("AsyncFile.CountFileCacheWritesBlocked"), filename);
|
||||
countFileCacheReadsBlocked.init( LiteralStringRef("AsyncFile.CountFileCacheReadsBlocked"), filename);
|
||||
countFileCacheWrites.init(LiteralStringRef("AsyncFile.CountFileCacheWrites"), filename);
|
||||
countFileCacheReads.init(LiteralStringRef("AsyncFile.CountFileCacheReads"), filename);
|
||||
countFileCacheWritesBlocked.init(LiteralStringRef("AsyncFile.CountFileCacheWritesBlocked"), filename);
|
||||
countFileCacheReadsBlocked.init(LiteralStringRef("AsyncFile.CountFileCacheReadsBlocked"), filename);
|
||||
countFileCachePageReadsHit.init(LiteralStringRef("AsyncFile.CountFileCachePageReadsHit"), filename);
|
||||
countFileCachePageReadsMissed.init(LiteralStringRef("AsyncFile.CountFileCachePageReadsMissed"), filename);
|
||||
countFileCachePageReadsMerged.init(LiteralStringRef("AsyncFile.CountFileCachePageReadsMerged"), filename);
|
||||
countFileCacheFinds.init( LiteralStringRef("AsyncFile.CountFileCacheFinds"), filename);
|
||||
countFileCacheReadBytes.init( LiteralStringRef("AsyncFile.CountFileCacheReadBytes"), filename);
|
||||
countFileCacheFinds.init(LiteralStringRef("AsyncFile.CountFileCacheFinds"), filename);
|
||||
countFileCacheReadBytes.init(LiteralStringRef("AsyncFile.CountFileCacheReadBytes"), filename);
|
||||
|
||||
countCacheWrites.init( LiteralStringRef("AsyncFile.CountCacheWrites"));
|
||||
countCacheReads.init( LiteralStringRef("AsyncFile.CountCacheReads"));
|
||||
countCacheWritesBlocked.init( LiteralStringRef("AsyncFile.CountCacheWritesBlocked"));
|
||||
countCacheReadsBlocked.init( LiteralStringRef("AsyncFile.CountCacheReadsBlocked"));
|
||||
countCacheWrites.init(LiteralStringRef("AsyncFile.CountCacheWrites"));
|
||||
countCacheReads.init(LiteralStringRef("AsyncFile.CountCacheReads"));
|
||||
countCacheWritesBlocked.init(LiteralStringRef("AsyncFile.CountCacheWritesBlocked"));
|
||||
countCacheReadsBlocked.init(LiteralStringRef("AsyncFile.CountCacheReadsBlocked"));
|
||||
countCachePageReadsHit.init(LiteralStringRef("AsyncFile.CountCachePageReadsHit"));
|
||||
countCachePageReadsMissed.init(LiteralStringRef("AsyncFile.CountCachePageReadsMissed"));
|
||||
countCachePageReadsMerged.init(LiteralStringRef("AsyncFile.CountCachePageReadsMerged"));
|
||||
countCacheFinds.init( LiteralStringRef("AsyncFile.CountCacheFinds"));
|
||||
countCacheReadBytes.init( LiteralStringRef("AsyncFile.CountCacheReadBytes"));
|
||||
|
||||
countCacheFinds.init(LiteralStringRef("AsyncFile.CountCacheFinds"));
|
||||
countCacheReadBytes.init(LiteralStringRef("AsyncFile.CountCacheReadBytes"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -387,11 +388,18 @@ struct AFCPage : public EvictablePage, public FastAllocated<AFCPage> {
|
|||
|
||||
// If there are no active readers then if data is valid or we're replacing all of it we can write directly
|
||||
if (valid || fullPage) {
|
||||
if(!fullPage) {
|
||||
++owner->countFileCachePageReadsHit;
|
||||
++owner->countCachePageReadsHit;
|
||||
}
|
||||
valid = true;
|
||||
memcpy( static_cast<uint8_t*>(this->data) + offset, data, length );
|
||||
return yield();
|
||||
}
|
||||
|
||||
++owner->countFileCachePageReadsMissed;
|
||||
++owner->countCachePageReadsMissed;
|
||||
|
||||
// If data is not valid but no read is in progress, start reading
|
||||
if (notReading.isReady()) {
|
||||
notReading = readThrough( this );
|
||||
|
@ -410,7 +418,14 @@ struct AFCPage : public EvictablePage, public FastAllocated<AFCPage> {
|
|||
|
||||
Future<Void> readZeroCopy() {
|
||||
++zeroCopyRefCount;
|
||||
if (valid) return yield();
|
||||
if (valid) {
|
||||
++owner->countFileCachePageReadsHit;
|
||||
++owner->countCachePageReadsHit;
|
||||
return yield();
|
||||
}
|
||||
|
||||
++owner->countFileCachePageReadsMissed;
|
||||
++owner->countCachePageReadsMissed;
|
||||
|
||||
if (notReading.isReady()) {
|
||||
notReading = readThrough( this );
|
||||
|
@ -428,12 +443,17 @@ struct AFCPage : public EvictablePage, public FastAllocated<AFCPage> {
|
|||
|
||||
Future<Void> read( void* data, int length, int offset ) {
|
||||
if (valid) {
|
||||
++owner->countFileCachePageReadsHit;
|
||||
++owner->countCachePageReadsHit;
|
||||
owner->countFileCacheReadBytes += length;
|
||||
owner->countCacheReadBytes += length;
|
||||
memcpy( data, static_cast<uint8_t const*>(this->data) + offset, length );
|
||||
return yield();
|
||||
}
|
||||
|
||||
++owner->countFileCachePageReadsMissed;
|
||||
++owner->countCachePageReadsMissed;
|
||||
|
||||
if (notReading.isReady()) {
|
||||
notReading = readThrough( this );
|
||||
} else {
|
||||
|
|
|
@ -1578,6 +1578,68 @@ ACTOR static Future<JsonBuilderObject> workloadStatusFetcher(Reference<AsyncVar<
|
|||
return statusObj;
|
||||
}
|
||||
|
||||
ACTOR static Future<JsonBuilderObject> clusterSummaryStatisticsFetcher(WorkerEvents pMetrics, Future<ErrorOr<vector<std::pair<StorageServerInterface, EventMap>>>> storageServerFuture,
|
||||
Future<ErrorOr<vector<std::pair<TLogInterface, EventMap>>>> tlogFuture, std::set<std::string> *incomplete_reasons)
|
||||
{
|
||||
state JsonBuilderObject statusObj;
|
||||
try {
|
||||
state JsonBuilderObject cacheStatistics;
|
||||
|
||||
ErrorOr<vector<std::pair<StorageServerInterface, EventMap>>> storageServers = wait(storageServerFuture);
|
||||
|
||||
if (!storageServers.present()) {
|
||||
throw storageServers.getError();
|
||||
}
|
||||
|
||||
double storageCacheHitsHz = 0;
|
||||
double storageCacheMissesHz = 0;
|
||||
|
||||
for(auto &ss : storageServers.get()) {
|
||||
auto processMetrics = pMetrics.find(ss.first.address());
|
||||
if(processMetrics != pMetrics.end()) {
|
||||
int64_t hits = processMetrics->second.getInt64("CacheHits");
|
||||
int64_t misses = processMetrics->second.getInt64("CacheMisses");
|
||||
double elapsed = processMetrics->second.getDouble("Elapsed");
|
||||
storageCacheHitsHz += hits / elapsed;
|
||||
storageCacheMissesHz += misses / elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
cacheStatistics["storage_hit_rate"] = (storageCacheMissesHz == 0) ? 1.0 : storageCacheHitsHz / (storageCacheHitsHz + storageCacheMissesHz);
|
||||
|
||||
ErrorOr<vector<std::pair<TLogInterface, EventMap>>> tlogServers = wait(tlogFuture);
|
||||
|
||||
if(!tlogServers.present()) {
|
||||
throw tlogServers.getError();
|
||||
}
|
||||
|
||||
double logCacheHitsHz = 0;
|
||||
double logCacheMissesHz = 0;
|
||||
|
||||
for(auto &log : tlogServers.get()) {
|
||||
auto processMetrics = pMetrics.find(log.first.address());
|
||||
if(processMetrics != pMetrics.end()) {
|
||||
int64_t hits = processMetrics->second.getInt64("CacheHits");
|
||||
int64_t misses = processMetrics->second.getInt64("CacheMisses");
|
||||
double elapsed = processMetrics->second.getDouble("Elapsed");
|
||||
logCacheHitsHz += hits / elapsed;
|
||||
logCacheMissesHz += misses / elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
cacheStatistics["log_hit_rate"] = (logCacheMissesHz == 0) ? 1.0 : logCacheHitsHz / (logCacheHitsHz + logCacheMissesHz);
|
||||
statusObj["page_cache"] = cacheStatistics;
|
||||
}
|
||||
catch (Error& e) {
|
||||
if (e.code() == error_code_actor_cancelled)
|
||||
throw;
|
||||
|
||||
incomplete_reasons->insert("Unknown cache statistics.");
|
||||
}
|
||||
|
||||
return statusObj;
|
||||
}
|
||||
|
||||
static JsonBuilderArray oldTlogFetcher(int* oldLogFaultTolerance, Reference<AsyncVar<struct ServerDBInfo>> db, std::unordered_map<NetworkAddress, WorkerInterface> const& address_workers) {
|
||||
JsonBuilderArray oldTlogsArray;
|
||||
|
||||
|
@ -2025,6 +2087,7 @@ ACTOR Future<StatusReply> clusterGetStatus(
|
|||
futures2.push_back(workloadStatusFetcher(db, workers, mWorker, rkWorker, &qos, &data_overlay, &status_incomplete_reasons, storageServerFuture));
|
||||
futures2.push_back(layerStatusFetcher(cx, &messages, &status_incomplete_reasons));
|
||||
futures2.push_back(lockedStatusFetcher(db, &messages, &status_incomplete_reasons));
|
||||
futures2.push_back(clusterSummaryStatisticsFetcher(pMetrics, storageServerFuture, tLogFuture, &status_incomplete_reasons));
|
||||
|
||||
state std::vector<JsonBuilderObject> workerStatuses = wait(getAll(futures2));
|
||||
|
||||
|
@ -2069,6 +2132,11 @@ ACTOR Future<StatusReply> clusterGetStatus(
|
|||
statusObj.addContents(workerStatuses[3]);
|
||||
}
|
||||
|
||||
// Insert cluster summary statistics
|
||||
if(!workerStatuses[4].empty()) {
|
||||
statusObj.addContents(workerStatuses[4]);
|
||||
}
|
||||
|
||||
// Need storage servers now for processStatusFetcher() below.
|
||||
ErrorOr<vector<std::pair<StorageServerInterface, EventMap>>> _storageServers = wait(storageServerFuture);
|
||||
if (_storageServers.present()) {
|
||||
|
|
|
@ -124,8 +124,8 @@ struct NetworkData {
|
|||
countFileCachePageReadsMerged = getValue(LiteralStringRef("AsyncFile.CountCachePageReadsMerged"));
|
||||
countFileCacheFinds = getValue(LiteralStringRef("AsyncFile.CountCacheFinds"));
|
||||
countFileCacheReadBytes = getValue(LiteralStringRef("AsyncFile.CountCacheReadBytes"));
|
||||
countFilePageCacheHits = getValue(LiteralStringRef("EvictablePageCache.CacheHits"));
|
||||
countFilePageCacheMisses = getValue(LiteralStringRef("EvictablePageCache.CacheMisses"));
|
||||
countFilePageCacheHits = getValue(LiteralStringRef("AsyncFile.CountCachePageReadsHit"));
|
||||
countFilePageCacheMisses = getValue(LiteralStringRef("AsyncFile.CountCachePageReadsMissed"));
|
||||
countFilePageCacheEvictions = getValue(LiteralStringRef("EvictablePageCache.CacheEvictions"));
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue