<commit_before>#ifndef NFL_GMP_HPP
#define NFL_GMP_HPP

#include <vector>
#include "nfl/poly.hpp"

namespace nfl {

template <class T, size_t Degree, size_t NbModuli>
typename poly<T, Degree, NbModuli>::GMP poly<T, Degree, NbModuli>::gmp;

/*
 * Constructors
 */
template <class T, size_t Degree, size_t NbModuli>
poly<T, Degree, NbModuli>::poly(mpz_t const& v) {
  set_mpz(v);
}

template <class T, size_t Degree, size_t NbModuli>
poly<T, Degree, NbModuli>::poly(mpz_class const& v) {
  set_mpz({v}, (size_t)1);
}

template <class T, size_t Degree, size_t NbModuli>
poly<T, Degree, NbModuli>::poly(std::initializer_list<mpz_class> const& values, size_t length) {
  set_mpz(values, length);
}

template <class T, size_t Degree, size_t NbModuli>
poly<T, Degree, NbModuli>::poly(mpz_t* const& values, size_t length) {
  set_mpz(values, length);
}

template <class T, size_t Degree, size_t NbModuli>
poly<T, Degree, NbModuli>::poly(mpz_class* const& values, size_t length) {
  set_mpz(values, length);
}

template <class T, size_t Degree, size_t NbModuli>
void poly<T, Degree, NbModuli>::set_mpz(mpz_t const& v) {
  set_mpz({mpz_class(v)}, (size_t)1);
}

template <class T, size_t Degree, size_t NbModuli>
void poly<T, Degree, NbModuli>::set_mpz(mpz_class const& v) {
  set_mpz({v}, (size_t)1);
}

/*
 * set_mpz's functions
 */
template <class T, size_t Degree, size_t NbModuli>
void poly<T, Degree, NbModuli>::set_mpz(mpz_t* const& values, size_t length) {
  std::vector<mpz_class> v;
  for (size_t i = 0; i < length; i++) {
    v.push_back(mpz_class(values[i]));
  }
  set_mpz(v.begin(), v.end(), length);
}

template <class T, size_t Degree, size_t NbModuli>
void poly<T, Degree, NbModuli>::set_mpz(mpz_class* const& values, size_t length) {
  std::vector<mpz_class> v;
  for (size_t i = 0; i < length; i++) {
    v.push_back(values[i]);
  }
  set_mpz(v.begin(), v.end(), length);
}

template <class T, size_t Degree, size_t NbModuli>
void poly<T, Degree, NbModuli>::set_mpz(
    std::initializer_list<mpz_class> const& values, size_t length) {
  set_mpz(values.begin(), values.end(), length);
}

template <class T, size_t Degree, size_t NbModuli>
template <class It>
void poly<T, Degree, NbModuli>::set_mpz(It first, It last, size_t length) {
  // CRITICAL: the object must be 32-bytes aligned to avoid vectorization issues
  assert((unsigned long)(this->_data) % 32 == 0);

  auto* iter = begin();
  auto viter = first;

  size_t size = (!length) ? std::distance(first, last) : length;
  // If the initializer has no more values than the polynomial degree use them
  // to initialize the associated coefficients for each sub-modulus
  if (size <= degree || size == degree * nmoduli) {
    for (size_t cm = 0; cm < nmoduli; ++cm) {
      viter = (size != degree * nmoduli) ? first : viter;

      for (size_t i = 0; i < degree; i++) {
        if (viter < last) {
          *iter++ = mpz_fdiv_ui(viter->get_mpz_t(), params<T>::P[cm]);
          viter++;
        } else
          *iter++ = 0;
      }
    }
  } else {
    throw std::runtime_error(
        "gmp: CRITICAL, initializer of size above degree but different "
        "from nmoduli*degree");
  }
}

template <class T, size_t Degree, size_t NbModuli>
poly<T, Degree, NbModuli>::GMP::GMP() {
  // Compute product of moduli
  mpz_init_set_ui(moduli_product, 1);
  for (size_t i = 0; i < nmoduli; i++) {
    mpz_mul_ui(moduli_product, moduli_product, params<T>::P[i]);
  }

  bits_in_moduli_product = mpz_sizeinbase(moduli_product, 2);

  // Compute Shoup value for optimized reduction modulo "moduli_product"
  mpz_t one;
  mpz_init_set_ui(one, 1);
  mpz_init(modulus_shoup);
  mpz_mul_2exp(modulus_shoup, one, bits_in_moduli_product +
                                       sizeof(T) * CHAR_BIT +
                                       params<T>::logkMaxNbModuli + 1);
  mpz_tdiv_q(modulus_shoup, modulus_shoup, moduli_product);

  // Compute the lifting coefficients
  mpz_t quotient;
  mpz_init(quotient);
  lifting_integers = (mpz_t*)malloc(nmoduli * sizeof(mpz_t));

  for (size_t i = 0; i < nmoduli; i++) {
    // Current modulus
    mpz_t current_modulus;
    mpz_init_set_ui(current_modulus, params<T>::P[i]);

    // compute the product of primes except the current one
    mpz_divexact(quotient, moduli_product, current_modulus);

    // Compute the inverse of the product
    mpz_init(lifting_integers[i]);
    mpz_invert(lifting_integers[i], quotient, current_modulus);

    // Multiply by the quotient
    mpz_mul(lifting_integers[i], lifting_integers[i], quotient);
    mpz_clear(current_modulus);
  }

  // Clear
  mpz_clear(one);
  mpz_clear(quotient);
}

template <class T, size_t Degree, size_t NbModuli>
poly<T, Degree, NbModuli>::GMP::~GMP() {
  for (size_t i = 0; i < nmoduli; i++) {
    mpz_clear(lifting_integers[i]);
  }
  free(lifting_integers);
  mpz_clear(modulus_shoup);
  mpz_clear(moduli_product);
}

/**
 * Functions to convert a poly into an array of mpz_t, and back
 *
 * The mpz_t array is allocated with new[]
 */

template <class T, size_t Degree, size_t NbModuli>
mpz_t* poly<T, Degree, NbModuli>::GMP::poly2mpz(poly const& op) {
  // Assign and init
  mpz_t* poly_mpz = new mpz_t[degree];
  for (size_t i = 0; i < degree; i++) {
    mpz_init(poly_mpz[i]);
  }

  // Fill
  poly2mpz(poly_mpz, op);

  return poly_mpz;
}

template <class T, size_t Degree, size_t NbModuli>
void poly<T, Degree, NbModuli>::GMP::poly2mpz(mpz_t* rop, poly const& op) {
  mpz_t tmp;
  mpz_init2(tmp, (bits_in_moduli_product << 2));
  for (size_t i = 0; i < degree; i++) {
    mpz_set_ui(rop[i], 0);
    for (size_t cm = 0; cm < nmoduli; cm++) {
      if (op(cm, i) != 0) {
        mpz_mul_ui(tmp, lifting_integers[cm], op(cm, i));
      }
      mpz_add(rop[i], rop[i], tmp);
    }
    // Modular reduction using Shoup
    mpz_mul(tmp, rop[i], modulus_shoup);
    mpz_tdiv_q_2exp(tmp, tmp, bits_in_moduli_product + sizeof(T) * CHAR_BIT +
                                  params<T>::logkMaxNbModuli + 1);
    mpz_mul(tmp, tmp, moduli_product);
    mpz_sub(rop[i], rop[i], tmp);
    if (mpz_cmp(rop[i], moduli_product) >= 0) {
      mpz_sub(rop[i], rop[i], moduli_product);
    }
  }
  mpz_clear(tmp);
}

template <class T, size_t Degree, size_t NbModuli>
void poly<T, Degree, NbModuli>::GMP::mpz2poly(poly<T, Degree, NbModuli>& rop,
                                              mpz_t* const& poly_mpz) {
  for (size_t cm = 0; cm < nmoduli; cm++) {
    for (size_t i = 0; i < degree; i++) {
      rop(cm, i) = mpz_fdiv_ui(poly_mpz[i], params<T>::P[cm]);
    }
  }
}
}

#endif<commit_msg>Minor modification of initialization of vectors<commit_after>#ifndef NFL_GMP_HPP
#define NFL_GMP_HPP

#include <vector>
#include "nfl/poly.hpp"

