<commit_before>//  regimes.cpp : examples of working with posit regimes
//
// Copyright (C) 2017-2018 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.

#include "common.hpp"
#include <posit>

// test reporting helper
int ReportTestResult(int nrOfFailedTests, std::string description, std::string test_operation)
{
	if (nrOfFailedTests > 0) {
		std::cout << description << " " << test_operation << " FAIL " << nrOfFailedTests << " failed test cases" << std::endl;
	}
	else {
		std::cout << description << " " << test_operation << " PASS" << std::endl;
	}
	return nrOfFailedTests;
}

/*
Regime range example for a posit<6,es>
	 regime      scale
	 00000          ~   associated with either 0 or NaR (Not a Real)
	 00001         -4
	 0001-         -3
	 001--         -2
	 01---         -1
	 10---          0
	 110--          1
	 1110-          2
	 11110          3
	 11111          4
*/
template<size_t nbits, size_t es>
int ValidateRegimeOperations(std::string tag, bool bReportIndividualTestCases) {
	const int NR_TEST_CASES = nbits;
	int nrOfFailedTestCases = 0;

	sw::unum::regime<nbits, es> r;
	for (int k = -NR_TEST_CASES; k < NR_TEST_CASES + 1; k++) {
		int reference = r.regime_size(k);
		size_t nrRegimeBits = r.assign_regime_pattern(k);
		if (nrRegimeBits != reference) {
			nrOfFailedTestCases++;
			if (bReportIndividualTestCases) std::cout << "FAIL: k = " << std::setw(3) << k << " regime is " << r << " bits " << nrRegimeBits << " reference " << reference << std::endl;
		}
		else {
			//if (bReportIndividualTestCases) std::cout << "PASS: k = " << std::setw(3) << k << " regime is " << r << " bits " << nrRegimeBits << " reference " << reference << std::endl;
		}
	}

	return nrOfFailedTestCases;
}

template<size_t nbits, size_t es>
int ValidateInwardProjection(std::string tag, bool bReportIndividualTestCases) {
	int nrOfFailedTests = 0;
	unsigned useed_scale = unsigned(1) << es;

	sw::unum::posit<nbits, es> p;
	// k represents the regime encoding
	int size = int(nbits);
	for (int k = -size + 1; k <= size - 1; k++) {
		int scale = k*useed_scale;
		bool inward = p.check_inward_projection_range(k*useed_scale);
		bool reference = k < 0 ? k == -size + 1 : k == size - 1;
		if (inward != reference) {
			nrOfFailedTests++;
			std::cout << "FAIL : k = " << setw(3) << k << " scale = " << std::setw(3) << scale << " inward projection range " << inward << " reference " << reference << std::endl;
		}
		std::cout << "k = " << setw(3) << k << " scale = " << std::setw(3) << scale << " inward projection range " << inward << std::endl;

	}
	return nrOfFailedTests;
}

template<size_t nbits, size_t es>
int ValidateRegimeScales(std::string tag, bool bReportIndividualTestCases) {
	int nrOfFailedTests = 0;
	int useed_scale = int(1) << es;  // int because we are doing int math with it

	sw::unum::regime<nbits, es> r1;
	sw::unum::posit<nbits, es> p; // for check_inward_projection_range
	// scale represents the binary scale of a value to test
	int size = int(nbits);
	for (int k = (-size + 1); k <= (size - 1); k++) {
		int scale = k*useed_scale;
		r1.assign_regime_pattern(k);
		if (r1.scale() != scale) {
			if (p.check_inward_projection_range(scale)) {
				if (r1.scale() == (k - 1)*useed_scale || r1.scale() == (k + 1)*useed_scale) {
					continue;
				}
			}
			nrOfFailedTests++;
			std::cout << "k = " << std::setw(3) << k
				<< " scale = " << std::setw(3) << scale
				<< " calc k " << std::setw(3) << r1.regime_k()
				<< " bits " << r1 << ":scale=" << r1.scale()
				<< " clamp " << p.check_inward_projection_range(scale) << std::endl;
		}

	}
	return nrOfFailedTests;
}

#define MANUAL_TESTING 0
#define STRESS_TESTING 0

int main(int argc, char** argv)
try {
	using namespace std;

	bool bReportIndividualTestCases = false;
	int nrOfFailedTestCases = 0;

	std::string tag = "Regime conversion failed";

#if MANUAL_TESTING

	// generate individual testcases to hand trace/debug
#if 0
	regime<10, 2> r;
	for (int k = -7; k < 9; k++) {
		int regime_size = r.assign_regime_pattern(k);
		cout << "k = " << setw(3) << k << " regime is " << r << " regime size is " << regime_size << " bits" << endl;
	}
#endif

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<3, 0>(tag, bReportIndividualTestCases), "posit<3,0>", "regimes");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<4, 1>(tag, bReportIndividualTestCases), "posit<4,1>", "regimes");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<5, 2>(tag, bReportIndividualTestCases), "posit<5,2>", "regimes");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<6, 3>(tag, bReportIndividualTestCases), "posit<6,3>", "regimes");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<7, 4>(tag, bReportIndividualTestCases), "posit<7,4>", "regimes");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<8, 5>(tag, bReportIndividualTestCases), "posit<8,5>", "regimes");
	return 0;
	nrOfFailedTestCases += ReportTestResult(ValidateInwardProjection<3, 0>(tag, bReportIndividualTestCases), "posit<3,0>", "regimes");
	nrOfFailedTestCases += ReportTestResult(ValidateInwardProjection<4, 1>(tag, bReportIndividualTestCases), "posit<4,1>", "regimes");
	nrOfFailedTestCases += ReportTestResult(ValidateInwardProjection<5, 2>(tag, bReportIndividualTestCases), "posit<5,2>", "regimes");
	nrOfFailedTestCases += ReportTestResult(ValidateInwardProjection<6, 3>(tag, bReportIndividualTestCases), "posit<6,3>", "regimes");

#else
	cout << "Regime tests" << endl;

	// TEST REGIME DECODE
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<3, 0>(tag, bReportIndividualTestCases), "regime<3,0>", "regime");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<4, 0>(tag, bReportIndividualTestCases), "regime<4,0>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<4, 1>(tag, bReportIndividualTestCases), "regime<4,1>", "regime");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<5, 0>(tag, bReportIndividualTestCases), "regime<5,0>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<5, 1>(tag, bReportIndividualTestCases), "regime<5,1>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<5, 2>(tag, bReportIndividualTestCases), "regime<5,2>", "regime");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<6, 0>(tag, bReportIndividualTestCases), "regime<6,0>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<6, 1>(tag, bReportIndividualTestCases), "regime<6,1>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<6, 2>(tag, bReportIndividualTestCases), "regime<6,2>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<6, 3>(tag, bReportIndividualTestCases), "regime<6,3>", "regime");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<7, 0>(tag, bReportIndividualTestCases), "regime<7,0>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<7, 1>(tag, bReportIndividualTestCases), "regime<7,1>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<7, 2>(tag, bReportIndividualTestCases), "regime<7,2>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<7, 3>(tag, bReportIndividualTestCases), "regime<7,3>", "regime");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<8, 0>(tag, bReportIndividualTestCases), "regime<8,0>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<8, 1>(tag, bReportIndividualTestCases), "regime<8,1>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<8, 2>(tag, bReportIndividualTestCases), "regime<8,2>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<8, 3>(tag, bReportIndividualTestCases), "regime<8,3>", "regime");

	// TEST REGIME CONVERSION
	// DIFFERENT WAY TO TEST REGIME CONSTRUCTION
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<3, 0>(tag, bReportIndividualTestCases), "posit<3,0>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<4, 1>(tag, bReportIndividualTestCases), "posit<4,1>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<5, 2>(tag, bReportIndividualTestCases), "posit<5,2>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<6, 3>(tag, bReportIndividualTestCases), "posit<6,3>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<7, 4>(tag, bReportIndividualTestCases), "posit<7,4>", "scales");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<8, 0>(tag, bReportIndividualTestCases), "posit<8,0>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<8, 1>(tag, bReportIndividualTestCases), "posit<8,1>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<8, 2>(tag, bReportIndividualTestCases), "posit<8,2>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<8, 3>(tag, bReportIndividualTestCases), "posit<8,3>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<8, 4>(tag, bReportIndividualTestCases), "posit<8,4>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<8, 5>(tag, bReportIndividualTestCases), "posit<8,5>", "scales");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<16, 0>(tag, bReportIndividualTestCases), "posit<16,0>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<16, 1>(tag, bReportIndividualTestCases), "posit<16,1>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<16, 2>(tag, bReportIndividualTestCases), "posit<16,2>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<16, 3>(tag, bReportIndividualTestCases), "posit<16,3>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<16, 4>(tag, bReportIndividualTestCases), "posit<16,4>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<16, 5>(tag, bReportIndividualTestCases), "posit<16,5>", "scales");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<32, 0>(tag, bReportIndividualTestCases), "posit<32,0>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<32, 1>(tag, bReportIndividualTestCases), "posit<32,1>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<32, 2>(tag, bReportIndividualTestCases), "posit<32,2>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<32, 3>(tag, bReportIndividualTestCases), "posit<32,3>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<32, 4>(tag, bReportIndividualTestCases), "posit<32,4>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<32, 5>(tag, bReportIndividualTestCases), "posit<32,5>", "scales");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<64, 0>(tag, bReportIndividualTestCases), "posit<64,0>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<64, 1>(tag, bReportIndividualTestCases), "posit<64,1>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<64, 2>(tag, bReportIndividualTestCases), "posit<64,2>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<64, 3>(tag, bReportIndividualTestCases), "posit<64,3>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<64, 4>(tag, bReportIndividualTestCases), "posit<64,4>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<64, 5>(tag, bReportIndividualTestCases), "posit<64,5>", "scales");
#endif

	return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
catch (char const* msg) {
	std::cerr << msg << std::endl;
	return EXIT_FAILURE;
}
catch (...) {
	std::cerr << "Caught unknown exception" << std::endl;
	return EXIT_FAILURE;
}
<commit_msg>Compilation fix<commit_after>//  regimes.cpp : examples of working with posit regimes
//
// Copyright (C) 2017-2018 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.

#include "common.hpp"
#include <posit>

// test reporting helper
int ReportTestResult(int nrOfFailedTests, std::string description, std::string test_operation)
{
	if (nrOfFailedTests > 0) {
		std::cout << description << " " << test_operation << " FAIL " << nrOfFailedTests << " failed test cases" << std::endl;
	}
	else {
		std::cout << description << " " << test_operation << " PASS" << std::endl;
	}
	return nrOfFailedTests;
}

/*
Regime range example for a posit<6,es>
	 regime      scale
	 00000          ~   associated with either 0 or NaR (Not a Real)
	 00001         -4
	 0001-         -3
	 001--         -2
	 01---         -1
	 10---          0
	 110--          1
	 1110-          2
	 11110          3
	 11111          4
*/
template<size_t nbits, size_t es>
int ValidateRegimeOperations(std::string tag, bool bReportIndividualTestCases) {
	const int NR_TEST_CASES = nbits;
	int nrOfFailedTestCases = 0;

	sw::unum::regime<nbits, es> r;
	for (int k = -NR_TEST_CASES; k < NR_TEST_CASES + 1; k++) {
		int reference = r.regime_size(k);
		size_t nrRegimeBits = r.assign_regime_pattern(k);
		if (nrRegimeBits != reference) {
			nrOfFailedTestCases++;
			if (bReportIndividualTestCases) std::cout << "FAIL: k = " << std::setw(3) << k << " regime is " << r << " bits " << nrRegimeBits << " reference " << reference << std::endl;
		}
		else {
			//if (bReportIndividualTestCases) std::cout << "PASS: k = " << std::setw(3) << k << " regime is " << r << " bits " << nrRegimeBits << " reference " << reference << std::endl;
		}
	}

	return nrOfFailedTestCases;
}

