<commit_before>// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "paymentservertests.h"

#include "optionsmodel.h"
#include "paymentrequestdata.h"

#include "amount.h"
#include "random.h"
#include "script/script.h"
#include "script/standard.h"
#include "util.h"
#include "utilstrencodings.h"

#include <openssl/x509.h>
#include <openssl/x509_vfy.h>

#include <QFileOpenEvent>
#include <QTemporaryFile>

X509 *parse_b64der_cert(const char* cert_data)
{
    std::vector<unsigned char> data = DecodeBase64(cert_data);
    assert(data.size() > 0);
    const unsigned char* dptr = &data[0];
    X509 *cert = d2i_X509(NULL, &dptr, data.size());
    assert(cert);
    return cert;
}

//
// Test payment request handling
//

static SendCoinsRecipient handleRequest(PaymentServer* server, std::vector<unsigned char>& data)
{
    RecipientCatcher sigCatcher;
    QObject::connect(server, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)),
        &sigCatcher, SLOT(getRecipient(SendCoinsRecipient)));

    // Write data to a temp file:
    QTemporaryFile f;
    f.open();
    f.write((const char*)&data[0], data.size());
    f.close();

    // Create a QObject, install event filter from PaymentServer
    // and send a file open event to the object
    QObject object;
    object.installEventFilter(server);
    QFileOpenEvent event(f.fileName());
    // If sending the event fails, this will cause sigCatcher to be empty,
    // which will lead to a test failure anyway.
    QCoreApplication::sendEvent(&object, &event);

    QObject::disconnect(server, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)),
        &sigCatcher, SLOT(getRecipient(SendCoinsRecipient)));

    // Return results from sigCatcher
    return sigCatcher.recipient;
}

void PaymentServerTests::paymentServerTests()
{
    SelectParams(CBaseChainParams::MAIN);
    OptionsModel optionsModel;
    PaymentServer* server = new PaymentServer(NULL, false);
    X509_STORE* caStore = X509_STORE_new();
    X509_STORE_add_cert(caStore, parse_b64der_cert(caCert1_BASE64));
    PaymentServer::LoadRootCAs(caStore);
    server->setOptionsModel(&optionsModel);
    server->uiReady();

    std::vector<unsigned char> data;
    SendCoinsRecipient r;
    QString merchant;

    // Now feed PaymentRequests to server, and observe signals it produces

    // Dogecoin: Disable certificate tests as we don't touch this code, and building test
    // data would take significant effort. Also pending discussion on spec
    // This payment request validates directly against the
    // caCert1 certificate authority:
    /* data = DecodeBase64(paymentrequest1_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString("testmerchant.org"));

    // Signed, but expired, merchant cert in the request:
    data = DecodeBase64(paymentrequest2_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString(""));

    // 10-long certificate chain, all intermediates valid:
    data = DecodeBase64(paymentrequest3_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString("testmerchant8.org"));

    // Long certificate chain, with an expired certificate in the middle:
    data = DecodeBase64(paymentrequest4_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString(""));

    // Validly signed, but by a CA not in our root CA list:
    data = DecodeBase64(paymentrequest5_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString(""));

    // Try again with no root CA's, verifiedMerchant should be empty:
    caStore = X509_STORE_new();
    PaymentServer::LoadRootCAs(caStore);
    data = DecodeBase64(paymentrequest1_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString(""));

    // Load second root certificate
    caStore = X509_STORE_new();
    X509_STORE_add_cert(caStore, parse_b64der_cert(caCert2_BASE64));
    PaymentServer::LoadRootCAs(caStore); */

    QByteArray byteArray;

    // For the tests below we just need the payment request data from
    // paymentrequestdata.h parsed + stored in r.paymentRequest.
    //
    // These tests require us to bypass the following normal client execution flow
    // shown below to be able to explicitly just trigger a certain condition!
    //
    // handleRequest()
    // -> PaymentServer::eventFilter()
    //   -> PaymentServer::handleURIOrFile()
    //     -> PaymentServer::readPaymentRequestFromFile()
    //       -> PaymentServer::processPaymentRequest()

    // Contains a testnet paytoaddress, so payment request network doesn't match client network:
    data = DecodeBase64(paymentrequest1_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized, because network "main" is default, even for
    // uninizialized payment requests and that will fail our test here.
    QVERIFY(r.paymentRequest.IsInitialized());
    QCOMPARE(PaymentServer::verifyNetwork(r.paymentRequest.getDetails()), false);

    // Expired payment request (expires is set to 1 = 1970-01-01 00:00:01):
    data = DecodeBase64(paymentrequest2_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized
    QVERIFY(r.paymentRequest.IsInitialized());
    // compares 1 < GetTime() == false (treated as expired payment request)
    QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true);

    // Unexpired payment request (expires is set to 0x7FFFFFFFFFFFFFFF = max. int64_t):
    // 9223372036854775807 (uint64), 9223372036854775807 (int64_t) and -1 (int32_t)
    // -1 is 1969-12-31 23:59:59 (for a 32 bit time values)
    data = DecodeBase64(paymentrequest3_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized
    QVERIFY(r.paymentRequest.IsInitialized());
    // compares 9223372036854775807 < GetTime() == false (treated as unexpired payment request)
    QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), false);

    // Unexpired payment request (expires is set to 0x8000000000000000 > max. int64_t, allowed uint64):
    // 9223372036854775808 (uint64), -9223372036854775808 (int64_t) and 0 (int32_t)
    // 0 is 1970-01-01 00:00:00 (for a 32 bit time values)
    data = DecodeBase64(paymentrequest4_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized
    QVERIFY(r.paymentRequest.IsInitialized());
    // compares -9223372036854775808 < GetTime() == true (treated as expired payment request)
    QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true);

    // Test BIP70 DoS protection:
    unsigned char randData[BIP70_MAX_PAYMENTREQUEST_SIZE + 1];
    GetRandBytes(randData, sizeof(randData));
    // Write data to a temp file:
    QTemporaryFile tempFile;
    tempFile.open();
    tempFile.write((const char*)randData, sizeof(randData));
    tempFile.close();
    // compares 50001 <= BIP70_MAX_PAYMENTREQUEST_SIZE == false
    QCOMPARE(PaymentServer::verifySize(tempFile.size()), false);

    // Payment request with amount overflow (amount is set to 21000001 BTC):
    data = DecodeBase64(paymentrequest5_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized
    QVERIFY(r.paymentRequest.IsInitialized());
    // Extract address and amount from the request
    QList<std::pair<CScript, CAmount> > sendingTos = r.paymentRequest.getPayTo();
    Q_FOREACH (const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
        CTxDestination dest;
        if (ExtractDestination(sendingTo.first, dest))
            QCOMPARE(PaymentServer::verifyAmount(sendingTo.second), false);
    }

    delete server;
}

void RecipientCatcher::getRecipient(SendCoinsRecipient r)
{
    recipient = r;
}
<commit_msg>qt-tests: Disable payment server test that moves 21M+1 coins.<commit_after>// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "paymentservertests.h"

#include "optionsmodel.h"
#include "paymentrequestdata.h"

#include "amount.h"
#include "random.h"
#include "script/script.h"
#include "script/standard.h"
#include "util.h"
#include "utilstrencodings.h"

#include <openssl/x509.h>
#include <openssl/x509_vfy.h>

#include <QFileOpenEvent>
#include <QTemporaryFile>

X509 *parse_b64der_cert(const char* cert_data)
{
    std::vector<unsigned char> data = DecodeBase64(cert_data);
    assert(data.size() > 0);
    const unsigned char* dptr = &data[0];
    X509 *cert = d2i_X509(NULL, &dptr, data.size());
    assert(cert);
    return cert;
}

//
// Test payment request handling
//

static SendCoinsRecipient handleRequest(PaymentServer* server, std::vector<unsigned char>& data)
{
    RecipientCatcher sigCatcher;
    QObject::connect(server, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)),
        &sigCatcher, SLOT(getRecipient(SendCoinsRecipient)));

    // Write data to a temp file:
    QTemporaryFile f;
    f.open();
    f.write((const char*)&data[0], data.size());
    f.close();

    // Create a QObject, install event filter from PaymentServer
    // and send a file open event to the object
    QObject object;
    object.installEventFilter(server);
    QFileOpenEvent event(f.fileName());
    // If sending the event fails, this will cause sigCatcher to be empty,
    // which will lead to a test failure anyway.
    QCoreApplication::sendEvent(&object, &event);

    QObject::disconnect(server, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)),
        &sigCatcher, SLOT(getRecipient(SendCoinsRecipient)));

    // Return results from sigCatcher
    return sigCatcher.recipient;
}

