

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  This file is part of PSYCLONE version 2.0.0.170915_Beta4 (15 September 2017)
//_/_/  
//_/_/  developed by
//_/_/  
//_/_/  Communicative Machines Ltd. 
//_/_/    http://cmlabs.com/
//_/_/  Copyright (c) 2017
//_/_/  
//_/_/  in collaboration with 
//_/_/  
//_/_/  Icelandic Institute for Intelligent Machines ses
//_/_/    Menntavegur 1
//_/_/    101 Reykjavik
//_/_/    ICELAND
//_/_/    http://www.iiim.is/
//_/_/
//_/_/  PSYCLONE 2.0 is released under the GNU Lesser General Public License 
//_/_/  (LGPL) version 3.0, and is subject to the following
//_/_/  
//_/_/  - CADIA Clause: The license granted in and to the software under this 
//_/_/    agreement is a limited-use license. The software may not be used in 
//_/_/    furtherance of: (i) intentionally causing bodily injury or severe 
//_/_/    emotional harm to any person; (ii) invading the personal privacy or 
//_/_/    violating the human rights of any person; or (iii) committing or 
//_/_/    preparing for any act of war. 
//_/_/    
//_/_/  A commercial license for PSYCLONE 2.0 is also available to 
//_/_/  any interested party from the copyright holder.
//_/_/  
//_/_/  You can redistribute this copy of PSYCLONE 2.0 and/or modify it under 
//_/_/  the terms of the GNU General Public License as published by the Free 
//_/_/  Software Foundation, either version 3 of the License, or (at your 
//_/_/  option) any later version.
//_/_/  
//_/_/  You should have received a copy of the GNU General Public License
//_/_/  and the GNU Lesser General Public License along with PSYCLONE 2.0.  
//_/_/  If not, see <http://www.gnu.org/licenses/>.
//_/_/  
//_/_/  PSYCLONE 2.0 is distributed in the hope that it will be useful,
//_/_/  but WITHOUT ANY WARRANTY; without even the implied warranty of
//_/_/  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//_/_/  GNU General Public License for more details.
//_/_/
//_/_/  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
//_/_/  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
//_/_/  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
//_/_/  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
//_/_/  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
//_/_/  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
//_/_/  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
//_/_/  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
//_/_/  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
//_/_/  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
//_/_/  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
#if !defined(_MONITORING_H_)
#define _MONITORING_H_

#pragma once

#include "MovingAverage.h"
#include "MemoryManager.h"
#include "NetworkManager.h"

namespace	cmlabs{

class Node;
class Logging;


struct PerformanceMatrixResults {
	uint32 from;
	uint32 to;
	double countPerSec[3];
	double valuePerSec[3];
    friend std::ostream& operator<<(std::ostream& os, const PerformanceMatrixResults& entry);
};


class PerformanceMatrix {
public:
	PerformanceMatrix(uint32 binTimeMS = 100, uint16 binCount = 350);
	~PerformanceMatrix();
	bool add(uint32 from, uint32 to, double val, uint32 count = 1, uint64 time = GetTimeNow());

	bool getAverage(uint32 from, uint32 to, uint32 ms, double& val, uint64& count, uint64 now = GetTimeNow());

	std::map<uint64, PerformanceMatrixResults> getThroughputResults(uint32 ms1, uint32 ms2, uint32 ms3, uint64 now = GetTimeNow());
	std::string getThroughputXML(const char* tagname, uint32 ms1, uint32 ms2, uint32 ms3, uint64 now = GetTimeNow());
	char* getThroughputBinary(uint32 &size, uint32 ms1, uint32 ms2, uint32 ms3, uint64 now = GetTimeNow());