template<size_t nbits, size_t es>
int ValidateInwardProjection(std::string tag, bool bReportIndividualTestCases) {
	int nrOfFailedTests = 0;
	unsigned useed_scale = unsigned(1) << es;

	sw::unum::posit<nbits, es> p;
	// k represents the regime encoding
	int size = int(nbits);
	for (int k = -size + 1; k <= size - 1; k++) {
		int scale = k*useed_scale;
		bool inward = p.check_inward_projection_range(k*useed_scale);
		bool reference = k < 0 ? k == -size + 1 : k == size - 1;
		if (inward != reference) {
			nrOfFailedTests++;
			std::cout << "FAIL : k = " << std::setw(3) << k << " scale = " << std::setw(3) << scale << " inward projection range " << inward << " reference " << reference << std::endl;
		}
		std::cout << "k = " << std::setw(3) << k << " scale = " << std::setw(3) << scale << " inward projection range " << inward << std::endl;

	}
	return nrOfFailedTests;
}

template<size_t nbits, size_t es>
int ValidateRegimeScales(std::string tag, bool bReportIndividualTestCases) {
	int nrOfFailedTests = 0;
	int useed_scale = int(1) << es;  // int because we are doing int math with it

	sw::unum::regime<nbits, es> r1;
	sw::unum::posit<nbits, es> p; // for check_inward_projection_range
	// scale represents the binary scale of a value to test
	int size = int(nbits);
	for (int k = (-size + 1); k <= (size - 1); k++) {
		int scale = k*useed_scale;
		r1.assign_regime_pattern(k);
		if (r1.scale() != scale) {
			if (p.check_inward_projection_range(scale)) {
				if (r1.scale() == (k - 1)*useed_scale || r1.scale() == (k + 1)*useed_scale) {
					continue;
				}
			}
			nrOfFailedTests++;
			std::cout << "k = " << std::setw(3) << k
				<< " scale = " << std::setw(3) << scale
				<< " calc k " << std::setw(3) << r1.regime_k()
				<< " bits " << r1 << ":scale=" << r1.scale()
				<< " clamp " << p.check_inward_projection_range(scale) << std::endl;
		}

	}
	return nrOfFailedTests;
}

#define MANUAL_TESTING 0
#define STRESS_TESTING 0

int main(int argc, char** argv)
try {
	using namespace std;

	bool bReportIndividualTestCases = false;
	int nrOfFailedTestCases = 0;

	std::string tag = "Regime conversion failed";

#if MANUAL_TESTING

	// generate individual testcases to hand trace/debug
#if 0
	regime<10, 2> r;
	for (int k = -7; k < 9; k++) {
		int regime_size = r.assign_regime_pattern(k);
		cout << "k = " << setw(3) << k << " regime is " << r << " regime size is " << regime_size << " bits" << endl;
	}
#endif

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<3, 0>(tag, bReportIndividualTestCases), "posit<3,0>", "regimes");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<4, 1>(tag, bReportIndividualTestCases), "posit<4,1>", "regimes");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<5, 2>(tag, bReportIndividualTestCases), "posit<5,2>", "regimes");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<6, 3>(tag, bReportIndividualTestCases), "posit<6,3>", "regimes");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<7, 4>(tag, bReportIndividualTestCases), "posit<7,4>", "regimes");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<8, 5>(tag, bReportIndividualTestCases), "posit<8,5>", "regimes");
	return 0;
	nrOfFailedTestCases += ReportTestResult(ValidateInwardProjection<3, 0>(tag, bReportIndividualTestCases), "posit<3,0>", "regimes");
	nrOfFailedTestCases += ReportTestResult(ValidateInwardProjection<4, 1>(tag, bReportIndividualTestCases), "posit<4,1>", "regimes");
	nrOfFailedTestCases += ReportTestResult(ValidateInwardProjection<5, 2>(tag, bReportIndividualTestCases), "posit<5,2>", "regimes");
	nrOfFailedTestCases += ReportTestResult(ValidateInwardProjection<6, 3>(tag, bReportIndividualTestCases), "posit<6,3>", "regimes");

#else
	cout << "Regime tests" << endl;

	// TEST REGIME DECODE
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<3, 0>(tag, bReportIndividualTestCases), "regime<3,0>", "regime");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<4, 0>(tag, bReportIndividualTestCases), "regime<4,0>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<4, 1>(tag, bReportIndividualTestCases), "regime<4,1>", "regime");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<5, 0>(tag, bReportIndividualTestCases), "regime<5,0>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<5, 1>(tag, bReportIndividualTestCases), "regime<5,1>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<5, 2>(tag, bReportIndividualTestCases), "regime<5,2>", "regime");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<6, 0>(tag, bReportIndividualTestCases), "regime<6,0>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<6, 1>(tag, bReportIndividualTestCases), "regime<6,1>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<6, 2>(tag, bReportIndividualTestCases), "regime<6,2>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<6, 3>(tag, bReportIndividualTestCases), "regime<6,3>", "regime");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<7, 0>(tag, bReportIndividualTestCases), "regime<7,0>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<7, 1>(tag, bReportIndividualTestCases), "regime<7,1>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<7, 2>(tag, bReportIndividualTestCases), "regime<7,2>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<7, 3>(tag, bReportIndividualTestCases), "regime<7,3>", "regime");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<8, 0>(tag, bReportIndividualTestCases), "regime<8,0>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<8, 1>(tag, bReportIndividualTestCases), "regime<8,1>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<8, 2>(tag, bReportIndividualTestCases), "regime<8,2>", "regime");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeOperations<8, 3>(tag, bReportIndividualTestCases), "regime<8,3>", "regime");

	// TEST REGIME CONVERSION
	// DIFFERENT WAY TO TEST REGIME CONSTRUCTION
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<3, 0>(tag, bReportIndividualTestCases), "posit<3,0>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<4, 1>(tag, bReportIndividualTestCases), "posit<4,1>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<5, 2>(tag, bReportIndividualTestCases), "posit<5,2>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<6, 3>(tag, bReportIndividualTestCases), "posit<6,3>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<7, 4>(tag, bReportIndividualTestCases), "posit<7,4>", "scales");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<8, 0>(tag, bReportIndividualTestCases), "posit<8,0>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<8, 1>(tag, bReportIndividualTestCases), "posit<8,1>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<8, 2>(tag, bReportIndividualTestCases), "posit<8,2>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<8, 3>(tag, bReportIndividualTestCases), "posit<8,3>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<8, 4>(tag, bReportIndividualTestCases), "posit<8,4>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<8, 5>(tag, bReportIndividualTestCases), "posit<8,5>", "scales");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<16, 0>(tag, bReportIndividualTestCases), "posit<16,0>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<16, 1>(tag, bReportIndividualTestCases), "posit<16,1>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<16, 2>(tag, bReportIndividualTestCases), "posit<16,2>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<16, 3>(tag, bReportIndividualTestCases), "posit<16,3>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<16, 4>(tag, bReportIndividualTestCases), "posit<16,4>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<16, 5>(tag, bReportIndividualTestCases), "posit<16,5>", "scales");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<32, 0>(tag, bReportIndividualTestCases), "posit<32,0>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<32, 1>(tag, bReportIndividualTestCases), "posit<32,1>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<32, 2>(tag, bReportIndividualTestCases), "posit<32,2>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<32, 3>(tag, bReportIndividualTestCases), "posit<32,3>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<32, 4>(tag, bReportIndividualTestCases), "posit<32,4>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<32, 5>(tag, bReportIndividualTestCases), "posit<32,5>", "scales");

	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<64, 0>(tag, bReportIndividualTestCases), "posit<64,0>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<64, 1>(tag, bReportIndividualTestCases), "posit<64,1>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<64, 2>(tag, bReportIndividualTestCases), "posit<64,2>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<64, 3>(tag, bReportIndividualTestCases), "posit<64,3>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<64, 4>(tag, bReportIndividualTestCases), "posit<64,4>", "scales");
	nrOfFailedTestCases += ReportTestResult(ValidateRegimeScales<64, 5>(tag, bReportIndividualTestCases), "posit<64,5>", "scales");
#endif

	return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
catch (char const* msg) {
	std::cerr << msg << std::endl;
	return EXIT_FAILURE;
}
catch (...) {
	std::cerr << "Caught unknown exception" << std::endl;
	return EXIT_FAILURE;
}
<|endoftext|>


<commit_before>#include "client.h"

#include <iostream>
#include <stdlib.h>
#include <string.h>

#include <boost/assert.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/xpressive/xpressive.hpp>

#define DEFAULT_ASSET_TIMEOUT 4000

using namespace std;
namespace asio = boost::asio;
namespace xpressive = boost::xpressive;

using namespace bithorde;

uint64_t rand64() {
	// TODO: improve seeding throuh srandomdev
	return (((uint64_t)rand()) << 32) | rand();
}

Client::Client(asio::io_service& ioSvc, string myName) :
	_ioSvc(ioSvc),
	_connection(),
	_myName(myName),
	_handleAllocator(1),
	_rpcIdAllocator(1),
	_protoVersion(0)
{
}

void Client::connect(Connection::Pointer newConn) {
	BOOST_ASSERT(!_connection);

	_rpcIdAllocator.reset();
	_connection = newConn;

	_messageConnection = _connection->message.connect(Connection::MessageSignal::slot_type(&Client::onIncomingMessage, this, _1, _2));
	_writableConnection = _connection->writable.connect(writable);
	_disconnectedConnection = _connection->disconnected.connect(Connection::VoidSignal::slot_type(&Client::onDisconnected, this));

	sayHello();
}

void Client::connect(asio::ip::tcp::endpoint& ep) {
	connect(Connection::create(_ioSvc, ep));
}

void Client::connect(asio::local::stream_protocol::endpoint& ep) {
	connect(Connection::create(_ioSvc, ep));
}

void Client::connect(string spec) {
	xpressive::sregex host_port_regex = xpressive::sregex::compile("(\\w+):(\\d+)");
	xpressive::smatch res;
	if (spec[0] == '/') {
		asio::local::stream_protocol::endpoint ep(spec);
		connect(ep);
	} else if (xpressive::regex_match(spec, res, host_port_regex)) {
		asio::ip::tcp::resolver resolver(_ioSvc);
		asio::ip::tcp::resolver::query q(res[1], res[2]);
		asio::ip::tcp::resolver::iterator iter = resolver.resolve(q);
		if (iter != asio::ip::tcp::resolver::iterator()) {
			asio::ip::tcp::endpoint ep(iter->endpoint());
			connect(ep);
		}
	} else {
		throw string("Failed to parse: " + spec);
	}
}

void Client::onDisconnected() {
	_connection.reset();
	for (auto iter=_assetMap.begin(); iter != _assetMap.end(); iter++) {
		ReadAsset* asset = dynamic_cast<ReadAsset*>(iter->second);
		if (asset) {
			bithorde::AssetStatus s;
			s.set_status(bithorde::DISCONNECTED);
			asset->statusUpdate(s);
		} else {
			_handleAllocator.free(iter->first);
			_assetMap.erase(iter);
		}
	}
	disconnected();
}

bool Client::isConnected()
{
	return _connection;
}

const std::string& Client::peerName()
{
	return _peerName;
}

bool Client::sendMessage(Connection::MessageType type, const::google::protobuf::Message &msg)
{
	BOOST_ASSERT(_connection);

	return _connection->sendMessage(type, msg);
}

void Client::sayHello() {
	bithorde::HandShake h;
	h.set_protoversion(2);
	h.set_name(_myName);

	sendMessage(Connection::HandShake, h);
}

void Client::onIncomingMessage(Connection::MessageType type, ::google::protobuf::Message& msg)
{
	switch (type) {
	case Connection::HandShake: return onMessage((bithorde::HandShake&) msg);
	case Connection::BindRead: return onMessage((bithorde::BindRead&) msg);
	case Connection::AssetStatus: return onMessage((bithorde::AssetStatus&) msg);
	case Connection::ReadRequest: return onMessage((bithorde::Read::Request&) msg);
	case Connection::ReadResponse: return onMessage((bithorde::Read::Response&) msg);
	case Connection::BindWrite: return onMessage((bithorde::BindWrite&) msg);
	case Connection::DataSegment: return onMessage((bithorde::DataSegment&) msg);
	case Connection::HandShakeConfirmed: return onMessage((bithorde::HandShakeConfirmed&) msg);
	case Connection::Ping: return onMessage((bithorde::Ping&) msg);
	}
}

