def test_get_core_record_lookup():
    # Make sure this internal utility produces appropriate results.
    e = Experiment(Mock())

    # Two cores, one will eventually record router values, the other will not.
    core0 = e.new_core()
    core1 = e.new_core()
    cores = [core0, core1]
    e._placements = {core0: (0, 0), core1: (0, 0)}
    e._router_recording_cores = set()

    # Two flows, one connected loop-back, one connected to the other core.
    flow0 = e.new_flow(core0, core0)
    flow1 = e.new_flow(core0, core1)
    cores_source_flows = {core0: [flow0, flow1], core1: []}
    cores_sink_flows = {core0: [flow0], core1: [flow1]}

    # If nothing is being recorded, the sets should just contain permanent
    # counters
    cores_records = e._get_core_record_lookup(
        cores, cores_source_flows, cores_sink_flows)
    assert cores_records == {
        core0: [(core0, Counters.deadlines_missed)],
        core1: [(core1, Counters.deadlines_missed)],
    }

    # If only core counters are being used, they should be included
    e.record_sent = True
    e.record_received = True
    cores_records = e._get_core_record_lookup(
        cores, cores_source_flows, cores_sink_flows)
    assert cores_records == {
        core0: [(core0, Counters.deadlines_missed),
                (flow0, Counters.sent), (flow1, Counters.sent),
                (flow0, Counters.received)],
        core1: [(core1, Counters.deadlines_missed),
                (flow1, Counters.received)],
    }

    # If any routing table entries are present, they should be added to
    # anything in the router_recording_cores lookup.
    e._router_recording_cores = set([core0])
    e.record_external_multicast = True
    cores_records = e._get_core_record_lookup(
        cores,
        cores_source_flows,
        cores_sink_flows)
    assert cores_records == {
        core0: [(core0, Counters.deadlines_missed),
                ((0, 0), Counters.external_multicast),
                (flow0, Counters.sent), (flow1, Counters.sent),
                (flow0, Counters.received)],
        core1: [(core1, Counters.deadlines_missed),
                (flow1, Counters.received)],
    }
def test_get_vertex_record_lookup():
    # Make sure this internal utility produces appropriate results.
    e = Experiment(Mock())

    # Two vertices, one will eventually record router values, the other will
    # not.
    vertex0 = e.new_vertex()
    vertex1 = e.new_vertex()
    vertices = [vertex0, vertex1]
    placements = {vertex0: (0, 0), vertex1: (0, 0)}

    # Two nets, one connected loop-back, one connected to the other vertex.
    net0 = e.new_net(vertex0, vertex0)
    net1 = e.new_net(vertex0, vertex1)
    vertices_source_nets = {vertex0: [net0, net1], vertex1: []}
    vertices_sink_nets = {vertex0: [net0], vertex1: [net1]}

    # If nothing is being recorded, the sets should be empty.
    vertices_records = e._get_vertex_record_lookup(
        vertices, set(), placements, vertices_source_nets, vertices_sink_nets)
    assert vertices_records == {
        vertex0: [],
        vertex1: [],
    }

    # If only vertex counters are being used, they should be included
    e.record_sent = True
    e.record_received = True
    vertices_records = e._get_vertex_record_lookup(
        vertices, set(), placements, vertices_source_nets, vertices_sink_nets)
    assert vertices_records == {
        vertex0: [(net0, Counters.sent), (net1, Counters.sent),
                  (net0, Counters.received)],
        vertex1: [(net1, Counters.received)],
    }

    # If any routing table entries are present, they should be added to
    # anything in the router_recording_vertices lookup.
    router_recording_vertices = set([vertex0])
    e.record_external_multicast = True
    vertices_records = e._get_vertex_record_lookup(
        vertices,
        router_recording_vertices,
        placements,
        vertices_source_nets,
        vertices_sink_nets)
    assert vertices_records == {
        vertex0: [((0, 0), Counters.external_multicast),
                  (net0, Counters.sent), (net1, Counters.sent),
                  (net0, Counters.received)],
        vertex1: [(net1, Counters.received)],
    }
Exemple #3
0
def test_get_core_record_lookup():
    # Make sure this internal utility produces appropriate results.
    e = Experiment(Mock())

    # Two cores, one will eventually record router values, the other will not.
    core0 = e.new_core()
    core1 = e.new_core()
    cores = [core0, core1]
    e._placements = {core0: (0, 0), core1: (0, 0)}
    e._router_recording_cores = set()

    # Two flows, one connected loop-back, one connected to the other core.
    flow0 = e.new_flow(core0, core0)
    flow1 = e.new_flow(core0, core1)
    cores_source_flows = {core0: [flow0, flow1], core1: []}
    cores_sink_flows = {core0: [flow0], core1: [flow1]}

    # If nothing is being recorded, the sets should just contain permanent
    # counters
    cores_records = e._get_core_record_lookup(cores, cores_source_flows,
                                              cores_sink_flows)
    assert cores_records == {
        core0: [(core0, Counters.deadlines_missed)],
        core1: [(core1, Counters.deadlines_missed)],
    }

    # If only core counters are being used, they should be included
    e.record_sent = True
    e.record_received = True
    cores_records = e._get_core_record_lookup(cores, cores_source_flows,
                                              cores_sink_flows)
    assert cores_records == {
        core0: [(core0, Counters.deadlines_missed), (flow0, Counters.sent),
                (flow1, Counters.sent), (flow0, Counters.received)],
        core1: [(core1, Counters.deadlines_missed),
                (flow1, Counters.received)],
    }

    # If any routing table entries are present, they should be added to
    # anything in the router_recording_cores lookup.
    e._router_recording_cores = set([core0])
    e.record_external_multicast = True
    cores_records = e._get_core_record_lookup(cores, cores_source_flows,
                                              cores_sink_flows)
    assert cores_records == {
        core0: [(core0, Counters.deadlines_missed),
                ((0, 0), Counters.external_multicast), (flow0, Counters.sent),
                (flow1, Counters.sent), (flow0, Counters.received)],
        core1: [(core1, Counters.deadlines_missed),
                (flow1, Counters.received)],
    }
