<commit_before>//------------------------------------------------------------------------------
//  pnaclInstance.cc
//------------------------------------------------------------------------------
#include "Pre.h"
#include "pnaclInstance.h"
#include "Core/Assert.h"
#include "Core/App.h"
#include "ppapi/cpp/input_event.h"
#include "ppapi/cpp/var.h"
#include "ppapi/lib/gl/gles2/gl2ext_ppapi.h"

// externally provided Oryol main function
void PNaclAppCreator();

namespace Oryol {
namespace _priv {

pnaclInstance* pnaclInstance::self = nullptr;

//------------------------------------------------------------------------------
pnaclInstance::pnaclInstance(PP_Instance inst) :
pp::Instance(inst),
callbackFactory(this),
width(0),
height(0),
app(nullptr) {
    o_assert(nullptr == self);
    self = this;
}

//------------------------------------------------------------------------------
pnaclInstance::~pnaclInstance() {
    o_assert(nullptr != self);
    self = nullptr;
}

//------------------------------------------------------------------------------
bool
pnaclInstance::HasInstance() {
    return (nullptr != pnaclInstance::self);
}

//------------------------------------------------------------------------------
pnaclInstance*
pnaclInstance::Instance() {
    o_assert(nullptr != pnaclInstance::self);
    return pnaclInstance::self;
}

//------------------------------------------------------------------------------
bool
pnaclInstance::Init(uint32_t argc, const char* argn[], const char* argv[]) {
    // FIXME: convert command line args
    return true;
}

//------------------------------------------------------------------------------
void
pnaclInstance::DidChangeView(const pp::View& view) {
    int32_t newWidth = view.GetRect().width();
    int32_t newHeight = view.GetRect().height();

    if (this->context.is_null()) {
        // first call, setup everything and call the Oryol main function
        this->width = newWidth;
        this->height = newHeight;
        if (!this->initGL()) {
            // GL initialization failed
            return;
        }
        PNaclAppCreator();
    }
    else {
        // FIXME: a resize happened
        this->width = newWidth;
        this->height = newHeight;
    }
}

//------------------------------------------------------------------------------
void
pnaclInstance::DidChangeFocus(bool hasFocus) {
    pp::Instance::DidChangeFocus(hasFocus);
}

//------------------------------------------------------------------------------
bool
pnaclInstance::HandleInputEvent(const pp::InputEvent& event) {
    if (this->inputEventFunc) {
        return this->inputEventFunc(event);
    }
    else {
        return pp::Instance::HandleInputEvent(event);
    }
}

//------------------------------------------------------------------------------
bool
pnaclInstance::HandleDocumentLoad(const pp::URLLoader& urlLoader) {
    // FIXME!
    return pp::Instance::HandleDocumentLoad(urlLoader);
}

//------------------------------------------------------------------------------
void
pnaclInstance::HandleMessage(const pp::Var& message) {
    // FIXME!
    pp::Instance::HandleMessage(message);
}

//------------------------------------------------------------------------------
bool
pnaclInstance::initGL() {
    o_assert((this->width > 0) && (this->height > 0));

    if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) {
        Log::Error("Unable to initial GL PPAPI!\n");
        return false;
    }
    const int32_t attribList[] = {
        PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 0,
        PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24,
        PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 8,
        PP_GRAPHICS3DATTRIB_WIDTH, this->width,
        PP_GRAPHICS3DATTRIB_HEIGHT, this->height,
        PP_GRAPHICS3DATTRIB_NONE
    };
    this->context = pp::Graphics3D(this, attribList);
    if (!this->BindGraphics(this->context)) {
        Log::Error("Unable to bind 3D context!\n");
        this->context = pp::Graphics3D();
        glSetCurrentContextPPAPI(0);
        return false;
    }
    glSetCurrentContextPPAPI(this->context.pp_resource());
    return true;
}

//------------------------------------------------------------------------------
void
pnaclInstance::startMainLoop(App* app_) {
    o_assert(nullptr == this->app);
    o_assert(nullptr != app_);
    this->app = app_;
    this->doOneFrame(0);
}

//------------------------------------------------------------------------------
void
pnaclInstance::doOneFrame(int32_t) {
    o_assert(nullptr != this->app);
    o_assert(!this->context.is_null());
    this->app->onFrame();
    this->flushMessages();
    this->context.SwapBuffers(this->callbackFactory.NewCallback(&pnaclInstance::doOneFrame));
}

//------------------------------------------------------------------------------
int32
pnaclInstance::GetFramebufferWidth() const {
    return this->width;
}

//------------------------------------------------------------------------------
int32
pnaclInstance::GetFramebufferHeight() const {
    return this->height;
}

//------------------------------------------------------------------------------
/**
    NOTE: this method can be called from any thread.
*/
void
pnaclInstance::putMsg(const char* str) {
    this->msgLock.LockWrite();
    this->msgQueue.Enqueue(pp::Var(str));
    this->msgLock.UnlockWrite();
}

//------------------------------------------------------------------------------
void
pnaclInstance::flushMessages() {
    this->msgLock.LockWrite();
    Queue<pp::Var> q(std::move(this->msgQueue));
    this->msgLock.UnlockWrite();
    while (!q.Empty()) {
        pp::Var var(q.Dequeue());
        o_assert(var.is_string());
        this->PostMessage(var);
    }
}

//------------------------------------------------------------------------------
void
pnaclInstance::enableInput(std::function<bool(const pp::InputEvent&)> func) {
    this->RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE |
                             PP_INPUTEVENT_CLASS_WHEEL |
                             PP_INPUTEVENT_CLASS_KEYBOARD);
    this->inputEventFunc = func;
}

//------------------------------------------------------------------------------
void
pnaclInstance::disableInput() {
    this->RequestInputEvents(0);
    this->inputEventFunc = nullptr;
}

} // namespace _priv
} // namespace Oryol<commit_msg>Compile fix for PNaCl (Assert.h -> Assertion.h)<commit_after>//------------------------------------------------------------------------------
//  pnaclInstance.cc
//------------------------------------------------------------------------------
#include "Pre.h"
#include "pnaclInstance.h"
#include "Core/Assertion.h"
#include "Core/App.h"
#include "ppapi/cpp/input_event.h"
#include "ppapi/cpp/var.h"
#include "ppapi/lib/gl/gles2/gl2ext_ppapi.h"

// externally provided Oryol main function
void PNaclAppCreator();

namespace Oryol {
namespace _priv {

pnaclInstance* pnaclInstance::self = nullptr;

//------------------------------------------------------------------------------
pnaclInstance::pnaclInstance(PP_Instance inst) :
pp::Instance(inst),
callbackFactory(this),
width(0),
height(0),
app(nullptr) {
    o_assert(nullptr == self);
    self = this;
}

//------------------------------------------------------------------------------
pnaclInstance::~pnaclInstance() {
    o_assert(nullptr != self);
    self = nullptr;
}

//------------------------------------------------------------------------------
bool
pnaclInstance::HasInstance() {
    return (nullptr != pnaclInstance::self);
}

//------------------------------------------------------------------------------
pnaclInstance*
pnaclInstance::Instance() {
    o_assert(nullptr != pnaclInstance::self);
    return pnaclInstance::self;
}

//------------------------------------------------------------------------------
bool
pnaclInstance::Init(uint32_t argc, const char* argn[], const char* argv[]) {
    // FIXME: convert command line args
    return true;
}

//------------------------------------------------------------------------------
void
pnaclInstance::DidChangeView(const pp::View& view) {
    int32_t newWidth = view.GetRect().width();
    int32_t newHeight = view.GetRect().height();

    if (this->context.is_null()) {
        // first call, setup everything and call the Oryol main function
        this->width = newWidth;
        this->height = newHeight;
        if (!this->initGL()) {
            // GL initialization failed
            return;
        }
        PNaclAppCreator();
    }
    else {
        // FIXME: a resize happened
        this->width = newWidth;
        this->height = newHeight;
    }
}

//------------------------------------------------------------------------------
void
pnaclInstance::DidChangeFocus(bool hasFocus) {
    pp::Instance::DidChangeFocus(hasFocus);
}

//------------------------------------------------------------------------------
bool
pnaclInstance::HandleInputEvent(const pp::InputEvent& event) {
    if (this->inputEventFunc) {
        return this->inputEventFunc(event);
    }
    else {
        return pp::Instance::HandleInputEvent(event);
    }
}

//------------------------------------------------------------------------------
bool
pnaclInstance::HandleDocumentLoad(const pp::URLLoader& urlLoader) {
    // FIXME!
    return pp::Instance::HandleDocumentLoad(urlLoader);
}

//------------------------------------------------------------------------------
void
pnaclInstance::HandleMessage(const pp::Var& message) {
    // FIXME!
    pp::Instance::HandleMessage(message);
}

//------------------------------------------------------------------------------
bool
pnaclInstance::initGL() {
    o_assert((this->width > 0) && (this->height > 0));

    if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) {
        Log::Error("Unable to initial GL PPAPI!\n");
        return false;
    }
    const int32_t attribList[] = {
        PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 0,
        PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24,
        PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 8,
        PP_GRAPHICS3DATTRIB_WIDTH, this->width,
        PP_GRAPHICS3DATTRIB_HEIGHT, this->height,
        PP_GRAPHICS3DATTRIB_NONE
    };
    this->context = pp::Graphics3D(this, attribList);
    if (!this->BindGraphics(this->context)) {
        Log::Error("Unable to bind 3D context!\n");
        this->context = pp::Graphics3D();
        glSetCurrentContextPPAPI(0);
        return false;
    }
    glSetCurrentContextPPAPI(this->context.pp_resource());
    return true;
}

//------------------------------------------------------------------------------
void
pnaclInstance::startMainLoop(App* app_) {
    o_assert(nullptr == this->app);
    o_assert(nullptr != app_);
    this->app = app_;
    this->doOneFrame(0);
}

//------------------------------------------------------------------------------
void
pnaclInstance::doOneFrame(int32_t) {
    o_assert(nullptr != this->app);
    o_assert(!this->context.is_null());
    this->app->onFrame();
    this->flushMessages();
    this->context.SwapBuffers(this->callbackFactory.NewCallback(&pnaclInstance::doOneFrame));
}

//------------------------------------------------------------------------------
int32
pnaclInstance::GetFramebufferWidth() const {
    return this->width;
}

//------------------------------------------------------------------------------
int32
pnaclInstance::GetFramebufferHeight() const {
    return this->height;
}

//------------------------------------------------------------------------------
/**
    NOTE: this method can be called from any thread.
*/
void
pnaclInstance::putMsg(const char* str) {
    this->msgLock.LockWrite();
    this->msgQueue.Enqueue(pp::Var(str));
    this->msgLock.UnlockWrite();
}

//------------------------------------------------------------------------------
void
pnaclInstance::flushMessages() {
    this->msgLock.LockWrite();
    Queue<pp::Var> q(std::move(this->msgQueue));
    this->msgLock.UnlockWrite();
    while (!q.Empty()) {
        pp::Var var(q.Dequeue());
        o_assert(var.is_string());
        this->PostMessage(var);
    }
}

//------------------------------------------------------------------------------
void
pnaclInstance::enableInput(std::function<bool(const pp::InputEvent&)> func) {
    this->RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE |
                             PP_INPUTEVENT_CLASS_WHEEL |
                             PP_INPUTEVENT_CLASS_KEYBOARD);
    this->inputEventFunc = func;
}

