<commit_before>int total=0; int rejected=0;
Float_t fromPt=1.; Float_t toPt=5.;

namespace RawProduction {
  class Output;
}

void CountReject(RawProduction::Output& output, const char* trigger, int cent, const char* pid, const char* methode)
{
  TH1* hist = output.GetHistogram(Form("%s/c%03i/%s/%s", trigger, cent, pid, methode));
  int fromBin = hist->FindBin(fromPt);
  int toBin = hist->FindBin( toPt);
  for(int bin = fromBin; bin<=toBin; ++bin) {
    ++total;
    if( 0. == hist->GetBinContent(bin))
      ++rejected;
  }
}

void CountRejected()
{
  gROOT->LoadMacro("MakeRawProduction.C+g");
  RawProduction::Output output("RawProduction21.root");
  gStyle->SetOptStat(0);

  TStringToken pids("All Allcore Allwou Disp Disp2 Dispcore Dispwou CPV CPVcore CPV2 Both Bothcore", " ");
  while( pids.NextToken() ) {
    TStringToken fits("mr1r mr1 mr2r mr2", " ");
    while( fits.NextToken() ) {
      CountReject(output, "kMB", -1, pids.Data(), fits.Data());
      //CountReject(output, "kMB", -11, pids.Data(), fits.Data());
      CountReject(output, "kMB", -10, pids.Data(), fits.Data());
      //CountReject(output, "kMB", -6, pids.Data(), fits.Data());

      CountReject(output, "kCentral", -1, pids.Data(), fits.Data());

      //CountReject(output, "kSemiCentral", -11, pids.Data(), fits.Data());
    }
  }

  Printf("fits:%i,  rejected:%i", total, rejected);
}
<commit_msg>Minor cleanup of CountRejected.C<commit_after>int total=0; int rejected=0;
Float_t fromPt=1.; Float_t toPt=5.;

namespace RawProduction {
  class Output;
}

void CountReject(RawProduction::Output& output, const char* trigger, int cent, const char* pid, const char* methode)
{
  TH1* hist = output.GetHistogram(Form("%s/c%03i/%s/%s", trigger, cent, pid, methode));
  int fromBin = hist->FindBin(fromPt);
  int toBin = hist->FindBin( toPt);
  for(int bin = fromBin; bin<=toBin; ++bin) {
    ++total;
    if( 0. == hist->GetBinContent(bin))
      ++rejected;
  }
}

void CountRejected()
{
  gROOT->LoadMacro("MakeRawProduction.C+g");
  RawProduction::Output output("RawProduction.root");
  gStyle->SetOptStat(0);

  TStringToken pids("All Allcore Allwou Disp Disp2 Dispcore Dispwou CPV CPVcore CPV2 Both Bothcore", " ");
  while( pids.NextToken() ) {
    TStringToken fits("mr1r mr1 mr2r mr2", " ");
    while( fits.NextToken() ) {
      CountReject(output, "kMB", -1, pids.Data(), fits.Data());
      //CountReject(output, "kMB", -11, pids.Data(), fits.Data());
      CountReject(output, "kMB", -10, pids.Data(), fits.Data());
      //CountReject(output, "kMB", -6, pids.Data(), fits.Data());

      CountReject(output, "kCentral", -1, pids.Data(), fits.Data());

      //CountReject(output, "kSemiCentral", -11, pids.Data(), fits.Data());
    }
  }

  Printf("fits:%i,  rejected:%i", total, rejected);
}
<|endoftext|>


<commit_before>// BenchmarkRegex.cpp : Defines the entry point for the console application.
//

#include <vector>
#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <cmath>
#include <cassert>
#include <sstream>
#include <cstdlib>
#include <chrono>
#include <regex>
#include <unordered_map>
#include <map>
#include <thread>
#include <mutex>
#include <memory>

using namespace std;

const int LOOP = 1000000;
const int THREADS = 4;

class timer
{
public:
	timer() = default;
	void start_timing(const string& text_)
	{
		text = text_;
		begin = chrono::high_resolution_clock::now();
	}
	void stop_timing()
	{
		auto end = chrono::high_resolution_clock::now();
		auto dur = end - begin;
		auto ms = chrono::duration_cast<chrono::milliseconds>(dur).count();
		cout << setw(35) << text << ":" << setw(5) << ms << "ms" << endl;
	}

private:
	string text;
	chrono::steady_clock::time_point begin;
};

#ifdef WIN32

#pragma optimize("", off)
template <class T>
void do_not_optimize_away(T* datum) {
	datum = datum;
}
#pragma optimize("", on)

#else
static void do_not_optimize_away(void* p) {
	asm volatile("" : : "g"(p) : "memory");
}
#endif

struct singleton
{
public:
	typedef unordered_map<thread::id, unique_ptr<regex> > MapType;
	static void init(const string& reg_exp) { s_reg_exp = reg_exp; }
	static const regex& get()
	{
		lock_guard<mutex> lock(s_mutex);

		thread::id thread_id = this_thread::get_id();
		MapType::iterator it = s_map.find(thread_id);
		if (it == s_map.end())
		{
			prevent_false_sharing(1000);
			s_map[thread_id] = unique_ptr<regex>(new regex(s_reg_exp));
			return *s_map[thread_id];
		}
		return *(it->second);
	}
private:
	static void prevent_false_sharing(size_t size)
	{
		unique_ptr<char[]> p = unique_ptr<char[]>(new char[size]);
		s_vec_temp_alloc.push_back(move(p));
	}
	static MapType s_map;
	static string s_reg_exp;
	static mutex s_mutex;
	static vector< unique_ptr<char[]> > s_vec_temp_alloc;
};
singleton::MapType singleton::s_map;
string singleton::s_reg_exp;
mutex singleton::s_mutex;
vector< unique_ptr<char[]> > singleton::s_vec_temp_alloc;

struct factory
{
public:
	static unique_ptr<regex> get(const string& reg_exp)
	{
		lock_guard<mutex> lock(s_mutex);
		prevent_false_sharing(1000);
		return unique_ptr<regex>(new regex(reg_exp));
	}
private:
	static void prevent_false_sharing(size_t size)
	{
		unique_ptr<char[]> p = unique_ptr<char[]>(new char[size]);
		s_vec_temp_alloc.push_back(move(p));
	}
	static mutex s_mutex;
	static vector< unique_ptr<char[]> > s_vec_temp_alloc;
};
mutex factory::s_mutex;
vector< unique_ptr<char[]> > factory::s_vec_temp_alloc;

const string local_match(const string& text);
const string static_match(const string& text); // not reentrant-safe
const string singleton_match(const string& text);
const string factory_match(const string& text, const regex& regex);

void parallel_invoke(const int size, const int threads, function<void(int, int)> func)
{
	typedef unique_ptr<thread> PtrType;
	vector< PtrType > vec;
	int each = size / threads;

	for (int i = 0; i < threads; ++i)
	{
		if (i == threads - 1) // last thread
		{
			vec.emplace_back(PtrType(new thread(func, each*i, each*(i + 1) + (size % threads) - 1)));
		}
		else
		{
			vec.emplace_back(PtrType(new thread(func, each*i, each*(i + 1) - 1 )));
		}
	}

	for (size_t i = 0; i < vec.size(); ++i)
	{
		vec[i]->join();
	}
}

const string REG_EXP = ".*PRICE:.*US\\$(\\d+\\.\\d+|[-+]*\\d+).*PER SHARE";

int main(int argc, char* argv[])
{
	string str1 = "Zoomer PRICE: US$1.23 PER SHARE";
	string str2 = "Boomer PRICE: US$4.56 PER SHARE";

	vector<string> vec;
	vec.push_back(str1);
	vec.push_back(str2);

	timer stopwatch;

	stopwatch.start_timing("local regex object");
	for(int j = 0; j < LOOP; ++j)
	{
		for(size_t i = 0; i < vec.size(); ++i)
		{
			do_not_optimize_away(local_match(vec[i]).c_str());
		}
	}
	stopwatch.stop_timing();

	stopwatch.start_timing("static regex object");
	for(int j = 0; j < LOOP; ++j)
	{
		for(size_t i = 0; i < vec.size(); ++i)
		{
			do_not_optimize_away(static_match(vec[i]).c_str());
		}
	}
	stopwatch.stop_timing();

	singleton::init(REG_EXP);
	stopwatch.start_timing("singleton regex object");
	for (int j = 0; j < LOOP; ++j)
	{
		for (size_t i = 0; i < vec.size(); ++i)
		{
			do_not_optimize_away(singleton_match(vec[i]).c_str());
		}
	}
	stopwatch.stop_timing();

	ostringstream os;
	os << "local regex object(" << THREADS << " threads)";
	stopwatch.start_timing(os.str());
	parallel_invoke(LOOP, THREADS, [&vec](int start, int end) {
		for (int j = start; j < end; ++j)
		{
			for (size_t i = 0; i < vec.size(); ++i)
			{
				do_not_optimize_away(local_match(vec[i]).c_str());
			}
		}
	});
	stopwatch.stop_timing();

	os.clear();
	os.str("");
	os << "singleton regex object(" << THREADS << " threads)";
	stopwatch.start_timing(os.str());
	parallel_invoke(LOOP, THREADS, [&vec] (int start, int end) {
		for (int j = start; j < end; ++j)
		{
			for (size_t i = 0; i < vec.size(); ++i)
			{
				do_not_optimize_away(singleton_match(vec[i]).c_str());
			}
		}
	});
	stopwatch.stop_timing();

	os.clear();
	os.str("");
	os << "factory regex object(" << THREADS << " threads)";
	stopwatch.start_timing(os.str());
	parallel_invoke(LOOP, THREADS, [&vec](int start, int end) {
		unique_ptr<regex> ptr = factory::get(REG_EXP);
		const regex& regex = *ptr;

		for (int j = start; j < end; ++j)
		{
			for (size_t i = 0; i < vec.size(); ++i)
			{
				do_not_optimize_away(factory_match(vec[i], regex).c_str());
			}
		}
	});
	stopwatch.stop_timing();

	/*
	cout << local_match(str1) << endl;
	cout << local_match(str2) << endl;
	cout << static_match(str1) << endl;
	cout << static_match(str2) << endl;
	singleton::init(REG_EXP);
	cout << singleton_match(str1) << endl;
	cout << singleton_match(str2) << endl;
	const regex regex(REG_EXP);
	cout << factory_match(str1, regex) << endl;
	cout << factory_match(str2, regex) << endl;
	*/

	return 0;
}

const string local_match(const string& text)
{
	string price = "";
	smatch what;
	const regex regex(REG_EXP);
	if (regex_match(text, what, regex))
	{
		price = what[1];
	}
	return price;
}

const string static_match(const string& text) // not reentrant-safe
{
	string price = "";
	smatch what;
	static const regex regex(REG_EXP);
	if (regex_match(text, what, regex))
	{
		price = what[1];
	}
	return price;
}

const string singleton_match(const string& text)
{
	string price = "";
	smatch what;
	const regex& regex = singleton::get();
	if (regex_match(text, what, regex))
	{
		price = what[1];
	}
	return price;
}

const string factory_match(const string& text, const regex& regex)
{
	string price = "";
	smatch what;
	if (regex_match(text, what, regex))
	{
		price = what[1];
	}
	return price;
}
<commit_msg>Add thread_local benchmark<commit_after>// BenchmarkRegex.cpp : Defines the entry point for the console application.
//

#include <vector>
#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <cmath>
#include <cassert>
#include <sstream>
#include <cstdlib>
#include <chrono>
#include <regex>
#include <unordered_map>
#include <map>
#include <thread>
#include <mutex>
#include <memory>

using namespace std;

const int LOOP = 1000000;
const int THREADS = 4;

class timer
{
public:
	timer() = default;
	void start_timing(const string& text_)
	{
		text = text_;
		begin = chrono::high_resolution_clock::now();
	}
	void stop_timing()
	{
		auto end = chrono::high_resolution_clock::now();
		auto dur = end - begin;
		auto ms = chrono::duration_cast<chrono::milliseconds>(dur).count();
		cout << setw(38) << text << ":" << setw(5) << ms << "ms" << endl;
	}

private:
	string text;
	chrono::steady_clock::time_point begin;
};

#ifdef WIN32

#pragma optimize("", off)
template <class T>
void do_not_optimize_away(T* datum) {
	datum = datum;
}
#pragma optimize("", on)

