class NCPTL_CodeGen:
    def __init__(self, options):
        "Initialize the execution-trace module."
        self.backend_name = "c_trace"
        self.errmsg = NCPTL_Error(self.backend_name)

        # Process any arguments we were given.
        leftover_opts = []
        target_backend = ""
        self.use_curses = 0
        for arg in range(0, len(options)):
            trace_match = re.match(r'--trace=(.*)', options[arg])
            if trace_match:
                target_backend = trace_match.group(1)
            elif options[arg] == "--curses":
                self.use_curses = 1
            elif options[arg] == "--help":
                # Utilize c_generic's help-string mechanism.
                import codegen_c_generic
                generic_self = codegen_c_generic.NCPTL_CodeGen()
                generic_self.backend_name = self.backend_name
                generic_self.cmdline_options.extend([
                    ("--trace=<string>", "Specify a backend to trace"),
                    ("--curses",
                     """Display the trace with curses instead of with
                                  fprintf()""")
                ])
                generic_self.show_help()
                raise SystemExit, 0
            else:
                leftover_opts.append(options[arg])
        if not target_backend:
            self.errmsg.error_fatal(
                "a target backend must be specified using --trace")

        # Reparent ourselves to the traced backend.
        try:
            exec("import codegen_%s" % target_backend)
            exec("immediate_ancestor = codegen_%s.NCPTL_CodeGen" %
                 target_backend)
        except:
            self.errmsg.error_fatal("Unable to initialize the %s backend" %
                                    target_backend)
        try:
            self.name2class[target_backend] = immediate_ancestor
        except AttributeError:
            self.name2class = {target_backend: immediate_ancestor}
        try:
            self.name2class["c_trace"].__bases__ = (immediate_ancestor, )
        except KeyError:
            # We're the top-level class.
            self.__class__.__bases__ = (immediate_ancestor, )
            self.name2class["c_trace"] = self.__class__
        self.c_trace_parent = self.name2class["c_trace"].__bases__[0]
        immediate_ancestor.__init__(self, leftover_opts)
        self.intercept_node_funcs(self.name2class["c_trace"])
        if self.use_curses:
            self.set_param("LIBS", "prepend", "-lcurses")
        self.define_eventnames = 1
        self.backend_name = "c_trace + " + self.backend_name
        self.backend_desc = "event tracer atop " + self.backend_desc

        # Add a command-line option to specify which task should be monitored.
        if self.use_curses:
            self.base_global_parameters.extend([
                ("NCPTL_TYPE_INT", "cursestask", "monitor", "M",
                 "Processor to monitor", "0"),
                ("NCPTL_TYPE_INT", "cursesdelay", "delay", "D",
                 "Delay in milliseconds after each screen update (0=no delay)",
                 "0"),
                ("NCPTL_TYPE_INT", "breakpoint", "breakpoint", "B",
                 "Source line at which to enter single-stepping mode (-1=none; 0=first event)",
                 "-1")
            ])

    def intercept_node_funcs(self, someclass):
        """
           Modify all of the n_* methods (except hooks) in a class
           and all its parent classes so as to invoke store_node
           before doing anything else.
        """
        for baseclass in someclass.__bases__:
            self.intercept_node_funcs(baseclass)
        for method_name, method_body in someclass.__dict__.items():
            if self.__class__.__dict__.has_key(method_name):
                # The n_* methods defined in this file already do the
                # equivalent of store_node so there's no need to
                # modify them.
                continue
            if type(method_body) == types.FunctionType and re.match(
                    r'n_[a-z_]+$', method_name):
                # Closure kludge -- work around Python's lack of true
                # closures (and lack of anything even remotely like a
                # closure in Python 1.5).
                class CloKlu:
                    def __init__(self, trueself, method_name, method_body):
                        self.trueself = trueself
                        self.method_name = method_name
                        self.method_body = method_body
                        setattr(trueself, method_name, self.store_node)

                    def store_node(self, node):
                        self.trueself.current_node = node
                        return self.method_body(self.trueself, node)

                CloKlu(self, method_name, method_body)

    # ---------------------- #
    # (Re)implementation of  #
    # hook and other methods #
    # ---------------------- #

    def code_specify_include_files_POST(self, localvars):
        "Specify extra header files needed by the c_trace backend."
        includefiles = self.invoke_hook("code_specify_include_files_POST",
                                        localvars,
                                        invoke_on=self.c_trace_parent)
        if self.use_curses:
            self.push("#include <curses.h>", includefiles)
        return includefiles

    def code_declare_datatypes_EXTRA_EVENT_STATE(self, localvars):
        "Declare some extra tracing state to attach to each event."
        newdecls = []
        self.code_declare_var(type="int",
                              name="virtrank",
                              comment="Task's current virtual rank",
                              stack=newdecls)
        self.code_declare_var(
            type="int",
            name="firstline",
            comment="First line of source code corresponding to this event",
            stack=newdecls)
        self.code_declare_var(
            type="int",
            name="lastline",
            comment="Last line of source code corresponding to this event",
            stack=newdecls)
        newdecls = newdecls + self.invoke_hook(
            "code_declare_datatypes_EXTRA_EVENT_STATE",
            localvars,
            invoke_on=self.c_trace_parent)
        return newdecls

    def code_def_alloc_event_POST(self, localvars):
        "Add some tracing data to every event."
        return ([
            "newevent->virtrank = virtrank;",
            "newevent->firstline = currentline[0];",
            "newevent->lastline = currentline[1];"
        ] + self.invoke_hook("code_def_alloc_event_POST",
                             localvars,
                             invoke_on=self.c_trace_parent))

    def code_def_procev_EVENTS_DECL(self, localvars):
        "Declare extra variables needed within the main loop by the c_trace backend."
        newdecls = []
        if self.use_curses:
            self.code_declare_var(
                type="static int",
                name="prevsrcline",
                rhs="-1",
                comment="Previously executed source-code line",
                stack=newdecls)
        return newdecls + self.invoke_hook("code_def_procev_EVENTS_DECL",
                                           localvars,
                                           invoke_on=self.c_trace_parent)

    def code_define_main_PRE_EVENTS(self, localvars):
        "Prepare curses for the main event loop."
        newcode = self.invoke_hook("code_define_main_PRE_EVENTS",
                                   localvars,
                                   invoke_on=self.c_trace_parent)
        self.push("totalevents = numevents;", newcode)
        if self.use_curses:
            self.push("if (physrank == cursestask) {", newcode)
            self.code_declare_var(name="numevs",
                                  comment="Mutable version of numevents",
                                  stack=newcode)
            self.code_declare_var(name="numtasks",
                                  comment="Mutable version of var_num_tasks",
                                  stack=newcode)
            self.pushmany([
                "if (numevents)",
                "for (numevs=numevents, eventdigits=0; numevs; numevs/=10, eventdigits++)",
                ";",
                "for (numtasks=var_num_tasks-1, taskdigits=0; numtasks; numtasks/=10, taskdigits++)",
                ";", "(void) attrset (A_BOLD);",
                'mvprintw (LINES-1, 0, "Phys: %%*s  Virt: %%*s  Action: %%%ds  Event: %%-*s/%%-*s",'
                % self.event_string_len,
                'taskdigits, "", taskdigits, "", "", eventdigits, "", eventdigits, "");',
                "(void) attrset (A_NORMAL);",
                'mvprintw (LINES-1, 6, "%*d", taskdigits, physrank);',
                'mvprintw (LINES-1, %d+2*taskdigits+eventdigits, "/%%*" NICS, eventdigits, numevents);'
                % (33 + self.event_string_len), "}"
            ],
                          stack=newcode)
        return newcode

    def code_def_procev_PRE_SWITCH(self, localvars):
        "Output a trace message or update the screen before processing an event."
        newcode = []
        if self.use_curses:
            self.event_string_len = 0
            for evstr in self.events_used.keys():
                if self.event_string_len < len(evstr) - 3:
                    self.event_string_len = len(evstr) - 3
            self.pushmany([
                "if (physrank == cursestask) {",
                " /* Indicate which source-code line is currently active. */",
                "if (thisev->firstline-1 != prevsrcline) {",
                "mvchgat (prevsrcline, 6, -1, A_NORMAL, 0, NULL);",
                "(void) touchline (curseswin, prevsrcline, 1);",
                "if (thisev->firstline-1>=0 && thisev->firstline-1<LINES-1) {",
                "mvchgat (thisev->firstline-1, 6, -1, A_STANDOUT, 0, NULL);",
                "(void) touchline (curseswin, thisev->firstline-1, 1);", "}",
                "prevsrcline = thisev->firstline - 1;", "}", "",
                " /* Display other useful trace information. */",
                'mvprintw (LINES-1, 14+taskdigits, "%*d", taskdigits, thisev->virtrank);',
                'mvprintw (LINES-1, 24+2*taskdigits, "%%-%ds", eventnames[thisev->type]);'
                % self.event_string_len,
                'mvprintw (LINES-1, %d+2*taskdigits, "%%*" NICS, eventdigits, i+1);'
                % (33 + self.event_string_len), "",
                " /* Update the screen and process keyboard commands. */",
                "(void) refresh ();",
                "if ((i==0 && breakpoint==0) || ((int)breakpoint==thisev->firstline)) {",
                " /* Enable single-stepping mode. */", "(void) nocbreak();",
                "(void) cbreak();", "(void) nodelay (curseswin, FALSE);", "}",
                "switch (getch()) {", "case 's':", "case 'S':",
                " /* Enable single-stepping mode. */", "(void) nocbreak();",
                "(void) cbreak();", "(void) nodelay (curseswin, FALSE);",
                "break;", "", "case ' ':",
                " /* Enable normal execution mode. */", "if (cursesdelay)",
                "(void) halfdelay ((int) ((cursesdelay + 99) / 100));", "else",
                "(void) nodelay (curseswin, TRUE);", "break;", "", "case 'd':",
                "case 'D':", " /* Delete the break point. */",
                "breakpoint = -1;", "break;", "", "case 'q':", "case 'Q':",
                " /* Quit the program. */",
                'ncptl_fatal ("User interactively entered \\"Q\\" to quit the program");',
                "break;", "", "default:",
                " /* No other keys do anything special. */", "break;", "}", "}"
            ],
                          stack=newcode)
        else:
            self.pushmany([
                'fprintf (stderr, "[TRACE] phys: %d | virt: %d | action: %s | event: %" NICS " / %" NICS " | lines: %d - %d\\n",',
                "physrank, thisev->virtrank, eventnames[thisev->type], i+1, totalevents, thisev->firstline, thisev->lastline);"
            ],
                          stack=newcode)
        newcode = newcode + self.invoke_hook("code_define_main_PRE_SWITCH",
                                             localvars,
                                             invoke_on=self.c_trace_parent)
        return newcode

    def code_declare_globals_EXTRA(self, localvars):
        "Declare additional C global variables needed by the c_trace backend."
        newvars = []
        self.code_declare_var(
            type="int",
            name="currentline",
            arraysize="2",
            comment="Current lines of source code (beginning and ending)",
            stack=newvars)
        self.code_declare_var(name="totalevents",
                              comment="Total # of events in the event list",
                              stack=newvars)
        if self.use_curses:
            self.code_declare_var(
                type="WINDOW *",
                name="curseswin",
                comment="Window to use for curses-based tracing",
                stack=newvars)
            self.code_declare_var(name="cursestask",
                                  comment="Task to trace using curses",
                                  stack=newvars)
            self.code_declare_var(
                name="cursesdelay",
                comment="Delay in milliseconds after each curses screen update",
                stack=newvars)
            self.code_declare_var(
                name="breakpoint",
                comment="Source line at which to enter single-stepping mode",
                stack=newvars)
            self.code_declare_var(type="int",
                                  name="eventdigits",
                                  rhs="1",
                                  comment="Number of digits in numevents",
                                  stack=newvars)
            self.code_declare_var(type="int",
                                  name="taskdigits",
                                  rhs="1",
                                  comment="Number of digits in var_num_tasks",
                                  stack=newvars)

        # Make all declarations static.
        static_newvars = []
        for var in newvars:
            static_newvars.append("static " + var)

        # Provide a hook for including more variables.
        static_newvars = static_newvars + self.invoke_hook(
            "code_declare_globals_EXTRA",
            localvars,
            invoke_on=self.c_trace_parent)
        return static_newvars

    def code_def_init_decls_POST(self, localvars):
        "Declare extra variables needed within conc_initialize()."
        newdecls = self.invoke_hook("code_def_init_decls_POST",
                                    localvars,
                                    invoke_on=self.c_trace_parent)
        if self.use_curses:
            self.srcloop = self.code_declare_var(
                type="int",
                suffix="loop",
                comment="Loop over source-code lines",
                stack=newdecls)
        return newdecls

    def code_define_functions_INIT_COMM_3(self, localvars):
        "Generate code to initialize the c_trace backend."
        initcode = self.invoke_hook("code_define_functions_INIT_COMM_3",
                                    localvars,
                                    invoke_on=self.c_trace_parent,
                                    after=[""])
        if self.use_curses:
            self.pushmany([
                "", " /* Initialize curses. */",
                "if (physrank == cursestask) {", "if (!(curseswin=initscr()))",
                'ncptl_fatal ("Unable to initialize the curses library");',
                "(void) cbreak();", "(void) noecho();", "(void) curs_set (0);",
                "if (cursesdelay)",
                "(void) halfdelay ((int)((cursesdelay+99)/100));", "else",
                "(void) nodelay (curseswin, TRUE);",
                "for (%s=0; %s<(int)(sizeof(sourcecode)/sizeof(char *))-1; %s++) {"
                % (self.srcloop, self.srcloop, self.srcloop),
                "if (%s >= LINES-1)" % self.srcloop, "break;",
                "(void) attrset (A_BOLD);",
                '(void) mvprintw (%s, 0, "%%3d.  ", %s+1);' %
                (self.srcloop, self.srcloop), "(void) attrset (A_NORMAL);",
                '(void) printw ("%%.*s", COLS, sourcecode[%s]);' %
                self.srcloop, "}", "(void) refresh();", "}"
            ],
                          stack=initcode)
        return initcode

    # Completely redefine codegen_c_generic.py's code_allocate_event method.
    def code_allocate_event(self,
                            event_type,
                            stack=None,
                            declare="CONC_EVENT *thisev ="):
        "Push the code to allocate an event and keep track of used events."
        self.push(
            "%s (currentline[0]=%d, currentline[1]=%d, conc_allocate_event (%s));"
            % (declare, self.current_node.lineno0, self.current_node.lineno1,
               event_type), stack)
        self.events_used[event_type] = 1

    def code_def_exit_handler_BODY(self, localvars):
        "Shut down curses if necessary."
        if self.use_curses:
            exitcode = ["if (physrank == cursestask)", "(void) endwin();"]
        else:
            exitcode = []
        exitcode = exitcode + self.invoke_hook("code_def_exit_handler_BODY",
                                               localvars,
                                               invoke_on=self.c_trace_parent)
        return exitcode

    def n_outputs(self, node):
        "Write a message to standard out, but not if we're using curses."
        self.current_node = node
        self.c_trace_parent.n_outputs(self, node)
        if self.use_curses:
            self.arbitrary_code[-1] = []
