/* -----------------------------------------------------------------------------
- * $Id: Profiling.c,v 1.11 1999/11/04 10:15:50 simonmar Exp $
+ * $Id: Profiling.c,v 1.12 2000/02/17 17:19:42 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
  */
 CostCentre *CC_LIST;
 CostCentreStack *CCS_LIST;
-CCSDecList *New_CCS_LIST;
 
 /*
  * Built-in cost centres and cost-centre stacks:
 CCS_DECLARE(CCS_DONTZuCARE, CC_DONTZuCARE, CC_IS_BORING,   );
 
 /* 
+ * Uniques for the XML log-file format
+ */
+#define CC_UQ         1
+#define CCS_UQ        2
+#define TC_UQ         3
+#define HEAP_OBJ_UQ   4
+#define TIME_UPD_UQ   5
+#define HEAP_UPD_UQ   6
+
+/* 
  * Static Functions
  */
 
 static    void printCCS            ( CostCentreStack *ccs );
 #endif
 static    void initTimeProfiling   ( void );
+static    void initProfilingLogFile( void );
+
+static    void reportCCS_XML       ( CostCentreStack *ccs );
 
 /* -----------------------------------------------------------------------------
    Initialise the profiling environment
   CCCS = CCS_SYSTEM;
 
   /* Initialize counters for IDs */
-  CC_ID  = 0;
-  CCS_ID = 0;
-  HP_ID  = 0;
+  CC_ID  = 1;
+  CCS_ID = 1;
+  HP_ID  = 1;
   
   /* Initialize Declaration lists to NULL */
   CC_LIST  = NULL;
   registerCostCentres();
   CCCS = CCS_SYSTEM;
 
+  /* Set up the log file, and dump the header and cost centre
+   * information into it.
+   */
+  initProfilingLogFile();
+
   /* find all the "special" cost centre stacks, and make them children
    * of CCS_MAIN.
    */
   ASSERT(CCS_MAIN->prevStack == 0);
   CCS_MAIN->root = CC_MAIN;
+  DecCCS(CCS_MAIN);
   for (ccs = CCS_LIST; ccs != CCS_MAIN; ) {
     next = ccs->prevStack;
     ccs->prevStack = 0;
   }
 }
   
-void
-initTimeProfiling(void)
+static void
+initProfilingLogFile(void)
 {
-  time_profiling = rtsTrue;
-
   /* Initialise the log file name */
   prof_filename = stgMallocBytes(strlen(prog_argv[0]) + 6, "initProfiling");
   sprintf(prof_filename, "%s.prof", prog_argv[0]);
 
+  /* open the log file */
+  if ((prof_file = fopen(prof_filename, "w")) == NULL) {
+    fprintf(stderr, "Can't open profiling report file %s\n", prof_filename);
+    RtsFlags.CcFlags.doCostCentres = 0;
+    return;
+  }
+  
+  if (RtsFlags.CcFlags.doCostCentres == COST_CENTRES_XML) {
+    /* dump the time, and the profiling interval */
+    fprintf(prof_file, "\"%s\"\n", time_str());
+    fprintf(prof_file, "\"%d ms\"\n", TICK_MILLISECS);
+    
+    /* declare all the cost centres */
+    {
+      CostCentre *cc;
+      for (cc = CC_LIST; cc != NULL; cc = cc->link) {
+       fprintf(prof_file, "%d %d \"%s\" \"%s\" \"%s\"\n",
+               CC_UQ, cc->ccID, cc->label, cc->module, cc->group);
+      }
+    }
+  }
+}
+
+void
+initTimeProfiling(void)
+{
+  time_profiling = rtsTrue;
+
   /* Start ticking */
   startProfTimer();
 };
 CostCentreStack *
 AppendCCS ( CostCentreStack *ccs1, CostCentreStack *ccs2 )
 {
-  CostCentreStack *ccs;
+  CostCentreStack *ccs = NULL;
 
   /* Optimisation: if we attempt to append a CCS to itself, we're
    * going to end up with the same ccs after a great deal of pushing
 static void
 DecCCS(CostCentreStack *ccs)
 {
-   CCSDecList *temp_list;
-       
-   temp_list = 
-     (CCSDecList *) stgMallocBytes(sizeof(CCSDecList), 
-                                  "Error allocating space for CCSDecList");
-   temp_list->ccs = ccs;
-   temp_list->nextList = New_CCS_LIST;
-   
-   New_CCS_LIST = temp_list;
+  if (prof_file && RtsFlags.CcFlags.doCostCentres == COST_CENTRES_XML) {
+    if (ccs->prevStack == EMPTY_STACK)
+      fprintf(prof_file, "%d %d 1 %d\n", CCS_UQ, 
+             ccs->ccsID, ccs->cc->ccID);
+    else
+      fprintf(prof_file, "%d %d 2 %d %d\n", CCS_UQ, 
+             ccs->ccsID, ccs->cc->ccID, ccs->prevStack->ccsID);
+  }
 }
 
 /* -----------------------------------------------------------------------------
    Generating a time & allocation profiling report.
    -------------------------------------------------------------------------- */
 
-static FILE *prof_file;
-
 /* -----------------------------------------------------------------------------
    Generating the aggregated per-cost-centre time/alloc report.
    -------------------------------------------------------------------------- */
     rtsBool do_groups = rtsFalse;
 #endif
 
-    if (!RtsFlags.CcFlags.doCostCentres)
-       return;
-
     stopProfTimer();
 
     total_prof_ticks = 0;
     total_alloc = 0;
     count_ticks(CCS_MAIN);
     
-    /* open profiling output file */
-    if ((prof_file = fopen(prof_filename, "w")) == NULL) {
-       fprintf(stderr, "Can't open profiling report file %s\n", prof_filename);
-       return;
+    switch (RtsFlags.CcFlags.doCostCentres) {
+    case 0:
+      return;
+    case COST_CENTRES_XML:
+      gen_XML_logfile();
+      return;
+    default:
     }
+
     fprintf(prof_file, "\t%s Time and Allocation Profiling Report  (%s)\n", 
            time_str(), "Final");
 
   }
 }
 