namespace nfl {

template <class T, size_t Degree, size_t NbModuli>
typename poly<T, Degree, NbModuli>::GMP poly<T, Degree, NbModuli>::gmp;

/*
 * Constructors
 */
template <class T, size_t Degree, size_t NbModuli>
poly<T, Degree, NbModuli>::poly(mpz_t const& v) {
  set_mpz(v);
}

template <class T, size_t Degree, size_t NbModuli>
poly<T, Degree, NbModuli>::poly(mpz_class const& v) {
  set_mpz({v}, (size_t)1);
}

template <class T, size_t Degree, size_t NbModuli>
poly<T, Degree, NbModuli>::poly(std::initializer_list<mpz_class> const& values, size_t length) {
  set_mpz(values, length);
}

template <class T, size_t Degree, size_t NbModuli>
poly<T, Degree, NbModuli>::poly(mpz_t* const& values, size_t length) {
  set_mpz(values, length);
}

template <class T, size_t Degree, size_t NbModuli>
poly<T, Degree, NbModuli>::poly(mpz_class* const& values, size_t length) {
  set_mpz(values, length);
}

template <class T, size_t Degree, size_t NbModuli>
void poly<T, Degree, NbModuli>::set_mpz(mpz_t const& v) {
  set_mpz({mpz_class(v)}, (size_t)1);
}

template <class T, size_t Degree, size_t NbModuli>
void poly<T, Degree, NbModuli>::set_mpz(mpz_class const& v) {
  set_mpz({v}, (size_t)1);
}

/*
 * set_mpz's functions
 */
template <class T, size_t Degree, size_t NbModuli>
void poly<T, Degree, NbModuli>::set_mpz(mpz_t* const& values, size_t length) {
  std::vector<mpz_class> v(length);
  for (size_t i = 0; i < length; i++) {
    v[i] = values[i];
  }
  set_mpz(v.begin(), v.end(), length);
}

template <class T, size_t Degree, size_t NbModuli>
void poly<T, Degree, NbModuli>::set_mpz(mpz_class* const& values, size_t length) {
  std::vector<mpz_class> v(length);
  for (size_t i = 0; i < length; i++) {
    v[i] = values[i];
  }
  set_mpz(v.begin(), v.end(), length);
}

template <class T, size_t Degree, size_t NbModuli>
void poly<T, Degree, NbModuli>::set_mpz(
    std::initializer_list<mpz_class> const& values, size_t length) {
  set_mpz(values.begin(), values.end(), length);
}

template <class T, size_t Degree, size_t NbModuli>
template <class It>
void poly<T, Degree, NbModuli>::set_mpz(It first, It last, size_t length) {
  // CRITICAL: the object must be 32-bytes aligned to avoid vectorization issues
  assert((unsigned long)(this->_data) % 32 == 0);

  auto* iter = begin();
  auto viter = first;

  size_t size = (!length) ? std::distance(first, last) : length;
  // If the initializer has no more values than the polynomial degree use them
  // to initialize the associated coefficients for each sub-modulus
  if (size <= degree || size == degree * nmoduli) {
    for (size_t cm = 0; cm < nmoduli; ++cm) {
      viter = (size != degree * nmoduli) ? first : viter;

      for (size_t i = 0; i < degree; i++) {
        if (viter < last) {
          *iter++ = mpz_fdiv_ui(viter->get_mpz_t(), params<T>::P[cm]);
          viter++;
        } else
          *iter++ = 0;
      }
    }
  } else {
    throw std::runtime_error(
        "gmp: CRITICAL, initializer of size above degree but different "
        "from nmoduli*degree");
  }
}

template <class T, size_t Degree, size_t NbModuli>
poly<T, Degree, NbModuli>::GMP::GMP() {
  // Compute product of moduli
  mpz_init_set_ui(moduli_product, 1);
  for (size_t i = 0; i < nmoduli; i++) {
    mpz_mul_ui(moduli_product, moduli_product, params<T>::P[i]);
  }

  bits_in_moduli_product = mpz_sizeinbase(moduli_product, 2);

  // Compute Shoup value for optimized reduction modulo "moduli_product"
  mpz_t one;
  mpz_init_set_ui(one, 1);
  mpz_init(modulus_shoup);
  mpz_mul_2exp(modulus_shoup, one, bits_in_moduli_product +
                                       sizeof(T) * CHAR_BIT +
                                       params<T>::logkMaxNbModuli + 1);
  mpz_tdiv_q(modulus_shoup, modulus_shoup, moduli_product);

  // Compute the lifting coefficients
  mpz_t quotient;
  mpz_init(quotient);
  lifting_integers = (mpz_t*)malloc(nmoduli * sizeof(mpz_t));

  for (size_t i = 0; i < nmoduli; i++) {
    // Current modulus
    mpz_t current_modulus;
    mpz_init_set_ui(current_modulus, params<T>::P[i]);

    // compute the product of primes except the current one
    mpz_divexact(quotient, moduli_product, current_modulus);

    // Compute the inverse of the product
    mpz_init(lifting_integers[i]);
    mpz_invert(lifting_integers[i], quotient, current_modulus);

    // Multiply by the quotient
    mpz_mul(lifting_integers[i], lifting_integers[i], quotient);
    mpz_clear(current_modulus);
  }

  // Clear
  mpz_clear(one);
  mpz_clear(quotient);
}

template <class T, size_t Degree, size_t NbModuli>
poly<T, Degree, NbModuli>::GMP::~GMP() {
  for (size_t i = 0; i < nmoduli; i++) {
    mpz_clear(lifting_integers[i]);
  }
  free(lifting_integers);
  mpz_clear(modulus_shoup);
  mpz_clear(moduli_product);
}

/**
 * Functions to convert a poly into an array of mpz_t, and back
 *
 * The mpz_t array is allocated with new[]
 */

template <class T, size_t Degree, size_t NbModuli>
mpz_t* poly<T, Degree, NbModuli>::GMP::poly2mpz(poly const& op) {
  // Assign and init
  mpz_t* poly_mpz = new mpz_t[degree];
  for (size_t i = 0; i < degree; i++) {
    mpz_init(poly_mpz[i]);
  }

  // Fill
  poly2mpz(poly_mpz, op);

  return poly_mpz;
}

template <class T, size_t Degree, size_t NbModuli>
void poly<T, Degree, NbModuli>::GMP::poly2mpz(mpz_t* rop, poly const& op) {
  mpz_t tmp;
  mpz_init2(tmp, (bits_in_moduli_product << 2));
  for (size_t i = 0; i < degree; i++) {
    mpz_set_ui(rop[i], 0);
    for (size_t cm = 0; cm < nmoduli; cm++) {
      if (op(cm, i) != 0) {
        mpz_mul_ui(tmp, lifting_integers[cm], op(cm, i));
      }
      mpz_add(rop[i], rop[i], tmp);
    }
    // Modular reduction using Shoup
    mpz_mul(tmp, rop[i], modulus_shoup);
    mpz_tdiv_q_2exp(tmp, tmp, bits_in_moduli_product + sizeof(T) * CHAR_BIT +
                                  params<T>::logkMaxNbModuli + 1);
    mpz_mul(tmp, tmp, moduli_product);
    mpz_sub(rop[i], rop[i], tmp);
    if (mpz_cmp(rop[i], moduli_product) >= 0) {
      mpz_sub(rop[i], rop[i], moduli_product);
    }
  }
  mpz_clear(tmp);
}

template <class T, size_t Degree, size_t NbModuli>
void poly<T, Degree, NbModuli>::GMP::mpz2poly(poly<T, Degree, NbModuli>& rop,
                                              mpz_t* const& poly_mpz) {
  for (size_t cm = 0; cm < nmoduli; cm++) {
    for (size_t i = 0; i < degree; i++) {
      rop(cm, i) = mpz_fdiv_ui(poly_mpz[i], params<T>::P[cm]);
    }
  }
}
}

#endif<|endoftext|>


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

#include "FassDb.h"
#include "FassLog.h"

#include <fstream>
#include <sstream>
#include <stdexcept>
#include <unistd.h>
#include <iostream>
#include <istream>
#include <ostream>
#include <string>

#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>

using boost::asio::ip::tcp;
using namespace std;

bool InfluxDb::init_db(){

    ostringstream oss;
    oss << "Initializing database \"" << _dbname << "\" at http://" << _endpoint << ":" << _port;
    FassLog::log("INFLUXDB", Log::INFO, oss);

    string response;
    bool rc;

    // ping endpoint
    rc = InfluxDb::ping_db();
    if ( !rc ) {
    	FassLog::log("INFLUXDB", Log::ERROR, "Could not ping DB!");
        return false;
    }
    // create a new database, the action has no effect if the database already exists
    rc = InfluxDb::create_db();
    if ( !rc ) {
    	FassLog::log("INFLUXDB", Log::ERROR, "Error creating database!");
    }

    return true;
}

bool InfluxDb::query_db(string method, string q, string &retval){

    // for the time being we let it hardcoded
    const string protocol("HTTP/1.0");
    //FassLog::log("SARA", Log::INFO, "Starting query");

    try{
       // Taken form an example in the boost documentation
       boost::asio::io_service io_service;

       // Get a list of endpoints corresponding to the server name
       tcp::resolver resolver(io_service);
       tcp::resolver::query query(_endpoint, boost::lexical_cast<string>(_port));
       tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

       // Try each endpoint until we successfully establish a connection
       tcp::socket socket(io_service);
       boost::asio::connect(socket, endpoint_iterator);

       // Form the request. We specify the "Connection: close" header so that the
       // server will close the socket after transmitting the response. This will
       // allow us to treat all data up until the EOF as the content
       boost::asio::streambuf request;
       std::ostream request_stream(&request);
       //request_stream << "GET " << "/ping" << " HTTP/1.0\r\n";
       //request_stream << method << " " << "/ping" << " HTTP/1.0\r\n";
       //string search = "show%20databases";
       //request_stream << method << " " << "/query?pretty=true&db=" << _dbname << "&q=" << search << " " << protocol << "\r\n";
       request_stream << method << " " << q << " " << protocol << "\r\n";
       request_stream << "Host: " << _endpoint << "\r\n";
       request_stream << "Accept: */*\r\n";
       request_stream << "Content-Type: application/x-www-form-urlencoded\r\n";
       request_stream << "Connection: close\r\n\r\n";

       // Send the request
       boost::asio::write(socket, request);

       // Read the response status line. The response streambuf will automatically
       // grow to accommodate the entire line. The growth may be limited by passing
       // a maximum size to the streambuf constructor
       boost::asio::streambuf response;
       boost::asio::read_until(socket, response, "\r\n");

       // Check that response is OK
       std::istream response_stream(&response);
       std::string http_version;
       response_stream >> http_version;
       unsigned int status_code;
       response_stream >> status_code;
       std::string status_message;
       std::getline(response_stream, status_message);
       if (!response_stream || http_version.substr(0, 5) != "HTTP/"){
                retval="Invalid response.";
       		FassLog::log("DB-QUERY", Log::ERROR, retval);
                return false;
       }
       if (status_code != 200 && status_code != 204){ // ping success results in 204
	       ostringstream oss_sc;
	       oss_sc << "Response returned with status code " << status_code;
               //retval=oss_sc.str();
               retval=status_message;
       	       FassLog::log("DB_QUERY", Log::ERROR, retval);
               return false;
       }
       if (status_code == 204 ){ // ping success results in 204
       	       FassLog::log("DB-QUERY", Log::DDEBUG, "Success pinging InfluxDb!");
               return true;
       }

       // Read the response headers, which are terminated by a blank line
       boost::asio::read_until(socket, response, "\r\n\r\n");

       // Process the response headers
       ostringstream oss_h;
       std::string header;
       while (std::getline(response_stream, header) && header != "\r")
               oss_h  << header << "\n";
       oss_h << "\n";

       // Write whatever content we already have to output
       if (response.size() > 0)  oss_h << &response;
       FassLog::log("DB-QUERY", Log::DDEBUG, oss_h);

       // Read until EOF, writing data to output as we go
       boost::system::error_code error;
       ostringstream oss_r;
       while (boost::asio::read(socket, response,boost::asio::transfer_at_least(1), error))
               oss_r << &response;
       if (error != boost::asio::error::eof)
               throw boost::system::system_error(error);
       retval=oss_r.str();
       FassLog::log("DB-QUERY", Log::DDEBUG, oss_r);
    } catch (std::exception& e){
       ostringstream oss_e;
       oss_e << e.what();
       FassLog::log("DB-QUERY", Log::ERROR, oss_e);
       retval=oss_e.str();
       return false;
    }

    return true;

}

bool InfluxDb::ping_db(){

    string response;
    bool retval=InfluxDb::query_db("GET", "/ping", response);
    return retval;
}

bool InfluxDb::create_db(){

    string response;
    ostringstream query;
    query << "/query?pretty=true&q=create%20database%20" << _dbname;
    bool retval=InfluxDb::query_db("POST", query.str(), response);
    return retval;
}

bool InfluxDb::write_initial_shares(const float share, const string user, const string group, const long int timestamp){

    FassLog::log("INFLUXDB", Log::INFO, "Writing initial shares.");

    return true;

}

bool InfluxDb::write_queue(const int priority, const string user, const string group, const int vmid,  const float cpus, const float memory, const long int starttime, const long int timestamp){

    FassLog::log("INFLUXDB", Log::INFO, "Writing queue.");

    return true;
}