void PaymentServerTests::paymentServerTests()
{
    SelectParams(CBaseChainParams::MAIN);
    OptionsModel optionsModel;
    PaymentServer* server = new PaymentServer(NULL, false);
    X509_STORE* caStore = X509_STORE_new();
    X509_STORE_add_cert(caStore, parse_b64der_cert(caCert1_BASE64));
    PaymentServer::LoadRootCAs(caStore);
    server->setOptionsModel(&optionsModel);
    server->uiReady();

    std::vector<unsigned char> data;
    SendCoinsRecipient r;
    QString merchant;

    // Now feed PaymentRequests to server, and observe signals it produces

    // Dogecoin: Disable certificate tests as we don't touch this code, and building test
    // data would take significant effort. Also pending discussion on spec
    // This payment request validates directly against the
    // caCert1 certificate authority:
    /* data = DecodeBase64(paymentrequest1_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString("testmerchant.org"));

    // Signed, but expired, merchant cert in the request:
    data = DecodeBase64(paymentrequest2_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString(""));

    // 10-long certificate chain, all intermediates valid:
    data = DecodeBase64(paymentrequest3_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString("testmerchant8.org"));

    // Long certificate chain, with an expired certificate in the middle:
    data = DecodeBase64(paymentrequest4_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString(""));

    // Validly signed, but by a CA not in our root CA list:
    data = DecodeBase64(paymentrequest5_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString(""));

    // Try again with no root CA's, verifiedMerchant should be empty:
    caStore = X509_STORE_new();
    PaymentServer::LoadRootCAs(caStore);
    data = DecodeBase64(paymentrequest1_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString(""));

    // Load second root certificate
    caStore = X509_STORE_new();
    X509_STORE_add_cert(caStore, parse_b64der_cert(caCert2_BASE64));
    PaymentServer::LoadRootCAs(caStore); */

    QByteArray byteArray;

    // For the tests below we just need the payment request data from
    // paymentrequestdata.h parsed + stored in r.paymentRequest.
    //
    // These tests require us to bypass the following normal client execution flow
    // shown below to be able to explicitly just trigger a certain condition!
    //
    // handleRequest()
    // -> PaymentServer::eventFilter()
    //   -> PaymentServer::handleURIOrFile()
    //     -> PaymentServer::readPaymentRequestFromFile()
    //       -> PaymentServer::processPaymentRequest()

    // Contains a testnet paytoaddress, so payment request network doesn't match client network:
    data = DecodeBase64(paymentrequest1_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized, because network "main" is default, even for
    // uninizialized payment requests and that will fail our test here.
    QVERIFY(r.paymentRequest.IsInitialized());
    QCOMPARE(PaymentServer::verifyNetwork(r.paymentRequest.getDetails()), false);

    // Expired payment request (expires is set to 1 = 1970-01-01 00:00:01):
    data = DecodeBase64(paymentrequest2_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized
    QVERIFY(r.paymentRequest.IsInitialized());
    // compares 1 < GetTime() == false (treated as expired payment request)
    QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true);

    // Unexpired payment request (expires is set to 0x7FFFFFFFFFFFFFFF = max. int64_t):
    // 9223372036854775807 (uint64), 9223372036854775807 (int64_t) and -1 (int32_t)
    // -1 is 1969-12-31 23:59:59 (for a 32 bit time values)
    data = DecodeBase64(paymentrequest3_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized
    QVERIFY(r.paymentRequest.IsInitialized());
    // compares 9223372036854775807 < GetTime() == false (treated as unexpired payment request)
    QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), false);

    // Unexpired payment request (expires is set to 0x8000000000000000 > max. int64_t, allowed uint64):
    // 9223372036854775808 (uint64), -9223372036854775808 (int64_t) and 0 (int32_t)
    // 0 is 1970-01-01 00:00:00 (for a 32 bit time values)
    data = DecodeBase64(paymentrequest4_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized
    QVERIFY(r.paymentRequest.IsInitialized());
    // compares -9223372036854775808 < GetTime() == true (treated as expired payment request)
    QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true);

    // Test BIP70 DoS protection:
    unsigned char randData[BIP70_MAX_PAYMENTREQUEST_SIZE + 1];
    GetRandBytes(randData, sizeof(randData));
    // Write data to a temp file:
    QTemporaryFile tempFile;
    tempFile.open();
    tempFile.write((const char*)randData, sizeof(randData));
    tempFile.close();
    // compares 50001 <= BIP70_MAX_PAYMENTREQUEST_SIZE == false
    QCOMPARE(PaymentServer::verifySize(tempFile.size()), false);

    // Payment request with amount overflow (amount is set to 21000001 BTC):
    /* PL: This doesn't work for Dogecoin (as there is no actual maximum coins)
     *     I'm disabling this test for now.
    data = DecodeBase64(paymentrequest5_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized
    QVERIFY(r.paymentRequest.IsInitialized());
    // Extract address and amount from the request
    QList<std::pair<CScript, CAmount> > sendingTos = r.paymentRequest.getPayTo();
    Q_FOREACH (const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
        CTxDestination dest;
        if (ExtractDestination(sendingTo.first, dest))
            QCOMPARE(PaymentServer::verifyAmount(sendingTo.second), false);
    }
    */

    delete server;
}

void RecipientCatcher::getRecipient(SendCoinsRecipient r)
{
    recipient = r;
}
<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#pragma once

#include <chrono>
#include <cstddef>
#include <string>
#include <vector>

#include "caf/atom.hpp"
#include "caf/string_view.hpp"
#include "caf/timestamp.hpp"

// -- hard-coded default values for various CAF options ------------------------

namespace caf {
namespace defaults {

namespace stream {

extern const timespan desired_batch_complexity;
extern const timespan max_batch_delay;
extern const timespan credit_round_interval;

} // namespace streaming

namespace scheduler {

extern const atom_value policy;
extern string_view profiling_output_file;
extern const size_t max_threads;
extern const size_t max_throughput;
extern const timespan profiling_resolution;

} // namespace scheduler

namespace work_stealing {

extern const size_t aggressive_poll_attempts;
extern const size_t aggressive_steal_interval;
extern const size_t moderate_poll_attempts;
extern const size_t moderate_steal_interval;
extern const timespan moderate_sleep_duration;
extern const size_t relaxed_steal_interval;
extern const timespan relaxed_sleep_duration;

} // namespace work_stealing

namespace logger {

extern string_view component_filter;
extern const atom_value console;
extern string_view console_format;
extern const atom_value console_verbosity;
extern string_view file_format;
extern string_view file_name;
extern const atom_value file_verbosity;

} // namespace logger

namespace middleman {

extern std::vector<std::string> app_identifiers;
extern const atom_value network_backend;
extern const size_t max_consecutive_reads;
extern const size_t heartbeat_interval;
extern const size_t cached_udp_buffers;
extern const size_t max_pending_msgs;
extern const size_t workers;

} // namespace middleman

} // namespace defaults
} // namespace caf
<commit_msg>Mark hardcoded defaults as explicitly visible<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#pragma once

#include <chrono>
#include <cstddef>
#include <string>
#include <vector>

#include "caf/config.hpp"
#include "caf/atom.hpp"
#include "caf/string_view.hpp"
#include "caf/timestamp.hpp"

// -- hard-coded default values for various CAF options ------------------------

namespace caf {
namespace defaults {

namespace stream {

extern CAF_API const timespan desired_batch_complexity;
extern CAF_API const timespan max_batch_delay;
extern CAF_API const timespan credit_round_interval;

} // namespace streaming

namespace scheduler {

extern CAF_API const atom_value policy;
extern CAF_API string_view profiling_output_file;
extern CAF_API const size_t max_threads;
extern CAF_API const size_t max_throughput;
extern CAF_API const timespan profiling_resolution;

} // namespace scheduler

namespace work_stealing {

extern CAF_API const size_t aggressive_poll_attempts;
extern CAF_API const size_t aggressive_steal_interval;
extern CAF_API const size_t moderate_poll_attempts;
extern CAF_API const size_t moderate_steal_interval;
extern CAF_API const timespan moderate_sleep_duration;
extern CAF_API const size_t relaxed_steal_interval;
extern CAF_API const timespan relaxed_sleep_duration;

} // namespace work_stealing

namespace logger {

extern CAF_API string_view component_filter;
extern CAF_API const atom_value console;
extern CAF_API string_view console_format;
extern CAF_API const atom_value console_verbosity;
extern CAF_API string_view file_format;
extern CAF_API string_view file_name;
extern CAF_API const atom_value file_verbosity;

} // namespace logger

namespace middleman {

extern CAF_API std::vector<std::string> app_identifiers;
extern CAF_API const atom_value network_backend;
extern CAF_API const size_t max_consecutive_reads;
extern CAF_API const size_t heartbeat_interval;
extern CAF_API const size_t cached_udp_buffers;
extern CAF_API const size_t max_pending_msgs;
extern CAF_API const size_t workers;

} // namespace middleman

} // namespace defaults
} // namespace caf
<|endoftext|>


<commit_before>/*
 * cf. M. Hjorth-Jensen, Computational Physics, University of Oslo (2015)
 * http://www.mn.uio.no/fysikk/english/people/aca/mhjensen/
 * Ernest Yeung (I typed it up and made modifications)
 * ernestyalumni@gmail.com
 * MIT License
 * cf. Chapter 3 Numerical differentiation and interpolation
 * 3.1 Numerical Differentiation
 * 3.1.1.1 Initializations and main program
 */
/*
**   Program to compute the second derivative of exp(x).
**   Three calling functions are included
**   in this version.  In one function we read in the data from screen,
**   the next function computes the second derivative
**   while the last function prints out data to screen.
*/
using namespace std;
#include <iostream>

void initialize(double *, double *, int *);
void second_derivative(int, double, double, double *, double *);
void output(double *, double *, double, int);

int main()
{
  // declarations of variables
  int number_of_steps;
  double x, initial_step;
  double *h_step, *computed_derivative;
  // read in input data from screen
  initialize(&initial_step, &x, &number_of_steps);
  // allocate space in memory for the one-dimensional arrays
  // h_step and computed_derivative
  h_step = new double[number_of_steps];
  computed_derivative = new double[number_of_steps];
  // compute the second derivative of exp(x)
  second_derivative(number_of_steps, x, initial_step, h_step, computed_derivative);
  // Then we print the results to file
  output(h_step, computed_derivative, x, number_of_steps);
  // free memory
  delete [] h_step;
  delete [] computed_derivative;
  return 0;
} // end main program

<commit_msg>program1.cpp compiles and works<commit_after>/*
 * cf. M. Hjorth-Jensen, Computational Physics, University of Oslo (2015)
 * http://www.mn.uio.no/fysikk/english/people/aca/mhjensen/
 * Ernest Yeung (I typed it up and made modifications)
 * ernestyalumni@gmail.com
 * MIT License
 * cf. Chapter 3 Numerical differentiation and interpolation
 * 3.1 Numerical Differentiation
 * 3.1.1.1 Initializations and main program
 */
/*
**   Program to compute the second derivative of exp(x).
**   Three calling functions are included
**   in this version.  In one function we read in the data from screen,
**   the next function computes the second derivative
**   while the last function prints out data to screen.
*/
/*
** Big note - at least to me, program1.cpp in pp. 51 of Hjorth-Jensen's notes
** code appears incomplete, and wouldn't compile (I don't think).  I looked here:
** https://github.com/CompPhysics/ComputationalPhysicsMSU/blob/master/doc/Programs/LecturePrograms/programs/Classes/cpp/program1.cpp
** and the entire code for program1.cpp appears there
*/

using namespace std;
// #include <iostream> I don't think this is correct of Hjorth-Jensen since printf,scanf are used
#include <stdio.h>
#include <cmath>

