<commit_before>#include <dlfcn.h>
#include <cassert>
#include <fstream>
#include <zmq.hpp>
#include <quidpp.h>
#include <package.h>
#include <Python.h>
#include "common/util.h"
#include "ace/interface.h"
#include "protoc/processjob.pb.h"
#include "dirent.h"
#include "wal.h"
#include "exec.h"
#include "ace/config.h"
#include "ace/ipc.h"

void Execute::init(ControlClient *control, const std::string& _master) {
	DIR *dir = nullptr;
	struct dirent *ent = nullptr;

	Execute& exec = Execute::getInstance();
	exec.jobcontrol = control;
	exec.master = _master;

return;
	if ((dir = opendir(WALDIR)) != NULL) {

		/* print all the files and directories within directory */
		while ((ent = readdir(dir)) != NULL) {
			if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
				continue;

			Wal::rollback(ent->d_name, [](const std::string & name, Execute::Parameter & param) {

				/* Run procedure */
				Execute::run(name, param);

				/* Setup subjobs if any */
				Execute::prospect(name);
			});
		}

		closedir(dir);
	}
}

void Execute::run(const std::string& name, Parameter& param) {
	Wal *executionLog = new Wal(name, param);

	Execute& exec = Execute::getInstance();

	std::cout << "Running package " << name << std::endl;

	/* Move worker in accept mode */
	exec.jobcontrol->setStateAccepted();

	/* Set members of shared object via callback */
	exec.workerid = exec.jobcontrol->workerId();
	exec.clusterjobs = exec.jobcontrol->clusterJobs();
	exec.module = name;
	exec.jobid = param.jobid;
	exec.jobname = param.jobname;
	exec.jobquid = param.jobquid;
	exec.jobpartition = param.jobpartition;
	exec.jobpartition_count = param.jobpartition_count;
	exec.jobstate = param.jobstate;
	exec.jobparent = param.jobparent;

	/* Ensure package exist */
	if (!file_exist(PKGDIR "/" + name)) {
		exec.jobcontrol->setStateIdle();
		std::cerr << "Package does not exist" << std::endl;
		return;
	}

	//TODO: check if module directory already exist

	/* Extract package in job directory */
	if (package_extract((PKGDIR "/" + name).c_str(), ("cache/local/" + name).c_str())) {
		exec.jobcontrol->setStateIdle();
		std::cerr << "Cannot open package " << std::endl;
		return;
	}

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::INIT);

	wchar_t *program = Py_DecodeLocale("Chella Worker", NULL);
	if (!program) {
		std::cerr << "Cannot decode name" << std::endl;
		return;
	}

	chdir((LOCALDIR "/" + name).c_str());
	setenv("PYTHONPATH", ".", 1);
	Py_SetProgramName(program);
	Py_Initialize();

	PyObject *pModuleJob = PyImport_ImportModule("job_example");
	if (!pModuleJob) {
		PyErr_Print();
		return;
	}

	/* Initialize Ace modules */
	PyObject *pMethodConfig = Ace::Config::PyAce_ModuleClass();
	PyObject *pMethodCallback = Ace::IPC::PyAce_ModuleClass();

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::LOAD);

	/* Create Ace config instance */
	PyObject *pInstanceConfig = PyObject_CallObject(pMethodConfig, NULL);
	if (!pInstanceConfig) {
		PyErr_Print();
		return;
	}

	/* Locate job init and call routine */
	PyObject *pFuncJobInit = PyObject_GetAttrString(pModuleJob, "job_init");
	if (!pFuncJobInit || !PyCallable_Check(pFuncJobInit)) {
		PyErr_Print();
		return;
	}

	PyObject *pArgsJobInit = Py_BuildValue("(O)", pInstanceConfig);
	PyObject *pInstanceJobInit = PyObject_CallObject(pFuncJobInit, pArgsJobInit);
	if (!pInstanceJobInit) {
		PyErr_Print();
		return;
	}

	PyObject *pFuncJobInvoke = PyObject_GetAttrString(pInstanceJobInit, "invoke");
	if (!pFuncJobInvoke || !PyCallable_Check(pFuncJobInvoke)) {
		PyErr_Print();
		return;
	}

	/* Instantiate job class */
	PyObject *pInstanceJob = PyObject_CallObject(pFuncJobInvoke, NULL);
	if (!pInstanceJob) {
		PyErr_Print();
		return;
	}

	PyObject *pResult = NULL;
	pResult = PyObject_CallMethod(pInstanceJob, "inject", "(Oisssii)", pMethodCallback,
		exec.jobid,
		exec.jobname.c_str(),
		name.c_str(),
		exec.jobquid.c_str(),
		exec.jobpartition,
		exec.jobpartition_count);
	if (!pResult) {
		PyErr_Print();
		return;
	}

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::INJECT);

	pResult = PyObject_CallMethod(pInstanceJob, "setup_once", NULL);
	if (!pResult) {
		PyErr_Print();
		return;
	}

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::SETUP_ONCE);

	pResult = PyObject_CallMethod(pInstanceJob, "setup", NULL);
	if (!pResult) {
		PyErr_Print();
		return;
	}

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::SETUP);

	pResult = PyObject_CallMethod(pInstanceJob, "run", "(y#)", param.jobdata.data(), param.jobdata.size());
	if (!pResult) {
		PyErr_Print();
		return;
	}

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::RUN);

	pResult = PyObject_CallMethod(pInstanceJob, "teardown", NULL);
	if (!pResult) {
		PyErr_Print();
		return;
	}

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::TEARDOWN);

	pResult = PyObject_CallMethod(pInstanceJob, "teardown_once", NULL);
	if (!pResult) {
		PyErr_Print();
		return;
	}

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::TEARDOWN_ONCE);

	PyObject *pMemberChains = PyObject_GetAttrString(pInstanceJob, "chains");
	if (!pMemberChains) {
		PyErr_Print();
		return;
	}

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::PULLCHAIN);

	Py_DECREF(pResult);
	Py_DECREF(pMemberChains);
	Py_DECREF(pInstanceJob);
	Py_DECREF(pMethodCallback);
	Py_DECREF(pMethodConfig);
	Py_DECREF(pModuleJob);

	/* Release resources allocated for this job */
	Py_Finalize();
	exec.sessionCleanup();

	/* Mark WAL done */
	executionLog->markDone();

	std::cout << "Job routine reached end" << std::endl;

	/* Move worker in idle mode */
	exec.jobcontrol->setStateIdle();

	delete executionLog;
}

void Execute::prospect(const std::string& name) {
	zmq::context_t context(1);
	zmq::socket_t socket(context, ZMQ_REQ);
	Execute& exec = Execute::getInstance();

	if (!exec.chain) {
		return;
	}

	if (!file_exist(PKGDIR "/" + name)) {
		std::cerr << "Cannot access library" << std::endl;
		return;
	}

	std::ifstream ifs(PKGDIR "/" + name);
	std::string content((std::istreambuf_iterator<char>(ifs)),
						(std::istreambuf_iterator<char>()));

	socket.connect(("tcp://" + exec.master).c_str());
	std::cout << "Connect to master " << exec.master << std::endl;

	for (unsigned int i = 0; i < exec.chain->size(); ++i) {
		auto subjob = exec.chain->at(i);

		ProcessJob job;
		job.set_name(subjob->name);
		job.set_id(i);
		job.set_quid(quidpp::Quid().toString(true));
		job.set_content(content);
		job.set_partition(i);
		job.set_partition_count(exec.chain->size());
		job.set_state(ProcessJob::PARTITION);
		job.set_quid_parent(exec.chain->parentQuid());
		job.set_data(subjob->data);

		std::cout << "Submit subjob " << i << " linked to parent " << exec.chain->parentQuid() + "(" + exec.chain->parentName() + ")" << std::endl;

		std::string serialized;
		job.SerializeToString(&serialized);

		zmq::message_t request(serialized.size());
		memcpy(reinterpret_cast<void *>(request.data()), serialized.c_str(), serialized.size());
		socket.send(request);

		/* Get the reply */
		zmq::message_t reply;
		socket.recv(&reply);
	}

	delete exec.chain;
	exec.chain = nullptr;
}

void Execute::dispose() {
	DIR *dir = nullptr;
	struct dirent *ent = nullptr;

	if ((dir = opendir(PKGDIR)) != NULL) {

		/* print all the files and directories within directory */
		while ((ent = readdir(dir)) != NULL) {
			if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
				continue;
			remove((PKGDIR "/" + std::string(ent->d_name)).c_str());
		}

		closedir(dir);
	}

	if ((dir = opendir(WALDIR)) != NULL) {

		/* print all the files and directories within directory */
		while ((ent = readdir(dir)) != NULL) {
			if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
				continue;
			remove((WALDIR "/" + std::string(ent->d_name)).c_str());
		}

		closedir(dir);
	}
}
<commit_msg>Measure job runtime<commit_after>#include <dlfcn.h>
#include <cassert>
#include <fstream>
#include <zmq.hpp>
#include <quidpp.h>
#include <package.h>
#include <Python.h>
#include "common/util.h"
#include "ace/interface.h"
#include "protoc/processjob.pb.h"
#include "dirent.h"
#include "wal.h"
#include "exec.h"
#include "ace/config.h"
#include "ace/ipc.h"

void Execute::init(ControlClient *control, const std::string& _master) {
	DIR *dir = nullptr;
	struct dirent *ent = nullptr;

	Execute& exec = Execute::getInstance();
	exec.jobcontrol = control;
	exec.master = _master;

return;
	if ((dir = opendir(WALDIR)) != NULL) {

		/* print all the files and directories within directory */
		while ((ent = readdir(dir)) != NULL) {
			if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
				continue;

			Wal::rollback(ent->d_name, [](const std::string & name, Execute::Parameter & param) {

				/* Run procedure */
				Execute::run(name, param);

				/* Setup subjobs if any */
				Execute::prospect(name);
			});
		}

		closedir(dir);
	}
}

