timer.cxx 7.94 KB
Newer Older
1 2 3 4 5 6 7 8 9
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <time.h>
#include "string.h"
#include "assert.h"
#include <iostream>
#include <vector>
10
#include "timer.h"
11
#include "util.h"
12

13
#define MAX_NAME_LENGTH 53
14
#define MAX_TOT_SYMBOLS_LEN 1000000
15

16
int main_argc = 0;
Devin Matthews's avatar
Devin Matthews committed
17
const char * const * main_argv;
18 19 20
MPI_Comm comm;
double excl_time;
double complete_time;
21
int set_contxt = 0;
22
int output_file_counter = 0;
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
    

class function_timer{
  public:
    char name[MAX_NAME_LENGTH];
    double start_time;
    double start_excl_time;
    double acc_time;
    double acc_excl_time;
    int calls;

    double total_time;
    double total_excl_time;
    int total_calls;

  public: 
    function_timer(char const * name_, 
                   double const start_time_,
                   double const start_excl_time_){
42
      snprintf(name, MAX_NAME_LENGTH, "%s", name_);
43 44 45 46 47 48 49 50
      start_time = start_time_;
      start_excl_time = start_excl_time_;
      acc_time = 0.0;
      acc_excl_time = 0.0;
      calls = 0;
    }

    void compute_totals(MPI_Comm comm){ 
51
      PMPI_Allreduce(&acc_time, &total_time, 1, 
52
                    MPI_DOUBLE, MPI_SUM, comm);
53
      PMPI_Allreduce(&acc_excl_time, &total_excl_time, 1, 
54
                    MPI_DOUBLE, MPI_SUM, comm);
55
      PMPI_Allreduce(&calls, &total_calls, 1, 
56 57 58 59 60 61 62 63 64 65 66 67 68 69
                    MPI_INT, MPI_SUM, comm);
    }

    bool operator<(function_timer const & w) const {
      return total_time > w.total_time;
    }

    void print(FILE *         output, 
               MPI_Comm const comm, 
               int const      rank,
               int const      np){
      int i;
      if (rank == 0){
        fprintf(output, "%s", name);
70
        char * space = (char*)CTF_alloc(MAX_NAME_LENGTH-strlen(name)+1);
71 72 73 74 75
        for (i=0; i<MAX_NAME_LENGTH-(int)strlen(name); i++){
          space[i] = ' ';
        }
        space[i] = '\0';
        fprintf(output, "%s", space);
76 77 78 79
        fprintf(output,"%5d   %3d.%04d  %3d.%02d  %3d.%04d  %3d.%02d\n",
                total_calls/np,
                (int)(total_time/np),
                ((int)(1000.*(total_time)/np))%1000,
80 81
                (int)(100.*(total_time)/complete_time),
                ((int)(10000.*(total_time)/complete_time))%100,
82 83
                (int)(total_excl_time/np),
                ((int)(1000.*(total_excl_time)/np))%1000,
84 85
                (int)(100.*(total_excl_time)/complete_time),
                ((int)(10000.*(total_excl_time)/complete_time))%100);
86
        CTF_free(space);
87 88 89 90 91 92 93 94 95 96
      } 
    }
};

bool comp_name(function_timer const & w1, function_timer const & w2) {
  return strcmp(w1.name, w2.name)>0;
}

std::vector<function_timer> function_timers;

97
CTF_Timer::CTF_Timer(const char * name){
98
#ifdef PROFILE
99 100
  int i;
  if (function_timers.size() == 0) {
101 102 103 104 105 106
    if (name[0] == 'M' && name[1] == 'P' && 
        name[2] == 'I' && name[3] == '_'){
      exited = 1;
      original = 0;
      return;
    }
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
    original = 1;
    index = 0;
    excl_time = 0.0;
    function_timers.push_back(function_timer(name, MPI_Wtime(), 0.0)); 
  } else {
    for (i=0; i<(int)function_timers.size(); i++){
      if (strcmp(function_timers[i].name, name) == 0){
        /*function_timers[i].start_time = MPI_Wtime();
        function_timers[i].start_excl_time = excl_time;*/
        break;
      }
    }
    index = i;
    original = (index==0);
  }
  if (index == (int)function_timers.size()) {
    function_timers.push_back(function_timer(name, MPI_Wtime(), excl_time)); 
  }
  timer_name = name;
  exited = 0;
127
#endif
128 129
}
  
130
void CTF_Timer::start(){
131
#ifdef PROFILE
132 133 134 135
  if (!exited){
    function_timers[index].start_time = MPI_Wtime();
    function_timers[index].start_excl_time = excl_time;
  }
136
#endif
137 138
}

139
void CTF_Timer::stop(){
140
#ifdef PROFILE
141 142 143 144 145 146 147 148 149 150
  if (!exited){
    double delta_time = MPI_Wtime() - function_timers[index].start_time;
    function_timers[index].acc_time += delta_time;
    function_timers[index].acc_excl_time += delta_time - 
          (excl_time- function_timers[index].start_excl_time); 
    excl_time = function_timers[index].start_excl_time + delta_time;
    function_timers[index].calls++;
    exit();
    exited = 1;
  }
151
#endif
152 153
}

154
CTF_Timer::~CTF_Timer(){ }
155

