{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "71f85f2a-423f-44d2-b80d-da9ac8d3961a", "metadata": {}, "outputs": [], "source": [ "import simpy\n", "import random\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import pandas as pd\n", "from enum import Enum\n", "import os\n", "import shutil\n", "from tqdm import tqdm\n", "import math\n", "\n", "# Types of cache\n", "class CacheType(Enum):\n", " LRU = 1\n", " RANDOM_EVICTION = 2\n", " TTL = 3\n", "\n", "# Constants\n", "SEED = 42\n", "DATABASE_OBJECTS = 100 # Number of objects in the database\n", "ACCESS_COUNT_LIMIT = 100 # Total time to run the simulation\n", "EXPERIMENT_BASE_DIR = \"./experiments/\"\n", "TEMP_BASE_DIR = \"./.aoi_cache/\"\n", "\n", "ZIPF_CONSTANT = 2 # Shape parameter for the Zipf distribution (controls skewness) Needs to be: 1< \n", "\n", "# Set random seeds\n", "random.seed(SEED)\n", "np.random.seed(SEED)\n", "\n", "os.makedirs(TEMP_BASE_DIR, exist_ok=True)" ] }, { "cell_type": "markdown", "id": "9a37d7a3-3e11-4b89-8dce-6091dd38b16f", "metadata": {}, "source": [ "How to set certain parameters for specific scenarios\n", "\n", "\n", "| Name | Cache Capacity | MAX_REFRESH_RATE | cache_type | CACHE_TTL |\n", "| -------------------- | -------------------- | ---------------- | ------------------------- | --------- |\n", "| Default | DATABASE_OBJECTS | 1< | CacheType.LRU | 5 |\n", "| No Refresh | DATABASE_OBJECTS | 0 | CacheType.LRU | 5 |\n", "| Infinite TTL | DATABASE_OBJECTS / 2 | 0 | CacheType.LRU | 0 |\n", "| Random Eviction (RE) | DATABASE_OBJECTS / 2 | 1< | CacheType.RANDOM_EVICTION | 5 |\n", "| RE without Refresh | DATABASE_OBJECTS / 2 | 0 | CacheType.RANDOM_EVICTION | 5 |\n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "3d0ab5b1-162a-42c8-80a3-d31f763101f1", "metadata": {}, "outputs": [], "source": [ "# Configuration (Just example, will be overwritten in next block\n", "CACHE_CAPACITY = DATABASE_OBJECTS # Maximum number of objects the cache can hold\n", "\n", "# MAX_REFRESH_RATE is used as the maximum for a uniform\n", "# distribution for mu.\n", "# If MAX_REFRESH_RATE is 0, we do not do any refreshes.\n", "MAX_REFRESH_RATE = 0\n", "\n", "cache_type = CacheType.LRU\n", "\n", "# CACHE_TTL is used to determin which TTL to set when an\n", "# object is pulled into the cache\n", "# If CACHE_TTL is set to 0, the TTL is infinite\n", "CACHE_TTL = 5\n" ] }, { "cell_type": "code", "execution_count": 3, "id": "3ff299ca-ec65-453b-b167-9a0f7728a207", "metadata": {}, "outputs": [], "source": [ "configurations = {\n", " \"default\": (DATABASE_OBJECTS, 10, CacheType.LRU, 5),\n", " \"No Refresh\": (DATABASE_OBJECTS, 0, CacheType.LRU, 5),\n", " \"Infinite TTL\": (int(DATABASE_OBJECTS / 2), 0, CacheType.LRU, 0),\n", " \"Random Eviction\": (int(DATABASE_OBJECTS / 2), 10, CacheType.RANDOM_EVICTION, 5),\n", " \"RE without Refresh\": (int(DATABASE_OBJECTS / 2), 0, CacheType.RANDOM_EVICTION, 5),\n", " \"No Refresh (0.5s ttl)\": (DATABASE_OBJECTS, 0, CacheType.TTL, 0.5),\n", " \"No Refresh (1.0s ttl)\": (DATABASE_OBJECTS, 0, CacheType.TTL, 1),\n", " \"No Refresh (2.0s ttl)\": (DATABASE_OBJECTS, 0, CacheType.TTL, 2),\n", " \"No Refresh (3.0s ttl)\": (DATABASE_OBJECTS, 0, CacheType.TTL, 3),\n", " \"No Refresh (4.0s ttl)\": (DATABASE_OBJECTS, 0, CacheType.TTL, 4),\n", " \"No Refresh (5.0s ttl)\": (DATABASE_OBJECTS, 0, CacheType.TTL, 5),\n", "}\n", "\n", "experiment_name = \"No Refresh (0.5s ttl)\"\n", "config = configurations[experiment_name]\n", "\n", "CACHE_CAPACITY = config[0]\n", "MAX_REFRESH_RATE = config[1]\n", "cache_type = config[2]\n", "CACHE_TTL = config[3]\n", "\n", "if cache_type == CacheType.TTL:\n", " assert CACHE_TTL > 0, \"Needs CACHE_TTL to be greater than 0 when using TTL-Cache.\"\n", " assert CACHE_CAPACITY >= DATABASE_OBJECTS, \"Cache Size needs to be greater or equal to the amount of Database Objects.\"" ] }, { "cell_type": "code", "execution_count": 4, "id": "5cea042f-e9fc-4a1e-9750-de212ca70601", "metadata": {}, "outputs": [], "source": [ "class Database:\n", " def __init__(self):\n", " # Each object now has a specific refresh rate 'mu'\n", " self.data = {i: f\"Object {i}\" for i in range(1, DATABASE_OBJECTS + 1)}\n", " self.lambda_values = {i: np.random.zipf(ZIPF_CONSTANT) for i in range(1, DATABASE_OBJECTS + 1)} # Request rate 'lambda' for each object\n", " # Refresh rate 'mu' for each object\n", " if MAX_REFRESH_RATE == 0:\n", " self.mu_values = {i: 0 for i in range(1,DATABASE_OBJECTS + 1)} \n", " else:\n", " self.mu_values = {i: np.random.uniform(1, MAX_REFRESH_RATE) for i in range(1, DATABASE_OBJECTS + 1)}\n", " self.next_request = {i: np.random.exponential(1/self.lambda_values[i]) for i in range(1, DATABASE_OBJECTS + 1)}\n", "\n", "\n", " def get_object(self, obj_id):\n", " # print(f\"[{env.now:.2f}] Database: Fetched {self.data.get(obj_id, 'Unknown')} for ID {obj_id}\")\n", " return self.data.get(obj_id, None)" ] }, { "cell_type": "code", "execution_count": 5, "id": "499bf543-b2c6-4e4d-afcc-0a6665ce3ae1", "metadata": {}, "outputs": [], "source": [ "class Cache:\n", " def __init__(self, env, db, cache_type):\n", " self.cache_type = cache_type\n", " self.env = env\n", " self.db = db\n", " self.storage = {} # Dictionary to store cached objects\n", " self.ttl = {} # Dictionary to store TTLs\n", " self.initial_fetch = {} # Dictionary to store when an object was fetched from the databse to determine the age\n", " self.cache_size_over_time = [] # To record cache state at each interval\n", " self.cache_next_request_over_time = []\n", " self.request_log = {i: [] for i in range(1, DATABASE_OBJECTS + 1)}\n", " self.hits = {i: 0 for i in range(1, DATABASE_OBJECTS + 1)} # Track hits per object\n", " self.misses = {i: 0 for i in range(1, DATABASE_OBJECTS + 1)} # Track misses per object\n", " self.cumulative_age = {i: 0 for i in range(1, DATABASE_OBJECTS + 1)} # Track cumulative age per object\n", " self.access_count = {i: 0 for i in range(1, DATABASE_OBJECTS + 1)} # Track access count per object\n", " self.next_refresh = {} # Track the next refresh time for each cached object\n", " self.object_start_time = {} # Used as helper variable to determine the starting time of an object in the cache\n", " self.cumulative_cache_time = {i: 0 for i in range(1, DATABASE_OBJECTS + 1)} # Stores the cumulative time the object has spent between its eviction and when it was first pulled into the cache\n", " \n", " def get(self, obj_id):\n", " if obj_id in self.storage:\n", " # Cache hit: Refresh TTL if TTL-Cache\n", " if self.cache_type == CacheType.TTL:\n", " if self.ttl[obj_id] > env.now:\n", " self.ttl[obj_id] = env.now + CACHE_TTL\n", " \n", " # Cache hit: increment hit count and update cumulative age\n", " self.hits[obj_id] += 1\n", " self.access_count[obj_id] += 1\n", " \n", " self.cumulative_age[obj_id] += (env.now - self.initial_fetch[obj_id])\n", "\n", " # Cache hit: Refresh database object on hit\n", " # self.initial_fetch[obj_id] = env.now\n", " else:\n", " assert obj_id not in self.storage.keys(), \"Found object in cache on miss.\"\n", " assert obj_id not in self.initial_fetch.keys(), \"Found age timer on miss.\"\n", " assert obj_id not in self.object_start_time.keys(), \"Found cache time ratio timer on miss.\"\n", " # Cache miss: Add TTL if TTL-Cache\n", " # When full cache: If non-TTL-Cache: Evict. If TTL-Cache: Don't add to Cache.\n", " if self.cache_type == CacheType.TTL:\n", " assert obj_id not in self.ttl.keys(), \"Found cache time ratio timer on miss.\"\n", " self.ttl[obj_id] = env.now + CACHE_TTL\n", " else:\n", " if len(self.storage) == DATABASE_OBJECTS:\n", " if self.cache_type == CacheType.LRU:\n", " self.evict_oldest()\n", " elif self.cache_type == CacheType.RANDOM_EVICTION:\n", " self.evict_random()\n", " elif self.cache-type == CacheType.TTL:\n", " return\n", " \n", " # Cache miss: increment miss count\n", " self.misses[obj_id] += 1\n", " self.access_count[obj_id] += 1\n", " \n", " # Cache miss: Fetch the object from the database\n", " self.storage[obj_id] = self.db.get_object(obj_id)\n", " self.object_start_time[obj_id] = env.now\n", " \n", " self.initial_fetch[obj_id] = env.now\n", " self.cumulative_age[obj_id] += (env.now - self.initial_fetch[obj_id])\n", " \n", " if MAX_REFRESH_RATE != 0:\n", " self.next_refresh[obj_id] = env.now + np.random.exponential(1/self.db.mu_values[obj_id]) # Schedule refresh\n", " \n", " def evict_oldest(self):\n", " \"\"\"Remove the oldest item from the cache to make space.\"\"\"\n", " oldest_id = min(self.initial_fetch, key=self.initial_fetch.get) # Find the oldest item by age\n", " print(f\"[{env.now:.2f}] Cache: Evicting oldest object {oldest_id} to make space at {self.ttl[oldest_id]:.2f}\")\n", " self.cumulative_cache_time[obj_id] += (env.now - self.object_start_time[obj_id])\n", " del self.storage[oldest_id]\n", " del self.initial_fetch[oldest_id]\n", " del self.object_start_time[obj_id]\n", "\n", " def evict_random(self):\n", " \"\"\"Remove a random item from the cache to make space.\"\"\"\n", " random_id = np.random.choice(list(self.storage.keys())) # Select a random key from the cache\n", " print(f\"[{env.now:.2f}] Cache: Evicting random object {random_id} to make space at {self.ttl[random_id]:.2f}\")\n", " self.cumulative_cache_time[obj_id] += (env.now - self.object_start_time[obj_id])\n", " del self.storage[random_id]\n", " del self.initial_fetch[random_id]\n", " del self.object_start_time[obj_id]\n", " \n", " def refresh_object(self, obj_id):\n", " \"\"\"Refresh the object from the database to keep it up-to-date. TTL is increased on refresh.\"\"\"\n", " obj = self.db.get_object(obj_id)\n", " self.storage[obj_id] = obj\n", " if self.cache_type == CacheType.TTL:\n", " self.ttl[obj_id] = env.now + CACHE_TTL\n", " self.cumulative_cache_time[obj_id] += (env.now - self.object_start_time[obj_id])\n", " # print(f\"[{env.now:.2f}] Cache: Refreshed object {obj_id}\")\n", " \n", " def check_expired(self):\n", " \"\"\"Increment age of each cached object.\"\"\"\n", " if self.cache_type == CacheType.TTL:\n", " for obj_id in list(self.ttl.keys()):\n", " if self.ttl[obj_id] <= env.now:\n", " # Remove object if its TTL expired\n", " # print(f\"[{env.now:.2f}] Cache: Object {obj_id} expired\")\n", " self.cumulative_cache_time[obj_id] += (env.now - self.object_start_time[obj_id])\n", " del self.storage[obj_id]\n", " del self.ttl[obj_id]\n", " del self.initial_fetch[obj_id]\n", " del self.object_start_time[obj_id]\n", "\n", " \n", " def record_cache_state(self):\n", " \"\"\"Record the current cache state (number of objects in cache) over time.\"\"\"\n", " self.cache_size_over_time.append((env.now, len(self.storage)))\n", " self.cache_next_request_over_time.append((env.now, self.db.next_request.copy()))" ] }, { "cell_type": "code", "execution_count": 6, "id": "7286d498-aa6c-4efb-bb28-fe29736eab64", "metadata": {}, "outputs": [], "source": [ "def age_cache_process(env, cache):\n", " \"\"\"Process that ages cache objects over time, removes expired items, and refreshes based on object-specific intervals.\"\"\"\n", " while True:\n", " if cache.cache_type == CacheType.TTL:\n", " cache.check_expired() # Remove expired objects\n", "\n", " if MAX_REFRESH_RATE != 0:\n", " # Refresh objects based on their individual refresh intervals\n", " for obj_id in list(cache.storage.keys()):\n", " # Check if it's time to refresh this object based on next_refresh\n", " if env.now >= cache.next_refresh[obj_id]:\n", " cache.refresh_object(obj_id)\n", " # Schedule the next refresh based on the object's mu\n", " cache.next_refresh[obj_id] = env.now + np.random.exponential(1/cache.db.mu_values[obj_id])\n", " \n", " cache.record_cache_state() # Record cache state at each time step\n", " yield env.timeout(0.05) # Run every second" ] }, { "cell_type": "code", "execution_count": 7, "id": "687f5634-8edf-4337-b42f-bbb292d47f0f", "metadata": {}, "outputs": [], "source": [ "def client_request_process(env, cache, event):\n", " \"\"\"Client process that makes requests for objects from the cache.\"\"\"\n", " last_print = 0\n", " with tqdm(total=ACCESS_COUNT_LIMIT, desc=\"Progress\", leave=True) as pbar:\n", " while True:\n", " obj_id, next_request = min(cache.db.next_request.items(), key=lambda x: x[1])\n", " yield env.timeout(next_request - env.now)\n", "\n", " # For progress bar\n", " if (int(env.now) % 1) == 0 and int(env.now) != last_print:\n", " last_print = int(env.now)\n", " pbar.n = min(cache.access_count.values())\n", " pbar.refresh()\n", " \n", " if env.now >= next_request:\n", " # print(f\"[{env.now:.2f}] Client: Requesting object {obj_id}\")\n", " cache.get(obj_id)\n", " \n", " # print(f\"[{env.now:.2f}] Client: Schedule next request for {obj_id}\")\n", " next_request = env.now + np.random.exponential(1/cache.db.lambda_values[obj_id])\n", " cache.request_log[obj_id].append(next_request)\n", " cache.db.next_request[obj_id] = next_request\n", " \n", " # Simulation stop condition\n", " if all(access_count >= ACCESS_COUNT_LIMIT for access_count in cache.access_count.values()):\n", " print(f\"Simulation ended after {env.now} seconds.\")\n", " for obj_id in cache.storage.keys():\n", " cache.cumulative_cache_time[obj_id] += (env.now - cache.object_start_time[obj_id])\n", " event.succeed()" ] }, { "cell_type": "code", "execution_count": 8, "id": "c8516830-9880-4d9e-a91b-000338baf9d6", "metadata": { "scrolled": true }, "outputs": [], "source": [ "# Initialize simulation environment\n", "env = simpy.Environment()\n", "\n", "# Instantiate components\n", "db = Database()\n", "cache = Cache(env, db, cache_type)\n", "stop_event = env.event()" ] }, { "cell_type": "code", "execution_count": 9, "id": "2ba34b36-9ed5-4996-9600-11dfd25d8e60", "metadata": { "scrolled": true }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Progress: 99%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▋ | 99/100 [00:00<00:00, 158.42it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Simulation ended after 123.41758277479552 seconds.\n", "CPU times: user 550 ms, sys: 98.6 ms, total: 648 ms\n", "Wall time: 632 ms\n" ] } ], "source": [ "%%time\n", "\n", "# Start processes\n", "env.process(age_cache_process(env, cache))\n", "env.process(client_request_process(env, cache, stop_event))\n", "\n", "# Run the simulation\n", "env.run(until=stop_event)\n", "simulation_end_time = env.now" ] }, { "cell_type": "code", "execution_count": 10, "id": "3b6f7c1f-ea54-4496-bb9a-370cee2d2751", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Object 1: Hit Rate = 0.39, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.40, Average Age = 0.15, Expected Age = 0.08\n", "Object 2: Hit Rate = 0.80, Expected Hit Rate = 0.78, Average Time spend in Cache: 0.80, Average Age = 0.73, Expected Age = 0.32\n", "Object 3: Hit Rate = 0.37, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.44, Average Age = 0.16, Expected Age = 0.07\n", "Object 4: Hit Rate = 0.37, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.39, Average Age = 0.15, Expected Age = 0.07\n", "Object 5: Hit Rate = 0.60, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.63, Average Age = 0.29, Expected Age = 0.18\n", "Object 6: Hit Rate = 0.38, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.39, Average Age = 0.12, Expected Age = 0.07\n", "Object 7: Hit Rate = 0.93, Expected Hit Rate = 0.92, Average Time spend in Cache: 0.94, Average Age = 2.35, Expected Age = 0.43\n", "Object 8: Hit Rate = 0.41, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.41, Average Age = 0.19, Expected Age = 0.09\n", "Object 9: Hit Rate = 0.36, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.38, Average Age = 0.10, Expected Age = 0.06\n", "Object 10: Hit Rate = 0.37, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.38, Average Age = 0.14, Expected Age = 0.07\n", "Object 11: Hit Rate = 0.65, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.63, Average Age = 0.33, Expected Age = 0.21\n", "Object 12: Hit Rate = 0.45, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.41, Average Age = 0.17, Expected Age = 0.10\n", "Object 13: Hit Rate = 0.43, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.44, Average Age = 0.19, Expected Age = 0.09\n", "Object 14: Hit Rate = 0.33, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.41, Average Age = 0.10, Expected Age = 0.06\n", "Object 15: Hit Rate = 0.65, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.66, Average Age = 0.36, Expected Age = 0.21\n", "Object 16: Hit Rate = 0.62, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.62, Average Age = 0.38, Expected Age = 0.19\n", "Object 17: Hit Rate = 0.37, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.40, Average Age = 0.13, Expected Age = 0.07\n", "Object 18: Hit Rate = 0.38, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.39, Average Age = 0.14, Expected Age = 0.07\n", "Object 19: Hit Rate = 0.78, Expected Hit Rate = 0.78, Average Time spend in Cache: 0.76, Average Age = 0.60, Expected Age = 0.30\n", "Object 20: Hit Rate = 0.41, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.39, Average Age = 0.18, Expected Age = 0.08\n", "Object 21: Hit Rate = 0.46, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.42, Average Age = 0.19, Expected Age = 0.11\n", "Object 22: Hit Rate = 0.46, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.46, Average Age = 0.19, Expected Age = 0.10\n", "Object 23: Hit Rate = 0.42, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.45, Average Age = 0.15, Expected Age = 0.09\n", "Object 24: Hit Rate = 0.67, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.65, Average Age = 0.39, Expected Age = 0.23\n", "Object 25: Hit Rate = 0.37, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.40, Average Age = 0.11, Expected Age = 0.07\n", "Object 26: Hit Rate = 0.43, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.44, Average Age = 0.15, Expected Age = 0.09\n", "Object 27: Hit Rate = 0.42, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.41, Average Age = 0.16, Expected Age = 0.09\n", "Object 28: Hit Rate = 0.91, Expected Hit Rate = 0.92, Average Time spend in Cache: 0.91, Average Age = 1.78, Expected Age = 0.42\n", "Object 29: Hit Rate = 0.41, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.43, Average Age = 0.17, Expected Age = 0.08\n", "Object 30: Hit Rate = 0.46, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.39, Average Age = 0.20, Expected Age = 0.10\n", "Object 31: Hit Rate = 0.35, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.40, Average Age = 0.15, Expected Age = 0.06\n", "Object 32: Hit Rate = 0.85, Expected Hit Rate = 0.86, Average Time spend in Cache: 0.86, Average Age = 1.01, Expected Age = 0.37\n", "Object 33: Hit Rate = 0.37, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.39, Average Age = 0.15, Expected Age = 0.07\n", "Object 34: Hit Rate = 0.86, Expected Hit Rate = 0.86, Average Time spend in Cache: 0.86, Average Age = 0.91, Expected Age = 0.37\n", "Object 35: Hit Rate = 0.40, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.44, Average Age = 0.17, Expected Age = 0.08\n", "Object 36: Hit Rate = 0.32, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.34, Average Age = 0.09, Expected Age = 0.05\n", "Object 37: Hit Rate = 0.48, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.46, Average Age = 0.23, Expected Age = 0.11\n", "Object 38: Hit Rate = 0.75, Expected Hit Rate = 0.78, Average Time spend in Cache: 0.79, Average Age = 0.59, Expected Age = 0.28\n", "Object 39: Hit Rate = 0.98, Expected Hit Rate = 0.98, Average Time spend in Cache: 0.98, Average Age = 6.02, Expected Age = 0.48\n", "Object 40: Hit Rate = 0.45, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.40, Average Age = 0.18, Expected Age = 0.10\n", "Object 41: Hit Rate = 0.85, Expected Hit Rate = 0.86, Average Time spend in Cache: 0.87, Average Age = 0.97, Expected Age = 0.36\n", "Object 42: Hit Rate = 0.88, Expected Hit Rate = 0.86, Average Time spend in Cache: 0.87, Average Age = 1.44, Expected Age = 0.39\n", "Object 43: Hit Rate = 0.62, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.56, Average Age = 0.34, Expected Age = 0.19\n", "Object 44: Hit Rate = 0.31, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.39, Average Age = 0.08, Expected Age = 0.05\n", "Object 45: Hit Rate = 0.40, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.41, Average Age = 0.17, Expected Age = 0.08\n", "Object 46: Hit Rate = 0.47, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.42, Average Age = 0.20, Expected Age = 0.11\n", "Object 47: Hit Rate = 0.99, Expected Hit Rate = 0.99, Average Time spend in Cache: 0.99, Average Age = 15.52, Expected Age = 0.49\n", "Object 48: Hit Rate = 0.49, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.44, Average Age = 0.29, Expected Age = 0.12\n", "Object 49: Hit Rate = 0.51, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.43, Average Age = 0.23, Expected Age = 0.13\n", "Object 50: Hit Rate = 0.41, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.38, Average Age = 0.14, Expected Age = 0.08\n", "Object 51: Hit Rate = 0.91, Expected Hit Rate = 0.92, Average Time spend in Cache: 0.90, Average Age = 1.40, Expected Age = 0.41\n", "Object 52: Hit Rate = 0.99, Expected Hit Rate = 0.99, Average Time spend in Cache: 0.99, Average Age = 8.54, Expected Age = 0.49\n", "Object 53: Hit Rate = 0.34, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.42, Average Age = 0.13, Expected Age = 0.06\n", "Object 54: Hit Rate = 0.37, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.46, Average Age = 0.14, Expected Age = 0.07\n", "Object 55: Hit Rate = 0.43, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.42, Average Age = 0.26, Expected Age = 0.09\n", "Object 56: Hit Rate = 0.42, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.39, Average Age = 0.13, Expected Age = 0.09\n", "Object 57: Hit Rate = 0.35, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.41, Average Age = 0.09, Expected Age = 0.06\n", "Object 58: Hit Rate = 1.00, Expected Hit Rate = 1.00, Average Time spend in Cache: 1.00, Average Age = 25.12, Expected Age = 0.50\n", "Object 59: Hit Rate = 0.59, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.57, Average Age = 0.28, Expected Age = 0.17\n", "Object 60: Hit Rate = 0.43, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.43, Average Age = 0.21, Expected Age = 0.09\n", "Object 61: Hit Rate = 1.00, Expected Hit Rate = 1.00, Average Time spend in Cache: 1.00, Average Age = 62.77, Expected Age = 0.50\n", "Object 62: Hit Rate = 0.45, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.44, Average Age = 0.18, Expected Age = 0.10\n", "Object 63: Hit Rate = 0.38, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.38, Average Age = 0.15, Expected Age = 0.07\n", "Object 64: Hit Rate = 0.67, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.67, Average Age = 0.35, Expected Age = 0.22\n", "Object 65: Hit Rate = 0.45, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.43, Average Age = 0.17, Expected Age = 0.10\n", "Object 66: Hit Rate = 0.99, Expected Hit Rate = 0.99, Average Time spend in Cache: 0.99, Average Age = 15.37, Expected Age = 0.49\n", "Object 67: Hit Rate = 0.45, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.46, Average Age = 0.19, Expected Age = 0.10\n", "Object 68: Hit Rate = 1.00, Expected Hit Rate = 1.00, Average Time spend in Cache: 1.00, Average Age = 61.45, Expected Age = 0.50\n", "Object 69: Hit Rate = 0.37, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.38, Average Age = 0.12, Expected Age = 0.07\n", "Object 70: Hit Rate = 0.39, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.40, Average Age = 0.16, Expected Age = 0.08\n", "Object 71: Hit Rate = 0.66, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.62, Average Age = 0.47, Expected Age = 0.22\n", "Object 72: Hit Rate = 0.36, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.40, Average Age = 0.15, Expected Age = 0.06\n", "Object 73: Hit Rate = 0.42, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.43, Average Age = 0.18, Expected Age = 0.09\n", "Object 74: Hit Rate = 0.44, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.45, Average Age = 0.20, Expected Age = 0.10\n", "Object 75: Hit Rate = 0.78, Expected Hit Rate = 0.78, Average Time spend in Cache: 0.75, Average Age = 0.68, Expected Age = 0.30\n", "Object 76: Hit Rate = 0.65, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.65, Average Age = 0.40, Expected Age = 0.21\n", "Object 77: Hit Rate = 0.65, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.63, Average Age = 0.36, Expected Age = 0.21\n", "Object 78: Hit Rate = 0.80, Expected Hit Rate = 0.78, Average Time spend in Cache: 0.81, Average Age = 0.83, Expected Age = 0.32\n", "Object 79: Hit Rate = 1.00, Expected Hit Rate = 1.00, Average Time spend in Cache: 1.00, Average Age = 32.55, Expected Age = 0.50\n", "Object 80: Hit Rate = 0.33, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.40, Average Age = 0.11, Expected Age = 0.06\n", "Object 81: Hit Rate = 0.42, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.39, Average Age = 0.16, Expected Age = 0.09\n", "Object 82: Hit Rate = 0.92, Expected Hit Rate = 0.92, Average Time spend in Cache: 0.92, Average Age = 1.87, Expected Age = 0.42\n", "Object 83: Hit Rate = 0.65, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.65, Average Age = 0.36, Expected Age = 0.21\n", "Object 84: Hit Rate = 0.45, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.46, Average Age = 0.19, Expected Age = 0.10\n", "Object 85: Hit Rate = 0.35, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.36, Average Age = 0.11, Expected Age = 0.06\n", "Object 86: Hit Rate = 0.55, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.58, Average Age = 0.29, Expected Age = 0.15\n", "Object 87: Hit Rate = 0.50, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.41, Average Age = 0.26, Expected Age = 0.12\n", "Object 88: Hit Rate = 0.59, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.61, Average Age = 0.28, Expected Age = 0.18\n", "Object 89: Hit Rate = 0.44, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.43, Average Age = 0.18, Expected Age = 0.10\n", "Object 90: Hit Rate = 0.35, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.42, Average Age = 0.13, Expected Age = 0.06\n", "Object 91: Hit Rate = 0.63, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.63, Average Age = 0.31, Expected Age = 0.20\n", "Object 92: Hit Rate = 0.62, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.61, Average Age = 0.35, Expected Age = 0.19\n", "Object 93: Hit Rate = 0.80, Expected Hit Rate = 0.78, Average Time spend in Cache: 0.80, Average Age = 0.86, Expected Age = 0.32\n", "Object 94: Hit Rate = 0.38, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.41, Average Age = 0.15, Expected Age = 0.07\n", "Object 95: Hit Rate = 0.66, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.62, Average Age = 0.32, Expected Age = 0.22\n", "Object 96: Hit Rate = 0.40, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.43, Average Age = 0.13, Expected Age = 0.08\n", "Object 97: Hit Rate = 0.43, Expected Hit Rate = 0.39, Average Time spend in Cache: 0.41, Average Age = 0.19, Expected Age = 0.09\n", "Object 98: Hit Rate = 1.00, Expected Hit Rate = 1.00, Average Time spend in Cache: 1.00, Average Age = 62.04, Expected Age = 0.50\n", "Object 99: Hit Rate = 0.86, Expected Hit Rate = 0.86, Average Time spend in Cache: 0.87, Average Age = 0.96, Expected Age = 0.37\n", "Object 100: Hit Rate = 0.64, Expected Hit Rate = 0.63, Average Time spend in Cache: 0.61, Average Age = 0.31, Expected Age = 0.21\n" ] } ], "source": [ "statistics = []\n", "# Calculate and print hit rate and average age for each object\n", "for obj_id in range(1, DATABASE_OBJECTS + 1):\n", " if cache.access_count[obj_id] != 0:\n", " hit_rate = cache.hits[obj_id] / max(1, cache.access_count[obj_id]) # Avoid division by zero\n", " expected_hit_rate = 1-math.exp(-db.lambda_values[obj_id]*CACHE_TTL)\n", " avg_cache_time = cache.cumulative_cache_time[obj_id] / max(1, simulation_end_time) # Only average over hits\n", " avg_age = cache.cumulative_age[obj_id] / max(1, cache.access_count[obj_id])\n", " expected_age = pow(hit_rate,2) / 2\n", " print(f\"Object {obj_id}: Hit Rate = {hit_rate:.2f}, Expected Hit Rate = {expected_hit_rate:.2f}, Average Time spend in Cache: {avg_cache_time:.2f}, Average Age = {avg_age:.2f}, Expected Age = {expected_age:.2f}\")\n", " statistics.append({\"obj_id\": obj_id,\"hit_rate\": hit_rate, \"expected_hit_rate\": expected_hit_rate, \"avg_cache_time\":avg_cache_time, \"avg_age\": avg_age, \"expected_age\": expected_age})" ] }, { "cell_type": "code", "execution_count": 11, "id": "b2d18372-cdba-4151-ae32-5bf45466bf94", "metadata": {}, "outputs": [], "source": [ "stats = pd.DataFrame(statistics)\n", "stats.to_csv(f\"{TEMP_BASE_DIR}/hit_age.csv\",index=False)\n", "stats.drop(\"obj_id\", axis=1).describe().to_csv(f\"{TEMP_BASE_DIR}/overall_hit_age.csv\")" ] }, { "cell_type": "code", "execution_count": 12, "id": "80971714-44f1-47db-9e89-85be7c885bde", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
| \n", " | access_count | \n", "hits | \n", "misses | \n", "mu | \n", "lambda | \n", "hit_rate | \n", "expected_hit_rate | \n", "expected_hit_rate_delta | \n", "avg_cache_time | \n", "cache_time_delta | \n", "avg_age | \n", "expected_age | \n", "age_delta | \n", "
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | \n", "122 | \n", "48 | \n", "74 | \n", "0 | \n", "1 | \n", "0.393443 | \n", "0.393469 | \n", "-0.000027 | \n", "0.403492 | \n", "-0.010049 | \n", "0.152056 | \n", "0.077399 | \n", "0.074657 | \n", "
| 2 | \n", "382 | \n", "304 | \n", "78 | \n", "0 | \n", "3 | \n", "0.795812 | \n", "0.776870 | \n", "0.018942 | \n", "0.796822 | \n", "-0.001011 | \n", "0.725838 | \n", "0.316658 | \n", "0.409180 | \n", "
| 3 | \n", "127 | \n", "47 | \n", "80 | \n", "0 | \n", "1 | \n", "0.370079 | \n", "0.393469 | \n", "-0.023391 | \n", "0.439155 | \n", "-0.069076 | \n", "0.161354 | \n", "0.068479 | \n", "0.092875 | \n", "
| 4 | \n", "113 | \n", "42 | \n", "71 | \n", "0 | \n", "1 | \n", "0.371681 | \n", "0.393469 | \n", "-0.021788 | \n", "0.386356 | \n", "-0.014674 | \n", "0.146023 | \n", "0.069074 | \n", "0.076949 | \n", "
| 5 | \n", "244 | \n", "147 | \n", "97 | \n", "0 | \n", "2 | \n", "0.602459 | \n", "0.632121 | \n", "-0.029662 | \n", "0.628468 | \n", "-0.026009 | \n", "0.287673 | \n", "0.181478 | \n", "0.106195 | \n", "
| ... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
| 96 | \n", "139 | \n", "56 | \n", "83 | \n", "0 | \n", "1 | \n", "0.402878 | \n", "0.393469 | \n", "0.009408 | \n", "0.432752 | \n", "-0.029874 | \n", "0.126856 | \n", "0.081155 | \n", "0.045700 | \n", "
| 97 | \n", "127 | \n", "55 | \n", "72 | \n", "0 | \n", "1 | \n", "0.433071 | \n", "0.393469 | \n", "0.039602 | \n", "0.413172 | \n", "0.019899 | \n", "0.191692 | \n", "0.093775 | \n", "0.097917 | \n", "
| 98 | \n", "4578 | \n", "4577 | \n", "1 | \n", "0 | \n", "37 | \n", "0.999782 | \n", "1.000000 | \n", "-0.000218 | \n", "0.999689 | \n", "0.000092 | \n", "62.040629 | \n", "0.499782 | \n", "61.540847 | \n", "
| 99 | \n", "482 | \n", "415 | \n", "67 | \n", "0 | \n", "4 | \n", "0.860996 | \n", "0.864665 | \n", "-0.003669 | \n", "0.866371 | \n", "-0.005375 | \n", "0.959311 | \n", "0.370657 | \n", "0.588654 | \n", "
| 100 | \n", "249 | \n", "160 | \n", "89 | \n", "0 | \n", "2 | \n", "0.642570 | \n", "0.632121 | \n", "0.010450 | \n", "0.610462 | \n", "0.032108 | \n", "0.305314 | \n", "0.206448 | \n", "0.098866 | \n", "
100 rows × 13 columns
\n", "