def test_simple_wt_write(pyocf_ctx): cache_device = RamVolume(S.from_MiB(50)) core_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device(cache_device) core = Core.using_device(core_device) queue = cache.get_default_queue() cache.add_core(core) vol = CoreVolume(core, open=True) cache_device.reset_stats() core_device.reset_stats() r = Rio().target(vol).readwrite(ReadWrite.WRITE).size( S.from_sector(1)).run([queue]) assert cache_device.get_stats()[IoDir.WRITE] == 1 cache.settle() stats = cache.get_stats() assert stats["req"]["wr_full_misses"]["value"] == 1 assert stats["usage"]["occupancy"]["value"] == 1 assert vol.md5() == core_device.md5() cache.stop()
def test_read_data_consistency(pyocf_ctx, cacheline_size, cache_mode, rand_seed): CACHELINE_COUNT = 9 SECTOR_SIZE = Size.from_sector(1).B CLS = cacheline_size // SECTOR_SIZE WORKSET_SIZE = CACHELINE_COUNT * cacheline_size WORKSET_OFFSET = 128 * cacheline_size SECTOR_COUNT = int(WORKSET_SIZE / SECTOR_SIZE) ITRATION_COUNT = 50 random.seed(rand_seed) # start sector for each region (positions of '*' on the above diagram) region_start = ([0, 3 * CLS, 4 * CLS - 1] + [4 * CLS + i for i in range(CLS)] + [5 * CLS, 5 * CLS + 1, 6 * CLS]) num_regions = len(region_start) # possible IO start sectors for test iteration (positions of '>' on the above diagram) start_sec = [0, CLS, 2 * CLS, 3 * CLS, 4 * CLS - 2, 4 * CLS - 1 ] + [4 * CLS + i for i in range(CLS)] # possible IO end sectors for test iteration (positions o '<' on the above diagram) end_sec = ([3 * CLS - 1] + [4 * CLS + i for i in range(CLS)] + [ 5 * CLS, 5 * CLS + 1, 6 * CLS - 1, 7 * CLS - 1, 8 * CLS - 1, 9 * CLS - 1 ]) data = {} # memset n-th sector of core data with n << 2 data[SectorStatus.INVALID] = bytes([ get_byte(((x // SECTOR_SIZE) << 2) + 0, x % 4) for x in range(WORKSET_SIZE) ]) # memset n-th sector of clean data with n << 2 + 1 data[SectorStatus.CLEAN] = bytes([ get_byte(((x // SECTOR_SIZE) << 2) + 1, x % 4) for x in range(WORKSET_SIZE) ]) # memset n-th sector of dirty data with n << 2 + 2 data[SectorStatus.DIRTY] = bytes([ get_byte(((x // SECTOR_SIZE) << 2) + 2, x % 4) for x in range(WORKSET_SIZE) ]) result_b = bytes(WORKSET_SIZE) cache_device = RamVolume(Size.from_MiB(50)) core_device = RamVolume(Size.from_MiB(50)) cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WO, cache_line_size=cacheline_size) core = Core.using_device(core_device) cache.add_core(core) queue = cache.get_default_queue() vol = CoreVolume(core, open=True) insert_order = list(range(CACHELINE_COUNT)) # set fixed generated sector statuses region_statuses = [ [I, I, I] + [I for i in range(CLS)] + [I, I, I], [I, I, I] + [D for i in range(CLS)] + [I, I, I], [I, I, I] + [C for i in range(CLS)] + [I, I, I], [I, I, I] + [D for i in range(CLS // 2 - 1)] + [I] + [D for i in range(CLS // 2)] + [I, I, I], [I, I, I] + [D for i in range(CLS // 2 - 1)] + [I, I] + [D for i in range(CLS // 2 - 1)] + [I, I, I], [I, I, I] + [D for i in range(CLS // 2 - 2)] + [I, I, D, C] + [D for i in range(CLS // 2 - 2)] + [I, I, I], [I, I, D] + [D for i in range(CLS)] + [D, I, I], [I, I, D] + [D for i in range(CLS // 2 - 1)] + [I] + [D for i in range(CLS // 2)] + [D, I, I], ] # add randomly generated sector statuses for _ in range(ITRATION_COUNT - len(region_statuses)): region_statuses.append( [random.choice(list(SectorStatus)) for _ in range(num_regions)]) # iterate over generated status combinations and perform the test for region_state in region_statuses: # write data to core and invalidate all CL and write data pattern to core cache.change_cache_mode(cache_mode=CacheMode.PT) io_to_exp_obj( vol, queue, WORKSET_OFFSET, len(data[SectorStatus.INVALID]), data[SectorStatus.INVALID], 0, IoDir.WRITE, ) # randomize cacheline insertion order to exercise different # paths with regard to cache I/O physical addresses continuousness random.shuffle(insert_order) sectors = [ insert_order[i // CLS] * CLS + (i % CLS) for i in range(SECTOR_COUNT) ] # insert clean sectors - iterate over cachelines in @insert_order order cache.change_cache_mode(cache_mode=CacheMode.WT) for sec in sectors: region = sector_to_region(sec, region_start) if region_state[region] != SectorStatus.INVALID: io_to_exp_obj( vol, queue, WORKSET_OFFSET + SECTOR_SIZE * sec, SECTOR_SIZE, data[SectorStatus.CLEAN], sec * SECTOR_SIZE, IoDir.WRITE, ) # write dirty sectors cache.change_cache_mode(cache_mode=CacheMode.WB) for sec in sectors: region = sector_to_region(sec, region_start) if region_state[region] == SectorStatus.DIRTY: io_to_exp_obj( vol, queue, WORKSET_OFFSET + SECTOR_SIZE * sec, SECTOR_SIZE, data[SectorStatus.DIRTY], sec * SECTOR_SIZE, IoDir.WRITE, ) cache.change_cache_mode(cache_mode=cache_mode) core_device.reset_stats() # get up to 32 randomly selected pairs of (start,end) sectors # 32 is enough to cover all combinations for 4K and 8K cacheline size io_ranges = [(s, e) for s, e in product(start_sec, end_sec) if s < e] random.shuffle(io_ranges) io_ranges = io_ranges[:32] # run the test for each selected IO range for currently set up region status for start, end in io_ranges: print_test_case(region_start, region_state, start, end, SECTOR_COUNT, CLS) # issue read START = start * SECTOR_SIZE END = end * SECTOR_SIZE size = (end - start + 1) * SECTOR_SIZE assert 0 == io_to_exp_obj( vol, queue, WORKSET_OFFSET + START, size, result_b, START, IoDir.READ ), "error reading in {}: region_state={}, start={}, end={}, insert_order={}".format( cache_mode, region_state, start, end, insert_order) # verify read data for sec in range(start, end + 1): # just check the first 32bits of sector (this is the size of fill pattern) region = sector_to_region(sec, region_start) start_byte = sec * SECTOR_SIZE expected_data = bytes_to_uint32( data[region_state[region]][start_byte + 0], data[region_state[region]][start_byte + 1], data[region_state[region]][start_byte + 2], data[region_state[region]][start_byte + 3], ) actual_data = bytes_to_uint32( result_b[start_byte + 0], result_b[start_byte + 1], result_b[start_byte + 2], result_b[start_byte + 3], ) assert ( actual_data == expected_data ), "unexpected data in sector {}, region_state={}, start={}, end={}, insert_order={}\n".format( sec, region_state, start, end, insert_order) if cache_mode == CacheMode.WO: # WO is not supposed to clean dirty data assert ( core_device.get_stats()[IoDir.WRITE] == 0 ), "unexpected write to core device, region_state={}, start={}, end={}, insert_order = {}\n".format( region_state, start, end, insert_order)