next up previous contents
Next: select_alternatives.cc Up: Source Code Previous: integrate.cc

add_profiling.cc

#include "add_profiling.h"

/**********************************************************************/
/* Definitions */
/***************/

int global_argc;
char **global_argv;
int max_UID_encountered = 0;

/**********************************************************************/
/* Code */
/********/

// [....]

/****************/

void instrument_returns(tree_node *this_node, void *x)
{
  // Converts "ret e1" to "temp = e1; ...insert_tn...; return temp".

  if (! this_node->is_instr())
    return;

  instruction *this_instr = ((tree_instr *) this_node)->instr();
  if (this_instr->opcode() != io_ret)
    return;

  in_rrr *this_return = ((in_rrr *) this_instr);
  operand return_operand = this_return->src1_op();
  switch (return_operand.kind())
    {
    case OPER_NULL:
      /* Fall through to OPER_SYM case */
    case OPER_SYM:
      this_node->parent()->insert_before
	(((tree_node *) x)->clone(this_node->scope()), this_node->list_e());
      break;
    case OPER_INSTR:
      {
	assert(return_operand.is_expr());

	block b1 = block::new_sym(return_operand.type());
	sym_node *temp_sym = b1.get_sym();

	block b2(b1 = block(return_operand.clone(this_node->scope())));
	tree_node_list *tnl = b2.make_tree_node_list();
	this_node->parent()->insert_before(tnl, this_node->list_e());
	this_node->parent()->insert_before
	  (((tree_node *) x)->clone(this_node->scope()), this_node->list_e());

	return_operand.remove();
	this_return->set_src1((var_sym *) temp_sym);
      }
      break;
    default:
      assert(0); /* Should never be reached */
    }
}

/****************/

void instrument_TNL(tree_proc *tp, tree_node_list *tnl, int UID,
		    char *pre, char *post)
{
  proc_sym *qhead_sym =
    ((global_symtab *) global_symbol_table)->lookup_proc(pre);
  proc_sym *qtail_sym =
    ((global_symtab *) global_symbol_table)->lookup_proc(post);
  assert (qhead_sym != NULL);
  assert (qtail_sym != NULL);

  block::set_proc(tp);
  block qhead(qhead_sym);
  block qtail(qtail_sym);
  block uid(UID);
  block verbose(debug_level);

  block call_qhead;
    call_qhead.set(block::CALL(qhead,uid,verbose));
  tnl->push(call_qhead.make_tree_node());

  block call_qtail;
    call_qtail.set(block::CALL(qtail,uid,verbose));
  tree_node *tn = call_qtail.make_tree_node();
  tnl->append(new tree_node_list_e(tn));
  if (debug_level >= 3) print_TNL(tnl);
  tnl->map(instrument_returns, tn);
  if (debug_level >= 3) print_TNL(tnl);
    // In cases where the TNL ends with a return, this code inserts
    // multiple calls to qtail.  Could be fixed.... XXX
}

/****************/

void wrap_main(tree_proc *tp, tree_node_list *tnl,
	       char *pre, char *base_filename, int counters, int verbose1,
	       char *post, int verbose2)
{
  /* Similar to instrument_TNL in some ways, but not similar
    enough to make it sensible to combine the two */

  proc_sym *qhead_sym =
    ((global_symtab *) global_symbol_table)->lookup_proc(pre);
  proc_sym *qtail_sym =
    ((global_symtab *) global_symbol_table)->lookup_proc(post);
  assert (qhead_sym != NULL);
  assert (qtail_sym != NULL);

  type_node *char_array = file_symbol_table->install_type
    (new array_type(type_char, 0, strlen(base_filename)-1));

  var_sym *base_filename_sym = file_symbol_table->new_var
    (char_array, "qp_basefilename");
#define VD_DATA_ALIGNMENT 8
  var_def *base_filename_def =
    new var_def(base_filename_sym,VD_DATA_ALIGNMENT);
  immed_list *il = new immed_list();
  for (int loop = 0; loop<strlen(base_filename); loop++)
    il->append(new immed_list_e(*(new immed(base_filename[loop]))));
  il->push(new immed_list_e(*(new immed(8))));
  base_filename_def->append_annote(k_multi_init, (void *) il);
  file_symbol_table->add_def(base_filename_def);

  block::set_proc(tp);

  block call_qhead;
    call_qhead.set(block::CALL(new block(qhead_sym),
			       new block(base_filename_sym),
			       new block(counters),
			       new block(verbose1)));
  tnl->push(call_qhead.make_tree_node());

  block call_qtail;
    call_qtail.set(block::CALL(new block(qtail_sym),
			       new block(verbose2)));
  tree_node *tn = call_qtail.make_tree_node();
  tnl->append(new tree_node_list_e(tn));
  if (debug_level >= 3) print_TNL(tnl);
  tnl->map(instrument_returns, tn);
  if (debug_level >= 3) print_TNL(tnl);
    // In cases where the TNL ends with a return, this code inserts
    // multiple calls to qtail.  Could be fixed.... XXX

  /* XXX: deal with calls to exit(); extra headache: multiple counters
    may still be "ticking".  I could rewrite qp_dump() to deal with
    that, I suppose. */
}

