<commit_before>#include <CMDParser.hpp>
#include <DataTypes.hpp>
#include <sensor.hpp>
#include <devicemanager.hpp>
#include <device.hpp>
#include <FileValue.hpp>

#include <glm/gtc/type_ptr.hpp>

#include <zmq.hpp>
#include <cmath>
#include <iostream>
#include <chrono>         // std::chrono::seconds
#include <thread>

struct feedback{
  glm::mat4 cyclops_mat;
  glm::mat4 screen_mat;
  glm::mat4 model_mat;
  unsigned recon_mode;
};

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

  unsigned model_tracking_id = 0;
  unsigned art_port = 5000;
  unsigned start_port = 9000;
  std::string sender_ip = "127.0.0.1";

  CMDParser p("glass_ids");
  p.addOpt("m",1,"model_tracking_id", "default: 0");
  p.addOpt("r",1,"reconmodefilename", "default: none");
  p.addOpt("a",1,"artport", "default: 5000");
  p.addOpt("s",1,"senderip", "default: 127.0.0.1");
  p.addOpt("p",1,"port", "default: 9000");

  p.init(argc,argv);

  if(p.isOptSet("m")){
    model_tracking_id = p.getOptsInt("m")[0];
  }

  if(p.isOptSet("a")){
    art_port = p.getOptsInt("a")[0];
  }

  if(p.isOptSet("p")){
    start_port = p.getOptsInt("p")[0];
  }

  if(p.isOptSet("s")){
    sender_ip = p.getOptsString("s")[0];
  }

  sensor::FileValue* recon_mode = 0;
  if(p.isOptSet("r")){
    recon_mode = new sensor::FileValue(p.getOptsString("r")[0].c_str());
  }

  // prepare tracking system
  sensor::device* d = sensor::devicemanager::the()->get_dtrack(art_port, sensor::timevalue::const_050_ms);
  sensor::sensor* model = new sensor::sensor(d, model_tracking_id);

  zmq::context_t ctx(1); // means single threaded
  uint32_t hwm = 1;
  std::vector<zmq::socket_t*> sockets;
  std::vector<sensor::sensor*> glasses;
  // parse glass_ids and generate socket endpoints
  for(const auto& g_id : p.getArgs()){
     std::string endpoint = std::string("tcp://" + sender_ip + ":" + std::to_string(start_port));
     ++start_port;
     zmq::socket_t* socket = new zmq::socket_t(ctx, ZMQ_PUB); // means a publisher
     socket->setsockopt(ZMQ_SNDHWM,&hwm, sizeof(hwm));
     socket->bind(endpoint.c_str());
     sockets.push_back(socket);
     glasses.push_back(new sensor::sensor(d, std::stoi(g_id)));
     std::cout << "sending glass id " << std::stoi(g_id) << " to endpoint " << endpoint <<  std::endl;
  }

#if 0
  std::string socket_name(p.getArgs()[0]);

  zmq::context_t ctx(1); // means single threaded
  zmq::socket_t  socket(ctx, ZMQ_PUB); // means a publisher
  uint32_t hwm = 1;
  socket.setsockopt(ZMQ_SNDHWM,&hwm, sizeof(hwm));

  std::string endpoint("tcp://" + socket_name);
  socket.bind(endpoint.c_str());

  // prepare tracking system
  sensor::device* d = sensor::devicemanager::the()->get_dtrack(art_port, sensor::timevalue::const_050_ms);
  sensor::sensor* head = new sensor::sensor(d, head_tracking_id);
  sensor::sensor* model = new sensor::sensor(d, model_tracking_id);
#endif

  glm::mat4 scale_mat;
  scale_mat[0][0] = 0.25;
  scale_mat[1][1] = 0.25;
  scale_mat[2][2] = 0.25;

  glm::mat4 trans_mat;
  trans_mat[3][0] = 0.0;
  trans_mat[3][1] = 0.15;
  trans_mat[3][2] = 0.0;

  feedback fb;
  fb.recon_mode = 1;
  fb.cyclops_mat[3][0] = 0.0;
  fb.cyclops_mat[3][1] = 1.8;
  fb.cyclops_mat[3][2] = 0.0;

  fb.screen_mat[3][0] = 0.0; // -0.05
  fb.screen_mat[3][1] = 1.445; // 1.24
  fb.screen_mat[3][2] = -2.03;

  // initial model is at center screen position
  fb.model_mat = fb.screen_mat * (trans_mat * scale_mat);

  while(true){

#if 0
    // receive data from tracking system
    if((head_tracking_id) != 0 && (model_tracking_id != 0)){
      fb.cyclops_mat = head->getMatrix();
      fb.model_mat = model->getMatrix() * (trans_mat * scale_mat);
    }
#endif

    if(recon_mode != 0){
      recon_mode->read(fb.recon_mode);
    }

    fb.model_mat = model->getMatrix() * (trans_mat * scale_mat);
    for(unsigned i = 0; i != glasses.size(); ++i){
       fb.cyclops_mat = glasses[i]->getMatrix();
       zmq::message_t zmqm(sizeof(feedback));
       memcpy( (unsigned char* ) zmqm.data(), (const unsigned char*) &fb, sizeof(feedback));
       sockets[i]->send(zmqm);
    }

#if 0
    zmq::message_t zmqm(sizeof(feedback));
    memcpy( (unsigned char* ) zmqm.data(), (const unsigned char*) &fb, sizeof(feedback));
    socket.send(zmqm);
#endif

    std::this_thread::sleep_for( std::chrono::milliseconds(16) );

  }

  return 0;
}

<commit_msg>added stream slot for input<commit_after>#include <CMDParser.hpp>
#include <DataTypes.hpp>
#include <sensor.hpp>
#include <devicemanager.hpp>
#include <device.hpp>
#include <FileValue.hpp>

#include <glm/gtc/type_ptr.hpp>

#include <zmq.hpp>
#include <cmath>
#include <iostream>
#include <chrono>         // std::chrono::seconds
#include <thread>

struct feedback{
  glm::mat4 cyclops_mat;
  glm::mat4 screen_mat;
  glm::mat4 model_mat;
  unsigned recon_mode;
  unsigned stream_slot;
};

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

  unsigned model_tracking_id = 0;
  unsigned art_port = 5000;
  unsigned start_port = 9000;
  std::string sender_ip = "127.0.0.1";

  CMDParser p("glass_ids");
  p.addOpt("m",1,"model_tracking_id", "default: 0");
  p.addOpt("r",1,"reconmodefilename", "specifiy a file for selecting the reconstruction mode default: none");
  p.addOpt("x",1,"streamslotfilename", "specifiy a file for selecting the stream slot default: none");
  p.addOpt("a",1,"artport", "default: 5000");
  p.addOpt("s",1,"senderip", "default: 127.0.0.1");
  p.addOpt("p",1,"port", "default: 9000");

  p.init(argc,argv);

  if(p.isOptSet("m")){
    model_tracking_id = p.getOptsInt("m")[0];
  }

  if(p.isOptSet("a")){
    art_port = p.getOptsInt("a")[0];
  }

  if(p.isOptSet("p")){
    start_port = p.getOptsInt("p")[0];
  }

  if(p.isOptSet("s")){
    sender_ip = p.getOptsString("s")[0];
  }

  sensor::FileValue* recon_mode = 0;
  if(p.isOptSet("r")){
    recon_mode = new sensor::FileValue(p.getOptsString("r")[0].c_str());
  }

  sensor::FileValue* stream_slot = 0;
  if(p.isOptSet("x")){
    stream_slot = new sensor::FileValue(p.getOptsString("x")[0].c_str());
  }

  // prepare tracking system
  sensor::device* d = sensor::devicemanager::the()->get_dtrack(art_port, sensor::timevalue::const_050_ms);
  sensor::sensor* model = new sensor::sensor(d, model_tracking_id);

  zmq::context_t ctx(1); // means single threaded
  uint32_t hwm = 1;
  std::vector<zmq::socket_t*> sockets;
  std::vector<sensor::sensor*> glasses;
  // parse glass_ids and generate socket endpoints
  for(const auto& g_id : p.getArgs()){
     std::string endpoint = std::string("tcp://" + sender_ip + ":" + std::to_string(start_port));
     ++start_port;
     zmq::socket_t* socket = new zmq::socket_t(ctx, ZMQ_PUB); // means a publisher
     socket->setsockopt(ZMQ_SNDHWM,&hwm, sizeof(hwm));
     socket->bind(endpoint.c_str());
     sockets.push_back(socket);
     glasses.push_back(new sensor::sensor(d, std::stoi(g_id)));
     std::cout << "sending glass id " << std::stoi(g_id) << " to endpoint " << endpoint <<  std::endl;
  }

  glm::mat4 scale_mat;
  scale_mat[0][0] = 0.25;
  scale_mat[1][1] = 0.25;
  scale_mat[2][2] = 0.25;

  glm::mat4 trans_mat;
  trans_mat[3][0] = 0.0;
  trans_mat[3][1] = 0.15;
  trans_mat[3][2] = 0.0;

  feedback fb;
  fb.recon_mode = 1;
  fb.stream_slot = 0;
  fb.cyclops_mat[3][0] = 0.0;
  fb.cyclops_mat[3][1] = 1.8;
  fb.cyclops_mat[3][2] = 0.0;

  fb.screen_mat[3][0] = 0.0; // -0.05
  fb.screen_mat[3][1] = 1.445; // 1.24
  fb.screen_mat[3][2] = -2.03;

  // initial model is at center screen position
  fb.model_mat = fb.screen_mat * (trans_mat * scale_mat);

  while(true){

    if(recon_mode != 0){
      recon_mode->read(fb.recon_mode);
    }

    if(stream_slot != 0){
      stream_slot->read(fb.stream_slot);
    }

    fb.model_mat = model->getMatrix() * (trans_mat * scale_mat);
    for(unsigned i = 0; i != glasses.size(); ++i){
       fb.cyclops_mat = glasses[i]->getMatrix();
       zmq::message_t zmqm(sizeof(feedback));
       memcpy( (unsigned char* ) zmqm.data(), (const unsigned char*) &fb, sizeof(feedback));
       sockets[i]->send(zmqm);
    }

    std::this_thread::sleep_for( std::chrono::milliseconds(16) );

  }

  if(recon_mode != 0){
    delete recon_mode;
  }

  if(stream_slot != 0){
    delete stream_slot;
  }

  return 0;
}

<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
// Copyright (c) 2014 Francois Beaune, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "renderclipboardhandler.h"

// appleseed.studio headers.
#include "mainwindow/rendering/renderwidget.h"

// Qt headers.
#include <QApplication>
#include <QClipboard>
#include <QEvent>
#include <QKeyEvent>
#include <Qt>

namespace appleseed {
namespace studio {

RenderClipboardHandler::RenderClipboardHandler(RenderWidget* widget)
  : m_widget(widget)
{
    m_widget->installEventFilter(this);
}

RenderClipboardHandler::~RenderClipboardHandler()
{
    m_widget->removeEventFilter(this);
}

bool RenderClipboardHandler::eventFilter(QObject* object, QEvent* event)
{
    if (event->type() == QEvent::KeyPress)
    {
        const QKeyEvent* key_event = static_cast<QKeyEvent*>(event);

        if (key_event->modifiers() == Qt::ControlModifier && key_event->key() == Qt::Key_C)
        {
            QApplication::clipboard()->setImage(m_widget->get_image());
            return true;
        }
    }

    return QObject::eventFilter(object, event);
}

}   // namespace studio
}   // namespace appleseed
<commit_msg>print a log message when copying the render to the clipboard.<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
// Copyright (c) 2014 Francois Beaune, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "renderclipboardhandler.h"

// appleseed.studio headers.
#include "mainwindow/rendering/renderwidget.h"

// appleseed.renderer headers.
#include "renderer/api/log.h"

// Qt headers.
#include <QApplication>
#include <QClipboard>
#include <QEvent>
#include <QKeyEvent>
#include <Qt>

namespace appleseed {
namespace studio {

RenderClipboardHandler::RenderClipboardHandler(RenderWidget* widget)
  : m_widget(widget)
{
    m_widget->installEventFilter(this);
}

RenderClipboardHandler::~RenderClipboardHandler()
{
    m_widget->removeEventFilter(this);
}

bool RenderClipboardHandler::eventFilter(QObject* object, QEvent* event)
{
    if (event->type() == QEvent::KeyPress)
    {
        const QKeyEvent* key_event = static_cast<QKeyEvent*>(event);

        if (key_event->modifiers() == Qt::ControlModifier && key_event->key() == Qt::Key_C)
        {
            QApplication::clipboard()->setImage(m_widget->get_image());
            RENDERER_LOG_INFO("copied render to the clipboard.");
            return true;
        }
    }

    return QObject::eventFilter(object, event);
}

}   // namespace studio
}   // namespace appleseed
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#pragma once

#include <unordered_map>
#include <ros/ros.h>
#include <std_msgs/Float64MultiArray.h>
#include <std_msgs/Float64.h>
#include <eigen3/Eigen/Eigen>

namespace zubax_posekf
{

class DebugPublisher
{
    static constexpr unsigned QueueSize = 10;

    ros::NodeHandle node_;
    std::unordered_map<std::string, ros::Publisher> pubs_;

