예제 #1
0
def test_machine(monkeypatch):
    # Make sure requesting the machine works, is read-only and produces a
    # deprecation warning.
    from network_tester import experiment
    mock_system_info = Mock()
    mock_machine = Mock()
    mock_build_machine = Mock(return_value=mock_machine)
    mock_mc = Mock()
    monkeypatch.setattr(experiment, "build_machine", mock_build_machine)

    e = Experiment(mock_mc)
    e.system_info = mock_system_info

    with warnings.catch_warnings(record=True) as w:
        warnings.simplefilter("always")

        # Machine object should be returned built from the system info.
        assert not mock_build_machine.called
        assert e.machine is mock_machine
        mock_build_machine.called_once_with(mock_system_info)

        # Should be flagged as deprecated
        assert len(w) == 1
        assert issubclass(w[0].category, DeprecationWarning)

    # Machine should be regenerated every time (i.e. is explicitly read-only)
    mock_build_machine.reset_mock()
    assert e.machine is mock_machine
    mock_build_machine.called_once_with(mock_system_info)
예제 #2
0
def test_system_info(monkeypatch):
    # Make sure lazy-loading of the system_info works
    mock_system_info = Mock()
    mock_mc = Mock()
    mock_mc.get_system_info.return_value = mock_system_info
    e = Experiment(mock_mc)

    # First time the system info should be fetched
    assert not mock_mc.get_system_info.called
    assert e.system_info is mock_system_info
    assert mock_mc.get_system_info.called
    mock_mc.get_system_info.reset_mock()

    # Next time it shouldn't
    assert e.system_info is mock_system_info
    assert not mock_mc.get_system_info.called

    # It shouldn't if set manually either...
    mock_machine2 = Mock()
    e.system_info = mock_machine2
    assert e.system_info is mock_machine2
    assert not mock_mc.get_system_info.called

    # It should if reset manually
    e.system_info = None
    assert e.system_info is mock_system_info
    assert mock_mc.get_system_info.called
def test_empty(num_vertices, num_nets_per_vertex):
    """Test that we can produce a Result object for various scenarios where no
    results will exist."""
    experiment = Experiment(Mock())

    vertices = [experiment.new_vertex() for _ in range(num_vertices)]
    nets = [experiment.new_net(v, v)
            for v in vertices
            for _ in range(num_nets_per_vertex)]
    router_recording_vertices = set()
    placements = {v: (0, 0) for v in vertices}
    routes = {n: RoutingTree((0, 0),
                             set([(Routes.core(vertices.index(n.sinks[0])),
                                   n.sinks[0])]))
              for n in nets}
    vertices_result_data = {v: b"\0\0\0\0" for v in vertices}
    groups = {}
    vertices_records = {v: [] for v in vertices}

    r = Results(experiment, vertices, nets, vertices_records,
                router_recording_vertices, placements, routes,
                vertices_result_data, groups)

    assert r.errors == set()

    assert len(r.totals()) == 0
    assert len(r.vertex_totals()) == 0
    assert len(r.net_totals()) == 0
    assert len(r.net_counters()) == 0
    assert len(r.router_counters()) == 0
예제 #4
0
def test_errors(cores_result_data, expected_errors):
    """Test that we can produce a Result object for various scenarios where no
    results will exist."""
    experiment = Experiment(Mock())

    cores_result_data = {experiment.new_core(): d
                         for d in cores_result_data}
    cores = list(cores_result_data)
    flows = []
    router_recording_cores = set()
    placements = {}
    routes = {}
    groups = {}
    cores_records = {c: [] for c in cores}

    r = Results(experiment, cores, flows, cores_records,
                router_recording_cores, placements, routes,
                cores_result_data, groups)

    assert r.errors == expected_errors

    if expected_errors:
        assert "error" in repr(r)
    else:
        assert "error" not in repr(r)
def test_errors(vertices_result_data, expected_errors):
    """Test that we can produce a Result object for various scenarios where no
    results will exist."""
    experiment = Experiment(Mock())

    vertices_result_data = {experiment.new_vertex(): d
                            for d in vertices_result_data}
    vertices = list(vertices_result_data)
    nets = []
    router_recording_vertices = set()
    placements = {}
    routes = {}
    groups = {}
    vertices_records = {v: [] for v in vertices}

    r = Results(experiment, vertices, nets, vertices_records,
                router_recording_vertices, placements, routes,
                vertices_result_data, groups)

    assert r.errors == expected_errors

    if expected_errors:
        assert "error" in repr(r)
    else:
        assert "error" not in repr(r)
def test_machine(monkeypatch):
    # Make sure lazy-loading of the machine works
    mock_machine = Mock()
    mock_mc = Mock()
    mock_mc.get_machine.return_value = mock_machine
    e = Experiment(mock_mc)

    # First time the machine should be fetched
    assert not mock_mc.get_machine.called
    assert e.machine is mock_machine
    assert mock_mc.get_machine.called
    mock_mc.get_machine.reset_mock()

    # Next time it shouldn't
    assert e.machine is mock_machine
    assert not mock_mc.get_machine.called

    # It shouldn't if set manually either...
    mock_machine2 = Mock()
    e.machine = mock_machine2
    assert e.machine is mock_machine2
    assert not mock_mc.get_machine.called

    # It should if reset manually
    e.machine = None
    assert e.machine is mock_machine
    assert mock_mc.get_machine.called
예제 #7
0
def test_empty(num_cores, num_flows_per_core):
    """Test that we can produce a Result object for various scenarios where no
    results will exist."""
    experiment = Experiment(Mock())

    cores = [experiment.new_core() for _ in range(num_cores)]
    flows = [experiment.new_flow(c, c)
             for c in cores
             for _ in range(num_flows_per_core)]
    router_recording_cores = set()
    placements = {c: (0, 0) for c in cores}
    routes = {f: RoutingTree((0, 0),
                             set([(Routes.core(cores.index(f.sinks[0])),
                                   f.sinks[0])]))
              for f in flows}
    cores_result_data = {c: b"\0\0\0\0" for c in cores}
    groups = {}
    cores_records = {c: [] for c in cores}

    r = Results(experiment, cores, flows, cores_records,
                router_recording_cores, placements, routes,
                cores_result_data, groups)

    assert r.errors == set()

    assert len(r.totals()) == 0
    assert len(r.core_totals()) == 0
    assert len(r.flow_totals()) == 0
    assert len(r.flow_counters()) == 0
    assert len(r.router_counters()) == 0
예제 #8
0
def test_system_info(monkeypatch):
    # Make sure lazy-loading of the system_info works
    mock_system_info = Mock()
    mock_mc = Mock()
    mock_mc.get_system_info.return_value = mock_system_info
    e = Experiment(mock_mc)

    # First time the system info should be fetched
    assert not mock_mc.get_system_info.called
    assert e.system_info is mock_system_info
    assert mock_mc.get_system_info.called
    mock_mc.get_system_info.reset_mock()

    # Next time it shouldn't
    assert e.system_info is mock_system_info
    assert not mock_mc.get_system_info.called

    # It shouldn't if set manually either...
    mock_machine2 = Mock()
    e.system_info = mock_machine2
    assert e.system_info is mock_machine2
    assert not mock_mc.get_system_info.called

    # It should if reset manually
    e.system_info = None
    assert e.system_info is mock_system_info
    assert mock_mc.get_system_info.called
