Ejemplo n.º 1
0
    def test_single_rate_equivalent_simple_multirate( self ):
        # create a small simple multirate graph
        g = nx.DiGraph()
        g.add_node( 1, wcet = 2 )
        g.add_node( 2, wcet = 3 )
        g.add_edge( 1, 2, production = 2, consumption = 3 )
        g.add_edge( 2, 1, production = 3, consumption = 2, tokens = 4 )
        sdfg = core.SDFGraph(g)

        # transform to single rate equivalent
        hsdfg = single_rate_equivalent( sdfg )
        self.assertIn( (1, 1), hsdfg.nodes() )
        self.assertIn( (1, 2), hsdfg.nodes() )
        self.assertIn( (1, 3), hsdfg.nodes() )
        self.assertIn( (2, 1), hsdfg.nodes() )
        self.assertIn( (2, 2), hsdfg.nodes() )
        self.assertEqual( hsdfg.number_of_nodes(), 5 )
        self.assertEqual( hsdfg.number_of_edges(), 5 )

        self.assertIn( ((1, 2), (2, 1)), hsdfg.edges() )
        self.assertIn( ((1, 3), (2, 2)), hsdfg.edges() )
        self.assertIn( ((2, 2), (1, 1)), hsdfg.edges() )
        self.assertIn( ((2, 2), (1, 2)), hsdfg.edges() )
        self.assertIn( ((2, 1), (1, 3)), hsdfg.edges() )

        toks = lambda a, b: hsdfg.get_edge_data( a, b, 0 ).get('tokens', 0)
        self.assertEqual( toks( (1, 2), (2, 1) ), 0 )
        self.assertEqual( toks( (1, 3), (2, 2) ), 0 )
        self.assertEqual( toks( (2, 2), (1, 1) ), 1 )
        self.assertEqual( toks( (2, 2), (1, 2) ), 1 )
        self.assertEqual( toks( (2, 1), (1, 3) ), 0 )
Ejemplo n.º 2
0
 def test_strictly_periodic_feasible_schedule(self):
     # create a small simple multirate graph
     g = nx.DiGraph()
     g.add_node(1, wcet=2)
     g.add_node(2, wcet=3)
     g.add_edge(1, 2, production=2, consumption=3)
     g.add_edge(2, 1, production=3, consumption=2, tokens=4)
     sdfg = core.SDFGraph(g)
Ejemplo n.º 3
0
def multi_rate_equivalent(sdfg):
    result = nx.MultiDiGraph()
    for v, data in sdfg.nodes_iter(data=True):
        phi = data.get('phases', 1)
        for i in range(phi):
            result.add_node((v, i + 1),
                            wcet=data.get('wcet', core.Cyclic(0))[i])

    for v, w, data in sdfg.edges_iter(data=True):
        Tv = sdfg.nodes[v].get('phases', 1)
        Tw = sdfg.nodes[w].get('phases', 1)
        prates = data.get('production')
        crates = data.get('consumption')
        tokens = data.get('tokens')
        plen = len(prates)
        assert Tv == len(prates)
        assert Tw == len(crates)

        # consuming actor in unfolded graph has a single phase
        # and consumption rate equal to crates.sum()
        csum = crates.sum()

        # sum of production rates in multi-rate equivalent of unfolded graph
        psum = prates.sum()

        gvw = gcd(csum, psum)

        # iterate consuming actors
        for j in range(Tw):
            # determine which incoming channels must be added
            # see Algorithm ? in PhD thesis
            for i in range(plen):
                delta_i_n = tokens + prates.sum(stop=i +
                                                1) - crates.sum(stop=j + 1)
                delta_i1_n = tokens + prates.sum(stop=i) - crates.sum(stop=j +
                                                                      1)
                sol_min = (gvw - delta_i_n - 1) // gvw
                sol_max = (gvw - delta_i1_n - 1) // gvw

                if sol_min < sol_max:
                    # add channel
                    extra_data = dict()
                    if 'var' in data:
                        extra_data['var'] = data['var']

                    result.add_edge((v, i + 1), (w, j + 1),
                                    production=psum,
                                    consumption=csum,
                                    tokens=tokens + prates.sum(stop=i) +
                                    crates.sum(start=j + 1),
                                    **extra_data)

    return core.SDFGraph(result)