void Client::onMessage(const bithorde::HandShake &msg)
{
	if (msg.protoversion() >= 2) {
		_protoVersion = 2;
	} else {
		cerr << "Only Protocol-version 2 or higer supported" << endl;
		// TODO: disconnect properly
		return;
	}

	_peerName = msg.name();

	if (msg.has_challenge()) {
		cerr << "Challenge required" << endl;
		// Setup encryption
	} else {
		for (auto iter = _assetMap.begin(); iter != _assetMap.end(); iter++) {
			ReadAsset* asset = dynamic_cast<ReadAsset*>(iter->second);
			BOOST_ASSERT(iter->second);
			informBound(*asset);
		}

		authenticated(_peerName);
	}
}

void Client::onMessage(const bithorde::BindRead & msg) {
	cerr << "unsupported: handling BindRead" << endl;
	bithorde::AssetStatus resp;
	resp.set_handle(msg.handle());
	resp.set_status(ERROR);
	sendMessage(bithorde::Connection::AssetStatus, resp);
}
void Client::onMessage(const bithorde::AssetStatus & msg) {
	if (!msg.has_handle())
		return;
	Asset::Handle handle = msg.handle();
	if (_assetMap.count(handle)) {
		Asset* a = _assetMap[handle];
		if (a) {
			a->handleMessage(msg);
		} else if (msg.status() != bithorde::Status::SUCCESS) {
			_assetMap.erase(handle);
			_handleAllocator.free(handle);
		} else {
			cerr << "WARNING: Status OK recieved for Asset supposedly closed or re-written." << endl;
		}
	} else {
		cerr << "WARNING: AssetStatus for unmapped handle" << endl;
	}
}

void Client::onMessage(const bithorde::Read::Request & msg) {
	cerr << "unsupported: handling Read-Requests" << endl;
	bithorde::Read::Response resp;
	resp.set_reqid(msg.reqid());
	resp.set_status(ERROR);
	sendMessage(bithorde::Connection::ReadResponse, resp);
}

void Client::onMessage(const bithorde::Read::Response & msg) {
	Asset::Handle assetHandle = _requestIdMap[msg.reqid()];
	if (_assetMap.count(assetHandle)) {
		Asset* a = _assetMap[assetHandle];
		a->handleMessage(msg);
	} else {
		cerr << "WARNING: ReadResponse " << msg.reqid() << msg.has_reqid() << " for unmapped handle" << endl;
	}
}

void Client::onMessage(const bithorde::BindWrite & msg) {
	cerr << "unsupported: handling BindWrite" << endl;
	bithorde::AssetStatus resp;
	resp.set_handle(msg.handle());
	resp.set_status(ERROR);
	sendMessage(bithorde::Connection::AssetStatus, resp);
}
void Client::onMessage(const bithorde::DataSegment & msg) {
	cerr << "unsupported: handling DataSegment-pushes" << endl;
	_connection->close();
}
void Client::onMessage(const bithorde::HandShakeConfirmed & msg) {
	cerr << "unsupported: challenge-response handshakes" << endl;
	_connection->close();
}
void Client::onMessage(const bithorde::Ping & msg) {
	bithorde::Ping reply;
	_connection->sendMessage(Connection::Ping, reply);
}

bool Client::bind(ReadAsset &asset) {
	if (!asset.isBound()) {
		BOOST_ASSERT(asset._handle < 0);
		BOOST_ASSERT(asset.requestIds().size() > 0);
		asset._handle = _handleAllocator.allocate();
		BOOST_ASSERT(asset._handle > 0);
		_assetMap[asset._handle] = &asset;
	}

	return informBound(asset);
}

bool Client::bind(UploadAsset & asset)
{
	// TODO: BOOST_ASSERT(asset._client == this);
	BOOST_ASSERT(asset._handle < 0);
	BOOST_ASSERT(asset.size() > 0);
	asset._handle = _handleAllocator.allocate();
	_assetMap[asset._handle] = &asset;
	bithorde::BindWrite msg;
	msg.set_handle(asset._handle);
	msg.set_size(asset.size());
	const auto& link = asset.link();
	if (!link.empty())
		msg.set_linkpath(link.string());
	return _connection->sendMessage(Connection::BindWrite, msg);
}

bool Client::release(Asset & asset)
{
	BOOST_ASSERT(asset.isBound());
	bithorde::BindRead msg;
	msg.set_handle(asset._handle);
	msg.set_timeout(DEFAULT_ASSET_TIMEOUT);
	msg.set_uuid(rand64());

	_assetMap[asset._handle] = NULL;
	asset._handle = -1;

	return _connection->sendMessage(Connection::BindRead, msg);
}

bool Client::informBound(const ReadAsset& asset)
{
	BOOST_ASSERT(_connection);
	BOOST_ASSERT(asset._handle >= 0);

	if (!_connection)
		return false;

	bithorde::BindRead msg;
	msg.set_handle(asset._handle);

	auto ids = asset.requestIds();
	for (auto iter = ids.begin(); iter < ids.end(); iter++) {
		ReadAsset::Identifier& id = *iter;
		bithorde::Identifier * bhId = msg.add_ids();
		bhId->set_type(id.first);
		bhId->set_id(id.second.data(), id.second.size());
	}
	msg.set_timeout(DEFAULT_ASSET_TIMEOUT);
	msg.set_uuid(rand64());
	return _connection->sendMessage(Connection::BindRead, msg);
}

int Client::allocRPCRequest(Asset::Handle asset)
{
	int res = _rpcIdAllocator.allocate();
	_requestIdMap[res] = asset;
	return res;
}

void Client::releaseRPCRequest(int reqId)
{
	_requestIdMap.erase(reqId);
	_rpcIdAllocator.free(reqId);
}
<commit_msg>[lib/client]Minor assertion and logging-fixes.<commit_after>#include "client.h"

#include <iostream>
#include <stdlib.h>
#include <string.h>

#include <boost/assert.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/xpressive/xpressive.hpp>

#define DEFAULT_ASSET_TIMEOUT 4000

using namespace std;
namespace asio = boost::asio;
namespace xpressive = boost::xpressive;

using namespace bithorde;

uint64_t rand64() {
	// TODO: improve seeding throuh srandomdev
	return (((uint64_t)rand()) << 32) | rand();
}

Client::Client(asio::io_service& ioSvc, string myName) :
	_ioSvc(ioSvc),
	_connection(),
	_myName(myName),
	_handleAllocator(1),
	_rpcIdAllocator(1),
	_protoVersion(0)
{
}

void Client::connect(Connection::Pointer newConn) {
	BOOST_ASSERT(!_connection);

	_rpcIdAllocator.reset();
	_connection = newConn;

	_messageConnection = _connection->message.connect(Connection::MessageSignal::slot_type(&Client::onIncomingMessage, this, _1, _2));
	_writableConnection = _connection->writable.connect(writable);
	_disconnectedConnection = _connection->disconnected.connect(Connection::VoidSignal::slot_type(&Client::onDisconnected, this));

	sayHello();
}

void Client::connect(asio::ip::tcp::endpoint& ep) {
	connect(Connection::create(_ioSvc, ep));
}

void Client::connect(asio::local::stream_protocol::endpoint& ep) {
	connect(Connection::create(_ioSvc, ep));
}

void Client::connect(string spec) {
	xpressive::sregex host_port_regex = xpressive::sregex::compile("(\\w+):(\\d+)");
	xpressive::smatch res;
	if (spec[0] == '/') {
		asio::local::stream_protocol::endpoint ep(spec);
		connect(ep);
	} else if (xpressive::regex_match(spec, res, host_port_regex)) {
		asio::ip::tcp::resolver resolver(_ioSvc);
		asio::ip::tcp::resolver::query q(res[1], res[2]);
		asio::ip::tcp::resolver::iterator iter = resolver.resolve(q);
		if (iter != asio::ip::tcp::resolver::iterator()) {
			asio::ip::tcp::endpoint ep(iter->endpoint());
			connect(ep);
		}
	} else {
		throw string("Failed to parse: " + spec);
	}
}

void Client::onDisconnected() {
	_connection.reset();
	for (auto iter=_assetMap.begin(); iter != _assetMap.end(); iter++) {
		ReadAsset* asset = dynamic_cast<ReadAsset*>(iter->second);
		if (asset) {
			bithorde::AssetStatus s;
			s.set_status(bithorde::DISCONNECTED);
			asset->statusUpdate(s);
		} else {
			_handleAllocator.free(iter->first);
			_assetMap.erase(iter);
		}
	}
	disconnected();
}

bool Client::isConnected()
{
	return _connection;
}

const std::string& Client::peerName()
{
	return _peerName;
}

bool Client::sendMessage(Connection::MessageType type, const::google::protobuf::Message &msg)
{
	BOOST_ASSERT(_connection);

	return _connection->sendMessage(type, msg);
}

void Client::sayHello() {
	bithorde::HandShake h;
	h.set_protoversion(2);
	h.set_name(_myName);

	sendMessage(Connection::HandShake, h);
}

void Client::onIncomingMessage(Connection::MessageType type, ::google::protobuf::Message& msg)
{
	switch (type) {
	case Connection::HandShake: return onMessage((bithorde::HandShake&) msg);
	case Connection::BindRead: return onMessage((bithorde::BindRead&) msg);
	case Connection::AssetStatus: return onMessage((bithorde::AssetStatus&) msg);
	case Connection::ReadRequest: return onMessage((bithorde::Read::Request&) msg);
	case Connection::ReadResponse: return onMessage((bithorde::Read::Response&) msg);
	case Connection::BindWrite: return onMessage((bithorde::BindWrite&) msg);
	case Connection::DataSegment: return onMessage((bithorde::DataSegment&) msg);
	case Connection::HandShakeConfirmed: return onMessage((bithorde::HandShakeConfirmed&) msg);
	case Connection::Ping: return onMessage((bithorde::Ping&) msg);
	}
}

void Client::onMessage(const bithorde::HandShake &msg)
{
	if (msg.protoversion() >= 2) {
		_protoVersion = 2;
	} else {
		cerr << "Only Protocol-version 2 or higer supported" << endl;
		// TODO: disconnect properly
		return;
	}

	_peerName = msg.name();

	if (msg.has_challenge()) {
		cerr << "Challenge required" << endl;
		// Setup encryption
	} else {
		for (auto iter = _assetMap.begin(); iter != _assetMap.end(); iter++) {
			ReadAsset* asset = dynamic_cast<ReadAsset*>(iter->second);
			BOOST_ASSERT(iter->second);
			informBound(*asset);
		}

		authenticated(_peerName);
	}
}

void Client::onMessage(const bithorde::BindRead & msg) {
	cerr << "unsupported: handling BindRead" << endl;
	bithorde::AssetStatus resp;
	resp.set_handle(msg.handle());
	resp.set_status(ERROR);
	sendMessage(bithorde::Connection::AssetStatus, resp);
}
void Client::onMessage(const bithorde::AssetStatus & msg) {
	if (!msg.has_handle())
		return;
	Asset::Handle handle = msg.handle();
	if (_assetMap.count(handle)) {
		Asset* a = _assetMap[handle];
		if (a) {
			a->handleMessage(msg);
		} else if (msg.status() != bithorde::Status::SUCCESS) {
			_assetMap.erase(handle);
			_handleAllocator.free(handle);
		} else {
			cerr << "WARNING: Status OK recieved for Asset supposedly closed or re-written." << endl;
		}
	} else {
		cerr << "WARNING: AssetStatus " << bithorde::Status_Name(msg.status()) << " for unmapped handle" << endl;
	}
}