예제 #9
0
def test_machine(monkeypatch):
    # Make sure requesting the machine works, is read-only and produces a
    # deprecation warning.
    from network_tester import experiment
    mock_system_info = Mock()
    mock_machine = Mock()
    mock_build_machine = Mock(return_value=mock_machine)
    mock_mc = Mock()
    monkeypatch.setattr(experiment, "build_machine", mock_build_machine)

    e = Experiment(mock_mc)
    e.system_info = mock_system_info

    with warnings.catch_warnings(record=True) as w:
        warnings.simplefilter("always")

        # Machine object should be returned built from the system info.
        assert not mock_build_machine.called
        assert e.machine is mock_machine
        mock_build_machine.called_once_with(mock_system_info)

        # Should be flagged as deprecated
        assert len(w) == 1
        assert issubclass(w[0].category, DeprecationWarning)

    # Machine should be regenerated every time (i.e. is explicitly read-only)
    mock_build_machine.reset_mock()
    assert e.machine is mock_machine
    mock_build_machine.called_once_with(mock_system_info)
def test_empty(num_cores, num_flows_per_core):
    """Test that we can produce a Result object for various scenarios where no
    results will exist."""
    experiment = Experiment(Mock())

    cores = [experiment.new_core() for _ in range(num_cores)]
    flows = [
        experiment.new_flow(c, c) for c in cores
        for _ in range(num_flows_per_core)
    ]
    router_recording_cores = set()
    placements = {c: (0, 0) for c in cores}
    routes = {
        f: RoutingTree(
            (0, 0), set([(Routes.core(cores.index(f.sinks[0])), f.sinks[0])]))
        for f in flows
    }
    cores_result_data = {c: b"\0\0\0\0" for c in cores}
    groups = {}
    cores_records = {c: [] for c in cores}

    r = Results(experiment, cores, flows, cores_records,
                router_recording_cores, placements, routes, cores_result_data,
                groups)

    assert r.errors == set()

    assert len(r.totals()) == 0
    assert len(r.core_totals()) == 0
    assert len(r.flow_totals()) == 0
    assert len(r.flow_counters()) == 0
    assert len(r.router_counters()) == 0
예제 #11
0
def test_core_chip_incomplete():
    # If only X or only Y are specified, things should fail
    mock_mc = Mock()
    e = Experiment(mock_mc)

    with pytest.raises(ValueError):
        e.new_core(chip_x=0)
    with pytest.raises(ValueError):
        e.new_core(chip_y=0)
예제 #12
0
def test_group_labels():
    # Make sure groups can have labels added
    e = Experiment(Mock())
    group0 = e.new_group()
    group0.add_label("group", 123)
    group0.add_label("colour", "green")

    assert group0.labels == {
        "group": 123,
        "colour": "green",
    }
예제 #13
0
def test_group_labels():
    # Make sure groups can have labels added
    e = Experiment(Mock())
    group0 = e.new_group()
    group0.add_label("group", 123)
    group0.add_label("colour", "green")

    assert group0.labels == {
        "group": 123,
        "colour": "green",
    }
예제 #14
0
def test_hostname_or_machine_controler(monkeypatch):
    # If a hostname is passed in, a new MC should be made
    from network_tester import experiment
    mock_mc = Mock()
    monkeypatch.setattr(experiment, "MachineController", mock_mc)
    Experiment("localhost")
    mock_mc.assert_called_once_with("localhost")
    mock_mc.reset_mock()

    # If an MC is passed in, that should be used
    Experiment(mock_mc)
    assert not mock_mc.called
예제 #15
0
def test_non_nestable_groups():
    # Experimental groups must not be allowed to nest
    e = Experiment(Mock())

    with e.new_group() as group0:
        assert e._cur_group is group0

        with pytest.raises(Exception):
            with e.new_group():
                pass  # pragma: no cover

        # Group should not have been changed
        assert e._cur_group is group0
예제 #16
0
def test_non_nestable_groups():
    # Experimental groups must not be allowed to nest
    e = Experiment(Mock())

    with e.new_group() as group0:
        assert e._cur_group is group0

        with pytest.raises(Exception):
            with e.new_group():
                pass  # pragma: no cover

        # Group should not have been changed
        assert e._cur_group is group0
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)],
    }
예제 #18
0
def test_api_changed_errors():
    # Make sure all API-change errors work
    mock_mc = Mock()
    e = Experiment(mock_mc)

    with pytest.raises(APIChangedError):
        e.new_vertex()
    with pytest.raises(APIChangedError):
        e.new_net()
    with pytest.raises(APIChangedError):
        e.place_and_route()
    with pytest.raises(APIChangedError):
        e.placements = {}
    with pytest.raises(APIChangedError):
        e.allocations = {}
    with pytest.raises(APIChangedError):
        e.routes = {}
def test_new_net():
    # Make sure nets are created and the arguments are those supported by Rig's
    # net construct.
    e = Experiment(Mock())

    vertices = [e.new_vertex() for _ in range(10)]

    # Arguments should be passed through
    net = e.new_net(vertices[0], vertices[1:])
    assert isinstance(net, Net)
    assert net.source == vertices[0]
    assert net.sinks == vertices[1:]
    assert net.weight == 1.0

    # As should kwargs
    net = e.new_net(source=vertices[0], sinks=vertices[9], weight=123)
    assert isinstance(net, Net)
    assert net.source == vertices[0]
    assert net.sinks == [vertices[9]]
    assert net.weight == 123
예제 #20
0
def test_new_flow():
    # Make sure flows are created and the arguments are those supported by
    # Rig's Net construct.
    e = Experiment(Mock())

    cores = [e.new_core() for _ in range(10)]

    # Arguments should be passed through
    flow = e.new_flow(cores[0], cores[1:])
    assert isinstance(flow, RigNet)
    assert flow.source == cores[0]
    assert flow.sinks == cores[1:]
    assert flow.weight == 1.0

    # As should kwargs
    flow = e.new_flow(source=cores[0], sinks=cores[9], weight=123)
    assert isinstance(flow, RigNet)
    assert flow.source == cores[0]
    assert flow.sinks == [cores[9]]
    assert flow.weight == 123
예제 #21
0
def test_new_flow():
    # Make sure flows are created and the arguments are those supported by
    # Rig's Net construct.
    e = Experiment(Mock())

    cores = [e.new_core() for _ in range(10)]

    # Arguments should be passed through
    flow = e.new_flow(cores[0], cores[1:])
    assert isinstance(flow, RigNet)
    assert flow.source == cores[0]
    assert flow.sinks == cores[1:]
    assert flow.weight == 1.0

    # As should kwargs
    flow = e.new_flow(source=cores[0], sinks=cores[9], weight=123)
    assert isinstance(flow, RigNet)
    assert flow.source == cores[0]
    assert flow.sinks == [cores[9]]
    assert flow.weight == 123