def test_add_router_recording_vertices():
    # Make sure this internal utility adds extra vertices only when required.
    mock_mc = Mock()
    e = Experiment(mock_mc)

    machine = Machine(2, 2)
    mock_mc.get_machine.return_value = machine

    vertex0 = e.new_vertex()
    vertex1 = e.new_vertex()
    e.placements = {vertex0: (0, 0),
                    vertex1: (0, 0)}
    e.record_sent = True
    e.record_blocked = True
    e.record_received = True
    e.place_and_route()

    # If only recording vertex-specific values, no extra vertices should
    # appear.
    (vertices, router_recording_vertices,
     placements, allocations, routes) = \
        e._add_router_recording_vertices()
    assert vertices == [vertex0, vertex1]
    assert router_recording_vertices == set()
    assert placements == {vertex0: (0, 0), vertex1: (0, 0)}

    # If recording any router registers, a vertex must be allocated on every
    # chip, creating new ones when required.
    e.record_external_multicast = True
    (vertices, router_recording_vertices,
     placements, allocations, routes) =\
        e._add_router_recording_vertices()

    # Should have three extra vertices, one for each unused chip.
    assert len(vertices) == 5

    # The original vertices should still be there
    assert vertex0 in vertices
    assert vertex1 in vertices

    # There should be a router recording vertex on each chip
    assert sorted(placements[v] for v in router_recording_vertices) == \
        sorted(machine)

    # The vertex used on (0, 0) should be one we put there, not a new vertex
    assert (vertex0 in router_recording_vertices) ^ \
        (vertex1 in router_recording_vertices)
def test_run(auto_create_group, samples_per_group, num_cores,
             num_flows_per_core, error, error_code, record, reinject_packets):
    """Make sure that the run command carries out an experiment as would be
    expected."""
    system_info = SystemInfo(3, 1, {
        (x, y): ChipInfo(num_cores=18,
                         core_states=[AppState.run] + [AppState.idle] * 17,
                         working_links=set(Links),
                         largest_free_sdram_block=110*1024*1024,
                         largest_free_sram_block=1024*1024)
        for x in range(3)
        for y in range(1)
    })

    mock_mc = Mock()
    mock_mc.get_system_info.return_value = system_info

    mock_application_ctx = Mock()
    mock_application_ctx.__enter__ = Mock()
    mock_application_ctx.__exit__ = Mock()
    mock_mc.application.return_value = mock_application_ctx

    if reinject_packets:
        # If reinjecting, a core is added to every chip
        mock_mc.wait_for_cores_to_reach_state.return_value = len(system_info)
    else:
        # If not reinjecting, only the user-defined cores exist
        mock_mc.wait_for_cores_to_reach_state.return_value = num_cores

    def mock_sdram_file_read(size):
        return error_code + b"\0"*(size - 4)
    mock_sdram_file = Mock()
    mock_sdram_file.read.side_effect = mock_sdram_file_read

    mock_mc.sdram_alloc_as_filelike.return_value = mock_sdram_file

    e = Experiment(mock_mc)
    e.timestep = 1e-6
    e.warmup = 0.01
    e.duration = 0.01
    e.cooldown = 0.01
    e.flush_time = 0.01

    # Record the result of _construct_core_commands to allow checking of
    # memory allocation sizes
    construct_core_commands = e._construct_core_commands
    cores_commands = {}

    def wrapped_construct_core_commands(core, *args, **kwargs):
        commands = construct_core_commands(core=core, *args, **kwargs)
        cores_commands[core] = commands
        return commands
    e._construct_core_commands = Mock(
        side_effect=wrapped_construct_core_commands)

    if record:
        e.record_sent = True

    e.reinject_packets = reinject_packets

    # Create example cores. Cores are placed on sequential chips along the
    # x-axis.
    cores = [e.new_core(x, 0) for x in range(num_cores)]
    for c in cores:
        for _ in range(num_flows_per_core):
            e.new_flow(c, c)

    # Create example groups
    for num_samples in samples_per_group:
        with e.new_group():
            e.record_interval = e.duration / float(num_samples)

    # The run should fail with an exception when expected.
    if error and (num_cores > 0 or reinject_packets):
        with pytest.raises(NetworkTesterError) as exc_info:
            e.run(0x33, create_group_if_none_exist=auto_create_group)
        results = exc_info.value.results
    else:
        results = e.run(0x33, create_group_if_none_exist=auto_create_group)

    # The results should be of the correct type...
    assert isinstance(results, Results)

    # The results returned should be all zeros (since that is what was written
    # back)
    if record and num_cores > 0 and num_flows_per_core > 0:
        assert sum(results.totals()["sent"]) == 0

    # The supplied app ID should be used
    mock_mc.application.assert_called_once_with(0x33)

    # If reinjection is enabled, the binary should have been loaded
    print([call[1][0] for call in mock_mc.load_application.mock_calls])
    reinjector_loaded = any((len(call[1][0]) == 1 and
                             "reinjector.aplx" in list(call[1][0])[0])
                            for call in mock_mc.load_application.mock_calls)
    if reinject_packets:
        assert reinjector_loaded
    else:
        assert not reinjector_loaded

    # Each chip should have been issued with a suitable malloc for any cores
    # on it.
    for x, core in enumerate(cores):
        cmds_size = cores_commands[core].size
        if record:
            # The space required to record deadlines_missed and the sent
            # counters.
            result_size = (1 + ((1 + num_flows_per_core) *
                                sum(samples_per_group))) * 4
        else:
            # Just the status value and deadlines_missed
            result_size = (1 + sum(samples_per_group)) * 4
        size = max(cmds_size, result_size)
        core_num = e._allocations[core][Cores].start
        mock_mc.sdram_alloc_as_filelike.assert_any_call(size, x=x, y=0,
                                                        tag=core_num)

    # The correct number of barriers should have been reached
    num_groups = len(samples_per_group)
    if auto_create_group:
        num_groups = max(1, num_groups)
    assert len(mock_mc.send_signal.mock_calls) == num_groups
