Back to all questions

How to Calculate the Cache Hit Ratio?

Edward Tsinovoi
Cache Hit Ratio
March 29, 2024

The formula for calculating cache hit ratio is:

Cache Hit Ratio = (Number of Cache Hits / Total Number of Requests) * 100

Here is how we can find these values, and calculate it as accurately as possible:

Step #1: Count the Cache Hits

A cache hit occurs when the data requested by the computing process is already present in the cache memory, eliminating the need to retrieve it from slower, primary storage. To count cache hits:

  • Implement monitoring on the system to log every request made for data.
  • For each request, check if the requested data is found in the cache.
  • Every time a request is fulfilled directly from the cache, increment a "cache hit" counter.
  • Depending on the system, use built-in tools, cache management software, or custom scripts to automate the counting and logging of cache hits.
  • Decide on a specific time frame for analysis, such as a day or during a particular operation, to ensure consistency in your measurements.

Step #2: Count the Cache Misses

A cache miss happens when the requested data is not found in the cache, necessitating a fetch from the slower main storage. To count cache misses:

  • Similar to monitoring hits, you also need to log every instance where the system fails to find the requested data in the cache.
  • Each time the system has to retrieve data from a slower storage tier due to its absence in the cache, increment a "cache miss" counter.
  • Use cache management tools or develop scripts that can differentiate between cache hits and misses and log them accordingly. 
  • Ensure that the counting of cache misses is done over the same period or set of operations as the cache hits to maintain accuracy in comparison.

Step #3: Calculate the Cache Hit Ratio

With the counts of both cache hits and misses, you can use the following cache hit rate formula to calculate the cache hit ratio:

Cache Hit Ratio = (Number of Cache Hits / Total Number of Requests) × 100

Here, the Total Number of Requests is the sum of the cache hits and cache misses. This calculation provides the efficiency of the cache as a percentage, offering insight into how well the cache is performing. 

High cache hit ratios indicate effective caching strategies, leading to faster data access times and improved overall system performance.

Optional Step: Scripting

This is when you make the computer do your bidding, and can vary depending on your unique hardware and infrastructure. Here is a simulated example of how it might look as a piece of code. 

#include <iostream>


    #include <unordered_map>
   
    #include <list>
   
    class LRUCache {
      int capacity;
      std::list < int > recentList; // Stores keys of cache in order of recency
      std::unordered_map < int, std::pair < int, std::list < int > ::iterator >> cache; // Maps keys to pairs of values and iterators pointing to the keys' positions in recentList
   
      public:
        LRUCache(int capacity): capacity(capacity) {}
   
      int get(int key) {
        auto found = cache.find(key);
        if (found == cache.end()) {
          std::cout << "Cache miss for key " << key << std::endl;
          return -1; // Simulate cache miss
        }
   
        // Move the accessed key to the front (most recent position) of the list
        recentList.erase(found -> second.second);
        recentList.push_front(key);
        found -> second.second = recentList.begin();
   
        std::cout << "Cache hit for key " << key << std::endl;
        return found -> second.first; // Return the found value
      }
   
      void put(int key, int value) {
        auto found = cache.find(key);
   
        if (found != cache.end()) {
          // Update existing entry and move it to the most recent position
          recentList.erase(found -> second.second);
          recentList.push_front(key);
          cache[key] = {
            value,
            recentList.begin()
          };
        } else {
          if (cache.size() == capacity) {
            // Evict the least recently used (LRU) item
            int lru = recentList.back();
            recentList.pop_back();
            cache.erase(lru);
            std::cout << "Evicting key " << lru << std::endl;
          }
   
          // Insert new item as most recent
          recentList.push_front(key);
          cache[key] = {
            value,
            recentList.begin()
          };
        }
      }
    };
   
    int main() {
      LRUCache cache(2); // Small cache for demonstration
   
      cache.put(1, 10);
      cache.put(2, 20);
      std::cout << "Get 1: " << cache.get(1) << std::endl; // Cache hit
      cache.put(3, 30); // Causes eviction of key 2 (LRU)
      std::cout << "Get 2: " << cache.get(2) << std::endl; // Cache miss
   
      return 0;
    }

Note how the inputs here are being assumed. In a realistic scenario, you would either have, or will have (the usual case) to develop (for custom hardwares) APIs to catch these hits.