void Execute::run(const std::string& name, Parameter& param) {
	Wal *executionLog = new Wal(name, param);

	struct timeval t1, t2;

	Execute& exec = Execute::getInstance();

	std::cout << "Running package " << name << std::endl;

	/* Move worker in accept mode */
	exec.jobcontrol->setStateAccepted();

	/* Set members of shared object via callback */
	exec.workerid = exec.jobcontrol->workerId();
	exec.clusterjobs = exec.jobcontrol->clusterJobs();
	exec.module = name;
	exec.jobid = param.jobid;
	exec.jobname = param.jobname;
	exec.jobquid = param.jobquid;
	exec.jobpartition = param.jobpartition;
	exec.jobpartition_count = param.jobpartition_count;
	exec.jobstate = param.jobstate;
	exec.jobparent = param.jobparent;

	/* Ensure package exist */
	if (!file_exist(PKGDIR "/" + name)) {
		exec.jobcontrol->setStateIdle();
		std::cerr << "Package does not exist" << std::endl;
		return;
	}

	//TODO: check if module directory already exist

	/* Extract package in job directory */
	if (package_extract((PKGDIR "/" + name).c_str(), ("cache/local/" + name).c_str())) {
		exec.jobcontrol->setStateIdle();
		std::cerr << "Cannot open package " << std::endl;
		return;
	}

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::INIT);

	wchar_t *program = Py_DecodeLocale("Chella Worker", NULL);
	if (!program) {
		std::cerr << "Cannot decode name" << std::endl;
		return;
	}

	chdir((LOCALDIR "/" + name).c_str());
	setenv("PYTHONPATH", ".", 1);
	Py_SetProgramName(program);
	Py_Initialize();

	PyObject *pModuleJob = PyImport_ImportModule("job_example");
	if (!pModuleJob) {
		PyErr_Print();
		return;
	}

	/* Initialize Ace modules */
	PyObject *pMethodConfig = Ace::Config::PyAce_ModuleClass();
	PyObject *pMethodCallback = Ace::IPC::PyAce_ModuleClass();

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::LOAD);
	gettimeofday(&t1, NULL);

	/* Create Ace config instance */
	PyObject *pInstanceConfig = PyObject_CallObject(pMethodConfig, NULL);
	if (!pInstanceConfig) {
		PyErr_Print();
		return;
	}

	/* Locate job init and call routine */
	PyObject *pFuncJobInit = PyObject_GetAttrString(pModuleJob, "job_init");
	if (!pFuncJobInit || !PyCallable_Check(pFuncJobInit)) {
		PyErr_Print();
		return;
	}

	PyObject *pArgsJobInit = Py_BuildValue("(O)", pInstanceConfig);
	PyObject *pInstanceJobInit = PyObject_CallObject(pFuncJobInit, pArgsJobInit);
	if (!pInstanceJobInit) {
		PyErr_Print();
		return;
	}

	PyObject *pFuncJobInvoke = PyObject_GetAttrString(pInstanceJobInit, "invoke");
	if (!pFuncJobInvoke || !PyCallable_Check(pFuncJobInvoke)) {
		PyErr_Print();
		return;
	}

	/* Instantiate job class */
	PyObject *pInstanceJob = PyObject_CallObject(pFuncJobInvoke, NULL);
	if (!pInstanceJob) {
		PyErr_Print();
		return;
	}

	PyObject *pResult = NULL;
	pResult = PyObject_CallMethod(pInstanceJob, "inject", "(Oisssii)", pMethodCallback,
		exec.jobid,
		exec.jobname.c_str(),
		name.c_str(),
		exec.jobquid.c_str(),
		exec.jobpartition,
		exec.jobpartition_count);
	if (!pResult) {
		PyErr_Print();
		return;
	}

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::INJECT);

	pResult = PyObject_CallMethod(pInstanceJob, "setup_once", NULL);
	if (!pResult) {
		PyErr_Print();
		return;
	}

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::SETUP_ONCE);

	pResult = PyObject_CallMethod(pInstanceJob, "setup", NULL);
	if (!pResult) {
		PyErr_Print();
		return;
	}

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::SETUP);

	pResult = PyObject_CallMethod(pInstanceJob, "run", "(y#)", param.jobdata.data(), param.jobdata.size());
	if (!pResult) {
		PyErr_Print();
		return;
	}

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::RUN);

	pResult = PyObject_CallMethod(pInstanceJob, "teardown", NULL);
	if (!pResult) {
		PyErr_Print();
		return;
	}

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::TEARDOWN);

	pResult = PyObject_CallMethod(pInstanceJob, "teardown_once", NULL);
	if (!pResult) {
		PyErr_Print();
		return;
	}

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::TEARDOWN_ONCE);

	PyObject *pMemberChains = PyObject_GetAttrString(pInstanceJob, "chains");
	if (!pMemberChains) {
		PyErr_Print();
		return;
	}

	/* Move WAL forward */
	executionLog->setCheckpoint(Wal::Checkpoint::PULLCHAIN);
	gettimeofday(&t2, NULL);

	Py_DECREF(pResult);
	Py_DECREF(pMemberChains);
	Py_DECREF(pInstanceJob);
	Py_DECREF(pMethodCallback);
	Py_DECREF(pMethodConfig);
	Py_DECREF(pModuleJob);

	/* Release resources allocated for this job */
	Py_Finalize();
	exec.sessionCleanup();

	/* Mark WAL done */
	executionLog->markDone();

	double runtime = (t2.tv_sec - t1.tv_sec) * 1000.0;
	runtime += (t2.tv_usec - t1.tv_usec) / 1000.0;

	std::cout << "Job routine reached end" << std::endl;
	std::cout << "Total runtime: " << runtime << std::endl;

	/* Move worker in idle mode */
	exec.jobcontrol->setStateIdle();

	delete executionLog;
}

void Execute::prospect(const std::string& name) {
	zmq::context_t context(1);
	zmq::socket_t socket(context, ZMQ_REQ);
	Execute& exec = Execute::getInstance();

	if (!exec.chain) {
		return;
	}

	if (!file_exist(PKGDIR "/" + name)) {
		std::cerr << "Cannot access library" << std::endl;
		return;
	}

	std::ifstream ifs(PKGDIR "/" + name);
	std::string content((std::istreambuf_iterator<char>(ifs)),
						(std::istreambuf_iterator<char>()));

	socket.connect(("tcp://" + exec.master).c_str());
	std::cout << "Connect to master " << exec.master << std::endl;

	for (unsigned int i = 0; i < exec.chain->size(); ++i) {
		auto subjob = exec.chain->at(i);

		ProcessJob job;
		job.set_name(subjob->name);
		job.set_id(i);
		job.set_quid(quidpp::Quid().toString(true));
		job.set_content(content);
		job.set_partition(i);
		job.set_partition_count(exec.chain->size());
		job.set_state(ProcessJob::PARTITION);
		job.set_quid_parent(exec.chain->parentQuid());
		job.set_data(subjob->data);

		std::cout << "Submit subjob " << i << " linked to parent " << exec.chain->parentQuid() + "(" + exec.chain->parentName() + ")" << std::endl;

		std::string serialized;
		job.SerializeToString(&serialized);

		zmq::message_t request(serialized.size());
		memcpy(reinterpret_cast<void *>(request.data()), serialized.c_str(), serialized.size());
		socket.send(request);

		/* Get the reply */
		zmq::message_t reply;
		socket.recv(&reply);
	}

	delete exec.chain;
	exec.chain = nullptr;
}

void Execute::dispose() {
	DIR *dir = nullptr;
	struct dirent *ent = nullptr;

	if ((dir = opendir(PKGDIR)) != NULL) {

		/* print all the files and directories within directory */
		while ((ent = readdir(dir)) != NULL) {
			if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
				continue;
			remove((PKGDIR "/" + std::string(ent->d_name)).c_str());
		}

		closedir(dir);
	}

	if ((dir = opendir(WALDIR)) != NULL) {

		/* print all the files and directories within directory */
		while ((ent = readdir(dir)) != NULL) {
			if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
				continue;
			remove((WALDIR "/" + std::string(ent->d_name)).c_str());
		}

		closedir(dir);
	}
}
<|endoftext|>


<commit_before>/* Description: A simple command shell */
/* Created by: 	David / 13513019
				Gerry Kastogi / 13513011
				Jessica Andjani / 13513086
*/
/*** Compile instruction: g++ shell.cpp -o shell -lreadline ***/

#include "shellfunc.h"	//Self-made

using namespace std;

string NextToken(string temp, int &i){
	string arg;

	//Ignore blank
	while(i<temp.length() && temp[i]==' '){
		i++;
	}

	//If first character encounter special delimiter
	if((temp[i]=='>' || temp[i]=='<' || temp[i]=='|') && i<temp.length()){
		arg=temp[i];
		i++;
	}
	else{ //Read command until found delimiter
		while(i<temp.length()){
			if (temp[i]=='>' || temp[i]=='<' || temp[i]==' ' || temp[i]=='|'){
				break;
			}
			else{
				arg+=temp[i];
				i++;
			}
		}
	}
	return arg;
}

int ReadCommand(string temp, int& i, char ** argv, int (&stats)[3], string& filein, string& fileout){
	string arg;
	char *cstr;
	int argc=0;
    do{
		arg=NextToken(temp, i);
		if(!arg.compare("<")){
			filein=NextToken(temp,i);
			stats[0]=1;
		}
		else if(!arg.compare(">")){
			fileout=NextToken(temp,i);
			stats[1]=1;
		}
		else if(!arg.compare("|")){	//Pipeline
			stats[2]=1;
			break;
		}
		else{
			cstr = new char[arg.size()];
			strcpy(cstr, arg.c_str());
			argv[argc] = cstr;
			argc++;
		}
	}
	while (i<temp.length());

	argv[argc] = NULL;

	return argc;
}

int ParseCommand(string temp, char ** argv, char ** argv2, int (&stats)[3], int (&stats2)[3], string& filein, string& fileout){
	int argc=0; //Argumen ke berapa
    int i=0;

    argc+=ReadCommand(temp, i,argv, stats, filein, fileout);
    if(stats[2]==1){	//Pipeline occured
    	argc+=ReadCommand(temp, i, argv2, stats2, filein, fileout);
    }
    return argc;
}

void RunCommand(char ** argv, char ** argv2, int stats[], int stats2[], string filein, string fileout){
	//Change Directory
	if(argv[0]==NULL){
		//Do Nothing
	}
	else if(strcmp(argv[0], "cd")==0)
		changeDir(argv[1]);
	//Exit Program
	else if(strcmp(argv[0], "quit")==0)
		exit(0);
	else{
		pid_t pid=fork();
		if(pid==0){ //Child Process
			if(stats[2]==1) //Pipeline
				Pipe(argv, argv2, stats, stats2, filein, fileout);
			else //Run Program Normally
				RunProgram1(argv, stats, filein, fileout);
		}
		else if (pid>0){
			waitpid(pid,NULL,0);
		}
	}
}

int main(){
	int argc;	//Jumlah argv yang terpakai
	char* argv[100];	//Menampung parameter
	char* argv2[100];	//Dipakai jika menggunakan pipeline
	string filein, fileout;	//Digunakan jika menggunakan redirect

	//Program terminalnya
	while (true){
		/*	stats[0]==1 jika menyimpan redirect in 	*/
		/*	stats[1]==1 jika menyimpan redirect out */
		/*	stats[2]==1 jika terjadi pipeline	*/
		int stats[] = {0, 0, 0};
		int stats2[] = {0, 0, 0};	//Digunakan jika memakai pipeline

		rl_bind_key('\t', rl_complete);	//Auto complete on
		char* buf;
		char* dir;
		strcpy(dir,"~"); strcat(dir, Directory()); strcat(dir,"> "); //Concat gak jelas

		buf = readline(dir);	//Baca input
		if(buf[0]!=0){
			add_history(buf);
			string temp = buf;
			//Parse
			argc= ParseCommand(temp, argv, argv2, stats, stats2, filein, fileout);
			//Jalanin command yang sudah di parse
			RunCommand(argv, argv2, stats, stats2, filein, fileout);
		}
		free(buf);
	}

	return 0;
}<commit_msg>Translating comment into english<commit_after>/* Description: A simple command shell */
/* Created by: 	David / 13513019
		Gerry Kastogi / 13513011
		Jessica Andjani / 13513086
*/
/*** Compile instruction: g++ shell.cpp -o shell -lreadline ***/

#include "shellfunc.h"	//Self-made

using namespace std;

string NextToken(string temp, int &i){
	string arg;

	//Ignore blank
	while(i<temp.length() && temp[i]==' '){
		i++;
	}

	//If first character encounter special delimiter
	if((temp[i]=='>' || temp[i]=='<' || temp[i]=='|') && i<temp.length()){
		arg=temp[i];
		i++;
	}
	else{ //Read command until found delimiter
		while(i<temp.length()){
			if (temp[i]=='>' || temp[i]=='<' || temp[i]==' ' || temp[i]=='|'){
				break;
			}
			else{
				arg+=temp[i];
				i++;
			}
		}
	}
	return arg;
}