Ejemplo n.º 4
0
    def test_single_rate_apx_cyclostatic( self ):
        # create a small simple multirate graph
        g = nx.DiGraph()
        g.add_node( 1, wcet = (2, 1) )
        g.add_node( 2, wcet = (3, 4) )
        g.add_edge( 1, 2, production = (2, 1), consumption = (3, 2) )
        g.add_edge( 2, 1, production = (2, 3), consumption = (0, 3), tokens = 4 )
        sdfg = core.SDFGraph(g)

        # transform to single rate equivalent
        hsdfg = single_rate_apx( sdfg )

        toks = lambda a, b: hsdfg.get_edge_data( a, b, 0 ).get('tokens', 0)
        self.assertEqual( toks( 1, 2 ), -2 )
        self.assertEqual( toks( 2, 1 ), 4 )
Ejemplo n.º 5
0
def generate_cycle(n = 3):
    # generate a rate-vector
    zs = generate_canonical_int_vector( n, 2, 10 )
    g = nx.MultiDiGraph()
    for i in range( n ):
        g.add_node( i + 1, wcet = 1 )

    g.add_edge( n, 1, production = zs[ n - 1 ], consumption = zs[ 0 ], gcd = gcd( zs[ n - 1 ], zs[ 0 ]) )
    for i in range( 1, n ):
        prate = zs[ i - 1 ]
        crate = zs[ i ]
        g.add_edge( i, i + 1, production = prate, consumption = crate, gcd = gcd( prate, crate ))

    apx = transform.single_rate_apx( core.SDFGraph( g ))

    tokens = 0
    for v, w, data in apx.edges_iter( data = True ):
        tokens += data.get( 'tokens', 0 )

    add_tokens( g, 1 - tokens )
    return zs, g
Ejemplo n.º 6
0
                t = t - cs[ 0 ]
                csum += cs[ 0 ]
                cs = cs[1:]
                nops += 1

            vs.append( csum )
            for _ in range( nops ):
                vs.append( 0 )

    return core.cyclic( vs )


if __name__ == '__main__':
    seed( 42 )
    rates, graph = generate_cycle( 9 )
    true_period = 1 / sse.find_throughput( core.SDFGraph( graph ))
    print( "Actual period = {}".format( true_period ))

    sdfg = core.SDFGraph( graph )
    apx = transform.single_rate_apx( sdfg )
    for v in sdfg:
        # measure the impact of vectorizing v 
        _, w, out_data = sdfg.out_edges( v, data = True )[ 0 ]
        u, _, in_data = sdfg.in_edges( v, data = True )[ 0 ]
        p_in, c_in, t_in = in_data['production'], in_data['consumption'], in_data.get('tokens', 0)
        p_out, c_out, t_out = out_data['production'], out_data['consumption'], out_data.get('tokens', 0)
        assert c_in == p_out, "rates must match"
        delta_apx( p_in, t_in, c_in, t_out, c_out )


