def test_stop(pyocf_ctx, mode: CacheMode, cls: CacheLineSize, with_flush: bool): """Stopping cache. Check if cache is stopped properly in different modes with or without preceding flush operation. """ cache_device = Volume(Size.from_MiB(20)) core_device = Volume(Size.from_MiB(5)) cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls) core_exported = Core.using_device(core_device) cache.add_core(core_exported) cls_no = 10 run_io_and_cache_data_if_possible(core_exported, mode, cls, cls_no) stats = cache.get_stats() assert int(stats["conf"]["dirty"]) == (cls_no if mode.lazy_write() else 0),\ "Dirty data before MD5" md5_exported_core = core_exported.exp_obj_md5() if with_flush: cache.flush() cache.stop() if mode.lazy_write() and not with_flush: assert core_device.md5() != md5_exported_core, \ "MD5 check: core device vs exported object with dirty data" else: assert core_device.md5() == md5_exported_core, \ "MD5 check: core device vs exported object with clean data"
def check_stats_read_empty(exported_obj: Core, mode: CacheMode, cls: CacheLineSize): stats = exported_obj.cache.get_stats() assert stats["conf"]["cache_mode"] == mode, "Cache mode" assert exported_obj.cache.device.get_stats()[IoDir.WRITE] == (1 if mode.read_insert() else 0), \ "Writes to cache device" assert exported_obj.device.get_stats()[IoDir.READ] == 1, "Reads from core device" assert stats["req"]["rd_full_misses"]["value"] == (0 if mode == CacheMode.PT else 1), \ "Read full misses" assert stats["usage"]["occupancy"]["value"] == \ ((cls / CacheLineSize.LINE_4KiB) if mode.read_insert() else 0), "Occupancy"
def check_stats_write_empty(exported_obj: Core, mode: CacheMode, cls: CacheLineSize): stats = exported_obj.cache.get_stats() assert stats["conf"]["cache_mode"] == mode, "Cache mode" # TODO(ajrutkow): why 1 for WT ?? assert exported_obj.cache.device.get_stats()[IoDir.WRITE] == \ (2 if mode.lazy_write() else (1 if mode == CacheMode.WT else 0)), \ "Writes to cache device" assert exported_obj.device.get_stats()[IoDir.WRITE] == (0 if mode.lazy_write() else 1), \ "Writes to core device" assert stats["req"]["wr_full_misses"]["value"] == (1 if mode.write_insert() else 0), \ "Write full misses" assert stats["usage"]["occupancy"]["value"] == \ ((cls / CacheLineSize.LINE_4KiB) if mode.write_insert() else 0), \ "Occupancy"
def test_start_stop_multiple(pyocf_ctx): """Starting/stopping multiple caches. Check whether OCF allows for starting multiple caches and stopping them in random order """ caches = [] caches_no = randrange(6, 11) for i in range(1, caches_no): cache_device = Volume(Size.from_MiB(20)) cache_name = f"cache{i}" cache_mode = CacheMode(randrange(0, len(CacheMode))) size = 4096 * 2**randrange(0, len(CacheLineSize)) cache_line_size = CacheLineSize(size) cache = Cache.start_on_device( cache_device, name=cache_name, cache_mode=cache_mode, cache_line_size=cache_line_size) caches.append(cache) stats = cache.get_stats() assert stats["conf"]["cache_mode"] == cache_mode, "Cache mode" assert stats["conf"]["cache_line_size"] == cache_line_size, "Cache line size" assert stats["conf"]["cache_name"] == cache_name, "Cache name" caches.sort(key=lambda e: randrange(1000)) for cache in caches: logger.info("Getting stats before stopping cache") stats = cache.get_stats() cache_name = stats["conf"]["cache_name"] cache.stop() assert get_cache_by_name(pyocf_ctx, cache_name) != 0, "Try getting cache after stopping it"
def check_stats_write_after_read(exported_obj: Core, mode: CacheMode, cls: CacheLineSize, read_from_empty=False): stats = exported_obj.cache.get_stats() assert exported_obj.cache.device.get_stats()[IoDir.WRITE] == \ (0 if mode in {CacheMode.WI, CacheMode.PT} else (2 if read_from_empty and mode.lazy_write() else 1)), \ "Writes to cache device" assert exported_obj.device.get_stats()[IoDir.WRITE] == (0 if mode.lazy_write() else 1), \ "Writes to core device" assert stats["req"]["wr_hits"]["value"] == \ (1 if (mode.read_insert() and mode != CacheMode.WI) or (mode.write_insert() and not read_from_empty) else 0), \ "Write hits" assert stats["usage"]["occupancy"]["value"] == \ (0 if mode in {CacheMode.WI, CacheMode.PT} else (cls / CacheLineSize.LINE_4KiB)), \ "Occupancy"
def check_md5_sums(exported_obj: Core, mode: CacheMode): if mode.lazy_write(): assert exported_obj.device.md5() != exported_obj.exp_obj_md5(), \ "MD5 check: core device vs exported object without flush" exported_obj.cache.flush() assert exported_obj.device.md5() == exported_obj.exp_obj_md5(), \ "MD5 check: core device vs exported object after flush" else: assert exported_obj.device.md5() == exported_obj.exp_obj_md5(), \ "MD5 check: core device vs exported object"
def check_md5_sums(core: Core, mode: CacheMode): if mode.lazy_write(): assert core.device.md5() != core.get_front_volume().md5(), \ "MD5 check: core device vs exported object without flush" core.cache.flush() assert core.device.md5() == core.get_front_volume().md5(), \ "MD5 check: core device vs exported object after flush" else: assert core.device.md5() == core.get_front_volume().md5(), \ "MD5 check: core device vs exported object"
def test_start_stop_incrementally(pyocf_ctx): """Starting/stopping multiple caches incrementally. Check whether OCF behaves correctly when few caches at a time are in turns added and removed (#added > #removed) until their number reaches limit, and then proportions are reversed and number of caches gradually falls to 0. """ counter = count() caches = [] caches_limit = 10 add = True run = True increase = True while run: if add: for i in range(0, randrange(3, 5) if increase else randrange(1, 3)): cache_device = Volume(Size.from_MiB(20)) cache_name = f"cache{next(counter)}" cache_mode = CacheMode(randrange(0, len(CacheMode))) size = 4096 * 2**randrange(0, len(CacheLineSize)) cache_line_size = CacheLineSize(size) cache = Cache.start_on_device(cache_device, name=cache_name, cache_mode=cache_mode, cache_line_size=cache_line_size) caches.append(cache) stats = cache.get_stats() assert stats["conf"]["cache_mode"] == cache_mode, "Cache mode" assert stats["conf"][ "cache_line_size"] == cache_line_size, "Cache line size" assert stats["conf"]["cache_name"] == cache_name, "Cache name" if len(caches) == caches_limit: increase = False else: for i in range(0, randrange(1, 3) if increase else randrange(3, 5)): if len(caches) == 0: run = False break cache = caches.pop() logger.info("Getting stats before stopping cache") stats = cache.get_stats() cache_name = stats["conf"]["cache_name"] cache.stop() assert get_cache_by_name(pyocf_ctx, cache_name) != 0, \ "Try getting cache after stopping it" add = not add
def test_100_start_stop(pyocf_ctx): """Starting/stopping stress test. Check OCF behaviour when cache is started and stopped continuously """ for i in range(1, 101): cache_device = Volume(Size.from_MiB(20)) cache_mode = CacheMode(randrange(0, len(CacheMode))) size = 4096 * 2**randrange(0, len(CacheLineSize)) cache_line_size = CacheLineSize(size) cache = Cache.start_on_device( cache_device, cache_mode=cache_mode, cache_line_size=cache_line_size) stats = cache.get_stats() assert stats["conf"]["cache_mode"] == cache_mode, "Cache mode" assert stats["conf"]["cache_line_size"] == cache_line_size, "Cache line size" assert stats["conf"]["cache_id"] == 1, "Cache id" cache.stop() assert get_cache_by_id(pyocf_ctx, 1) != 0, "Try getting cache after stopping it"