<commit_before>// Copyright Steinwurf ApS 2011-2012.
// Distributed under the "STEINWURF RESEARCH LICENSE 1.0".
// See accompanying file LICENSE.rst or
// http://www.steinwurf.com/licensing

#include <ctime>
#include <cstdint>

//#include <boost/make_shared.hpp>

#include <gauge/gauge.hpp>
#include <gauge/console_printer.hpp>
#include <gauge/python_printer.hpp>
#include <gauge/csv_printer.hpp>
#include <gauge/json_printer.hpp>

#include <tables/table.hpp>

extern "C"
{
#include <gf_rand.h>
#include <jerasure.h>
#include <reed_sol.h>
}

struct reed_sol_van_encoder
{
    reed_sol_van_encoder(uint32_t symbols, uint32_t symbol_size) :
        m_symbols(symbols), m_symbol_size(symbol_size)
    {
        k = m_symbols;
        m = m_symbols;
        w = 8;
        m_block_size = m_symbols * m_symbol_size;

        matrix = reed_sol_vandermonde_coding_matrix(k, m, w);

        // Allocate data and coding pointer arrays
        data = new char*[k];
        coding = new char*[m];
    }

    ~reed_sol_van_encoder()
    {
        if (data) delete[] data;
        if (coding) delete[] coding;
    }

    void set_symbols(uint8_t* ptr, uint32_t size)
    {
        // Set pointers to point to the input symbols
        for (int i = 0; i < k; i++)
        {
            assert((i+1) * m_symbol_size <= size);
            data[i] = (char*)ptr + i * m_symbol_size;
        }
    }

    void encode_all(std::vector<std::vector<uint8_t>>& payloads)
    {
        uint32_t payload_count = payloads.size();
        assert(payload_count == (uint32_t)m);

        for (uint32_t i = 0; i < payload_count; ++i)
        {
            coding[i] = (char*)&(payloads[i][0]);
        }

        jerasure_matrix_encode(k, m, w, matrix, data, coding, m_symbol_size);
    }

    uint32_t block_size() { return m_block_size; }
    uint32_t symbol_size() { return m_symbol_size; }
    uint32_t payload_size() { return m_symbol_size; }

protected:
    // Code parameters
    int k, m, w;

    // Number of symbols
    uint32_t m_symbols;
    // Size of k+m symbols
    uint32_t m_symbol_size;
    // Size of a full generation (k symbols)
    uint32_t m_block_size;

    /* Jerasure Arguments */
    char** data;
    char** coding;
    int* matrix;
};

struct reed_sol_van_decoder
{
    reed_sol_van_decoder(uint32_t symbols, uint32_t symbol_size) :
        m_symbols(symbols), m_symbol_size(symbol_size)
    {
        k = m_symbols;
        m = m_symbols;
        w = 8;
        m_block_size = m_symbols * m_symbol_size;

//         matrix = reed_sol_vandermonde_coding_matrix(k, m, w);
//
//         // Allocate data and coding pointer arrays
//         data = new char*[k];
//         coding = new char*[m];
    }

    uint32_t block_size() { return m_block_size; }
    uint32_t symbol_size() { return m_symbol_size; }
    uint32_t payload_size() { return m_symbol_size; }

protected:
    // Code parameters
    int k, m, w;

    // Number of symbols
    uint32_t m_symbols;
    // Size of k+m symbols
    uint32_t m_symbol_size;
    // Size of a full generation (k symbols)
    uint32_t m_block_size;

    /* Jerasure Arguments */
    char** data;
    char** coding;
    int* matrix;
};

/// A test block represents an encoder and decoder pair
template<class Encoder, class Decoder>
struct throughput_benchmark : public gauge::time_benchmark
{
    void init()
    {
        m_factor = 1;
        gauge::time_benchmark::init();
    }

    void start()
    {
        m_encoded_symbols = 0;
        m_decoded_symbols = 0;
        gauge::time_benchmark::start();
    }

    void stop()
    {
        gauge::time_benchmark::stop();
    }

    double measurement()
    {
        // Get the time spent per iteration
        double time = gauge::time_benchmark::measurement();

        gauge::config_set cs = get_current_configuration();
        std::string type = cs.get_value<std::string>("type");
        uint32_t symbol_size = cs.get_value<uint32_t>("symbol_size");

        // The number of bytes {en|de}coded
        uint64_t total_bytes = 0;

        if(type == "decoder")
        {
            total_bytes = m_decoded_symbols * symbol_size;
        }
        else if(type == "encoder")
        {
            total_bytes = m_encoded_symbols * symbol_size;
        }
        else
        {
            assert(0);
        }

        // The bytes per iteration
        uint64_t bytes =
            total_bytes / gauge::time_benchmark::iteration_count();

        return bytes / time; // MB/s for each iteration
    }

    void store_run(tables::table& results)
    {
        if(!results.has_column("throughput"))
            results.add_column("throughput");

        results.set_value("throughput", measurement());
    }

    bool accept_measurement()
    {
        gauge::config_set cs = get_current_configuration();

        std::string type = cs.get_value<std::string>("type");

//         if(type == "decoder")
//         {
//             // If we are benchmarking a decoder we only accept
//             // the measurement if the decoding was successful
//             if(!m_decoder->is_complete())
//             {
//                 // We did not generate enough payloads to decode successfully,
//                 // so we will generate more payloads for next run
//                 m_factor++;
//
//                 return false;
//             }
//         }

        return gauge::time_benchmark::accept_measurement();
    }

    std::string unit_text() const
    {
        return "MB/s";
    }

    void get_options(gauge::po::variables_map& options)
    {
        auto symbols = options["symbols"].as<std::vector<uint32_t> >();
        auto symbol_size = options["symbol_size"].as<std::vector<uint32_t> >();
        auto types = options["type"].as<std::vector<std::string> >();

        assert(symbols.size() > 0);
        assert(symbol_size.size() > 0);
        assert(types.size() > 0);

        for (uint32_t i = 0; i < symbols.size(); ++i)
        {
            for (uint32_t j = 0; j < symbol_size.size(); ++j)
            {
                // Symbol size must be a multiple of 32
                assert(symbol_size[j] % 32 == 0);
                for (uint32_t u = 0; u < types.size(); ++u)
                {
                    gauge::config_set cs;
                    cs.set_value<uint32_t>("symbols", symbols[i]);
                    cs.set_value<uint32_t>("symbol_size", symbol_size[j]);

                    cs.set_value<std::string>("type", types[u]);

                    add_configuration(cs);
                }
            }
        }
    }

    void setup()
    {
        gauge::config_set cs = get_current_configuration();

        uint32_t symbols = cs.get_value<uint32_t>("symbols");
        uint32_t symbol_size = cs.get_value<uint32_t>("symbol_size");

        m_encoder = std::make_shared<Encoder>(symbols, symbol_size);
        m_decoder = std::make_shared<Decoder>(symbols, symbol_size);

        // Prepare the data to be encoded
        m_encoded_data.resize(m_encoder->block_size());

        for (uint8_t &e : m_encoded_data)
        {
            e = rand() % 256;
        }

        m_encoder->set_symbols(&m_encoded_data[0], m_encoded_data.size());

        // Prepare storage to the encoded payloads
        uint32_t payload_count = symbols * m_factor;

        m_payloads.resize(payload_count);
        for (uint32_t i = 0; i < payload_count; ++i)
        {
            m_payloads[i].resize(m_encoder->payload_size());
        }

        m_temp_payload.resize(m_encoder->payload_size());
    }

    void encode_payloads()
    {
        m_encoder->set_symbols(&m_encoded_data[0], m_encoded_data.size());

        m_encoder->encode_all(m_payloads);
        m_encoded_symbols += m_payloads.size();
    }

    void decode_payloads()
    {
        uint32_t payload_count = m_payloads.size();

        for (uint32_t i = 0; i < payload_count; ++i)
        {
            std::copy(m_payloads[i].begin(),
                      m_payloads[i].end(),
                      m_temp_payload.begin());

//             m_decoder->decode(&m_temp_payload[0]);
//
//             ++m_decoded_symbols;
//
//             if(m_decoder->is_complete())
//             {
//                 return;
//             }
        }
    }

    /// Run the encoder
    void run_encode()
    {
        // The clock is running
        RUN
        {
            encode_payloads();
        }
    }

    /// Run the decoder
    void run_decode()
    {
        // Encode some data
        encode_payloads();

        // The clock is running
        RUN
        {
            // We have to make sure the decoder is in a "clean" state
            // i.e. no symbols already decoded.
            //m_decoder->initialize(*m_decoder_factory);

            // Decode the payloads
            decode_payloads();
        }
    }

    void run_benchmark()
    {
        gauge::config_set cs = get_current_configuration();

        std::string type = cs.get_value<std::string>("type");

        if (type == "encoder")
        {
            run_encode();
        }
        else if (type == "decoder")
        {
            run_decode();
        }
        else
        {
            assert(0);
        }
    }

protected:

    /// The encoder
    std::shared_ptr<Encoder> m_encoder;

    /// The decoder
    std::shared_ptr<Decoder> m_decoder;

    /// The number of symbols encoded
    uint32_t m_encoded_symbols;

    /// The number of symbols decoded
    uint32_t m_decoded_symbols;

    /// The data encoded
    std::vector<uint8_t> m_encoded_data;

    /// Temporary payload to not destroy the already encoded payloads
    /// when decoding
    std::vector<uint8_t> m_temp_payload;

    /// Storage for encoded symbols
    std::vector< std::vector<uint8_t> > m_payloads;

    /// Multiplication factor for payload_count
    uint32_t m_factor;
};

/// Using this macro we may specify options. For specifying options
/// we use the boost program options library. So you may additional
/// details on how to do it in the manual for that library.
BENCHMARK_OPTION(throughput_options)
{
    gauge::po::options_description options;

    std::vector<uint32_t> symbols;
    symbols.push_back(16);
//     symbols.push_back(32);
//     symbols.push_back(64);
//     symbols.push_back(128);
//     symbols.push_back(256);
//     symbols.push_back(512);

    auto default_symbols =
        gauge::po::value<std::vector<uint32_t> >()->default_value(
            symbols, "")->multitoken();

    // Symbol size must be a multiple of 32
    std::vector<uint32_t> symbol_size;
    symbol_size.push_back(1000000);

    auto default_symbol_size =
        gauge::po::value<std::vector<uint32_t> >()->default_value(
            symbol_size, "")->multitoken();

    std::vector<std::string> types;
    types.push_back("encoder");
    types.push_back("decoder");

    auto default_types =
        gauge::po::value<std::vector<std::string> >()->default_value(
            types, "")->multitoken();

    options.add_options()
        ("symbols", default_symbols, "Set the number of symbols");

    options.add_options()
        ("symbol_size", default_symbol_size, "Set the symbol size in bytes");

    options.add_options()
        ("type", default_types, "Set type [encoder|decoder]");

    gauge::runner::instance().register_options(options);
}

//------------------------------------------------------------------
// Reed-Solomon Vandermonde
//------------------------------------------------------------------

typedef throughput_benchmark<reed_sol_van_encoder, reed_sol_van_decoder>
    reed_sol_van_throughput;

BENCHMARK_F(reed_sol_van_throughput, Jerasure, ReedSolVan, 5)
{
    run_benchmark();
}

int main(int argc, const char* argv[])
{
    srand(static_cast<uint32_t>(time(0)));

    gauge::runner::add_default_printers();
    gauge::runner::run_benchmarks(argc, argv);

    return 0;
}
<commit_msg>Properly initialize coding matrix<commit_after>// Copyright Steinwurf ApS 2011-2012.
// Distributed under the "STEINWURF RESEARCH LICENSE 1.0".
// See accompanying file LICENSE.rst or
// http://www.steinwurf.com/licensing