Ejemplo n.º 7
0
def unfold(sdfg, dct=None, **periods):
    if dct is not None:
        periods.update(dct)

    result = nx.MultiDiGraph()
    for v, data in sdfg.nodes_iter(data=True):
        Tv = periods.get(v, 1)
        for i in range(Tv):
            result.add_node((v, i + 1) if Tv > 1 else v,
                            wcet=data.get('wcet', core.Cyclic(0))[i::Tv])

    for v, w, data in sdfg.edges_iter(data=True):
        Tv = periods.get(v, 1)
        Tw = periods.get(w, 1)
        prates = data.get('production', core.Cyclic(1))
        crates = data.get('consumption', core.Cyclic(1))
        tokens = data.get('tokens', 0)
        plen = len(prates)

        # consuming actor in unfolded graph has a single phase
        # and consumption rate equal to periods_w * crates.sum()
        csum = crates.sum() * Tw // gcd(Tw, len(crates))

        # sum of production rates in multi-rate equivalent of unfolded graph
        psum = prates.sum() * Tv // gcd(Tv, len(prates))

        gm = gcd(csum, psum)
        gvw = gcd(csum, prates.sum())

        # multiplicative inverse of (psum // gvw) modulo (gm // gvw)
        g_cd, mulinv, _ = xgcd(prates.sum() // gvw, gm // gvw)
        assert g_cd == 1

        # iterate consuming actors
        for j in range(Tw):
            # determine which incoming channels must be added
            incoming = set()

            # see Algorithm ? in PhD thesis
            sols = set()
            for n0 in range(len(crates) // gcd(len(crates), Tw)):
                for i0 in range(plen):
                    delta_i_n = tokens + prates.sum(stop=i0 + 1) - crates.sum(
                        stop=j + 1 + n0 * Tw)
                    delta_i1_n = tokens + prates.sum(stop=i0) - crates.sum(
                        stop=j + 1 + n0 * Tw)
                    sol_min = (gvw - delta_i_n - 1) // gvw
                    sol_max = (gvw - delta_i1_n - 1) // gvw

                    for sol in range(sol_min, sol_max):
                        s = (i0 + sol * mulinv * plen) % gcd(
                            Tv, plen * gm // gvw)
                        sols.add(s)

            for i_residue in sols:
                for i0 in range(i_residue, Tv, gcd(Tv, plen * gm // gvw)):
                    incoming.add(i0)

            # compute consumption rates for incoming channels
            tokens_c, incoming_crates = sample_crates(crates, j, Tw)

            # add incoming channels:
            for i in incoming:
                # compute production rates
                tokens_p, incoming_prates = sample_prates(prates, i, Tv)

                extra_data = dict()
                if 'var' in data:
                    extra_data['var'] = data['var']

                # add channel
                vi = (v, i + 1) if Tv > 1 else v
                wj = (w, j + 1) if Tw > 1 else w
                result.add_edge(vi,
                                wj,
                                production=incoming_prates,
                                consumption=incoming_crates,
                                tokens=tokens + tokens_c + tokens_p,
                                **extra_data)

    return core.SDFGraph(result)
Ejemplo n.º 8
0
def periodic_state(graph, time, admissible=True):
    result = nx.MultiDiGraph()
    schedule = sched.strictly_periodic_schedule(graph, admissible)

    # compute completed and active firings
    firings = dict()
    for v, data in graph.nodes(data=True):
        start_v, period_v = schedule[v]
        wcets = data['wcet']

        num_phases = data['phases']
        assert num_phases == len(wcets)

        started_firings = math.floor((time - start_v) / period_v) + 1
        completed_firings = math.floor(
            (time - wcets[0] - start_v) / (period_v * num_phases)) + 1
        for i in range(1, num_phases):
            first_firing = start_v + i * period_v
            completed_firings = min(
                completed_firings,
                math.floor((time - wcets[i] - first_firing) /
                           (period_v * num_phases)) + 1)

        # compute active firings

        idx = completed_productions
        future = dict()
        while start_time <= time:
            # firing with <0-based index> = idx has started but not completed before time
            # add it as an active firing
            future[completion_time] = future.get(completion_time, 0) + 1
            idx += 1
            start_time += period_v
            completion_time = max(completion_time, start_time + wcets[idx])

        firings[v] = completed_productions, future

        result.add_node(v, wcet=wcets[completed_productions:], active=future)

    # compute marking
    for v, w, key, data in graph.edges(keys=True, data=True):
        crates = data['consumption']
        prates = data['production']
        tokens = data['tokens']

        v_completed, _ = firings[v]
        w_completed, w_active = firings[w]

        completed_productions = v_completed
        started_consumptions = w_completed + sum(w_active.values())

        print(
            "({}, {}): Production = {}, consumption = {}, tokens = {}".format(
                v, w, prates, crates, tokens))

        if completed_productions > 0:
            tokens += prates.sum(0, completed_productions)
        else:
            tokens -= prates.sum(completed_productions, 0)

        if started_consumptions > 0:
            tokens -= crates.sum(0, started_consumptions)
        else:
            tokens += crates.sum(started_consumptions, 0)

        result.add_edge(v,
                        w,
                        key,
                        production=prates[completed_productions:],
                        consumption=crates[started_consumptions:],
                        tokens=tokens)

    return core.SDFGraph(result)