28 #ifndef ABSTRACTDRIVER_H
29 #define ABSTRACTDRIVER_H
33 #include <sys/types.h>
40 #include "FileByteSource.h"
51 #define MAX_PATH_LENGTH 1000
52 #define MIN_PATH_RESERVED_LENGTH 100
54 #define MAX_NEEDED_ELEMENTS 100
55 #define MAX_CONFIGURATION_PATHS 32
57 #define INITIAL_AEPS_PER_FRAME 1
75 typedef typename GC::CORE_CONFIG
CC;
81 typedef typename CC::PARAM_CONFIG
P;
86 typedef typename CC::ATOM_TYPE
T;
92 enum { W = GC::GRID_WIDTH};
98 enum { H = GC::GRID_HEIGHT};
104 enum { R = P::EVENT_WINDOW_RADIUS};
145 Element<CC>* m_neededElements[MAX_NEEDED_ELEMENTS];
146 u32 m_neededElementCount;
150 if(m_neededElementCount >= MAX_NEEDED_ELEMENTS)
155 m_neededElements[m_neededElementCount++] = element;
161 typedef typename GC::CORE_CONFIG
CC;
162 typedef typename CC::PARAM_CONFIG
P;
163 enum { W = GC::GRID_WIDTH};
164 enum { H = GC::GRID_HEIGHT};
165 enum { R = P::EVENT_WINDOW_RADIUS};
169 fp.Printf(
"# AEPS AEPS/Frame AER100 Overhead100");
170 for(u32 i = 0; i < m_neededElementCount; i++)
173 for(
const char* p = m_neededElements[i]->GetName(); *p; p++)
188 fp.
Print((u64)GetAEPS());
190 fp.
Print(GetAEPSPerFrame());
192 fp.
Print((u64)(100.0 * GetAER()));
194 fp.
Print((u64)(100.0 * GetOverheadPercent()));
196 for(u32 i = 0; i < m_neededElementCount; i++)
199 fp.
Print((u32)GetGrid().GetAtomCount(m_neededElements[i]->GetType()));
204 void SetIgnoreThreadingProblems(
bool value)
206 m_ignoreThreadingProblems = value;
209 void WriteTimeBasedData()
214 FILE* fp = fopen(path,
"r");
224 FILE* fp = fopen(path,
"a");
225 FileByteSink fbs(fp);
227 WriteTimeBasedData(fbs, exists);
241 const s32 ONE_THOUSAND = 1000;
242 const s32 ONE_MILLION = ONE_THOUSAND*ONE_THOUSAND;
246 u32 startMS = GetTicks();
247 if (m_ticksLastStopped != 0)
248 m_msSpentOverhead += startMS - m_ticksLastStopped;
250 m_msSpentOverhead = 0;
252 Sleep(m_microsSleepPerFrame/ONE_MILLION,
253 (u64) (m_microsSleepPerFrame%ONE_MILLION)*ONE_THOUSAND);
255 m_ticksLastStopped = GetTicks();
259 u32 thisPeriodMS = m_ticksLastStopped - startMS;
260 m_msSpentRunning += thisPeriodMS;
262 u64 totalEvents = grid.GetTotalEventsExecuted();
263 u32 totalSites = grid.GetTotalSites();
264 m_AEPS = totalEvents / totalSites;
265 m_AER = 1000 * (m_AEPS / m_msSpentRunning);
267 u64 newEvents = totalEvents - m_lastTotalEvents;
268 m_lastTotalEvents = totalEvents;
270 if (thisPeriodMS == 0) {
271 LOG.
Warning(
"Zero ms in sample");
274 double thisAERsample = 1000.0 * newEvents / totalSites / thisPeriodMS;
276 const double BACKWARDS_AVERAGE_RATE = 0.99;
277 m_recentAER = BACKWARDS_AVERAGE_RATE * m_recentAER +
278 (1 - BACKWARDS_AVERAGE_RATE) * thisAERsample;
280 m_overheadPercent = 100.0*m_msSpentOverhead/(m_msSpentRunning+m_msSpentOverhead);
282 double diff = m_AEPS - m_lastFrameAEPS;
283 double err = MIN(1.0, MAX(-1.0, m_aepsPerFrame - diff));
286 m_microsSleepPerFrame = (100+20*err)*m_microsSleepPerFrame/100;
287 m_microsSleepPerFrame = MIN(100000000, MAX(1000, m_microsSleepPerFrame));
289 m_lastFrameAEPS = m_AEPS;
291 CheckEpochProcessing(grid);
305 if(m_aepsPerFrame <= amount)
311 m_aepsPerFrame -= amount;
324 m_aepsPerFrame += amount;
325 if(m_aepsPerFrame >= 1000)
327 m_aepsPerFrame = 1000;
352 for(u32 i = 0; i < m_neededElementCount; i++)
354 GetGrid().Needed(*m_neededElements[i]);
396 SetDataDirFromArgs(NULL,
this);
401 const char* (subs[]) =
403 "",
"vid",
"eps",
"tbd",
"teps",
"save",
"screenshot",
"autosave"
406 for(u32 i = 0; i <
sizeof(subs) /
sizeof(subs[0]); i++)
409 if(mkdir(path, 0777))
411 args.
Die(
"Couldn't make simulation sub-directory '%s' : %s",
412 path, strerror(errno));
418 FILE* fp = fopen(path,
"w");
419 fprintf(fp,
"#AEPS activesites empty dreg res wall sort-hits"
420 "sort-misses sort-total sort-hit-pctg\n");
423 m_elementRegistry.
AddPath(
"~/.mfm/res/elements");
424 m_elementRegistry.
AddPath(SHARED_DIR
"/res/elements");
425 m_elementRegistry.
AddPath(
"./bin");
426 m_elementRegistry.Init();
430 m_grid.SetIgnoreThreadingProblems(m_ignoreThreadingProblems);
444 if(m_haltAfterAEPS > 0 && m_AEPS > m_haltAfterAEPS)
451 void SetAEPSPerEpoch(u32 aeps)
453 m_AEPSPerEpoch = aeps;
456 u32 GetAEPSPerEpoch()
const
458 return m_AEPSPerEpoch;
467 u32 m_ticksLastStopped;
471 u64 m_msSpentRunning;
472 u64 m_msSpentOverhead;
473 s32 m_microsSleepPerFrame;
474 double m_overheadPercent;
475 double m_lastFrameAEPS;
479 u32 m_autosavePerEpochs;
480 u32 m_accelerateAfterEpochs;
482 u32 m_surgeAfterEpochs;
487 bool m_ignoreThreadingProblems;
504 u64 m_lastTotalEvents;
509 VArguments m_varguments;
511 u32 m_configurationPathCount;
512 u32 m_currentConfigurationPath;
513 const char* (m_configurationPaths[MAX_CONFIGURATION_PATHS]);
515 char m_simDirBasePath[MAX_PATH_LENGTH];
516 u32 m_simDirBasePathLength;
521 gettimeofday(&tv, NULL);
524 u64 ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
526 return ms - m_startTimeMS;
533 static void PrintArgUsage(
const char* not_needed,
void* vargs)
535 VArguments& args = *((VArguments*)vargs);
539 static void PrintVersion(
const char* not_needed,
void* nullForShort)
541 fprintf(stderr,
"%s\n", nullForShort ? MFM_VERSION_STRING_LONG : MFM_VERSION_STRING_SHORT);
545 static void SetLoggingLevel(
const char* level,
void* not_needed)
550 static void SetSeedFromArgs(
const char* seedstr,
void* driver)
552 u32 seed = atoi(seedstr);
557 ((AbstractDriver*)driver)->SetSeed(seed);
560 static void SetAEPSPerEpochFromArgs(
const char* aepsStr,
void* driverptr)
562 AbstractDriver& driver = *((AbstractDriver*)driverptr);
563 VArguments& args = driver.m_varguments;
565 u32 epochAEPS = atoi(aepsStr);
568 args.Die(
"AEPS per epoch must be non-negative, not %d", epochAEPS);
570 driver.SetAEPSPerEpoch(epochAEPS);
573 static void SetAutosavePerEpochsFromArgs(
const char* arg,
void* driverptr)
575 AbstractDriver& driver = *((AbstractDriver*)driverptr);
576 VArguments& args = driver.m_varguments;
581 args.Die(
"Autosave per epochs must be non-negative, not %d", val);
583 driver.m_autosavePerEpochs = val;
586 static void SetPicturesPerRateFromArgs(
const char* aeps,
void* driverptr)
588 AbstractDriver* driver = (AbstractDriver*)driverptr;
590 driver->m_accelerateAfterEpochs = atoi(aeps);
593 static void SetSurgePerEpochFromArgs(
const char* aeps,
void* driverptr)
595 AbstractDriver* driver = (AbstractDriver*)driverptr;
597 driver->m_surgeAfterEpochs = atoi(aeps);
599 if (driver->m_surgeAfterEpochs > 0)
601 driver->m_acceleration = 0;
605 static void SetGridImages(
const char* not_needed,
void* driver)
607 ((AbstractDriver*)driver)->m_gridImages = 1;
610 static void SetTileImages(
const char* not_needed,
void* driver)
612 ((AbstractDriver*)driver)->m_tileImages = 1;
615 static void SetDataDirFromArgs(
const char* dirPath,
void* driverPtr)
617 AbstractDriver& driver = *((AbstractDriver*)driverPtr);
618 VArguments& args = driver.m_varguments;
620 if(!dirPath || strlen(dirPath) == 0)
626 if(mkdir(dirPath, 0777))
631 args.Die(
"Couldn't make directory '%s' : %s", dirPath, strerror(errno));
635 u64 startTime = Utils::GetDateTimeNow();
637 snprintf(driver.m_simDirBasePath, MAX_PATH_LENGTH - 1,
638 "%s/%d%06d/", dirPath,
639 Utils::GetDateFromDateTime(startTime),
640 Utils::GetTimeFromDateTime(startTime));
642 driver.m_simDirBasePathLength = strlen(driver.m_simDirBasePath);
644 if(driver.m_simDirBasePathLength >= MAX_PATH_LENGTH - MIN_PATH_RESERVED_LENGTH)
646 args.Die(
"Path name too long '%s'", dirPath);
650 static void RegisterElementPath(
const char* path,
void* driverptr)
652 AbstractDriver& driver = *((AbstractDriver*)driverptr);
654 driver.m_elementRegistry.AddPath(path);
657 static void SetHaltAfterAEPSFromArgs(
const char* aeps,
void* driverptr)
659 AbstractDriver& driver = *((AbstractDriver*)driverptr);
661 driver.m_haltAfterAEPS = atoi(aeps);
664 static void LoadFromConfigFile(
const char* path,
void* driverptr)
666 AbstractDriver& driver = *((AbstractDriver*)driverptr);
667 VArguments& args = driver.m_varguments;
669 if (driver.m_configurationPathCount >= MAX_CONFIGURATION_PATHS)
671 args.Die(
"Too many configuration paths, max %d, for '%s'",
672 MAX_CONFIGURATION_PATHS,
675 driver.m_configurationPaths[driver.m_configurationPathCount] = path;
676 ++driver.m_configurationPathCount;
679 static void SetIgnoreThreadingProblems(
const char* not_used,
void* driverptr)
681 AbstractDriver& driver = *((AbstractDriver*)driverptr);
683 LOG.
Warning(
"Threading errors treatead as warnings. Beware of inconsistencies.");
685 driver.SetIgnoreThreadingProblems(
true);
688 void CheckEpochProcessing(
OurGrid& grid)
690 if (m_AEPSPerEpoch >= 0 || m_accelerateAfterEpochs > 0 || m_surgeAfterEpochs > 0)
692 if (m_AEPS >= m_nextEpochAEPS)
695 m_nextEpochAEPS += m_AEPSPerEpoch;
702 void AutosaveGrid(u32 epochs)
704 const char* filename =
709 void SaveGrid(
const char* filename)
712 LOG.
Message(
"Saving to: %s", filename);
713 ExternalConfig<GC> cfg(this->GetGrid());
714 FILE* fp = fopen(filename,
"w");
721 void LoadFromConfigurationPath()
723 if (m_configurationPathCount > 0)
725 ++m_currentConfigurationPath;
726 if (m_currentConfigurationPath >= m_configurationPathCount)
728 m_currentConfigurationPath = 0;
730 ReloadCurrentConfigurationPath();
750 buf.Printf(
"%s",m_simDirBasePath);
752 va_start(ap, format);
753 buf.Vprintf(format, ap);
761 void ReloadCurrentConfigurationPath()
763 if(m_configurationPathCount == 0)
768 const char * path = m_configurationPaths[m_currentConfigurationPath];
770 LOG.
Debug(
"Loading configuration from %s...", path);
772 ExternalConfig<GC> cfg(GetGrid());
773 RegisterExternalConfigFunctions<GC>(cfg);
774 FileByteSource fs(path);
778 cfg.SetByteSource(fs, path);
786 LOG.
Error(
"Can't read configuration file '%s'", path);
799 LOG.
Debug(
"Epoch %d: %d AEPS", epochs, epochAEPS);
808 FILE* fp = fopen(path,
"w");
810 grid.WriteEPSImage(fbs);
817 FILE* fp = fopen(path,
"w");
819 grid.WriteEPSAverageImage(fbs2);
825 if (m_autosavePerEpochs > 0 && (epochs % m_autosavePerEpochs) == 0)
827 this->AutosaveGrid(epochs);
830 if (m_accelerateAfterEpochs > 0 && (epochs % m_accelerateAfterEpochs) == 0)
832 this->SetAEPSPerEpoch(this->GetAEPSPerEpoch() + m_acceleration);
835 if (m_accelerateAfterEpochs > 0 &&
836 m_surgeAfterEpochs > 0 &&
837 (epochs % m_surgeAfterEpochs) == 0)
845 m_neededElementCount(0),
846 m_grid(m_elementRegistry),
847 m_ticksLastStopped(0),
851 m_msSpentOverhead(0),
852 m_microsSleepPerFrame(50000),
853 m_overheadPercent(0.0),
854 m_aepsPerFrame(INITIAL_AEPS_PER_FRAME),
856 m_autosavePerEpochs(1),
857 m_accelerateAfterEpochs(0),
859 m_surgeAfterEpochs(0),
862 m_ignoreThreadingProblems(false),
865 m_lastTotalEvents(0),
868 m_configurationPathCount(0),
869 m_currentConfigurationPath(
U32_MAX)
872 void Init(u32 argc,
const char** argv)
880 m_startTimeMS = GetTicks();
885 VArguments & GetVArguments()
890 void RegisterArgument(
const char* description,
const char* filter,
891 VArgumentHandleValue func,
void* handlerArg,
894 m_varguments.
RegisterArgument(description, filter, func, handlerArg, runFunc);
897 void RegisterSection(
const char* sectionLabel)
914 RegisterSection(
"General switches");
916 RegisterArgument(
"Display this help message, then exit.",
917 "-h|--help", &PrintArgUsage, (
void*)(&m_varguments),
false);
919 RegisterArgument(
"Amount of logging output is ARG (0 -> none, 8 -> max)",
920 "-l|--log", &SetLoggingLevel, NULL,
true);
922 RegisterArgument(
"Print the brief version number, then exit.",
923 "-v|--version", &PrintVersion, NULL,
false);
925 RegisterArgument(
"Print the full version number, then exit.",
926 "-V|--Version", &PrintVersion,
this,
false);
928 RegisterArgument(
"Set master PRNG seed to ARG (u32)",
929 "-s|--seed", &SetSeedFromArgs,
this,
true);
931 RegisterArgument(
"Set epoch length to ARG AEPS",
932 "-e|--epoch", &SetAEPSPerEpochFromArgs,
this,
true);
934 RegisterArgument(
"Autosave grid every ARG epochs (default 1; 0 for never)",
935 "-a|--autosave", &SetAutosavePerEpochsFromArgs,
this,
true);
937 this->RegisterArgument(
"Increase the epoch length every ARG epochs",
939 &SetPicturesPerRateFromArgs,
this,
true);
941 this->RegisterArgument(
"Increase the epoch length acceleration every ARG epochs",
943 &SetSurgePerEpochFromArgs,
this,
true);
945 RegisterArgument(
"Each epoch, write grid AEPS image to per-sim eps/ directory",
946 "--gridImages", &SetGridImages,
this,
false);
948 RegisterArgument(
"Each epoch, write tile AEPS image to per-sim teps/ directory",
949 "--tileImages", &SetTileImages,
this,
false);
951 RegisterArgument(
"If ARG > 0, Halts after ARG elapsed aeps.",
952 "--haltafteraeps", &SetHaltAfterAEPSFromArgs,
this,
true);
954 RegisterArgument(
"Store data in per-sim directories under ARG (string)",
955 "-d|--dir", &SetDataDirFromArgs,
this,
true);
957 RegisterArgument(
"Add ARG as a path to search for element libraries",
958 "-ep|--elementpath", &RegisterElementPath,
this,
true);
960 RegisterArgument(
"Load initial configuration from file at path ARG (string)",
961 "-cp|--configpath", &LoadFromConfigFile,
this,
true);
963 RegisterArgument(
"Continue execution after detected thread failures",
964 "--ignorethreadbugs", &SetIgnoreThreadingProblems,
969 virtual void ReinitUs()
972 u32 GetHaltAfterAEPS()
974 return m_haltAfterAEPS;
987 void SetAER(
double aer)
992 double GetRecentAER()
997 void SetRecentAER(
double aer)
1002 u32 GetAEPSPerFrame()
1004 return m_aepsPerFrame;
1007 double GetOverheadPercent()
1009 return m_overheadPercent;
1017 void SetSeed(u32 seed)
1021 FAIL(ILLEGAL_ARGUMENT);
1023 m_grid.SetSeed(seed);
1028 m_lastFrameAEPS = 0;
1034 m_grid.Needed(Element_Empty<CC>::THE_INSTANCE);
1042 LoadFromConfigurationPath();
1049 MFMPrintErrorEnvironment(stderr, &unwindProtect_errorEnvironment);
1050 fprintf(stderr,
"Failure reached top-level! Aborting\n");
void RegisterArgument(const char *description, const char *filter, VArgumentHandleValue func, void *handlerArg, bool runFunc)
Definition: VArguments.cpp:25
void Warning(const char *format,...)
Definition: Logger.h:273
Level SetLevel(u32 newLevel)
Definition: Logger.h:127
Grid< GC > OurGrid
Definition: AbstractDriver.h:137
void DecrementAEPSPerFrame(u32 amount)
Definition: AbstractDriver.h:303
virtual void OnceOnly(VArguments &args)
Definition: AbstractDriver.h:392
ElementRegistry< CC > OurElementRegistry
Definition: AbstractDriver.h:125
void IncrementAEPSPerFrame(u32 amount)
Definition: AbstractDriver.h:322
ElementTable< CC > OurElementTable
Definition: AbstractDriver.h:143
Definition: AbstractDriver.h:67
Definition: StdElements.h:38
virtual void PostReinit(VArguments &args)
Definition: AbstractDriver.h:339
virtual void RunHelper()
Definition: AbstractDriver.h:436
virtual void PostReinitPhysics()
Definition: AbstractDriver.h:363
virtual void AddDriverArguments()
Definition: AbstractDriver.h:912
void Reset()
Definition: OverflowableCharBufferByteSink.h:192
void Pause()
Definition: Grid.h:378
void UpdateGrid(OurGrid &grid)
Definition: AbstractDriver.h:239
const char * GetZString()
Definition: OverflowableCharBufferByteSink.h:143
CC::ATOM_TYPE T
Definition: AbstractDriver.h:86
void Error(const char *format,...)
Definition: Logger.h:259
static const u32 GRID_WIDTH
Definition: AbstractDriver.h:114
void CheckCaches()
Definition: Grid.tcc:516
void AddPath(const char *path)
Definition: ElementRegistry.tcc:139
const char * GetSimDirPathTemporary(const char *format,...) const
Definition: AbstractDriver.h:746
virtual void DefineNeededElements()=0
virtual void ReinitEden()=0
StdElements< CC > OurStdElements
Definition: AbstractDriver.h:131
bool HasOverflowed() const
Definition: OverflowableCharBufferByteSink.h:206
Definition: FileByteSink.h:41
Definition: ElementRegistry.h:48
static const u32 EVENT_WINDOW_RADIUS
Definition: AbstractDriver.h:109
CC::PARAM_CONFIG P
Definition: AbstractDriver.h:81
void Unpause()
Definition: Grid.h:387
Definition: OverflowableCharBufferByteSink.h:41
void ReinitPhysics()
Definition: AbstractDriver.h:350
void Die(const char *format,...)
Definition: VArguments.cpp:16
void ProcessArguments(u32 argc, const char **argv)
Definition: VArguments.cpp:91
virtual void WriteByte(u8 ch)
Definition: ByteSink.h:81
GC::CORE_CONFIG CC
Definition: AbstractDriver.h:75
void Print(const char *str, s32 fieldWidth=-1, u8 padChar= ' ')
Definition: ByteSink.cpp:31
void Debug(const char *format,...)
Definition: Logger.h:301
void RegisterSection(const char *label)
Definition: VArguments.cpp:43
virtual void PostUpdate()
Definition: AbstractDriver.h:376
Definition: ElementTable.h:46
void Message(const char *format,...)
Definition: Logger.h:287
Definition: VArguments.h:48
void RecountAtoms()
Definition: Grid.tcc:160
virtual void DoEpochEvents(OurGrid &grid, u32 epochs, u32 epochAEPS)
Definition: AbstractDriver.h:797
bool Appeared(const char *argName) const
Definition: VArguments.cpp:147
static const u32 GRID_HEIGHT
Definition: AbstractDriver.h:119
#define U32_MAX
Definition: itype.h:95