@q Copyright (C) 2004-2011, Ondra Kamenik @>

@ Start of {\tt journal.cpp} file.

@c
#include "journal.h"
#include "kord_exception.h"

#if !defined(__MINGW32__)
# include <sys/resource.h>
# include <sys/utsname.h>
#endif
#include <cstdlib>
#include <unistd.h>
#include <ctime>

SystemResources _sysres;
#if defined(__MINGW32__)
@<|sysconf| Win32 implementation@>;
#endif

#if defined(__APPLE__)
#define _SC_PHYS_PAGES 2
#define _SC_AVPHYS_PAGES 3
#endif

@<|SystemResources| constructor code@>;
@<|SystemResources::pageSize| code@>;
@<|SystemResources::physicalPages| code@>;
@<|SystemResources::onlineProcessors| code@>;
@<|SystemResources::availableMemory| code@>;
@<|SystemResources::getRUS| code@>;
@<|SystemResourcesFlash| constructor code@>;
@<|SystemResourcesFlash::diff| code@>;
@<|JournalRecord::operator<<| symmetry code@>;
@<|JournalRecord::writePrefix| code@>;
@<|JournalRecord::writePrefixForEnd| code@>;
@<|JournalRecordPair| destructor code@>;
@<|endrec| code@>;
@<|Journal::printHeader| code@>;

@ 
@<|SystemResources| constructor code@>=
SystemResources::SystemResources()
{
	gettimeofday(&start, NULL);
}


@ 
@<|SystemResources::pageSize| code@>=
long int SystemResources::pageSize()
{
	return sysconf(_SC_PAGESIZE);
}

@ 
@<|SystemResources::physicalPages| code@>=
long int SystemResources::physicalPages()
{
	return sysconf(_SC_PHYS_PAGES);
}

@ 
@<|SystemResources::onlineProcessors| code@>=
long int SystemResources::onlineProcessors()
{
	return sysconf(_SC_NPROCESSORS_ONLN);
}

@ 
@<|SystemResources::availableMemory| code@>=
long int SystemResources::availableMemory()
{
	return pageSize()*sysconf(_SC_AVPHYS_PAGES);
}

@ Here we read the current values of resource usage. For MinGW, we
implement only a number of available physical memory pages.

@<|SystemResources::getRUS| code@>=
void SystemResources::getRUS(double& load_avg, long int& pg_avail,
							 double& utime, double& stime, double& elapsed,
							 long int& idrss, long int& majflt)
{
	struct timeval now;
	gettimeofday(&now, NULL);
	elapsed = now.tv_sec-start.tv_sec + (now.tv_usec-start.tv_usec)*1.0e-6;

#if !defined(__MINGW32__)
	struct rusage rus;
	getrusage(RUSAGE_SELF, &rus);
	utime = rus.ru_utime.tv_sec+rus.ru_utime.tv_usec*1.0e-6;
	stime = rus.ru_stime.tv_sec+rus.ru_stime.tv_usec*1.0e-6;
	idrss = rus.ru_idrss;
	majflt = rus.ru_majflt;
#else
	utime = -1.0;
	stime = -1.0;
	idrss = -1;
	majflt = -1;
#endif

#if !defined(__MINGW32__) && !defined(__CYGWIN32__) && !defined(__CYGWIN__) && !defined(__MINGW64__) && !defined(__CYGWIN64__)
	getloadavg(&load_avg, 1);
#else
	load_avg = -1.0;
#endif

	pg_avail = sysconf(_SC_AVPHYS_PAGES);
}

@ 
@<|SystemResourcesFlash| constructor code@>=
SystemResourcesFlash::SystemResourcesFlash()
{
	_sysres.getRUS(load_avg, pg_avail, utime, stime,
				   elapsed, idrss, majflt);
}

@ 
@<|SystemResourcesFlash::diff| code@>=
void SystemResourcesFlash::diff(const SystemResourcesFlash& pre)
{
	utime -= pre.utime;
	stime -= pre.stime;
	elapsed -= pre.elapsed;
	idrss -= pre.idrss;
	majflt -= pre.majflt;
}

@ 
@<|JournalRecord::operator<<| symmetry code@>=
JournalRecord& JournalRecord::operator<<(const IntSequence& s)
{
	operator<<("[");
	for (int i = 0; i < s.size(); i++) {
		operator<<(s[i]);
		if (i < s.size()-1)
			operator<<(",");
	}
	operator<<("]");
	return *this;
}

@ 
@<|JournalRecord::writePrefix| code@>=
void JournalRecord::writePrefix(const SystemResourcesFlash& f)
{
	for (int i = 0; i < MAXLEN; i++)
		prefix[i] = ' ';
	double mb = 1024*1024;
	sprintf(prefix, "%07.6g", f.elapsed);
	sprintf(prefix+7, ":%c%05d", recChar, ord);
	sprintf(prefix+14, ":%1.1f", f.load_avg);
	sprintf(prefix+18, ":%05.4g", f.pg_avail*_sysres.pageSize()/mb);
	sprintf(prefix+24, "%s", ":      : ");
	for (int i = 0; i < 2*journal.getDepth(); i++)
		prefix[i+33]=' ';
	prefix[2*journal.getDepth()+33]='\0';
}