	static std::map<uint64, PerformanceMatrixResults> GetThroughputResultsFromBinary(const char* data, uint32 size);
	static std::string GetThroughputXMLFromBinary(const char* tagname, const char* data, uint32 size);
	static std::string GetThroughputXMLFromResults(const char* tagname, std::map<uint64, PerformanceMatrixResults>& results);

protected:
	std::map<uint64, MovingAverage*> matrix;
	uint32 binTimeMS;
	uint16 binCount;
	utils::Mutex mutex;
};

struct OSProcStats {
	uint64 difTicks;
	double procCPU;
	double osCPU;
	uint64 procMem;
	bool add(OSProcStats &u) {
		procCPU += u.procCPU;
		osCPU += u.osCPU;
		procMem += u.procMem;
		return true;
	}
};

class MonitoringStats {
public:
	MonitoringStats() {
		time = 0;
		maxMemoryBytes = 0;
		memset(&lastStats, 0, sizeof(PerfStats));
		memset(&lastPerfStruct, 0, sizeof(AveragePerfStats));
	}
	uint64 time;

	MovingAverage cpuTicksDif;
	MovingAverage memoryBytesTotal;

	MovingAverage systemMemoryPercent;
	MovingAverage osMemoryPercent;
	MovingAverage percentOfSystemCPU;
	MovingAverage percentOfOSCPU;
	uint64 maxMemoryBytes;

	MovingAverage dataInputDif;
	MovingAverage dataOutputDif;
	MovingAverage dataQueuesDif;
	MovingAverage cycleCountDif;

	PerfStats lastStats;
	AveragePerfStats lastPerfStruct;

	bool addStats(PerfStats &stats, uint64 time, uint64 osMem, OSProcStats &procStats);
	bool processData(uint32 ms1, uint32 ms2, uint32 ms3, uint64 now = GetTimeNow());
};

class Monitoring : public Runnable
{
public:
	friend THREAD_RET THREAD_FUNCTION_CALL MonitoringRun(THREAD_ARG arg);

	// ***************** Constructors *****************
	Monitoring(uint32 ms1, uint32 ms2, uint32 ms3);
	virtual ~Monitoring();

	// ***************** Initialisation *****************
	bool init(Node* parent);
	bool startMonitoring();

	bool addCommunication(uint16 fromNodeID, uint16 toNodeID, uint32 from, uint32 to, uint32 size, uint32 count, uint64 time);

	bool setPerfDataFromOtherNode(const char* data, uint32 size, uint16 remoteNodeID);

	std::string getPerformanceMatrixXML();

	char* getNodeMatrixBinary(uint32 &size, uint64 now = GetTimeNow());
	char* getCompMatrixBinary(uint32 &size, uint64 now = GetTimeNow());

protected:
	Node* node;
	PsyType perfType;

	uint32 ms1;
	uint32 ms2;
	uint32 ms3;

	MonitoringStats localNodeStats;
	std::map<uint32, MonitoringStats*> localSpaceStats;
	std::map<uint32, MonitoringStats*> localComponentStats;

	std::map<uint16, AveragePerfStats*> otherNodeStats;
	std::map<uint32, AveragePerfStats*> otherSpaceStats;
	std::map<uint32, AveragePerfStats*> otherComponentStats;

	PerformanceMatrix* nodeCom;
	PerformanceMatrix* compCom;

	MovingAverage totalPercentOfOSCPU;
	MovingAverage totalPercentOfOSMemory;
	MovingAverage computerPercentOfOSCPU;
	MovingAverage computerPercentOfOSMemory;
	double localSystemCPUUsage[3];
	double localSystemMemoryUsage[3];
	double computerMemoryUsage[3];
	double computerCPUUsage[3];

	uint64 osMemorySize;
	uint64 osMemoryFree;
	uint64 prevOSTicks;
	uint64 prevOSIdleTicks;
	uint64 prevProcTicks;

	// ***************** Running *****************
	bool run();

	bool gatherPerformanceStats();
	bool sendOutPerformanceMessages(uint64 now);

};

THREAD_RET THREAD_FUNCTION_CALL MonitoringRun(THREAD_ARG arg);

}

#include "Node.h"

#endif // _MONITORING_H_