void initialize(double *, double *, int *);
void second_derivative(int, double, double, double *, double *);
void output(double *, double *, double, int);

int main()
{
  // declarations of variables

  int number_of_steps;
  double x, initial_step;
  double *h_step, *computed_derivative;

  // read in input data from screen

  initialize(&initial_step, &x, &number_of_steps);

  // allocate space in memory for the one-dimensional arrays
  // h_step and computed_derivative

  h_step = new double[number_of_steps];
  computed_derivative = new double[number_of_steps];

  // compute the second derivative of exp(x)

  second_derivative(number_of_steps, x, initial_step, h_step, computed_derivative);

  // Then we print the results to file

  output(h_step, computed_derivative, x, number_of_steps);
  // free memory
  delete [] h_step;
  delete [] computed_derivative;
  return 0;
} // end main program

//   Read in from screen the air temp, the number of steps
//   final time and the initial temperature */

void initialize(double *initial_step, double *x, int *number_of_steps)
{
  printf("Read in from screen initial step, x, and number of steps\n");
  scanf("%lf %lf %d", initial_step, x, number_of_steps);
  return;
}  // end of function initialize

// This function computes the second derivative

void second_derivative( int number_of_steps, double x, double initial_step,
			double *h_step, double *computed_derivative)
{
  int counter;
  double h;

  //    calculate the step size
  //    initialize the derivative, y and x (in minutes)
  //    and iteration counter

  h = initial_step;

  // start computing for different step sizes
  for (counter=0; counter < number_of_steps; counter++ )
    {

      // setup arrays with derivatives and step sizes

      h_step[counter] = h;
      computed_derivative[counter] =
	(exp(x+h)-2.*exp(x) + exp(x-h))/(h*h);
      h = h*0.5;
    } // end of do loop

  return;

} // end of function second derivative

// function to write out the final results
void output(double *h_step, double *computed_derivative, double x,
	    int number_of_steps)
{
  int i;
  FILE *output_file;
  output_file = fopen("out.dat", "w");
  for (i=0; i < number_of_steps; i++)
    {
      fprintf(output_file, "%12.5E %12.5E \n",
	      log10(h_step[i]),log10(fabs(computed_derivative[i]-exp(x))/exp(x)));
    }
  fclose(output_file);

} // end of function output

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $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 either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** 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.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "mainwindow.h"
#include "stationdialog.h"

#include <QtCore/QSettings>
#include <QtCore/QTimer>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QBitmap>
#include <QtGui/QLinearGradient>
#include <QtGui/QMouseEvent>
#include <QtGui/QPainter>

MainWindow::MainWindow()
    : QWidget(0, Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint)
{
    QAction *quitAction = new QAction(tr("E&xit"), this);
    quitAction->setShortcut(tr("Ctrl+Q"));
    connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));

    QAction *configAction = new QAction(tr("&Select station..."), this);
    configAction->setShortcut(tr("Ctrl+C"));
    connect(configAction, SIGNAL(triggered()), this, SLOT(configure()));

    addAction(configAction);
    addAction(quitAction);

    setContextMenuPolicy(Qt::ActionsContextMenu);

    setWindowTitle(tr("Traffic Info Oslo"));

    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(updateTimeInformation()));
    timer->start(1000*60);

    const QSettings settings("Qt Software", "trafficinfo");
    m_station = StationInformation(settings.value("stationId", "03012130").toString(),
                                   settings.value("stationName", "Nydalen [T-bane] (OSL)").toString());
    m_lines = settings.value("lines", QStringList()).toStringList();

    updateTimeInformation();
}

MainWindow::~MainWindow()
{
    QSettings settings("Qt Software", "trafficinfo");
    settings.setValue("stationId", m_station.id());
    settings.setValue("stationName", m_station.name());
    settings.setValue("lines", m_lines);
}

QSize MainWindow::sizeHint() const
{
    return QSize(300, 200);
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton) {
        move(event->globalPos() - m_dragPosition);
        event->accept();
    }
}

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        m_dragPosition = event->globalPos() - frameGeometry().topLeft();
        event->accept();
    }
}

void MainWindow::paintEvent(QPaintEvent*)
{
    QLinearGradient gradient(QPoint(width()/2, 0), QPoint(width()/2, height()));
    const QColor qtGreen(102, 176, 54);
    gradient.setColorAt(0, qtGreen.dark());
    gradient.setColorAt(0.5, qtGreen);
    gradient.setColorAt(1, qtGreen.dark());

    QPainter p(this);
    p.fillRect(0, 0, width(), height(), gradient);

    QFont headerFont("Sans Serif", 12, QFont::Bold);
    QFont normalFont("Sans Serif", 9, QFont::Normal);

    // draw it twice for shadow effect
    p.setFont(headerFont);
    QRect headerRect(1, 1, width(), 25);
    p.setPen(Qt::black);
    p.drawText(headerRect, Qt::AlignCenter, m_station.name());

    headerRect.moveTopLeft(QPoint(0, 0));
    p.setPen(Qt::white);
    p.drawText(headerRect, Qt::AlignCenter, m_station.name());

    p.setFont(normalFont);
    int pos = 40;
    for (int i = 0; i < m_times.count() && i < 9; ++i) {
        p.setPen(Qt::black);
        p.drawText(51, pos + 1, m_times.at(i).time());
        p.drawText(101, pos + 1, m_times.at(i).direction());

        p.setPen(Qt::white);
        p.drawText(50, pos, m_times.at(i).time());
        p.drawText(100, pos, m_times.at(i).direction());

        pos += 18;
    }
}

void MainWindow::resizeEvent(QResizeEvent*)
{
    QBitmap maskBitmap(width(), height());
    maskBitmap.clear();

    QPainter p(&maskBitmap);
    p.setBrush(Qt::black);
    p.drawRoundRect(0, 0, width(), height(), 20, 30);
    p.end();

    setMask(maskBitmap);
}

void MainWindow::updateTimeInformation()
{
    TimeQuery query;
    m_times = query.query(m_station.id(), m_lines, QDateTime::currentDateTime());

    update();
}

void MainWindow::configure()
{
    StationDialog dlg(m_station.name(), m_lines, this);
    if (dlg.exec()) {
        m_station = dlg.selectedStation();
        m_lines = dlg.lineNumbers();
        updateTimeInformation();
    }
}
<commit_msg>Make the traffic info example not hit the server every minute.<commit_after>/****************************************************************************
**
** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $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 either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** 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.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "mainwindow.h"
#include "stationdialog.h"

#include <QtCore/QSettings>
#include <QtCore/QTimer>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QBitmap>
#include <QtGui/QLinearGradient>
#include <QtGui/QMouseEvent>
#include <QtGui/QPainter>

MainWindow::MainWindow()
    : QWidget(0, Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint)
{
    QAction *quitAction = new QAction(tr("E&xit"), this);
    quitAction->setShortcut(tr("Ctrl+Q"));
    connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));

    QAction *configAction = new QAction(tr("&Select station..."), this);
    configAction->setShortcut(tr("Ctrl+C"));
    connect(configAction, SIGNAL(triggered()), this, SLOT(configure()));

    addAction(configAction);
    addAction(quitAction);

    setContextMenuPolicy(Qt::ActionsContextMenu);

    setWindowTitle(tr("Traffic Info Oslo"));

    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(updateTimeInformation()));
    timer->start(1000*60*5);

    const QSettings settings("Qt Software", "trafficinfo");
    m_station = StationInformation(settings.value("stationId", "03012130").toString(),
                                   settings.value("stationName", "Nydalen [T-bane] (OSL)").toString());
    m_lines = settings.value("lines", QStringList()).toStringList();

    updateTimeInformation();
}

MainWindow::~MainWindow()
{
    QSettings settings("Qt Software", "trafficinfo");
    settings.setValue("stationId", m_station.id());
    settings.setValue("stationName", m_station.name());
    settings.setValue("lines", m_lines);
}

QSize MainWindow::sizeHint() const
{
    return QSize(300, 200);
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton) {
        move(event->globalPos() - m_dragPosition);
        event->accept();
    }
}

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        m_dragPosition = event->globalPos() - frameGeometry().topLeft();
        event->accept();
    }
}

void MainWindow::paintEvent(QPaintEvent*)
{
    QLinearGradient gradient(QPoint(width()/2, 0), QPoint(width()/2, height()));
    const QColor qtGreen(102, 176, 54);
    gradient.setColorAt(0, qtGreen.dark());
    gradient.setColorAt(0.5, qtGreen);
    gradient.setColorAt(1, qtGreen.dark());

    QPainter p(this);
    p.fillRect(0, 0, width(), height(), gradient);

    QFont headerFont("Sans Serif", 12, QFont::Bold);
    QFont normalFont("Sans Serif", 9, QFont::Normal);

    // draw it twice for shadow effect
    p.setFont(headerFont);
    QRect headerRect(1, 1, width(), 25);
    p.setPen(Qt::black);
    p.drawText(headerRect, Qt::AlignCenter, m_station.name());

    headerRect.moveTopLeft(QPoint(0, 0));
    p.setPen(Qt::white);
    p.drawText(headerRect, Qt::AlignCenter, m_station.name());

    p.setFont(normalFont);
    int pos = 40;
    for (int i = 0; i < m_times.count() && i < 9; ++i) {
        p.setPen(Qt::black);
        p.drawText(51, pos + 1, m_times.at(i).time());
        p.drawText(101, pos + 1, m_times.at(i).direction());

        p.setPen(Qt::white);
        p.drawText(50, pos, m_times.at(i).time());
        p.drawText(100, pos, m_times.at(i).direction());

        pos += 18;
    }
}

void MainWindow::resizeEvent(QResizeEvent*)
{
    QBitmap maskBitmap(width(), height());
    maskBitmap.clear();

    QPainter p(&maskBitmap);
    p.setBrush(Qt::black);
    p.drawRoundRect(0, 0, width(), height(), 20, 30);
    p.end();

    setMask(maskBitmap);
}

void MainWindow::updateTimeInformation()
{
    TimeQuery query;
    m_times = query.query(m_station.id(), m_lines, QDateTime::currentDateTime());

    update();
}

void MainWindow::configure()
{
    StationDialog dlg(m_station.name(), m_lines, this);
    if (dlg.exec()) {
        m_station = dlg.selectedStation();
        m_lines = dlg.lineNumbers();
        updateTimeInformation();
    }
}
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file EthereumHost.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */

#include "EthereumHost.h"

#include <set>
#include <chrono>
#include <thread>
#include <libdevcore/Common.h>
#include <libp2p/Host.h>
#include <libp2p/Session.h>
#include <libethcore/Exceptions.h>
#include "BlockChain.h"
#include "TransactionQueue.h"
#include "BlockQueue.h"
#include "EthereumPeer.h"
#include "DownloadMan.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace p2p;

EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId):
	HostCapability<EthereumPeer>(),
	Worker		("ethsync"),
	m_chain		(_ch),
	m_tq		(_tq),
	m_bq		(_bq),
	m_networkId	(_networkId)
{
	m_latestBlockSent = _ch.currentHash();
}

EthereumHost::~EthereumHost()
{
	for (auto i: peerSessions())
		i.first->cap<EthereumPeer>().get()->abortSync();
}

bool EthereumHost::ensureInitialised()
{
	if (!m_latestBlockSent)
	{
		// First time - just initialise.
		m_latestBlockSent = m_chain.currentHash();
		clog(NetNote) << "Initialising: latest=" << m_latestBlockSent.abridged();

		for (auto const& i: m_tq.transactions())
			m_transactionsSent.insert(i.first);
		return true;
	}
	return false;
}

void EthereumHost::noteNeedsSyncing(EthereumPeer* _who)
{
	// if already downloading hash-chain, ignore.
	if (isSyncing())
	{
		clog(NetAllDetail) << "Sync in progress: Just set to help out.";
		if (m_syncer->m_asking == Asking::Blocks)
			_who->transition(Asking::Blocks);
	}
	else
		// otherwise check to see if we should be downloading...
		_who->attemptSync();
}

void EthereumHost::changeSyncer(EthereumPeer* _syncer)
{
	if (_syncer)
		clog(NetAllDetail) << "Changing syncer to" << _syncer->session()->socketId();
	else
		clog(NetAllDetail) << "Clearing syncer.";

	m_syncer = _syncer;
	if (isSyncing())
	{
		if (_syncer->m_asking == Asking::Blocks)
			for (auto j: peerSessions())
			{
				auto e = j.first->cap<EthereumPeer>().get();
				if (e != _syncer && e->m_asking == Asking::Nothing)
					e->transition(Asking::Blocks);
			}
	}
	else
	{
		// start grabbing next hash chain if there is one.
		for (auto j: peerSessions())
		{
			j.first->cap<EthereumPeer>()->attemptSync();
			if (isSyncing())
				return;
		}
		clog(NetNote) << "No more peers to sync with.";
	}
}

void EthereumHost::noteDoneBlocks(EthereumPeer* _who, bool _clemency)
{
	if (m_man.isComplete())
	{
		// Done our chain-get.
		clog(NetNote) << "Chain download complete.";
		// 1/100th for each useful block hash.
		_who->addRating(m_man.chain().size() / 100);
		m_man.reset();
	}
	else if (_who->isSyncing())
	{
		if (_clemency)
			clog(NetNote) << "Chain download failed. Aborted while incomplete.";
		else
		{
			// Done our chain-get.
			clog(NetWarn) << "Chain download failed. Peer with blocks didn't have them all. This peer is bad and should be punished.";
			clog(NetWarn) << m_man.remaining();
			clog(NetWarn) << "WOULD BAN.";
//			m_banned.insert(_who->session()->id());			// We know who you are!
//			_who->disable("Peer sent hashes but was unable to provide the blocks.");
		}
		m_man.reset();
	}
}

void EthereumHost::reset()
{
	if (m_syncer)
		m_syncer->abortSync();

	m_man.resetToChain(h256s());

	m_latestBlockSent = h256();
	m_transactionsSent.clear();
}

void EthereumHost::doWork()
{
	bool netChange = ensureInitialised();
	auto h = m_chain.currentHash();
	// If we've finished our initial sync (including getting all the blocks into the chain so as to reduce invalid transactions), start trading transactions & blocks
	if (!isSyncing() && m_chain.isKnown(m_latestBlockSent))
	{
		if (m_newTransactions)
		{
			m_newTransactions = false;
			maintainTransactions();
		}
		if (m_newBlocks)
		{
			m_newBlocks = false;
			maintainBlocks(h);
		}
	}

	for (auto p: peerSessions())
		if (shared_ptr<EthereumPeer> const& ep = p.first->cap<EthereumPeer>())
			ep->tick();

//	return netChange;
	// TODO: Figure out what to do with netChange.
	(void)netChange;
}

void EthereumHost::maintainTransactions()
{
	// Send any new transactions.
	map<std::shared_ptr<EthereumPeer>, h256s> peerTransactions;
	auto ts = m_tq.transactions();
	for (auto const& i: ts)
	{
		bool unsent = !m_transactionsSent.count(i.first);
		for (auto const& p: randomSelection(25, [&](EthereumPeer* p) { return p->m_requireTransactions || (unsent && !p->m_knownTransactions.count(i.first)); }))
			peerTransactions[p].push_back(i.first);
	}
	for (auto const& t: ts)
		m_transactionsSent.insert(t.first);
	for (auto p: peerSessions())
		if (auto ep = p.first->cap<EthereumPeer>())
		{
			bytes b;
			unsigned n = 0;
			for (auto const& h: peerTransactions[ep])
			{
				ep->m_knownTransactions.insert(h);
				b += ts[h].rlp();
				++n;
			}

			ep->clearKnownTransactions();

			if (n || ep->m_requireTransactions)
			{
				RLPStream ts;
				ep->prep(ts, TransactionsPacket, n).appendRaw(b, n);
				ep->sealAndSend(ts);
			}
			ep->m_requireTransactions = false;
		}
}

std::vector<std::shared_ptr<EthereumPeer>> EthereumHost::randomSelection(unsigned _percent, std::function<bool(EthereumPeer*)> const& _allow)
{
	std::vector<std::shared_ptr<EthereumPeer>> candidates;
	candidates.reserve(peerSessions().size());
	for (auto const& j: peerSessions())
	{
		auto pp = j.first->cap<EthereumPeer>();
		if (_allow(pp.get()))
			candidates.push_back(pp);
	}

	std::vector<std::shared_ptr<EthereumPeer>> ret;
	for (unsigned i = (peerSessions().size() * _percent + 99) / 100; i-- && candidates.size();)
	{
		unsigned n = rand() % candidates.size();
		ret.push_back(std::move(candidates[n]));
		candidates.erase(candidates.begin() + n);
	}
	return ret;
}

void EthereumHost::maintainBlocks(h256 _currentHash)
{
	// Send any new blocks.
	auto detailsFrom = m_chain.details(m_latestBlockSent);
	auto detailsTo = m_chain.details(_currentHash);
	if (detailsFrom.totalDifficulty < detailsTo.totalDifficulty)
	{
		if (diff(detailsFrom.number, detailsTo.number) < 20)
		{
			// don't be sending more than 20 "new" blocks. if there are any more we were probably waaaay behind.
			clog(NetMessageSummary) << "Sending a new block (current is" << _currentHash << ", was" << m_latestBlockSent << ")";

			h256s blocks = get<0>(m_chain.treeRoute(m_latestBlockSent, _currentHash, false, false, true));

			for (auto const& p: randomSelection(25, [&](EthereumPeer* p){return !p->m_knownBlocks.count(_currentHash); }))
				for (auto const& b: blocks)
					if (!p->m_knownBlocks.count(b))
					{
						RLPStream ts;
						p->prep(ts, NewBlockPacket, 2).appendRaw(m_chain.block(b), 1).append(m_chain.details(b).totalDifficulty);

						Guard l(p->x_knownBlocks);
						p->sealAndSend(ts);
						p->m_knownBlocks.clear();
					}
		}
		m_latestBlockSent = _currentHash;
	}
}
<commit_msg>Broadcast everything to everyone.<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file EthereumHost.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */

#include "EthereumHost.h"

#include <set>
#include <chrono>
#include <thread>
#include <libdevcore/Common.h>
#include <libp2p/Host.h>
#include <libp2p/Session.h>
#include <libethcore/Exceptions.h>
#include "BlockChain.h"
#include "TransactionQueue.h"
#include "BlockQueue.h"
#include "EthereumPeer.h"
#include "DownloadMan.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace p2p;

EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId):
	HostCapability<EthereumPeer>(),
	Worker		("ethsync"),
	m_chain		(_ch),
	m_tq		(_tq),
	m_bq		(_bq),
	m_networkId	(_networkId)
{
	m_latestBlockSent = _ch.currentHash();
}

EthereumHost::~EthereumHost()
{
	for (auto i: peerSessions())
		i.first->cap<EthereumPeer>().get()->abortSync();
}

bool EthereumHost::ensureInitialised()
{
	if (!m_latestBlockSent)
	{
		// First time - just initialise.
		m_latestBlockSent = m_chain.currentHash();
		clog(NetNote) << "Initialising: latest=" << m_latestBlockSent.abridged();

		for (auto const& i: m_tq.transactions())
			m_transactionsSent.insert(i.first);
		return true;
	}
	return false;
}

void EthereumHost::noteNeedsSyncing(EthereumPeer* _who)
{
	// if already downloading hash-chain, ignore.
	if (isSyncing())
	{
		clog(NetAllDetail) << "Sync in progress: Just set to help out.";
		if (m_syncer->m_asking == Asking::Blocks)
			_who->transition(Asking::Blocks);
	}
	else
		// otherwise check to see if we should be downloading...
		_who->attemptSync();
}