Exemple #2
0
    # Load the named backend.
    backend = locate_backend(backend)
    try:
        if backend != None:
            if be_verbose:
                sys.stderr.write("# Loading the %s backend from %s ...\n" %
                                 (backend, os.path.abspath(backend2path[backend])))
            orig_path = sys.path
            if pythondir:
                sys.path.insert(0, pythondir)
            if os.environ.has_key("NCPTL_PATH"):
                sys.path[:0] = string.split(os.environ["NCPTL_PATH"], ":")
            exec("from codegen_%s import NCPTL_CodeGen" % backend)
            sys.path = orig_path
    except ImportError, reason:
        errmsg.error_fatal('unable to load backend "%s" (reason: %s)' %
                           (backend, str(reason)))

    # Prepare to announce what we're going to compile.  This is useful
    # in case the user mistakenly omitted a filename and doesn't
    # realize that ncptl expects input from stdin.
    if entirefile == None:
        if filelist==[] or filelist[0]=="-":
            infilename = "<stdin>"

            # As a special case, if --help appears on the command
            # line, and we would normally read from standard input,
            # specify a dummy, empty program so the backend will
            # output a help message and exit.  Note that --help *must*
            # be a backend option at this point because we've already
            # processed the frontend's command line and therefore
            # would have already seen a frontend --help.
