<commit_before>/**
 * @file asynclog.cpp
 * @brief This defines the `AsyncLog` class.
 */

#include "mapcache.hpp"

/**
 * @details This obtains a reference to the emit method in the passed in
 * `EventEmitter` object and initialises the mutex and async watcher.
 *
 * @param emitter A Node `EventEmitter` handle
 */
AsyncLog::AsyncLog(Persistent<Object> emitter) {
  assert(!emitter.IsEmpty());
  this->emitter = Persistent<Object>::New(emitter); // our own persistent reference
  Handle<Value> emit_val = emitter->Get(String::New("emit"));
  assert(emit_val->IsFunction());
  Handle<Function> emit_func = Handle<Function>::Cast(emit_val);
  callback = Persistent<Function>::New(emit_func);

  // ensure we can access this instance from the watcher, as it will be
  // accessed asynchronously via the static `EmitLogs` method.
  async.data = this;

  uv_mutex_init(&mutex);
  uv_async_init(uv_default_loop(), &async, EmitLogs);
}

/**
 * @details This is the callback that is passed to the mapcache core library.
 * It formats the message, queues it for emitting later, and then flags `libuv`
 * to deal with it by calling `EmitLogs` at its convenience.
 *
 * This callback will be fired in an asynchronous thread that will *not* be the
 * same as that the main V8/Node.js is running in.
 */
void AsyncLog::LogRequestContext(mapcache_context *c, mapcache_log_level level, char *message, ...) {
  MapCache::request_context *r_ctxt = (MapCache::request_context*) c;
  AsyncLog *self;
  va_list args;

  // we need a reference to the logger
  if (!r_ctxt->async_log) return;
  self = r_ctxt->async_log;

  Log *log = new Log();

  // format the message into a string
  va_start(args, message);
  log->message = apr_pvsprintf(c->pool, message, args);
  va_end(args);
  log->level = level;

  // add the message to the queue
  uv_mutex_lock(&(self->mutex));
  self->message_queue.push(log);
  uv_mutex_unlock(&(self->mutex));

  // flag the message queue as being ready for processing by `EmitLogs`
  uv_ref((uv_handle_t *) &(self->async)); // ensure `async` isn't destroyed
  uv_async_send(&(self->async));
}
/**
 * @details This drains the message queue, emitting each message via the
 * `EventEmitter` handle.  The queue paradigm is necessary as `uv_async_send`
 * does *not* guarantee that `EmitLogs` will be called each time that
 * `LogRequestContext` is fired and therefore messages have to be buffered.
 */
void AsyncLog::EmitLogs(uv_async_t *handle, int status /*UNUSED*/) {
  HandleScope scope;            // back in the main Node/V8 thread
  const unsigned short argc = 3;

  AsyncLog *self = static_cast<AsyncLog*>(handle->data);
  Handle<Value> argv[argc] = {
    String::New("log")          // event name
  };

  uv_mutex_lock(&(self->mutex)); // `handle->data` is thread sensitive
  while (!self->message_queue.empty()) {
    Log *log = self->message_queue.front();
    argv[1] = Uint32::New(log->level);
    argv[2] = String::New(log->message.c_str());

    self->message_queue.pop();   // drain the queue
    delete log;

    self->callback->Call(self->emitter, argc, argv);

    // decrement the reference count created in `LogRequestContext`
    uv_unref((uv_handle_t *) handle);
  }
  uv_mutex_unlock(&(self->mutex));
}
<commit_msg>Added licence text<commit_after>/******************************************************************************
 * Copyright (c) 2012, GeoData Institute (www.geodata.soton.ac.uk)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *****************************************************************************/

/**
 * @file asynclog.cpp
 * @brief This defines the `AsyncLog` class.
 */

#include "mapcache.hpp"

/**
 * @details This obtains a reference to the emit method in the passed in
 * `EventEmitter` object and initialises the mutex and async watcher.
 *
 * @param emitter A Node `EventEmitter` handle
 */
AsyncLog::AsyncLog(Persistent<Object> emitter) {
  assert(!emitter.IsEmpty());
  this->emitter = Persistent<Object>::New(emitter); // our own persistent reference
  Handle<Value> emit_val = emitter->Get(String::New("emit"));
  assert(emit_val->IsFunction());
  Handle<Function> emit_func = Handle<Function>::Cast(emit_val);
  callback = Persistent<Function>::New(emit_func);

  // ensure we can access this instance from the watcher, as it will be
  // accessed asynchronously via the static `EmitLogs` method.
  async.data = this;

  uv_mutex_init(&mutex);
  uv_async_init(uv_default_loop(), &async, EmitLogs);
}

/**
 * @details This is the callback that is passed to the mapcache core library.
 * It formats the message, queues it for emitting later, and then flags `libuv`
 * to deal with it by calling `EmitLogs` at its convenience.
 *
 * This callback will be fired in an asynchronous thread that will *not* be the
 * same as that the main V8/Node.js is running in.
 */
void AsyncLog::LogRequestContext(mapcache_context *c, mapcache_log_level level, char *message, ...) {
  MapCache::request_context *r_ctxt = (MapCache::request_context*) c;
  AsyncLog *self;
  va_list args;

  // we need a reference to the logger
  if (!r_ctxt->async_log) return;
  self = r_ctxt->async_log;

  Log *log = new Log();

  // format the message into a string
  va_start(args, message);
  log->message = apr_pvsprintf(c->pool, message, args);
  va_end(args);
  log->level = level;

  // add the message to the queue
  uv_mutex_lock(&(self->mutex));
  self->message_queue.push(log);
  uv_mutex_unlock(&(self->mutex));

  // flag the message queue as being ready for processing by `EmitLogs`
  uv_ref((uv_handle_t *) &(self->async)); // ensure `async` isn't destroyed
  uv_async_send(&(self->async));
}
/**
 * @details This drains the message queue, emitting each message via the
 * `EventEmitter` handle.  The queue paradigm is necessary as `uv_async_send`
 * does *not* guarantee that `EmitLogs` will be called each time that
 * `LogRequestContext` is fired and therefore messages have to be buffered.
 */
void AsyncLog::EmitLogs(uv_async_t *handle, int status /*UNUSED*/) {
  HandleScope scope;            // back in the main Node/V8 thread
  const unsigned short argc = 3;

  AsyncLog *self = static_cast<AsyncLog*>(handle->data);
  Handle<Value> argv[argc] = {
    String::New("log")          // event name
  };

  uv_mutex_lock(&(self->mutex)); // `handle->data` is thread sensitive
  while (!self->message_queue.empty()) {
    Log *log = self->message_queue.front();
    argv[1] = Uint32::New(log->level);
    argv[2] = String::New(log->message.c_str());

    self->message_queue.pop();   // drain the queue
    delete log;

    self->callback->Call(self->emitter, argc, argv);

    // decrement the reference count created in `LogRequestContext`
    uv_unref((uv_handle_t *) handle);
  }
  uv_mutex_unlock(&(self->mutex));
}
<|endoftext|>


<commit_before>#include "Preheat.h"

namespace cura
{

void Preheat::setConfig(MeshGroup& settings)
{
    for (int extruder_nr = 0; extruder_nr < settings.getExtruderCount(); extruder_nr++)
    {
        assert(settings.getExtruderTrain(extruder_nr) != nullptr);
        ExtruderTrain& extruder_train = *settings.getExtruderTrain(extruder_nr);
        config_per_extruder.emplace_back();
        Config& config = config_per_extruder.back();
        config.time_to_cooldown_1_degree = 1.0 / extruder_train.getSettingInSeconds("machine_nozzle_cool_down_speed"); // 0.5
        config.time_to_heatup_1_degree = 1.0 / extruder_train.getSettingInSeconds("machine_nozzle_heat_up_speed"); // 0.5
        config.heatup_cooldown_time_mod_while_printing = 1.0 / extruder_train.getSettingInSeconds("material_extrusion_cool_down_speed"); // 0.1
        config.standby_temp = extruder_train.getSettingInSeconds("material_standby_temperature"); // 150

        config.min_time_window = extruder_train.getSettingInSeconds("machine_min_cool_heat_time_window");

        config.material_print_temperature = extruder_train.getSettingInDegreeCelsius("material_print_temperature");
        config.material_print_temperature_layer_0 = extruder_train.getSettingInDegreeCelsius("material_print_temperature_layer_0");
        config.material_initial_print_temperature = extruder_train.getSettingInDegreeCelsius("material_initial_print_temperature");
        config.material_final_print_temperature = extruder_train.getSettingInDegreeCelsius("material_final_print_temperature");

        config.flow_dependent_temperature = extruder_train.getSettingBoolean("material_flow_dependent_temperature");

        config.flow_temp_graph = extruder_train.getSettingAsFlowTempGraph("material_flow_temp_graph"); // [[0.1,180],[20,230]]
    }
}

double Preheat::timeToHeatFromStandbyToPrintTemp(unsigned int extruder, double temp)
{
    return (temp - config_per_extruder[extruder].standby_temp) * config_per_extruder[extruder].time_to_heatup_1_degree;
}

double Preheat::getTimeToGoFromTempToTemp(int extruder, double temp_before, double temp_after, bool during_printing)
{
    Config& config = config_per_extruder[extruder];
    if (temp_after > temp_before)
    {
        return (temp_after - temp_before) * (config.time_to_heatup_1_degree + during_printing * config.heatup_cooldown_time_mod_while_printing);
    }
    else
    {
        return (temp_before - temp_after) * (config.time_to_cooldown_1_degree - during_printing * config.heatup_cooldown_time_mod_while_printing);
    }
}

double Preheat::getTemp(unsigned int extruder, double flow, bool is_initial_layer)
{
    if (is_initial_layer)
    {
        return config_per_extruder[extruder].material_print_temperature_layer_0;
    }
    return config_per_extruder[extruder].flow_temp_graph.getTemp(flow, config_per_extruder[extruder].material_print_temperature, config_per_extruder[extruder].flow_dependent_temperature);
}

Preheat::WarmUpResult Preheat::timeBeforeEndToInsertPreheatCommand_coolDownWarmUp(double time_window, unsigned int extruder, double temp)
{
    WarmUpResult result;
    const Config& config = config_per_extruder[extruder];
    result.total_time_window = time_window;
    double time_ratio_cooldown_heatup = config.time_to_cooldown_1_degree / config.time_to_heatup_1_degree;
    double time_to_heat_from_standby_to_print_temp = timeToHeatFromStandbyToPrintTemp(extruder, temp);
    double time_needed_to_reach_standby_temp = time_to_heat_from_standby_to_print_temp * (1.0 + time_ratio_cooldown_heatup);
    if (time_needed_to_reach_standby_temp < time_window)
    {
        result.heating_time = time_to_heat_from_standby_to_print_temp;
        result.lowest_temperature = config.standby_temp;
    }
    else
    {
        result.heating_time = time_window * config.time_to_heatup_1_degree / (config.time_to_cooldown_1_degree + config.time_to_heatup_1_degree);
        result.lowest_temperature = std::max(config.standby_temp, temp - result.heating_time / config.time_to_heatup_1_degree);
    }
    return result;
}

Preheat::CoolDownResult Preheat::timeBeforeEndToInsertPreheatCommand_warmUpCoolDown(double time_window, unsigned int extruder, double temp0, double temp1, double temp2, bool during_printing)
{
    CoolDownResult result;
    const Config& config = config_per_extruder[extruder];
    double time_to_cooldown_1_degree = config.time_to_cooldown_1_degree - during_printing * config.heatup_cooldown_time_mod_while_printing;
    double time_to_heatup_1_degree = config.time_to_heatup_1_degree + during_printing * config.heatup_cooldown_time_mod_while_printing;

    result.total_time_window = time_window;

    //      limited_time_window
    //      ^^^^^^^^^^
    //               _> temp1
    //       /""""""\                                       .
    //      / . . . .\ . . .> outer_temp                    .
    //     ^temp0     \                                     .
    //                 \                                    .
    //                  ^temp2
    double outer_temp;
    double limited_time_window;
    double extra_cooldown_time = 0;
    if (temp0 < temp2)
    { // extra time needed during heating
        double extra_heatup_time = (temp2 - temp0) * time_to_heatup_1_degree;
        limited_time_window = time_window - extra_heatup_time;
        outer_temp = temp0;
    }
    else
    {
        extra_cooldown_time = (temp0 - temp2) * time_to_cooldown_1_degree;
        limited_time_window = time_window - extra_cooldown_time;
        outer_temp = temp2;
    }
    double time_ratio_cooldown_heatup = time_to_cooldown_1_degree / time_to_heatup_1_degree;
    double cool_down_time = getTimeToGoFromTempToTemp(extruder, outer_temp, temp1, during_printing);
    double time_needed_to_reach_temp1 = cool_down_time * (1.0 + time_ratio_heatup_cooldown);
    if (time_needed_to_reach_temp1 < limited_time_window)
    {
        result.cooling_time = cool_down_time;
        result.highest_temperature = temp1;
    }
    else
    {
        result.cooling_time = limited_time_window * time_to_heatup_1_degree / (time_to_cooldown_1_degree + time_to_heatup_1_degree);
        result.highest_temperature = std::min(temp1, temp2 + result.cooling_time / time_to_cooldown_1_degree);
    }

    result.cooling_time += extra_cooldown_time;
    return result;
}

double Preheat::timeBeforeEndToInsertPreheatCommand_warmUp(double from_temp, unsigned int extruder, double temp, bool printing)
{
    if (temp > from_temp)
    {
        if (printing)
        {
            return (temp - from_temp) * (config_per_extruder[extruder].time_to_heatup_1_degree + config_per_extruder[extruder].heatup_cooldown_time_mod_while_printing);
        }
        else
        {
            return (temp - from_temp) * config_per_extruder[extruder].time_to_heatup_1_degree;
        }
    }
    else
    {
        if (printing)
        {
            return (from_temp - temp) * config_per_extruder[extruder].time_to_cooldown_1_degree;
        }
        else
        {
            return (from_temp - temp) * std::max(0.0, config_per_extruder[extruder].time_to_cooldown_1_degree - config_per_extruder[extruder].heatup_cooldown_time_mod_while_printing);
        }
    }
}

}//namespace cura
<commit_msg>fix: for warmUpCoolDown compute max temp accurately (CURA-1932)<commit_after>#include "Preheat.h"