def test_construct_core_commands(router_access_core):
    # XXX: This test is *very* far from being complete. In particular, though
    # the problem supplied is realistic, the output is not checked thouroughly
    # enough.
    e = Experiment(Mock())

    # A simple example network as follows:
    #       f0
    #  c0 ---+--> c1
    #   |    '--> c2
    #   +-------> c3
    #      f1
    # We'll pretend all of them are on the same chip and core0 is the one
    # designated as the router-value recording core.

    core0 = e.new_core()
    core1 = e.new_core()
    core2 = e.new_core()
    core3 = e.new_core()

    cores = [core0, core1, core2, core3]

    flow0 = e.new_flow(core0, [core1, core2])
    flow1 = e.new_flow(core0, core3)

    # Seed randomly
    e.seed = None

    e.timestep = 1e-6
    e.warmup = 0.001
    e.duration = 1.0
    e.cooldown = 0.001
    e.flush_time = 0.01

    e.record_sent = True

    e.reinject_packets = True

    # By default, nothing should send and everything should consume
    e.probability = 0.0
    e.consume = True
    e.router_timeout = 240

    # In group0, everything consumes and f0 sends 100% packets and f1 sends 50%
    # packets.
    with e.new_group():
        flow0.probability = 1.0
        flow1.probability = 0.5

    # In group1, nothing consumes and f0 and f1 send 100%
    with e.new_group():
        flow0.probability = 1.0
        flow1.probability = 1.0
        e.consume = False
        e.router_timeout = 0

    # In group2, we have a timeout with emergency routing enabled
    with e.new_group():
        e.router_timeout = (16, 16)

    flow_keys = {flow0: 0xAA00, flow1: 0xBB00}

    cores_source_flows = {
        core0: [flow0, flow1],
        core1: [],
        core2: [],
        core3: [],
    }
    cores_sink_flows = {
        core0: [],
        core1: [flow0],
        core2: [flow0],
        core3: [flow1],
    }

    core_commands = {
        core: e._construct_core_commands(
            core=core,
            source_flows=cores_source_flows[core],
            sink_flows=cores_sink_flows[core],
            flow_keys=flow_keys,
            records=[Counters.deadlines_missed, Counters.sent],
            router_access_core=router_access_core).pack()
        for core in cores
    }

    # Make sure all cores have the right number of sources/sinks set
    for core in cores:
        commands = core_commands[core]
        num_sources = len(cores_source_flows[core])
        num_sinks = len(cores_sink_flows[core])
        ref_cmd = struct.pack("<II", NT_CMD.NUM,
                              (num_sources | num_sinks << 16))
        assert ref_cmd in commands

    # Make sure all cores have the right set of sources and sinks
    for core in cores:
        commands = core_commands[core]
        sources = cores_source_flows[core]
        sinks = cores_sink_flows[core]

        for source_num, source_flow in enumerate(sources):
            ref_cmd = struct.pack("<II", NT_CMD.SOURCE_KEY | (source_num << 8),
                                  flow_keys[source_flow])
            assert ref_cmd in commands

        for sink_num, sink_flow in enumerate(sinks):
            ref_cmd = struct.pack("<II", NT_CMD.SINK_KEY | (sink_num << 8),
                                  flow_keys[sink_flow])
            assert ref_cmd in commands

    # Make sure all cores have the right set of timing values
    for core in cores:
        commands = core_commands[core]

        ref_cmd = struct.pack("<II", NT_CMD.TIMESTEP, 1000)
        assert ref_cmd in commands

    # Make sure all cores have the right timeout set
    for core in cores:
        commands = core_commands[core]

        ref_cmd0 = struct.pack("<I", NT_CMD.ROUTER_TIMEOUT)
        ref_cmd1 = struct.pack("<I", NT_CMD.ROUTER_TIMEOUT_RESTORE)
        if router_access_core:
            assert ref_cmd0 in commands
            assert ref_cmd1 in commands
        else:
            assert ref_cmd0 not in commands
            assert ref_cmd1 not in commands

    # Make sure all cores packet reinjection enabled if requested
    for core in cores:
        commands = core_commands[core]

        ref_cmd0 = struct.pack("<I", NT_CMD.REINJECTION_ENABLE)
        ref_cmd1 = struct.pack("<I", NT_CMD.REINJECTION_DISABLE)
        if router_access_core:
            assert ref_cmd0 in commands
            assert ref_cmd1 in commands
        else:
            assert ref_cmd0 not in commands
            assert ref_cmd1 not in commands
