<commit_before>#include <iostream>
#include <sstream>

#include <realm.hpp>
#include <realm/util/file.hpp>

#include "../util/timer.hpp"
#include "../util/random.hpp"
#include "../util/benchmark_results.hpp"

using namespace realm;
using namespace realm::util;
using namespace realm::test_util;

/**
  This bechmark suite represents a number of common use cases,
  from the perspective of the bindings. It does *not* benchmark
  the type-safe C++ API, but only the things that language bindings
  are likely to use internally.

  This has the following implications:
  - All access is done with a SharedGroup in transactions.
  - The SharedGroup has full durability (is backed by a file).
    (but all benchmarks are also run with MemOnly durability for comparison)
  - Cases have been derived from:
    https://github.com/realm/realm-java/blob/bp-performance-test/realm/src/androidTest/java/io/realm/RealmPerformanceTest.java
*/

static const char realm_path[] = "/tmp/benchmark-common-tasks.realm";
static const size_t min_repetitions = 10;
static const size_t max_repetitions = 100;
static const double min_duration_s = 0.05;

struct Benchmark
{
    virtual const char* name() const = 0;
    virtual void setup(SharedGroup&) {}
    virtual void teardown(SharedGroup&) {}
    virtual void operator()(SharedGroup&) = 0;
};

struct AddTable : Benchmark {
    const char* name() const { return "AddTable"; }

    void operator()(SharedGroup& group)
    {
        WriteTransaction tr(group);
        TableRef t = tr.add_table(name());
        t->add_column(type_String, "first");
        t->add_column(type_Int, "second");
        t->add_column(type_DateTime, "third");
        tr.commit();
    }

    void teardown(SharedGroup& group)
    {
        Group& g = group.begin_write();
        g.remove_table(name());
        group.commit();
    }
};

struct BenchmarkWithStringsTable : Benchmark {
    void setup(SharedGroup& group)
    {
        WriteTransaction tr(group);
        TableRef t = tr.add_table("StringOnly");
        t->add_column(type_String, "chars");
        tr.commit();
    }

    void teardown(SharedGroup& group)
    {
        Group& g = group.begin_write();
        g.remove_table("StringOnly");
        group.commit();
    }
};

struct BenchmarkWithStrings : BenchmarkWithStringsTable {
    void setup(SharedGroup& group)
    {
        BenchmarkWithStringsTable::setup(group);
        WriteTransaction tr(group);
        TableRef t = tr.get_table("StringOnly");
        t->add_empty_row(REALM_MAX_BPNODE_SIZE - 1);
        for (size_t i = 0; i < REALM_MAX_BPNODE_SIZE - 1; ++i) {
            std::stringstream ss;
            ss << rand();
            t->set_string(0, i, ss.str());
        }
        tr.commit();
    }
};

struct BenchmarkWithLongStrings : BenchmarkWithStrings {
    void setup(SharedGroup& group)
    {
        BenchmarkWithStrings::setup(group);
        WriteTransaction tr(group);
        TableRef t = tr.get_table("StringOnly");
        t->insert_empty_row(0);
        // This should be enough to upgrade the entire array:
        t->set_string(0, 0, "A really long string, longer than 63 bytes at least, I guess......");
        tr.commit();
    }
};

struct BenchmarkQuery : BenchmarkWithStrings {
    const char* name() const { return "Query"; }

    void operator()(SharedGroup& group)
    {
        ReadTransaction tr(group);
        ConstTableRef table = tr.get_table("StringOnly");
        ConstTableView view = table->find_all_string(0, "200");
    }
};

struct BenchmarkSize : BenchmarkWithStrings {
    const char* name() const { return "Size"; }

    void operator()(SharedGroup& group)
    {
        ReadTransaction tr(group);
        ConstTableRef table = tr.get_table("StringOnly");
        volatile size_t dummy = table->size();
        static_cast<void>(dummy);
    }
};

struct BenchmarkSort : BenchmarkWithStrings {
    const char* name() const { return "Sort"; }

    void operator()(SharedGroup& group)
    {
        ReadTransaction tr(group);
        ConstTableRef table = tr.get_table("StringOnly");
        ConstTableView view = table->get_sorted_view(0);
    }
};

struct BenchmarkInsert : BenchmarkWithStringsTable {
    const char* name() const { return "Insert"; }

    void operator()(SharedGroup& group)
    {
        WriteTransaction tr(group);
        TableRef t = tr.get_table("StringOnly");
        for (size_t i = 0; i < 10000; ++i) {
            t->add_empty_row();
            t->set_string(0, i, "a");
        }
        tr.commit();
    }
};

struct BenchmarkGetString : BenchmarkWithStrings {
    const char* name() const { return "GetString"; }

    void operator()(SharedGroup& group)
    {
        ReadTransaction tr(group);
        ConstTableRef table = tr.get_table("StringOnly");
        size_t len = table->size();
        volatile int dummy = 0;
        for (size_t i = 0; i < len; ++i) {
            StringData str = table->get_string(0, i);
            dummy += str[0]; // to avoid over-optimization
        }
    }
};

struct BenchmarkSetString : BenchmarkWithStrings {
    const char* name() const { return "SetString"; }

    void operator()(SharedGroup& group)
    {
        WriteTransaction tr(group);
        TableRef table = tr.get_table("StringOnly");
        size_t len = table->size();
        for (size_t i = 0; i < len; ++i) {
            table->set_string(0, i, "c");
        }
        tr.commit();
    }
};

struct BenchmarkCreateIndex : BenchmarkWithStrings {
    const char* name() const { return "CreateIndex"; }
    void operator()(SharedGroup& group)
    {
        WriteTransaction tr(group);
        TableRef table = tr.get_table("StringOnly");
        table->add_search_index(0);
        tr.commit();
    }
};

struct BenchmarkGetLongString : BenchmarkWithLongStrings {
    const char* name() const { return "GetLongString"; }

    void operator()(SharedGroup& group)
    {
        ReadTransaction tr(group);
        ConstTableRef table = tr.get_table("StringOnly");
        size_t len = table->size();
        volatile int dummy = 0;
        for (size_t i = 0; i < len; ++i) {
            StringData str = table->get_string(0, i);
            dummy += str[0]; // to avoid over-optimization
        }
    }
};

struct BenchmarkSetLongString : BenchmarkWithLongStrings {
    const char* name() const { return "SetLongString"; }

    void operator()(SharedGroup& group)
    {
        WriteTransaction tr(group);
        TableRef table = tr.get_table("StringOnly");
        size_t len = table->size();
        for (size_t i = 0; i < len; ++i) {
            table->set_string(0, i, "c");
        }
        tr.commit();
    }
};

struct BenchmarkQueryNot : Benchmark {
    const char* name() const { return "QueryNot"; }

    void setup(SharedGroup& group)
    {
        WriteTransaction tr(group);
        TableRef table = tr.add_table(name());
        table->add_column(type_Int, "first");
        table->add_empty_row(1000);
        for (size_t i = 0; i < 1000; ++i) {
            table->set_int(0, i, 1);
        }
        tr.commit();
    }

    void operator()(SharedGroup& group)
    {
        ReadTransaction tr(group);
        ConstTableRef table = tr.get_table(name());
        Query q = table->where();
        q.not_equal(0, 2); // never found, = worst case
        TableView results = q.find_all();
        results.size();
    }

    void teardown(SharedGroup& group)
    {
        Group& g = group.begin_write();
        g.remove_table(name());
        group.commit();
    }
};

static const char* durability_level_to_cstr(SharedGroup::DurabilityLevel level)
{
    switch (level) {
        case SharedGroup::durability_Full: return "Full";
        case SharedGroup::durability_MemOnly: return "MemOnly";
#ifndef _WIN32
        case SharedGroup::durability_Async: return "Async";
#endif
    }
}

void run_benchmark_once(Benchmark& benchmark, SharedGroup& sg, Timer& timer)
{
    timer.pause();
    benchmark.setup(sg);
    timer.unpause();

    benchmark(sg);

    timer.pause();
    benchmark.teardown(sg);
    timer.unpause();
}

/// This little piece of likely over-engineering runs the benchmark a number of times,
/// with each durability setting, and reports the results for each run.
template <typename B>
void run_benchmark(BenchmarkResults& results)
{
#ifdef _WIN32
    const size_t num_durabilities = 2;
#else
    const size_t num_durabilities = 2; // FIXME Figure out how to run the async commit daemon.
#endif

    Timer timer(Timer::type_UserTime);
    for (size_t i = 0; i < num_durabilities; ++i) {
        // Open a SharedGroup:
        File::try_remove(realm_path);
        std::unique_ptr<SharedGroup> group;
        SharedGroup::DurabilityLevel level = static_cast<SharedGroup::DurabilityLevel>(i);
        group.reset(new SharedGroup(realm_path, false, level));

        B benchmark;

        // Generate the benchmark result texts:
        std::stringstream lead_text_ss;
        std::stringstream ident_ss;
        lead_text_ss << benchmark.name() << " (" << durability_level_to_cstr(level) << ")";
        ident_ss << benchmark.name() << "_" << durability_level_to_cstr(level);
        std::string ident = ident_ss.str();

        // Warm-up and initial measuring:
        Timer t_unused(Timer::type_UserTime);
        run_benchmark_once(benchmark, *group, t_unused);

        size_t rep;
        double total = 0;
        for (rep = 0; rep < max_repetitions && (rep < min_repetitions || total < min_duration_s); ++rep) {
            Timer t;
            run_benchmark_once(benchmark, *group, t);
            double s = t.get_elapsed_time();
            total += s;
            results.submit(ident.c_str(), s);
        }

        results.finish(ident, lead_text_ss.str());
    }
}

int main(int, const char**)
{
    BenchmarkResults results(40);

    run_benchmark<AddTable>(results);
    run_benchmark<BenchmarkQuery>(results);
    run_benchmark<BenchmarkQueryNot>(results);
    run_benchmark<BenchmarkSize>(results);
    run_benchmark<BenchmarkSort>(results);
    run_benchmark<BenchmarkInsert>(results);
    run_benchmark<BenchmarkGetString>(results);
    run_benchmark<BenchmarkSetString>(results);
    run_benchmark<BenchmarkCreateIndex>(results);
    run_benchmark<BenchmarkGetLongString>(results);
    run_benchmark<BenchmarkSetLongString>(results);

    return 0;
}
<commit_msg>Added SortInt benchmark, and adjusted strings benchmark to be more accurate.<commit_after>#include <iostream>
#include <sstream>

#include <realm.hpp>
#include <realm/util/file.hpp>

#include "../util/timer.hpp"
#include "../util/random.hpp"
#include "../util/benchmark_results.hpp"

using namespace realm;
using namespace realm::util;
using namespace realm::test_util;

/**
  This bechmark suite represents a number of common use cases,
  from the perspective of the bindings. It does *not* benchmark
  the type-safe C++ API, but only the things that language bindings
  are likely to use internally.

  This has the following implications:
  - All access is done with a SharedGroup in transactions.
  - The SharedGroup has full durability (is backed by a file).
    (but all benchmarks are also run with MemOnly durability for comparison)
  - Cases have been derived from:
    https://github.com/realm/realm-java/blob/bp-performance-test/realm/src/androidTest/java/io/realm/RealmPerformanceTest.java
*/