namespace cura
{

void Preheat::setConfig(MeshGroup& settings)
{
    for (int extruder_nr = 0; extruder_nr < settings.getExtruderCount(); extruder_nr++)
    {
        assert(settings.getExtruderTrain(extruder_nr) != nullptr);
        ExtruderTrain& extruder_train = *settings.getExtruderTrain(extruder_nr);
        config_per_extruder.emplace_back();
        Config& config = config_per_extruder.back();
        config.time_to_cooldown_1_degree = 1.0 / extruder_train.getSettingInSeconds("machine_nozzle_cool_down_speed"); // 0.5
        config.time_to_heatup_1_degree = 1.0 / extruder_train.getSettingInSeconds("machine_nozzle_heat_up_speed"); // 0.5
        config.heatup_cooldown_time_mod_while_printing = 1.0 / extruder_train.getSettingInSeconds("material_extrusion_cool_down_speed"); // 0.1
        config.standby_temp = extruder_train.getSettingInSeconds("material_standby_temperature"); // 150

        config.min_time_window = extruder_train.getSettingInSeconds("machine_min_cool_heat_time_window");

        config.material_print_temperature = extruder_train.getSettingInDegreeCelsius("material_print_temperature");
        config.material_print_temperature_layer_0 = extruder_train.getSettingInDegreeCelsius("material_print_temperature_layer_0");
        config.material_initial_print_temperature = extruder_train.getSettingInDegreeCelsius("material_initial_print_temperature");
        config.material_final_print_temperature = extruder_train.getSettingInDegreeCelsius("material_final_print_temperature");

        config.flow_dependent_temperature = extruder_train.getSettingBoolean("material_flow_dependent_temperature");

        config.flow_temp_graph = extruder_train.getSettingAsFlowTempGraph("material_flow_temp_graph"); // [[0.1,180],[20,230]]
    }
}

double Preheat::timeToHeatFromStandbyToPrintTemp(unsigned int extruder, double temp)
{
    return (temp - config_per_extruder[extruder].standby_temp) * config_per_extruder[extruder].time_to_heatup_1_degree;
}

double Preheat::getTimeToGoFromTempToTemp(int extruder, double temp_before, double temp_after, bool during_printing)
{
    Config& config = config_per_extruder[extruder];
    if (temp_after > temp_before)
    {
        return (temp_after - temp_before) * (config.time_to_heatup_1_degree + during_printing * config.heatup_cooldown_time_mod_while_printing);
    }
    else
    {
        return (temp_before - temp_after) * (config.time_to_cooldown_1_degree - during_printing * config.heatup_cooldown_time_mod_while_printing);
    }
}

double Preheat::getTemp(unsigned int extruder, double flow, bool is_initial_layer)
{
    if (is_initial_layer)
    {
        return config_per_extruder[extruder].material_print_temperature_layer_0;
    }
    return config_per_extruder[extruder].flow_temp_graph.getTemp(flow, config_per_extruder[extruder].material_print_temperature, config_per_extruder[extruder].flow_dependent_temperature);
}

Preheat::WarmUpResult Preheat::timeBeforeEndToInsertPreheatCommand_coolDownWarmUp(double time_window, unsigned int extruder, double temp)
{
    WarmUpResult result;
    const Config& config = config_per_extruder[extruder];
    result.total_time_window = time_window;
    double time_ratio_cooldown_heatup = config.time_to_cooldown_1_degree / config.time_to_heatup_1_degree;
    double time_to_heat_from_standby_to_print_temp = timeToHeatFromStandbyToPrintTemp(extruder, temp);
    double time_needed_to_reach_standby_temp = time_to_heat_from_standby_to_print_temp * (1.0 + time_ratio_cooldown_heatup);
    if (time_needed_to_reach_standby_temp < time_window)
    {
        result.heating_time = time_to_heat_from_standby_to_print_temp;
        result.lowest_temperature = config.standby_temp;
    }
    else
    {
        result.heating_time = time_window * config.time_to_heatup_1_degree / (config.time_to_cooldown_1_degree + config.time_to_heatup_1_degree);
        result.lowest_temperature = std::max(config.standby_temp, temp - result.heating_time / config.time_to_heatup_1_degree);
    }
    return result;
}

Preheat::CoolDownResult Preheat::timeBeforeEndToInsertPreheatCommand_warmUpCoolDown(double time_window, unsigned int extruder, double temp0, double temp1, double temp2, bool during_printing)
{
    CoolDownResult result;
    const Config& config = config_per_extruder[extruder];
    double time_to_cooldown_1_degree = config.time_to_cooldown_1_degree - during_printing * config.heatup_cooldown_time_mod_while_printing;
    double time_to_heatup_1_degree = config.time_to_heatup_1_degree + during_printing * config.heatup_cooldown_time_mod_while_printing;

    result.total_time_window = time_window;

    //      limited_time_window
    //      ^^^^^^^^^^
    //               _> temp1
    //       /""""""\                                       .
    //      / . . . .\ . . .> outer_temp                    .
    //     ^temp0     \                                     .
    //                 \                                    .
    //                  ^temp2
    double outer_temp;
    double limited_time_window;
    if (temp0 < temp2)
    { // extra time needed during heating
        double extra_heatup_time = (temp2 - temp0) * time_to_heatup_1_degree;
        result.cooling_time = 0;
        limited_time_window = time_window - extra_heatup_time;
        outer_temp = temp0;
    }
    else
    {
        double extra_cooldown_time = (temp0 - temp2) * time_to_cooldown_1_degree;
        result.cooling_time = extra_cooldown_time;
        limited_time_window = time_window - extra_cooldown_time;
        outer_temp = temp2;
    }
    double time_ratio_cooldown_heatup = time_to_cooldown_1_degree / time_to_heatup_1_degree;
    double cool_down_time = getTimeToGoFromTempToTemp(extruder, outer_temp, temp1, during_printing);
    double time_needed_to_reach_temp1 = cool_down_time * (1.0 + time_ratio_cooldown_heatup);
    if (time_needed_to_reach_temp1 < limited_time_window)
    {
        result.cooling_time += cool_down_time;
        result.highest_temperature = temp1;
    }
    else
    {
        result.cooling_time += limited_time_window * time_to_heatup_1_degree / (time_to_cooldown_1_degree + time_to_heatup_1_degree);
        result.highest_temperature = std::min(temp1, temp2 + result.cooling_time / time_to_cooldown_1_degree);
    }

    return result;
}

double Preheat::timeBeforeEndToInsertPreheatCommand_warmUp(double from_temp, unsigned int extruder, double temp, bool printing)
{
    if (temp > from_temp)
    {
        if (printing)
        {
            return (temp - from_temp) * (config_per_extruder[extruder].time_to_heatup_1_degree + config_per_extruder[extruder].heatup_cooldown_time_mod_while_printing);
        }
        else
        {
            return (temp - from_temp) * config_per_extruder[extruder].time_to_heatup_1_degree;
        }
    }
    else
    {
        if (printing)
        {
            return (from_temp - temp) * config_per_extruder[extruder].time_to_cooldown_1_degree;
        }
        else
        {
            return (from_temp - temp) * std::max(0.0, config_per_extruder[extruder].time_to_cooldown_1_degree - config_per_extruder[extruder].heatup_cooldown_time_mod_while_printing);
        }
    }
}

}//namespace cura
<|endoftext|>


<commit_before>/*
 * Load balancer for AddressList.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "balancer.hxx"
#include "cache.hxx"
#include "address_list.hxx"
#include "net/SocketAddress.hxx"
#include "failure.hxx"
#include "bulldog.h"
#include "AllocatorPtr.hxx"

#include <assert.h>
#include <stdbool.h>
#include <time.h>

struct Balancer {
    struct Item final : CacheItem {
        struct pool *const pool;

        /** the index of the item that will be returned next */
        unsigned next = 0;

        AddressList addresses;

        Item(struct pool &_pool, const AddressList &_addresses)
            :CacheItem(std::chrono::minutes(30), 1),
             pool(&_pool), addresses(_pool, _addresses) {
        }

        const SocketAddress &NextAddress();
        const SocketAddress &NextAddressChecked(bool allow_fade);

        /* virtual methods from class CacheItem */
        void Destroy() override {
            pool_unref(pool);
        }
    };

    struct pool *pool;

    /**
     * This library uses the cache library to store remote host
     * states in a lossy way.
     */
    Cache cache;

    Balancer(struct pool &_pool, EventLoop &event_loop)
        :pool(&_pool),
         cache(event_loop, 1021, 2048) {}
};

static bool
check_failure(const SocketAddress address, bool allow_fade)
{
    enum failure_status status = failure_get_status(address);
    if (status == FAILURE_FADE && allow_fade)
        status = FAILURE_OK;
    return status == FAILURE_OK;
}

gcc_pure
static bool
check_bulldog(const SocketAddress address, bool allow_fade)
{
    return bulldog_check(address.GetAddress(), address.GetSize()) &&
        (allow_fade ||
         !bulldog_is_fading(address.GetAddress(), address.GetSize()));
}

static bool
CheckAddress(const SocketAddress address, bool allow_fade)
{
    return check_failure(address, allow_fade) &&
        check_bulldog(address, allow_fade);
}

static SocketAddress
next_failover_address(const AddressList &list)
{
    assert(list.GetSize() > 0);

    for (auto i : list)
        if (CheckAddress(i, true))
            return i;

    /* none available - return first node as last resort */
    return list[0];
}