#include <ctime>
#include <cstdint>

//#include <boost/make_shared.hpp>

#include <gauge/gauge.hpp>
#include <gauge/console_printer.hpp>
#include <gauge/python_printer.hpp>
#include <gauge/csv_printer.hpp>
#include <gauge/json_printer.hpp>

#include <tables/table.hpp>

extern "C"
{
#include <gf_rand.h>
#include <jerasure.h>
#include <reed_sol.h>
}

struct reed_sol_van_encoder
{
    reed_sol_van_encoder(uint32_t symbols, uint32_t symbol_size) :
        m_symbols(symbols), m_symbol_size(symbol_size), matrix(0)
    {
        k = m_symbols;
        m = m_symbols;
        w = 8;
        m_block_size = m_symbols * m_symbol_size;

        // Allocate data and coding pointer arrays
        data = new char*[k];
        coding = new char*[m];
    }

    ~reed_sol_van_encoder()
    {
        if (data) delete[] data;
        if (coding) delete[] coding;
        // matrix was allocated by
        if (matrix) { free(matrix); matrix = 0; }
    }

    void initialize()
    {
        if (matrix) { free(matrix); matrix = 0; }
        matrix = reed_sol_vandermonde_coding_matrix(k, m, w);
    }

    void set_symbols(uint8_t* ptr, uint32_t size)
    {
        // Set pointers to point to the input symbols
        for (int i = 0; i < k; i++)
        {
            assert((i+1) * m_symbol_size <= size);
            data[i] = (char*)ptr + i * m_symbol_size;
        }
    }

    void encode_all(std::vector<std::vector<uint8_t>>& payloads)
    {
        uint32_t payload_count = payloads.size();
        assert(payload_count == (uint32_t)m);

        for (uint32_t i = 0; i < payload_count; ++i)
        {
            coding[i] = (char*)&(payloads[i][0]);
        }

        jerasure_matrix_encode(k, m, w, matrix, data, coding, m_symbol_size);
    }

    uint32_t block_size() { return m_block_size; }
    uint32_t symbol_size() { return m_symbol_size; }
    uint32_t payload_size() { return m_symbol_size; }

protected:
    // Code parameters
    int k, m, w;

    // Number of symbols
    uint32_t m_symbols;
    // Size of k+m symbols
    uint32_t m_symbol_size;
    // Size of a full generation (k symbols)
    uint32_t m_block_size;

    /* Jerasure Arguments */
    char** data;
    char** coding;
    int* matrix;
};

struct reed_sol_van_decoder
{
    reed_sol_van_decoder(uint32_t symbols, uint32_t symbol_size) :
        m_symbols(symbols), m_symbol_size(symbol_size)
    {
        k = m_symbols;
        m = m_symbols;
        w = 8;
        m_block_size = m_symbols * m_symbol_size;

//         matrix = reed_sol_vandermonde_coding_matrix(k, m, w);
//
//         // Allocate data and coding pointer arrays
//         data = new char*[k];
//         coding = new char*[m];
    }

    uint32_t block_size() { return m_block_size; }
    uint32_t symbol_size() { return m_symbol_size; }
    uint32_t payload_size() { return m_symbol_size; }

protected:
    // Code parameters
    int k, m, w;

    // Number of symbols
    uint32_t m_symbols;
    // Size of k+m symbols
    uint32_t m_symbol_size;
    // Size of a full generation (k symbols)
    uint32_t m_block_size;

    /* Jerasure Arguments */
    char** data;
    char** coding;
    int* matrix;
};

/// A test block represents an encoder and decoder pair
template<class Encoder, class Decoder>
struct throughput_benchmark : public gauge::time_benchmark
{
    void init()
    {
        m_factor = 1;
        gauge::time_benchmark::init();
    }

    void start()
    {
        m_encoded_symbols = 0;
        m_decoded_symbols = 0;
        gauge::time_benchmark::start();
    }

    void stop()
    {
        gauge::time_benchmark::stop();
    }

    double measurement()
    {
        // Get the time spent per iteration
        double time = gauge::time_benchmark::measurement();

        gauge::config_set cs = get_current_configuration();
        std::string type = cs.get_value<std::string>("type");
        uint32_t symbol_size = cs.get_value<uint32_t>("symbol_size");

        // The number of bytes {en|de}coded
        uint64_t total_bytes = 0;

        if(type == "decoder")
        {
            total_bytes = m_decoded_symbols * symbol_size;
        }
        else if(type == "encoder")
        {
            total_bytes = m_encoded_symbols * symbol_size;
        }
        else
        {
            assert(0);
        }

        // The bytes per iteration
        uint64_t bytes =
            total_bytes / gauge::time_benchmark::iteration_count();

        return bytes / time; // MB/s for each iteration
    }

    void store_run(tables::table& results)
    {
        if(!results.has_column("throughput"))
            results.add_column("throughput");

        results.set_value("throughput", measurement());
    }

    bool accept_measurement()
    {
        gauge::config_set cs = get_current_configuration();

        std::string type = cs.get_value<std::string>("type");

//         if(type == "decoder")
//         {
//             // If we are benchmarking a decoder we only accept
//             // the measurement if the decoding was successful
//             if(!m_decoder->is_complete())
//             {
//                 // We did not generate enough payloads to decode successfully,
//                 // so we will generate more payloads for next run
//                 m_factor++;
//
//                 return false;
//             }
//         }

        return gauge::time_benchmark::accept_measurement();
    }

    std::string unit_text() const
    {
        return "MB/s";
    }

    void get_options(gauge::po::variables_map& options)
    {
        auto symbols = options["symbols"].as<std::vector<uint32_t> >();
        auto symbol_size = options["symbol_size"].as<std::vector<uint32_t> >();
        auto types = options["type"].as<std::vector<std::string> >();

        assert(symbols.size() > 0);
        assert(symbol_size.size() > 0);
        assert(types.size() > 0);

        for (uint32_t i = 0; i < symbols.size(); ++i)
        {
            for (uint32_t j = 0; j < symbol_size.size(); ++j)
            {
                // Symbol size must be a multiple of 32
                assert(symbol_size[j] % 32 == 0);
                for (uint32_t u = 0; u < types.size(); ++u)
                {
                    gauge::config_set cs;
                    cs.set_value<uint32_t>("symbols", symbols[i]);
                    cs.set_value<uint32_t>("symbol_size", symbol_size[j]);

                    cs.set_value<std::string>("type", types[u]);

                    add_configuration(cs);
                }
            }
        }
    }

    void setup()
    {
        gauge::config_set cs = get_current_configuration();

        uint32_t symbols = cs.get_value<uint32_t>("symbols");
        uint32_t symbol_size = cs.get_value<uint32_t>("symbol_size");

        m_encoder = std::make_shared<Encoder>(symbols, symbol_size);
        m_decoder = std::make_shared<Decoder>(symbols, symbol_size);

        // Prepare the data to be encoded
        m_encoded_data.resize(m_encoder->block_size());

        for (uint8_t &e : m_encoded_data)
        {
            e = rand() % 256;
        }

        m_encoder->set_symbols(&m_encoded_data[0], m_encoded_data.size());

        // Prepare storage to the encoded payloads
        uint32_t payload_count = symbols * m_factor;

        m_payloads.resize(payload_count);
        for (uint32_t i = 0; i < payload_count; ++i)
        {
            m_payloads[i].resize(m_encoder->payload_size());
        }

        m_temp_payload.resize(m_encoder->payload_size());
    }

    void encode_payloads()
    {
        m_encoder->set_symbols(&m_encoded_data[0], m_encoded_data.size());

        m_encoder->encode_all(m_payloads);
        m_encoded_symbols += m_payloads.size();
    }

    void decode_payloads()
    {
        uint32_t payload_count = m_payloads.size();

        for (uint32_t i = 0; i < payload_count; ++i)
        {
            std::copy(m_payloads[i].begin(),
                      m_payloads[i].end(),
                      m_temp_payload.begin());

//             m_decoder->decode(&m_temp_payload[0]);
//
//             ++m_decoded_symbols;
//
//             if(m_decoder->is_complete())
//             {
//                 return;
//             }
        }
    }

    /// Run the encoder
    void run_encode()
    {
        // The clock is running
        RUN
        {
            // We have to make sure the encoder is in a "clean" state
            m_encoder->initialize();
            encode_payloads();
        }
    }

    /// Run the decoder
    void run_decode()
    {
        // Encode some data
        encode_payloads();

        // The clock is running
        RUN
        {
            // We have to make sure the decoder is in a "clean" state
            // i.e. no symbols already decoded.
            //m_decoder->initialize(*m_decoder_factory);

            // Decode the payloads
            decode_payloads();
        }
    }

    void run_benchmark()
    {
        gauge::config_set cs = get_current_configuration();

        std::string type = cs.get_value<std::string>("type");

        if (type == "encoder")
        {
            run_encode();
        }
        else if (type == "decoder")
        {
            run_decode();
        }
        else
        {
            assert(0);
        }
    }

protected:

    /// The encoder
    std::shared_ptr<Encoder> m_encoder;

    /// The decoder
    std::shared_ptr<Decoder> m_decoder;

    /// The number of symbols encoded
    uint32_t m_encoded_symbols;

    /// The number of symbols decoded
    uint32_t m_decoded_symbols;

    /// The data encoded
    std::vector<uint8_t> m_encoded_data;

    /// Temporary payload to not destroy the already encoded payloads
    /// when decoding
    std::vector<uint8_t> m_temp_payload;

    /// Storage for encoded symbols
    std::vector< std::vector<uint8_t> > m_payloads;

    /// Multiplication factor for payload_count
    uint32_t m_factor;
};

/// Using this macro we may specify options. For specifying options
/// we use the boost program options library. So you may additional
/// details on how to do it in the manual for that library.
BENCHMARK_OPTION(throughput_options)
{
    gauge::po::options_description options;

    std::vector<uint32_t> symbols;
    symbols.push_back(16);
//     symbols.push_back(32);
//     symbols.push_back(64);
//     symbols.push_back(128);
//     symbols.push_back(256);
//     symbols.push_back(512);

    auto default_symbols =
        gauge::po::value<std::vector<uint32_t> >()->default_value(
            symbols, "")->multitoken();

    // Symbol size must be a multiple of 32
    std::vector<uint32_t> symbol_size;
    symbol_size.push_back(1000000);

    auto default_symbol_size =
        gauge::po::value<std::vector<uint32_t> >()->default_value(
            symbol_size, "")->multitoken();

    std::vector<std::string> types;
    types.push_back("encoder");
    types.push_back("decoder");

    auto default_types =
        gauge::po::value<std::vector<std::string> >()->default_value(
            types, "")->multitoken();

    options.add_options()
        ("symbols", default_symbols, "Set the number of symbols");

    options.add_options()
        ("symbol_size", default_symbol_size, "Set the symbol size in bytes");

    options.add_options()
        ("type", default_types, "Set type [encoder|decoder]");

    gauge::runner::instance().register_options(options);
}

//------------------------------------------------------------------
// Reed-Solomon Vandermonde
//------------------------------------------------------------------

typedef throughput_benchmark<reed_sol_van_encoder, reed_sol_van_decoder>
    reed_sol_van_throughput;

BENCHMARK_F(reed_sol_van_throughput, Jerasure, ReedSolVan, 5)
{
    run_benchmark();
}

