예제 #1
0
def create_indirect_read_recvs(ctxt: InvocationContext,
                               builder: GraphTypeBuilder):
    for (ai, arg) in ctxt.indirect_reads:
        with builder.subst(set=ctxt.stat.iter_set.id, index=ai,
                           dat=arg.dat.id):
            props = {"index": DataType(numpy.uint8, shape=())}
            builder.add_input_pin(
                "set_{set}", "{invocation}_arg{index}_read_recv", "dat_{dat}",
                props, None, """
                assert(deviceState->{invocation}_read_recv_count < {invocation}_{set}_read_recv_total);
                // Standard edge trigger for start of invocation
                if(!deviceState->{invocation}_in_progress){{
                    deviceState->{invocation}_in_progress=1;
                    deviceState->{invocation}_read_send_mask = {invocation}_{set}_read_send_mask_all;
                }}
                deviceState->{invocation}_read_recv_count++;
                """)
            if arg.index < 0:
                builder.extend_input_pin_handler(
                    "set_{set}", "{invocation}_arg{index}_read_recv", """
                copy_value(deviceState->{invocation}_arg{index}_buffer[edgeProperties->index], message->value);                
                """)
            else:
                builder.extend_input_pin_handler(
                    "set_{set}", "{invocation}_arg{index}_read_recv", """
                copy_value(deviceState->{invocation}_arg{index}_buffer, message->value);                
                """)
예제 #2
0
def create_indirect_write_recvs(ctxt: InvocationContext,
                                builder: GraphTypeBuilder):
    for (ai, arg) in ctxt.indirect_writes:
        with builder.subst(set=arg.to_set.id,
                           index=ai,
                           dat=arg.dat.id,
                           arity=arg.map.arity):
            if arg.index >= 0:
                props = None
                message_type = "dat_{dat}"
            else:
                props = {"index": scalar_uint32}
                message_type = "dat_{dat}_x{arity}"

            handler = """
                assert(deviceState->{invocation}_write_recv_count < deviceProperties->{invocation}_write_recv_total);
                // Standard edge trigger for start of invocation
                if(!deviceState->{invocation}_in_progress){{
                    deviceState->{invocation}_in_progress=1;
                    deviceState->{invocation}_read_send_mask = {invocation}_{set}_read_send_mask_all;
                }}
                deviceState->{invocation}_write_recv_count++;
            """
            if arg.access_mode == AccessMode.WRITE or arg.access_mode == AccessMode.RW:
                if arg.index >= 0:
                    handler += """
                    copy_value(deviceState->dat_{dat}, message->value);                
                    """
                else:
                    handler += """
                    copy_value(deviceState->dat_{dat}, message->value[edgeProperties->index]);                
                    """
            elif arg.access_mode == AccessMode.INC:
                if arg.index >= 0:
                    handler += """
                    inc_value(deviceState->dat_{dat}, message->value);                
                    """
                else:
                    handler += """
                    inc_value(deviceState->dat_{dat}, message->value[edgeProperties->index]);                
                    """
            else:
                raise RuntimeError("Unexpected access mode {}".format(
                    arg.access_mode))
            builder.add_input_pin("set_{set}",
                                  "{invocation}_arg{index}_write_recv",
                                  message_type, props, None, handler)
예제 #3
0
def create_invocation_begin(ctxt: InvocationContext,
                            builder: GraphTypeBuilder):
    for set in ctxt.get_all_involved_sets():
        with builder.subst(set=set.id):
            handler = """
            // Standard edge trigger for start of invocation
            if(!deviceState->{invocation}_in_progress){{
                deviceState->{invocation}_in_progress=1;
                deviceState->{invocation}_read_send_mask = {invocation}_{set}_read_send_mask_all;
            }}
            deviceState->{invocation}_read_recv_count++;
            """
            if set == ctxt.stat.iter_set:
                for (ai, arg) in ctxt.mutable_global_reads:
                    handler += """
                    copy_value(deviceState->global_{}, message->global_{});
                    """.format(arg.global_.id, arg.global_.id)
            builder.add_input_pin("set_{set}", "{invocation}_begin",
                                  "{invocation}_begin", None, None, handler)