//------------------------------------------------------------------------------
void
pnaclInstance::disableInput() {
    this->RequestInputEvents(0);
    this->inputEventFunc = nullptr;
}

} // namespace _priv
} // namespace Oryol
<|endoftext|>


<commit_before>#include <stdint.h>
#include <stdlib.h>

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
using namespace std;

#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>

#include <LineInformation.h> // symtabAPI
#include <CodeObject.h> // parseAPI
#include <InstructionDecoder.h> // instructionAPI
using namespace Dyninst;
using namespace SymtabAPI;
using namespace ParseAPI;
using namespace InstructionAPI;

char* fout_name;
char* fin_name;
char* bin_name;

ifstream fin;
ofstream fout;

Symtab *symtab_obj;
SymtabCodeSource *symtab_code_src;

int ip_idx;
bool is_mpi = false;
int taskid;
string hostname;

int dump_header()
{
    string linestr;
    istringstream ssIn;
    vector<string> tokens;

    getline(fin,linestr);

    if(linestr.compare(0,3,"MPI") == 0)
    {
        is_mpi = true;
        boost::split(tokens,linestr,boost::is_any_of("\n:"),boost::token_compress_on);

        // MPI Host
        boost::trim(tokens[1]);
        hostname = tokens[1];
        tokens.clear();

        // MPI Comm Rank
        getline(fin,linestr);
        boost::split(tokens,linestr,boost::is_any_of("\n:"),boost::token_compress_on);
        boost::trim(tokens[1]);
        taskid = boost::lexical_cast<int>(tokens[1]);
        tokens.clear();

        fout << "mpi_host,mpi_task,";

        getline(fin,linestr);
    }

    // Tuple header
    ssIn.str(linestr);
    boost::split(tokens,linestr,boost::is_any_of(","),boost::token_compress_on);

    fout << "source,line,instruction," << linestr << std::endl;

    ip_idx = 0;
    for(int i=0; i<tokens.size(); i++)
    {
        if(tokens[i] == "ip")
            return 0;
        ip_idx++;
    }

    cerr << "\"ip\" entry not found in header" << endl;

    return 1;
}

void dump_samples()
{
    string line;
    string tok;
    uint64_t ip;
    int sym_success;
    void *inst_raw;
    unsigned int addr_width = symtab_code_src->getAddressWidth();
    Architecture arch = symtab_obj->getArchitecture();
    while(getline(fin,line))
    {
        istringstream ssline(line);

        for(int i=0; i<=ip_idx; i++)
            getline(ssline,tok,',');

        istringstream sstok(tok);
        sstok >> hex >> ip;

        std::vector<Statement*> stats;
        sym_success = symtab_obj->getSourceLines(stats,ip);
        inst_raw = symtab_code_src->getPtrToInstruction(ip);

        if(is_mpi)
        {
            fout << hostname << ",";
            fout << taskid << ",";
        }

        if(sym_success)
        {
            fout << stats[0]->getFile().c_str() << ",";
            fout << stats[0]->getLine() << ",";
        }
        else
        {
            fout << "??,";
            fout << "??,";
        }

        if(inst_raw)
        {
            InstructionDecoder dec(inst_raw,addr_width,arch);
            Instruction::Ptr inst = dec.decode();
            Operation op = inst->getOperation();
            entryID eid = op.getID();
            std::string entrystr = NS_x86::entryNames_IAPI[eid];
            fout << entrystr << ",";
        }
        else
        {
            fout << "??,";
        }

        fout << line << std::endl;
    }
}

void usage(char **argv)
{
    cerr << "Usage: " << endl;
    cerr << argv[0] << " [options] <sample_file> <debug_binary>" << endl;
    cerr << "    [options]:" << endl;
    cerr << "        -o filename (default processed_<sample_file>)" << endl;
    cerr << "    <sample_file>: a csv file created using mitosrun" << endl;
    cerr << "    <debug_binary>: the binary executed with mitosrun (must contain debug symbols to be useful)" << endl;
}

void set_defaults()
{
    fout_name = (char*)malloc(strlen("processed_")+strlen(fin_name));
    sprintf(fout_name,"processed_%s",fin_name);
}

int parse_args(int argc, char **argv)
{
    int c;
    while((c=getopt(argc, argv, "o:")) != -1)
    {
        switch(c)
        {
            case 'o':
                fout_name = optarg;
                break;
            case '?':
                usage(argv);
                return 1;
            default:
                abort();
        }
    }

    if(optind+2 > argc)
    {
        usage(argv);
        return 1;
    }

    fin_name = argv[optind];
    bin_name = argv[optind+1];

    set_defaults();

    return 0;
}

int main(int argc, char **argv)
{
    if(argc < 3)
    {
        usage(argv);
        return 1;
    }

    if(parse_args(argc,argv))
        return 1;

    fin.open(fin_name);
    if(!fin.is_open())
    {
        cerr << "Error opening file " << fin_name << endl;
        cerr << "Aborting!" << endl;
        return 1;
    }

    fout.open(fout_name);
    if(!fout.is_open())
    {
        cerr << "Error opening file " << fout_name << endl;
        cerr << "Aborting!" << endl;
        return 1;
    }

    int success = Symtab::openFile(symtab_obj,bin_name);
    if(!success)
    {
        cerr << "SymtabAPI cannot open binary " << bin_name << endl;
        cerr << "Source/Line information will not be available!" << endl;
    }

    symtab_code_src = new SymtabCodeSource(bin_name);

    if(dump_header())
    {
        cerr << "Aborting!" << endl;
        return 1;
    }

    dump_samples();

    return 0;
}
<commit_msg>max instruction length<commit_after>#include <stdint.h>
#include <stdlib.h>

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
using namespace std;

#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>

#include <LineInformation.h> // symtabAPI
#include <CodeObject.h> // parseAPI
#include <InstructionDecoder.h> // instructionAPI
using namespace Dyninst;
using namespace SymtabAPI;
using namespace ParseAPI;
using namespace InstructionAPI;

char* fout_name;
char* fin_name;
char* bin_name;

ifstream fin;
ofstream fout;

Symtab *symtab_obj;
SymtabCodeSource *symtab_code_src;

int ip_idx;
bool is_mpi = false;
int taskid;
string hostname;

int dump_header()
{
    string linestr;
    istringstream ssIn;
    vector<string> tokens;

    getline(fin,linestr);

    if(linestr.compare(0,3,"MPI") == 0)
    {
        is_mpi = true;
        boost::split(tokens,linestr,boost::is_any_of("\n:"),boost::token_compress_on);

        // MPI Host
        boost::trim(tokens[1]);
        hostname = tokens[1];
        tokens.clear();

        // MPI Comm Rank
        getline(fin,linestr);
        boost::split(tokens,linestr,boost::is_any_of("\n:"),boost::token_compress_on);
        boost::trim(tokens[1]);
        taskid = boost::lexical_cast<int>(tokens[1]);
        tokens.clear();

        fout << "mpi_host,mpi_task,";

        getline(fin,linestr);
    }

    // Tuple header
    ssIn.str(linestr);
    boost::split(tokens,linestr,boost::is_any_of(","),boost::token_compress_on);

    fout << "source,line,instruction," << linestr << std::endl;

    ip_idx = 0;
    for(int i=0; i<tokens.size(); i++)
    {
        if(tokens[i] == "ip")
            return 0;
        ip_idx++;
    }

    cerr << "\"ip\" entry not found in header" << endl;

    return 1;
}

void dump_samples()
{
    string line;
    string tok;
    uint64_t ip;
    int sym_success;
    void *inst_raw;
    unsigned int addr_width = InstructionDecoder::maxInstructionLength;
    Architecture arch = symtab_obj->getArchitecture();
    while(getline(fin,line))
    {
        istringstream ssline(line);

        for(int i=0; i<=ip_idx; i++)
            getline(ssline,tok,',');

        istringstream sstok(tok);
        sstok >> hex >> ip;

        std::vector<Statement*> stats;
        sym_success = symtab_obj->getSourceLines(stats,ip);
        inst_raw = symtab_code_src->getPtrToInstruction(ip);

        if(is_mpi)
        {
            fout << hostname << ",";
            fout << taskid << ",";
        }

        if(sym_success)
        {
            fout << stats[0]->getFile().c_str() << ",";
            fout << stats[0]->getLine() << ",";
        }
        else
        {
            fout << "??,";
            fout << "??,";
        }

        if(inst_raw)
        {
            InstructionDecoder dec(inst_raw,addr_width,arch);
            Instruction::Ptr inst = dec.decode();
            Operation op = inst->getOperation();
            entryID eid = op.getID();
            std::string entrystr = NS_x86::entryNames_IAPI[eid];
            fout << entrystr << ",";
        }
        else
        {
            fout << "??,";
        }

        fout << line << std::endl;
    }
}

void usage(char **argv)
{
    cerr << "Usage: " << endl;
    cerr << argv[0] << " [options] <sample_file> <debug_binary>" << endl;
    cerr << "    [options]:" << endl;
    cerr << "        -o filename (default processed_<sample_file>)" << endl;
    cerr << "    <sample_file>: a csv file created using mitosrun" << endl;
    cerr << "    <debug_binary>: the binary executed with mitosrun (must contain debug symbols to be useful)" << endl;
}

void set_defaults()
{
    fout_name = (char*)malloc(strlen("processed_")+strlen(fin_name));
    sprintf(fout_name,"processed_%s",fin_name);
}

int parse_args(int argc, char **argv)
{
    int c;
    while((c=getopt(argc, argv, "o:")) != -1)
    {
        switch(c)
        {
            case 'o':
                fout_name = optarg;
                break;
            case '?':
                usage(argv);
                return 1;
            default:
                abort();
        }
    }

    if(optind+2 > argc)
    {
        usage(argv);
        return 1;
    }

    fin_name = argv[optind];
    bin_name = argv[optind+1];

    set_defaults();

    return 0;
}