static const char realm_path[] = "/tmp/benchmark-common-tasks.realm";
static const size_t min_repetitions = 10;
static const size_t max_repetitions = 100;
static const double min_duration_s = 0.05;

struct Benchmark
{
    virtual const char* name() const = 0;
    virtual void setup(SharedGroup&) {}
    virtual void teardown(SharedGroup&) {}
    virtual void operator()(SharedGroup&) = 0;
};

struct AddTable : Benchmark {
    const char* name() const { return "AddTable"; }

    void operator()(SharedGroup& group)
    {
        WriteTransaction tr(group);
        TableRef t = tr.add_table(name());
        t->add_column(type_String, "first");
        t->add_column(type_Int, "second");
        t->add_column(type_DateTime, "third");
        tr.commit();
    }

    void teardown(SharedGroup& group)
    {
        Group& g = group.begin_write();
        g.remove_table(name());
        group.commit();
    }
};

struct BenchmarkWithStringsTable : Benchmark {
    void setup(SharedGroup& group)
    {
        WriteTransaction tr(group);
        TableRef t = tr.add_table("StringOnly");
        t->add_column(type_String, "chars");
        tr.commit();
    }

    void teardown(SharedGroup& group)
    {
        Group& g = group.begin_write();
        g.remove_table("StringOnly");
        group.commit();
    }
};

struct BenchmarkWithStrings : BenchmarkWithStringsTable {
    void setup(SharedGroup& group)
    {
        BenchmarkWithStringsTable::setup(group);
        WriteTransaction tr(group);
        TableRef t = tr.get_table("StringOnly");
        t->add_empty_row(REALM_MAX_BPNODE_SIZE * 4);
        for (size_t i = 0; i < REALM_MAX_BPNODE_SIZE * 4; ++i) {
            std::stringstream ss;
            ss << rand();
            t->set_string(0, i, ss.str());
        }
        tr.commit();
    }
};

struct BenchmarkWithLongStrings : BenchmarkWithStrings {
    void setup(SharedGroup& group)
    {
        BenchmarkWithStrings::setup(group);
        WriteTransaction tr(group);
        TableRef t = tr.get_table("StringOnly");
        t->insert_empty_row(0);
        // This should be enough to upgrade the entire array:
        t->set_string(0, 0, "A really long string, longer than 63 bytes at least, I guess......");
        t->set_string(0, REALM_MAX_BPNODE_SIZE, "A really long string, longer than 63 bytes at least, I guess......");
        t->set_string(0, REALM_MAX_BPNODE_SIZE * 2, "A really long string, longer than 63 bytes at least, I guess......");
        t->set_string(0, REALM_MAX_BPNODE_SIZE * 3, "A really long string, longer than 63 bytes at least, I guess......");
        tr.commit();
    }
};

struct BenchmarkWithIntsTable : Benchmark {
    void setup(SharedGroup& group)
    {
        WriteTransaction tr(group);
        TableRef t = tr.add_table("IntOnly");
        t->add_column(type_Int, "ints");
        tr.commit();
    }

    void teardown(SharedGroup& group)
    {
        Group& g = group.begin_write();
        g.remove_table("IntOnly");
        group.commit();
    }
};

struct BenchmarkWithInts : BenchmarkWithIntsTable {
    void setup(SharedGroup& group)
    {
        BenchmarkWithIntsTable::setup(group);
        WriteTransaction tr(group);
        TableRef t = tr.get_table("IntOnly");
        t->add_empty_row(REALM_MAX_BPNODE_SIZE * 4);
        Random r;
        for (size_t i = 0; i < REALM_MAX_BPNODE_SIZE * 4; ++i) {
            t->set_int(0, i, r.draw_int<int64_t>());
        }
        tr.commit();
    }
};

struct BenchmarkQuery : BenchmarkWithStrings {
    const char* name() const { return "Query"; }

    void operator()(SharedGroup& group)
    {
        ReadTransaction tr(group);
        ConstTableRef table = tr.get_table("StringOnly");
        ConstTableView view = table->find_all_string(0, "200");
    }
};

struct BenchmarkSize : BenchmarkWithStrings {
    const char* name() const { return "Size"; }

    void operator()(SharedGroup& group)
    {
        ReadTransaction tr(group);
        ConstTableRef table = tr.get_table("StringOnly");
        volatile size_t dummy = table->size();
        static_cast<void>(dummy);
    }
};

struct BenchmarkSort : BenchmarkWithStrings {
    const char* name() const { return "Sort"; }

    void operator()(SharedGroup& group)
    {
        ReadTransaction tr(group);
        ConstTableRef table = tr.get_table("StringOnly");
        ConstTableView view = table->get_sorted_view(0);
    }
};

struct BenchmarkSortInt : BenchmarkWithInts {
    const char* name() const { return "SortInt"; }

    void operator()(SharedGroup& group)
    {
        ReadTransaction tr(group);
        ConstTableRef table = tr.get_table("IntOnly");
        ConstTableView view = table->get_sorted_view(0);
    }
};

struct BenchmarkInsert : BenchmarkWithStringsTable {
    const char* name() const { return "Insert"; }

    void operator()(SharedGroup& group)
    {
        WriteTransaction tr(group);
        TableRef t = tr.get_table("StringOnly");
        for (size_t i = 0; i < 10000; ++i) {
            t->add_empty_row();
            t->set_string(0, i, "a");
        }
        tr.commit();
    }
};

struct BenchmarkGetString : BenchmarkWithStrings {
    const char* name() const { return "GetString"; }

    void operator()(SharedGroup& group)
    {
        ReadTransaction tr(group);
        ConstTableRef table = tr.get_table("StringOnly");
        size_t len = table->size();
        volatile int dummy = 0;
        for (size_t i = 0; i < len; ++i) {
            StringData str = table->get_string(0, i);
            dummy += str[0]; // to avoid over-optimization
        }
    }
};

struct BenchmarkSetString : BenchmarkWithStrings {
    const char* name() const { return "SetString"; }

    void operator()(SharedGroup& group)
    {
        WriteTransaction tr(group);
        TableRef table = tr.get_table("StringOnly");
        size_t len = table->size();
        for (size_t i = 0; i < len; ++i) {
            table->set_string(0, i, "c");
        }
        tr.commit();
    }
};

struct BenchmarkCreateIndex : BenchmarkWithStrings {
    const char* name() const { return "CreateIndex"; }
    void operator()(SharedGroup& group)
    {
        WriteTransaction tr(group);
        TableRef table = tr.get_table("StringOnly");
        table->add_search_index(0);
        tr.commit();
    }
};

struct BenchmarkGetLongString : BenchmarkWithLongStrings {
    const char* name() const { return "GetLongString"; }

    void operator()(SharedGroup& group)
    {
        ReadTransaction tr(group);
        ConstTableRef table = tr.get_table("StringOnly");
        size_t len = table->size();
        volatile int dummy = 0;
        for (size_t i = 0; i < len; ++i) {
            StringData str = table->get_string(0, i);
            dummy += str[0]; // to avoid over-optimization
        }
    }
};

struct BenchmarkSetLongString : BenchmarkWithLongStrings {
    const char* name() const { return "SetLongString"; }

    void operator()(SharedGroup& group)
    {
        WriteTransaction tr(group);
        TableRef table = tr.get_table("StringOnly");
        size_t len = table->size();
        for (size_t i = 0; i < len; ++i) {
            table->set_string(0, i, "c");
        }
        tr.commit();
    }
};

struct BenchmarkQueryNot : Benchmark {
    const char* name() const { return "QueryNot"; }

    void setup(SharedGroup& group)
    {
        WriteTransaction tr(group);
        TableRef table = tr.add_table(name());
        table->add_column(type_Int, "first");
        table->add_empty_row(1000);
        for (size_t i = 0; i < 1000; ++i) {
            table->set_int(0, i, 1);
        }
        tr.commit();
    }

    void operator()(SharedGroup& group)
    {
        ReadTransaction tr(group);
        ConstTableRef table = tr.get_table(name());
        Query q = table->where();
        q.not_equal(0, 2); // never found, = worst case
        TableView results = q.find_all();
        results.size();
    }

    void teardown(SharedGroup& group)
    {
        Group& g = group.begin_write();
        g.remove_table(name());
        group.commit();
    }
};

static const char* durability_level_to_cstr(SharedGroup::DurabilityLevel level)
{
    switch (level) {
        case SharedGroup::durability_Full: return "Full";
        case SharedGroup::durability_MemOnly: return "MemOnly";
#ifndef _WIN32
        case SharedGroup::durability_Async: return "Async";
#endif
    }
}

void run_benchmark_once(Benchmark& benchmark, SharedGroup& sg, Timer& timer)
{
    timer.pause();
    benchmark.setup(sg);
    timer.unpause();

    benchmark(sg);

    timer.pause();
    benchmark.teardown(sg);
    timer.unpause();
}

/// This little piece of likely over-engineering runs the benchmark a number of times,
/// with each durability setting, and reports the results for each run.
template <typename B>
void run_benchmark(BenchmarkResults& results)
{
#ifdef _WIN32
    const size_t num_durabilities = 2;
#else
    const size_t num_durabilities = 2; // FIXME Figure out how to run the async commit daemon.
#endif

    Timer timer(Timer::type_UserTime);
    for (size_t i = 0; i < num_durabilities; ++i) {
        // Open a SharedGroup:
        File::try_remove(realm_path);
        std::unique_ptr<SharedGroup> group;
        SharedGroup::DurabilityLevel level = static_cast<SharedGroup::DurabilityLevel>(i);
        group.reset(new SharedGroup(realm_path, false, level));

        B benchmark;

        // Generate the benchmark result texts:
        std::stringstream lead_text_ss;
        std::stringstream ident_ss;
        lead_text_ss << benchmark.name() << " (" << durability_level_to_cstr(level) << ")";
        ident_ss << benchmark.name() << "_" << durability_level_to_cstr(level);
        std::string ident = ident_ss.str();

        // Warm-up and initial measuring:
        Timer t_unused(Timer::type_UserTime);
        run_benchmark_once(benchmark, *group, t_unused);

        size_t rep;
        double total = 0;
        for (rep = 0; rep < max_repetitions && (rep < min_repetitions || total < min_duration_s); ++rep) {
            Timer t;
            run_benchmark_once(benchmark, *group, t);
            double s = t.get_elapsed_time();
            total += s;
            results.submit(ident.c_str(), s);
        }

        results.finish(ident, lead_text_ss.str());
    }
}

int main(int, const char**)
{
    BenchmarkResults results(40);

    run_benchmark<AddTable>(results);
    run_benchmark<BenchmarkQuery>(results);
    run_benchmark<BenchmarkQueryNot>(results);
    run_benchmark<BenchmarkSize>(results);
    run_benchmark<BenchmarkSort>(results);
    run_benchmark<BenchmarkSortInt>(results);
    run_benchmark<BenchmarkInsert>(results);
    run_benchmark<BenchmarkGetString>(results);
    run_benchmark<BenchmarkSetString>(results);
    run_benchmark<BenchmarkCreateIndex>(results);
    run_benchmark<BenchmarkGetLongString>(results);
    run_benchmark<BenchmarkSetLongString>(results);

    return 0;
}
<|endoftext|>


<commit_before>#include "source/common/io/io_uring_impl.h"

#include "test/mocks/server/mocks.h"
#include "test/test_common/environment.h"
#include "test/test_common/utility.h"