def test_option_descriptors():
    """Make sure the option descriptors work."""
    e = Experiment(Mock())

    # Defualts should work
    assert e.seed is None
    assert e.probability == 1.0

    # Should be able to set
    e.probability = 0.1
    assert e.probability == 0.1

    # Should be able to set exceptions for groups
    with e.new_group():
        assert e.probability == 0.1
        e.probability = 1.0
        assert e.probability == 1.0

    assert e.probability == 0.1

    # Should be able to set non-exception-supporting options globally
    assert e.record_sent is False
    e.record_sent = True
    assert e.record_sent is True

    # Should be able to set exceptions for cores
    core0 = e.new_core()
    assert core0.probability == 0.1
    core0.probability = 0.5
    assert core0.probability == 0.5
    assert e.probability == 0.1

    # Should be able to set exceptions for flows
    flow0 = e.new_flow(core0, core0)
    assert flow0.probability == 0.5
    flow0.probability = 0.6
    assert flow0.probability == 0.6
    assert core0.probability == 0.5
    assert e.probability == 0.1

    # Should be able to set exceptions in groups for cores and flows
    with e.new_group():
        assert e.probability == 0.1
        assert core0.probability == 0.5
        assert flow0.probability == 0.6

        # Group probability shouldn't override core/flow probability
        e.probability = 1.0
        assert e.probability == 1.0
        assert core0.probability == 0.5
        assert flow0.probability == 0.6

        # Group+core probability should take precidence (but not over flows)
        core0.probability = 10.0
        assert e.probability == 1.0
        assert core0.probability == 10.0
        assert flow0.probability == 0.6

        # Group+flow probability should take overall precidence
        flow0.probability = 20.0
        assert e.probability == 1.0
        assert core0.probability == 10.0
        assert flow0.probability == 20.0

        # Should be able to get non-exception supporting options
        assert e.record_sent is True

        # Shouldn't be able to set non-exception-supporting options
        with pytest.raises(ValueError):
            e.record_sent = False

    # ...but only within the group
    assert e.probability == 0.1
    assert core0.probability == 0.5
    assert flow0.probability == 0.6