int ReadCommand(string temp, int& i, char ** argv, int (&stats)[3], string& filein, string& fileout){
	string arg;
	char *cstr;
	int argc=0;
    do{
		arg=NextToken(temp, i);
		if(!arg.compare("<")){
			filein=NextToken(temp,i);
			stats[0]=1;
		}
		else if(!arg.compare(">")){
			fileout=NextToken(temp,i);
			stats[1]=1;
		}
		else if(!arg.compare("|")){	//Pipeline
			stats[2]=1;
			break;
		}
		else{
			cstr = new char[arg.size()];
			strcpy(cstr, arg.c_str());
			argv[argc] = cstr;
			argc++;
		}
	}
	while (i<temp.length());

	argv[argc] = NULL;

	return argc;
}

int ParseCommand(string temp, char ** argv, char ** argv2, int (&stats)[3], int (&stats2)[3], string& filein, string& fileout){
	int argc=0; //Argument count
	int i=0;

	argc+=ReadCommand(temp, i,argv, stats, filein, fileout);
	if(stats[2]==1){	//Pipeline occured
	    argc+=ReadCommand(temp, i, argv2, stats2, filein, fileout);
	}
	return argc;
}

void RunCommand(char ** argv, char ** argv2, int stats[], int stats2[], string filein, string fileout){
	//Change Directory
	if(argv[0]==NULL){
		//Do Nothing
	}
	else if(strcmp(argv[0], "cd")==0)
		changeDir(argv[1]);
	//Exit Program
	else if(strcmp(argv[0], "quit")==0)
		exit(0);
	else{
		pid_t pid=fork();
		if(pid==0){ //Child Process
			if(stats[2]==1) //Pipeline
				Pipe(argv, argv2, stats, stats2, filein, fileout);
			else //Run Program Normally
				RunProgram1(argv, stats, filein, fileout);
		}
		else if (pid>0){
			waitpid(pid,NULL,0);
		}
	}
}

int main(){
	int argc;	//Number of argv used
	char* argv[100];	//Contains parameter
	char* argv2[100];	//Used if pipeline exists
	string filein, fileout;	//Used if I/O redirection exists

	//Program
	while (true){
		/*	stats[0]==1 if redirect in 	*/
		/*	stats[1]==1 if redirect out */
		/*	stats[2]==1 if pipeline	occured */
		int stats[] = {0, 0, 0};
		int stats2[] = {0, 0, 0};	//Used if pipeline exists

		rl_bind_key('\t', rl_complete);	//Auto complete on
		char* buf;
		char* dir;
		strcpy(dir,"~"); strcat(dir, Directory()); strcat(dir,"> "); //Concat

		buf = readline(dir);	//Baca input
		if(buf[0]!=0){
			add_history(buf);
			string temp = buf;
			//Parse
			argc= ParseCommand(temp, argv, argv2, stats, stats2, filein, fileout);
			//Run command that has been parsed
			RunCommand(argv, argv2, stats, stats2, filein, fileout);
		}
		free(buf);
	}

	return 0;
}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	VS1063 VLSI Audio Codec ドライバー
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>
#include "G13/port.hpp"
#include "common/csi_io.hpp"
#include "common/delay.hpp"
#include "common/format.hpp"
#include "ff12a/src/ff.h"

extern "C" {
	char sci_getch(void);
	uint16_t sci_length();
}

namespace chip {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  VS1063 テンプレートクラス
		@param[in]	CSI	CSI(SPI) 制御クラス
		@param[in]	SEL	/xCS 制御クラス
		@param[in]	DCS /xDCS 制御クラス
		@param[in]	REQ	DREQ 入力クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class CSI, class SEL, class DCS, class REQ>
	class VS1063 {

		CSI&	csi_;

		FIL		fp_;
		uint8_t	frame_;
		bool	open_;

		/// VS1063a コマンド表
		enum class CMD {
			MODE,			///< モード制御
			STATUS,			///< ステータス
			BASS,			///< 内臓の低音／高音強調
			CLOCKF,			///< クロック周波数＋逓倍器
			DECODE_TIME,	///< 再生時間［秒］
			AUDATA,			///< 各種オーディオ・データ
			WRAM,			///< RAM リード／ライト
			WRAMADDR,		///< RAM リード／ライト・アドレス
			HDAT0,			///< ストリーム・ヘッダ・データ０
			HDAT1,			///< ストリーム・ヘッダ・データ１
			AIADDR,			///< アプリケーション開始アドレス
			VOL,			///< ボリューム制御
			AICTRL0,   		///< アプリケーション制御レジスタ０
			AICTRL1,		///< アプリケーション制御レジスタ１
			AICTRL2,		///< アプリケーション制御レジスタ２
			AICTRL3			///< アプリケーション制御レジスタ３
		};

		inline void sleep_() { asm("nop"); }

		inline bool get_status_()
		{
			return REQ::P();
		}

		inline void wait_ready_()
		{
			while(REQ::P() == 0) sleep_();
		}

		void write_(CMD cmd, uint16_t data)
		{
			wait_ready_();

			SEL::P = 0;
			csi_.xchg(0x02);	// Write command (0x02)
			csi_.xchg(static_cast<uint8_t>(cmd));
			csi_.xchg(data >> 8);
			csi_.xchg(data & 0xff);
			SEL::P = 1;
		}

		uint16_t read_(CMD cmd)
		{
			wait_ready_();

			uint16_t data;
			SEL::P = 0;
			csi_.xchg(0x03);	// Read command (0x03)
			csi_.xchg(static_cast<uint8_t>(cmd));
			data  = static_cast<uint16_t>(CSI::xchg()) << 8;
			data |= csi_.xchg();
			SEL::P = 1;
			return data;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		VS1063(CSI& csi) : csi_(csi), frame_(0), open_(false) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  開始（初期化）
		*/
		//-----------------------------------------------------------------//
		void start()
		{
			SEL::PM = 0;
			SEL::PU = 0;

			DCS::PM = 0;
			DCS::PU = 0;

			REQ::PM = 1;
			REQ::PU = 0;

			SEL::P = 1;  // /xCS = H
			DCS::P = 1;  // /xDCS = H

			open_ = false;

			uint8_t intr_level = 0;
			if(!csi_.start(500000, CSI::PHASE::TYPE4, intr_level)) {
				utils::format("CSI1 Start fail ! (Clock spped over range)\n");
				return;
			}

	   		write_(CMD::MODE, 0x4800);
			write_(CMD::VOL,  0x4040);  // volume

//			write_(CMD::CLOCKF, 0x9800);
			write_(CMD::CLOCKF, 0x8BE8);  // 12MHz OSC 補正

			utils::delay::milli_second(10);

			if(!csi_.start(8000000, CSI::PHASE::TYPE4, intr_level)) {
				utils::format("CSI1 Start fail ! (Clock spped over range)\n");
				return;
			}
			utils::delay::milli_second(10);
		}

		//----------------------------------------------------------------//
		/*!
			@brief  サービス
		*/
		//----------------------------------------------------------------//
		bool service()
		{
			while(get_status_() != 0) {
				uint8_t buff[32];
				UINT len;
				if(f_read(&fp_, buff, sizeof(buff), &len) != FR_OK) {
					return false;
				}
				if(len > 0) {
					csi_.write(buff, len);
				}
				if(len < 32) {
					f_close(&fp_);
					open_ = false;
					return false;
				}
				++frame_;
				if(frame_ >= 40) {
					device::P4.B3 = !device::P4.B3();
					frame_ = 0;
				}

				if(sci_length()) {
					auto ch = sci_getch();
					if(ch == '>') {
						f_close(&fp_);
						open_ = false;
						return false;
					}
				}
			}
			return true;
		}

		//----------------------------------------------------------------//
		/*!
			@brief  再生
			@param[in]	fname	ファイル名
			@return エラーなら「false」
		*/
		//----------------------------------------------------------------//
		bool play(const char* fname)
		{
			set_volume(255);

			if(f_open(&fp_, fname, FA_READ) != FR_OK) {
				utils::format("Can't open input file: '%s'\n") % fname;
				return false;
			}
			open_ = true;

			frame_ = 0;
			DCS::P = 0;
			while(service()) {
				sleep_();
			}
			DCS::P = 1;

			return true;
		}

		//----------------------------------------------------------------//
		/*!
			@brief  ボリュームを設定
			@param[in]	ボリューム（２５５が最大、０が最小）
		*/
		//----------------------------------------------------------------//
		void set_volume(uint8_t vol)
		{
			vol ^= 0xff;
			write_(CMD::VOL, (vol << 8) | vol);
		}

		//----------------------------------------------------------------//
		/*!
			@brief  ボリュームを取得
			@return	ボリューム（２５５が最大、０が最小）
		*/
		//----------------------------------------------------------------//
		uint8_t get_volume()
		{
			return (read_(CMD::VOL) & 255) ^ 0xff;
		}
	};
}
<commit_msg>fix ID3 tag skip<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	VS1063 VLSI Audio Codec ドライバー
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>
#include "G13/port.hpp"
#include "common/csi_io.hpp"
#include "common/delay.hpp"
#include "common/format.hpp"
#include "ff12a/src/ff.h"

extern "C" {
	char sci_getch(void);
	uint16_t sci_length();
}

namespace chip {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  VS1063 テンプレートクラス
		@param[in]	CSI	CSI(SPI) 制御クラス
		@param[in]	SEL	/xCS 制御クラス
		@param[in]	DCS /xDCS 制御クラス
		@param[in]	REQ	DREQ 入力クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class CSI, class SEL, class DCS, class REQ>
	class VS1063 {

		CSI&	csi_;

		FIL		fp_;
		uint8_t	frame_;
		bool	open_;

		uint8_t buff_[256];

		/// VS1063a コマンド表
		enum class CMD {
			MODE,			///< モード制御
			STATUS,			///< ステータス
			BASS,			///< 内臓の低音／高音強調
			CLOCKF,			///< クロック周波数＋逓倍器
			DECODE_TIME,	///< 再生時間［秒］
			AUDATA,			///< 各種オーディオ・データ
			WRAM,			///< RAM リード／ライト
			WRAMADDR,		///< RAM リード／ライト・アドレス
			HDAT0,			///< ストリーム・ヘッダ・データ０
			HDAT1,			///< ストリーム・ヘッダ・データ１
			AIADDR,			///< アプリケーション開始アドレス
			VOL,			///< ボリューム制御
			AICTRL0,   		///< アプリケーション制御レジスタ０
			AICTRL1,		///< アプリケーション制御レジスタ１
			AICTRL2,		///< アプリケーション制御レジスタ２
			AICTRL3			///< アプリケーション制御レジスタ３
		};

		inline void sleep_() { asm("nop"); }

		inline bool get_status_()
		{
			return REQ::P();
		}

		inline void wait_ready_()
		{
			while(REQ::P() == 0) sleep_();
		}

		void write_(CMD cmd, uint16_t data)
		{
			wait_ready_();

			SEL::P = 0;
			csi_.xchg(0x02);	// Write command (0x02)
			csi_.xchg(static_cast<uint8_t>(cmd));
			csi_.xchg(data >> 8);
			csi_.xchg(data & 0xff);
			SEL::P = 1;
		}

		uint16_t read_(CMD cmd)
		{
			wait_ready_();

			uint16_t data;
			SEL::P = 0;
			csi_.xchg(0x03);	// Read command (0x03)
			csi_.xchg(static_cast<uint8_t>(cmd));
			data  = static_cast<uint16_t>(CSI::xchg()) << 8;
			data |= csi_.xchg();
			SEL::P = 1;
			return data;
		}