예제 #4
0
def create_invocation_controller(ctxt: InvocationContext,
                                 builder: GraphTypeBuilder):
    handler = """
        assert(deviceState->end_received==0);
        assert(deviceState->invocation_index==RTS_INDEX_controller_{invocation}_begin);
        deviceState->end_received=0;
        deviceState->rts=0;
        """
    for (ai, arg) in ctxt.mutable_global_reads:
        handler += builder.s("""
        copy_value(message->global_{name}, deviceState->global_{name});
        """,
                             name=arg.global_.id)

    builder.add_output_pin("controller", "{invocation}_begin",
                           "{invocation}_begin", handler)

    handler = """
        assert(deviceState->invocation_index==RTS_INDEX_controller_{invocation}_begin);
        assert(deviceState->end_received < graphProperties->{invocation}_total_responding_devices);
        deviceState->end_received++;
    """
    # Collect any inc's to global values
    for (ai, arg) in ctxt.global_writes:
        assert arg.access_mode == AccessMode.INC
        handler += builder.s("""
        inc_value(deviceState->global_{name}, message->global_{name});
        """,
                             name=arg.global_.id)
    # Check whether we have finished
    handler += """
        if(deviceState->end_received == graphProperties->{invocation}_total_responding_devices){{
    """

    handler += """
            deviceState->invocation_index=-1;
            deviceState->end_received=0;
            deviceState->rts=RTS_FLAG_controller_control;
        }}
    """
    builder.add_input_pin("controller", "{invocation}_end", "{invocation}_end",
                          None, None, handler)
예제 #5
0
def compile_global_controller(gi: str, spec: SystemSpecification,
                              builder: GraphTypeBuilder, code: Statement):
    create_controller_states(
        code)  # Make sure every statement has an entry state

    builder.add_device_state(gi, "rts", scalar_uint32)
    builder.add_device_state(gi, "state", scalar_uint32)

    # This will be used as a hidden global, and captures the value
    # of the condition for If and While
    assert "_cond_" in spec.globals

    start_state = get_statement_state(code)
    finish_state = make_state()

    builder.add_rts_clause(gi, "*readyToSend = deviceState->rts;\n")

    with builder.subst(start_state=start_state):
        handler = """
            deviceState->rts=RTS_FLAG_control;
            deviceState->state={start_state};
            handler_log(4, "rts=%x, state=%d", deviceState->rts, deviceState->state);
            """
        for mg in spec.globals.values():
            if isinstance(mg, MutableGlobal):
                handler += """
                copy_value(deviceState->global_{global_}, graphProperties->init_global_{global_});
                """.format(global_=mg.id)

        builder.add_input_pin(gi, "__init__", "__init__", None, None, handler)

    handler = raw("""
    handler_log(4, "rts=%x, state=%d", deviceState->rts, deviceState->state);
    *doSend=0;  // disable this send...
    deviceState->rts=RTS_FLAG_control; // ... but say that we want to send again (by default)
    switch(deviceState->state){
    """)
    handler += render_controller_statement(code, finish_state)
    handler += """
    case {finish_state}:
        handler_log(4, "Hit finish state.");
        handler_exit(0);
        break;
    default:
        handler_log(3, "Unknown state id %d.", deviceState->state);
        assert(0);
    }}
    """.format(finish_state=finish_state)

    builder.create_message_type("control", {})
    builder.add_output_pin(gi, "control", "control", handler)

    for user_code in find_scalars_in_code(code):
        name = user_code.id
        assert user_code.ast
        src = mini_op2.framework.kernel_translator.scalar_to_c(
            user_code.ast, name)
        builder.add_device_shared_code("controller", raw(src))

    for k in code.all_statements():
        if isinstance(k, While):
            name = k.id
            src = mini_op2.framework.kernel_translator.scalar_to_c(
                k.expr_ast, name)
            builder.add_device_shared_code("controller", raw(src))
예제 #6
0
def create_invocation_tester(testIndex: int, isLast: bool,
                             ctxt: InvocationContext,
                             builder: GraphTypeBuilder):
    with builder.subst(testIndex=testIndex, isLast=int(isLast)):
        handler = """
            assert(deviceState->end_received==0);
            assert(deviceState->test_state==2*{testIndex});
            deviceState->test_state++; // Odd value means we are waiting for the return
            deviceState->end_received=0;
            """
        #for (ai,arg) in ctxt.mutable_global_reads:
        #    handler+=builder.s("""
        #    copy_value(message->global_{name}, graphProperties->test_{invocation}_{name}_in);
        #    """,name=arg.global_.id)

        builder.add_output_pin("tester", "{invocation}_begin",
                               "{invocation}_begin", handler)

        handler = """
            assert(deviceState->test_state==2*{testIndex}+1);
            assert(deviceState->end_received < graphProperties->{invocation}_total_responding_devices);
            deviceState->end_received++;
        """
        # Collect any inc's to global values
        for (ai, arg) in ctxt.global_writes:
            assert arg.access_mode == AccessMode.INC
            handler += builder.s("""
            inc_value(deviceState->global_{name}, message->global_{name});
            """,
                                 name=arg.global_.id)
        # Check whether we have finished
        handler += """
            if(deviceState->end_received == graphProperties->{invocation}_total_responding_devices){{
        """
        # Remove for now - not clear how to do this.
        if False:
            # ... and if so, try to check the results are "right"
            for (ai, arg) in ctxt.global_writes:
                handler += builder.s("""
                    check_value(deviceState->global_{name}, graphProperties->test_{invocation}_{name}_out);
                """,
                                     name=arg.global_.id)

        handler += """
                if( {isLast} ){{
                    handler_exit(0);
                }}else{{
                    deviceState->test_state++; // start the next invocation
                    deviceState->end_received=0;
                }}
            }}
        """
        builder.add_input_pin("tester", "{invocation}_end", "{invocation}_end",
                              None, None, handler)

        builder.add_rts_clause(
            "tester", """
        if(deviceState->test_state==2*{testIndex}){{
            *readyToSend = RTS_FLAG_{invocation}_begin;
        }}
        """)