Exemple #8
0
def test_run(auto_create_group, samples_per_group, num_cores,
             num_flows_per_core, error, error_code, record, reinject_packets):
    """Make sure that the run command carries out an experiment as would be
    expected."""
    system_info = SystemInfo(
        3, 1,
        {(x, y): ChipInfo(num_cores=18,
                          core_states=[AppState.run] + [AppState.idle] * 17,
                          working_links=set(Links),
                          largest_free_sdram_block=110 * 1024 * 1024,
                          largest_free_sram_block=1024 * 1024)
         for x in range(3) for y in range(1)})

    mock_mc = Mock()
    mock_mc.get_system_info.return_value = system_info

    mock_application_ctx = Mock()
    mock_application_ctx.__enter__ = Mock()
    mock_application_ctx.__exit__ = Mock()
    mock_mc.application.return_value = mock_application_ctx

    if reinject_packets:
        # If reinjecting, a core is added to every chip
        mock_mc.wait_for_cores_to_reach_state.return_value = len(system_info)
    else:
        # If not reinjecting, only the user-defined cores exist
        mock_mc.wait_for_cores_to_reach_state.return_value = num_cores

    def mock_sdram_file_read(size):
        return error_code + b"\0" * (size - 4)

    mock_sdram_file = Mock()
    mock_sdram_file.read.side_effect = mock_sdram_file_read

    mock_mc.sdram_alloc_as_filelike.return_value = mock_sdram_file

    e = Experiment(mock_mc)
    e.timestep = 1e-6
    e.warmup = 0.01
    e.duration = 0.01
    e.cooldown = 0.01
    e.flush_time = 0.01

    # Record the result of _construct_core_commands to allow checking of
    # memory allocation sizes
    construct_core_commands = e._construct_core_commands
    cores_commands = {}

    def wrapped_construct_core_commands(core, *args, **kwargs):
        commands = construct_core_commands(core=core, *args, **kwargs)
        cores_commands[core] = commands
        return commands

    e._construct_core_commands = Mock(
        side_effect=wrapped_construct_core_commands)

    if record:
        e.record_sent = True

    e.reinject_packets = reinject_packets

    # Create example cores. Cores are placed on sequential chips along the
    # x-axis.
    cores = [e.new_core(x, 0) for x in range(num_cores)]
    for c in cores:
        for _ in range(num_flows_per_core):
            e.new_flow(c, c)

    # Create example groups
    for num_samples in samples_per_group:
        with e.new_group():
            e.record_interval = e.duration / float(num_samples)

    # The run should fail with an exception when expected.
    if error and (num_cores > 0 or reinject_packets):
        with pytest.raises(NetworkTesterError) as exc_info:
            e.run(0x33, create_group_if_none_exist=auto_create_group)
        results = exc_info.value.results
    else:
        results = e.run(0x33, create_group_if_none_exist=auto_create_group)

    # The results should be of the correct type...
    assert isinstance(results, Results)

    # The results returned should be all zeros (since that is what was written
    # back)
    if record and num_cores > 0 and num_flows_per_core > 0:
        assert sum(results.totals()["sent"]) == 0

    # The supplied app ID should be used
    mock_mc.application.assert_called_once_with(0x33)

    # If reinjection is enabled, the binary should have been loaded
    print([call[1][0] for call in mock_mc.load_application.mock_calls])
    reinjector_loaded = any(
        (len(call[1][0]) == 1 and "reinjector.aplx" in list(call[1][0])[0])
        for call in mock_mc.load_application.mock_calls)
    if reinject_packets:
        assert reinjector_loaded
    else:
        assert not reinjector_loaded

    # Each chip should have been issued with a suitable malloc for any cores
    # on it.
    for x, core in enumerate(cores):
        cmds_size = cores_commands[core].size
        if record:
            # The space required to record deadlines_missed and the sent
            # counters.
            result_size = (1 + (
                (1 + num_flows_per_core) * sum(samples_per_group))) * 4
        else:
            # Just the status value and deadlines_missed
            result_size = (1 + sum(samples_per_group)) * 4
        size = max(cmds_size, result_size)
        core_num = e._allocations[core][Cores].start
        mock_mc.sdram_alloc_as_filelike.assert_any_call(size,
                                                        x=x,
                                                        y=0,
                                                        tag=core_num)

    # The correct number of barriers should have been reached
    num_groups = len(samples_per_group)
    if auto_create_group:
        num_groups = max(1, num_groups)
    assert len(mock_mc.send_signal.mock_calls) == num_groups
Exemple #9
0
def test_construct_core_commands(router_access_core):
    # XXX: This test is *very* far from being complete. In particular, though
    # the problem supplied is realistic, the output is not checked thouroughly
    # enough.
    e = Experiment(Mock())

    # A simple example network as follows:
    #       f0
    #  c0 ---+--> c1
    #   |    '--> c2
    #   +-------> c3
    #      f1
    # We'll pretend all of them are on the same chip and core0 is the one
    # designated as the router-value recording core.

    core0 = e.new_core()
    core1 = e.new_core()
    core2 = e.new_core()
    core3 = e.new_core()

    cores = [core0, core1, core2, core3]

    flow0 = e.new_flow(core0, [core1, core2])
    flow1 = e.new_flow(core0, core3)

    # Seed randomly
    e.seed = None

    e.timestep = 1e-6
    e.warmup = 0.001
    e.duration = 1.0
    e.cooldown = 0.001
    e.flush_time = 0.01

    e.record_sent = True

    e.reinject_packets = True

    # By default, nothing should send and everything should consume
    e.probability = 0.0
    e.consume = True
    e.router_timeout = 240

    # In group0, everything consumes and f0 sends 100% packets and f1 sends 50%
    # packets.
    with e.new_group():
        flow0.probability = 1.0
        flow1.probability = 0.5

    # In group1, nothing consumes and f0 and f1 send 100%
    with e.new_group():
        flow0.probability = 1.0
        flow1.probability = 1.0
        e.consume = False
        e.router_timeout = 0

    # In group2, we have a timeout with emergency routing enabled
    with e.new_group():
        e.router_timeout = (16, 16)

    flow_keys = {flow0: 0xAA00, flow1: 0xBB00}

    cores_source_flows = {
        core0: [flow0, flow1],
        core1: [],
        core2: [],
        core3: [],
    }
    cores_sink_flows = {
        core0: [],
        core1: [flow0],
        core2: [flow0],
        core3: [flow1],
    }

    core_commands = {
        core: e._construct_core_commands(
            core=core,
            source_flows=cores_source_flows[core],
            sink_flows=cores_sink_flows[core],
            flow_keys=flow_keys,
            records=[Counters.deadlines_missed, Counters.sent],
            router_access_core=router_access_core).pack()
        for core in cores
    }

    # Make sure all cores have the right number of sources/sinks set
    for core in cores:
        commands = core_commands[core]
        num_sources = len(cores_source_flows[core])
        num_sinks = len(cores_sink_flows[core])
        ref_cmd = struct.pack("<II", NT_CMD.NUM,
                              (num_sources | num_sinks << 16))
        assert ref_cmd in commands

    # Make sure all cores have the right set of sources and sinks
    for core in cores:
        commands = core_commands[core]
        sources = cores_source_flows[core]
        sinks = cores_sink_flows[core]

        for source_num, source_flow in enumerate(sources):
            ref_cmd = struct.pack("<II", NT_CMD.SOURCE_KEY | (source_num << 8),
                                  flow_keys[source_flow])
            assert ref_cmd in commands

        for sink_num, sink_flow in enumerate(sinks):
            ref_cmd = struct.pack("<II", NT_CMD.SINK_KEY | (sink_num << 8),
                                  flow_keys[sink_flow])
            assert ref_cmd in commands

    # Make sure all cores have the right set of timing values
    for core in cores:
        commands = core_commands[core]

        ref_cmd = struct.pack("<II", NT_CMD.TIMESTEP, 1000)
        assert ref_cmd in commands

    # Make sure all cores have the right timeout set
    for core in cores:
        commands = core_commands[core]

        ref_cmd0 = struct.pack("<I", NT_CMD.ROUTER_TIMEOUT)
        ref_cmd1 = struct.pack("<I", NT_CMD.ROUTER_TIMEOUT_RESTORE)
        if router_access_core:
            assert ref_cmd0 in commands
            assert ref_cmd1 in commands
        else:
            assert ref_cmd0 not in commands
            assert ref_cmd1 not in commands

    # Make sure all cores packet reinjection enabled if requested
    for core in cores:
        commands = core_commands[core]

        ref_cmd0 = struct.pack("<I", NT_CMD.REINJECTION_ENABLE)
        ref_cmd1 = struct.pack("<I", NT_CMD.REINJECTION_DISABLE)
        if router_access_core:
            assert ref_cmd0 in commands
            assert ref_cmd1 in commands
        else:
            assert ref_cmd0 not in commands
            assert ref_cmd1 not in commands