예제 #22
0
def test_new_functions():
    # Make sure the e.new_* functions all work as expected
    e = Experiment(Mock())

    # Types should be appropriate
    core0 = e.new_core()
    assert isinstance(core0, Core)
    flow0 = e.new_flow(core0, core0)
    assert isinstance(flow0, Flow)
    group0 = e.new_group()
    assert isinstance(group0, Group)

    # Everything should be given unique names
    core1 = e.new_core()
    flow1 = e.new_flow(core1, core1)
    group1 = e.new_group()
    assert core0.name != core1.name
    assert flow0.name != flow1.name
    assert group0.name != group1.name

    # Custom names should be allowed
    core_foo = e.new_core(name="foo")
    flow_bar = e.new_flow(core_foo, core_foo, name="bar")
    group_baz = e.new_group(name="baz")
    assert core_foo.name == "foo"
    assert flow_bar.name == "bar"
    assert group_baz.name == "baz"

    # The objects should all give their name/type in their repr string
    assert repr(core0) == "<Core 0>"
    assert repr(flow0) == "<Flow 0>"
    assert repr(group0) == "<Group 0>"

    assert repr(core1) == "<Core 1>"
    assert repr(flow1) == "<Flow 1>"
    assert repr(group1) == "<Group 1>"

    assert repr(core_foo) == "<Core 'foo'>"
    assert repr(flow_bar) == "<Flow 'bar'>"
    assert repr(group_baz) == "<Group 'baz'>"
def test_new_functions():
    # Make sure the e.new_* functions all work as expected
    e = Experiment(Mock())

    # Types should be appropriate
    vertex0 = e.new_vertex()
    assert isinstance(vertex0, Vertex)
    net0 = e.new_net(vertex0, vertex0)
    assert isinstance(net0, Net)
    group0 = e.new_group()
    assert isinstance(group0, Group)

    # Everything should be given unique names
    vertex1 = e.new_vertex()
    net1 = e.new_net(vertex1, vertex1)
    group1 = e.new_group()
    assert vertex0.name != vertex1.name
    assert net0.name != net1.name
    assert group0.name != group1.name

    # Custom names should be allowed
    vertex_foo = e.new_vertex(name="foo")
    net_bar = e.new_net(vertex_foo, vertex_foo, name="bar")
    group_baz = e.new_group(name="baz")
    assert vertex_foo.name == "foo"
    assert net_bar.name == "bar"
    assert group_baz.name == "baz"

    # The objects should all give their name/type in their repr string
    assert repr(vertex0) == "<Vertex 0>"
    assert repr(net0) == "<Net 0>"
    assert repr(group0) == "<Group 0>"

    assert repr(vertex1) == "<Vertex 1>"
    assert repr(net1) == "<Net 1>"
    assert repr(group1) == "<Group 1>"

    assert repr(vertex_foo) == "<Vertex 'foo'>"
    assert repr(net_bar) == "<Net 'bar'>"
    assert repr(group_baz) == "<Group 'baz'>"
예제 #24
0
def test_core_chip_incomplete():
    # If only X or only Y are specified, things should fail
    mock_mc = Mock()
    e = Experiment(mock_mc)

    with pytest.raises(ValueError):
        e.new_core(chip_x=0)
    with pytest.raises(ValueError):
        e.new_core(chip_y=0)
def test_errors(cores_result_data, expected_errors):
    """Test that we can produce a Result object for various scenarios where no
    results will exist."""
    experiment = Experiment(Mock())

    cores_result_data = {experiment.new_core(): d for d in cores_result_data}
    cores = list(cores_result_data)
    flows = []
    router_recording_cores = set()
    placements = {}
    routes = {}
    groups = {}
    cores_records = {c: [] for c in cores}

    r = Results(experiment, cores, flows, cores_records,
                router_recording_cores, placements, routes, cores_result_data,
                groups)

    assert r.errors == expected_errors

    if expected_errors:
        assert "error" in repr(r)
    else:
        assert "error" not in repr(r)
def test_to_csv():
    """Make sure the CSV conversion utility actually works..."""
    dt = np.dtype([("a", np.uint), ("b", np.double), ("c", object)])

    e = Experiment(Mock())
    g0 = e.new_group("g0")
    g1 = e.new_group(1)
    c0 = e.new_core(name="c0")
    c1 = e.new_core(name=1)
    f0 = e.new_flow(c0, c0, name="f0")
    f1 = e.new_flow(c1, c1, name=1)

    # Empty dataset
    assert to_csv(np.zeros((0, ), dtype=dt)) == "a,b,c"
    assert to_csv(np.zeros((0, ), dtype=dt), False) == ""

    # Standard data types should be handled correctly
    a = np.zeros((2, ), dtype=dt)
    assert to_csv(a) == ("a,b,c\n" "0,0.0,0\n" "0,0.0,0")
    assert to_csv(a, False) == ("0,0.0,0\n" "0,0.0,0")

    # Nones should be printed specially
    a["c"][0] = None
    assert to_csv(a) == ("a,b,c\n" "0,0.0,NA\n" "0,0.0,0")

    # Groups, Flows and Cores should be printed specially
    a = np.zeros((6, ), dtype=dt)
    a["c"][0] = g0
    a["c"][1] = g1
    a["c"][2] = c0
    a["c"][3] = c1
    a["c"][4] = f0
    a["c"][5] = f1
    assert to_csv(a) == ("a,b,c\n"
                         "0,0.0,g0\n"
                         "0,0.0,1\n"
                         "0,0.0,c0\n"
                         "0,0.0,1\n"
                         "0,0.0,f0\n"
                         "0,0.0,1")
def test_to_csv():
    """Make sure the CSV conversion utility actually works..."""
    dt = np.dtype([("a", np.uint), ("b", np.double), ("c", object)])

    e = Experiment(Mock())
    g0 = e.new_group("g0")
    g1 = e.new_group(1)
    v0 = e.new_vertex("v0")
    v1 = e.new_vertex(1)
    n0 = e.new_net(v0, v0, name="n0")
    n1 = e.new_net(v1, v1, name=1)

    # Empty dataset
    assert to_csv(np.zeros((0,), dtype=dt)) == "a,b,c"
    assert to_csv(np.zeros((0,), dtype=dt), False) == ""

    # Standard data types should be handled correctly
    a = np.zeros((2,), dtype=dt)
    assert to_csv(a) == ("a,b,c\n"
                         "0,0.0,0\n"
                         "0,0.0,0")
    assert to_csv(a, False) == ("0,0.0,0\n"
                                "0,0.0,0")

    # Nones should be printed specially
    a["c"][0] = None
    assert to_csv(a) == ("a,b,c\n"
                         "0,0.0,NA\n"
                         "0,0.0,0")

    # Groups, Nets and Vertices should be printed specially
    a = np.zeros((6,), dtype=dt)
    a["c"][0] = g0
    a["c"][1] = g1
    a["c"][2] = v0
    a["c"][3] = v1
    a["c"][4] = n0
    a["c"][5] = n1
    assert to_csv(a) == ("a,b,c\n"
                         "0,0.0,g0\n"
                         "0,0.0,1\n"
                         "0,0.0,v0\n"
                         "0,0.0,1\n"
                         "0,0.0,n0\n"
                         "0,0.0,1")
