<commit_before>// ignore unused parameters in LLVM libraries
#if (__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

#include <llvm/Config/llvm-config.h>

#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))
 #include <llvm/Support/CFG.h>
#else
 #include <llvm/IR/CFG.h>
#endif

#include <llvm/IR/Instructions.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/raw_os_ostream.h>

#if (__clang__)
#pragma clang diagnostic pop // ignore -Wunused-parameter
#else
#pragma GCC diagnostic pop
#endif

#include "dg/llvm/analysis/PointsTo/PointerGraph.h"

namespace dg {
namespace analysis {
namespace pta {

void LLVMPointerGraphBuilder::addArgumentOperands(const llvm::CallInst *CI,
                                                     PSNode *arg, int idx)
{
    assert(idx < static_cast<int>(CI->getNumArgOperands()));
    PSNode *op = tryGetOperand(CI->getArgOperand(idx));
    if (op && !arg->hasOperand(op)) {
        // NOTE: do not add an operand multiple-times
        // (when a function is called multiple-times with
        // the same actual parameters)
        arg->addOperand(op);
    }
}

void LLVMPointerGraphBuilder::addArgumentOperands(const llvm::CallInst &CI, PSNode &node)
{
    auto sentinel = CI.getNumArgOperands();
    for (unsigned i = 0; i < sentinel; ++i) {
        PSNode *operand = tryGetOperand(CI.getArgOperand(i));
        if (operand && !node.hasOperand(operand)) {
            node.addOperand(operand);
        }
    }
}

void LLVMPointerGraphBuilder::addArgumentOperands(const llvm::Function *F,
                                                     PSNode *arg, int idx)
{
    using namespace llvm;

    for (auto I = F->use_begin(), E = F->use_end(); I != E; ++I) {
#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))
        const Value *use = *I;
#else
        const Value *use = I->getUser();
#endif
        const CallInst *CI = dyn_cast<CallInst>(use);
        if (CI && CI->getCalledFunction() == F)
            addArgumentOperands(CI, arg, idx);
    }
}

void LLVMPointerGraphBuilder::addArgumentsOperands(const llvm::Function *F,
                                                      const llvm::CallInst *CI, int index)
{
    for (auto A = F->arg_begin(), E = F->arg_end(); A != E; ++A, ++index) {
        auto it = nodes_map.find(&*A);
        assert(it != nodes_map.end());
        PSNodesSeq& cur = it->second;

        if (CI) {
            // with func ptr call we know from which
            // call we should take the values
            addArgumentOperands(CI, cur.getSingleNode(), index);
        } else {
             // with regular call just use all calls
            addArgumentOperands(F, cur.getSingleNode(), index);
        }
    }
}

void LLVMPointerGraphBuilder::addVariadicArgumentOperands(const llvm::Function *F,
                                                             const llvm::CallInst *CI,
                                                             PSNode *arg)
{
    for (unsigned idx = F->arg_size() - 1; idx < CI->getNumArgOperands(); ++idx)
        addArgumentOperands(CI, arg, idx);
}

void LLVMPointerGraphBuilder::addVariadicArgumentOperands(const llvm::Function *F,
                                                             PSNode *arg)
{
    using namespace llvm;

    for (auto I = F->use_begin(), E = F->use_end(); I != E; ++I) {
#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))
        const Value *use = *I;
#else
        const Value *use = I->getUser();
#endif
        const CallInst *CI = dyn_cast<CallInst>(use);
        if (CI && CI->getCalledFunction() == F)
            addVariadicArgumentOperands(F, CI, arg);
        // if this is funcptr, we handle it in the other
        // version of addVariadicArgumentOperands
    }
}

void LLVMPointerGraphBuilder::addReturnNodesOperands(const llvm::Function *F,
                                                     PointerSubgraph& subg,
                                                     PSNode *callNode)
{
    using namespace llvm;

    for (PSNode *r : subg.returnNodes) {
        // call-return node is like a PHI node
        // But we're interested only in the nodes that return some value
        // from subprocedure, not for all nodes that have no successor.
        if (callNode) {
            addReturnNodeOperand(callNode, r);
        } else {
            addReturnNodeOperand(F, r);
        }
    }
}

void LLVMPointerGraphBuilder::addReturnNodeOperand(PSNode *callNode, PSNode *ret) {
    assert(PSNodeRet::get(ret));
    auto callReturn = PSNodeCallRet::cast(callNode->getPairedNode());
    // the function must be defined, since we have the return node,
    // so there must be associated the return node
    assert(callReturn);
    assert(callReturn != callNode);
    assert(callReturn->getType() == PSNodeType::CALL_RETURN);

    if (!callReturn->hasOperand(ret))
        callReturn->addOperand(ret);

    // setup return edges (do it here, since recursive calls
    // may not have build return nodes earlier)
    PSNodeRet::get(ret)->addReturnSite(callReturn);
    callReturn->addReturn(ret);
}

void LLVMPointerGraphBuilder::addReturnNodeOperand(const llvm::Function *F, PSNode *op)
{
    using namespace llvm;

    for (auto I = F->use_begin(), E = F->use_end(); I != E; ++I) {
#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))
        const Value *use = *I;
#else
        const Value *use = I->getUser();
#endif
        // get every call and its assocciated return and add the operand
        const CallInst *CI = dyn_cast<CallInst>(use);
        if (CI && CI->getCalledFunction() == F) {
            PSNode *callNode = getNodes(CI)->getFirst();
            assert(PSNodeCall::cast(callNode) && "Got wrong node");
            // since we're building the graph from entry only where we can reach it,
            // we may not have all call-sites of this function
            if (!callNode)
                continue;

            addReturnNodeOperand(callNode, op);
        }
    }
}

void LLVMPointerGraphBuilder::addInterproceduralPthreadOperands(const llvm::Function *F, const llvm::CallInst *CI)
{
    // last argument (with index 3) is argument to function pthread_create will call
    addArgumentsOperands(F, CI, 3);
}

void LLVMPointerGraphBuilder::addInterproceduralOperands(const llvm::Function *F,
                                                            PointerSubgraph& subg,
                                                            const llvm::CallInst *CI,
                                                            PSNode *callNode)
{
    assert((!CI || callNode) && (!callNode || CI));

    // add operands to arguments' PHI nodes
    addArgumentsOperands(F, CI);

    if (F->isVarArg()) {
        assert(subg.vararg);
        if (CI)
            // funcptr call
            addVariadicArgumentOperands(F, CI, subg.vararg);
        else
            addVariadicArgumentOperands(F, subg.vararg);
    }

    if (!subg.returnNodes.empty()) {
        addReturnNodesOperands(F, subg, callNode);
    } else {
        // disconnect call-return nodes
        auto callReturnNode = PSNodeCallRet::cast(callNode->getPairedNode());
        assert(callReturnNode && callNode != callReturnNode);
        assert(callNode->getSingleSuccessor() == callReturnNode);
        callNode->removeSingleSuccessor();
    }
}

} // namespace pta
} // namespace analysis
} // namespace dg
<commit_msg>Fix a possible nullptr dereference<commit_after>// ignore unused parameters in LLVM libraries
#if (__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

#include <llvm/Config/llvm-config.h>

#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))
 #include <llvm/Support/CFG.h>
#else
 #include <llvm/IR/CFG.h>
#endif

#include <llvm/IR/Instructions.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/raw_os_ostream.h>

#if (__clang__)
#pragma clang diagnostic pop // ignore -Wunused-parameter
#else
#pragma GCC diagnostic pop
#endif

#include "dg/llvm/analysis/PointsTo/PointerGraph.h"