const SocketAddress &
Balancer::Item::NextAddress()
{
    assert(addresses.GetSize() >= 2);
    assert(next < addresses.GetSize());

    const SocketAddress &address = addresses[next];

    ++next;
    if (next >= addresses.GetSize())
        next = 0;

    return address;
}

const SocketAddress &
Balancer::Item::NextAddressChecked(bool allow_fade)
{
    const auto &first = NextAddress();
    const SocketAddress *ret = &first;
    do {
        if (CheckAddress(*ret, allow_fade))
            return *ret;

        ret = &NextAddress();
    } while (ret != &first);

    /* all addresses failed: */
    return first;
}

static const SocketAddress &
next_sticky_address_checked(const AddressList &al, unsigned session)
{
    assert(al.GetSize() >= 2);

    unsigned i = session % al.GetSize();
    bool allow_fade = true;

    const SocketAddress &first = al[i];
    const SocketAddress *ret = &first;
    do {
        if (CheckAddress(*ret, allow_fade))
            return *ret;

        /* only the first iteration is allowed to override
           FAILURE_FADE */
        allow_fade = false;

        ++i;
        if (i >= al.GetSize())
            i = 0;

        ret = &al[i];

    } while (ret != &first);

    /* all addresses failed: */
    return first;
}

/*
 * public API
 *
 */

Balancer *
balancer_new(struct pool &pool, EventLoop &event_loop)
{
    return new Balancer(pool, event_loop);
}

void
balancer_free(Balancer *balancer)
{
    delete balancer;
}

SocketAddress
balancer_get(Balancer &balancer, const AddressList &list,
             unsigned session)
{
    if (list.IsSingle())
        return list[0];

    switch (list.sticky_mode) {
    case StickyMode::NONE:
        break;

    case StickyMode::FAILOVER:
        return next_failover_address(list);

    case StickyMode::SOURCE_IP:
    case StickyMode::SESSION_MODULO:
    case StickyMode::COOKIE:
    case StickyMode::JVM_ROUTE:
        if (session != 0)
            return next_sticky_address_checked(list, session);
        break;
    }

    const char *key = list.GetKey();
    auto *item = (Balancer::Item *)balancer.cache.Get(key);

    if (item == nullptr) {
        /* create a new cache item */

        auto *pool = pool_new_linear(balancer.pool, "balancer_item", 1024);
        item = NewFromPool<Balancer::Item>(*pool, *pool, list);

        balancer.cache.Put(p_strdup(pool, key), *item);
    }

    return item->NextAddressChecked(list.sticky_mode == StickyMode::NONE);
}

void
balancer_event_add(Balancer &balancer)
{
    balancer.cache.EventAdd();
}

void
balancer_event_del(Balancer &balancer)
{
    balancer.cache.EventDel();
}
<commit_msg>balancer: don't copy AddressList into Balancer::Item<commit_after>/*
 * Load balancer for AddressList.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "balancer.hxx"
#include "cache.hxx"
#include "address_list.hxx"
#include "net/SocketAddress.hxx"
#include "failure.hxx"
#include "bulldog.h"
#include "AllocatorPtr.hxx"

#include <assert.h>
#include <stdbool.h>
#include <time.h>

struct Balancer {
    struct Item final : CacheItem {
        struct pool *const pool;

        /** the index of the item that will be returned next */
        unsigned next = 0;

        explicit Item(struct pool &_pool)
            :CacheItem(std::chrono::minutes(30), 1),
             pool(&_pool) {
        }

        const SocketAddress &NextAddress(const AddressList &addresses);
        const SocketAddress &NextAddressChecked(const AddressList &addresses,
                                                bool allow_fade);

        /* virtual methods from class CacheItem */
        void Destroy() override {
            pool_unref(pool);
        }
    };

    struct pool *pool;

    /**
     * This library uses the cache library to store remote host
     * states in a lossy way.
     */
    Cache cache;

    Balancer(struct pool &_pool, EventLoop &event_loop)
        :pool(&_pool),
         cache(event_loop, 1021, 2048) {}
};

static bool
check_failure(const SocketAddress address, bool allow_fade)
{
    enum failure_status status = failure_get_status(address);
    if (status == FAILURE_FADE && allow_fade)
        status = FAILURE_OK;
    return status == FAILURE_OK;
}

gcc_pure
static bool
check_bulldog(const SocketAddress address, bool allow_fade)
{
    return bulldog_check(address.GetAddress(), address.GetSize()) &&
        (allow_fade ||
         !bulldog_is_fading(address.GetAddress(), address.GetSize()));
}

static bool
CheckAddress(const SocketAddress address, bool allow_fade)
{
    return check_failure(address, allow_fade) &&
        check_bulldog(address, allow_fade);
}

static SocketAddress
next_failover_address(const AddressList &list)
{
    assert(list.GetSize() > 0);

    for (auto i : list)
        if (CheckAddress(i, true))
            return i;

    /* none available - return first node as last resort */
    return list[0];
}

const SocketAddress &
Balancer::Item::NextAddress(const AddressList &addresses)
{
    assert(addresses.GetSize() >= 2);
    assert(next < addresses.GetSize());

    const SocketAddress &address = addresses[next];

    ++next;
    if (next >= addresses.GetSize())
        next = 0;

    return address;
}

const SocketAddress &
Balancer::Item::NextAddressChecked(const AddressList &addresses,
                                   bool allow_fade)
{
    const auto &first = NextAddress(addresses);
    const SocketAddress *ret = &first;
    do {
        if (CheckAddress(*ret, allow_fade))
            return *ret;

        ret = &NextAddress(addresses);
    } while (ret != &first);

    /* all addresses failed: */
    return first;
}

static const SocketAddress &
next_sticky_address_checked(const AddressList &al, unsigned session)
{
    assert(al.GetSize() >= 2);

    unsigned i = session % al.GetSize();
    bool allow_fade = true;

    const SocketAddress &first = al[i];
    const SocketAddress *ret = &first;
    do {
        if (CheckAddress(*ret, allow_fade))
            return *ret;

        /* only the first iteration is allowed to override
           FAILURE_FADE */
        allow_fade = false;

        ++i;
        if (i >= al.GetSize())
            i = 0;

        ret = &al[i];

    } while (ret != &first);

    /* all addresses failed: */
    return first;
}

/*
 * public API
 *
 */

Balancer *
balancer_new(struct pool &pool, EventLoop &event_loop)
{
    return new Balancer(pool, event_loop);
}

void
balancer_free(Balancer *balancer)
{
    delete balancer;
}

SocketAddress
balancer_get(Balancer &balancer, const AddressList &list,
             unsigned session)
{
    if (list.IsSingle())
        return list[0];

    switch (list.sticky_mode) {
    case StickyMode::NONE:
        break;

    case StickyMode::FAILOVER:
        return next_failover_address(list);

    case StickyMode::SOURCE_IP:
    case StickyMode::SESSION_MODULO:
    case StickyMode::COOKIE:
    case StickyMode::JVM_ROUTE:
        if (session != 0)
            return next_sticky_address_checked(list, session);
        break;
    }

    const char *key = list.GetKey();
    auto *item = (Balancer::Item *)balancer.cache.Get(key);

    if (item == nullptr) {
        /* create a new cache item */

        auto *pool = pool_new_linear(balancer.pool, "balancer_item", 1024);
        item = NewFromPool<Balancer::Item>(*pool, *pool);

        balancer.cache.Put(p_strdup(pool, key), *item);
    }

    return item->NextAddressChecked(list,
                                    list.sticky_mode == StickyMode::NONE);
}

void
balancer_event_add(Balancer &balancer)
{
    balancer.cache.EventAdd();
}

void
balancer_event_del(Balancer &balancer)
{
    balancer.cache.EventDel();
}
<|endoftext|>


<commit_before>#include <cmath>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <random>
#include <set>
#include <vector>
#include <unordered_map>

namespace {

inline size_t GenerateMaskWithRightOnes(size_t onesCount) {
    return (1ull << onesCount) - 1ull;
}

class TCacheSet {
public:
    TCacheSet(size_t waysCount)
        : TicksTimer(0)
        , CacheWays(waysCount)
        , CacheHits(0)
    {}

    bool Touch(size_t cacheLineNum) {
        ++TicksTimer;
        TCacheLine* minTickLine = nullptr;
        size_t minTickTime = TicksTimer;
        for (auto& activeLine : CacheWays) {
            if (activeLine.LineNum != cacheLineNum) {
                if (activeLine.LineNum == -1) {
                    activeLine.TouchTick = TicksTimer;
                    activeLine.LineNum = cacheLineNum;
                    return false;
                }
                if (activeLine.TouchTick < minTickTime) {
                    minTickTime = activeLine.TouchTick;
                    minTickLine = &activeLine;
                }
            } else {
                activeLine.TouchTick = TicksTimer;
                ++CacheHits;
                return true;
            }
        }
        minTickLine->LineNum = cacheLineNum;
        minTickLine->TouchTick = TicksTimer;
        return false;
    }

    size_t GetCacheHits() const {
        return CacheHits;
    }

    size_t GetTicks() const {
        return TicksTimer;
    }

    size_t GetCacheMisses() const {
        return TicksTimer - CacheHits;
    }

    double GetCacheMissRate() const {
        return GetCacheMisses() / (TicksTimer * 1.0);
    }

private:
    struct TCacheLine {
        size_t LineNum = -1;
        size_t TouchTick = 0;
    };

private:
    size_t TicksTimer;
    std::vector<TCacheLine> CacheWays; // Contains LineNum == -1 if free

    size_t CacheHits;
};

class TCache {
public:
    TCache(size_t cacheSize, size_t cacheLineSize, size_t waysCount)
        : CacheSize(cacheSize)
        , CacheLineSize(cacheLineSize)
        , WaysCount(waysCount)
        , BlocksCount(CacheSize / cacheLineSize)
        , SetsCount(BlocksCount / WaysCount)
        , BlockOffsetSize(static_cast<size_t>(log2(CacheLineSize)))
        , ShiftedIndexMask(GenerateMaskWithRightOnes(static_cast<size_t>(log2(SetsCount))))
        , InvBlockMask(~GenerateMaskWithRightOnes(BlockOffsetSize))
        , CacheSets(SetsCount, {WaysCount})
    {
        std::cout << "Params: " << std::endl
                  << "\tCacheSize:\t"        << CacheSize        << ' ' << std::endl
                  << "\tCacheLineSize:\t"    << CacheLineSize    << ' ' << std::endl
                  << "\tWaysCount:\t"        << WaysCount        << ' ' << std::endl
                  << "\tBlocksCount:\t"      << BlocksCount      << ' ' << std::endl
                  << "\tSetsCount:\t"        << SetsCount        << ' ' << std::endl
                  << "\tBlockOffsetSize:\t"  << BlockOffsetSize  << ' ' << std::endl
                  << "\tShiftedIndexMask:\t" << ShiftedIndexMask << ' ' << std::endl
                  << "\tInvBlockMask:\t"     << InvBlockMask     << ' ' << std::endl;
    }

    /// @return true if needed cache line is in cache
    bool Touch(const void* ptr) {
        return CacheSets[GetIndexFromPtr(ptr)].Touch(GetCacheLineNumFromPtr(ptr));
    }

    void PrintStats() const {
        size_t cacheSetIdx = 0;
        double mean = 0.0;
        double meanSq = 0.0;
        size_t totalTicks = 0;
        for (const auto& cacheSet : CacheSets) {
            std::cout << cacheSetIdx << ")\t"
                      << cacheSet.GetCacheMisses() << "\t"
                      << cacheSet.GetTicks() << "\t= "
                      << std::setprecision(3) << cacheSet.GetCacheMissRate() * 100.0 << '%' << std::endl;
            ++cacheSetIdx;
            totalTicks += cacheSet.GetTicks();
            double misses = cacheSet.GetCacheMisses() * 1.0;
            mean += misses / CacheSets.size();
            meanSq += misses * misses / CacheSets.size();
        }
        std::cout << std::fixed << std::setprecision(3)
                  << "Misses:" << std::endl
                  << "\tmean=" << mean << std::endl
                  << "\tvar=" << (meanSq - mean * mean) << std::endl
                  << "\trate=" << (mean * CacheSets.size() / totalTicks) * 100 << '%'
                  << std::endl;

    }

private:
    size_t GetIndexFromPtr(const void* ptr) {
        return ((size_t)ptr >> BlockOffsetSize) & ShiftedIndexMask;
    }