void Client::onMessage(const bithorde::Read::Request & msg) {
	cerr << "unsupported: handling Read-Requests" << endl;
	bithorde::Read::Response resp;
	resp.set_reqid(msg.reqid());
	resp.set_status(ERROR);
	sendMessage(bithorde::Connection::ReadResponse, resp);
}

void Client::onMessage(const bithorde::Read::Response & msg) {
	Asset::Handle assetHandle = _requestIdMap[msg.reqid()];
	if (_assetMap.count(assetHandle)) {
		Asset* a = _assetMap[assetHandle];
		a->handleMessage(msg);
	} else {
		cerr << "WARNING: ReadResponse " << msg.reqid() << msg.has_reqid() << " for unmapped handle" << endl;
	}
}

void Client::onMessage(const bithorde::BindWrite & msg) {
	cerr << "unsupported: handling BindWrite" << endl;
	bithorde::AssetStatus resp;
	resp.set_handle(msg.handle());
	resp.set_status(ERROR);
	sendMessage(bithorde::Connection::AssetStatus, resp);
}
void Client::onMessage(const bithorde::DataSegment & msg) {
	cerr << "unsupported: handling DataSegment-pushes" << endl;
	_connection->close();
}
void Client::onMessage(const bithorde::HandShakeConfirmed & msg) {
	cerr << "unsupported: challenge-response handshakes" << endl;
	_connection->close();
}
void Client::onMessage(const bithorde::Ping & msg) {
	bithorde::Ping reply;
	_connection->sendMessage(Connection::Ping, reply);
}

bool Client::bind(ReadAsset &asset) {
	if (!asset.isBound()) {
		BOOST_ASSERT(asset._handle < 0);
		BOOST_ASSERT(asset.requestIds().size() > 0);
		asset._handle = _handleAllocator.allocate();
		BOOST_ASSERT(asset._handle > 0);
		BOOST_ASSERT(_assetMap.count(asset._handle) == 0);
		_assetMap[asset._handle] = &asset;
	}

	return informBound(asset);
}

bool Client::bind(UploadAsset & asset)
{
	// TODO: BOOST_ASSERT(asset._client == this);
	BOOST_ASSERT(asset._handle < 0);
	BOOST_ASSERT(asset.size() > 0);
	asset._handle = _handleAllocator.allocate();
	_assetMap[asset._handle] = &asset;
	bithorde::BindWrite msg;
	msg.set_handle(asset._handle);
	msg.set_size(asset.size());
	const auto& link = asset.link();
	if (!link.empty())
		msg.set_linkpath(link.string());
	return _connection->sendMessage(Connection::BindWrite, msg);
}

bool Client::release(Asset & asset)
{
	BOOST_ASSERT(asset.isBound());
	bithorde::BindRead msg;
	msg.set_handle(asset._handle);
	msg.set_timeout(DEFAULT_ASSET_TIMEOUT);
	msg.set_uuid(rand64());

	_assetMap.erase(asset._handle);
	asset._handle = -1;

	return _connection->sendMessage(Connection::BindRead, msg);
}

bool Client::informBound(const ReadAsset& asset)
{
	BOOST_ASSERT(_connection);
	BOOST_ASSERT(asset._handle >= 0);

	if (!_connection)
		return false;

	bithorde::BindRead msg;
	msg.set_handle(asset._handle);

	auto ids = asset.requestIds();
	for (auto iter = ids.begin(); iter < ids.end(); iter++) {
		ReadAsset::Identifier& id = *iter;
		bithorde::Identifier * bhId = msg.add_ids();
		bhId->set_type(id.first);
		bhId->set_id(id.second.data(), id.second.size());
	}
	msg.set_timeout(DEFAULT_ASSET_TIMEOUT);
	msg.set_uuid(rand64());
	return _connection->sendMessage(Connection::BindRead, msg);
}

int Client::allocRPCRequest(Asset::Handle asset)
{
	int res = _rpcIdAllocator.allocate();
	_requestIdMap[res] = asset;
	return res;
}

void Client::releaseRPCRequest(int reqId)
{
	_requestIdMap.erase(reqId);
	_rpcIdAllocator.free(reqId);
}
<|endoftext|>


<commit_before>/*
 * LocalSimilarityAttributizer.cpp
 *
 *  Created on: 26.07.2014
 *      Author: Gerd Lindner
 */

#include "LocalSimilarityAttributizer.h"
#include <math.h> //log
#include <set>
#include "../auxiliary/Log.h"

namespace NetworKit {

LocalSimilarityAttributizer::LocalSimilarityAttributizer() {}

EdgeAttribute LocalSimilarityAttributizer::getAttribute(const Graph& graph, const EdgeAttribute& attribute) {
	/*
	 * For each edge, we calculate the minimum required sparsification exponent e
	 * such that the edge is contained in the backbone.
	 */

	EdgeAttribute sparsificationExp(graph.upperEdgeIdBound(), 1.0);

	graph.forNodes([&](node i) {
		count d = graph.degree(i);

		/*
		 * The top d^e edges (sorted by similarity in descending order)
		 * are to be kept in the backbone.
		 */

		std::vector<AttributizedEdge> neighbors;
		graph.forNeighborsOf(i, [&](node _i, node j, edgeid eid) {
			double sim = getSimilarity(graph, i, j);
			neighbors.push_back(AttributizedEdge(i, j, eid, sim));
		});
		std::sort(neighbors.begin(), neighbors.end(), greater());

		count rank = 1;
		for(std::vector<AttributizedEdge>::iterator it = neighbors.begin(); it != neighbors.end(); ++it) {
			edgeid eid = it->eid;

			double e = 0.0;
			if (d > 1)
				e = log(rank) / log(d);

			sparsificationExp[eid] = std::min(e, sparsificationExp[eid]);
			rank++;
		}

	});

	return sparsificationExp;
}

/**
 * Returns the similarity between two nodes.
 */
double LocalSimilarityAttributizer::getSimilarity(const Graph& graph, node u, node v) {
	//Use the jaccard measure as similarity measure.
	/* TODO: The following implementation might be quite inefficient....
	 * can the implementation in community/JaccardMeasure be used?
	 */
	std::set<node> uNeighbors;
	graph.forNeighborsOf(u, [&](node n) {
		uNeighbors.insert(n);
	});

	count inUnion = graph.degree(u);
	count inIntersection = 0;

	graph.forNeighborsOf(v, [&](node n) {
		if (uNeighbors.erase(n))
			inIntersection++;
		else
			inUnion++;
	});

	return (double) inIntersection / (double) inUnion;
}

} /* namespace NetworKit */
<commit_msg>Parallelization in local similarity calculation<commit_after>/*
 * LocalSimilarityAttributizer.cpp
 *
 *  Created on: 26.07.2014
 *      Author: Gerd Lindner
 */

#include "LocalSimilarityAttributizer.h"
#include <math.h> //log
#include <set>
#include "../auxiliary/Log.h"

namespace NetworKit {

LocalSimilarityAttributizer::LocalSimilarityAttributizer() {}

EdgeAttribute LocalSimilarityAttributizer::getAttribute(const Graph& graph, const EdgeAttribute& attribute) {
	/*
	 * For each edge, we calculate the minimum required sparsification exponent e
	 * such that the edge is contained in the backbone.
	 */

	EdgeAttribute sparsificationExp(graph.upperEdgeIdBound(), 1.0);

	graph.parallelForNodes([&](node i) {
		count d = graph.degree(i);

		/*
		 * The top d^e edges (sorted by similarity in descending order)
		 * are to be kept in the backbone.
		 */

		std::vector<AttributizedEdge> neighbors;
		graph.forNeighborsOf(i, [&](node _i, node j, edgeid eid) {
			double sim = getSimilarity(graph, i, j);
			neighbors.push_back(AttributizedEdge(i, j, eid, sim));
		});
		std::sort(neighbors.begin(), neighbors.end(), greater());

		count rank = 1;
		for(std::vector<AttributizedEdge>::iterator it = neighbors.begin(); it != neighbors.end(); ++it) {
			edgeid eid = it->eid;

			double e = 0.0;
			if (d > 1)
				e = log(rank) / log(d);

			sparsificationExp[eid] = std::min(e, sparsificationExp[eid]);
			rank++;
		}

	});

	return sparsificationExp;
}

/**
 * Returns the similarity between two nodes.
 */
double LocalSimilarityAttributizer::getSimilarity(const Graph& graph, node u, node v) {
	//Use the jaccard measure as similarity measure.
	/* TODO: The following implementation might be quite inefficient....
	 * can the implementation in community/JaccardMeasure be used?
	 */
	std::set<node> uNeighbors;
	graph.forNeighborsOf(u, [&](node n) {
		uNeighbors.insert(n);
	});

	count inUnion = graph.degree(u);
	count inIntersection = 0;

	graph.forNeighborsOf(v, [&](node n) {
		if (uNeighbors.erase(n))
			inIntersection++;
		else
			inUnion++;
	});

	return (double) inIntersection / (double) inUnion;
}

} /* namespace NetworKit */
<|endoftext|>


<commit_before>//==- llvm/tools/dragongo/unittests/BackendCore/BackendCABIOracleTests.cpp -==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "TestUtils.h"
#include "go-llvm-cabi-oracle.h"
#include "go-llvm-backend.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "gtest/gtest.h"

using namespace llvm;
using namespace goBackendUnitTests;

namespace {

TEST(BackendCABIOracleTests, Basic) {
  LLVMContext C;
  std::unique_ptr<Llvm_backend> bep(new Llvm_backend(C, nullptr, nullptr));
  Llvm_backend *be = bep.get();

  Btype *bi8t = be->integer_type(false, 8);
  Btype *bu8t = be->integer_type(true, 8);
  Btype *bf32t = be->float_type(32);
  Btype *bf64t = be->float_type(64);
  Btype *st0 = mkBackendStruct(be, nullptr);
  Btype *st1 = mkBackendStruct(be, bi8t, "a", bu8t, "b", bf32t, "c", nullptr);
  Btype *st2 = mkBackendStruct(be, bf64t, "f1", bf64t, "f2", nullptr);

  {
    BFunctionType *befty1 = mkFuncTyp(be,
                                      L_PARM, bi8t,
                                      L_PARM, bf32t,
                                      L_PARM, st0,
                                      L_PARM, st1,
                                      L_RES, st2,
                                      L_END);
    CABIOracle cab(befty1, be->typeManager(), llvm::CallingConv::X86_64_SysV);
    const char *exp = R"RAW_RESULT(
      Return: Direct { { double, double } } sigOffset: -1
      Param 1: Direct AttrSext { i8 } sigOffset: 0
      Param 2: Direct { float } sigOffset: 1
      Param 3: Ignore { void } sigOffset: -1
      Param 4: Direct { i64 } sigOffset: 2
    )RAW_RESULT";
    std::string reason;
    bool equal = difftokens(exp, cab.toString(), reason);
    EXPECT_EQ("pass", equal ? "pass" : reason);
    EXPECT_EQ(repr(cab.getFunctionTypeForABI()),
              "{ double, double } (i8, float, i64)");
  }
}