class NCPTL_CodeGen:
    def __init__(self, options):
        "Initialize the execution-trace module."
        self.backend_name = "c_trace"
        self.errmsg = NCPTL_Error(self.backend_name)

        # Process any arguments we were given.
        leftover_opts = []
        target_backend = ""
        self.use_curses = 0
        for arg in range(0, len(options)):
            trace_match = re.match(r'--trace=(.*)', options[arg])
            if trace_match:
                target_backend = trace_match.group(1)
            elif options[arg] == "--curses":
                self.use_curses = 1
            elif options[arg] == "--help":
                # Utilize c_generic's help-string mechanism.
                import codegen_c_generic
                generic_self = codegen_c_generic.NCPTL_CodeGen()
                generic_self.backend_name = self.backend_name
                generic_self.cmdline_options.extend([
                    ("--trace=<string>", "Specify a backend to trace"),
                    ("--curses",
                     """Display the trace with curses instead of with
                                  fprintf()""")])
                generic_self.show_help()
                raise SystemExit, 0
            else:
                leftover_opts.append(options[arg])
        if not target_backend:
            self.errmsg.error_fatal("a target backend must be specified using --trace")

        # Reparent ourselves to the traced backend.
        try:
            exec("import codegen_%s" % target_backend)
            exec("immediate_ancestor = codegen_%s.NCPTL_CodeGen" %
                 target_backend)
        except:
            self.errmsg.error_fatal("Unable to initialize the %s backend" % target_backend)
        try:
            self.name2class[target_backend] = immediate_ancestor
        except AttributeError:
            self.name2class = {target_backend: immediate_ancestor}
        try:
            self.name2class["c_trace"].__bases__ = (immediate_ancestor,)
        except KeyError:
            # We're the top-level class.
            self.__class__.__bases__ = (immediate_ancestor,)
            self.name2class["c_trace"] = self.__class__
        self.c_trace_parent = self.name2class["c_trace"].__bases__[0]
        immediate_ancestor.__init__(self, leftover_opts)
        self.intercept_node_funcs(self.name2class["c_trace"])
        if self.use_curses:
            self.set_param("LIBS", "prepend", "-lcurses")
        self.define_eventnames = 1
        self.backend_name = "c_trace + " + self.backend_name
        self.backend_desc = "event tracer atop " + self.backend_desc

        # Add a command-line option to specify which task should be monitored.
        if self.use_curses:
            self.base_global_parameters.extend([("NCPTL_TYPE_INT",
                                                 "cursestask",
                                                 "monitor",
                                                 "M",
                                                 "Processor to monitor",
                                                 "0"),
                                                ("NCPTL_TYPE_INT",
                                                 "cursesdelay",
                                                 "delay",
                                                 "D",
                                                 "Delay in milliseconds after each screen update (0=no delay)",
                                                 "0"),
                                                ("NCPTL_TYPE_INT",
                                                 "breakpoint",
                                                 "breakpoint",
                                                 "B",
                                                 "Source line at which to enter single-stepping mode (-1=none; 0=first event)",
                                                 "-1")])

    def intercept_node_funcs(self, someclass):
        """
           Modify all of the n_* methods (except hooks) in a class
           and all its parent classes so as to invoke store_node
           before doing anything else.
        """
        for baseclass in someclass.__bases__:
            self.intercept_node_funcs(baseclass)
        for method_name, method_body in someclass.__dict__.items():
            if self.__class__.__dict__.has_key(method_name):
                # The n_* methods defined in this file already do the
                # equivalent of store_node so there's no need to
                # modify them.
                continue
            if type(method_body)==types.FunctionType and re.match(r'n_[a-z_]+$', method_name):
                # Closure kludge -- work around Python's lack of true
                # closures (and lack of anything even remotely like a
                # closure in Python 1.5).
                class CloKlu:
                    def __init__(self, trueself, method_name, method_body):
                        self.trueself = trueself
                        self.method_name = method_name
                        self.method_body = method_body
                        setattr(trueself, method_name, self.store_node)

                    def store_node(self, node):
                        self.trueself.current_node = node
                        return self.method_body(self.trueself, node)
                CloKlu(self, method_name, method_body)


    # ---------------------- #
    # (Re)implementation of  #
    # hook and other methods #
    # ---------------------- #

    def code_specify_include_files_POST(self, localvars):
        "Specify extra header files needed by the c_trace backend."
        includefiles = self.invoke_hook("code_specify_include_files_POST",
                                        localvars, invoke_on=self.c_trace_parent)
        if self.use_curses:
            self.push("#include <curses.h>", includefiles)
        return includefiles

    def code_declare_datatypes_EXTRA_EVENT_STATE(self, localvars):
        "Declare some extra tracing state to attach to each event."
        newdecls = []
        self.code_declare_var(type="int", name="virtrank",
                              comment="Task's current virtual rank",
                              stack=newdecls)
        self.code_declare_var(type="int", name="firstline",
                              comment="First line of source code corresponding to this event",
                              stack=newdecls)
        self.code_declare_var(type="int", name="lastline",
                              comment="Last line of source code corresponding to this event",
                              stack=newdecls)
        newdecls = newdecls + self.invoke_hook("code_declare_datatypes_EXTRA_EVENT_STATE",
                                               localvars, invoke_on=self.c_trace_parent)
        return newdecls

    def code_def_alloc_event_POST(self, localvars):
        "Add some tracing data to every event."
        return ([
            "newevent->virtrank = virtrank;",
            "newevent->firstline = currentline[0];",
            "newevent->lastline = currentline[1];"] +
                self.invoke_hook("code_def_alloc_event_POST", localvars,
                                 invoke_on=self.c_trace_parent))

    def code_def_procev_EVENTS_DECL(self, localvars):
        "Declare extra variables needed within the main loop by the c_trace backend."
        newdecls = []
        if self.use_curses:
            self.code_declare_var(type="static int", name="prevsrcline", rhs="-1",
                                  comment="Previously executed source-code line",
                                  stack=newdecls)
        return newdecls + self.invoke_hook("code_def_procev_EVENTS_DECL",
                                           localvars, invoke_on=self.c_trace_parent)


    def code_define_main_PRE_EVENTS(self, localvars):
        "Prepare curses for the main event loop."
        newcode = self.invoke_hook("code_define_main_PRE_EVENTS",
                                   localvars, invoke_on=self.c_trace_parent)
        self.push("totalevents = numevents;", newcode);
        if self.use_curses:
            self.push("if (physrank == cursestask) {", newcode)
            self.code_declare_var(name="numevs",
                                  comment="Mutable version of numevents",
                                  stack=newcode)
            self.code_declare_var(name="numtasks",
                                  comment="Mutable version of var_num_tasks",
                                  stack=newcode)
            self.pushmany([
                "if (numevents)",
                "for (numevs=numevents, eventdigits=0; numevs; numevs/=10, eventdigits++)",
                ";",
                "for (numtasks=var_num_tasks-1, taskdigits=0; numtasks; numtasks/=10, taskdigits++)",
                ";",
                "(void) attrset (A_BOLD);",
                'mvprintw (LINES-1, 0, "Phys: %%*s  Virt: %%*s  Action: %%%ds  Event: %%-*s/%%-*s",' %
                self.event_string_len,
                'taskdigits, "", taskdigits, "", "", eventdigits, "", eventdigits, "");',
                "(void) attrset (A_NORMAL);",
                'mvprintw (LINES-1, 6, "%*d", taskdigits, physrank);',
                'mvprintw (LINES-1, %d+2*taskdigits+eventdigits, "/%%*" NICS, eventdigits, numevents);' %
                (33+self.event_string_len),
                "}"],
                          stack=newcode)
        return newcode

    def code_def_procev_PRE_SWITCH(self, localvars):
        "Output a trace message or update the screen before processing an event."
        newcode = []
        if self.use_curses:
            self.event_string_len = 0
            for evstr in self.events_used.keys():
                if self.event_string_len < len(evstr)-3:
                    self.event_string_len = len(evstr)-3
            self.pushmany([
                "if (physrank == cursestask) {",
                " /* Indicate which source-code line is currently active. */",
                "if (thisev->firstline-1 != prevsrcline) {",
                "mvchgat (prevsrcline, 6, -1, A_NORMAL, 0, NULL);",
                "(void) touchline (curseswin, prevsrcline, 1);",
                "if (thisev->firstline-1>=0 && thisev->firstline-1<LINES-1) {",
                "mvchgat (thisev->firstline-1, 6, -1, A_STANDOUT, 0, NULL);",
                "(void) touchline (curseswin, thisev->firstline-1, 1);",
                "}",
                "prevsrcline = thisev->firstline - 1;",
                "}",
                "",
                " /* Display other useful trace information. */",
                'mvprintw (LINES-1, 14+taskdigits, "%*d", taskdigits, thisev->virtrank);',
                'mvprintw (LINES-1, 24+2*taskdigits, "%%-%ds", eventnames[thisev->type]);' %
                self.event_string_len,
                'mvprintw (LINES-1, %d+2*taskdigits, "%%*" NICS, eventdigits, i+1);' %
                (33+self.event_string_len),
                "",
                " /* Update the screen and process keyboard commands. */",
                "(void) refresh ();",
                "if ((i==0 && breakpoint==0) || ((int)breakpoint==thisev->firstline)) {",
                " /* Enable single-stepping mode. */",
                "(void) nocbreak();",
                "(void) cbreak();",
                "(void) nodelay (curseswin, FALSE);",
                "}",
                "switch (getch()) {",
                "case 's':",
                "case 'S':",
                " /* Enable single-stepping mode. */",
                "(void) nocbreak();",
                "(void) cbreak();",
                "(void) nodelay (curseswin, FALSE);",
                "break;",
                "",
                "case ' ':",
                " /* Enable normal execution mode. */",
                "if (cursesdelay)",
                "(void) halfdelay ((int) ((cursesdelay + 99) / 100));",
                "else",
                "(void) nodelay (curseswin, TRUE);",
                "break;",
                "",
                "case 'd':",
                "case 'D':",
                " /* Delete the break point. */",
                "breakpoint = -1;",
                "break;",
                "",
                "case 'q':",
                "case 'Q':",
                " /* Quit the program. */",
                'ncptl_fatal ("User interactively entered \\"Q\\" to quit the program");',
                "break;",
                "",
                "default:",
                " /* No other keys do anything special. */",
                "break;",
                "}",
                "}"],
                          stack=newcode)
        else:
            self.pushmany([
                'fprintf (stderr, "[TRACE] phys: %d | virt: %d | action: %s | event: %" NICS " / %" NICS " | lines: %d - %d\\n",',
                "physrank, thisev->virtrank, eventnames[thisev->type], i+1, totalevents, thisev->firstline, thisev->lastline);"],
                          stack=newcode)
        newcode = newcode + self.invoke_hook("code_define_main_PRE_SWITCH",
                                             localvars, invoke_on=self.c_trace_parent)
        return newcode

    def code_declare_globals_EXTRA(self, localvars):
        "Declare additional C global variables needed by the c_trace backend."
        newvars = []
        self.code_declare_var(type="int", name="currentline", arraysize="2",
                              comment="Current lines of source code (beginning and ending)",
                              stack=newvars)
        self.code_declare_var(name="totalevents",
                              comment="Total # of events in the event list",
                              stack=newvars)
        if self.use_curses:
            self.code_declare_var(type="WINDOW *", name="curseswin",
                                  comment="Window to use for curses-based tracing",
                                  stack=newvars)
            self.code_declare_var(name="cursestask",
                                  comment="Task to trace using curses",
                                  stack=newvars)
            self.code_declare_var(name="cursesdelay",
                                  comment="Delay in milliseconds after each curses screen update",
                                  stack=newvars)
            self.code_declare_var(name="breakpoint",
                                  comment="Source line at which to enter single-stepping mode",
                                  stack=newvars)
            self.code_declare_var(type="int", name="eventdigits", rhs="1",
                                  comment="Number of digits in numevents",
                                  stack=newvars)
            self.code_declare_var(type="int", name="taskdigits", rhs="1",
                                  comment="Number of digits in var_num_tasks",
                                  stack=newvars)

        # Make all declarations static.
        static_newvars = []
        for var in newvars:
            static_newvars.append("static " + var)

        # Provide a hook for including more variables.
        static_newvars = static_newvars + self.invoke_hook("code_declare_globals_EXTRA",
                                                           localvars, invoke_on=self.c_trace_parent)
        return static_newvars

    def code_def_init_decls_POST(self, localvars):
        "Declare extra variables needed within conc_initialize()."
        newdecls = self.invoke_hook("code_def_init_decls_POST", localvars,
                                    invoke_on=self.c_trace_parent)
        if self.use_curses:
            self.srcloop = self.code_declare_var(type="int", suffix="loop",
                                                 comment="Loop over source-code lines",
                                                 stack=newdecls)
        return newdecls

    def code_define_functions_INIT_COMM_3(self, localvars):
        "Generate code to initialize the c_trace backend."
        initcode = self.invoke_hook("code_define_functions_INIT_COMM_3",
                                    localvars,
                                    invoke_on=self.c_trace_parent,
                                    after=[""])
        if self.use_curses:
            self.pushmany([
                "",
                " /* Initialize curses. */",
                "if (physrank == cursestask) {",
                "if (!(curseswin=initscr()))",
                'ncptl_fatal ("Unable to initialize the curses library");',
                "(void) cbreak();",
                "(void) noecho();",
                "(void) curs_set (0);",
                "if (cursesdelay)",
                "(void) halfdelay ((int)((cursesdelay+99)/100));",
                "else",
                "(void) nodelay (curseswin, TRUE);",
                "for (%s=0; %s<(int)(sizeof(sourcecode)/sizeof(char *))-1; %s++) {" %
                (self.srcloop, self.srcloop, self.srcloop),
                "if (%s >= LINES-1)" % self.srcloop,
                "break;",
                "(void) attrset (A_BOLD);",
                '(void) mvprintw (%s, 0, "%%3d.  ", %s+1);' %
                (self.srcloop, self.srcloop),
                "(void) attrset (A_NORMAL);",
                '(void) printw ("%%.*s", COLS, sourcecode[%s]);' % self.srcloop,
                "}",
                "(void) refresh();",
                "}"],
                          stack=initcode)
        return initcode

    # Completely redefine codegen_c_generic.py's code_allocate_event method.
    def code_allocate_event(self, event_type, stack=None,
                            declare="CONC_EVENT *thisev ="):
        "Push the code to allocate an event and keep track of used events."
        self.push("%s (currentline[0]=%d, currentline[1]=%d, conc_allocate_event (%s));" %
                  (declare,
                   self.current_node.lineno0, self.current_node.lineno1,
                   event_type),
                  stack)
        self.events_used[event_type] = 1

    def code_def_exit_handler_BODY(self, localvars):
        "Shut down curses if necessary."
        if self.use_curses:
            exitcode = ["if (physrank == cursestask)",
                        "(void) endwin();"]
        else:
            exitcode = []
        exitcode = exitcode + self.invoke_hook("code_def_exit_handler_BODY",
                                               localvars, invoke_on=self.c_trace_parent)
        return exitcode

    def n_outputs(self, node):
        "Write a message to standard out, but not if we're using curses."
        self.current_node = node
        self.c_trace_parent.n_outputs(self, node)
        if self.use_curses:
            self.arbitrary_code[-1] = []