Exemple #10
0
def test_option_descriptors():
    """Make sure the option descriptors work."""
    e = Experiment(Mock())

    # Defualts should work
    assert e.seed is None
    assert e.probability == 1.0

    # Should be able to set
    e.probability = 0.1
    assert e.probability == 0.1

    # Should be able to set exceptions for groups
    with e.new_group():
        assert e.probability == 0.1
        e.probability = 1.0
        assert e.probability == 1.0

    assert e.probability == 0.1

    # Should be able to set non-exception-supporting options globally
    assert e.record_sent is False
    e.record_sent = True
    assert e.record_sent is True

    # Should be able to set exceptions for cores
    core0 = e.new_core()
    assert core0.probability == 0.1
    core0.probability = 0.5
    assert core0.probability == 0.5
    assert e.probability == 0.1

    # Should be able to set exceptions for flows
    flow0 = e.new_flow(core0, core0)
    assert flow0.probability == 0.5
    flow0.probability = 0.6
    assert flow0.probability == 0.6
    assert core0.probability == 0.5
    assert e.probability == 0.1

    # Should be able to set exceptions in groups for cores and flows
    with e.new_group():
        assert e.probability == 0.1
        assert core0.probability == 0.5
        assert flow0.probability == 0.6

        # Group probability shouldn't override core/flow probability
        e.probability = 1.0
        assert e.probability == 1.0
        assert core0.probability == 0.5
        assert flow0.probability == 0.6

        # Group+core probability should take precidence (but not over flows)
        core0.probability = 10.0
        assert e.probability == 1.0
        assert core0.probability == 10.0
        assert flow0.probability == 0.6

        # Group+flow probability should take overall precidence
        flow0.probability = 20.0
        assert e.probability == 1.0
        assert core0.probability == 10.0
        assert flow0.probability == 20.0

        # Should be able to get non-exception supporting options
        assert e.record_sent is True

        # Shouldn't be able to set non-exception-supporting options
        with pytest.raises(ValueError):
            e.record_sent = False

    # ...but only within the group
    assert e.probability == 0.1
    assert core0.probability == 0.5
    assert flow0.probability == 0.6