    template <typename Message>
    ros::Publisher& getPublisher(const std::string& name)
    {
        auto pub = pubs_.find(name);
        if (pub == pubs_.end())
        {
            (void)pubs_.insert({name, node_.advertise<Message>(name, QueueSize)});
            pub = pubs_.find(name);
            ROS_INFO("Debug publisher: New topic '%s' of type '%s'",
                     name.c_str(), ros::message_traits::DataType<Message>::value());
        }
        ROS_ASSERT(pub != pubs_.end());
        return pub->second;
    }

public:
    DebugPublisher(const std::string& ros_ns = "debug")
        : node_(ros_ns)
    { }

    template <class Message>
    void publishROSMessage(const std::string& name, const Message& msg)
    {
        getPublisher<Message>(name).publish(msg);
    }

    template <typename Derived>
    void publish(const std::string& name, const Eigen::MatrixBase<Derived>& matrix)
    {
        std_msgs::Float64MultiArray msg;

        msg.layout.dim.resize(2);
        msg.layout.dim[0].stride = static_cast<unsigned>(matrix.rows() * matrix.cols());
        msg.layout.dim[0].size   = static_cast<unsigned>(matrix.rows());
        msg.layout.dim[1].stride = static_cast<unsigned>(matrix.cols());
        msg.layout.dim[1].size   = static_cast<unsigned>(matrix.cols());
        msg.data.resize(static_cast<unsigned>(matrix.size()));

        {
            unsigned write_idx = 0;
            for (int row_idx = 0; row_idx < matrix.rows(); row_idx++)
            {
                // We can't access the matrix elements directly via coeff() in a generic way
                const auto row = matrix.row(row_idx);
                for (int col_idx = 0; col_idx < matrix.cols(); col_idx++)
                {
                    msg.data[write_idx++] = row[col_idx];
                }
            }
        }

        publishROSMessage(name, msg);
    }

    void publish(const std::string& name, const double scalar)
    {
        std_msgs::Float64 msg;
        msg.data = scalar;
        publishROSMessage(name, msg);
    }
};

}
<commit_msg>Debug publisher generalization<commit_after>/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#pragma once

#include <unordered_map>
#include <ros/ros.h>
#include <std_msgs/Float64MultiArray.h>
#include <std_msgs/Float64.h>
#include <eigen3/Eigen/Eigen>

namespace zubax_posekf
{

class DebugPublisher
{
    static constexpr unsigned QueueSize = 10;

    ros::NodeHandle node_;
    std::unordered_map<std::string, ros::Publisher> pubs_;

    template <typename Message>
    ros::Publisher& getPublisher(const std::string& name)
    {
        auto pub = pubs_.find(name);
        if (pub == pubs_.end())
        {
            (void)pubs_.insert({name, node_.advertise<Message>(name, QueueSize)});
            pub = pubs_.find(name);
            ROS_INFO("Debug publisher: New topic '%s' of type '%s'",
                     name.c_str(), ros::message_traits::DataType<Message>::value());
        }
        ROS_ASSERT(pub != pubs_.end());
        return pub->second;
    }

public:
    DebugPublisher(const std::string& ros_ns = "debug")
        : node_(ros_ns)
    { }

    template <class Message>
    void publishROSMessage(const std::string& name, const Message& msg)
    {
        getPublisher<Message>(name).publish(msg);
    }

    template <typename Derived>
    void publish(const std::string& name, const Eigen::MatrixBase<Derived>& matrix)
    {
        std_msgs::Float64MultiArray msg;

        msg.layout.dim.resize(2);
        msg.layout.dim[0].stride = static_cast<unsigned>(matrix.rows() * matrix.cols());
        msg.layout.dim[0].size   = static_cast<unsigned>(matrix.rows());
        msg.layout.dim[1].stride = static_cast<unsigned>(matrix.cols());
        msg.layout.dim[1].size   = static_cast<unsigned>(matrix.cols());
        msg.data.resize(static_cast<unsigned>(matrix.size()));

        {
            unsigned write_idx = 0;
            for (int row_idx = 0; row_idx < matrix.rows(); row_idx++)
            {
                // We can't access the matrix elements directly via coeff() in a generic way
                const auto row = matrix.row(row_idx);
                for (int col_idx = 0; col_idx < matrix.cols(); col_idx++)
                {
                    msg.data[write_idx++] = static_cast<double>(row[col_idx]);
                }
            }
        }

        publishROSMessage(name, msg);
    }

    void publish(const std::string& name, const double scalar)
    {
        std_msgs::Float64 msg;
        msg.data = scalar;
        publishROSMessage(name, msg);
    }
};

}
<|endoftext|>


<commit_before>/*
 * This material contains unpublished, proprietary software of
 * Entropic Research Laboratory, Inc. Any reproduction, distribution,
 * or publication of this work must be authorized in writing by Entropic
 * Research Laboratory, Inc., and must bear the notice:
 *
 *    "Copyright (c) 1990-1996 Entropic Research Laboratory, Inc.
 *                   All rights reserved"
 *
 * The copyright notice above does not evidence any actual or intended
 * publication of this source code.
 *
 * Written by:  Derek Lin
 * Checked by:
 * Revised by:  David Talkin
 *
 * Brief description:  Estimates F0 using normalized cross correlation and
 *   dynamic programming.
 *
 */

#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <limits.h>
#include <stdexcept>
#include <sstream>
#include <vector>

#include "f0.h"

int	    debug_level = 0;

// ----------------------------------------
// Externs
extern "C" {
int init_dp_f0(double freq, F0_params *par, long *buffsize, long *sdstep);
int dp_f0(float *fdata, int buff_size, int sdstep, double freq, F0_params *par,
          float **f0p_pt, float **vuvp_pt, float **rms_speech_pt,
          float **acpkp_pt, int *vecsize, int last_time);
}

namespace GetF0 {

// EXCEPTIONS

#define CREATE_ERROR(_Name, _Base)                                   \
  class _Name : public _Base {                                       \
  public:                                                            \
    explicit _Name(const std::string &what_arg) : _Base(what_arg) {} \
  };

CREATE_ERROR(RuntimeError, std::runtime_error);
CREATE_ERROR(LogicError, std::logic_error);
CREATE_ERROR(ParameterError, RuntimeError);
CREATE_ERROR(ProcessingError, RuntimeError);
CREATE_ERROR(AssertionError, LogicError);

#undef CREATE_ERROR

#define THROW_ERROR(condition, exception, s) \
  do {                                       \
    if (condition) {                         \
      std::stringstream ss;                  \
      ss << s;                               \
      throw exception(ss.str());             \
    }                                        \
  } while (0);

class GetF0 {
public:
  GetF0();

  int derp();

protected:

  /// @brief Provide a `buffer` we can read `num_records` samples
  /// from, returning how many samples we can read. Returning less
  /// than requested samples is a termination condition.
  ///
  /// `buffer` is not guaranteed to not be written to. (TODO: check to
  /// see if buffer can be written to.)
  virtual long readSamples(float **buffer, long num_records) { return 0; }

  /// @brief Like `readSamples`, but read `step` samples from previous
  /// buffer.
  virtual long readSamplesOverlap(float **buffer, long num_records, long step)
  {
    return 0;
  }

  virtual void writeOutput(float *f0p, float *vuvp, float *rms_speech,
                           float *acpkp, int vecsize)
  {
  }

private:

  static void check_f0_params(F0_params *par, double sample_freq);

};

int GetF0::derp()
{
  int done;
  long buff_size, actsize;
  double sf, output_starts, frame_rate;
  float *f0p, *vuvp, *rms_speech, *acpkp;
  int i, vecsize;
  long sdstep = 0;

  F0_params par;
  par.cand_thresh = 0.3;
  par.lag_weight = 0.3;
  par.freq_weight = 0.02;
  par.trans_cost = 0.005;
  par.trans_amp = 0.5;
  par.trans_spec = 0.5;
  par.voice_bias = 0.0;
  par.double_cost = 0.35;
  par.min_f0 = 50;
  par.max_f0 = 550;
  par.frame_step = 0.01;
  par.wind_dur = 0.0075;
  par.n_cands = 20;
  par.mean_f0 = 200;     /* unused */
  par.mean_f0_weight = 0.0;  /* unused */
  par.conditioning = 0;    /*unused */

#define SW_CUSTOMIZABLE(x) //TODO(sw)
  SW_CUSTOMIZABLE(debug_level);

  SW_CUSTOMIZABLE(par.frame_step);
  SW_CUSTOMIZABLE(par.cand_thresh);
  SW_CUSTOMIZABLE(par.lag_weight);
  SW_CUSTOMIZABLE(par.freq_weight);
  SW_CUSTOMIZABLE(par.trans_cost);
  SW_CUSTOMIZABLE(par.trans_amp);
  SW_CUSTOMIZABLE(par.trans_spec);
  SW_CUSTOMIZABLE(par.voice_bias);
  SW_CUSTOMIZABLE(par.double_cost);
  SW_CUSTOMIZABLE(par.min_f0);
  SW_CUSTOMIZABLE(par.max_f0);
  SW_CUSTOMIZABLE(par.wind_dur);
  SW_CUSTOMIZABLE(par.n_cands);
#undef SW_CUSTOMIZABLE

#define SW_FILE_PARAMS(x, y) //TODO (sw)
  SW_FILE_PARAMS(sf, "sampling frequency");
#undef SW_FILE_PARAMS

  check_f0_params(&par, sf);

  /*SW: Removed range restricter, but this may be interesting:
    if (total_samps < ((par->frame_step * 2.0) + par->wind_dur) * sf), then
      input range too small*/

  output_starts = par.wind_dur/2.0;
  /* Average delay due to loc. of ref. window center. */
  frame_rate = 1.0 / par.frame_step;

  /* Initialize variables in get_f0.c; allocate data structures;
   * determine length and overlap of input frames to read.
   *
   * sw: Looks like init_dp_f0 never returns errors via rcode, but put
   * under assertion.
   */
  THROW_ERROR(init_dp_f0(sf, &par, &buff_size, &sdstep) ||
                  buff_size > INT_MAX || sdstep > INT_MAX,
              AssertionError, "problem in init_dp_f0().");

  /*SW: pass sdstep to caller so it knows how much we have to buffer. */

  if (debug_level)
    Fprintf(stderr, "init_dp_f0 returned buff_size %ld, sdstep %ld.\n",
	    buff_size, sdstep);

  float* fdata = nullptr;
  actsize = readSamples(&fdata, buff_size);

  while (1) {

    done = (actsize < buff_size);

    THROW_ERROR(dp_f0(fdata, (int)actsize, (int)sdstep, sf, &par, &f0p, &vuvp,
                      &rms_speech, &acpkp, &vecsize, done),
                ProcessingError, "problem in dp_f0().");

    writeOutput(f0p, vuvp, rms_speech, acpkp, vecsize);

    if (done)
      break;

    actsize = readSamplesOverlap(&fdata, buff_size, sdstep);

  }

  exit(0);
}

/*
 * Some consistency checks on parameter values.
 */
void GetF0::check_f0_params(F0_params *par, double sample_freq)
{
  std::vector<std::string> errors;

  if ((par->cand_thresh < 0.01) || (par->cand_thresh > 0.99)) {
    errors.push_back("cand_thresh parameter must be between [0.01, 0.99].");
  }
  if ((par->wind_dur > .1) || (par->wind_dur < .0001)) {
    errors.push_back("wind_dur parameter must be between [0.0001, 0.1].");
  }
  if ((par->n_cands > 100) || (par->n_cands < 3)) {
    errors.push_back("n_cands parameter must be between [3,100].");
  }
  if ((par->max_f0 <= par->min_f0) || (par->max_f0 >= (sample_freq / 2.0)) ||
      (par->min_f0 < (sample_freq / 10000.0))) {
    errors.push_back(
        "min(max)_f0 parameter inconsistent with sampling frequency.");
  }
  double dstep =
      ((double)((int)(0.5 + (sample_freq * par->frame_step)))) / sample_freq;
  if (dstep != par->frame_step) {
    if (debug_level)
      Fprintf(stderr,
              "Frame step set to %f to exactly match signal sample rate.\n",
              dstep);
    par->frame_step = dstep;
  }
  if ((par->frame_step > 0.1) || (par->frame_step < (1.0 / sample_freq))) {
    errors.push_back(
        "frame_step parameter must be between [1/sampling rate, "
        "0.1].");
  }

  if (!errors.empty()) {
    std::stringstream ss;
    bool first = true;
    for (auto &error : errors) {
      if (!first) ss << " ";
      ss << error;
    }

    THROW_ERROR(true, ParameterError, ss.str());
  }
}

} // namespace GetF0
<commit_msg>Pulled out init_params<commit_after>/*
 * This material contains unpublished, proprietary software of
 * Entropic Research Laboratory, Inc. Any reproduction, distribution,
 * or publication of this work must be authorized in writing by Entropic
 * Research Laboratory, Inc., and must bear the notice:
 *
 *    "Copyright (c) 1990-1996 Entropic Research Laboratory, Inc.
 *                   All rights reserved"
 *
 * The copyright notice above does not evidence any actual or intended
 * publication of this source code.
 *
 * Written by:  Derek Lin
 * Checked by:
 * Revised by:  David Talkin
 *
 * Brief description:  Estimates F0 using normalized cross correlation and
 *   dynamic programming.
 *
 */