Exemple #4
0
    backend = locate_backend(backend)
    try:
        if backend != None:
            if be_verbose:
                sys.stderr.write(
                    "# Loading the %s backend from %s ...\n" %
                    (backend, os.path.abspath(backend2path[backend])))
            orig_path = sys.path
            if pythondir:
                sys.path.insert(0, pythondir)
            if os.environ.has_key("NCPTL_PATH"):
                sys.path[:0] = string.split(os.environ["NCPTL_PATH"], ":")
            exec("from codegen_%s import NCPTL_CodeGen" % backend)
            sys.path = orig_path
    except ImportError, reason:
        errmsg.error_fatal('unable to load backend "%s" (reason: %s)' %
                           (backend, str(reason)))

    # Prepare to announce what we're going to compile.  This is useful
    # in case the user mistakenly omitted a filename and doesn't
    # realize that ncptl expects input from stdin.
    if entirefile == None:
        if filelist == [] or filelist[0] == "-":
            infilename = "<stdin>"

            # As a special case, if --help appears on the command
            # line, and we would normally read from standard input,
            # specify a dummy, empty program so the backend will
            # output a help message and exit.  Note that --help *must*
            # be a backend option at this point because we've already
            # processed the frontend's command line and therefore
            # would have already seen a frontend --help.