def test_run(auto_create_group, samples_per_group, num_vertices,
             num_nets_per_vertex, error, error_code, record, reinject_packets):
    """Make sure that the run command carries out an experiment as would be
    expected."""
    machine = Machine(3, 1)

    mock_mc = Mock()
    mock_mc.get_machine.return_value = machine

    mock_application_ctx = Mock()
    mock_application_ctx.__enter__ = Mock()
    mock_application_ctx.__exit__ = Mock()
    mock_mc.application.return_value = mock_application_ctx

    mock_mc.get_machine.return_value = machine

    if reinject_packets:
        # If reinjecting, a core is added to every chip
        mock_mc.wait_for_cores_to_reach_state.return_value = len(list(machine))
    else:
        # If not reinjecting, only the vertices are given cores
        mock_mc.wait_for_cores_to_reach_state.return_value = num_vertices

    def mock_sdram_file_read(size):
        return error_code + b"\0"*(size - 4)
    mock_sdram_file = Mock()
    mock_sdram_file.read.side_effect = mock_sdram_file_read

    mock_mc.sdram_alloc_as_filelike.return_value = mock_sdram_file

    e = Experiment(mock_mc)
    e.timestep = 1e-6
    e.warmup = 0.01
    e.duration = 0.01
    e.cooldown = 0.01
    e.flush_time = 0.01

    # Record the result of _construct_vertex_commands to allow checking of
    # memory allocation sizes
    construct_vertex_commands = e._construct_vertex_commands
    vertices_commands = {}

    def wrapped_construct_vertex_commands(vertex, *args, **kwargs):
        commands = construct_vertex_commands(vertex=vertex, *args, **kwargs)
        vertices_commands[vertex] = commands
        return commands
    e._construct_vertex_commands = Mock(
        side_effect=wrapped_construct_vertex_commands)

    if record:
        e.record_sent = True

    e.reinject_packets = reinject_packets

    # Create example vertices
    vertices = [e.new_vertex() for _ in range(num_vertices)]
    for v in vertices:
        for _ in range(num_nets_per_vertex):
            e.new_net(v, v)

    # Vertices are placed on sequential chips along the x-axis
    e.placements = {v: (x, 0) for x, v in enumerate(vertices)}

    # Create example groups
    for num_samples in samples_per_group:
        with e.new_group():
            e.record_interval = e.duration / float(num_samples)

    # The run should fail with an exception when expected.
    if error and (num_vertices > 0 or reinject_packets):
        with pytest.raises(NetworkTesterError) as exc_info:
            e.run(0x33, create_group_if_none_exist=auto_create_group)
        results = exc_info.value.results
    else:
        results = e.run(0x33, create_group_if_none_exist=auto_create_group)

    # The results should be of the correct type...
    assert isinstance(results, Results)

    # The results returned should be all zeros (since that is what was written
    # back)
    if record and num_vertices > 0 and num_nets_per_vertex > 0:
        assert sum(results.totals()["sent"]) == 0

    # The supplied app ID should be used
    mock_mc.application.assert_called_once_with(0x33)

    # If reinjection is enabled, the binary should have been loaded
    reinjector_loaded = any("reinjector.aplx" in call[1][0]
                            for call in mock_mc.load_application.mock_calls)
    if reinject_packets:
        assert reinjector_loaded
    else:
        assert not reinjector_loaded

    # Each chip should have been issued with a suitable malloc for any vertices
    # on it.
    for x, vertex in enumerate(vertices):
        cmds_size = vertices_commands[vertex].size
        if record:
            # The space required to record the sent counters.
            result_size = (1 + (num_nets_per_vertex *
                                sum(samples_per_group))) * 4
        else:
            result_size = 4  # Just the status value
        size = max(cmds_size, result_size)
        if reinject_packets:
            # During packet reinjection, core 1 is used.
            core_num = 2
        else:
            core_num = 1
        mock_mc.sdram_alloc_as_filelike.assert_any_call(size, x=x, y=0,
                                                        tag=core_num)

    # The correct number of barriers should have been reached
    num_groups = len(samples_per_group)
    if auto_create_group:
        num_groups = max(1, num_groups)
    assert len(mock_mc.send_signal.mock_calls) == num_groups
