// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; -*-
////////////////////////////////////////////////////////////////////
//
// $Id: memstat.cpp 630 2010-04-27 13:52:24Z Sebastian Kupferschmid $
//
////////////////////////////////////////////////////////////////////

#include "common/memstat.h"
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstdlib>
#include <iostream>

using namespace std;

MemStat* MemStat::memstat = NULL;

MemStat& MemStat::getMemStat() {
    if (memstat == NULL) {
	memstat = new MemStat();
    }
    return *memstat;
}

MemStat::MemStat() : 
    begin(times(&buf))
{    
    // note that the pid is an integer, hence the size of the filename
    // is big enough
    char filename[64]; 
    sprintf(filename, "/proc/%d/stat", static_cast<int>(getpid()));
    file.open(filename);

    // on_exit functions are called in reverse order
    on_exit(MemStat::exit, 0);

    signal(SIGABRT, MemStat::error_handle);
    signal(SIGTERM, MemStat::error_handle);
    signal(SIGSEGV, MemStat::error_handle);
    signal(SIGINT,  MemStat::error_handle);
}

void MemStat::exit(int exit_code, void*) {
    getMemStat().collect_info(exit_code);
}
    
void MemStat::error_handle(int exit_code) {
    getMemStat().collect_info(exit_code);
}

void MemStat::collect_info(int exit_code) {   
    // we have to check if this method was called before to prevent
    // the program to print statstics more than once. Actually doing
    // this with the _exit() function causes a profiler not to produce
    // any output.
    static bool first_call = true;
    if (!first_call) {
	return;
    }
    first_call = false;
    this->exit_code = exit_code;
    end = times(&buf);
    int cnt = 0; 
    char tmp[64];
    while (cnt < NUM_PROC_ENTRIES && file) {
	switch (cnt++) {
	case VSIZE: 
	    file >> vsize;
	    vsize /= 1024;
	    break;
	case STIME:
	    file >> stime;
	    stime /= 100.0;
	    break;
	case UTIME:
	    file >> utime;
	    utime /= 100.0;
	    break;
	case CUTIME:
	    file >> cutime;
	    cutime /= 100.0;
	    break;
	case CSTIME:
	    file >> cstime;
	    cstime /= 100.0;
	    break;
	default:
	    file >> tmp;
	    break;
	}
    }
    // Note that closing the file may lock the process, hence we omit
    // this.
    // file.close();
    show_info();
    ::exit(exit_code);
}      

void MemStat::show_info() {
    cout.flush();
    cerr.flush();
    printf("\n--\n");
    printf("vsize   %8lu KB\n", vsize);
    printf("system  %8.2f s\n", stime);
    printf("user    %8.2f s\n", utime);
    printf("cuser   %8.2f s\n", cutime);
    printf("csystem %8.2f s\n", cstime);
    printf("elapsed %8.2f s\n", (end - begin) / 100.0);
    printf("exit    %8d\n", exit_code);
}
