Exemplo n.º 1
0
def test_simple_wt_write(pyocf_ctx):
    cache_device = Volume(S.from_MiB(30))
    core_device = Volume(S.from_MiB(30))

    cache = Cache.start_on_device(cache_device)
    core = Core.using_device(core_device)

    cache.add_core(core)

    cache_device.reset_stats()
    core_device.reset_stats()

    write_data = Data.from_string("This is test data")
    io = core.new_io(cache.get_default_queue(),
                     S.from_sector(1).B, write_data.size, IoDir.WRITE, 0, 0)
    io.set_data(write_data)

    cmpl = OcfCompletion([("err", c_int)])
    io.callback = cmpl.callback
    io.submit()
    cmpl.wait()

    assert cmpl.results["err"] == 0
    assert cache_device.get_stats()[IoDir.WRITE] == 1
    stats = cache.get_stats()
    assert stats["req"]["wr_full_misses"]["value"] == 1
    assert stats["usage"]["occupancy"]["value"] == 1

    assert core.exp_obj_md5() == core_device.md5()
    cache.stop()
Exemplo n.º 2
0
def test_simple_wt_write(pyocf_ctx):
    cache_device = Volume(S.from_MiB(100))
    core_device = Volume(S.from_MiB(200))

    cache = Cache.start_on_device(cache_device)
    core = Core.using_device(core_device)

    queue = Queue(cache)
    cache.add_core(core)

    cache_device.reset_stats()
    core_device.reset_stats()

    write_data = Data.from_string("This is test data")
    io = core.new_io()
    io.set_data(write_data)
    io.configure(20, write_data.size, IoDir.WRITE, 0, 0)
    io.set_queue(queue)
    io.submit()

    assert cache_device.get_stats()[IoDir.WRITE] == 1
    stats = cache.get_stats()
    assert stats["req"]["wr_full_misses"]["value"] == 1
    assert stats["usage"]["occupancy"]["value"] == 1

    assert core.exp_obj_md5() == core_device.md5()
Exemplo n.º 3
0
def test_start_write_first_and_check_mode(pyocf_ctx, mode: CacheMode, cls: CacheLineSize):
    """Test starting cache in different modes with different cache line sizes.
    After start check proper cache mode behaviour, starting with write operation.
    """

    cache_device = Volume(Size.from_MiB(40))
    core_device = Volume(Size.from_MiB(10))
    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)

    logger.info("[STAGE] Initial write to exported object")
    cache_device.reset_stats()
    core_device.reset_stats()

    test_data = Data.from_string("This is test data")
    io_to_core(core_exported, test_data, Size.from_sector(1).B)
    check_stats_write_empty(core_exported, mode, cls)

    logger.info("[STAGE] Read from exported object after initial write")
    io_from_exported_object(core_exported, test_data.size, Size.from_sector(1).B)
    check_stats_read_after_write(core_exported, mode, cls, True)

    logger.info("[STAGE] Write to exported object after read")
    cache_device.reset_stats()
    core_device.reset_stats()

    test_data = Data.from_string("Changed test data")

    io_to_core(core_exported, test_data, Size.from_sector(1).B)
    check_stats_write_after_read(core_exported, mode, cls)

    check_md5_sums(core_exported, mode)