		bool probe_mp3_()
		{
			UINT len;
			if(f_read(&fp_, buff_, 10, &len) != FR_OK) {
				return false;
			}
			if(len != 10) {
				f_close(&fp_);
				return false;
			}

			if(buff_[0] == 'I' && buff_[1] == 'D' && buff_[2] == '3') ;
			else {
				return false;
			}

			// skip TAG
			uint32_t ofs = static_cast<uint32_t>(buff_[6]) << 21;
			ofs |= static_cast<uint32_t>(buff_[7]) << 14;
			ofs |= static_cast<uint32_t>(buff_[8]) << 7;
			ofs |= static_cast<uint32_t>(buff_[9]);
			f_lseek(&fp_, ofs);

			utils::format("Find ID3 tag skip: %d\n") % ofs;

			return true;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		VS1063(CSI& csi) : csi_(csi), frame_(0), open_(false) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  開始（初期化）
		*/
		//-----------------------------------------------------------------//
		void start()
		{
			SEL::PM = 0;
			SEL::PU = 0;

			DCS::PM = 0;
			DCS::PU = 0;

			REQ::PM = 1;
			REQ::PU = 0;

			SEL::P = 1;  // /xCS = H
			DCS::P = 1;  // /xDCS = H

			open_ = false;

			uint8_t intr_level = 0;
			if(!csi_.start(500000, CSI::PHASE::TYPE4, intr_level)) {
				utils::format("CSI1 Start fail ! (Clock spped over range)\n");
				return;
			}

///	   		write_(CMD::MODE, 0x4840);
	   		write_(CMD::MODE, 0x4800);
			write_(CMD::VOL,  0x4040);  // volume

//			write_(CMD::CLOCKF, 0x9800);
			write_(CMD::CLOCKF, 0x8BE8);  // 12MHz OSC 補正

			utils::delay::milli_second(10);

			if(!csi_.start(8000000, CSI::PHASE::TYPE4, intr_level)) {
				utils::format("CSI1 Start fail ! (Clock spped over range)\n");
				return;
			}
			utils::delay::milli_second(10);

			set_volume(255);
		}

		//----------------------------------------------------------------//
		/*!
			@brief  サービス
		*/
		//----------------------------------------------------------------//
		bool service()
		{
			UINT len;
			if(f_read(&fp_, buff_, sizeof(buff_), &len) != FR_OK) {
				return false;
			}
			if(len == 0) return false;

			const uint8_t* p = buff_;
			while(len > 0) {
				while(get_status_() == 0) ;
				uint16_t l = 32;
				if(l > len) l = len;
				csi_.write(p, l);
				p += l;
				len -= l;
			}

			++frame_;
			if(frame_ >= 40) {
				device::P4.B3 = !device::P4.B3();
				frame_ = 0;
			}

			if(sci_length()) {
				auto ch = sci_getch();
				if(ch == '>') {
					return false;
				}
			}
			return true;
		}

		//----------------------------------------------------------------//
		/*!
			@brief  再生
			@param[in]	fname	ファイル名
			@return エラーなら「false」
		*/
		//----------------------------------------------------------------//
		bool play(const char* fname)
		{
			utils::format("Play: '%s'\n") % fname;

			if(f_open(&fp_, fname, FA_READ) != FR_OK) {
				utils::format("Can't open input file: '%s'\n") % fname;
				return false;
			}

			// ファイル・フォーマットを確認
			probe_mp3_();

			{
				open_ = true;

				frame_ = 0;
				DCS::P = 0;
				while(service()) {
					sleep_();
				}
				DCS::P = 1;
			}

			f_close(&fp_);
			open_ = false;

			return true;
		}

		//----------------------------------------------------------------//
		/*!
			@brief  ボリュームを設定
			@param[in]	ボリューム（２５５が最大、０が最小）
		*/
		//----------------------------------------------------------------//
		void set_volume(uint8_t vol)
		{
			vol ^= 0xff;
			write_(CMD::VOL, (vol << 8) | vol);
		}

		//----------------------------------------------------------------//
		/*!
			@brief  ボリュームを取得
			@return	ボリューム（２５５が最大、０が最小）
		*/
		//----------------------------------------------------------------//
		uint8_t get_volume()
		{
			return (read_(CMD::VOL) & 255) ^ 0xff;
		}
	};
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * Copyright (c) 2009-2014, MAV'RIC Development Team
 * 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 	serial_udp.cpp
 *
 * \author 	MAV'RIC Team
 *
 * \brief 	Linux implementation of serial peripherals using UDP
 *
 ******************************************************************************/

#include "serial_udp.hpp"

extern "C"
{
	#include <unistd.h>
	// #include <stdlib.h>
	#include <stdio.h>
	#include <errno.h>
	#include <string.h>
	#include <sys/socket.h>
	#include <sys/types.h>
	#include <netinet/in.h>
	#include <fcntl.h>
	#include <time.h>
	#include <sys/time.h>
	#include <time.h>
	#include <arpa/inet.h>
	// #include "print_util.h"
}

//------------------------------------------------------------------------------
// PUBLIC FUNCTIONS IMPLEMENTATION
//------------------------------------------------------------------------------

Serial_udp::Serial_udp(serial_udp_conf_t config):
	tx_udp_(udp_client(config.ip, config.tx_port)),
	rx_udp_(udp_server(config.ip, config.rx_port))
{
	config = config;

	// Init buffers
	buffer_init(&tx_buffer_);
	buffer_init(&rx_buffer_);

	// Set rx as non blocking
	int sock = rx_udp_.get_socket();
	int flags = fcntl (sock, F_GETFL, 0 );
	fcntl( sock, F_SETFL, flags | O_NONBLOCK );
}

bool Serial_udp::init(void)
{
	return true;
}

uint32_t Serial_udp::readable(void)
{
	int32_t recsize;
	char 	buf[BUFFER_SIZE];

	recsize = rx_udp_.recv(buf, BUFFER_SIZE);

	for( int32_t i=0; i<recsize; i++ )
	{
		buffer_put( &rx_buffer_, buf[i] );
	}

	return buffer_bytes_available(&rx_buffer_);
}

uint32_t Serial_udp::writeable(void)
{
	return buffer_bytes_free( &tx_buffer_ );
}

void Serial_udp::flush(void)
{
	int32_t bytes_sent;

	bytes_sent = tx_udp_.send((const char*)tx_buffer_.Buffer, buffer_bytes_available(&tx_buffer_));

	if( bytes_sent == (int32_t)buffer_bytes_available( &tx_buffer_ ) )
	{
		buffer_clear( &tx_buffer_ );
	}
	else
	{
		for(int32_t i=0; i<bytes_sent; i++ )
		{
			buffer_get( &tx_buffer_ );
		}
	}
}

bool Serial_udp::write(const uint8_t* bytes, const uint32_t size)
{
	bool ret = true;

	// Queue byte
	for (uint32_t i = 0; i < size; ++i)
	{
		ret &= buffer_put( &tx_buffer_, bytes[i] );
	}

	// Start transmission
	if( buffer_bytes_available( &tx_buffer_ ) >= 1 )
	{
		flush();
	}

	return ret;
}

bool Serial_udp::read(uint8_t bytes[], const uint32_t size)
{
	bool ret = false;

	if( readable() >= size )
	{
		for (uint32_t i = 0; i < size; ++i)
		{
			bytes[i] = buffer_get( &rx_buffer_ );
		}
		ret = true;
	}

	return ret;
}

//------------------------------------------------------------------------------
// PRIVATE FUNCTIONS IMPLEMENTATION
//------------------------------------------------------------------------------<commit_msg>Cosmetics<commit_after>/*******************************************************************************
 * Copyright (c) 2009-2014, MAV'RIC Development Team
 * 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 	serial_udp.cpp
 *
 * \author 	MAV'RIC Team
 *
 * \brief 	Linux implementation of serial peripherals using UDP
 *
 ******************************************************************************/

#include "serial_udp.hpp"

extern "C"
{
	#include <fcntl.h>
}

//------------------------------------------------------------------------------
// PUBLIC FUNCTIONS IMPLEMENTATION
//------------------------------------------------------------------------------

Serial_udp::Serial_udp(serial_udp_conf_t config):
	tx_udp_(udp_client(config.ip, config.tx_port)),
	rx_udp_(udp_server(config.ip, config.rx_port))
{
	config = config;

	// Init buffers
	buffer_init(&tx_buffer_);
	buffer_init(&rx_buffer_);

	// Set rx as non blocking
	int sock = rx_udp_.get_socket();
	int flags = fcntl (sock, F_GETFL, 0 );
	fcntl( sock, F_SETFL, flags | O_NONBLOCK );
}

bool Serial_udp::init(void)
{
	return true;
}

uint32_t Serial_udp::readable(void)
{
	int32_t recsize;
	char 	buf[BUFFER_SIZE];

	recsize = rx_udp_.recv(buf, BUFFER_SIZE);

	for( int32_t i=0; i<recsize; i++ )
	{
		buffer_put( &rx_buffer_, buf[i] );
	}

	return buffer_bytes_available(&rx_buffer_);
}

uint32_t Serial_udp::writeable(void)
{
	return buffer_bytes_free( &tx_buffer_ );
}

void Serial_udp::flush(void)
{
	int32_t bytes_sent;

	bytes_sent = tx_udp_.send((const char*)tx_buffer_.Buffer, buffer_bytes_available(&tx_buffer_));

	if( bytes_sent == (int32_t)buffer_bytes_available( &tx_buffer_ ) )
	{
		buffer_clear( &tx_buffer_ );
	}
	else
	{
		for(int32_t i=0; i<bytes_sent; i++ )
		{
			buffer_get( &tx_buffer_ );
		}
	}
}

bool Serial_udp::write(const uint8_t* bytes, const uint32_t size)
{
	bool ret = true;

	// Queue byte
	for (uint32_t i = 0; i < size; ++i)
	{
		ret &= buffer_put( &tx_buffer_, bytes[i] );
	}

	// Start transmission
	if( buffer_bytes_available( &tx_buffer_ ) >= 1 )
	{
		flush();
	}

	return ret;
}

bool Serial_udp::read(uint8_t bytes[], const uint32_t size)
{
	bool ret = false;

	if( readable() >= size )
	{
		for (uint32_t i = 0; i < size; ++i)
		{
			bytes[i] = buffer_get( &rx_buffer_ );
		}
		ret = true;
	}

	return ret;
}

//------------------------------------------------------------------------------
// PRIVATE FUNCTIONS IMPLEMENTATION
//------------------------------------------------------------------------------<|endoftext|>


<commit_before>/********************************************************************
 * Copyright © 2017 Computational Molecular Biology Group,          *
 *                  Freie Universität Berlin (GER)                  *
 *                                                                  *
 * This file is part of ReaDDy.                                     *
 *                                                                  *
 * ReaDDy is free software: you can redistribute it and/or modify   *
 * it under the terms of the GNU Lesser General Public License as   *
 * published by the Free Software Foundation, either version 3 of   *
 * the License, or (at your option) any later version.              *
 *                                                                  *
 * This program is distributed in the hope that it will be useful,  *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the     *
 * GNU Lesser General Public License for more details.              *
 *                                                                  *
 * You should have received a copy of the GNU Lesser General        *
 * Public License along with this program. If not, see              *
 * <http://www.gnu.org/licenses/>.                                  *
 ********************************************************************/

/**
 * @file Timer.cpp
 * @brief Implementation of timer classes
 * @author chrisfroe
 * @date 01.09.17
 * @copyright GNU Lesser General Public License v3.0
 */

#include <readdy/common/Timer.h>
#include <readdy/common/string.h>

namespace readdy {
namespace util {

constexpr const char PerformanceNode::slash[];

PerformanceNode::PerformanceNode(const std::string &name, bool measure) : _name(validateName(name)), _measure(measure), _data(0., 0) { }

PerformanceNode &PerformanceNode::subnode(const std::string &name) {
    auto validatedName = validateName(name);
    const auto &it = std::find_if(children.begin(), children.end(),
                                  [&validatedName](const performance_node_ref &node) { return node->_name == validatedName; });
    if (it == children.end()) {
        children.push_back(std::make_unique<PerformanceNode>(validatedName, _measure));
        return *children.back();
    }
    return **it;
}

void PerformanceNode::clear() {
    _data.cumulativeTime = 0.;
    _data.count = 0;
    for (auto &c : children) {
        c->clear();
    }
}

Timer PerformanceNode::timeit() {
    return Timer(_data, _measure);
}

const PerformanceData &PerformanceNode::data() const {
    return _data;
}

const PerformanceNode &PerformanceNode::direct_child(const std::string &name) const {
    const auto &it = std::find_if(children.begin(), children.end(), [&name](const performance_node_ref &node) { return node->_name == name; });
    if (it == children.end()) {
        throw std::runtime_error(fmt::format("Child with name {} does not exist", name));
    }
    return **it;
}

const std::size_t PerformanceNode::n_children() const {
    return children.size();
}

std::string PerformanceNode::describe(const size_t level) const {
    std::string s;
    for (auto i = 0; i < level; ++i) {
        s += "\t";
    }
    s += fmt::format("{}: time {} s, count {}\n", _name, _data.cumulativeTime, _data.count);
    for (const auto &c : children) {
        s += c->describe(level + 1);
    }
    return s;
}

std::vector<std::string> PerformanceNode::parse(const std::string &path) const {
    std::vector<std::string> labels;
    std::string residualPath(path);
    auto slashPos = residualPath.find(slash);
    while (slashPos != residualPath.npos) {
        auto lhs = residualPath.substr(0, slashPos);
        auto rhs = residualPath.substr(slashPos + std::strlen(slash), residualPath.npos);
        util::str::trim(lhs);
        util::str::trim(rhs);
        residualPath = rhs;
        labels.push_back(lhs);
        slashPos = residualPath.find(slash);
    }
    labels.push_back(residualPath);
    return labels;
}

const PerformanceNode &PerformanceNode::child(const std::vector<std::string> &labels) const {
    if (labels.empty()) {
        throw std::invalid_argument("labels must not be empty");
    }
    std::vector<std::reference_wrapper<const PerformanceNode>> nodes;
    nodes.push_back(std::cref(direct_child(labels[0])));
    for (auto i = 1; i< labels.size(); ++i) {
        auto previousNode = nodes.back();
        auto nextNode = std::cref(previousNode.get().direct_child(labels[i]));
        nodes.push_back(nextNode);
    }
    return nodes.back();
}

const PerformanceNode &PerformanceNode::child(const std::string &path) const {
    if (path.find(slash)) {
        const auto &labels = parse(path);
        return child(labels);
    } else {
        return direct_child(path);
    }
}

const std::string &PerformanceNode::name() const {
    return _name;
}

std::string PerformanceNode::validateName(const std::string &name) const {
    if (name.find(slash) != name.npos) {
        throw std::invalid_argument(fmt::format("name {} contains forbidden char {}", name, slash));
    }
    return util::str::trim_copy(name);
}

Timer::Timer(PerformanceData &target, bool measure) : target(target), measure(measure) {
    if (measure) {
        begin = std::chrono::high_resolution_clock::now();
    }
}

Timer::~Timer() {
    if (measure) {
        std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
        long elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count();
        const auto elapsedSeconds = static_cast<PerformanceData::time>(1e-6) * static_cast<PerformanceData::time>(elapsed);
        std::unique_lock<std::mutex> lock(target.mutex);
        target.cumulativeTime += elapsedSeconds;
        target.count++;
    }
}

}
}<commit_msg>simplify tree descending<commit_after>/********************************************************************
 * Copyright © 2017 Computational Molecular Biology Group,          *
 *                  Freie Universität Berlin (GER)                  *
 *                                                                  *
 * This file is part of ReaDDy.                                     *
 *                                                                  *
 * ReaDDy is free software: you can redistribute it and/or modify   *
 * it under the terms of the GNU Lesser General Public License as   *
 * published by the Free Software Foundation, either version 3 of   *
 * the License, or (at your option) any later version.              *
 *                                                                  *
 * This program is distributed in the hope that it will be useful,  *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the     *
 * GNU Lesser General Public License for more details.              *
 *                                                                  *
 * You should have received a copy of the GNU Lesser General        *
 * Public License along with this program. If not, see              *
 * <http://www.gnu.org/licenses/>.                                  *
 ********************************************************************/

/**
 * @file Timer.cpp
 * @brief Implementation of timer classes
 * @author chrisfroe
 * @date 01.09.17
 * @copyright GNU Lesser General Public License v3.0
 */

#include <readdy/common/Timer.h>
#include <readdy/common/string.h>

namespace readdy {
namespace util {

constexpr const char PerformanceNode::slash[];

PerformanceNode::PerformanceNode(const std::string &name, bool measure) : _name(validateName(name)), _measure(measure), _data(0., 0) { }

PerformanceNode &PerformanceNode::subnode(const std::string &name) {
    auto validatedName = validateName(name);
    const auto &it = std::find_if(children.begin(), children.end(),
                                  [&validatedName](const performance_node_ref &node) { return node->_name == validatedName; });
    if (it == children.end()) {
        children.push_back(std::make_unique<PerformanceNode>(validatedName, _measure));
        return *children.back();
    }
    return **it;
}

void PerformanceNode::clear() {
    _data.cumulativeTime = 0.;
    _data.count = 0;
    for (auto &c : children) {
        c->clear();
    }
}

Timer PerformanceNode::timeit() {
    return Timer(_data, _measure);
}

const PerformanceData &PerformanceNode::data() const {
    return _data;
}

const PerformanceNode &PerformanceNode::direct_child(const std::string &name) const {
    const auto &it = std::find_if(children.begin(), children.end(), [&name](const performance_node_ref &node) { return node->_name == name; });
    if (it == children.end()) {
        throw std::runtime_error(fmt::format("Child with name {} does not exist", name));
    }
    return **it;
}

const std::size_t PerformanceNode::n_children() const {
    return children.size();
}

std::string PerformanceNode::describe(const size_t level) const {
    std::string s;
    for (auto i = 0; i < level; ++i) {
        s += "\t";
    }
    s += fmt::format("{}: time {} s, count {}\n", _name, _data.cumulativeTime, _data.count);
    for (const auto &c : children) {
        s += c->describe(level + 1);
    }
    return s;
}

std::vector<std::string> PerformanceNode::parse(const std::string &path) const {
    std::vector<std::string> labels;
    std::string residualPath(path);
    auto slashPos = residualPath.find(slash);
    while (slashPos != residualPath.npos) {
        auto lhs = residualPath.substr(0, slashPos);
        auto rhs = residualPath.substr(slashPos + std::strlen(slash), residualPath.npos);
        util::str::trim(lhs);
        util::str::trim(rhs);
        residualPath = rhs;
        labels.push_back(lhs);
        slashPos = residualPath.find(slash);
    }
    labels.push_back(residualPath);
    return labels;
}

const PerformanceNode &PerformanceNode::child(const std::vector<std::string> &labels) const {
    if (labels.empty()) {
        throw std::invalid_argument("labels must not be empty");
    }
    std::reference_wrapper<const PerformanceNode> currentNode {direct_child(labels[0])};
    for (auto i = 1; i< labels.size(); ++i) {
        currentNode = std::cref(currentNode.get().direct_child(labels[i]));
    }
    return currentNode.get();
}

const PerformanceNode &PerformanceNode::child(const std::string &path) const {
    if (path.find(slash)) {
        const auto &labels = parse(path);
        return child(labels);
    } else {
        return direct_child(path);
    }
}

const std::string &PerformanceNode::name() const {
    return _name;
}

std::string PerformanceNode::validateName(const std::string &name) const {
    if (name.find(slash) != name.npos) {
        throw std::invalid_argument(fmt::format("name {} contains forbidden char {}", name, slash));
    }
    return util::str::trim_copy(name);
}

Timer::Timer(PerformanceData &target, bool measure) : target(target), measure(measure) {
    if (measure) {
        begin = std::chrono::high_resolution_clock::now();
    }
}

Timer::~Timer() {
    if (measure) {
        std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
        long elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count();
        const auto elapsedSeconds = static_cast<PerformanceData::time>(1e-6) * static_cast<PerformanceData::time>(elapsed);
        std::unique_lock<std::mutex> lock(target.mutex);
        target.cumulativeTime += elapsedSeconds;
        target.count++;
    }
}

}
}<|endoftext|>


<commit_before>#ifndef SLICE_HPP
#define SLICE_HPP

#include "iterbase.hpp"

#include <iterator>
#include <type_traits>
#include <initializer_list>

namespace iter {