#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <limits.h>
#include <stdexcept>
#include <sstream>
#include <vector>

#include "f0.h"

int	    debug_level = 0;

// ----------------------------------------
// Externs
extern "C" {
int init_dp_f0(double freq, F0_params *par, long *buffsize, long *sdstep);
int dp_f0(float *fdata, int buff_size, int sdstep, double freq, F0_params *par,
          float **f0p_pt, float **vuvp_pt, float **rms_speech_pt,
          float **acpkp_pt, int *vecsize, int last_time);
}

namespace GetF0 {

// EXCEPTIONS

#define CREATE_ERROR(_Name, _Base)                                   \
  class _Name : public _Base {                                       \
  public:                                                            \
    explicit _Name(const std::string &what_arg) : _Base(what_arg) {} \
  };

CREATE_ERROR(RuntimeError, std::runtime_error);
CREATE_ERROR(LogicError, std::logic_error);
CREATE_ERROR(ParameterError, RuntimeError);
CREATE_ERROR(ProcessingError, RuntimeError);
CREATE_ERROR(AssertionError, LogicError);

#undef CREATE_ERROR

#define THROW_ERROR(condition, exception, s) \
  do {                                       \
    if (condition) {                         \
      std::stringstream ss;                  \
      ss << s;                               \
      throw exception(ss.str());             \
    }                                        \
  } while (0);

class GetF0 {
public:
  GetF0();

  int derp();

protected:

  /// @brief Provide a `buffer` we can read `num_records` samples
  /// from, returning how many samples we can read. Returning less
  /// than requested samples is a termination condition.
  ///
  /// `buffer` is not guaranteed to not be written to. (TODO: check to
  /// see if buffer can be written to.)
  virtual long readSamples(float **buffer, long num_records) { return 0; }

  /// @brief Like `readSamples`, but read `step` samples from previous
  /// buffer.
  virtual long readSamplesOverlap(float **buffer, long num_records, long step)
  {
    return 0;
  }

  virtual void writeOutput(float *f0p, float *vuvp, float *rms_speech,
                           float *acpkp, int vecsize)
  {
  }

private:

  F0_params m_par;

  void init_params();

  static void check_f0_params(F0_params *par, double sample_freq);

};

GetF0::GetF0()
{
  init_params();
}

void GetF0::init_params()
{
  m_par.cand_thresh = 0.3;
  m_par.lag_weight = 0.3;
  m_par.freq_weight = 0.02;
  m_par.trans_cost = 0.005;
  m_par.trans_amp = 0.5;
  m_par.trans_spec = 0.5;
  m_par.voice_bias = 0.0;
  m_par.double_cost = 0.35;
  m_par.min_f0 = 50;
  m_par.max_f0 = 550;
  m_par.frame_step = 0.01;
  m_par.wind_dur = 0.0075;
  m_par.n_cands = 20;
  m_par.mean_f0 = 200;        /* unused */
  m_par.mean_f0_weight = 0.0; /* unused */
  m_par.conditioning = 0;     /*unused */
}

int GetF0::derp()
{
  int done;
  long buff_size, actsize;
  double sf, output_starts, frame_rate;
  float *f0p, *vuvp, *rms_speech, *acpkp;
  int i, vecsize;
  long sdstep = 0;

#define SW_CUSTOMIZABLE(x) //TODO(sw)
  SW_CUSTOMIZABLE(debug_level);

  SW_CUSTOMIZABLE(m_par.frame_step);
  SW_CUSTOMIZABLE(m_par.cand_thresh);
  SW_CUSTOMIZABLE(m_par.lag_weight);
  SW_CUSTOMIZABLE(m_par.freq_weight);
  SW_CUSTOMIZABLE(m_par.trans_cost);
  SW_CUSTOMIZABLE(m_par.trans_amp);
  SW_CUSTOMIZABLE(m_par.trans_spec);
  SW_CUSTOMIZABLE(m_par.voice_bias);
  SW_CUSTOMIZABLE(m_par.double_cost);
  SW_CUSTOMIZABLE(m_par.min_f0);
  SW_CUSTOMIZABLE(m_par.max_f0);
  SW_CUSTOMIZABLE(m_par.wind_dur);
  SW_CUSTOMIZABLE(m_par.n_cands);
#undef SW_CUSTOMIZABLE

#define SW_FILE_PARAMS(x, y) //TODO (sw)
  SW_FILE_PARAMS(sf, "sampling frequency");
#undef SW_FILE_PARAMS

  check_f0_params(&m_par, sf);

  /*SW: Removed range restricter, but this may be interesting:
    if (total_samps < ((par->frame_step * 2.0) + par->wind_dur) * sf), then
      input range too small*/

  output_starts = m_par.wind_dur/2.0;
  /* Average delay due to loc. of ref. window center. */
  frame_rate = 1.0 / m_par.frame_step;

  /* Initialize variables in get_f0.c; allocate data structures;
   * determine length and overlap of input frames to read.
   *
   * sw: Looks like init_dp_f0 never returns errors via rcode, but put
   * under assertion.
   */
  THROW_ERROR(init_dp_f0(sf, &m_par, &buff_size, &sdstep) ||
                  buff_size > INT_MAX || sdstep > INT_MAX,
              AssertionError, "problem in init_dp_f0().");

  /*SW: pass sdstep to caller so it knows how much we have to buffer. */

  if (debug_level)
    Fprintf(stderr, "init_dp_f0 returned buff_size %ld, sdstep %ld.\n",
	    buff_size, sdstep);

  float* fdata = nullptr;
  actsize = readSamples(&fdata, buff_size);

  while (1) {

    done = (actsize < buff_size);

    THROW_ERROR(dp_f0(fdata, (int)actsize, (int)sdstep, sf, &m_par, &f0p, &vuvp,
                      &rms_speech, &acpkp, &vecsize, done),
                ProcessingError, "problem in dp_f0().");

    writeOutput(f0p, vuvp, rms_speech, acpkp, vecsize);

    if (done)
      break;

    actsize = readSamplesOverlap(&fdata, buff_size, sdstep);

  }

  exit(0);
}

/*
 * Some consistency checks on parameter values.
 */
void GetF0::check_f0_params(F0_params *par, double sample_freq)
{
  std::vector<std::string> errors;

  if ((par->cand_thresh < 0.01) || (par->cand_thresh > 0.99)) {
    errors.push_back("cand_thresh parameter must be between [0.01, 0.99].");
  }
  if ((par->wind_dur > .1) || (par->wind_dur < .0001)) {
    errors.push_back("wind_dur parameter must be between [0.0001, 0.1].");
  }
  if ((par->n_cands > 100) || (par->n_cands < 3)) {
    errors.push_back("n_cands parameter must be between [3,100].");
  }
  if ((par->max_f0 <= par->min_f0) || (par->max_f0 >= (sample_freq / 2.0)) ||
      (par->min_f0 < (sample_freq / 10000.0))) {
    errors.push_back(
        "min(max)_f0 parameter inconsistent with sampling frequency.");
  }
  double dstep =
      ((double)((int)(0.5 + (sample_freq * par->frame_step)))) / sample_freq;
  if (dstep != par->frame_step) {
    if (debug_level)
      Fprintf(stderr,
              "Frame step set to %f to exactly match signal sample rate.\n",
              dstep);
    par->frame_step = dstep;
  }
  if ((par->frame_step > 0.1) || (par->frame_step < (1.0 / sample_freq))) {
    errors.push_back(
        "frame_step parameter must be between [1/sampling rate, "
        "0.1].");
  }

  if (!errors.empty()) {
    std::stringstream ss;
    bool first = true;
    for (auto &error : errors) {
      if (!first) ss << " ";
      ss << error;
    }

    THROW_ERROR(true, ParameterError, ss.str());
  }
}

} // namespace GetF0
<|endoftext|>


<commit_before>// Copyright (c) 2013 - 2015, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <nix/file/FeatureFS.hpp>

#include <nix/util/util.hpp>
#include <nix/DataArray.hpp>
#include <nix/file/DataArrayFS.hpp>

using namespace std;
using namespace nix::base;

namespace nix {
namespace file {

string linkTypeToString(LinkType link_type) {
    static vector<string> type_names = {"tagged", "untagged", "indexed"};
    return type_names[static_cast<int>(link_type)];
}

LinkType linkTypeFromString(const string &str) {
    if (str == "tagged")
        return LinkType::Tagged;
    else if (str == "untagged")
        return LinkType::Untagged;
    else if (str == "indexed")
        return LinkType::Indexed;
    else
        throw runtime_error("Unable to create a LinkType from the string: " + str);
}

FeatureFS::FeatureFS(const shared_ptr<IFile> &file, const shared_ptr<IBlock> &block, const string &loc)
    : EntityFS(file, loc), block(block)
{
}

FeatureFS::FeatureFS(const shared_ptr<IFile> &file, const shared_ptr<IBlock> &block, const string &loc,
                     const string &id, DataArray data, LinkType link_type)
    : FeatureFS(file, block, loc, id, data, link_type, util::getTime())
{
}

FeatureFS::FeatureFS(const shared_ptr<IFile> &file, const shared_ptr<IBlock> &block, const string &loc,
                     const string &id, DataArray data, LinkType link_type, time_t time)
    : EntityFS(file, loc, id, time), block(block)
{
    linkType(link_type);
    // TODO: the line below currently throws an exception if the DataArray
    // is not in block - to consider if we prefer copying it to the block
    this->data(data.id());
}

void FeatureFS::linkType(LinkType link_type) {
    // linkTypeToString will generate an error if link_type is invalid
    setAttr("link_type", linkTypeToString(link_type));
    forceUpdatedAt();
}

void FeatureFS::data(const std::string &name_or_id) {
    if (name_or_id.empty())
        throw EmptyString("data(id)");
    if (!block->hasDataArray(name_or_id))
        throw std::runtime_error("FeatureFS::data: DataArray not found in block!");

    auto target = dynamic_pointer_cast<DataArrayFS>(block->getDataArray(name_or_id));
    // FIXME create Link
    //group().createLink(target->group(), "data");
    forceUpdatedAt();
}

shared_ptr<IDataArray> FeatureFS::data() const {
    shared_ptr<IDataArray> da;
    /*
    bool error = false;

    if (group().hasGroup("data")) {
        Group other_group = group().openGroup("data", false);
        da = make_shared<DataArrayHDF5>(file(), block, other_group);
        if (!block->hasDataArray(da->id())) error = true;
    }
    else error = true;

    // NOTE: we check that link exists in both places, here & in entity
    // if error = true it was missing in one of the two
    if (error)
        throw std::runtime_error("FeatureHDF5::data: DataArray not found!");
    */
    return da;
}

LinkType FeatureFS::linkType() const {
    if (hasAttr("link_type")) {
        string link_type;
        getAttr("link_type", link_type);
        return linkTypeFromString(link_type);
    } else {
        throw MissingAttr("data");
    }
}

FeatureFS::~FeatureFS() {}

} // ns nix::file
} // ns nix
<commit_msg>[file_backend/Feature] avoid warning...<commit_after>// Copyright (c) 2013 - 2015, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <nix/file/FeatureFS.hpp>

#include <nix/util/util.hpp>
#include <nix/DataArray.hpp>
#include <nix/file/DataArrayFS.hpp>

using namespace std;
using namespace nix::base;

namespace nix {
namespace file {

string linkTypeToString(LinkType link_type) {
    static vector<string> type_names = {"tagged", "untagged", "indexed"};
    return type_names[static_cast<int>(link_type)];
}

LinkType linkTypeFromString(const string &str) {
    if (str == "tagged")
        return LinkType::Tagged;
    else if (str == "untagged")
        return LinkType::Untagged;
    else if (str == "indexed")
        return LinkType::Indexed;
    else
        throw runtime_error("Unable to create a LinkType from the string: " + str);
}

FeatureFS::FeatureFS(const shared_ptr<IFile> &file, const shared_ptr<IBlock> &block, const string &loc)
    : EntityFS(file, loc), block(block)
{
}

FeatureFS::FeatureFS(const shared_ptr<IFile> &file, const shared_ptr<IBlock> &block, const string &loc,
                     const string &id, DataArray data, LinkType link_type)
    : FeatureFS(file, block, loc, id, data, link_type, util::getTime())
{
}

FeatureFS::FeatureFS(const shared_ptr<IFile> &file, const shared_ptr<IBlock> &block, const string &loc,
                     const string &id, DataArray data, LinkType link_type, time_t time)
    : EntityFS(file, loc, id, time), block(block)
{
    linkType(link_type);
    // TODO: the line below currently throws an exception if the DataArray
    // is not in block - to consider if we prefer copying it to the block
    this->data(data.id());
}

void FeatureFS::linkType(LinkType link_type) {
    // linkTypeToString will generate an error if link_type is invalid
    setAttr("link_type", linkTypeToString(link_type));
    forceUpdatedAt();
}

void FeatureFS::data(const std::string &name_or_id) {
    if (name_or_id.empty())
        throw EmptyString("data(id)");
    if (!block->hasDataArray(name_or_id))
        throw std::runtime_error("FeatureFS::data: DataArray not found in block!");

    auto target = dynamic_pointer_cast<DataArrayFS>(block->getDataArray(name_or_id));
    // FIXME create Link
    //group().createLink(target->group(), "data");
    forceUpdatedAt();
}

shared_ptr<IDataArray> FeatureFS::data() const {
    shared_ptr<IDataArray> da;
    /*
    bool error = false;

    if (group().hasGroup("data")) {
        Group other_group = group().openGroup("data", false);
        da = make_shared<DataArrayHDF5>(file(), block, other_group);
        if (!block->hasDataArray(da->id())) error = true;
    }
    else error = true;

    // NOTE: we check that link exists in both places, here & in entity
    // if error = true it was missing in one of the two
    if (error)
        throw std::runtime_error("FeatureHDF5::data: DataArray not found!");
    */
    return da;
}

LinkType FeatureFS::linkType() const {
    if (hasAttr("link_type")) {
        string link_type;
        getAttr("link_type", link_type);
        return linkTypeFromString(link_type);
    } else {
        throw MissingAttr("data");
    }
}

FeatureFS::~FeatureFS() {}

} // ns nix::file
} // ns nix
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "MethodSimilarityOrderer.h"