int main(int argc, const char* argv[])
{
    srand(static_cast<uint32_t>(time(0)));

    gauge::runner::add_default_printers();
    gauge::runner::run_benchmarks(argc, argv);

    return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Intel Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "net/base/net_util.h"
#include "xwalk/application/browser/application_system.h"
#include "xwalk/application/common/application.h"
#include "xwalk/application/common/constants.h"
#include "xwalk/runtime/browser/runtime.h"
#include "xwalk/runtime/browser/runtime_registry.h"
#include "xwalk/runtime/common/xwalk_notification_types.h"
#include "xwalk/test/base/in_process_browser_test.h"

namespace {

bool WaitForRuntimeCountCallback(int* count) {
  --(*count);
  return *count == 0;
}

}  // namespace

using xwalk::application::Application;
using xwalk::Runtime;
using xwalk::RuntimeRegistry;

class ApplicationMainDocumentBrowserTest: public InProcessBrowserTest {
 public:
  virtual void SetUp() OVERRIDE;
  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;

  base::FilePath test_data_dir_;
};

void ApplicationMainDocumentBrowserTest::SetUp() {
  PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir_);
  test_data_dir_ = test_data_dir_
    .Append(FILE_PATH_LITERAL("xwalk"))
    .Append(FILE_PATH_LITERAL("application"))
    .Append(FILE_PATH_LITERAL("test"))
    .Append(FILE_PATH_LITERAL("data"));
  InProcessBrowserTest::SetUp();
}

void ApplicationMainDocumentBrowserTest::SetUpCommandLine(
    CommandLine* command_line) {
  GURL url = net::FilePathToFileURL(test_data_dir_.Append(
        FILE_PATH_LITERAL("main_document")));
  command_line->AppendArg(url.spec());
}

// Verifies the runtime creation when main document is used.
IN_PROC_BROWSER_TEST_F(ApplicationMainDocumentBrowserTest, MainDocument) {
  content::RunAllPendingInMessageLoop();
  const xwalk::RuntimeList& runtimes = RuntimeRegistry::Get()->runtimes();
  // At least the main document's runtime exist after launch.
  ASSERT_GE(runtimes.size(), 1U);

  Runtime* main_runtime = runtimes[0];
  xwalk::RuntimeContext* runtime_context = main_runtime->runtime_context();
  xwalk::application::ApplicationService* service =
    runtime_context->GetApplicationSystem()->application_service();
  const Application* app = service->GetRunningApplication();
  GURL generated_url =
    app->GetResourceURL(xwalk::application::kGeneratedMainDocumentFilename);
  // Check main document URL.
  ASSERT_EQ(main_runtime->web_contents()->GetURL(), generated_url);
  ASSERT_TRUE(!main_runtime->window());

  // There should exist 2 runtimes(one for generated main document, one for the
  // window created by main document). As WindowedNotificationObserver::Wait()
  // will call the callback function once when inovke, so add one more for the
  // Wait() to consume.
  int count = 2 - runtimes.size() + 1;
  if (count > 1) {
    content::WindowedNotificationObserver(
        xwalk::NOTIFICATION_RUNTIME_OPENED,
        base::Bind(&WaitForRuntimeCountCallback, &count)).Wait();
  }

  ASSERT_EQ(2, RuntimeRegistry::Get()->runtimes().size());
}
<commit_msg>Fix main document browser test timeout issue<commit_after>// Copyright (c) 2013 Intel Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "net/base/net_util.h"
#include "xwalk/application/browser/application_system.h"
#include "xwalk/application/common/application.h"
#include "xwalk/application/common/constants.h"
#include "xwalk/runtime/browser/runtime.h"
#include "xwalk/runtime/browser/runtime_registry.h"
#include "xwalk/runtime/common/xwalk_notification_types.h"
#include "xwalk/test/base/in_process_browser_test.h"

namespace {

bool WaitForRuntimeCountCallback(int* count) {
  --(*count);
  return *count == 0;
}

}  // namespace

using xwalk::application::Application;
using xwalk::Runtime;
using xwalk::RuntimeRegistry;

class ApplicationMainDocumentBrowserTest: public InProcessBrowserTest {
 public:
  virtual void SetUp() OVERRIDE;
  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;

  base::FilePath test_data_dir_;
};

void ApplicationMainDocumentBrowserTest::SetUp() {
  PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir_);
  test_data_dir_ = test_data_dir_
    .Append(FILE_PATH_LITERAL("xwalk"))
    .Append(FILE_PATH_LITERAL("application"))
    .Append(FILE_PATH_LITERAL("test"))
    .Append(FILE_PATH_LITERAL("data"));
  InProcessBrowserTest::SetUp();
}

void ApplicationMainDocumentBrowserTest::SetUpCommandLine(
    CommandLine* command_line) {
  GURL url = net::FilePathToFileURL(test_data_dir_.Append(
        FILE_PATH_LITERAL("main_document")));
  command_line->AppendArg(url.spec());
}