#else
static void do_not_optimize_away(void* p) {
	asm volatile("" : : "g"(p) : "memory");
}
#endif

struct singleton
{
public:
	typedef unordered_map<thread::id, unique_ptr<regex> > MapType;
	static void init(const string& reg_exp) { s_reg_exp = reg_exp; }
	static const regex& get()
	{
		lock_guard<mutex> lock(s_mutex);

		thread::id thread_id = this_thread::get_id();
		MapType::iterator it = s_map.find(thread_id);
		if (it == s_map.end())
		{
			prevent_false_sharing(1000);
			s_map[thread_id] = unique_ptr<regex>(new regex(s_reg_exp));
			return *s_map[thread_id];
		}
		return *(it->second);
	}
private:
	static void prevent_false_sharing(size_t size)
	{
		unique_ptr<char[]> p = unique_ptr<char[]>(new char[size]);
		s_vec_temp_alloc.push_back(move(p));
	}
	static MapType s_map;
	static string s_reg_exp;
	static mutex s_mutex;
	static vector< unique_ptr<char[]> > s_vec_temp_alloc;
};
singleton::MapType singleton::s_map;
string singleton::s_reg_exp;
mutex singleton::s_mutex;
vector< unique_ptr<char[]> > singleton::s_vec_temp_alloc;

struct factory
{
public:
	static unique_ptr<regex> get(const string& reg_exp)
	{
		lock_guard<mutex> lock(s_mutex);
		prevent_false_sharing(1000);
		return unique_ptr<regex>(new regex(reg_exp));
	}
private:
	static void prevent_false_sharing(size_t size)
	{
		unique_ptr<char[]> p = unique_ptr<char[]>(new char[size]);
		s_vec_temp_alloc.push_back(move(p));
	}
	static mutex s_mutex;
	static vector< unique_ptr<char[]> > s_vec_temp_alloc;
};
mutex factory::s_mutex;
vector< unique_ptr<char[]> > factory::s_vec_temp_alloc;

const string local_match(const string& text);
const string static_match(const string& text); // not reentrant-safe
const string thread_local_match(const string& text); // not reentrant-safe
const string singleton_match(const string& text);
const string factory_match(const string& text, const regex& regex);

void parallel_invoke(const int size, const int threads, function<void(int, int)> func)
{
	typedef unique_ptr<thread> PtrType;
	vector< PtrType > vec;
	int each = size / threads;

	for (int i = 0; i < threads; ++i)
	{
		if (i == threads - 1) // last thread
		{
			vec.emplace_back(PtrType(new thread(func, each*i, each*(i + 1) + (size % threads) - 1)));
		}
		else
		{
			vec.emplace_back(PtrType(new thread(func, each*i, each*(i + 1) - 1 )));
		}
	}

	for (size_t i = 0; i < vec.size(); ++i)
	{
		vec[i]->join();
	}
}

const string REG_EXP = ".*PRICE:.*US\\$(\\d+\\.\\d+|[-+]*\\d+).*PER SHARE";
#include <utility>

int main(int argc, char* argv[])
{
	int a = 1, b = 2;
	std::swap(a, b);
	string str1 = "Zoomer PRICE: US$1.23 PER SHARE";
	string str2 = "Boomer PRICE: US$4.56 PER SHARE";

	vector<string> vec;
	vec.push_back(str1);
	vec.push_back(str2);

	timer stopwatch;

	stopwatch.start_timing("local regex object");
	for(int j = 0; j < LOOP; ++j)
	{
		for(size_t i = 0; i < vec.size(); ++i)
		{
			do_not_optimize_away(local_match(vec[i]).c_str());
		}
	}
	stopwatch.stop_timing();

	stopwatch.start_timing("static regex object");
	for(int j = 0; j < LOOP; ++j)
	{
		for(size_t i = 0; i < vec.size(); ++i)
		{
			do_not_optimize_away(static_match(vec[i]).c_str());
		}
	}
	stopwatch.stop_timing();

	singleton::init(REG_EXP);
	stopwatch.start_timing("singleton regex object");
	for (int j = 0; j < LOOP; ++j)
	{
		for (size_t i = 0; i < vec.size(); ++i)
		{
			do_not_optimize_away(singleton_match(vec[i]).c_str());
		}
	}
	stopwatch.stop_timing();

	singleton::init(REG_EXP);
	stopwatch.start_timing("thread_local regex object");
	for (int j = 0; j < LOOP; ++j)
	{
		for (size_t i = 0; i < vec.size(); ++i)
		{
			do_not_optimize_away(thread_local_match(vec[i]).c_str());
		}
	}
	stopwatch.stop_timing();

	ostringstream os;
	os << "local regex object(" << THREADS << " threads)";
	stopwatch.start_timing(os.str());
	parallel_invoke(LOOP, THREADS, [&vec](int start, int end) {
		for (int j = start; j < end; ++j)
		{
			for (size_t i = 0; i < vec.size(); ++i)
			{
				do_not_optimize_away(local_match(vec[i]).c_str());
			}
		}
	});
	stopwatch.stop_timing();

	os.clear();
	os.str("");
	os << "singleton regex object(" << THREADS << " threads)";
	stopwatch.start_timing(os.str());
	parallel_invoke(LOOP, THREADS, [&vec] (int start, int end) {
		for (int j = start; j < end; ++j)
		{
			for (size_t i = 0; i < vec.size(); ++i)
			{
				do_not_optimize_away(singleton_match(vec[i]).c_str());
			}
		}
	});
	stopwatch.stop_timing();

	os.clear();
	os.str("");
	os << "factory regex object(" << THREADS << " threads)";
	stopwatch.start_timing(os.str());
	parallel_invoke(LOOP, THREADS, [&vec](int start, int end) {
		unique_ptr<regex> ptr = factory::get(REG_EXP);
		const regex& regex = *ptr;

		for (int j = start; j < end; ++j)
		{
			for (size_t i = 0; i < vec.size(); ++i)
			{
				do_not_optimize_away(factory_match(vec[i], regex).c_str());
			}
		}
	});
	stopwatch.stop_timing();

	os.clear();
	os.str("");
	os << "thread_local regex object(" << THREADS << " threads)";
	stopwatch.start_timing(os.str());
	parallel_invoke(LOOP, THREADS, [&vec](int start, int end) {
		unique_ptr<regex> ptr = factory::get(REG_EXP);
		const regex& regex = *ptr;

		for (int j = start; j < end; ++j)
		{
			for (size_t i = 0; i < vec.size(); ++i)
			{
				do_not_optimize_away(thread_local_match(vec[i]).c_str());
			}
		}
	});
	stopwatch.stop_timing();

	/*
	cout << local_match(str1) << endl;
	cout << local_match(str2) << endl;
	cout << static_match(str1) << endl;
	cout << static_match(str2) << endl;
	singleton::init(REG_EXP);
	cout << singleton_match(str1) << endl;
	cout << singleton_match(str2) << endl;
	const regex regex(REG_EXP);
	cout << factory_match(str1, regex) << endl;
	cout << factory_match(str2, regex) << endl;
	cout << thread_local_match(str1) << endl;
	cout << thread_local_match(str2) << endl;
	*/

	return 0;
}

const string local_match(const string& text)
{
	string price = "";
	smatch what;
	const regex regex(REG_EXP);
	if (regex_match(text, what, regex))
	{
		price = what[1];
	}
	return price;
}

const string static_match(const string& text) // not reentrant-safe
{
	string price = "";
	smatch what;
	static const regex regex(REG_EXP);
	if (regex_match(text, what, regex))
	{
		price = what[1];
	}
	return price;
}

const string thread_local_match(const string& text) // not reentrant-safe
{
	string price = "";
	smatch what;
	static thread_local const regex regex(REG_EXP);
	if (regex_match(text, what, regex))
	{
		price = what[1];
	}
	return price;
}

const string singleton_match(const string& text)
{
	string price = "";
	smatch what;
	const regex& regex = singleton::get();
	if (regex_match(text, what, regex))
	{
		price = what[1];
	}
	return price;
}

const string factory_match(const string& text, const regex& regex)
{
	string price = "";
	smatch what;
	if (regex_match(text, what, regex))
	{
		price = what[1];
	}
	return price;
}
<|endoftext|>


<commit_before>#include <ma.h>
#include <apf.h>
#include <gmi_mesh.h>
#include <apfMDS.h>
#include <PCU.h>

int main(int argc, char** argv)
{
  assert(argc==4);
  MPI_Init(&argc,&argv);
  PCU_Comm_Init();
  gmi_register_mesh();
  ma::Mesh* m = apf::loadMdsMesh(argv[1],argv[2]);
  ma::runUniformRefinement(m);
  m->writeNative(argv[3]);
  m->destroyNative();
  apf::destroyMesh(m);
  PCU_Comm_Free();
  MPI_Finalize();
}

<commit_msg>uniform exe doesn't snap or fix shape now<commit_after>#include <ma.h>
#include <apf.h>
#include <gmi_mesh.h>
#include <apfMDS.h>
#include <PCU.h>

int main(int argc, char** argv)
{
  assert(argc==4);
  MPI_Init(&argc,&argv);
  PCU_Comm_Init();
  gmi_register_mesh();
  ma::Mesh* m = apf::loadMdsMesh(argv[1],argv[2]);
  ma::Input* in = ma::configureUniformRefine(m, 1);
  if (in->shouldSnap) {
    in->shouldSnap = false;
    assert(in->shouldTransferParametric);
  }
  in->shouldFixShape = false;
  ma::adapt(in);
  m->writeNative(argv[3]);
  m->destroyNative();
  apf::destroyMesh(m);
  PCU_Comm_Free();
  MPI_Finalize();
}

<|endoftext|>


<commit_before>#ifndef COMMANDITERATIONUPDATE_CPP_
#define COMMANDITERATIONUPDATE_CPP_

#include "itkCommand.h"

// Class to handle blah blah blah

using namespace std;

template<typename OptimizerType>
class CommandIterationUpdate : public itk::Command
{
public:
  typedef CommandIterationUpdate   Self;
  typedef itk::Command             Superclass;
  typedef itk::SmartPointer<Self>  Pointer;

  itkNewMacro( Self );

protected:
  CommandIterationUpdate() {}

public:
  typedef const OptimizerType* OptimizerPointer;

  void Execute(itk::Object *caller, const itk::EventObject & event)
    {
	  // in this case, just calls the const version of Execute
    Execute( (const itk::Object *)caller, event);
    }

  void Execute(const itk::Object * object, const itk::EventObject & event)
    {
    OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( object );

    if( ! itk::IterationEvent().CheckEvent( &event ) )
      {
      return;
      }

    cout << optimizer->GetCurrentIteration() << " = ";
    cout << optimizer->GetValue() << " : ";
    cout << optimizer->GetCurrentPosition() << endl;
    }
};
#endif<commit_msg>Changed tab spacing in CommandIterationUpdate.hpp<commit_after>#ifndef COMMANDITERATIONUPDATE_CPP_
#define COMMANDITERATIONUPDATE_CPP_

#include "itkCommand.h"

// Class to handle blah blah blah

using namespace std;

template<typename OptimizerType>
class CommandIterationUpdate : public itk::Command
{
public:
  typedef CommandIterationUpdate   Self;
  typedef itk::Command             Superclass;
  typedef itk::SmartPointer<Self>  Pointer;

  itkNewMacro( Self );

protected:
  CommandIterationUpdate() {}

public:
  typedef const OptimizerType* OptimizerPointer;

  void Execute(itk::Object *caller, const itk::EventObject & event)
  {
	  // in this case, just calls the const version of Execute
    Execute( (const itk::Object *)caller, event);
  }

  void Execute(const itk::Object * object, const itk::EventObject & event)
  {
    OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( object );

    if( ! itk::IterationEvent().CheckEvent( &event ) )
      {
      return;
      }

    cout << optimizer->GetCurrentIteration() << " = ";
    cout << optimizer->GetValue() << " : ";
    cout << optimizer->GetCurrentPosition() << endl;
  }
};
#endif<|endoftext|>


<commit_before>// Register two LoRes slices to each other

#include "boost/filesystem.hpp"

// my files
#include "Stack.hpp"
#include "StackInitializers.hpp"
#include "RegistrationBuilder.hpp"
#include "StackAligner.hpp"
#include "StackIOHelpers.hpp"
#include "IOHelpers.hpp"
#include "StackTransforms.hpp"
#include "Dirs.hpp"
#include "Parameters.hpp"
#include "Profiling.hpp"

