PetaVision  Alpha
StatsProbe.cpp
1 /*
2  * StatsProbe.cpp
3  *
4  * Created on: Mar 10, 2009
5  * Author: Craig Rasmussen
6  */
7 
8 #include "StatsProbe.hpp"
9 #include "../layers/HyPerLayer.hpp"
10 #include <float.h> // FLT_MAX/MIN
11 #include <string.h>
12 
13 namespace PV {
14 
15 StatsProbe::StatsProbe(const char *name, HyPerCol *hc) {
16  initialize_base();
17  initialize(name, hc);
18 }
19 
20 StatsProbe::StatsProbe() : LayerProbe() {
21  initialize_base();
22  // Derived classes should call initialize
23 }
24 
25 StatsProbe::~StatsProbe() {
26  int rank = parent->columnId();
27  if (rank == 0 and !mOutputStreams.empty()) {
28  iotimer->fprint_time(output(0));
29  mpitimer->fprint_time(output(0));
30  comptimer->fprint_time(output(0));
31  }
32  delete iotimer;
33  delete mpitimer;
34  delete comptimer;
35  free(sum);
36  free(sum2);
37  free(nnz);
38  free(fMin);
39  free(fMax);
40  free(avg);
41  free(sigma);
42 }
43 
44 int StatsProbe::initialize_base() {
45  fMin = NULL;
46  fMax = NULL;
47  sum = NULL;
48  sum2 = NULL;
49  nnz = NULL;
50  avg = NULL;
51  sigma = NULL;
52 
53  type = BufV;
54  iotimer = NULL;
55  mpitimer = NULL;
56  comptimer = NULL;
57  nnzThreshold = (float)0;
58  return PV_SUCCESS;
59 }
60 
61 int StatsProbe::initialize(const char *name, HyPerCol *hc) {
62  int status = LayerProbe::initialize(name, hc);
63 
64  assert(status == PV_SUCCESS);
65 
66  int nbatch = parent->getNBatch();
67 
68  fMin = (float *)malloc(sizeof(float) * nbatch);
69  fMax = (float *)malloc(sizeof(float) * nbatch);
70  sum = (double *)malloc(sizeof(double) * nbatch);
71  sum2 = (double *)malloc(sizeof(double) * nbatch);
72  avg = (float *)malloc(sizeof(float) * nbatch);
73  sigma = (float *)malloc(sizeof(float) * nbatch);
74  nnz = (int *)malloc(sizeof(int) * nbatch);
75  resetStats();
76 
77  return status;
78 }
79 
80 void StatsProbe::resetStats() {
81  for (int b = 0; b < parent->getNBatch(); b++) {
82  fMin[b] = FLT_MAX;
83  fMax[b] = -FLT_MAX;
84  sum[b] = 0.0f;
85  sum2[b] = 0.0f;
86  avg[b] = 0.0f;
87  sigma[b] = 0.0f;
88  nnz[b] = 0;
89  }
90 }
91 
92 int StatsProbe::ioParamsFillGroup(enum ParamsIOFlag ioFlag) {
93  int status = LayerProbe::ioParamsFillGroup(ioFlag);
94  ioParam_buffer(ioFlag);
95  ioParam_nnzThreshold(ioFlag);
96  return status;
97 }
98 
99 void StatsProbe::requireType(PVBufType requiredType) {
100  PVParams *params = parent->parameters();
101  if (params->stringPresent(getName(), "buffer")) {
102  params->handleUnnecessaryStringParameter(getName(), "buffer");
103  StatsProbe::ioParam_buffer(PARAMS_IO_READ);
104  if (type != requiredType) {
105  const char *requiredString = NULL;
106  switch (requiredType) {
107  case BufV: requiredString = "\"MembranePotential\" or \"V\""; break;
108  case BufActivity: requiredString = "\"Activity\" or \"A\""; break;
109  default: assert(0); break;
110  }
111  if (type != BufV) {
112  if (parent->columnId() == 0) {
113  ErrorLog().printf(
114  " Value \"%s\" is inconsistent with allowed values %s.\n",
115  params->stringValue(getName(), "buffer"),
116  requiredString);
117  }
118  }
119  }
120  }
121  else {
122  type = requiredType;
123  }
124 }
125 
126 void StatsProbe::ioParam_buffer(enum ParamsIOFlag ioFlag) {
127  char *buffer = NULL;
128  if (ioFlag == PARAMS_IO_WRITE) {
129  switch (type) {
130  case BufV: buffer = strdup("MembranePotential"); break;
131  case BufActivity: buffer = strdup("Activity");
132  }
133  }
134  parent->parameters()->ioParamString(
135  ioFlag, getName(), "buffer", &buffer, "Activity", true /*warnIfAbsent*/);
136  if (ioFlag == PARAMS_IO_READ) {
137  assert(buffer);
138  size_t len = strlen(buffer);
139  for (size_t c = 0; c < len; c++) {
140  buffer[c] = (char)tolower((int)buffer[c]);
141  }
142  if (!strcmp(buffer, "v") || !strcmp(buffer, "membranepotential")) {
143  type = BufV;
144  }
145  else if (!strcmp(buffer, "a") || !strcmp(buffer, "activity")) {
146  type = BufActivity;
147  }
148  else {
149  if (parent->columnId() == 0) {
150  const char *bufnameinparams = parent->parameters()->stringValue(getName(), "buffer");
151  assert(bufnameinparams);
152  ErrorLog().printf(
153  "%s: buffer \"%s\" is not recognized.\n", getDescription_c(), bufnameinparams);
154  }
155  MPI_Barrier(parent->getCommunicator()->communicator());
156  exit(EXIT_FAILURE);
157  }
158  }
159  free(buffer);
160  buffer = NULL;
161 }
162 
163 void StatsProbe::ioParam_nnzThreshold(enum ParamsIOFlag ioFlag) {
164  parent->parameters()->ioParamValue(ioFlag, getName(), "nnzThreshold", &nnzThreshold, 0.0f);
165 }
166 
168 
169 Response::Status StatsProbe::registerData(Checkpointer *checkpointer) {
170  auto status = LayerProbe::registerData(checkpointer);
171  if (!Response::completed(status)) {
172  return status;
173  }
174 
175  std::string timermessagehead;
176  timermessagehead.append("StatsProbe ").append(getName());
177  std::string timermessage;
178 
179  timermessage = timermessagehead + " I/O timer ";
180  iotimer = new Timer(timermessage.c_str());
181  checkpointer->registerTimer(iotimer);
182 
183  timermessage = timermessagehead + " MPI timer ";
184  mpitimer = new Timer(timermessage.c_str());
185  checkpointer->registerTimer(mpitimer);
186 
187  timermessage = timermessagehead + " Comp timer ";
188  comptimer = new Timer(timermessage.c_str());
189  checkpointer->registerTimer(comptimer);
190  return Response::SUCCESS;
191 }
192 
193 Response::Status StatsProbe::outputState(double timed) {
194 #ifdef PV_USE_MPI
195  Communicator *icComm = parent->getCommunicator();
196  MPI_Comm comm = icComm->communicator();
197  int rank = icComm->commRank();
198  const int rcvProc = 0;
199 #endif // PV_USE_MPI
200 
201  int nk;
202  const float *buf;
203  resetStats();
204 
205  nk = getTargetLayer()->getNumNeurons();
206 
207  int nbatch = getTargetLayer()->getLayerLoc()->nbatch;
208 
209  comptimer->start();
210  switch (type) {
211  case BufV:
212  for (int b = 0; b < nbatch; b++) {
213  buf = getTargetLayer()->getV() + b * getTargetLayer()->getNumNeurons();
214  if (buf == NULL) {
215 #ifdef PV_USE_MPI
216  if (rank != rcvProc) {
217  return Response::SUCCESS;
218  }
219 #endif // PV_USE_MPI
220  output(b) << getMessage() << "V buffer is NULL\n";
221  return Response::SUCCESS;
222  }
223  for (int k = 0; k < nk; k++) {
224  float a = buf[k];
225  sum[b] += (double)a;
226  sum2[b] += (double)(a * a);
227  if (fabsf(a) > nnzThreshold) {
228  nnz[b]++;
229  }
230  if (a < fMin[b]) {
231  fMin[b] = a;
232  }
233  if (a > fMax[b]) {
234  fMax[b] = a;
235  }
236  }
237  }
238  break;
239  case BufActivity:
240  for (int b = 0; b < nbatch; b++) {
241  buf = getTargetLayer()->getLayerData() + b * getTargetLayer()->getNumExtended();
242  assert(buf != NULL);
243  for (int k = 0; k < nk; k++) {
244  const PVLayerLoc *loc = getTargetLayer()->getLayerLoc();
245  int kex = kIndexExtended(
246  k,
247  loc->nx,
248  loc->ny,
249  loc->nf,
250  loc->halo.lt,
251  loc->halo.rt,
252  loc->halo.dn,
253  loc->halo.up); // TODO: faster to use strides
254  // and a double-loop than
255  // compute
256  // kIndexExtended for every neuron?
257  float a = buf[kex];
258  sum[b] += (double)a;
259  sum2[b] += (double)(a * a);
260  if (fabsf(a) > nnzThreshold) {
261  nnz[b]++; // Optimize for different datatypes of a?
262  }
263  if (a < fMin[b]) {
264  fMin[b] = a;
265  }
266  if (a > fMax[b]) {
267  fMax[b] = a;
268  }
269  }
270  }
271  break;
272  default: pvAssert(0); break;
273  }
274  comptimer->stop();
275 
276 #ifdef PV_USE_MPI
277  mpitimer->start();
278  int ierr;
279 
280  // In place reduction to prevent allocating a temp recv buffer
281  ierr = MPI_Allreduce(MPI_IN_PLACE, sum, nbatch, MPI_DOUBLE, MPI_SUM, comm);
282  ierr = MPI_Allreduce(MPI_IN_PLACE, sum2, nbatch, MPI_DOUBLE, MPI_SUM, comm);
283  ierr = MPI_Allreduce(MPI_IN_PLACE, nnz, nbatch, MPI_INT, MPI_SUM, comm);
284  ierr = MPI_Allreduce(MPI_IN_PLACE, fMin, nbatch, MPI_FLOAT, MPI_MIN, comm);
285  ierr = MPI_Allreduce(MPI_IN_PLACE, fMax, nbatch, MPI_FLOAT, MPI_MAX, comm);
286  ierr = MPI_Allreduce(MPI_IN_PLACE, &nk, 1, MPI_INT, MPI_SUM, comm);
287 
288  mpitimer->stop();
289  if (rank != rcvProc) {
290  return Response::SUCCESS;
291  }
292 
293 #endif // PV_USE_MPI
294  float divisor = nk;
295 
296  iotimer->start();
297  for (int b = 0; b < nbatch; b++) {
298  avg[b] = (float)sum[b] / divisor;
299  sigma[b] = sqrtf((float)sum2[b] / divisor - avg[b] * avg[b]);
300  float avgval = 0.0f;
301  char const *avgnote = nullptr;
302  if (type == BufActivity && getTargetLayer()->getSparseFlag()) {
303  avgval = 1000.0f * avg[b]; // convert spikes per millisecond to hertz.
304  avgnote = " Hz (/dt ms)";
305  }
306  else {
307  avgval = avg[b];
308  avgnote = "";
309  }
310  output(b).printf(
311  "%st==%6.1f b==%d N==%d Total==%f Min==%f Avg==%f%s "
312  "Max==%f sigma==%f nnz==%d",
313  getMessage(),
314  (double)timed,
315  (int)b,
316  (int)divisor,
317  (double)sum[b],
318  (double)fMin[b],
319  (double)avgval,
320  avgnote,
321  (double)fMax[b],
322  (double)sigma[b],
323  (int)nnz[b]);
324  output(b) << std::endl;
325  }
326 
327  iotimer->stop();
328 
329  return Response::SUCCESS;
330 }
331 
332 int StatsProbe::checkpointTimers(PrintStream &timerstream) {
333  iotimer->fprint_time(timerstream);
334  mpitimer->fprint_time(timerstream);
335  comptimer->fprint_time(timerstream);
336  return PV_SUCCESS;
337 }
338 }
virtual int ioParamsFillGroup(enum ParamsIOFlag ioFlag) override
Definition: StatsProbe.cpp:92
virtual Response::Status outputState(double timef) override
Definition: StatsProbe.cpp:193
void setNumValues(int n)
Definition: BaseProbe.cpp:221
LayerProbe(const char *name, HyPerCol *hc)
Definition: LayerProbe.cpp:22
virtual int ioParamsFillGroup(enum ParamsIOFlag ioFlag) override
Definition: BaseProbe.cpp:76
PrintStream & output(int b)
Definition: BaseProbe.hpp:291
static bool completed(Status &a)
Definition: Response.hpp:49
virtual Response::Status registerData(Checkpointer *checkpointer) override
Definition: StatsProbe.cpp:169
int initialize(const char *name, HyPerCol *hc)
Definition: LayerProbe.cpp:38
const char * getMessage()
Definition: BaseProbe.hpp:280
virtual Response::Status registerData(Checkpointer *checkpointer) override
Definition: BaseProbe.cpp:320
void handleUnnecessaryStringParameter(const char *group_name, const char *param_name)
Definition: PVParams.cpp:1704
const float * getLayerData(int delay=0)
virtual void initNumValues() override
Definition: StatsProbe.cpp:167