namespace dg {
namespace analysis {
namespace pta {

void LLVMPointerGraphBuilder::addArgumentOperands(const llvm::CallInst *CI,
                                                     PSNode *arg, int idx)
{
    assert(idx < static_cast<int>(CI->getNumArgOperands()));
    PSNode *op = tryGetOperand(CI->getArgOperand(idx));
    if (op && !arg->hasOperand(op)) {
        // NOTE: do not add an operand multiple-times
        // (when a function is called multiple-times with
        // the same actual parameters)
        arg->addOperand(op);
    }
}

void LLVMPointerGraphBuilder::addArgumentOperands(const llvm::CallInst &CI, PSNode &node)
{
    auto sentinel = CI.getNumArgOperands();
    for (unsigned i = 0; i < sentinel; ++i) {
        PSNode *operand = tryGetOperand(CI.getArgOperand(i));
        if (operand && !node.hasOperand(operand)) {
            node.addOperand(operand);
        }
    }
}

void LLVMPointerGraphBuilder::addArgumentOperands(const llvm::Function *F,
                                                     PSNode *arg, int idx)
{
    using namespace llvm;

    for (auto I = F->use_begin(), E = F->use_end(); I != E; ++I) {
#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))
        const Value *use = *I;
#else
        const Value *use = I->getUser();
#endif
        const CallInst *CI = dyn_cast<CallInst>(use);
        if (CI && CI->getCalledFunction() == F)
            addArgumentOperands(CI, arg, idx);
    }
}

void LLVMPointerGraphBuilder::addArgumentsOperands(const llvm::Function *F,
                                                      const llvm::CallInst *CI, int index)
{
    for (auto A = F->arg_begin(), E = F->arg_end(); A != E; ++A, ++index) {
        auto it = nodes_map.find(&*A);
        assert(it != nodes_map.end());
        PSNodesSeq& cur = it->second;

        if (CI) {
            // with func ptr call we know from which
            // call we should take the values
            addArgumentOperands(CI, cur.getSingleNode(), index);
        } else {
             // with regular call just use all calls
            addArgumentOperands(F, cur.getSingleNode(), index);
        }
    }
}

void LLVMPointerGraphBuilder::addVariadicArgumentOperands(const llvm::Function *F,
                                                             const llvm::CallInst *CI,
                                                             PSNode *arg)
{
    for (unsigned idx = F->arg_size() - 1; idx < CI->getNumArgOperands(); ++idx)
        addArgumentOperands(CI, arg, idx);
}

void LLVMPointerGraphBuilder::addVariadicArgumentOperands(const llvm::Function *F,
                                                             PSNode *arg)
{
    using namespace llvm;

    for (auto I = F->use_begin(), E = F->use_end(); I != E; ++I) {
#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))
        const Value *use = *I;
#else
        const Value *use = I->getUser();
#endif
        const CallInst *CI = dyn_cast<CallInst>(use);
        if (CI && CI->getCalledFunction() == F)
            addVariadicArgumentOperands(F, CI, arg);
        // if this is funcptr, we handle it in the other
        // version of addVariadicArgumentOperands
    }
}

void LLVMPointerGraphBuilder::addReturnNodesOperands(const llvm::Function *F,
                                                     PointerSubgraph& subg,
                                                     PSNode *callNode)
{
    using namespace llvm;

    for (PSNode *r : subg.returnNodes) {
        // call-return node is like a PHI node
        // But we're interested only in the nodes that return some value
        // from subprocedure, not for all nodes that have no successor.
        if (callNode) {
            addReturnNodeOperand(callNode, r);
        } else {
            addReturnNodeOperand(F, r);
        }
    }
}

void LLVMPointerGraphBuilder::addReturnNodeOperand(PSNode *callNode, PSNode *ret) {
    assert(PSNodeRet::get(ret));
    auto callReturn = PSNodeCallRet::cast(callNode->getPairedNode());
    // the function must be defined, since we have the return node,
    // so there must be associated the return node
    assert(callReturn);
    assert(callReturn != callNode);
    assert(callReturn->getType() == PSNodeType::CALL_RETURN);

    if (!callReturn->hasOperand(ret))
        callReturn->addOperand(ret);

    // setup return edges (do it here, since recursive calls
    // may not have build return nodes earlier)
    PSNodeRet::get(ret)->addReturnSite(callReturn);
    callReturn->addReturn(ret);
}

void LLVMPointerGraphBuilder::addReturnNodeOperand(const llvm::Function *F, PSNode *op)
{
    using namespace llvm;

    for (auto I = F->use_begin(), E = F->use_end(); I != E; ++I) {
#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))
        const Value *use = *I;
#else
        const Value *use = I->getUser();
#endif
        // get every call and its assocciated return and add the operand
        const CallInst *CI = dyn_cast<CallInst>(use);
        if (CI && CI->getCalledFunction() == F) {
            PSNode *callNode = getNodes(CI)->getFirst();
            assert(PSNodeCall::cast(callNode) && "Got wrong node");
            // since we're building the graph from entry only where we can reach it,
            // we may not have all call-sites of this function
            if (!callNode)
                continue;

            addReturnNodeOperand(callNode, op);
        }
    }
}

void LLVMPointerGraphBuilder::addInterproceduralPthreadOperands(const llvm::Function *F, const llvm::CallInst *CI)
{
    // last argument (with index 3) is argument to function pthread_create will call
    addArgumentsOperands(F, CI, 3);
}

void LLVMPointerGraphBuilder::addInterproceduralOperands(const llvm::Function *F,
                                                         PointerSubgraph& subg,
                                                         const llvm::CallInst *CI,
                                                         PSNode *callNode)
{
    assert((!CI || callNode) && (!callNode || CI));

    // add operands to arguments' PHI nodes
    addArgumentsOperands(F, CI);

    if (F->isVarArg()) {
        assert(subg.vararg);
        if (CI)
            // funcptr call
            addVariadicArgumentOperands(F, CI, subg.vararg);
        else
            addVariadicArgumentOperands(F, subg.vararg);
    }

    if (!subg.returnNodes.empty()) {
        addReturnNodesOperands(F, subg, callNode);
    } else if (callNode) {
        // disconnect call-return nodes
        auto callReturnNode = PSNodeCallRet::cast(callNode->getPairedNode());
        assert(callReturnNode && callNode != callReturnNode);
        assert(callNode->getSingleSuccessor() == callReturnNode);
        callNode->removeSingleSuccessor();
    }
}

} // namespace pta
} // namespace analysis
} // namespace dg
<|endoftext|>


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

#include "fx/ConvolverSound.h"
#include "fx/BinauralSound.h"
#include "fx/Source.h"
#include "fx/HRTF.h"
#include "util/ThreadPool.h"
#include "devices/DeviceManager.h"
#include "devices/IDevice.h"
#include "devices/IDeviceFactory.h"
#include "devices/IHandle.h"
#include "plugin/PluginManager.h"
#include "file/File.h"
#include "Exception.h"

#include <iostream>
#include <thread>
#include <chrono>
#include <sstream>
#include <iomanip>

using namespace aud;

void loadHRTFs(std::shared_ptr<HRTF> hrtfs);

int main(int argc, char* argv[])
{
	if(argc != 2)
	{
		std::cerr << "Usage: " << argv[0] << " <sound>"  << std::endl;
		return 1;
	}

	PluginManager::loadPlugins("");

	auto factory = DeviceManager::getDefaultDeviceFactory();
	auto device = factory->openDevice();

	std::shared_ptr<FFTPlan> plan(std::make_shared<FFTPlan>(4096, true));
	std::shared_ptr<ThreadPool> threadPool(std::make_shared<ThreadPool>(std::thread::hardware_concurrency()));
	std::shared_ptr<File> file1(std::make_shared<File>(argv[1]));
	std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>(plan));
	std::shared_ptr<Source> source = std::make_shared<Source>(0, 0);

	loadHRTFs(hrtfs);

	std::shared_ptr<BinauralSound> binaural(std::make_shared<BinauralSound>(file1, hrtfs, source, threadPool, plan));
	std::shared_ptr<ImpulseResponse> ir = std::make_shared<ImpulseResponse>(std::make_shared<StreamBuffer>(std::make_shared<File>("full/headphones+spkr/Opti-inverse.wav")), plan);
	std::shared_ptr<ConvolverSound> convolver = std::make_shared<ConvolverSound>(binaural, ir, threadPool, plan);

	device->lock();
	auto handle = device->play(convolver);
	handle->setLoopCount(-1);
	device->unlock();

	float x = 0;
	float y = 0;
	float yInc = 1;
	while(true)
	{
		std::this_thread::sleep_for(std::chrono::milliseconds(100));
		x += 3;
		y += yInc;
		if(y >= 80)
		{
			y = 80;
			yInc = -1;
		}
		else if(y <= -40)
		{
			y = -40;
			yInc = 1;
		}
		if(x >= 360)
			x = 0;
		source->setAzimuth(x);
		//source->setElevation(y);
		std::cout << "Azimuth: " << x << "Elevation: " << y << std::endl;
	}

	return 0;
}

void loadHRTFs(std::shared_ptr<HRTF> hrtfs)
{
	std::stringstream ss;

	int step = 5;
	int az = 0;
	int azF = 355;
	while(azF >= 0)
	{
		ss << std::setw(3) << std::setfill('0') << azF;
		hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>("full/elev0/L0e" + ss.str() + "a.wav")), az, 0);
		hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>("full/elev10/L10e" + ss.str() + "a.wav")), az, 10);
		hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>("full/elev-10/L-10e" + ss.str() + "a.wav")), az, -10);
		hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>("full/elev20/L20e" + ss.str() + "a.wav")), az, 20);
		hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>("full/elev-20/L-20e" + ss.str() + "a.wav")), az, -20);
		az += step;
		azF -= step;
		ss.str("");
		ss.clear();
	}

	step = 6;
	az = 0;
	azF = 354;
	while(azF >= 0)
	{
		ss << std::setw(3) << std::setfill('0') << azF;
		hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>("full/elev30/L30e" + ss.str() + "a.wav")), az, 30);
		hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>("full/elev-30/L-30e" + ss.str() + "a.wav")), az, -30);
		az += step;
		azF -= step;
		ss.str("");
		ss.clear();
	}

	step = 1;
	az = 0;
	azF = 360;
	while(azF >= 0)
	{
		ss << std::setw(3) << std::setfill('0') << azF;
		try
		{
			hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>("full/elev40/L40e" + ss.str() + "a.wav")), az, 40);
			hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>("full/elev-40/L-40e" + ss.str() + "a.wav")), az, -40);
		}
		catch(Exception& e)
		{
		}

		az += step;
		azF -= step;
		ss.str("");
		ss.clear();
	}

	step = 8;
	az = 0;
	azF = 352;
	while(azF >= 0)
	{
		ss << std::setw(3) << std::setfill('0') << azF;
		hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>("full/elev50/L50e" + ss.str() + "a.wav")), az, 50);
		az += step;
		azF -= step;
		ss.str("");
		ss.clear();
	}

	step = 10;
	az = 0;
	azF = 350;
	while(azF >= 0)
	{
		ss << std::setw(3) << std::setfill('0') << azF;
		hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>("full/elev60/L60e" + ss.str() + "a.wav")), az, 60);
		az += step;
		azF -= step;
		ss.str("");
		ss.clear();
	}

	step = 15;
	az = 0;
	azF = 345;
	while(azF >= 0)
	{
		ss << std::setw(3) << std::setfill('0') << azF;
		hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>("full/elev70/L70e" + ss.str() + "a.wav")), az, 70);
		az += step;
		azF -= step;
		ss.str("");
		ss.clear();
	}

	step = 30;
	az = 0;
	azF = 330;
	while(azF >= 0)
	{
		ss << std::setw(3) << std::setfill('0') << azF;
		hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>("full/elev80/L80e" + ss.str() + "a.wav")), az, 80);
		az += step;
		azF -= step;
		ss.str("");
		ss.clear();
	}

	hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>("full/elev90/L90e000a.wav")), 0, 90);
}
<commit_msg>Changed the way to load HRTFs in the binaural demo. (Windows only for now)<commit_after>/*******************************************************************************
* Copyright 2009-2015 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/

#include "fx/ConvolverSound.h"
#include "fx/BinauralSound.h"
#include "fx/Source.h"
#include "fx/HRTF.h"
#include "util/ThreadPool.h"
#include "devices/DeviceManager.h"
#include "devices/IDevice.h"
#include "devices/IDeviceFactory.h"
#include "devices/IHandle.h"
#include "plugin/PluginManager.h"
#include "file/File.h"
#include "Exception.h"

#include <windows.h>
#include <string>
#include <iostream>
#include <thread>
#include <chrono>

using namespace aud;

void loadHRTFs(std::string path, std::shared_ptr<HRTF> hrtfs);

int main(int argc, char* argv[])
{
	/*This demo uses KEMAR HRTFs.*/
	if(argc != 3 && argc != 4)
	{
		std::cerr << "Usage: " << argv[0] << " <sound>"  << " <HRTFs path>" << " [inverse speaker impulse response]" << std::endl;
		return 1;
	}

	PluginManager::loadPlugins("");

	auto factory = DeviceManager::getDefaultDeviceFactory();
	auto device = factory->openDevice();

	std::shared_ptr<FFTPlan> plan(std::make_shared<FFTPlan>(4096, true));
	std::shared_ptr<ThreadPool> threadPool(std::make_shared<ThreadPool>(std::thread::hardware_concurrency()));
	std::shared_ptr<File> file1(std::make_shared<File>(argv[1]));
	std::shared_ptr<HRTF> hrtfs(std::make_shared<HRTF>(plan));
	std::shared_ptr<Source> source = std::make_shared<Source>(0, 0);

	loadHRTFs(argv[2], hrtfs);

	std::shared_ptr<BinauralSound> binaural(std::make_shared<BinauralSound>(file1, hrtfs, source, threadPool, plan));

	device->lock();
	if (argc == 4)
	{
		std::shared_ptr<ImpulseResponse> ir = std::make_shared<ImpulseResponse>(std::make_shared<StreamBuffer>(std::make_shared<File>(argv[3])), plan);
		std::shared_ptr<ConvolverSound> convolver = std::make_shared<ConvolverSound>(binaural, ir, threadPool, plan);
		auto handle = device->play(convolver);
		handle->setLoopCount(-1);
	}
	else
	{
		auto handle = device->play(binaural);
		handle->setLoopCount(-1);
	}
	device->unlock();

	float x = 0;
	float y = 0;
	float yInc = 5;
	while(true)
	{
		std::this_thread::sleep_for(std::chrono::milliseconds(500));
		x += 15;
		y += yInc;
		if(y >= 60)
		{
			y = 60;
			yInc = -5;
		}
		else if(y <= -40)
		{
			y = -40;
			yInc = 5;
		}
		if(x >= 360)
			x = 0;

		source->setAzimuth(x);
		source->setElevation(y);
		std::cout << " Azimuth: " << x << " - Elevation: " << y << std::endl;
	}

	return 0;
}