TEST(BackendCABIOracleTests, Extended) {
  LLVMContext C;
  std::unique_ptr<Llvm_backend> bep(new Llvm_backend(C, nullptr, nullptr));
  Llvm_backend *be = bep.get();

  Btype *bi8t = be->integer_type(false, 8);
  Btype *bu8t = be->integer_type(true, 8);
  Btype *bf32t = be->float_type(32);
  Btype *bf64t = be->float_type(64);
  Btype *st0 = mkBackendStruct(be, nullptr);
  Btype *st1 = mkBackendStruct(be, bi8t, "a", bu8t, "b", bf32t, "c", nullptr);
  Btype *st2 = mkBackendStruct(be, bf64t, "f1", bf64t, "f2", nullptr);
  Btype *st3 = mkBackendStruct(be, st2, "f1", bi8t, "f2", nullptr);
  Btype *st4 = mkBackendStruct(be, bf32t, "f1", bf32t, "f2", nullptr);

  struct FcnItem {
    FcnItem(const std::vector<Btype*> &r,
            const std::vector<Btype*> &p,
            const char *t) : results(r), parms(p), exp(t) { }
    std::vector<Btype*> results;
    std::vector<Btype*> parms;
    const char *exp;
  };

  Btype *nt = nullptr;
  std::vector<FcnItem> items = {

    FcnItem( {  }, {  }, "void ()"),

    FcnItem( { bi8t }, { }, "i8 ()"),

    FcnItem( {  }, { bi8t }, "void (i8)"),

    FcnItem({ bi8t, bf64t }, { bi8t, bu8t, st0 }, "{ i8, double } (i8, i8)"),

    FcnItem({ st2 }, { st2, st0, st4, st1 },
            "{ double, double } (double, double, <2 x float>, i64)"),

    FcnItem({ st3 }, { st3, st0, bu8t },
            "{ { double, double }, i8 }* ({ { double, double }, i8 }*, i8)"),
  };

  for (auto &item : items) {
    std::vector<Backend::Btyped_identifier> results;
    std::vector<Backend::Btyped_identifier> params;
    for (auto &r : item.results)
      results.push_back(mkid(r));
    for (auto &p : item.parms)
      params.push_back(mkid(p));
    Btype *rt = nullptr;
    if (results.size() > 1)
      rt = be->struct_type(results);
    Btype *t = be->function_type(mkid(nt), params, results, rt, Location());
    BFunctionType *bft = t->castToBFunctionType();
    CABIOracle cab(bft, be->typeManager(), llvm::CallingConv::X86_64_SysV);
    cab.dump();
    EXPECT_EQ(repr(cab.getFunctionTypeForABI()), item.exp);
  }
}

}
<commit_msg>Unit test tweaks.<commit_after>//==- llvm/tools/dragongo/unittests/BackendCore/BackendCABIOracleTests.cpp -==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "TestUtils.h"
#include "go-llvm-cabi-oracle.h"
#include "go-llvm-backend.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "gtest/gtest.h"

using namespace llvm;
using namespace goBackendUnitTests;

namespace {

TEST(BackendCABIOracleTests, Basic) {
  LLVMContext C;
  std::unique_ptr<Llvm_backend> bep(new Llvm_backend(C, nullptr, nullptr));
  Llvm_backend *be = bep.get();

  Btype *bi8t = be->integer_type(false, 8);
  Btype *bu8t = be->integer_type(true, 8);
  Btype *bf32t = be->float_type(32);
  Btype *bf64t = be->float_type(64);
  Btype *st0 = mkBackendStruct(be, nullptr);
  Btype *st1 = mkBackendStruct(be, bi8t, "a", bu8t, "b", bf32t, "c", nullptr);
  Btype *st2 = mkBackendStruct(be, bf64t, "f1", bf64t, "f2", nullptr);

  {
    BFunctionType *befty1 = mkFuncTyp(be,
                                      L_PARM, bi8t,
                                      L_PARM, bf32t,
                                      L_PARM, st0,
                                      L_PARM, st1,
                                      L_RES, st2,
                                      L_END);
    CABIOracle cab(befty1, be->typeManager(), llvm::CallingConv::X86_64_SysV);
    const char *exp = R"RAW_RESULT(
      Return: Direct { { double, double } } sigOffset: -1
      Param 1: Direct AttrSext { i8 } sigOffset: 0
      Param 2: Direct { float } sigOffset: 1
      Param 3: Ignore { void } sigOffset: -1
      Param 4: Direct { i64 } sigOffset: 2
    )RAW_RESULT";
    std::string reason;
    bool equal = difftokens(exp, cab.toString(), reason);
    EXPECT_EQ("pass", equal ? "pass" : reason);
    EXPECT_EQ(repr(cab.getFunctionTypeForABI()),
              "{ double, double } (i8, float, i64)");
  }
}

TEST(BackendCABIOracleTests, Extended) {
  LLVMContext C;
  std::unique_ptr<Llvm_backend> bep(new Llvm_backend(C, nullptr, nullptr));
  Llvm_backend *be = bep.get();

  Btype *bi8t = be->integer_type(false, 8);
  Btype *bu8t = be->integer_type(true, 8);
  Btype *bf32t = be->float_type(32);
  Btype *bf64t = be->float_type(64);
  Btype *st0 = mkBackendStruct(be, nullptr);
  Btype *st1 = mkBackendStruct(be, bi8t, "a", bu8t, "b", bf32t, "c", nullptr);
  Btype *st2 = mkBackendStruct(be, bf64t, "f1", bf64t, "f2", nullptr);
  Btype *st3 = mkBackendStruct(be, st2, "f1", bi8t, "f2", nullptr);
  Btype *st4 = mkBackendStruct(be, bf32t, "f1", bf32t, "f2", nullptr);

  struct FcnItem {
    FcnItem(const std::vector<Btype*> &r,
            const std::vector<Btype*> &p,
            const char *t) : results(r), parms(p), exp(t) { }
    std::vector<Btype*> results;
    std::vector<Btype*> parms;
    const char *exp;
  };

  Btype *nt = nullptr;
  std::vector<FcnItem> items = {

    FcnItem( {  }, {  }, "void ()"),

    FcnItem( { bi8t }, { }, "i8 ()"),

    FcnItem( {  }, { bi8t }, "void (i8)"),

    FcnItem({ bi8t, bf64t }, { bi8t, bu8t, st0 }, "{ i8, double } (i8, i8)"),

    FcnItem({ st2 }, { st2, st0, st4, st1 },
            "{ double, double } (double, double, <2 x float>, i64)"),

    FcnItem({ st3 }, { st3, st0, bu8t },
            "{ { double, double }, i8 }* ({ { double, double }, i8 }*, i8)"),

    FcnItem({ st3 }, { st3, st0, bu8t },
            "{ { double, double }, i8 }* ({ { double, double }, i8 }*, i8)"),
  };

  for (auto &item : items) {
    std::vector<Backend::Btyped_identifier> results;
    std::vector<Backend::Btyped_identifier> params;
    for (auto &r : item.results)
      results.push_back(mkid(r));
    for (auto &p : item.parms)
      params.push_back(mkid(p));
    Btype *rt = nullptr;
    if (results.size() > 1)
      rt = be->struct_type(results);
    Btype *t = be->function_type(mkid(nt), params, results, rt, Location());
    BFunctionType *bft = t->castToBFunctionType();
    CABIOracle cab(bft, be->typeManager(), llvm::CallingConv::X86_64_SysV);
    cab.dump();
    EXPECT_EQ(repr(cab.getFunctionTypeForABI()), item.exp);
  }
}

}
<|endoftext|>


<commit_before>#include "NSetCache.h"
#include "DumpLogManager.h"
#include <algorithm>

NSetCache::NSetCache(uint cacheSize, uint cacheBlockSize, uint nWay, uint* systemMemory, uint hitTime, uint missPenalty)
: _nWay(nWay), _systemMemory(systemMemory), _blockSize(cacheBlockSize), _hitCount(0), _missCount(0),_hitTime(hitTime), _missPenalty(missPenalty)
{
    auto log2 = [](double n)
    {
        return log(n) / log(2);
    };
    CacheLine line;
    line.offset = log2(_blockSize);

    uint cacheSetCount = (cacheSize / _blockSize) / nWay;
    line.index = log2(cacheSetCount);

    line.tag = 32 - (line.index + line.offset);

    _lineInfo = line;

    _cacheDatas = new CacheEntry*[line.index + 1];

    for (uint i = 0; i < line.index + 1; ++i)
    {
        _cacheDatas[i] = new CacheEntry[nWay];
        for(uint wayIdx = 0; wayIdx < nWay; ++wayIdx)
        {
            _cacheDatas[i][wayIdx].datas = new uint[_blockSize];
            memset(_cacheDatas[i][wayIdx].datas, 0, sizeof(uint) * _blockSize);
        }
    }
}

NSetCache::~NSetCache()
{

}

NSetCache::CacheLine NSetCache::MakeCacheLineCommand(uint address)
{
    auto FillBit = [](unsigned int offset, unsigned int length)
    {
        uint result = 1;

        for (uint i = 0; i < length; ++i)
            result |= (1 << i);

        result <<= offset;
        return result;
    };

    ASSERT_COND_MSG((address % 4) == 0, "Error, Invalid address");
    uint offset = 32 - _lineInfo.tag;

    CacheLine line;
    uint mask = FillBit(offset, _lineInfo.tag);
    line.tag = (address & mask) >> offset;

    mask = FillBit(_lineInfo.offset, _lineInfo.index);
    line.index = (address & mask) >> _lineInfo.offset;

    mask = FillBit(0, _lineInfo.offset);
    line.offset = (address & mask);

    return line;
}

bool NSetCache::IsValid(const CacheLine& command, CacheEntry** outEntry)
{
    for (uint i = 0; i < _nWay; ++i)
    {
        CacheEntry& entry = _cacheDatas[command.index][i];
        if (entry.isEmpty == false)
        {
            if (outEntry)
                (*outEntry) = &entry;

            return (entry.isEmpty == false);
        }
    }

    return false;
}

bool NSetCache::IsTagMatch(const CacheLine& command, CacheEntry** outEntry)
{
    for (uint i = 0; i < _nWay; ++i)
    {
        CacheEntry& entry = _cacheDatas[command.index][i];

        if (entry.tag == command.tag)
        {
            if (outEntry)
                (*outEntry) = &entry;

            return (entry.isEmpty == false);
        }
    }

    return false;
}

bool NSetCache::LoadCache(uint address)
{
    CacheLine command = MakeCacheLineCommand(address);
    uint offset = (address / _blockSize) * _blockSize;

    bool success = false;
    for (uint wayIdx = 0; wayIdx < _nWay; ++wayIdx)
    {
        CacheEntry& entry = _cacheDatas[command.index][wayIdx];
        if (entry.isEmpty)
        {
            entry.tag = command.tag;
            entry.isEmpty = false;
            entry.isRequiredUpdate = false;
            entry.timeStamp = clock();

            memcpy(entry.datas, &_systemMemory[offset / 4], _blockSize);

            entry.memAddress = offset;
            success = true;

            break;
        }
    }

    return success;
}

bool NSetCache::Replace(uint address)
{
    //maybe.., i think that write lru algo.
    CacheLine command = MakeCacheLineCommand(address);

    //first valus is wayIdx
    std::vector<std::pair<uint, clock_t>> timeStamps;

    bool isAllReadCache = false;
    for (uint wayIdx = 0; wayIdx < _nWay; ++wayIdx)
    {
        timeStamps.push_back(std::make_pair(wayIdx, _cacheDatas[command.index][wayIdx].timeStamp));
        isAllReadCache = (_cacheDatas[command.index][wayIdx].isRequiredUpdate == false);
    }

    auto sortFunc = [](const std::pair<uint, clock_t>& left, const std::pair<uint, clock_t>& right)
    {
        return left.second < right.second;
    };

    std::sort(timeStamps.begin(), timeStamps.end(), sortFunc);
    const std::pair<uint, clock_t>& replaceTarget = timeStamps[0];

    //first value is way idx
    CacheEntry& entry = _cacheDatas[command.index][replaceTarget.first];
    {
        uint writeAddress = entry.memAddress;

        if(entry.isRequiredUpdate)
            memcpy(&_systemMemory[writeAddress / 4], entry.datas, _blockSize);

        entry.isRequiredUpdate = false;
        entry.isEmpty = true;
    }

    return LoadCache(address);
}