void checkUsage(int argc, char const *argv[]) {
  if( argc < 4 )
  {
    cerr << "\nUsage: " << endl;
    cerr << argv[0] << " dataSet slice1 slice2 (writeVolumes=false)\n\n";
    cerr << "e.g. " << argv[0] << " Rat28 0053 0054 true\n\n";
    exit(EXIT_FAILURE);
  }
}

int main(int argc, char const *argv[]) {
  using namespace boost::filesystem;

  // Verify the number of parameters in the command line
  checkUsage(argc, argv);

  // Process command line arguments
  Dirs::SetDataSet(argv[1]);
  string slice1BaseName(argv[2]);
  string slice2BaseName(argv[3]);
  Dirs::SetOutputDirName("LoResCorrectionTransforms");
  vector< string > slice1FileName, slice2FileName;
  string blockDir(Dirs::ImagesDir() + "LoRes_rgb/downsamples_1/");
  slice1FileName.push_back(Dirs::BlockDir() + slice1BaseName + ".bmp");
  slice2FileName.push_back(Dirs::BlockDir() + slice2BaseName + ".bmp");

  // initialise stack objects with correct spacings, sizes etc
  typedef Stack< float, itk::ResampleImageFilter, itk::LinearInterpolateImageFunction > StackType;
  StackType::SliceVectorType slice1Image = readImages< StackType >(slice1FileName);
  StackType::SliceVectorType slice2Image = readImages< StackType >(slice2FileName);
  boost::shared_ptr< StackType > slice1Stack = InitializeLoResStack<StackType>(slice1Image);
  boost::shared_ptr< StackType > slice2Stack = InitializeLoResStack<StackType>(slice2Image);

  // initialize stacks' transforms
  StackTransforms::InitializeWithTranslation( *slice1Stack, StackTransforms::GetLoResTranslation("whole_heart") );
  StackTransforms::InitializeWithTranslation( *slice2Stack, StackTransforms::GetLoResTranslation("whole_heart") );

  // create output dir before write operations
  create_directory( Dirs::ResultsDir() );

  // Build LoRes slices
  slice1Stack->updateVolumes();
  slice2Stack->updateVolumes();
  if(argc >= 5)
  {
    writeImage< StackType::SliceType >( slice1Stack->GetResampledSlice(0), Dirs::ResultsDir() + slice1BaseName + ".mha" );
    writeImage< StackType::SliceType >( slice2Stack->GetResampledSlice(0), Dirs::ResultsDir() + slice2BaseName + "_before_registration.mha" );
    writeImage< StackType::SliceType >( slice1Stack->GetOriginalImage(0), Dirs::ResultsDir() + slice1BaseName + "_original.mha" );
    writeImage< StackType::SliceType >( slice2Stack->GetOriginalImage(0), Dirs::ResultsDir() + slice2BaseName + "_original.mha" );
  }
  // initialise registration framework
  boost::shared_ptr<YAML::Node> pParameters = config("2_slice_parameters.yml");
  typedef RegistrationBuilder< StackType > RegistrationBuilderType;
  RegistrationBuilderType registrationBuilder(*pParameters);
  RegistrationBuilderType::RegistrationType::Pointer registration = registrationBuilder.GetRegistration();

  // Could change this to register against original fixed image and fixed image masks,
  // by applying the inverse fixed transform to the moving one, registering, then
  // applying the fixed transform back again afterwards.
  registration->SetFixedImage( slice1Stack->GetResampledSlice(0) );
  registration->SetMovingImage( slice2Stack->GetOriginalImage(0) );

  registration->GetMetric()->SetFixedImageMask( slice1Stack->GetResampled2DMask(0) );
  registration->GetMetric()->SetMovingImageMask( slice2Stack->GetOriginal2DMask(0) );

  registration->SetTransform( slice2Stack->GetTransform(0) );

  registration->SetInitialTransformParameters( slice2Stack->GetTransform(0)->GetParameters() );

  try { registration->Update(); }
  catch( itk::ExceptionObject & err )
  {
    std::cerr << "ExceptionObject caught !" << std::endl;
    std::cerr << err << std::endl;
    return EXIT_FAILURE;
  }

  cout << "Optimizer stop condition: "
       << registration->GetOptimizer()->GetStopConditionDescription() << endl << endl;

  // write registered image
  slice2Stack->updateVolumes();
  if(argc >= 5)
  {
    writeImage< StackType::SliceType >( slice2Stack->GetResampledSlice(0), Dirs::ResultsDir() + slice2BaseName + "_after_registration.mha" );
  }

  // Write resultant transform
  // subtract initial translation, so that
  // transform represents the relative translation from one slice to another
  StackTransforms::Translate(*slice2Stack, -StackTransforms::GetLoResTranslation("whole_heart"));
  vector< string > transformFileName(1, slice1BaseName + "_" + slice2BaseName);
  Save(*slice2Stack, transformFileName, Dirs::ResultsDir());

  return EXIT_SUCCESS;

}
<commit_msg>Removed debugging output from Register2Slices.<commit_after>// Register two LoRes slices to each other

#include "boost/filesystem.hpp"

// my files
#include "Stack.hpp"
#include "StackInitializers.hpp"
#include "RegistrationBuilder.hpp"
#include "StackAligner.hpp"
#include "StackIOHelpers.hpp"
#include "IOHelpers.hpp"
#include "StackTransforms.hpp"
#include "Dirs.hpp"
#include "Parameters.hpp"
#include "Profiling.hpp"

void checkUsage(int argc, char const *argv[]) {
  if( argc < 4 )
  {
    cerr << "\nUsage: " << endl;
    cerr << argv[0] << " dataSet slice1 slice2 (writeVolumes=false)\n\n";
    cerr << "e.g. " << argv[0] << " Rat28 0053 0054 true\n\n";
    exit(EXIT_FAILURE);
  }
}

int main(int argc, char const *argv[]) {
  using namespace boost::filesystem;

  // Verify the number of parameters in the command line
  checkUsage(argc, argv);

  // Process command line arguments
  Dirs::SetDataSet(argv[1]);
  string slice1BaseName(argv[2]);
  string slice2BaseName(argv[3]);
  Dirs::SetOutputDirName("LoResCorrectionTransforms");
  vector< string > slice1FileName, slice2FileName;
  string blockDir(Dirs::ImagesDir() + "LoRes_rgb/downsamples_1/");
  slice1FileName.push_back(Dirs::BlockDir() + slice1BaseName + ".bmp");
  slice2FileName.push_back(Dirs::BlockDir() + slice2BaseName + ".bmp");

  // initialise stack objects with correct spacings, sizes etc
  typedef Stack< float, itk::ResampleImageFilter, itk::LinearInterpolateImageFunction > StackType;
  StackType::SliceVectorType slice1Image = readImages< StackType >(slice1FileName);
  StackType::SliceVectorType slice2Image = readImages< StackType >(slice2FileName);
  boost::shared_ptr< StackType > slice1Stack = InitializeLoResStack<StackType>(slice1Image);
  boost::shared_ptr< StackType > slice2Stack = InitializeLoResStack<StackType>(slice2Image);

  // initialize stacks' transforms
  StackTransforms::InitializeWithTranslation( *slice1Stack, StackTransforms::GetLoResTranslation("whole_heart") );
  StackTransforms::InitializeWithTranslation( *slice2Stack, StackTransforms::GetLoResTranslation("whole_heart") );

  // create output dir before write operations
  create_directory( Dirs::ResultsDir() );

  // Build LoRes slices
  slice1Stack->updateVolumes();
  slice2Stack->updateVolumes();
  if(argc >= 5)
  {
    writeImage< StackType::SliceType >( slice1Stack->GetResampledSlice(0), Dirs::ResultsDir() + slice1BaseName + ".mha" );
    writeImage< StackType::SliceType >( slice2Stack->GetResampledSlice(0), Dirs::ResultsDir() + slice2BaseName + "_before_registration.mha" );
  }
  // initialise registration framework
  boost::shared_ptr<YAML::Node> pParameters = config("2_slice_parameters.yml");
  typedef RegistrationBuilder< StackType > RegistrationBuilderType;
  RegistrationBuilderType registrationBuilder(*pParameters);
  RegistrationBuilderType::RegistrationType::Pointer registration = registrationBuilder.GetRegistration();

  // Could change this to register against original fixed image and fixed image masks,
  // by applying the inverse fixed transform to the moving one, registering, then
  // applying the fixed transform back again afterwards.
  registration->SetFixedImage( slice1Stack->GetResampledSlice(0) );
  registration->SetMovingImage( slice2Stack->GetOriginalImage(0) );

  registration->GetMetric()->SetFixedImageMask( slice1Stack->GetResampled2DMask(0) );
  registration->GetMetric()->SetMovingImageMask( slice2Stack->GetOriginal2DMask(0) );

  registration->SetTransform( slice2Stack->GetTransform(0) );

  registration->SetInitialTransformParameters( slice2Stack->GetTransform(0)->GetParameters() );

  try { registration->Update(); }
  catch( itk::ExceptionObject & err )
  {
    std::cerr << "ExceptionObject caught !" << std::endl;
    std::cerr << err << std::endl;
    return EXIT_FAILURE;
  }

  cout << "Optimizer stop condition: "
       << registration->GetOptimizer()->GetStopConditionDescription() << endl << endl;

  // write registered image
  slice2Stack->updateVolumes();
  if(argc >= 5)
  {
    writeImage< StackType::SliceType >( slice2Stack->GetResampledSlice(0), Dirs::ResultsDir() + slice2BaseName + "_after_registration.mha" );
  }

  // Write resultant transform
  // subtract initial translation, so that
  // transform represents the relative translation from one slice to another
  StackTransforms::Translate(*slice2Stack, -StackTransforms::GetLoResTranslation("whole_heart"));
  vector< string > transformFileName(1, slice1BaseName + "_" + slice2BaseName);
  Save(*slice2Stack, transformFileName, Dirs::ResultsDir());

  return EXIT_SUCCESS;

}
<|endoftext|>


<commit_before>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/flow/layers/transform_layer.h"

namespace flutter {

TransformLayer::TransformLayer(const SkMatrix& transform)
    : transform_(transform) {
  // Checks (in some degree) that SkMatrix transform_ is valid and initialized.
  //
  // If transform_ is uninitialized, this assert may look flaky as it doesn't
  // fail all the time, and some rerun may make it pass. But don't ignore it and
  // just rerun the test if this is triggered, since even a flaky failure here
  // may signify a potentially big problem in the code.
  //
  // We have to write this flaky test because there is no reliable way to test
  // whether a variable is initialized or not in C++.
  FML_CHECK(transform_.isFinite());
}

TransformLayer::~TransformLayer() = default;

void TransformLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
  SkMatrix child_matrix;
  child_matrix.setConcat(matrix, transform_);

  SkRect previous_cull_rect = context->cull_rect;
  SkMatrix inverse_transform_;
  // Perspective projections don't produce rectangles that are useful for
  // culling for some reason.
  if (!transform_.hasPerspective() && transform_.invert(&inverse_transform_)) {
    inverse_transform_.mapRect(&context->cull_rect);
  } else {
    context->cull_rect = kGiantRect;
  }

  SkRect child_paint_bounds = SkRect::MakeEmpty();
  PrerollChildren(context, child_matrix, &child_paint_bounds);

  transform_.mapRect(&child_paint_bounds);
  set_paint_bounds(child_paint_bounds);

  context->cull_rect = previous_cull_rect;
}

#if defined(OS_FUCHSIA)

void TransformLayer::UpdateScene(SceneUpdateContext& context) {
  FML_DCHECK(needs_system_composite());

  SceneUpdateContext::Transform transform(context, transform_);
  UpdateSceneChildren(context);
}

#endif  // defined(OS_FUCHSIA)