    //Forward declarations of Slice and slice
    //template <typename Container, typename DifferenceType>
    //class Slice;

    //template <typename T>
    //Slice<std::initializer_list<T>> slice( std::initializer_list<T>);

    //template <typename Container, typename DifferenceType>
    //Slice<Container> slice(Container &&);
    template <typename T>
    class has_size
    {
        typedef char one;
        typedef long two;

        template <typename C> static one test( decltype(&C::size) ) ;
        template <typename C> static two test(...);

        public:
        enum { value = sizeof(test<T>(0)) == sizeof(char) };
    };
    template <typename Container>
    typename std::enable_if<has_size<Container>::value, std::size_t>::type
    size(const Container& container) {
        return container.size();
    }

    template <typename Container>
    typename std::enable_if<!has_size<Container>::value, std::size_t>::type
    size(const Container& container) {
        return std::distance(std::begin(container), std::end(container));
    }

    template <typename T, std::size_t N>
    std::size_t size(const T (&)[N]) {
        return N;
    }

    template <typename Container, typename DifferenceType>
    class Slice {
        private:
            Container container;
            DifferenceType start;
            DifferenceType stop;
            DifferenceType step;

            // The only thing allowed to directly instantiate an Slice is
            // the slice function
            //friend Slice slice<Container, DifferenceType>(Container &&);
            //template <typename T>
            //friend Slice<std::initializer_list<T>> slice(std::initializer_list<T>);
        public:
            Slice(Container in_container, DifferenceType start,
                  DifferenceType stop, DifferenceType step)
                : container(std::forward<Container>(in_container)),
                start{start},
                stop{stop},
                step{step}
            {
                // sets stop = start if the range is empty
                if ((start < stop && step <=0) ||
                        (start > stop && step >=0)){
                    this->stop = start;
                }
                if (this->stop > static_cast<DifferenceType>(
                            size(this->container))) {
                    this->stop = static_cast<DifferenceType>(size(
                                this->container));
                }
                if (this->start < 0) {
                    this->start = 0;
                }
            }

            Slice() = delete;
            Slice& operator=(const Slice&) = delete;

            Slice(const Slice &) = default;