#include "DexInstruction.h"
#include "Show.h"
#include "Trace.h"
#include "WorkQueue.h"

namespace {
// Similarity score for each candidate method, based on the number of
// shared, missing and additional hash ids when compared to the previously
// chosen method.
struct Score {
  uint32_t shared{0};
  uint32_t missing{0};
  uint32_t additional{0};
  int32_t value() const { return 2 * shared - missing - 2 * additional; }
};

template <typename T>
struct CountingFakeOutputIterator {
  uint32_t& counter;
  T fake;
  explicit CountingFakeOutputIterator(uint32_t& c) : counter(c) {}
  CountingFakeOutputIterator& operator++() {
    counter++;
    return *this;
  }
  T& operator*() { return fake; }
};
}; // namespace

void MethodSimilarityOrderer::gather_code_hash_ids(
    const std::vector<DexInstruction*>& instructions,
    std::vector<CodeHashId>& code_hash_ids) {

  std::unordered_set<StableHash> stable_hashes;

  // For any instruction,we can compute a (stable) hash representing
  // it.
  for (size_t i = 0; i < instructions.size(); i++) {
    uint64_t code_hash{0};
    auto insn = instructions.at(i);
    auto op = insn->opcode();
    code_hash = code_hash * 23 + op;
    if (insn->has_literal()) {
      code_hash = code_hash * 7 + insn->get_literal();
    }
    if (insn->has_range()) {
      code_hash =
          (code_hash * 11 + insn->range_base()) * 11 + insn->range_size();
    }
    if (insn->has_dest()) {
      code_hash = code_hash * 13 + insn->dest();
    }
    for (unsigned j = 0; j < insn->srcs_size(); j++) {
      code_hash = code_hash * 17 + insn->src(j);
    }
    stable_hashes.insert(code_hash);
  };

  // Initialize the vector for code hash.
  // Publish code hash ids from stable hashes.
  code_hash_ids.reserve(stable_hashes.size());
  for (StableHash stable_hash : stable_hashes) {
    if (m_stable_hash_to_code_hash_id.count(stable_hash) == 0) {
      // Assign a unique code hash id if it appears for the first time.
      auto code_hash_id = m_stable_hash_to_code_hash_id.size();
      m_stable_hash_to_code_hash_id[stable_hash] = code_hash_id;
    }
    code_hash_ids.push_back(m_stable_hash_to_code_hash_id[stable_hash]);
  }
  // Sort the code hash Ids to check the overlaps in the linear time.
  std::sort(code_hash_ids.begin(), code_hash_ids.end());
}

// For the given code hash ids (i) and code hash ids (j), get score for j
// against i.
static inline Score get_score(
    const std::vector<MethodSimilarityOrderer::CodeHashId>& code_hash_ids_i,
    const std::vector<MethodSimilarityOrderer::CodeHashId>& code_hash_ids_j) {
  uint32_t i_size = code_hash_ids_i.size();
  uint32_t j_size = code_hash_ids_j.size();

  Score score;
  std::set_intersection(
      code_hash_ids_i.begin(), code_hash_ids_i.end(), code_hash_ids_j.begin(),
      code_hash_ids_j.end(),
      CountingFakeOutputIterator<MethodSimilarityOrderer::CodeHashId>(
          score.shared));

  score.missing = i_size - score.shared;
  score.additional = j_size - score.shared;

  return score;
}

void MethodSimilarityOrderer::compute_score() {
  m_score_map.clear();
  m_score_map.resize(m_id_to_method.size());

  // Maximum number of code items can be 65536.
  redex_assert(m_id_to_method.size() <= (1 << 16));

  std::vector<MethodId> indices(m_id_to_method.size());
  std::iota(indices.begin(), indices.end(), 0);
  workqueue_run<MethodId>(
      [&](MethodId i_id) {
        const auto& code_hash_ids_i = m_method_id_to_code_hash_ids[i_id];
        std::unordered_map<ScoreValue, boost::dynamic_bitset<>> score_map;

        for (uint32_t j_id = 0; j_id < (uint32_t)m_id_to_method.size();
             j_id++) {
          if (i_id == j_id) {
            continue;
          }

          const auto& code_hash_ids_j = m_method_id_to_code_hash_ids[j_id];
          auto score = get_score(code_hash_ids_i, code_hash_ids_j);
          if (score.value() >= 0) {
            auto& method_id_bitset = score_map[score.value()];
            if (method_id_bitset.size() <= j_id) {
              method_id_bitset.resize(j_id + 1);
            }
            method_id_bitset.set(static_cast<size_t>(j_id));
          }
        }

        if (!score_map.empty()) {
          std::map<ScoreValue, boost::dynamic_bitset<>,
                   std::greater<ScoreValue>>
              map;
          // Mapping from score value (key) to Method Ids. The key is in a
          // decreasing score order. Becuase it iterates Method Id in order,
          // the vector is already sorted by Method index (source order).
          for (auto&& [score_value, method_ids] : score_map) {
            map[score_value] = std::move(method_ids);
          }
          m_score_map[i_id] = std::move(map);
        }
      },
      indices);
}

void MethodSimilarityOrderer::insert(DexMethod* method) {
  always_assert(m_method_to_id.count(method) == 0);
  // While the number of methods can reach 65536 (2^16), at
  // this stage not all methods have been added, so we assert that
  // the number can fit on 16 bits and safely be assigned to a MethodId index.
  redex_assert(m_id_to_method.size() < (1 << 16));
  MethodId index = m_id_to_method.size();
  m_id_to_method.emplace(index, method);
  m_method_to_id.emplace(method, index);

  auto& code_hash_ids = m_method_id_to_code_hash_ids[index];
  auto* code = method->get_dex_code();
  if (code) {
    gather_code_hash_ids(code->get_instructions(), code_hash_ids);
  }
}

boost::optional<MethodSimilarityOrderer::MethodId>
MethodSimilarityOrderer::get_next() {
  // Clear best candidates.
  if (m_id_to_method.empty()) {
    return {};
  }

  if (m_last_method_id != boost::none) {
    // Iterate m_score_map from the highest score..
    for (const auto& [score, method_id_bitset] :
         m_score_map[*m_last_method_id]) {
      for (auto meth_id = method_id_bitset.find_first();
           meth_id != boost::dynamic_bitset<>::npos;
           meth_id = method_id_bitset.find_next(meth_id)) {
        // The first match is the one with the highest score
        // at the smallest index in the source order.
        if (m_id_to_method.count(static_cast<MethodId>(meth_id))) {
          TRACE(OPUT, 3,
                "[method-similarity-orderer] selected %s with score %d",
                SHOW(m_id_to_method[static_cast<MethodId>(meth_id)]), score);
          return meth_id;
        }
      }
    }
  }
  boost::optional<MethodId> best_method_id = m_id_to_method.begin()->first;
  TRACE(OPUT,
        3,
        "[method-similarity-orderer] reverted to %s",
        SHOW(*best_method_id));
  return best_method_id;
}

void MethodSimilarityOrderer::remove_method(DexMethod* meth) {
  if (!m_method_to_id.count(meth)) return;

  auto method_id = m_method_to_id[meth];
  m_id_to_method.erase(method_id);
  m_method_to_id.erase(meth);
}

void MethodSimilarityOrderer::order(std::vector<DexMethod*>& methods) {
  Timer t("Reordering methods by similarity");

  for (auto* method : methods) {
    insert(method);
  }

  methods.clear();

  // Compute scores among methods in parallel.
  compute_score();

  m_last_method_id = boost::none;
  for (boost::optional<MethodId> best_method_id = get_next();
       best_method_id != boost::none;
       best_method_id = get_next()) {
    m_last_method_id = best_method_id;
    auto meth = m_id_to_method[*m_last_method_id];
    methods.push_back(meth);
    remove_method(meth);
  }
}
<commit_msg>Hash callee method names for better compression<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "MethodSimilarityOrderer.h"

#include "DexInstruction.h"
#include "Show.h"
#include "Trace.h"
#include "WorkQueue.h"

namespace {
// Similarity score for each candidate method, based on the number of
// shared, missing and additional hash ids when compared to the previously
// chosen method.
struct Score {
  uint32_t shared{0};
  uint32_t missing{0};
  uint32_t additional{0};
  int32_t value() const { return 2 * shared - missing - 2 * additional; }
};

template <typename T>
struct CountingFakeOutputIterator {
  uint32_t& counter;
  T fake;
  explicit CountingFakeOutputIterator(uint32_t& c) : counter(c) {}
  CountingFakeOutputIterator& operator++() {
    counter++;
    return *this;
  }
  T& operator*() { return fake; }
};
}; // namespace

void MethodSimilarityOrderer::gather_code_hash_ids(
    const std::vector<DexInstruction*>& instructions,
    std::vector<CodeHashId>& code_hash_ids) {

  std::unordered_set<StableHash> stable_hashes;

  // For any instruction,we can compute a (stable) hash representing
  // it.
  for (size_t i = 0; i < instructions.size(); i++) {
    uint64_t code_hash{0};
    auto insn = instructions.at(i);
    auto op = insn->opcode();
    code_hash = code_hash * 23 + op;
    if (insn->has_literal()) {
      code_hash = code_hash * 7 + insn->get_literal();
    }
    if (insn->has_range()) {
      code_hash =
          (code_hash * 11 + insn->range_base()) * 11 + insn->range_size();
    }
    if (insn->has_dest()) {
      code_hash = code_hash * 13 + insn->dest();
    }
    for (unsigned j = 0; j < insn->srcs_size(); j++) {
      code_hash = code_hash * 17 + insn->src(j);
    }
    if (insn->has_method()) {
      auto callee = ((DexOpcodeMethod*)insn)->get_method();
      stable_hashes.insert(std::hash<std::string>{}(show(callee)));
    }
    stable_hashes.insert(code_hash);
  };

  // Initialize the vector for code hash.
  // Publish code hash ids from stable hashes.
  code_hash_ids.reserve(stable_hashes.size());
  for (StableHash stable_hash : stable_hashes) {
    if (m_stable_hash_to_code_hash_id.count(stable_hash) == 0) {
      // Assign a unique code hash id if it appears for the first time.
      auto code_hash_id = m_stable_hash_to_code_hash_id.size();
      m_stable_hash_to_code_hash_id[stable_hash] = code_hash_id;
    }
    code_hash_ids.push_back(m_stable_hash_to_code_hash_id[stable_hash]);
  }
  // Sort the code hash Ids to check the overlaps in the linear time.
  std::sort(code_hash_ids.begin(), code_hash_ids.end());
}

// For the given code hash ids (i) and code hash ids (j), get score for j
// against i.
static inline Score get_score(
    const std::vector<MethodSimilarityOrderer::CodeHashId>& code_hash_ids_i,
    const std::vector<MethodSimilarityOrderer::CodeHashId>& code_hash_ids_j) {
  uint32_t i_size = code_hash_ids_i.size();
  uint32_t j_size = code_hash_ids_j.size();

  Score score;
  std::set_intersection(
      code_hash_ids_i.begin(), code_hash_ids_i.end(), code_hash_ids_j.begin(),
      code_hash_ids_j.end(),
      CountingFakeOutputIterator<MethodSimilarityOrderer::CodeHashId>(
          score.shared));

  score.missing = i_size - score.shared;
  score.additional = j_size - score.shared;

  return score;
}