void TransformLayer::Paint(PaintContext& context) const {
  TRACE_EVENT0("flutter", "TransformLayer::Paint");
  FML_DCHECK(needs_painting());

  SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
  context.internal_nodes_canvas->concat(transform_);
  PaintChildren(context);
}

}  // namespace flutter
<commit_msg>Set identity instead of crash in opt build (#9262)<commit_after>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/flow/layers/transform_layer.h"

namespace flutter {

TransformLayer::TransformLayer(const SkMatrix& transform)
    : transform_(transform) {
  // Checks (in some degree) that SkMatrix transform_ is valid and initialized.
  //
  // If transform_ is uninitialized, this assert may look flaky as it doesn't
  // fail all the time, and some rerun may make it pass. But don't ignore it and
  // just rerun the test if this is triggered, since even a flaky failure here
  // may signify a potentially big problem in the code.
  //
  // We have to write this flaky test because there is no reliable way to test
  // whether a variable is initialized or not in C++.
  FML_DCHECK(transform_.isFinite());
  if (!transform_.isFinite()) {
    FML_LOG(ERROR) << "TransformLayer is constructed with an invalid matrix.";
    transform_.setIdentity();
  }
}

TransformLayer::~TransformLayer() = default;

void TransformLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
  SkMatrix child_matrix;
  child_matrix.setConcat(matrix, transform_);

  SkRect previous_cull_rect = context->cull_rect;
  SkMatrix inverse_transform_;
  // Perspective projections don't produce rectangles that are useful for
  // culling for some reason.
  if (!transform_.hasPerspective() && transform_.invert(&inverse_transform_)) {
    inverse_transform_.mapRect(&context->cull_rect);
  } else {
    context->cull_rect = kGiantRect;
  }

  SkRect child_paint_bounds = SkRect::MakeEmpty();
  PrerollChildren(context, child_matrix, &child_paint_bounds);

  transform_.mapRect(&child_paint_bounds);
  set_paint_bounds(child_paint_bounds);

  context->cull_rect = previous_cull_rect;
}

#if defined(OS_FUCHSIA)

void TransformLayer::UpdateScene(SceneUpdateContext& context) {
  FML_DCHECK(needs_system_composite());

  SceneUpdateContext::Transform transform(context, transform_);
  UpdateSceneChildren(context);
}

#endif  // defined(OS_FUCHSIA)

void TransformLayer::Paint(PaintContext& context) const {
  TRACE_EVENT0("flutter", "TransformLayer::Paint");
  FML_DCHECK(needs_painting());

  SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
  context.internal_nodes_canvas->concat(transform_);
  PaintChildren(context);
}

}  // namespace flutter
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <folly/detail/CacheLocality.h>

#ifndef _MSC_VER
#define _GNU_SOURCE 1 // for RTLD_NOLOAD
#include <dlfcn.h>
#endif
#include <fstream>

#include <folly/Conv.h>
#include <folly/Exception.h>
#include <folly/FileUtil.h>
#include <folly/Format.h>
#include <folly/ScopeGuard.h>

namespace folly { namespace detail {

///////////// CacheLocality

/// Returns the best real CacheLocality information available
static CacheLocality getSystemLocalityInfo() {
#ifdef __linux__
  try {
    return CacheLocality::readFromSysfs();
  } catch (...) {
    // keep trying
  }
#endif

  long numCpus = sysconf(_SC_NPROCESSORS_CONF);
  if (numCpus <= 0) {
    // This shouldn't happen, but if it does we should try to keep
    // going.  We are probably not going to be able to parse /sys on
    // this box either (although we will try), which means we are going
    // to fall back to the SequentialThreadId splitter.  On my 16 core
    // (x hyperthreading) dev box 16 stripes is enough to get pretty good
    // contention avoidance with SequentialThreadId, and there is little
    // improvement from going from 32 to 64.  This default gives us some
    // wiggle room
    numCpus = 32;
  }
  return CacheLocality::uniform(numCpus);
}

template <>
const CacheLocality& CacheLocality::system<std::atomic>() {
  static CacheLocality cache(getSystemLocalityInfo());
  return cache;
}

// Each level of cache has sharing sets, which are the set of cpus
// that share a common cache at that level.  These are available in a
// hex bitset form (/sys/devices/system/cpu/cpu0/index0/shared_cpu_map,
// for example).  They are also available in a human-readable list form,
// as in /sys/devices/system/cpu/cpu0/index0/shared_cpu_list.  The list
// is a comma-separated list of numbers and ranges, where the ranges are
// a pair of decimal numbers separated by a '-'.
//
// To sort the cpus for optimum locality we don't really need to parse
// the sharing sets, we just need a unique representative from the
// equivalence class.  The smallest value works fine, and happens to be
// the first decimal number in the file.  We load all of the equivalence
// class information from all of the cpu*/index* directories, order the
// cpus first by increasing last-level cache equivalence class, then by
// the smaller caches.  Finally, we break ties with the cpu number itself.

/// Returns the first decimal number in the string, or throws an exception
/// if the string does not start with a number terminated by ',', '-',
/// '\n', or eos.
static size_t parseLeadingNumber(const std::string& line) {
  auto raw = line.c_str();
  char *end;
  unsigned long val = strtoul(raw, &end, 10);
  if (end == raw || (*end != ',' && *end != '-' && *end != '\n' && *end != 0)) {
    throw std::runtime_error(to<std::string>(
        "error parsing list '", line, "'").c_str());
  }
  return val;
}

CacheLocality CacheLocality::readFromSysfsTree(
    const std::function<std::string(std::string)>& mapping) {
  // number of equivalence classes per level
  std::vector<size_t> numCachesByLevel;

  // the list of cache equivalence classes, where equivalance classes
  // are named by the smallest cpu in the class
  std::vector<std::vector<size_t>> equivClassesByCpu;

  std::vector<size_t> cpus;

  while (true) {
    auto cpu = cpus.size();
    std::vector<size_t> levels;
    for (size_t index = 0; ; ++index) {
      auto dir = format("/sys/devices/system/cpu/cpu{}/cache/index{}/",
                        cpu, index).str();
      auto cacheType = mapping(dir + "type");
      auto equivStr = mapping(dir + "shared_cpu_list");
      if (cacheType.size() == 0 || equivStr.size() == 0) {
        // no more caches
        break;
      }
      if (cacheType[0] == 'I') {
        // cacheType in { "Data", "Instruction", "Unified" }. skip icache
        continue;
      }
      auto equiv = parseLeadingNumber(equivStr);
      auto level = levels.size();
      levels.push_back(equiv);

      if (equiv == cpu) {
        // we only want to count the equiv classes once, so we do it when
        // we first encounter them
        while (numCachesByLevel.size() <= level) {
          numCachesByLevel.push_back(0);
        }
        numCachesByLevel[level]++;
      }
    }

    if (levels.size() == 0) {
      // no levels at all for this cpu, we must be done
      break;
    }
    equivClassesByCpu.emplace_back(std::move(levels));
    cpus.push_back(cpu);
  }

  if (cpus.size() == 0) {
    throw std::runtime_error("unable to load cache sharing info");
  }

  std::sort(cpus.begin(), cpus.end(), [&](size_t lhs, size_t rhs) -> bool {
    // sort first by equiv class of cache with highest index, direction
    // doesn't matter.  If different cpus have different numbers of
    // caches then this code might produce a sub-optimal ordering, but
    // it won't crash
    auto& lhsEquiv = equivClassesByCpu[lhs];
    auto& rhsEquiv = equivClassesByCpu[rhs];
    for (int i = std::min(lhsEquiv.size(), rhsEquiv.size()) - 1; i >= 0; --i) {
      if (lhsEquiv[i] != rhsEquiv[i]) {
        return lhsEquiv[i] < rhsEquiv[i];
      }
    }

    // break ties deterministically by cpu
    return lhs < rhs;
  });

  // the cpus are now sorted by locality, with neighboring entries closer
  // to each other than entries that are far away.  For striping we want
  // the inverse map, since we are starting with the cpu
  std::vector<size_t> indexes(cpus.size());
  for (size_t i = 0; i < cpus.size(); ++i) {
    indexes[cpus[i]] = i;
  }

  return CacheLocality{
      cpus.size(), std::move(numCachesByLevel), std::move(indexes) };
}

CacheLocality CacheLocality::readFromSysfs() {
  return readFromSysfsTree([](std::string name) {
    std::ifstream xi(name.c_str());
    std::string rv;
    std::getline(xi, rv);
    return rv;
  });
}

CacheLocality CacheLocality::uniform(size_t numCpus) {
  CacheLocality rv;

  rv.numCpus = numCpus;

  // one cache shared by all cpus
  rv.numCachesByLevel.push_back(numCpus);

  // no permutations in locality index mapping
  for (size_t cpu = 0; cpu < numCpus; ++cpu) {
    rv.localityIndexByCpu.push_back(cpu);
  }

  return rv;
}

////////////// Getcpu

/// Resolves the dynamically loaded symbol __vdso_getcpu, returning null
/// on failure
static Getcpu::Func loadVdsoGetcpu() {
#ifdef _MSC_VER
  return nullptr;
#else
  void* h = dlopen("linux-vdso.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
  if (h == nullptr) {
    return nullptr;
  }

  auto func = Getcpu::Func(dlsym(h, "__vdso_getcpu"));
  if (func == nullptr) {
    // technically a null result could either be a failure or a successful
    // lookup of a symbol with the null value, but the second can't actually
    // happen for this symbol.  No point holding the handle forever if
    // we don't need the code
    dlclose(h);
  }

  return func;
#endif
}

Getcpu::Func Getcpu::vdsoFunc() {
  static Func func = loadVdsoGetcpu();
  return func;
}

#ifdef FOLLY_TLS
/////////////// SequentialThreadId

template<>
std::atomic<size_t> SequentialThreadId<std::atomic>::prevId(0);

template<>
FOLLY_TLS size_t SequentialThreadId<std::atomic>::currentId(0);
#endif

/////////////// AccessSpreader

template<>
const AccessSpreader<std::atomic>
AccessSpreader<std::atomic>::stripeByCore(
    CacheLocality::system<>().numCachesByLevel.front());

template<>
const AccessSpreader<std::atomic>
AccessSpreader<std::atomic>::stripeByChip(
    CacheLocality::system<>().numCachesByLevel.back());

template<>
AccessSpreaderArray<std::atomic,128>
AccessSpreaderArray<std::atomic,128>::sharedInstance = {};

/// Always claims to be on CPU zero, node zero
static int degenerateGetcpu(unsigned* cpu, unsigned* node, void* /* unused */) {
  if (cpu != nullptr) {
    *cpu = 0;
  }
  if (node != nullptr) {
    *node = 0;
  }
  return 0;
}

template<>
Getcpu::Func AccessSpreader<std::atomic>::pickGetcpuFunc(size_t numStripes) {
  if (numStripes == 1) {
    // there's no need to call getcpu if there is only one stripe.
    // This should not be common, so we don't want to waste a test and
    // branch in the main code path, but we might as well use a faster
    // function pointer
    return &degenerateGetcpu;
  } else {
    auto best = Getcpu::vdsoFunc();
    return best ? best : &FallbackGetcpuType::getcpu;
  }
}

} } // namespace folly::detail
<commit_msg>Make folly/future portable on android<commit_after>/*
 * Copyright 2015 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <folly/detail/CacheLocality.h>

#ifndef _MSC_VER
#define _GNU_SOURCE 1 // for RTLD_NOLOAD
#include <dlfcn.h>
#endif
#include <fstream>

#include <folly/Conv.h>
#include <folly/Exception.h>
#include <folly/FileUtil.h>
#include <folly/Format.h>
#include <folly/ScopeGuard.h>

namespace folly { namespace detail {

///////////// CacheLocality

/// Returns the best real CacheLocality information available
static CacheLocality getSystemLocalityInfo() {
#ifdef __linux__
  try {
    return CacheLocality::readFromSysfs();
  } catch (...) {
    // keep trying
  }
#endif

  long numCpus = sysconf(_SC_NPROCESSORS_CONF);
  if (numCpus <= 0) {
    // This shouldn't happen, but if it does we should try to keep
    // going.  We are probably not going to be able to parse /sys on
    // this box either (although we will try), which means we are going
    // to fall back to the SequentialThreadId splitter.  On my 16 core
    // (x hyperthreading) dev box 16 stripes is enough to get pretty good
    // contention avoidance with SequentialThreadId, and there is little
    // improvement from going from 32 to 64.  This default gives us some
    // wiggle room
    numCpus = 32;
  }
  return CacheLocality::uniform(numCpus);
}

template <>
const CacheLocality& CacheLocality::system<std::atomic>() {
  static CacheLocality cache(getSystemLocalityInfo());
  return cache;
}

// Each level of cache has sharing sets, which are the set of cpus
// that share a common cache at that level.  These are available in a
// hex bitset form (/sys/devices/system/cpu/cpu0/index0/shared_cpu_map,
// for example).  They are also available in a human-readable list form,
// as in /sys/devices/system/cpu/cpu0/index0/shared_cpu_list.  The list
// is a comma-separated list of numbers and ranges, where the ranges are
// a pair of decimal numbers separated by a '-'.
//
// To sort the cpus for optimum locality we don't really need to parse
// the sharing sets, we just need a unique representative from the
// equivalence class.  The smallest value works fine, and happens to be
// the first decimal number in the file.  We load all of the equivalence
// class information from all of the cpu*/index* directories, order the
// cpus first by increasing last-level cache equivalence class, then by
// the smaller caches.  Finally, we break ties with the cpu number itself.

/// Returns the first decimal number in the string, or throws an exception
/// if the string does not start with a number terminated by ',', '-',
/// '\n', or eos.
static size_t parseLeadingNumber(const std::string& line) {
  auto raw = line.c_str();
  char *end;
  unsigned long val = strtoul(raw, &end, 10);
  if (end == raw || (*end != ',' && *end != '-' && *end != '\n' && *end != 0)) {
    throw std::runtime_error(to<std::string>(
        "error parsing list '", line, "'").c_str());
  }
  return val;
}

CacheLocality CacheLocality::readFromSysfsTree(
    const std::function<std::string(std::string)>& mapping) {
  // number of equivalence classes per level
  std::vector<size_t> numCachesByLevel;

  // the list of cache equivalence classes, where equivalance classes
  // are named by the smallest cpu in the class
  std::vector<std::vector<size_t>> equivClassesByCpu;

  std::vector<size_t> cpus;

  while (true) {
    auto cpu = cpus.size();
    std::vector<size_t> levels;
    for (size_t index = 0; ; ++index) {
      auto dir = format("/sys/devices/system/cpu/cpu{}/cache/index{}/",
                        cpu, index).str();
      auto cacheType = mapping(dir + "type");
      auto equivStr = mapping(dir + "shared_cpu_list");
      if (cacheType.size() == 0 || equivStr.size() == 0) {
        // no more caches
        break;
      }
      if (cacheType[0] == 'I') {
        // cacheType in { "Data", "Instruction", "Unified" }. skip icache
        continue;
      }
      auto equiv = parseLeadingNumber(equivStr);
      auto level = levels.size();
      levels.push_back(equiv);

      if (equiv == cpu) {
        // we only want to count the equiv classes once, so we do it when
        // we first encounter them
        while (numCachesByLevel.size() <= level) {
          numCachesByLevel.push_back(0);
        }
        numCachesByLevel[level]++;
      }
    }

    if (levels.size() == 0) {
      // no levels at all for this cpu, we must be done
      break;
    }
    equivClassesByCpu.emplace_back(std::move(levels));
    cpus.push_back(cpu);
  }

  if (cpus.size() == 0) {
    throw std::runtime_error("unable to load cache sharing info");
  }

  std::sort(cpus.begin(), cpus.end(), [&](size_t lhs, size_t rhs) -> bool {
    // sort first by equiv class of cache with highest index, direction
    // doesn't matter.  If different cpus have different numbers of
    // caches then this code might produce a sub-optimal ordering, but
    // it won't crash
    auto& lhsEquiv = equivClassesByCpu[lhs];
    auto& rhsEquiv = equivClassesByCpu[rhs];
    for (int i = std::min(lhsEquiv.size(), rhsEquiv.size()) - 1; i >= 0; --i) {
      if (lhsEquiv[i] != rhsEquiv[i]) {
        return lhsEquiv[i] < rhsEquiv[i];
      }
    }

    // break ties deterministically by cpu
    return lhs < rhs;
  });

  // the cpus are now sorted by locality, with neighboring entries closer
  // to each other than entries that are far away.  For striping we want
  // the inverse map, since we are starting with the cpu
  std::vector<size_t> indexes(cpus.size());
  for (size_t i = 0; i < cpus.size(); ++i) {
    indexes[cpus[i]] = i;
  }

  return CacheLocality{
      cpus.size(), std::move(numCachesByLevel), std::move(indexes) };
}

CacheLocality CacheLocality::readFromSysfs() {
  return readFromSysfsTree([](std::string name) {
    std::ifstream xi(name.c_str());
    std::string rv;
    std::getline(xi, rv);
    return rv;
  });
}

CacheLocality CacheLocality::uniform(size_t numCpus) {
  CacheLocality rv;

  rv.numCpus = numCpus;

  // one cache shared by all cpus
  rv.numCachesByLevel.push_back(numCpus);

  // no permutations in locality index mapping
  for (size_t cpu = 0; cpu < numCpus; ++cpu) {
    rv.localityIndexByCpu.push_back(cpu);
  }

  return rv;
}

////////////// Getcpu

/// Resolves the dynamically loaded symbol __vdso_getcpu, returning null
/// on failure
static Getcpu::Func loadVdsoGetcpu() {
#if defined(_MSC_VER) || defined(__BIONIC__)
  return nullptr;
#else
  void* h = dlopen("linux-vdso.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
  if (h == nullptr) {
    return nullptr;
  }

  auto func = Getcpu::Func(dlsym(h, "__vdso_getcpu"));
  if (func == nullptr) {
    // technically a null result could either be a failure or a successful
    // lookup of a symbol with the null value, but the second can't actually
    // happen for this symbol.  No point holding the handle forever if
    // we don't need the code
    dlclose(h);
  }

  return func;
#endif
}

Getcpu::Func Getcpu::vdsoFunc() {
  static Func func = loadVdsoGetcpu();
  return func;
}

#ifdef FOLLY_TLS
/////////////// SequentialThreadId

template<>
std::atomic<size_t> SequentialThreadId<std::atomic>::prevId(0);

template<>
FOLLY_TLS size_t SequentialThreadId<std::atomic>::currentId(0);
#endif

/////////////// AccessSpreader

template<>
const AccessSpreader<std::atomic>
AccessSpreader<std::atomic>::stripeByCore(
    CacheLocality::system<>().numCachesByLevel.front());

template<>
const AccessSpreader<std::atomic>
AccessSpreader<std::atomic>::stripeByChip(
    CacheLocality::system<>().numCachesByLevel.back());

template<>
AccessSpreaderArray<std::atomic,128>
AccessSpreaderArray<std::atomic,128>::sharedInstance = {};

/// Always claims to be on CPU zero, node zero
static int degenerateGetcpu(unsigned* cpu, unsigned* node, void* /* unused */) {
  if (cpu != nullptr) {
    *cpu = 0;
  }
  if (node != nullptr) {
    *node = 0;
  }
  return 0;
}

template<>
Getcpu::Func AccessSpreader<std::atomic>::pickGetcpuFunc(size_t numStripes) {
  if (numStripes == 1) {
    // there's no need to call getcpu if there is only one stripe.
    // This should not be common, so we don't want to waste a test and
    // branch in the main code path, but we might as well use a faster
    // function pointer
    return &degenerateGetcpu;
  } else {
    auto best = Getcpu::vdsoFunc();
    return best ? best : &FallbackGetcpuType::getcpu;
  }
}

} } // namespace folly::detail
<|endoftext|>