            class Iterator
                : public std::iterator<std::input_iterator_tag,
                    iterator_traits_deref<Container>>
            {
                private:
                    iterator_type<Container> sub_iter;
                    DifferenceType current;
                    DifferenceType stop;
                    DifferenceType step;

                public:
                    Iterator (iterator_type<Container> si, DifferenceType start,
                            DifferenceType stop, DifferenceType step)
                        : sub_iter{si},
                        current{start},
                        stop{stop},
                        step{step}
                    { }

                    iterator_deref<Container> operator*() const {
                        return *this->sub_iter;
                    }

                    Iterator& operator++() {
                        std::advance(this->sub_iter, this->step);
                        this->current += this->step;
                        return *this;
                    }

                    Iterator operator++(int) {
                        auto ret = *this;
                        ++*this;
                        return ret;
                    }

                    bool operator!=(const Iterator &) const {
                        return (this->step > 0 && this->current < this->stop)
                            || (this->step < 0 && this->current > this->stop);
                    }

                    bool operator==(const Iterator& other) const {
                        return !(*this != other);
                    }
            };

            Iterator begin() {
                return {std::next(std::begin(this->container), this->start),
                        this->start, this->stop, this->step};
            }

            Iterator end() {
                return {std::next(std::begin(this->container), this->stop),
                        this->stop, this->stop, this->step};
            }

    };

    // Helper function to instantiate a Slice
    template <typename Container, typename DifferenceType>
    Slice<Container, DifferenceType> slice(
            Container&& container,
            DifferenceType start, DifferenceType stop, DifferenceType step=1) {
        return {std::forward<Container>(container), start, stop, step};
    }

    //only give the end as an arg and assume step  is 1 and begin is 0
    template <typename Container, typename DifferenceType>
    Slice<Container, DifferenceType> slice(
            Container&& container, DifferenceType stop) {
        return {std::forward<Container>(container), 0, stop, 1};
    }

    template <typename T, typename DifferenceType>
    Slice<std::initializer_list<T>, DifferenceType> slice(
            std::initializer_list<T> il, DifferenceType start,
            DifferenceType stop, DifferenceType step=1) {
        return {il, start, stop, step};
    }

    template <typename T, typename DifferenceType>
    Slice<std::initializer_list<T>, DifferenceType> slice(
            std::initializer_list<T> il, DifferenceType stop) {
        return {il, 0, stop, 1};
    }
}

#endif //SLICE_HPP
<commit_msg>adjusts include guards<commit_after>#ifndef ITER_SLICE_HPP
#define ITER_SLICE_HPP

#include "iterbase.hpp"

#include <iterator>
#include <type_traits>
#include <initializer_list>

namespace iter {

    //Forward declarations of Slice and slice
    //template <typename Container, typename DifferenceType>
    //class Slice;

    //template <typename T>
    //Slice<std::initializer_list<T>> slice( std::initializer_list<T>);

    //template <typename Container, typename DifferenceType>
    //Slice<Container> slice(Container &&);
    template <typename T>
    class has_size
    {
        typedef char one;
        typedef long two;

        template <typename C> static one test( decltype(&C::size) ) ;
        template <typename C> static two test(...);

        public:
        enum { value = sizeof(test<T>(0)) == sizeof(char) };
    };
    template <typename Container>
    typename std::enable_if<has_size<Container>::value, std::size_t>::type
    size(const Container& container) {
        return container.size();
    }

    template <typename Container>
    typename std::enable_if<!has_size<Container>::value, std::size_t>::type
    size(const Container& container) {
        return std::distance(std::begin(container), std::end(container));
    }

    template <typename T, std::size_t N>
    std::size_t size(const T (&)[N]) {
        return N;
    }

    template <typename Container, typename DifferenceType>
    class Slice {
        private:
            Container container;
            DifferenceType start;
            DifferenceType stop;
            DifferenceType step;

            // The only thing allowed to directly instantiate an Slice is
            // the slice function
            //friend Slice slice<Container, DifferenceType>(Container &&);
            //template <typename T>
            //friend Slice<std::initializer_list<T>> slice(std::initializer_list<T>);
        public:
            Slice(Container in_container, DifferenceType start,
                  DifferenceType stop, DifferenceType step)
                : container(std::forward<Container>(in_container)),
                start{start},
                stop{stop},
                step{step}
            {
                // sets stop = start if the range is empty
                if ((start < stop && step <=0) ||
                        (start > stop && step >=0)){
                    this->stop = start;
                }
                if (this->stop > static_cast<DifferenceType>(
                            size(this->container))) {
                    this->stop = static_cast<DifferenceType>(size(
                                this->container));
                }
                if (this->start < 0) {
                    this->start = 0;
                }
            }

            Slice() = delete;
            Slice& operator=(const Slice&) = delete;

            Slice(const Slice &) = default;

            class Iterator
                : public std::iterator<std::input_iterator_tag,
                    iterator_traits_deref<Container>>
            {
                private:
                    iterator_type<Container> sub_iter;
                    DifferenceType current;
                    DifferenceType stop;
                    DifferenceType step;

                public:
                    Iterator (iterator_type<Container> si, DifferenceType start,
                            DifferenceType stop, DifferenceType step)
                        : sub_iter{si},
                        current{start},
                        stop{stop},
                        step{step}
                    { }

                    iterator_deref<Container> operator*() const {
                        return *this->sub_iter;
                    }

                    Iterator& operator++() {
                        std::advance(this->sub_iter, this->step);
                        this->current += this->step;
                        return *this;
                    }

                    Iterator operator++(int) {
                        auto ret = *this;
                        ++*this;
                        return ret;
                    }

                    bool operator!=(const Iterator &) const {
                        return (this->step > 0 && this->current < this->stop)
                            || (this->step < 0 && this->current > this->stop);
                    }

                    bool operator==(const Iterator& other) const {
                        return !(*this != other);
                    }
            };

            Iterator begin() {
                return {std::next(std::begin(this->container), this->start),
                        this->start, this->stop, this->step};
            }

            Iterator end() {
                return {std::next(std::begin(this->container), this->stop),
                        this->stop, this->stop, this->step};
            }

    };

    // Helper function to instantiate a Slice
    template <typename Container, typename DifferenceType>
    Slice<Container, DifferenceType> slice(
            Container&& container,
            DifferenceType start, DifferenceType stop, DifferenceType step=1) {
        return {std::forward<Container>(container), start, stop, step};
    }

    //only give the end as an arg and assume step  is 1 and begin is 0
    template <typename Container, typename DifferenceType>
    Slice<Container, DifferenceType> slice(
            Container&& container, DifferenceType stop) {
        return {std::forward<Container>(container), 0, stop, 1};
    }

    template <typename T, typename DifferenceType>
    Slice<std::initializer_list<T>, DifferenceType> slice(
            std::initializer_list<T> il, DifferenceType start,
            DifferenceType stop, DifferenceType step=1) {
        return {il, start, stop, step};
    }