예제 #28
0
def test_to_csv():
    """Make sure the CSV conversion utility actually works..."""
    dt = np.dtype([("a", np.uint), ("b", np.double), ("c", object)])

    e = Experiment(Mock())
    g0 = e.new_group("g0")
    g1 = e.new_group(1)
    c0 = e.new_core(name="c0")
    c1 = e.new_core(name=1)
    f0 = e.new_flow(c0, c0, name="f0")
    f1 = e.new_flow(c1, c1, name=1)

    # Empty dataset
    assert to_csv(np.zeros((0,), dtype=dt)) == "a,b,c"
    assert to_csv(np.zeros((0,), dtype=dt), False) == ""

    # Standard data types should be handled correctly
    a = np.zeros((2,), dtype=dt)
    assert to_csv(a) == ("a,b,c\n"
                         "0,0.0,0\n"
                         "0,0.0,0")
    assert to_csv(a, False) == ("0,0.0,0\n"
                                "0,0.0,0")

    # Nones should be printed specially
    a["c"][0] = None
    assert to_csv(a) == ("a,b,c\n"
                         "0,0.0,NA\n"
                         "0,0.0,0")

    # Groups, Flows and Cores should be printed specially
    a = np.zeros((6,), dtype=dt)
    a["c"][0] = g0
    a["c"][1] = g1
    a["c"][2] = c0
    a["c"][3] = c1
    a["c"][4] = f0
    a["c"][5] = f1
    assert to_csv(a) == ("a,b,c\n"
                         "0,0.0,g0\n"
                         "0,0.0,1\n"
                         "0,0.0,c0\n"
                         "0,0.0,1\n"
                         "0,0.0,f0\n"
                         "0,0.0,1")
예제 #29
0
def test_group_num_samples():
    e = Experiment(Mock())

    # When the recording interval is zero, only one sample per group should be
    # made, regardless of group duration.
    with e.new_group() as group:
        e.record_interval = 0.0
        e.duration = 0.0
        assert group.num_samples == 1

    with e.new_group() as group:
        e.record_interval = 0.0
        e.duration = 10.0
        assert group.num_samples == 1

    # When the recording interval set longer than the group, no recordings
    # should be made.
    with e.new_group() as group:
        e.record_interval = 2.0
        e.duration = 1.0
        assert group.num_samples == 0

    # When the recording interval is equal to the group, duration, one
    # recording should be made.
    with e.new_group() as group:
        e.record_interval = 1.0
        e.duration = 1.0
        assert group.num_samples == 1

    # When the recording interval is a fraction of the group duration, the
    # appropriate number of recordings should be made.
    with e.new_group() as group:
        e.record_interval = 0.1
        e.duration = 1.0
        assert group.num_samples == 10
예제 #30
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
예제 #31
0
def experiment(spinnaker_ip):
    return Experiment(spinnaker_ip)
예제 #32
0
def test_run_callbacks():
    """Make sure that the run command's callbacks occur at the right time."""
    num_groups = 3

    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

    mock_mc.wait_for_cores_to_reach_state.return_value = len(system_info)

    def mock_sdram_file_read(size):
        return b"\0\0\0\0" + 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

    # Enough to cause a recording core to be added to every chip
    e.record_dropped_multicast = True

    # Create a number of groups
    groups = []
    for group_num in range(num_groups):
        groups.append(e.new_group())

    before_load_calls = []
    before_group_calls = []
    before_read_results_calls = []

    def before_load(experiment):
        before_load_calls.append(experiment)

        assert experiment is e

        # Loading should not have started
        assert not mock_mc.sdram_alloc_as_filelike.called

    def before_group(experiment, group):
        before_group_calls.append((experiment, group))

        assert experiment is e

        # Loading should have ocurred
        assert mock_mc.sdram_alloc_as_filelike.called

        # The group should appear in the correct sequence
        assert group is groups.pop(0)

        # The number of barriers reached should be progressing
        assert len(mock_mc.wait_for_cores_to_reach_state.mock_calls) == \
            (num_groups - len(groups))

    def before_read_results(experiment):
        before_read_results_calls.append(experiment)

        assert experiment is e

        # All groups should have been run
        assert len(groups) == 0

        # Reading should not have started
        assert not mock_sdram_file.read.called

    # The run should fail with an exception when expected.
    results = e.run(0x33,
                    before_load=before_load,
                    before_group=before_group,
                    before_read_results=before_read_results)

    # The results should come out as usual...
    assert isinstance(results, Results)

    # All callbacks should have been called
    assert len(before_load_calls) == 1
    assert len(before_group_calls) == num_groups
    assert len(before_read_results_calls) == 1