// Verifies the runtime creation when main document is used.
IN_PROC_BROWSER_TEST_F(ApplicationMainDocumentBrowserTest, MainDocument) {
  content::RunAllPendingInMessageLoop();
  const xwalk::RuntimeList& runtimes = RuntimeRegistry::Get()->runtimes();
  // At least the main document's runtime exist after launch.
  ASSERT_GE(runtimes.size(), 1U);

  Runtime* main_runtime = runtimes[0];
  xwalk::RuntimeContext* runtime_context = main_runtime->runtime_context();
  xwalk::application::ApplicationService* service =
    runtime_context->GetApplicationSystem()->application_service();
  const Application* app = service->GetRunningApplication();
  GURL generated_url =
    app->GetResourceURL(xwalk::application::kGeneratedMainDocumentFilename);
  // Check main document URL.
  ASSERT_EQ(main_runtime->web_contents()->GetURL(), generated_url);
  ASSERT_TRUE(!main_runtime->window());

  // There should exist 2 runtimes(one for generated main document, one for the
  // window created by main document).
  int count = 2 - runtimes.size();
  if (count) {
    content::WindowedNotificationObserver(
        xwalk::NOTIFICATION_RUNTIME_OPENED,
        base::Bind(&WaitForRuntimeCountCallback, &count)).Wait();
  }

  ASSERT_EQ(2, RuntimeRegistry::Get()->runtimes().size());
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include "thrift/lib/cpp2/server/Cpp2Connection.h"

#include "thrift/lib/cpp/async/TEventConnection.h"
#include "thrift/lib/cpp/async/TAsyncSocket.h"
#include "thrift/lib/cpp2/server/ThriftServer.h"
#include "thrift/lib/cpp2/server/Cpp2Worker.h"
#include "thrift/lib/cpp2/security/SecurityKillSwitch.h"
#include <thrift/lib/cpp2/protocol/BinaryProtocol.h>

#include <assert.h>

namespace apache { namespace thrift {

using namespace apache::thrift::protocol;
using namespace apache::thrift::server;
using namespace apache::thrift::transport;
using namespace apache::thrift::async;
using namespace std;
using apache::thrift::TApplicationException;

Cpp2Connection::Cpp2Connection(
  std::shared_ptr<TAsyncSocket> asyncSocket,
  const TSocketAddress* address,
  Cpp2Worker* worker)
    : processor_(worker->getServer()->getCpp2Processor())
    , channel_(new HeaderServerChannel(asyncSocket))
    , worker_(worker)
    , context_(address,
               asyncSocket.get(),
               channel_->getHeader(),
               channel_->getSaslServer(),
               worker->getServer()->getEventBaseManager())
    , socket_(asyncSocket) {
  channel_->setQueueSends(worker->getServer()->getQueueSends());
  channel_->getHeader()->setMinCompressBytes(
    worker_->getServer()->getMinCompressBytes());
  auto observer = worker->getServer()->getObserver();
  if (observer) {
    channel_->setSampleRate(observer->getSampleRate());
  }

  // If the security kill switch is present, make the security policy default
  // to "permitted" or "disabled".
  if (isSecurityKillSwitchEnabled()) {
    worker_->getServer()->setNonSaslEnabled(true);
  }

  if (worker_->getServer()->getSaslEnabled() &&
      worker_->getServer()->getNonSaslEnabled()) {
    // Check if we need to use a stub, otherwise set the kerberos principal
    auto factory = worker_->getServer()->getSaslServerFactory();
    if (factory) {
      channel_->setSaslServer(
        unique_ptr<SaslServer>(factory(asyncSocket->getEventBase()))
      );
    } else {
      channel_->getSaslServer()->setServiceIdentity(
        worker_->getServer()->getServicePrincipal());
    }
    channel_->getHeader()->setSecurityPolicy(THRIFT_SECURITY_PERMITTED);
  } else if (worker_->getServer()->getSaslEnabled()) {
    // Check if we need to use a stub, otherwise set the kerberos principal
    auto factory = worker_->getServer()->getSaslServerFactory();
    if (factory) {
      channel_->setSaslServer(
        unique_ptr<SaslServer>(factory(asyncSocket->getEventBase()))
      );
    } else {
      channel_->getSaslServer()->setServiceIdentity(
        worker_->getServer()->getServicePrincipal());
    }
    channel_->getHeader()->setSecurityPolicy(THRIFT_SECURITY_REQUIRED);
  } else {
    // If neither is set, act as if non-sasl was specified.
    channel_->getHeader()->setSecurityPolicy(THRIFT_SECURITY_DISABLED);
  }

  auto handler = worker->getServer()->getEventHandler();
  if (handler) {
    handler->newConnection(&context_);
  }
}

Cpp2Connection::~Cpp2Connection() {
  cancelTimeout();
  channel_.reset();
}

void Cpp2Connection::stop() {
  cancelTimeout();
  for (auto req : activeRequests_) {
    req->cancelRequest();
    auto observer = worker_->getServer()->getObserver();
    if (observer) {
      observer->taskKilled();
    }
  }

  if (channel_) {
    channel_->setCallback(nullptr);
  }

  auto handler = worker_->getServer()->getEventHandler();
  if (handler) {
    handler->connectionDestroyed(&context_);
  }
}

void Cpp2Connection::timeoutExpired() noexcept {
  // Only disconnect if there are no active requests. No need to set another
  // timeout here because it's going to be set when all the requests are
  // handled.
  if (activeRequests_.empty()) {
    disconnect("idle timeout");
  }
}

void Cpp2Connection::disconnect(const char* comment) noexcept {
  // This must be the last call, it may delete this.
  folly::ScopeGuard guard = folly::makeGuard([&]{
    worker_->closeConnection(shared_from_this());
  });

  VLOG(1) << "ERROR: Disconnect: " << comment << " on channel: " <<
    context_.getPeerAddress()->describe();
  auto observer = worker_->getServer()->getObserver();
  if (observer) {
    observer->connDropped();
  }
}

void Cpp2Connection::requestTimeoutExpired() {
  VLOG(1) << "ERROR: Task expired on channel: " <<
    context_.getPeerAddress()->describe();
  auto observer = worker_->getServer()->getObserver();
  if (observer) {
    observer->taskTimeout();
  }
}

bool Cpp2Connection::pending() {
  return socket_->isPending();
}

void Cpp2Connection::killRequest(
    ResponseChannel::Request& req,
    TApplicationException::TApplicationExceptionType reason,
    const char* comment) {
  VLOG(1) << "ERROR: Task killed: " << comment
          << ": " << context_.getPeerAddress()->getAddressStr();

  auto server = worker_->getServer();
  auto observer = server->getObserver();
  if (observer) {
    if (reason ==
         TApplicationException::TApplicationExceptionType::LOADSHEDDING) {
      observer->serverOverloaded();
    } else {
      observer->taskKilled();
    }
  }

  // Nothing to do for Thrift oneway request.
  if (req.isOneway()) {
    return;
  }

  // Thrift1 oneway request doesn't use ONEWAY_REQUEST_ID and
  // may end up here. No need to send error back for such requests
  if (!processor_->isOnewayMethod(req.getBuf(),
      channel_->getHeader())) {
    apache::thrift::TApplicationException x(reason, comment);
    req.sendError(std::make_exception_ptr(x), kOverloadedErrorCode);
  } else {
    // Send an empty request so reqId will be handler properly
    req.sendReply(std::unique_ptr<folly::IOBuf>());
  }
}

// Response Channel callbacks
void Cpp2Connection::requestReceived(
  unique_ptr<ResponseChannel::Request>&& req) {

  auto server = worker_->getServer();
  auto observer = server->getObserver();

  auto injectedFailure = server->maybeInjectFailure();
  switch (injectedFailure) {
  case ThriftServer::InjectedFailure::NONE:
    break;
  case ThriftServer::InjectedFailure::ERROR:
    killRequest(*req,
        TApplicationException::TApplicationExceptionType::INJECTED_FAILURE,
        "injected failure");
    return;
  case ThriftServer::InjectedFailure::DROP:
    VLOG(1) << "ERROR: injected drop: "
            << context_.getPeerAddress()->getAddressStr();
    return;
  case ThriftServer::InjectedFailure::DISCONNECT:
    disconnect("injected failure");
    return;
  }

  int activeRequests = worker_->activeRequests_;
  activeRequests += worker_->pendingCount();

  if (server->isOverloaded(activeRequests)) {
    killRequest(*req,
        TApplicationException::TApplicationExceptionType::LOADSHEDDING,
        "loadshedding request");
    return;
  }

  server->incGlobalActiveRequests();
  if (req->timestamps_.readBegin != 0) {
    // Expensive operations; this happens once every
    // TServerCounters.sampleRate
    req->timestamps_.processBegin =
      apache::thrift::concurrency::Util::currentTimeUsec();
    if (observer) {
      observer->queuedRequests(
        server->getThreadManager()->pendingTaskCount());
      if (server->getIsUnevenLoad()) {
        observer->activeRequests(server->getGlobalActiveRequests());
      }
    }
  }

  unique_ptr<folly::IOBuf> buf = req->getBuf()->clone();
  unique_ptr<Cpp2Request> t2r(
    new Cpp2Request(std::move(req), shared_from_this()));
  activeRequests_.insert(t2r.get());
  ++worker_->activeRequests_;

  if (observer) {
    observer->receivedRequest();
  }

  auto timeoutTime = server->getTaskExpireTime();
  if (server->useClientTimeout_) {
    auto clientTimeoutTime = channel_->getHeader()->getClientTimeout();
    if (clientTimeoutTime > std::chrono::milliseconds(0) &&
        clientTimeoutTime < timeoutTime) {
      timeoutTime = clientTimeoutTime;
    }
  }
  if (timeoutTime > std::chrono::milliseconds(0)) {
    worker_->scheduleTimeout(t2r.get(), timeoutTime);
    t2r->setStreamTimeout(timeoutTime);
  }
  auto reqContext = t2r->getContext();

  try {
    processor_->process(std::move(t2r),
                        std::move(buf),
                        static_cast<apache::thrift::protocol::PROTOCOL_TYPES>
                        (channel_->getHeader()->getProtocolId()),
                        reqContext,
                        worker_->getEventBase(),
                        server->getThreadManager().get());
  } catch (...) {
    LOG(WARNING) << "Process exception: " <<
      folly::exceptionStr(std::current_exception());
    throw;
  }
}

void Cpp2Connection::channelClosed(std::exception_ptr&& ex) {
  // This must be the last call, it may delete this.
  folly::ScopeGuard guard = folly::makeGuard([&]{
    worker_->closeConnection(shared_from_this());
  });

  VLOG(4) << "Channel " <<
    context_.getPeerAddress()->describe() << " closed";
}

void Cpp2Connection::removeRequest(Cpp2Request *req) {
  activeRequests_.erase(req);
  if (activeRequests_.empty()) {
    worker_->scheduleIdleConnectionTimeout(this);
  }
}

Cpp2Connection::Cpp2Request::Cpp2Request(
    std::unique_ptr<ResponseChannel::Request> req,
    std::shared_ptr<Cpp2Connection> con)
  : req_(std::move(req))
  , connection_(con)
  , reqContext_(&con->context_) {
  RequestContext::create();
}

MessageChannel::SendCallback*
Cpp2Connection::Cpp2Request::prepareSendCallback(
    MessageChannel::SendCallback* sendCallback,
    apache::thrift::server::TServerObserver* observer) {
  // If we are sampling this call, wrap it with a Cpp2Sample, which also
  // implements MessageChannel::SendCallback. Callers of sendReply/sendError
  // are responsible for cleaning up their own callbacks.
  MessageChannel::SendCallback* cb = sendCallback;
  if (req_->timestamps_.readBegin != 0) {
    req_->timestamps_.processEnd =
      apache::thrift::concurrency::Util::currentTimeUsec();
    // Cpp2Sample will delete itself when it's callback is called.
    cb = new Cpp2Sample(
      std::move(req_->timestamps_),
      observer,
      sendCallback);
  }
  return cb;
}

void Cpp2Connection::Cpp2Request::sendReply(
    std::unique_ptr<folly::IOBuf>&& buf,
    MessageChannel::SendCallback* sendCallback) {
  if (req_->isActive()) {
    auto observer = connection_->getWorker()->getServer()->getObserver().get();
    req_->sendReply(
      std::move(buf),
      prepareSendCallback(sendCallback, observer));
    cancelTimeout();
    if (observer) {
      observer->sentReply();
    }
  }
}

void Cpp2Connection::Cpp2Request::sendError(
    std::exception_ptr ex,
    std::string exCode,
    MessageChannel::SendCallback* sendCallback) {
  if (req_->isActive()) {
    auto observer = connection_->getWorker()->getServer()->getObserver().get();
    req_->sendError(ex, exCode, prepareSendCallback(sendCallback, observer));
    cancelTimeout();
  }
}

void Cpp2Connection::Cpp2Request::sendReplyWithStreams(
    std::unique_ptr<folly::IOBuf>&& data,
    std::unique_ptr<StreamManager>&& streams,
    MessageChannel::SendCallback* sendCallback) {
  if (req_->isActive()) {
    auto observer = connection_->getWorker()->getServer()->getObserver().get();
    req_->sendReplyWithStreams(
        std::move(data),
        std::move(streams),
        prepareSendCallback(sendCallback, observer));
    cancelTimeout();
    if (observer) {
      observer->sentReply();
    }
  }
}

void Cpp2Connection::Cpp2Request::setStreamTimeout(
    const std::chrono::milliseconds& timeout) {
  if (req_->isActive()) {
    req_->setStreamTimeout(timeout);
  }
}

void Cpp2Connection::Cpp2Request::timeoutExpired() noexcept {
  apache::thrift::TApplicationException x(
      TApplicationException::TApplicationExceptionType::TIMEOUT,
      "Task expired");
  sendError(std::make_exception_ptr(x), kTaskExpiredErrorCode);
  req_->cancel();
  connection_->requestTimeoutExpired();
}

Cpp2Connection::Cpp2Request::~Cpp2Request() {
  connection_->removeRequest(this);
  cancelTimeout();
  connection_->getWorker()->activeRequests_--;
  connection_->getWorker()->getServer()->decGlobalActiveRequests();
}

// Cancel request is usually called from a different thread than sendReply.
void Cpp2Connection::Cpp2Request::cancelRequest() {
  cancelTimeout();
  req_->cancel();
}

Cpp2Connection::Cpp2Sample::Cpp2Sample(
    apache::thrift::server::TServerObserver::CallTimestamps&& timestamps,
    apache::thrift::server::TServerObserver* observer,
    MessageChannel::SendCallback* chainedCallback)
  : timestamps_(timestamps)
  , observer_(observer)
  , chainedCallback_(chainedCallback) {
  DCHECK(observer != nullptr);
}

void Cpp2Connection::Cpp2Sample::sendQueued() {
  if (chainedCallback_ != nullptr) {
    chainedCallback_->sendQueued();
  }
  timestamps_.writeBegin =
    apache::thrift::concurrency::Util::currentTimeUsec();
}

void Cpp2Connection::Cpp2Sample::messageSent() {
  if (chainedCallback_ != nullptr) {
    chainedCallback_->messageSent();
  }
  timestamps_.writeEnd =
    apache::thrift::concurrency::Util::currentTimeUsec();
  delete this;
}

void Cpp2Connection::Cpp2Sample::messageSendError(std::exception_ptr&& e){
  if (chainedCallback_ != nullptr) {
    chainedCallback_->messageSendError(std::move(e));
  }
  timestamps_.writeEnd =
    apache::thrift::concurrency::Util::currentTimeUsec();
  delete this;
}

Cpp2Connection::Cpp2Sample::~Cpp2Sample() {
  if (observer_) {
    observer_->callCompleted(timestamps_);
  }
}

}} // apache::thrift
<commit_msg>more logging for taskKilled<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include "thrift/lib/cpp2/server/Cpp2Connection.h"

#include "thrift/lib/cpp/async/TEventConnection.h"
#include "thrift/lib/cpp/async/TAsyncSocket.h"
#include "thrift/lib/cpp2/server/ThriftServer.h"
#include "thrift/lib/cpp2/server/Cpp2Worker.h"
#include "thrift/lib/cpp2/security/SecurityKillSwitch.h"
#include <thrift/lib/cpp2/protocol/BinaryProtocol.h>

#include <assert.h>

namespace apache { namespace thrift {

using namespace apache::thrift::protocol;
using namespace apache::thrift::server;
using namespace apache::thrift::transport;
using namespace apache::thrift::async;
using namespace std;
using apache::thrift::TApplicationException;

Cpp2Connection::Cpp2Connection(
  std::shared_ptr<TAsyncSocket> asyncSocket,
  const TSocketAddress* address,
  Cpp2Worker* worker)
    : processor_(worker->getServer()->getCpp2Processor())
    , channel_(new HeaderServerChannel(asyncSocket))
    , worker_(worker)
    , context_(address,
               asyncSocket.get(),
               channel_->getHeader(),
               channel_->getSaslServer(),
               worker->getServer()->getEventBaseManager())
    , socket_(asyncSocket) {
  channel_->setQueueSends(worker->getServer()->getQueueSends());
  channel_->getHeader()->setMinCompressBytes(
    worker_->getServer()->getMinCompressBytes());
  auto observer = worker->getServer()->getObserver();
  if (observer) {
    channel_->setSampleRate(observer->getSampleRate());
  }

  // If the security kill switch is present, make the security policy default
  // to "permitted" or "disabled".
  if (isSecurityKillSwitchEnabled()) {
    worker_->getServer()->setNonSaslEnabled(true);
  }

  if (worker_->getServer()->getSaslEnabled() &&
      worker_->getServer()->getNonSaslEnabled()) {
    // Check if we need to use a stub, otherwise set the kerberos principal
    auto factory = worker_->getServer()->getSaslServerFactory();
    if (factory) {
      channel_->setSaslServer(
        unique_ptr<SaslServer>(factory(asyncSocket->getEventBase()))
      );
    } else {
      channel_->getSaslServer()->setServiceIdentity(
        worker_->getServer()->getServicePrincipal());
    }
    channel_->getHeader()->setSecurityPolicy(THRIFT_SECURITY_PERMITTED);
  } else if (worker_->getServer()->getSaslEnabled()) {
    // Check if we need to use a stub, otherwise set the kerberos principal
    auto factory = worker_->getServer()->getSaslServerFactory();
    if (factory) {
      channel_->setSaslServer(
        unique_ptr<SaslServer>(factory(asyncSocket->getEventBase()))
      );
    } else {
      channel_->getSaslServer()->setServiceIdentity(
        worker_->getServer()->getServicePrincipal());
    }
    channel_->getHeader()->setSecurityPolicy(THRIFT_SECURITY_REQUIRED);
  } else {
    // If neither is set, act as if non-sasl was specified.
    channel_->getHeader()->setSecurityPolicy(THRIFT_SECURITY_DISABLED);
  }

  auto handler = worker->getServer()->getEventHandler();
  if (handler) {
    handler->newConnection(&context_);
  }
}

Cpp2Connection::~Cpp2Connection() {
  cancelTimeout();
  channel_.reset();
}

void Cpp2Connection::stop() {
  cancelTimeout();
  for (auto req : activeRequests_) {
    VLOG(1) << "Task killed due to channel close: " <<
      context_.getPeerAddress()->describe();
    req->cancelRequest();
    auto observer = worker_->getServer()->getObserver();
    if (observer) {
      observer->taskKilled();
    }
  }

  if (channel_) {
    channel_->setCallback(nullptr);
  }

  auto handler = worker_->getServer()->getEventHandler();
  if (handler) {
    handler->connectionDestroyed(&context_);
  }
}

void Cpp2Connection::timeoutExpired() noexcept {
  // Only disconnect if there are no active requests. No need to set another
  // timeout here because it's going to be set when all the requests are
  // handled.
  if (activeRequests_.empty()) {
    disconnect("idle timeout");
  }
}

void Cpp2Connection::disconnect(const char* comment) noexcept {
  // This must be the last call, it may delete this.
  folly::ScopeGuard guard = folly::makeGuard([&]{
    worker_->closeConnection(shared_from_this());
  });

  VLOG(1) << "ERROR: Disconnect: " << comment << " on channel: " <<
    context_.getPeerAddress()->describe();
  auto observer = worker_->getServer()->getObserver();
  if (observer) {
    observer->connDropped();
  }
}

void Cpp2Connection::requestTimeoutExpired() {
  VLOG(1) << "ERROR: Task expired on channel: " <<
    context_.getPeerAddress()->describe();
  auto observer = worker_->getServer()->getObserver();
  if (observer) {
    observer->taskTimeout();
  }
}

bool Cpp2Connection::pending() {
  return socket_->isPending();
}

void Cpp2Connection::killRequest(
    ResponseChannel::Request& req,
    TApplicationException::TApplicationExceptionType reason,
    const char* comment) {
  VLOG(1) << "ERROR: Task killed: " << comment
          << ": " << context_.getPeerAddress()->getAddressStr();

  auto server = worker_->getServer();
  auto observer = server->getObserver();
  if (observer) {
    if (reason ==
         TApplicationException::TApplicationExceptionType::LOADSHEDDING) {
      observer->serverOverloaded();
    } else {
      observer->taskKilled();
    }
  }

  // Nothing to do for Thrift oneway request.
  if (req.isOneway()) {
    return;
  }

  // Thrift1 oneway request doesn't use ONEWAY_REQUEST_ID and
  // may end up here. No need to send error back for such requests
  if (!processor_->isOnewayMethod(req.getBuf(),
      channel_->getHeader())) {
    apache::thrift::TApplicationException x(reason, comment);
    req.sendError(std::make_exception_ptr(x), kOverloadedErrorCode);
  } else {
    // Send an empty request so reqId will be handler properly
    req.sendReply(std::unique_ptr<folly::IOBuf>());
  }
}

// Response Channel callbacks
void Cpp2Connection::requestReceived(
  unique_ptr<ResponseChannel::Request>&& req) {

  auto server = worker_->getServer();
  auto observer = server->getObserver();

  auto injectedFailure = server->maybeInjectFailure();
  switch (injectedFailure) {
  case ThriftServer::InjectedFailure::NONE:
    break;
  case ThriftServer::InjectedFailure::ERROR:
    killRequest(*req,
        TApplicationException::TApplicationExceptionType::INJECTED_FAILURE,
        "injected failure");
    return;
  case ThriftServer::InjectedFailure::DROP:
    VLOG(1) << "ERROR: injected drop: "
            << context_.getPeerAddress()->getAddressStr();
    return;
  case ThriftServer::InjectedFailure::DISCONNECT:
    disconnect("injected failure");
    return;
  }

  int activeRequests = worker_->activeRequests_;
  activeRequests += worker_->pendingCount();

  if (server->isOverloaded(activeRequests)) {
    killRequest(*req,
        TApplicationException::TApplicationExceptionType::LOADSHEDDING,
        "loadshedding request");
    return;
  }

  server->incGlobalActiveRequests();
  if (req->timestamps_.readBegin != 0) {
    // Expensive operations; this happens once every
    // TServerCounters.sampleRate
    req->timestamps_.processBegin =
      apache::thrift::concurrency::Util::currentTimeUsec();
    if (observer) {
      observer->queuedRequests(
        server->getThreadManager()->pendingTaskCount());
      if (server->getIsUnevenLoad()) {
        observer->activeRequests(server->getGlobalActiveRequests());
      }
    }
  }

  unique_ptr<folly::IOBuf> buf = req->getBuf()->clone();
  unique_ptr<Cpp2Request> t2r(
    new Cpp2Request(std::move(req), shared_from_this()));
  activeRequests_.insert(t2r.get());
  ++worker_->activeRequests_;

  if (observer) {
    observer->receivedRequest();
  }

  auto timeoutTime = server->getTaskExpireTime();
  if (server->useClientTimeout_) {
    auto clientTimeoutTime = channel_->getHeader()->getClientTimeout();
    if (clientTimeoutTime > std::chrono::milliseconds(0) &&
        clientTimeoutTime < timeoutTime) {
      timeoutTime = clientTimeoutTime;
    }
  }
  if (timeoutTime > std::chrono::milliseconds(0)) {
    worker_->scheduleTimeout(t2r.get(), timeoutTime);
    t2r->setStreamTimeout(timeoutTime);
  }
  auto reqContext = t2r->getContext();

  try {
    processor_->process(std::move(t2r),
                        std::move(buf),
                        static_cast<apache::thrift::protocol::PROTOCOL_TYPES>
                        (channel_->getHeader()->getProtocolId()),
                        reqContext,
                        worker_->getEventBase(),
                        server->getThreadManager().get());
  } catch (...) {
    LOG(WARNING) << "Process exception: " <<
      folly::exceptionStr(std::current_exception());
    throw;
  }
}

void Cpp2Connection::channelClosed(std::exception_ptr&& ex) {
  // This must be the last call, it may delete this.
  folly::ScopeGuard guard = folly::makeGuard([&]{
    worker_->closeConnection(shared_from_this());
  });

  VLOG(4) << "Channel " <<
    context_.getPeerAddress()->describe() << " closed: " <<
    folly::exceptionStr(ex);
}

void Cpp2Connection::removeRequest(Cpp2Request *req) {
  activeRequests_.erase(req);
  if (activeRequests_.empty()) {
    worker_->scheduleIdleConnectionTimeout(this);
  }
}

Cpp2Connection::Cpp2Request::Cpp2Request(
    std::unique_ptr<ResponseChannel::Request> req,
    std::shared_ptr<Cpp2Connection> con)
  : req_(std::move(req))
  , connection_(con)
  , reqContext_(&con->context_) {
  RequestContext::create();
}

MessageChannel::SendCallback*
Cpp2Connection::Cpp2Request::prepareSendCallback(
    MessageChannel::SendCallback* sendCallback,
    apache::thrift::server::TServerObserver* observer) {
  // If we are sampling this call, wrap it with a Cpp2Sample, which also
  // implements MessageChannel::SendCallback. Callers of sendReply/sendError
  // are responsible for cleaning up their own callbacks.
  MessageChannel::SendCallback* cb = sendCallback;
  if (req_->timestamps_.readBegin != 0) {
    req_->timestamps_.processEnd =
      apache::thrift::concurrency::Util::currentTimeUsec();
    // Cpp2Sample will delete itself when it's callback is called.
    cb = new Cpp2Sample(
      std::move(req_->timestamps_),
      observer,
      sendCallback);
  }
  return cb;
}

void Cpp2Connection::Cpp2Request::sendReply(
    std::unique_ptr<folly::IOBuf>&& buf,
    MessageChannel::SendCallback* sendCallback) {
  if (req_->isActive()) {
    auto observer = connection_->getWorker()->getServer()->getObserver().get();
    req_->sendReply(
      std::move(buf),
      prepareSendCallback(sendCallback, observer));
    cancelTimeout();
    if (observer) {
      observer->sentReply();
    }
  }
}

void Cpp2Connection::Cpp2Request::sendError(
    std::exception_ptr ex,
    std::string exCode,
    MessageChannel::SendCallback* sendCallback) {
  if (req_->isActive()) {
    auto observer = connection_->getWorker()->getServer()->getObserver().get();
    req_->sendError(ex, exCode, prepareSendCallback(sendCallback, observer));
    cancelTimeout();
  }
}

void Cpp2Connection::Cpp2Request::sendReplyWithStreams(
    std::unique_ptr<folly::IOBuf>&& data,
    std::unique_ptr<StreamManager>&& streams,
    MessageChannel::SendCallback* sendCallback) {
  if (req_->isActive()) {
    auto observer = connection_->getWorker()->getServer()->getObserver().get();
    req_->sendReplyWithStreams(
        std::move(data),
        std::move(streams),
        prepareSendCallback(sendCallback, observer));
    cancelTimeout();
    if (observer) {
      observer->sentReply();
    }
  }
}

void Cpp2Connection::Cpp2Request::setStreamTimeout(
    const std::chrono::milliseconds& timeout) {
  if (req_->isActive()) {
    req_->setStreamTimeout(timeout);
  }
}

void Cpp2Connection::Cpp2Request::timeoutExpired() noexcept {
  apache::thrift::TApplicationException x(
      TApplicationException::TApplicationExceptionType::TIMEOUT,
      "Task expired");
  sendError(std::make_exception_ptr(x), kTaskExpiredErrorCode);
  req_->cancel();
  connection_->requestTimeoutExpired();
}

Cpp2Connection::Cpp2Request::~Cpp2Request() {
  connection_->removeRequest(this);
  cancelTimeout();
  connection_->getWorker()->activeRequests_--;
  connection_->getWorker()->getServer()->decGlobalActiveRequests();
}

// Cancel request is usually called from a different thread than sendReply.
void Cpp2Connection::Cpp2Request::cancelRequest() {
  cancelTimeout();
  req_->cancel();
}

Cpp2Connection::Cpp2Sample::Cpp2Sample(
    apache::thrift::server::TServerObserver::CallTimestamps&& timestamps,
    apache::thrift::server::TServerObserver* observer,
    MessageChannel::SendCallback* chainedCallback)
  : timestamps_(timestamps)
  , observer_(observer)
  , chainedCallback_(chainedCallback) {
  DCHECK(observer != nullptr);
}

void Cpp2Connection::Cpp2Sample::sendQueued() {
  if (chainedCallback_ != nullptr) {
    chainedCallback_->sendQueued();
  }
  timestamps_.writeBegin =
    apache::thrift::concurrency::Util::currentTimeUsec();
}

void Cpp2Connection::Cpp2Sample::messageSent() {
  if (chainedCallback_ != nullptr) {
    chainedCallback_->messageSent();
  }
  timestamps_.writeEnd =
    apache::thrift::concurrency::Util::currentTimeUsec();
  delete this;
}

void Cpp2Connection::Cpp2Sample::messageSendError(std::exception_ptr&& e){
  if (chainedCallback_ != nullptr) {
    chainedCallback_->messageSendError(std::move(e));
  }
  timestamps_.writeEnd =
    apache::thrift::concurrency::Util::currentTimeUsec();
  delete this;
}

Cpp2Connection::Cpp2Sample::~Cpp2Sample() {
  if (observer_) {
    observer_->callCompleted(timestamps_);
  }
}

}} // apache::thrift
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "cppfindreferences.h"
#include "cppmodelmanagerinterface.h"
#include "cpptoolsconstants.h"

#include <texteditor/basetexteditor.h>
#include <texteditor/basefilefind.h>
#include <find/searchresultwindow.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/filesearch.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>

#include <ASTVisitor.h>
#include <AST.h>
#include <Control.h>
#include <Literals.h>
#include <TranslationUnit.h>
#include <Symbols.h>
#include <Names.h>
#include <Scope.h>

#include <cplusplus/CppDocument.h>
#include <cplusplus/CppBindings.h>
#include <cplusplus/Overview.h>

#include <QtCore/QTime>
#include <QtCore/QtConcurrentRun>
#include <QtCore/QtConcurrentMap>
#include <QtCore/QDir>
#include <QtGui/QApplication>
#include <qtconcurrent/runextensions.h>

#include <functional>

using namespace CppTools::Internal;
using namespace CPlusPlus;

namespace {

class ProcessFile: public std::unary_function<QString, QList<Usage> >
{
    const CppTools::CppModelManagerInterface::WorkingCopy workingCopy;
    const Snapshot snapshot;
    Symbol *symbol;

public:
    ProcessFile(const CppTools::CppModelManagerInterface::WorkingCopy &workingCopy,
                const Snapshot snapshot,
                Symbol *symbol)
        : workingCopy(workingCopy), snapshot(snapshot), symbol(symbol)
    { }

    QList<Usage> operator()(const QString &fileName)
    {
        QList<Usage> usages;
        const Identifier *symbolId = symbol->identifier();

        if (Document::Ptr previousDoc = snapshot.document(fileName)) {
            Control *control = previousDoc->control();
            if (! control->findIdentifier(symbolId->chars(), symbolId->size()))
                return usages; // skip this document, it's not using symbolId.
        }

        QByteArray source;

        if (workingCopy.contains(fileName))
            source = snapshot.preprocessedCode(workingCopy.source(fileName), fileName);
        else {
            QFile file(fileName);
            if (! file.open(QFile::ReadOnly))
                return usages;

            const QString contents = QTextStream(&file).readAll(); // ### FIXME
            source = snapshot.preprocessedCode(contents, fileName);
        }

        Document::Ptr doc = snapshot.documentFromSource(source, fileName);
        doc->tokenize();

        Control *control = doc->control();
        if (control->findIdentifier(symbolId->chars(), symbolId->size()) != 0) {
            doc->check();

            FindUsages process(doc, snapshot);
            process.setGlobalNamespaceBinding(bind(doc, snapshot));

            process(symbol);
            usages = process.usages();
        }

        return usages;
    }
};

class UpdateUI: public std::binary_function<QList<Usage> &, QList<Usage>, void>
{
    QFutureInterface<Usage> *future;

public:
    UpdateUI(QFutureInterface<Usage> *future): future(future) {}

    void operator()(QList<Usage> &, const QList<Usage> &usages)
    {
        foreach (const Usage &u, usages)
            future->reportResult(u);

        future->setProgressValue(future->progressValue() + 1);
    }
};

} // end of anonymous namespace

CppFindReferences::CppFindReferences(CppTools::CppModelManagerInterface *modelManager)
    : QObject(modelManager),
      _modelManager(modelManager),
      _resultWindow(ExtensionSystem::PluginManager::instance()->getObject<Find::SearchResultWindow>())
{
    m_watcher.setPendingResultsLimit(1);
    connect(&m_watcher, SIGNAL(resultsReadyAt(int,int)), this, SLOT(displayResults(int,int)));
    connect(&m_watcher, SIGNAL(finished()), this, SLOT(searchFinished()));
}

CppFindReferences::~CppFindReferences()
{
}

QList<int> CppFindReferences::references(Symbol *symbol,
                                         Document::Ptr doc,
                                         const Snapshot& snapshot) const
{
    QList<int> references;

    FindUsages findUsages(doc, snapshot);
    findUsages.setGlobalNamespaceBinding(bind(doc, snapshot));
    findUsages(symbol);
    references = findUsages.references();

    return references;
}

static void find_helper(QFutureInterface<Usage> &future,
                        const CppTools::CppModelManagerInterface::WorkingCopy workingCopy,
                        Snapshot snapshot,
                        Symbol *symbol)
{
    QTime tm;
    tm.start();

    const Identifier *symbolId = symbol->identifier();
    Q_ASSERT(symbolId != 0);

    const QString sourceFile = QString::fromUtf8(symbol->fileName(), symbol->fileNameLength());
    QStringList files(sourceFile);

    if (symbol->isClass() || symbol->isForwardClassDeclaration()) {
        foreach (const Document::Ptr &doc, snapshot) {
            if (doc->fileName() == sourceFile)
                continue;

            Control *control = doc->control();

            if (control->findIdentifier(symbolId->chars(), symbolId->size()))
                files.append(doc->fileName());
        }
    } else {
        files += snapshot.filesDependingOn(sourceFile);
    }
    files.removeDuplicates();
    //qDebug() << "done in:" << tm.elapsed() << "number of files to parse:" << files.size();

    future.setProgressRange(0, files.size());

    ProcessFile process(workingCopy, snapshot, symbol);
    UpdateUI reduce(&future);

    QtConcurrent::blockingMappedReduced<QList<Usage> > (files, process, reduce);

    future.setProgressValue(files.size());
}

void CppFindReferences::findUsages(Symbol *symbol)
{
    Find::SearchResult *search = _resultWindow->startNewSearch(Find::SearchResultWindow::SearchOnly);

    connect(search, SIGNAL(activated(Find::SearchResultItem)),
            this, SLOT(openEditor(Find::SearchResultItem)));

    findAll_helper(symbol);
}

void CppFindReferences::renameUsages(Symbol *symbol)
{
    if (const Identifier *id = symbol->identifier()) {
        const QString textToReplace = QString::fromUtf8(id->chars(), id->size());

        Find::SearchResult *search = _resultWindow->startNewSearch(Find::SearchResultWindow::SearchAndReplace);
        _resultWindow->setTextToReplace(textToReplace);

        connect(search, SIGNAL(activated(Find::SearchResultItem)),
                this, SLOT(openEditor(Find::SearchResultItem)));

        connect(search, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>)),
                SLOT(onReplaceButtonClicked(QString,QList<Find::SearchResultItem>)));

        findAll_helper(symbol);
    }
}