class NCPTL_CodeGen:
    thisfile = globals()["__file__"]

    #---------------------#
    # Exported functions  #
    # (called from the    #
    # compiler front end) #
    #---------------------#

    def __init__(self, options=None):
        "Initialize the LibSea code generation module."
        self.errmsg = NCPTL_Error()     # Placeholder until generate is called

        # Process any arguments we were given.
        self.source_truncate = 100      # Truncate node source code after this many characters
        for arg in range(0, len(options)):
            arg_match = re.match(r'--(node-code)=(.*)', options[arg])
            if arg_match:
                argname, argvalue = arg_match.group(1), arg_match.group(2)
                if argname == "node-code":
                    argvalue = int(argvalue)
                    if argvalue == -1:
                        self.source_truncate = sys.maxint
                    else:
                        self.source_truncate = argvalue
        for arg in range(0, len(options)):
            if options[arg] == "--help":
                self.show_help()
                sys.exit(0)

    def show_help(self):
        "Output a help message."
        print """\
Usage: libsea_ast [OPTION...]
  --node-code=<number>       Truncate node source code after this many
                             characters [default: 100]

Help options:
  --help                     Show this help message"""

    def generate(self, ast, filesource='<stdin>', filetarget="-", sourcecode=None):
        "Compile an AST into a list of lines of LibSea code."
        self.filesource = filesource       # Input file
        self.sourcecode = sourcecode       # coNCePTuaL source code
        self.backend_name = "libsea_graph"
        self.backend_desc = "parse tree in CAIDA's LibSea graph format"
        self.errmsg = NCPTL_Error(filesource)
        self.next_global_ID = 0            # Next LibSea ID to assign to a node

        # Write a LibSea prologue.
        self.libseacode = []
        if self.filesource == "<command line>":
            inputfile = "the source program"
            cleanfilename = "stdin_graph"
        else:
            inputfile = os.path.abspath(self.filesource)
            cleanfilename = (re.sub(r'\W', '_',
                                    os.path.splitext(os.path.split(inputfile)[1])[0]) +
                             "_graph")
        self.libseacode.extend([
                "#" * 78,
                "# This file was generated by coNCePTuaL on %s" %
                time.asctime(time.localtime(time.time())),
                "# using the %s backend (%s)." %
                (self.backend_name, self.backend_desc),
                "# Do not modify this file; modify %s instead." % inputfile,
                "#" * 78])
        if self.sourcecode:
            self.libseacode.extend([
                "#",
                "# Entire source program",
                "# ---------------------"])
            for oneline in string.split(string.strip(self.sourcecode), "\n"):
                self.libseacode.append("#   %s" % oneline)
            self.libseacode.extend([
                    "#",
                    "#" * 78,
                    ""])

        # Acquire information about the graph structure.
        self.assign_node_IDs(ast)
        nodes = sorted(self.accumulate_nodes(ast))
        nodefmtwidth = int(math.ceil(math.log10(len(nodes))))
        links = sorted(self.accumulate_edges(ast))
        linkfmtwidth = int(math.ceil(math.log10(len(links))))

        # Produce LibSea code for the graph metadata.
        self.libseacode.extend([
                "Graph",
                "{",
                "  ### metadata ###",
                '  @name="%s";' % os.path.splitext(os.path.basename(filesource))[0],
                '  @description="Parse tree for %s";' % inputfile,
                "  @numNodes=%d;" % len(nodes),
                "  @numLinks=%d;" % len(links),
                "  @numPaths=0;",
                "  @numPathLinks=0;",
                ""])

        # Produce LibSea code for the graph structural data.
        self.libseacode.extend([
                "  ### structural data ###",
                "  @links=["])
        for src, dest in links[:-1]:
            self.libseacode.append("    { %*d; %*d; }," % \
                                       (linkfmtwidth, src, linkfmtwidth, dest))
        self.libseacode.append("    { %*d; %*d; }" % \
                                   (linkfmtwidth, links[-1][0],
                                    linkfmtwidth, links[-1][1]))
        self.libseacode.extend([
                "  ];",
                "  @paths=;",
                ""])

        # Produce LibSea code for the graph attribute data.
        self.libseacode.extend([
                "  ### attribute data ###",
                "  @enumerations=;",
                "  @attributeDefinitions=["])
        self.libseacode.extend(self.format_attribute("Type", 1, nodes))
        self.libseacode.extend(self.format_attribute("Attribute", 2, nodes))
        self.libseacode.extend(self.format_attribute("Source_code", 3, nodes))
        self.libseacode.extend(self.format_selection_attr("Is_simple_stmt",
                                                          [n[0] for n in nodes if n[1] == "simple_stmt"]))
        self.libseacode.extend(self.format_selection_attr("Is_constant",
                                                          [n[0] for n in nodes if n[4]]))
        self.libseacode.extend(self.format_selection_attr("Is_definition",
                                                          [n[0] for n in nodes if n[5]]))
        self.libseacode.extend(self.format_selection_attr("Is_leaf",
                                               self.accumulate_leaves(ast)))
        self.libseacode.extend([
                "    {",
                "      @name=$Is_root_node;",
                "      @type=bool;",
                "      @default=|| false ||;",
                "      @nodeValues=[ { 0; T; } ];   # Root node",
                "      @linkValues=["])
        for linknum in range(len(links)-1):
            self.libseacode.append("        { %*d; T; }," % (linkfmtwidth, linknum))
        self.libseacode.extend([
                "        { %*d; T; }" % (linkfmtwidth, len(links)-1),
                "      ];",
                "      @pathValues=;",
                "    }",
                "  ];",
                "  @qualifiers=[",
                "    {",
                "      @type=$spanning_tree;",
                "      @name=$Parse_tree;",
                '      @description="Abstract syntax tree corresponding to %s";' % inputfile,
                "      @attributes=[",
                "        { @attribute=7; @alias=$root; },",
                "        { @attribute=7; @alias=$tree_link; }",
                "      ];",
                "    }",
                "  ];",
                ""])

        # Produce LibSea code for the remaining (unused) graph features.
        self.libseacode.extend([
                "  ### visualization hints ###",
                "  ; ; ; ;",
                "",
                "  ### interface hints ###",
                "  ; ; ; ; ;",
                "}"])

        # Return the complete LibSea graph.
        return self.libseacode

    def compile_only(self, progfilename, codelines, outfilename, verbose=0, keepints=0):
        "Output LibSea code."
        if progfilename == "<command line>":
            progfilename = "a.out.ncptl"
        if outfilename == "-":
            outfilename, _ = os.path.splitext(progfilename)
            outfilename = outfilename + ".graph"
        try:
            outfile = open(outfilename, "w")
            for oneline in codelines:
                outfile.write("%s\n" % oneline)
            outfile.close()
        except IOError, (errno, strerror):
            self.errmsg.error_fatal("Unable to produce %s (%s)" % (outfilename, strerror),
                                    filename=self.backend_name)
        if verbose:
            sys.stderr.write("# Files generated: %s\n" % outfilename)