void EthereumHost::changeSyncer(EthereumPeer* _syncer)
{
	if (_syncer)
		clog(NetAllDetail) << "Changing syncer to" << _syncer->session()->socketId();
	else
		clog(NetAllDetail) << "Clearing syncer.";

	m_syncer = _syncer;
	if (isSyncing())
	{
		if (_syncer->m_asking == Asking::Blocks)
			for (auto j: peerSessions())
			{
				auto e = j.first->cap<EthereumPeer>().get();
				if (e != _syncer && e->m_asking == Asking::Nothing)
					e->transition(Asking::Blocks);
			}
	}
	else
	{
		// start grabbing next hash chain if there is one.
		for (auto j: peerSessions())
		{
			j.first->cap<EthereumPeer>()->attemptSync();
			if (isSyncing())
				return;
		}
		clog(NetNote) << "No more peers to sync with.";
	}
}

void EthereumHost::noteDoneBlocks(EthereumPeer* _who, bool _clemency)
{
	if (m_man.isComplete())
	{
		// Done our chain-get.
		clog(NetNote) << "Chain download complete.";
		// 1/100th for each useful block hash.
		_who->addRating(m_man.chain().size() / 100);
		m_man.reset();
	}
	else if (_who->isSyncing())
	{
		if (_clemency)
			clog(NetNote) << "Chain download failed. Aborted while incomplete.";
		else
		{
			// Done our chain-get.
			clog(NetWarn) << "Chain download failed. Peer with blocks didn't have them all. This peer is bad and should be punished.";
			clog(NetWarn) << m_man.remaining();
			clog(NetWarn) << "WOULD BAN.";
//			m_banned.insert(_who->session()->id());			// We know who you are!
//			_who->disable("Peer sent hashes but was unable to provide the blocks.");
		}
		m_man.reset();
	}
}

void EthereumHost::reset()
{
	if (m_syncer)
		m_syncer->abortSync();

	m_man.resetToChain(h256s());

	m_latestBlockSent = h256();
	m_transactionsSent.clear();
}

void EthereumHost::doWork()
{
	bool netChange = ensureInitialised();
	auto h = m_chain.currentHash();
	// If we've finished our initial sync (including getting all the blocks into the chain so as to reduce invalid transactions), start trading transactions & blocks
	if (!isSyncing() && m_chain.isKnown(m_latestBlockSent))
	{
		if (m_newTransactions)
		{
			m_newTransactions = false;
			maintainTransactions();
		}
		if (m_newBlocks)
		{
			m_newBlocks = false;
			maintainBlocks(h);
		}
	}

	for (auto p: peerSessions())
		if (shared_ptr<EthereumPeer> const& ep = p.first->cap<EthereumPeer>())
			ep->tick();

//	return netChange;
	// TODO: Figure out what to do with netChange.
	(void)netChange;
}

void EthereumHost::maintainTransactions()
{
	// Send any new transactions.
	map<std::shared_ptr<EthereumPeer>, h256s> peerTransactions;
	auto ts = m_tq.transactions();
	for (auto const& i: ts)
	{
		bool unsent = !m_transactionsSent.count(i.first);
		for (auto const& p: randomSelection(100, [&](EthereumPeer* p) { return p->m_requireTransactions || (unsent && !p->m_knownTransactions.count(i.first)); }))
			peerTransactions[p].push_back(i.first);
	}
	for (auto const& t: ts)
		m_transactionsSent.insert(t.first);
	for (auto p: peerSessions())
		if (auto ep = p.first->cap<EthereumPeer>())
		{
			bytes b;
			unsigned n = 0;
			for (auto const& h: peerTransactions[ep])
			{
				ep->m_knownTransactions.insert(h);
				b += ts[h].rlp();
				++n;
			}

			ep->clearKnownTransactions();

			if (n || ep->m_requireTransactions)
			{
				RLPStream ts;
				ep->prep(ts, TransactionsPacket, n).appendRaw(b, n);
				ep->sealAndSend(ts);
			}
			ep->m_requireTransactions = false;
		}
}

std::vector<std::shared_ptr<EthereumPeer>> EthereumHost::randomSelection(unsigned _percent, std::function<bool(EthereumPeer*)> const& _allow)
{
	std::vector<std::shared_ptr<EthereumPeer>> candidates;
	candidates.reserve(peerSessions().size());
	for (auto const& j: peerSessions())
	{
		auto pp = j.first->cap<EthereumPeer>();
		if (_allow(pp.get()))
			candidates.push_back(pp);
	}

	std::vector<std::shared_ptr<EthereumPeer>> ret;
	for (unsigned i = (peerSessions().size() * _percent + 99) / 100; i-- && candidates.size();)
	{
		unsigned n = rand() % candidates.size();
		ret.push_back(std::move(candidates[n]));
		candidates.erase(candidates.begin() + n);
	}
	return ret;
}