void CppFindReferences::findAll_helper(Symbol *symbol)
{
    if (! (symbol && symbol->identifier()))
        return;

    _resultWindow->popup(true);

    const Snapshot snapshot = _modelManager->snapshot();
    const CppTools::CppModelManagerInterface::WorkingCopy workingCopy = _modelManager->workingCopy();

    Core::ProgressManager *progressManager = Core::ICore::instance()->progressManager();

    QFuture<Usage> result;

    result = QtConcurrent::run(&find_helper, workingCopy, snapshot, symbol);
    m_watcher.setFuture(result);

    Core::FutureProgress *progress = progressManager->addTask(result, tr("Searching..."),
                                                              CppTools::Constants::TASK_SEARCH);

    connect(progress, SIGNAL(clicked()), _resultWindow, SLOT(popup()));
}

static void applyChanges(QTextDocument *doc, const QString &text, const QList<Find::SearchResultItem> &items)
{
    QList<QTextCursor> cursors;

    foreach (const Find::SearchResultItem &item, items) {
        const int blockNumber = item.lineNumber - 1;
        QTextCursor tc(doc->findBlockByNumber(blockNumber));

        const int cursorPosition = tc.position() + item.searchTermStart;

        int cursorIndex = 0;
        for (; cursorIndex < cursors.size(); ++cursorIndex) {
            const QTextCursor &tc = cursors.at(cursorIndex);

            if (tc.position() == cursorPosition)
                break;
        }

        if (cursorIndex != cursors.size())
            continue; // skip this change.

        tc.setPosition(cursorPosition);
        tc.setPosition(tc.position() + item.searchTermLength,
                       QTextCursor::KeepAnchor);
        cursors.append(tc);
    }

    foreach (QTextCursor tc, cursors)
        tc.insertText(text);
}