/**********************************************************************/

int lookup_set_UID(annote *the_an, char *k_annotation_type)
{
  CStringSet *the_set = pIL2pCStringSet(the_an->immeds());
  annote_list_iter anli = annote_list_iter(global_symbol_table->annotes());
  while (! anli.is_empty())
    {
      annote *an = anli.step();
      if (an->name() == k_annotation_type)
	{
	  immed_list *il = an->immeds();
	  immed_list_e *ile = new immed_list_e(il->pop());
	  assert(ile->contents.is_integer());
	  CStringSet *set = pIL2pCStringSet(il);
	  il->push(ile);
	  if (*set == *the_set)
	    {
	      int UID = ile->contents.integer();
	      if (UID > max_UID_encountered)
		max_UID_encountered = UID;
	      return UID;
	    }
	}
    }
  assert(0); /* Shouldn't ever be reached */
  return -1; /* Make compiler happy */
}

/**********************************************************************/

void check_block(tree_node *t, tree_proc *tp)
{
  annote *an_statement = NULL;
  annote *an_set = NULL;
  int UID = 0;

  switch (t->kind())
    {
    case TREE_IF:
      an_statement = t->annotes()->peek_annote(k_qif_statement);
      if (an_statement == NULL)
	return; /* Not a quasistatic if at all */
      an_set = t->annotes()->peek_annote(k_qif_set);
      if (an_set == NULL)
	return; /* Not the first quasistatic if in a chain */
      (void) t->annotes()->get_annote(k_qif_set_analyzed);
        /* The k_qif_set_analyzed annotation was useful during the
	  stage of calculating the set, but is now useless.  The
	  get_annote function is a mutator, not just observer. */
      UID = lookup_set_UID(an_set, k_qif_set);
      instrument_TNL(tp, ((tree_if *) t)->then_part(),
		     UID, "qp_start", "qp_stop");
      while (1)
	{
	  tree_node_list *pElseTNL = ((tree_if *) t)->else_part();
	  if (pElseTNL->count() == 0)
	    break; /* "... NO FINAL QELSE" */
	  if ((pElseTNL->count() == 1)
	      && (pElseTNL->head()->contents->is_block()))
	    {
	      instrument_TNL(tp, pElseTNL, UID, "qp_start", "qp_stop");
	      break;
	    }
	  assert(pElseTNL->count() > 1);
	  tree_node *pTN = pElseTNL->head()->next()->contents;
	  if (pTN->is_if()
	      && (pTN->annotes()->peek_annote(k_qif_statement) != NULL))
	    {
	      t = pTN;
	      instrument_TNL(tp, ((tree_if *) t)->then_part(),
			     UID, "qp_start", "qp_stop");
	      /* Do *NOT* break here */
	    }
	  else /* "... FINAL QELSE" */
	    {
	      instrument_TNL(tp, pElseTNL, UID, "qp_start", "qp_stop");
	      break;
	    }
	}
      break;
    case TREE_BLOCK:
      an_statement = t->annotes()->peek_annote(k_qinfluence_statement);
      if (an_statement == NULL)
	return; /* Not a qinfluence statement at all */
      an_set = t->annotes()->peek_annote(k_qinfluence_set);
      assert(an_set != NULL);
      UID = lookup_set_UID(an_set, k_qinfluence_set);
      instrument_TNL(tp, ((tree_block *) t)->body(),
		     UID, "qp_start", "qp_stop");
      break;
    default:
      ; /* Do nothing */
    }
}

/**********************************************************************/

void do_proc(tree_proc *tp)
{
  if (file_symbol_table == NULL)
    {
      file_symbol_table = tp->scope();
      while (file_symbol_table->kind() != SYMTAB_FILE)
	file_symbol_table = file_symbol_table->parent();
    }
  if (global_symbol_table == NULL)
    {
      global_symbol_table = file_symbol_table;
      while (global_symbol_table->kind() != SYMTAB_GLOBAL)
	global_symbol_table = global_symbol_table->parent();
    }

  tp->map(check_block, tp);
  /* Important that tp->map comes before a call to wrap_main,
    in case main itself needs to be instrumented. */

  if (strcmp(tp->proc()->name(),"main") == 0)
    wrap_main(tp, tp->body(),
	      "qp_initialize", global_argv[global_argc-1],
	          max_UID_encountered+1, debug_level,
	      "qp_dump", debug_level);
}

/**********************************************************************/

int main(int argc, char *argv[])
{
  global_argc = argc;
  global_argv = argv;

  start_suif(argc, argv);
  register_qannotations();

  process_command_line(argc, argv);
  if (argc-optind != 2)
    {
      fprintf(stderr, "%s: wrong number of filenames given on command line.\n",
	      argv[0]);
      exit(1);
    }

#define WRITE_BACK_TO_FILE TRUE
  my_suif_proc_iter(argc, argv, do_proc, NULL, NULL, WRITE_BACK_TO_FILE);
}

/**********************************************************************/



Reinventing Computing, MIT AI Lab. Author: pshuang@ai.mit.edu (Ping Huang)