int main(int argc, char **argv)
{
    if(argc < 3)
    {
        usage(argv);
        return 1;
    }

    if(parse_args(argc,argv))
        return 1;

    fin.open(fin_name);
    if(!fin.is_open())
    {
        cerr << "Error opening file " << fin_name << endl;
        cerr << "Aborting!" << endl;
        return 1;
    }

    fout.open(fout_name);
    if(!fout.is_open())
    {
        cerr << "Error opening file " << fout_name << endl;
        cerr << "Aborting!" << endl;
        return 1;
    }

    int success = Symtab::openFile(symtab_obj,bin_name);
    if(!success)
    {
        cerr << "SymtabAPI cannot open binary " << bin_name << endl;
        cerr << "Source/Line information will not be available!" << endl;
    }

    symtab_code_src = new SymtabCodeSource(bin_name);

    if(dump_header())
    {
        cerr << "Aborting!" << endl;
        return 1;
    }

    dump_samples();

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/*
 * Copyright (C) 2016-present ScyllaDB
 *
 * Modified by ScyllaDB
 */

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

#include "client_state.hh"
#include "auth/authorizer.hh"
#include "auth/authenticator.hh"
#include "auth/common.hh"
#include "auth/resource.hh"
#include "exceptions/exceptions.hh"
#include "validation.hh"
#include "db/system_keyspace.hh"
#include "db/schema_tables.hh"
#include "tracing/trace_keyspace_helper.hh"
#include "db/system_distributed_keyspace.hh"
#include "database.hh"
#include "cdc/log.hh"
#include "utils/overloaded_functor.hh"
#include <seastar/core/coroutine.hh>

thread_local api::timestamp_type service::client_state::_last_timestamp_micros = 0;

void service::client_state::set_login(auth::authenticated_user user) {
    _user = std::move(user);
}

future<> service::client_state::check_user_can_login() {
    if (auth::is_anonymous(*_user)) {
        return make_ready_future();
    }

    auto& role_manager = _auth_service->underlying_role_manager();

    return role_manager.exists(*_user->name).then([this](bool exists) mutable {
        if (!exists) {
            return make_exception_future<>(exceptions::authentication_exception(
                            format("User {} doesn't exist - create it with CREATE USER query first",
                                            *_user->name)));
        }
        return make_ready_future();
    }).then([this, &role_manager] {
        return role_manager.can_login(*_user->name).then([this](bool can_login) {
            if (!can_login) {
                return make_exception_future<>(exceptions::authentication_exception(format("{} is not permitted to log in", *_user->name)));
            }

            return make_ready_future();
        });
    });
}

void service::client_state::validate_login() const {
    if (!_user) {
        throw exceptions::unauthorized_exception("You have not logged in");
    }
}

void service::client_state::ensure_not_anonymous() const {
    validate_login();
    if (auth::is_anonymous(*_user)) {
        throw exceptions::unauthorized_exception("You have to be logged in and not anonymous to perform this request");
    }
}

future<> service::client_state::has_all_keyspaces_access(
                auth::permission p) const {
    if (_is_internal) {
        return make_ready_future();
    }
    validate_login();

    return do_with(auth::resource(auth::resource_kind::data), [this, p](const auto& r) {
        return ensure_has_permission({p, r});
    });
}

future<> service::client_state::has_keyspace_access(const database& db, const sstring& ks,
                auth::permission p) const {
    return do_with(ks, auth::make_data_resource(ks), [this, p, &db](auto const& ks, auto const& r) {
        return has_access(db, ks, {p, r});
    });
}

future<> service::client_state::has_column_family_access(const database& db, const sstring& ks,
                const sstring& cf, auth::permission p, auth::command_desc::type t) const {
    validation::validate_column_family(db, ks, cf);

    return do_with(ks, auth::make_data_resource(ks, cf), [this, p, t, &db](const auto& ks, const auto& r) {
        return has_access(db, ks, {p, r, t});
    });
}

future<> service::client_state::has_schema_access(const database& db, const schema& s, auth::permission p) const {
    return do_with(
            s.ks_name(),
            auth::make_data_resource(s.ks_name(),s.cf_name()),
            [this, p, &db](auto const& ks, auto const& r) {
        return has_access(db, ks, {p, r});
    });
}

future<> service::client_state::has_access(const database& db, const sstring& ks, auth::command_desc cmd) const {
    if (ks.empty()) {
        return make_exception_future<>(exceptions::invalid_request_exception("You have not set a keyspace for this session"));
    }
    if (_is_internal) {
        return make_ready_future();
    }

    validate_login();

    static const auto alteration_permissions = auth::permission_set::of<
            auth::permission::CREATE, auth::permission::ALTER, auth::permission::DROP>();

    // we only care about schema modification.
    if (alteration_permissions.contains(cmd.permission)) {
        // prevent system keyspace modification
        auto name = ks;
        std::transform(name.begin(), name.end(), name.begin(), ::tolower);
        if (is_system_keyspace(name)) {
            return make_exception_future<>(exceptions::unauthorized_exception(ks + " keyspace is not user-modifiable."));
        }

        //
        // we want to disallow dropping any contents of TRACING_KS and disallow dropping the `auth::meta::AUTH_KS`
        // keyspace.
        //

        const bool dropping_anything_in_tracing = (name == tracing::trace_keyspace_helper::KEYSPACE_NAME)
                && (cmd.permission == auth::permission::DROP);

        const bool dropping_auth_keyspace = (cmd.resource == auth::make_data_resource(auth::meta::AUTH_KS))
                && (cmd.permission == auth::permission::DROP);

        if (dropping_anything_in_tracing || dropping_auth_keyspace) {
            return make_exception_future<>(exceptions::unauthorized_exception(
                    format("Cannot {} {}", auth::permissions::to_string(cmd.permission), cmd.resource)));
        }
    }

    static thread_local std::unordered_set<auth::resource> readable_system_resources = [] {
        std::unordered_set<auth::resource> tmp;
        for (auto cf : { db::system_keyspace::LOCAL, db::system_keyspace::PEERS }) {
            tmp.insert(auth::make_data_resource(db::system_keyspace::NAME, cf));
        }
        for (auto cf : db::schema_tables::all_table_names(db::schema_features::full())) {
            tmp.insert(auth::make_data_resource(db::schema_tables::NAME, cf));
        }
        return tmp;
    }();

    if (cmd.permission == auth::permission::SELECT && readable_system_resources.contains(cmd.resource)) {
        return make_ready_future();
    }
    if (alteration_permissions.contains(cmd.permission)) {
        if (auth::is_protected(*_auth_service, cmd)) {
            return make_exception_future<>(exceptions::unauthorized_exception(format("{} is protected", cmd.resource)));
        }
    }

    if (cmd.resource.kind() == auth::resource_kind::data) {
        const auto resource_view = auth::data_resource_view(cmd.resource);
        if (resource_view.table()) {
            if (cmd.permission == auth::permission::DROP) {
                if (cdc::is_log_for_some_table(db, ks, *resource_view.table())) {
                    return make_exception_future<>(exceptions::unauthorized_exception(
                            format("Cannot {} cdc log table {}", auth::permissions::to_string(cmd.permission), cmd.resource)));
                }
            }

            static constexpr auto cdc_topology_description_forbidden_permissions = auth::permission_set::of<
                    auth::permission::ALTER, auth::permission::DROP>();

            if (cdc_topology_description_forbidden_permissions.contains(cmd.permission)) {
                if ((ks == db::system_distributed_keyspace::NAME || ks == db::system_distributed_keyspace::NAME_EVERYWHERE)
                        && (resource_view.table() == db::system_distributed_keyspace::CDC_DESC_V2
                        || resource_view.table() == db::system_distributed_keyspace::CDC_TOPOLOGY_DESCRIPTION
                        || resource_view.table() == db::system_distributed_keyspace::CDC_TIMESTAMPS
                        || resource_view.table() == db::system_distributed_keyspace::CDC_GENERATIONS_V2)) {
                    return make_exception_future<>(exceptions::unauthorized_exception(
                            format("Cannot {} {}", auth::permissions::to_string(cmd.permission), cmd.resource)));
                }
            }
        }
    }

    return ensure_has_permission(cmd);
}

future<bool> service::client_state::check_has_permission(auth::command_desc cmd) const {
    if (_is_internal) {
        return make_ready_future<bool>(true);
    }

    return do_with(cmd.resource.parent(), [this, cmd](const std::optional<auth::resource>& parent_r) {
        return auth::get_permissions(*_auth_service, *_user, cmd.resource).then(
                [this, p = cmd.permission, &parent_r](auth::permission_set set) {
            if (set.contains(p)) {
                return make_ready_future<bool>(true);
            }
            if (parent_r) {
                return check_has_permission({p, *parent_r});
            }
            return make_ready_future<bool>(false);
        });
    });
}

future<> service::client_state::ensure_has_permission(auth::command_desc cmd) const {
    return check_has_permission(cmd).then([this, cmd](bool ok) {
        if (!ok) {
            return make_exception_future<>(exceptions::unauthorized_exception(
                format("User {} has no {} permission on {} or any of its parents",
                        *_user,
                        auth::permissions::to_string(cmd.permission),
                        cmd.resource)));
        }
        return make_ready_future<>();
    });
}

void service::client_state::set_keyspace(database& db, std::string_view keyspace) {
    // Skip keyspace validation for non-authenticated users. Apparently, some client libraries
    // call set_keyspace() before calling login(), and we have to handle that.
    if (_user && !db.has_keyspace(keyspace)) {
        throw exceptions::invalid_request_exception(format("Keyspace '{}' does not exist", keyspace));
    }
    _keyspace = sstring(keyspace);
}

future<> service::client_state::ensure_exists(const auth::resource& r) const {
    return _auth_service->exists(r).then([&r](bool exists) {
        if (!exists) {
            return make_exception_future<>(exceptions::invalid_request_exception(format("{} doesn't exist.", r)));
        }

        return make_ready_future<>();
    });
}

future<> service::client_state::maybe_update_per_service_level_params() {
    if (_sl_controller && _user && _user->name) {
        auto& role_manager = _auth_service->underlying_role_manager();
        auto role_set = co_await role_manager.query_granted(_user->name.value(), auth::recursive_role_query::yes);
        auto slo_opt = co_await _sl_controller->find_service_level(role_set);
        if (!slo_opt) {
            co_return;
        }
        auto slo_timeout_or = [&] (const lowres_clock::duration& default_timeout) {
            return std::visit(overloaded_functor{
                [&] (const qos::service_level_options::unset_marker&) -> lowres_clock::duration {
                    return default_timeout;
                },
                [&] (const qos::service_level_options::delete_marker&) -> lowres_clock::duration {
                    return default_timeout;
                },
                [&] (const lowres_clock::duration& d) -> lowres_clock::duration {
                    return d;
                },
            }, slo_opt->timeout);
        };
        _timeout_config.read_timeout = slo_timeout_or(_default_timeout_config.read_timeout);
        _timeout_config.write_timeout = slo_timeout_or(_default_timeout_config.write_timeout);
        _timeout_config.range_read_timeout = slo_timeout_or(_default_timeout_config.range_read_timeout);
        _timeout_config.counter_write_timeout = slo_timeout_or(_default_timeout_config.counter_write_timeout);
        _timeout_config.truncate_timeout = slo_timeout_or(_default_timeout_config.truncate_timeout);
        _timeout_config.cas_timeout = slo_timeout_or(_default_timeout_config.cas_timeout);
        _timeout_config.other_timeout = slo_timeout_or(_default_timeout_config.other_timeout);

        _workload_type = slo_opt->workload;
    }
}
<commit_msg>service: coroutinize client_state.cc<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/*
 * Copyright (C) 2016-present ScyllaDB
 *
 * Modified by ScyllaDB
 */

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

#include "client_state.hh"
#include "auth/authorizer.hh"
#include "auth/authenticator.hh"
#include "auth/common.hh"
#include "auth/resource.hh"
#include "exceptions/exceptions.hh"
#include "validation.hh"
#include "db/system_keyspace.hh"
#include "db/schema_tables.hh"
#include "tracing/trace_keyspace_helper.hh"
#include "db/system_distributed_keyspace.hh"
#include "database.hh"
#include "cdc/log.hh"
#include "utils/overloaded_functor.hh"
#include <seastar/core/coroutine.hh>

thread_local api::timestamp_type service::client_state::_last_timestamp_micros = 0;

void service::client_state::set_login(auth::authenticated_user user) {
    _user = std::move(user);
}

future<> service::client_state::check_user_can_login() {
    if (auth::is_anonymous(*_user)) {
        co_return;
    }

    auto& role_manager = _auth_service->underlying_role_manager();

    const bool exists = co_await role_manager.exists(*_user->name);

    if (!exists) {
        throw exceptions::authentication_exception(
                format("User {} doesn't exist - create it with CREATE USER query first", *_user->name));
    }

    bool can_login = co_await role_manager.can_login(*_user->name);
    if (!can_login) {
        throw exceptions::authentication_exception(format("{} is not permitted to log in", *_user->name));
    }
}

void service::client_state::validate_login() const {
    if (!_user) {
        throw exceptions::unauthorized_exception("You have not logged in");
    }
}

void service::client_state::ensure_not_anonymous() const {
    validate_login();
    if (auth::is_anonymous(*_user)) {
        throw exceptions::unauthorized_exception("You have to be logged in and not anonymous to perform this request");
    }
}

future<> service::client_state::has_all_keyspaces_access(
                auth::permission p) const {
    if (_is_internal) {
        co_return;
    }
    validate_login();

    auth::resource r{auth::resource_kind::data};
    co_return co_await ensure_has_permission({p, r});
}

future<> service::client_state::has_keyspace_access(const database& db, const sstring& ks,
                auth::permission p) const {
    auth::resource r = auth::make_data_resource(ks);
    co_return co_await has_access(db, ks, {p, r});
}

future<> service::client_state::has_column_family_access(const database& db, const sstring& ks,
                const sstring& cf, auth::permission p, auth::command_desc::type t) const {
    // NOTICE: callers of this function tend to assume that this error will be thrown
    // synchronously and will be intercepted in a try-catch block. Thus, this function can only
    // be translated to a coroutine after all such callers are inspected and amended first.
    validation::validate_column_family(db, ks, cf);

    return do_with(ks, auth::make_data_resource(ks, cf), [this, p, t, &db](const auto& ks, const auto& r) {
        return has_access(db, ks, {p, r, t});
    });
}

future<> service::client_state::has_schema_access(const database& db, const schema& s, auth::permission p) const {
    auth::resource r = auth::make_data_resource(s.ks_name(), s.cf_name());
    co_return co_await has_access(db, s.ks_name(), {p, r});
}

future<> service::client_state::has_access(const database& db, const sstring& ks, auth::command_desc cmd) const {
    if (ks.empty()) {
        return make_exception_future<>(exceptions::invalid_request_exception("You have not set a keyspace for this session"));
    }
    if (_is_internal) {
        return make_ready_future();
    }

    validate_login();

    static const auto alteration_permissions = auth::permission_set::of<
            auth::permission::CREATE, auth::permission::ALTER, auth::permission::DROP>();

    // we only care about schema modification.
    if (alteration_permissions.contains(cmd.permission)) {
        // prevent system keyspace modification
        auto name = ks;
        std::transform(name.begin(), name.end(), name.begin(), ::tolower);
        if (is_system_keyspace(name)) {
            return make_exception_future<>(exceptions::unauthorized_exception(ks + " keyspace is not user-modifiable."));
        }

        //
        // we want to disallow dropping any contents of TRACING_KS and disallow dropping the `auth::meta::AUTH_KS`
        // keyspace.
        //

        const bool dropping_anything_in_tracing = (name == tracing::trace_keyspace_helper::KEYSPACE_NAME)
                && (cmd.permission == auth::permission::DROP);

        const bool dropping_auth_keyspace = (cmd.resource == auth::make_data_resource(auth::meta::AUTH_KS))
                && (cmd.permission == auth::permission::DROP);

        if (dropping_anything_in_tracing || dropping_auth_keyspace) {
            return make_exception_future<>(exceptions::unauthorized_exception(
                    format("Cannot {} {}", auth::permissions::to_string(cmd.permission), cmd.resource)));
        }
    }

    static thread_local std::unordered_set<auth::resource> readable_system_resources = [] {
        std::unordered_set<auth::resource> tmp;
        for (auto cf : { db::system_keyspace::LOCAL, db::system_keyspace::PEERS }) {
            tmp.insert(auth::make_data_resource(db::system_keyspace::NAME, cf));
        }
        for (auto cf : db::schema_tables::all_table_names(db::schema_features::full())) {
            tmp.insert(auth::make_data_resource(db::schema_tables::NAME, cf));
        }
        return tmp;
    }();

    if (cmd.permission == auth::permission::SELECT && readable_system_resources.contains(cmd.resource)) {
        return make_ready_future();
    }
    if (alteration_permissions.contains(cmd.permission)) {
        if (auth::is_protected(*_auth_service, cmd)) {
            return make_exception_future<>(exceptions::unauthorized_exception(format("{} is protected", cmd.resource)));
        }
    }

    if (cmd.resource.kind() == auth::resource_kind::data) {
        const auto resource_view = auth::data_resource_view(cmd.resource);
        if (resource_view.table()) {
            if (cmd.permission == auth::permission::DROP) {
                if (cdc::is_log_for_some_table(db, ks, *resource_view.table())) {
                    return make_exception_future<>(exceptions::unauthorized_exception(
                            format("Cannot {} cdc log table {}", auth::permissions::to_string(cmd.permission), cmd.resource)));
                }
            }

            static constexpr auto cdc_topology_description_forbidden_permissions = auth::permission_set::of<
                    auth::permission::ALTER, auth::permission::DROP>();

            if (cdc_topology_description_forbidden_permissions.contains(cmd.permission)) {
                if ((ks == db::system_distributed_keyspace::NAME || ks == db::system_distributed_keyspace::NAME_EVERYWHERE)
                        && (resource_view.table() == db::system_distributed_keyspace::CDC_DESC_V2
                        || resource_view.table() == db::system_distributed_keyspace::CDC_TOPOLOGY_DESCRIPTION
                        || resource_view.table() == db::system_distributed_keyspace::CDC_TIMESTAMPS
                        || resource_view.table() == db::system_distributed_keyspace::CDC_GENERATIONS_V2)) {
                    return make_exception_future<>(exceptions::unauthorized_exception(
                            format("Cannot {} {}", auth::permissions::to_string(cmd.permission), cmd.resource)));
                }
            }
        }
    }

    return ensure_has_permission(cmd);
}

future<bool> service::client_state::check_has_permission(auth::command_desc cmd) const {
    if (_is_internal) {
        co_return true;
    }

    std::optional<auth::resource> parent_r = cmd.resource.parent();

    auth::permission_set set = co_await auth::get_permissions(*_auth_service, *_user, cmd.resource);
    if (set.contains(cmd.permission)) {
        co_return true;
    }
    if (parent_r) {
        co_return co_await check_has_permission({cmd.permission, *parent_r});
    }
    co_return false;
}

future<> service::client_state::ensure_has_permission(auth::command_desc cmd) const {
    return check_has_permission(cmd).then([this, cmd](bool ok) {
        if (!ok) {
            return make_exception_future<>(exceptions::unauthorized_exception(
                format("User {} has no {} permission on {} or any of its parents",
                        *_user,
                        auth::permissions::to_string(cmd.permission),
                        cmd.resource)));
        }
        return make_ready_future<>();
    });
}

void service::client_state::set_keyspace(database& db, std::string_view keyspace) {
    // Skip keyspace validation for non-authenticated users. Apparently, some client libraries
    // call set_keyspace() before calling login(), and we have to handle that.
    if (_user && !db.has_keyspace(keyspace)) {
        throw exceptions::invalid_request_exception(format("Keyspace '{}' does not exist", keyspace));
    }
    _keyspace = sstring(keyspace);
}

future<> service::client_state::ensure_exists(const auth::resource& r) const {
    return _auth_service->exists(r).then([&r](bool exists) {
        if (!exists) {
            return make_exception_future<>(exceptions::invalid_request_exception(format("{} doesn't exist.", r)));
        }

        return make_ready_future<>();
    });
}

future<> service::client_state::maybe_update_per_service_level_params() {
    if (_sl_controller && _user && _user->name) {
        auto& role_manager = _auth_service->underlying_role_manager();
        auto role_set = co_await role_manager.query_granted(_user->name.value(), auth::recursive_role_query::yes);
        auto slo_opt = co_await _sl_controller->find_service_level(role_set);
        if (!slo_opt) {
            co_return;
        }
        auto slo_timeout_or = [&] (const lowres_clock::duration& default_timeout) {
            return std::visit(overloaded_functor{
                [&] (const qos::service_level_options::unset_marker&) -> lowres_clock::duration {
                    return default_timeout;
                },
                [&] (const qos::service_level_options::delete_marker&) -> lowres_clock::duration {
                    return default_timeout;
                },
                [&] (const lowres_clock::duration& d) -> lowres_clock::duration {
                    return d;
                },
            }, slo_opt->timeout);
        };
        _timeout_config.read_timeout = slo_timeout_or(_default_timeout_config.read_timeout);
        _timeout_config.write_timeout = slo_timeout_or(_default_timeout_config.write_timeout);
        _timeout_config.range_read_timeout = slo_timeout_or(_default_timeout_config.range_read_timeout);
        _timeout_config.counter_write_timeout = slo_timeout_or(_default_timeout_config.counter_write_timeout);
        _timeout_config.truncate_timeout = slo_timeout_or(_default_timeout_config.truncate_timeout);
        _timeout_config.cas_timeout = slo_timeout_or(_default_timeout_config.cas_timeout);
        _timeout_config.other_timeout = slo_timeout_or(_default_timeout_config.other_timeout);

        _workload_type = slo_opt->workload;
    }
}
<|endoftext|>


<commit_before>namespace mant {
  namespace robotic {
    class ParallelKinematicMachine3PRUS {
      public:
        inline explicit ParallelKinematicMachine3PRUS() noexcept;
        inline std::vector<arma::Mat<double>> getModelCharacterisation(
            const arma::Col<double>& endEffectorPose,
            const arma::Mat<double>& redundantJointActuations) const noexcept;

        inline arma::Mat<double>::fixed<2, 3> getLinkLengths() const noexcept;

        inline arma::Mat<double> getActuation(
            const arma::Col<double>& endEffectorPose,
            const arma::Mat<double>& redundantJointActuations) const noexcept;
        inline void setLinkLengths(
            const arma::Mat<double>::fixed<2, 3>& linkLengths) noexcept;

        inline double getPositionError(
            const arma::Col<double>& endEffectorPose,
            const arma::Mat<double>& redundantJointActuations) const noexcept;
        inline arma::Mat<double>::fixed<3, 3> getEndEffectorJointPositions() const noexcept;

        inline void setEndEffectorJointPositions(
            const arma::Mat<double>::fixed<3, 3>& endEffectorJointPositions) noexcept;

        inline arma::Mat<double>::fixed<3, 3> getRedundantJointStartPositions() const noexcept;

        inline void setRedundantJointStartPositions(
            const arma::Mat<double>::fixed<3, 3>& redundantJointStartPositions) noexcept;

        inline arma::Mat<double>::fixed<3, 3> getRedundantJointEndPositions() const noexcept;

        inline void setRedundantJointEndPositions(
            const arma::Mat<double>::fixed<3, 3>& redundantJointEndPositions) noexcept;

        inline arma::Mat<double>::fixed<2, 3> getBaseJointAngles() const noexcept;

        inline void setBaseJointAngles(
            const arma::Mat<double>::fixed<2, 3>& baseJointAngles) noexcept;

      protected:
        arma::Mat<double>::fixed<3, 3> endEffectorJointsRelative_;
        arma::Mat<double>::fixed<3, 3> linkLengths_;

        arma::Cube<double>::fixed<3, 3, 3> baseJointsRotation_;
        arma::Mat<double>::fixed<3, 3> baseJointsNormal_;

        arma::Mat<double>::fixed<3, 3> redundantJointStarts_;
        arma::Mat<double>::fixed<3, 3> redundantJointEnds_;
        arma::Mat<double>::fixed<3, 3> redundantJointsStartToEnd_;
        arma::Col<unsigned int> redundantJointIndicies_;
        arma::Mat<double> redundantJointAngles_;
    };

    //
    // Implementation
    //

    inline ParallelKinematicMachine3PRUS::ParallelKinematicMachine3PRUS() noexcept {
      setLinkLengths({
        0.24, 0.56,
        0.24, 0.56,
        0.24, 0.56});

      setEndEffectorJointPositions({
        -0.027346281319362, 0.067684421383375, 0.0,
        0.072289569018135, -0.010159636370085, 0.0,
        -0.044943287698773, -0.057524785013291, 0.0});

      setRedundantJointStartPositions({
        -0.050659008749464, 0.360457577021932, -0.6,
        0.337494923062311, -0.136356800003392, -0.6,
        -0.286835914312847, -0.224100777018540, -0.6});

      setRedundantJointEndPositions({
        -0.050659008749464, 0.360457577021932, 0.2,
        0.337494923062311, -0.136356800003392, 0.2,
        -0.286835914312847, -0.224100777018540, 0.2});

      setBaseJointAngles({
        0.0, 6.143558967020040,
        0.0, 1.954768762233649,
        0.0, 4.049163864626845});

      redundantJointStartToEndPositions_ = redundantJointEndPositions_ - redundantJointStartPositions_;
      redundantJointIndicies_ = arma::find(arma::any(redundantJointStartToEndPositions_));

      redundantJointAngles_.set_size(3, redundantJointIndicies_.n_elem);

      for (std::size_t n = 0; n < redundantJointIndicies_.n_elem; ++n) {
        const double& redundantJointXAngle = std::atan2(redundantJointStartToEndPositions_.at(1, n), redundantJointStartToEndPositions_.at(0, n));
        const double& redundantJointYAngle = std::atan2(redundantJointStartToEndPositions_.at(2, n), redundantJointStartToEndPositions_.at(1, n));
        redundantJointAngles_.col(n) = arma::Col<double>::fixed<3>({std::cos(redundantJointXAngle) * std::cos(redundantJointYAngle), std::sin(redundantJointXAngle) * std::cos(redundantJointYAngle), std::sin(redundantJointYAngle)});
      }

      for (std::size_t n = 0; n < baseJointAngles_.n_cols; ++n) {
        baseJointRotations_.slice(n) = get3DRotationMatrix(redundantJointAngles_.at(0, n), 0, redundantJointAngles_.at(1, n));
      }

      for (std::size_t n = 0; n < baseJointRotations_.n_slices; ++n) {
        baseJointNormals_.col(n) = arma::normalise(arma::cross(baseJointRotations_.slice(n).col(0), baseJointRotations_.slice(n).col(2)));
      }
    }

    inline std::vector<arma::Mat<double>> ParallelKinematicMachine3PRUS::getModelCharacterisation(
        const arma::Col<double>& endEffectorPose,
        const arma::Mat<double>& redundantJointActuations) const noexcept {
      std::vector<arma::Mat<double>> modelCharacterisation;
    inline arma::Mat<double>::fixed<2, 3> ParallelKinematicMachine3PRUS::getLinkLengths() const noexcept {
      return linkLengths_;
    }

    inline void ParallelKinematicMachine3PRUS::setLinkLengths(
        const arma::Mat<double>::fixed<2, 3>& linkLengths) noexcept {
      linkLengths_ = linkLengths;
    }

    inline arma::Mat<double>::fixed<3, 3> ParallelKinematicMachine3PRUS::getEndEffectorJointPositions() const noexcept {
      return endEffectorJointPositions_;
    }

    inline void ParallelKinematicMachine3PRUS::setEndEffectorJointPositions(
        const arma::Mat<double>::fixed<3, 3>& endEffectorJointPositions) noexcept {
      endEffectorJointPositions_ = endEffectorJointPositions;
    }

    inline arma::Mat<double>::fixed<3, 3> ParallelKinematicMachine3PRUS::getRedundantJointStartPositions() const noexcept {
      return redundantJointStartPositions_;
    }

    inline void ParallelKinematicMachine3PRUS::setRedundantJointStartPositions(
        const arma::Mat<double>::fixed<3, 3>& redundantJointStartPositions) noexcept {
      redundantJointStartPositions_ = redundantJointStartPositions;
    }

    inline arma::Mat<double>::fixed<3, 3> ParallelKinematicMachine3PRUS::getRedundantJointEndPositions() const noexcept {
      return redundantJointEndPositions_;
    }

    inline void ParallelKinematicMachine3PRUS::setRedundantJointEndPositions(
        const arma::Mat<double>::fixed<3, 3>& redundantJointEndPositions) noexcept {
      redundantJointEndPositions_ = redundantJointEndPositions;
    }

    inline arma::Mat<double>::fixed<2, 3> ParallelKinematicMachine3PRUS::getBaseJointAngles() const noexcept {
      return baseJointAngles_;
    }

    inline void ParallelKinematicMachine3PRUS::setBaseJointAngles(
        const arma::Mat<double>::fixed<2, 3>& baseJointAngles) noexcept {
      baseJointAngles_ = baseJointAngles;
    }

      if (arma::any(arma::vectorise(redundantJointActuations < 0)) || arma::any(arma::vectorise(redundantJointActuations > 1))) {
        throw std::logic_error("All values for the actuation of redundantion joints must be between [0, 1].");
      }

      const arma::Col<double>::fixed<3>& endEffectorPosition = endEffectorPose.subvec(0, 2);
      const double& endEffectorRollAngle = endEffectorPose.at(3);
      const double& endEffectorPitchAngle = endEffectorPose.at(4);
      const double& endEffectorYawAngle = endEffectorPose.at(5);

      arma::Mat<double>::fixed<3, 3> baseJoints = redundantJointStarts_;
      for (std::size_t n = 0; n < redundantJointIndicies_.n_elem; n++) {
        const unsigned int& redundantJointIndex = redundantJointIndicies_.at(n);
        baseJoints.col(redundantJointIndex) += redundantJointActuations.at(redundantJointIndex) * redundantJointsStartToEnd_.col(redundantJointIndex);
      }

      arma::Mat<double>::fixed<3, 3> endEffectorJoints = get3DRotationMatrix(endEffectorRollAngle, endEffectorPitchAngle, endEffectorYawAngle) * endEffectorJointsRelative_;
      endEffectorJoints.each_col() += endEffectorPosition;

      arma::Mat<double>::fixed<3, 3> passiveJoints;
      for (std::size_t n = 0; n < baseJoints.n_cols; ++n) {
        passiveJoints.col(n) = getCircleSphereIntersection(baseJoints.col(n), linkLengths_.at(0, n), baseJointsNormal_.col(n), endEffectorJoints.col(n), linkLengths_.at(1, n));
      }

      modelCharacterisation.push_back(baseJoints);
      modelCharacterisation.push_back(endEffectorJoints);
      modelCharacterisation.push_back(passiveJoints);

      return modelCharacterisation;
    }

    inline arma::Mat<double> ParallelKinematicMachine3PRUS::getActuation(
        const arma::Col<double>& endEffectorPose,
        const arma::Mat<double>& redundantJointActuations) const noexcept {
      const std::vector<arma::Mat<double>>& modelCharacterisation = getModelCharacterisation(endEffectorPose, redundantJointActuations);

      const arma::Mat<double>::fixed<3, 3>& baseJointPositions = modelCharacterisation.at(0);
      const arma::Mat<double>::fixed<3, 3>& passiveJointPositions = modelCharacterisation.at(2);

      const arma::Mat<double>::fixed<3, 3>& baseToPassiveJointPositions = passiveJointPositions - baseJointPositions;

      arma::Row<double>::fixed<3> actuation;
      for (std::size_t n = 0; n < baseToPassiveJointPositions.n_elem; ++n) {
        actuation.at(n) = std::atan2(baseToPassiveJointPositions.at(0, n), baseToPassiveJointPositions.at(2, n));
      }

      return actuation;
    }

    inline double ParallelKinematicMachine3PRUS::getPositionError(
        const arma::Col<double>& endEffectorPose,
        const arma::Mat<double>& redundantJointActuations) const noexcept {
      const std::vector<arma::Mat<double>>& modelCharacterisation = getModelCharacterisation(endEffectorPose, redundantJointActuations);

      const arma::Mat<double>::fixed<3, 3>& baseJoints = modelCharacterisation.at(0);

      const arma::Mat<double>::fixed<3, 3>& endEffectorJoints = modelCharacterisation.at(1);
      arma::Mat<double>::fixed<3, 3> endEffectorJointsRotated = endEffectorJoints;
      endEffectorJointsRotated.each_col() -= endEffectorPose.subvec(0, 2);

      const arma::Mat<double>::fixed<3, 3>& passiveJoints = modelCharacterisation.at(2);

      arma::Mat<double>::fixed<3, 3> relativeBaseToPassiveJoints = passiveJoints - baseJoints;
      for (std::size_t n = 0; n < relativeBaseToPassiveJoints.n_cols; ++n) {
        relativeBaseToPassiveJoints.col(n) = baseJointsRotation_.slice(n) * relativeBaseToPassiveJoints.col(n);
      }

      const arma::Mat<double>::fixed<3, 3>& baseToEndEffectorJoints = endEffectorJoints - baseJoints;

      arma::Mat<double>::fixed<6, 3> forwardKinematic;
      forwardKinematic.rows(0, 2) = baseToEndEffectorJoints;
      for (std::size_t n = 0; n < baseToEndEffectorJoints.n_cols; ++n) {
        forwardKinematic.submat(3, n, 5, n) = arma::cross(endEffectorJointsRotated.col(n), baseToEndEffectorJoints.col(n));
      }

      arma::Mat<double> inverseKinematic(3, 3 + redundantJointIndicies_.n_elem, arma::fill::zeros);
      inverseKinematic.diag() = forwardKinematic.row(0) % relativeBaseToPassiveJoints.row(1) - forwardKinematic.row(1) % relativeBaseToPassiveJoints.row(0);
      for (std::size_t n = 0; n < redundantJointIndicies_.n_elem; ++n) {
        const unsigned int& redundantJointIndex = redundantJointIndicies_.at(n);
        inverseKinematic.at(n, 3 + n) = arma::dot(baseToEndEffectorJoints.col(redundantJointIndex), redundantJointAngles_.col(redundantJointIndex));
      }

      return -1.0 / arma::cond(arma::solve(forwardKinematic.t(), inverseKinematic));
    }
  }
}
<commit_msg>devel: Renamed some API and fixed matrix/vector size<commit_after>namespace mant {
  namespace robotic {
    class ParallelKinematicMachine3PRUS {
      public:
        inline explicit ParallelKinematicMachine3PRUS() noexcept;

        inline arma::Mat<double>::fixed<2, 3> getLinkLengths() const noexcept;

        inline void setLinkLengths(
            const arma::Mat<double>::fixed<2, 3>& linkLengths) noexcept;

        inline arma::Mat<double>::fixed<3, 3> getEndEffectorJointPositions() const noexcept;

        inline void setEndEffectorJointPositions(
            const arma::Mat<double>::fixed<3, 3>& endEffectorJointPositions) noexcept;

        inline arma::Mat<double>::fixed<3, 3> getRedundantJointStartPositions() const noexcept;

        inline void setRedundantJointStartPositions(
            const arma::Mat<double>::fixed<3, 3>& redundantJointStartPositions) noexcept;

        inline arma::Mat<double>::fixed<3, 3> getRedundantJointEndPositions() const noexcept;

        inline void setRedundantJointEndPositions(
            const arma::Mat<double>::fixed<3, 3>& redundantJointEndPositions) noexcept;

        inline arma::Mat<double>::fixed<2, 3> getBaseJointAngles() const noexcept;

        inline void setBaseJointAngles(
            const arma::Mat<double>::fixed<2, 3>& baseJointAngles) noexcept;

        inline std::vector<arma::Mat<double>::fixed<3, 3>> getModel(
            const arma::Col<double>::fixed<6>& endEffectorPose,
            const arma::Row<double>& redundantJointActuations) const;

        inline arma::Row<double>::fixed<3> getActuation(
            const arma::Col<double>::fixed<6>& endEffectorPose,
            const arma::Row<double>& redundantJointActuations) const;

        inline arma::Col<double>::fixed<6> getEndEffectorPose(
            const arma::Row<double>::fixed<3>& actuations,
            const arma::Row<double>& redundantJointActuations) const;

        inline double getEndEffectorPoseAccuracy(
            const arma::Col<double>::fixed<6>& endEffectorPose,
            const arma::Row<double>& redundantJointActuations) const;

      protected:
        arma::Mat<double>::fixed<3, 3> endEffectorJointsRelative_;
        arma::Mat<double>::fixed<3, 3> linkLengths_;

        arma::Cube<double>::fixed<3, 3, 3> baseJointsRotation_;
        arma::Mat<double>::fixed<3, 3> baseJointsNormal_;

        arma::Mat<double>::fixed<3, 3> redundantJointStarts_;
        arma::Mat<double>::fixed<3, 3> redundantJointEnds_;
        arma::Mat<double>::fixed<3, 3> redundantJointsStartToEnd_;
        arma::Col<unsigned int> redundantJointIndicies_;
        arma::Mat<double> redundantJointAngles_;
    };

    //
    // Implementation
    //

    inline ParallelKinematicMachine3PRUS::ParallelKinematicMachine3PRUS() noexcept {
      setLinkLengths({
        0.24, 0.56,
        0.24, 0.56,
        0.24, 0.56});

      setEndEffectorJointPositions({
        -0.027346281319362, 0.067684421383375, 0.0,
        0.072289569018135, -0.010159636370085, 0.0,
        -0.044943287698773, -0.057524785013291, 0.0});

      setRedundantJointStartPositions({
        -0.050659008749464, 0.360457577021932, -0.6,
        0.337494923062311, -0.136356800003392, -0.6,
        -0.286835914312847, -0.224100777018540, -0.6});

      setRedundantJointEndPositions({
        -0.050659008749464, 0.360457577021932, 0.2,
        0.337494923062311, -0.136356800003392, 0.2,
        -0.286835914312847, -0.224100777018540, 0.2});

      setBaseJointAngles({
        0.0, 6.143558967020040,
        0.0, 1.954768762233649,
        0.0, 4.049163864626845});

      redundantJointStartToEndPositions_ = redundantJointEndPositions_ - redundantJointStartPositions_;
      redundantJointIndicies_ = arma::find(arma::any(redundantJointStartToEndPositions_));

      redundantJointAngles_.set_size(3, redundantJointIndicies_.n_elem);

      for (std::size_t n = 0; n < redundantJointIndicies_.n_elem; ++n) {
        const double& redundantJointXAngle = std::atan2(redundantJointStartToEndPositions_.at(1, n), redundantJointStartToEndPositions_.at(0, n));
        const double& redundantJointYAngle = std::atan2(redundantJointStartToEndPositions_.at(2, n), redundantJointStartToEndPositions_.at(1, n));
        redundantJointAngles_.col(n) = arma::Col<double>::fixed<3>({std::cos(redundantJointXAngle) * std::cos(redundantJointYAngle), std::sin(redundantJointXAngle) * std::cos(redundantJointYAngle), std::sin(redundantJointYAngle)});
      }

      for (std::size_t n = 0; n < baseJointAngles_.n_cols; ++n) {
        baseJointRotations_.slice(n) = get3DRotationMatrix(redundantJointAngles_.at(0, n), 0, redundantJointAngles_.at(1, n));
      }

      for (std::size_t n = 0; n < baseJointRotations_.n_slices; ++n) {
        baseJointNormals_.col(n) = arma::normalise(arma::cross(baseJointRotations_.slice(n).col(0), baseJointRotations_.slice(n).col(2)));
      }
    }

    inline arma::Mat<double>::fixed<2, 3> ParallelKinematicMachine3PRUS::getLinkLengths() const noexcept {
      return linkLengths_;
    }

    inline void ParallelKinematicMachine3PRUS::setLinkLengths(
        const arma::Mat<double>::fixed<2, 3>& linkLengths) noexcept {
      linkLengths_ = linkLengths;
    }

    inline arma::Mat<double>::fixed<3, 3> ParallelKinematicMachine3PRUS::getEndEffectorJointPositions() const noexcept {
      return endEffectorJointPositions_;
    }

    inline void ParallelKinematicMachine3PRUS::setEndEffectorJointPositions(
        const arma::Mat<double>::fixed<3, 3>& endEffectorJointPositions) noexcept {
      endEffectorJointPositions_ = endEffectorJointPositions;
    }

    inline arma::Mat<double>::fixed<3, 3> ParallelKinematicMachine3PRUS::getRedundantJointStartPositions() const noexcept {
      return redundantJointStartPositions_;
    }

    inline void ParallelKinematicMachine3PRUS::setRedundantJointStartPositions(
        const arma::Mat<double>::fixed<3, 3>& redundantJointStartPositions) noexcept {
      redundantJointStartPositions_ = redundantJointStartPositions;
    }

    inline arma::Mat<double>::fixed<3, 3> ParallelKinematicMachine3PRUS::getRedundantJointEndPositions() const noexcept {
      return redundantJointEndPositions_;
    }

    inline void ParallelKinematicMachine3PRUS::setRedundantJointEndPositions(
        const arma::Mat<double>::fixed<3, 3>& redundantJointEndPositions) noexcept {
      redundantJointEndPositions_ = redundantJointEndPositions;
    }

    inline arma::Mat<double>::fixed<2, 3> ParallelKinematicMachine3PRUS::getBaseJointAngles() const noexcept {
      return baseJointAngles_;
    }

    inline void ParallelKinematicMachine3PRUS::setBaseJointAngles(
        const arma::Mat<double>::fixed<2, 3>& baseJointAngles) noexcept {
      baseJointAngles_ = baseJointAngles;
    }

    inline std::vector<arma::Mat<double>::fixed<3, 3>> ParallelKinematicMachine3PRUS::getModel(
        const arma::Col<double>::fixed<6>& endEffectorPose,
        const arma::Row<double>& redundantJointActuations) const {
      if (arma::any(arma::vectorise(redundantJointActuations < 0)) || arma::any(arma::vectorise(redundantJointActuations > 1))) {
        throw std::logic_error("All values for the actuation of redundantion joints must be between [0, 1].");
      }

      const arma::Col<double>::fixed<3>& endEffectorPosition = endEffectorPose.subvec(0, 2);
      const double& endEffectorRollAngle = endEffectorPose.at(3);
      const double& endEffectorPitchAngle = endEffectorPose.at(4);
      const double& endEffectorYawAngle = endEffectorPose.at(5);

      arma::Mat<double>::fixed<3, 3> baseJoints = redundantJointStarts_;
      for (std::size_t n = 0; n < redundantJointIndicies_.n_elem; n++) {
        const unsigned int& redundantJointIndex = redundantJointIndicies_.at(n);
        baseJoints.col(redundantJointIndex) += redundantJointActuations.at(redundantJointIndex) * redundantJointsStartToEnd_.col(redundantJointIndex);
      }

      arma::Mat<double>::fixed<3, 3> endEffectorJoints = get3DRotationMatrix(endEffectorRollAngle, endEffectorPitchAngle, endEffectorYawAngle) * endEffectorJointsRelative_;
      endEffectorJoints.each_col() += endEffectorPosition;

      arma::Mat<double>::fixed<3, 3> passiveJoints;
      for (std::size_t n = 0; n < baseJoints.n_cols; ++n) {
        passiveJoints.col(n) = getCircleSphereIntersection(baseJoints.col(n), linkLengths_.at(0, n), baseJointsNormal_.col(n), endEffectorJoints.col(n), linkLengths_.at(1, n));
      }

      modelCharacterisation.push_back(baseJoints);
      modelCharacterisation.push_back(endEffectorJoints);
      modelCharacterisation.push_back(passiveJoints);

      return model;
    }

    inline arma::Row<double>::fixed<3> ParallelKinematicMachine3PRUS::getActuation(
        const arma::Col<double>::fixed<6>& endEffectorPose,
        const arma::Row<double>& redundantJointActuations) const {
      const std::vector<arma::Mat<double>::fixed<3, 3>>& model = getModel(endEffectorPose, redundantJointActuations);

      const arma::Mat<double>::fixed<3, 3>& baseJointPositions = model.at(0);
      const arma::Mat<double>::fixed<3, 3>& passiveJointPositions = model.at(1);

      const arma::Mat<double>::fixed<3, 3>& baseToPassiveJointPositions = passiveJointPositions - baseJointPositions;

      arma::Row<double>::fixed<3> actuation;
      for (std::size_t n = 0; n < baseToPassiveJointPositions.n_elem; ++n) {
        actuation.at(n) = std::atan2(baseToPassiveJointPositions.at(0, n), baseToPassiveJointPositions.at(2, n));
      }

      return actuation;
    }

    inline arma::Col<double>::fixed<6> ParallelKinematicMachine3PRUS::getEndEffectorPose(
        const arma::Row<double>::fixed<3>& actuations,
        const arma::Row<double>& redundantJointActuations) const {
      // TODO Direct kinematic (estimate position, using a simple HillCLimber algorithm)
      return {0, 0, 0, 0, 0, 0};
    }

    inline double ParallelKinematicMachine3PRUS::getEndEffectorPoseAccuracy(
        const arma::Col<double>::fixed<6>& endEffectorPose,
        const arma::Row<double>& redundantJointActuations) const {
      const std::vector<arma::Mat<double>::fixed<3, 3>>& model = getModel(endEffectorPose, redundantJointActuations);

      const arma::Mat<double>::fixed<3, 3>& baseJoints = model.at(0);

      const arma::Mat<double>::fixed<3, 3>& endEffectorJoints = model.at(2);
      arma::Mat<double>::fixed<3, 3> endEffectorJointsRotated = endEffectorJoints;
      endEffectorJointsRotated.each_col() -= endEffectorPose.subvec(0, 2);

      const arma::Mat<double>::fixed<3, 3>& passiveJoints = model.at(1);

      arma::Mat<double>::fixed<3, 3> relativeBaseToPassiveJoints = passiveJoints - baseJoints;
      for (std::size_t n = 0; n < relativeBaseToPassiveJoints.n_cols; ++n) {
        relativeBaseToPassiveJoints.col(n) = baseJointsRotation_.slice(n) * relativeBaseToPassiveJoints.col(n);
      }

      const arma::Mat<double>::fixed<3, 3>& baseToEndEffectorJoints = endEffectorJoints - baseJoints;

      arma::Mat<double>::fixed<6, 3> forwardKinematic;
      forwardKinematic.rows(0, 2) = baseToEndEffectorJoints;
      for (std::size_t n = 0; n < baseToEndEffectorJoints.n_cols; ++n) {
        forwardKinematic.submat(3, n, 5, n) = arma::cross(endEffectorJointsRotated.col(n), baseToEndEffectorJoints.col(n));
      }

      arma::Mat<double> inverseKinematic(3, 3 + redundantJointIndicies_.n_elem, arma::fill::zeros);
      inverseKinematic.diag() = forwardKinematic.row(0) % relativeBaseToPassiveJoints.row(1) - forwardKinematic.row(1) % relativeBaseToPassiveJoints.row(0);
      for (std::size_t n = 0; n < redundantJointIndicies_.n_elem; ++n) {
        const unsigned int& redundantJointIndex = redundantJointIndicies_.at(n);
        inverseKinematic.at(n, 3 + n) = arma::dot(baseToEndEffectorJoints.col(redundantJointIndex), redundantJointAngles_.col(redundantJointIndex));
      }

      return -1.0 / arma::cond(arma::solve(forwardKinematic.t(), inverseKinematic));
    }
  }
}
<|endoftext|>


<commit_before>#include <gflags/gflags.h>
#include <stddef.h>
#include <algorithm>
#include <chrono>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

#include "ncode_common/src/common.h"
#include "ncode_common/src/event_queue.h"
#include "ncode_common/src/file.h"
#include "ncode_common/src/htsim/match.h"
#include "ncode_common/src/logging.h"
#include "ncode_common/src/lp/demand_matrix.h"
#include "ncode_common/src/net/net_common.h"
#include "ncode_common/src/net/net_gen.h"
#include "ncode_common/src/strutil.h"
#include "common.h"
#include "controller.h"
#include "mean_est/mean_est.h"
#include "metrics/metrics.h"
#include "net_instrument.h"
#include "net_mock.h"
#include "opt/ctr.h"
#include "opt/opt.h"
#include "opt/path_provider.h"
#include "pcap_data.h"
#include "routing_system.h"
#include "tldr.h"

using namespace std::chrono;

DEFINE_string(topology, "", "A file with a topology");
DEFINE_string(traffic_matrix, "", "A file with a traffic matrix");
DEFINE_string(pcap_trace_store, "trace_store.pb",
              "A file with information about .pcap traces");
DEFINE_string(pcap_trace_fit_store, "",
              "A file with a series of PBTraceToFitRate protobufs");
DEFINE_uint64(period_duration_ms, 60000, "Length of the period");
DEFINE_uint64(history_bin_size_ms, 100, "How big each history bin is");
DEFINE_double(decay_factor, 0.0, "How quickly to decay prediction");
DEFINE_double(estimator_headroom, 1.1, "Fixed headroom for the estimator");
DEFINE_double(link_capacity_scale, 1.0,
              "By how much to scale all links' bandwidth");
DEFINE_double(link_delay_scale, 1.3, "By how much to scale all links' delay");
DEFINE_double(tm_scale, 1.0, "By how much to scale the traffic matrix");
DEFINE_uint64(duration_ms, 90000, "For how long to run (in simulated time)");
DEFINE_double(exceed_probability, 0.001,
              "Probability convolution to exceed rate");

// A global variable that will keep a reference to the event queue, useful for
// logging, as the logging handler only accepts a C-style function pointer.
static nc::EventQueue* event_queue_global_ptr;

void CustomLogHandler(nc::LogLevel level, const char* filename, int line,
                      const std::string& message, nc::LogColor color) {
  uint64_t time_as_ms = event_queue_global_ptr->TimeToRawMillis(
      event_queue_global_ptr->CurrentTime());
  std::string new_message = nc::StrCat(time_as_ms, "ms ", message);
  nc::DefaultLogHandler(level, filename, line, new_message, color);
}

static uint64_t FlowCountFromBinsSequence(const ctr::BinSequence& bin_sequence,
                                          ctr::PcapDataBinCache* bin_cache) {
  std::vector<uint64_t> syns;

  for (const auto& bin :
       bin_sequence.AccumulateBins(bin_sequence.bin_size(), bin_cache)) {
    syns.emplace_back(bin.flows_enter);
  }

  return ctr::GetFlowCountFromSyns(syns);
}

static void HandleDefault(
    const nc::net::GraphStorage& graph,
    std::map<ctr::AggregateId, std::unique_ptr<ctr::BinSequence>>&&
        initial_sequences,
    nc::net::DevicePortNumber enter_port, milliseconds poll_period,
    milliseconds round_duration, nc::EventQueue* event_queue,
    ctr::controller::NetworkContainer* network_container) {
  // Will first add aggregates and populate the device factory.
  ctr::MockSimDeviceFactory device_factory(enter_port, event_queue);
  for (auto& id_and_bin_sequence : initial_sequences) {
    const ctr::AggregateId& id = id_and_bin_sequence.first;
    std::unique_ptr<ctr::BinSequence>& bin_sequence =
        id_and_bin_sequence.second;
    std::unique_ptr<ctr::BinSequence> from_start =
        bin_sequence->CutFromStart(round_duration);

    uint64_t flow_count =
        FlowCountFromBinsSequence(*from_start, device_factory.bin_cache());
    ctr::AggregateHistory init_history = from_start->GenerateHistory(
        poll_period, flow_count, device_factory.bin_cache());

    nc::htsim::MatchRuleKey key_for_aggregate =
        network_container->AddAggregate(id, init_history);

    // Will add the bin sequence to the source device.
    const std::string& src_device_id = graph.GetNode(id.src())->id();
    device_factory.AddBinSequence(src_device_id, key_for_aggregate,
                                  std::move(bin_sequence));

    // Will also add the reverse aggregate for ACKs.
    //    auto ack_history =
    //        ctr::GetDummyHistory(nc::net::Bandwidth::FromKBitsPerSecond(100),
    //                             milliseconds(FLAGS_history_bin_size_ms),
    //                             milliseconds(FLAGS_period_duration_ms), 10);
    //    network_container->AddAggregate(id.Reverse(), ack_history);
  }

  // Records per-path stats.
  ctr::InputPacketObserver input_packet_observer(
      network_container->controller(), milliseconds(10), event_queue);

  // Monitors queues.
  ctr::OutputPacketObserver output_packet_observer(event_queue);

  // Now that the device factory is ready, we can initialize the container.
  network_container->AddElementsFromGraph(
      &device_factory, &input_packet_observer, &output_packet_observer);
  network_container->InitAggregatesInController();

  ctr::NetInstrument net_instrument(network_container->internal_queues(),
                                    network_container->flow_group_tcp_sources(),
                                    milliseconds(10), event_queue);
  device_factory.Init();
  event_queue->RunAndStopIn(milliseconds(FLAGS_duration_ms));
  output_packet_observer.RecordDist();
}

static std::string StripExtension(const std::string& filename) {
  std::size_t found = filename.find_last_of(".");
  return filename.substr(0, found);
}

int main(int argc, char** argv) {
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  nc::metrics::InitMetrics();

  // The event queue.
  nc::SimTimeEventQueue event_queue;
  event_queue_global_ptr = &event_queue;
  nc::SetLogHandler(CustomLogHandler);

  auto timestamp_provider =
      ::nc::make_unique<nc::metrics::SimTimestampProvider>(&event_queue);
  nc::metrics::DefaultMetricManager()->set_timestamp_provider(
      std::move(timestamp_provider));

  CHECK(!FLAGS_topology.empty());
  CHECK(!FLAGS_traffic_matrix.empty());

  std::vector<std::string> node_order;
  nc::net::GraphBuilder builder = nc::net::LoadRepetitaOrDie(
      nc::File::ReadFileToStringOrDie(FLAGS_topology), &node_order);
  builder.RemoveMultipleLinks();
  builder.ScaleCapacity(FLAGS_link_capacity_scale);
  builder.ScaleDelay(FLAGS_link_delay_scale);
  nc::net::GraphStorage graph(builder);

  nc::net::Delay diameter = graph.Stats().sp_delay_percentiles.back();
  if (diameter < milliseconds(10)) {
    LOG(FATAL) << "Graph diameter too small ("
               << duration_cast<milliseconds>(diameter).count() << "ms)";
  }

  ctr::PcapTraceStore trace_store(FLAGS_pcap_trace_store);
  std::string fit_store = FLAGS_pcap_trace_fit_store;
  if (fit_store.empty()) {
    fit_store = nc::StrCat(StripExtension(FLAGS_traffic_matrix), "_fit.pb");
  }
  CHECK(nc::File::Exists(fit_store)) << " fit store does not exist "
                                     << fit_store;

  ctr::PcapTraceFitStore trace_fit_store(fit_store, &trace_store);
  std::unique_ptr<nc::lp::DemandMatrix> demand_matrix =
      nc::lp::DemandMatrix::LoadRepetitaOrDie(
          nc::File::ReadFileToStringOrDie(FLAGS_traffic_matrix), node_order,
          &graph);
  demand_matrix = demand_matrix->Scale(FLAGS_tm_scale);

  size_t i = -1;
  std::map<ctr::AggregateId, std::unique_ptr<ctr::BinSequence>>
      initial_sequences;
  for (const auto& matrix_element : demand_matrix->elements()) {
    LOG(INFO) << "Looking for traces to match " << matrix_element.demand.Mbps()
              << "Mbps";
    std::unique_ptr<ctr::BinSequence> bin_sequence =
        trace_fit_store.GetBinSequence(matrix_element.demand);
    CHECK(bin_sequence);

    std::unique_ptr<ctr::BinSequence> bin_sequence_extended =
        trace_store.ExtendBinSequence(*bin_sequence);

    initial_sequences.emplace(
        std::piecewise_construct,
        std::forward_as_tuple(matrix_element.src, matrix_element.dst),
        std::forward_as_tuple(std::move(bin_sequence_extended)));
    LOG(INFO) << "Bin sequence " << ++i << " / "
              << demand_matrix->elements().size();
  }

  ctr::PathProvider path_provider(&graph);
  ctr::CTROptimizer opt(&path_provider, 0.95, true, false);

  ctr::ProbModelConfig prob_model_config;
  prob_model_config.exceed_probability = FLAGS_exceed_probability;

  ctr::MeanScaleEstimatorFactory estimator_factory(
      {FLAGS_estimator_headroom, FLAGS_decay_factor, FLAGS_decay_factor, 10});
  ctr::RoutingSystemConfig routing_system_config;
  routing_system_config.prob_model_config = prob_model_config;
  ctr::RoutingSystem routing_system(routing_system_config, &opt,
                                    &estimator_factory);

  nc::net::IPAddress controller_ip(100);
  nc::net::IPAddress device_ip_base(20000);
  nc::net::IPAddress tldr_ip_base(30000);
  nc::net::IPAddress flow_group_ip_base(40000);
  nc::net::DevicePortNumber enter_port(4000);
  nc::net::DevicePortNumber exit_port(5000);

  milliseconds round_duration(FLAGS_period_duration_ms);
  milliseconds poll_period(FLAGS_history_bin_size_ms);

  ctr::controller::Controller controller(controller_ip, &routing_system,
                                         &event_queue, &graph);
  ctr::controller::NetworkContainerConfig containter_config(
      device_ip_base, tldr_ip_base, flow_group_ip_base, enter_port, exit_port,
      milliseconds(100), milliseconds(1000000), false);

  nc::ThresholdEnforcerPolicy te_policy;
  ctr::TLDRConfig tldr_config(te_policy, prob_model_config,
                              nc::htsim::kWildIPAddress,
                              nc::htsim::kWildIPAddress, controller_ip,
                              round_duration, poll_period, 100);
  ctr::controller::NetworkContainer network_container(
      containter_config, tldr_config, &graph, &controller, &event_queue);

  nc::htsim::ProgressIndicator progress_indicator(milliseconds(100),
                                                  &event_queue);
  HandleDefault(graph, std::move(initial_sequences), enter_port, poll_period,
                round_duration, &event_queue, &network_container);

  nc::metrics::DefaultMetricManager()->PersistAllMetrics();
}
<commit_msg>added a flag<commit_after>#include <gflags/gflags.h>
#include <stddef.h>
#include <algorithm>
#include <chrono>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

#include "ncode_common/src/common.h"
#include "ncode_common/src/event_queue.h"
#include "ncode_common/src/file.h"
#include "ncode_common/src/htsim/match.h"
#include "ncode_common/src/logging.h"
#include "ncode_common/src/lp/demand_matrix.h"
#include "ncode_common/src/net/net_common.h"
#include "ncode_common/src/net/net_gen.h"
#include "ncode_common/src/strutil.h"
#include "common.h"
#include "controller.h"
#include "mean_est/mean_est.h"
#include "metrics/metrics.h"
#include "net_instrument.h"
#include "net_mock.h"
#include "opt/ctr.h"
#include "opt/opt.h"
#include "opt/path_provider.h"
#include "pcap_data.h"
#include "routing_system.h"
#include "tldr.h"

using namespace std::chrono;

DEFINE_string(topology, "", "A file with a topology");
DEFINE_string(traffic_matrix, "", "A file with a traffic matrix");
DEFINE_string(pcap_trace_store, "trace_store.pb",
              "A file with information about .pcap traces");
DEFINE_string(pcap_trace_fit_store, "",
              "A file with a series of PBTraceToFitRate protobufs");
DEFINE_uint64(period_duration_ms, 60000, "Length of the period");
DEFINE_uint64(history_bin_size_ms, 100, "How big each history bin is");
DEFINE_double(decay_factor, 0.0, "How quickly to decay prediction");
DEFINE_double(estimator_headroom, 1.1, "Fixed headroom for the estimator");
DEFINE_double(link_capacity_scale, 1.0,
              "By how much to scale all links' bandwidth");
DEFINE_double(link_delay_scale, 1.3, "By how much to scale all links' delay");
DEFINE_double(tm_scale, 1.0, "By how much to scale the traffic matrix");
DEFINE_uint64(duration_ms, 90000, "For how long to run (in simulated time)");
DEFINE_double(exceed_probability, 0.001,
              "Probability convolution to exceed rate");
DEFINE_bool(sp_opt, false, "If true will run SP routing instead of CTR");

// A global variable that will keep a reference to the event queue, useful for
// logging, as the logging handler only accepts a C-style function pointer.
static nc::EventQueue* event_queue_global_ptr;

void CustomLogHandler(nc::LogLevel level, const char* filename, int line,
                      const std::string& message, nc::LogColor color) {
  uint64_t time_as_ms = event_queue_global_ptr->TimeToRawMillis(
      event_queue_global_ptr->CurrentTime());
  std::string new_message = nc::StrCat(time_as_ms, "ms ", message);
  nc::DefaultLogHandler(level, filename, line, new_message, color);
}

static uint64_t FlowCountFromBinsSequence(const ctr::BinSequence& bin_sequence,
                                          ctr::PcapDataBinCache* bin_cache) {
  std::vector<uint64_t> syns;

  for (const auto& bin :
       bin_sequence.AccumulateBins(bin_sequence.bin_size(), bin_cache)) {
    syns.emplace_back(bin.flows_enter);
  }

  return ctr::GetFlowCountFromSyns(syns);
}

static void HandleDefault(
    const nc::net::GraphStorage& graph,
    std::map<ctr::AggregateId, std::unique_ptr<ctr::BinSequence>>&&
        initial_sequences,
    nc::net::DevicePortNumber enter_port, milliseconds poll_period,
    milliseconds round_duration, nc::EventQueue* event_queue,
    ctr::controller::NetworkContainer* network_container) {
  // Will first add aggregates and populate the device factory.
  ctr::MockSimDeviceFactory device_factory(enter_port, event_queue);
  for (auto& id_and_bin_sequence : initial_sequences) {
    const ctr::AggregateId& id = id_and_bin_sequence.first;
    std::unique_ptr<ctr::BinSequence>& bin_sequence =
        id_and_bin_sequence.second;
    std::unique_ptr<ctr::BinSequence> from_start =
        bin_sequence->CutFromStart(round_duration);

    uint64_t flow_count =
        FlowCountFromBinsSequence(*from_start, device_factory.bin_cache());
    ctr::AggregateHistory init_history = from_start->GenerateHistory(
        poll_period, flow_count, device_factory.bin_cache());

    nc::htsim::MatchRuleKey key_for_aggregate =
        network_container->AddAggregate(id, init_history);

    // Will add the bin sequence to the source device.
    const std::string& src_device_id = graph.GetNode(id.src())->id();
    device_factory.AddBinSequence(src_device_id, key_for_aggregate,
                                  std::move(bin_sequence));

    // Will also add the reverse aggregate for ACKs.
    //    auto ack_history =
    //        ctr::GetDummyHistory(nc::net::Bandwidth::FromKBitsPerSecond(100),
    //                             milliseconds(FLAGS_history_bin_size_ms),
    //                             milliseconds(FLAGS_period_duration_ms), 10);
    //    network_container->AddAggregate(id.Reverse(), ack_history);
  }

  // Records per-path stats.
  ctr::InputPacketObserver input_packet_observer(
      network_container->controller(), milliseconds(10), event_queue);

  // Monitors queues.
  ctr::OutputPacketObserver output_packet_observer(event_queue);

  // Now that the device factory is ready, we can initialize the container.
  network_container->AddElementsFromGraph(
      &device_factory, &input_packet_observer, &output_packet_observer);
  network_container->InitAggregatesInController();

  ctr::NetInstrument net_instrument(network_container->internal_queues(),
                                    network_container->flow_group_tcp_sources(),
                                    milliseconds(10), event_queue);
  device_factory.Init();
  event_queue->RunAndStopIn(milliseconds(FLAGS_duration_ms));
  output_packet_observer.RecordDist();
}

static std::string StripExtension(const std::string& filename) {
  std::size_t found = filename.find_last_of(".");
  return filename.substr(0, found);
}

int main(int argc, char** argv) {
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  nc::metrics::InitMetrics();

  // The event queue.
  nc::SimTimeEventQueue event_queue;
  event_queue_global_ptr = &event_queue;
  nc::SetLogHandler(CustomLogHandler);

  auto timestamp_provider =
      ::nc::make_unique<nc::metrics::SimTimestampProvider>(&event_queue);
  nc::metrics::DefaultMetricManager()->set_timestamp_provider(
      std::move(timestamp_provider));

  CHECK(!FLAGS_topology.empty());
  CHECK(!FLAGS_traffic_matrix.empty());

  std::vector<std::string> node_order;
  nc::net::GraphBuilder builder = nc::net::LoadRepetitaOrDie(
      nc::File::ReadFileToStringOrDie(FLAGS_topology), &node_order);
  builder.RemoveMultipleLinks();
  builder.ScaleCapacity(FLAGS_link_capacity_scale);
  builder.ScaleDelay(FLAGS_link_delay_scale);
  nc::net::GraphStorage graph(builder);

  nc::net::Delay diameter = graph.Stats().sp_delay_percentiles.back();
  if (diameter < milliseconds(10)) {
    LOG(FATAL) << "Graph diameter too small ("
               << duration_cast<milliseconds>(diameter).count() << "ms)";
  }

  ctr::PcapTraceStore trace_store(FLAGS_pcap_trace_store);
  std::string fit_store = FLAGS_pcap_trace_fit_store;
  if (fit_store.empty()) {
    fit_store = nc::StrCat(StripExtension(FLAGS_traffic_matrix), "_fit.pb");
  }
  CHECK(nc::File::Exists(fit_store)) << " fit store does not exist "
                                     << fit_store;

  ctr::PcapTraceFitStore trace_fit_store(fit_store, &trace_store);
  std::unique_ptr<nc::lp::DemandMatrix> demand_matrix =
      nc::lp::DemandMatrix::LoadRepetitaOrDie(
          nc::File::ReadFileToStringOrDie(FLAGS_traffic_matrix), node_order,
          &graph);
  demand_matrix = demand_matrix->Scale(FLAGS_tm_scale);

  size_t i = -1;
  std::map<ctr::AggregateId, std::unique_ptr<ctr::BinSequence>>
      initial_sequences;
  for (const auto& matrix_element : demand_matrix->elements()) {
    LOG(INFO) << "Looking for traces to match " << matrix_element.demand.Mbps()
              << "Mbps";
    std::unique_ptr<ctr::BinSequence> bin_sequence =
        trace_fit_store.GetBinSequence(matrix_element.demand);
    CHECK(bin_sequence);

    std::unique_ptr<ctr::BinSequence> bin_sequence_extended =
        trace_store.ExtendBinSequence(*bin_sequence);

    initial_sequences.emplace(
        std::piecewise_construct,
        std::forward_as_tuple(matrix_element.src, matrix_element.dst),
        std::forward_as_tuple(std::move(bin_sequence_extended)));
    LOG(INFO) << "Bin sequence " << ++i << " / "
              << demand_matrix->elements().size();
  }

  ctr::PathProvider path_provider(&graph);
  std::unique_ptr<ctr::Optimizer> opt;
  if (FLAGS_sp_opt) {
    opt = nc::make_unique<ctr::ShortestPathOptimizer>(&path_provider);
  } else {
    double link_cap_multiplier = 2 - FLAGS_estimator_headroom;
    CHECK(link_cap_multiplier > 0);
    opt = nc::make_unique<ctr::CTROptimizer>(&path_provider,
                                             link_cap_multiplier, true, false);
  }

  ctr::ProbModelConfig prob_model_config;
  prob_model_config.exceed_probability = FLAGS_exceed_probability;

  ctr::MeanScaleEstimatorFactory estimator_factory(
      {FLAGS_estimator_headroom, FLAGS_decay_factor, FLAGS_decay_factor, 10});
  ctr::RoutingSystemConfig routing_system_config;
  routing_system_config.prob_model_config = prob_model_config;
  ctr::RoutingSystem routing_system(routing_system_config, opt.get(),
                                    &estimator_factory);

  nc::net::IPAddress controller_ip(100);
  nc::net::IPAddress device_ip_base(20000);
  nc::net::IPAddress tldr_ip_base(30000);
  nc::net::IPAddress flow_group_ip_base(40000);
  nc::net::DevicePortNumber enter_port(4000);
  nc::net::DevicePortNumber exit_port(5000);

  milliseconds round_duration(FLAGS_period_duration_ms);
  milliseconds poll_period(FLAGS_history_bin_size_ms);

  ctr::controller::Controller controller(controller_ip, &routing_system,
                                         &event_queue, &graph);
  ctr::controller::NetworkContainerConfig containter_config(
      device_ip_base, tldr_ip_base, flow_group_ip_base, enter_port, exit_port,
      milliseconds(100), milliseconds(1000000), false);

  nc::ThresholdEnforcerPolicy te_policy;
  ctr::TLDRConfig tldr_config(te_policy, prob_model_config,
                              nc::htsim::kWildIPAddress,
                              nc::htsim::kWildIPAddress, controller_ip,
                              round_duration, poll_period, 100);
  ctr::controller::NetworkContainer network_container(
      containter_config, tldr_config, &graph, &controller, &event_queue);

  nc::htsim::ProgressIndicator progress_indicator(milliseconds(100),
                                                  &event_queue);
  HandleDefault(graph, std::move(initial_sequences), enter_port, poll_period,
                round_duration, &event_queue, &network_container);

  nc::metrics::DefaultMetricManager()->PersistAllMetrics();
}
<|endoftext|>