    size_t GetCacheLineNumFromPtr(const void* ptr) {
        return (size_t)ptr & InvBlockMask;
    }

private:
    const size_t CacheSize;
    const size_t CacheLineSize;
    const size_t WaysCount;
    const size_t BlocksCount;
    const size_t SetsCount;
    const size_t BlockOffsetSize;

    const size_t ShiftedIndexMask;
    const size_t InvBlockMask;

    std::vector<TCacheSet> CacheSets;
};

void MultSimpleTooled(TCache& cache,
                      const float* __restrict a,
                      const float* __restrict b,
                      float* __restrict c,
                      int n)
{
    /// We suppose that i j k, as iteration vars, would be placed to registers
    /// So cache will work only with n, a, b, c and corresponding arrays
    cache.Touch(&n); // for next loop start
    for (int i = 0; i < n; ++i) {
        cache.Touch(&n); // for next loop start
        for (int j = 0; j < n; ++j) {
            //>-- c[i * n + j]
            // cache.Touch(&i);
            // cache.Touch(&j);
            cache.Touch(&n);
            cache.Touch(&c);
            cache.Touch(&c[i * n + j]);
            //<-- c[i * n + j]

            c[i * n + j] = 0.f;

            cache.Touch(&n); // for next loop start
            for (int k = 0; k < n; ++k) {
                // cache.Touch(&i);
                // cache.Touch(&j);
                // cache.Touch(&k);
                cache.Touch(&n);
                cache.Touch(&a);
                cache.Touch(&b);
                cache.Touch(&c);
                cache.Touch(&a[i * n + k]);
                cache.Touch(&b[k * n + j]);
                cache.Touch(&c[i * n + j]);

                c[i * n + j] += a[i * n + k] * b[k * n + j];

                //>-- k < n
                // cache.Touch(&k);
                cache.Touch(&n);
                //<-- k < n
            }

            //>-- j < n
            // cache.Touch(&j);
            cache.Touch(&n);
            //<-- j < n
        }

        //>-- i < n
        // cache.Touch(&i);
        cache.Touch(&n);
        //<-- i < n
    }
}

void MultSimple(const float* __restrict a, const float* __restrict b, float* __restrict c, int n)
{
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            c[i * n + j] = 0.f;
            for (int k = 0; k < n; ++k) {
                c[i * n + j] += a[i * n + k] * b[k * n + j];
            }
        }
    }
}

void FillRandom(float* a, int n)
{
    std::default_random_engine eng;
    std::uniform_real_distribution<float> dist;

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            a[i * n + j] = dist(eng);
        }
    }
}

}

int main(int argc, char* argv[])
{
    if (argc < 5) {
        std::cerr << "Usage: " << argv[0]
                  << " MATRIX_SIZE CACHE_SIZE_KB CACHE_LINE_SIZE_B WAYS_COUNT" << std::endl;
        return 1;
    }
    const int n = atoi(argv[1]);
    const size_t cacheSizeKB    = atoi(argv[2]);
    const size_t cacheLineSizeB = atoi(argv[3]);
    const size_t waysCount      = atoi(argv[4]);
    std::cout << "n = " << n << std::endl;
    std::cout << "Cache: " << cacheSizeKB << "KB, "
              << waysCount << " ways with "
              << cacheLineSizeB << "b cache line." << std::endl;
    float* a = new float[n * n];
    float* b = new float[n * n];
    float* c = new float[n * n];

    FillRandom(a, n);
    FillRandom(b, n);
    TCache cache(cacheSizeKB * 1024 /* kb */, cacheLineSizeB /* b */, waysCount /* ways */);
    {
        const auto startTime = std::clock();
        MultSimpleTooled(cache, a, b, c, n);
        const auto endTime = std::clock();

        std::cout << "timeSimple: " << double(endTime - startTime) / CLOCKS_PER_SEC << std::endl;
    }
    cache.PrintStats();

    delete[] a;
    delete[] b;
    delete[] c;
}

<commit_msg>Pretty print. Total misses count added to output.<commit_after>#include <cmath>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <random>
#include <set>
#include <vector>
#include <unordered_map>

namespace {

inline size_t GenerateMaskWithRightOnes(size_t onesCount) {
    return (1ull << onesCount) - 1ull;
}

class TCacheSet {
public:
    TCacheSet(size_t waysCount)
        : TicksTimer(0)
        , CacheWays(waysCount)
        , CacheHits(0)
    {}

    bool Touch(size_t cacheLineNum) {
        ++TicksTimer;
        TCacheLine* minTickLine = nullptr;
        size_t minTickTime = TicksTimer;
        for (auto& activeLine : CacheWays) {
            if (activeLine.LineNum != cacheLineNum) {
                if (activeLine.LineNum == -1) {
                    activeLine.TouchTick = TicksTimer;
                    activeLine.LineNum = cacheLineNum;
                    return false;
                }
                if (activeLine.TouchTick < minTickTime) {
                    minTickTime = activeLine.TouchTick;
                    minTickLine = &activeLine;
                }
            } else {
                activeLine.TouchTick = TicksTimer;
                ++CacheHits;
                return true;
            }
        }
        minTickLine->LineNum = cacheLineNum;
        minTickLine->TouchTick = TicksTimer;
        return false;
    }

    size_t GetCacheHits() const {
        return CacheHits;
    }

    size_t GetTicks() const {
        return TicksTimer;
    }

    size_t GetCacheMisses() const {
        return TicksTimer - CacheHits;
    }

    double GetCacheMissRate() const {
        return GetCacheMisses() / (TicksTimer * 1.0);
    }

private:
    struct TCacheLine {
        size_t LineNum = -1;
        size_t TouchTick = 0;
    };

private:
    size_t TicksTimer;
    std::vector<TCacheLine> CacheWays; // Contains LineNum == -1 if free

    size_t CacheHits;
};

class TCache {
public:
    TCache(size_t cacheSize, size_t cacheLineSize, size_t waysCount)
        : CacheSize(cacheSize)
        , CacheLineSize(cacheLineSize)
        , WaysCount(waysCount)
        , BlocksCount(CacheSize / cacheLineSize)
        , SetsCount(BlocksCount / WaysCount)
        , BlockOffsetSize(static_cast<size_t>(log2(CacheLineSize)))
        , ShiftedIndexMask(GenerateMaskWithRightOnes(static_cast<size_t>(log2(SetsCount))))
        , InvBlockMask(~GenerateMaskWithRightOnes(BlockOffsetSize))
        , CacheSets(SetsCount, {WaysCount})
    {
        std::cout << "Params: " << std::endl
                  << "\tCacheSize:\t"        << CacheSize        << ' ' << std::endl
                  << "\tCacheLineSize:\t"    << CacheLineSize    << ' ' << std::endl
                  << "\tWaysCount:\t"        << WaysCount        << ' ' << std::endl
                  << "\tBlocksCount:\t"      << BlocksCount      << ' ' << std::endl
                  << "\tSetsCount:\t"        << SetsCount        << ' ' << std::endl
                  << "\tBlockOffsetSize:\t"  << BlockOffsetSize  << ' ' << std::endl
                  << "\tShiftedIndexMask:\t" << ShiftedIndexMask << ' ' << std::endl
                  << "\tInvBlockMask:\t"     << InvBlockMask     << ' ' << std::endl;
    }

    /// @return true if needed cache line is in cache
    bool Touch(const void* ptr) {
        return CacheSets[GetIndexFromPtr(ptr)].Touch(GetCacheLineNumFromPtr(ptr));
    }

    void PrintStats() const {
        size_t cacheSetIdx = 0;
        size_t total = 0;
        double mean = 0.0;
        double meanSq = 0.0;
        size_t totalTicks = 0;
        for (const auto& cacheSet : CacheSets) {
            std::cout << cacheSetIdx << ")\t"
                      << cacheSet.GetCacheMisses() << "\t"
                      << cacheSet.GetTicks() << "\t= "
                      << std::setprecision(3) << cacheSet.GetCacheMissRate() * 100.0 << '%' << std::endl;
            ++cacheSetIdx;
            totalTicks += cacheSet.GetTicks();
            total += cacheSet.GetCacheMisses();
            double misses = cacheSet.GetCacheMisses() * 1.0;
            mean += misses / CacheSets.size();
            meanSq += misses * misses / CacheSets.size();
        }
        std::cout << std::fixed << std::setprecision(3)
                  << "Misses:" << std::endl
                  << "\ttotal=" << total << std::endl
                  << "\trate=" << (total * 100.0 / totalTicks) << '%' << std::endl
                  << "\tmean=" << mean << std::endl
                  << "\tvar=" << (meanSq - mean * mean)
                  << std::endl;

    }

private:
    size_t GetIndexFromPtr(const void* ptr) {
        return ((size_t)ptr >> BlockOffsetSize) & ShiftedIndexMask;
    }

    size_t GetCacheLineNumFromPtr(const void* ptr) {
        return (size_t)ptr & InvBlockMask;
    }

private:
    const size_t CacheSize;
    const size_t CacheLineSize;
    const size_t WaysCount;
    const size_t BlocksCount;
    const size_t SetsCount;
    const size_t BlockOffsetSize;

    const size_t ShiftedIndexMask;
    const size_t InvBlockMask;

    std::vector<TCacheSet> CacheSets;
};

void MultSimpleTooled(TCache& cache,
                      const float* __restrict a,
                      const float* __restrict b,
                      float* __restrict c,
                      int n)
{
    /// We suppose that i j k, as iteration vars, would be placed to registers
    /// So cache will work only with n, a, b, c and corresponding arrays
    cache.Touch(&n); // for next loop start
    for (int i = 0; i < n; ++i) {
        cache.Touch(&n); // for next loop start
        for (int j = 0; j < n; ++j) {
            //>-- c[i * n + j]
            // cache.Touch(&i);
            // cache.Touch(&j);
            cache.Touch(&n);
            cache.Touch(&c);
            cache.Touch(&c[i * n + j]);
            //<-- c[i * n + j]

            c[i * n + j] = 0.f;

            cache.Touch(&n); // for next loop start
            for (int k = 0; k < n; ++k) {
                // cache.Touch(&i);
                // cache.Touch(&j);
                // cache.Touch(&k);
                cache.Touch(&n);
                cache.Touch(&a);
                cache.Touch(&b);
                cache.Touch(&c);
                cache.Touch(&a[i * n + k]);
                cache.Touch(&b[k * n + j]);
                cache.Touch(&c[i * n + j]);

                c[i * n + j] += a[i * n + k] * b[k * n + j];

                //>-- k < n
                // cache.Touch(&k);
                cache.Touch(&n);
                //<-- k < n
            }

            //>-- j < n
            // cache.Touch(&j);
            cache.Touch(&n);
            //<-- j < n
        }

        //>-- i < n
        // cache.Touch(&i);
        cache.Touch(&n);
        //<-- i < n
    }
}

void MultSimple(const float* __restrict a, const float* __restrict b, float* __restrict c, int n)
{
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            c[i * n + j] = 0.f;
            for (int k = 0; k < n; ++k) {
                c[i * n + j] += a[i * n + k] * b[k * n + j];
            }
        }
    }
}

void FillRandom(float* a, int n)
{
    std::default_random_engine eng;
    std::uniform_real_distribution<float> dist;

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            a[i * n + j] = dist(eng);
        }
    }
}

}

