File:/home/sbrandt/cactus/Cactus/arrangements/Carpet/Carpet/src/TimerSet.cc
1:#include <cassert>
2:#include <cstdio>
3:#include <cstring>
4:#include <list>
5:
6:#include <cctk.h>
7:#include <cctk_Parameters.h>
8:#include <util_String.h>
9:
10:#if HAVE_UNISTD_H
11:#  include <fcntl.h>
12:#  include <unistd.h>
13:#endif
14:
15:#include <defs.hh>
16:
17:#include <Timers.hh>
18:#include <CactusTimer.hh>
19:#include <TimerNode.hh>
20:#include <TimerSet.hh>
21:
22:namespace Carpet {
23:
24:  using namespace std;
25:
26:  // A global timer set
27:  TimerSet timerSet;
28:
29:  // Add a timer
30:  void
31:  TimerSet::add (CactusTimer * const timer)
32:  {
33:    timers.push_back (timer);
34:  }
35:
36:  // Remove a timer
37:  void
38:  TimerSet::remove (CactusTimer * const timer)
39:  {
40:    timers.remove (timer);
41:  }
42:
43:  // Print all timer names
44:  void
45:  TimerSet::printNames ()
46:    const
47:  {
48:    printf ("Timer names:\n");
49:    int n = 0;
50:    for (list <CactusTimer *>::const_iterator
51:           itimer = timers.begin(); itimer != timers.end(); ++ itimer)
52:    {
53:      printf ("   [%4d] %s\n", n, (* itimer)->name().c_str());
54:      ++ n;
55:    }
56:  }
57:
58:  // Print all timer data
59:  void
60:  TimerSet::printData ()
61:  {
62:    for (list <CactusTimer *>::const_iterator
63:           itimer = timers.begin(); itimer != timers.end(); ++ itimer)
64:    {
65:      (* itimer)->printData ();
66:    }
67:    printf ("\n");
68:  }
69:
70:  // Print all timer data
71:  void
72:  TimerSet::writeData (cGH const * const cctkGH,
73:                       char const * const filename)
74:  {
75:    int const oldfd = redirect (cctkGH, filename);
76:#if 0
77:    printf ("********************************************************************************\n");
78:#endif
79:    printf ("# Carpet timing information at iteration %d time %g:\n",
80:            cctkGH->cctk_iteration, (double) cctkGH->cctk_time);
81:    timerSet.printData ();
82:    unredirect (oldfd);
83:  }
84:
85:  // If filename is not empty, then redirect stdout to a file
86:  int
87:  TimerSet::redirect (cGH const * const cctkGH,
88:                      char const * const filename)
89:  {
90:    DECLARE_CCTK_PARAMETERS;
91:
92:    if (CCTK_EQUALS (filename, "")) {
93:      return -1;
94:    }
95:
96:#ifndef HAVE_UNISTD_H
97:    CCTK_WARN (1, "Cannot redirect timer output to a file; the operating system does not support this");
98:    return -1;
99:#else
100:
101:    int const myproc = CCTK_MyProc (cctkGH);
102:    char fullname [10000];
103:    Util_snprintf (fullname, sizeof fullname,
104:                   "%s/%s.%04d.txt", out_dir, filename, myproc);
105:
106:    int flags = O_WRONLY | O_CREAT | O_APPEND; // append
107:    static bool first_time = true;
108:    if (first_time) {
109:      first_time = false;
110:      if (IO_TruncateOutputFiles (cctkGH)) {
111:        flags = O_WRONLY | O_CREAT | O_TRUNC; // truncate
112:      }
113:    }
114:
115:    // Temporarily redirect stdout
116:    fflush (stdout);
117:    int const oldfd = dup (1);  // fd 1 is stdout
118:    int const mode = 0644;      // rw-r--r--, or a+r u+w
119:    int const fdfile = open (fullname, flags, mode);
120:    if (fdfile < 0) {
121:      CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
122:                  "Could not open timer output file \"%s\"", fullname);
123:      close (oldfd);
124:      return -1;
125:    }
126:    // close (1);
127:    // int const fd = dup (fdfile); // dup to 1, i.e., stdout again
128:    int const fd = dup2 (fdfile, 1); // dup to 1, i.e., stdout again
129:    assert (fd == 1);
130:    close (fdfile);
131:    return oldfd;
132:#endif
133:  }
134:
135:  // Redirect stdout back
136:  void
137:  TimerSet::unredirect (int const oldfd)
138:  {
139:    if (oldfd < 0) return;
140:
141:#ifdef HAVE_UNISTD_H
142:    fflush (stdout);
143:    // close (1);
144:    // int const fd = dup (oldfd);
145:    int const fd = dup2 (oldfd, 1);
146:    if (not (fd == 1)) {
147:      fprintf(stderr, "oldfd=%d fd=%d\n", oldfd, fd);
148:    }
149:    assert (fd == 1);
150:    close (oldfd);
151:#endif
152:  }
153:
154:
155:  /// Reduce each timers in the set across all processes and update
156:  /// each timer with the reduction information.
157:  void TimerSet::reduce()
158:  {
159:    // Collect timer names that each process has
160:
161:    // Construct union of all timer names, sort canonically and assign
162:    // integer identifiers
163:
164:    // For each timer, identify which processes have that timer
165:
166:    // Reduce the timer across all those processes (return to root proc only)
167:
168:    serialise(cout);
169:  }
170:
171:  ostream& TimerSet::serialise(ostream &os)
172:  {
173:    for (list <CactusTimer *>::const_iterator
174:           itimer = timers.begin(); itimer != timers.end(); ++ itimer)
175:    {
176:      (*itimer)->serialise(os);
177:      os << endl;
178:    }
179:    return os;
180:  }
181:
182:/*
183:
184:
185:Each process has a list of (string,real) pairs.  I want to return a
186:list of these where the reals have been reduced using a reduction
187:operator.  Not all processes have the same strings present.
188: */
189:
190:} // namespace Carpet