예제 #33
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
def test_option_getters_setters():
    """Make sure the internal option get/set API works."""
    e = Experiment(Mock())

    group0 = e.new_group()
    vertex0 = e.new_vertex()
    vertex1 = e.new_vertex()
    net0 = e.new_net(vertex0, vertex1)
    net1 = e.new_net(vertex1, vertex0)

    # Make sure the getters setters use specific values with the correct
    # priority.

    # Should get global (default) value
    assert e._get_option_value("timestep") == 0.001
    assert e._get_option_value("timestep", group=group0) == 0.001
    assert e._get_option_value("timestep", vert_or_net=vertex0) == 0.001
    assert e._get_option_value("timestep", vert_or_net=net0) == 0.001
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=vertex0) == 0.001
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=net0) == 0.001

    # Should be able to change the default value
    e._set_option_value("timestep", 0.1)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 0.1
    assert e._get_option_value("timestep", vert_or_net=vertex0) == 0.1
    assert e._get_option_value("timestep", vert_or_net=net0) == 0.1
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=vertex0) == 0.1
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=net0) == 0.1

    # Should be able to change the value for a particular vertex
    e._set_option_value("timestep", 0.5, vert_or_net=vertex0)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 0.1
    assert e._get_option_value("timestep", vert_or_net=vertex0) == 0.5
    assert e._get_option_value("timestep", vert_or_net=net0) == 0.5
    assert e._get_option_value("timestep", vert_or_net=net1) == 0.1
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=vertex0) == 0.5
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=net0) == 0.5
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=net1) == 0.1

    # Should be able to change the value for a particular net
    e._set_option_value("timestep", 0.6, vert_or_net=net0)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 0.1
    assert e._get_option_value("timestep", vert_or_net=vertex0) == 0.5
    assert e._get_option_value("timestep", vert_or_net=net0) == 0.6
    assert e._get_option_value("timestep", vert_or_net=net1) == 0.1
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=vertex0) == 0.5
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=net0) == 0.6
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=net1) == 0.1

    # Should be able to change the value for a particular group (vertex/net
    # values should override still)
    e._set_option_value("timestep", 1.0, group=group0)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 1.0
    assert e._get_option_value("timestep", vert_or_net=vertex0) == 0.5
    assert e._get_option_value("timestep", vert_or_net=net0) == 0.6
    assert e._get_option_value("timestep", vert_or_net=net1) == 0.1
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=vertex0) == 0.5
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=net0) == 0.6
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=net1) == 1.0

    # Should be able to change the value for a particular vertex-group pair and
    # the net value should still take priority
    e._set_option_value("timestep", 10.0, group=group0, vert_or_net=vertex0)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 1.0
    assert e._get_option_value("timestep", vert_or_net=vertex0) == 0.5
    assert e._get_option_value("timestep", vert_or_net=net0) == 0.6
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=vertex0) == 10.0
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=net0) == 0.6

    # Should be able to change the value for a particular vertex-group pair and
    # implicitly set a net value which has not been overridden.
    e._set_option_value("timestep", 20.0, group=group0, vert_or_net=vertex1)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 1.0
    assert e._get_option_value("timestep", vert_or_net=vertex1) == 0.1
    assert e._get_option_value("timestep", vert_or_net=net1) == 0.1
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=vertex1) == 20.0
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=net1) == 20.0

    # Should be able to change the value for a particular net-group pair and
    # it should take priority over anything else in that group.
    e._set_option_value("timestep", 30.0, group=group0, vert_or_net=net0)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 1.0
    assert e._get_option_value("timestep", vert_or_net=vertex0) == 0.5
    assert e._get_option_value("timestep", vert_or_net=net0) == 0.6
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=vertex0) == 10.0
    assert e._get_option_value("timestep",
                               group=group0,
                               vert_or_net=net0) == 30.0

    # Should be able to get values which don't support exceptions
    assert e._get_option_value("record_sent") is False
    assert e._get_option_value("record_sent", group=group0) is False
    assert e._get_option_value("record_sent", vert_or_net=vertex0) is False
    assert e._get_option_value("record_sent",
                               group=group0,
                               vert_or_net=vertex0) is False

    # Should be able to set values which don't support exceptions
    e._set_option_value("record_sent", True)
    assert e._get_option_value("record_sent") is True
    assert e._get_option_value("record_sent", group=group0) is True
    assert e._get_option_value("record_sent", vert_or_net=vertex0) is True
    assert e._get_option_value("record_sent",
                               group=group0,
                               vert_or_net=vertex0) is True

    # Shouldn't be able to set exceptions to options which don't support them
    with pytest.raises(ValueError):
        e._set_option_value("record_sent", False, group=group0)
    with pytest.raises(ValueError):
        e._set_option_value("record_sent", False, vert_or_net=vertex0)
    with pytest.raises(ValueError):
        e._set_option_value("record_sent",
                            False,
                            group=group0,
                            vert_or_net=vertex0)
예제 #35
0
def test_run_callbacks():
    """Make sure that the run command's callbacks occur at the right time."""
    num_groups = 3

    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

    mock_mc.wait_for_cores_to_reach_state.return_value = len(system_info)

    def mock_sdram_file_read(size):
        return b"\0\0\0\0" + 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

    # Enough to cause a recording core to be added to every chip
    e.record_dropped_multicast = True

    # Create a number of groups
    groups = []
    for group_num in range(num_groups):
        groups.append(e.new_group())

    before_load_calls = []
    before_group_calls = []
    before_read_results_calls = []

    def before_load(experiment):
        before_load_calls.append(experiment)

        assert experiment is e

        # Loading should not have started
        assert not mock_mc.sdram_alloc_as_filelike.called

    def before_group(experiment, group):
        before_group_calls.append((experiment, group))

        assert experiment is e

        # Loading should have ocurred
        assert mock_mc.sdram_alloc_as_filelike.called

        # The group should appear in the correct sequence
        assert group is groups.pop(0)

        # The number of barriers reached should be progressing
        assert len(mock_mc.wait_for_cores_to_reach_state.mock_calls) == \
            (num_groups - len(groups))

    def before_read_results(experiment):
        before_read_results_calls.append(experiment)

        assert experiment is e

        # All groups should have been run
        assert len(groups) == 0

        # Reading should not have started
        assert not mock_sdram_file.read.called

    # The run should fail with an exception when expected.
    results = e.run(0x33,
                    before_load=before_load,
                    before_group=before_group,
                    before_read_results=before_read_results)

    # The results should come out as usual...
    assert isinstance(results, Results)

    # All callbacks should have been called
    assert len(before_load_calls) == 1
    assert len(before_group_calls) == num_groups
    assert len(before_read_results_calls) == 1
예제 #36
0
def test_option_getters_setters():
    """Make sure the internal option get/set API works."""
    e = Experiment(Mock())

    group0 = e.new_group()
    core0 = e.new_core()
    core1 = e.new_core()
    flow0 = e.new_flow(core0, core1)
    flow1 = e.new_flow(core1, core0)

    # Make sure the getters setters use specific values with the correct
    # priority.

    # Should get global (default) value
    assert e._get_option_value("timestep") == 0.001
    assert e._get_option_value("timestep", group=group0) == 0.001
    assert e._get_option_value("timestep", core_or_flow=core0) == 0.001
    assert e._get_option_value("timestep", core_or_flow=flow0) == 0.001
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=core0) == 0.001
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=flow0) == 0.001

    # Should be able to change the default value
    e._set_option_value("timestep", 0.1)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 0.1
    assert e._get_option_value("timestep", core_or_flow=core0) == 0.1
    assert e._get_option_value("timestep", core_or_flow=flow0) == 0.1
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=core0) == 0.1
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=flow0) == 0.1

    # Should be able to change the value for a particular core
    e._set_option_value("timestep", 0.5, core_or_flow=core0)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 0.1
    assert e._get_option_value("timestep", core_or_flow=core0) == 0.5
    assert e._get_option_value("timestep", core_or_flow=flow0) == 0.5
    assert e._get_option_value("timestep", core_or_flow=flow1) == 0.1
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=core0) == 0.5
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=flow0) == 0.5
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=flow1) == 0.1

    # Should be able to change the value for a particular flow
    e._set_option_value("timestep", 0.6, core_or_flow=flow0)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 0.1
    assert e._get_option_value("timestep", core_or_flow=core0) == 0.5
    assert e._get_option_value("timestep", core_or_flow=flow0) == 0.6
    assert e._get_option_value("timestep", core_or_flow=flow1) == 0.1
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=core0) == 0.5
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=flow0) == 0.6
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=flow1) == 0.1

    # Should be able to change the value for a particular group (core/flow
    # values should override still)
    e._set_option_value("timestep", 1.0, group=group0)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 1.0
    assert e._get_option_value("timestep", core_or_flow=core0) == 0.5
    assert e._get_option_value("timestep", core_or_flow=flow0) == 0.6
    assert e._get_option_value("timestep", core_or_flow=flow1) == 0.1
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=core0) == 0.5
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=flow0) == 0.6
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=flow1) == 1.0

    # Should be able to change the value for a particular core-group pair and
    # the flow value should still take priority
    e._set_option_value("timestep", 10.0, group=group0, core_or_flow=core0)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 1.0
    assert e._get_option_value("timestep", core_or_flow=core0) == 0.5
    assert e._get_option_value("timestep", core_or_flow=flow0) == 0.6
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=core0) == 10.0
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=flow0) == 0.6

    # Should be able to change the value for a particular core-group pair and
    # implicitly set a flow value which has not been overridden.
    e._set_option_value("timestep", 20.0, group=group0, core_or_flow=core1)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 1.0
    assert e._get_option_value("timestep", core_or_flow=core1) == 0.1
    assert e._get_option_value("timestep", core_or_flow=flow1) == 0.1
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=core1) == 20.0
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=flow1) == 20.0

    # Should be able to change the value for a particular flow-group pair and
    # it should take priority over anything else in that group.
    e._set_option_value("timestep", 30.0, group=group0, core_or_flow=flow0)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 1.0
    assert e._get_option_value("timestep", core_or_flow=core0) == 0.5
    assert e._get_option_value("timestep", core_or_flow=flow0) == 0.6
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=core0) == 10.0
    assert e._get_option_value("timestep", group=group0,
                               core_or_flow=flow0) == 30.0

    # Should be able to get values which don't support exceptions
    assert e._get_option_value("record_sent") is False
    assert e._get_option_value("record_sent", group=group0) is False
    assert e._get_option_value("record_sent", core_or_flow=core0) is False
    assert e._get_option_value("record_sent", group=group0,
                               core_or_flow=core0) is False

    # Should be able to set values which don't support exceptions
    e._set_option_value("record_sent", True)
    assert e._get_option_value("record_sent") is True
    assert e._get_option_value("record_sent", group=group0) is True
    assert e._get_option_value("record_sent", core_or_flow=core0) is True
    assert e._get_option_value("record_sent", group=group0,
                               core_or_flow=core0) is True

    # Shouldn't be able to set exceptions to options which don't support them
    with pytest.raises(ValueError):
        e._set_option_value("record_sent", False, group=group0)
    with pytest.raises(ValueError):
        e._set_option_value("record_sent", False, core_or_flow=core0)
    with pytest.raises(ValueError):
        e._set_option_value("record_sent",
                            False,
                            group=group0,
                            core_or_flow=core0)