void MethodSimilarityOrderer::compute_score() {
  m_score_map.clear();
  m_score_map.resize(m_id_to_method.size());

  // Maximum number of code items can be 65536.
  redex_assert(m_id_to_method.size() <= (1 << 16));

  std::vector<MethodId> indices(m_id_to_method.size());
  std::iota(indices.begin(), indices.end(), 0);
  workqueue_run<MethodId>(
      [&](MethodId i_id) {
        const auto& code_hash_ids_i = m_method_id_to_code_hash_ids[i_id];
        std::unordered_map<ScoreValue, boost::dynamic_bitset<>> score_map;

        for (uint32_t j_id = 0; j_id < (uint32_t)m_id_to_method.size();
             j_id++) {
          if (i_id == j_id) {
            continue;
          }

          const auto& code_hash_ids_j = m_method_id_to_code_hash_ids[j_id];
          auto score = get_score(code_hash_ids_i, code_hash_ids_j);
          if (score.value() >= 0) {
            auto& method_id_bitset = score_map[score.value()];
            if (method_id_bitset.size() <= j_id) {
              method_id_bitset.resize(j_id + 1);
            }
            method_id_bitset.set(static_cast<size_t>(j_id));
          }
        }

        if (!score_map.empty()) {
          std::map<ScoreValue, boost::dynamic_bitset<>,
                   std::greater<ScoreValue>>
              map;
          // Mapping from score value (key) to Method Ids. The key is in a
          // decreasing score order. Becuase it iterates Method Id in order,
          // the vector is already sorted by Method index (source order).
          for (auto&& [score_value, method_ids] : score_map) {
            map[score_value] = std::move(method_ids);
          }
          m_score_map[i_id] = std::move(map);
        }
      },
      indices);
}

void MethodSimilarityOrderer::insert(DexMethod* method) {
  always_assert(m_method_to_id.count(method) == 0);
  // While the number of methods can reach 65536 (2^16), at
  // this stage not all methods have been added, so we assert that
  // the number can fit on 16 bits and safely be assigned to a MethodId index.
  redex_assert(m_id_to_method.size() < (1 << 16));
  MethodId index = m_id_to_method.size();
  m_id_to_method.emplace(index, method);
  m_method_to_id.emplace(method, index);

  auto& code_hash_ids = m_method_id_to_code_hash_ids[index];
  auto* code = method->get_dex_code();
  if (code) {
    gather_code_hash_ids(code->get_instructions(), code_hash_ids);
  }
}

boost::optional<MethodSimilarityOrderer::MethodId>
MethodSimilarityOrderer::get_next() {
  // Clear best candidates.
  if (m_id_to_method.empty()) {
    return {};
  }

  if (m_last_method_id != boost::none) {
    // Iterate m_score_map from the highest score..
    for (const auto& [score, method_id_bitset] :
         m_score_map[*m_last_method_id]) {
      for (auto meth_id = method_id_bitset.find_first();
           meth_id != boost::dynamic_bitset<>::npos;
           meth_id = method_id_bitset.find_next(meth_id)) {
        // The first match is the one with the highest score
        // at the smallest index in the source order.
        if (m_id_to_method.count(static_cast<MethodId>(meth_id))) {
          TRACE(OPUT, 3,
                "[method-similarity-orderer] selected %s with score %d",
                SHOW(m_id_to_method[static_cast<MethodId>(meth_id)]), score);
          return meth_id;
        }
      }
    }
  }
  boost::optional<MethodId> best_method_id = m_id_to_method.begin()->first;
  TRACE(OPUT,
        3,
        "[method-similarity-orderer] reverted to %s",
        SHOW(*best_method_id));
  return best_method_id;
}

void MethodSimilarityOrderer::remove_method(DexMethod* meth) {
  if (!m_method_to_id.count(meth)) return;

  auto method_id = m_method_to_id[meth];
  m_id_to_method.erase(method_id);
  m_method_to_id.erase(meth);
}

void MethodSimilarityOrderer::order(std::vector<DexMethod*>& methods) {
  Timer t("Reordering methods by similarity");

  for (auto* method : methods) {
    insert(method);
  }

  methods.clear();

  // Compute scores among methods in parallel.
  compute_score();

  m_last_method_id = boost::none;
  for (boost::optional<MethodId> best_method_id = get_next();
       best_method_id != boost::none;
       best_method_id = get_next()) {
    m_last_method_id = best_method_id;
    auto meth = m_id_to_method[*m_last_method_id];
    methods.push_back(meth);
    remove_method(meth);
  }
}
<|endoftext|>


<commit_before>// Time:  O(1)
// Space: O(1)

// Below is the interface for Iterator, which is already defined for you.
// **DO NOT** modify the interface for Iterator.
class Iterator {
    struct Data;
	Data* data;
public:
	Iterator(const vector<int>& nums);
	Iterator(const Iterator& iter);
	virtual ~Iterator();
	// Returns the next element in the iteration.
	int next();
	// Returns true if the iteration has more elements.
	bool hasNext() const;
};

class PeekingIterator : public Iterator {
public:
    PeekingIterator(const vector<int>& nums) : Iterator(nums), has_next_(Iterator::hasNext()) {
        // Initialize any member here.
        // **DO NOT** save a copy of nums and manipulate it directly.
        // You should only use the Iterator interface methods.
    }

    // Returns the next element in the iteration without advancing the iterator.
    int peek() {
        if (!has_peeked_) {
            has_peeked_ = true;
            val_ = Iterator::next();
        }
        return val_;
    }

    // hasNext() and next() should behave the same as in the Iterator interface.
    // Override them if needed.
    int next() {
        val_ = peek();
        has_peeked_ = false;
        has_next_ = Iterator::hasNext();
        return val_;
    }

    bool hasNext() const {
        return has_next_;
    }

private:
    int val_;
    bool has_next_;
    bool has_peeked_ = false;
};
<commit_msg>Update peeking-iterator.cpp<commit_after>// Time:  O(1) per peek(), next(), hasNext()
// Space: O(1)

// Below is the interface for Iterator, which is already defined for you.
// **DO NOT** modify the interface for Iterator.
class Iterator {
    struct Data;
	Data* data;
public:
	Iterator(const vector<int>& nums);
	Iterator(const Iterator& iter);
	virtual ~Iterator();
	// Returns the next element in the iteration.
	int next();
	// Returns true if the iteration has more elements.
	bool hasNext() const;
};

class PeekingIterator : public Iterator {
public:
    PeekingIterator(const vector<int>& nums) : Iterator(nums), has_next_(Iterator::hasNext()) {
        // Initialize any member here.
        // **DO NOT** save a copy of nums and manipulate it directly.
        // You should only use the Iterator interface methods.
    }

    // Returns the next element in the iteration without advancing the iterator.
    int peek() {
        if (!has_peeked_) {
            has_peeked_ = true;
            val_ = Iterator::next();
        }
        return val_;
    }

    // hasNext() and next() should behave the same as in the Iterator interface.
    // Override them if needed.
    int next() {
        val_ = peek();
        has_peeked_ = false;
        has_next_ = Iterator::hasNext();
        return val_;
    }

    bool hasNext() const {
        return has_next_;
    }

private:
    int val_;
    bool has_next_;
    bool has_peeked_ = false;
};
<|endoftext|>


<commit_before>/*
 * ArcEmu MMORPG Server
 * Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
 * Copyright (C) 2008-2009 <http://www.ArcEmu.org/>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "StdAfx.h"

initialiseSingleton( AddonMgr );

//#define DEBUG_PRINT_ADDON_PACKET			// Prints out Received addon packet when char logging in

// hacky key
static uint8 PublicKey[265] = { 0x02, 0x01, 0x01, 0xC3, 0x5B, 0x50, 0x84, 0xB9, 0x3E, 0x32, 0x42, 0x8C, 0xD0, 0xC7, 0x48, 0xFA, 0x0E, 0x5D, 0x54, 0x5A, 0xA3, 0x0E, 0x14, 0xBA, 0x9E, 0x0D, 0xB9, 0x5D, 0x8B, 0xEE, 0xB6, 0x84, 0x93, 0x45, 0x75, 0xFF, 0x31, 0xFE, 0x2F, 0x64, 0x3F, 0x3D, 0x6D, 0x07, 0xD9, 0x44, 0x9B, 0x40, 0x85, 0x59, 0x34, 0x4E, 0x10, 0xE1, 0xE7, 0x43, 0x69, 0xEF, 0x7C, 0x16, 0xFC, 0xB4, 0xED, 0x1B, 0x95, 0x28, 0xA8, 0x23, 0x76, 0x51, 0x31, 0x57, 0x30, 0x2B, 0x79, 0x08, 0x50, 0x10, 0x1C, 0x4A, 0x1A, 0x2C, 0xC8, 0x8B, 0x8F, 0x05, 0x2D, 0x22, 0x3D, 0xDB, 0x5A, 0x24, 0x7A, 0x0F, 0x13, 0x50, 0x37, 0x8F, 0x5A, 0xCC, 0x9E, 0x04, 0x44, 0x0E, 0x87, 0x01, 0xD4, 0xA3, 0x15, 0x94, 0x16, 0x34, 0xC6, 0xC2, 0xC3, 0xFB, 0x49, 0xFE, 0xE1, 0xF9, 0xDA, 0x8C, 0x50, 0x3C, 0xBE, 0x2C, 0xBB, 0x57, 0xED, 0x46, 0xB9, 0xAD, 0x8B, 0xC6, 0xDF, 0x0E, 0xD6, 0x0F, 0xBE, 0x80, 0xB3, 0x8B, 0x1E, 0x77, 0xCF, 0xAD, 0x22, 0xCF, 0xB7, 0x4B, 0xCF, 0xFB, 0xF0, 0x6B, 0x11, 0x45, 0x2D, 0x7A, 0x81, 0x18, 0xF2, 0x92, 0x7E, 0x98, 0x56, 0x5D, 0x5E, 0x69, 0x72, 0x0A, 0x0D, 0x03, 0x0A, 0x85, 0xA2, 0x85, 0x9C, 0xCB, 0xFB, 0x56, 0x6E, 0x8F, 0x44, 0xBB, 0x8F, 0x02, 0x22, 0x68, 0x63, 0x97, 0xBC, 0x85, 0xBA, 0xA8, 0xF7, 0xB5, 0x40, 0x68, 0x3C, 0x77, 0x86, 0x6F, 0x4B, 0xD7, 0x88, 0xCA, 0x8A, 0xD7, 0xCE, 0x36, 0xF0, 0x45, 0x6E, 0xD5, 0x64, 0x79, 0x0F, 0x17, 0xFC, 0x64, 0xDD, 0x10, 0x6F, 0xF3, 0xF5, 0xE0, 0xA6, 0xC3, 0xFB, 0x1B, 0x8C, 0x29, 0xEF, 0x8E, 0xE5, 0x34, 0xCB, 0xD1, 0x2A, 0xCE, 0x79, 0xC3, 0x9A, 0x0D, 0x36, 0xEA, 0x01, 0xE0, 0xAA, 0x91, 0x20, 0x54, 0xF0, 0x72, 0xD8, 0x1E, 0xC7, 0x89, 0xD2, 0x00, 0x00, 0x00, 0x00, 0x00};

AddonMgr::AddonMgr()
{
	KnownAddons.clear();
}

AddonMgr::~AddonMgr()
{
	std::map<std::string, AddonEntry*>::iterator itr;
	for(itr = KnownAddons.begin(); itr!=KnownAddons.end(); ++itr)
	{
		delete itr->second;
	}
	KnownAddons.clear();
}

bool AddonMgr::IsAddonBanned(uint64 crc, std::string name)
{
	return false;	// bleh needs work
}

bool AddonMgr::IsAddonBanned(std::string name, uint64 crc)
{
	std::map<std::string,AddonEntry*>::iterator i = KnownAddons.find(name);
	if(i != KnownAddons.end())
	{
		if(i->second->banned)
		{
			sLog.outDebug("Addon %s is banned.", name.c_str());
			return true;
		}
	}
	else
	{
		// New addon. It'll be saved to db at server shutdown.
		AddonEntry *ent = new AddonEntry;
		ent->name = name;
		ent->crc = crc;
		ent->banned = false;	// by default.. we can change this I guess..
		ent->isNew = true;
		ent->showinlist = true;

		sLog.outDebug("Discovered new addon %s sent by client.", name.c_str());

		KnownAddons[ent->name] = ent;
	}

	return false;
}

bool AddonMgr::ShouldShowInList(std::string name)
{
	std::map<std::string,AddonEntry*>::iterator i = KnownAddons.find(name);
	if(i != KnownAddons.end())
	{
		if(i->second->showinlist)
			return true;
		else
			return false;
	}
	else
	{
		// New addon. It'll be saved to db at server shutdown.
		AddonEntry *ent = new AddonEntry;
		ent->name = name;
		ent->crc = 0;
		ent->banned = false;	// by default.. we can change this I guess..
		ent->isNew = true;
		ent->showinlist = true;

		sLog.outDebug("Discovered new addon %s sent by client.", name.c_str());

		KnownAddons[ent->name] = ent;
	}

	return true;
}

void AddonMgr::SendAddonInfoPacket(WorldPacket *source, uint32 pos, WorldSession *m_session)
{
	WorldPacket returnpacket;
	returnpacket.Initialize(SMSG_ADDON_INFO);	// SMSG_ADDON_INFO

	uint32 realsize;
	uLongf rsize;

	//source->hexlike();

	try
	{
		*source >> realsize;
	}
	catch (ByteBuffer::error &)
	{
		sLog.outDebug("Warning: Incomplete auth session sent.");
		return;
	}
	rsize = realsize;
	size_t position = source->rpos();

	ByteBuffer unpacked;
	unpacked.resize(realsize);

	if((source->size() - position) < 4 || realsize == 0)
	{
		// we shouldnt get here.. but just in case this will stop any crash here.
		sLog.outDebug("Warning: Incomplete auth session sent.");
		return;
	}
	int32 result;
	result = uncompress((uint8*)unpacked.contents(), &rsize, (uint8*)(*source).contents() + position, (uLong)((*source).size() - position));

	if(result != Z_OK)
	{
		sLog.outError("Decompression of addon section of CMSG_AUTH_SESSION failed.");
		return;
	}

	sLog.outDetail("Decompression of addon section of CMSG_AUTH_SESSION succeeded.");

	uint8 Enable; // based on the parsed files from retool
	uint32 crc;
	uint32 unknown;

	std::string name;

	uint32 addoncount;
	unpacked >> addoncount;

	for(uint32 i = 0; i < addoncount; i++)
	{
		unpacked >> name;
		unpacked >> Enable;
		unpacked >> crc;
		unpacked >> unknown;

		// Hacky fix, Yea I know its a hacky fix I will make a proper handler one's I got the crc crap
		if (crc != 0x4C1C776D) // CRC of public key version 2.0.1
			returnpacket.append(PublicKey,264); // part of the hacky fix
		else
			returnpacket << uint8(0x02) << uint8(0x01) << uint8(0x00) << uint32(0) << uint8(0);
		/*if(!AppendPublicKey(returnpacket, name, crc))
			returnpacket << uint8(1) << uint8(0) << uint8(0);*/
	}
	m_session->SendPacket(&returnpacket);
}