uint NSetCache::FetchData(uint address)
{
    GlobalDumpLogManager->AddLog("Cache Fetch Data\n");
    uint result = 0;
    CacheLine command = MakeCacheLineCommand(address);

    CacheEntry* entry = nullptr;
    bool isHit = IsValid(command) && IsTagMatch(command, &entry);
    if (isHit) //딱히 더 손볼건 없는듯
    {
        GlobalDumpLogManager->AddLog("Cache Hit\t\t| Current Count = " + std::to_string(++_hitCount), true);
        ASSERT_COND_MSG(entry, "Error, what the");
        result = entry->datas[command.offset / 4];
    }
    else
    {
        GlobalDumpLogManager->AddLog("Cache Miss\t\t| Current Count = " + std::to_string(++_missCount), true);

        if (LoadCache(address) == false)
            ASSERT_COND_MSG(Replace(address), "Error, where is your memory?");

        isHit = IsValid(command) && IsTagMatch(command, &entry);
        ASSERT_COND_MSG(isHit, "Error, Invalid result value");
        result = entry->datas[command.offset / 4];
    }

    HitAndAMATLog();

    entry->timeStamp = clock();
    return result;
}

void NSetCache::InputData(uint address, uint data)
{
    CacheLine command = MakeCacheLineCommand(address);

    CacheEntry* entry = nullptr;
    bool isHit = IsValid(command) && IsTagMatch(command, &entry);

    if (isHit)
    {
        GlobalDumpLogManager->AddLog("Cache Hit\t\t| Current Count = " + std::to_string(++_hitCount), true);
    }
    else
    {
        GlobalDumpLogManager->AddLog("Cache Miss\t\t| Current Count = " + std::to_string(++_missCount), true);

        if (LoadCache(address) == false)
            ASSERT_COND_MSG(Replace(address), "Error, where is your memory?");

        isHit = IsValid(command) && IsTagMatch(command, &entry);
        ASSERT_COND_MSG(isHit, "Error, Invalid result value");
    }

    HitAndAMATLog();

    entry->datas[command.offset / 4] = data;
    entry->isRequiredUpdate = true;
    entry->timeStamp = clock();
}

void NSetCache::HitAndAMATLog(bool usePrintLog)
{
    float hitRate = (float)_hitCount / (float)(_hitCount + _missCount);
    std::string buff = "Current Hit Rate\t| " + std::to_string(hitRate);
    GlobalDumpLogManager->AddLog(buff, true);
    if(usePrintLog)
        printf("%s\n", buff.c_str());

    float missRate = (float)_missCount / (float)(_hitCount + _missCount);
    buff = "Current AMAT\t\t| " + std::to_string((hitRate * _hitTime) + (missRate * _missPenalty));
    GlobalDumpLogManager->AddLog(buff, true);
    if(usePrintLog)
        printf("%s\n", buff.c_str());
}<commit_msg>버그 수정<commit_after>#include "NSetCache.h"
#include "DumpLogManager.h"
#include <algorithm>

NSetCache::NSetCache(uint cacheSize, uint cacheBlockSize, uint nWay, uint* systemMemory, uint hitTime, uint missPenalty)
: _nWay(nWay), _systemMemory(systemMemory), _blockSize(cacheBlockSize), _hitCount(0), _missCount(0),_hitTime(hitTime), _missPenalty(missPenalty)
{
    auto log2 = [](double n)
    {
        return log(n) / log(2);
    };
    CacheLine line;
    line.offset = log2(_blockSize);

    uint cacheSetCount = (cacheSize / _blockSize) / nWay;
    line.index = log2(cacheSetCount);

    line.tag = 32 - (line.index + line.offset);

    _lineInfo = line;

    _cacheDatas = new CacheEntry*[line.index + 1];

    for (uint i = 0; i < line.index + 1; ++i)
    {
        _cacheDatas[i] = new CacheEntry[nWay];
        for(uint wayIdx = 0; wayIdx < nWay; ++wayIdx)
        {
            _cacheDatas[i][wayIdx].datas = new uint[_blockSize / 4];
            memset(_cacheDatas[i][wayIdx].datas, 0, _blockSize);
        }
    }
}

NSetCache::~NSetCache()
{

}

NSetCache::CacheLine NSetCache::MakeCacheLineCommand(uint address)
{
    auto FillBit = [](unsigned int offset, unsigned int length)
    {
        uint result = 1;

        for (uint i = 0; i < length; ++i)
            result |= (1 << i);

        result <<= offset;
        return result;
    };

    ASSERT_COND_MSG((address % 4) == 0, "Error, Invalid address");
    uint offset = 32 - _lineInfo.tag;

    CacheLine line;
    uint mask = FillBit(offset, _lineInfo.tag);
    line.tag = (address & mask) >> offset;

    mask = FillBit(_lineInfo.offset, _lineInfo.index);
    line.index = (address & mask) >> _lineInfo.offset;

    mask = FillBit(0, _lineInfo.offset);
    line.offset = (address & mask);

    return line;
}

bool NSetCache::IsValid(const CacheLine& command, CacheEntry** outEntry)
{
    for (uint i = 0; i < _nWay; ++i)
    {
        CacheEntry& entry = _cacheDatas[command.index][i];
        if (entry.isEmpty == false)
        {
            if (outEntry)
                (*outEntry) = &entry;

            return (entry.isEmpty == false);
        }
    }

    return false;
}

bool NSetCache::IsTagMatch(const CacheLine& command, CacheEntry** outEntry)
{
    for (uint i = 0; i < _nWay; ++i)
    {
        CacheEntry& entry = _cacheDatas[command.index][i];

        if (entry.tag == command.tag)
        {
            if (outEntry)
                (*outEntry) = &entry;

            return (entry.isEmpty == false);
        }
    }

    return false;
}

bool NSetCache::LoadCache(uint address)
{
    CacheLine command = MakeCacheLineCommand(address);
    uint offset = (address / _blockSize) * _blockSize;

    bool success = false;
    for (uint wayIdx = 0; wayIdx < _nWay; ++wayIdx)
    {
        CacheEntry& entry = _cacheDatas[command.index][wayIdx];
        if (entry.isEmpty)
        {
            entry.tag = command.tag;
            entry.isEmpty = false;
            entry.isRequiredUpdate = false;
            entry.timeStamp = clock();

            memcpy(entry.datas, &_systemMemory[offset / 4], _blockSize);

            entry.memAddress = offset;
            success = true;

            break;
        }
    }

    return success;
}

bool NSetCache::Replace(uint address)
{
    //maybe.., i think that write lru algo.
    CacheLine command = MakeCacheLineCommand(address);

    //first valus is wayIdx
    std::vector<std::pair<uint, clock_t>> timeStamps;

    bool isAllReadCache = false;
    for (uint wayIdx = 0; wayIdx < _nWay; ++wayIdx)
    {
        timeStamps.push_back(std::make_pair(wayIdx, _cacheDatas[command.index][wayIdx].timeStamp));
        isAllReadCache = (_cacheDatas[command.index][wayIdx].isRequiredUpdate == false);
    }

    auto sortFunc = [](const std::pair<uint, clock_t>& left, const std::pair<uint, clock_t>& right)
    {
        return left.second < right.second;
    };

    std::sort(timeStamps.begin(), timeStamps.end(), sortFunc);
    const std::pair<uint, clock_t>& replaceTarget = timeStamps[0];

    //first value is way idx
    CacheEntry& entry = _cacheDatas[command.index][replaceTarget.first];
    {
        uint writeAddress = entry.memAddress;

        if(entry.isRequiredUpdate)
            memcpy(&_systemMemory[writeAddress / 4], entry.datas, _blockSize);

        entry.isRequiredUpdate = false;
        entry.isEmpty = true;
    }

    return LoadCache(address);
}

uint NSetCache::FetchData(uint address)
{
    GlobalDumpLogManager->AddLog("Cache Fetch Data\n");
    uint result = 0;
    CacheLine command = MakeCacheLineCommand(address);

    CacheEntry* entry = nullptr;
    bool isHit = IsValid(command) && IsTagMatch(command, &entry);
    if (isHit) //딱히 더 손볼건 없는듯
    {
        GlobalDumpLogManager->AddLog("Cache Hit\t\t| Current Count = " + std::to_string(++_hitCount), true);
        ASSERT_COND_MSG(entry, "Error, what the");
        result = entry->datas[command.offset / 4];
    }
    else
    {
        GlobalDumpLogManager->AddLog("Cache Miss\t\t| Current Count = " + std::to_string(++_missCount), true);

        if (LoadCache(address) == false)
            ASSERT_COND_MSG(Replace(address), "Error, where is your memory?");

        isHit = IsValid(command) && IsTagMatch(command, &entry);
        ASSERT_COND_MSG(isHit, "Error, Invalid result value");
        result = entry->datas[command.offset / 4];
    }

    HitAndAMATLog();

    entry->timeStamp = clock();
    return result;
}

void NSetCache::InputData(uint address, uint data)
{
    CacheLine command = MakeCacheLineCommand(address);

    CacheEntry* entry = nullptr;
    bool isHit = IsValid(command) && IsTagMatch(command, &entry);

    if (isHit)
    {
        GlobalDumpLogManager->AddLog("Cache Hit\t\t| Current Count = " + std::to_string(++_hitCount), true);
    }
    else
    {
        GlobalDumpLogManager->AddLog("Cache Miss\t\t| Current Count = " + std::to_string(++_missCount), true);

        if (LoadCache(address) == false)
            ASSERT_COND_MSG(Replace(address), "Error, where is your memory?");

        isHit = IsValid(command) && IsTagMatch(command, &entry);
        ASSERT_COND_MSG(isHit, "Error, Invalid result value");
    }

    HitAndAMATLog();

    entry->datas[command.offset / 4] = data;
    entry->isRequiredUpdate = true;
    entry->timeStamp = clock();
}

void NSetCache::HitAndAMATLog(bool usePrintLog)
{
    float hitRate = (float)_hitCount / (float)(_hitCount + _missCount);
    std::string buff = "Current Hit Rate\t| " + std::to_string(hitRate);
    GlobalDumpLogManager->AddLog(buff, true);
    if(usePrintLog)
        printf("%s\n", buff.c_str());

    float missRate = (float)_missCount / (float)(_hitCount + _missCount);
    buff = "Current AMAT\t\t| " + std::to_string((hitRate * _hitTime) + (missRate * _missPenalty));
    GlobalDumpLogManager->AddLog(buff, true);
    if(usePrintLog)
        printf("%s\n", buff.c_str());
}<|endoftext|>


<commit_before>/******************************************************************
 *
 * Round for C++
 *
 * Copyright (C) Satoshi Konno 2015
 *
 * This is licensed under BSD-style license, see file COPYING.
 *
 ******************************************************************/

#include <round/ui/console/Command.h>

const std::string Round::Console::search::NAME = "search";

const std::string Round::Console::search::getDescription() const {
  return "Search new clusters and nodes";
}

bool Round::Console::search::exec(Round::Console::Client *client, const Input *input, Message *msg, Error *err) const {
  return client->search(err);
}
<commit_msg>* Updated search() to show wait animation.<commit_after>/******************************************************************
 *
 * Round for C++
 *
 * Copyright (C) Satoshi Konno 2015
 *
 * This is licensed under BSD-style license, see file COPYING.
 *
 ******************************************************************/

#include <iostream>
#include <round/ui/console/Command.h>

const std::string Round::Console::search::NAME = "search";

const std::string Round::Console::search::getDescription() const {
  return "Search new clusters and nodes";
}

bool Round::Console::search::exec(Round::Console::Client *client, const Input *input, Message *msg, Error *err) const {
  bool isSuccess = client->search(err);
  waitAnimation(5000);
  return isSuccess;
}
<|endoftext|>


<commit_before>// Copyright 2010-2012 RethinkDB, all rights reserved.
#ifndef RPC_DIRECTORY_WRITE_MANAGER_HPP_
#define RPC_DIRECTORY_WRITE_MANAGER_HPP_

#include "errors.hpp"
#include <boost/shared_ptr.hpp>

#include "concurrency/auto_drainer.hpp"
#include "concurrency/fifo_enforcer.hpp"
#include "concurrency/watchable.hpp"
#include "rpc/connectivity/connectivity.hpp"

class message_service_t;