Exemple #6
0
class NCPTL_CodeGen:
    def __init__(self, options):
        "Initialize the profiling module."
        self.backend_name = "c_profile"
        self.errmsg = NCPTL_Error(self.backend_name)

        # Process any arguments we were given.
        leftover_opts = []
        target_backend = ""
        for arg in range(0, len(options)):
            profile_match = re.match(r'--profile=(.*)', options[arg])
            if profile_match:
                target_backend = profile_match.group(1)
            elif options[arg] == "--help":
                # Utilize c_generic's help-string mechanism.
                import codegen_c_generic
                generic_self = codegen_c_generic.NCPTL_CodeGen()
                generic_self.backend_name = self.backend_name
                generic_self.cmdline_options.extend([
                    ("--profile=<string>", "Specify a backend to profile")
                ])
                generic_self.show_help()
                raise SystemExit, 0
            else:
                leftover_opts.append(options[arg])
        if not target_backend:
            self.errmsg.error_fatal(
                "a target backend must be specified using --profile")

        # Reparent ourselves to the profiled backend.
        try:
            exec("import codegen_%s" % target_backend)
            exec("immediate_ancestor = codegen_%s.NCPTL_CodeGen" %
                 target_backend)
        except:
            self.errmsg.error_fatal("Unable to initialize the %s backend" %
                                    target_backend)
        try:
            self.name2class[target_backend] = immediate_ancestor
        except AttributeError:
            self.name2class = {target_backend: immediate_ancestor}
        try:
            self.name2class["c_profile"].__bases__ = (immediate_ancestor, )
        except KeyError:
            # We're the top-level class.
            self.__class__.__bases__ = (immediate_ancestor, )
            self.name2class["c_profile"] = self.__class__
        self.c_profile_parent = self.name2class["c_profile"].__bases__[0]
        immediate_ancestor.__init__(self, leftover_opts)
        self.define_eventnames = 1
        self.backend_name = "c_profile + " + self.backend_name
        self.backend_desc = "event profiler atop " + self.backend_desc

    # ---------------------- #
    # (Re)implementation of  #
    # hook and other methods #
    # ---------------------- #

    def code_declare_globals_EXTRA(self, localvars):
        "Declare a few arrays to store profile data."
        newcode = self.invoke_hook("code_declare_globals_EXTRA",
                                   localvars,
                                   invoke_on=self.c_profile_parent)
        self.code_declare_var(name="profeventtimings",
                              arraysize="EV_CODE+1",
                              type="static ncptl_int",
                              comment="Total time spent in each event",
                              stack=newcode)
        self.code_declare_var(
            name="profeventtallies",
            arraysize="EV_CODE+1",
            type="static ncptl_int",
            comment="Number of times each event was executed",
            stack=newcode)
        return newcode

    def code_define_main_POST_INIT(self, localvars):
        "Initialize the profile data."
        newcode = self.invoke_hook("code_define_main_POST_INIT",
                                   localvars,
                                   invoke_on=self.c_profile_parent)
        self.push(
            "memset ((void *)profeventtimings, 0, sizeof(ncptl_int)*(EV_CODE+1));",
            newcode)
        self.push(
            "memset ((void *)profeventtallies, 0, sizeof(ncptl_int)*(EV_CODE+1));",
            newcode)
        return newcode

    def code_def_procev_EVENTS_DECL(self, localvars):
        "Declare a variable for storing an event starting time."
        newcode = self.invoke_hook("code_def_procev_EVENTS_DECL",
                                   localvars,
                                   invoke_on=self.c_profile_parent)
        self.code_declare_var(
            name="eventtype",
            rhs="thisev->type",
            comment=
            "Preserved copy of thisev->type in case EV_REPEAT alters thisev",
            stack=newcode)
        self.code_declare_var(
            name="eventstarttime",
            rhs="ncptl_time()",
            comment="Time at which the current event began executing",
            stack=newcode)
        return newcode

    def code_def_procev_POST_SWITCH(self, localvars):
        "Accumulate the time taken by the current event."
        newcode = self.invoke_hook("code_def_procev_POST_SWITCH",
                                   localvars,
                                   invoke_on=self.c_profile_parent)
        self.push(
            "profeventtimings[eventtype] += ncptl_time() - eventstarttime;",
            stack=newcode)
        self.push("profeventtallies[eventtype]++;", stack=newcode)
        return newcode

    def code_def_finalize_DECL(self, localvars):
        "Allocate variables needed to write the profiling information."
        newcode = self.invoke_hook("code_def_finalize_DECL",
                                   localvars,
                                   invoke_on=self.c_profile_parent)
        if self.program_uses_log_file:
            self.code_declare_var(type="char",
                                  name="profilekey",
                                  arraysize="256",
                                  comment="Space to hold an event name",
                                  stack=newcode)
            self.code_declare_var(
                type="char",
                name="profilevalue",
                arraysize="256",
                comment="Space to hold a line of profile information",
                stack=newcode)
        self.profloopvar = self.code_declare_var(
            type="int",
            suffix="ev",
            comment="Loop over event types",
            stack=newcode)
        self.code_declare_var(name="numevents",
                              rhs="ncptl_queue_length (eventqueue)",
                              comment="Total number of events processed",
                              stack=newcode)
        return newcode

    def code_def_finalize_PRE(self, localvars):
        "Write profiling information to either stderr or a log file."
        newcode = self.invoke_hook("code_def_finalize_PRE",
                                   localvars,
                                   invoke_on=self.c_profile_parent)
        profloopvar = self.profloopvar
        if self.program_uses_log_file:
            # Write to the log file.
            self.pushmany([
                "for (%s=0; %s<NUM_EVS; %s++)" % ((profloopvar, ) * 3),
                "if (profeventtallies[%s]) {" % profloopvar,
                'sprintf (profilekey, "Profile of %%s (microseconds, count, average)", eventnames[%s]);'
                % profloopvar,
                'sprintf (profilevalue, "%%" NICS " %%" NICS " %%.1f", profeventtimings[%s], profeventtallies[%s], (double)profeventtimings[%s]/(double)profeventtallies[%s]);'
                % ((profloopvar, ) * 4),
                "ncptl_log_add_comment (profilekey, profilevalue);", "}",
                'strcpy (profilekey, "Profile of event memory");',
                'sprintf (profilevalue, "%" NICS " bytes (%" NICS " events * %" NICS " bytes/event)",'
                "numevents*sizeof(CONC_EVENT), numevents, (ncptl_int)sizeof(CONC_EVENT));",
                "ncptl_log_add_comment (profilekey, profilevalue);"
            ],
                          stack=newcode)
        else:
            # Write to the standard error device.
            self.pushmany([
                "for (%s=0; %s<NUM_EVS; %s++)" % ((profloopvar, ) * 3),
                "if (profeventtallies[%s]) {" % profloopvar,
                'fprintf (stderr, "%%d %%s %%" NICS " %%" NICS " %%.1f\\n", physrank, eventnames[%s], profeventtimings[%s], profeventtallies[%s], (double)profeventtimings[%s]/(double)profeventtallies[%s]);'
                % (profloopvar, profloopvar, profloopvar, profloopvar,
                   profloopvar), "}",
                'fprintf (stderr, "%d event-memory %" NICS " %" NICS " %" NICS "\n",',
                "physrank, numevents*sizeof(CONC_EVENT), numevents, (ncptl_int)sizeof(CONC_EVENT));"
            ],
                          stack=newcode)
        return newcode