#include "gtest/gtest.h"

namespace Envoy {
namespace Io {
namespace {

class IoUringImplTest : public ::testing::Test {
public:
  IoUringImplTest() : api_(Api::createApiForTest()) {
    if (isIoUringSupported()) {
      factory_ = std::make_unique<IoUringFactoryImpl>(2, false, context_.threadLocal());
      factory_->onServerInitialized();
    } else {
      should_skip_ = true;
    }
  }

  void SetUp() override {
    if (should_skip_) {
      GTEST_SKIP();
    }
  }

  void TearDown() override {
    if (should_skip_) {
      return;
    }

    auto& uring = factory_->getOrCreate();
    if (uring.isEventfdRegistered()) {
      uring.unregisterEventfd();
    }
  }

  Api::ApiPtr api_;
  testing::NiceMock<Server::Configuration::MockServerFactoryContext> context_;
  std::unique_ptr<IoUringFactoryImpl> factory_{};
  bool should_skip_{};
};

class IoUringImplParamTest
    : public IoUringImplTest,
      public testing::WithParamInterface<std::function<IoUringResult(IoUring&, os_fd_t)>> {};

INSTANTIATE_TEST_SUITE_P(InvalidPrepareMethodParamsTest, IoUringImplParamTest,
                         testing::Values(
                             [](IoUring& uring, os_fd_t fd) -> IoUringResult {
                               return uring.prepareAccept(fd, nullptr, nullptr, nullptr);
                             },
                             [](IoUring& uring, os_fd_t fd) -> IoUringResult {
                               auto address =
                                   std::make_shared<Network::Address::EnvoyInternalInstance>(
                                       "test");
                               return uring.prepareConnect(fd, address, nullptr);
                             },
                             [](IoUring& uring, os_fd_t fd) -> IoUringResult {
                               return uring.prepareReadv(fd, nullptr, 0, 0, nullptr);
                             },
                             [](IoUring& uring, os_fd_t fd) -> IoUringResult {
                               return uring.prepareWritev(fd, nullptr, 0, 0, nullptr);
                             },
                             [](IoUring& uring, os_fd_t fd) -> IoUringResult {
                               return uring.prepareClose(fd, nullptr);
                             }));

TEST_P(IoUringImplParamTest, InvalidParams) {
  os_fd_t fd;
  SET_SOCKET_INVALID(fd);
  auto dispatcher = api_->allocateDispatcher("test_thread");

  auto& uring = factory_->getOrCreate();

  os_fd_t event_fd = uring.registerEventfd();
  const Event::FileTriggerType trigger = Event::PlatformDefaultTriggerType;
  int32_t completions_nr = 0;
  auto file_event = dispatcher->createFileEvent(
      event_fd,
      [&uring, &completions_nr](uint32_t) {
        uring.forEveryCompletion([&completions_nr](void*, int32_t res) {
          EXPECT_TRUE(res < 0);
          completions_nr++;
        });
      },
      trigger, Event::FileReadyType::Read);

  auto prepare_method = GetParam();
  IoUringResult res = prepare_method(uring, fd);
  EXPECT_EQ(res, IoUringResult::Ok);
  res = prepare_method(uring, fd);
  EXPECT_EQ(res, IoUringResult::Ok);
  res = prepare_method(uring, fd);
  EXPECT_EQ(res, IoUringResult::Failed);
  res = uring.submit();
  EXPECT_EQ(res, IoUringResult::Ok);
  res = uring.submit();
  EXPECT_EQ(res, IoUringResult::Ok);

  dispatcher->run(Event::Dispatcher::RunType::NonBlock);
  EXPECT_EQ(completions_nr, 2);
}

TEST_F(IoUringImplTest, Instantiate) {
  auto& uring1 = factory_->getOrCreate();
  auto& uring2 = factory_->getOrCreate();
  EXPECT_EQ(&uring1, &uring2);
}

TEST_F(IoUringImplTest, RegisterEventfd) {
  auto& uring = factory_->getOrCreate();

  EXPECT_FALSE(uring.isEventfdRegistered());
  uring.registerEventfd();
  EXPECT_TRUE(uring.isEventfdRegistered());
  uring.unregisterEventfd();
  EXPECT_FALSE(uring.isEventfdRegistered());
  EXPECT_DEATH(uring.unregisterEventfd(), "unable to unregister eventfd");
}

TEST_F(IoUringImplTest, PrepareReadvAllDataFitsOneChunk) {
  std::string test_dir = TestEnvironment::temporaryDirectory();
  TestEnvironment::createPath(test_dir);
  std::string test_file = TestEnvironment::writeStringToFileForTest(
      absl::StrCat(test_dir, "/prepare_readv"), "test text", true);
  os_fd_t fd = open(test_file.c_str(), O_RDONLY);
  ASSERT_TRUE(fd >= 0);

  auto dispatcher = api_->allocateDispatcher("test_thread");

  uint8_t buffer[4096]{};
  struct iovec iov;
  iov.iov_base = buffer;
  iov.iov_len = 4096;

  auto& uring = factory_->getOrCreate();
  os_fd_t event_fd = uring.registerEventfd();

  const Event::FileTriggerType trigger = Event::PlatformDefaultTriggerType;
  int32_t completions_nr = 0;
  auto file_event = dispatcher->createFileEvent(
      event_fd,
      [&uring, &completions_nr, d = dispatcher.get()](uint32_t) {
        uring.forEveryCompletion([&completions_nr](void*, int32_t res) {
          completions_nr++;
          EXPECT_EQ(res, strlen("test text"));
        });
        d->exit();
      },
      trigger, Event::FileReadyType::Read);

  uring.prepareReadv(fd, &iov, 1, 0, nullptr);
  EXPECT_STREQ(static_cast<char*>(iov.iov_base), "");
  uring.submit();

  dispatcher->run(Event::Dispatcher::RunType::Block);

  // Check that the completion callback has been actually called.
  EXPECT_EQ(completions_nr, 1);
  // The file's content is in the read buffer now.
  EXPECT_STREQ(static_cast<char*>(iov.iov_base), "test text");
  TestEnvironment::removePath(test_dir);
}

TEST_F(IoUringImplTest, PrepareReadvQueueOverflow) {
  std::string test_dir = TestEnvironment::temporaryDirectory();
  TestEnvironment::createPath(test_dir);
  std::string test_file = TestEnvironment::writeStringToFileForTest(
      absl::StrCat(test_dir, "/prepare_readv_overflow"), "abcdefhg", true);
  os_fd_t fd = open(test_file.c_str(), O_RDONLY);
  ASSERT_TRUE(fd >= 0);

  auto dispatcher = api_->allocateDispatcher("test_thread");

  uint8_t buffer1[2]{};
  struct iovec iov1;
  iov1.iov_base = buffer1;
  iov1.iov_len = 2;
  uint8_t buffer2[2]{};
  struct iovec iov2;
  iov2.iov_base = buffer2;
  iov2.iov_len = 2;
  uint8_t buffer3[2]{};
  struct iovec iov3;
  iov3.iov_base = buffer3;
  iov3.iov_len = 2;

  auto& uring = factory_->getOrCreate();

  os_fd_t event_fd = uring.registerEventfd();
  const Event::FileTriggerType trigger = Event::PlatformDefaultTriggerType;
  int32_t completions_nr = 0;
  auto file_event = dispatcher->createFileEvent(
      event_fd,
      [&uring, &completions_nr](uint32_t) {
        uring.forEveryCompletion([&completions_nr](void* user_data, int32_t res) {
          EXPECT_TRUE(user_data != nullptr);
          EXPECT_EQ(res, 2);
          completions_nr++;
          // Note: generally events are not guaranteed to complete in the same order
          // we submit them, but for this case of reading from a single file it's ok
          // to expect the same order.
          EXPECT_EQ(reinterpret_cast<int64_t>(user_data), completions_nr);
        });
      },
      trigger, Event::FileReadyType::Read);

  IoUringResult res = uring.prepareReadv(fd, &iov1, 1, 0, reinterpret_cast<void*>(1));
  EXPECT_EQ(res, IoUringResult::Ok);
  res = uring.prepareReadv(fd, &iov2, 1, 2, reinterpret_cast<void*>(2));
  EXPECT_EQ(res, IoUringResult::Ok);
  res = uring.prepareReadv(fd, &iov3, 1, 4, reinterpret_cast<void*>(3));
  // Expect the submission queue overflow.
  EXPECT_EQ(res, IoUringResult::Failed);
  res = uring.submit();
  EXPECT_EQ(res, IoUringResult::Ok);

  // Even though we haven't been notified about ops completion the buffers
  // are filled already.
  EXPECT_EQ(static_cast<char*>(iov1.iov_base)[0], 'a');
  EXPECT_EQ(static_cast<char*>(iov1.iov_base)[1], 'b');
  EXPECT_EQ(static_cast<char*>(iov2.iov_base)[0], 'c');
  EXPECT_EQ(static_cast<char*>(iov2.iov_base)[1], 'd');

  dispatcher->run(Event::Dispatcher::RunType::NonBlock);

  // Only 2 completions are expected because the completion queue can contain
  // no more than 2 entries.
  EXPECT_EQ(completions_nr, 2);

  // Check a new event gets handled in the next dispatcher run.
  res = uring.prepareReadv(fd, &iov3, 1, 4, reinterpret_cast<void*>(3));
  EXPECT_EQ(res, IoUringResult::Ok);
  res = uring.submit();
  EXPECT_EQ(res, IoUringResult::Ok);

  EXPECT_EQ(static_cast<char*>(iov3.iov_base)[0], 'e');
  EXPECT_EQ(static_cast<char*>(iov3.iov_base)[1], 'f');

  dispatcher->run(Event::Dispatcher::RunType::NonBlock);
  // Check the completion callback was called actually.
  EXPECT_EQ(completions_nr, 3);
  TestEnvironment::removePath(test_dir);
}

} // namespace
} // namespace Io
} // namespace Envoy
<commit_msg>io_uring: don't remove test tmp directory manually (#20787)<commit_after>#include "source/common/io/io_uring_impl.h"

#include "test/mocks/server/mocks.h"
#include "test/test_common/environment.h"
#include "test/test_common/utility.h"

#include "gtest/gtest.h"

namespace Envoy {
namespace Io {
namespace {

class IoUringImplTest : public ::testing::Test {
public:
  IoUringImplTest() : api_(Api::createApiForTest()) {
    if (isIoUringSupported()) {
      factory_ = std::make_unique<IoUringFactoryImpl>(2, false, context_.threadLocal());
      factory_->onServerInitialized();
    } else {
      should_skip_ = true;
    }
  }

  void SetUp() override {
    if (should_skip_) {
      GTEST_SKIP();
    }
  }

  void TearDown() override {
    if (should_skip_) {
      return;
    }

    auto& uring = factory_->getOrCreate();
    if (uring.isEventfdRegistered()) {
      uring.unregisterEventfd();
    }
  }

