File: util.cpp

package info (click to toggle)
golly 3.3-1.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 20,176 kB
  • sloc: cpp: 72,638; ansic: 25,919; python: 7,921; sh: 4,245; objc: 3,721; java: 2,781; xml: 1,362; makefile: 530; javascript: 279; perl: 69
file content (251 lines) | stat: -rw-r--r-- 6,273 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
// This file is part of Golly.
// See docs/License.html for the copyright notice.

#include "util.h"
#include <stdio.h>
#include <stdlib.h>

#ifdef _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif

/**
 *   For now error just uses stderr.
 */
class baselifeerrors : public lifeerrors {
public:
   virtual void fatal(const char *s) {
      fprintf(stderr, "%s\n", s) ;
      exit(10) ;
   }
   virtual void warning(const char *s) {
      fprintf(stderr, "%s\n", s) ;
   }
   virtual void status(const char *s) {
      fprintf(stderr, "%s\n", s) ;
   }
   virtual void beginprogress(const char *) {
      aborted = false ;
   }
   virtual bool abortprogress(double, const char *) {
      return false ;
   }
   virtual void endprogress() {
      // do nothing
   }
   virtual const char *getuserrules() {
      return "" ;
   }
   virtual const char *getrulesdir() {
      return "" ;
   }
} ;

baselifeerrors baselifeerrors ;
lifeerrors *errorhandler = &baselifeerrors ;

void lifeerrors::seterrorhandler(lifeerrors *o) {
  if (o == 0)
    errorhandler = &baselifeerrors ;
  else
    errorhandler = o ;
}

void lifefatal(const char *s) {
   errorhandler->fatal(s) ;
}

void lifewarning(const char *s) {
   errorhandler->warning(s) ;
}

void lifestatus(const char *s) {
   errorhandler->status(s) ;
}

void lifebeginprogress(const char *dlgtitle) {
   errorhandler->beginprogress(dlgtitle) ;
}

bool lifeabortprogress(double fracdone, const char *newmsg) {
   return errorhandler->aborted |=
      errorhandler->abortprogress(fracdone, newmsg) ;
}

bool isaborted() {
   return errorhandler->aborted ;
}

void lifeendprogress() {
   errorhandler->endprogress() ;
}

const char *lifegetuserrules() {
   return errorhandler->getuserrules() ;
}

const char *lifegetrulesdir() {
   return errorhandler->getrulesdir() ;
}

static FILE *f ;
FILE *getdebugfile() {
  if (f == 0)
    f = fopen("trace.txt", "w") ;
  return f ;
}
/**
 *   Manage reading lines from a FILE* without worrying about
 *   line terminates.  Note that the fgets() routine does not
 *   insert any line termination characters at all.
 */
linereader::linereader(FILE *f) {
   setfile(f) ;
}
void linereader::setfile(FILE *f) {
   fp = f ;
   lastchar = 0 ;
   closeonfree = 0 ;    // AKT: avoid crash on Linux
}
void linereader::setcloseonfree() {
   closeonfree = 1 ;
}
int linereader::close() {
   if (fp) {
      int r = fclose(fp) ;
      fp = 0 ;
      return r ;
   }
   return 0 ;
}
linereader::~linereader() {
   if (closeonfree)
      close() ;
}
const int LF = 10 ;
const int CR = 13 ;
char *linereader::fgets(char *buf, int maxlen) {
   int i = 0 ;
   for (;;) {
      if (i+1 >= maxlen) {
         buf[i] = 0 ;
         return buf ;
      }
      int c = getc(fp) ;
      switch (c) {
      case EOF:
         if (i == 0)
            return 0 ;
         buf[i] = 0 ;
         return buf ;
      case LF:
         if (lastchar != CR) {
            lastchar = LF ;
            buf[i] = 0 ;
            return buf ;
         }
         break ;
      case CR:
         lastchar = CR ;
         buf[i] = 0 ;
         return buf ;
      default:
         lastchar = c ;
         buf[i++] = (char)c ;
         break ;
      }
   }
}

#ifdef _WIN32
static double freq = 0.0;
double gollySecondCount() {
   LARGE_INTEGER now;
   if (freq == 0.0) {
      LARGE_INTEGER f;
      QueryPerformanceFrequency(&f);
      freq = (double)f.QuadPart;
      if (freq <= 0.0) freq = 1.0;	// play safe and avoid div by 0
   }
   QueryPerformanceCounter(&now);
   return (now.QuadPart) / freq;
}
#else
double gollySecondCount() {
   struct timeval tv ;
   gettimeofday(&tv, 0) ;
   return tv.tv_sec + 0.000001 * tv.tv_usec ;
}
#endif

/*
 *   Reporting.
 *   The node count listed here wants to be big to reduce the number
 *   of "get times" we do (which can be fairly expensive on some systems),
 *   but it wants to be small in case something is going wrong like swapping
 *   and we want to tell the user that the node rate has dropped.
 *   A value of 65K is a reasonable compromise.
 */
int hperf::reportMask = ((1<<16)-1) ; // node count between checks
/*
 *   How frequently do we update the status bar?  Every two seconds
 *   should be reasonable.  If we set this to zero, then that disables
 *   performance reporting.
 */
double hperf::reportInterval = 2 ; // time between reports
/*
 *   Static buffer for status updates.
 */
char perfstatusline[200] ;
void hperf::report(hperf &mark, int verbose) {
   double ts = gollySecondCount() ;
   double elapsed = ts - mark.timeStamp ;
   if (reportInterval == 0 || elapsed < reportInterval)
      return ;
   timeStamp = ts ;
   nodesCalculated += fastNodeInc ;
   fastNodeInc = 0 ;
   if (verbose) {
      double nodeCount = nodesCalculated - mark.nodesCalculated ;
      double halfFrac = 0 ;
      if (nodeCount > 0)
         halfFrac = (halfNodes - mark.halfNodes) / nodeCount ;
      double depthDelta = depthSum - mark.depthSum ;
      sprintf(perfstatusline, "RATE noderate %g depth %g half %g",
                       nodeCount/elapsed, 1+depthDelta/nodeCount, halfFrac) ;
      lifestatus(perfstatusline) ;
   }
   mark = *this ;
}
void hperf::reportStep(hperf &mark, hperf &ratemark, double newGen, int verbose) {
   nodesCalculated += fastNodeInc ;
   fastNodeInc = 0 ;
   frames++ ;
   timeStamp = gollySecondCount() ;
   double elapsed = timeStamp - mark.timeStamp ;
   if (reportInterval == 0 || elapsed < reportInterval)
      return ;
   if (verbose) {
      double inc = newGen - mark.genval ;
      if (inc == 0)
         inc = 1e30 ;
      double nodeCount = nodesCalculated - mark.nodesCalculated ;
      double halfFrac = 0 ;
      if (nodeCount > 0)
         halfFrac = (halfNodes - mark.halfNodes) / nodeCount ;
      double depthDelta = depthSum - mark.depthSum ;
      double genspersec = inc / elapsed ;
      double nodespergen = nodeCount / inc ;
      double fps = (frames - mark.frames) / elapsed ;
      sprintf(perfstatusline,
          "PERF gps %g nps %g fps %g depth %g half %g npg %g nodes %g",
          genspersec, nodeCount/elapsed, fps, 1+depthDelta/nodeCount, halfFrac,
          nodespergen, nodeCount) ;
      lifestatus(perfstatusline) ;
   }
   genval = newGen ;
   mark = *this ;
   ratemark = *this ;
}