예제 #37
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
예제 #38
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)],
    }
예제 #39
0
def test_group_num_samples():
    e = Experiment(Mock())

    # When the recording interval is zero, only one sample per group should be
    # made, regardless of group duration.
    with e.new_group() as group:
        e.record_interval = 0.0
        e.duration = 0.0
        assert group.num_samples == 1

    with e.new_group() as group:
        e.record_interval = 0.0
        e.duration = 10.0
        assert group.num_samples == 1

    # When the recording interval set longer than the group, no recordings
    # should be made.
    with e.new_group() as group:
        e.record_interval = 2.0
        e.duration = 1.0
        assert group.num_samples == 0

    # When the recording interval is equal to the group, duration, one
    # recording should be made.
    with e.new_group() as group:
        e.record_interval = 1.0
        e.duration = 1.0
        assert group.num_samples == 1

    # When the recording interval is a fraction of the group duration, the
    # appropriate number of recordings should be made.
    with e.new_group() as group:
        e.record_interval = 0.1
        e.duration = 1.0
        assert group.num_samples == 10
예제 #40
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
예제 #42
0
def test_api_changed_errors():
    # Make sure all API-change errors work
    mock_mc = Mock()
    e = Experiment(mock_mc)

    with pytest.raises(APIChangedError):
        e.new_vertex()
    with pytest.raises(APIChangedError):
        e.new_net()
    with pytest.raises(APIChangedError):
        e.place_and_route()
    with pytest.raises(APIChangedError):
        e.placements = {}
    with pytest.raises(APIChangedError):
        e.allocations = {}
    with pytest.raises(APIChangedError):
        e.routes = {}
예제 #43
0
def test_any_router_registers_used(router_register):
    # Should return true if any router register is set to be recorded
    e = Experiment(Mock())

    # Should not be true by default
    assert not e._any_router_registers_used()

    # Should be true when any register enabled
    setattr(e, "record_{}".format(router_register), True)
    assert e._any_router_registers_used()

    # But not when disabled again
    setattr(e, "record_{}".format(router_register), False)
    assert not e._any_router_registers_used()

    # Should be true if reinjection is used
    e.reinject_packets = True
    assert e._any_router_registers_used()
    e.reinject_packets = False
    assert not e._any_router_registers_used()

    # Should be true when a timeout is set
    e.router_timeout = 16
    assert e._any_router_registers_used()
    e.router_timeout = (16, 16)
    assert e._any_router_registers_used()
    e.router_timeout = None
    assert not e._any_router_registers_used()
    with e.new_group():
        e.router_timeout = 16
    assert e._any_router_registers_used()