  Api::ApiPtr api_;
  testing::NiceMock<Server::Configuration::MockServerFactoryContext> context_;
  std::unique_ptr<IoUringFactoryImpl> factory_{};
  bool should_skip_{};
};

class IoUringImplParamTest
    : public IoUringImplTest,
      public testing::WithParamInterface<std::function<IoUringResult(IoUring&, os_fd_t)>> {};

INSTANTIATE_TEST_SUITE_P(InvalidPrepareMethodParamsTest, IoUringImplParamTest,
                         testing::Values(
                             [](IoUring& uring, os_fd_t fd) -> IoUringResult {
                               return uring.prepareAccept(fd, nullptr, nullptr, nullptr);
                             },
                             [](IoUring& uring, os_fd_t fd) -> IoUringResult {
                               auto address =
                                   std::make_shared<Network::Address::EnvoyInternalInstance>(
                                       "test");
                               return uring.prepareConnect(fd, address, nullptr);
                             },
                             [](IoUring& uring, os_fd_t fd) -> IoUringResult {
                               return uring.prepareReadv(fd, nullptr, 0, 0, nullptr);
                             },
                             [](IoUring& uring, os_fd_t fd) -> IoUringResult {
                               return uring.prepareWritev(fd, nullptr, 0, 0, nullptr);
                             },
                             [](IoUring& uring, os_fd_t fd) -> IoUringResult {
                               return uring.prepareClose(fd, nullptr);
                             }));

TEST_P(IoUringImplParamTest, InvalidParams) {
  os_fd_t fd;
  SET_SOCKET_INVALID(fd);
  auto dispatcher = api_->allocateDispatcher("test_thread");

  auto& uring = factory_->getOrCreate();

  os_fd_t event_fd = uring.registerEventfd();
  const Event::FileTriggerType trigger = Event::PlatformDefaultTriggerType;
  int32_t completions_nr = 0;
  auto file_event = dispatcher->createFileEvent(
      event_fd,
      [&uring, &completions_nr](uint32_t) {
        uring.forEveryCompletion([&completions_nr](void*, int32_t res) {
          EXPECT_TRUE(res < 0);
          completions_nr++;
        });
      },
      trigger, Event::FileReadyType::Read);

  auto prepare_method = GetParam();
  IoUringResult res = prepare_method(uring, fd);
  EXPECT_EQ(res, IoUringResult::Ok);
  res = prepare_method(uring, fd);
  EXPECT_EQ(res, IoUringResult::Ok);
  res = prepare_method(uring, fd);
  EXPECT_EQ(res, IoUringResult::Failed);
  res = uring.submit();
  EXPECT_EQ(res, IoUringResult::Ok);
  res = uring.submit();
  EXPECT_EQ(res, IoUringResult::Ok);

  dispatcher->run(Event::Dispatcher::RunType::NonBlock);
  EXPECT_EQ(completions_nr, 2);
}

TEST_F(IoUringImplTest, Instantiate) {
  auto& uring1 = factory_->getOrCreate();
  auto& uring2 = factory_->getOrCreate();
  EXPECT_EQ(&uring1, &uring2);
}

TEST_F(IoUringImplTest, RegisterEventfd) {
  auto& uring = factory_->getOrCreate();

  EXPECT_FALSE(uring.isEventfdRegistered());
  uring.registerEventfd();
  EXPECT_TRUE(uring.isEventfdRegistered());
  uring.unregisterEventfd();
  EXPECT_FALSE(uring.isEventfdRegistered());
  EXPECT_DEATH(uring.unregisterEventfd(), "unable to unregister eventfd");
}

TEST_F(IoUringImplTest, PrepareReadvAllDataFitsOneChunk) {
  std::string test_file =
      TestEnvironment::writeStringToFileForTest("prepare_readv", "test text", true);
  os_fd_t fd = open(test_file.c_str(), O_RDONLY);
  ASSERT_TRUE(fd >= 0);

  auto dispatcher = api_->allocateDispatcher("test_thread");

  uint8_t buffer[4096]{};
  struct iovec iov;
  iov.iov_base = buffer;
  iov.iov_len = 4096;

  auto& uring = factory_->getOrCreate();
  os_fd_t event_fd = uring.registerEventfd();

  const Event::FileTriggerType trigger = Event::PlatformDefaultTriggerType;
  int32_t completions_nr = 0;
  auto file_event = dispatcher->createFileEvent(
      event_fd,
      [&uring, &completions_nr, d = dispatcher.get()](uint32_t) {
        uring.forEveryCompletion([&completions_nr](void*, int32_t res) {
          completions_nr++;
          EXPECT_EQ(res, strlen("test text"));
        });
        d->exit();
      },
      trigger, Event::FileReadyType::Read);

  uring.prepareReadv(fd, &iov, 1, 0, nullptr);
  EXPECT_STREQ(static_cast<char*>(iov.iov_base), "");
  uring.submit();

  dispatcher->run(Event::Dispatcher::RunType::Block);

  // Check that the completion callback has been actually called.
  EXPECT_EQ(completions_nr, 1);
  // The file's content is in the read buffer now.
  EXPECT_STREQ(static_cast<char*>(iov.iov_base), "test text");
}

TEST_F(IoUringImplTest, PrepareReadvQueueOverflow) {
  std::string test_file =
      TestEnvironment::writeStringToFileForTest("prepare_readv_overflow", "abcdefhg", true);
  os_fd_t fd = open(test_file.c_str(), O_RDONLY);
  ASSERT_TRUE(fd >= 0);

  auto dispatcher = api_->allocateDispatcher("test_thread");

  uint8_t buffer1[2]{};
  struct iovec iov1;
  iov1.iov_base = buffer1;
  iov1.iov_len = 2;
  uint8_t buffer2[2]{};
  struct iovec iov2;
  iov2.iov_base = buffer2;
  iov2.iov_len = 2;
  uint8_t buffer3[2]{};
  struct iovec iov3;
  iov3.iov_base = buffer3;
  iov3.iov_len = 2;

  auto& uring = factory_->getOrCreate();

  os_fd_t event_fd = uring.registerEventfd();
  const Event::FileTriggerType trigger = Event::PlatformDefaultTriggerType;
  int32_t completions_nr = 0;
  auto file_event = dispatcher->createFileEvent(
      event_fd,
      [&uring, &completions_nr](uint32_t) {
        uring.forEveryCompletion([&completions_nr](void* user_data, int32_t res) {
          EXPECT_TRUE(user_data != nullptr);
          EXPECT_EQ(res, 2);
          completions_nr++;
          // Note: generally events are not guaranteed to complete in the same order
          // we submit them, but for this case of reading from a single file it's ok
          // to expect the same order.
          EXPECT_EQ(reinterpret_cast<int64_t>(user_data), completions_nr);
        });
      },
      trigger, Event::FileReadyType::Read);

  IoUringResult res = uring.prepareReadv(fd, &iov1, 1, 0, reinterpret_cast<void*>(1));
  EXPECT_EQ(res, IoUringResult::Ok);
  res = uring.prepareReadv(fd, &iov2, 1, 2, reinterpret_cast<void*>(2));
  EXPECT_EQ(res, IoUringResult::Ok);
  res = uring.prepareReadv(fd, &iov3, 1, 4, reinterpret_cast<void*>(3));
  // Expect the submission queue overflow.
  EXPECT_EQ(res, IoUringResult::Failed);
  res = uring.submit();
  EXPECT_EQ(res, IoUringResult::Ok);

  // Even though we haven't been notified about ops completion the buffers
  // are filled already.
  EXPECT_EQ(static_cast<char*>(iov1.iov_base)[0], 'a');
  EXPECT_EQ(static_cast<char*>(iov1.iov_base)[1], 'b');
  EXPECT_EQ(static_cast<char*>(iov2.iov_base)[0], 'c');
  EXPECT_EQ(static_cast<char*>(iov2.iov_base)[1], 'd');

  dispatcher->run(Event::Dispatcher::RunType::NonBlock);

  // Only 2 completions are expected because the completion queue can contain
  // no more than 2 entries.
  EXPECT_EQ(completions_nr, 2);

  // Check a new event gets handled in the next dispatcher run.
  res = uring.prepareReadv(fd, &iov3, 1, 4, reinterpret_cast<void*>(3));
  EXPECT_EQ(res, IoUringResult::Ok);
  res = uring.submit();
  EXPECT_EQ(res, IoUringResult::Ok);

  EXPECT_EQ(static_cast<char*>(iov3.iov_base)[0], 'e');
  EXPECT_EQ(static_cast<char*>(iov3.iov_base)[1], 'f');

  dispatcher->run(Event::Dispatcher::RunType::NonBlock);
  // Check the completion callback was called actually.
  EXPECT_EQ(completions_nr, 3);
}

} // namespace
} // namespace Io
} // namespace Envoy
<|endoftext|>


<commit_before>// test rest api using cpprestsdk
// Yang Yu (gnayuy@gmail.com)

// g++ -std=c++11 -I/usr/local/include -o httpclientDataStream httpclientDataStream.cpp -L/usr/local/lib -lcpprest -lboost_system -lboost_chrono -lboost_thread -lboost_random -lboost_regex -lssl -lcrypto

//
#include <iostream>
#include <sstream>
#include <codecvt>
using namespace std;

//
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>

#include <cpprest/http_listener.h>              // HTTP server
#include <cpprest/json.h>                       // JSON library
#include <cpprest/uri.h>                        // URI library
#include <cpprest/ws_client.h>                  // WebSocket client
#include <cpprest/containerstream.h>            // Async streams backed by STL containers
#include <cpprest/interopstream.h>              // Bridges for integrating Async streams with STL and WinRT streams
#include <cpprest/rawptrstream.h>               // Async streams backed by raw pointer to memory
#include <cpprest/producerconsumerstream.h>     // Async streams for producer consumer scenarios

using namespace utility;                    // Common utilities like string conversions
using namespace web;                        // Common features like URIs.
using namespace web::http;                  // Common HTTP functionality
using namespace web::http::client;          // HTTP client features
using namespace concurrency::streams;       // Asynchronous streams

//using namespace web::http::experimental::listener;          // HTTP server
//using namespace web::experimental::web_sockets::client;     // WebSockets client
//using namespace web::json;                                  // JSON library

// POST <api URL>/node/<UUID>/<data name>/raw/0_1_2/<size>/<offset>[?queryopts]