+/* -----------------------------------------------------------------------------
+   Generate the XML time/allocation profile
+   -------------------------------------------------------------------------- */
+
+void
+gen_XML_logfile( void )
+{
+  fprintf(prof_file, "%d %lu", TIME_UPD_UQ, total_prof_ticks);
+
+  reportCCS_XML(pruneCCSTree(CCS_MAIN));
+
+  fprintf(prof_file, " 0\n");
+
+  fclose(prof_file);
+}
+
+static void 
+reportCCS_XML(CostCentreStack *ccs)
+{
+  CostCentre *cc;
+  IndexTable *i;
+
+  cc = ccs->cc;
+  
+  fprintf(prof_file, " 1 %d %lu %lu %lu", 
+         ccs->ccsID, ccs->scc_count, ccs->time_ticks, ccs->mem_alloc);
+
+  for (i = ccs->indexTable; i != 0; i = i->next) {
+    reportCCS_XML(i->ccs);
+  }
+}
+
 #ifdef DEBUG
 static void
 printCCS ( CostCentreStack *ccs )
 
 /* -----------------------------------------------------------------------------
- * $Id: RtsFlags.c,v 1.25 2000/02/17 14:15:10 simonmar Exp $
+ * $Id: RtsFlags.c,v 1.26 2000/02/17 17:19:42 simonmar Exp $
  *
  * (c) The AQUA Project, Glasgow University, 1994-1997
  * (c) The GHC Team, 1998-1999
 
 #if defined(PROFILING) || defined(PAR)
     RtsFlags.CcFlags.doCostCentres     = 0;
-    RtsFlags.CcFlags.sortBy            = SORTCC_TIME;
 #endif /* PROFILING or PAR */
 
 #ifdef PROFILING
 
              case 'P': /* detailed cost centre profiling (time/alloc) */
                COST_CENTRE_USING_BUILD_ONLY(
-               RtsFlags.CcFlags.doCostCentres++;
+               RtsFlags.CcFlags.doCostCentres = COST_CENTRES_VERBOSE;
                )
              case 'p': /* cost centre profiling (time/alloc) */
                COST_CENTRE_USING_BUILD_ONLY(
-               RtsFlags.CcFlags.doCostCentres++;
-
                switch (rts_argv[arg][2]) {
-                 case SORTCC_LABEL:
-                 case SORTCC_TIME:
-                 case SORTCC_ALLOC:
-                       RtsFlags.CcFlags.sortBy = rts_argv[arg][2];
+                 case 'x':
+                   RtsFlags.CcFlags.doCostCentres = COST_CENTRES_XML;
                    break;
                  default:
-                       RtsFlags.CcFlags.sortBy = SORTCC_TIME;
+                   RtsFlags.CcFlags.doCostCentres = COST_CENTRES_SUMMARY;
                    break;
                }
                ) break;