156
void CTF_Timer::exit(){
157
#ifdef PROFILE
158
  if (set_contxt && original && !exited) {
159
    if (comm != MPI_COMM_WORLD){
160
      //function_timers.clear();
161 162
      return;
    }
163
    int rank, np, i, j, p, len_symbols, nrecv_symbols;
164 165 166 167 168

    MPI_Comm_rank(comm, &rank);
    MPI_Comm_size(comm, &np);


169
    char all_symbols[MAX_TOT_SYMBOLS_LEN];
170
    char recv_symbols[MAX_TOT_SYMBOLS_LEN];
171
    FILE * output = NULL;
172 173 174 175

    if (rank == 0){
      char filename[300];
      char part[300];
176
      
177
      sprintf(filename, "profile.");
178 179 180 181
      srand(time(NULL));
      sprintf(filename+strlen(filename), "%d.", output_file_counter);
      output_file_counter++;
      
182
      int off;
183
      if (main_argc > 0){
184
        for (i=0; i<main_argc; i++){
185 186 187 188
          for (off=strlen(main_argv[i]); off>=1; off--){
            if (main_argv[i][off-1] == '/') break;
          }
          sprintf(filename+strlen(filename), "%s.", main_argv[i]+off);
189 190 191 192 193
        }
      } 
      sprintf(filename+strlen(filename), "-p%d.out", np);
      
      
194 195
      output = stdout;// fopen(filename, "w");
      printf("%s\n",filename);
196 197 198 199 200 201 202
      char heading[MAX_NAME_LENGTH+200];
      for (i=0; i<MAX_NAME_LENGTH; i++){
        part[i] = ' ';
      }
      part[i] = '\0';
      sprintf(heading,"%s",part);
      //sprintf(part,"calls   total sec   exclusive sec\n");
203
      sprintf(part,"       inclusive         exclusive\n");
204 205 206 207 208 209 210 211 212 213 214 215 216
      strcat(heading,part);
      fprintf(output, "%s", heading);
      for (i=0; i<MAX_NAME_LENGTH; i++){
        part[i] = ' ';
      }
      part[i] = '\0';
      sprintf(heading,"%s",part);
      sprintf(part, "calls        sec       %%"); 
      strcat(heading,part);
      sprintf(part, "       sec       %%\n"); 
      strcat(heading,part);
      fprintf(output, "%s", heading);

217 218 219 220 221
    }
    len_symbols = 0;
    for (i=0; i<(int)function_timers.size(); i++){
      sprintf(all_symbols+len_symbols, "%s", function_timers[i].name);
      len_symbols += strlen(function_timers[i].name)+1;
222 223
    }
    if (np > 1){
224 225 226 227 228
      for (int lp=1; lp<log2(np)+1; lp++){
        int gap = 1<<lp;
        if (rank%gap == gap/2){
          PMPI_Send(&len_symbols, 1, MPI_INT, rank-gap/2, 1, comm);
          PMPI_Send(all_symbols, len_symbols, MPI_CHAR, rank-gap/2, 2, comm);
229
        }
230
        if (rank%gap==0 && rank+gap/2<np){
231
          MPI_Status stat;
232 233 234
          PMPI_Recv(&nrecv_symbols, 1, MPI_INT, rank+gap/2, 1, comm, &stat);
          PMPI_Recv(recv_symbols, nrecv_symbols, MPI_CHAR, rank+gap/2, 2, comm, &stat);
          for (i=0; i<nrecv_symbols; i+=strlen(recv_symbols+i)+1){
235
            j=0;
236
            while (j<len_symbols && strcmp(all_symbols+j, recv_symbols+i) != 0){
237 238 239 240
              j+=strlen(all_symbols+j)+1;
            }
            
            if (j>=len_symbols){
241 242
              sprintf(all_symbols+len_symbols, "%s", recv_symbols+i);
              len_symbols += strlen(recv_symbols+i)+1;
243 244 245 246
            }
          }
        }
      }
247 248
      PMPI_Bcast(&len_symbols, 1, MPI_INT, 0, comm);
      PMPI_Bcast(all_symbols, len_symbols, MPI_CHAR, 0, comm);
249 250
      j=0;
      while (j<len_symbols){
251
        CTF_Timer t(all_symbols+j);
252 253 254
        j+=strlen(all_symbols+j)+1;
      }
    }
255
    LIBT_ASSERT(len_symbols <= MAX_TOT_SYMBOLS_LEN);
256 257 258 259 260 261 262

    std::sort(function_timers.begin(), function_timers.end(),comp_name);
    for (i=0; i<(int)function_timers.size(); i++){
      function_timers[i].compute_totals(comm);
    }
    std::sort(function_timers.begin(), function_timers.end());
    complete_time = function_timers[0].total_time;
263 264 265 266
    if (rank == 0){
      for (i=0; i<(int)function_timers.size(); i++){
        function_timers[i].print(output,comm,rank,np);
      }
267 268
    }
    
269
/*    if (rank == 0){
270
      fclose(output);
271
    } */
272
    function_timers.clear();
273 274
    
  }
275
#endif
276 277
}

Devin Matthews's avatar
Devin Matthews committed
278
void CTF_set_main_args(int argc, const char * const * argv){
279 280 281 282
  main_argv = argv;
  main_argc = argc;
}

283
void CTF_set_context(MPI_Comm ctxt){
284 285
  if (!set_contxt)
    comm = ctxt;
286 287
  set_contxt = 1;
}