<commit_before>
#include <iostream>

#include <allegro/system.h>
#include <allegro/color.h>
#include <allegro/target.h>
#include <allegro/display.h>
#include <allegro/keyboard.h>
#include <allegro/timer.h>
#include <allegro/event.h>
#include <allegro/event_queue.h>

#include <gui/container.h>
#include <gui/form_layout.h>
#include <gui/box_layout.h>
#include <gui/grid_layout.h>
#include <gui/tree_layout.h>

namespace {

////////////////////////////////////////

std::shared_ptr<layout> test_box( std::shared_ptr<container> c )
{
	auto l =  std::make_shared<box_layout>( c, direction::DOWN );
	for ( size_t i = 0; i < 5; ++i )
	{
		auto a = l->new_area( i == 2 ? 1.0 : 0.0 );
		a->set_minimum( 100, 24 );
	}
	return l;
}

////////////////////////////////////////

std::shared_ptr<layout> test_tree( std::shared_ptr<container> c )
{
	auto l = std::make_shared<tree_layout>( c, 24.0 );
	for ( size_t i = 0; i < 2; ++i )
	{
		auto a = l->new_area( 0.0 );
		a->set_minimum( 100, 24 );
	}
	auto b1 = l->new_branch();
	for ( size_t i = 0; i < 2; ++i )
	{
		auto a = b1->new_area();
		a->set_minimum( 100, 24 );
	}
	for ( size_t i = 0; i < 2; ++i )
	{
		auto a = l->new_area( 0.0 );
		a->set_minimum( 100, 24 );
	}
	l->new_area( 1.0 );

	return l;
}

////////////////////////////////////////

std::shared_ptr<layout> test_form( std::shared_ptr<container> c )
{
	std::shared_ptr<area> a, b;

	auto l = std::make_shared<form_layout>( c );

	for ( size_t i = 0; i < 5; ++i )
	{
		std::tie( a, b ) = l->new_row();
		a->set_minimum( 100, 24 );
		b->set_minimum( 100, 24 );
	}

	return l;
}

////////////////////////////////////////

std::shared_ptr<layout> test_grid( std::shared_ptr<container> c )
{
	auto l = std::make_shared<grid_layout>( c );

	for ( size_t i = 0; i < 5; ++i )
		auto tmp = l->new_column( i == 2 ? 1.0 : 0.0 );

	for ( size_t i = 0; i < 5; ++i )
	{
		auto tmp = l->new_row( i == 2 ? 1.0 : 0.0 );
		for ( auto a: tmp )
			a->set_minimum( 50, 24 );
	}

	return l;
}

////////////////////////////////////////

int safemain( int argc, char **argv )
{
	allegro::system sys;
	al_set_new_display_flags( ALLEGRO_WINDOWED | ALLEGRO_RESIZABLE );

	allegro::event_queue queue;

	allegro::display win( 640, 480 );
	win.set_title( "Hello World" );
	queue.add_source( win );

	allegro::keyboard keyb;
	queue.add_source( keyb );

	allegro::timer timer( 0.1 );
	queue.add_source( timer );

	allegro::color black( 0, 0, 0 );
	allegro::color white( 255, 255, 255 );

	std::shared_ptr<container> c = std::make_shared<container>();

	auto layout = test_grid( c );

	auto recompute_layout = [&] ( double w, double h ) {
		c->bounds()->set_horizontal( 0, w );
		c->bounds()->set_vertical( 0, h );

		layout->recompute_minimum();
		layout->recompute_layout();
	};

	recompute_layout( 640, 480 );

	timer.start();
	bool done = false;
	do
	{
		allegro::event ev;
		queue.wait( ev );
		switch ( ev.type() )
		{
			case allegro::EVENT_KEY_DOWN:
			case allegro::EVENT_DISPLAY_CLOSE:
				done = true;
				break;

			case allegro::EVENT_DISPLAY_RESIZE:
				recompute_layout( ev.width(), ev.height() );
				ev.acknowledge_resize();
				break;

			case allegro::EVENT_TIMER:
			{
				allegro::target t( win );
				t.clear( white );
				for ( auto a: *c )
					t.draw_rect( a->x1() + 0.5, a->y1() + 0.5, a->x2() - 0.5, a->y2() - 0.5, black, 1.F );
				t.flip();
				break;
			}

			default:
				break;
		}
	} while ( !done );

	return 0;
}
}

////////////////////////////////////////

int main( int argc, char *argv[] )
{
	int ret = -1;
	try
	{
		ret = safemain( argc, argv );
	}
	catch ( std::exception &e )
	{
		print_exception( std::cerr, e );
	}
	return ret;
}

////////////////////////////////////////

<commit_msg>Added multiple test without recompiling.<commit_after>
#include <iostream>
#include <map>
#include <functional>

#include <allegro/system.h>
#include <allegro/color.h>
#include <allegro/target.h>
#include <allegro/display.h>
#include <allegro/keyboard.h>
#include <allegro/timer.h>
#include <allegro/event.h>
#include <allegro/event_queue.h>

#include <gui/container.h>
#include <gui/form_layout.h>
#include <gui/box_layout.h>
#include <gui/grid_layout.h>
#include <gui/tree_layout.h>