void CppFindReferences::onReplaceButtonClicked(const QString &text,
                                               const QList<Find::SearchResultItem> &items)
{
    Core::EditorManager::instance()->hideEditorInfoBar(QLatin1String("CppEditor.Rename"));

    const QStringList fileNames = TextEditor::BaseFileFind::replaceAll(text, items);
    if (!fileNames.isEmpty()) {
        _modelManager->updateSourceFiles(fileNames);
        _resultWindow->hide();
    }
}

void CppFindReferences::displayResults(int first, int last)
{
    for (int index = first; index != last; ++index) {
        Usage result = m_watcher.future().resultAt(index);
        _resultWindow->addResult(result.path,
                                 result.line,
                                 result.lineText,
                                 result.col,
                                 result.len);
    }
}

void CppFindReferences::searchFinished()
{
    _resultWindow->finishSearch();
    emit changed();
}

void CppFindReferences::openEditor(const Find::SearchResultItem &item)
{
    TextEditor::BaseTextEditor::openEditorAt(item.fileName, item.lineNumber, item.searchTermStart);
}

<commit_msg>Remove unused code.<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "cppfindreferences.h"
#include "cppmodelmanagerinterface.h"
#include "cpptoolsconstants.h"

#include <texteditor/basetexteditor.h>
#include <texteditor/basefilefind.h>
#include <find/searchresultwindow.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/filesearch.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>

#include <ASTVisitor.h>
#include <AST.h>
#include <Control.h>
#include <Literals.h>
#include <TranslationUnit.h>
#include <Symbols.h>
#include <Names.h>
#include <Scope.h>

#include <cplusplus/CppDocument.h>
#include <cplusplus/CppBindings.h>
#include <cplusplus/Overview.h>

#include <QtCore/QTime>
#include <QtCore/QtConcurrentRun>
#include <QtCore/QtConcurrentMap>
#include <QtCore/QDir>
#include <QtGui/QApplication>
#include <qtconcurrent/runextensions.h>

#include <functional>

using namespace CppTools::Internal;
using namespace CPlusPlus;

namespace {

class ProcessFile: public std::unary_function<QString, QList<Usage> >
{
    const CppTools::CppModelManagerInterface::WorkingCopy workingCopy;
    const Snapshot snapshot;
    Symbol *symbol;

public:
    ProcessFile(const CppTools::CppModelManagerInterface::WorkingCopy &workingCopy,
                const Snapshot snapshot,
                Symbol *symbol)
        : workingCopy(workingCopy), snapshot(snapshot), symbol(symbol)
    { }

    QList<Usage> operator()(const QString &fileName)
    {
        QList<Usage> usages;
        const Identifier *symbolId = symbol->identifier();

        if (Document::Ptr previousDoc = snapshot.document(fileName)) {
            Control *control = previousDoc->control();
            if (! control->findIdentifier(symbolId->chars(), symbolId->size()))
                return usages; // skip this document, it's not using symbolId.
        }

        QByteArray source;

        if (workingCopy.contains(fileName))
            source = snapshot.preprocessedCode(workingCopy.source(fileName), fileName);
        else {
            QFile file(fileName);
            if (! file.open(QFile::ReadOnly))
                return usages;

            const QString contents = QTextStream(&file).readAll(); // ### FIXME
            source = snapshot.preprocessedCode(contents, fileName);
        }

        Document::Ptr doc = snapshot.documentFromSource(source, fileName);
        doc->tokenize();

        Control *control = doc->control();
        if (control->findIdentifier(symbolId->chars(), symbolId->size()) != 0) {
            doc->check();

            FindUsages process(doc, snapshot);
            process.setGlobalNamespaceBinding(bind(doc, snapshot));

            process(symbol);
            usages = process.usages();
        }

        return usages;
    }
};

class UpdateUI: public std::binary_function<QList<Usage> &, QList<Usage>, void>
{
    QFutureInterface<Usage> *future;

public:
    UpdateUI(QFutureInterface<Usage> *future): future(future) {}