void EthereumHost::maintainBlocks(h256 _currentHash)
{
	// Send any new blocks.
	auto detailsFrom = m_chain.details(m_latestBlockSent);
	auto detailsTo = m_chain.details(_currentHash);
	if (detailsFrom.totalDifficulty < detailsTo.totalDifficulty)
	{
		if (diff(detailsFrom.number, detailsTo.number) < 20)
		{
			// don't be sending more than 20 "new" blocks. if there are any more we were probably waaaay behind.
			clog(NetMessageSummary) << "Sending a new block (current is" << _currentHash << ", was" << m_latestBlockSent << ")";

			h256s blocks = get<0>(m_chain.treeRoute(m_latestBlockSent, _currentHash, false, false, true));

			for (auto const& p: randomSelection(100, [&](EthereumPeer* p){return !p->m_knownBlocks.count(_currentHash); }))
				for (auto const& b: blocks)
					if (!p->m_knownBlocks.count(b))
					{
						RLPStream ts;
						p->prep(ts, NewBlockPacket, 2).appendRaw(m_chain.block(b), 1).append(m_chain.details(b).totalDifficulty);

						Guard l(p->x_knownBlocks);
						p->sealAndSend(ts);
						p->m_knownBlocks.clear();
					}
		}
		m_latestBlockSent = _currentHash;
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/**
 * @file heaptrack_interpret.cpp
 *
 * @brief Interpret raw heaptrack data and add Dwarf based debug information.
 */

#include <iostream>
#include <sstream>
#include <unordered_map>
#include <vector>
#include <tuple>
#include <algorithm>
#include <stdio_ext.h>

#include <cxxabi.h>

#include <boost/algorithm/string/predicate.hpp>

#include "libbacktrace/backtrace.h"
#include "libbacktrace/internal.h"
#include "linereader.h"

using namespace std;

namespace {

string demangle(const char* function)
{
    if (!function) {
        return {};
    } else if (function[0] != '_' || function[1] != 'Z') {
        return {function};
    }

    string ret;
    int status = 0;
    char* demangled = abi::__cxa_demangle(function, 0, 0, &status);
    if (demangled) {
        ret = demangled;
        free(demangled);
    }
    return ret;
}

struct AddressInformation
{
    string function;
    string file;
    int line = 0;
};

struct Module
{
    Module(uintptr_t addressStart, uintptr_t addressEnd, backtrace_state* backtraceState, size_t moduleIndex)
        : addressStart(addressStart)
        , addressEnd(addressEnd)
        , moduleIndex(moduleIndex)
        , backtraceState(backtraceState)
    {
    }

    AddressInformation resolveAddress(uintptr_t address) const
    {
        AddressInformation info;
        if (!backtraceState) {
            return info;
        }

        backtrace_pcinfo(backtraceState, address,
                         [] (void *data, uintptr_t /*addr*/, const char *file, int line, const char *function) -> int {
                            auto info = reinterpret_cast<AddressInformation*>(data);
                            info->function = demangle(function);
                            info->file = file ? file : "";
                            info->line = line;
                            return 0;
                         }, [] (void */*data*/, const char */*msg*/, int /*errnum*/) {}, &info);

        if (info.function.empty()) {
            backtrace_syminfo(backtraceState, address,
                              [] (void *data, uintptr_t /*pc*/, const char *symname, uintptr_t /*symval*/, uintptr_t /*symsize*/) {
                                if (symname) {
                                    reinterpret_cast<AddressInformation*>(data)->function = demangle(symname);
                                }
                              }, [] (void */*data*/, const char *msg, int errnum) {
                                cerr << "Module backtrace error (code " << errnum << "): " << msg << endl;
                              }, &info);
        }

        return info;
    }

    bool operator<(const Module& module) const
    {
        return make_tuple(addressStart, addressEnd, moduleIndex)
             < make_tuple(module.addressStart, module.addressEnd, module.moduleIndex);
    }

    bool operator!=(const Module& module) const
    {
        return make_tuple(addressStart, addressEnd, moduleIndex)
            != make_tuple(module.addressStart, module.addressEnd, module.moduleIndex);
    }

    uintptr_t addressStart;
    uintptr_t addressEnd;
    size_t moduleIndex;
    backtrace_state* backtraceState;
};

struct Allocation
{
    // backtrace entry point
    size_t ipIndex;
    // number of allocations
    size_t allocations;
    // amount of bytes leaked
    size_t leaked;
};

/**
 * Information for a single call to an allocation function
 */
struct AllocationInfo
{
    size_t ipIndex;
    size_t size;
};

struct ResolvedIP
{
    size_t moduleIndex = 0;
    size_t fileIndex = 0;
    size_t functionIndex = 0;
    int line = 0;
};

struct AccumulatedTraceData
{
    AccumulatedTraceData()
    {
        m_modules.reserve(256);
        m_backtraceStates.reserve(64);
        m_internedData.reserve(4096);
        m_encounteredIps.reserve(32768);
    }

    ~AccumulatedTraceData()
    {
        fprintf(stdout, "# strings: %lu\n# ips: %lu\n",
                m_internedData.size(), m_encounteredIps.size());
    }

    ResolvedIP resolve(const uintptr_t ip)
    {
        if (m_modulesDirty) {
            // sort by addresses, required for binary search below
            sort(m_modules.begin(), m_modules.end());

            for (size_t i = 0; i < m_modules.size(); ++i) {
                const auto& m1 = m_modules[i];
                for (size_t j = i + 1; j < m_modules.size(); ++j) {
                    if (i == j) {
                        continue;
                    }
                    const auto& m2 = m_modules[j];
                    if ((m1.addressStart <= m2.addressStart && m1.addressEnd > m2.addressStart) ||
                        (m1.addressStart < m2.addressEnd && m1.addressEnd >= m2.addressEnd))
                    {
                        cerr << "OVERLAPPING MODULES: " << hex
                             << m1.moduleIndex << " (" << m1.addressStart << " to " << m1.addressEnd << ") and "
                             << m1.moduleIndex << " (" << m2.addressStart << " to " << m2.addressEnd << ")\n"
                             << dec;
                    } else if (m2.addressStart >= m1.addressEnd) {
                        break;
                    }
                }
            }

            m_modulesDirty = false;
        }

        ResolvedIP data;
        // find module for this instruction pointer
        auto module = lower_bound(m_modules.begin(), m_modules.end(), ip,
                                    [] (const Module& module, const uintptr_t ip) -> bool {
                                        return module.addressEnd < ip;
                                    });
        if (module != m_modules.end() && module->addressStart <= ip && module->addressEnd >= ip) {
            data.moduleIndex = module->moduleIndex;
            const auto info = module->resolveAddress(ip);
            data.fileIndex = intern(info.file);
            data.functionIndex = intern(info.function);
            data.line = info.line;
        }
        return data;
    }

    size_t intern(const string& str)
    {
        if (str.empty()) {
            return 0;
        }

        auto it = m_internedData.find(str);
        if (it != m_internedData.end()) {
            return it->second;
        }
        const size_t id = m_internedData.size() + 1;
        m_internedData.insert(it, make_pair(str, id));
        fprintf(stdout, "s %s\n", str.c_str());
        return id;
    }

    void addModule(backtrace_state* backtraceState, const size_t moduleIndex,
                   const uintptr_t addressStart, const uintptr_t addressEnd)
    {
        m_modules.emplace_back(addressStart, addressEnd, backtraceState, moduleIndex);
        m_modulesDirty = true;
    }

    void clearModules()
    {
        // TODO: optimize this, reuse modules that are still valid
        m_modules.clear();
        m_modulesDirty = true;
    }

    size_t addIp(const uintptr_t instructionPointer)
    {
        if (!instructionPointer) {
            return 0;
        }

        auto it = m_encounteredIps.find(instructionPointer);
        if (it != m_encounteredIps.end()) {
            return it->second;
        }

        const size_t ipId = m_encounteredIps.size() + 1;
        m_encounteredIps.insert(it, make_pair(instructionPointer, ipId));

        const auto ip = resolve(instructionPointer);
        fprintf(stdout, "i %lx %lx", instructionPointer, ip.moduleIndex);
        if (ip.functionIndex || ip.fileIndex) {
            fprintf(stdout, " %lx", ip.functionIndex);
            if (ip.fileIndex) {
                fprintf(stdout, " %lx %x", ip.fileIndex, ip.line);
            }
        }
        fputc('\n', stdout);
        return ipId;
    }

    /**
     * Prevent the same file from being initialized multiple times.
     * This drastically cuts the memory consumption down
     */
    backtrace_state* findBacktraceState(const string& fileName, uintptr_t addressStart, bool isExe)
    {
        if (boost::algorithm::starts_with(fileName, "linux-vdso.so")) {
            // prevent warning, since this will always fail
            return nullptr;
        }

        auto it = m_backtraceStates.find(fileName);
        if (it != m_backtraceStates.end()) {
            return it->second;
        }

        struct CallbackData {
            const string* fileName;
        };
        CallbackData data = {&fileName};

        auto errorHandler = [] (void *rawData, const char *msg, int errnum) {
            auto data = reinterpret_cast<const CallbackData*>(rawData);
            cerr << "Failed to create backtrace state for module " << *data->fileName << ": "
                 << msg << " / " << strerror(errnum) << " (error code " << errnum << ")" << endl;
        };

        auto state = backtrace_create_state(fileName.c_str(), /* we are single threaded, so: not thread safe */ false,
                                            errorHandler, &data);

        if (state) {
            const int descriptor = backtrace_open(fileName.c_str(), errorHandler, &data, nullptr);
            if (descriptor >= 1) {
                int foundSym = 0;
                int foundDwarf = 0;
                auto ret = elf_add(state, descriptor, addressStart, errorHandler, &data,
                                   &state->fileline_fn, &foundSym, &foundDwarf, isExe);
                if (ret && foundSym) {
                    state->syminfo_fn = &elf_syminfo;
                }
            }
        }

        m_backtraceStates.insert(it, make_pair(fileName, state));

        return state;
    }

private:
    vector<Module> m_modules;
    unordered_map<string, backtrace_state*> m_backtraceStates;
    bool m_modulesDirty = false;

    unordered_map<string, size_t> m_internedData;
    unordered_map<uintptr_t, size_t> m_encounteredIps;
};

}

int main(int /*argc*/, char** /*argv*/)
{
    // optimize: we only have a single thread
    ios_base::sync_with_stdio(false);

    AccumulatedTraceData data;

    LineReader reader;

    string exe;

    __fsetlocking(stdout, FSETLOCKING_BYCALLER);
    __fsetlocking(stdin, FSETLOCKING_BYCALLER);

    while (reader.getLine(cin)) {
        if (reader.mode() == 'x') {
            reader >> exe;
        } else if (reader.mode() == 'm') {
            string fileName;
            reader >> fileName;
            if (fileName == "-") {
                data.clearModules();
            } else {
                const bool isExe = (fileName == "x");
                if (isExe) {
                    fileName = exe;
                }
                const auto moduleIndex = data.intern(fileName);
                uintptr_t addressStart = 0;
                if (!(reader >> addressStart)) {
                    cerr << "failed to parse line: " << reader.line() << endl;
                    return 1;
                }
                auto state = data.findBacktraceState(fileName, addressStart, isExe);
                uintptr_t vAddr = 0;
                uintptr_t memSize = 0;
                while ((reader >> vAddr) && (reader >> memSize)) {
                    data.addModule(state, moduleIndex,
                                   addressStart + vAddr,
                                   addressStart + vAddr + memSize);
                }
            }
        } else if (reader.mode() == 't') {
            uintptr_t instructionPointer = 0;
            size_t parentIndex = 0;
            if (!(reader >> instructionPointer) || !(reader >> parentIndex)) {
                cerr << "failed to parse line: " << reader.line() << endl;
                return 1;
            }
            // ensure ip is encountered
            const auto ipId = data.addIp(instructionPointer);
            // trace point, map current output index to parent index
            fprintf(stdout, "t %lx %lx\n", ipId, parentIndex);
        } else {
            fputs(reader.line().c_str(), stdout);
            fputc('\n', stdout);
        }
    }

    return 0;
}
<commit_msg>Group disabling of stdio locking code.<commit_after>/*
 * Copyright 2014 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/**
 * @file heaptrack_interpret.cpp
 *
 * @brief Interpret raw heaptrack data and add Dwarf based debug information.
 */

#include <iostream>
#include <sstream>
#include <unordered_map>
#include <vector>
#include <tuple>
#include <algorithm>
#include <stdio_ext.h>

#include <cxxabi.h>

#include <boost/algorithm/string/predicate.hpp>

#include "libbacktrace/backtrace.h"
#include "libbacktrace/internal.h"
#include "linereader.h"

using namespace std;

namespace {

string demangle(const char* function)
{
    if (!function) {
        return {};
    } else if (function[0] != '_' || function[1] != 'Z') {
        return {function};
    }

    string ret;
    int status = 0;
    char* demangled = abi::__cxa_demangle(function, 0, 0, &status);
    if (demangled) {
        ret = demangled;
        free(demangled);
    }
    return ret;
}

struct AddressInformation
{
    string function;
    string file;
    int line = 0;
};

struct Module
{
    Module(uintptr_t addressStart, uintptr_t addressEnd, backtrace_state* backtraceState, size_t moduleIndex)
        : addressStart(addressStart)
        , addressEnd(addressEnd)
        , moduleIndex(moduleIndex)
        , backtraceState(backtraceState)
    {
    }

    AddressInformation resolveAddress(uintptr_t address) const
    {
        AddressInformation info;
        if (!backtraceState) {
            return info;
        }

        backtrace_pcinfo(backtraceState, address,
                         [] (void *data, uintptr_t /*addr*/, const char *file, int line, const char *function) -> int {
                            auto info = reinterpret_cast<AddressInformation*>(data);
                            info->function = demangle(function);
                            info->file = file ? file : "";
                            info->line = line;
                            return 0;
                         }, [] (void */*data*/, const char */*msg*/, int /*errnum*/) {}, &info);

        if (info.function.empty()) {
            backtrace_syminfo(backtraceState, address,
                              [] (void *data, uintptr_t /*pc*/, const char *symname, uintptr_t /*symval*/, uintptr_t /*symsize*/) {
                                if (symname) {
                                    reinterpret_cast<AddressInformation*>(data)->function = demangle(symname);
                                }
                              }, [] (void */*data*/, const char *msg, int errnum) {
                                cerr << "Module backtrace error (code " << errnum << "): " << msg << endl;
                              }, &info);
        }

        return info;
    }

    bool operator<(const Module& module) const
    {
        return make_tuple(addressStart, addressEnd, moduleIndex)
             < make_tuple(module.addressStart, module.addressEnd, module.moduleIndex);
    }

    bool operator!=(const Module& module) const
    {
        return make_tuple(addressStart, addressEnd, moduleIndex)
            != make_tuple(module.addressStart, module.addressEnd, module.moduleIndex);
    }

    uintptr_t addressStart;
    uintptr_t addressEnd;
    size_t moduleIndex;
    backtrace_state* backtraceState;
};

struct Allocation
{
    // backtrace entry point
    size_t ipIndex;
    // number of allocations
    size_t allocations;
    // amount of bytes leaked
    size_t leaked;
};

/**
 * Information for a single call to an allocation function
 */
struct AllocationInfo
{
    size_t ipIndex;
    size_t size;
};

struct ResolvedIP
{
    size_t moduleIndex = 0;
    size_t fileIndex = 0;
    size_t functionIndex = 0;
    int line = 0;
};

struct AccumulatedTraceData
{
    AccumulatedTraceData()
    {
        m_modules.reserve(256);
        m_backtraceStates.reserve(64);
        m_internedData.reserve(4096);
        m_encounteredIps.reserve(32768);
    }

    ~AccumulatedTraceData()
    {
        fprintf(stdout, "# strings: %lu\n# ips: %lu\n",
                m_internedData.size(), m_encounteredIps.size());
    }

    ResolvedIP resolve(const uintptr_t ip)
    {
        if (m_modulesDirty) {
            // sort by addresses, required for binary search below
            sort(m_modules.begin(), m_modules.end());

            for (size_t i = 0; i < m_modules.size(); ++i) {
                const auto& m1 = m_modules[i];
                for (size_t j = i + 1; j < m_modules.size(); ++j) {
                    if (i == j) {
                        continue;
                    }
                    const auto& m2 = m_modules[j];
                    if ((m1.addressStart <= m2.addressStart && m1.addressEnd > m2.addressStart) ||
                        (m1.addressStart < m2.addressEnd && m1.addressEnd >= m2.addressEnd))
                    {
                        cerr << "OVERLAPPING MODULES: " << hex
                             << m1.moduleIndex << " (" << m1.addressStart << " to " << m1.addressEnd << ") and "
                             << m1.moduleIndex << " (" << m2.addressStart << " to " << m2.addressEnd << ")\n"
                             << dec;
                    } else if (m2.addressStart >= m1.addressEnd) {
                        break;
                    }
                }
            }

            m_modulesDirty = false;
        }

        ResolvedIP data;
        // find module for this instruction pointer
        auto module = lower_bound(m_modules.begin(), m_modules.end(), ip,
                                    [] (const Module& module, const uintptr_t ip) -> bool {
                                        return module.addressEnd < ip;
                                    });
        if (module != m_modules.end() && module->addressStart <= ip && module->addressEnd >= ip) {
            data.moduleIndex = module->moduleIndex;
            const auto info = module->resolveAddress(ip);
            data.fileIndex = intern(info.file);
            data.functionIndex = intern(info.function);
            data.line = info.line;
        }
        return data;
    }

    size_t intern(const string& str)
    {
        if (str.empty()) {
            return 0;
        }

        auto it = m_internedData.find(str);
        if (it != m_internedData.end()) {
            return it->second;
        }
        const size_t id = m_internedData.size() + 1;
        m_internedData.insert(it, make_pair(str, id));
        fprintf(stdout, "s %s\n", str.c_str());
        return id;
    }

    void addModule(backtrace_state* backtraceState, const size_t moduleIndex,
                   const uintptr_t addressStart, const uintptr_t addressEnd)
    {
        m_modules.emplace_back(addressStart, addressEnd, backtraceState, moduleIndex);
        m_modulesDirty = true;
    }

    void clearModules()
    {
        // TODO: optimize this, reuse modules that are still valid
        m_modules.clear();
        m_modulesDirty = true;
    }

    size_t addIp(const uintptr_t instructionPointer)
    {
        if (!instructionPointer) {
            return 0;
        }

        auto it = m_encounteredIps.find(instructionPointer);
        if (it != m_encounteredIps.end()) {
            return it->second;
        }

        const size_t ipId = m_encounteredIps.size() + 1;
        m_encounteredIps.insert(it, make_pair(instructionPointer, ipId));

        const auto ip = resolve(instructionPointer);
        fprintf(stdout, "i %lx %lx", instructionPointer, ip.moduleIndex);
        if (ip.functionIndex || ip.fileIndex) {
            fprintf(stdout, " %lx", ip.functionIndex);
            if (ip.fileIndex) {
                fprintf(stdout, " %lx %x", ip.fileIndex, ip.line);
            }
        }
        fputc('\n', stdout);
        return ipId;
    }

    /**
     * Prevent the same file from being initialized multiple times.
     * This drastically cuts the memory consumption down
     */
    backtrace_state* findBacktraceState(const string& fileName, uintptr_t addressStart, bool isExe)
    {
        if (boost::algorithm::starts_with(fileName, "linux-vdso.so")) {
            // prevent warning, since this will always fail
            return nullptr;
        }

        auto it = m_backtraceStates.find(fileName);
        if (it != m_backtraceStates.end()) {
            return it->second;
        }

        struct CallbackData {
            const string* fileName;
        };
        CallbackData data = {&fileName};

        auto errorHandler = [] (void *rawData, const char *msg, int errnum) {
            auto data = reinterpret_cast<const CallbackData*>(rawData);
            cerr << "Failed to create backtrace state for module " << *data->fileName << ": "
                 << msg << " / " << strerror(errnum) << " (error code " << errnum << ")" << endl;
        };

        auto state = backtrace_create_state(fileName.c_str(), /* we are single threaded, so: not thread safe */ false,
                                            errorHandler, &data);

        if (state) {
            const int descriptor = backtrace_open(fileName.c_str(), errorHandler, &data, nullptr);
            if (descriptor >= 1) {
                int foundSym = 0;
                int foundDwarf = 0;
                auto ret = elf_add(state, descriptor, addressStart, errorHandler, &data,
                                   &state->fileline_fn, &foundSym, &foundDwarf, isExe);
                if (ret && foundSym) {
                    state->syminfo_fn = &elf_syminfo;
                }
            }
        }

        m_backtraceStates.insert(it, make_pair(fileName, state));

        return state;
    }

private:
    vector<Module> m_modules;
    unordered_map<string, backtrace_state*> m_backtraceStates;
    bool m_modulesDirty = false;

    unordered_map<string, size_t> m_internedData;
    unordered_map<uintptr_t, size_t> m_encounteredIps;
};

}

int main(int /*argc*/, char** /*argv*/)
{
    // optimize: we only have a single thread
    ios_base::sync_with_stdio(false);
    __fsetlocking(stdout, FSETLOCKING_BYCALLER);
    __fsetlocking(stdin, FSETLOCKING_BYCALLER);

    AccumulatedTraceData data;

    LineReader reader;

    string exe;

    while (reader.getLine(cin)) {
        if (reader.mode() == 'x') {
            reader >> exe;
        } else if (reader.mode() == 'm') {
            string fileName;
            reader >> fileName;
            if (fileName == "-") {
                data.clearModules();
            } else {
                const bool isExe = (fileName == "x");
                if (isExe) {
                    fileName = exe;
                }
                const auto moduleIndex = data.intern(fileName);
                uintptr_t addressStart = 0;
                if (!(reader >> addressStart)) {
                    cerr << "failed to parse line: " << reader.line() << endl;
                    return 1;
                }
                auto state = data.findBacktraceState(fileName, addressStart, isExe);
                uintptr_t vAddr = 0;
                uintptr_t memSize = 0;
                while ((reader >> vAddr) && (reader >> memSize)) {
                    data.addModule(state, moduleIndex,
                                   addressStart + vAddr,
                                   addressStart + vAddr + memSize);
                }
            }
        } else if (reader.mode() == 't') {
            uintptr_t instructionPointer = 0;
            size_t parentIndex = 0;
            if (!(reader >> instructionPointer) || !(reader >> parentIndex)) {
                cerr << "failed to parse line: " << reader.line() << endl;
                return 1;
            }
            // ensure ip is encountered
            const auto ipId = data.addIp(instructionPointer);
            // trace point, map current output index to parent index
            fprintf(stdout, "t %lx %lx\n", ipId, parentIndex);
        } else {
            fputs(reader.line().c_str(), stdout);
            fputc('\n', stdout);
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2011 Heiko Strathmann
 * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society
 */

#include <shogun/base/init.h>
#include <shogun/base/Parameter.h>
#include <shogun/base/ParameterMap.h>

using namespace shogun;

void print_message(FILE* target, const char* str)
{
	fprintf(target, "%s", str);
}

void test_mapping_1()
{
	ParameterMap* map=new ParameterMap();

	map->put(
			new SGParamInfo("number", CT_SCALAR, ST_NONE, PT_FLOAT64, 2),
			new SGParamInfo("number", CT_SCALAR, ST_NONE, PT_INT32, 1)
	);

	map->put(
			new SGParamInfo("number", CT_SCALAR, ST_NONE, PT_INT32, 1),
			new SGParamInfo("number", CT_SCALAR, ST_NONE, PT_FLOAT64, 0)
	);

	map->put(
			new SGParamInfo("number_2", CT_SCALAR, ST_NONE, PT_INT32, 1),
			new SGParamInfo("number_to_keep", CT_SCALAR, ST_NONE, PT_INT32, 0)
	);

	/* finalizing the map is needed before accessing it */
	map->finalize_map();

	map->print_map();
	SG_SPRINT("\n");

	/* get some elements from map, one/two ARE in map, three and four are NOT */
	DynArray<SGParamInfo*> dummies;
	dummies.append_element(new SGParamInfo("number", CT_SCALAR, ST_NONE,
			PT_INT32, 1));
	dummies.append_element(new SGParamInfo("number", CT_SCALAR, ST_NONE,
			PT_FLOAT64, 2));
	dummies.append_element(new SGParamInfo("number", CT_SCALAR, ST_NONE,
				PT_INT32, 2));
	dummies.append_element(new SGParamInfo("number", CT_SCALAR, ST_NONE,
			PT_FLOAT64, 0));
	dummies.append_element(new SGParamInfo("number_2", CT_SCALAR, ST_NONE,
			PT_INT32, 1));

	for (index_t i=0; i<dummies.get_num_elements(); ++i)
	{
		SGParamInfo* current=dummies.get_element(i);

		char* s=current->to_string();
		SG_SPRINT("searching for: %s\n", s);
		SG_FREE(s);

		const SGParamInfo* result=map->get(current);
		if (result)
		{
			s=result->to_string();
			SG_SPRINT("found: %s\n\n", s);
			SG_FREE(s);
		}
		else
			SG_SPRINT("nothing found\n\n");

		delete current;
	}

	delete map;
}

void print_value(const SGParamInfo* key, ParameterMap* map)
{
	const SGParamInfo* current=map->get(key);
	key->print_param_info();
	SG_SPRINT("value: ");

	if (current)
		current->print_param_info();
	else
		SG_SPRINT("no element\n");

	SG_SPRINT("\n");
}

void test_mapping_2()
{
	ParameterMap* map=new ParameterMap();

	EContainerType cfrom=CT_SCALAR;
	EContainerType cto=CT_MATRIX;

	EStructType sfrom=ST_NONE;
	EStructType sto=ST_STRING;

	EPrimitiveType pfrom=PT_BOOL;
	EPrimitiveType pto=PT_SGOBJECT;

	map->put(new SGParamInfo("1", cfrom, sfrom, pfrom, 2),
			new SGParamInfo("eins", cto, sto, pto, 1));
	map->put(new SGParamInfo("2", cfrom, sfrom, pfrom, 2),
			new SGParamInfo("zwei", cto, sto, pto, 1));
	map->put(new SGParamInfo("3", cfrom, sfrom, pfrom, 4),
			new SGParamInfo("drei", cto, sto, pto, 3));
	map->put(new SGParamInfo("4", cfrom, sfrom, pfrom, 4),
			new SGParamInfo("vier", cto, sto, pto, 3));

	SG_SPRINT("before finalization:\n");
	map->print_map();
	map->finalize_map();

	SG_SPRINT("\n\nafter finalization:\n");
	map->print_map();

	const SGParamInfo* key;

	SG_SPRINT("\n\ntesting map\n");
	key=new SGParamInfo("1", cfrom, sfrom, pfrom, 1);
	print_value(key, map);
	delete key;

	key=new SGParamInfo("2", cfrom, sfrom, pfrom, 2);
	print_value(key, map);
	delete key;

	key=new SGParamInfo("2", cto, sfrom, pfrom, 2);
	print_value(key, map);
	delete key;

	key=new SGParamInfo("2", cfrom, sto, pfrom, 2);
	print_value(key, map);
	delete key;

	key=new SGParamInfo("2", cfrom, sfrom, pto, 2);
	print_value(key, map);
	delete key;

	key=new SGParamInfo("5", cfrom, sfrom, pfrom, 4);
	print_value(key, map);
	delete key;

	delete map;
}

int main(int argc, char **argv)
{
	init_shogun(&print_message, &print_message, &print_message);

	test_mapping_1();
	test_mapping_2();

	exit_shogun();

	return 0;
}

<commit_msg>adapted for new mutli-value per key parameter map and added testcase<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2011 Heiko Strathmann
 * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society
 */

#include <shogun/base/init.h>
#include <shogun/base/Parameter.h>
#include <shogun/base/ParameterMap.h>

using namespace shogun;

void print_message(FILE* target, const char* str)
{
	fprintf(target, "%s", str);
}

void test_mapping_1()
{
	ParameterMap* map=new ParameterMap();

	map->put(
			new SGParamInfo("number", CT_SCALAR, ST_NONE, PT_FLOAT64, 2),
			new SGParamInfo("number", CT_SCALAR, ST_NONE, PT_INT32, 1)
	);

	map->put(
			new SGParamInfo("number", CT_SCALAR, ST_NONE, PT_INT32, 1),
			new SGParamInfo("number", CT_SCALAR, ST_NONE, PT_FLOAT64, 0)
	);

	map->put(
			new SGParamInfo("number_2", CT_SCALAR, ST_NONE, PT_INT32, 1),
			new SGParamInfo("number_to_keep", CT_SCALAR, ST_NONE, PT_INT32, 0)
	);

	/* finalizing the map is needed before accessing it */
	SG_SPRINT("\n\before finalization:\n");
	map->finalize_map();

	SG_SPRINT("\n\nafter finalization:\n");
	map->print_map();
	SG_SPRINT("\n");

	/* get some elements from map, one/two ARE in map, three and four are NOT */
	DynArray<SGParamInfo*> dummies;
	dummies.append_element(new SGParamInfo("number", CT_SCALAR, ST_NONE,
			PT_INT32, 1));
	dummies.append_element(new SGParamInfo("number", CT_SCALAR, ST_NONE,
			PT_FLOAT64, 2));
	dummies.append_element(new SGParamInfo("number", CT_SCALAR, ST_NONE,
				PT_INT32, 2));
	dummies.append_element(new SGParamInfo("number", CT_SCALAR, ST_NONE,
			PT_FLOAT64, 0));
	dummies.append_element(new SGParamInfo("number_2", CT_SCALAR, ST_NONE,
			PT_INT32, 1));

	for (index_t i=0; i<dummies.get_num_elements(); ++i)
	{
		SGParamInfo* current=dummies.get_element(i);

		char* s=current->to_string();
		SG_SPRINT("searching for: %s\n", s);
		SG_FREE(s);

		DynArray<const SGParamInfo*>* result=map->get(current, 0);
		if (result)
		{
			for (index_t i=0; i<result->get_num_elements(); ++i)
			{
				s=result->get_element(i)->to_string();
				SG_SPRINT("found: %s\n\n", s);
				SG_FREE(s);
			}
		}
		else
			SG_SPRINT("nothing found\n\n");

		delete current;
	}

	delete map;
}

void print_value(const SGParamInfo* key, ParameterMap* map)
{
	DynArray<const SGParamInfo*>* current=map->get(key, 0);
	key->print_param_info();
	SG_SPRINT("value: ");

	if (current)
	{
		for (index_t i=0; i<current->get_num_elements(); ++i)
			current->get_element(i)->print_param_info("\t");
	}
	else
		SG_SPRINT("no elements\n");

	SG_SPRINT("\n");
}

void test_mapping_2()
{
	ParameterMap* map=new ParameterMap();

	EContainerType cfrom=CT_SCALAR;
	EContainerType cto=CT_MATRIX;

	EStructType sfrom=ST_NONE;
	EStructType sto=ST_STRING;

	EPrimitiveType pfrom=PT_BOOL;
	EPrimitiveType pto=PT_SGOBJECT;

	map->put(new SGParamInfo("1", cfrom, sfrom, pfrom, 2),
			new SGParamInfo("eins", cto, sto, pto, 1));
	map->put(new SGParamInfo("2", cfrom, sfrom, pfrom, 2),
			new SGParamInfo("zwei", cto, sto, pto, 1));
	map->put(new SGParamInfo("3", cfrom, sfrom, pfrom, 4),
			new SGParamInfo("drei", cto, sto, pto, 3));
	map->put(new SGParamInfo("4", cfrom, sfrom, pfrom, 4),
			new SGParamInfo("vier", cto, sto, pto, 3));

	map->finalize_map();

	SG_SPRINT("\n\nafter finalization:\n");
	map->print_map();

	const SGParamInfo* key;

	SG_SPRINT("\n\ntesting map\n");
	key=new SGParamInfo("1", cfrom, sfrom, pfrom, 1);
	print_value(key, map);
	delete key;

	key=new SGParamInfo("2", cfrom, sfrom, pfrom, 2);
	print_value(key, map);
	delete key;

	key=new SGParamInfo("2", cto, sfrom, pfrom, 2);
	print_value(key, map);
	delete key;

	key=new SGParamInfo("2", cfrom, sto, pfrom, 2);
	print_value(key, map);
	delete key;

	key=new SGParamInfo("2", cfrom, sfrom, pto, 2);
	print_value(key, map);
	delete key;

	key=new SGParamInfo("5", cfrom, sfrom, pfrom, 4);
	print_value(key, map);
	delete key;

	delete map;
}

void test_mapping_0()
{
	/* test multiple values per key */
	ParameterMap* map=new ParameterMap();

	EContainerType cfrom=CT_SCALAR;
	EContainerType cto=CT_MATRIX;

	EStructType sfrom=ST_NONE;
	EStructType sto=ST_STRING;

	EPrimitiveType pfrom=PT_BOOL;
	EPrimitiveType pto=PT_SGOBJECT;

	/* 3 equal keys */
	map->put(new SGParamInfo("1", cfrom, sfrom, pfrom, 2),
			new SGParamInfo("eins a", cto, sto, pto, 1));

	map->put(new SGParamInfo("1", cfrom, sfrom, pfrom, 2),
			new SGParamInfo("eins b", cto, sto, pto, 1));

	map->put(new SGParamInfo("1", cfrom, sfrom, pfrom, 2),
			new SGParamInfo("eins c", cto, sto, pto, 1));

	/* 2 equal keys */
	map->put(new SGParamInfo("2", cfrom, sfrom, pfrom, 2),
			new SGParamInfo("zwei a", cto, sto, pto, 1));

	map->put(new SGParamInfo("2", cfrom, sfrom, pfrom, 2),
			new SGParamInfo("zwei b", cto, sto, pto, 1));

	map->finalize_map();

	SG_SPRINT("printing finalized map\n");
	map->print_map();

	/* assert that all is there */
	DynArray<const SGParamInfo*>* result;
	bool found;

	/* key 0 */
	result=map->get(SGParamInfo("1", cfrom, sfrom, pfrom, 2));
	ASSERT(result);

	/* first value element */
	found=false;
	for (index_t i=0; i<result->get_num_elements(); ++i)
	{
		if (*result->get_element(i) == SGParamInfo("eins a", cto, sto, pto, 1))
			found=true;
	}
	ASSERT(found);

	/* second value element */
	found=false;
	for (index_t i=0; i<result->get_num_elements(); ++i)
	{
		if (*result->get_element(i) == SGParamInfo("eins b", cto, sto, pto, 1))
			found=true;
	}
	ASSERT(found);

	/* third value element */
	found=false;
	for (index_t i=0; i<result->get_num_elements(); ++i)
	{
		if (*result->get_element(i) == SGParamInfo("eins c", cto, sto, pto, 1))
			found=true;
	}
	ASSERT(found);

	/* key 1 */
	result=map->get(SGParamInfo("2", cfrom, sfrom, pfrom, 2));
	ASSERT(result);

	/* first value element */
	found=false;
	for (index_t i=0; i<result->get_num_elements(); ++i)
	{
		if (*result->get_element(i) == SGParamInfo("zwei a", cto, sto, pto, 1))
			found=true;
	}
	ASSERT(found);

	/* second value element */
	found=false;
	for (index_t i=0; i<result->get_num_elements(); ++i)
	{
		if (*result->get_element(i) == SGParamInfo("zwei b", cto, sto, pto, 1))
			found=true;
	}
	ASSERT(found);

	delete map;
}

int main(int argc, char **argv)
{
	init_shogun(&print_message, &print_message, &print_message);

	test_mapping_0();
	test_mapping_1();
	test_mapping_2();

	exit_shogun();

	return 0;
}

<|endoftext|>