template<class metadata_t>
class directory_write_manager_t : private peers_list_callback_t {
public:
    directory_write_manager_t(
        message_service_t *message_service,
        const clone_ptr_t<watchable_t<metadata_t> > &value) THROWS_NOTHING;
    ~directory_write_manager_t();

private:
    void on_connect(peer_id_t peer) THROWS_NOTHING;
    void on_disconnect(peer_id_t p);
    void on_change() THROWS_NOTHING;

    void send_initialization(peer_id_t peer,
                             uint64_t session_id,
                             const metadata_t &initial_value,
                             fifo_enforcer_state_t metadata_fifo_state,
                             auto_drainer_t::lock_t keepalive) THROWS_NOTHING;
    void send_update(peer_id_t peer,
                     uint64_t session_id,
                     const boost::shared_ptr<metadata_t> &new_value,
                     fifo_enforcer_write_token_t metadata_fifo_token,
                     auto_drainer_t::lock_t keepalive) THROWS_NOTHING;

    // Returns true if sessions.find(peer)->second == session_id -- we haven't gotten
    // on_disconnect since the session_id was noted.
    bool still_connected(peer_id_t peer, uint64_t session_id) const;

    class initialization_writer_t;
    class update_writer_t;

    message_service_t *const message_service;
    clone_ptr_t<watchable_t<metadata_t> > value_watchable;
    fifo_enforcer_source_t metadata_fifo_source;

    // `session_counter` and `sessions` let `send_initialization()` and
    // `send_update()` check if the given peer has disconnected and reconnected
    // between when they were spawned and not.  They only communicate to the peer if
    // it hasn't reconnected in the mean time.  This prevents us from sending two
    // initialization messages to the same peer (after quickly disconnecting and
    // reconnecting).
    uint64_t session_counter;
    std::map<peer_id_t, uint64_t> sessions;

    auto_drainer_t drainer;
    typename watchable_t<metadata_t>::subscription_t value_subscription;
    connectivity_service_t::peers_list_subscription_t connectivity_subscription;

    DISABLE_COPYING(directory_write_manager_t);
};

#endif /* RPC_DIRECTORY_WRITE_MANAGER_HPP_ */
<commit_msg>Added an editorial comment.<commit_after>// Copyright 2010-2012 RethinkDB, all rights reserved.
#ifndef RPC_DIRECTORY_WRITE_MANAGER_HPP_
#define RPC_DIRECTORY_WRITE_MANAGER_HPP_

#include "errors.hpp"
#include <boost/shared_ptr.hpp>

#include "concurrency/auto_drainer.hpp"
#include "concurrency/fifo_enforcer.hpp"
#include "concurrency/watchable.hpp"
#include "rpc/connectivity/connectivity.hpp"

class message_service_t;

template<class metadata_t>
class directory_write_manager_t : private peers_list_callback_t {
public:
    directory_write_manager_t(
        message_service_t *message_service,
        const clone_ptr_t<watchable_t<metadata_t> > &value) THROWS_NOTHING;
    ~directory_write_manager_t();

private:
    void on_connect(peer_id_t peer) THROWS_NOTHING;
    void on_disconnect(peer_id_t p);
    void on_change() THROWS_NOTHING;

    void send_initialization(peer_id_t peer,
                             uint64_t session_id,
                             const metadata_t &initial_value,
                             fifo_enforcer_state_t metadata_fifo_state,
                             auto_drainer_t::lock_t keepalive) THROWS_NOTHING;
    void send_update(peer_id_t peer,
                     uint64_t session_id,
                     const boost::shared_ptr<metadata_t> &new_value,
                     fifo_enforcer_write_token_t metadata_fifo_token,
                     auto_drainer_t::lock_t keepalive) THROWS_NOTHING;

    // Returns true if sessions.find(peer)->second == session_id -- we haven't gotten
    // on_disconnect since the session_id was noted.
    bool still_connected(peer_id_t peer, uint64_t session_id) const;

    class initialization_writer_t;
    class update_writer_t;

    message_service_t *const message_service;
    clone_ptr_t<watchable_t<metadata_t> > value_watchable;
    fifo_enforcer_source_t metadata_fifo_source;

    // `session_counter` and `sessions` let `send_initialization()` and
    // `send_update()` check if the given peer has disconnected and reconnected
    // between when they were spawned and not.  They only communicate to the peer if
    // it hasn't reconnected in the mean time.  This prevents us from sending two
    // initialization messages to the same peer (after quickly disconnecting and
    // reconnecting).  (It would be better if the message service or connectivity
    // service did this for us.)
    uint64_t session_counter;
    std::map<peer_id_t, uint64_t> sessions;

    auto_drainer_t drainer;
    typename watchable_t<metadata_t>::subscription_t value_subscription;
    connectivity_service_t::peers_list_subscription_t connectivity_subscription;

    DISABLE_COPYING(directory_write_manager_t);
};

#endif /* RPC_DIRECTORY_WRITE_MANAGER_HPP_ */
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2017, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the copyright holder nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  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 HOLDER 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.
 */

/**
 * @file
 *   This file implements data poll (mac data request command) manager class.
 */

#define WPP_NAME "data_poll_manager.tmh"

#ifdef OPENTHREAD_CONFIG_FILE
#include OPENTHREAD_CONFIG_FILE
#else
#include <openthread-config.h>
#endif

#include "data_poll_manager.hpp"

#include <openthread/platform/random.h>

#include "common/code_utils.hpp"
#include "common/logging.hpp"
#include "common/message.hpp"
#include "net/ip6.hpp"
#include "net/netif.hpp"
#include "thread/mesh_forwarder.hpp"
#include "thread/mle.hpp"
#include "thread/thread_netif.hpp"