    void operator()(QList<Usage> &, const QList<Usage> &usages)
    {
        foreach (const Usage &u, usages)
            future->reportResult(u);

        future->setProgressValue(future->progressValue() + 1);
    }
};

} // end of anonymous namespace

CppFindReferences::CppFindReferences(CppTools::CppModelManagerInterface *modelManager)
    : QObject(modelManager),
      _modelManager(modelManager),
      _resultWindow(ExtensionSystem::PluginManager::instance()->getObject<Find::SearchResultWindow>())
{
    m_watcher.setPendingResultsLimit(1);
    connect(&m_watcher, SIGNAL(resultsReadyAt(int,int)), this, SLOT(displayResults(int,int)));
    connect(&m_watcher, SIGNAL(finished()), this, SLOT(searchFinished()));
}

CppFindReferences::~CppFindReferences()
{
}

QList<int> CppFindReferences::references(Symbol *symbol,
                                         Document::Ptr doc,
                                         const Snapshot& snapshot) const
{
    QList<int> references;

    FindUsages findUsages(doc, snapshot);
    findUsages.setGlobalNamespaceBinding(bind(doc, snapshot));
    findUsages(symbol);
    references = findUsages.references();

    return references;
}

static void find_helper(QFutureInterface<Usage> &future,
                        const CppTools::CppModelManagerInterface::WorkingCopy workingCopy,
                        Snapshot snapshot,
                        Symbol *symbol)
{
    QTime tm;
    tm.start();

    const Identifier *symbolId = symbol->identifier();
    Q_ASSERT(symbolId != 0);

    const QString sourceFile = QString::fromUtf8(symbol->fileName(), symbol->fileNameLength());
    QStringList files(sourceFile);

    if (symbol->isClass() || symbol->isForwardClassDeclaration()) {
        foreach (const Document::Ptr &doc, snapshot) {
            if (doc->fileName() == sourceFile)
                continue;

            Control *control = doc->control();

            if (control->findIdentifier(symbolId->chars(), symbolId->size()))
                files.append(doc->fileName());
        }
    } else {
        files += snapshot.filesDependingOn(sourceFile);
    }
    files.removeDuplicates();
    //qDebug() << "done in:" << tm.elapsed() << "number of files to parse:" << files.size();

    future.setProgressRange(0, files.size());

    ProcessFile process(workingCopy, snapshot, symbol);
    UpdateUI reduce(&future);

    QtConcurrent::blockingMappedReduced<QList<Usage> > (files, process, reduce);

    future.setProgressValue(files.size());
}

void CppFindReferences::findUsages(Symbol *symbol)
{
    Find::SearchResult *search = _resultWindow->startNewSearch(Find::SearchResultWindow::SearchOnly);

    connect(search, SIGNAL(activated(Find::SearchResultItem)),
            this, SLOT(openEditor(Find::SearchResultItem)));

    findAll_helper(symbol);
}

void CppFindReferences::renameUsages(Symbol *symbol)
{
    if (const Identifier *id = symbol->identifier()) {
        const QString textToReplace = QString::fromUtf8(id->chars(), id->size());

        Find::SearchResult *search = _resultWindow->startNewSearch(Find::SearchResultWindow::SearchAndReplace);
        _resultWindow->setTextToReplace(textToReplace);

        connect(search, SIGNAL(activated(Find::SearchResultItem)),
                this, SLOT(openEditor(Find::SearchResultItem)));

        connect(search, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>)),
                SLOT(onReplaceButtonClicked(QString,QList<Find::SearchResultItem>)));

        findAll_helper(symbol);
    }
}

void CppFindReferences::findAll_helper(Symbol *symbol)
{
    if (! (symbol && symbol->identifier()))
        return;

    _resultWindow->popup(true);

    const Snapshot snapshot = _modelManager->snapshot();
    const CppTools::CppModelManagerInterface::WorkingCopy workingCopy = _modelManager->workingCopy();

    Core::ProgressManager *progressManager = Core::ICore::instance()->progressManager();

    QFuture<Usage> result;

    result = QtConcurrent::run(&find_helper, workingCopy, snapshot, symbol);
    m_watcher.setFuture(result);

    Core::FutureProgress *progress = progressManager->addTask(result, tr("Searching..."),
                                                              CppTools::Constants::TASK_SEARCH);

    connect(progress, SIGNAL(clicked()), _resultWindow, SLOT(popup()));
}

void CppFindReferences::onReplaceButtonClicked(const QString &text,
                                               const QList<Find::SearchResultItem> &items)
{
    Core::EditorManager::instance()->hideEditorInfoBar(QLatin1String("CppEditor.Rename"));

    const QStringList fileNames = TextEditor::BaseFileFind::replaceAll(text, items);
    if (!fileNames.isEmpty()) {
        _modelManager->updateSourceFiles(fileNames);
        _resultWindow->hide();
    }
}

void CppFindReferences::displayResults(int first, int last)
{
    for (int index = first; index != last; ++index) {
        Usage result = m_watcher.future().resultAt(index);
        _resultWindow->addResult(result.path,
                                 result.line,
                                 result.lineText,
                                 result.col,
                                 result.len);
    }
}

void CppFindReferences::searchFinished()
{
    _resultWindow->finishSearch();
    emit changed();
}

void CppFindReferences::openEditor(const Find::SearchResultItem &item)
{
    TextEditor::BaseTextEditor::openEditorAt(item.fileName, item.lineNumber, item.searchTermStart);
}

<|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) 2012 Heiko Strathmann
 */

#include <shogun/statistics/QuadraticTimeMMD.h>
#include <shogun/features/Features.h>
#include <shogun/mathematics/Statistics.h>

using namespace shogun;

CQuadraticTimeMMD::CQuadraticTimeMMD() : CKernelTwoSampleTestStatistic()
{
	init();
}

CQuadraticTimeMMD::CQuadraticTimeMMD(CKernel* kernel, CFeatures* p_and_q,
		index_t q_start) :
		CKernelTwoSampleTestStatistic(kernel, p_and_q, q_start)
{
	init();

	if (q_start!=p_and_q->get_num_vectors()/2)
	{
		SG_ERROR("CQuadraticTimeMMD: Only features with equal number of vectors "
				"are currently possible\n");
	}
}

CQuadraticTimeMMD::~CQuadraticTimeMMD()
{

}

void CQuadraticTimeMMD::init()
{
	/* TODO register parameters*/
	m_num_samples_spectrum=0;
	m_num_eigenvalues_spectrum=0;
}

float64_t CQuadraticTimeMMD::compute_statistic()
{
	/* split computations into three terms from JLMR paper (see documentation )*/
	index_t m=m_q_start;
	index_t n=m_p_and_q->get_num_vectors()-m_q_start;

	/* init kernel with features */
	m_kernel->init(m_p_and_q, m_p_and_q);

	/* first term */
	float64_t first=0;
	for (index_t i=0; i<m; ++i)
	{
		/* ensure i!=j while adding up */
		for (index_t j=0; j<m; ++j)
			first+=i==j ? 0 :m_kernel->kernel(i,j);
	}
	first/=m*(m-1);

	/* second term */
	float64_t second=0;
	for (index_t i=m_q_start; i<m_q_start+n; ++i)
	{
		/* ensure i!=j while adding up */
		for (index_t j=m_q_start; j<m_q_start+n; ++j)
			second+=i==j ? 0 :m_kernel->kernel(i,j);
	}
	second/=n*(n-1);

	/* third term */
	float64_t third=0;
	for (index_t i=0; i<m; ++i)
	{
		for (index_t j=m_q_start; j<m_q_start+n; ++j)
			third+=m_kernel->kernel(i,j);
	}
	third*=2.0/(m*n);

	return first+second-third;
}

float64_t CQuadraticTimeMMD::compute_p_value(float64_t statistic)
{
	float64_t result=0;

	switch (m_p_value_method)
	{
	case MMD2_SPECTRUM:
	{
#ifdef HAVE_LAPACK
		/* get samples from null-distribution and compute p-value of statistic */
		SGVector<float64_t> null_samples=sample_null_spectrum(
				m_num_samples_spectrum, m_num_eigenvalues_spectrum);
		CMath::qsort(null_samples);
		float64_t pos=CMath::find_position_to_insert(null_samples, statistic);
		result=1.0-pos/null_samples.vlen;
#else // HAVE_LAPACK
		SG_ERROR("CQuadraticTimeMMD::compute_p_value(): Only possible if "
				"shogun is compiled with LAPACK enabled\n");
#endif // HAVE_LAPACK
		break;
	}

	case MMD2_GAMMA:
		result=compute_p_value_gamma(statistic);
		break;
	default:
		result=CKernelTwoSampleTestStatistic::compute_p_value(statistic);
		break;
	}

	return result;
}

#ifdef HAVE_LAPACK
SGVector<float64_t> CQuadraticTimeMMD::sample_null_spectrum(index_t num_samples,
		index_t num_eigenvalues)
{
	/* the whole procedure is already checked against MATLAB implementation */

	if (m_q_start!=m_p_and_q->get_num_vectors()/2)
	{
		/* TODO support different numbers of samples */
		SG_ERROR("%s::sample_null_spectrum(): Currently, only equal "
				"sample sizes are supported\n", get_name());
	}

	if (num_samples<=2)
	{
		SG_ERROR("%s::sample_null_spectrum(): Number of samples has to be at"
				" least 2, better in the hundrets", get_name());
	}

	if (num_eigenvalues>2*m_q_start-1)
	{
		SG_ERROR("%s::sample_null_spectrum(): Number of Eigenvalues too large\n",
				get_name());
	}

	if (num_eigenvalues<1)
	{
		SG_ERROR("%s::sample_null_spectrum(): Number of Eigenvalues too small\n",
				get_name());
	}

	/* imaginary matrix K=[K KL; KL' L] (MATLAB notation)
	 * K is matrix for XX, L is matrix for YY, KL is XY, LK is YX
	 * works since X and Y are concatenated here */
	m_kernel->init(m_p_and_q, m_p_and_q);
	SGMatrix<float64_t> K=m_kernel->get_kernel_matrix();

	/* center matrix K=H*K*H */
	K.center();

	/* compute eigenvalues and select num_eigenvalues largest ones */
	SGVector<float64_t> eigenvalues=SGMatrix<float64_t>::compute_eigenvectors(K);
	SGVector<float64_t> largest_ev(num_eigenvalues);

	/* scale by 1/2/m on the fly and take abs value*/
	for (index_t i=0; i<num_eigenvalues; ++i)
		largest_ev[i]=CMath::abs(1.0/2/m_q_start*eigenvalues[eigenvalues.vlen-1-i]);

	/* finally, sample from null distribution */
	SGVector<float64_t> null_samples(num_samples);
	for (index_t i=0; i<num_samples; ++i)
	{
		/* 2*sum(kEigs.*(randn(length(kEigs),1)).^2); */
		null_samples[i]=0;
		for (index_t j=0; j<largest_ev.vlen; ++j)
			null_samples[i]+=largest_ev[j]*CMath::pow(2.0, 2);

		null_samples[i]*=2;
	}

	return null_samples;
}
#endif // HAVE_LAPACK