예제 #44
0
def test_place_and_route(record_reinjected):
    mock_mc = Mock()
    mock_mc.get_system_info.return_value = SystemInfo(2, 2, {
        (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(2)
        for y in range(2)
    })
    mock_place = Mock(side_effect=place)
    mock_allocate = Mock(side_effect=allocate)
    mock_route = Mock(side_effect=route)

    e = Experiment(mock_mc)
    c0 = e.new_core(0, 0)
    c1 = e.new_core()
    f0 = e.new_flow(c0, c1)
    e.record_reinjected = record_reinjected

    # Prior to place-and-route the placements, allocations and routes should
    # not be available
    with pytest.raises(AttributeError):
        e.placements
    with pytest.raises(AttributeError):
        e.allocations
    with pytest.raises(AttributeError):
        e.routes

    e._place_and_route(place=mock_place,
                       allocate=mock_allocate,
                       route=mock_route)
    assert mock_place.called
    assert mock_allocate.called
    assert mock_route.called

    # Check constraints
    constraints = list(mock_place.mock_calls[0][2]["constraints"])

    # Should reserve core 0 as the monitor
    reserved_monitor = False
    for i, constraint in enumerate(constraints):  # pragma: no branch
        if (  # pragma: no branch
                isinstance(constraint, ReserveResourceConstraint) and
                constraint.resource is Cores and
                constraint.reservation == slice(0, 1) and
                constraint.location is None):
            reserved_monitor = True
            del constraints[i]
            break
    assert reserved_monitor

    # Should force the location of c0
    c0_constrained = False
    for i, constraint in enumerate(constraints):  # pragma: no branch
        if (isinstance(constraint, LocationConstraint) and  # pragma: no branch
                constraint.vertex is c0 and
                constraint.location == (0, 0)):
            c0_constrained = True
            del constraints[i]
            break
    assert c0_constrained

    # If reinjection is used, a reinjection core should have been added for
    # each chip. Record it in a dict {(x, y): _ReinjectionCore, ...}
    reinjection_cores = {}
    for i, constraint in reversed(  # pragma: no branch
            list(enumerate(constraints))):
        if (isinstance(constraint, LocationConstraint) and  # pragma: no branch
                isinstance(constraint.vertex, _ReinjectionCore)):
            reinjection_cores[constraint.location] = constraint.vertex
            del constraints[i]

    if record_reinjected:
        # Should have one reinjection core per chip
        assert set(reinjection_cores) == set(e.system_info)
    else:
        assert len(reinjection_cores) == 0

    # No other constraints should exist
    assert len(constraints) == 0

    # Check that recording cores were not added to chips which already had a
    # core on.
    router_recording_cores = set(e._placements).difference(
        set([c0, c1]).union(set(itervalues(reinjection_cores)))
    )
    core_placements = set([e._placements[c0], e._placements[c1]])
    assert core_placements.isdisjoint(  # pragma: no branch
        set(e._placements[c] for c in router_recording_cores))

    # Check that all chips have a router-recording vertex if reinjection is
    # used but otherwise no cores have been added.
    if record_reinjected:
        all_used_chips = core_placements.union(
            set(e._placements[c] for c in router_recording_cores))
        assert all_used_chips == set(e.system_info)
    else:
        assert len(router_recording_cores) == 0

    # In the placements and allocations reported we should have include the
    # extra cores for recording and reinjection.
    assert set(e._placements) == set(e._allocations)

    # The routes generated should correspond to the flows created
    assert set(e._routes) == set([f0])

    # Finally, check the placements, allocations and routes reported back only
    # include user-created vertices.
    assert set(e.placements) == set([c0, c1])
    assert set(e.allocations) == set([c0, c1])
    assert set(e.routes) == set([f0])
예제 #45
0
def test_any_router_registers_used(router_register):
    # Should return true if any router register is set to be recorded
    e = Experiment(Mock())

    # Should not be true by default
    assert not e._any_router_registers_used()

    # Should be true when any register enabled
    setattr(e, "record_{}".format(router_register), True)
    assert e._any_router_registers_used()

    # But not when disabled again
    setattr(e, "record_{}".format(router_register), False)
    assert not e._any_router_registers_used()

    # Should be true if reinjection is used
    e.reinject_packets = True
    assert e._any_router_registers_used()
    e.reinject_packets = False
    assert not e._any_router_registers_used()

    # Should be true when a timeout is set
    e.router_timeout = 16
    assert e._any_router_registers_used()
    e.router_timeout = (16, 16)
    assert e._any_router_registers_used()
    e.router_timeout = None
    assert not e._any_router_registers_used()
    with e.new_group():
        e.router_timeout = 16
    assert e._any_router_registers_used()
예제 #46
0
def test_new_functions():
    # Make sure the e.new_* functions all work as expected
    e = Experiment(Mock())

    # Types should be appropriate
    core0 = e.new_core()
    assert isinstance(core0, Core)
    flow0 = e.new_flow(core0, core0)
    assert isinstance(flow0, Flow)
    group0 = e.new_group()
    assert isinstance(group0, Group)

    # Everything should be given unique names
    core1 = e.new_core()
    flow1 = e.new_flow(core1, core1)
    group1 = e.new_group()
    assert core0.name != core1.name
    assert flow0.name != flow1.name
    assert group0.name != group1.name

    # Custom names should be allowed
    core_foo = e.new_core(name="foo")
    flow_bar = e.new_flow(core_foo, core_foo, name="bar")
    group_baz = e.new_group(name="baz")
    assert core_foo.name == "foo"
    assert flow_bar.name == "bar"
    assert group_baz.name == "baz"

    # The objects should all give their name/type in their repr string
    assert repr(core0) == "<Core 0>"
    assert repr(flow0) == "<Flow 0>"
    assert repr(group0) == "<Group 0>"

    assert repr(core1) == "<Core 1>"
    assert repr(flow1) == "<Flow 1>"
    assert repr(group1) == "<Group 1>"

    assert repr(core_foo) == "<Core 'foo'>"
    assert repr(flow_bar) == "<Flow 'bar'>"
    assert repr(group_baz) == "<Group 'baz'>"
예제 #47
0
def test_reinjection_used(reinjection_register):
    # Should return true if any router register is set to be recorded
    e = Experiment(Mock())

    # Should not be true by default
    assert not e._reinjection_used()

    # Should be true when any register enabled
    setattr(e, "record_{}".format(reinjection_register), True)
    assert e._reinjection_used()

    # But not when disabled again
    setattr(e, "record_{}".format(reinjection_register), False)
    assert not e._reinjection_used()

    # Should be true when reinjection is enabled at any point
    e.reinject_packets = True
    assert e._reinjection_used()
    e.reinject_packets = False
    assert not e._reinjection_used()
    with e.new_group():
        e.reinject_packets = True
    assert e._reinjection_used()
예제 #48
0
def test_reinjection_used(reinjection_register):
    # Should return true if any router register is set to be recorded
    e = Experiment(Mock())

    # Should not be true by default
    assert not e._reinjection_used()

    # Should be true when any register enabled
    setattr(e, "record_{}".format(reinjection_register), True)
    assert e._reinjection_used()

    # But not when disabled again
    setattr(e, "record_{}".format(reinjection_register), False)
    assert not e._reinjection_used()

    # Should be true when reinjection is enabled at any point
    e.reinject_packets = True
    assert e._reinjection_used()
    e.reinject_packets = False
    assert not e._reinjection_used()
    with e.new_group():
        e.reinject_packets = True
    assert e._reinjection_used()
예제 #49
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
예제 #50
0
def test_place_and_route(record_reinjected):
    mock_mc = Mock()
    mock_mc.get_system_info.return_value = SystemInfo(
        2, 2,
        {(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(2) for y in range(2)})
    mock_place = Mock(side_effect=place)
    mock_allocate = Mock(side_effect=allocate)
    mock_route = Mock(side_effect=route)

    e = Experiment(mock_mc)
    c0 = e.new_core(0, 0)
    c1 = e.new_core()
    f0 = e.new_flow(c0, c1)
    e.record_reinjected = record_reinjected

    # Prior to place-and-route the placements, allocations and routes should
    # not be available
    with pytest.raises(AttributeError):
        e.placements
    with pytest.raises(AttributeError):
        e.allocations
    with pytest.raises(AttributeError):
        e.routes

    e._place_and_route(place=mock_place,
                       allocate=mock_allocate,
                       route=mock_route)
    assert mock_place.called
    assert mock_allocate.called
    assert mock_route.called

    # Check constraints
    constraints = list(mock_place.mock_calls[0][2]["constraints"])

    # Should reserve core 0 as the monitor
    reserved_monitor = False
    for i, constraint in enumerate(constraints):  # pragma: no branch
        if (  # pragma: no branch
                isinstance(constraint, ReserveResourceConstraint)
                and constraint.resource is Cores
                and constraint.reservation == slice(0, 1)
                and constraint.location is None):
            reserved_monitor = True
            del constraints[i]
            break
    assert reserved_monitor

    # Should force the location of c0
    c0_constrained = False
    for i, constraint in enumerate(constraints):  # pragma: no branch
        if (isinstance(constraint, LocationConstraint) and  # pragma: no branch
                constraint.vertex is c0 and constraint.location == (0, 0)):
            c0_constrained = True
            del constraints[i]
            break
    assert c0_constrained

    # If reinjection is used, a reinjection core should have been added for
    # each chip. Record it in a dict {(x, y): _ReinjectionCore, ...}
    reinjection_cores = {}
    for i, constraint in reversed(  # pragma: no branch
            list(enumerate(constraints))):
        if (isinstance(constraint, LocationConstraint) and  # pragma: no branch
                isinstance(constraint.vertex, _ReinjectionCore)):
            reinjection_cores[constraint.location] = constraint.vertex
            del constraints[i]

    if record_reinjected:
        # Should have one reinjection core per chip
        assert set(reinjection_cores) == set(e.system_info)
    else:
        assert len(reinjection_cores) == 0

    # No other constraints should exist
    assert len(constraints) == 0

    # Check that recording cores were not added to chips which already had a
    # core on.
    router_recording_cores = set(e._placements).difference(
        set([c0, c1]).union(set(itervalues(reinjection_cores))))
    core_placements = set([e._placements[c0], e._placements[c1]])
    assert core_placements.isdisjoint(  # pragma: no branch
        set(e._placements[c] for c in router_recording_cores))

    # Check that all chips have a router-recording vertex if reinjection is
    # used but otherwise no cores have been added.
    if record_reinjected:
        all_used_chips = core_placements.union(
            set(e._placements[c] for c in router_recording_cores))
        assert all_used_chips == set(e.system_info)
    else:
        assert len(router_recording_cores) == 0

    # In the placements and allocations reported we should have include the
    # extra cores for recording and reinjection.
    assert set(e._placements) == set(e._allocations)

    # The routes generated should correspond to the flows created
    assert set(e._routes) == set([f0])

    # Finally, check the placements, allocations and routes reported back only
    # include user-created vertices.
    assert set(e.placements) == set([c0, c1])
    assert set(e.allocations) == set([c0, c1])
    assert set(e.routes) == set([f0])
예제 #51
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)],
    }