void loadHRTFs(std::string path, std::shared_ptr<HRTF> hrtfs)
{
	std::string readpath = path;

	WIN32_FIND_DATA entry;
	bool found_file = true;
	std::string search = readpath + "\\*";
	HANDLE dir = FindFirstFile(search.c_str(), &entry);
	float azim, elev;

	while(found_file)
	{
		std::string filename = entry.cFileName;

		if (filename.front() == 'R')
		{
			elev = std::stof(filename.substr(1, filename.find("e") - 1));
			azim = std::stof(filename.substr(filename.find("e") + 1, filename.find("a") - filename.find("e") - 1));
			hrtfs->addImpulseResponse(std::make_shared<StreamBuffer>(std::make_shared<File>(path + "/" + filename)), azim, elev);
		}
		found_file = FindNextFile(dir, &entry);
	}
	FindClose(dir);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015-2017 ARM Limited
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2004-2005 The Regents of The University of Michigan
 * Copyright (c) 2013 Advanced Micro Devices, Inc.
 * 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 the copyright holders 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.
 */

#ifndef __CPU_O3_RENAME_MAP_HH__
#define __CPU_O3_RENAME_MAP_HH__

#include <iostream>
#include <utility>
#include <vector>

#include "arch/types.hh"
#include "config/the_isa.hh"
#include "cpu/o3/free_list.hh"
#include "cpu/o3/regfile.hh"
#include "cpu/reg_class.hh"
#include "enums/VecRegRenameMode.hh"

/**
 * Register rename map for a single class of registers (e.g., integer
 * or floating point).  Because the register class is implicitly
 * determined by the rename map instance being accessed, all
 * architectural register index parameters and values in this class
 * are relative (e.g., %fp2 is just index 2).
 */
class SimpleRenameMap
{
  private:
    using Arch2PhysMap = std::vector<PhysRegIdPtr>;
    /** The acutal arch-to-phys register map */
    Arch2PhysMap map;
  public:
    using iterator = Arch2PhysMap::iterator;
    using const_iterator = Arch2PhysMap::const_iterator;
  private:

    /**
     * Pointer to the free list from which new physical registers
     * should be allocated in rename()
     */
    SimpleFreeList *freeList;

    /**
     * The architectural index of the zero register. This register is
     * mapped but read-only, so we ignore attempts to rename it via
     * the rename() method.  If there is no such register for this map
     * table, it should be set to an invalid index so that it never
     * matches.
     */
    RegId zeroReg;

  public:

    SimpleRenameMap();

    ~SimpleRenameMap() {};

    /**
     * Because we have an array of rename maps (one per thread) in the CPU,
     * it's awkward to initialize this object via the constructor.
     * Instead, this method is used for initialization.
     */
    void init(unsigned size, SimpleFreeList *_freeList, RegIndex _zeroReg);

    /**
     * Pair of a physical register and a physical register.  Used to
     * return the physical register that a logical register has been
     * renamed to, and the previous physical register that the same
     * logical register was previously mapped to.
     */
    typedef std::pair<PhysRegIdPtr, PhysRegIdPtr> RenameInfo;

    /**
     * Tell rename map to get a new free physical register to remap
     * the specified architectural register.
     * @param arch_reg The architectural register to remap.
     * @return A RenameInfo pair indicating both the new and previous
     * physical registers.
     */
    RenameInfo rename(const RegId& arch_reg);

    /**
     * Look up the physical register mapped to an architectural register.
     * @param arch_reg The architectural register to look up.
     * @return The physical register it is currently mapped to.
     */
    PhysRegIdPtr lookup(const RegId& arch_reg) const
    {
        assert(arch_reg.flatIndex() <= map.size());
        return map[arch_reg.flatIndex()];
    }

    /**
     * Update rename map with a specific mapping.  Generally used to
     * roll back to old mappings on a squash.
     * @param arch_reg The architectural register to remap.
     * @param phys_reg The physical register to remap it to.
     */
    void setEntry(const RegId& arch_reg, PhysRegIdPtr phys_reg)
    {
        assert(arch_reg.flatIndex() <= map.size());
        map[arch_reg.flatIndex()] = phys_reg;
    }

    /** Return the number of free entries on the associated free list. */
    unsigned numFreeEntries() const { return freeList->numFreeRegs(); }

    /** Forward begin/cbegin to the map. */
    /** @{ */
    iterator begin() { return map.begin(); }
    const_iterator begin() const { return map.begin(); }
    const_iterator cbegin() const { return map.cbegin(); }
    /** @} */

    /** Forward end/cend to the map. */
    /** @{ */
    iterator end() { return map.end(); }
    const_iterator end() const { return map.end(); }
    const_iterator cend() const { return map.cend(); }
    /** @} */
};

/**
 * Unified register rename map for all classes of registers.  Wraps a
 * set of class-specific rename maps.  Methods that do not specify a
 * register class (e.g., rename()) take register ids,
 * while methods that do specify a register class (e.g., renameInt())
 * take register indices.
 */
class UnifiedRenameMap
{
  private:
    static constexpr uint32_t NVecElems = TheISA::NumVecElemPerVecReg;
    using VecReg = TheISA::VecReg;
    using VecPredReg = TheISA::VecPredReg;

    /** The integer register rename map */
    SimpleRenameMap intMap;

    /** The floating-point register rename map */
    SimpleRenameMap floatMap;

    /** The condition-code register rename map */
    SimpleRenameMap ccMap;

    /** The vector register rename map */
    SimpleRenameMap vecMap;

    /** The vector element register rename map */
    SimpleRenameMap vecElemMap;

    /** The predicate register rename map */
    SimpleRenameMap predMap;

    using VecMode = Enums::VecRegRenameMode;
    VecMode vecMode;

    /**
     * The register file object is used only to get PhysRegIdPtr
     * on MiscRegs, as they are stored in it.
     */
    PhysRegFile *regFile;

  public:

    typedef SimpleRenameMap::RenameInfo RenameInfo;

    /** Default constructor.  init() must be called prior to use. */
    UnifiedRenameMap() : regFile(nullptr) {};

    /** Destructor. */
    ~UnifiedRenameMap() {};

    /** Initializes rename map with given parameters. */
    void init(PhysRegFile *_regFile,
              RegIndex _intZeroReg,
              RegIndex _floatZeroReg,
              UnifiedFreeList *freeList,
              VecMode _mode);

    /**
     * Tell rename map to get a new free physical register to remap
     * the specified architectural register. This version takes a
     * RegId and reads the  appropriate class-specific rename table.
     * @param arch_reg The architectural register id to remap.
     * @return A RenameInfo pair indicating both the new and previous
     * physical registers.
     */
    RenameInfo rename(const RegId& arch_reg)
    {
        switch (arch_reg.classValue()) {
          case IntRegClass:
            return intMap.rename(arch_reg);
          case FloatRegClass:
            return floatMap.rename(arch_reg);
          case VecRegClass:
            assert(vecMode == Enums::Full);
            return vecMap.rename(arch_reg);
          case VecElemClass:
            assert(vecMode == Enums::Elem);
            return vecElemMap.rename(arch_reg);
          case VecPredRegClass:
            return predMap.rename(arch_reg);
          case CCRegClass:
            return ccMap.rename(arch_reg);
          case MiscRegClass:
            {
            // misc regs aren't really renamed, just remapped
            PhysRegIdPtr phys_reg = lookup(arch_reg);
            // Set the new register to the previous one to keep the same
            // mapping throughout the execution.
            return RenameInfo(phys_reg, phys_reg);
            }

          default:
            panic("rename rename(): unknown reg class %s\n",
                  arch_reg.className());
        }
    }

    /**
     * Look up the physical register mapped to an architectural register.
     * This version takes a flattened architectural register id
     * and calls the appropriate class-specific rename table.
     * @param arch_reg The architectural register to look up.
     * @return The physical register it is currently mapped to.
     */
    PhysRegIdPtr lookup(const RegId& arch_reg) const
    {
        switch (arch_reg.classValue()) {
          case IntRegClass:
            return intMap.lookup(arch_reg);

          case FloatRegClass:
            return  floatMap.lookup(arch_reg);

          case VecRegClass:
            assert(vecMode == Enums::Full);
            return  vecMap.lookup(arch_reg);

          case VecElemClass:
            assert(vecMode == Enums::Elem);
            return  vecElemMap.lookup(arch_reg);

          case VecPredRegClass:
            return predMap.lookup(arch_reg);

          case CCRegClass:
            return ccMap.lookup(arch_reg);

          case MiscRegClass:
            // misc regs aren't really renamed, they keep the same
            // mapping throughout the execution.
            return regFile->getMiscRegId(arch_reg.flatIndex());

          default:
            panic("rename lookup(): unknown reg class %s\n",
                  arch_reg.className());
        }
    }

    /**
     * Update rename map with a specific mapping.  Generally used to
     * roll back to old mappings on a squash.  This version takes a
     * flattened architectural register id and calls the
     * appropriate class-specific rename table.
     * @param arch_reg The architectural register to remap.
     * @param phys_reg The physical register to remap it to.
     */
    void setEntry(const RegId& arch_reg, PhysRegIdPtr phys_reg)
    {
        switch (arch_reg.classValue()) {
          case IntRegClass:
            assert(phys_reg->isIntPhysReg());
            return intMap.setEntry(arch_reg, phys_reg);

          case FloatRegClass:
            assert(phys_reg->isFloatPhysReg());
            return floatMap.setEntry(arch_reg, phys_reg);

          case VecRegClass:
            assert(phys_reg->isVectorPhysReg());
            assert(vecMode == Enums::Full);
            return vecMap.setEntry(arch_reg, phys_reg);

          case VecElemClass:
            assert(phys_reg->isVectorPhysElem());
            assert(vecMode == Enums::Elem);
            return vecElemMap.setEntry(arch_reg, phys_reg);

          case VecPredRegClass:
            assert(phys_reg->isVecPredPhysReg());
            return predMap.setEntry(arch_reg, phys_reg);

          case CCRegClass:
            assert(phys_reg->isCCPhysReg());
            return ccMap.setEntry(arch_reg, phys_reg);

          case MiscRegClass:
            // Misc registers do not actually rename, so don't change
            // their mappings.  We end up here when a commit or squash
            // tries to update or undo a hardwired misc reg nmapping,
            // which should always be setting it to what it already is.
            assert(phys_reg == lookup(arch_reg));
            return;

          default:
            panic("rename setEntry(): unknown reg class %s\n",
                  arch_reg.className());
        }
    }

    /**
     * Return the minimum number of free entries across all of the
     * register classes.  The minimum is used so we guarantee that
     * this number of entries is available regardless of which class
     * of registers is requested.
     */
    unsigned numFreeEntries() const
    {
        return std::min(std::min(
                std::min(intMap.numFreeEntries(), floatMap.numFreeEntries()),
                vecMode == Enums::Full ? vecMap.numFreeEntries()
                                    : vecElemMap.numFreeEntries()),
                predMap.numFreeEntries());
    }

    unsigned numFreeIntEntries() const { return intMap.numFreeEntries(); }
    unsigned numFreeFloatEntries() const { return floatMap.numFreeEntries(); }
    unsigned numFreeVecEntries() const
    {
        return vecMode == Enums::Full
                ? vecMap.numFreeEntries()
                : vecElemMap.numFreeEntries();
    }
    unsigned numFreePredEntries() const { return predMap.numFreeEntries(); }
    unsigned numFreeCCEntries() const { return ccMap.numFreeEntries(); }

    /**
     * Return whether there are enough registers to serve the request.
     */
    bool canRename(uint32_t intRegs, uint32_t floatRegs, uint32_t vectorRegs,
                   uint32_t vecElemRegs, uint32_t vecPredRegs,
                   uint32_t ccRegs) const
    {
        return intRegs <= intMap.numFreeEntries() &&
            floatRegs <= floatMap.numFreeEntries() &&
            vectorRegs <= vecMap.numFreeEntries() &&
            vecElemRegs <= vecElemMap.numFreeEntries() &&
            vecPredRegs <= predMap.numFreeEntries() &&
            ccRegs <= ccMap.numFreeEntries();
    }
    /**
     * Set vector mode to Full or Elem.
     * Ignore 'silent' modifications.
     *
     * @param newVecMode new vector renaming mode
     */
    void switchMode(VecMode newVecMode);

    /**
     * Switch freeList of registers from Full to Elem or vicevers
     * depending on vecMode (vector renaming mode).
     */
    void switchFreeList(UnifiedFreeList* freeList);

};

#endif //__CPU_O3_RENAME_MAP_HH__
<commit_msg>cpu: Some cleanups in the O3 rename map.<commit_after>/*
 * Copyright (c) 2015-2017 ARM Limited
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2004-2005 The Regents of The University of Michigan
 * Copyright (c) 2013 Advanced Micro Devices, Inc.
 * 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 the copyright holders 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.
 */

#ifndef __CPU_O3_RENAME_MAP_HH__
#define __CPU_O3_RENAME_MAP_HH__

#include <iostream>
#include <utility>
#include <vector>

#include "arch/types.hh"
#include "config/the_isa.hh"
#include "cpu/o3/free_list.hh"
#include "cpu/o3/regfile.hh"
#include "cpu/reg_class.hh"
#include "enums/VecRegRenameMode.hh"

/**
 * Register rename map for a single class of registers (e.g., integer
 * or floating point).  Because the register class is implicitly
 * determined by the rename map instance being accessed, all
 * architectural register index parameters and values in this class
 * are relative (e.g., %fp2 is just index 2).
 */
class SimpleRenameMap
{
  private:
    using Arch2PhysMap = std::vector<PhysRegIdPtr>;
    /** The acutal arch-to-phys register map */
    Arch2PhysMap map;
  public:
    using iterator = Arch2PhysMap::iterator;
    using const_iterator = Arch2PhysMap::const_iterator;
  private:

    /**
     * Pointer to the free list from which new physical registers
     * should be allocated in rename()
     */
    SimpleFreeList *freeList;

    /**
     * The architectural index of the zero register. This register is
     * mapped but read-only, so we ignore attempts to rename it via
     * the rename() method.  If there is no such register for this map
     * table, it should be set to an invalid index so that it never
     * matches.
     */
    RegId zeroReg;

  public:

    SimpleRenameMap();

    ~SimpleRenameMap() {};

    /**
     * Because we have an array of rename maps (one per thread) in the CPU,
     * it's awkward to initialize this object via the constructor.
     * Instead, this method is used for initialization.
     */
    void init(unsigned size, SimpleFreeList *_freeList, RegIndex _zeroReg);

    /**
     * Pair of a physical register and a physical register.  Used to
     * return the physical register that a logical register has been
     * renamed to, and the previous physical register that the same
     * logical register was previously mapped to.
     */
    typedef std::pair<PhysRegIdPtr, PhysRegIdPtr> RenameInfo;

    /**
     * Tell rename map to get a new free physical register to remap
     * the specified architectural register.
     * @param arch_reg The architectural register to remap.
     * @return A RenameInfo pair indicating both the new and previous
     * physical registers.
     */
    RenameInfo rename(const RegId& arch_reg);

    /**
     * Look up the physical register mapped to an architectural register.
     * @param arch_reg The architectural register to look up.
     * @return The physical register it is currently mapped to.
     */
    PhysRegIdPtr
    lookup(const RegId& arch_reg) const
    {
        assert(arch_reg.flatIndex() <= map.size());
        return map[arch_reg.flatIndex()];
    }

    /**
     * Update rename map with a specific mapping.  Generally used to
     * roll back to old mappings on a squash.
     * @param arch_reg The architectural register to remap.
     * @param phys_reg The physical register to remap it to.
     */
    void
    setEntry(const RegId& arch_reg, PhysRegIdPtr phys_reg)
    {
        assert(arch_reg.flatIndex() <= map.size());
        map[arch_reg.flatIndex()] = phys_reg;
    }

    /** Return the number of free entries on the associated free list. */
    unsigned numFreeEntries() const { return freeList->numFreeRegs(); }

    /** Forward begin/cbegin to the map. */
    /** @{ */
    iterator begin() { return map.begin(); }
    const_iterator begin() const { return map.begin(); }
    const_iterator cbegin() const { return map.cbegin(); }
    /** @} */

    /** Forward end/cend to the map. */
    /** @{ */
    iterator end() { return map.end(); }
    const_iterator end() const { return map.end(); }
    const_iterator cend() const { return map.cend(); }
    /** @} */
};

/**
 * Unified register rename map for all classes of registers.  Wraps a
 * set of class-specific rename maps.  Methods that do not specify a
 * register class (e.g., rename()) take register ids,
 * while methods that do specify a register class (e.g., renameInt())
 * take register indices.
 */
class UnifiedRenameMap
{
  private:
    static constexpr uint32_t NVecElems = TheISA::NumVecElemPerVecReg;
    using VecReg = TheISA::VecReg;
    using VecPredReg = TheISA::VecPredReg;

    /** The integer register rename map */
    SimpleRenameMap intMap;

    /** The floating-point register rename map */
    SimpleRenameMap floatMap;

    /** The condition-code register rename map */
    SimpleRenameMap ccMap;

    /** The vector register rename map */
    SimpleRenameMap vecMap;

    /** The vector element register rename map */
    SimpleRenameMap vecElemMap;

    /** The predicate register rename map */
    SimpleRenameMap predMap;

    using VecMode = Enums::VecRegRenameMode;
    VecMode vecMode;

    /**
     * The register file object is used only to get PhysRegIdPtr
     * on MiscRegs, as they are stored in it.
     */
    PhysRegFile *regFile;

  public:

    typedef SimpleRenameMap::RenameInfo RenameInfo;

    /** Default constructor.  init() must be called prior to use. */
    UnifiedRenameMap() : regFile(nullptr) {};

    /** Destructor. */
    ~UnifiedRenameMap() {};

    /** Initializes rename map with given parameters. */
    void init(PhysRegFile *_regFile,
              RegIndex _intZeroReg,
              RegIndex _floatZeroReg,
              UnifiedFreeList *freeList,
              VecMode _mode);

    /**
     * Tell rename map to get a new free physical register to remap
     * the specified architectural register. This version takes a
     * RegId and reads the  appropriate class-specific rename table.
     * @param arch_reg The architectural register id to remap.
     * @return A RenameInfo pair indicating both the new and previous
     * physical registers.
     */
    RenameInfo rename(const RegId& arch_reg)
    {
        switch (arch_reg.classValue()) {
          case IntRegClass:
            return intMap.rename(arch_reg);
          case FloatRegClass:
            return floatMap.rename(arch_reg);
          case VecRegClass:
            assert(vecMode == Enums::Full);
            return vecMap.rename(arch_reg);
          case VecElemClass:
            assert(vecMode == Enums::Elem);
            return vecElemMap.rename(arch_reg);
          case VecPredRegClass:
            return predMap.rename(arch_reg);
          case CCRegClass:
            return ccMap.rename(arch_reg);
          case MiscRegClass:
            {
            // misc regs aren't really renamed, just remapped
            PhysRegIdPtr phys_reg = lookup(arch_reg);
            // Set the new register to the previous one to keep the same
            // mapping throughout the execution.
            return RenameInfo(phys_reg, phys_reg);
            }

          default:
            panic("rename rename(): unknown reg class %s\n",
                  arch_reg.className());
        }
    }

    /**
     * Look up the physical register mapped to an architectural register.
     * This version takes a flattened architectural register id
     * and calls the appropriate class-specific rename table.
     * @param arch_reg The architectural register to look up.
     * @return The physical register it is currently mapped to.
     */
    PhysRegIdPtr
    lookup(const RegId& arch_reg) const
    {
        switch (arch_reg.classValue()) {
          case IntRegClass:
            return intMap.lookup(arch_reg);

          case FloatRegClass:
            return  floatMap.lookup(arch_reg);

          case VecRegClass:
            assert(vecMode == Enums::Full);
            return  vecMap.lookup(arch_reg);

          case VecElemClass:
            assert(vecMode == Enums::Elem);
            return  vecElemMap.lookup(arch_reg);

          case VecPredRegClass:
            return predMap.lookup(arch_reg);

          case CCRegClass:
            return ccMap.lookup(arch_reg);

          case MiscRegClass:
            // misc regs aren't really renamed, they keep the same
            // mapping throughout the execution.
            return regFile->getMiscRegId(arch_reg.flatIndex());

          default:
            panic("rename lookup(): unknown reg class %s\n",
                  arch_reg.className());
        }
    }

    /**
     * Update rename map with a specific mapping.  Generally used to
     * roll back to old mappings on a squash.  This version takes a
     * flattened architectural register id and calls the
     * appropriate class-specific rename table.
     * @param arch_reg The architectural register to remap.
     * @param phys_reg The physical register to remap it to.
     */
    void
    setEntry(const RegId& arch_reg, PhysRegIdPtr phys_reg)
    {
        switch (arch_reg.classValue()) {
          case IntRegClass:
            assert(phys_reg->isIntPhysReg());
            return intMap.setEntry(arch_reg, phys_reg);

          case FloatRegClass:
            assert(phys_reg->isFloatPhysReg());
            return floatMap.setEntry(arch_reg, phys_reg);

          case VecRegClass:
            assert(phys_reg->isVectorPhysReg());
            assert(vecMode == Enums::Full);
            return vecMap.setEntry(arch_reg, phys_reg);

          case VecElemClass:
            assert(phys_reg->isVectorPhysElem());
            assert(vecMode == Enums::Elem);
            return vecElemMap.setEntry(arch_reg, phys_reg);

          case VecPredRegClass:
            assert(phys_reg->isVecPredPhysReg());
            return predMap.setEntry(arch_reg, phys_reg);

          case CCRegClass:
            assert(phys_reg->isCCPhysReg());
            return ccMap.setEntry(arch_reg, phys_reg);

          case MiscRegClass:
            // Misc registers do not actually rename, so don't change
            // their mappings.  We end up here when a commit or squash
            // tries to update or undo a hardwired misc reg nmapping,
            // which should always be setting it to what it already is.
            assert(phys_reg == lookup(arch_reg));
            return;

          default:
            panic("rename setEntry(): unknown reg class %s\n",
                  arch_reg.className());
        }
    }

    /**
     * Return the minimum number of free entries across all of the
     * register classes.  The minimum is used so we guarantee that
     * this number of entries is available regardless of which class
     * of registers is requested.
     */
    unsigned
    numFreeEntries() const
    {
        return std::min({intMap.numFreeEntries(),
                         floatMap.numFreeEntries(),
                         vecMode == Enums::Full ? vecMap.numFreeEntries() :
                                                  vecElemMap.numFreeEntries(),
                         predMap.numFreeEntries()});
    }

    unsigned numFreeIntEntries() const { return intMap.numFreeEntries(); }
    unsigned numFreeFloatEntries() const { return floatMap.numFreeEntries(); }
    unsigned
    numFreeVecEntries() const
    {
        return vecMode == Enums::Full
                ? vecMap.numFreeEntries()
                : vecElemMap.numFreeEntries();
    }
    unsigned numFreePredEntries() const { return predMap.numFreeEntries(); }
    unsigned numFreeCCEntries() const { return ccMap.numFreeEntries(); }

    /**
     * Return whether there are enough registers to serve the request.
     */
    bool
    canRename(uint32_t intRegs, uint32_t floatRegs, uint32_t vectorRegs,
              uint32_t vecElemRegs, uint32_t vecPredRegs,
              uint32_t ccRegs) const
    {
        return intRegs <= intMap.numFreeEntries() &&
            floatRegs <= floatMap.numFreeEntries() &&
            vectorRegs <= vecMap.numFreeEntries() &&
            vecElemRegs <= vecElemMap.numFreeEntries() &&
            vecPredRegs <= predMap.numFreeEntries() &&
            ccRegs <= ccMap.numFreeEntries();
    }
    /**
     * Set vector mode to Full or Elem.
     * Ignore 'silent' modifications.
     *
     * @param newVecMode new vector renaming mode
     */
    void switchMode(VecMode newVecMode);

    /**
     * Switch freeList of registers from Full to Elem or vicevers
     * depending on vecMode (vector renaming mode).
     */
    void switchFreeList(UnifiedFreeList* freeList);

};

#endif //__CPU_O3_RENAME_MAP_HH__
<|endoftext|>


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

#include "gcs_server.h"

#include "actor_info_handler_impl.h"
#include "error_info_handler_impl.h"
#include "gcs_actor_manager.h"
#include "gcs_node_manager.h"
#include "gcs_object_manager.h"
#include "job_info_handler_impl.h"
#include "ray/common/network_util.h"
#include "ray/common/ray_config.h"
#include "stats_handler_impl.h"
#include "task_info_handler_impl.h"
#include "worker_info_handler_impl.h"

namespace ray {
namespace gcs {

GcsServer::GcsServer(const ray::gcs::GcsServerConfig &config)
    : config_(config),
      rpc_server_(config.grpc_server_name, config.grpc_server_port,
                  config.grpc_server_thread_num),
      client_call_manager_(main_service_) {}

GcsServer::~GcsServer() { Stop(); }

void GcsServer::Start() {
  // Init backend client.
  InitBackendClient();

  // Init gcs pub sub instance.
  gcs_pub_sub_ = std::make_shared<gcs::GcsPubSub>(redis_gcs_client_->GetRedisClient());

  // Init gcs table storage.
  gcs_table_storage_ =
      std::make_shared<gcs::RedisGcsTableStorage>(redis_gcs_client_->GetRedisClient());

  // Init gcs node_manager.
  InitGcsNodeManager();

  // Init gcs detector.
  gcs_redis_failure_detector_ = std::make_shared<GcsRedisFailureDetector>(
      main_service_, redis_gcs_client_->primary_context(), [this]() { Stop(); });
  gcs_redis_failure_detector_->Start();

  // Init gcs actor manager.
  InitGcsActorManager();

  // Register rpc service.
  job_info_handler_ = InitJobInfoHandler();
  job_info_service_.reset(new rpc::JobInfoGrpcService(main_service_, *job_info_handler_));
  rpc_server_.RegisterService(*job_info_service_);

  actor_info_handler_ = InitActorInfoHandler();
  actor_info_service_.reset(
      new rpc::ActorInfoGrpcService(main_service_, *actor_info_handler_));
  rpc_server_.RegisterService(*actor_info_service_);

  node_info_service_.reset(
      new rpc::NodeInfoGrpcService(main_service_, *gcs_node_manager_));
  rpc_server_.RegisterService(*node_info_service_);

  object_info_handler_ = InitObjectInfoHandler();
  object_info_service_.reset(
      new rpc::ObjectInfoGrpcService(main_service_, *object_info_handler_));
  rpc_server_.RegisterService(*object_info_service_);

  task_info_handler_ = InitTaskInfoHandler();
  task_info_service_.reset(
      new rpc::TaskInfoGrpcService(main_service_, *task_info_handler_));
  rpc_server_.RegisterService(*task_info_service_);

  stats_handler_ = InitStatsHandler();
  stats_service_.reset(new rpc::StatsGrpcService(main_service_, *stats_handler_));
  rpc_server_.RegisterService(*stats_service_);

  error_info_handler_ = InitErrorInfoHandler();
  error_info_service_.reset(
      new rpc::ErrorInfoGrpcService(main_service_, *error_info_handler_));
  rpc_server_.RegisterService(*error_info_service_);

  worker_info_handler_ = InitWorkerInfoHandler();
  worker_info_service_.reset(
      new rpc::WorkerInfoGrpcService(main_service_, *worker_info_handler_));
  rpc_server_.RegisterService(*worker_info_service_);

  // Run rpc server.
  rpc_server_.Run();

  // Store gcs rpc server address in redis.
  StoreGcsServerAddressInRedis();
  is_started_ = true;

  // Run the event loop.
  // Using boost::asio::io_context::work to avoid ending the event loop when
  // there are no events to handle.
  boost::asio::io_context::work worker(main_service_);
  main_service_.run();
}

void GcsServer::Stop() {
  RAY_LOG(INFO) << "Stopping gcs server.";
  // Shutdown the rpc server
  rpc_server_.Shutdown();

  // Stop the event loop.
  main_service_.stop();

  is_stopped_ = true;
  RAY_LOG(INFO) << "Finished stopping gcs server.";
}

void GcsServer::InitBackendClient() {
  GcsClientOptions options(config_.redis_address, config_.redis_port,
                           config_.redis_password, config_.is_test);
  redis_gcs_client_ = std::make_shared<RedisGcsClient>(options);
  auto status = redis_gcs_client_->Connect(main_service_);
  RAY_CHECK(status.ok()) << "Failed to init redis gcs client as " << status;
}

void GcsServer::InitGcsNodeManager() {
  RAY_CHECK(redis_gcs_client_ != nullptr);
  gcs_node_manager_ =
      std::make_shared<GcsNodeManager>(main_service_, redis_gcs_client_->Nodes(),
                                       redis_gcs_client_->Errors(), gcs_pub_sub_);
}

void GcsServer::InitGcsActorManager() {
  RAY_CHECK(redis_gcs_client_ != nullptr && gcs_node_manager_ != nullptr);
  auto scheduler = std::make_shared<GcsActorScheduler>(
      main_service_, redis_gcs_client_->Actors(), *gcs_node_manager_, gcs_pub_sub_,
      /*schedule_failure_handler=*/
      [this](std::shared_ptr<GcsActor> actor) {
        // When there are no available nodes to schedule the actor the
        // gcs_actor_scheduler will treat it as failed and invoke this handler. In
        // this case, the actor manager should schedule the actor once an
        // eligible node is registered.
        gcs_actor_manager_->OnActorCreationFailed(std::move(actor));
      },
      /*schedule_success_handler=*/
      [this](std::shared_ptr<GcsActor> actor) {
        gcs_actor_manager_->OnActorCreationSuccess(std::move(actor));
      },
      /*lease_client_factory=*/
      [this](const rpc::Address &address) {
        auto node_manager_worker_client = rpc::NodeManagerWorkerClient::make(
            address.ip_address(), address.port(), client_call_manager_);
        return std::make_shared<ray::raylet::RayletClient>(
            std::move(node_manager_worker_client));
      },
      /*client_factory=*/
      [this](const rpc::Address &address) {
        return std::make_shared<rpc::CoreWorkerClient>(address, client_call_manager_);
      });
  gcs_actor_manager_ = std::make_shared<GcsActorManager>(
      scheduler, redis_gcs_client_->Actors(), gcs_pub_sub_,
      [this](const rpc::Address &address) {
        return std::make_shared<rpc::CoreWorkerClient>(address, client_call_manager_);
      });
  gcs_node_manager_->AddNodeAddedListener(
      [this](const std::shared_ptr<rpc::GcsNodeInfo> &) {
        // Because a new node has been added, we need to try to schedule the pending
        // actors.
        gcs_actor_manager_->SchedulePendingActors();
      });

  gcs_node_manager_->AddNodeRemovedListener(
      [this](std::shared_ptr<rpc::GcsNodeInfo> node) {
        // All of the related actors should be reconstructed when a node is removed from
        // the GCS.
        gcs_actor_manager_->OnNodeDead(ClientID::FromBinary(node->node_id()));
      });
  RAY_CHECK_OK(redis_gcs_client_->Workers().AsyncSubscribeToWorkerFailures(
      [this](const WorkerID &id, const rpc::WorkerFailureData &worker_failure_data) {
        auto &worker_address = worker_failure_data.worker_address();
        WorkerID worker_id = WorkerID::FromBinary(worker_address.worker_id());
        ClientID node_id = ClientID::FromBinary(worker_address.raylet_id());
        gcs_actor_manager_->OnWorkerDead(node_id, worker_id,
                                         worker_failure_data.intentional_disconnect());
      },
      /*done_callback=*/nullptr));
}

std::unique_ptr<rpc::JobInfoHandler> GcsServer::InitJobInfoHandler() {
  return std::unique_ptr<rpc::DefaultJobInfoHandler>(
      new rpc::DefaultJobInfoHandler(gcs_table_storage_, gcs_pub_sub_));
}

std::unique_ptr<rpc::ActorInfoHandler> GcsServer::InitActorInfoHandler() {
  return std::unique_ptr<rpc::DefaultActorInfoHandler>(new rpc::DefaultActorInfoHandler(
      *redis_gcs_client_, *gcs_actor_manager_, gcs_pub_sub_));
}

std::unique_ptr<rpc::ObjectInfoHandler> GcsServer::InitObjectInfoHandler() {
  return std::unique_ptr<GcsObjectManager>(
      new GcsObjectManager(gcs_table_storage_, gcs_pub_sub_, *gcs_node_manager_));
}

void GcsServer::StoreGcsServerAddressInRedis() {
  std::string address =
      GetValidLocalIp(
          GetPort(),
          RayConfig::instance().internal_gcs_service_connect_wait_milliseconds()) +
      ":" + std::to_string(GetPort());
  RAY_LOG(INFO) << "Gcs server address = " << address;

  RAY_CHECK_OK(redis_gcs_client_->primary_context()->RunArgvAsync(
      {"SET", "GcsServerAddress", address}));
  RAY_LOG(INFO) << "Finished setting gcs server address: " << address;
}

std::unique_ptr<rpc::TaskInfoHandler> GcsServer::InitTaskInfoHandler() {
  return std::unique_ptr<rpc::DefaultTaskInfoHandler>(
      new rpc::DefaultTaskInfoHandler(gcs_table_storage_, gcs_pub_sub_));
}

std::unique_ptr<rpc::StatsHandler> GcsServer::InitStatsHandler() {
  return std::unique_ptr<rpc::DefaultStatsHandler>(
      new rpc::DefaultStatsHandler(gcs_table_storage_));
}

std::unique_ptr<rpc::ErrorInfoHandler> GcsServer::InitErrorInfoHandler() {
  return std::unique_ptr<rpc::DefaultErrorInfoHandler>(
      new rpc::DefaultErrorInfoHandler(*redis_gcs_client_));
}

std::unique_ptr<rpc::WorkerInfoHandler> GcsServer::InitWorkerInfoHandler() {
  return std::unique_ptr<rpc::DefaultWorkerInfoHandler>(new rpc::DefaultWorkerInfoHandler(
      *redis_gcs_client_, gcs_table_storage_, gcs_pub_sub_));
}

}  // namespace gcs
}  // namespace ray
<commit_msg>fix testActorRestart failure bug (#8613)<commit_after>// Copyright 2017 The Ray Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "gcs_server.h"

#include "actor_info_handler_impl.h"
#include "error_info_handler_impl.h"
#include "gcs_actor_manager.h"
#include "gcs_node_manager.h"
#include "gcs_object_manager.h"
#include "job_info_handler_impl.h"
#include "ray/common/network_util.h"
#include "ray/common/ray_config.h"
#include "stats_handler_impl.h"
#include "task_info_handler_impl.h"
#include "worker_info_handler_impl.h"

namespace ray {
namespace gcs {

GcsServer::GcsServer(const ray::gcs::GcsServerConfig &config)
    : config_(config),
      rpc_server_(config.grpc_server_name, config.grpc_server_port,
                  config.grpc_server_thread_num),
      client_call_manager_(main_service_) {}

GcsServer::~GcsServer() { Stop(); }

void GcsServer::Start() {
  // Init backend client.
  InitBackendClient();

  // Init gcs pub sub instance.
  gcs_pub_sub_ = std::make_shared<gcs::GcsPubSub>(redis_gcs_client_->GetRedisClient());

  // Init gcs table storage.
  gcs_table_storage_ =
      std::make_shared<gcs::RedisGcsTableStorage>(redis_gcs_client_->GetRedisClient());

  // Init gcs node_manager.
  InitGcsNodeManager();

  // Init gcs detector.
  gcs_redis_failure_detector_ = std::make_shared<GcsRedisFailureDetector>(
      main_service_, redis_gcs_client_->primary_context(), [this]() { Stop(); });
  gcs_redis_failure_detector_->Start();

  // Init gcs actor manager.
  InitGcsActorManager();

  // Register rpc service.
  job_info_handler_ = InitJobInfoHandler();
  job_info_service_.reset(new rpc::JobInfoGrpcService(main_service_, *job_info_handler_));
  rpc_server_.RegisterService(*job_info_service_);

  actor_info_handler_ = InitActorInfoHandler();
  actor_info_service_.reset(
      new rpc::ActorInfoGrpcService(main_service_, *actor_info_handler_));
  rpc_server_.RegisterService(*actor_info_service_);

  node_info_service_.reset(
      new rpc::NodeInfoGrpcService(main_service_, *gcs_node_manager_));
  rpc_server_.RegisterService(*node_info_service_);

  object_info_handler_ = InitObjectInfoHandler();
  object_info_service_.reset(
      new rpc::ObjectInfoGrpcService(main_service_, *object_info_handler_));
  rpc_server_.RegisterService(*object_info_service_);

  task_info_handler_ = InitTaskInfoHandler();
  task_info_service_.reset(
      new rpc::TaskInfoGrpcService(main_service_, *task_info_handler_));
  rpc_server_.RegisterService(*task_info_service_);

  stats_handler_ = InitStatsHandler();
  stats_service_.reset(new rpc::StatsGrpcService(main_service_, *stats_handler_));
  rpc_server_.RegisterService(*stats_service_);

  error_info_handler_ = InitErrorInfoHandler();
  error_info_service_.reset(
      new rpc::ErrorInfoGrpcService(main_service_, *error_info_handler_));
  rpc_server_.RegisterService(*error_info_service_);

  worker_info_handler_ = InitWorkerInfoHandler();
  worker_info_service_.reset(
      new rpc::WorkerInfoGrpcService(main_service_, *worker_info_handler_));
  rpc_server_.RegisterService(*worker_info_service_);

  // Run rpc server.
  rpc_server_.Run();

  // Store gcs rpc server address in redis.
  StoreGcsServerAddressInRedis();
  is_started_ = true;

  // Run the event loop.
  // Using boost::asio::io_context::work to avoid ending the event loop when
  // there are no events to handle.
  boost::asio::io_context::work worker(main_service_);
  main_service_.run();
}

void GcsServer::Stop() {
  RAY_LOG(INFO) << "Stopping gcs server.";
  // Shutdown the rpc server
  rpc_server_.Shutdown();

  // Stop the event loop.
  main_service_.stop();

  is_stopped_ = true;
  RAY_LOG(INFO) << "Finished stopping gcs server.";
}

void GcsServer::InitBackendClient() {
  GcsClientOptions options(config_.redis_address, config_.redis_port,
                           config_.redis_password, config_.is_test);
  redis_gcs_client_ = std::make_shared<RedisGcsClient>(options);
  auto status = redis_gcs_client_->Connect(main_service_);
  RAY_CHECK(status.ok()) << "Failed to init redis gcs client as " << status;
}

void GcsServer::InitGcsNodeManager() {
  RAY_CHECK(redis_gcs_client_ != nullptr);
  gcs_node_manager_ =
      std::make_shared<GcsNodeManager>(main_service_, redis_gcs_client_->Nodes(),
                                       redis_gcs_client_->Errors(), gcs_pub_sub_);
}

void GcsServer::InitGcsActorManager() {
  RAY_CHECK(redis_gcs_client_ != nullptr && gcs_node_manager_ != nullptr);
  auto scheduler = std::make_shared<GcsActorScheduler>(
      main_service_, redis_gcs_client_->Actors(), *gcs_node_manager_, gcs_pub_sub_,
      /*schedule_failure_handler=*/
      [this](std::shared_ptr<GcsActor> actor) {
        // When there are no available nodes to schedule the actor the
        // gcs_actor_scheduler will treat it as failed and invoke this handler. In
        // this case, the actor manager should schedule the actor once an
        // eligible node is registered.
        gcs_actor_manager_->OnActorCreationFailed(std::move(actor));
      },
      /*schedule_success_handler=*/
      [this](std::shared_ptr<GcsActor> actor) {
        gcs_actor_manager_->OnActorCreationSuccess(std::move(actor));
      },
      /*lease_client_factory=*/
      [this](const rpc::Address &address) {
        auto node_manager_worker_client = rpc::NodeManagerWorkerClient::make(
            address.ip_address(), address.port(), client_call_manager_);
        return std::make_shared<ray::raylet::RayletClient>(
            std::move(node_manager_worker_client));
      },
      /*client_factory=*/
      [this](const rpc::Address &address) {
        return std::make_shared<rpc::CoreWorkerClient>(address, client_call_manager_);
      });
  gcs_actor_manager_ = std::make_shared<GcsActorManager>(
      scheduler, redis_gcs_client_->Actors(), gcs_pub_sub_,
      [this](const rpc::Address &address) {
        return std::make_shared<rpc::CoreWorkerClient>(address, client_call_manager_);
      });
  gcs_node_manager_->AddNodeAddedListener(
      [this](const std::shared_ptr<rpc::GcsNodeInfo> &) {
        // Because a new node has been added, we need to try to schedule the pending
        // actors.
        gcs_actor_manager_->SchedulePendingActors();
      });

  gcs_node_manager_->AddNodeRemovedListener(
      [this](std::shared_ptr<rpc::GcsNodeInfo> node) {
        // All of the related actors should be reconstructed when a node is removed from
        // the GCS.
        gcs_actor_manager_->OnNodeDead(ClientID::FromBinary(node->node_id()));
      });

  auto on_subscribe = [this](const std::string &id, const std::string &data) {
    rpc::WorkerFailureData worker_failure_data;
    worker_failure_data.ParseFromString(data);
    auto &worker_address = worker_failure_data.worker_address();
    WorkerID worker_id = WorkerID::FromBinary(id);
    ClientID node_id = ClientID::FromBinary(worker_address.raylet_id());
    gcs_actor_manager_->OnWorkerDead(node_id, worker_id,
                                     worker_failure_data.intentional_disconnect());
  };
  RAY_CHECK_OK(gcs_pub_sub_->SubscribeAll(WORKER_FAILURE_CHANNEL, on_subscribe, nullptr));
}

std::unique_ptr<rpc::JobInfoHandler> GcsServer::InitJobInfoHandler() {
  return std::unique_ptr<rpc::DefaultJobInfoHandler>(
      new rpc::DefaultJobInfoHandler(gcs_table_storage_, gcs_pub_sub_));
}

std::unique_ptr<rpc::ActorInfoHandler> GcsServer::InitActorInfoHandler() {
  return std::unique_ptr<rpc::DefaultActorInfoHandler>(new rpc::DefaultActorInfoHandler(
      *redis_gcs_client_, *gcs_actor_manager_, gcs_pub_sub_));
}

std::unique_ptr<rpc::ObjectInfoHandler> GcsServer::InitObjectInfoHandler() {
  return std::unique_ptr<GcsObjectManager>(
      new GcsObjectManager(gcs_table_storage_, gcs_pub_sub_, *gcs_node_manager_));
}

void GcsServer::StoreGcsServerAddressInRedis() {
  std::string address =
      GetValidLocalIp(
          GetPort(),
          RayConfig::instance().internal_gcs_service_connect_wait_milliseconds()) +
      ":" + std::to_string(GetPort());
  RAY_LOG(INFO) << "Gcs server address = " << address;

  RAY_CHECK_OK(redis_gcs_client_->primary_context()->RunArgvAsync(
      {"SET", "GcsServerAddress", address}));
  RAY_LOG(INFO) << "Finished setting gcs server address: " << address;
}

std::unique_ptr<rpc::TaskInfoHandler> GcsServer::InitTaskInfoHandler() {
  return std::unique_ptr<rpc::DefaultTaskInfoHandler>(
      new rpc::DefaultTaskInfoHandler(gcs_table_storage_, gcs_pub_sub_));
}

std::unique_ptr<rpc::StatsHandler> GcsServer::InitStatsHandler() {
  return std::unique_ptr<rpc::DefaultStatsHandler>(
      new rpc::DefaultStatsHandler(gcs_table_storage_));
}

std::unique_ptr<rpc::ErrorInfoHandler> GcsServer::InitErrorInfoHandler() {
  return std::unique_ptr<rpc::DefaultErrorInfoHandler>(
      new rpc::DefaultErrorInfoHandler(*redis_gcs_client_));
}

std::unique_ptr<rpc::WorkerInfoHandler> GcsServer::InitWorkerInfoHandler() {
  return std::unique_ptr<rpc::DefaultWorkerInfoHandler>(new rpc::DefaultWorkerInfoHandler(
      *redis_gcs_client_, gcs_table_storage_, gcs_pub_sub_));
}

}  // namespace gcs
}  // namespace ray
<|endoftext|>


<commit_before>#include "report.hpp"
#include "calendar.hpp"
#include <fmo/assert.hpp>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <vector>

Report::Report(const Results& results, const Results& baseline, const Args& args, float seconds) {
    mResults = &results;

    std::ostringstream out;
    info(out, results, baseline, args, seconds);
    mInfo = out.str();
}

void Report::write(std::ostream& out) { out << mInfo; }

void Report::save(const std::string& directory) {
    if (mResults->empty()) return;
    std::string fn = directory + '/' + safeTimestamp() + ".txt";
    std::ofstream out{fn, std::ios_base::out | std::ios_base::binary};

    if (!out) {
        std::cerr << "failed to open '" << fn << "'\n";
        throw std::runtime_error("failed to open file for writing results");
    }

    write(out);
    out << '\n';
    out << "/FMO/EVALUATION/V2/\n";
    out << mResults->size() << '\n';

    Evaluation evals[4] = {Evaluation::FN, Evaluation::FP, Evaluation::TN, Evaluation::TP};
    const char* names[4] = {"FN", "FP", "TN", "TP"};

    for (auto& entry : *mResults) {
        auto& name = entry.first;
        auto& file = *entry.second;
        out << name << ' ' << file.size() << '\n';

        for (int e = 0; e < 4; e++) {
            out << names[e];
            Evaluation eval = evals[e];

            for (auto value : file) { out << ' ' << (value == eval); }

            out << '\n';
        }
    }
}

void Report::info(std::ostream& out, const Results& results, const Results& baseline,
                  const Args& args, float seconds) {
    std::vector<std::string> fields;
    bool haveBase = false;
    int count[4] = {0, 0, 0, 0};
    int countBase[4] = {0, 0, 0, 0};

    auto reset = [](int* count) {
        count[0] = 0;
        count[1] = 0;
        count[2] = 0;
        count[3] = 0;
    };
    auto precision = [](int* count) {
        int div = count[int(Evaluation::TP)] + count[int(Evaluation::FP)];
        if (div == 0) return 0.;
        return count[int(Evaluation::TP)] / double(div);
    };
    auto recall = [](int* count) {
        int div = count[int(Evaluation::TP)] + count[int(Evaluation::FN)];
        if (div == 0) return 0.;
        return count[int(Evaluation::TP)] / double(div);
    };
    auto percent = [](std::ostream& out, double val) {
        out << std::fixed << std::setprecision(2) << (val * 100) << '%';
    };
    auto countStr = [&](Evaluation eval) {
        std::ostringstream out;
        int val = count[int(eval)];
        out << val;
        if (haveBase) {
            int delta = val - countBase[int(eval)];
            if (delta != 0) { out << " (" << std::showpos << delta << std::noshowpos << ')'; }
        }
        return out.str();
    };
    auto percentStr = [&](double (*calc)(int*)) {
        std::ostringstream out;
        double val = calc(count);
        percent(out, val);
        if (haveBase) {
            double delta = val - calc(countBase);
            if (std::abs(delta) > 0.005) {
                out << " (" << std::showpos;
                percent(out, delta);
                out << std::noshowpos << ')';
            }
        }
        return out.str();
    };

    fields.push_back("name");
    fields.push_back("tp");
    fields.push_back("tn");
    fields.push_back("fp");
    fields.push_back("fn");
    fields.push_back("precision");
    fields.push_back("recall");

    for (auto& entry : results) {
        auto& name = entry.first;
        auto& file = *entry.second;
        if (file.size() == 0) continue;
        auto& baseFile = baseline.getFile(name);
        haveBase = baseFile.size() == file.size();

        reset(count);
        for (auto eval : file) { count[int(eval)]++; }
        if (haveBase) {
            reset(countBase);
            for (auto eval : baseFile) { countBase[int(eval)]++; }
        }

        fields.push_back(name);
        fields.push_back(countStr(Evaluation::TP));
        fields.push_back(countStr(Evaluation::TN));
        fields.push_back(countStr(Evaluation::FP));
        fields.push_back(countStr(Evaluation::FN));
        fields.push_back(percentStr(precision));
        fields.push_back(percentStr(recall));
    }

    constexpr int COLS = 7;
    FMO_ASSERT(fields.size() % COLS == 0, "bad number of fields");

    if (fields.size() == COLS) {
        // no entries -- quit
        return;
    }

    int colSize[COLS] = {0, 0, 0, 0, 0, 0, 0};
    for (auto it = fields.begin(); it != fields.end();) {
        for (int col = 0; col < COLS; col++, it++) {
            colSize[col] = std::max(colSize[col], int(it->size()) + 1);
        }
    }

    out << "parameters:\n" << std::defaultfloat << std::setprecision(6);
    out << "generated on: " << timestamp() << '\n';
    out << "evaluation time: " << std::fixed << std::setprecision(1) << seconds << " s\n";
    args.printParameters(out, '\n');
    out << '\n';
    int row = 0;
    for (auto it = fields.begin(); it != fields.end();) {
        out << std::setw(colSize[0]) << std::left << *it++ << std::right;
        for (int col = 1; col < COLS; col++, it++) { out << '|' << std::setw(colSize[col]) << *it; }
        out << '\n';
        if (row++ == 0) {
            for (int i = 0; i < colSize[0]; i++) { out << '-'; }
            for (int col = 1; col < COLS; col++) {
                out << '|';
                for (int i = 0; i < colSize[col]; i++) { out << '-'; }
            }
            out << '\n';
        }
    }
}
<commit_msg>Fix parameter printing in results<commit_after>#include "report.hpp"
#include "calendar.hpp"
#include <fmo/assert.hpp>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <vector>

Report::Report(const Results& results, const Results& baseline, const Args& args, float seconds) {
    mResults = &results;

    std::ostringstream out;
    info(out, results, baseline, args, seconds);
    mInfo = out.str();
}

void Report::write(std::ostream& out) { out << mInfo; }

void Report::save(const std::string& directory) {
    if (mResults->empty()) return;
    std::string fn = directory + '/' + safeTimestamp() + ".txt";
    std::ofstream out{fn, std::ios_base::out | std::ios_base::binary};

    if (!out) {
        std::cerr << "failed to open '" << fn << "'\n";
        throw std::runtime_error("failed to open file for writing results");
    }

    write(out);
    out << '\n';
    out << "/FMO/EVALUATION/V2/\n";
    out << mResults->size() << '\n';

    Evaluation evals[4] = {Evaluation::FN, Evaluation::FP, Evaluation::TN, Evaluation::TP};
    const char* names[4] = {"FN", "FP", "TN", "TP"};

    for (auto& entry : *mResults) {
        auto& name = entry.first;
        auto& file = *entry.second;
        out << name << ' ' << file.size() << '\n';

        for (int e = 0; e < 4; e++) {
            out << names[e];
            Evaluation eval = evals[e];

            for (auto value : file) { out << ' ' << (value == eval); }

            out << '\n';
        }
    }
}

void Report::info(std::ostream& out, const Results& results, const Results& baseline,
                  const Args& args, float seconds) {
    std::vector<std::string> fields;
    bool haveBase = false;
    int count[4] = {0, 0, 0, 0};
    int countBase[4] = {0, 0, 0, 0};

    auto reset = [](int* count) {
        count[0] = 0;
        count[1] = 0;
        count[2] = 0;
        count[3] = 0;
    };
    auto precision = [](int* count) {
        int div = count[int(Evaluation::TP)] + count[int(Evaluation::FP)];
        if (div == 0) return 0.;
        return count[int(Evaluation::TP)] / double(div);
    };
    auto recall = [](int* count) {
        int div = count[int(Evaluation::TP)] + count[int(Evaluation::FN)];
        if (div == 0) return 0.;
        return count[int(Evaluation::TP)] / double(div);
    };
    auto percent = [](std::ostream& out, double val) {
        out << std::fixed << std::setprecision(2) << (val * 100) << '%';
    };
    auto countStr = [&](Evaluation eval) {
        std::ostringstream out;
        int val = count[int(eval)];
        out << val;
        if (haveBase) {
            int delta = val - countBase[int(eval)];
            if (delta != 0) { out << " (" << std::showpos << delta << std::noshowpos << ')'; }
        }
        return out.str();
    };
    auto percentStr = [&](double (*calc)(int*)) {
        std::ostringstream out;
        double val = calc(count);
        percent(out, val);
        if (haveBase) {
            double delta = val - calc(countBase);
            if (std::abs(delta) > 0.005) {
                out << " (" << std::showpos;
                percent(out, delta);
                out << std::noshowpos << ')';
            }
        }
        return out.str();
    };

    fields.push_back("name");
    fields.push_back("tp");
    fields.push_back("tn");
    fields.push_back("fp");
    fields.push_back("fn");
    fields.push_back("precision");
    fields.push_back("recall");

    for (auto& entry : results) {
        auto& name = entry.first;
        auto& file = *entry.second;
        if (file.size() == 0) continue;
        auto& baseFile = baseline.getFile(name);
        haveBase = baseFile.size() == file.size();

        reset(count);
        for (auto eval : file) { count[int(eval)]++; }
        if (haveBase) {
            reset(countBase);
            for (auto eval : baseFile) { countBase[int(eval)]++; }
        }

        fields.push_back(name);
        fields.push_back(countStr(Evaluation::TP));
        fields.push_back(countStr(Evaluation::TN));
        fields.push_back(countStr(Evaluation::FP));
        fields.push_back(countStr(Evaluation::FN));
        fields.push_back(percentStr(precision));
        fields.push_back(percentStr(recall));
    }

    constexpr int COLS = 7;
    FMO_ASSERT(fields.size() % COLS == 0, "bad number of fields");

    if (fields.size() == COLS) {
        // no entries -- quit
        return;
    }

    int colSize[COLS] = {0, 0, 0, 0, 0, 0, 0};
    for (auto it = fields.begin(); it != fields.end();) {
        for (int col = 0; col < COLS; col++, it++) {
            colSize[col] = std::max(colSize[col], int(it->size()) + 1);
        }
    }

    out << "parameters: " << std::defaultfloat << std::setprecision(6);
    args.printParameters(out, ' ');
    out << "\n\n";
    out << "generated on: " << timestamp() << '\n';
    out << "evaluation time: " << std::fixed << std::setprecision(1) << seconds << " s\n";
    out << '\n';
    int row = 0;
    for (auto it = fields.begin(); it != fields.end();) {
        out << std::setw(colSize[0]) << std::left << *it++ << std::right;
        for (int col = 1; col < COLS; col++, it++) { out << '|' << std::setw(colSize[col]) << *it; }
        out << '\n';
        if (row++ == 0) {
            for (int i = 0; i < colSize[0]; i++) { out << '-'; }
            for (int col = 1; col < COLS; col++) {
                out << '|';
                for (int i = 0; i < colSize[col]; i++) { out << '-'; }
            }
            out << '\n';
        }
    }
}
<|endoftext|>