namespace {

////////////////////////////////////////

std::shared_ptr<layout> test_box( std::shared_ptr<container> c )
{
	auto l =  std::make_shared<box_layout>( c, direction::DOWN );
	for ( size_t i = 0; i < 5; ++i )
	{
		auto a = l->new_area( i == 2 ? 1.0 : 0.0 );
		a->set_minimum( 100, 24 );
	}
	return l;
}

////////////////////////////////////////

std::shared_ptr<layout> test_tree( std::shared_ptr<container> c )
{
	auto l = std::make_shared<tree_layout>( c, 24.0 );
	for ( size_t i = 0; i < 2; ++i )
	{
		auto a = l->new_area( 0.0 );
		a->set_minimum( 100, 24 );
	}
	auto b1 = l->new_branch();
	for ( size_t i = 0; i < 2; ++i )
	{
		auto a = b1->new_area();
		a->set_minimum( 100, 24 );
	}
	for ( size_t i = 0; i < 2; ++i )
	{
		auto a = l->new_area( 0.0 );
		a->set_minimum( 100, 24 );
	}
	l->new_area( 1.0 );

	return l;
}

////////////////////////////////////////

std::shared_ptr<layout> test_form( std::shared_ptr<container> c )
{
	std::shared_ptr<area> a, b;

	auto l = std::make_shared<form_layout>( c );

	for ( size_t i = 0; i < 5; ++i )
	{
		std::tie( a, b ) = l->new_row();
		a->set_minimum( 100, 24 );
		b->set_minimum( 100, 24 );
	}

	return l;
}

////////////////////////////////////////

std::shared_ptr<layout> test_grid( std::shared_ptr<container> c )
{
	auto l = std::make_shared<grid_layout>( c );

	for ( size_t i = 0; i < 5; ++i )
		auto tmp = l->new_column( i == 2 ? 1.0 : 0.0 );

	for ( size_t i = 0; i < 5; ++i )
	{
		auto tmp = l->new_row( i == 2 ? 1.0 : 0.0 );
		for ( auto a: tmp )
			a->set_minimum( 50, 24 );
	}

	return l;
}

////////////////////////////////////////

std::map<std::string,std::function<std::shared_ptr<layout>(std::shared_ptr<container>)>> tests =
{
	{ "grid", test_grid },
	{ "box", test_box },
	{ "form", test_form },
	{ "tree", test_tree },
};

////////////////////////////////////////

int safemain( int argc, char **argv )
{
	precondition( argc > 1, "expected argument" );

	allegro::system sys;
	al_set_new_display_flags( ALLEGRO_WINDOWED | ALLEGRO_RESIZABLE );

	allegro::event_queue queue;

	allegro::display win( 640, 480 );
	win.set_title( "Hello World" );
	queue.add_source( win );

	allegro::keyboard keyb;
	queue.add_source( keyb );

	allegro::timer timer( 0.1 );
	queue.add_source( timer );

	allegro::color black( 0, 0, 0 );
	allegro::color white( 255, 255, 255 );

	std::shared_ptr<container> c = std::make_shared<container>();

	auto layout = tests[argv[1]]( c );

	auto recompute_layout = [&] ( double w, double h ) {
		c->bounds()->set_horizontal( 0, w );
		c->bounds()->set_vertical( 0, h );

		layout->recompute_minimum();
		layout->recompute_layout();
	};

	recompute_layout( 640, 480 );

	timer.start();
	bool done = false;
	do
	{
		allegro::event ev;
		queue.wait( ev );
		switch ( ev.type() )
		{
			case allegro::EVENT_KEY_DOWN:
			case allegro::EVENT_DISPLAY_CLOSE:
				done = true;
				break;

			case allegro::EVENT_DISPLAY_RESIZE:
				recompute_layout( ev.width(), ev.height() );
				ev.acknowledge_resize();
				break;

			case allegro::EVENT_TIMER:
			{
				allegro::target t( win );
				t.clear( white );
				for ( auto a: *c )
					t.draw_rect( a->x1() + 0.5, a->y1() + 0.5, a->x2() - 0.5, a->y2() - 0.5, black, 1.F );
				t.flip();
				break;
			}

			default:
				break;
		}
	} while ( !done );

	return 0;
}
}

////////////////////////////////////////

int main( int argc, char *argv[] )
{
	int ret = -1;
	try
	{
		ret = safemain( argc, argv );
	}
	catch ( std::exception &e )
	{
		print_exception( std::cerr, e );
	}
	return ret;
}

////////////////////////////////////////

<|endoftext|>


<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "MooseMesh.h"
#include "Factory.h"
#include "MeshModifier.h"
#include "GatherNearbyElements.h"

// libMesh
#include "boundary_info.h"
#include "mesh_tools.h"
#include "mesh_refinement.h"
#include "parallel.h"
#include "mesh_communication.h"
#include "parallel_mesh.h"

static const int GRAIN_SIZE = 1;     // the grain_size does not have much influence on our execution speed

MooseMesh::MooseMesh(int mesh_dim) :
    _mesh(mesh_dim),
    _is_changed(false),
    //_is_parallel(false),
    _active_local_elem_range(NULL),
    _active_semilocal_node_range(NULL),
    _active_node_range(NULL),
    _local_node_range(NULL),
    _bnd_node_range(NULL),
    _patch_size(40)
{
}

MooseMesh::MooseMesh(const MooseMesh & other_mesh) :
    _mesh(other_mesh._mesh),
    _is_changed(false),
    //_is_parallel(false),
    _active_local_elem_range(NULL),
    _active_semilocal_node_range(NULL),
    _active_node_range(NULL),
    _local_node_range(NULL),
    _bnd_node_range(NULL),
    _patch_size(40)
{
  (*_mesh.boundary_info) = (*other_mesh._mesh.boundary_info);
}

MooseMesh::~MooseMesh()
{
  freeBndNodes();

  delete _active_local_elem_range;
  delete _active_node_range;
  delete _active_semilocal_node_range;
  delete _local_node_range;
  delete _bnd_node_range;
}

void
MooseMesh::freeBndNodes()
{
  // free memory
  for (std::vector<BndNode *>::iterator it = _bnd_nodes.begin(); it != _bnd_nodes.end(); ++it)
    delete (*it);

  for (std::map<short int, std::vector<unsigned int> >::iterator it = _node_set_nodes.begin(); it != _node_set_nodes.end(); ++it)
    it->second.clear();
  _node_set_nodes.clear();
}

void
MooseMesh::read(const std::string file_name)
{
  _mesh.read(file_name);
}

void
MooseMesh::prepare()
{
  // This is now done in Nemesis_IO::read()
  // If we are using a truly Parallel mesh (like Nemesis) then we might not even have neighbors!
//  if(parallel())
//    MeshCommunication().gather_neighboring_elements(libmesh_cast_ref<ParallelMesh&>(getMesh()));
//
  _mesh.prepare_for_use(false);

  // If using ParallelMesh this will delete non-local elements from the current processor
  // If using SerialMesh, this function is a no-op.
  _mesh.delete_remote_elements();

  if(!_mesh.is_serial())
    Moose::gatherNearbyElements(*this, _ghosted_boundaries, _ghosted_boundaries_inflation);

  // Collect (local) subdomain IDs
  const MeshBase::element_iterator el_end = _mesh.elements_end();
/*
  unsigned int num_elems = 0;
  for (MeshBase::element_iterator el = _mesh.elements_begin(); el != el_end; ++el)
    num_elems++;

//  std::cerr<<libMesh::processor_id()<<": num_elems: "<<num_elems<<std::endl;

  Parallel::sum(num_elems);

  std::cout<<"Total elems: "<<num_elems<<std::endl;
*/

  for (MeshBase::element_iterator el = _mesh.elements_begin(); el != el_end; ++el)
    _mesh_subdomains.insert((*el)->subdomain_id());

  // Collect (local) boundary IDs
  const std::set<short>& local_bids = _mesh.boundary_info->get_boundary_ids();
  _mesh_boundary_ids.insert(local_bids.begin(), local_bids.end());

  // Communicate subdomain and boundary IDs if this is a parallel mesh
  if (!_mesh.is_serial())
    {
      // Subdomain size before
      // std::cout << "(before) _mesh_subdomains.size()=" << _mesh_subdomains.size() << std::endl;

      // Pack our subdomain IDs into a vector
      std::vector<subdomain_id_type> mesh_subdomains_vector(_mesh_subdomains.begin(),
							    _mesh_subdomains.end());

      // Gather them all into an enlarged vector
      Parallel::allgather(mesh_subdomains_vector);

      // Attempt to insert any new IDs into the set (any existing ones will be skipped)
      _mesh_subdomains.insert(mesh_subdomains_vector.begin(),
			      mesh_subdomains_vector.end());

      // Subdomain size after
      // std::cout << "(after) _mesh_subdomains.size()=" << _mesh_subdomains.size() << std::endl;

      // Boundary ID size before
      // std::cout << "(before) _mesh_boundary_ids.size()=" << _mesh_boundary_ids.size() << std::endl;

      // Pack our boundary IDs into a vector for communication
      std::vector<short> mesh_boundary_ids_vector(_mesh_boundary_ids.begin(),
						  _mesh_boundary_ids.end());

      // Gather them all into an enlarged vector
      Parallel::allgather(mesh_boundary_ids_vector);

      // Attempt to insert any new IDs into the set (any existing ones will be skipped)
      _mesh_boundary_ids.insert(mesh_boundary_ids_vector.begin(),
				mesh_boundary_ids_vector.end());

      // Boundary ID size after
      // std::cout << "(after) _mesh_boundary_ids.size()=" << _mesh_boundary_ids.size() << std::endl;
    }

  update();
}

void
MooseMesh::update()
{
  // Rebuild the boundary conditions
  build_node_list_from_side_list();
  //Update the node to elem map
  _node_to_elem_map.clear();
  MeshTools::build_nodes_to_elem_map(_mesh, _node_to_elem_map);
  buildNodeList();
  cacheInfo();
}

#ifdef LIBMESH_ENABLE_AMR
void
MooseMesh::uniformlyRefine(int level)
{
  MeshRefinement mesh_refinement(_mesh);
  mesh_refinement.uniformly_refine(level);
}
#endif //LIBMESH_ENABLE_AMR

void
MooseMesh::meshChanged()
{
  update();

  // Rebuild the active local element range
  delete _active_local_elem_range;
  _active_local_elem_range = NULL;
  // Rebuild the node range
  delete _active_node_range;
  _active_node_range = NULL;
  // Rebuild the semilocal range
  delete _active_semilocal_node_range;
  _active_semilocal_node_range = NULL;
  // Rebuild the local node range
  delete _local_node_range;
  _local_node_range = NULL;
  // Rebuild the boundary node range
  delete _bnd_node_range;
  _bnd_node_range = NULL;

  // Rebuild the ranges
  getActiveLocalElementRange();
  getActiveNodeRange();
  getLocalNodeRange();
  getBoundaryNodeRange();

  // Print out information about the adapted mesh if requested
//  if (_print_mesh_changed)
//  {
//    std::cout << "\nMesh Changed:\n";
//    _mesh->print_info();
//  }

  // Lets the output system know that the mesh has changed recently.
  _is_changed = true;
}

void
MooseMesh::updateActiveSemiLocalNodeRange(std::set<unsigned int> & ghosted_elems)
{
  _semilocal_node_list.clear();

  // First add the nodes connected to local elems
  ConstElemRange * active_local_elems = getActiveLocalElementRange();
  for(ConstElemRange::const_iterator it=active_local_elems->begin();
      it!=active_local_elems->end();
      ++it)
  {
    const Elem * elem = *it;
    for(unsigned int n=0; n<elem->n_nodes(); n++)
    {
      Node * node = elem->get_node(n);

      _semilocal_node_list.insert(node);
    }
  }

  // Now add the nodes connected to ghosted_elems
  for(std::set<unsigned int>::iterator it=ghosted_elems.begin();
      it!=ghosted_elems.end();
      ++it)
  {
    Elem * elem = _mesh.elem(*it);
    for(unsigned int n=0; n<elem->n_nodes(); n++)
    {
      Node * node = elem->get_node(n);

      _semilocal_node_list.insert(node);
    }
  }

  delete _active_semilocal_node_range;

  // Now create the actual range
  _active_semilocal_node_range = new SemiLocalNodeRange(_semilocal_node_list.begin(), _semilocal_node_list.end());
}