float64_t CQuadraticTimeMMD::compute_p_value_gamma(float64_t statistic)
{
	/* the whole procedure is already checked against MATLAB implementation */

	if (m_q_start!=m_p_and_q->get_num_vectors()/2)
	{
		/* TODO support different numbers of samples */
		SG_ERROR("%s::compute_threshold_gamma(): Currently, only equal "
				"sample sizes are supported\n", get_name());
	}

	/* imaginary matrix K=[K KL; KL' L] (MATLAB notation)
	 * K is matrix for XX, L is matrix for YY, KL is XY, LK is YX
	 * works since X and Y are concatenated here */
	m_kernel->init(m_p_and_q, m_p_and_q);

	/* compute mean under H0 of MMD, which is
	 * meanMMD  = 2/m * ( 1  - 1/m*sum(diag(KL))  );
	 * in MATLAB */
	float64_t mean_mmd=0;
	for (index_t i=0; i<m_q_start; ++i)
	{
		/* virtual KL matrix is in upper right corner of SHOGUN K matrix
		 * so this sums the diagonal of the matrix between X and Y*/
		mean_mmd+=m_kernel->kernel(i, m_q_start+i);
	}
	mean_mmd=2.0/m_q_start*(1.0-1.0/m_q_start*mean_mmd);

	/* compute variance under H0 of MMD, which is
	 * varMMD = 2/m/(m-1) * 1/m/(m-1) * sum(sum( (K + L - KL - KL').^2 ));
	 * in MATLAB, so sum up all elements */
	float64_t var_mmd=0;
	for (index_t i=0; i<m_q_start; ++i)
	{
		for (index_t j=0; j<m_q_start; ++j)
		{
			/* dont add diagonal of all pairs of imaginary kernel matrices */
			if (i==j || m_q_start+i==j || m_q_start+j==i)
				continue;

			float64_t to_add=m_kernel->kernel(i, j);
			to_add+=m_kernel->kernel(m_q_start+i, m_q_start+j);
			to_add-=m_kernel->kernel(i, m_q_start+j);
			to_add-=m_kernel->kernel(m_q_start+i, j);
			var_mmd+=CMath::pow(to_add, 2);
		}
	}
	var_mmd*=2.0/m_q_start/(m_q_start-1)*1.0/m_q_start/(m_q_start-1);

	/* parameters for gamma distribution */
	float64_t a=CMath::pow(mean_mmd, 2)/var_mmd;
	float64_t b=var_mmd*m_q_start / mean_mmd;

	/* return: cdf('gam',statistic,al,bet) (MATLAB)
	 * which will get the position in the null distribution */
	return CStatistics::gamma_cdf(statistic, a, b);
}

void CQuadraticTimeMMD::set_num_samples_sepctrum(index_t num_samples_spectrum)
{
	m_num_samples_spectrum=num_samples_spectrum;
}

void CQuadraticTimeMMD::set_num_eigenvalues_spectrum(
		index_t num_eigenvalues_spectrum)
{
	m_num_eigenvalues_spectrum=num_eigenvalues_spectrum;
}
<commit_msg>fixed a cast error<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) 2012 Heiko Strathmann
 */

#include <shogun/statistics/QuadraticTimeMMD.h>
#include <shogun/features/Features.h>
#include <shogun/mathematics/Statistics.h>

using namespace shogun;

CQuadraticTimeMMD::CQuadraticTimeMMD() : CKernelTwoSampleTestStatistic()
{
	init();
}

CQuadraticTimeMMD::CQuadraticTimeMMD(CKernel* kernel, CFeatures* p_and_q,
		index_t q_start) :
		CKernelTwoSampleTestStatistic(kernel, p_and_q, q_start)
{
	init();

	if (q_start!=p_and_q->get_num_vectors()/2)
	{
		SG_ERROR("CQuadraticTimeMMD: Only features with equal number of vectors "
				"are currently possible\n");
	}
}

CQuadraticTimeMMD::~CQuadraticTimeMMD()
{

}

void CQuadraticTimeMMD::init()
{
	/* TODO register parameters*/
	m_num_samples_spectrum=0;
	m_num_eigenvalues_spectrum=0;
}

float64_t CQuadraticTimeMMD::compute_statistic()
{
	/* split computations into three terms from JLMR paper (see documentation )*/
	index_t m=m_q_start;
	index_t n=m_p_and_q->get_num_vectors()-m_q_start;

	/* init kernel with features */
	m_kernel->init(m_p_and_q, m_p_and_q);

	/* first term */
	float64_t first=0;
	for (index_t i=0; i<m; ++i)
	{
		/* ensure i!=j while adding up */
		for (index_t j=0; j<m; ++j)
			first+=i==j ? 0 :m_kernel->kernel(i,j);
	}
	first/=m*(m-1);

	/* second term */
	float64_t second=0;
	for (index_t i=m_q_start; i<m_q_start+n; ++i)
	{
		/* ensure i!=j while adding up */
		for (index_t j=m_q_start; j<m_q_start+n; ++j)
			second+=i==j ? 0 :m_kernel->kernel(i,j);
	}
	second/=n*(n-1);

	/* third term */
	float64_t third=0;
	for (index_t i=0; i<m; ++i)
	{
		for (index_t j=m_q_start; j<m_q_start+n; ++j)
			third+=m_kernel->kernel(i,j);
	}
	third*=2.0/(m*n);

	return first+second-third;
}

float64_t CQuadraticTimeMMD::compute_p_value(float64_t statistic)
{
	float64_t result=0;

	switch (m_p_value_method)
	{
	case MMD2_SPECTRUM:
	{
#ifdef HAVE_LAPACK
		/* get samples from null-distribution and compute p-value of statistic */
		SGVector<float64_t> null_samples=sample_null_spectrum(
				m_num_samples_spectrum, m_num_eigenvalues_spectrum);
		CMath::qsort(null_samples);
		index_t pos=CMath::find_position_to_insert(null_samples, statistic);
		result=1.0-((float64_t)pos)/null_samples.vlen;
#else // HAVE_LAPACK
		SG_ERROR("CQuadraticTimeMMD::compute_p_value(): Only possible if "
				"shogun is compiled with LAPACK enabled\n");
#endif // HAVE_LAPACK
		break;
	}

	case MMD2_GAMMA:
		result=compute_p_value_gamma(statistic);
		break;
	default:
		result=CKernelTwoSampleTestStatistic::compute_p_value(statistic);
		break;
	}

	return result;
}

#ifdef HAVE_LAPACK
SGVector<float64_t> CQuadraticTimeMMD::sample_null_spectrum(index_t num_samples,
		index_t num_eigenvalues)
{
	/* the whole procedure is already checked against MATLAB implementation */

	if (m_q_start!=m_p_and_q->get_num_vectors()/2)
	{
		/* TODO support different numbers of samples */
		SG_ERROR("%s::sample_null_spectrum(): Currently, only equal "
				"sample sizes are supported\n", get_name());
	}

	if (num_samples<=2)
	{
		SG_ERROR("%s::sample_null_spectrum(): Number of samples has to be at"
				" least 2, better in the hundrets", get_name());
	}

	if (num_eigenvalues>2*m_q_start-1)
	{
		SG_ERROR("%s::sample_null_spectrum(): Number of Eigenvalues too large\n",
				get_name());
	}

	if (num_eigenvalues<1)
	{
		SG_ERROR("%s::sample_null_spectrum(): Number of Eigenvalues too small\n",
				get_name());
	}

	/* imaginary matrix K=[K KL; KL' L] (MATLAB notation)
	 * K is matrix for XX, L is matrix for YY, KL is XY, LK is YX
	 * works since X and Y are concatenated here */
	m_kernel->init(m_p_and_q, m_p_and_q);
	SGMatrix<float64_t> K=m_kernel->get_kernel_matrix();

	/* center matrix K=H*K*H */
	K.center();

	/* compute eigenvalues and select num_eigenvalues largest ones */
	SGVector<float64_t> eigenvalues=SGMatrix<float64_t>::compute_eigenvectors(K);
	SGVector<float64_t> largest_ev(num_eigenvalues);

	/* take largest EV, scale by 1/2/m on the fly and take abs value*/
	for (index_t i=0; i<num_eigenvalues; ++i)
		largest_ev[i]=CMath::abs(1.0/2/m_q_start*eigenvalues[eigenvalues.vlen-1-i]);

	/* finally, sample from null distribution */
	SGVector<float64_t> null_samples(num_samples);
	for (index_t i=0; i<num_samples; ++i)
	{
		/* 2*sum(kEigs.*(randn(length(kEigs),1)).^2); */
		null_samples[i]=0;
		for (index_t j=0; j<largest_ev.vlen; ++j)
			null_samples[i]+=largest_ev[j]*CMath::pow(CMath::randn_double(), 2);

		null_samples[i]*=2;
	}

	return null_samples;
}
#endif // HAVE_LAPACK

float64_t CQuadraticTimeMMD::compute_p_value_gamma(float64_t statistic)
{
	/* the whole procedure is already checked against MATLAB implementation */

	if (m_q_start!=m_p_and_q->get_num_vectors()/2)
	{
		/* TODO support different numbers of samples */
		SG_ERROR("%s::compute_threshold_gamma(): Currently, only equal "
				"sample sizes are supported\n", get_name());
	}

	/* imaginary matrix K=[K KL; KL' L] (MATLAB notation)
	 * K is matrix for XX, L is matrix for YY, KL is XY, LK is YX
	 * works since X and Y are concatenated here */
	m_kernel->init(m_p_and_q, m_p_and_q);

	/* compute mean under H0 of MMD, which is
	 * meanMMD  = 2/m * ( 1  - 1/m*sum(diag(KL))  );
	 * in MATLAB */
	float64_t mean_mmd=0;
	for (index_t i=0; i<m_q_start; ++i)
	{
		/* virtual KL matrix is in upper right corner of SHOGUN K matrix
		 * so this sums the diagonal of the matrix between X and Y*/
		mean_mmd+=m_kernel->kernel(i, m_q_start+i);
	}
	mean_mmd=2.0/m_q_start*(1.0-1.0/m_q_start*mean_mmd);

	/* compute variance under H0 of MMD, which is
	 * varMMD = 2/m/(m-1) * 1/m/(m-1) * sum(sum( (K + L - KL - KL').^2 ));
	 * in MATLAB, so sum up all elements */
	float64_t var_mmd=0;
	for (index_t i=0; i<m_q_start; ++i)
	{
		for (index_t j=0; j<m_q_start; ++j)
		{
			/* dont add diagonal of all pairs of imaginary kernel matrices */
			if (i==j || m_q_start+i==j || m_q_start+j==i)
				continue;

			float64_t to_add=m_kernel->kernel(i, j);
			to_add+=m_kernel->kernel(m_q_start+i, m_q_start+j);
			to_add-=m_kernel->kernel(i, m_q_start+j);
			to_add-=m_kernel->kernel(m_q_start+i, j);
			var_mmd+=CMath::pow(to_add, 2);
		}
	}
	var_mmd*=2.0/m_q_start/(m_q_start-1)*1.0/m_q_start/(m_q_start-1);

	/* parameters for gamma distribution */
	float64_t a=CMath::pow(mean_mmd, 2)/var_mmd;
	float64_t b=var_mmd*m_q_start / mean_mmd;

	/* return: cdf('gam',statistic,al,bet) (MATLAB)
	 * which will get the position in the null distribution */
	return CStatistics::gamma_cdf(statistic, a, b);
}

void CQuadraticTimeMMD::set_num_samples_sepctrum(index_t num_samples_spectrum)
{
	m_num_samples_spectrum=num_samples_spectrum;
}

void CQuadraticTimeMMD::set_num_eigenvalues_spectrum(
		index_t num_eigenvalues_spectrum)
{
	m_num_eigenvalues_spectrum=num_eigenvalues_spectrum;
}
<|endoftext|>