//
int main(int argc, char* argv[])
{
    utility::string_t port = U("8000");
    utility::string_t address = U("http://localhost:");
    address.append(port);

    http::uri uri = http::uri(address);
    http::uri_builder builder(uri);
    http_client client(builder.append_path(U("/api/node/cd0/grayscale/raw/0_1_2/32_32_32/0_0_0")).to_uri());

    if(argc<2)
    {
        cout<<"Please enter POST[0]/GET[1] method option!"<<endl;
        return -1;
    }

    int method = atoi(argv[1]);

    if(method==0)
    {
        unsigned char *buf = NULL;
        try
        {
            const size_t size = 32*32*32;
            buf = new unsigned char [size];

            for(int i=0; i<size; i++)
            {
                buf[i] = i%255;
            }

            cout<<"test raw buffer"<<endl;
            rawptr_buffer<unsigned char> rawBuf(buf, size, std::ios::in);
            cout<<"success raw buffer"<<rawBuf.size()<<endl;

//            concurrency::streams::istream isbuf;

//            isbuf.read(rawBuf,size);
//            cout<<"success read rawbuf to istream"<<endl;

            try
            {
                //auto response = client.request(methods::POST, builder.to_string(), isbuf, size, U("application/octet-stream"), pplx::cancellation_token::none()).get();
                auto response = client.request(methods::POST, builder.to_string(), rawBuf, U("application/octet-stream")).get();
                printf("Response code:%d\n", response.status_code());
            }
            catch(http_exception& e)
            {
                printf("Exception:%s\n", e.what());
            }
        }
        catch(...)
        {
            cout<<"fail to allocate memory for buf"<<endl;
            return -1;
        }

    }
    else if(method==1)
    {

        client.request(methods::GET).then([](http_response response)
        {
            if(response.status_code() != status_codes::OK)
            {
                // Handle error cases...
                return pplx::task_from_result();
            }

            // Perform actions here reading from the response stream...
            // In this example, we print the first 15 characters of the response to the console.
            concurrency::streams::istream bodyStream = response.body();
            container_buffer<std::string> inStringBuffer;
            bodyStream.read(inStringBuffer, 15).then([inStringBuffer](size_t bytesRead)
            {
                const std::string &text = inStringBuffer.collection();

                // For demonstration, convert the response text to a wide-character string.
                std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf16conv;
                std::wostringstream ss;
                ss << utf16conv.from_bytes(text.c_str()) << std::endl;
                std::wcout << ss.str();
            });
        });

//        try
//        {
//            auto response = client.request(methods::GET, builder.to_string(), buf, U("application/octet-stream")).get();
//            printf("Response code:%d, buf[8]=%d\n", response.status_code(), buf[8]);
//        }
//        catch(http_exception& e)
//        {
//            printf("Exception:%s\n", e.what());
//        }
    }
    else
    {
        cout<<"Invalid request method!"<<endl;
        return -1;
    }

    //
    return 0;
}
<commit_msg>update streamming codes<commit_after>// test rest api using cpprestsdk
// Yang Yu (gnayuy@gmail.com)

// g++ -std=c++11 -I/usr/local/include -o httpclientStream httpclientStream.cpp -L/usr/local/lib -lcpprest -lboost_system -lboost_chrono -lboost_thread -lboost_random -lboost_regex -lssl -lcrypto

//
#include <iostream>
#include <sstream>
#include <codecvt>
using namespace std;

//
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>

#include <cpprest/http_listener.h>              // HTTP server
#include <cpprest/json.h>                       // JSON library
#include <cpprest/uri.h>                        // URI library
#include <cpprest/ws_client.h>                  // WebSocket client
#include <cpprest/containerstream.h>            // Async streams backed by STL containers
#include <cpprest/interopstream.h>              // Bridges for integrating Async streams with STL and WinRT streams
#include <cpprest/rawptrstream.h>               // Async streams backed by raw pointer to memory
#include <cpprest/producerconsumerstream.h>     // Async streams for producer consumer scenarios

using namespace utility;                    // Common utilities like string conversions
using namespace web;                        // Common features like URIs.
using namespace web::http;                  // Common HTTP functionality
using namespace web::http::client;          // HTTP client features
using namespace concurrency::streams;       // Asynchronous streams

//using namespace web::http::experimental::listener;          // HTTP server
//using namespace web::experimental::web_sockets::client;     // WebSockets client
//using namespace web::json;                                  // JSON library

// POST <api URL>/node/<UUID>/<data name>/raw/0_1_2/<size>/<offset>[?queryopts]
// http://localhost:8000/api/node/345/grayscale/raw/0_1/128_128/0_0_0/jpg:80

pplx::task<void> HTTPGetAsync(http_client client, uri_builder builder)
{
    auto path_query_fragment = builder.to_string();

    // Make an HTTP GET request and asynchronously process the response
    return client.request(methods::GET, path_query_fragment).then([](http_response response)
    {
        // Display the status code that the server returned
        std::wostringstream stream;
        stream << U("Server returned returned status code ") << response.status_code() << U('.') << std::endl;
        std::wcout << stream.str();

        stream.str(std::wstring());
        stream << U("Content length: ") << response.headers().content_length() << U(" bytes") << std::endl;
        stream << U("Content type: ") << response.headers().content_type().c_str() << std::endl;
        std::wcout << stream.str();

        auto bodyStream = response.body();
        concurrency::streams::stringstreambuf sbuffer;
        auto& target = sbuffer.collection();

        bodyStream.read_to_end(sbuffer).get();

        stream.str(std::wstring());
        stream << U("Response body: ") << target.c_str();
        std::wcout << stream.str();
    });
}

pplx::task<void> HTTPPostAsync(http_client client, uri_builder builder, concurrency::streams::istream isbuf, utility::size64_t size)
{
    auto path_query_fragment = builder.to_string();

    http_request msg(methods::POST);
    msg.set_request_uri(path_query_fragment);
    msg.set_body(isbuf, size, U("application/octet-stream"));

    // Make an HTTP POST request and asynchronously process the response
    return client.request(msg, pplx::cancellation_token::none()).then([](http_response response)
    {
        // Display the status code that the server returned
        std::wostringstream stream;
        stream << U("Server returned returned status code ") << response.status_code() << U('.') << std::endl;
        std::wcout << stream.str();

        stream.str(std::wstring());
        stream << U("Content length: ") << response.headers().content_length() << U(" bytes") << std::endl;
        stream << U("Content type: ") << response.headers().content_type().c_str() << std::endl;
        std::wcout << stream.str();

    });
}

//
int main(int argc, char* argv[])
{
    utility::string_t port = U("8000");
    utility::string_t address = U("http://localhost:");
    address.append(port);

    http::uri uri = http::uri(address);
    http_client client(uri);
    http::uri_builder builder(U("/api/node/61c/grayscale/raw/0_1_2/32_32_32/0_0_0"));
    //http_client client(builder.append_path(U("/api/node/4ab/grayscale/raw/0_1_2/32_32_32/0_0_0")).to_uri());

    if(argc<2)
    {
        cout<<"Please enter POST[0]/GET[1] method option!"<<endl;
        return -1;
    }

    int method = atoi(argv[1]);

    if(method==0)
    {
        unsigned char *buf = NULL;
        try
        {
            utility::size64_t size = 32768; //32*32*32
            buf = new unsigned char [size];

            for(int i=0; i<size; i++)
            {
                buf[i] = i%255;
            }

            rawptr_buffer<unsigned char> rawBuf(buf, size, std::ios::in);
            cout<<"success raw buffer with size: "<<rawBuf.size()<<endl;

            concurrency::streams::istream isbuf(rawBuf);

            auto path_query_fragment = builder.to_string();

            cout<<"test "<<path_query_fragment.c_str()<<endl;

            HTTPPostAsync(client, builder, isbuf, size).wait();

//            try
//            {
//                auto response = client.request(methods::POST, path_query_fragment, isbuf).get();
//                printf("Response code:%d\n", response.status_code());
//            }
//            catch(http_exception& e)
//            {
//                printf("Exception:%s\n", e.what());
//            }

            //            const size_t rawDataSize = 8;
            //            unsigned char* rawData = new unsigned char[rawDataSize];
            //            memcpy(&rawData[0], "raw data", rawDataSize);
            //            rawptr_buffer<unsigned char> rawOutBuffer(rawData, rawDataSize, std::ios::in);
            //            concurrency::streams::ostream outStream;
            //            outStream.write(rawOutBuffer, rawDataSize).then([rawData](size_t bytesWritten)
            //            {
            //                delete []rawData;

            //                // Perform actions here once the string as been written...
            //            });
        }
        catch(...)
        {
            cout<<"fail to allocate memory for buf"<<endl;
            return -1;
        }

        //
        //        if(buf) {delete []buf; buf=NULL;}

    }
    else if(method==1)
    {

        HTTPGetAsync(client, builder).wait();

        //        client.request(methods::GET).then([](http_response response)
        //        {
        //            if(response.status_code() != status_codes::OK)
        //            {
        //                // Handle error cases...
        //                return pplx::task_from_result();
        //            }

        //            // Perform actions here reading from the response stream...
        //            // In this example, we print the first 15 characters of the response to the console.
        //            concurrency::streams::istream bodyStream = response.body();
        //            container_buffer<std::string> inStringBuffer;
        //            bodyStream.read(inStringBuffer, 15).then([inStringBuffer](size_t bytesRead)
        //            {
        //                const std::string &text = inStringBuffer.collection();

        //                // For demonstration, convert the response text to a wide-character string.
        //                std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf16conv;
        //                std::wostringstream ss;
        //                ss << utf16conv.from_bytes(text.c_str()) << std::endl;
        //                std::wcout << ss.str();
        //            });
        //        });

        //        try
        //        {
        //            auto response = client.request(methods::GET, builder.to_string(), buf, U("application/octet-stream")).get();
        //            printf("Response code:%d, buf[8]=%d\n", response.status_code(), buf[8]);
        //        }
        //        catch(http_exception& e)
        //        {
        //            printf("Exception:%s\n", e.what());
        //        }
    }
    else
    {
        cout<<"Invalid request method!"<<endl;
        return -1;
    }

    //
    return 0;
}
<|endoftext|>


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

// A binary wrapper for QuicClient.
// Connects to a host using QUIC, sends a request to the provided URL, and
// displays the response.
//
// Some usage examples:
//
// Standard request/response:
//   quic_client www.google.com
//   quic_client www.google.com --quiet
//   quic_client www.google.com --port=443
//
// Use a specific version:
//   quic_client www.google.com --quic_version=23
//
// Send a POST instead of a GET:
//   quic_client www.google.com --body="this is a POST body"
//
// Append additional headers to the request:
//   quic_client www.google.com --headers="Header-A: 1234; Header-B: 5678"
//
// Connect to a host different to the URL being requested:
//   quic_client mail.google.com --host=www.google.com
//
// Connect to a specific IP:
//   IP=`dig www.google.com +short | head -1`
//   quic_client www.google.com --host=${IP}
//
// Send repeated requests and change ephemeral port between requests
//   quic_client www.google.com --num_requests=10
//
// Try to connect to a host which does not speak QUIC:
//   quic_client www.example.com
//
// This tool is available as a built binary at:
// /google/data/ro/teams/quic/tools/quic_client
// After submitting changes to this file, you will need to follow the
// instructions at go/quic_client_binary_update

#include "net/third_party/quiche/src/quic/tools/quic_toy_client.h"

#include <iostream>
#include <memory>
#include <string>
#include <vector>

#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_system_event_loop.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
#include "net/third_party/quiche/src/quic/tools/fake_proof_verifier.h"
#include "net/third_party/quiche/src/quic/tools/quic_url.h"

namespace {

using quic::QuicSocketAddress;
using quic::QuicStringPiece;
using quic::QuicTextUtils;
using quic::QuicUrl;

}  // namespace

DEFINE_QUIC_COMMAND_LINE_FLAG(
    std::string,
    host,
    "",
    "The IP or hostname to connect to. If not provided, the host "
    "will be derived from the provided URL.");

DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, port, 0, "The port to connect to.");

DEFINE_QUIC_COMMAND_LINE_FLAG(std::string,
                              body,
                              "",
                              "If set, send a POST with this body.");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    std::string,
    body_hex,
    "",
    "If set, contents are converted from hex to ascii, before "
    "sending as body of a POST. e.g. --body_hex=\"68656c6c6f\"");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    std::string,
    headers,
    "",
    "A semicolon separated list of key:value pairs to "
    "add to request headers.");

