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 ;
}
|