def test_construct_vertex_commands(router_access_vertex):
    # XXX: This test is *very* far from being complete. In particular, though
    # the problem supplied is realistic, the output is not checked thouroughly
    # enough.
    e = Experiment(Mock())

    # A simple example network as follows:
    #       n0
    #  v0 ---+--> v1
    #   |    '--> v2
    #   +-------> v3
    #      n1
    # We'll pretend all of them are on the same chip and vertex0 is the one
    # designated as the router-value recording vertex.

    vertex0 = e.new_vertex()
    vertex1 = e.new_vertex()
    vertex2 = e.new_vertex()
    vertex3 = e.new_vertex()

    vertices = [vertex0, vertex1, vertex2, vertex3]

    net0 = e.new_net(vertex0, [vertex1, vertex2])
    net1 = e.new_net(vertex0, vertex3)

    # Seed randomly
    e.seed = None

    e.timestep = 1e-6
    e.warmup = 0.001
    e.duration = 1.0
    e.cooldown = 0.001
    e.flush_time = 0.01

    e.record_sent = True

    e.reinject_packets = True

    # By default, nothing should send and everything should consume
    e.probability = 0.0
    e.consume = True
    e.router_timeout = 240

    # In group0, everything consumes and n0 sends 100% packets and n1 sends 50%
    # packets.
    with e.new_group():
        net0.probability = 1.0
        net1.probability = 0.5

    # In group1, nothing consumes and n0 and n1 send 100%
    with e.new_group():
        net0.probability = 1.0
        net1.probability = 1.0
        e.consume = False
        e.router_timeout = 0

    # In group2, we have a timeout with emergency routing enabled
    with e.new_group():
        e.router_timeout = (16, 16)

    net_keys = {net0: 0xAA00, net1: 0xBB00}

    vertices_source_nets = {
        vertex0: [net0, net1],
        vertex1: [],
        vertex2: [],
        vertex3: [],
    }
    vertices_sink_nets = {
        vertex0: [],
        vertex1: [net0],
        vertex2: [net0],
        vertex3: [net1],
    }

    vertex_commands = {
        vertex: e._construct_vertex_commands(
            vertex=vertex,
            source_nets=vertices_source_nets[vertex],
            sink_nets=vertices_sink_nets[vertex],
            net_keys=net_keys,
            records=[Counters.sent],
            router_access_vertex=router_access_vertex).pack()
        for vertex in vertices
    }

    # Make sure all vertices have the right number of sources/sinks set
    for vertex in vertices:
        commands = vertex_commands[vertex]
        num_sources = len(vertices_source_nets[vertex])
        num_sinks = len(vertices_sink_nets[vertex])
        ref_cmd = struct.pack("<II", NT_CMD.NUM,
                              (num_sources | num_sinks << 8))
        assert ref_cmd in commands

    # Make sure all vertices have the right set of sources and sinks
    for vertex in vertices:
        commands = vertex_commands[vertex]
        sources = vertices_source_nets[vertex]
        sinks = vertices_sink_nets[vertex]

        for source_num, source_net in enumerate(sources):
            ref_cmd = struct.pack("<II", NT_CMD.SOURCE_KEY | (source_num << 8),
                                  net_keys[source_net])
            assert ref_cmd in commands

        for sink_num, sink_net in enumerate(sinks):
            ref_cmd = struct.pack("<II", NT_CMD.SINK_KEY | (sink_num << 8),
                                  net_keys[sink_net])
            assert ref_cmd in commands

    # Make sure all vertices have the right set of timing values
    for vertex in vertices:
        commands = vertex_commands[vertex]

        ref_cmd = struct.pack("<II", NT_CMD.TIMESTEP, 1000)
        assert ref_cmd in commands

    # Make sure all vertices have the right timeout set
    for vertex in vertices:
        commands = vertex_commands[vertex]

        ref_cmd0 = struct.pack("<I", NT_CMD.ROUTER_TIMEOUT)
        ref_cmd1 = struct.pack("<I", NT_CMD.ROUTER_TIMEOUT_RESTORE)
        if router_access_vertex:
            assert ref_cmd0 in commands
            assert ref_cmd1 in commands
        else:
            assert ref_cmd0 not in commands
            assert ref_cmd1 not in commands

    # Make sure all vertices packet reinjection enabled if requested
    for vertex in vertices:
        commands = vertex_commands[vertex]

        ref_cmd0 = struct.pack("<I", NT_CMD.REINJECTION_ENABLE)
        ref_cmd1 = struct.pack("<I", NT_CMD.REINJECTION_DISABLE)
        if router_access_vertex:
            assert ref_cmd0 in commands
            assert ref_cmd1 in commands
        else:
            assert ref_cmd0 not in commands
            assert ref_cmd1 not in commands
def test_option_descriptors():
    """Make sure the option descriptors work."""
    e = Experiment(Mock())

    # Defualts should work
    assert e.seed is None
    assert e.probability == 1.0

    # Should be able to set
    e.probability = 0.1
    assert e.probability == 0.1

    # Should be able to set exceptions for groups
    with e.new_group():
        assert e.probability == 0.1
        e.probability = 1.0
        assert e.probability == 1.0

    assert e.probability == 0.1

    # Should be able to set non-exception-supporting options globally
    assert e.record_sent is False
    e.record_sent = True
    assert e.record_sent is True

    # Should be able to set exceptions for vertices
    vertex0 = e.new_vertex()
    assert vertex0.probability == 0.1
    vertex0.probability = 0.5
    assert vertex0.probability == 0.5
    assert e.probability == 0.1

    # Should be able to set exceptions for nets
    net0 = e.new_net(vertex0, vertex0)
    assert net0.probability == 0.5
    net0.probability = 0.6
    assert net0.probability == 0.6
    assert vertex0.probability == 0.5
    assert e.probability == 0.1

    # Should be able to set exceptions in groups for vertices and nets
    with e.new_group():
        assert e.probability == 0.1
        assert vertex0.probability == 0.5
        assert net0.probability == 0.6

        # Group probability shouldn't override vertex/net probability
        e.probability = 1.0
        assert e.probability == 1.0
        assert vertex0.probability == 0.5
        assert net0.probability == 0.6

        # Group+vertex probability should take precidence (but not over nets)
        vertex0.probability = 10.0
        assert e.probability == 1.0
        assert vertex0.probability == 10.0
        assert net0.probability == 0.6

        # Group+net probability should take overall precidence
        net0.probability = 20.0
        assert e.probability == 1.0
        assert vertex0.probability == 10.0
        assert net0.probability == 20.0

        # Should be able to get non-exception supporting options
        assert e.record_sent is True

        # Shouldn't be able to set non-exception-supporting options
        with pytest.raises(ValueError):
            e.record_sent = False

    # ...but only within the group
    assert e.probability == 0.1
    assert vertex0.probability == 0.5
    assert net0.probability == 0.6