@ 
@<|JournalRecord::writePrefixForEnd| code@>=
void JournalRecordPair::writePrefixForEnd(const SystemResourcesFlash& f)
{
	for (int i = 0; i < MAXLEN; i++)
		prefix_end[i] = ' ';
	double mb = 1024*1024;
	SystemResourcesFlash difnow;
	difnow.diff(f);
	sprintf(prefix_end, "%07.6g", f.elapsed+difnow.elapsed);
	sprintf(prefix_end+7, ":E%05d", ord);
	sprintf(prefix_end+14, ":%1.1f", difnow.load_avg);
	sprintf(prefix_end+18, ":%05.4g", difnow.pg_avail*_sysres.pageSize()/mb);
	sprintf(prefix_end+24, ":%06.5g", difnow.majflt*_sysres.pageSize()/mb);
	sprintf(prefix_end+31, "%s", ": ");
	for (int i = 0; i < 2*journal.getDepth(); i++)
		prefix_end[i+33]=' ';
	prefix_end[2*journal.getDepth()+33]='\0';
}

@ 
@<|JournalRecordPair| destructor code@>=
JournalRecordPair::~JournalRecordPair()
{
	journal.decrementDepth();
	writePrefixForEnd(flash);
	journal << prefix_end;
	journal << mes;
	journal << endl;
	journal.flush();
}

@ 
@<|endrec| code@>=
JournalRecord& endrec(JournalRecord& rec)
{
	rec.journal << rec.prefix;
	rec.journal << rec.mes;
	rec.journal << endl;
	rec.journal.flush();
	rec.journal.incrementOrd();
	return rec;
}

@ 
@<|Journal::printHeader| code@>=
void Journal::printHeader()
{
	(*this)<< "This is Dynare++, Copyright (C) 2004-2011, Ondra Kamenik\n"
	       << "Dynare++ comes with ABSOLUTELY NO WARRANTY and is distributed under\n"
		     << "GPL: modules integ, tl, kord, sylv, src, extern and documentation\n"
	       << "LGPL: modules parser, utils\n"
	       << " for GPL  see http://www.gnu.org/licenses/gpl.html\n"
	       << " for LGPL see http://www.gnu.org/licenses/lgpl.html\n"
	       << "\n\n";

#if !defined(__MINGW32__)
	utsname info;
	uname(&info);
	(*this)<< "System info: ";
	(*this)<< info.sysname << " " << info.release << " " << info.version << " ";
	(*this)<< info.machine << ", processors online: " << _sysres.onlineProcessors();

	(*this)<< "\n\nStart time: ";
	char ts[100];
	time_t curtime = time(NULL);
	tm loctime;
	localtime_r(&curtime, &loctime);
	asctime_r(&loctime, ts);
	(*this)<< ts << "\n";
#else
	(*this) << "System info: (not implemented for MINGW)\n";
	(*this) << "Start time:  (not implemented for MINGW)\n\n";
#endif
	
	(*this)<< "  ------ elapsed time (seconds)                     \n";
	(*this)<< "  |       ------ record unique identifier           \n";
	(*this)<< "  |       |     ------ load average                 \n";
	(*this)<< "  |       |     |    ------ available memory (MB)   \n";
	(*this)<< "  |       |     |    |     ------  major faults (MB)\n";
	(*this)<< "  |       |     |    |     |                        \n";
	(*this)<< "  V       V     V    V     V                        \n";
	(*this)<< "\n";
}


@ Here we implement |sysconf| for MinGW. We implement only page size,
number of physial pages, and a number of available physical pages. The
pagesize is set to 1024 bytes, real pagesize can differ but it is not
important. We can do this since Windows kernel32 |GlobalMemoryStatus|
call returns number of bytes.

Number of online processors is not implemented and returns -1, since
Windows kernel32 |GetSystemInfo| call is too complicated.

@<|sysconf| Win32 implementation@>=
#ifndef NOMINMAX
# define NOMINMAX // Do not define "min" and "max" macros
#endif
#include <windows.h>

#define _SC_PAGESIZE 1
#define _SC_PHYS_PAGES 2
#define _SC_AVPHYS_PAGES 3
#define _SC_NPROCESSORS_ONLN 4
@#
long sysconf(int name)
{
	switch (name) {
	case _SC_PAGESIZE:@;
		return 1024;
	case _SC_PHYS_PAGES:@;
		{
			MEMORYSTATUS memstat;
			GlobalMemoryStatus(&memstat);
			return memstat.dwTotalPhys/1024;
		}
	case _SC_AVPHYS_PAGES:@;
		{
			MEMORYSTATUS memstat;
			GlobalMemoryStatus(&memstat);
			return memstat.dwAvailPhys/1024;
		}
	case _SC_NPROCESSORS_ONLN:@;
		return -1;
	default:@; 
		KORD_RAISE("Not implemented in Win32 sysconf.");
		return -1;
	}
}

@ End of {\tt journal.cpp} file.