int main(int argc, char* argv[])
{
    if (argc < 5) {
        std::cerr << "Usage: " << argv[0]
                  << " MATRIX_SIZE CACHE_SIZE_KB CACHE_LINE_SIZE_B WAYS_COUNT" << std::endl;
        return 1;
    }
    const int n = atoi(argv[1]);
    const size_t cacheSizeKB    = atoi(argv[2]);
    const size_t cacheLineSizeB = atoi(argv[3]);
    const size_t waysCount      = atoi(argv[4]);
    std::cout << "n = " << n << std::endl;
    std::cout << "Cache: " << cacheSizeKB << "KB, "
              << waysCount << " ways with "
              << cacheLineSizeB << "b cache line." << std::endl;
    float* a = new float[n * n];
    float* b = new float[n * n];
    float* c = new float[n * n];

    FillRandom(a, n);
    FillRandom(b, n);
    TCache cache(cacheSizeKB * 1024 /* kb */, cacheLineSizeB /* b */, waysCount /* ways */);
    {
        const auto startTime = std::clock();
        MultSimpleTooled(cache, a, b, c, n);
        const auto endTime = std::clock();

        std::cout << "timeSimple: " << double(endTime - startTime) / CLOCKS_PER_SEC << std::endl;
    }
    cache.PrintStats();

    delete[] a;
    delete[] b;
    delete[] c;
}

<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "PlayerInfo.h"

/* system implementation headers */
#include <errno.h>
#include <stdio.h>
#include <string>
#include <ctype.h>

/* implementation-specific common headers */
#include "TextUtils.h"

WordFilter PlayerInfo::serverSpoofingFilter;
TimeKeeper PlayerInfo::now = TimeKeeper::getCurrent();

bool	PlayerInfo::callSignFiltering = false;
WordFilter *PlayerInfo::filterData	= NULL;
bool	PlayerInfo::simpleFiltering   = true;

PlayerInfo::PlayerInfo(int _playerIndex) :
  playerIndex(_playerIndex), state(PlayerInLimbo), hasDoneEntering(false),
  flag(-1), spamWarns(0), lastMsgTime(now), paused(false),
  pausedSince(TimeKeeper::getNullTime()), autopilot(false), tracker(0)
{
  notResponding = false;
  memset(email, 0, EmailLen);
  memset(callSign, 0, CallSignLen);
  memset(token, 0, TokenLen);
  memset(clientVersion, 0, VersionLen);
}

void PlayerInfo::setFilterParameters(bool	_callSignFiltering,
				     WordFilter &_filterData,
				     bool	_simpleFiltering)
{
  callSignFiltering = _callSignFiltering;
  filterData	= &_filterData;
  simpleFiltering   = _simpleFiltering;
}

void PlayerInfo::resetPlayer(bool ctf) {
  wasRabbit = false;

  lastupdate = now;
  lastmsg    = now;

  replayState = ReplayNone;

  playedEarly = false;

  restartOnBase = ctf;
}

void PlayerInfo::setRestartOnBase(bool on) {
  restartOnBase = on;
}

bool PlayerInfo::shouldRestartAtBase() {
  return restartOnBase;
}

void PlayerInfo::signingOn() {
  state = PlayerDead;
}

void PlayerInfo::setAlive() {
  state = PlayerAlive;
  paused = false;
  flag = -1;
}

void PlayerInfo::setDead() {
  state = PlayerDead;
}

void *PlayerInfo::packUpdate(void *buf) {
  buf = nboPackUShort(buf, uint16_t(type));
  buf = nboPackUShort(buf, uint16_t(team));
  return buf;
}

void *PlayerInfo::packId(void *buf) {
  buf = nboPackString(buf, callSign, CallSignLen);
  buf = nboPackString(buf, email, EmailLen);
  return buf;
}

bool PlayerInfo::unpackEnter(void *buf, uint16_t &rejectCode, char *rejectMsg)
{
  // data: type, team, name, email
  uint16_t _type;
  int16_t _team;
  buf = nboUnpackUShort(buf, _type);
  buf = nboUnpackShort(buf, _team);
  type = PlayerType(_type);
  team = TeamColor(_team);
  buf = nboUnpackString(buf, callSign, CallSignLen);
  buf = nboUnpackString(buf, email, EmailLen);
  buf = nboUnpackString(buf, token, TokenLen);
  buf = nboUnpackString(buf, clientVersion, VersionLen);

  // terminate the strings
  callSign[CallSignLen - 1] = '\0';
  email[EmailLen - 1] = '\0';
  token[TokenLen - 1] = '\0';
  clientVersion[VersionLen - 1] = '\0';
  cleanEMail();

  DEBUG2("Player %s [%d] sent version string: %s\n",
	 callSign, playerIndex, clientVersion);
  // spoof filter holds "SERVER" for robust name comparisons
  if (serverSpoofingFilter.wordCount() == 0) {
    serverSpoofingFilter.addToFilter("SERVER", "");
  }

  if (!isCallSignReadable()) {
    DEBUG2("rejecting unreadable callsign: %s\n", callSign);
    rejectCode   = RejectBadCallsign;
    strcpy(rejectMsg, errorString.c_str());
    return false;
  }
  // no spoofing the server name
  if (serverSpoofingFilter.filter(callSign)) {
    rejectCode   = RejectRepeatCallsign;
    strcpy(rejectMsg, "The callsign specified is already in use.");
    return false;
  }
  if (!isEMailReadable()) {
    DEBUG2("rejecting unreadable player email: %s (%s)\n", callSign, email);
    rejectCode   = RejectBadEmail;
    strcpy(rejectMsg, "The e-mail was rejected.  Try a different e-mail.");
    return false;
  }

  // make sure the callsign is not obscene/filtered
  if (callSignFiltering) {
    DEBUG2("checking callsign: %s\n",callSign);

    char cs[CallSignLen];
    memcpy(cs, callSign, sizeof(char) * CallSignLen);
    if (filterData->filter(cs, simpleFiltering)) {
      rejectCode = RejectBadCallsign;
      strcpy(rejectMsg,
	     "The callsign was rejected. Try a different callsign.");
      return false;
    }
  }

  // make sure the email is not obscene/filtered
  if (callSignFiltering) {
    DEBUG2("checking email: %s\n", email);
    char em[EmailLen];
    memcpy(em, email, sizeof(char) * EmailLen);
    if (filterData->filter(em, simpleFiltering)) {
      rejectCode = RejectBadEmail;
      strcpy(rejectMsg, "The e-mail was rejected. Try a different e-mail.");
      return false;
    }
  }

  if (token[0] == 0) {
    strcpy(token, "NONE");
  }
  hasDoneEntering = true;
  return true;
}

const char *PlayerInfo::getCallSign() const {
  return callSign;
}

bool PlayerInfo::isCallSignReadable() {
  // callsign readability filter, make sure there are more alphanum than non
  // keep a count of alpha-numerics

  int callsignlen = (int)strlen(callSign);
  // reject less than 3 characters
  if (callsignlen < 3) {
    errorString = "Callsigns must be at least 3 characters.";
    return false;
  }

  // reject trailing space
  if (isspace(callSign[strlen(callSign) - 1])) {
    errorString = "Trailing spaces are not allowed in callsigns.";
    return false;
  }

  // prevent spoofing global login indicators + and @ in the scoreboard
  // and reserve # for /kick or /ban #slot
  if (*callSign=='+' || *callSign=='@' || *callSign=='#' ) {
    errorString = "Callsigns are not allowed to start with +, @, or #.";
    return false;
  }

  // start with true to reject leading space
  bool lastWasSpace = true;
  int alnumCount = 0;
  const char *sp = callSign;
  do {
    // reject sequential spaces
    if (lastWasSpace && isspace(*sp)) {
      errorString = "Leading or consecutive spaces are not allowed in callsigns.";
      return false;
    }

    // reject ' and " and any nonprintable
    if ((*sp == '\'') || (*sp == '"') || ((unsigned)*sp > 0x7f) || !isprint(*sp)) {
      errorString = "Non-printable characters and quotes are not allowed in callsigns.";
      return false;
    }
    if (isspace(*sp)) {
      // only space is valid, not tab etc.
      if (*sp != ' ') {
	      errorString = "Invalid whitespace in callsign.";
	      return false;
      }
      lastWasSpace = true;
    } else {
      lastWasSpace = false;
      if (isalnum(*sp))
	      alnumCount++;
    }
  } while (*++sp);

  bool readable = ((float)alnumCount / (float)callsignlen) > 0.5f;
  if (!readable)
    errorString = "Callsign rejected. Please use mostly letters and numbers.";
  return readable;
}

const char *PlayerInfo::getEMail() const {
  return email;
}

void PlayerInfo::cleanEMail() {
  // strip leading whitespace from email
  char *sp = email;
  char *tp = sp;
  while (isspace(*sp))
    sp++;

  // strip any non-printable characters and ' and " from email
  do {
    if (isprint(*sp) && (*sp != '\'') && (*sp != '"')) {
      *tp++ = *sp;
    }
  } while (*++sp);
  *tp = *sp;

  // strip trailing whitespace from email
  while (isspace(*--tp)) {
    *tp=0;
  }
}

bool PlayerInfo::isEMailReadable() {
  // email/"team" readability filter, make sure there are more
  // alphanum than non
  int emailAlnumCount = 0;
  char *sp = email;
  do {
    if (isalnum(*sp)) {
      emailAlnumCount++;
    }
  } while (*++sp);
  int emaillen = (int)strlen(email);
  return (emaillen <= 4) || (((float)emailAlnumCount / (float)emaillen) > 0.5);
}

const char *PlayerInfo::getToken() const {
  return token;
}

void PlayerInfo::clearToken() {
  token[0] = '\0';
}

void *PlayerInfo::packVirtualFlagCapture(void *buf) {
  buf = nboPackUShort(buf, uint16_t(int(team) - 1));
  buf = nboPackUShort(buf, uint16_t(1 + (int(team) % 4)));
  return buf;
}

bool PlayerInfo::isTeam(TeamColor _team) const {
  return team == _team;
}

bool PlayerInfo::isObserver() const {
  return team == ObserverTeam;
}

TeamColor PlayerInfo::getTeam() const {
  return team;
}

void PlayerInfo::setTeam(TeamColor _team) {
  team = _team;
}

void PlayerInfo::wasARabbit() {
  team = HunterTeam;
  wasRabbit = true;
}

void PlayerInfo::wasNotARabbit() {
  wasRabbit = false;
}

void PlayerInfo::resetFlag() {
  flag = -1;
  lastFlagDropTime = now;
}

void PlayerInfo::setFlag(int _flag) {
  flag = _flag;
}

bool PlayerInfo::isFlagTransitSafe() {
  return now - lastFlagDropTime >= 2.0f;
}

const char *PlayerInfo::getClientVersion() {
  return clientVersion;
}

std::string PlayerInfo::getIdleStat() {
  std::string reply;
  if ((state > PlayerInLimbo) && (team != ObserverTeam)) {
    reply = TextUtils::format("%s\t: %4ds", callSign,
				int(now - lastupdate));
    if (paused) {
      reply += TextUtils::format("  paused %4ds", int(now - pausedSince));
    }
  }
  return reply;
}

bool PlayerInfo::canBeRabbit(bool relaxing) {
  if (paused || notResponding || (team == ObserverTeam))
    return false;
  return relaxing ? (state > PlayerInLimbo) : (state == PlayerAlive);
}

void PlayerInfo::setPaused(bool _paused) {
  paused = _paused;
  pausedSince = now;
}

void PlayerInfo::setAutoPilot(bool _autopilot) {
  autopilot = _autopilot;
}

bool PlayerInfo::isTooMuchIdling(float kickThresh) {
  bool idling = false;
  if ((state > PlayerInLimbo) && (team != ObserverTeam)) {
    int idletime = (int)(now - lastupdate);
    int pausetime = 0;
    if (paused && now - pausedSince > idletime)
      pausetime = (int)(now - pausedSince);
    idletime = idletime > pausetime ? idletime : pausetime;
    if (idletime
	> (now - lastmsg < kickThresh ? 3 * kickThresh : kickThresh)) {
      DEBUG1("Kicking player %s [%d] idle %d\n", callSign, playerIndex,
	     idletime);
      idling = true;
    }
  }
  return idling;
}