bool AddonMgr::AppendPublicKey(WorldPacket& data, string AddonName, uint32 CRC)
{
	if(CRC == 0x4C1C776D)
	{
		// Open public key file with that addon
		map<string, ByteBuffer>::iterator itr = AddonData.find(AddonName);
		if(itr != AddonData.end())
			data.append(itr->second);
		else
		{
			// open the file
			char path[500];
			snprintf(path, 500, "addons\\%s.pub", AddonName.c_str());
			FILE * f = fopen(path, "rb");
			if(f != 0)
			{
				// read the file into a bytebuffer
				ByteBuffer buf;
				fseek(f, 0, SEEK_END);
				uint32 length = 264/*ftell(f)*/;
				fseek(f, 0, SEEK_SET);
				buf.resize(length);
				fread((void*)buf.contents(), length, 1, f);
				fclose(f);

				AddonData[AddonName] = buf;
				data.append(buf);
			}
			else
			{
				ByteBuffer buf;
				buf.append(PublicKey, 264);
				AddonData[AddonName] = buf;
				data.append(buf);
			}
		}
		return true;
	}
	return false;
}

void AddonMgr::LoadFromDB()
{
	QueryResult *result = WorldDatabase.Query("SELECT * FROM clientaddons");
	if(!result)
	{
		sLog.outString("Query failed: SELECT * FROM clientaddons");
		return;
	}

	do
	{
		Field *field = result->Fetch();
		AddonEntry *ent = new AddonEntry;

		ent->name = field[1].GetString();
		ent->crc = field[2].GetUInt64();
		ent->banned = (field[3].GetUInt32()>0? true:false);
		ent->isNew = false;
		if(result->GetFieldCount() == 5)				// To avoid crashes for stilly nubs who don't update table :P
			ent->showinlist = (field[4].GetUInt32()>0 ? true : false);

		KnownAddons[ent->name] = ent;
	} while(result->NextRow());

	delete result;
}

void AddonMgr::SaveToDB()
{
	sLog.outString("AddonMgr: Saving any new addons discovered in this session to database.");
	for(std::map<std::string, AddonEntry*>::iterator itr = KnownAddons.begin();itr!=KnownAddons.end();++itr)
	{
		if(itr->second->isNew)
		{
			sLog.outDetail("Saving new addon %s", itr->second->name.c_str());
			std::stringstream ss;
			ss << "INSERT INTO clientaddons (name, crc, banned, showinlist) VALUES(\""
				<< WorldDatabase.EscapeString(itr->second->name) << "\",\""
				<< itr->second->crc << "\",\""
				<< itr->second->banned << "\",\""
				<< itr->second->showinlist << "\");";

			WorldDatabase.Execute(ss.str().c_str());
		}
	}
}
<commit_msg>- hmm this should not fix the potential problem completely because of the dynamicness of the packet.. this one should be atleast something.<commit_after>/*
 * ArcEmu MMORPG Server
 * Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
 * Copyright (C) 2008-2009 <http://www.ArcEmu.org/>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "StdAfx.h"

initialiseSingleton( AddonMgr );

//#define DEBUG_PRINT_ADDON_PACKET			// Prints out Received addon packet when char logging in

// hacky key
static uint8 PublicKey[265] = { 0x02, 0x01, 0x01, 0xC3, 0x5B, 0x50, 0x84, 0xB9, 0x3E, 0x32, 0x42, 0x8C, 0xD0, 0xC7, 0x48, 0xFA, 0x0E, 0x5D, 0x54, 0x5A, 0xA3, 0x0E, 0x14, 0xBA, 0x9E, 0x0D, 0xB9, 0x5D, 0x8B, 0xEE, 0xB6, 0x84, 0x93, 0x45, 0x75, 0xFF, 0x31, 0xFE, 0x2F, 0x64, 0x3F, 0x3D, 0x6D, 0x07, 0xD9, 0x44, 0x9B, 0x40, 0x85, 0x59, 0x34, 0x4E, 0x10, 0xE1, 0xE7, 0x43, 0x69, 0xEF, 0x7C, 0x16, 0xFC, 0xB4, 0xED, 0x1B, 0x95, 0x28, 0xA8, 0x23, 0x76, 0x51, 0x31, 0x57, 0x30, 0x2B, 0x79, 0x08, 0x50, 0x10, 0x1C, 0x4A, 0x1A, 0x2C, 0xC8, 0x8B, 0x8F, 0x05, 0x2D, 0x22, 0x3D, 0xDB, 0x5A, 0x24, 0x7A, 0x0F, 0x13, 0x50, 0x37, 0x8F, 0x5A, 0xCC, 0x9E, 0x04, 0x44, 0x0E, 0x87, 0x01, 0xD4, 0xA3, 0x15, 0x94, 0x16, 0x34, 0xC6, 0xC2, 0xC3, 0xFB, 0x49, 0xFE, 0xE1, 0xF9, 0xDA, 0x8C, 0x50, 0x3C, 0xBE, 0x2C, 0xBB, 0x57, 0xED, 0x46, 0xB9, 0xAD, 0x8B, 0xC6, 0xDF, 0x0E, 0xD6, 0x0F, 0xBE, 0x80, 0xB3, 0x8B, 0x1E, 0x77, 0xCF, 0xAD, 0x22, 0xCF, 0xB7, 0x4B, 0xCF, 0xFB, 0xF0, 0x6B, 0x11, 0x45, 0x2D, 0x7A, 0x81, 0x18, 0xF2, 0x92, 0x7E, 0x98, 0x56, 0x5D, 0x5E, 0x69, 0x72, 0x0A, 0x0D, 0x03, 0x0A, 0x85, 0xA2, 0x85, 0x9C, 0xCB, 0xFB, 0x56, 0x6E, 0x8F, 0x44, 0xBB, 0x8F, 0x02, 0x22, 0x68, 0x63, 0x97, 0xBC, 0x85, 0xBA, 0xA8, 0xF7, 0xB5, 0x40, 0x68, 0x3C, 0x77, 0x86, 0x6F, 0x4B, 0xD7, 0x88, 0xCA, 0x8A, 0xD7, 0xCE, 0x36, 0xF0, 0x45, 0x6E, 0xD5, 0x64, 0x79, 0x0F, 0x17, 0xFC, 0x64, 0xDD, 0x10, 0x6F, 0xF3, 0xF5, 0xE0, 0xA6, 0xC3, 0xFB, 0x1B, 0x8C, 0x29, 0xEF, 0x8E, 0xE5, 0x34, 0xCB, 0xD1, 0x2A, 0xCE, 0x79, 0xC3, 0x9A, 0x0D, 0x36, 0xEA, 0x01, 0xE0, 0xAA, 0x91, 0x20, 0x54, 0xF0, 0x72, 0xD8, 0x1E, 0xC7, 0x89, 0xD2, 0x00, 0x00, 0x00, 0x00, 0x00};

AddonMgr::AddonMgr()
{
	KnownAddons.clear();
}

AddonMgr::~AddonMgr()
{
	std::map<std::string, AddonEntry*>::iterator itr;
	for(itr = KnownAddons.begin(); itr!=KnownAddons.end(); ++itr)
	{
		delete itr->second;
	}
	KnownAddons.clear();
}

bool AddonMgr::IsAddonBanned(uint64 crc, std::string name)
{
	return false;	// bleh needs work
}

bool AddonMgr::IsAddonBanned(std::string name, uint64 crc)
{
	std::map<std::string,AddonEntry*>::iterator i = KnownAddons.find(name);
	if(i != KnownAddons.end())
	{
		if(i->second->banned)
		{
			sLog.outDebug("Addon %s is banned.", name.c_str());
			return true;
		}
	}
	else
	{
		// New addon. It'll be saved to db at server shutdown.
		AddonEntry *ent = new AddonEntry;
		ent->name = name;
		ent->crc = crc;
		ent->banned = false;	// by default.. we can change this I guess..
		ent->isNew = true;
		ent->showinlist = true;

		sLog.outDebug("Discovered new addon %s sent by client.", name.c_str());

		KnownAddons[ent->name] = ent;
	}

	return false;
}

bool AddonMgr::ShouldShowInList(std::string name)
{
	std::map<std::string,AddonEntry*>::iterator i = KnownAddons.find(name);
	if(i != KnownAddons.end())
	{
		if(i->second->showinlist)
			return true;
		else
			return false;
	}
	else
	{
		// New addon. It'll be saved to db at server shutdown.
		AddonEntry *ent = new AddonEntry;
		ent->name = name;
		ent->crc = 0;
		ent->banned = false;	// by default.. we can change this I guess..
		ent->isNew = true;
		ent->showinlist = true;

		sLog.outDebug("Discovered new addon %s sent by client.", name.c_str());

		KnownAddons[ent->name] = ent;
	}

	return true;
}

void AddonMgr::SendAddonInfoPacket(WorldPacket *source, uint32 pos, WorldSession *m_session)
{
	WorldPacket returnpacket;
	returnpacket.Initialize(SMSG_ADDON_INFO);	// SMSG_ADDON_INFO

	uint32 realsize;
	uLongf rsize;

	//source->hexlike();

	try
	{
		*source >> realsize;
	}
	catch (ByteBuffer::error &)
	{
		sLog.outDebug("Warning: Incomplete auth session sent.");
		return;
	}
	rsize = realsize;
	size_t position = source->rpos();

	ByteBuffer unpacked;
	unpacked.resize(realsize);

	if((source->size() - position) < 4 || realsize == 0)
	{
		// we shouldnt get here.. but just in case this will stop any crash here.
		sLog.outDebug("Warning: Incomplete auth session sent.");
		return;
	}
	int32 result;
	result = uncompress((uint8*)unpacked.contents(), &rsize, (uint8*)(*source).contents() + position, (uLong)((*source).size() - position));

	if(result != Z_OK)
	{
		sLog.outError("Decompression of addon section of CMSG_AUTH_SESSION failed.");
		return;
	}

	sLog.outDetail("Decompression of addon section of CMSG_AUTH_SESSION succeeded.");

	uint8 Enable; // based on the parsed files from retool
	uint32 crc;
	uint32 unknown;

	std::string name;

	uint32 addoncount;
	unpacked >> addoncount;

	for(uint32 i = 0; i < addoncount; i++)
	{
		if(unpacked.rpos() >= unpacked.size())
			break;

		unpacked >> name;
		unpacked >> Enable;
		unpacked >> crc;
		unpacked >> unknown;

		// Hacky fix, Yea I know its a hacky fix I will make a proper handler one's I got the crc crap
		if (crc != 0x4C1C776D) // CRC of public key version 2.0.1
			returnpacket.append(PublicKey,264); // part of the hacky fix
		else
			returnpacket << uint8(0x02) << uint8(0x01) << uint8(0x00) << uint32(0) << uint8(0);
		/*if(!AppendPublicKey(returnpacket, name, crc))
			returnpacket << uint8(1) << uint8(0) << uint8(0);*/
	}
	m_session->SendPacket(&returnpacket);
}

bool AddonMgr::AppendPublicKey(WorldPacket& data, string AddonName, uint32 CRC)
{
	if(CRC == 0x4C1C776D)
	{
		// Open public key file with that addon
		map<string, ByteBuffer>::iterator itr = AddonData.find(AddonName);
		if(itr != AddonData.end())
			data.append(itr->second);
		else
		{
			// open the file
			char path[500];
			snprintf(path, 500, "addons\\%s.pub", AddonName.c_str());
			FILE * f = fopen(path, "rb");
			if(f != 0)
			{
				// read the file into a bytebuffer
				ByteBuffer buf;
				fseek(f, 0, SEEK_END);
				uint32 length = 264/*ftell(f)*/;
				fseek(f, 0, SEEK_SET);
				buf.resize(length);
				fread((void*)buf.contents(), length, 1, f);
				fclose(f);

				AddonData[AddonName] = buf;
				data.append(buf);
			}
			else
			{
				ByteBuffer buf;
				buf.append(PublicKey, 264);
				AddonData[AddonName] = buf;
				data.append(buf);
			}
		}
		return true;
	}
	return false;
}