Exemplo n.º 4
0
def test_wo_read_data_consistency(pyocf_ctx):
    # start sector for each region
    region_start = [0, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
    # possible start sectors for test iteration
    start_sec = [0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
    # possible end sectors for test iteration
    end_sec = [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 23]

    CACHELINE_COUNT = 3
    CACHELINE_SIZE = 4096
    SECTOR_SIZE = Size.from_sector(1).B
    CLS = CACHELINE_SIZE // SECTOR_SIZE
    WORKSET_SIZE = CACHELINE_COUNT * CACHELINE_SIZE
    WORKSET_OFFSET = 1024 * CACHELINE_SIZE
    SECTOR_COUNT = int(WORKSET_SIZE / SECTOR_SIZE)
    ITRATION_COUNT = 200

    # fixed test cases
    fixed_combinations = [
        [I, I, D, D, D, D, D, D, D, D, I, I],
        [I, I, C, C, C, C, C, C, C, C, I, I],
        [I, I, D, D, D, I, D, D, D, D, I, I],
        [I, I, D, D, D, I, I, D, D, D, I, I],
        [I, I, I, I, D, I, I, D, C, D, I, I],
        [I, D, D, D, D, D, D, D, D, D, D, I],
        [C, C, I, D, D, I, D, D, D, D, D, I],
        [D, D, D, D, D, D, D, D, D, D, D, I],
    ]

    data = {}
    # memset n-th sector of core data with n
    data[SectorStatus.INVALID] = bytes(
        [x // SECTOR_SIZE for x in range(WORKSET_SIZE)])
    # memset n-th sector of clean data with n + 100
    data[SectorStatus.CLEAN] = bytes(
        [100 + x // SECTOR_SIZE for x in range(WORKSET_SIZE)])
    # memset n-th sector of dirty data with n + 200
    data[SectorStatus.DIRTY] = bytes(
        [200 + x // SECTOR_SIZE for x in range(WORKSET_SIZE)])

    result_b = bytes(WORKSET_SIZE)

    cache_device = Volume(Size.from_MiB(30))
    core_device = Volume(Size.from_MiB(30))

    cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WO)
    core = Core.using_device(core_device)

    cache.add_core(core)

    insert_order = [x for x in range(CACHELINE_COUNT)]

    # generate regions status combinations and shuffle it
    combinations = []
    state_combinations = product(SectorStatus, repeat=len(region_start))
    for S in state_combinations:
        combinations.append(S)
    random.shuffle(combinations)

    # add fixed test cases at the beginning
    combinations = fixed_combinations + combinations

    for S in combinations[:ITRATION_COUNT]:
        # write data to core and invalidate all CL
        cache.change_cache_mode(cache_mode=CacheMode.PT)
        io_to_exp_obj(core, 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 S[region] != SectorStatus.INVALID:
                io_to_exp_obj(core, 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.WO)
        for sec in sectors:
            region = sector_to_region(sec, region_start)
            if S[region] == SectorStatus.DIRTY:
                io_to_exp_obj(core, WORKSET_OFFSET + SECTOR_SIZE * sec,
                              SECTOR_SIZE, data[SectorStatus.DIRTY],
                              sec * SECTOR_SIZE, IoDir.WRITE)

        core_device.reset_stats()

        for s in start_sec:
            for e in end_sec:
                if s > e:
                    continue

                # issue WO read
                START = s * SECTOR_SIZE
                END = e * SECTOR_SIZE
                size = (e - s + 1) * SECTOR_SIZE
                assert 0 == io_to_exp_obj(
                    core, WORKSET_OFFSET + START, size, result_b, START,
                    IoDir.READ
                ), "error reading in WO mode: S={}, start={}, end={}, insert_order={}".format(
                    S, s, e, insert_order)

                # verify read data
                for sec in range(s, e + 1):
                    # just check the first byte of sector
                    region = sector_to_region(sec, region_start)
                    check_byte = sec * SECTOR_SIZE
                    assert (
                        result_b[check_byte] == data[S[region]][check_byte]
                    ), "unexpected data in sector {}, S={}, s={}, e={}, insert_order={}\n".format(
                        sec, S, s, e, insert_order)

                # WO is not supposed to clean dirty data
                assert (
                    core_device.get_stats()[IoDir.WRITE] == 0
                ), "unexpected write to core device, S={}, s={}, e={}, insert_order = {}\n".format(
                    S, s, e, insert_order)
Exemplo n.º 5
0
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 = Volume(Size.from_MiB(30))
    core_device = Volume(Size.from_MiB(30))

    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)

    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(
            core,
            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(
                    core,
                    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(
                    core,
                    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(
                core, 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)