class NCPTL_CodeGen:
    def __init__(self, options):
        "Initialize the profiling module."
        self.backend_name = "c_profile"
        self.errmsg = NCPTL_Error(self.backend_name)

        # Process any arguments we were given.
        leftover_opts = []
        target_backend = ""
        for arg in range(0, len(options)):
            profile_match = re.match(r'--profile=(.*)', options[arg])
            if profile_match:
                target_backend = profile_match.group(1)
            elif options[arg] == "--help":
                # Utilize c_generic's help-string mechanism.
                import codegen_c_generic
                generic_self = codegen_c_generic.NCPTL_CodeGen()
                generic_self.backend_name = self.backend_name
                generic_self.cmdline_options.extend([
                    ("--profile=<string>", "Specify a backend to profile")])
                generic_self.show_help()
                raise SystemExit, 0
            else:
                leftover_opts.append(options[arg])
        if not target_backend:
            self.errmsg.error_fatal("a target backend must be specified using --profile")

        # Reparent ourselves to the profiled backend.
        try:
            exec("import codegen_%s" % target_backend)
            exec("immediate_ancestor = codegen_%s.NCPTL_CodeGen" %
                 target_backend)
        except:
            self.errmsg.error_fatal("Unable to initialize the %s backend" % target_backend)
        try:
            self.name2class[target_backend] = immediate_ancestor
        except AttributeError:
            self.name2class = {target_backend: immediate_ancestor}
        try:
            self.name2class["c_profile"].__bases__ = (immediate_ancestor,)
        except KeyError:
            # We're the top-level class.
            self.__class__.__bases__ = (immediate_ancestor,)
            self.name2class["c_profile"] = self.__class__
        self.c_profile_parent = self.name2class["c_profile"].__bases__[0]
        immediate_ancestor.__init__(self, leftover_opts)
        self.define_eventnames = 1
        self.backend_name = "c_profile + " + self.backend_name
        self.backend_desc = "event profiler atop " + self.backend_desc


    # ---------------------- #
    # (Re)implementation of  #
    # hook and other methods #
    # ---------------------- #

    def code_declare_globals_EXTRA(self, localvars):
        "Declare a few arrays to store profile data."
        newcode = self.invoke_hook("code_declare_globals_EXTRA", localvars,
                                   invoke_on=self.c_profile_parent)
        self.code_declare_var(name="profeventtimings", arraysize="EV_CODE+1",
                              type="static ncptl_int",
                              comment="Total time spent in each event",
                              stack=newcode)
        self.code_declare_var(name="profeventtallies", arraysize="EV_CODE+1",
                              type="static ncptl_int",
                              comment="Number of times each event was executed",
                              stack=newcode)
        return newcode

    def code_define_main_POST_INIT(self, localvars):
        "Initialize the profile data."
        newcode = self.invoke_hook("code_define_main_POST_INIT", localvars,
                                   invoke_on=self.c_profile_parent)
        self.push("memset ((void *)profeventtimings, 0, sizeof(ncptl_int)*(EV_CODE+1));", newcode);
        self.push("memset ((void *)profeventtallies, 0, sizeof(ncptl_int)*(EV_CODE+1));", newcode);
        return newcode

    def code_def_procev_EVENTS_DECL(self, localvars):
        "Declare a variable for storing an event starting time."
        newcode = self.invoke_hook("code_def_procev_EVENTS_DECL", localvars,
                                   invoke_on=self.c_profile_parent)
        self.code_declare_var(name="eventtype", rhs="thisev->type",
                              comment="Preserved copy of thisev->type in case EV_REPEAT alters thisev",
                              stack=newcode)
        self.code_declare_var(name="eventstarttime", rhs="ncptl_time()",
                              comment="Time at which the current event began executing",
                              stack=newcode)
        return newcode

    def code_def_procev_POST_SWITCH(self, localvars):
        "Accumulate the time taken by the current event."
        newcode = self.invoke_hook("code_def_procev_POST_SWITCH", localvars,
                                   invoke_on=self.c_profile_parent)
        self.push("profeventtimings[eventtype] += ncptl_time() - eventstarttime;",
                  stack=newcode)
        self.push("profeventtallies[eventtype]++;", stack=newcode)
        return newcode

    def code_def_finalize_DECL(self, localvars):
        "Allocate variables needed to write the profiling information."
        newcode = self.invoke_hook("code_def_finalize_DECL", localvars,
                                   invoke_on=self.c_profile_parent)
        if self.program_uses_log_file:
            self.code_declare_var(type="char", name="profilekey", arraysize="256",
                                  comment="Space to hold an event name",
                                  stack=newcode)
            self.code_declare_var(type="char", name="profilevalue", arraysize="256",
                                  comment="Space to hold a line of profile information",
                                  stack=newcode)
        self.profloopvar = self.code_declare_var(type="int", suffix="ev",
                                                 comment="Loop over event types",
                                                 stack=newcode)
        self.code_declare_var(name="numevents",
                              rhs="ncptl_queue_length (eventqueue)",
                              comment="Total number of events processed",
                              stack=newcode)
        return newcode

    def code_def_finalize_PRE(self, localvars):
        "Write profiling information to either stderr or a log file."
        newcode = self.invoke_hook("code_def_finalize_PRE", localvars,
                                   invoke_on=self.c_profile_parent)
        profloopvar = self.profloopvar
        if self.program_uses_log_file:
            # Write to the log file.
            self.pushmany([
                "for (%s=0; %s<NUM_EVS; %s++)" % ((profloopvar,) * 3),
                "if (profeventtallies[%s]) {" % profloopvar,
                'sprintf (profilekey, "Profile of %%s (microseconds, count, average)", eventnames[%s]);' % profloopvar,
                'sprintf (profilevalue, "%%" NICS " %%" NICS " %%.1f", profeventtimings[%s], profeventtallies[%s], (double)profeventtimings[%s]/(double)profeventtallies[%s]);' %
                ((profloopvar,) * 4),
                "ncptl_log_add_comment (profilekey, profilevalue);",
                "}",
                'strcpy (profilekey, "Profile of event memory");',
                'sprintf (profilevalue, "%" NICS " bytes (%" NICS " events * %" NICS " bytes/event)",'
                "numevents*sizeof(CONC_EVENT), numevents, (ncptl_int)sizeof(CONC_EVENT));",
                "ncptl_log_add_comment (profilekey, profilevalue);"],
                          stack=newcode)
        else:
            # Write to the standard error device.
            self.pushmany([
                "for (%s=0; %s<NUM_EVS; %s++)" % ((profloopvar,) * 3),
                "if (profeventtallies[%s]) {" % profloopvar,
                'fprintf (stderr, "%%d %%s %%" NICS " %%" NICS " %%.1f\\n", physrank, eventnames[%s], profeventtimings[%s], profeventtallies[%s], (double)profeventtimings[%s]/(double)profeventtallies[%s]);' %
                (profloopvar, profloopvar, profloopvar, profloopvar, profloopvar),
                "}",
                'fprintf (stderr, "%d event-memory %" NICS " %" NICS " %" NICS "\n",',
                "physrank, numevents*sizeof(CONC_EVENT), numevents, (ncptl_int)sizeof(CONC_EVENT));"],
                          stack=newcode)
        return newcode