class CacheStats: stats_list = [ "config_stats", "usage_stats", "inactive_usage_stats", "request_stats", "block_stats", "error_stats", ] def __init__(self, stats): try: self.config_stats = CacheConfigStats( stats["cache id"], stats["cache size"], stats["cache device"], stats["core devices"], stats["inactive core devices"], stats["write policy"], stats["eviction policy"], stats["cleaning policy"], stats["promotion policy"], stats["cache line size"], stats["metadata memory footprint"], stats["dirty for"], stats["metadata mode"], stats["status"], ) except KeyError: pass try: self.usage_stats = UsageStats( stats["occupancy"], stats["free"], stats["clean"], stats["dirty"] ) except KeyError: pass try: self.inactive_usage_stats = InactiveUsageStats( stats["inactive occupancy"], stats["inactive clean"], stats["inactive dirty"], ) except KeyError: pass try: self.request_stats = RequestStats( stats["read hits"], stats["read partial misses"], stats["read full misses"], stats["read total"], stats["write hits"], stats["write partial misses"], stats["write full misses"], stats["write total"], stats["pass-through reads"], stats["pass-through writes"], stats["serviced requests"], stats["total requests"], ) except KeyError: pass try: self.block_stats = BlockStats( stats["reads from core(s)"], stats["writes to core(s)"], stats["total to/from core(s)"], stats["reads from cache"], stats["writes to cache"], stats["total to/from cache"], stats["reads from exported object(s)"], stats["writes to exported object(s)"], stats["total to/from exported object(s)"], ) except KeyError: pass try: self.error_stats = ErrorStats( stats["cache read errors"], stats["cache write errors"], stats["cache total errors"], stats["core read errors"], stats["core write errors"], stats["core total errors"], stats["total errors"], ) except KeyError: pass def __str__(self): status = "" for stats_item in self.stats_list: current_stat = getattr(self, stats_item, None) if current_stat: status += f"--- Cache {current_stat}" return status def __eq__(self, other): if not other: return False for stats_item in self.stats_list: if getattr(self, stats_item, None) != getattr(other, stats_item, None): return False return True class CoreStats: stats_list = [ "config_stats", "usage_stats", "request_stats", "block_stats", "error_stats", ] def __init__(self, stats): try: self.config_stats = CoreConfigStats( stats["core id"], stats["core device"], stats["exported object"], stats["core size"], stats["dirty for"], stats["status"], stats["seq cutoff threshold"], stats["seq cutoff policy"], ) except KeyError: pass try: self.usage_stats = UsageStats( stats["occupancy"], stats["free"], stats["clean"], stats["dirty"] ) except KeyError: pass try: self.request_stats = RequestStats( stats["read hits"], stats["read partial misses"], stats["read full misses"], stats["read total"], stats["write hits"], stats["write partial misses"], stats["write full misses"], stats["write total"], stats["pass-through reads"], stats["pass-through writes"], stats["serviced requests"], stats["total requests"], ) except KeyError: pass try: self.block_stats = BlockStats( stats["reads from core"], stats["writes to core"], stats["total to/from core"], stats["reads from cache"], stats["writes to cache"], stats["total to/from cache"], stats["reads from exported object"], stats["writes to exported object"], stats["total to/from exported object"], ) except KeyError: pass try: self.error_stats = ErrorStats( stats["cache read errors"], stats["cache write errors"], stats["cache total errors"], stats["core read errors"], stats["core write errors"], stats["core total errors"], stats["total errors"], ) except KeyError: pass def __str__(self): status = "" for stats_item in self.stats_list: current_stat = getattr(self, stats_item, None) if current_stat: status += f"--- Core {current_stat}" return status def __eq__(self, other): if not other: return False for stats_item in self.stats_list: if getattr(self, stats_item, None) != getattr(other, stats_item, None): return False return True class IoClassStats: stats_list = ["config_stats", "usage_stats", "request_stats", "block_stats"] def __init__(self, stats): try: self.config_stats = IoClassConfigStats( stats["io class id"], stats["io class name"], stats["eviction priority"], stats["selective allocation"], ) except KeyError: pass try: self.usage_stats = UsageStats( stats["occupancy"], stats["free"], stats["clean"], stats["dirty"] ) except KeyError: pass try: self.request_stats = RequestStats( stats["read hits"], stats["read partial misses"], stats["read full misses"], stats["read total"], stats["write hits"], stats["write partial misses"], stats["write full misses"], stats["write total"], stats["pass-through reads"], stats["pass-through writes"], stats["serviced requests"], stats["total requests"], ) except KeyError: pass try: self.block_stats = BlockStats( stats["reads from core(s)"], stats["writes to core(s)"], stats["total to/from core(s)"], stats["reads from cache"], stats["writes to cache"], stats["total to/from cache"], stats["reads from exported object(s)"], stats["writes to exported object(s)"], stats["total to/from exported object(s)"], ) except KeyError: pass def __str__(self): status = "" for stats_item in self.stats_list: current_stat = getattr(self, stats_item, None) if current_stat: status += f"--- IO class {current_stat}" return status def __eq__(self, other): if not other: return False for stats_item in self.stats_list: if getattr(self, stats_item, None) != getattr(other, stats_item, None): return False return True class CacheConfigStats: def __init__( self, cache_id, cache_size, cache_dev, core_dev, inactive_core_dev, write_policy, eviction_policy, cleaning_policy, promotion_policy, cache_line_size, metadata_memory_footprint, dirty_for, metadata_mode, status, ): self.cache_id = cache_id self.cache_size = cache_size self.cache_dev = cache_dev self.core_dev = core_dev self.inactive_core_dev = inactive_core_dev self.write_policy = write_policy self.eviction_policy = eviction_policy self.cleaning_policy = cleaning_policy self.promotion_policy = promotion_policy self.cache_line_size = cache_line_size self.metadata_memory_footprint = metadata_memory_footprint self.dirty_for = dirty_for self.metadata_mode = metadata_mode self.status = status def __str__(self): return ( f"Config stats:\n" f"Cache ID: {self.cache_id}\n" f"Cache size: {self.cache_size}\n" f"Cache device: {self.cache_dev}\n" f"Core devices: {self.core_dev}\n" f"Inactive core devices: {self.inactive_core_dev}\n" f"Write policy: {self.write_policy}\n" f"Eviction policy: {self.eviction_policy}\n" f"Cleaning policy: {self.cleaning_policy}\n" f"Promotion policy: {self.promotion_policy}\n" f"Cache line size: {self.cache_line_size}\n" f"Metadata memory footprint: {self.metadata_memory_footprint}\n" f"Dirty for: {self.dirty_for}\n" f"Metadata mode: {self.metadata_mode}\n" f"Status: {self.status}\n" ) def __eq__(self, other): if not other: return False return ( self.cache_id == other.cache_id and self.cache_size == other.cache_size and self.cache_dev == other.cache_dev and self.core_dev == other.core_dev and self.inactive_core_dev == other.inactive_core_dev and self.write_policy == other.write_policy and self.eviction_policy == other.eviction_policy and self.cleaning_policy == other.cleaning_policy and self.promotion_policy == other.promotion_policy and self.cache_line_size == other.cache_line_size and self.metadata_memory_footprint == other.metadata_memory_footprint and self.dirty_for == other.dirty_for and self.metadata_mode == other.metadata_mode and self.status == other.status ) class CoreConfigStats: def __init__( self, core_id, core_dev, exp_obj, core_size, dirty_for, status, seq_cutoff_threshold, seq_cutoff_policy, ): self.core_id = core_id self.core_dev = core_dev self.exp_obj = exp_obj self.core_size = core_size self.dirty_for = dirty_for self.status = status self.seq_cutoff_threshold = seq_cutoff_threshold self.seq_cutoff_policy = seq_cutoff_policy def __str__(self): return ( f"Config stats:\n" f"Core ID: {self.core_id}\n" f"Core device: {self.core_dev}\n" f"Exported object: {self.exp_obj}\n" f"Core size: {self.core_size}\n" f"Dirty for: {self.dirty_for}\n" f"Status: {self.status}\n" f"Seq cutoff threshold: {self.seq_cutoff_threshold}\n" f"Seq cutoff policy: {self.seq_cutoff_policy}\n" ) def __eq__(self, other): if not other: return False return ( self.core_id == other.core_id and self.core_dev == other.core_dev and self.exp_obj == other.exp_obj and self.core_size == other.core_size and self.dirty_for == other.dirty_for and self.status == other.status and self.seq_cutoff_threshold == other.seq_cutoff_threshold and self.seq_cutoff_policy == other.seq_cutoff_policy ) class IoClassConfigStats: def __init__( self, io_class_id, io_class_name, eviction_priority, selective_allocation ): self.io_class_id = io_class_id self.io_class_name = io_class_name self.eviction_priority = eviction_priority self.selective_allocation = selective_allocation def __str__(self): return ( f"Config stats:\n" f"IO class ID: {self.io_class_id}\n" f"IO class name: {self.io_class_name}\n" f"Eviction priority: {self.eviction_priority}\n" f"Selective allocation: {self.selective_allocation}\n" ) def __eq__(self, other): if not other: return False return ( self.io_class_id == other.io_class_id and self.io_class_name == other.io_class_name and self.eviction_priority == other.eviction_priority and self.selective_allocation == other.selective_allocation ) class UsageStats: def __init__(self, occupancy, free, clean, dirty): self.occupancy = occupancy self.free = free self.clean = clean self.dirty = dirty def __str__(self): return ( f"Usage stats:\n" f"Occupancy: {self.occupancy}\n" f"Free: {self.free}\n" f"Clean: {self.clean}\n" f"Dirty: {self.dirty}\n" ) def __eq__(self, other): if not other: return False return ( self.occupancy == other.occupancy and self.free == other.free and self.clean == other.clean and self.dirty == other.dirty ) class InactiveUsageStats: def __init__(self, inactive_occupancy, inactive_clean, inactive_dirty): self.inactive_occupancy = inactive_occupancy self.inactive_clean = inactive_clean self.inactive_dirty = inactive_dirty def __str__(self): return ( f"Inactive usage stats:\n" f"Inactive occupancy: {self.inactive_occupancy}\n" f"Inactive clean: {self.inactive_clean}\n" f"Inactive dirty: {self.inactive_dirty}\n" ) def __eq__(self, other): if not other: return False return ( self.inactive_occupancy == other.inactive_occupancy and self.inactive_clean == other.inactive_clean and self.inactive_dirty == other.inactive_dirty ) class RequestStats: def __init__( self, read_hits, read_part_misses, read_full_misses, read_total, write_hits, write_part_misses, write_full_misses, write_total, pass_through_reads, pass_through_writes, requests_serviced, requests_total, ): self.read = RequestStatsChunk( read_hits, read_part_misses, read_full_misses, read_total ) self.write = RequestStatsChunk( write_hits, write_part_misses, write_full_misses, write_total ) self.pass_through_reads = pass_through_reads self.pass_through_writes = pass_through_writes self.requests_serviced = requests_serviced self.requests_total = requests_total def __str__(self): return ( f"Request stats:\n" f"Read:\n{self.read}" f"Write:\n{self.write}" f"Pass-through reads: {self.pass_through_reads}\n" f"Pass-through writes: {self.pass_through_writes}\n" f"Serviced requests: {self.requests_serviced}\n" f"Total requests: {self.requests_total}\n" ) def __eq__(self, other): if not other: return False return ( self.read == other.read and self.write == other.write and self.pass_through_reads == other.pass_through_reads and self.pass_through_writes == other.pass_through_writes and self.requests_serviced == other.requests_serviced and self.requests_total == other.requests_total ) class RequestStatsChunk: def __init__(self, hits, part_misses, full_misses, total): self.hits = hits self.part_misses = part_misses self.full_misses = full_misses self.total = total def __str__(self): return ( f"Hits: {self.hits}\n" f"Partial misses: {self.part_misses}\n" f"Full misses: {self.full_misses}\n" f"Total: {self.total}\n" ) def __eq__(self, other): if not other: return False return ( self.hits == other.hits and self.part_misses == other.part_misses and self.full_misses == other.full_misses and self.total == other.total ) class BlockStats: def __init__( self, core_reads, core_writes, core_total, cache_reads, cache_writes, cache_total, exp_obj_reads, exp_obj_writes, exp_obj_total, ): self.core = BasicStatsChunk(core_reads, core_writes, core_total) self.cache = BasicStatsChunk(cache_reads, cache_writes, cache_total) self.exp_obj = BasicStatsChunk(exp_obj_reads, exp_obj_writes, exp_obj_total) def __str__(self): return ( f"Block stats:\n" f"Core(s):\n{self.core}" f"Cache:\n{self.cache}" f"Exported object(s):\n{self.exp_obj}" ) def __eq__(self, other): if not other: return False return ( self.core == other.core and self.cache == other.cache and self.exp_obj == other.exp_obj ) class ErrorStats: def __init__( self, cache_read_errors, cache_write_errors, cache_total_errors, core_read_errors, core_write_errors, core_total_errors, total_errors, ): self.cache = BasicStatsChunk( cache_read_errors, cache_write_errors, cache_total_errors ) self.core = BasicStatsChunk( core_read_errors, core_write_errors, core_total_errors ) self.total_errors = total_errors def __str__(self): return ( f"Error stats:\n" f"Cache errors:\n{self.cache}" f"Core errors:\n{self.core}" f"Total errors: {self.total_errors}\n" ) def __eq__(self, other): if not other: return False return ( self.cache == other.cache and self.core == other.core and self.total_errors == other.total_errors ) class BasicStatsChunk: def __init__(self, reads, writes, total): self.reads = reads self.writes = writes self.total = total def __str__(self): return f"Reads: {self.reads}\nWrites: {self.writes}\nTotal: {self.total}\n" def __eq__(self, other): if not other: return False return ( self.reads == other.reads and self.writes == other.writes and self.total == other.total )