예제 #7
0
def sync_compiler(spec: SystemSpecification, code: Statement):
    builder = GraphTypeBuilder("op2_inst")

    builder.add_shared_code_raw(r"""
    #include <cmath>
    #include <cstdio>
    #include <cstdarg>
    
    void fprintf_stderr(const char *msg, ...)
    {
        va_list v;
        va_start(v,msg);
        vfprintf(stderr, msg, v);
        fprintf(stderr, "\n");
        va_end(v);
    }
    
    template<class T,unsigned N>
    void copy_value(T (&x)[N], const T (&y)[N]){
        for(unsigned i=0; i<N; i++){
            x[i]=y[i];
        }
    }
    
    template<class T,unsigned N,unsigned M>
    void copy_value(T (&x)[N][M], const T (&y)[N][M]){
        for(unsigned i=0; i<N; i++){
            for(unsigned j=0; j<M; j++){
                x[i][j]=y[i][j];
            }
        }
    }
    
    /*template<class T>
    void copy_value(T &x, const T (&y)[1]){
        x[0]=y[0];
    }*/
    
    template<class T,unsigned N>
    void inc_value(T (&x)[N], const T (&y)[N]){
        for(unsigned i=0; i<N; i++){
            x[i]+=y[i];
        }
    }
    
    template<class T,unsigned N>
    void zero_value(T (&x)[N]){
        for(unsigned i=0; i<N; i++){
            x[i]=0;
        }
    }
    
    /* Mainly for debug. Used to roughly check that a calculated value is correct, based
        on "known-good" pre-calculated values. Leaves a lot to be desired... */
    template<class T,unsigned N>
    void check_value(T (&got)[N], T (&ref)[N] ){
        for(unsigned i=0; i<N; i++){
            auto diff=std::abs( got[i] - ref[i] );
            assert( diff < 1e-6 ); // Bleh...
        }
    }
    """)

    builder.create_message_type("executeMsgType", {})

    # Support two kinds of global. Only one can be wired into an instance.
    builder.create_device_type(
        "controller")  # This runs the actual program logic
    builder.create_device_type(
        "tester")  # This solely tests each invocation in turn
    builder.add_device_state("tester", "test_state",
                             DataType(shape=(), dtype=numpy.uint32))
    builder.add_device_state("tester", "end_received",
                             DataType(shape=(), dtype=numpy.uint32))
    builder.add_device_state("controller", "end_received",
                             DataType(shape=(), dtype=numpy.uint32))
    builder.add_device_state("controller", "invocation_index",
                             DataType(shape=(), dtype=numpy.uint32))
    for global_ in spec.globals.values():
        if isinstance(global_, MutableGlobal):
            builder.add_device_state("controller",
                                     "global_{}".format(global_.id),
                                     global_.data_type)
            builder.add_device_state("tester", "global_{}".format(global_.id),
                                     global_.data_type)
            builder.add_graph_property("init_global_{}".format(global_.id),
                                       global_.data_type)
        elif isinstance(global_, ConstGlobal):
            builder.add_graph_property("global_{}".format(global_.id),
                                       global_.data_type)

        else:
            raise RuntimeError("Unexpected global type : {}", type(global_))

    builder.merge_message_type("__init__", {})
    for s in spec.sets.values():
        with builder.subst(set="set_" + s.id):
            builder.create_device_type("{set}")
            init_handler = ""
            for dat in s.dats.values():
                with builder.subst(dat=dat.id):
                    builder.add_device_property("{set}", "init_dat_{dat}",
                                                dat.data_type)
                    builder.add_device_state("{set}", "dat_{dat}",
                                             dat.data_type)
                    init_handler += builder.s(
                        "       copy_value(deviceState->dat_{dat}, deviceProperties->init_dat_{dat});\n"
                    )
            builder.add_input_pin("{set}", "__init__", "__init__", None, None,
                                  init_handler)

    kernels = find_kernels_in_code(code)

    emitted_kernels = set()
    for (i, stat) in enumerate(kernels):
        ctxt = InvocationContext(spec, stat)
        with builder.subst(invocation=ctxt.invocation):
            compile_invocation(spec, builder, ctxt, emitted_kernels)
            create_invocation_tester(i, i + 1 == len(kernels), ctxt, builder)
            create_invocation_controller(ctxt, builder)

    compile_global_controller("controller", spec, builder, code)

    return builder