namespace ot {

DataPollManager::DataPollManager(MeshForwarder &aMeshForwarder):
    mMeshForwarder(aMeshForwarder),
    mTimer(aMeshForwarder.GetNetif().GetIp6().mTimerScheduler, &DataPollManager::HandlePollTimer, this),
    mExternalPollPeriod(0),
    mPollPeriod(0),
    mEnabled(false),
    mAttachMode(false),
    mRetxMode(false),
    mNoBufferRetxMode(false),
    mPollTimeoutCounter(0),
    mPollTxFailureCounter(0),
    mRemainingFastPolls(0)
{
}

otInstance *DataPollManager::GetInstance(void)
{
    return mMeshForwarder.GetInstance();
}

ThreadError DataPollManager::StartPolling(void)
{
    ThreadError error = kThreadError_None;

    VerifyOrExit(!mEnabled, error = kThreadError_Already);
    VerifyOrExit((mMeshForwarder.GetNetif().GetMle().GetDeviceMode() & Mle::ModeTlv::kModeFFD) == 0,
                 error = kThreadError_InvalidState);

    mEnabled = true;
    ScheduleNextPoll(kRecalculatePollPeriod);

exit:
    return error;
}

void DataPollManager::StopPolling(void)
{
    mTimer.Stop();
    mAttachMode = false;
    mRetxMode = false;
    mNoBufferRetxMode = false;
    mPollTimeoutCounter = 0;
    mPollTxFailureCounter = 0;
    mRemainingFastPolls = 0;
    mEnabled = false;
}

ThreadError DataPollManager::SendDataPoll(void)
{
    ThreadError error;
    Message *message;

    VerifyOrExit(mEnabled, error = kThreadError_InvalidState);
    VerifyOrExit(!mMeshForwarder.GetNetif().GetMac().GetRxOnWhenIdle(), error = kThreadError_InvalidState);

    mTimer.Stop();

    for (message = mMeshForwarder.GetSendQueue().GetHead(); message; message = message->GetNext())
    {
        VerifyOrExit(message->GetType() != Message::kTypeMacDataPoll, error = kThreadError_Already);
    }

    message = mMeshForwarder.GetNetif().GetIp6().mMessagePool.New(Message::kTypeMacDataPoll, 0);
    VerifyOrExit(message != NULL, error = kThreadError_NoBufs);

    error = mMeshForwarder.SendMessage(*message);

    if (error != kThreadError_None)
    {
        message->Free();
    }

exit:

    switch (error)
    {
    case kThreadError_None:
        otLogDebgMac(GetInstance(), "Sent poll");

        if (mNoBufferRetxMode == true)
        {
            mNoBufferRetxMode = false;
            ScheduleNextPoll(kRecalculatePollPeriod);
        }
        else
        {
            ScheduleNextPoll(kUsePreviousPollPeriod);
        }

        break;

    case kThreadError_InvalidState:
        otLogWarnMac(GetInstance(), "Data poll tx requested while data polling was not enabled!");
        StopPolling();
        break;

    case kThreadError_Already:
        otLogDebgMac(GetInstance(), "Data poll tx requested when a previous data request still in send queue.");
        ScheduleNextPoll(kUsePreviousPollPeriod);
        break;

    case kThreadError_NoBufs:
    default:
        mNoBufferRetxMode = true;
        ScheduleNextPoll(kRecalculatePollPeriod);
        break;
    }

    return error;
}

void DataPollManager::SetExternalPollPeriod(uint32_t aPeriod)
{
    if (mExternalPollPeriod != aPeriod)
    {
        mExternalPollPeriod = aPeriod;

        if (mEnabled)
        {
            ScheduleNextPoll(kRecalculatePollPeriod);
        }
    }
}

void DataPollManager::HandlePollSent(ThreadError aError)
{
    bool shouldRecalculatePollPeriod = false;

    VerifyOrExit(mEnabled);

    switch (aError)
    {
    case kThreadError_None:

        if (mRemainingFastPolls != 0)
        {
            mRemainingFastPolls--;
            shouldRecalculatePollPeriod = (mRemainingFastPolls == 0);
        }

        if (mRetxMode == true)
        {
            mRetxMode = false;
            mPollTxFailureCounter = 0;
            shouldRecalculatePollPeriod = true;
        }

        break;

    default:
        mPollTxFailureCounter++;

        if (mPollTxFailureCounter < kMaxPollRetxAttempts)
        {
            if (mRetxMode == false)
            {
                mRetxMode = true;
                shouldRecalculatePollPeriod = true;
            }
        }
        else
        {
            otLogWarnMac(GetInstance(), "Data poll tx failed in %d back-to-back attempts.", mPollTxFailureCounter);

            mRetxMode = false;
            mPollTxFailureCounter = 0;
            shouldRecalculatePollPeriod = true;
        }

        break;
    }

    if (shouldRecalculatePollPeriod)
    {
        ScheduleNextPoll(kRecalculatePollPeriod);
    }

exit:
    return;
}

void DataPollManager::HandlePollTimeout(void)
{
    // A data poll timeout happened, i.e., the ack in response to
    // a data poll indicated that a frame was pending, but no frame
    // was received after timeout interval.

    VerifyOrExit(mEnabled);

    mPollTimeoutCounter++;

    if (mPollTimeoutCounter <= kQuickPollsAfterTimeout)
    {
        SendDataPoll();
    }
    else
    {
        otLogInfoMac(GetInstance(), "Data poll timeout happened %d times back-to-back.", mPollTimeoutCounter);
        mPollTimeoutCounter = 0;
    }

exit:
    return;
}

void DataPollManager::CheckFramePending(Mac::Frame &aFrame)
{
    VerifyOrExit(mEnabled);

    mPollTimeoutCounter = 0;

    if (aFrame.GetFramePending() == true)
    {
        SendDataPoll();
    }

exit:
    return;
}

void DataPollManager::RecalculatePollPeriod(void)
{
    if (mEnabled)
    {
        ScheduleNextPoll(kRecalculatePollPeriod);
    }
}

void DataPollManager::SetAttachMode(bool aMode)
{
    if (mAttachMode != aMode)
    {
        mAttachMode = aMode;

        if (mEnabled)
        {
            ScheduleNextPoll(kRecalculatePollPeriod);
        }
    }
}

void DataPollManager::SendFastPolls(uint8_t aNumFastPolls)
{
    bool shouldRecalculatePollPeriod = (mRemainingFastPolls == 0);

    if (aNumFastPolls == 0)
    {
        aNumFastPolls = kDefaultFastPolls;
    }

    if (aNumFastPolls > kMaxFastPolls)
    {
        aNumFastPolls = kMaxFastPolls;
    }

    if (mRemainingFastPolls < aNumFastPolls)
    {
        mRemainingFastPolls = aNumFastPolls;
    }

    if (mEnabled && shouldRecalculatePollPeriod)
    {
        ScheduleNextPoll(kRecalculatePollPeriod);
    }
}

void DataPollManager::ScheduleNextPoll(PollPeriodSelector aPollPeriodSelector)
{
    if (aPollPeriodSelector == kRecalculatePollPeriod)
    {
        mPollPeriod = CalculatePollPeriod();
    }

    if (mTimer.IsRunning())
    {
        uint32_t elapsedTime = Timer::GetNow() - mTimer.Gett0();

        if (elapsedTime >= mPollPeriod)
        {
            SendDataPoll();
        }
        else
        {
            mTimer.Start(mPollPeriod - elapsedTime);
        }
    }
    else
    {
        mTimer.Start(mPollPeriod);
    }
}

uint32_t DataPollManager::CalculatePollPeriod(void) const
{
    uint32_t period = 0;

    if (mAttachMode == true)
    {
        period = kAttachDataPollPeriod;
    }

    if (mRetxMode == true)
    {
        if ((period == 0) || (period > kRetxPollPeriod))
        {
            period = kRetxPollPeriod;
        }
    }

    if (mNoBufferRetxMode == true)
    {
        if ((period == 0) || (period > kNoBufferRetxPollPeriod))
        {
            period = kNoBufferRetxPollPeriod;
        }
    }

    if (mRemainingFastPolls != 0)
    {
        if ((period == 0) || (period > kFastPollPeriod))
        {
            period = kFastPollPeriod;
        }
    }

    if (mExternalPollPeriod != 0)
    {
        if ((period == 0) || (period > mExternalPollPeriod))
        {
            period = mExternalPollPeriod;
        }
    }

    if (period == 0)
    {
        period = Timer::SecToMsec(mMeshForwarder.GetNetif().GetMle().GetTimeout()) -  kRetxPollPeriod * kMaxPollRetxAttempts;

        if (period == 0)
        {
            period = kMinPollPeriod;
        }
    }

    return period;
}

void DataPollManager::HandlePollTimer(void *aContext)
{
    static_cast<DataPollManager *>(aContext)->SendDataPoll();
}

}  // namespace ot
<commit_msg>`DataPollManager`: Simplify restarting of data poll timer. (#1737)<commit_after>/*
 *  Copyright (c) 2017, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the copyright holder nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  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 HOLDER 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.
 */

/**
 * @file
 *   This file implements data poll (mac data request command) manager class.
 */

#define WPP_NAME "data_poll_manager.tmh"

#ifdef OPENTHREAD_CONFIG_FILE
#include OPENTHREAD_CONFIG_FILE
#else
#include <openthread-config.h>
#endif

#include "data_poll_manager.hpp"

#include <openthread/platform/random.h>

#include "common/code_utils.hpp"
#include "common/logging.hpp"
#include "common/message.hpp"
#include "net/ip6.hpp"
#include "net/netif.hpp"
#include "thread/mesh_forwarder.hpp"
#include "thread/mle.hpp"
#include "thread/thread_netif.hpp"

namespace ot {

DataPollManager::DataPollManager(MeshForwarder &aMeshForwarder):
    mMeshForwarder(aMeshForwarder),
    mTimer(aMeshForwarder.GetNetif().GetIp6().mTimerScheduler, &DataPollManager::HandlePollTimer, this),
    mExternalPollPeriod(0),
    mPollPeriod(0),
    mEnabled(false),
    mAttachMode(false),
    mRetxMode(false),
    mNoBufferRetxMode(false),
    mPollTimeoutCounter(0),
    mPollTxFailureCounter(0),
    mRemainingFastPolls(0)
{
}

otInstance *DataPollManager::GetInstance(void)
{
    return mMeshForwarder.GetInstance();
}

ThreadError DataPollManager::StartPolling(void)
{
    ThreadError error = kThreadError_None;

    VerifyOrExit(!mEnabled, error = kThreadError_Already);
    VerifyOrExit((mMeshForwarder.GetNetif().GetMle().GetDeviceMode() & Mle::ModeTlv::kModeFFD) == 0,
                 error = kThreadError_InvalidState);

    mEnabled = true;
    ScheduleNextPoll(kRecalculatePollPeriod);

exit:
    return error;
}

void DataPollManager::StopPolling(void)
{
    mTimer.Stop();
    mAttachMode = false;
    mRetxMode = false;
    mNoBufferRetxMode = false;
    mPollTimeoutCounter = 0;
    mPollTxFailureCounter = 0;
    mRemainingFastPolls = 0;
    mEnabled = false;
}

ThreadError DataPollManager::SendDataPoll(void)
{
    ThreadError error;
    Message *message;

    VerifyOrExit(mEnabled, error = kThreadError_InvalidState);
    VerifyOrExit(!mMeshForwarder.GetNetif().GetMac().GetRxOnWhenIdle(), error = kThreadError_InvalidState);

    mTimer.Stop();

    for (message = mMeshForwarder.GetSendQueue().GetHead(); message; message = message->GetNext())
    {
        VerifyOrExit(message->GetType() != Message::kTypeMacDataPoll, error = kThreadError_Already);
    }

    message = mMeshForwarder.GetNetif().GetIp6().mMessagePool.New(Message::kTypeMacDataPoll, 0);
    VerifyOrExit(message != NULL, error = kThreadError_NoBufs);

    error = mMeshForwarder.SendMessage(*message);

    if (error != kThreadError_None)
    {
        message->Free();
    }

exit:

    switch (error)
    {
    case kThreadError_None:
        otLogDebgMac(GetInstance(), "Sent poll");

        if (mNoBufferRetxMode == true)
        {
            mNoBufferRetxMode = false;
            ScheduleNextPoll(kRecalculatePollPeriod);
        }
        else
        {
            ScheduleNextPoll(kUsePreviousPollPeriod);
        }

        break;

    case kThreadError_InvalidState:
        otLogWarnMac(GetInstance(), "Data poll tx requested while data polling was not enabled!");
        StopPolling();
        break;

    case kThreadError_Already:
        otLogDebgMac(GetInstance(), "Data poll tx requested when a previous data request still in send queue.");
        ScheduleNextPoll(kUsePreviousPollPeriod);
        break;

    case kThreadError_NoBufs:
    default:
        mNoBufferRetxMode = true;
        ScheduleNextPoll(kRecalculatePollPeriod);
        break;
    }

    return error;
}

void DataPollManager::SetExternalPollPeriod(uint32_t aPeriod)
{
    if (mExternalPollPeriod != aPeriod)
    {
        mExternalPollPeriod = aPeriod;

        if (mEnabled)
        {
            ScheduleNextPoll(kRecalculatePollPeriod);
        }
    }
}

void DataPollManager::HandlePollSent(ThreadError aError)
{
    bool shouldRecalculatePollPeriod = false;

    VerifyOrExit(mEnabled);

    switch (aError)
    {
    case kThreadError_None:

        if (mRemainingFastPolls != 0)
        {
            mRemainingFastPolls--;
            shouldRecalculatePollPeriod = (mRemainingFastPolls == 0);
        }

        if (mRetxMode == true)
        {
            mRetxMode = false;
            mPollTxFailureCounter = 0;
            shouldRecalculatePollPeriod = true;
        }

        break;

    default:
        mPollTxFailureCounter++;

        if (mPollTxFailureCounter < kMaxPollRetxAttempts)
        {
            if (mRetxMode == false)
            {
                mRetxMode = true;
                shouldRecalculatePollPeriod = true;
            }
        }
        else
        {
            otLogWarnMac(GetInstance(), "Data poll tx failed in %d back-to-back attempts.", mPollTxFailureCounter);

            mRetxMode = false;
            mPollTxFailureCounter = 0;
            shouldRecalculatePollPeriod = true;
        }

        break;
    }

    if (shouldRecalculatePollPeriod)
    {
        ScheduleNextPoll(kRecalculatePollPeriod);
    }

exit:
    return;
}

void DataPollManager::HandlePollTimeout(void)
{
    // A data poll timeout happened, i.e., the ack in response to
    // a data poll indicated that a frame was pending, but no frame
    // was received after timeout interval.

    VerifyOrExit(mEnabled);

    mPollTimeoutCounter++;

    if (mPollTimeoutCounter <= kQuickPollsAfterTimeout)
    {
        SendDataPoll();
    }
    else
    {
        otLogInfoMac(GetInstance(), "Data poll timeout happened %d times back-to-back.", mPollTimeoutCounter);
        mPollTimeoutCounter = 0;
    }

exit:
    return;
}

void DataPollManager::CheckFramePending(Mac::Frame &aFrame)
{
    VerifyOrExit(mEnabled);

    mPollTimeoutCounter = 0;

    if (aFrame.GetFramePending() == true)
    {
        SendDataPoll();
    }

exit:
    return;
}

void DataPollManager::RecalculatePollPeriod(void)
{
    if (mEnabled)
    {
        ScheduleNextPoll(kRecalculatePollPeriod);
    }
}

void DataPollManager::SetAttachMode(bool aMode)
{
    if (mAttachMode != aMode)
    {
        mAttachMode = aMode;

        if (mEnabled)
        {
            ScheduleNextPoll(kRecalculatePollPeriod);
        }
    }
}

void DataPollManager::SendFastPolls(uint8_t aNumFastPolls)
{
    bool shouldRecalculatePollPeriod = (mRemainingFastPolls == 0);

    if (aNumFastPolls == 0)
    {
        aNumFastPolls = kDefaultFastPolls;
    }

    if (aNumFastPolls > kMaxFastPolls)
    {
        aNumFastPolls = kMaxFastPolls;
    }

    if (mRemainingFastPolls < aNumFastPolls)
    {
        mRemainingFastPolls = aNumFastPolls;
    }

    if (mEnabled && shouldRecalculatePollPeriod)
    {
        ScheduleNextPoll(kRecalculatePollPeriod);
    }
}

void DataPollManager::ScheduleNextPoll(PollPeriodSelector aPollPeriodSelector)
{
    if (aPollPeriodSelector == kRecalculatePollPeriod)
    {
        mPollPeriod = CalculatePollPeriod();
    }

    if (mTimer.IsRunning())
    {
        mTimer.StartAt(mTimer.Gett0(), mPollPeriod);
    }
    else
    {
        mTimer.Start(mPollPeriod);
    }
}

uint32_t DataPollManager::CalculatePollPeriod(void) const
{
    uint32_t period = 0;

    if (mAttachMode == true)
    {
        period = kAttachDataPollPeriod;
    }

    if (mRetxMode == true)
    {
        if ((period == 0) || (period > kRetxPollPeriod))
        {
            period = kRetxPollPeriod;
        }
    }

    if (mNoBufferRetxMode == true)
    {
        if ((period == 0) || (period > kNoBufferRetxPollPeriod))
        {
            period = kNoBufferRetxPollPeriod;
        }
    }

    if (mRemainingFastPolls != 0)
    {
        if ((period == 0) || (period > kFastPollPeriod))
        {
            period = kFastPollPeriod;
        }
    }

    if (mExternalPollPeriod != 0)
    {
        if ((period == 0) || (period > mExternalPollPeriod))
        {
            period = mExternalPollPeriod;
        }
    }

    if (period == 0)
    {
        period = Timer::SecToMsec(mMeshForwarder.GetNetif().GetMle().GetTimeout()) -  kRetxPollPeriod * kMaxPollRetxAttempts;

        if (period == 0)
        {
            period = kMinPollPeriod;
        }
    }

    return period;
}

void DataPollManager::HandlePollTimer(void *aContext)
{
    static_cast<DataPollManager *>(aContext)->SendDataPoll();
}

}  // namespace ot
<|endoftext|>