DEFINE_QUIC_COMMAND_LINE_FLAG(bool,
                              quiet,
                              false,
                              "Set to true for a quieter output experience.");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    std::string,
    quic_version,
    "",
    "QUIC version to speak, e.g. 21. If not set, then all available "
    "versions are offered in the handshake. Also supports wire versions "
    "such as Q043 or T099.");

DEFINE_QUIC_COMMAND_LINE_FLAG(bool,
                              quic_ietf_draft,
                              false,
                              "Use the IETF draft version. This also enables "
                              "required internal QUIC flags.");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    bool,
    version_mismatch_ok,
    false,
    "If true, a version mismatch in the handshake is not considered a "
    "failure. Useful for probing a server to determine if it speaks "
    "any version of QUIC.");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    bool,
    force_version_negotiation,
    false,
    "If true, start by proposing a version that is reserved for version "
    "negotiation.");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    bool,
    redirect_is_success,
    true,
    "If true, an HTTP response code of 3xx is considered to be a "
    "successful response, otherwise a failure.");

DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t,
                              initial_mtu,
                              0,
                              "Initial MTU of the connection.");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    int32_t,
    num_requests,
    1,
    "How many sequential requests to make on a single connection.");

DEFINE_QUIC_COMMAND_LINE_FLAG(bool,
                              disable_certificate_verification,
                              false,
                              "If true, don't verify the server certificate.");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    bool,
    drop_response_body,
    false,
    "If true, drop response body immediately after it is received.");

namespace quic {

QuicToyClient::QuicToyClient(ClientFactory* client_factory)
    : client_factory_(client_factory) {}

int QuicToyClient::SendRequestsAndPrintResponses(
    std::vector<std::string> urls) {
  QuicUrl url(urls[0], "https");
  std::string host = GetQuicFlag(FLAGS_host);
  if (host.empty()) {
    host = url.host();
  }
  int port = GetQuicFlag(FLAGS_port);
  if (port == 0) {
    port = url.port();
  }

  quic::ParsedQuicVersionVector versions = quic::CurrentSupportedVersions();

  std::string quic_version_string = GetQuicFlag(FLAGS_quic_version);
  if (GetQuicFlag(FLAGS_quic_ietf_draft)) {
    quic::QuicVersionInitializeSupportForIetfDraft();
    versions = {{quic::PROTOCOL_TLS1_3, quic::QUIC_VERSION_99}};
    quic::QuicEnableVersion(versions[0]);

  } else if (!quic_version_string.empty()) {
    if (quic_version_string[0] == 'T') {
      // ParseQuicVersionString checks quic_supports_tls_handshake.
      SetQuicReloadableFlag(quic_supports_tls_handshake, true);
    }
    quic::ParsedQuicVersion parsed_quic_version =
        quic::ParseQuicVersionString(quic_version_string);
    if (parsed_quic_version.transport_version ==
        quic::QUIC_VERSION_UNSUPPORTED) {
      return 1;
    }
    versions = {parsed_quic_version};
    quic::QuicEnableVersion(parsed_quic_version);
  }

  if (GetQuicFlag(FLAGS_force_version_negotiation)) {
    versions.insert(versions.begin(),
                    quic::QuicVersionReservedForNegotiation());
  }

  const int32_t num_requests(GetQuicFlag(FLAGS_num_requests));
  std::unique_ptr<quic::ProofVerifier> proof_verifier;
  if (GetQuicFlag(FLAGS_disable_certificate_verification)) {
    proof_verifier = std::make_unique<FakeProofVerifier>();
  } else {
    proof_verifier = quic::CreateDefaultProofVerifier(url.host());
  }

  // Build the client, and try to connect.
  std::unique_ptr<QuicSpdyClientBase> client = client_factory_->CreateClient(
      url.host(), host, port, versions, std::move(proof_verifier));

  if (client == nullptr) {
    std::cerr << "Failed to create client." << std::endl;
    return 1;
  }

  int32_t initial_mtu = GetQuicFlag(FLAGS_initial_mtu);
  client->set_initial_max_packet_length(
      initial_mtu != 0 ? initial_mtu : quic::kDefaultMaxPacketSize);
  client->set_drop_response_body(GetQuicFlag(FLAGS_drop_response_body));
  if (!client->Initialize()) {
    std::cerr << "Failed to initialize client." << std::endl;
    return 1;
  }
  if (!client->Connect()) {
    quic::QuicErrorCode error = client->session()->error();
    if (error == quic::QUIC_INVALID_VERSION) {
      std::cerr << "Server talks QUIC, but none of the versions supported by "
                << "this client: " << ParsedQuicVersionVectorToString(versions)
                << std::endl;
      // 0: No error.
      // 20: Failed to connect due to QUIC_INVALID_VERSION.
      return GetQuicFlag(FLAGS_version_mismatch_ok) ? 0 : 20;
    }
    std::cerr << "Failed to connect to " << host << ":" << port
              << ". Error: " << quic::QuicErrorCodeToString(error) << std::endl;
    return 1;
  }
  std::cerr << "Connected to " << host << ":" << port << std::endl;

  // Construct the string body from flags, if provided.
  std::string body = GetQuicFlag(FLAGS_body);
  if (!GetQuicFlag(FLAGS_body_hex).empty()) {
    DCHECK(GetQuicFlag(FLAGS_body).empty())
        << "Only set one of --body and --body_hex.";
    body = QuicTextUtils::HexDecode(GetQuicFlag(FLAGS_body_hex));
  }

  // Construct a GET or POST request for supplied URL.
  spdy::SpdyHeaderBlock header_block;
  header_block[":method"] = body.empty() ? "GET" : "POST";
  header_block[":scheme"] = url.scheme();
  header_block[":authority"] = url.HostPort();
  header_block[":path"] = url.PathParamsQuery();

  // Append any additional headers supplied on the command line.
  const std::string headers = GetQuicFlag(FLAGS_headers);
  for (QuicStringPiece sp : QuicTextUtils::Split(headers, ';')) {
    QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&sp);
    if (sp.empty()) {
      continue;
    }
    std::vector<QuicStringPiece> kv = QuicTextUtils::Split(sp, ':');
    QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[0]);
    QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[1]);
    header_block[kv[0]] = kv[1];
  }

  // Make sure to store the response, for later output.
  client->set_store_response(true);

  for (int i = 0; i < num_requests; ++i) {
    // Send the request.
    client->SendRequestAndWaitForResponse(header_block, body, /*fin=*/true);

    // Print request and response details.
    if (!GetQuicFlag(FLAGS_quiet)) {
      std::cout << "Request:" << std::endl;
      std::cout << "headers:" << header_block.DebugString();
      if (!GetQuicFlag(FLAGS_body_hex).empty()) {
        // Print the user provided hex, rather than binary body.
        std::cout << "body:\n"
                  << QuicTextUtils::HexDump(
                         QuicTextUtils::HexDecode(GetQuicFlag(FLAGS_body_hex)))
                  << std::endl;
      } else {
        std::cout << "body: " << body << std::endl;
      }
      std::cout << std::endl;

      if (!client->preliminary_response_headers().empty()) {
        std::cout << "Preliminary response headers: "
                  << client->preliminary_response_headers() << std::endl;
        std::cout << std::endl;
      }

      std::cout << "Response:" << std::endl;
      std::cout << "headers: " << client->latest_response_headers()
                << std::endl;
      std::string response_body = client->latest_response_body();
      if (!GetQuicFlag(FLAGS_body_hex).empty()) {
        // Assume response is binary data.
        std::cout << "body:\n"
                  << QuicTextUtils::HexDump(response_body) << std::endl;
      } else {
        std::cout << "body: " << response_body << std::endl;
      }
      std::cout << "trailers: " << client->latest_response_trailers()
                << std::endl;
    }

    if (!client->connected()) {
      std::cerr << "Request caused connection failure. Error: "
                << quic::QuicErrorCodeToString(client->session()->error())
                << std::endl;
      return 1;
    }

    int response_code = client->latest_response_code();
    if (response_code >= 200 && response_code < 300) {
      std::cout << "Request succeeded (" << response_code << ")." << std::endl;
    } else if (response_code >= 300 && response_code < 400) {
      if (GetQuicFlag(FLAGS_redirect_is_success)) {
        std::cout << "Request succeeded (redirect " << response_code << ")."
                  << std::endl;
      } else {
        std::cout << "Request failed (redirect " << response_code << ")."
                  << std::endl;
        return 1;
      }
    } else {
      std::cout << "Request failed (" << response_code << ")." << std::endl;
      return 1;
    }

    // Change the ephemeral port if there are more requests to do.
    if (i + 1 < num_requests) {
      if (!client->ChangeEphemeralPort()) {
        std::cerr << "Failed to change ephemeral port." << std::endl;
        return 1;
      }
    }
  }

  return 0;
}

}  // namespace quic
<commit_msg>Add a --disable_port_changes option to quic_client to not change ports after every request.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// A binary wrapper for QuicClient.
// Connects to a host using QUIC, sends a request to the provided URL, and
// displays the response.
//
// Some usage examples:
//
// Standard request/response:
//   quic_client www.google.com
//   quic_client www.google.com --quiet
//   quic_client www.google.com --port=443
//
// Use a specific version:
//   quic_client www.google.com --quic_version=23
//
// Send a POST instead of a GET:
//   quic_client www.google.com --body="this is a POST body"
//
// Append additional headers to the request:
//   quic_client www.google.com --headers="Header-A: 1234; Header-B: 5678"
//
// Connect to a host different to the URL being requested:
//   quic_client mail.google.com --host=www.google.com
//
// Connect to a specific IP:
//   IP=`dig www.google.com +short | head -1`
//   quic_client www.google.com --host=${IP}
//
// Send repeated requests and change ephemeral port between requests
//   quic_client www.google.com --num_requests=10
//
// Try to connect to a host which does not speak QUIC:
//   quic_client www.example.com
//
// This tool is available as a built binary at:
// /google/data/ro/teams/quic/tools/quic_client
// After submitting changes to this file, you will need to follow the
// instructions at go/quic_client_binary_update

#include "net/third_party/quiche/src/quic/tools/quic_toy_client.h"

#include <iostream>
#include <memory>
#include <string>
#include <vector>

#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_system_event_loop.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
#include "net/third_party/quiche/src/quic/tools/fake_proof_verifier.h"
#include "net/third_party/quiche/src/quic/tools/quic_url.h"

namespace {

using quic::QuicSocketAddress;
using quic::QuicStringPiece;
using quic::QuicTextUtils;
using quic::QuicUrl;

}  // namespace

DEFINE_QUIC_COMMAND_LINE_FLAG(
    std::string,
    host,
    "",
    "The IP or hostname to connect to. If not provided, the host "
    "will be derived from the provided URL.");

DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, port, 0, "The port to connect to.");

DEFINE_QUIC_COMMAND_LINE_FLAG(std::string,
                              body,
                              "",
                              "If set, send a POST with this body.");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    std::string,
    body_hex,
    "",
    "If set, contents are converted from hex to ascii, before "
    "sending as body of a POST. e.g. --body_hex=\"68656c6c6f\"");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    std::string,
    headers,
    "",
    "A semicolon separated list of key:value pairs to "
    "add to request headers.");

DEFINE_QUIC_COMMAND_LINE_FLAG(bool,
                              quiet,
                              false,
                              "Set to true for a quieter output experience.");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    std::string,
    quic_version,
    "",
    "QUIC version to speak, e.g. 21. If not set, then all available "
    "versions are offered in the handshake. Also supports wire versions "
    "such as Q043 or T099.");