예제 #52
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
예제 #53
0
def test_option_getters_setters():
    """Make sure the internal option get/set API works."""
    e = Experiment(Mock())

    group0 = e.new_group()
    core0 = e.new_core()
    core1 = e.new_core()
    flow0 = e.new_flow(core0, core1)
    flow1 = e.new_flow(core1, core0)

    # Make sure the getters setters use specific values with the correct
    # priority.

    # Should get global (default) value
    assert e._get_option_value("timestep") == 0.001
    assert e._get_option_value("timestep", group=group0) == 0.001
    assert e._get_option_value("timestep", core_or_flow=core0) == 0.001
    assert e._get_option_value("timestep", core_or_flow=flow0) == 0.001
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=core0) == 0.001
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=flow0) == 0.001

    # Should be able to change the default value
    e._set_option_value("timestep", 0.1)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 0.1
    assert e._get_option_value("timestep", core_or_flow=core0) == 0.1
    assert e._get_option_value("timestep", core_or_flow=flow0) == 0.1
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=core0) == 0.1
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=flow0) == 0.1

    # Should be able to change the value for a particular core
    e._set_option_value("timestep", 0.5, core_or_flow=core0)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 0.1
    assert e._get_option_value("timestep", core_or_flow=core0) == 0.5
    assert e._get_option_value("timestep", core_or_flow=flow0) == 0.5
    assert e._get_option_value("timestep", core_or_flow=flow1) == 0.1
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=core0) == 0.5
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=flow0) == 0.5
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=flow1) == 0.1

    # Should be able to change the value for a particular flow
    e._set_option_value("timestep", 0.6, core_or_flow=flow0)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 0.1
    assert e._get_option_value("timestep", core_or_flow=core0) == 0.5
    assert e._get_option_value("timestep", core_or_flow=flow0) == 0.6
    assert e._get_option_value("timestep", core_or_flow=flow1) == 0.1
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=core0) == 0.5
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=flow0) == 0.6
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=flow1) == 0.1

    # Should be able to change the value for a particular group (core/flow
    # values should override still)
    e._set_option_value("timestep", 1.0, group=group0)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 1.0
    assert e._get_option_value("timestep", core_or_flow=core0) == 0.5
    assert e._get_option_value("timestep", core_or_flow=flow0) == 0.6
    assert e._get_option_value("timestep", core_or_flow=flow1) == 0.1
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=core0) == 0.5
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=flow0) == 0.6
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=flow1) == 1.0

    # Should be able to change the value for a particular core-group pair and
    # the flow value should still take priority
    e._set_option_value("timestep", 10.0, group=group0, core_or_flow=core0)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 1.0
    assert e._get_option_value("timestep", core_or_flow=core0) == 0.5
    assert e._get_option_value("timestep", core_or_flow=flow0) == 0.6
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=core0) == 10.0
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=flow0) == 0.6

    # Should be able to change the value for a particular core-group pair and
    # implicitly set a flow value which has not been overridden.
    e._set_option_value("timestep", 20.0, group=group0, core_or_flow=core1)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 1.0
    assert e._get_option_value("timestep", core_or_flow=core1) == 0.1
    assert e._get_option_value("timestep", core_or_flow=flow1) == 0.1
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=core1) == 20.0
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=flow1) == 20.0

    # Should be able to change the value for a particular flow-group pair and
    # it should take priority over anything else in that group.
    e._set_option_value("timestep", 30.0, group=group0, core_or_flow=flow0)
    assert e._get_option_value("timestep") == 0.1
    assert e._get_option_value("timestep", group=group0) == 1.0
    assert e._get_option_value("timestep", core_or_flow=core0) == 0.5
    assert e._get_option_value("timestep", core_or_flow=flow0) == 0.6
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=core0) == 10.0
    assert e._get_option_value("timestep",
                               group=group0,
                               core_or_flow=flow0) == 30.0

    # Should be able to get values which don't support exceptions
    assert e._get_option_value("record_sent") is False
    assert e._get_option_value("record_sent", group=group0) is False
    assert e._get_option_value("record_sent", core_or_flow=core0) is False
    assert e._get_option_value("record_sent",
                               group=group0,
                               core_or_flow=core0) is False

    # Should be able to set values which don't support exceptions
    e._set_option_value("record_sent", True)
    assert e._get_option_value("record_sent") is True
    assert e._get_option_value("record_sent", group=group0) is True
    assert e._get_option_value("record_sent", core_or_flow=core0) is True
    assert e._get_option_value("record_sent",
                               group=group0,
                               core_or_flow=core0) is True

    # Shouldn't be able to set exceptions to options which don't support them
    with pytest.raises(ValueError):
        e._set_option_value("record_sent", False, group=group0)
    with pytest.raises(ValueError):
        e._set_option_value("record_sent", False, core_or_flow=core0)
    with pytest.raises(ValueError):
        e._set_option_value("record_sent",
                            False,
                            group=group0,
                            core_or_flow=core0)
def example_experiment():
    """The experiment used in example_results."""
    return Experiment(Mock())