void AddonMgr::LoadFromDB()
{
	QueryResult *result = WorldDatabase.Query("SELECT * FROM clientaddons");
	if(!result)
	{
		sLog.outString("Query failed: SELECT * FROM clientaddons");
		return;
	}

	do
	{
		Field *field = result->Fetch();
		AddonEntry *ent = new AddonEntry;

		ent->name = field[1].GetString();
		ent->crc = field[2].GetUInt64();
		ent->banned = (field[3].GetUInt32()>0? true:false);
		ent->isNew = false;
		if(result->GetFieldCount() == 5)				// To avoid crashes for stilly nubs who don't update table :P
			ent->showinlist = (field[4].GetUInt32()>0 ? true : false);

		KnownAddons[ent->name] = ent;
	} while(result->NextRow());

	delete result;
}

void AddonMgr::SaveToDB()
{
	sLog.outString("AddonMgr: Saving any new addons discovered in this session to database.");
	for(std::map<std::string, AddonEntry*>::iterator itr = KnownAddons.begin();itr!=KnownAddons.end();++itr)
	{
		if(itr->second->isNew)
		{
			sLog.outDetail("Saving new addon %s", itr->second->name.c_str());
			std::stringstream ss;
			ss << "INSERT INTO clientaddons (name, crc, banned, showinlist) VALUES(\""
				<< WorldDatabase.EscapeString(itr->second->name) << "\",\""
				<< itr->second->crc << "\",\""
				<< itr->second->banned << "\",\""
				<< itr->second->showinlist << "\");";

			WorldDatabase.Execute(ss.str().c_str());
		}
	}
}
<|endoftext|>


<commit_before>/* This file exists to provide some stat monitors for process statistics and the like. */

#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>

#include <vector>

#include "arch/io/io_utils.hpp"
#include "containers/printf_buffer.hpp"
#include "perfmon.hpp"
#include "logger.hpp"
#include "utils.hpp"
#include "thread_local.hpp"

/* Class to represent and parse the contents of /proc/[pid]/stat */

struct proc_pid_stat_exc_t : public std::exception {
    explicit proc_pid_stat_exc_t(const char *format, ...) __attribute__ ((format (printf, 2, 3))) {
        va_list ap;
        va_start(ap, format);
        msg = vstrprintf(format, ap);
        va_end(ap);
    }
    std::string msg;
    const char *what() const throw () {
        return msg.c_str();
    }
    ~proc_pid_stat_exc_t() throw () { }
};

struct proc_pid_stat_t {
    int pid;
    char name[500];
    char state;
    int ppid, pgrp, session, tty_nr, tpgid;
    unsigned int flags;
    uint64_t minflt, cminflt, majflt, cmajflt, utime, stime;
    int64_t cutime, cstime, priority, nice, num_threads, itrealvalue;
    uint64_t starttime;
    uint64_t vsize;
    int64_t rss;
    uint64_t rsslim, startcode, endcode, startstack, kstkesp, kstkeip, signal, blocked,
        sigignore, sigcatch, wchan, nswap, cnswap;
    int exit_signal, processor;
    unsigned int rt_priority, policy;
    uint64_t delayacct_blkio_ticks;
    uint64_t guest_time;
    int64_t cguest_time;

    static proc_pid_stat_t for_pid(pid_t pid) {
        printf_buffer_t<100> path("/proc/%d/stat", pid);
        proc_pid_stat_t stat;
        stat.read_from_file(path.c_str());
        return stat;
    }

    static proc_pid_stat_t for_pid_and_tid(pid_t pid, pid_t tid) {
        printf_buffer_t<100> path("/proc/%d/task/%d/stat", pid, tid);
        proc_pid_stat_t stat;
        stat.read_from_file(path.c_str());
        return stat;
    }

private:
    void read_from_file(const char * path) {
        scoped_fd_t stat_file(open(path, O_RDONLY));
        if (stat_file.get() == INVALID_FD) {
            throw proc_pid_stat_exc_t("Could not open '%s': %s (errno = %d)", path, strerror(errno), errno);
        }

        char buffer[1000];
        int res = ::read(stat_file.get(), buffer, sizeof(buffer));
        if (res <= 0) {
            throw proc_pid_stat_exc_t("Could not read '%s': %s (errno = %d)", path, strerror(errno), errno);
        }

        buffer[res] = '\0';

        const int items_to_parse = 44;
        int res2 = sscanf(buffer, "%d %s %c %d %d %d %d %d %u"
                          " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64
                          " %" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64
                          " %" SCNu64 " %" SCNu64 " %" SCNd64
                          " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64
                          " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64
                          " %d %d"
                          " %u %u"
                          " %" SCNu64
                          " %" SCNu64
                          " %" SCNd64,
                          &pid,
                          name,
                          &state,
                          &ppid, &pgrp, &session, &tty_nr, &tpgid,
                          &flags,
                          &minflt, &cminflt, &majflt, &cmajflt, &utime, &stime,
                          &cutime, &cstime, &priority, &nice, &num_threads, &itrealvalue,
                          &starttime,
                          &vsize,
                          &rss,
                          &rsslim, &startcode, &endcode, &startstack, &kstkesp, &kstkeip, &signal, &blocked,
                          &sigignore, &sigcatch, &wchan, &nswap, &cnswap,
                          &exit_signal, &processor,
                          &rt_priority, &policy,
                          &delayacct_blkio_ticks,
                          &guest_time,
                          &cguest_time);
        if (res2 != items_to_parse) {
            throw proc_pid_stat_exc_t("Could not parse '%s': expected to parse %d items, parsed "
                "%d. Buffer contents: %s", path, items_to_parse, res2, buffer);
        }
    }
};

/* perfmon_system_t is used to monitor system stats that do not need to be polled. */
struct perfmon_system_t : public perfmon_t {
    bool have_reported_error;
    explicit perfmon_system_t(perfmon_collection_t *parent = NULL) : perfmon_t(parent), have_reported_error(false), start_time(time(NULL)) { }

    void *begin_stats() {
        return NULL;
    }
    void visit_stats(void *) {
    }
    void end_stats(void *, perfmon_result_t *dest) {
        put_timestamp(dest);
        dest->insert("version", new perfmon_result_t(std::string(RETHINKDB_VERSION)));
        dest->insert("pid", new perfmon_result_t(strprintf("%d", getpid())));

        proc_pid_stat_t pid_stat;
        try {
            pid_stat = proc_pid_stat_t::for_pid(getpid());
        } catch (proc_pid_stat_exc_t e) {
            if (!have_reported_error) {
                logWRN("Error in reporting system stats: %s (Further errors like this will be suppressed.)", e.what());
                have_reported_error = true;
            }
            return;
        }

        dest->insert("memory_virtual", new perfmon_result_t(strprintf("%lu", pid_stat.vsize)));
        dest->insert("memory_real", new perfmon_result_t(strprintf("%ld", pid_stat.rss * sysconf(_SC_PAGESIZE))));
    }
    void put_timestamp(perfmon_result_t *dest) {
        struct timespec now;
        int res = clock_gettime(CLOCK_REALTIME, &now);
        guarantee_err(res == 0, "clock_gettime(CLOCK_REALTIME) failed");
        dest->insert("uptime", new perfmon_result_t(strprintf("%d", int(difftime(start_time, now.tv_sec)))));
        dest->insert("timestamp", new perfmon_result_t(format_time(now)));
    }

    time_t start_time;
} pm_system;

/* Some of the stats need to be polled periodically. Call this function periodically on each
thread to ensure that stats are up to date. It takes a void* so that it can be called as a timer
callback. */

perfmon_sampler_t
    pm_cpu_user("cpu_user", secs_to_ticks(5), false, NULL),
    pm_cpu_system("cpu_system", secs_to_ticks(5), false, NULL),
    pm_cpu_combined("cpu_combined", secs_to_ticks(5), false, NULL),
    pm_memory_faults("memory_faults", secs_to_ticks(5), false, NULL);

TLS(proc_pid_stat_t, last_stats);
TLS_with_init(ticks_t, last_ticks, 0);
TLS_with_init(bool, have_reported_stats_error, false);

void poll_system_stats(void *) {

    proc_pid_stat_t current_stats;
    try {
        current_stats = proc_pid_stat_t::for_pid_and_tid(getpid(), syscall(SYS_gettid));
    } catch (proc_pid_stat_exc_t e) {
        if (!TLS_get_have_reported_stats_error()) {
            logWRN("Error in reporting per-thread stats: %s (Further errors like this will "
                "be suppressed.)", e.what());
            TLS_set_have_reported_stats_error(true);
        }
    }
    ticks_t current_ticks = get_ticks();

    if (TLS_get_last_ticks() == 0) {
        TLS_set_last_stats(current_stats);
        TLS_set_last_ticks(current_ticks);
    } else if (current_ticks > TLS_get_last_ticks() + secs_to_ticks(1)) {
        double realtime_elapsed = ticks_to_secs(current_ticks - TLS_get_last_ticks()) * sysconf(_SC_CLK_TCK);
        pm_cpu_user.record((current_stats.utime - TLS_get_last_stats().utime) / realtime_elapsed);
        pm_cpu_system.record((current_stats.stime - TLS_get_last_stats().stime) / realtime_elapsed);
        pm_cpu_combined.record(
            (current_stats.utime - TLS_get_last_stats().utime +
             current_stats.stime - TLS_get_last_stats().stime) /
             realtime_elapsed);
        pm_memory_faults.record((current_stats.majflt - TLS_get_last_stats().majflt) / realtime_elapsed);

        TLS_set_last_stats(current_stats);
        TLS_set_last_ticks(current_ticks);
    }
}

<commit_msg>Fixing uptime stat. Tsk tsk tsk.<commit_after>/* This file exists to provide some stat monitors for process statistics and the like. */

#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>

#include <vector>

#include "arch/io/io_utils.hpp"
#include "containers/printf_buffer.hpp"
#include "perfmon.hpp"
#include "logger.hpp"
#include "utils.hpp"
#include "thread_local.hpp"

/* Class to represent and parse the contents of /proc/[pid]/stat */

struct proc_pid_stat_exc_t : public std::exception {
    explicit proc_pid_stat_exc_t(const char *format, ...) __attribute__ ((format (printf, 2, 3))) {
        va_list ap;
        va_start(ap, format);
        msg = vstrprintf(format, ap);
        va_end(ap);
    }
    std::string msg;
    const char *what() const throw () {
        return msg.c_str();
    }
    ~proc_pid_stat_exc_t() throw () { }
};

struct proc_pid_stat_t {
    int pid;
    char name[500];
    char state;
    int ppid, pgrp, session, tty_nr, tpgid;
    unsigned int flags;
    uint64_t minflt, cminflt, majflt, cmajflt, utime, stime;
    int64_t cutime, cstime, priority, nice, num_threads, itrealvalue;
    uint64_t starttime;
    uint64_t vsize;
    int64_t rss;
    uint64_t rsslim, startcode, endcode, startstack, kstkesp, kstkeip, signal, blocked,
        sigignore, sigcatch, wchan, nswap, cnswap;
    int exit_signal, processor;
    unsigned int rt_priority, policy;
    uint64_t delayacct_blkio_ticks;
    uint64_t guest_time;
    int64_t cguest_time;

    static proc_pid_stat_t for_pid(pid_t pid) {
        printf_buffer_t<100> path("/proc/%d/stat", pid);
        proc_pid_stat_t stat;
        stat.read_from_file(path.c_str());
        return stat;
    }

    static proc_pid_stat_t for_pid_and_tid(pid_t pid, pid_t tid) {
        printf_buffer_t<100> path("/proc/%d/task/%d/stat", pid, tid);
        proc_pid_stat_t stat;
        stat.read_from_file(path.c_str());
        return stat;
    }

private:
    void read_from_file(const char * path) {
        scoped_fd_t stat_file(open(path, O_RDONLY));
        if (stat_file.get() == INVALID_FD) {
            throw proc_pid_stat_exc_t("Could not open '%s': %s (errno = %d)", path, strerror(errno), errno);
        }

        char buffer[1000];
        int res = ::read(stat_file.get(), buffer, sizeof(buffer));
        if (res <= 0) {
            throw proc_pid_stat_exc_t("Could not read '%s': %s (errno = %d)", path, strerror(errno), errno);
        }

        buffer[res] = '\0';

        const int items_to_parse = 44;
        int res2 = sscanf(buffer, "%d %s %c %d %d %d %d %d %u"
                          " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64
                          " %" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64
                          " %" SCNu64 " %" SCNu64 " %" SCNd64
                          " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64
                          " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64
                          " %d %d"
                          " %u %u"
                          " %" SCNu64
                          " %" SCNu64
                          " %" SCNd64,
                          &pid,
                          name,
                          &state,
                          &ppid, &pgrp, &session, &tty_nr, &tpgid,
                          &flags,
                          &minflt, &cminflt, &majflt, &cmajflt, &utime, &stime,
                          &cutime, &cstime, &priority, &nice, &num_threads, &itrealvalue,
                          &starttime,
                          &vsize,
                          &rss,
                          &rsslim, &startcode, &endcode, &startstack, &kstkesp, &kstkeip, &signal, &blocked,
                          &sigignore, &sigcatch, &wchan, &nswap, &cnswap,
                          &exit_signal, &processor,
                          &rt_priority, &policy,
                          &delayacct_blkio_ticks,
                          &guest_time,
                          &cguest_time);
        if (res2 != items_to_parse) {
            throw proc_pid_stat_exc_t("Could not parse '%s': expected to parse %d items, parsed "
                "%d. Buffer contents: %s", path, items_to_parse, res2, buffer);
        }
    }
};