DEFINE_QUIC_COMMAND_LINE_FLAG(bool,
                              quic_ietf_draft,
                              false,
                              "Use the IETF draft version. This also enables "
                              "required internal QUIC flags.");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    bool,
    version_mismatch_ok,
    false,
    "If true, a version mismatch in the handshake is not considered a "
    "failure. Useful for probing a server to determine if it speaks "
    "any version of QUIC.");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    bool,
    force_version_negotiation,
    false,
    "If true, start by proposing a version that is reserved for version "
    "negotiation.");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    bool,
    redirect_is_success,
    true,
    "If true, an HTTP response code of 3xx is considered to be a "
    "successful response, otherwise a failure.");

DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t,
                              initial_mtu,
                              0,
                              "Initial MTU of the connection.");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    int32_t,
    num_requests,
    1,
    "How many sequential requests to make on a single connection.");

DEFINE_QUIC_COMMAND_LINE_FLAG(bool,
                              disable_certificate_verification,
                              false,
                              "If true, don't verify the server certificate.");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    bool,
    drop_response_body,
    false,
    "If true, drop response body immediately after it is received.");

DEFINE_QUIC_COMMAND_LINE_FLAG(
    bool,
    disable_port_changes,
    false,
    "If true, do not change local port after each request.");

namespace quic {

QuicToyClient::QuicToyClient(ClientFactory* client_factory)
    : client_factory_(client_factory) {}

int QuicToyClient::SendRequestsAndPrintResponses(
    std::vector<std::string> urls) {
  QuicUrl url(urls[0], "https");
  std::string host = GetQuicFlag(FLAGS_host);
  if (host.empty()) {
    host = url.host();
  }
  int port = GetQuicFlag(FLAGS_port);
  if (port == 0) {
    port = url.port();
  }

  quic::ParsedQuicVersionVector versions = quic::CurrentSupportedVersions();

  std::string quic_version_string = GetQuicFlag(FLAGS_quic_version);
  if (GetQuicFlag(FLAGS_quic_ietf_draft)) {
    quic::QuicVersionInitializeSupportForIetfDraft();
    versions = {{quic::PROTOCOL_TLS1_3, quic::QUIC_VERSION_99}};
    quic::QuicEnableVersion(versions[0]);

  } else if (!quic_version_string.empty()) {
    if (quic_version_string[0] == 'T') {
      // ParseQuicVersionString checks quic_supports_tls_handshake.
      SetQuicReloadableFlag(quic_supports_tls_handshake, true);
    }
    quic::ParsedQuicVersion parsed_quic_version =
        quic::ParseQuicVersionString(quic_version_string);
    if (parsed_quic_version.transport_version ==
        quic::QUIC_VERSION_UNSUPPORTED) {
      return 1;
    }
    versions = {parsed_quic_version};
    quic::QuicEnableVersion(parsed_quic_version);
  }

  if (GetQuicFlag(FLAGS_force_version_negotiation)) {
    versions.insert(versions.begin(),
                    quic::QuicVersionReservedForNegotiation());
  }

  const int32_t num_requests(GetQuicFlag(FLAGS_num_requests));
  std::unique_ptr<quic::ProofVerifier> proof_verifier;
  if (GetQuicFlag(FLAGS_disable_certificate_verification)) {
    proof_verifier = std::make_unique<FakeProofVerifier>();
  } else {
    proof_verifier = quic::CreateDefaultProofVerifier(url.host());
  }

  // Build the client, and try to connect.
  std::unique_ptr<QuicSpdyClientBase> client = client_factory_->CreateClient(
      url.host(), host, port, versions, std::move(proof_verifier));

  if (client == nullptr) {
    std::cerr << "Failed to create client." << std::endl;
    return 1;
  }

  int32_t initial_mtu = GetQuicFlag(FLAGS_initial_mtu);
  client->set_initial_max_packet_length(
      initial_mtu != 0 ? initial_mtu : quic::kDefaultMaxPacketSize);
  client->set_drop_response_body(GetQuicFlag(FLAGS_drop_response_body));
  if (!client->Initialize()) {
    std::cerr << "Failed to initialize client." << std::endl;
    return 1;
  }
  if (!client->Connect()) {
    quic::QuicErrorCode error = client->session()->error();
    if (error == quic::QUIC_INVALID_VERSION) {
      std::cerr << "Server talks QUIC, but none of the versions supported by "
                << "this client: " << ParsedQuicVersionVectorToString(versions)
                << std::endl;
      // 0: No error.
      // 20: Failed to connect due to QUIC_INVALID_VERSION.
      return GetQuicFlag(FLAGS_version_mismatch_ok) ? 0 : 20;
    }
    std::cerr << "Failed to connect to " << host << ":" << port
              << ". Error: " << quic::QuicErrorCodeToString(error) << std::endl;
    return 1;
  }
  std::cerr << "Connected to " << host << ":" << port << std::endl;

  // Construct the string body from flags, if provided.
  std::string body = GetQuicFlag(FLAGS_body);
  if (!GetQuicFlag(FLAGS_body_hex).empty()) {
    DCHECK(GetQuicFlag(FLAGS_body).empty())
        << "Only set one of --body and --body_hex.";
    body = QuicTextUtils::HexDecode(GetQuicFlag(FLAGS_body_hex));
  }

  // Construct a GET or POST request for supplied URL.
  spdy::SpdyHeaderBlock header_block;
  header_block[":method"] = body.empty() ? "GET" : "POST";
  header_block[":scheme"] = url.scheme();
  header_block[":authority"] = url.HostPort();
  header_block[":path"] = url.PathParamsQuery();

  // Append any additional headers supplied on the command line.
  const std::string headers = GetQuicFlag(FLAGS_headers);
  for (QuicStringPiece sp : QuicTextUtils::Split(headers, ';')) {
    QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&sp);
    if (sp.empty()) {
      continue;
    }
    std::vector<QuicStringPiece> kv = QuicTextUtils::Split(sp, ':');
    QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[0]);
    QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[1]);
    header_block[kv[0]] = kv[1];
  }

  // Make sure to store the response, for later output.
  client->set_store_response(true);

  for (int i = 0; i < num_requests; ++i) {
    // Send the request.
    client->SendRequestAndWaitForResponse(header_block, body, /*fin=*/true);

    // Print request and response details.
    if (!GetQuicFlag(FLAGS_quiet)) {
      std::cout << "Request:" << std::endl;
      std::cout << "headers:" << header_block.DebugString();
      if (!GetQuicFlag(FLAGS_body_hex).empty()) {
        // Print the user provided hex, rather than binary body.
        std::cout << "body:\n"
                  << QuicTextUtils::HexDump(
                         QuicTextUtils::HexDecode(GetQuicFlag(FLAGS_body_hex)))
                  << std::endl;
      } else {
        std::cout << "body: " << body << std::endl;
      }
      std::cout << std::endl;

      if (!client->preliminary_response_headers().empty()) {
        std::cout << "Preliminary response headers: "
                  << client->preliminary_response_headers() << std::endl;
        std::cout << std::endl;
      }

      std::cout << "Response:" << std::endl;
      std::cout << "headers: " << client->latest_response_headers()
                << std::endl;
      std::string response_body = client->latest_response_body();
      if (!GetQuicFlag(FLAGS_body_hex).empty()) {
        // Assume response is binary data.
        std::cout << "body:\n"
                  << QuicTextUtils::HexDump(response_body) << std::endl;
      } else {
        std::cout << "body: " << response_body << std::endl;
      }
      std::cout << "trailers: " << client->latest_response_trailers()
                << std::endl;
    }

    if (!client->connected()) {
      std::cerr << "Request caused connection failure. Error: "
                << quic::QuicErrorCodeToString(client->session()->error())
                << std::endl;
      return 1;
    }

    int response_code = client->latest_response_code();
    if (response_code >= 200 && response_code < 300) {
      std::cout << "Request succeeded (" << response_code << ")." << std::endl;
    } else if (response_code >= 300 && response_code < 400) {
      if (GetQuicFlag(FLAGS_redirect_is_success)) {
        std::cout << "Request succeeded (redirect " << response_code << ")."
                  << std::endl;
      } else {
        std::cout << "Request failed (redirect " << response_code << ")."
                  << std::endl;
        return 1;
      }
    } else {
      std::cout << "Request failed (" << response_code << ")." << std::endl;
      return 1;
    }

    // Change the ephemeral port if there are more requests to do.
    if (!GetQuicFlag(FLAGS_disable_port_changes) && i + 1 < num_requests) {
      if (!client->ChangeEphemeralPort()) {
        std::cerr << "Failed to change ephemeral port." << std::endl;
        return 1;
      }
    }
  }

  return 0;
}

}  // namespace quic
<|endoftext|>