void
MooseMesh::buildNodeList()
{
  freeBndNodes();

  /// Boundary node list (node ids and corresponding side-set ids, arrays always have the same length)
  std::vector<unsigned int> nodes;
  std::vector<short int> ids;
  _mesh.boundary_info->build_node_list(nodes, ids);

  int n = nodes.size();
  _bnd_nodes.resize(n);
  for (int i = 0; i < n; i++)
  {
    _bnd_nodes[i] = new BndNode(&_mesh.node(nodes[i]), ids[i]);
    _node_set_nodes[ids[i]].push_back(nodes[i]);
  }
}

ConstElemRange *
MooseMesh::getActiveLocalElementRange()
{
  if (!_active_local_elem_range)
  {
    _active_local_elem_range = new ConstElemRange(_mesh.active_local_elements_begin(),
                                                  _mesh.active_local_elements_end(), GRAIN_SIZE);
  }

  return _active_local_elem_range;
}

NodeRange *
MooseMesh::getActiveNodeRange()
{
  if (!_active_node_range)
  {
    _active_node_range = new NodeRange(_mesh.active_nodes_begin(),
                                       _mesh.active_nodes_end(), GRAIN_SIZE);
  }

  return _active_node_range;
}

SemiLocalNodeRange *
MooseMesh::getActiveSemiLocalNodeRange()
{
  mooseAssert(_active_semilocal_node_range, "_active_semilocal_node_range has not been created yet!");
/*
  if (!_active_node_range)
  {
    _active_semilocal_node_range = new NodeRange(_mesh.local_nodes_begin(),
                                                 _mesh.local_nodes_end(), GRAIN_SIZE);
  }
 */

  return _active_semilocal_node_range;
}

ConstNodeRange *
MooseMesh::getLocalNodeRange()
{
  if (!_local_node_range)
  {
    _local_node_range = new ConstNodeRange(_mesh.local_nodes_begin(),
                                           _mesh.local_nodes_end(), GRAIN_SIZE);
  }

  return _local_node_range;
}

ConstBndNodeRange *
MooseMesh::getBoundaryNodeRange()
{
  if (!_bnd_node_range)
  {
    _bnd_node_range = new ConstBndNodeRange(bnd_nodes_begin(),
                                            bnd_nodes_end(), GRAIN_SIZE);
  }

  return _bnd_node_range;
}

// MooseMesh Modifiers /////
void
MooseMesh::addMeshModifer(const std::string & mod_name, const std::string & name, InputParameters parameters)
{
  _mesh_modifiers.push_back(static_cast<MeshModifier *>(Factory::instance()->create(mod_name, name, parameters)));
}

void
MooseMesh::applyMeshModifications()
{
  for (std::vector<MeshModifier *>::iterator i = _mesh_modifiers.begin(); i != _mesh_modifiers.end(); ++i)
    (*i)->modifyMesh(_mesh);
}

void
MooseMesh::cacheInfo()
{
  for (MeshBase::element_iterator el = _mesh.local_elements_begin(); el != _mesh.local_elements_end(); ++el)
  {
    Elem * elem = *el;
    for(unsigned int nd = 0; nd < elem->n_nodes(); ++nd)
    {
      Node & node = *elem->get_node(nd);
      _block_node_list[node.id()].insert(elem->subdomain_id());
    }
  }
}

std::set<subdomain_id_type> &
MooseMesh::getNodeBlockIds(const Node & node)
{
  return _block_node_list[node.id()];
}

// default begin() accessor
bnd_node_iterator
MooseMesh::bnd_nodes_begin ()
{
  Predicates::NotNull<bnd_node_iterator_imp> p;
  return bnd_node_iterator(_bnd_nodes.begin(), _bnd_nodes.end(), p);
}