bool InfluxDb::write_usage(const float cpu_usage, const float memory_usage, const string user, const string group, const long int since, const long int timestamp){

    FassLog::log("INFLUXDB", Log::INFO, "Writing usage records.");

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

#include <unistd.h>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>

#include "FassDb.h"
#include "FassLog.h"

using boost::asio::ip::tcp;

bool InfluxDb::init_db() {
    ostringstream oss;
    oss << "Initializing database \"" << _dbname << "\" at http://"
	<< _endpoint << ":" << _port;
    FassLog::log("INFLUXDB", Log::INFO, oss);

    string response;
    bool rc;

    // ping endpoint
    rc = InfluxDb::ping_db();
    if ( !rc ) {
        FassLog::log("INFLUXDB", Log::ERROR, "Could not ping DB!");
        return false;
    }
    // create a new database,
    // the action has no effect if the database already exists
    rc = InfluxDb::create_db();
    if ( !rc ) {
      FassLog::log("INFLUXDB", Log::ERROR, "Error creating database!");
    }
    return true;
}

bool InfluxDb::query_db(string method, string q, string &retval) {
    // for the time being we let it hardcoded
    const string protocol("HTTP/1.0");
    // FassLog::log("SARA", Log::INFO, "Starting query");

    try {
       // Taken form an example in the boost documentation
       boost::asio::io_service io_service;

       // Get a list of endpoints corresponding to the server name
       tcp::resolver resolver(io_service);
       tcp::resolver::query query(_endpoint,
				  boost::lexical_cast<string>(_port));
       tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

       // Try each endpoint until we successfully establish a connection
       tcp::socket socket(io_service);
       boost::asio::connect(socket, endpoint_iterator);

       // Form the request. We specify the "Connection: close" header
       // so that the server will close the socket
       // after transmitting the response. This will
       // allow us to treat all data
       // up until the EOF as the content
       boost::asio::streambuf request;
       std::ostream request_stream(&request);
       // request_stream << "GET " << "/ping" << " HTTP/1.0\r\n";
       // request_stream << method << " " << "/ping" << " HTTP/1.0\r\n";
       // string search = "show%20databases";
       // request_stream << method << " " << "/query?pretty=true&db=" << _dbname << "&q=" << search << " " << protocol << "\r\n";
       request_stream << method << " " << q << " " << protocol << "\r\n";
       request_stream << "Host: " << _endpoint << "\r\n";
       request_stream << "Accept: */*\r\n";
       request_stream << "Content-Type: application/x-www-form-urlencoded\r\n";
       request_stream << "Connection: close\r\n\r\n";

       // Send the request
       boost::asio::write(socket, request);

       // Read the response status line. The response streambuf will automatically
       // grow to accommodate the entire line. The growth may be limited by passing
       // a maximum size to the streambuf constructor
       boost::asio::streambuf response;
       boost::asio::read_until(socket, response, "\r\n");

       // Check that response is OK
       std::istream response_stream(&response);
       std::string http_version;
       response_stream >> http_version;
       unsigned int status_code;
       response_stream >> status_code;
       std::string status_message;
       std::getline(response_stream, status_message);
       if (!response_stream
	   || http_version.substr(0, 5) != "HTTP/") {
                retval = "Invalid response.";
                FassLog::log("DB-QUERY", Log::ERROR, retval);
                return false;
       }
       if (status_code != 200 && status_code != 204) {
	       // ping success results in 204
               ostringstream oss_sc;
               oss_sc << "Response returned with status code " << status_code;
               // retval=oss_sc.str();
               retval = status_message;
               FassLog::log("DB_QUERY", Log::ERROR, retval);
	       return false;
       }
       if (status_code == 204) {
	       // ping success results in 204
	       FassLog::log("DB-QUERY", Log::DDEBUG, "Success pinging InfluxDb!");
               return true;
       }

       // Read the response headers, which are terminated by a blank line
       boost::asio::read_until(socket, response, "\r\n\r\n");

       // Process the response headers
       ostringstream oss_h;
       std::string header;
       while (std::getline(response_stream, header)
	      && header != "\r")
	       oss_h  << header << "\n";
       oss_h << "\n";

       // Write whatever content we already have to output
       if (response.size() > 0)  oss_h << &response;
       FassLog::log("DB-QUERY", Log::DDEBUG, oss_h);

       // Read until EOF, writing data to output as we go
       boost::system::error_code error;
       ostringstream oss_r;
       while (boost::asio::read(socket, response,
				boost::asio::transfer_at_least(1), error))
	       oss_r << &response;
       if (error != boost::asio::error::eof)
	       throw boost::system::system_error(error);
       retval = oss_r.str();
       FassLog::log("DB-QUERY", Log::DDEBUG, oss_r);
    } catch (std::exception& e) {
       ostringstream oss_e;
       oss_e << e.what();
       FassLog::log("DB-QUERY", Log::ERROR, oss_e);
       retval = oss_e.str();
       return false;
    }

    return true;
}

bool InfluxDb::ping_db() {
    string response;
    bool retval = InfluxDb::query_db("GET", "/ping", response);
    return retval;
}

bool InfluxDb::create_db() {
    string response;
    ostringstream query;
    query << "/query?pretty=true&q=create%20database%20" << _dbname;
    bool retval = InfluxDb::query_db("POST", query.str(), response);
    return retval;
}

bool InfluxDb::write_initial_shares(const float share, const string user,
				    const string group, const long timestamp) {
    FassLog::log("INFLUXDB", Log::INFO, "Writing initial shares.");

    return true;
}

bool InfluxDb::write_queue(const int priority, const string user,
			   const string group, const int vmid,
			   const float cpus, const float memory,
			   const long starttime, const long timestamp) {
    FassLog::log("INFLUXDB", Log::INFO, "Writing queue.");

    return true;
}

bool InfluxDb::write_usage(const float cpu_usage, const float memory_usage,
			   const string user, const string group,
			   const long since, const long timestamp) {
    FassLog::log("INFLUXDB", Log::INFO, "Writing usage records.");

    return true;
}
<|endoftext|>


<commit_before>/*!
 *  Copyright (c) 2016 by Contributors
 * \file graph_attr_types.cc
 * \brief Graph node data structure.
 */
#include <nnvm/graph.h>
#include <nnvm/op_attr_types.h>
#include <limits>

namespace nnvm {

const IndexedGraph& Graph::indexed_graph() {
  if (indexed_graph_ == nullptr) {
    indexed_graph_.reset(new IndexedGraph(*this));
  }
  return *indexed_graph_;
}

// implement constructor from graph
IndexedGraph::IndexedGraph(const Graph &g) {
  entry_rptr_.push_back(0);
  std::vector<size_t> inputs_rptr{0}, control_rptr{0};

  DFSVisit(g.outputs, [this, &inputs_rptr, &control_rptr]
             (const NodePtr& n) {
      CHECK_LT(nodes_.size(), std::numeric_limits<uint32_t>::max());
      uint32_t nid = static_cast<uint32_t>(nodes_.size());
      // nodes_
      IndexedGraph::Node new_node;
      new_node.source = n.get();
      nodes_.emplace_back(std::move(new_node));
      // arg_nodes_
      if (n->is_variable()) {
        input_nodes_.push_back(nid);
      }
      // node2index_
      node2index_[n.get()] = nid;
      // entry rptr
      entry_rptr_.push_back(entry_rptr_.back() + n->num_outputs());
      // input entries
      for (const auto& e : n->inputs) {
        auto it = node2index_.find(e.node.get());
        CHECK(it != node2index_.end() && it->first == e.node.get());
        input_entries_.emplace_back(NodeEntry{it->second, e.index, e.version});
      }
      inputs_rptr.push_back(input_entries_.size());
      // control deps
      for (const auto& nptr : n->control_deps) {
        auto it = node2index_.find(nptr.get());
        CHECK(it != node2index_.end() && it->first == nptr.get());
        control_deps_.push_back(it->second);
      }
      control_rptr.push_back(control_deps_.size());
  });

  for (const auto& e : g.outputs) {
    outputs_.emplace_back(NodeEntry{
        node2index_.at(e.node.get()), e.index, e.version});
  }

  static auto& fmutate_inputs = Op::GetAttr<FMutateInputs>("FMutateInputs");
  std::unordered_set<uint32_t> mutable_inputs;
  // setup array view
  // input_entries_ and control_rptr must not change after this step.
  const NodeEntry* iptr = dmlc::BeginPtr(input_entries_);
  for (size_t nid = 0; nid < nodes_.size(); ++nid) {
    nodes_[nid].inputs = array_view<NodeEntry>(
        iptr + inputs_rptr[nid], iptr + inputs_rptr[nid + 1]);
    if (nodes_[nid].source->op() != nullptr &&
        fmutate_inputs.count(nodes_[nid].source->op())) {
      for (uint32_t i : fmutate_inputs[nodes_[nid].source->op()](nodes_[nid].source->attrs)) {
        mutable_input_nodes_.insert(nodes_[nid].inputs[i].node_id);
      }
    }
  }
  const uint32_t* cptr = dmlc::BeginPtr(control_deps_);
  for (size_t nid = 0; nid < nodes_.size(); ++nid) {
    nodes_[nid].control_deps = array_view<uint32_t>(
        cptr + control_rptr[nid], cptr + control_rptr[nid + 1]);
  }
}

}  // namespace nnvm
<commit_msg>rm unused variable (#143)<commit_after>/*!
 *  Copyright (c) 2016 by Contributors
 * \file graph_attr_types.cc
 * \brief Graph node data structure.
 */
#include <nnvm/graph.h>
#include <nnvm/op_attr_types.h>
#include <limits>

namespace nnvm {

const IndexedGraph& Graph::indexed_graph() {
  if (indexed_graph_ == nullptr) {
    indexed_graph_.reset(new IndexedGraph(*this));
  }
  return *indexed_graph_;
}

// implement constructor from graph
IndexedGraph::IndexedGraph(const Graph &g) {
  entry_rptr_.push_back(0);
  std::vector<size_t> inputs_rptr{0}, control_rptr{0};

  DFSVisit(g.outputs, [this, &inputs_rptr, &control_rptr]
             (const NodePtr& n) {
      CHECK_LT(nodes_.size(), std::numeric_limits<uint32_t>::max());
      uint32_t nid = static_cast<uint32_t>(nodes_.size());
      // nodes_
      IndexedGraph::Node new_node;
      new_node.source = n.get();
      nodes_.emplace_back(std::move(new_node));
      // arg_nodes_
      if (n->is_variable()) {
        input_nodes_.push_back(nid);
      }
      // node2index_
      node2index_[n.get()] = nid;
      // entry rptr
      entry_rptr_.push_back(entry_rptr_.back() + n->num_outputs());
      // input entries
      for (const auto& e : n->inputs) {
        auto it = node2index_.find(e.node.get());
        CHECK(it != node2index_.end() && it->first == e.node.get());
        input_entries_.emplace_back(NodeEntry{it->second, e.index, e.version});
      }
      inputs_rptr.push_back(input_entries_.size());
      // control deps
      for (const auto& nptr : n->control_deps) {
        auto it = node2index_.find(nptr.get());
        CHECK(it != node2index_.end() && it->first == nptr.get());
        control_deps_.push_back(it->second);
      }
      control_rptr.push_back(control_deps_.size());
  });

  for (const auto& e : g.outputs) {
    outputs_.emplace_back(NodeEntry{
        node2index_.at(e.node.get()), e.index, e.version});
  }

  static auto& fmutate_inputs = Op::GetAttr<FMutateInputs>("FMutateInputs");
  // setup array view
  // input_entries_ and control_rptr must not change after this step.
  const NodeEntry* iptr = dmlc::BeginPtr(input_entries_);
  for (size_t nid = 0; nid < nodes_.size(); ++nid) {
    nodes_[nid].inputs = array_view<NodeEntry>(
        iptr + inputs_rptr[nid], iptr + inputs_rptr[nid + 1]);
    if (nodes_[nid].source->op() != nullptr &&
        fmutate_inputs.count(nodes_[nid].source->op())) {
      for (uint32_t i : fmutate_inputs[nodes_[nid].source->op()](nodes_[nid].source->attrs)) {
        mutable_input_nodes_.insert(nodes_[nid].inputs[i].node_id);
      }
    }
  }
  const uint32_t* cptr = dmlc::BeginPtr(control_deps_);
  for (size_t nid = 0; nid < nodes_.size(); ++nid) {
    nodes_[nid].control_deps = array_view<uint32_t>(
        cptr + control_rptr[nid], cptr + control_rptr[nid + 1]);
  }
}

}  // namespace nnvm
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Script Generator project on Qt Labs.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "prigenerator.h"
#include "shellgenerator.h"
#include "reporthandler.h"
#include "fileout.h"

void PriGenerator::addHeader(const QString &folder, const QString &header)
{
    priHash[folder].headers << header;
}

void PriGenerator::addSource(const QString &folder, const QString &source)
{
    priHash[folder].sources << source;
}

static void collectAndRemoveFile(QTextStream& stream, const QString& file) {
  QFile f(file);
  if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
    QString s = QString::fromLatin1(f.readAll());
    if (file.endsWith(".cpp")) {
      // remove first line include
      s = s.mid(s.indexOf('\n')+1);
    }
    stream << s;
    f.close();
    QFile::remove(file);
  }
}

static QString combineIncludes(const QString& text) {
  QStringList lines = text.split('\n');
  QSet<QString> includes;
  QString result;
  foreach(QString line, lines) {
    if (line.startsWith("#include")) {
      includes.insert(line);
    } else if (line.startsWith("#")) {
      // skip preprocessor stuff
    } else {
      result += line + "\n";
    }
  }
  QStringList includeList = includes.toList();
  qSort(includeList);
  result = includeList.join("\n") + result;
  return result;
}

static QStringList compactFiles(const QStringList& list, const QString& ext, const QString& dir, const QString& prefix) {
  QStringList outList;
  int count = list.count();
  int fileNum = 0;
  QString srcDir = dir;
  if (dir.endsWith("_builtin")) {
    srcDir = dir.left(dir.length()-strlen("_builtin"));
  }
  while (count>0) {
    QString outFileName = prefix + QString::number(fileNum) + ext;
    FileOut file(dir + "/" + outFileName);
    if (ext == ".cpp") {
      file.stream << "#include \"" + prefix + QString::number(fileNum) + ".h\"\n";
    }
    outList << outFileName;
    QString allText;
    QTextStream ts(&allText);
    for (int i = 0; i<MAX_CLASSES_PER_FILE && count>0; i++) {
      collectAndRemoveFile(ts,  srcDir + "/" + list.at(list.length()-count));
      count--;
    }
    allText = combineIncludes(allText);
    file.stream << allText;
    fileNum++;
  }
  return outList;
}

void PriGenerator::generate()
{
    QHashIterator<QString, Pri> pri(priHash);
    while (pri.hasNext()) {
        pri.next();
        QStringList list = pri.value().headers;
        if (list.isEmpty())
            continue;

        QString folder = pri.key();
        folder.replace('\\','/');
        int idx = folder.indexOf('/');
        folder = folder.left(idx);

        qSort(list.begin(), list.end());
        FileOut file(m_out_dir + "/generated_cpp/" + pri.key());

        // strange idea to do the file compacting so late, but it is the most effective way without patching the generator a lot
        bool compact = true;
        if (compact) {
          list = compactFiles(list, ".h", m_out_dir + "/generated_cpp/" + folder, folder);
        }

        file.stream << "HEADERS += \\\n";
        foreach (const QString &entry, list) {
          file.stream << "           $$PWD/" << entry << " \\\n";
        }

        file.stream << "\n";
        file.stream << "SOURCES += \\\n";
        list = pri.value().sources;
        qSort(list.begin(), list.end());
        if (compact) {
          list = compactFiles(list, ".cpp", m_out_dir + "/generated_cpp/" + folder, folder);
        }
        foreach (const QString &entry, list) {
            file.stream << "           $$PWD/" << entry << " \\\n";
        }
        file.stream << "           $$PWD/" << folder << "_init.cpp\n";

        if (file.done())
            ++m_num_generated_written;
        ++m_num_generated;
    }
}
<commit_msg>fixed Qt3Support member<commit_after>/****************************************************************************
**
** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Script Generator project on Qt Labs.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "prigenerator.h"
#include "shellgenerator.h"
#include "reporthandler.h"
#include "fileout.h"

void PriGenerator::addHeader(const QString &folder, const QString &header)
{
    priHash[folder].headers << header;
}

void PriGenerator::addSource(const QString &folder, const QString &source)
{
    priHash[folder].sources << source;
}

static void collectAndRemoveFile(QTextStream& stream, const QString& file) {
  QFile f(file);
  if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
    QString s = QString::fromLatin1(f.readAll());
    if (file.endsWith(".cpp")) {
      // remove first line include
      s = s.mid(s.indexOf('\n')+1);
    }
    stream << s;
    f.close();
    QFile::remove(file);
  }
}

static QString combineIncludes(const QString& text) {
  QStringList lines = text.split('\n');
  QSet<QString> includes;
  QString result;
  foreach(QString line, lines) {
    if (line.startsWith("#include")) {
      includes.insert(line);
    } else if (line.startsWith("#")) {
      // skip preprocessor stuff
    } else {
      result += line + "\n";
    }
  }
  QStringList includeList = includes.toList();
  qSort(includeList);
  result = includeList.join("\n") + result;
  return result;
}

static QStringList compactFiles(const QStringList& list, const QString& ext, const QString& dir, const QString& prefix) {
  QStringList outList;
  int count = list.count();
  int fileNum = 0;
  QString srcDir = dir;
  if (dir.endsWith("_builtin")) {
    srcDir = dir.left(dir.length()-strlen("_builtin"));
  }
  while (count>0) {
    QString outFileName = prefix + QString::number(fileNum) + ext;
    FileOut file(dir + "/" + outFileName);
    if (ext == ".cpp") {
      file.stream << "#include \"" + prefix + QString::number(fileNum) + ".h\"\n";
    }
    outList << outFileName;
    QString allText;
    QTextStream ts(&allText);
    for (int i = 0; i<MAX_CLASSES_PER_FILE && count>0; i++) {
      collectAndRemoveFile(ts,  srcDir + "/" + list.at(list.count()-count));
      count--;
    }
    allText = combineIncludes(allText);
    file.stream << allText;
    fileNum++;
  }
  return outList;
}

void PriGenerator::generate()
{
    QHashIterator<QString, Pri> pri(priHash);
    while (pri.hasNext()) {
        pri.next();
        QStringList list = pri.value().headers;
        if (list.isEmpty())
            continue;

        QString folder = pri.key();
        folder.replace('\\','/');
        int idx = folder.indexOf('/');
        folder = folder.left(idx);

        qSort(list.begin(), list.end());
        FileOut file(m_out_dir + "/generated_cpp/" + pri.key());

        // strange idea to do the file compacting so late, but it is the most effective way without patching the generator a lot
        bool compact = true;
        if (compact) {
          list = compactFiles(list, ".h", m_out_dir + "/generated_cpp/" + folder, folder);
        }

        file.stream << "HEADERS += \\\n";
        foreach (const QString &entry, list) {
          file.stream << "           $$PWD/" << entry << " \\\n";
        }

        file.stream << "\n";
        file.stream << "SOURCES += \\\n";
        list = pri.value().sources;
        qSort(list.begin(), list.end());
        if (compact) {
          list = compactFiles(list, ".cpp", m_out_dir + "/generated_cpp/" + folder, folder);
        }
        foreach (const QString &entry, list) {
            file.stream << "           $$PWD/" << entry << " \\\n";
        }
        file.stream << "           $$PWD/" << folder << "_init.cpp\n";

        if (file.done())
            ++m_num_generated_written;
        ++m_num_generated;
    }
}
<|endoftext|>


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

using namespace nvinfer1;
using nvinfer1::plugin::InstanceNormalizationPlugin;
using nvinfer1::plugin::InstanceNormalizationPluginCreator;

#define CHECK_CUDA(call)                                                                                \
    do                                                                                \
    {                                                                                \
        cudaError_t status = call;                                                                                \
        if (status != cudaSuccess)                                                                                \
        {                                                                                \
            return status;                                                                                \
        }                                                                                \
    } while (0)

#define CHECK_CUDNN(call)                                                                                \
    do                                                                                \
    {                                                                                \
        cudnnStatus_t status = call;                                                                                \
        if (status != CUDNN_STATUS_SUCCESS)                                                                            \
        {                                                                                \
            return status;                                                                                \
        }                                                                                \
    } while (0)

inline bool is_CHW(nvinfer1::Dims const& dims)
{
    return (dims.nbDims == 3 && dims.type[0] == nvinfer1::DimensionType::kCHANNEL
        && dims.type[1] == nvinfer1::DimensionType::kSPATIAL && dims.type[2] == nvinfer1::DimensionType::kSPATIAL);
}

// This is derived from: https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
inline float half_to_float_fast(unsigned short value)
{
    union F32
    {
        unsigned int u;
        float f;
    };
    static const F32 magic = {(254 - 15) << 23};
    static const F32 was_infnan = {(127 + 16) << 23};
    F32 result;
    result.u = (value & 0x7fff) << 13; // exponent/mantissa bits
    result.f *= magic.f;               // exponent adjust
    if (result.f >= was_infnan.f)
    { // make sure Inf/NaN survive
        result.u |= 255 << 23;
    }
    result.u |= (value & 0x8000) << 16; // sign bit
    return result.f;
}

cudnnStatus_t convert_trt2cudnn_dtype(nvinfer1::DataType trt_dtype, cudnnDataType_t* cudnn_dtype)
{
    switch (trt_dtype)
    {
    case nvinfer1::DataType::kFLOAT: *cudnn_dtype = CUDNN_DATA_FLOAT; break;
    case nvinfer1::DataType::kHALF: *cudnn_dtype = CUDNN_DATA_HALF; break;
    default: return CUDNN_STATUS_BAD_PARAM;
    }
    return CUDNN_STATUS_SUCCESS;
}

namespace {
    constexpr const char* INSTANCE_PLUGIN_VERSION{"001"};
    constexpr const char* INSTANCE_PLUGIN_NAME{"InstanceNormalization_TRT"};
}

PluginFieldCollection InstanceNormalizationPluginCreator::mFC{};
std::vector<PluginField> InstanceNormalizationPluginCreator::mPluginAttributes;

InstanceNormalizationPlugin::InstanceNormalizationPlugin(
    float epsilon, const std::vector<float>& scale, const std::vector<float>& bias)
    : _epsilon(epsilon)
    , _nchan(scale.size())
    , _h_scale(scale)
    , _h_bias(bias)
    , _initialized(false)
{
    ASSERT(scale.size() == bias.size());
}

InstanceNormalizationPlugin::InstanceNormalizationPlugin(
    float epsilon, nvinfer1::Weights const& scale, nvinfer1::Weights const& bias)
    : _epsilon(epsilon)
    , _nchan(scale.count)
    , _initialized(false)
{
    ASSERT(scale.count == bias.count);
    if (scale.type == nvinfer1::DataType::kFLOAT)
    {
        _h_scale.assign((float*) scale.values, (float*) scale.values + scale.count);
    }
    else if (scale.type == nvinfer1::DataType::kHALF)
    {
        _h_scale.reserve(_nchan);
        for (int c = 0; c < _nchan; ++c)
        {
            unsigned short value = ((unsigned short*) scale.values)[c];
            _h_scale.push_back(half_to_float_fast(value));
        }
    }
    else
    {
        throw std::runtime_error("Unsupported scale dtype");
    }
    if (bias.type == nvinfer1::DataType::kFLOAT)
    {
        _h_bias.assign((float*) bias.values, (float*) bias.values + bias.count);
    }
    else if (bias.type == nvinfer1::DataType::kHALF)
    {
        _h_bias.reserve(_nchan);
        for (int c = 0; c < _nchan; ++c)
        {
            unsigned short value = ((unsigned short*) bias.values)[c];
            _h_bias.push_back(half_to_float_fast(value));
        }
    }
    else
    {
        throw std::runtime_error("Unsupported bias dtype");
    }
}

InstanceNormalizationPlugin::InstanceNormalizationPlugin(void const* serialData, size_t serialLength) : _initialized(false)
{
    deserialize_value(&serialData, &serialLength, &_epsilon);
    deserialize_value(&serialData, &serialLength, &_nchan);
    deserialize_value(&serialData, &serialLength, &_h_scale);
    deserialize_value(&serialData, &serialLength, &_h_bias);
}

InstanceNormalizationPlugin::~InstanceNormalizationPlugin()
{
    terminate();
}

// InstanceNormalizationPlugin returns one output.
int InstanceNormalizationPlugin::getNbOutputs() const
{
    return 1;
}

DimsExprs InstanceNormalizationPlugin::getOutputDimensions(
    int outputIndex, const nvinfer1::DimsExprs* inputs, int nbInputs, nvinfer1::IExprBuilder& exprBuilder)
{
    nvinfer1::DimsExprs output(inputs[0]);
    return output;
}

int InstanceNormalizationPlugin::initialize()
{
    _initialized = true;
    CHECK_CUDNN(cudnnCreate(&_cudnn_handle));
    CHECK_CUDNN(cudnnCreateTensorDescriptor(&_b_desc));
    CHECK_CUDNN(cudnnCreateTensorDescriptor(&_x_desc));
    CHECK_CUDNN(cudnnCreateTensorDescriptor(&_y_desc));
    return 0;
}

void InstanceNormalizationPlugin::terminate()
{
    if (!_initialized)
    {
        return;
    }
    cudnnDestroyTensorDescriptor(_y_desc);
    cudnnDestroyTensorDescriptor(_x_desc);
    cudnnDestroyTensorDescriptor(_b_desc);
    cudnnDestroy(_cudnn_handle);
    _initialized = false;
}

size_t InstanceNormalizationPlugin::getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs, int nbInputs, const nvinfer1::PluginTensorDesc* outputs, int nbOutputs) const
{
    return 0;
}

int InstanceNormalizationPlugin::enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
    const nvinfer1::PluginTensorDesc* outputDesc, const void* const* inputs, void* const* outputs, void* workspace,
    cudaStream_t stream)
{
    nvinfer1::Dims input_dims = inputDesc[0].dims;
    int n = input_dims.d[0];
    int c = input_dims.d[1];
    int h = input_dims.d[2];
    int w = input_dims.d[3];
    size_t nchan_bytes = c * sizeof(float);

    // Note: We repeat the data for each batch entry so that we can do the full
    //       computation in a single CUDNN call in enqueue().
    CHECK_CUDA(cudaMalloc((void**) &_d_scale, n * nchan_bytes));
    CHECK_CUDA(cudaMalloc((void**) &_d_bias, n * nchan_bytes));
    for (int i = 0; i < n; ++i)
    {
        CHECK_CUDA(cudaMemcpy(_d_scale + i * c, _h_scale.data(), nchan_bytes, cudaMemcpyHostToDevice));
        CHECK_CUDA(cudaMemcpy(_d_bias + i * c, _h_bias.data(), nchan_bytes, cudaMemcpyHostToDevice));
    }

    CHECK_CUDNN(cudnnSetTensor4dDescriptor(_b_desc, CUDNN_TENSOR_NCHW, CUDNN_DATA_FLOAT, 1, n * c, 1, 1));
    cudnnDataType_t cudnn_dtype;
    CHECK_CUDNN(convert_trt2cudnn_dtype(inputDesc[0].type, &cudnn_dtype));
    CHECK_CUDNN(cudnnSetTensor4dDescriptor(_x_desc, CUDNN_TENSOR_NCHW, cudnn_dtype, 1, n * c, h, w));
    CHECK_CUDNN(cudnnSetTensor4dDescriptor(_y_desc, CUDNN_TENSOR_NCHW, cudnn_dtype, 1, n * c, h, w));
    float alpha = 1;
    float beta = 0;
    void const* x_ptr = inputs[0];
    void* y_ptr = outputs[0];
    CHECK_CUDNN(cudnnSetStream(_cudnn_handle, stream));
    // Note: Use of CUDNN_BATCHNORM_SPATIAL_PERSISTENT can cause numerical
    //       overflows (NaNs) for fp32 data in some circumstances. The lower-
    //       performance CUDNN_BATCHNORM_SPATIAL should be used if this is not
    //       acceptable.
    CHECK_CUDNN(cudnnBatchNormalizationForwardTraining(_cudnn_handle, CUDNN_BATCHNORM_SPATIAL_PERSISTENT, &alpha, &beta,
        _x_desc, x_ptr, _y_desc, y_ptr, _b_desc, _d_scale, _d_bias, 1., nullptr, nullptr, _epsilon, nullptr, nullptr));
    cudaFree(_d_bias);
    cudaFree(_d_scale);
    return 0;
}

size_t InstanceNormalizationPlugin::getSerializationSize() const
{
    return (serialized_size(_epsilon) +
            serialized_size(_nchan) +
            serialized_size(_h_scale) +
            serialized_size(_h_bias));
}

void InstanceNormalizationPlugin::serialize(void *buffer) const
{
    serialize_value(&buffer, _epsilon);
    serialize_value(&buffer, _nchan);
    serialize_value(&buffer, _h_scale);
    serialize_value(&buffer, _h_bias);
}

bool InstanceNormalizationPlugin::supportsFormatCombination(
    int pos, const nvinfer1::PluginTensorDesc* inOut, int nbInputs, int nbOutputs)
{
    ASSERT(inOut && pos < (nbInputs + nbOutputs));
    return ((inOut[pos].type == nvinfer1::DataType::kFLOAT || inOut[pos].type == nvinfer1::DataType::kHALF)
        && inOut[pos].format == nvinfer1::PluginFormat::kNCHW);
}

const char* InstanceNormalizationPlugin::getPluginType() const
{
    return INSTANCE_PLUGIN_NAME;
}

const char* InstanceNormalizationPlugin::getPluginVersion() const
{
    return INSTANCE_PLUGIN_VERSION;
}

void InstanceNormalizationPlugin::destroy()
{
    delete this;
}

IPluginV2DynamicExt* InstanceNormalizationPlugin::clone() const
{
    auto plugin = new InstanceNormalizationPlugin{_epsilon, _h_scale, _h_bias};
    plugin->setPluginNamespace(mPluginNamespace);
    return plugin;
}

// Set plugin namespace
void InstanceNormalizationPlugin::setPluginNamespace(const char* pluginNamespace)
{
    mPluginNamespace = pluginNamespace;
}

const char* InstanceNormalizationPlugin::getPluginNamespace() const
{
    return mPluginNamespace;
}

nvinfer1::DataType InstanceNormalizationPlugin::getOutputDataType(
    int index, const nvinfer1::DataType* inputTypes, int nbInputs) const
{
    ASSERT(inputTypes && nbInputs > 0 && index == 0);
    return inputTypes[0];
}

// Attach the plugin object to an execution context and grant the plugin the access to some context resource.
void InstanceNormalizationPlugin::attachToContext(cudnnContext* cudnnContext, cublasContext* cublasContext, IGpuAllocator* gpuAllocator)
{
}

// Detach the plugin object from its execution context.
void InstanceNormalizationPlugin::detachFromContext() {}

void InstanceNormalizationPlugin::configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in, int nbInputs,
    const nvinfer1::DynamicPluginTensorDesc* out, int nbOutputs)
{
    for (int i = 0; i < nbInputs; i++)
    {
      for (int j = 0; j < in[0].desc.dims.nbDims; j++)
      {
        // Do not support dynamic dimensions
        ASSERT(in[0].desc.dims.d[j] != -1);
      }
    }
}

// InstanceNormalizationPluginCreator methods
InstanceNormalizationPluginCreator::InstanceNormalizationPluginCreator()
{
    mPluginAttributes.emplace_back(PluginField("epsilon", nullptr, PluginFieldType::kFLOAT32, 1));
    mPluginAttributes.emplace_back(PluginField("scales", nullptr, PluginFieldType::kFLOAT32, 1));
    mPluginAttributes.emplace_back(PluginField("bias", nullptr, PluginFieldType::kFLOAT32, 1));

    mFC.nbFields = mPluginAttributes.size();
    mFC.fields = mPluginAttributes.data();
}

const char* InstanceNormalizationPluginCreator::getPluginName() const
{
    return INSTANCE_PLUGIN_NAME;
}

const char* InstanceNormalizationPluginCreator::getPluginVersion() const
{
    return INSTANCE_PLUGIN_VERSION;
}

const PluginFieldCollection* InstanceNormalizationPluginCreator::getFieldNames()
{
    return &mFC;
}

IPluginV2DynamicExt* InstanceNormalizationPluginCreator::createPlugin(const char* name, const nvinfer1::PluginFieldCollection* fc)
{
    std::vector<float> scaleValues;
    std::vector<float> biasValues;
    float epsilon {};
    const PluginField* fields = fc->fields;
    for (int i = 0; i < fc->nbFields; ++i)
    {
        const char* attrName = fields[i].name;
        if (!strcmp(attrName, "epsilon"))
        {
            ASSERT(fields[i].type == PluginFieldType::kFLOAT32);
            epsilon= *(static_cast<const float*>(fields[i].data));
        }
        else if (!strcmp(attrName, "scales"))
        {
            ASSERT(fields[i].type == PluginFieldType::kFLOAT32);
            int size = fields[i].length;
            scaleValues.reserve(size);
            const auto* w = static_cast<const float*>(fields[i].data);
            for (int j = 0; j < size; j++)
            {
                scaleValues.push_back(*w);
                w++;
            }
        }
        else if (!strcmp(attrName, "bias"))
        {
            ASSERT(fields[i].type == PluginFieldType::kFLOAT32);
            int size = fields[i].length;
            biasValues.reserve(size);
            const auto* w = static_cast<const float*>(fields[i].data);
            for (int j = 0; j < size; j++)
            {
                biasValues.push_back(*w);
                w++;
            }
        }
    }

    Weights scaleWeights{DataType::kFLOAT, scaleValues.data(), (int64_t) scaleValues.size()};
    Weights biasWeights{DataType::kFLOAT, biasValues.data(), (int64_t) biasValues.size()};

    InstanceNormalizationPlugin* obj = new InstanceNormalizationPlugin(epsilon, scaleWeights, biasWeights);
    obj->setPluginNamespace(mNamespace.c_str());
    return obj;
}

IPluginV2DynamicExt* InstanceNormalizationPluginCreator::deserializePlugin(const char* name, const void* serialData, size_t serialLength)
{
    InstanceNormalizationPlugin* obj = new InstanceNormalizationPlugin{serialData, serialLength};
    obj->setPluginNamespace(mNamespace.c_str());
    return obj;
}
<commit_msg>Ensure input and ouput types are the same for InstanceNormalizationPlugin (#356)<commit_after>/*
 * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <stdexcept>
#include "instanceNormalizationPlugin.h"

using namespace nvinfer1;
using nvinfer1::plugin::InstanceNormalizationPlugin;
using nvinfer1::plugin::InstanceNormalizationPluginCreator;

#define CHECK_CUDA(call)                                                                                \
    do                                                                                \
    {                                                                                \
        cudaError_t status = call;                                                                                \
        if (status != cudaSuccess)                                                                                \
        {                                                                                \
            return status;                                                                                \
        }                                                                                \
    } while (0)

#define CHECK_CUDNN(call)                                                                                \
    do                                                                                \
    {                                                                                \
        cudnnStatus_t status = call;                                                                                \
        if (status != CUDNN_STATUS_SUCCESS)                                                                            \
        {                                                                                \
            return status;                                                                                \
        }                                                                                \
    } while (0)

inline bool is_CHW(nvinfer1::Dims const& dims)
{
    return (dims.nbDims == 3 && dims.type[0] == nvinfer1::DimensionType::kCHANNEL
        && dims.type[1] == nvinfer1::DimensionType::kSPATIAL && dims.type[2] == nvinfer1::DimensionType::kSPATIAL);
}

// This is derived from: https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
inline float half_to_float_fast(unsigned short value)
{
    union F32
    {
        unsigned int u;
        float f;
    };
    static const F32 magic = {(254 - 15) << 23};
    static const F32 was_infnan = {(127 + 16) << 23};
    F32 result;
    result.u = (value & 0x7fff) << 13; // exponent/mantissa bits
    result.f *= magic.f;               // exponent adjust
    if (result.f >= was_infnan.f)
    { // make sure Inf/NaN survive
        result.u |= 255 << 23;
    }
    result.u |= (value & 0x8000) << 16; // sign bit
    return result.f;
}

cudnnStatus_t convert_trt2cudnn_dtype(nvinfer1::DataType trt_dtype, cudnnDataType_t* cudnn_dtype)
{
    switch (trt_dtype)
    {
    case nvinfer1::DataType::kFLOAT: *cudnn_dtype = CUDNN_DATA_FLOAT; break;
    case nvinfer1::DataType::kHALF: *cudnn_dtype = CUDNN_DATA_HALF; break;
    default: return CUDNN_STATUS_BAD_PARAM;
    }
    return CUDNN_STATUS_SUCCESS;
}

namespace {
    constexpr const char* INSTANCE_PLUGIN_VERSION{"001"};
    constexpr const char* INSTANCE_PLUGIN_NAME{"InstanceNormalization_TRT"};
}

PluginFieldCollection InstanceNormalizationPluginCreator::mFC{};
std::vector<PluginField> InstanceNormalizationPluginCreator::mPluginAttributes;

InstanceNormalizationPlugin::InstanceNormalizationPlugin(
    float epsilon, const std::vector<float>& scale, const std::vector<float>& bias)
    : _epsilon(epsilon)
    , _nchan(scale.size())
    , _h_scale(scale)
    , _h_bias(bias)
    , _initialized(false)
{
    ASSERT(scale.size() == bias.size());
}

InstanceNormalizationPlugin::InstanceNormalizationPlugin(
    float epsilon, nvinfer1::Weights const& scale, nvinfer1::Weights const& bias)
    : _epsilon(epsilon)
    , _nchan(scale.count)
    , _initialized(false)
{
    ASSERT(scale.count == bias.count);
    if (scale.type == nvinfer1::DataType::kFLOAT)
    {
        _h_scale.assign((float*) scale.values, (float*) scale.values + scale.count);
    }
    else if (scale.type == nvinfer1::DataType::kHALF)
    {
        _h_scale.reserve(_nchan);
        for (int c = 0; c < _nchan; ++c)
        {
            unsigned short value = ((unsigned short*) scale.values)[c];
            _h_scale.push_back(half_to_float_fast(value));
        }
    }
    else
    {
        throw std::runtime_error("Unsupported scale dtype");
    }
    if (bias.type == nvinfer1::DataType::kFLOAT)
    {
        _h_bias.assign((float*) bias.values, (float*) bias.values + bias.count);
    }
    else if (bias.type == nvinfer1::DataType::kHALF)
    {
        _h_bias.reserve(_nchan);
        for (int c = 0; c < _nchan; ++c)
        {
            unsigned short value = ((unsigned short*) bias.values)[c];
            _h_bias.push_back(half_to_float_fast(value));
        }
    }
    else
    {
        throw std::runtime_error("Unsupported bias dtype");
    }
}

InstanceNormalizationPlugin::InstanceNormalizationPlugin(void const* serialData, size_t serialLength) : _initialized(false)
{
    deserialize_value(&serialData, &serialLength, &_epsilon);
    deserialize_value(&serialData, &serialLength, &_nchan);
    deserialize_value(&serialData, &serialLength, &_h_scale);
    deserialize_value(&serialData, &serialLength, &_h_bias);
}

InstanceNormalizationPlugin::~InstanceNormalizationPlugin()
{
    terminate();
}

// InstanceNormalizationPlugin returns one output.
int InstanceNormalizationPlugin::getNbOutputs() const
{
    return 1;
}

DimsExprs InstanceNormalizationPlugin::getOutputDimensions(
    int outputIndex, const nvinfer1::DimsExprs* inputs, int nbInputs, nvinfer1::IExprBuilder& exprBuilder)
{
    nvinfer1::DimsExprs output(inputs[0]);
    return output;
}

int InstanceNormalizationPlugin::initialize()
{
    _initialized = true;
    CHECK_CUDNN(cudnnCreate(&_cudnn_handle));
    CHECK_CUDNN(cudnnCreateTensorDescriptor(&_b_desc));
    CHECK_CUDNN(cudnnCreateTensorDescriptor(&_x_desc));
    CHECK_CUDNN(cudnnCreateTensorDescriptor(&_y_desc));
    return 0;
}

void InstanceNormalizationPlugin::terminate()
{
    if (!_initialized)
    {
        return;
    }
    cudnnDestroyTensorDescriptor(_y_desc);
    cudnnDestroyTensorDescriptor(_x_desc);
    cudnnDestroyTensorDescriptor(_b_desc);
    cudnnDestroy(_cudnn_handle);
    _initialized = false;
}

size_t InstanceNormalizationPlugin::getWorkspaceSize(const nvinfer1::PluginTensorDesc* inputs, int nbInputs, const nvinfer1::PluginTensorDesc* outputs, int nbOutputs) const
{
    return 0;
}

int InstanceNormalizationPlugin::enqueue(const nvinfer1::PluginTensorDesc* inputDesc,
    const nvinfer1::PluginTensorDesc* outputDesc, const void* const* inputs, void* const* outputs, void* workspace,
    cudaStream_t stream)
{
    nvinfer1::Dims input_dims = inputDesc[0].dims;
    int n = input_dims.d[0];
    int c = input_dims.d[1];
    int h = input_dims.d[2];
    int w = input_dims.d[3];
    size_t nchan_bytes = c * sizeof(float);

    // Note: We repeat the data for each batch entry so that we can do the full
    //       computation in a single CUDNN call in enqueue().
    CHECK_CUDA(cudaMalloc((void**) &_d_scale, n * nchan_bytes));
    CHECK_CUDA(cudaMalloc((void**) &_d_bias, n * nchan_bytes));
    for (int i = 0; i < n; ++i)
    {
        CHECK_CUDA(cudaMemcpy(_d_scale + i * c, _h_scale.data(), nchan_bytes, cudaMemcpyHostToDevice));
        CHECK_CUDA(cudaMemcpy(_d_bias + i * c, _h_bias.data(), nchan_bytes, cudaMemcpyHostToDevice));
    }

    CHECK_CUDNN(cudnnSetTensor4dDescriptor(_b_desc, CUDNN_TENSOR_NCHW, CUDNN_DATA_FLOAT, 1, n * c, 1, 1));
    cudnnDataType_t cudnn_dtype;
    CHECK_CUDNN(convert_trt2cudnn_dtype(inputDesc[0].type, &cudnn_dtype));
    CHECK_CUDNN(cudnnSetTensor4dDescriptor(_x_desc, CUDNN_TENSOR_NCHW, cudnn_dtype, 1, n * c, h, w));
    CHECK_CUDNN(cudnnSetTensor4dDescriptor(_y_desc, CUDNN_TENSOR_NCHW, cudnn_dtype, 1, n * c, h, w));
    float alpha = 1;
    float beta = 0;
    void const* x_ptr = inputs[0];
    void* y_ptr = outputs[0];
    CHECK_CUDNN(cudnnSetStream(_cudnn_handle, stream));
    // Note: Use of CUDNN_BATCHNORM_SPATIAL_PERSISTENT can cause numerical
    //       overflows (NaNs) for fp32 data in some circumstances. The lower-
    //       performance CUDNN_BATCHNORM_SPATIAL should be used if this is not
    //       acceptable.
    CHECK_CUDNN(cudnnBatchNormalizationForwardTraining(_cudnn_handle, CUDNN_BATCHNORM_SPATIAL_PERSISTENT, &alpha, &beta,
        _x_desc, x_ptr, _y_desc, y_ptr, _b_desc, _d_scale, _d_bias, 1., nullptr, nullptr, _epsilon, nullptr, nullptr));
    cudaFree(_d_bias);
    cudaFree(_d_scale);
    return 0;
}

size_t InstanceNormalizationPlugin::getSerializationSize() const
{
    return (serialized_size(_epsilon) +
            serialized_size(_nchan) +
            serialized_size(_h_scale) +
            serialized_size(_h_bias));
}

void InstanceNormalizationPlugin::serialize(void *buffer) const
{
    serialize_value(&buffer, _epsilon);
    serialize_value(&buffer, _nchan);
    serialize_value(&buffer, _h_scale);
    serialize_value(&buffer, _h_bias);
}

bool InstanceNormalizationPlugin::supportsFormatCombination(
    int pos, const nvinfer1::PluginTensorDesc* inOut, int nbInputs, int nbOutputs)
{
    ASSERT(inOut && pos < (nbInputs + nbOutputs));
    return ((inOut[pos].type == nvinfer1::DataType::kFLOAT || inOut[pos].type == nvinfer1::DataType::kHALF)
        && inOut[pos].format == nvinfer1::PluginFormat::kNCHW && inOut[pos].type == inOut[0].type);
}

const char* InstanceNormalizationPlugin::getPluginType() const
{
    return INSTANCE_PLUGIN_NAME;
}

const char* InstanceNormalizationPlugin::getPluginVersion() const
{
    return INSTANCE_PLUGIN_VERSION;
}

void InstanceNormalizationPlugin::destroy()
{
    delete this;
}

IPluginV2DynamicExt* InstanceNormalizationPlugin::clone() const
{
    auto plugin = new InstanceNormalizationPlugin{_epsilon, _h_scale, _h_bias};
    plugin->setPluginNamespace(mPluginNamespace);
    return plugin;
}

// Set plugin namespace
void InstanceNormalizationPlugin::setPluginNamespace(const char* pluginNamespace)
{
    mPluginNamespace = pluginNamespace;
}

const char* InstanceNormalizationPlugin::getPluginNamespace() const
{
    return mPluginNamespace;
}

nvinfer1::DataType InstanceNormalizationPlugin::getOutputDataType(
    int index, const nvinfer1::DataType* inputTypes, int nbInputs) const
{
    ASSERT(inputTypes && nbInputs > 0 && index == 0);
    return inputTypes[0];
}

// Attach the plugin object to an execution context and grant the plugin the access to some context resource.
void InstanceNormalizationPlugin::attachToContext(cudnnContext* cudnnContext, cublasContext* cublasContext, IGpuAllocator* gpuAllocator)
{
}

// Detach the plugin object from its execution context.
void InstanceNormalizationPlugin::detachFromContext() {}

void InstanceNormalizationPlugin::configurePlugin(const nvinfer1::DynamicPluginTensorDesc* in, int nbInputs,
    const nvinfer1::DynamicPluginTensorDesc* out, int nbOutputs)
{
    for (int i = 0; i < nbInputs; i++)
    {
      for (int j = 0; j < in[0].desc.dims.nbDims; j++)
      {
        // Do not support dynamic dimensions
        ASSERT(in[0].desc.dims.d[j] != -1);
      }
    }
}

// InstanceNormalizationPluginCreator methods
InstanceNormalizationPluginCreator::InstanceNormalizationPluginCreator()
{
    mPluginAttributes.emplace_back(PluginField("epsilon", nullptr, PluginFieldType::kFLOAT32, 1));
    mPluginAttributes.emplace_back(PluginField("scales", nullptr, PluginFieldType::kFLOAT32, 1));
    mPluginAttributes.emplace_back(PluginField("bias", nullptr, PluginFieldType::kFLOAT32, 1));

    mFC.nbFields = mPluginAttributes.size();
    mFC.fields = mPluginAttributes.data();
}

const char* InstanceNormalizationPluginCreator::getPluginName() const
{
    return INSTANCE_PLUGIN_NAME;
}

const char* InstanceNormalizationPluginCreator::getPluginVersion() const
{
    return INSTANCE_PLUGIN_VERSION;
}

const PluginFieldCollection* InstanceNormalizationPluginCreator::getFieldNames()
{
    return &mFC;
}

IPluginV2DynamicExt* InstanceNormalizationPluginCreator::createPlugin(const char* name, const nvinfer1::PluginFieldCollection* fc)
{
    std::vector<float> scaleValues;
    std::vector<float> biasValues;
    float epsilon {};
    const PluginField* fields = fc->fields;
    for (int i = 0; i < fc->nbFields; ++i)
    {
        const char* attrName = fields[i].name;
        if (!strcmp(attrName, "epsilon"))
        {
            ASSERT(fields[i].type == PluginFieldType::kFLOAT32);
            epsilon= *(static_cast<const float*>(fields[i].data));
        }
        else if (!strcmp(attrName, "scales"))
        {
            ASSERT(fields[i].type == PluginFieldType::kFLOAT32);
            int size = fields[i].length;
            scaleValues.reserve(size);
            const auto* w = static_cast<const float*>(fields[i].data);
            for (int j = 0; j < size; j++)
            {
                scaleValues.push_back(*w);
                w++;
            }
        }
        else if (!strcmp(attrName, "bias"))
        {
            ASSERT(fields[i].type == PluginFieldType::kFLOAT32);
            int size = fields[i].length;
            biasValues.reserve(size);
            const auto* w = static_cast<const float*>(fields[i].data);
            for (int j = 0; j < size; j++)
            {
                biasValues.push_back(*w);
                w++;
            }
        }
    }

    Weights scaleWeights{DataType::kFLOAT, scaleValues.data(), (int64_t) scaleValues.size()};
    Weights biasWeights{DataType::kFLOAT, biasValues.data(), (int64_t) biasValues.size()};

    InstanceNormalizationPlugin* obj = new InstanceNormalizationPlugin(epsilon, scaleWeights, biasWeights);
    obj->setPluginNamespace(mNamespace.c_str());
    return obj;
}

IPluginV2DynamicExt* InstanceNormalizationPluginCreator::deserializePlugin(const char* name, const void* serialData, size_t serialLength)
{
    InstanceNormalizationPlugin* obj = new InstanceNormalizationPlugin{serialData, serialLength};
    obj->setPluginNamespace(mNamespace.c_str());
    return obj;
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/debug.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/params.hpp>
#include <mapnik/plugin.hpp>
#include <mapnik/util/fs.hpp>

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/predicate.hpp>
#pragma GCC diagnostic pop

// stl
#include <algorithm>
#include <map>
#include <stdexcept>

namespace mapnik {

template class singleton<datasource_cache, CreateStatic>;

extern datasource_ptr create_static_datasource(parameters const& params);
extern std::vector<std::string> get_static_datasource_names();

bool is_input_plugin(std::string const& filename)
{
    return boost::algorithm::ends_with(filename,std::string(".input"));
}

datasource_cache::datasource_cache()
{
    PluginInfo::init();
}

datasource_cache::~datasource_cache()
{
    PluginInfo::exit();
}

datasource_ptr datasource_cache::create(parameters const& params)
{
    boost::optional<std::string> type = params.get<std::string>("type");
    if ( ! type)
    {
        throw config_error(std::string("Could not create datasource. Required ") +
                           "parameter 'type' is missing");
    }

    datasource_ptr ds;

#ifdef MAPNIK_STATIC_PLUGINS
    // return if it's created, raise otherwise
    ds = create_static_datasource(params);
    if (ds)
    {
        return ds;
    }
#endif

    std::map<std::string,std::shared_ptr<PluginInfo> >::iterator itr;
    // add scope to ensure lock is released asap
    {
#ifdef MAPNIK_THREADSAFE
        std::lock_guard<std::recursive_mutex> lock(instance_mutex_);
#endif
        itr=plugins_.find(*type);
        if (itr == plugins_.end())
        {
            std::string s("Could not create datasource for type: '");
            s += *type + "'";
            if (plugin_directories_.empty())
            {
                s += " (no datasource plugin directories have been successfully registered)";
            }
            else
            {
                s += " (searched for datasource plugins in '" + plugin_directories() + "')";
            }
            throw config_error(s);
        }
    }

    if (! itr->second->valid())
    {
        throw std::runtime_error(std::string("Cannot load library: ") +
                                 itr->second->get_error());
    }

    // http://www.mr-edd.co.uk/blog/supressing_gcc_warnings
#ifdef __GNUC__
    __extension__
#endif
        create_ds create_datasource = reinterpret_cast<create_ds>(itr->second->get_symbol("create"));

    if (! create_datasource)
    {
        throw std::runtime_error(std::string("Cannot load symbols: ") +
                                 itr->second->get_error());
    }

    ds = datasource_ptr(create_datasource(params), datasource_deleter());

    return ds;
}

std::string datasource_cache::plugin_directories()
{
#ifdef MAPNIK_THREADSAFE
    std::lock_guard<std::recursive_mutex> lock(instance_mutex_);
#endif
    return boost::algorithm::join(plugin_directories_,", ");
}

std::vector<std::string> datasource_cache::plugin_names()
{
    std::vector<std::string> names;

#ifdef MAPNIK_STATIC_PLUGINS
    names = get_static_datasource_names();
#endif

#ifdef MAPNIK_THREADSAFE
    std::lock_guard<std::recursive_mutex> lock(instance_mutex_);
#endif

    std::map<std::string,std::shared_ptr<PluginInfo> >::const_iterator itr;
    for (itr = plugins_.begin(); itr != plugins_.end(); ++itr)
    {
        names.push_back(itr->first);
    }

    return names;
}

bool datasource_cache::register_datasources(std::string const& dir, bool recurse)
{
#ifdef MAPNIK_THREADSAFE
    std::lock_guard<std::recursive_mutex> lock(instance_mutex_);
#endif
    if (!mapnik::util::exists(dir))
    {
        return false;
    }
    plugin_directories_.insert(dir);
    if (!mapnik::util::is_directory(dir))
    {
        return register_datasource(dir);
    }
    bool success = false;
    try
    {
        for (std::string const& file_name : mapnik::util::list_directory(dir))
        {
            if (mapnik::util::is_directory(file_name) && recurse)
            {
                if (register_datasources(file_name, true))
                {
                    success = true;
                }
            }
            else
            {
                std::string base_name = mapnik::util::basename(file_name);
                if (!boost::algorithm::starts_with(base_name,".") &&
                    mapnik::util::is_regular_file(file_name) &&
                    is_input_plugin(file_name))
                {
                    if (register_datasource(file_name))
                    {
                        success = true;
                    }
                }
            }
        }
    }
    catch (std::exception const& ex)
    {
        MAPNIK_LOG_ERROR(datasource_cache) << "register_datasources: " << ex.what();
    }
    return success;
}

bool datasource_cache::register_datasource(std::string const& filename)
{
#ifdef MAPNIK_THREADSAFE
    std::lock_guard<std::recursive_mutex> lock(instance_mutex_);
#endif
    try
    {
        if (!mapnik::util::exists(filename))
        {
            MAPNIK_LOG_ERROR(datasource_cache)
                    << "Cannot load '"
                    << filename << "' (plugin does not exist)";
            return false;
        }
        std::shared_ptr<PluginInfo> plugin = std::make_shared<PluginInfo>(filename,"datasource_name");
        if (plugin->valid())
        {
            if (plugin->name().empty())
            {
                MAPNIK_LOG_ERROR(datasource_cache)
                        << "Problem loading plugin library '"
                        << filename << "' (plugin is lacking compatible interface)";
            }
            else
            {
                if (plugins_.emplace(plugin->name(),plugin).second)
                {
                    MAPNIK_LOG_DEBUG(datasource_cache)
                            << "datasource_cache: Registered="
                            << plugin->name();
                    return true;
                }
            }
        }
        else
        {
            MAPNIK_LOG_ERROR(datasource_cache)
                    << "Problem loading plugin library: "
                    << filename << " (dlopen failed - plugin likely has an unsatisfied dependency or incompatible ABI)";
        }
    }
    catch (std::exception const& ex)
    {
        MAPNIK_LOG_ERROR(datasource_cache)
                << "Exception caught while loading plugin library: "
                << filename << " (" << ex.what() << ")";
    }
    return false;
}

}
<commit_msg>minor formatting<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/debug.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/params.hpp>
#include <mapnik/plugin.hpp>
#include <mapnik/util/fs.hpp>

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/predicate.hpp>
#pragma GCC diagnostic pop

// stl
#include <algorithm>
#include <map>
#include <stdexcept>

namespace mapnik {

template class singleton<datasource_cache, CreateStatic>;

extern datasource_ptr create_static_datasource(parameters const& params);
extern std::vector<std::string> get_static_datasource_names();

bool is_input_plugin(std::string const& filename)
{
    return boost::algorithm::ends_with(filename,std::string(".input"));
}

datasource_cache::datasource_cache()
{
    PluginInfo::init();
}

datasource_cache::~datasource_cache()
{
    PluginInfo::exit();
}

datasource_ptr datasource_cache::create(parameters const& params)
{
    boost::optional<std::string> type = params.get<std::string>("type");
    if ( ! type)
    {
        throw config_error(std::string("Could not create datasource. Required ") +
                           "parameter 'type' is missing");
    }

    datasource_ptr ds;

#ifdef MAPNIK_STATIC_PLUGINS
    // return if it's created, raise otherwise
    ds = create_static_datasource(params);
    if (ds)
    {
        return ds;
    }
#endif

    std::map<std::string,std::shared_ptr<PluginInfo> >::iterator itr;
    // add scope to ensure lock is released asap
    {
#ifdef MAPNIK_THREADSAFE
        std::lock_guard<std::recursive_mutex> lock(instance_mutex_);
#endif
        itr = plugins_.find(*type);
        if (itr == plugins_.end())
        {
            std::string s("Could not create datasource for type: '");
            s += *type + "'";
            if (plugin_directories_.empty())
            {
                s += " (no datasource plugin directories have been successfully registered)";
            }
            else
            {
                s += " (searched for datasource plugins in '" + plugin_directories() + "')";
            }
            throw config_error(s);
        }
    }

    if (!itr->second->valid())
    {
        throw std::runtime_error(std::string("Cannot load library: ") +
                                 itr->second->get_error());
    }

    // http://www.mr-edd.co.uk/blog/supressing_gcc_warnings
#ifdef __GNUC__
    __extension__
#endif
        create_ds create_datasource = reinterpret_cast<create_ds>(itr->second->get_symbol("create"));

    if (! create_datasource)
    {
        throw std::runtime_error(std::string("Cannot load symbols: ") +
                                 itr->second->get_error());
    }

    ds = datasource_ptr(create_datasource(params), datasource_deleter());

    return ds;
}

std::string datasource_cache::plugin_directories()
{
#ifdef MAPNIK_THREADSAFE
    std::lock_guard<std::recursive_mutex> lock(instance_mutex_);
#endif
    return boost::algorithm::join(plugin_directories_,", ");
}

std::vector<std::string> datasource_cache::plugin_names()
{
    std::vector<std::string> names;

#ifdef MAPNIK_STATIC_PLUGINS
    names = get_static_datasource_names();
#endif

#ifdef MAPNIK_THREADSAFE
    std::lock_guard<std::recursive_mutex> lock(instance_mutex_);
#endif

    std::map<std::string,std::shared_ptr<PluginInfo> >::const_iterator itr;
    for (itr = plugins_.begin(); itr != plugins_.end(); ++itr)
    {
        names.push_back(itr->first);
    }

    return names;
}

bool datasource_cache::register_datasources(std::string const& dir, bool recurse)
{
#ifdef MAPNIK_THREADSAFE
    std::lock_guard<std::recursive_mutex> lock(instance_mutex_);
#endif
    if (!mapnik::util::exists(dir))
    {
        return false;
    }
    plugin_directories_.insert(dir);
    if (!mapnik::util::is_directory(dir))
    {
        return register_datasource(dir);
    }
    bool success = false;
    try
    {
        for (std::string const& file_name : mapnik::util::list_directory(dir))
        {
            if (mapnik::util::is_directory(file_name) && recurse)
            {
                if (register_datasources(file_name, true))
                {
                    success = true;
                }
            }
            else
            {
                std::string base_name = mapnik::util::basename(file_name);
                if (!boost::algorithm::starts_with(base_name,".") &&
                    mapnik::util::is_regular_file(file_name) &&
                    is_input_plugin(file_name))
                {
                    if (register_datasource(file_name))
                    {
                        success = true;
                    }
                }
            }
        }
    }
    catch (std::exception const& ex)
    {
        MAPNIK_LOG_ERROR(datasource_cache) << "register_datasources: " << ex.what();
    }
    return success;
}

bool datasource_cache::register_datasource(std::string const& filename)
{
#ifdef MAPNIK_THREADSAFE
    std::lock_guard<std::recursive_mutex> lock(instance_mutex_);
#endif
    try
    {
        if (!mapnik::util::exists(filename))
        {
            MAPNIK_LOG_ERROR(datasource_cache)
                    << "Cannot load '"
                    << filename << "' (plugin does not exist)";
            return false;
        }
        std::shared_ptr<PluginInfo> plugin = std::make_shared<PluginInfo>(filename,"datasource_name");
        if (plugin->valid())
        {
            if (plugin->name().empty())
            {
                MAPNIK_LOG_ERROR(datasource_cache)
                        << "Problem loading plugin library '"
                        << filename << "' (plugin is lacking compatible interface)";
            }
            else
            {
                if (plugins_.emplace(plugin->name(),plugin).second)
                {
                    MAPNIK_LOG_DEBUG(datasource_cache)
                            << "datasource_cache: Registered="
                            << plugin->name();
                    return true;
                }
            }
        }
        else
        {
            MAPNIK_LOG_ERROR(datasource_cache)
                    << "Problem loading plugin library: "
                    << filename << " (dlopen failed - plugin likely has an unsatisfied dependency or incompatible ABI)";
        }
    }
    catch (std::exception const& ex)
    {
        MAPNIK_LOG_ERROR(datasource_cache)
                << "Exception caught while loading plugin library: "
                << filename << " (" << ex.what() << ")";
    }
    return false;
}

}
<|endoftext|>


<commit_before>/* AM - amplitude modulation of input

   p0 = output start time
   p1 = input start time
   p2 = duration
   p3 = amplitude multiplier *
   p4 = modulation oscillator frequency (Hz) **
   p5 = input channel [optional, default is 0]
   p6 = pan (in percent-to-left form: 0-1) [optional; default is 0]
   p7 = reference to AM modulator wavetable [optional; if missing, must use
        gen 2 ***]

   p3 (amplitude), p4 (mod freq) and p6 (pan) can receive dynamic updates
   from a table or real-time control source.

   * If an old-style gen table 1 is present, its values will be multiplied
   by the p3 amplitude multiplier, even if the latter is dynamic.

   ** For backwards compatibility, if p4 is zero (or its first value is
   zero, if p4 is dynamic), then an old-style gen table 3 must be present,
   and will override any changing values in p4.  However, the preferred
   way is to use either a constant or dynamic pfield for p4 instead of
   the makegen.

   *** If p7 is missing, you must use an old-style gen table 2 for the
   modulator waveform.

   Note that you get either amplitude modulation or ring modulation,
   depending on whether the modulator waveform is unipolar or bipolar
   (unipolar = amp. mod., bipolar = ring mod.).

   To make a unipolar sine wave, you have to add a DC component 90 degrees
   out of phase.  For example, the following creates a sine wave that
   oscillates between 0 and 1:

      wave = maketable("wave3", 1000, 0,.5,90, 1,.5,0)

   Author unknown (probably Brad Garton).
   Modulator frequency table and xtra comments added by John Gibson, 1/12/02.
   rev for v4, JGG, 7/22/04
*/
#include <stdio.h>
#include <stdlib.h>
#include <ugens.h>
#include <Instrument.h>
#include <PField.h>
#include "AM.h"
#include <rt.h>
#include <rtdefs.h>

AM::AM() : Instrument()
{
	in = NULL;
	modosc = NULL;
	freqtable = NULL;
	branch = 0;
}

AM::~AM()
{
	delete [] in;
	delete modosc;
}

int AM::init(double p[], int n_args)
{
	float outskip = p[0];
	float inskip = p[1];
	float dur = p[2];
	inchan = (int) p[5];

	if (rtsetinput(inskip, this) == -1)
		return DONT_SCHEDULE;	// no input
	if (inchan >= inputChannels())
		return die("AM", "You asked for channel %d of a %d-channel file.",
														inchan, inputChannels());
	nsamps = rtsetoutput(outskip, dur, this);
	if (outputChannels() > 2)
		return die("AM", "Can't handle more than 2 output channels.");

	amptable = floc(1);
	if (amptable) {
		int amplen = fsize(1);
		tableset(dur, amplen, amptabs);
	}

	double *wavetable = NULL;
	int tablelen = 0;
	if (n_args > 7) {      // handle table coming in as optional p7 TablePField
		const PField &field = getPField(7);
		tablelen = field.values();
		wavetable = (double *) field;
	}
	if (wavetable == NULL) {
		wavetable = floc(2);
		if (wavetable == NULL)
			return die("AM", "Either use the wavetable pfield (p7) or make "
                    "an old-style gen function in slot 2.");
		tablelen = fsize(2);
	}

	modfreq = p[4];
	modosc = new Ooscili(modfreq, wavetable, tablelen);

	if (modfreq == 0.0) {
		freqtable = floc(3);
		if (freqtable) {
			int len = fsize(3);
      	tableset(dur, len, freqtabs);
		}
		else
			return die("AM", "If p4 is zero, old-style gen table 3 must "
									"contain modulator frequency curve.");
	}

	skip = (int) (SR / (float) resetval);

	return nSamps();
}

int AM::configure()
{
	in = new float [RTBUFSAMPS * inputChannels()];
	return in ? 0 : -1;
}

int AM::run()
{
	const int samps = framesToRun() * inputChannels();

	rtgetin(in, this, samps);

	for (int i = 0; i < samps; i += inputChannels())  {
		if (--branch <= 0) {
			double p[7];
			update(p, 7, kAmp | kFreq | kPan);
			amp = p[3];
			if (amptable)
				amp *= tablei(currentFrame(), amptable, amptabs);
			if (freqtable)
				modfreq = tablei(currentFrame(), freqtable, freqtabs);
			else
				modfreq = p[4];
			modosc->setfreq(modfreq);
			spread = p[6];
			branch = skip;
		}

		float out[2];
		out[0] = in[i + inchan] * modosc->next() * amp;

		if (outputChannels() == 2) {
			out[1] = out[0] * (1.0 - spread);
			out[0] *= spread;
		}

		rtaddout(out);
		increment();
	}
	return framesToRun();
}

Instrument *makeAM()
{
	AM *inst;

	inst = new AM();
	inst->set_bus_config("AM");

	return inst;
}

void
rtprofile()
{
	RT_INTRO("AM",makeAM);
}

<commit_msg>Comment change.<commit_after>/* AM - amplitude modulation of input

   p0 = output start time
   p1 = input start time
   p2 = duration
   p3 = amplitude multiplier *
   p4 = modulation oscillator frequency (Hz) **
   p5 = input channel [optional, default is 0]
   p6 = pan (in percent-to-left form: 0-1) [optional; default is 0]
   p7 = reference to AM modulator wavetable [optional; if missing, must use
        gen 2 ***]

   p3 (amplitude), p4 (mod freq) and p6 (pan) can receive dynamic updates
   from a table or real-time control source.

   Note that you get either amplitude modulation or ring modulation,
   depending on whether the modulator waveform is unipolar or bipolar
   (unipolar = amp. mod., bipolar = ring mod.).

   To make a unipolar sine wave, you have to add a DC component 90 degrees
   out of phase.  For example, the following creates a sine wave that
   oscillates between 0 and 1:

      wave = maketable("wave3", 1000, 0,.5,90, 1,.5,0)

   ---

   Notes about backward compatibility with pre-v4 scores:

   * If an old-style gen table 1 is present, its values will be multiplied
   by the p3 amplitude multiplier, even if the latter is dynamic.

   ** For backwards compatibility, if p4 is zero (or its first value is
   zero, if p4 is dynamic), then an old-style gen table 3 must be present,
   and will override any changing values in p4.  However, the preferred
   way is to use either a constant or dynamic pfield for p4 instead of
   the makegen.

   *** If p7 is missing, you must use an old-style gen table 2 for the
   modulator waveform.

   Author unknown (probably Brad Garton).
   Modulator frequency table and xtra comments added by John Gibson, 1/12/02.
   rev for v4, JGG, 7/22/04
*/
#include <stdio.h>
#include <stdlib.h>
#include <ugens.h>
#include <Instrument.h>
#include <PField.h>
#include "AM.h"
#include <rt.h>
#include <rtdefs.h>

AM::AM() : Instrument()
{
	in = NULL;
	modosc = NULL;
	freqtable = NULL;
	branch = 0;
}

AM::~AM()
{
	delete [] in;
	delete modosc;
}

int AM::init(double p[], int n_args)
{
	float outskip = p[0];
	float inskip = p[1];
	float dur = p[2];
	inchan = (int) p[5];

	if (rtsetinput(inskip, this) == -1)
		return DONT_SCHEDULE;	// no input
	if (inchan >= inputChannels())
		return die("AM", "You asked for channel %d of a %d-channel file.",
														inchan, inputChannels());
	nsamps = rtsetoutput(outskip, dur, this);
	if (outputChannels() > 2)
		return die("AM", "Can't handle more than 2 output channels.");

	amptable = floc(1);
	if (amptable) {
		int amplen = fsize(1);
		tableset(dur, amplen, amptabs);
	}

	double *wavetable = NULL;
	int tablelen = 0;
	if (n_args > 7) {      // handle table coming in as optional p7 TablePField
		const PField &field = getPField(7);
		tablelen = field.values();
		wavetable = (double *) field;
	}
	if (wavetable == NULL) {
		wavetable = floc(2);
		if (wavetable == NULL)
			return die("AM", "Either use the wavetable pfield (p7) or make "
                    "an old-style gen function in slot 2.");
		tablelen = fsize(2);
	}

	modfreq = p[4];
	modosc = new Ooscili(modfreq, wavetable, tablelen);

	if (modfreq == 0.0) {
		freqtable = floc(3);
		if (freqtable) {
			int len = fsize(3);
      	tableset(dur, len, freqtabs);
		}
		else
			return die("AM", "If p4 is zero, old-style gen table 3 must "
									"contain modulator frequency curve.");
	}

	skip = (int) (SR / (float) resetval);

	return nSamps();
}

int AM::configure()
{
	in = new float [RTBUFSAMPS * inputChannels()];
	return in ? 0 : -1;
}

int AM::run()
{
	const int samps = framesToRun() * inputChannels();

	rtgetin(in, this, samps);

	for (int i = 0; i < samps; i += inputChannels())  {
		if (--branch <= 0) {
			double p[7];
			update(p, 7, kAmp | kFreq | kPan);
			amp = p[3];
			if (amptable)
				amp *= tablei(currentFrame(), amptable, amptabs);
			if (freqtable)
				modfreq = tablei(currentFrame(), freqtable, freqtabs);
			else
				modfreq = p[4];
			modosc->setfreq(modfreq);
			spread = p[6];
			branch = skip;
		}

		float out[2];
		out[0] = in[i + inchan] * modosc->next() * amp;

		if (outputChannels() == 2) {
			out[1] = out[0] * (1.0 - spread);
			out[0] *= spread;
		}

		rtaddout(out);
		increment();
	}
	return framesToRun();
}

Instrument *makeAM()
{
	AM *inst;

	inst = new AM();
	inst->set_bus_config("AM");

	return inst;
}

void
rtprofile()
{
	RT_INTRO("AM",makeAM);
}

<|endoftext|>