    template <typename T, typename DifferenceType>
    Slice<std::initializer_list<T>, DifferenceType> slice(
            std::initializer_list<T> il, DifferenceType stop) {
        return {il, 0, stop, 1};
    }
}

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2011,2015, Robert Escriva
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * 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.
//     * Neither the name of po6 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 OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// po6
#include "po6/net/socket.h"

using po6::net::socket;

socket :: socket()
    : fd(-1)
{
}

socket :: ~socket() throw ()
{
}

bool
socket :: reset(int domain, int type, int protocol)
{
    *this = ::socket(domain, type, protocol);
    return get() >= 0;
}

// On all platforms I checked, a sockaddr_in6 is larger than a
// sockaddr, which in turn is larger than a sockaddr_in.  As a
// result, we allocate the largest of the three and call it a
// sockaddr.

bool
socket :: bind(const ipaddr& addr, in_port_t port)
{
    sockaddr_in6 sa6;
    socklen_t salen = sizeof(sa6);
    sockaddr* sa = reinterpret_cast<sockaddr*>(&sa6);
    addr.pack(sa, &salen, port);
    return ::bind(get(), sa, salen) == 0;
}

bool
socket :: bind(const ipaddr& addr)
{
    return bind(addr, 0);
}

bool
socket :: bind(const location& loc)
{
    return bind(loc.address, loc.port);
}

bool
socket :: connect(const ipaddr& addr, in_port_t port)
{
    sockaddr_in6 sa6;
    socklen_t salen = sizeof(sa6);
    sockaddr* sa = reinterpret_cast<sockaddr*>(&sa6);
    addr.pack(sa, &salen, port);
    return ::connect(get(), sa, salen) == 0;
}

bool
socket :: connect(const location& loc)
{
    return connect(loc.address, loc.port);
}

bool
socket :: listen(int backlog)
{
    return ::listen(get(), backlog) == 0;
}

bool
socket :: accept(socket* newsock)
{
    newsock->close();
    int ret;

    if ((ret = ::accept(get(), NULL, NULL)) < 0)
    {
        return false;
    }

    *newsock = ret;
    return true;
}

bool
socket :: shutdown(int how)
{
    return ::shutdown(get(), how) == 0;
}

bool
socket :: getpeername(location* loc)
{
    sockaddr_in6 sa6;
    socklen_t salen = sizeof(sa6);
    sockaddr* sa = reinterpret_cast<sockaddr*>(&sa6);

    if (::getpeername(get(), sa, &salen) < 0)
    {
        return false;
    }

    return loc->set(sa, salen);
}

bool
socket :: getsockname(location* loc)
{
    sockaddr_in6 sa6;
    socklen_t salen = sizeof(sa6);
    sockaddr* sa = reinterpret_cast<sockaddr*>(&sa6);

    if (::getsockname(get(), sa, &salen) < 0)
    {
        return false;
    }

    return loc->set(sa, salen);
}

bool
socket :: set_sockopt(int level, int optname,
                      const void *optval, socklen_t optlen)
{
    return setsockopt(get(), level, optname, optval, optlen) == 0;
}

bool
socket :: set_reuseaddr()
{
    int yes = 1;
    return set_sockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
}

bool
socket :: set_tcp_nodelay()
{
    int yes = 1;
    return set_sockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes));
}

bool
socket :: sndbuf(size_t size)
{
    return set_sockopt(SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
}

bool
socket :: rcvbuf(size_t size)
{
    return set_sockopt(SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
}

bool
socket :: sndlowat(size_t size)
{
    return set_sockopt(SOL_SOCKET, SO_SNDLOWAT, &size, sizeof(size));
}

bool
socket :: rcvlowat(size_t size)
{
    return set_sockopt(SOL_SOCKET, SO_RCVLOWAT, &size, sizeof(size));
}

ssize_t
socket :: recv(void *buf, size_t len, int flags)
{
    return ::recv(get(), buf, len, flags);
}

ssize_t
socket :: xrecv(void *buf, size_t len, int flags)
{
    size_t rem = len;
    ssize_t amt = 0;

    while (rem > 0)
    {
        if ((amt = recv(buf, rem, flags)) < 0)
        {
            if (rem == len)
            {
                return -1;
            }
            else
            {
                break;
            }
        }
        else if (amt == 0)
        {
            break;
        }

        rem -= amt;
        buf = static_cast<char*>(buf) + amt;
    }

    return len - rem;
}

ssize_t
socket :: send(const void *buf, size_t len, int flags)
{
    return ::send(get(), buf, len, flags);
}

ssize_t
socket :: xsend(const void *buf, size_t len, int flags)
{
    size_t rem = len;
    ssize_t amt = 0;

    while (rem > 0)
    {
        if ((amt = send(buf, rem, flags)) < 0)
        {
            if (rem == len)
            {
                return -1;
            }
            else
            {
                break;
            }
        }
        else if (amt == 0)
        {
            break;
        }

        rem -= amt;
        buf = static_cast<const char*>(buf) + amt;
    }

    return len - rem;
}

po6::net::socket&
socket :: operator = (int f)
{
    *dynamic_cast<fd*>(this) = f;
    return *this;
}
<commit_msg>Discard "using po6::net::socket"<commit_after>// Copyright (c) 2011,2015, Robert Escriva
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * 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.
//     * Neither the name of po6 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 OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// po6
#include "po6/net/socket.h"

po6 :: net :: socket :: socket()
    : fd(-1)
{
}

po6 :: net :: socket :: ~socket() throw ()
{
}

bool
po6 :: net :: socket :: reset(int domain, int type, int protocol)
{
    *this = ::socket(domain, type, protocol);
    return get() >= 0;
}

// On all platforms I checked, a sockaddr_in6 is larger than a
// sockaddr, which in turn is larger than a sockaddr_in.  As a
// result, we allocate the largest of the three and call it a
// sockaddr.

bool
po6 :: net :: socket :: bind(const ipaddr& addr, in_port_t port)
{
    sockaddr_in6 sa6;
    socklen_t salen = sizeof(sa6);
    sockaddr* sa = reinterpret_cast<sockaddr*>(&sa6);
    addr.pack(sa, &salen, port);
    return ::bind(get(), sa, salen) == 0;
}

bool
po6 :: net :: socket :: bind(const ipaddr& addr)
{
    return bind(addr, 0);
}

bool
po6 :: net :: socket :: bind(const location& loc)
{
    return bind(loc.address, loc.port);
}

bool
po6 :: net :: socket :: connect(const ipaddr& addr, in_port_t port)
{
    sockaddr_in6 sa6;
    socklen_t salen = sizeof(sa6);
    sockaddr* sa = reinterpret_cast<sockaddr*>(&sa6);
    addr.pack(sa, &salen, port);
    return ::connect(get(), sa, salen) == 0;
}

bool
po6 :: net :: socket :: connect(const location& loc)
{
    return connect(loc.address, loc.port);
}

bool
po6 :: net :: socket :: listen(int backlog)
{
    return ::listen(get(), backlog) == 0;
}

bool
po6 :: net :: socket :: accept(socket* newsock)
{
    newsock->close();
    int ret;

    if ((ret = ::accept(get(), NULL, NULL)) < 0)
    {
        return false;
    }

    *newsock = ret;
    return true;
}

bool
po6 :: net :: socket :: shutdown(int how)
{
    return ::shutdown(get(), how) == 0;
}

bool
po6 :: net :: socket :: getpeername(location* loc)
{
    sockaddr_in6 sa6;
    socklen_t salen = sizeof(sa6);
    sockaddr* sa = reinterpret_cast<sockaddr*>(&sa6);

    if (::getpeername(get(), sa, &salen) < 0)
    {
        return false;
    }

    return loc->set(sa, salen);
}

bool
po6 :: net :: socket :: getsockname(location* loc)
{
    sockaddr_in6 sa6;
    socklen_t salen = sizeof(sa6);
    sockaddr* sa = reinterpret_cast<sockaddr*>(&sa6);

    if (::getsockname(get(), sa, &salen) < 0)
    {
        return false;
    }

    return loc->set(sa, salen);
}

bool
po6 :: net :: socket :: set_sockopt(int level, int optname,
                                    const void *optval, socklen_t optlen)
{
    return setsockopt(get(), level, optname, optval, optlen) == 0;
}

bool
po6 :: net :: socket :: set_reuseaddr()
{
    int yes = 1;
    return set_sockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
}

bool
po6 :: net :: socket :: set_tcp_nodelay()
{
    int yes = 1;
    return set_sockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes));
}

bool
po6 :: net :: socket :: sndbuf(size_t size)
{
    return set_sockopt(SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
}

bool
po6 :: net :: socket :: rcvbuf(size_t size)
{
    return set_sockopt(SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
}

bool
po6 :: net :: socket :: sndlowat(size_t size)
{
    return set_sockopt(SOL_SOCKET, SO_SNDLOWAT, &size, sizeof(size));
}

bool
po6 :: net :: socket :: rcvlowat(size_t size)
{
    return set_sockopt(SOL_SOCKET, SO_RCVLOWAT, &size, sizeof(size));
}

ssize_t
po6 :: net :: socket :: recv(void *buf, size_t len, int flags)
{
    return ::recv(get(), buf, len, flags);
}

ssize_t
po6 :: net :: socket :: xrecv(void *buf, size_t len, int flags)
{
    size_t rem = len;
    ssize_t amt = 0;

    while (rem > 0)
    {
        if ((amt = recv(buf, rem, flags)) < 0)
        {
            if (rem == len)
            {
                return -1;
            }
            else
            {
                break;
            }
        }
        else if (amt == 0)
        {
            break;
        }

        rem -= amt;
        buf = static_cast<char*>(buf) + amt;
    }

    return len - rem;
}

ssize_t
po6 :: net :: socket :: send(const void *buf, size_t len, int flags)
{
    return ::send(get(), buf, len, flags);
}

ssize_t
po6 :: net :: socket :: xsend(const void *buf, size_t len, int flags)
{
    size_t rem = len;
    ssize_t amt = 0;

    while (rem > 0)
    {
        if ((amt = send(buf, rem, flags)) < 0)
        {
            if (rem == len)
            {
                return -1;
            }
            else
            {
                break;
            }
        }
        else if (amt == 0)
        {
            break;
        }

        rem -= amt;
        buf = static_cast<const char*>(buf) + amt;
    }

    return len - rem;
}

po6::net::socket&
po6 :: net :: socket :: operator = (int f)
{
    *dynamic_cast<fd*>(this) = f;
    return *this;
}
<|endoftext|>


<commit_before>#include <cstdlib>
#include <cstdio>
#include <cstdint>
#include <cstring>
#include <cassert>
#include <algorithm>
#include <memory>

#ifdef WITH_RUNTIME_STATS
#   include "runtime_stats.cpp" // must be included before anything else
#endif
#include "input_data.cpp"
#include "quicksort-all.cpp"
#include "avx2-altquicksort.h"

#define USE_RDTSC // undef to get measurments in seconds
#ifdef USE_RDTSC
#   include "rdtsc.cpp"
#else
#   include "gettime.cpp"
#endif

class PerformanceTest final {

    int         iterations;
    InputData&  input;
    uint32_t*   tmp;

public:
    PerformanceTest(int n, InputData& input)
        : iterations(n)
        , input(input) {

        assert(iterations > 0);
        tmp = new uint32_t[input.count()];
    }

    ~PerformanceTest() {
        delete[] tmp;
    }

public:
    template <typename SORT_FUNCTION>
    uint64_t run(SORT_FUNCTION sort) {

        uint64_t time = 0;

        int k = iterations;
        while (k--) {
            memcpy(tmp, input.pointer(), input.size());

            uint64_t t1, t2;

#ifdef USE_RDTSC
            RDTSC_START(t1);
#else
            t1 = get_time();
#endif
            sort(input.pointer(), 0, input.count() - 1);

#ifdef USE_RDTSC
            RDTSC_START(t2);
#else
            t1 = get_time();
#endif

            const uint64_t dt = t2 - t1;

            if (time == 0) {
                time = dt;
            } else if (dt < time) {
                time = dt;
            }
        }

        return time;
    }
};

enum class InputType {
    randomfew,
    randomuniq,
    random,
    ascending,
    descending,
};

const char* as_string(InputType type) {
    switch (type) {
        case InputType::randomfew:
            return "randomfew";

        case InputType::randomuniq:
            return "randomuniq";

        case InputType::random:
            return "random";

        case InputType::ascending:
            return "ascending";

        case InputType::descending:
            return "descending";

        default:
            return "<unknown>";
    }
}

void std_qsort_wrapper(uint32_t* array, int left, int right) {

    std::qsort(array + left, right - left + 1, sizeof(uint32_t),  [](const void* a, const void* b)
    {
        uint32_t a1 = *static_cast<const uint32_t*>(a);
        uint32_t a2 = *static_cast<const uint32_t*>(b);

        if(a1 < a2) return -1;
        if(a1 > a2) return 1;
        return 0;
    });
}

void std_stable_sort_wrapper(uint32_t* array, int left, int right) {

    std::stable_sort(array + left, array + right + 1);
}

void std_sort_wrapper(uint32_t* array, int left, int right) {

    std::sort(array + left, array + right + 1);
}

class Test {

    std::unique_ptr<InputData> data;
    InputType   type;
    size_t      count;
    int         iterations;

public:
    Test(InputType type, size_t count, int iterations)
        : type(type)
        , count(count)
        , iterations(iterations) {

        switch (type) {
            case InputType::randomfew:
                data.reset(new InputRandomFew(count));
                break;

            case InputType::randomuniq:
                data.reset(new InputRandomUnique(count));
                break;

            case InputType::random:
                data.reset(new InputRandom(count));
                break;

            case InputType::ascending:
                data.reset(new InputAscending(count));
                break;

            case InputType::descending:
                data.reset(new InputDescending(count));
                break;
        }
    }

    void run() {

        printf("items count: %lu (%lu bytes), input %s\n", data->count(), data->size(), as_string(type));

        uint64_t ref = 0;
        ref = measure("std::sort",              std_sort_wrapper,             ref);
        measure("std::qsort",                   std_qsort_wrapper,            ref);
        measure("std::stable_sort",             std_stable_sort_wrapper,      ref);
        measure("quick sort",                   quicksort,                    ref);
#ifdef HAVE_AVX2_INSTRUCTIONS
        measure("AVX2 quick sort",              qs::avx2::quicksort,          ref);
        measure("AVX2 alt quicksort",           wrapped_avx2_pivotonlast_sort,ref);
#endif
#ifdef HAVE_AVX512F_INSTRUCTIONS
        measure("AVX512 quick sort",            qs::avx512::quicksort,        ref);
        measure("AVX512 quick sort - aux buf",  qs::avx512::auxbuffer_quicksort, ref);
        measure("AVX512 + popcnt quick sort",   qs::avx512::popcnt_quicksort, ref);
        measure("AVX512 + BMI2 quick sort",     qs::avx512::bmi2_quicksort,   ref);
#endif
    }

private:
    template <typename SORT_FUNCTION>
    uint64_t measure(const char* name, SORT_FUNCTION sort, uint64_t ref) {

        PerformanceTest test(iterations, *data);

        printf("%30s ... ", name); fflush(stdout);
#ifdef WITH_RUNTIME_STATS
        statistics.reset();
#endif
        uint64_t time = test.run(sort);

#ifdef USE_RDTSC
        printf("%10lu cycles", time);
        if (ref > 0) {
            printf(" (%0.2f)", ref/double(time));
        }

#   ifdef WITH_RUNTIME_STATS
        if (statistics.anything_collected()) {
            printf("\n");
            printf("\t\tpartition calls: %lu (+%lu scalar)\n", statistics.partition_calls, statistics.scalar__partition_calls);
            printf("\t\titems processed: %lu (+%lu by scalar partition)\n", statistics.items_processed, statistics.scalar__items_processed);

            const size_t total_items = statistics.items_processed + statistics.scalar__items_processed;

            if (total_items != 0) {
                const double cpi = double(time)/total_items;
                printf("\t\t               : %0.4f cycles/item\n", cpi * iterations);
            }
        }
#   endif // WITH_RUNTIME_STATS
#else
        printf("%0.4f s", time/1000000.0);
        if (ref > 0) {
            printf(" (%0.2f)\n", ref/double(time));
        }
#endif
        putchar('\n');

        return time;
    }
};

// ------------------------------------------------------------

void usage() {
    puts("usage:");
    puts("speed SIZE ITERATIONS INPUT");
    puts("");
    puts("where");
    puts("* SIZE       - number of 32-bit elements");
    puts("* ITERATIONS - number of iterations");
    puts("* INPUT      - one of:");
    puts("                 ascending (or asc)");
    puts("                 descending (or dsc, desc)");
    puts("                 random (or rnd, rand)");
    puts("                 randomfew");
    puts("                 randomuniq");
}

int main(int argc, char* argv[]) {

    if (argc < 4) {
        usage();
        return EXIT_FAILURE;
    }

    int count      = atoi(argv[1]);
    int iterations = atoi(argv[2]);
    InputType type;

#define is_keyword(key) (strcmp(argv[3], key) == 0)
    if (is_keyword("descending") || is_keyword("desc") || is_keyword("dsc")) {
        type = InputType::descending;
    } else if (is_keyword("ascending") || is_keyword("asc")) {
        type = InputType::ascending;
    } else if (is_keyword("random") || is_keyword("rnd") || is_keyword("rand")) {
        type = InputType::random;
    } else if (is_keyword("randomfew")) {
        type = InputType::randomfew;
    } else if (is_keyword("randomuniq")) {
        type = InputType::randomuniq;
    } else {
        usage();
        return EXIT_FAILURE;
    }
#undef is_keyword

#ifdef USE_RDTSC
    RDTSC_SET_OVERHEAD(rdtsc_overhead_func(1), iterations);
#endif
    Test test(type, count, iterations);
    test.run();

    return EXIT_SUCCESS;
}
<commit_msg>speed util: parse command line<commit_after>#include <cstdlib>
#include <cstdio>
#include <cstdint>
#include <cstring>
#include <cassert>
#include <algorithm>
#include <memory>

#include "cmdline.cpp"
#ifdef WITH_RUNTIME_STATS
#   include "runtime_stats.cpp" // must be included before anything else
#endif
#include "input_data.cpp"
#include "quicksort-all.cpp"
#include "avx2-altquicksort.h"

#define USE_RDTSC // undef to get measurments in seconds
#ifdef USE_RDTSC
#   include "rdtsc.cpp"
#else
#   include "gettime.cpp"
#endif

class PerformanceTest final {

    int         iterations;
    InputData&  input;
    uint32_t*   tmp;

public:
    PerformanceTest(int n, InputData& input)
        : iterations(n)
        , input(input) {

        assert(iterations > 0);
        tmp = new uint32_t[input.count()];
    }

    ~PerformanceTest() {
        delete[] tmp;
    }

public:
    template <typename SORT_FUNCTION>
    uint64_t run(SORT_FUNCTION sort) {

        uint64_t time = 0;

        int k = iterations;
        while (k--) {
            memcpy(tmp, input.pointer(), input.size());

            uint64_t t1, t2;

#ifdef USE_RDTSC
            RDTSC_START(t1);
#else
            t1 = get_time();
#endif
            sort(input.pointer(), 0, input.count() - 1);

#ifdef USE_RDTSC
            RDTSC_START(t2);
#else
            t1 = get_time();
#endif

            const uint64_t dt = t2 - t1;

            if (time == 0) {
                time = dt;
            } else if (dt < time) {
                time = dt;
            }
        }

        return time;
    }
};

enum class InputType {
    randomfew,
    randomuniq,
    random,
    ascending,
    descending,
};

const char* as_string(InputType type) {
    switch (type) {
        case InputType::randomfew:
            return "randomfew";

        case InputType::randomuniq:
            return "randomuniq";

        case InputType::random:
            return "random";

        case InputType::ascending:
            return "ascending";

        case InputType::descending:
            return "descending";

        default:
            return "<unknown>";
    }
}

void std_qsort_wrapper(uint32_t* array, int left, int right) {

    std::qsort(array + left, right - left + 1, sizeof(uint32_t),  [](const void* a, const void* b)
    {
        uint32_t a1 = *static_cast<const uint32_t*>(a);
        uint32_t a2 = *static_cast<const uint32_t*>(b);

        if(a1 < a2) return -1;
        if(a1 > a2) return 1;
        return 0;
    });
}

void std_stable_sort_wrapper(uint32_t* array, int left, int right) {

    std::stable_sort(array + left, array + right + 1);
}

void std_sort_wrapper(uint32_t* array, int left, int right) {

    std::sort(array + left, array + right + 1);
}

class Flags {
    public:
        bool std_sort;
        bool std_qsort;
        bool std_stable_sort;
        bool quicksort;
        bool avx2;
        bool avx2_alt;
        bool avx512;
        bool avx512_buf;
        bool avx512_popcnt;
        bool avx512_bmi;

    public:
        Flags(const CommandLine& cmd) {

            enable_all(false);

            bool any_set = false;
            if (cmd.has("-std-sort")) {
                std_sort = true;
                any_set = true;
            }

            if (cmd.has("-std-qsort")) {
                std_qsort = true;
                any_set = true;
            }

            if (cmd.has("-std-stable-sort") || cmd.has("-std-stable")) {
                std_stable_sort = true;
                any_set = true;
            }

            if (cmd.has("-quicksort")) {
                quicksort = true;
                any_set = true;
            }

            if (cmd.has("-avx2")) {
                avx2 = true;
                any_set = true;
            }

            if (cmd.has("-avx2-alt")) {
                avx2_alt = true;
                any_set = true;
            }

            if (cmd.has("-avx512")) {
                avx512 = true;
                any_set = true;
            }

            if (cmd.has("-avx512-buf")) {
                avx512_buf = true;
                any_set = true;
            }

            if (cmd.has("-avx512-popcnt")) {
                avx512_popcnt = true;
                any_set = true;
            }

            if (cmd.has("-avx512-bmi")) {
                avx512_bmi = true;
                any_set = true;
            }

            if (!any_set) {
                enable_all(true);
            }
        }

        void enable_all(bool val) {
            std_sort      = val;
            std_qsort     = val;
            std_stable_sort = val;
            quicksort     = val;
            avx2          = val;
            avx2_alt      = val;
            avx512        = val;
            avx512_buf    = val;
            avx512_popcnt = val;
            avx512_bmi    = val;
        }
};

class Test {

    std::unique_ptr<InputData> data;
    InputType   type;
    size_t      count;
    int         iterations;
    Flags       flags;
    uint64_t    ref;

public:
    Test(InputType type, size_t count, int iterations, Flags&& flags)
        : type(type)
        , count(count)
        , iterations(iterations)
        , flags(std::move(flags)) {

        switch (type) {
            case InputType::randomfew:
                data.reset(new InputRandomFew(count));
                break;

            case InputType::randomuniq:
                data.reset(new InputRandomUnique(count));
                break;

            case InputType::random:
                data.reset(new InputRandom(count));
                break;

            case InputType::ascending:
                data.reset(new InputAscending(count));
                break;

            case InputType::descending:
                data.reset(new InputDescending(count));
                break;
        }
    }

    void run() {

        printf("items count: %lu (%lu bytes), input %s\n", data->count(), data->size(), as_string(type));

        ref = 0;

        if (flags.std_sort) {
            measure("std::sort", std_sort_wrapper);
        }

        if (flags.std_qsort) {
            measure("std::qsort", std_qsort_wrapper);
        }

        if (flags.std_stable_sort) {
            measure("std::stable_sort", std_stable_sort_wrapper);
        }

        if (flags.std_qsort) {
            measure("quick sort", quicksort);
        }
#ifdef HAVE_AVX2_INSTRUCTIONS
        if (flags.avx2) {
            measure("AVX2 quick sort", qs::avx2::quicksort);
        }

        if (flags.avx2_alt) {
            measure("AVX2 alt quicksort", wrapped_avx2_pivotonlast_sort);
        }
#endif
#ifdef HAVE_AVX512F_INSTRUCTIONS
        if (flags.avx512) {
            measure("AVX512 quick sort", qs::avx512::quicksort);
        }

        if (flags.avx512_buf) {
            measure("AVX512 quick sort - aux buf", qs::avx512::auxbuffer_quicksort);
        }

        if (flags.avx512_popcnt) {
            measure("AVX512 + popcnt quick sort", qs::avx512::popcnt_quicksort);
        }

        if (flags.avx512_bmi) {
            measure("AVX512 + BMI2 quick sort", qs::avx512::bmi2_quicksort);
        }
#endif
    }

private:
    template <typename SORT_FUNCTION>
    void measure(const char* name, SORT_FUNCTION sort) {

        PerformanceTest test(iterations, *data);

        printf("%30s ... ", name); fflush(stdout);
#ifdef WITH_RUNTIME_STATS
        statistics.reset();
#endif
        uint64_t time = test.run(sort);

#ifdef USE_RDTSC
        printf("%10lu cycles", time);
        if (ref > 0) {
            printf(" (%0.2f)", ref/double(time));
        }

#   ifdef WITH_RUNTIME_STATS
        if (statistics.anything_collected()) {
            printf("\n");
            printf("\t\tpartition calls: %lu (+%lu scalar)\n", statistics.partition_calls, statistics.scalar__partition_calls);
            printf("\t\titems processed: %lu (+%lu by scalar partition)\n", statistics.items_processed, statistics.scalar__items_processed);

            const size_t total_items = statistics.items_processed + statistics.scalar__items_processed;

            if (total_items != 0) {
                const double cpi = double(time)/total_items;
                printf("\t\t               : %0.4f cycles/item\n", cpi * iterations);
            }
        }
#   endif // WITH_RUNTIME_STATS
#else
        printf("%0.4f s", time/1000000.0);
        if (ref > 0) {
            printf(" (%0.2f)\n", ref/double(time));
        }
#endif
        putchar('\n');

        if (ref == 0) {
            ref = time;
        }
    }
};

// ------------------------------------------------------------

void usage() {
    puts("usage:");
    puts("speed SIZE ITERATIONS INPUT [options]");
    puts("");
    puts("where");
    puts("* SIZE       - number of 32-bit elements");
    puts("* ITERATIONS - number of iterations");
    puts("* INPUT      - one of:");
    puts("                 ascending (or asc)");
    puts("                 descending (or dsc, desc)");
    puts("                 random (or rnd, rand)");
    puts("                 randomfew");
    puts("                 randomuniq");
    puts("options      - optional name of procedure(s) to run");
}

int main(int argc, char* argv[]) {

    if (argc < 4) {
        usage();
        return EXIT_FAILURE;
    }

    int count      = atoi(argv[1]);
    int iterations = atoi(argv[2]);
    InputType type;

#define is_keyword(key) (strcmp(argv[3], key) == 0)
    if (is_keyword("descending") || is_keyword("desc") || is_keyword("dsc")) {
        type = InputType::descending;
    } else if (is_keyword("ascending") || is_keyword("asc")) {
        type = InputType::ascending;
    } else if (is_keyword("random") || is_keyword("rnd") || is_keyword("rand")) {
        type = InputType::random;
    } else if (is_keyword("randomfew")) {
        type = InputType::randomfew;
    } else if (is_keyword("randomuniq")) {
        type = InputType::randomuniq;
    } else {
        usage();
        return EXIT_FAILURE;
    }
#undef is_keyword

#ifdef USE_RDTSC
    RDTSC_SET_OVERHEAD(rdtsc_overhead_func(1), iterations);
#endif
    CommandLine cmd(argc, argv);
    Flags flags(cmd);
    Test test(type, count, iterations, std::move(flags));
    test.run();

    return EXIT_SUCCESS;
}
<|endoftext|>