<commit_before>/*=============================================================================
	Copyright (c) 2012-2013 Richard Otis

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/

// Equilibrium calculations test fixture

#include "libgibbs/include/equilibrium.hpp"
#include "libtdb/include/database.hpp"
#include <sstream>

#ifndef INCLUDED_FIXTURE_EQ
#define INCLUDED_FIXTURE_EQ

struct EquilibriumFixture {
	EquilibriumFixture() : eqfact() {
	}
	void clear_conditions() {
		conditions = evalconditions();
	}
	double calculate() {
		// TODO: go beyond naive checking of the objective function
		Equilibrium testeq = Equilibrium(curdb, conditions, eqfact.GetIpopt());
		return testeq.GibbsEnergy();
	}
	void LoadDatabase(const std::string &filename) {
		if (filename != dbname) {
			// if this is a different database, load it
			curdb = Database(filename);
			dbname = filename;
		}
	}
	std::string PrintConditions() {
		std::stringstream msg;
		msg << std::endl << "Conditions: " << std::endl << "\t";
		auto sv_begin = conditions.statevars.cbegin();
		auto sv_end = conditions.statevars.cend();
		auto xf_begin = conditions.xfrac.cbegin();
		auto xf_end = conditions.xfrac.cend();
		auto el_begin = conditions.elements.cbegin();
		auto el_end = conditions.elements.cend();
		auto ph_begin = conditions.phases.cbegin();
		auto ph_end = conditions.phases.cend();
		for (auto i = sv_begin; i != sv_end; ++i) {
			msg << (*i).first << "=" << (*i).second << " ";
		}
		for (auto i = xf_begin; i != xf_end; ++i) {
			msg << "x(" << (*i).first << ")=" << (*i).second << " ";
		}
		if (el_begin != el_end) msg << std::endl << '\t';
		for (auto i = el_begin; i != el_end; ++i) {
			msg << *i << " ";
		}
		if (ph_begin != ph_end) msg << std::endl << "\t";
		for (auto i = ph_begin; i != ph_end; ++i) {
			msg << (*i).first << "=" << static_cast<char>((*i).second);
			msg << " ";
		}
		msg << std::endl;
		return msg.str();
	}
	EquilibriumFactory eqfact;
	evalconditions conditions;
	Database curdb;
	std::string dbname;
};

#endif
<commit_msg>remove reference to old interface<commit_after>/*=============================================================================
	Copyright (c) 2012-2013 Richard Otis

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/

// Equilibrium calculations test fixture

#include "libgibbs/include/equilibrium.hpp"
#include "libtdb/include/database.hpp"
#include <sstream>

#ifndef INCLUDED_FIXTURE_EQ
#define INCLUDED_FIXTURE_EQ

struct EquilibriumFixture {
	EquilibriumFixture() : eqfact() {
	}
	void clear_conditions() {
		conditions = evalconditions();
	}
	double calculate() {
		// TODO: go beyond naive checking of the objective function
		Equilibrium testeq = Equilibrium(curdb, conditions, eqfact.GetIpopt());
		return 0; // TODO: switch to new interface
	}
	void LoadDatabase(const std::string &filename) {
		if (filename != dbname) {
			// if this is a different database, load it
			curdb = Database(filename);
			dbname = filename;
		}
	}
	std::string PrintConditions() {
		std::stringstream msg;
		msg << std::endl << "Conditions: " << std::endl << "\t";
		auto sv_begin = conditions.statevars.cbegin();
		auto sv_end = conditions.statevars.cend();
		auto xf_begin = conditions.xfrac.cbegin();
		auto xf_end = conditions.xfrac.cend();
		auto el_begin = conditions.elements.cbegin();
		auto el_end = conditions.elements.cend();
		auto ph_begin = conditions.phases.cbegin();
		auto ph_end = conditions.phases.cend();
		for (auto i = sv_begin; i != sv_end; ++i) {
			msg << (*i).first << "=" << (*i).second << " ";
		}
		for (auto i = xf_begin; i != xf_end; ++i) {
			msg << "x(" << (*i).first << ")=" << (*i).second << " ";
		}
		if (el_begin != el_end) msg << std::endl << '\t';
		for (auto i = el_begin; i != el_end; ++i) {
			msg << *i << " ";
		}
		if (ph_begin != ph_end) msg << std::endl << "\t";
		for (auto i = ph_begin; i != ph_end; ++i) {
			msg << (*i).first << "=" << static_cast<char>((*i).second);
			msg << " ";
		}
		msg << std::endl;
		return msg.str();
	}
	EquilibriumFactory eqfact;
	evalconditions conditions;
	Database curdb;
	std::string dbname;
};

#endif
<|endoftext|>


<commit_before>#include <Halide.h>
#include <stdio.h>
#include "clock.h"
#include <memory>

using namespace Halide;

int main(int argc, char **argv) {
    ImageParam src(UInt(8), 3);
    Func dst;
    Var x, y, c;

    dst(x, y, c) = src(x, y, c);

    src.set_stride(0, 3);
    src.set_stride(2, 1);
    src.set_extent(2, 3);

    // This is the default format for Halide, but made explicit for illustration.
    dst.output_buffer().set_stride(0, 1);
    dst.output_buffer().set_extent(2, 3);

    dst.reorder(c, x, y).unroll(c);
    dst.vectorize(x, 16);

    // Allocate two 16 megapixel, 3 channel, 8-bit images -- input and output
    const int32_t buffer_size = 1 << 24;
    const int32_t buffer_side_length = 1 << 12;

    uint8_t *src_storage(new uint8_t[buffer_size * 3]);
    uint8_t *dst_storage(new uint8_t[buffer_size * 3]);

    buffer_t src_buffer;
    buffer_t dst_buffer;

    // Setup src to be RGB interleaved, with no extra padding between channels or rows.
    memset(&src_buffer, 0, sizeof(src_buffer));
    src_buffer.host = src_storage;
    src_buffer.extent[0] = buffer_side_length;
    src_buffer.stride[0] = 3;
    src_buffer.extent[1] = buffer_side_length;
    src_buffer.stride[1] = src_buffer.stride[0] * src_buffer.extent[0];
    src_buffer.extent[2] = 3;
    src_buffer.stride[2] = 1;
    src_buffer.elem_size = 1;

    // Setup dst to be planar, with no extra padding between channels or rows.
    memset(&dst_buffer, 0, sizeof(dst_buffer));
    dst_buffer.host = dst_storage;
    dst_buffer.extent[0] = buffer_side_length;
    dst_buffer.stride[0] = 1;
    dst_buffer.extent[1] = buffer_side_length;
    dst_buffer.stride[1] = dst_buffer.stride[0] * dst_buffer.extent[0];
    dst_buffer.extent[2] = 3;
    dst_buffer.stride[2] = dst_buffer.stride[1] * dst_buffer.extent[1];
    dst_buffer.elem_size = 1;

    Image<uint8_t> src_image(&src_buffer, "src_image");
    Image<uint8_t> dst_image(&dst_buffer, "dst_image");

    for (int32_t x = 0; x < buffer_side_length; x++) {
        for (int32_t y = 0; y < buffer_side_length; y++) {
	  src_image(x, y, 0) = 0;
          src_image(x, y, 1) = 128;
          src_image(x, y, 2) = 255;
        }
    }

    src.set(src_image);

    dst.compile_jit();

    double t1 = currentTime();
    dst.realize(dst_image);
    double t2 = currentTime();

    printf("Interelaved to planar bandwidth %.3e byte/s.\n", (buffer_size / (t2 - t1)) * 1000);

    for (int32_t x = 0; x < buffer_side_length; x++) {
        for (int32_t y = 0; y < buffer_side_length; y++) {
            assert(dst_image(x, y, 0) == 0);
            assert(dst_image(x, y, 1) == 128);
            assert(dst_image(x, y, 2) == 255);
        }
    }

    // Setup a semi-planar output case.
    memset(&dst_buffer, 0, sizeof(dst_buffer));
    dst_buffer.host = dst_storage;
    dst_buffer.extent[0] = buffer_side_length;
    dst_buffer.stride[0] = 1;
    dst_buffer.extent[1] = buffer_side_length;
    dst_buffer.stride[1] = dst_buffer.stride[0] * dst_buffer.extent[0] * 3;
    dst_buffer.extent[2] = 3;
    dst_buffer.stride[2] = dst_buffer.extent[0];
    dst_buffer.elem_size = 1;

    double t3 = currentTime();
    dst.realize(dst_image);
    double t4 = currentTime();

    for (int32_t x = 0; x < buffer_side_length; x++) {
        for (int32_t y = 0; y < buffer_side_length; y++) {
            assert(dst_image(x, y, 0) == 0);
            assert(dst_image(x, y, 1) == 128);
            assert(dst_image(x, y, 2) == 255);
        }
    }

    printf("Interelaved to semi-planar bandwidth %.3e byte/s.\n", (buffer_size / (t4 - t3)) * 1000);

    delete[] src_storage;
    delete[] dst_storage;

    printf("Success!\n");
    return 0;
}
<commit_msg>Make rgb_interleaved performance test's timing and correctness check more robust.<commit_after>#include <Halide.h>
#include <stdio.h>
#include "clock.h"
#include <memory>

using namespace Halide;

int main(int argc, char **argv) {
    ImageParam src(UInt(8), 3);
    Func dst;
    Var x, y, c;

    dst(x, y, c) = src(x, y, c);

    src.set_stride(0, 3);
    src.set_stride(2, 1);
    src.set_extent(2, 3);

    // This is the default format for Halide, but made explicit for illustration.
    dst.output_buffer().set_stride(0, 1);
    dst.output_buffer().set_extent(2, 3);

    dst.reorder(c, x, y).unroll(c);
    dst.vectorize(x, 16);

    // Run test many times to avoid timing jitter
    const int iterations = 20;

    // Allocate two 16 megapixel, 3 channel, 8-bit images -- input and output
    const int32_t buffer_side_length = (1 << 12);
    const int32_t buffer_size = buffer_side_length * buffer_side_length;

    uint8_t *src_storage(new uint8_t[buffer_size * 3]);
    uint8_t *dst_storage(new uint8_t[buffer_size * 3]);

    buffer_t src_buffer;
    buffer_t dst_buffer;

    // Setup src to be RGB interleaved, with no extra padding between channels or rows.
    memset(&src_buffer, 0, sizeof(src_buffer));
    src_buffer.host = src_storage;
    src_buffer.extent[0] = buffer_side_length;
    src_buffer.stride[0] = 3;
    src_buffer.extent[1] = buffer_side_length;
    src_buffer.stride[1] = src_buffer.stride[0] * src_buffer.extent[0];
    src_buffer.extent[2] = 3;
    src_buffer.stride[2] = 1;
    src_buffer.elem_size = 1;

    // Setup dst to be planar, with no extra padding between channels or rows.
    memset(&dst_buffer, 0, sizeof(dst_buffer));
    dst_buffer.host = dst_storage;
    dst_buffer.extent[0] = buffer_side_length;
    dst_buffer.stride[0] = 1;
    dst_buffer.extent[1] = buffer_side_length;
    dst_buffer.stride[1] = dst_buffer.stride[0] * dst_buffer.extent[0];
    dst_buffer.extent[2] = 3;
    dst_buffer.stride[2] = dst_buffer.stride[1] * dst_buffer.extent[1];
    dst_buffer.elem_size = 1;

    Image<uint8_t> src_image(&src_buffer, "src_image");
    Image<uint8_t> dst_image(&dst_buffer, "dst_image");

    for (int32_t x = 0; x < buffer_side_length; x++) {
        for (int32_t y = 0; y < buffer_side_length; y++) {
	  src_image(x, y, 0) = 0;
          src_image(x, y, 1) = 128;
          src_image(x, y, 2) = 255;
        }
    }
    memset(dst_storage, 0, buffer_size);

    src.set(src_image);

    dst.compile_jit();

    // Warm up caches, etc.
    dst.realize(dst_image);

    double t1 = currentTime();

    for (int i = 0; i < iterations; i++)
        dst.realize(dst_image);

    double t2 = currentTime();

    printf("Interelaved to planar bandwidth %.3e byte/s.\n", (buffer_size / (t2 - t1)) * 1000 * iterations);

    for (int32_t x = 0; x < buffer_side_length; x++) {
        for (int32_t y = 0; y < buffer_side_length; y++) {
            assert(dst_image(x, y, 0) == 0);
            assert(dst_image(x, y, 1) == 128);
            assert(dst_image(x, y, 2) == 255);
        }
    }

    // Setup a semi-planar output case.
    memset(&dst_buffer, 0, sizeof(dst_buffer));
    dst_buffer.host = dst_storage;
    dst_buffer.extent[0] = buffer_side_length;
    dst_buffer.stride[0] = 1;
    dst_buffer.extent[1] = buffer_side_length;
    dst_buffer.stride[1] = dst_buffer.stride[0] * dst_buffer.extent[0] * 3;
    dst_buffer.extent[2] = 3;
    dst_buffer.stride[2] = dst_buffer.extent[0];
    dst_buffer.elem_size = 1;

    memset(dst_storage, 0, buffer_size);

    double t3 = currentTime();

    for (int i = 0; i < iterations; i++)
        dst.realize(dst_image);

    double t4 = currentTime();

    for (int32_t x = 0; x < buffer_side_length; x++) {
        for (int32_t y = 0; y < buffer_side_length; y++) {
            assert(dst_image(x, y, 0) == 0);
            assert(dst_image(x, y, 1) == 128);
            assert(dst_image(x, y, 2) == 255);
        }
    }

    printf("Interelaved to semi-planar bandwidth %.3e byte/s.\n", (buffer_size / (t4 - t3)) * 1000 * iterations);

    delete[] src_storage;
    delete[] dst_storage;

    printf("Success!\n");
    return 0;
}
<|endoftext|>