// default end() accessor
bnd_node_iterator
MooseMesh::bnd_nodes_end ()
{
  Predicates::NotNull<bnd_node_iterator_imp> p;
  return bnd_node_iterator(_bnd_nodes.end(), _bnd_nodes.end(), p);
}
<commit_msg>Clean-up (this is done in Adaptivity class) (#000)<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "MooseMesh.h"
#include "Factory.h"
#include "MeshModifier.h"
#include "GatherNearbyElements.h"

// libMesh
#include "boundary_info.h"
#include "mesh_tools.h"
#include "mesh_refinement.h"
#include "parallel.h"
#include "mesh_communication.h"
#include "parallel_mesh.h"

static const int GRAIN_SIZE = 1;     // the grain_size does not have much influence on our execution speed

MooseMesh::MooseMesh(int mesh_dim) :
    _mesh(mesh_dim),
    _is_changed(false),
    //_is_parallel(false),
    _active_local_elem_range(NULL),
    _active_semilocal_node_range(NULL),
    _active_node_range(NULL),
    _local_node_range(NULL),
    _bnd_node_range(NULL),
    _patch_size(40)
{
}

MooseMesh::MooseMesh(const MooseMesh & other_mesh) :
    _mesh(other_mesh._mesh),
    _is_changed(false),
    //_is_parallel(false),
    _active_local_elem_range(NULL),
    _active_semilocal_node_range(NULL),
    _active_node_range(NULL),
    _local_node_range(NULL),
    _bnd_node_range(NULL),
    _patch_size(40)
{
  (*_mesh.boundary_info) = (*other_mesh._mesh.boundary_info);
}

MooseMesh::~MooseMesh()
{
  freeBndNodes();

  delete _active_local_elem_range;
  delete _active_node_range;
  delete _active_semilocal_node_range;
  delete _local_node_range;
  delete _bnd_node_range;
}

void
MooseMesh::freeBndNodes()
{
  // free memory
  for (std::vector<BndNode *>::iterator it = _bnd_nodes.begin(); it != _bnd_nodes.end(); ++it)
    delete (*it);

  for (std::map<short int, std::vector<unsigned int> >::iterator it = _node_set_nodes.begin(); it != _node_set_nodes.end(); ++it)
    it->second.clear();
  _node_set_nodes.clear();
}

void
MooseMesh::read(const std::string file_name)
{
  _mesh.read(file_name);
}

void
MooseMesh::prepare()
{
  // This is now done in Nemesis_IO::read()
  // If we are using a truly Parallel mesh (like Nemesis) then we might not even have neighbors!
//  if(parallel())
//    MeshCommunication().gather_neighboring_elements(libmesh_cast_ref<ParallelMesh&>(getMesh()));
//
  _mesh.prepare_for_use(false);

  // If using ParallelMesh this will delete non-local elements from the current processor
  // If using SerialMesh, this function is a no-op.
  _mesh.delete_remote_elements();

  if(!_mesh.is_serial())
    Moose::gatherNearbyElements(*this, _ghosted_boundaries, _ghosted_boundaries_inflation);

  // Collect (local) subdomain IDs
  const MeshBase::element_iterator el_end = _mesh.elements_end();
/*
  unsigned int num_elems = 0;
  for (MeshBase::element_iterator el = _mesh.elements_begin(); el != el_end; ++el)
    num_elems++;

//  std::cerr<<libMesh::processor_id()<<": num_elems: "<<num_elems<<std::endl;

  Parallel::sum(num_elems);

  std::cout<<"Total elems: "<<num_elems<<std::endl;
*/

  for (MeshBase::element_iterator el = _mesh.elements_begin(); el != el_end; ++el)
    _mesh_subdomains.insert((*el)->subdomain_id());

  // Collect (local) boundary IDs
  const std::set<short>& local_bids = _mesh.boundary_info->get_boundary_ids();
  _mesh_boundary_ids.insert(local_bids.begin(), local_bids.end());

  // Communicate subdomain and boundary IDs if this is a parallel mesh
  if (!_mesh.is_serial())
    {
      // Subdomain size before
      // std::cout << "(before) _mesh_subdomains.size()=" << _mesh_subdomains.size() << std::endl;

      // Pack our subdomain IDs into a vector
      std::vector<subdomain_id_type> mesh_subdomains_vector(_mesh_subdomains.begin(),
							    _mesh_subdomains.end());

      // Gather them all into an enlarged vector
      Parallel::allgather(mesh_subdomains_vector);

      // Attempt to insert any new IDs into the set (any existing ones will be skipped)
      _mesh_subdomains.insert(mesh_subdomains_vector.begin(),
			      mesh_subdomains_vector.end());

      // Subdomain size after
      // std::cout << "(after) _mesh_subdomains.size()=" << _mesh_subdomains.size() << std::endl;

      // Boundary ID size before
      // std::cout << "(before) _mesh_boundary_ids.size()=" << _mesh_boundary_ids.size() << std::endl;

      // Pack our boundary IDs into a vector for communication
      std::vector<short> mesh_boundary_ids_vector(_mesh_boundary_ids.begin(),
						  _mesh_boundary_ids.end());

      // Gather them all into an enlarged vector
      Parallel::allgather(mesh_boundary_ids_vector);

      // Attempt to insert any new IDs into the set (any existing ones will be skipped)
      _mesh_boundary_ids.insert(mesh_boundary_ids_vector.begin(),
				mesh_boundary_ids_vector.end());

      // Boundary ID size after
      // std::cout << "(after) _mesh_boundary_ids.size()=" << _mesh_boundary_ids.size() << std::endl;
    }

  update();
}

void
MooseMesh::update()
{
  // Rebuild the boundary conditions
  build_node_list_from_side_list();
  //Update the node to elem map
  _node_to_elem_map.clear();
  MeshTools::build_nodes_to_elem_map(_mesh, _node_to_elem_map);
  buildNodeList();
  cacheInfo();
}

#ifdef LIBMESH_ENABLE_AMR
void
MooseMesh::uniformlyRefine(int level)
{
  MeshRefinement mesh_refinement(_mesh);
  mesh_refinement.uniformly_refine(level);
}
#endif //LIBMESH_ENABLE_AMR

void
MooseMesh::meshChanged()
{
  update();

  // Rebuild the active local element range
  delete _active_local_elem_range;
  _active_local_elem_range = NULL;
  // Rebuild the node range
  delete _active_node_range;
  _active_node_range = NULL;
  // Rebuild the semilocal range
  delete _active_semilocal_node_range;
  _active_semilocal_node_range = NULL;
  // Rebuild the local node range
  delete _local_node_range;
  _local_node_range = NULL;
  // Rebuild the boundary node range
  delete _bnd_node_range;
  _bnd_node_range = NULL;

  // Rebuild the ranges
  getActiveLocalElementRange();
  getActiveNodeRange();
  getLocalNodeRange();
  getBoundaryNodeRange();

  // Lets the output system know that the mesh has changed recently.
  _is_changed = true;
}

void
MooseMesh::updateActiveSemiLocalNodeRange(std::set<unsigned int> & ghosted_elems)
{
  _semilocal_node_list.clear();

  // First add the nodes connected to local elems
  ConstElemRange * active_local_elems = getActiveLocalElementRange();
  for(ConstElemRange::const_iterator it=active_local_elems->begin();
      it!=active_local_elems->end();
      ++it)
  {
    const Elem * elem = *it;
    for(unsigned int n=0; n<elem->n_nodes(); n++)
    {
      Node * node = elem->get_node(n);

      _semilocal_node_list.insert(node);
    }
  }

  // Now add the nodes connected to ghosted_elems
  for(std::set<unsigned int>::iterator it=ghosted_elems.begin();
      it!=ghosted_elems.end();
      ++it)
  {
    Elem * elem = _mesh.elem(*it);
    for(unsigned int n=0; n<elem->n_nodes(); n++)
    {
      Node * node = elem->get_node(n);

      _semilocal_node_list.insert(node);
    }
  }

  delete _active_semilocal_node_range;

  // Now create the actual range
  _active_semilocal_node_range = new SemiLocalNodeRange(_semilocal_node_list.begin(), _semilocal_node_list.end());
}

void
MooseMesh::buildNodeList()
{
  freeBndNodes();

  /// Boundary node list (node ids and corresponding side-set ids, arrays always have the same length)
  std::vector<unsigned int> nodes;
  std::vector<short int> ids;
  _mesh.boundary_info->build_node_list(nodes, ids);

  int n = nodes.size();
  _bnd_nodes.resize(n);
  for (int i = 0; i < n; i++)
  {
    _bnd_nodes[i] = new BndNode(&_mesh.node(nodes[i]), ids[i]);
    _node_set_nodes[ids[i]].push_back(nodes[i]);
  }
}

ConstElemRange *
MooseMesh::getActiveLocalElementRange()
{
  if (!_active_local_elem_range)
  {
    _active_local_elem_range = new ConstElemRange(_mesh.active_local_elements_begin(),
                                                  _mesh.active_local_elements_end(), GRAIN_SIZE);
  }

  return _active_local_elem_range;
}

NodeRange *
MooseMesh::getActiveNodeRange()
{
  if (!_active_node_range)
  {
    _active_node_range = new NodeRange(_mesh.active_nodes_begin(),
                                       _mesh.active_nodes_end(), GRAIN_SIZE);
  }

  return _active_node_range;
}

SemiLocalNodeRange *
MooseMesh::getActiveSemiLocalNodeRange()
{
  mooseAssert(_active_semilocal_node_range, "_active_semilocal_node_range has not been created yet!");
/*
  if (!_active_node_range)
  {
    _active_semilocal_node_range = new NodeRange(_mesh.local_nodes_begin(),
                                                 _mesh.local_nodes_end(), GRAIN_SIZE);
  }
 */

  return _active_semilocal_node_range;
}

ConstNodeRange *
MooseMesh::getLocalNodeRange()
{
  if (!_local_node_range)
  {
    _local_node_range = new ConstNodeRange(_mesh.local_nodes_begin(),
                                           _mesh.local_nodes_end(), GRAIN_SIZE);
  }

  return _local_node_range;
}

ConstBndNodeRange *
MooseMesh::getBoundaryNodeRange()
{
  if (!_bnd_node_range)
  {
    _bnd_node_range = new ConstBndNodeRange(bnd_nodes_begin(),
                                            bnd_nodes_end(), GRAIN_SIZE);
  }

  return _bnd_node_range;
}

// MooseMesh Modifiers /////
void
MooseMesh::addMeshModifer(const std::string & mod_name, const std::string & name, InputParameters parameters)
{
  _mesh_modifiers.push_back(static_cast<MeshModifier *>(Factory::instance()->create(mod_name, name, parameters)));
}

void
MooseMesh::applyMeshModifications()
{
  for (std::vector<MeshModifier *>::iterator i = _mesh_modifiers.begin(); i != _mesh_modifiers.end(); ++i)
    (*i)->modifyMesh(_mesh);
}

void
MooseMesh::cacheInfo()
{
  for (MeshBase::element_iterator el = _mesh.local_elements_begin(); el != _mesh.local_elements_end(); ++el)
  {
    Elem * elem = *el;
    for(unsigned int nd = 0; nd < elem->n_nodes(); ++nd)
    {
      Node & node = *elem->get_node(nd);
      _block_node_list[node.id()].insert(elem->subdomain_id());
    }
  }
}

std::set<subdomain_id_type> &
MooseMesh::getNodeBlockIds(const Node & node)
{
  return _block_node_list[node.id()];
}

// default begin() accessor
bnd_node_iterator
MooseMesh::bnd_nodes_begin ()
{
  Predicates::NotNull<bnd_node_iterator_imp> p;
  return bnd_node_iterator(_bnd_nodes.begin(), _bnd_nodes.end(), p);
}

// default end() accessor
bnd_node_iterator
MooseMesh::bnd_nodes_end ()
{
  Predicates::NotNull<bnd_node_iterator_imp> p;
  return bnd_node_iterator(_bnd_nodes.end(), _bnd_nodes.end(), p);
}
<|endoftext|>


<commit_before>#include "cacheline.h"
#include "get.h"
#include "put.h"
#include "ring.h"
#include "sequence.h"

#include <thread>
#include <iostream>

//using namespace L3;

#ifndef L3_ITERATIONS
// 100 Million.
#define L3_ITERATIONS (100000000)
#endif

constexpr size_t iterations {L3_ITERATIONS};

#ifndef L3_QSIZE
#define L3_QSIZE 19 /* 1/2 MB */
#endif

constexpr size_t qSize {L3_QSIZE};

using Msg = size_t;

using Ring = L3::Ring<Msg, qSize>;
L3_CACHE_LINE Ring ring;
using Iterator = Ring::Iterator<ring>;

L3_CACHE_LINE L3::Sequence commitCursor{Ring::size - 1};
L3_CACHE_LINE L3::Sequence writeCursor{Ring::size};
L3_CACHE_LINE L3::Sequence readCursor{Ring::size};

using Get = L3::Get<readCursor, Iterator, L3::SequenceList<commitCursor>>;

using Put = L3::Put<
    writeCursor, commitCursor,
    Iterator,
    L3::SequenceList<readCursor>,
    L3::CommitPolicy::Unique>;

void
dbg()
{
    // std::cout << "Ring::size: " << Ring::size << std::endl;
    // std::cout << "qSize: " << qSize << std::endl;

    std::cout << "commitCursor: " << commitCursor
              << ", writeCursor: " << writeCursor
              << ", readCursor: " << readCursor
              << ", value: " << ring[readCursor]
              << std::endl;
}

bool test1Thread()
{
//    Put()(ring) = 42;
    Put() = 42;
    for(auto& m: Get())
    {
        std::cout << "m: " << m << std::endl;
        if(m != 42)
        {
            return false;
        }
    }
    Put() = 101;
    Put() = 202;
    for(auto& m: Get())
    {
        std::cout << "m: " << m << std::endl;
    }
    return true;
}

bool
test2Threads()
{
    std::thread prod1(
        [](){ for(Msg i = 1; i < iterations; ++i) Put() = i; });

    Msg previous = 0;
    for(Msg i = 1; i < iterations;)
    {
        for(auto& msg: Get())
        {
            i++;
            if(msg != previous + 1)
            {
                std::cout << "previous: " << previous
                          << ", msg: " << msg
                          << std::endl;
                return false;
            }
            previous = msg;
        }
    }
    prod1.join();

    return true;
}

int
main()
{
    bool status = true;
    status &= test1Thread();
    status &= test2Threads();
    return status ? 0 : 1;
}

<commit_msg>Small clean up.<commit_after>#include "cacheline.h"
#include "get.h"
#include "put.h"
#include "ring.h"
#include "sequence.h"

#include <thread>
#include <iostream>

#ifndef L3_ITERATIONS
// 100 Million.
#    define L3_ITERATIONS (100000000)
#endif

constexpr size_t iterations {L3_ITERATIONS};

#ifndef L3_QSIZE
#    define L3_QSIZE 19 /* 1/2 MB */
#endif

using Msg = size_t;
constexpr size_t qSize {L3_QSIZE};
using Ring = L3::Ring<Msg, qSize>;
L3_CACHE_LINE Ring ring;
using Iterator = Ring::Iterator<ring>;

L3_CACHE_LINE L3::Sequence commitCursor{Ring::size - 1};
L3_CACHE_LINE L3::Sequence writeCursor{Ring::size};
L3_CACHE_LINE L3::Sequence readCursor{Ring::size};

using Get = L3::Get<readCursor, Iterator, L3::SequenceList<commitCursor>>;

using Put = L3::Put<
    writeCursor, commitCursor,
    Iterator,
    L3::SequenceList<readCursor>,
    L3::CommitPolicy::Unique>;

void
dbg()
{
    std::cout << "commitCursor: " << commitCursor
              << ", writeCursor: " << writeCursor
              << ", readCursor: " << readCursor
              << ", value: " << ring[readCursor]
              << std::endl;
}

bool test1Thread()
{
    Put() = 42;
    for(auto& m: Get())
    {
        std::cout << "m: " << m << std::endl;
        if(m != 42)
        {
            return false;
        }
    }
    Put() = 101;
    Put() = 202;
    for(auto& m: Get())
    {
        std::cout << "m: " << m << std::endl;
    }
    return true;
}

bool
test2Threads()
{
    std::thread prod1(
        [](){ for(Msg i = 1; i < iterations; ++i) Put() = i; });

    Msg previous = 0;
    for(Msg i = 1; i < iterations;)
    {
        for(auto& msg: Get())
        {
            i++;
            if(msg != previous + 1)
            {
                std::cout << "previous: " << previous
                          << ", msg: " << msg
                          << std::endl;
                return false;
            }
            previous = msg;
        }
    }
    prod1.join();

    return true;
}

int
main()
{
    bool status = true;
    status &= test1Thread();
    status &= test2Threads();
    return status ? 0 : 1;
}

<|endoftext|>


<commit_before>#ifndef GENERIC_SWALLOW_HPP
# define GENERIC_SWALLOW_HPP
# pragma once

namespace generic
{

struct swallow
{
  template <typename ...T>
  swallow(T&&) noexcept
  {
  }
};

}

#endif // GENERIC_SWALLOW_HPP
<commit_msg>some fixes<commit_after>#ifndef GENERIC_SWALLOW_HPP
# define GENERIC_SWALLOW_HPP
# pragma once

namespace generic
{

struct swallow
{
  template <typename ...T>
  swallow(T&& ...) noexcept
  {
  }
};

}

#endif // GENERIC_SWALLOW_HPP
<|endoftext|>


<commit_before>#include "common.hpp"

#include "internal/cache.hpp"

TEST_CASE("Cache Check", "[cache]")
{
    using namespace libkeen::internal;

    Cache cache_ref;

    REQUIRE(cache_ref.connected());

    cache_ref.clear();

    std::string event_name = "name1";
    std::string event_data = "data1";

    std::string event_name_2 = "name2";
    std::string event_data_2 = "data2";

    cache_ref.push(event_name, event_data);
    REQUIRE(cache_ref.exists(event_name, event_data));

    std::vector<std::pair<std::string, std::string>> holder;
    cache_ref.pop(holder, 1);

    REQUIRE(holder.size() == 1);
    REQUIRE(holder.back().first == event_name);
    REQUIRE(holder.back().second == event_data);

    cache_ref.pop(holder, 10);
    REQUIRE(holder.size() == 1);
    REQUIRE(holder.back().first == event_name);
    REQUIRE(holder.back().second == event_data);

    cache_ref.push(event_name_2, event_data_2);
    REQUIRE(cache_ref.exists(event_name_2, event_data_2));

    cache_ref.pop(holder, 10);
    REQUIRE(holder.size() == 2);

    REQUIRE(holder.front().first == event_name);
    REQUIRE(holder.front().second == event_data);
    REQUIRE(holder.back().first == event_name_2);
    REQUIRE(holder.back().second == event_data_2);

    cache_ref.remove(event_name, event_data);
    REQUIRE(!cache_ref.exists(event_name, event_data));
}
<commit_msg>reworked cache unit tests, added a multi threaded access test + BDD style checks<commit_after>#include "common.hpp"
#include "asio.hpp"

#include "internal/cache.hpp"

SCENARIO("Cache functionality", "[cache]")
{
    std::vector<std::pair<std::string, std::string>> records;
    std::string key = "key";
    std::string val = "val";

    GIVEN("An instance of Cache class")
    {
        using namespace libkeen::internal;

        Cache cache;

        REQUIRE(cache.connected());

        cache.clear();
        REQUIRE(cache.count() == 0);

        THEN("A record is pushed")
        {
            cache.push(key, val);
            REQUIRE(cache.count() == 1);
            REQUIRE(cache.exists(key, val));
        }

        THEN("A record is popped")
        {
            cache.push(key, val);
            cache.pop(records, 10);

            REQUIRE(records.size() == 1);
            REQUIRE(records.back().first == key);
            REQUIRE(records.back().second == val);
            REQUIRE(cache.exists(key, val));
        }

        THEN("A record is removed")
        {
            cache.push(key, val);
            REQUIRE(cache.exists(key, val));

            cache.remove(key, val);
            REQUIRE(cache.count() == 0);
            REQUIRE(!cache.exists(key, val));
        }

        THEN("50 records are pushed single threaded")
        {
            REQUIRE(cache.count() == 0);

            int count = 50;
            for (int index = 0; index < count; ++index)
                cache.push(key + std::to_string(index), val + std::to_string(index));

            REQUIRE(cache.count() == count);

            cache.clear();
            REQUIRE(cache.count() == 0);
        }

        THEN("50 records are pushed multi threaded")
        {
            REQUIRE(cache.count() == 0);

            asio::io_service service;

            int count = 50;
            for (int index = 0; index < count; ++index)
                service.post([=, &cache] { cache.push(key + std::to_string(index), val + std::to_string(index)); });

            std::vector<std::thread> pool;
            for (unsigned t = 0; t < std::thread::hardware_concurrency(); ++t)
                pool.push_back(std::thread([&service] { service.run(); }));

            service.run();

            for (auto& worker : pool)
                if (worker.joinable())
                    worker.join();

            REQUIRE(cache.count() == count);
        }
    }
}
<|endoftext|>