bool PlayerInfo::hasStartedToNotRespond() {
  float notRespondingTime = BZDB.eval(StateDatabase::BZDB_NOTRESPONDINGTIME);
  bool startingToNotRespond = false;
  if (state > PlayerInLimbo) {
    bool oldnr = notResponding;
    notResponding = (now - lastupdate) > notRespondingTime;
    if (!oldnr && notResponding)
      startingToNotRespond = true;
  }
  return startingToNotRespond;
}

void PlayerInfo::hasSent() {
  lastmsg = now;
}

bool PlayerInfo::hasPlayedEarly() {
  bool returnValue = playedEarly;
  playedEarly      = false;
  return returnValue;
}

void PlayerInfo::setPlayedEarly(bool early) {
  playedEarly = early;
}

void PlayerInfo::updateIdleTime() {
  lastupdate = now;
}

void	PlayerInfo::setReplayState(PlayerReplayState _state) {
  replayState = _state;
}

PlayerReplayState PlayerInfo::getReplayState()
{
  return replayState;
}

void PlayerInfo::setTrackerID(unsigned short int t)
{
  tracker = t;
}

unsigned short int PlayerInfo::trackerID()
{
  return tracker;
}

void PlayerInfo::setCurrentTime(TimeKeeper tm)
{
  now = tm;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>Allows to use initials for callsigns<commit_after>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "PlayerInfo.h"

/* system implementation headers */
#include <errno.h>
#include <stdio.h>
#include <string>
#include <ctype.h>

/* implementation-specific common headers */
#include "TextUtils.h"

WordFilter PlayerInfo::serverSpoofingFilter;
TimeKeeper PlayerInfo::now = TimeKeeper::getCurrent();

bool	PlayerInfo::callSignFiltering = false;
WordFilter *PlayerInfo::filterData	= NULL;
bool	PlayerInfo::simpleFiltering   = true;

PlayerInfo::PlayerInfo(int _playerIndex) :
  playerIndex(_playerIndex), state(PlayerInLimbo), hasDoneEntering(false),
  flag(-1), spamWarns(0), lastMsgTime(now), paused(false),
  pausedSince(TimeKeeper::getNullTime()), autopilot(false), tracker(0)
{
  notResponding = false;
  memset(email, 0, EmailLen);
  memset(callSign, 0, CallSignLen);
  memset(token, 0, TokenLen);
  memset(clientVersion, 0, VersionLen);
}

void PlayerInfo::setFilterParameters(bool	_callSignFiltering,
				     WordFilter &_filterData,
				     bool	_simpleFiltering)
{
  callSignFiltering = _callSignFiltering;
  filterData	= &_filterData;
  simpleFiltering   = _simpleFiltering;
}

void PlayerInfo::resetPlayer(bool ctf) {
  wasRabbit = false;

  lastupdate = now;
  lastmsg    = now;

  replayState = ReplayNone;

  playedEarly = false;

  restartOnBase = ctf;
}

void PlayerInfo::setRestartOnBase(bool on) {
  restartOnBase = on;
}

bool PlayerInfo::shouldRestartAtBase() {
  return restartOnBase;
}

void PlayerInfo::signingOn() {
  state = PlayerDead;
}

void PlayerInfo::setAlive() {
  state = PlayerAlive;
  paused = false;
  flag = -1;
}

void PlayerInfo::setDead() {
  state = PlayerDead;
}

void *PlayerInfo::packUpdate(void *buf) {
  buf = nboPackUShort(buf, uint16_t(type));
  buf = nboPackUShort(buf, uint16_t(team));
  return buf;
}

void *PlayerInfo::packId(void *buf) {
  buf = nboPackString(buf, callSign, CallSignLen);
  buf = nboPackString(buf, email, EmailLen);
  return buf;
}

bool PlayerInfo::unpackEnter(void *buf, uint16_t &rejectCode, char *rejectMsg)
{
  // data: type, team, name, email
  uint16_t _type;
  int16_t _team;
  buf = nboUnpackUShort(buf, _type);
  buf = nboUnpackShort(buf, _team);
  type = PlayerType(_type);
  team = TeamColor(_team);
  buf = nboUnpackString(buf, callSign, CallSignLen);
  buf = nboUnpackString(buf, email, EmailLen);
  buf = nboUnpackString(buf, token, TokenLen);
  buf = nboUnpackString(buf, clientVersion, VersionLen);

  // terminate the strings
  callSign[CallSignLen - 1] = '\0';
  email[EmailLen - 1] = '\0';
  token[TokenLen - 1] = '\0';
  clientVersion[VersionLen - 1] = '\0';
  cleanEMail();

  DEBUG2("Player %s [%d] sent version string: %s\n",
	 callSign, playerIndex, clientVersion);
  // spoof filter holds "SERVER" for robust name comparisons
  if (serverSpoofingFilter.wordCount() == 0) {
    serverSpoofingFilter.addToFilter("SERVER", "");
  }

  if (!isCallSignReadable()) {
    DEBUG2("rejecting unreadable callsign: %s\n", callSign);
    rejectCode   = RejectBadCallsign;
    strcpy(rejectMsg, errorString.c_str());
    return false;
  }
  // no spoofing the server name
  if (serverSpoofingFilter.filter(callSign)) {
    rejectCode   = RejectRepeatCallsign;
    strcpy(rejectMsg, "The callsign specified is already in use.");
    return false;
  }
  if (!isEMailReadable()) {
    DEBUG2("rejecting unreadable player email: %s (%s)\n", callSign, email);
    rejectCode   = RejectBadEmail;
    strcpy(rejectMsg, "The e-mail was rejected.  Try a different e-mail.");
    return false;
  }

  // make sure the callsign is not obscene/filtered
  if (callSignFiltering) {
    DEBUG2("checking callsign: %s\n",callSign);

    char cs[CallSignLen];
    memcpy(cs, callSign, sizeof(char) * CallSignLen);
    if (filterData->filter(cs, simpleFiltering)) {
      rejectCode = RejectBadCallsign;
      strcpy(rejectMsg,
	     "The callsign was rejected. Try a different callsign.");
      return false;
    }
  }

  // make sure the email is not obscene/filtered
  if (callSignFiltering) {
    DEBUG2("checking email: %s\n", email);
    char em[EmailLen];
    memcpy(em, email, sizeof(char) * EmailLen);
    if (filterData->filter(em, simpleFiltering)) {
      rejectCode = RejectBadEmail;
      strcpy(rejectMsg, "The e-mail was rejected. Try a different e-mail.");
      return false;
    }
  }

  if (token[0] == 0) {
    strcpy(token, "NONE");
  }
  hasDoneEntering = true;
  return true;
}

const char *PlayerInfo::getCallSign() const {
  return callSign;
}

bool PlayerInfo::isCallSignReadable() {
  // callsign readability filter, make sure there are more alphanum than non
  // keep a count of alpha-numerics

  int callsignlen = (int)strlen(callSign);
  // reject less than 2 characters
  if (callsignlen < 2) {
    errorString = "Callsigns must be at least 2 characters.";
    return false;
  }

  // reject trailing space
  if (isspace(callSign[strlen(callSign) - 1])) {
    errorString = "Trailing spaces are not allowed in callsigns.";
    return false;
  }

  // prevent spoofing global login indicators + and @ in the scoreboard
  // and reserve # for /kick or /ban #slot
  if (*callSign=='+' || *callSign=='@' || *callSign=='#' ) {
    errorString = "Callsigns are not allowed to start with +, @, or #.";
    return false;
  }

  // start with true to reject leading space
  bool lastWasSpace = true;
  int alnumCount = 0;
  const char *sp = callSign;
  do {
    // reject sequential spaces
    if (lastWasSpace && isspace(*sp)) {
      errorString = "Leading or consecutive spaces are not allowed in callsigns.";
      return false;
    }

    // reject ' and " and any nonprintable
    if ((*sp == '\'') || (*sp == '"') || ((unsigned)*sp > 0x7f) || !isprint(*sp)) {
      errorString = "Non-printable characters and quotes are not allowed in callsigns.";
      return false;
    }
    if (isspace(*sp)) {
      // only space is valid, not tab etc.
      if (*sp != ' ') {
	      errorString = "Invalid whitespace in callsign.";
	      return false;
      }
      lastWasSpace = true;
    } else {
      lastWasSpace = false;
      if (isalnum(*sp))
	      alnumCount++;
    }
  } while (*++sp);

  bool readable = ((float)alnumCount / (float)callsignlen) > 0.5f;
  if (!readable)
    errorString = "Callsign rejected. Please use mostly letters and numbers.";
  return readable;
}

const char *PlayerInfo::getEMail() const {
  return email;
}

void PlayerInfo::cleanEMail() {
  // strip leading whitespace from email
  char *sp = email;
  char *tp = sp;
  while (isspace(*sp))
    sp++;

  // strip any non-printable characters and ' and " from email
  do {
    if (isprint(*sp) && (*sp != '\'') && (*sp != '"')) {
      *tp++ = *sp;
    }
  } while (*++sp);
  *tp = *sp;

  // strip trailing whitespace from email
  while (isspace(*--tp)) {
    *tp=0;
  }
}

bool PlayerInfo::isEMailReadable() {
  // email/"team" readability filter, make sure there are more
  // alphanum than non
  int emailAlnumCount = 0;
  char *sp = email;
  do {
    if (isalnum(*sp)) {
      emailAlnumCount++;
    }
  } while (*++sp);
  int emaillen = (int)strlen(email);
  return (emaillen <= 4) || (((float)emailAlnumCount / (float)emaillen) > 0.5);
}

const char *PlayerInfo::getToken() const {
  return token;
}

void PlayerInfo::clearToken() {
  token[0] = '\0';
}

void *PlayerInfo::packVirtualFlagCapture(void *buf) {
  buf = nboPackUShort(buf, uint16_t(int(team) - 1));
  buf = nboPackUShort(buf, uint16_t(1 + (int(team) % 4)));
  return buf;
}

bool PlayerInfo::isTeam(TeamColor _team) const {
  return team == _team;
}

bool PlayerInfo::isObserver() const {
  return team == ObserverTeam;
}

TeamColor PlayerInfo::getTeam() const {
  return team;
}

void PlayerInfo::setTeam(TeamColor _team) {
  team = _team;
}

void PlayerInfo::wasARabbit() {
  team = HunterTeam;
  wasRabbit = true;
}

void PlayerInfo::wasNotARabbit() {
  wasRabbit = false;
}

void PlayerInfo::resetFlag() {
  flag = -1;
  lastFlagDropTime = now;
}

void PlayerInfo::setFlag(int _flag) {
  flag = _flag;
}

bool PlayerInfo::isFlagTransitSafe() {
  return now - lastFlagDropTime >= 2.0f;
}

const char *PlayerInfo::getClientVersion() {
  return clientVersion;
}

std::string PlayerInfo::getIdleStat() {
  std::string reply;
  if ((state > PlayerInLimbo) && (team != ObserverTeam)) {
    reply = TextUtils::format("%s\t: %4ds", callSign,
				int(now - lastupdate));
    if (paused) {
      reply += TextUtils::format("  paused %4ds", int(now - pausedSince));
    }
  }
  return reply;
}

bool PlayerInfo::canBeRabbit(bool relaxing) {
  if (paused || notResponding || (team == ObserverTeam))
    return false;
  return relaxing ? (state > PlayerInLimbo) : (state == PlayerAlive);
}

void PlayerInfo::setPaused(bool _paused) {
  paused = _paused;
  pausedSince = now;
}

void PlayerInfo::setAutoPilot(bool _autopilot) {
  autopilot = _autopilot;
}

bool PlayerInfo::isTooMuchIdling(float kickThresh) {
  bool idling = false;
  if ((state > PlayerInLimbo) && (team != ObserverTeam)) {
    int idletime = (int)(now - lastupdate);
    int pausetime = 0;
    if (paused && now - pausedSince > idletime)
      pausetime = (int)(now - pausedSince);
    idletime = idletime > pausetime ? idletime : pausetime;
    if (idletime
	> (now - lastmsg < kickThresh ? 3 * kickThresh : kickThresh)) {
      DEBUG1("Kicking player %s [%d] idle %d\n", callSign, playerIndex,
	     idletime);
      idling = true;
    }
  }
  return idling;
}

bool PlayerInfo::hasStartedToNotRespond() {
  float notRespondingTime = BZDB.eval(StateDatabase::BZDB_NOTRESPONDINGTIME);
  bool startingToNotRespond = false;
  if (state > PlayerInLimbo) {
    bool oldnr = notResponding;
    notResponding = (now - lastupdate) > notRespondingTime;
    if (!oldnr && notResponding)
      startingToNotRespond = true;
  }
  return startingToNotRespond;
}

void PlayerInfo::hasSent() {
  lastmsg = now;
}

bool PlayerInfo::hasPlayedEarly() {
  bool returnValue = playedEarly;
  playedEarly      = false;
  return returnValue;
}

void PlayerInfo::setPlayedEarly(bool early) {
  playedEarly = early;
}

void PlayerInfo::updateIdleTime() {
  lastupdate = now;
}

void	PlayerInfo::setReplayState(PlayerReplayState _state) {
  replayState = _state;
}

PlayerReplayState PlayerInfo::getReplayState()
{
  return replayState;
}

void PlayerInfo::setTrackerID(unsigned short int t)
{
  tracker = t;
}

unsigned short int PlayerInfo::trackerID()
{
  return tracker;
}

void PlayerInfo::setCurrentTime(TimeKeeper tm)
{
  now = tm;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>// utility functions
//
#include "Utility.h"
#include "Sum.h"
#include "Product.h"

#define PHRED_MAX 99999.0 // max phred should be ~ 71141.779, so PHRED_MAX effectively means "1.0"

using namespace std;

short qualityChar2ShortInt(char c) {
    return static_cast<short>(c) - 33;
}

long double qualityChar2LongDouble(char c) {
    return static_cast<long double>(c) - 33;
}

long double lnqualityChar2ShortInt(char c) {
    return log(static_cast<short>(c) - 33);
}

char qualityInt2Char(short i) {
    return static_cast<char>(i + 33);
}

long double phred2ln(int qual) {
    return M_LN10 * qual * -.1;
}

long double ln2phred(long double prob) {
    return -10 * M_LOG10E * prob;
}

long double phred2float(int qual) {
    return pow(10, qual * -.1);
}

long double float2phred(long double prob) {
    if (prob == 1)
        return PHRED_MAX;
    long double p = -10 * (long double) log10(prob);
    if (p < 0 || p > PHRED_MAX) // int overflow guard
        return PHRED_MAX;
    else
        return p;
}

long double powln(long double m, int n) {
    return m * n;
}

// the probability that we have a completely true vector of qualities
long double jointQuality(const std::vector<short>& quals) {
    std::vector<long double> probs;
    for (int i = 0; i<quals.size(); ++i) {
        probs.push_back(phred2float(quals[i]));
    }
    // product of probability we don't have a true event for each element
    long double prod = 1 - probs.front();
    for (int i = 1; i<probs.size(); ++i) {
        prod *= 1 - probs.at(i);
    }
    // and then invert it again to get probability of an event
    return 1 - prod;
}

long double jointQuality(const std::string& qualstr) {

    long double jq = 1;
    // product of probability we don't have a true event for each element
    for (string::const_iterator q = qualstr.begin(); q != qualstr.end(); ++q) {
        jq *= 1 - phred2float(qualityChar2ShortInt(*q));
    }

    // and then invert it again to get probability of an event
    return 1 - jq;

}

std::vector<short> qualities(const std::string& qualstr) {

    std::vector<short> quals;
    for (int i=0; i<qualstr.size(); i++)
        quals.push_back(qualityChar2ShortInt(qualstr.at(i)));

    return quals;

}

long double sumQuality(const std::string& qualstr) {
    long double qual = 0;
    for (string::const_iterator q = qualstr.begin(); q != qualstr.end(); ++q)
            qual += qualityChar2LongDouble(*q);
    return qual;
}

// crudely averages quality scores in phred space
long double averageQuality(const std::string& qualstr) {

    long double qual = 0; //(long double) *max_element(quals.begin(), quals.end());
    for (string::const_iterator q = qualstr.begin(); q != qualstr.end(); ++q)
            qual += qualityChar2LongDouble(*q);
    return qual /= qualstr.size();

}

bool stringInVector(string item, vector<string> items) {
    for (vector<string>::iterator i = items.begin(); i != items.end(); ++i) {
        if (item == *i) {
            return true;
        }
    }
    return false;
}

bool allATGC(string& s) {
    for (string::iterator c = s.begin(); c != s.end(); ++c) {
        char b = *c;
        if (b != 'A' && b != 'T' && b != 'G' && b != 'C') {
            return false;
        }
    }
    return true;
}

int upper(int c) {
    return toupper((unsigned char) c);
}

string uppercase(string s) {
    transform(s.begin(), s.end(), s.begin(), upper);
    return s;
}

string strip(string const& str, char const* separators) {
    string::size_type const first = str.find_first_not_of(separators);
    return (first == string::npos) ? string()
        : str.substr(first, str.find_last_not_of(separators) - first + 1);
}

int binomialCoefficient(int n, int k) {
    int i = 1;
    int result = n - k + i++;
    while (i <= k) {
        result *= (n - k + i) / i;
        ++i;
    }
    return result;
}

long double poissonpln(int observed, int expected) {
    return ((log(expected) * observed) - expected) - factorialln(observed);
}

long double poissonp(int observed, int expected) {
    return pow(expected, observed) * pow(M_E, -expected) / factorial(observed);
}

// given the expected number of events is the max of a and b
// what is the probability that we might observe less than the observed?
long double poissonPvalLn(int a, int b) {

    int expected, observed;
    if (a > b) {
        expected = a; observed = b;
    } else {
        expected = b; observed = a;
    }

    vector<long double> probs;
    for (int i = 0; i < observed; ++i) {
        probs.push_back(poissonpln(i, expected));
    }

    return logsumexp_probs(probs);

}

long double gammaln(
		     long double x
		     ) {

  long double cofactors[] = { 76.18009173,
                              -86.50532033,
                              24.01409822,
                              -1.231739516,
                              0.120858003E-2,
                              -0.536382E-5 };

  long double x1 = x - 1.0;
  long double tmp = x1 + 5.5;
  tmp -= (x1 + 0.5) * log(tmp);
  long double ser = 1.0;
  for (int j=0; j<=5; j++) {
    x1 += 1.0;
    ser += cofactors[j]/x1;
  }
  long double y =  (-1.0 * tmp + log(2.50662827465 * ser));

  return y;
}

long double factorial(
		      int n
		      ) {
  if (n < 0) {
    return (long double)0.0;
  }
  else if (n == 0) {
    return (long double)1.0;
  }
  else {
    return exp(gammaln(n + 1.0));
  }
}

long double factorialln(
			int n
			) {
  if (n < 0) {
    return (long double)-1.0;
  }
  else if (n == 0) {
    return (long double)0.0;
  }
  else {
    return gammaln(n + 1.0);
  }
}

long double cofactor(
		     int n,
		     int i
		     ) {
  if ((n < 0) || (i < 0) || (n < i)) {
    return (long double)0.0;
  }
  else if (n == i) {
    return (long double)1.0;
  }
  else {
    return exp(gammaln(n + 1.0) - gammaln(i + 1.0) - gammaln(n-i + 1.0));
  }
}

long double cofactorln(
		       int n,
		       int i
		       ) {
  if ((n < 0) || (i < 0) || (n < i)) {
    return (long double)-1.0;
  }
  else if (n == i) {
    return (long double)0.0;
  }
  else {
    return gammaln(n + 1.0) - gammaln(i + 1.0) - gammaln(n-i + 1.0);
  }
}

// prevent underflows by returning exp(LDBL_MIN_EXP) if exponentiation will produce an underflow
long double safe_exp(long double ln) {
    if (ln < LDBL_MIN_EXP) {  // -16381
        return LDBL_MIN;      // 3.3621e-4932
    } else {
        return exp(ln);
    }
}

// 'safe' log summation for probabilities
long double logsumexp_probs(const vector<long double>& lnv) {
    vector<long double>::const_iterator i = lnv.begin();
    long double maxN = *i;
    ++i;
    for (; i != lnv.end(); ++i) {
        if (*i > maxN)
            maxN = *i;
    }
    long double sum = 0;
    for (vector<long double>::const_iterator i = lnv.begin(); i != lnv.end(); ++i) {
        sum += safe_exp(*i - maxN);
    }
    return maxN + log(sum);
}

// unsafe, kept for potential future use
long double logsumexp(const vector<long double>& lnv) {
    long double maxAbs, minN, maxN, c;
    vector<long double>::const_iterator i = lnv.begin();
    long double n = *i;
    maxAbs = n; maxN = n; minN = n;
    ++i;
    for (; i != lnv.end(); ++i) {
        n = *i;
        if (n > maxN)
            maxN = n;
        if (fabs(n) > maxAbs)
            maxAbs = fabs(n);
        if (n < minN)
            minN = n;
    }
    if (maxAbs > maxN) {
        c = minN;
    } else {
        c = maxN;
    }
    long double sum = 0;
    for (vector<long double>::const_iterator i = lnv.begin(); i != lnv.end(); ++i) {
        sum += exp(*i - c);
    }
    return c + log(sum);
}

long double betaln(const vector<long double>& alphas) {
    vector<long double> gammalnAlphas;
    gammalnAlphas.resize(alphas.size());
    transform(alphas.begin(), alphas.end(), gammalnAlphas.begin(), gammaln);
    return sum(gammalnAlphas) - gammaln(sum(alphas));
}

long double beta(const vector<long double>& alphas) {
    return exp(betaln(alphas));
}

// the sum of the harmonic series 1, n
long double harmonicSum(int n) {
    long double r = 0;
    long double i = 1;
    while (i <= n) {
        r += 1 / i;
        ++i;
    }
    return r;
}

bool isTransition(string& ref, string& alt) {
    if (((ref == "A" && alt == "G") || (ref == "G" && alt == "A")) ||
        ((ref == "C" && alt == "T") || (ref == "T" && alt == "C"))) {
        return true;
    } else {
        return false;
    }
}

// Levenshtein Distance Algorithm: C++ Implementation
// by Anders Sewerin Johansen
// http://www.merriampark.com/ldcpp.htm

int levenshteinDistance(const std::string source, const std::string target) {

  // Step 1

  const int n = source.length();
  const int m = target.length();
  if (n == 0) {
    return m;
  }
  if (m == 0) {
    return n;
  }

  // Good form to declare a TYPEDEF

  typedef std::vector< std::vector<int> > Tmatrix;

  Tmatrix matrix(n+1);

  // Size the vectors in the 2.nd dimension. Unfortunately C++ doesn't
  // allow for allocation on declaration of 2.nd dimension of vec of vec

  for (int i = 0; i <= n; i++) {
    matrix[i].resize(m+1);
  }

  // Step 2

  for (int i = 0; i <= n; i++) {
    matrix[i][0]=i;
  }

  for (int j = 0; j <= m; j++) {
    matrix[0][j]=j;
  }

  // Step 3

  for (int i = 1; i <= n; i++) {

    const char s_i = source[i-1];

    // Step 4

    for (int j = 1; j <= m; j++) {

      const char t_j = target[j-1];

      // Step 5

      int cost;
      if (s_i == t_j) {
        cost = 0;
      }
      else {
        cost = 1;
      }

      // Step 6

      const int above = matrix[i-1][j];
      const int left = matrix[i][j-1];
      const int diag = matrix[i-1][j-1];
      int cell = min( above + 1, min(left + 1, diag + cost));

      // Step 6A: Cover transposition, in addition to deletion,
      // insertion and substitution. This step is taken from:
      // Berghel, Hal ; Roach, David : "An Extension of Ukkonen's
      // Enhanced Dynamic Programming ASM Algorithm"
      // (http://www.acm.org/~hlb/publications/asm/asm.html)

      if (i>2 && j>2) {
        int trans=matrix[i-2][j-2]+1;
        if (source[i-2]!=t_j) trans++;
        if (s_i!=target[j-2]) trans++;
        if (cell>trans) cell=trans;
      }

      matrix[i][j]=cell;
    }
  }

  // Step 7

  return matrix[n][m];
}
<commit_msg>resolve ambiguious overload of pow<commit_after>// utility functions
//
#include "Utility.h"
#include "Sum.h"
#include "Product.h"

#define PHRED_MAX 99999.0 // max phred should be ~ 71141.779, so PHRED_MAX effectively means "1.0"

using namespace std;

short qualityChar2ShortInt(char c) {
    return static_cast<short>(c) - 33;
}

long double qualityChar2LongDouble(char c) {
    return static_cast<long double>(c) - 33;
}

long double lnqualityChar2ShortInt(char c) {
    return log(static_cast<short>(c) - 33);
}

char qualityInt2Char(short i) {
    return static_cast<char>(i + 33);
}

long double phred2ln(int qual) {
    return M_LN10 * qual * -.1;
}

long double ln2phred(long double prob) {
    return -10 * M_LOG10E * prob;
}

long double phred2float(int qual) {
    return pow(10, qual * -.1);
}

long double float2phred(long double prob) {
    if (prob == 1)
        return PHRED_MAX;
    long double p = -10 * (long double) log10(prob);
    if (p < 0 || p > PHRED_MAX) // int overflow guard
        return PHRED_MAX;
    else
        return p;
}

long double powln(long double m, int n) {
    return m * n;
}

// the probability that we have a completely true vector of qualities
long double jointQuality(const std::vector<short>& quals) {
    std::vector<long double> probs;
    for (int i = 0; i<quals.size(); ++i) {
        probs.push_back(phred2float(quals[i]));
    }
    // product of probability we don't have a true event for each element
    long double prod = 1 - probs.front();
    for (int i = 1; i<probs.size(); ++i) {
        prod *= 1 - probs.at(i);
    }
    // and then invert it again to get probability of an event
    return 1 - prod;
}

long double jointQuality(const std::string& qualstr) {

    long double jq = 1;
    // product of probability we don't have a true event for each element
    for (string::const_iterator q = qualstr.begin(); q != qualstr.end(); ++q) {
        jq *= 1 - phred2float(qualityChar2ShortInt(*q));
    }

    // and then invert it again to get probability of an event
    return 1 - jq;

}

std::vector<short> qualities(const std::string& qualstr) {

    std::vector<short> quals;
    for (int i=0; i<qualstr.size(); i++)
        quals.push_back(qualityChar2ShortInt(qualstr.at(i)));

    return quals;

}

long double sumQuality(const std::string& qualstr) {
    long double qual = 0;
    for (string::const_iterator q = qualstr.begin(); q != qualstr.end(); ++q)
            qual += qualityChar2LongDouble(*q);
    return qual;
}

// crudely averages quality scores in phred space
long double averageQuality(const std::string& qualstr) {

    long double qual = 0; //(long double) *max_element(quals.begin(), quals.end());
    for (string::const_iterator q = qualstr.begin(); q != qualstr.end(); ++q)
            qual += qualityChar2LongDouble(*q);
    return qual /= qualstr.size();

}

bool stringInVector(string item, vector<string> items) {
    for (vector<string>::iterator i = items.begin(); i != items.end(); ++i) {
        if (item == *i) {
            return true;
        }
    }
    return false;
}

bool allATGC(string& s) {
    for (string::iterator c = s.begin(); c != s.end(); ++c) {
        char b = *c;
        if (b != 'A' && b != 'T' && b != 'G' && b != 'C') {
            return false;
        }
    }
    return true;
}

int upper(int c) {
    return toupper((unsigned char) c);
}

string uppercase(string s) {
    transform(s.begin(), s.end(), s.begin(), upper);
    return s;
}

string strip(string const& str, char const* separators) {
    string::size_type const first = str.find_first_not_of(separators);
    return (first == string::npos) ? string()
        : str.substr(first, str.find_last_not_of(separators) - first + 1);
}

int binomialCoefficient(int n, int k) {
    int i = 1;
    int result = n - k + i++;
    while (i <= k) {
        result *= (n - k + i) / i;
        ++i;
    }
    return result;
}

long double poissonpln(int observed, int expected) {
    return ((log(expected) * observed) - expected) - factorialln(observed);
}

long double poissonp(int observed, int expected) {
    return (double) pow((double) expected, (double) observed) * (double) pow(M_E, (double) -expected) / factorial(observed);
}

// given the expected number of events is the max of a and b
// what is the probability that we might observe less than the observed?
long double poissonPvalLn(int a, int b) {

    int expected, observed;
    if (a > b) {
        expected = a; observed = b;
    } else {
        expected = b; observed = a;
    }

    vector<long double> probs;
    for (int i = 0; i < observed; ++i) {
        probs.push_back(poissonpln(i, expected));
    }

    return logsumexp_probs(probs);

}

long double gammaln(
		     long double x
		     ) {

  long double cofactors[] = { 76.18009173,
                              -86.50532033,
                              24.01409822,
                              -1.231739516,
                              0.120858003E-2,
                              -0.536382E-5 };

  long double x1 = x - 1.0;
  long double tmp = x1 + 5.5;
  tmp -= (x1 + 0.5) * log(tmp);
  long double ser = 1.0;
  for (int j=0; j<=5; j++) {
    x1 += 1.0;
    ser += cofactors[j]/x1;
  }
  long double y =  (-1.0 * tmp + log(2.50662827465 * ser));

  return y;
}

long double factorial(
		      int n
		      ) {
  if (n < 0) {
    return (long double)0.0;
  }
  else if (n == 0) {
    return (long double)1.0;
  }
  else {
    return exp(gammaln(n + 1.0));
  }
}

long double factorialln(
			int n
			) {
  if (n < 0) {
    return (long double)-1.0;
  }
  else if (n == 0) {
    return (long double)0.0;
  }
  else {
    return gammaln(n + 1.0);
  }
}

long double cofactor(
		     int n,
		     int i
		     ) {
  if ((n < 0) || (i < 0) || (n < i)) {
    return (long double)0.0;
  }
  else if (n == i) {
    return (long double)1.0;
  }
  else {
    return exp(gammaln(n + 1.0) - gammaln(i + 1.0) - gammaln(n-i + 1.0));
  }
}

long double cofactorln(
		       int n,
		       int i
		       ) {
  if ((n < 0) || (i < 0) || (n < i)) {
    return (long double)-1.0;
  }
  else if (n == i) {
    return (long double)0.0;
  }
  else {
    return gammaln(n + 1.0) - gammaln(i + 1.0) - gammaln(n-i + 1.0);
  }
}

// prevent underflows by returning exp(LDBL_MIN_EXP) if exponentiation will produce an underflow
long double safe_exp(long double ln) {
    if (ln < LDBL_MIN_EXP) {  // -16381
        return LDBL_MIN;      // 3.3621e-4932
    } else {
        return exp(ln);
    }
}

// 'safe' log summation for probabilities
long double logsumexp_probs(const vector<long double>& lnv) {
    vector<long double>::const_iterator i = lnv.begin();
    long double maxN = *i;
    ++i;
    for (; i != lnv.end(); ++i) {
        if (*i > maxN)
            maxN = *i;
    }
    long double sum = 0;
    for (vector<long double>::const_iterator i = lnv.begin(); i != lnv.end(); ++i) {
        sum += safe_exp(*i - maxN);
    }
    return maxN + log(sum);
}

// unsafe, kept for potential future use
long double logsumexp(const vector<long double>& lnv) {
    long double maxAbs, minN, maxN, c;
    vector<long double>::const_iterator i = lnv.begin();
    long double n = *i;
    maxAbs = n; maxN = n; minN = n;
    ++i;
    for (; i != lnv.end(); ++i) {
        n = *i;
        if (n > maxN)
            maxN = n;
        if (fabs(n) > maxAbs)
            maxAbs = fabs(n);
        if (n < minN)
            minN = n;
    }
    if (maxAbs > maxN) {
        c = minN;
    } else {
        c = maxN;
    }
    long double sum = 0;
    for (vector<long double>::const_iterator i = lnv.begin(); i != lnv.end(); ++i) {
        sum += exp(*i - c);
    }
    return c + log(sum);
}

long double betaln(const vector<long double>& alphas) {
    vector<long double> gammalnAlphas;
    gammalnAlphas.resize(alphas.size());
    transform(alphas.begin(), alphas.end(), gammalnAlphas.begin(), gammaln);
    return sum(gammalnAlphas) - gammaln(sum(alphas));
}

long double beta(const vector<long double>& alphas) {
    return exp(betaln(alphas));
}

// the sum of the harmonic series 1, n
long double harmonicSum(int n) {
    long double r = 0;
    long double i = 1;
    while (i <= n) {
        r += 1 / i;
        ++i;
    }
    return r;
}

bool isTransition(string& ref, string& alt) {
    if (((ref == "A" && alt == "G") || (ref == "G" && alt == "A")) ||
        ((ref == "C" && alt == "T") || (ref == "T" && alt == "C"))) {
        return true;
    } else {
        return false;
    }
}

// Levenshtein Distance Algorithm: C++ Implementation
// by Anders Sewerin Johansen
// http://www.merriampark.com/ldcpp.htm

int levenshteinDistance(const std::string source, const std::string target) {

  // Step 1

  const int n = source.length();
  const int m = target.length();
  if (n == 0) {
    return m;
  }
  if (m == 0) {
    return n;
  }

  // Good form to declare a TYPEDEF

  typedef std::vector< std::vector<int> > Tmatrix;

  Tmatrix matrix(n+1);

  // Size the vectors in the 2.nd dimension. Unfortunately C++ doesn't
  // allow for allocation on declaration of 2.nd dimension of vec of vec

  for (int i = 0; i <= n; i++) {
    matrix[i].resize(m+1);
  }

  // Step 2

  for (int i = 0; i <= n; i++) {
    matrix[i][0]=i;
  }

  for (int j = 0; j <= m; j++) {
    matrix[0][j]=j;
  }

  // Step 3

  for (int i = 1; i <= n; i++) {

    const char s_i = source[i-1];

    // Step 4

    for (int j = 1; j <= m; j++) {

      const char t_j = target[j-1];

      // Step 5

      int cost;
      if (s_i == t_j) {
        cost = 0;
      }
      else {
        cost = 1;
      }

      // Step 6

      const int above = matrix[i-1][j];
      const int left = matrix[i][j-1];
      const int diag = matrix[i-1][j-1];
      int cell = min( above + 1, min(left + 1, diag + cost));

      // Step 6A: Cover transposition, in addition to deletion,
      // insertion and substitution. This step is taken from:
      // Berghel, Hal ; Roach, David : "An Extension of Ukkonen's
      // Enhanced Dynamic Programming ASM Algorithm"
      // (http://www.acm.org/~hlb/publications/asm/asm.html)

      if (i>2 && j>2) {
        int trans=matrix[i-2][j-2]+1;
        if (source[i-2]!=t_j) trans++;
        if (s_i!=target[j-2]) trans++;
        if (cell>trans) cell=trans;
      }

      matrix[i][j]=cell;
    }
  }

  // Step 7

  return matrix[n][m];
}
<|endoftext|>