/* perfmon_system_t is used to monitor system stats that do not need to be polled. */
struct perfmon_system_t : public perfmon_t {
    bool have_reported_error;
    explicit perfmon_system_t(perfmon_collection_t *parent = NULL) : perfmon_t(parent), have_reported_error(false) {
        struct timespec now;
        int res = clock_gettime(CLOCK_MONOTONIC, &now);
        guarantee_err(res == 0, "clock_gettime(CLOCK_MONOTONIC) failed");
        start_time = now.tv_sec;
    }

    void *begin_stats() {
        return NULL;
    }
    void visit_stats(void *) {
    }
    void end_stats(void *, perfmon_result_t *dest) {
        put_timestamp(dest);
        dest->insert("version", new perfmon_result_t(std::string(RETHINKDB_VERSION)));
        dest->insert("pid", new perfmon_result_t(strprintf("%d", getpid())));

        proc_pid_stat_t pid_stat;
        try {
            pid_stat = proc_pid_stat_t::for_pid(getpid());
        } catch (proc_pid_stat_exc_t e) {
            if (!have_reported_error) {
                logWRN("Error in reporting system stats: %s (Further errors like this will be suppressed.)", e.what());
                have_reported_error = true;
            }
            return;
        }

        dest->insert("memory_virtual", new perfmon_result_t(strprintf("%lu", pid_stat.vsize)));
        dest->insert("memory_real", new perfmon_result_t(strprintf("%ld", pid_stat.rss * sysconf(_SC_PAGESIZE))));
    }
    void put_timestamp(perfmon_result_t *dest) {
        struct timespec now;
        int res = clock_gettime(CLOCK_MONOTONIC, &now);
        guarantee_err(res == 0, "clock_gettime(CLOCK_MONOTONIC) failed");
        dest->insert("uptime", new perfmon_result_t(strprintf("%ld", now.tv_sec - start_time)));
        dest->insert("timestamp", new perfmon_result_t(format_time(now)));
    }

    long start_time;
} pm_system;

/* Some of the stats need to be polled periodically. Call this function periodically on each
thread to ensure that stats are up to date. It takes a void* so that it can be called as a timer
callback. */

perfmon_sampler_t
    pm_cpu_user("cpu_user", secs_to_ticks(5), false, NULL),
    pm_cpu_system("cpu_system", secs_to_ticks(5), false, NULL),
    pm_cpu_combined("cpu_combined", secs_to_ticks(5), false, NULL),
    pm_memory_faults("memory_faults", secs_to_ticks(5), false, NULL);

TLS(proc_pid_stat_t, last_stats);
TLS_with_init(ticks_t, last_ticks, 0);
TLS_with_init(bool, have_reported_stats_error, false);

void poll_system_stats(void *) {

    proc_pid_stat_t current_stats;
    try {
        current_stats = proc_pid_stat_t::for_pid_and_tid(getpid(), syscall(SYS_gettid));
    } catch (proc_pid_stat_exc_t e) {
        if (!TLS_get_have_reported_stats_error()) {
            logWRN("Error in reporting per-thread stats: %s (Further errors like this will "
                "be suppressed.)", e.what());
            TLS_set_have_reported_stats_error(true);
        }
    }
    ticks_t current_ticks = get_ticks();

    if (TLS_get_last_ticks() == 0) {
        TLS_set_last_stats(current_stats);
        TLS_set_last_ticks(current_ticks);
    } else if (current_ticks > TLS_get_last_ticks() + secs_to_ticks(1)) {
        double realtime_elapsed = ticks_to_secs(current_ticks - TLS_get_last_ticks()) * sysconf(_SC_CLK_TCK);
        pm_cpu_user.record((current_stats.utime - TLS_get_last_stats().utime) / realtime_elapsed);
        pm_cpu_system.record((current_stats.stime - TLS_get_last_stats().stime) / realtime_elapsed);
        pm_cpu_combined.record(
            (current_stats.utime - TLS_get_last_stats().utime +
             current_stats.stime - TLS_get_last_stats().stime) /
             realtime_elapsed);
        pm_memory_faults.record((current_stats.majflt - TLS_get_last_stats().majflt) / realtime_elapsed);

        TLS_set_last_stats(current_stats);
        TLS_set_last_ticks(current_ticks);
    }
}

<|endoftext|>


<commit_before>// Copyright (c) 2013, Matthew Harvey. All rights reserved.

#include "transaction_type_ctrl.hpp"
#include "b_string.hpp"
#include "string_set_validator.hpp"
#include "transaction_ctrl.hpp"
#include "transaction_type.hpp"
#include <boost/optional.hpp>
#include <jewel/optional.hpp>
#include <wx/arrstr.h>
#include <wx/combobox.h>
#include <wx/gdicmn.h>
#include <wx/window.h>
#include <wx/windowid.h>
#include <vector>

using boost::optional;
using jewel::value;
using std::vector;

// For debugging
	#include <jewel/debug_log.hpp>
	#include <iostream>
	using std::endl;

namespace phatbooks
{

using transaction_type::num_transaction_types;
using transaction_type::TransactionType;

namespace gui
{

BEGIN_EVENT_TABLE(TransactionTypeCtrl, wxComboBox)
	EVT_KILL_FOCUS
	(	TransactionTypeCtrl::on_kill_focus
	)
	EVT_COMBOBOX
	(	wxID_ANY,
		TransactionTypeCtrl::on_change
	)
END_EVENT_TABLE()

TransactionTypeCtrl::TransactionTypeCtrl
(	wxWindow* p_parent,
	wxWindowID p_id,
	wxSize const& p_size
):
	wxComboBox
	(	p_parent,
		p_id,
		bstring_to_wx
		(	transaction_type_to_verb(static_cast<TransactionType>(0))
		),
		wxDefaultPosition,
		p_size,
		wxArrayString()
		//, wxCB_READONLY
	)
{
	wxArrayString transaction_type_verbs;
	assert (transaction_type_verbs.IsEmpty());
	vector<TransactionType> const tt = transaction_types();
	vector<TransactionType>::const_iterator it = tt.begin();
	vector<TransactionType>::const_iterator const end = tt.end();
	for ( ; it != end; ++it)
	{
		wxString const verb = bstring_to_wx
		(	transaction_type_to_verb(*it)
		);
		transaction_type_verbs.Add(verb);  // remember as valid name
		Append(verb);  // add to combobox
	}
	StringSetValidator validator
	(	GetValue(),
		transaction_type_verbs,
		"transaction type"
	);
	SetValidator(validator);
	SetSelection(0);  // In effort to avoid apparent bug in Windows.
	// TODO AutoComplete is irrelevant if we have the wxComboBox as readonly.
	// But we still might want to let the user select by just typing the first
	// letter or something.
	AutoComplete(transaction_type_verbs);
}

optional<transaction_type::TransactionType>
TransactionTypeCtrl::transaction_type() const
{
	optional<transaction_type::TransactionType> ret;
	int const selection = GetSelection();
	if (selection < 0)
	{
		return ret;
	}
	transaction_type::TransactionType const ttype =
		static_cast<transaction_type::TransactionType>(selection);
	assert_transaction_type_validity(ttype);
	ret = ttype;
	return ret;
}

void
TransactionTypeCtrl::set_transaction_type
(	transaction_type::TransactionType p_transaction_type
)
{
	SetSelection(static_cast<int>(p_transaction_type));
	return;
}

void
TransactionTypeCtrl::on_kill_focus(wxFocusEvent& event)
{
	// TODO Make a class from which we can privately inherit, to capture
	// this on_kill_focus behaviour, which is shared by several custom
	// widget classes in phatbooks::gui.

	// Unfortunately if we call Validate() and TransferDataToWindow()
	// directly on the AccountCtrl, it doesn't work. We have to call
	// through parent instead.
	GetParent()->Validate();
	GetParent()->TransferDataToWindow();
	event.Skip();
	return;
}

void
TransactionTypeCtrl::on_change(wxCommandEvent& event)
{
	(void)event;  // silence compiler re. unused param.
	TransactionCtrl* parent = dynamic_cast<TransactionCtrl*>(GetParent());
	assert(parent);
	optional<transaction_type::TransactionType> const maybe_ttype =
		transaction_type();
	if (!maybe_ttype)
	{
		return;
	}
	assert_transaction_type_validity(value(maybe_ttype));
	parent->refresh_for_transaction_type(value(maybe_ttype));
	return;
}

}  // namespace gui
}  // namespace phatbooks
<commit_msg>Made TransactionTypeCtrl read-only. This avoids having to handle EVT_TEXT events which are not EVT_COMBOBOX events. (Handling EVT_TEXT in this context has proven to be a problematic exercise.)<commit_after>// Copyright (c) 2013, Matthew Harvey. All rights reserved.

#include "transaction_type_ctrl.hpp"
#include "b_string.hpp"
#include "string_set_validator.hpp"
#include "transaction_ctrl.hpp"
#include "transaction_type.hpp"
#include <boost/optional.hpp>
#include <jewel/optional.hpp>
#include <wx/arrstr.h>
#include <wx/combobox.h>
#include <wx/gdicmn.h>
#include <wx/window.h>
#include <wx/windowid.h>
#include <vector>

using boost::optional;
using jewel::value;
using std::vector;

// For debugging
	#include <jewel/debug_log.hpp>
	#include <iostream>
	using std::endl;

namespace phatbooks
{

using transaction_type::num_transaction_types;
using transaction_type::TransactionType;

namespace gui
{

BEGIN_EVENT_TABLE(TransactionTypeCtrl, wxComboBox)
	EVT_KILL_FOCUS
	(	TransactionTypeCtrl::on_kill_focus
	)
	EVT_COMBOBOX
	(	wxID_ANY,
		TransactionTypeCtrl::on_change
	)
END_EVENT_TABLE()

TransactionTypeCtrl::TransactionTypeCtrl
(	wxWindow* p_parent,
	wxWindowID p_id,
	wxSize const& p_size
):
	wxComboBox
	(	p_parent,
		p_id,
		bstring_to_wx
		(	transaction_type_to_verb(static_cast<TransactionType>(0))
		),
		wxDefaultPosition,
		p_size,
		wxArrayString(),
		wxCB_READONLY
	)
{
	wxArrayString transaction_type_verbs;
	assert (transaction_type_verbs.IsEmpty());
	vector<TransactionType> const tt = transaction_types();
	vector<TransactionType>::const_iterator it = tt.begin();
	vector<TransactionType>::const_iterator const end = tt.end();
	for ( ; it != end; ++it)
	{
		wxString const verb = bstring_to_wx
		(	transaction_type_to_verb(*it)
		);
		transaction_type_verbs.Add(verb);  // remember as valid name
		Append(verb);  // add to combobox
	}
	StringSetValidator validator
	(	GetValue(),
		transaction_type_verbs,
		"transaction type"
	);
	SetValidator(validator);
	SetSelection(0);  // In effort to avoid apparent bug in Windows.
	// TODO AutoComplete is irrelevant if we have the wxComboBox as readonly.
	// But we still might want to let the user select by just typing the first
	// letter or something.
	AutoComplete(transaction_type_verbs);
}

optional<transaction_type::TransactionType>
TransactionTypeCtrl::transaction_type() const
{
	optional<transaction_type::TransactionType> ret;
	int const selection = GetSelection();
	if (selection < 0)
	{
		return ret;
	}
	transaction_type::TransactionType const ttype =
		static_cast<transaction_type::TransactionType>(selection);
	assert_transaction_type_validity(ttype);
	ret = ttype;
	return ret;
}

void
TransactionTypeCtrl::set_transaction_type
(	transaction_type::TransactionType p_transaction_type
)
{
	SetSelection(static_cast<int>(p_transaction_type));
	return;
}

void
TransactionTypeCtrl::on_kill_focus(wxFocusEvent& event)
{
	// TODO Make a class from which we can privately inherit, to capture
	// this on_kill_focus behaviour, which is shared by several custom
	// widget classes in phatbooks::gui.

	// Unfortunately if we call Validate() and TransferDataToWindow()
	// directly on the AccountCtrl, it doesn't work. We have to call
	// through parent instead.
	GetParent()->Validate();
	GetParent()->TransferDataToWindow();
	event.Skip();
	return;
}

void
TransactionTypeCtrl::on_change(wxCommandEvent& event)
{
	(void)event;  // silence compiler re. unused param.
	TransactionCtrl* parent = dynamic_cast<TransactionCtrl*>(GetParent());
	assert(parent);
	optional<transaction_type::TransactionType> const maybe_ttype =
		transaction_type();
	if (!maybe_ttype)
	{
		return;
	}
	assert_transaction_type_validity(value(maybe_ttype));
	parent->refresh_for_transaction_type(value(maybe_ttype));
	return;
}

}  // namespace gui
}  // namespace phatbooks
<|endoftext|>