<commit_before>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <gtest/gtest.h>
#include <arrayfire.h>
#include <af/dim4.hpp>
#include <af/defines.h>
#include <af/traits.hpp>
#include <af/image.h>
#include <vector>
#include <iostream>
#include <string>
#include <testHelpers.hpp>

using std::vector;
using std::string;
using std::cout;
using std::endl;
using af::cfloat;
using af::cdouble;

template<typename T>
class Regions : public ::testing::Test
{
    public:
        virtual void SetUp() {}
};

// create a list of types to be tested
typedef ::testing::Types<float, double, int, unsigned, short, ushort> TestTypes;

// register the type list
TYPED_TEST_CASE(Regions, TestTypes);

template<typename T>
void regionsTest(string pTestFile, af_connectivity connectivity, bool isSubRef = false, const vector<af_seq> * seqv = NULL)
{
    if (noDoubleTests<T>()) return;

    vector<af::dim4> numDims;
    vector<vector<uchar> > in;
    vector<vector<T> > tests;
    readTests<uchar, T, unsigned>(pTestFile,numDims,in,tests);

    af::dim4 idims = numDims[0];

    af_array inArray = 0;
    af_array tempArray = 0;
    af_array outArray = 0;

    if (isSubRef) {
        ASSERT_EQ(AF_SUCCESS, af_create_array(&tempArray, &(in[0].front()), idims.ndims(), idims.get(), (af_dtype) af::dtype_traits<char>::af_type));

        ASSERT_EQ(AF_SUCCESS, af_index(&inArray, tempArray, seqv->size(), &seqv->front()));
    } else {
        ASSERT_EQ(AF_SUCCESS, af_create_array(&inArray, &(in[0].front()), idims.ndims(), idims.get(), (af_dtype) af::dtype_traits<char>::af_type));
    }

    ASSERT_EQ(AF_SUCCESS, af_regions(&outArray, inArray, connectivity, (af_dtype) af::dtype_traits<T>::af_type));

    // Get result
    T* outData = new T[idims.elements()];
    ASSERT_EQ(AF_SUCCESS, af_get_data_ptr((void*)outData, outArray));

    // Compare result
    for (size_t testIter = 0; testIter < tests.size(); ++testIter) {
        vector<T> currGoldBar = tests[testIter];
        size_t nElems = currGoldBar.size();
        for (size_t elIter = 0; elIter < nElems; ++elIter) {
            ASSERT_EQ(currGoldBar[elIter], outData[elIter]) << "at: " << elIter << std::endl;
        }
    }

    // Delete
    delete[] outData;

    if(inArray   != 0) af_release_array(inArray);
    if(outArray  != 0) af_release_array(outArray);
    if(tempArray != 0) af_release_array(tempArray);
}

#define REGIONS_INIT(desc, file, conn, conn_type)                                           \
    TYPED_TEST(Regions, desc)                                                               \
    {                                                                                \
        regionsTest<TypeParam>(string(TEST_DIR"/regions/"#file"_"#conn".test"), conn_type); \
    }

    REGIONS_INIT(Regions0, regions_8x8, 4, AF_CONNECTIVITY_4);
    REGIONS_INIT(Regions1, regions_8x8, 8, AF_CONNECTIVITY_8);
    REGIONS_INIT(Regions2, regions_128x128, 4, AF_CONNECTIVITY_4);
    REGIONS_INIT(Regions3, regions_128x128, 8, AF_CONNECTIVITY_8);

///////////////////////////////////// CPP ////////////////////////////////
//
TEST(Regions, CPP)
{
    if (noDoubleTests<float>()) return;

    vector<af::dim4> numDims;
    vector<vector<float> > in;
    vector<vector<float> > tests;
    readTests<float, float, unsigned>(string(TEST_DIR"/regions/regions_8x8_4.test"),numDims,in,tests);

    af::dim4 idims = numDims[0];
    af::array input(idims, (float*)&(in[0].front()));
    af::array output = af::regions(input.as(b8));

    // Get result
    float* outData = new float[idims.elements()];
    output.host((void*)outData);

    // Compare result
    for (size_t testIter = 0; testIter < tests.size(); ++testIter) {
        vector<float> currGoldBar = tests[testIter];
        size_t nElems = currGoldBar.size();
        for (size_t elIter = 0; elIter < nElems; ++elIter) {
            ASSERT_EQ(currGoldBar[elIter], outData[elIter]) << "at: " << elIter << std::endl;
        }
    }

    // Delete
    delete[] outData;
}

///////////////////////////////// Documentation Examples ///////////////////
TEST(Regions, Docs_8)
{
    // input data
    uchar input[64] =  {
        0, 0, 0, 0, 1, 0, 0, 0,
        0, 0, 1, 0, 1, 0, 0, 1,
        0, 0, 0, 1, 0, 0, 0, 0,
        0, 0, 1, 0, 0, 1, 0, 0,
        1, 0, 0, 1, 0, 0, 1, 0,
        0, 0, 0, 1, 1, 0, 0, 1,
        1, 1, 0, 0, 0, 0, 0, 0,
        0, 1, 0, 1, 1, 1, 1, 0
    };
    // gold output
    float gold[64] =  {
        0, 0, 0, 0, 1, 0, 0, 0,
        0, 0, 1, 0, 1, 0, 0, 2,
        0, 0, 0, 1, 0, 0, 0, 0,
        0, 0, 1, 0, 0, 3, 0, 0,
        4, 0, 0, 1, 0, 0, 3, 0,
        0, 0, 0, 1, 1, 0, 0, 3,
        5, 5, 0, 0, 0, 0, 0, 0,
        0, 5, 0, 6, 6, 6, 6, 0
    };

    //![ex_image_regions]
    af::array in(8, 8, input);
    //af_print(in);
    // in =
    // 0   0   0   0   1   0   1   0
    // 0   0   0   0   0   0   1   1
    // 0   1   0   1   0   0   0   0
    // 0   0   1   0   1   1   0   1
    // 1   1   0   0   0   1   0   1
    // 0   0   0   1   0   0   0   1
    // 0   0   0   0   1   0   0   1
    // 0   1   0   0   0   1   0   0

    // Compute the label matrix using 8-way connectivity
    af::array out = regions(in.as(b8), AF_CONNECTIVITY_8);
    //af_print(out);
    // 0   0   0   0   4   0   5   0
    // 0   0   0   0   0   0   5   5
    // 0   1   0   1   0   0   0   0
    // 0   0   1   0   1   1   0   6
    // 1   1   0   0   0   1   0   6
    // 0   0   0   3   0   0   0   6
    // 0   0   0   0   3   0   0   6
    // 0   2   0   0   0   3   0   0
    //![ex_image_regions]

    float output[64];
    out.host((void*)output);

    for (int i=0; i<64; ++i) {
        ASSERT_EQ(gold[i], output[i])<<" mismatch at i="<<i<<std::endl;
    }
}

TEST(Regions, Docs_4)
{
    // input data
    uchar input[64] =  {
        0, 0, 0, 0, 1, 0, 0, 0,
        0, 0, 1, 0, 1, 0, 0, 1,
        0, 0, 0, 1, 0, 0, 0, 0,
        0, 0, 1, 0, 0, 1, 0, 0,
        1, 0, 0, 1, 0, 0, 1, 0,
        0, 0, 0, 1, 1, 0, 0, 1,
        1, 1, 0, 0, 0, 0, 0, 0,
        0, 1, 0, 1, 1, 1, 1, 0
    };
    // gold output
    float gold[64] =  {
        0.0000,  0.0000,  0.0000,  0.0000,  1.0000,  0.0000,  0.0000,  0.0000,
        0.0000,  0.0000,  2.0000,  0.0000,  1.0000,  0.0000,  0.0000,  3.0000,
        0.0000,  0.0000,  0.0000,  4.0000,  0.0000,  0.0000,  0.0000,  0.0000,
        0.0000,  0.0000,  5.0000,  0.0000,  0.0000,  6.0000,  0.0000,  0.0000,
        7.0000,  0.0000,  0.0000,  8.0000,  0.0000,  0.0000,  9.0000,  0.0000,
        0.0000,  0.0000,  0.0000,  8.0000,  8.0000,  0.0000,  0.0000, 10.0000,
        11.000, 11.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,
        0.0000, 11.0000,  0.0000, 12.0000, 12.0000, 12.0000, 12.0000,  0.0000
    };

    //![ex_image_regions_4conn]
    af::array in(8, 8, input);
    //af_print(in.T());
    //in
    //0  0  0  0  1  0  1  0
    //0  0  0  0  0  0  1  1
    //0  1  0  1  0  0  0  0
    //0  0  1  0  1  1  0  1
    //1  1  0  0  0  1  0  1
    //0  0  0  1  0  0  0  1
    //0  0  0  0  1  0  0  1
    //0  1  0  0  0  1  0  0
    // Compute the label matrix using 4-way connectivity
    af::array out = regions(in.as(b8), AF_CONNECTIVITY_4);
    //af_print(out.T());
    //out
    //0  0  0  0  7  0 11  0
    //0  0  0  0  0  0 11 11
    //0  2  0  5  0  0  0  0
    //0  0  4  0  8  8  0 12
    //1  1  0  0  0  8  0 12
    //0  0  0  6  0  0  0 12
    //0  0  0  0  9  0  0 12
    //0  3  0  0  0 10  0  0
    //![ex_image_regions_4conn]

    float output[64];
    out.host((void*)output);

    for (int i=0; i<64; ++i) {
        ASSERT_EQ(gold[i], output[i])<<" mismatch at i="<<i<<std::endl;
    }
}

TEST(Regions, Issue1650)
{
    const int dim = 101;
    const int sz  = dim*dim;
    std::vector<char> input(sz, 1);
    std::vector<float> gold(sz, 1.0f);

    af::array in  = af::array(dim, dim, input.data());
    af::array out = af::regions(in, AF_CONNECTIVITY_4);

    std::vector<float> output(sz);
    out.host((void*)output.data());

    for (int i=0; i<sz; ++i)
        ASSERT_FLOAT_EQ(gold[i], output[i])<<" mismatch at i="<<i<<std::endl;
}
<commit_msg>No component test case for regions<commit_after>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <gtest/gtest.h>
#include <arrayfire.h>
#include <af/dim4.hpp>
#include <af/defines.h>
#include <af/traits.hpp>
#include <af/image.h>
#include <vector>
#include <iostream>
#include <string>
#include <testHelpers.hpp>

using std::vector;
using std::string;
using std::cout;
using std::endl;
using af::cfloat;
using af::cdouble;

template<typename T>
class Regions : public ::testing::Test
{
    public:
        virtual void SetUp() {}
};

// create a list of types to be tested
typedef ::testing::Types<float, double, int, unsigned, short, ushort> TestTypes;

// register the type list
TYPED_TEST_CASE(Regions, TestTypes);

template<typename T>
void regionsTest(string pTestFile, af_connectivity connectivity, bool isSubRef = false, const vector<af_seq> * seqv = NULL)
{
    if (noDoubleTests<T>()) return;

    vector<af::dim4> numDims;
    vector<vector<uchar> > in;
    vector<vector<T> > tests;
    readTests<uchar, T, unsigned>(pTestFile,numDims,in,tests);

    af::dim4 idims = numDims[0];

    af_array inArray = 0;
    af_array tempArray = 0;
    af_array outArray = 0;

    if (isSubRef) {
        ASSERT_EQ(AF_SUCCESS, af_create_array(&tempArray, &(in[0].front()), idims.ndims(), idims.get(), (af_dtype) af::dtype_traits<char>::af_type));

        ASSERT_EQ(AF_SUCCESS, af_index(&inArray, tempArray, seqv->size(), &seqv->front()));
    } else {
        ASSERT_EQ(AF_SUCCESS, af_create_array(&inArray, &(in[0].front()), idims.ndims(), idims.get(), (af_dtype) af::dtype_traits<char>::af_type));
    }

    ASSERT_EQ(AF_SUCCESS, af_regions(&outArray, inArray, connectivity, (af_dtype) af::dtype_traits<T>::af_type));

    // Get result
    T* outData = new T[idims.elements()];
    ASSERT_EQ(AF_SUCCESS, af_get_data_ptr((void*)outData, outArray));

    // Compare result
    for (size_t testIter = 0; testIter < tests.size(); ++testIter) {
        vector<T> currGoldBar = tests[testIter];
        size_t nElems = currGoldBar.size();
        for (size_t elIter = 0; elIter < nElems; ++elIter) {
            ASSERT_EQ(currGoldBar[elIter], outData[elIter]) << "at: " << elIter << std::endl;
        }
    }

    // Delete
    delete[] outData;

    if(inArray   != 0) af_release_array(inArray);
    if(outArray  != 0) af_release_array(outArray);
    if(tempArray != 0) af_release_array(tempArray);
}

#define REGIONS_INIT(desc, file, conn, conn_type)                                           \
    TYPED_TEST(Regions, desc)                                                               \
    {                                                                                \
        regionsTest<TypeParam>(string(TEST_DIR"/regions/"#file"_"#conn".test"), conn_type); \
    }

    REGIONS_INIT(Regions0, regions_8x8, 4, AF_CONNECTIVITY_4);
    REGIONS_INIT(Regions1, regions_8x8, 8, AF_CONNECTIVITY_8);
    REGIONS_INIT(Regions2, regions_128x128, 4, AF_CONNECTIVITY_4);
    REGIONS_INIT(Regions3, regions_128x128, 8, AF_CONNECTIVITY_8);

///////////////////////////////////// CPP ////////////////////////////////
//
TEST(Regions, CPP)
{
    if (noDoubleTests<float>()) return;

    vector<af::dim4> numDims;
    vector<vector<float> > in;
    vector<vector<float> > tests;
    readTests<float, float, unsigned>(string(TEST_DIR"/regions/regions_8x8_4.test"),numDims,in,tests);

    af::dim4 idims = numDims[0];
    af::array input(idims, (float*)&(in[0].front()));
    af::array output = af::regions(input.as(b8));

    // Get result
    float* outData = new float[idims.elements()];
    output.host((void*)outData);

    // Compare result
    for (size_t testIter = 0; testIter < tests.size(); ++testIter) {
        vector<float> currGoldBar = tests[testIter];
        size_t nElems = currGoldBar.size();
        for (size_t elIter = 0; elIter < nElems; ++elIter) {
            ASSERT_EQ(currGoldBar[elIter], outData[elIter]) << "at: " << elIter << std::endl;
        }
    }

    // Delete
    delete[] outData;
}

///////////////////////////////// Documentation Examples ///////////////////
TEST(Regions, Docs_8)
{
    // input data
    uchar input[64] =  {
        0, 0, 0, 0, 1, 0, 0, 0,
        0, 0, 1, 0, 1, 0, 0, 1,
        0, 0, 0, 1, 0, 0, 0, 0,
        0, 0, 1, 0, 0, 1, 0, 0,
        1, 0, 0, 1, 0, 0, 1, 0,
        0, 0, 0, 1, 1, 0, 0, 1,
        1, 1, 0, 0, 0, 0, 0, 0,
        0, 1, 0, 1, 1, 1, 1, 0
    };
    // gold output
    float gold[64] =  {
        0, 0, 0, 0, 1, 0, 0, 0,
        0, 0, 1, 0, 1, 0, 0, 2,
        0, 0, 0, 1, 0, 0, 0, 0,
        0, 0, 1, 0, 0, 3, 0, 0,
        4, 0, 0, 1, 0, 0, 3, 0,
        0, 0, 0, 1, 1, 0, 0, 3,
        5, 5, 0, 0, 0, 0, 0, 0,
        0, 5, 0, 6, 6, 6, 6, 0
    };

    //![ex_image_regions]
    af::array in(8, 8, input);
    //af_print(in);
    // in =
    // 0   0   0   0   1   0   1   0
    // 0   0   0   0   0   0   1   1
    // 0   1   0   1   0   0   0   0
    // 0   0   1   0   1   1   0   1
    // 1   1   0   0   0   1   0   1
    // 0   0   0   1   0   0   0   1
    // 0   0   0   0   1   0   0   1
    // 0   1   0   0   0   1   0   0

    // Compute the label matrix using 8-way connectivity
    af::array out = regions(in.as(b8), AF_CONNECTIVITY_8);
    //af_print(out);
    // 0   0   0   0   4   0   5   0
    // 0   0   0   0   0   0   5   5
    // 0   1   0   1   0   0   0   0
    // 0   0   1   0   1   1   0   6
    // 1   1   0   0   0   1   0   6
    // 0   0   0   3   0   0   0   6
    // 0   0   0   0   3   0   0   6
    // 0   2   0   0   0   3   0   0
    //![ex_image_regions]

    float output[64];
    out.host((void*)output);

    for (int i=0; i<64; ++i) {
        ASSERT_EQ(gold[i], output[i])<<" mismatch at i="<<i<<std::endl;
    }
}

TEST(Regions, Docs_4)
{
    // input data
    uchar input[64] =  {
        0, 0, 0, 0, 1, 0, 0, 0,
        0, 0, 1, 0, 1, 0, 0, 1,
        0, 0, 0, 1, 0, 0, 0, 0,
        0, 0, 1, 0, 0, 1, 0, 0,
        1, 0, 0, 1, 0, 0, 1, 0,
        0, 0, 0, 1, 1, 0, 0, 1,
        1, 1, 0, 0, 0, 0, 0, 0,
        0, 1, 0, 1, 1, 1, 1, 0
    };
    // gold output
    float gold[64] =  {
        0.0000,  0.0000,  0.0000,  0.0000,  1.0000,  0.0000,  0.0000,  0.0000,
        0.0000,  0.0000,  2.0000,  0.0000,  1.0000,  0.0000,  0.0000,  3.0000,
        0.0000,  0.0000,  0.0000,  4.0000,  0.0000,  0.0000,  0.0000,  0.0000,
        0.0000,  0.0000,  5.0000,  0.0000,  0.0000,  6.0000,  0.0000,  0.0000,
        7.0000,  0.0000,  0.0000,  8.0000,  0.0000,  0.0000,  9.0000,  0.0000,
        0.0000,  0.0000,  0.0000,  8.0000,  8.0000,  0.0000,  0.0000, 10.0000,
        11.000, 11.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,
        0.0000, 11.0000,  0.0000, 12.0000, 12.0000, 12.0000, 12.0000,  0.0000
    };

    //![ex_image_regions_4conn]
    af::array in(8, 8, input);
    //af_print(in.T());
    //in
    //0  0  0  0  1  0  1  0
    //0  0  0  0  0  0  1  1
    //0  1  0  1  0  0  0  0
    //0  0  1  0  1  1  0  1
    //1  1  0  0  0  1  0  1
    //0  0  0  1  0  0  0  1
    //0  0  0  0  1  0  0  1
    //0  1  0  0  0  1  0  0
    // Compute the label matrix using 4-way connectivity
    af::array out = regions(in.as(b8), AF_CONNECTIVITY_4);
    //af_print(out.T());
    //out
    //0  0  0  0  7  0 11  0
    //0  0  0  0  0  0 11 11
    //0  2  0  5  0  0  0  0
    //0  0  4  0  8  8  0 12
    //1  1  0  0  0  8  0 12
    //0  0  0  6  0  0  0 12
    //0  0  0  0  9  0  0 12
    //0  3  0  0  0 10  0  0
    //![ex_image_regions_4conn]

    float output[64];
    out.host((void*)output);

    for (int i=0; i<64; ++i) {
        ASSERT_EQ(gold[i], output[i])<<" mismatch at i="<<i<<std::endl;
    }
}

TEST(Regions, WholeImageComponent)
{
    const int dim = 101;
    const int sz  = dim*dim;
    std::vector<char> input(sz, 1);
    std::vector<float> gold(sz, 1.0f);

    af::array in  = af::array(dim, dim, input.data());
    af::array out = af::regions(in, AF_CONNECTIVITY_4);

    std::vector<float> output(sz);
    out.host((void*)output.data());

    for (int i=0; i<sz; ++i)
        ASSERT_FLOAT_EQ(gold[i], output[i])<<" mismatch at i="<<i<<std::endl;
}

TEST(Regions, NoComponentImage)
{
    const int dim = 101;
    const int sz  = dim*dim;
    std::vector<char> input(sz, 0);
    std::vector<float> gold(sz, 0.0f);

    af::array in  = af::array(dim, dim, input.data());
    af::array out = af::regions(in, AF_CONNECTIVITY_4);

    std::vector<float> output(sz);
    out.host((void*)output.data());

    for (int i=0; i<sz; ++i)
        ASSERT_FLOAT_EQ(gold[i], output[i])<<" mismatch at i="<<i<<std::endl;
}
<|endoftext|>


<commit_before>#include "common.th"
#include "spi.th"

    prologue

    b <- 0
    b -> [(SPI_BASE + 0x14)] // set divider
    c <- 1
    c -> [(SPI_BASE + 0x18)] // set SS to 1

    b <- rel(IDLE_COMMAND)
    call(put_spi)

wait_for_sd_ready:
    b <- rel(RESET_COMMAND)
    call(put_spi)
    c <- [(SPI_BASE + 0x0)] // read data
    c <- c & 1  // check bottom bit
    c <- c <> 0
    // if the bottom bit was one (busy), c will be true
    jnzrel(c,wait_for_sd_ready)

    illegal

put_spi:
    push(d)
    push(e)
    push(k)
    e <- [b + 1]
    e -> [(SPI_BASE + 0x0)] // bits 0 - 31
    e <- [b + 0]
    e -> [(SPI_BASE + 0x4)] // bits 32 - 47

    k <- (48 + 8) // message length +  response length

    //e <- e | (1 << 11) // LSB mode

    d <- 1
    d <- d << 13
    e <- k | d // ASS mode
    e -> [(SPI_BASE + 0x10)]

    // GO_BSY
    e <- e | (1 << 8)
    e -> [(SPI_BASE + 0x10)]

    d <- k # wait count
    loop:
    d <- d - 1
    e <- d <> 0
    jnzrel(e,loop)

    pop(k)
    pop(e)
    pop(d)

    ret

IDLE_COMMAND:
    /*      01  |cmd-|  |cmd-argument------    ------------------|  |CRC--| 1   |rsp ---| */
    .word 0b01__000000__0000_0000_0000_0000, 0b0000_0000_0000_0000__0000000_1___1111_1111

RESET_COMMAND:
    /*      01  |cmd-|  |cmd-argument------    ------------------|  |CRC--| 1   |rsp ---| */
    .word 0b01__000001__0000_0000_0000_0000, 0b0000_0000_0000_0000__0000000_1___1111_1111

<commit_msg>Cleanup, refactoring, encapsulation of spi test<commit_after>#include "common.th"
#include "spi.th"

    prologue

    b <- 0
    b -> [(SPI_BASE + 0x14)] // set divider
    c <- 1
    c -> [(SPI_BASE + 0x18)] // set SS to 1

    b <- rel(IDLE_COMMAND)
    call(put_spi)

wait_for_sd_ready:
    b <- rel(RESET_COMMAND)
    c <- 8 // number of bits expected in response
    call(put_spi)
    b <- b & 1  // check bottom bit
    b <- b <> 0
    // if the bottom bit was one (busy), b will be true
    jnzrel(b,wait_for_sd_ready)

    illegal

    .global put_spi
put_spi:
    // argument b is address of most significant word of two 32-bit words
    // containing 56 bits (48 command bits + 8 response bits)
    // argument c is number of bits expected as response
    // result b is response word
    push(d)
    push(e)
    push(k)

    e <- [b + 1]
    e -> [(SPI_BASE + 0x0)] // bits 0 - 31
    e <- [b + 0]
    e -> [(SPI_BASE + 0x4)] // bits 32 - 56

    k <- (48 + 8) // message length + response length

    d <- 1
    d <- d << 13
    e <- k | d // ASS mode
    e -> [(SPI_BASE + 0x10)]

    // GO_BSY
    e <- e | (1 << 8)
    e -> [(SPI_BASE + 0x10)]

    d <- k # wait count
L_put_spi_clock_wait:
    d <- d - 1
    e <- d <> 0
    jnzrel(e,L_put_spi_clock_wait)

    b <- [(SPI_BASE + 0x0)] // read data
    // chop upper bits
    d <- -1
    d <- d << 8
    d <- ~ d
    b <- b & d

    pop(k)
    pop(e)
    pop(d)

    ret

IDLE_COMMAND:
    /*      01  |cmd-|  |cmd-argument------    ------------------|  |CRC--| 1   |rsp ---| */
    .word 0b01__000000__0000_0000_0000_0000, 0b0000_0000_0000_0000__0000000_1___1111_1111

RESET_COMMAND:
    /*      01  |cmd-|  |cmd-argument------    ------------------|  |CRC--| 1   |rsp ---| */
    .word 0b01__000001__0000_0000_0000_0000, 0b0000_0000_0000_0000__0000000_1___1111_1111

<|endoftext|>


<commit_before>#include <cassert>
#include <iostream>
#include <list>

#include <pqxx/pqxx>

#include <pqxx/compiler-internal.hxx>

using namespace PGSTD;
using namespace pqxx;

namespace
{
#ifndef PQXX_HAVE_DISTANCE
template<typename ITERATOR> size_t distance(ITERATOR begin, ITERATOR end)
{
  size_t d = 0;
  while (begin != end)
  {
    ++begin;
    ++d;
  }
  return d;
}
#endif // PQXX_HAVE_DISTANCE

void compare_results(string name, result lhs, result rhs)
{
  if (lhs != rhs)
    throw logic_error("Executing " + name + " as prepared statement "
	  "yields different results from direct execution");

  if (lhs.empty())
    throw logic_error("Results being compared are empty.  Not much point!");
}

string stringize(transaction_base &t, const string &arg)
{
  return "'" + t.esc(arg) + "'";
}
string stringize(transaction_base &t, const char arg[])
{
  return arg ? stringize(t,string(arg)) : "null";
}
string stringize(transaction_base &t, char arg[])
{
  return arg ? stringize(t, string(arg)) : "null";
}
template<typename T> string stringize(transaction_base &t, T i)
{
  return stringize(t, to_string(i));
}

// Substitute variables in raw query.  This is not likely to be very robust,
// but it should do for just this test.  The main shortcomings are escaping,
// and not knowing when to quote the variables.
// Note we do the replacement backwards (meaning forward_only iterators won't
// do!) to avoid substituting e.g. "$12" as "$1" first.
template<typename ITER> string subst(transaction_base &t,
	string q,
	ITER patbegin,
	ITER patend)
{
  int i = distance(patbegin, patend);
  for (ITER arg = patend; i > 0; --i)
  {
   --arg;
    const string marker = "$" + to_string(i),
	  var = stringize(t, *arg);
    const string::size_type msz = marker.size();
    while (q.find(marker) != string::npos) q.replace(q.find(marker),msz,var);
  }
  return q;
}

template<typename CNTNR> string subst(transaction_base &t,
	string q,
	const CNTNR &patterns)
{
  return subst(t, q, patterns.begin(), patterns.end());
}

} // namespace

// Test program for libpqxx.  Define and use prepared statements.
//
// Usage: test085
int main()
{
  try
  {
    /* A bit of nastiness in prepared statements: on 7.3.x backends we can't
     * compare pg_tables.tablename to a string.  We work around this by using
     * the LIKE operator.
     *
     * Later backend versions do not suffer from this problem.
     */
    const string QN_readpgtables = "ReadPGTables",
	  Q_readpgtables = "SELECT * FROM pg_tables",
	  QN_seetable = "SeeTable",
	  Q_seetable = Q_readpgtables + " WHERE tablename LIKE $1",
	  QN_seetables = "SeeTables",
	  Q_seetables = Q_seetable + " OR tablename LIKE $2";

    lazyconnection C;

    cout << "Preparing a simple statement..." << endl;
    C.prepare(QN_readpgtables, Q_readpgtables);
    nontransaction T(C, "test85");

    try
    {
      // See if a basic prepared statement works just like a regular query
      cout << "Basic correctness check on prepared statement..." << endl;
      compare_results(QN_readpgtables,
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));
    }
    catch (const exception &)
    {
      if (!C.supports(connection_base::cap_prepared_statements))
      {
        cout << "Backend version does not support prepared statements.  "
	        "Skipping."
	     << endl;
	return 0;
      }
      throw;
    }

    // Try prepare_now() on an already prepared statement
    C.prepare_now(QN_readpgtables);

    // Pro forma check: same thing but with name passed as C-style string
    compare_results(QN_readpgtables+"_char",
	T.prepared(QN_readpgtables.c_str()).exec(),
	T.exec(Q_readpgtables));

    cout << "Dropping prepared statement..." << endl;
    C.unprepare(QN_readpgtables);

    bool failed = true;
    try
    {
      disable_noticer d(C);
      C.prepare_now(QN_readpgtables);
      failed = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failed)
      throw runtime_error("prepare_now() succeeded on dropped statement");

    // Just to try and confuse things, "unprepare" twice
    cout << "Testing error detection and handling..." << endl;
    try { C.unprepare(QN_readpgtables); }
    catch (const exception &e) { cout << "(Expected) " << e.what() << endl; }

    // Verify that attempt to execute unprepared statement fails
    bool failsOK = true;
    try { T.prepared(QN_readpgtables).exec(); failsOK = false; }
    catch (const exception &e) { cout << "(Expected) " << e.what() << endl; }
    if (!failsOK) throw logic_error("Execute unprepared statement didn't fail");

    // Re-prepare the same statement and test again
    C.prepare(QN_readpgtables, Q_readpgtables);
    C.prepare_now(QN_readpgtables);
    compare_results(QN_readpgtables+"_2",
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));

    // Double preparation of identical statement should be ignored...
    C.prepare(QN_readpgtables, Q_readpgtables);
    compare_results(QN_readpgtables+"_double",
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));

    // ...But a modified definition shouldn't
    try
    {
      failsOK = true;
      C.prepare(QN_readpgtables, Q_readpgtables + " ORDER BY tablename");
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("Bad redefinition of statement went unnoticed");

    cout << "Testing prepared statement with parameter..." << endl;

    C.prepare(QN_seetable, Q_seetable)("varchar", pqxx::prepare::treat_string);

    vector<string> args;
    args.push_back("pg_type");
    compare_results(QN_seetable+"_seq",
	T.prepared(QN_seetable)(args[0]).exec(),
	T.exec(subst(T,Q_seetable,args)));

    cout << "Testing prepared statement with 2 parameters..." << endl;

    C.prepare(QN_seetables, Q_seetables)
      ("varchar",pqxx::prepare::treat_string)
      ("varchar",pqxx::prepare::treat_string);
    args.push_back("pg_index");
    compare_results(QN_seetables+"_seq",
      T.prepared(QN_seetables)(args[0])(args[1]).exec(),
      T.exec(subst(T,Q_seetables,args)));

    cout << "Testing prepared statement with a null parameter..." << endl;
    vector<const char *> ptrs;
    ptrs.push_back(0);
    ptrs.push_back("pg_index");
    compare_results(QN_seetables+"_null1",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.exec(subst(T,Q_seetables,ptrs)));
    compare_results(QN_seetables+"_null2",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)()(ptrs[1]).exec());
    compare_results(QN_seetables+"_null3",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)("somestring",false)(ptrs[1]).exec());
    compare_results(QN_seetables+"_null4",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)(42,false)(ptrs[1]).exec());
    compare_results(QN_seetables+"_null5",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)(0,false)(ptrs[1]).exec());

    cout << "Testing wrong numbers of parameters..." << endl;
    try
    {
      failsOK = true;
      T.prepared(QN_seetables)()()("hi mom!").exec();
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("No error for too many parameters");
    try
    {
      failsOK = true;
      T.prepared(QN_seetables)("who, me?").exec();
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("No error for too few parameters");

    cout << "Done." << endl;
  }
  catch (const feature_not_supported &e)
  {
    cout << "Backend version does not support prepared statements.  Skipping."
         << endl;
    return 0;
  }
  catch (const sql_error &e)
  {
    cerr << "SQL error: " << e.what() << endl
         << "Query was: " << e.query() << endl;
    return 1;
  }
  catch (const exception &e)
  {
    // All exceptions thrown by libpqxx are derived from std::exception
    cerr << "Exception: " << e.what() << endl;
    return 2;
  }
  catch (...)
  {
    // This is really unexpected (see above)
    cerr << "Unhandled exception" << endl;
    return 100;
  }

  return 0;
}

<commit_msg>Put compiler-internal include in a better place.<commit_after>#include <cassert>
#include <iostream>
#include <list>

#include <pqxx/compiler-internal.hxx>

#include <pqxx/pqxx>

using namespace PGSTD;
using namespace pqxx;

namespace
{
#ifndef PQXX_HAVE_DISTANCE
template<typename ITERATOR> size_t distance(ITERATOR begin, ITERATOR end)
{
  size_t d = 0;
  while (begin != end)
  {
    ++begin;
    ++d;
  }
  return d;
}
#endif // PQXX_HAVE_DISTANCE

void compare_results(string name, result lhs, result rhs)
{
  if (lhs != rhs)
    throw logic_error("Executing " + name + " as prepared statement "
	  "yields different results from direct execution");

  if (lhs.empty())
    throw logic_error("Results being compared are empty.  Not much point!");
}

string stringize(transaction_base &t, const string &arg)
{
  return "'" + t.esc(arg) + "'";
}
string stringize(transaction_base &t, const char arg[])
{
  return arg ? stringize(t,string(arg)) : "null";
}
string stringize(transaction_base &t, char arg[])
{
  return arg ? stringize(t, string(arg)) : "null";
}
template<typename T> string stringize(transaction_base &t, T i)
{
  return stringize(t, to_string(i));
}

// Substitute variables in raw query.  This is not likely to be very robust,
// but it should do for just this test.  The main shortcomings are escaping,
// and not knowing when to quote the variables.
// Note we do the replacement backwards (meaning forward_only iterators won't
// do!) to avoid substituting e.g. "$12" as "$1" first.
template<typename ITER> string subst(transaction_base &t,
	string q,
	ITER patbegin,
	ITER patend)
{
  int i = distance(patbegin, patend);
  for (ITER arg = patend; i > 0; --i)
  {
   --arg;
    const string marker = "$" + to_string(i),
	  var = stringize(t, *arg);
    const string::size_type msz = marker.size();
    while (q.find(marker) != string::npos) q.replace(q.find(marker),msz,var);
  }
  return q;
}

template<typename CNTNR> string subst(transaction_base &t,
	string q,
	const CNTNR &patterns)
{
  return subst(t, q, patterns.begin(), patterns.end());
}

} // namespace

// Test program for libpqxx.  Define and use prepared statements.
//
// Usage: test085
int main()
{
  try
  {
    /* A bit of nastiness in prepared statements: on 7.3.x backends we can't
     * compare pg_tables.tablename to a string.  We work around this by using
     * the LIKE operator.
     *
     * Later backend versions do not suffer from this problem.
     */
    const string QN_readpgtables = "ReadPGTables",
	  Q_readpgtables = "SELECT * FROM pg_tables",
	  QN_seetable = "SeeTable",
	  Q_seetable = Q_readpgtables + " WHERE tablename LIKE $1",
	  QN_seetables = "SeeTables",
	  Q_seetables = Q_seetable + " OR tablename LIKE $2";

    lazyconnection C;

    cout << "Preparing a simple statement..." << endl;
    C.prepare(QN_readpgtables, Q_readpgtables);
    nontransaction T(C, "test85");

    try
    {
      // See if a basic prepared statement works just like a regular query
      cout << "Basic correctness check on prepared statement..." << endl;
      compare_results(QN_readpgtables,
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));
    }
    catch (const exception &)
    {
      if (!C.supports(connection_base::cap_prepared_statements))
      {
        cout << "Backend version does not support prepared statements.  "
	        "Skipping."
	     << endl;
	return 0;
      }
      throw;
    }

    // Try prepare_now() on an already prepared statement
    C.prepare_now(QN_readpgtables);

    // Pro forma check: same thing but with name passed as C-style string
    compare_results(QN_readpgtables+"_char",
	T.prepared(QN_readpgtables.c_str()).exec(),
	T.exec(Q_readpgtables));

    cout << "Dropping prepared statement..." << endl;
    C.unprepare(QN_readpgtables);

    bool failed = true;
    try
    {
      disable_noticer d(C);
      C.prepare_now(QN_readpgtables);
      failed = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failed)
      throw runtime_error("prepare_now() succeeded on dropped statement");

    // Just to try and confuse things, "unprepare" twice
    cout << "Testing error detection and handling..." << endl;
    try { C.unprepare(QN_readpgtables); }
    catch (const exception &e) { cout << "(Expected) " << e.what() << endl; }

    // Verify that attempt to execute unprepared statement fails
    bool failsOK = true;
    try { T.prepared(QN_readpgtables).exec(); failsOK = false; }
    catch (const exception &e) { cout << "(Expected) " << e.what() << endl; }
    if (!failsOK) throw logic_error("Execute unprepared statement didn't fail");

    // Re-prepare the same statement and test again
    C.prepare(QN_readpgtables, Q_readpgtables);
    C.prepare_now(QN_readpgtables);
    compare_results(QN_readpgtables+"_2",
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));

    // Double preparation of identical statement should be ignored...
    C.prepare(QN_readpgtables, Q_readpgtables);
    compare_results(QN_readpgtables+"_double",
	T.prepared(QN_readpgtables).exec(),
	T.exec(Q_readpgtables));

    // ...But a modified definition shouldn't
    try
    {
      failsOK = true;
      C.prepare(QN_readpgtables, Q_readpgtables + " ORDER BY tablename");
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("Bad redefinition of statement went unnoticed");

    cout << "Testing prepared statement with parameter..." << endl;

    C.prepare(QN_seetable, Q_seetable)("varchar", pqxx::prepare::treat_string);

    vector<string> args;
    args.push_back("pg_type");
    compare_results(QN_seetable+"_seq",
	T.prepared(QN_seetable)(args[0]).exec(),
	T.exec(subst(T,Q_seetable,args)));

    cout << "Testing prepared statement with 2 parameters..." << endl;

    C.prepare(QN_seetables, Q_seetables)
      ("varchar",pqxx::prepare::treat_string)
      ("varchar",pqxx::prepare::treat_string);
    args.push_back("pg_index");
    compare_results(QN_seetables+"_seq",
      T.prepared(QN_seetables)(args[0])(args[1]).exec(),
      T.exec(subst(T,Q_seetables,args)));

    cout << "Testing prepared statement with a null parameter..." << endl;
    vector<const char *> ptrs;
    ptrs.push_back(0);
    ptrs.push_back("pg_index");
    compare_results(QN_seetables+"_null1",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.exec(subst(T,Q_seetables,ptrs)));
    compare_results(QN_seetables+"_null2",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)()(ptrs[1]).exec());
    compare_results(QN_seetables+"_null3",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)("somestring",false)(ptrs[1]).exec());
    compare_results(QN_seetables+"_null4",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)(42,false)(ptrs[1]).exec());
    compare_results(QN_seetables+"_null5",
	T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(),
	T.prepared(QN_seetables)(0,false)(ptrs[1]).exec());

    cout << "Testing wrong numbers of parameters..." << endl;
    try
    {
      failsOK = true;
      T.prepared(QN_seetables)()()("hi mom!").exec();
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("No error for too many parameters");
    try
    {
      failsOK = true;
      T.prepared(QN_seetables)("who, me?").exec();
      failsOK = false;
    }
    catch (const exception &e)
    {
      cout << "(Expected) " << e.what() << endl;
    }
    if (!failsOK)
      throw logic_error("No error for too few parameters");

    cout << "Done." << endl;
  }
  catch (const feature_not_supported &e)
  {
    cout << "Backend version does not support prepared statements.  Skipping."
         << endl;
    return 0;
  }
  catch (const sql_error &e)
  {
    cerr << "SQL error: " << e.what() << endl
         << "Query was: " << e.query() << endl;
    return 1;
  }
  catch (const exception &e)
  {
    // All exceptions thrown by libpqxx are derived from std::exception
    cerr << "Exception: " << e.what() << endl;
    return 2;
  }
  catch (...)
  {
    // This is really unexpected (see above)
    cerr << "Unhandled exception" << endl;
    return 100;
  }

  return 0;
}

<|endoftext|>


<commit_before>#include <cstdio>
#include <cstdlib>

#include <algorithm>
#include <map>
#include <memory>

#include "dashmm.h"

constexpr int source_test_count = 10000;
constexpr int target_test_count = 10000;

struct UserSourceData {
  double pos[3];
  double mass;
};

struct UserTargetData {
  double pos[3];
  double phi[2];    //real, imag
  double phi_direct[2];
};

void perform_the_big_test() {
  //create some arrays
  UserSourceData *sources = static_cast<UserSourceData *>(
        malloc(sizeof(UserSourceData) * source_test_count));
  UserTargetData *targets = static_cast<UserTargetData *>(
        malloc(sizeof(UserTargetData) * target_test_count));
  srand(12345);
  for (int i = 0; i < source_test_count; ++i) {
    sources[i].pos[0] = (double)rand() / RAND_MAX;
    sources[i].pos[1] = (double)rand() / RAND_MAX;
    sources[i].pos[2] = (double)rand() / RAND_MAX;
    sources[i].mass = (double)rand() / RAND_MAX + 1.0;
  }
  for (int i = 0; i < target_test_count; ++i) {
    targets[i].pos[0] = (double)rand() / RAND_MAX;
    targets[i].pos[1] = (double)rand() / RAND_MAX;
    targets[i].pos[2] = (double)rand() / RAND_MAX;
    targets[i].phi[0] = 0.0;
    targets[i].phi[1] = 0.0;
    targets[i].phi_direct[0] = 0.0;
    targets[i].phi_direct[1] = 0.0;
  }

  //prep sources
  dashmm::ObjectHandle source_handle;
  auto err = dashmm::allocate_array(source_test_count, sizeof(UserSourceData),
                            &source_handle);
  assert(err == dashmm::kSuccess);
  err = dashmm::array_put(source_handle, 0, source_test_count, sources);
  assert(err == dashmm::kSuccess);

  //prep targets
  dashmm::ObjectHandle target_handle;
  err = dashmm::allocate_array(target_test_count, sizeof(UserTargetData),
                               &target_handle);
  assert(err == dashmm::kSuccess);
  err = dashmm::array_put(target_handle, 0, target_test_count, targets);
  assert(err == dashmm::kSuccess);

  //get method and expansion
  auto bhmethod = dashmm::bh_method(0.6);
  assert(bhmethod != nullptr);
  auto lapcomexp = dashmm::laplace_COM_expansion();
  assert(lapcomexp != nullptr);

  //evaluate
  //TODO: Is it weird that evaluate eats the method and expansion?
  //*
  err = dashmm::evaluate(source_handle, offsetof(UserSourceData, pos),
                         offsetof(UserSourceData, mass),
                         target_handle, offsetof(UserTargetData, pos),
                         offsetof(UserTargetData, phi),
                         40,
                         std::unique_ptr<dashmm::Method>{bhmethod},
                         std::unique_ptr<dashmm::Expansion>{lapcomexp});
  //*/

  //*
  auto direct = dashmm::bh_method(0.0001);
  auto direxp = dashmm::laplace_COM_expansion();
  err = dashmm::evaluate(source_handle, offsetof(UserSourceData, pos),
                         offsetof(UserSourceData, mass),
                         target_handle, offsetof(UserTargetData, pos),
                         offsetof(UserTargetData, phi_direct),
                         40,
                         std::unique_ptr<dashmm::Method>{direct},
                         std::unique_ptr<dashmm::Expansion>{direxp});
  //*/

  //get targets
  err = dashmm::array_get(target_handle, 0, target_test_count, targets);
  assert(err == dashmm::kSuccess);
  //TODO: check that the data comes out
  for (int i = 0; i < target_test_count; ++i) {
    fprintf(stdout, "%d: %lg %lg %lg\n", i,
        targets[i].phi[0], targets[i].phi_direct[0],
        fabs(targets[i].phi[0] - targets[i].phi_direct[0])
                / targets[i].phi_direct[0]);
  }

  //free up stuff
  err = dashmm::deallocate_array(source_handle);
  assert(err == dashmm::kSuccess);
  err = dashmm::deallocate_array(target_handle);
  assert(err == dashmm::kSuccess);

  free(sources);
  free(targets);
}

int main(int argc, char **argv) {
  int perform_other_tests = 0;

  auto err = dashmm::init(&argc, &argv);
  if (err == dashmm::kInitError) {
    fprintf(stderr, "dashmm::init gave an error!\n");
  } else if (err == dashmm::kRuntimeError) {
    fprintf(stderr, "dashmm::init had trouble starting runtime\n");
  } else if (err != dashmm::kSuccess) {
    fprintf(stderr, "Woah! init() gave an unknown error\n");
  }

  perform_the_big_test();

  err = dashmm::finalize();
  if (err == dashmm::kFiniError) {
    fprintf(stderr, "dashmm::finalize gave an error\n");
  } else if (err != dashmm::kSuccess) {
    fprintf(stderr, "Woah! finalize() gave an unknown error\n");
  }

  return 0;
}
<commit_msg>Removed vestigial code from test.<commit_after>#include <cstdio>
#include <cstdlib>

#include <algorithm>
#include <map>
#include <memory>

#include "dashmm.h"

constexpr int source_test_count = 10000;
constexpr int target_test_count = 10000;

struct UserSourceData {
  double pos[3];
  double mass;
};

struct UserTargetData {
  double pos[3];
  double phi[2];    //real, imag
  double phi_direct[2];
};

void perform_the_big_test() {
  //create some arrays
  UserSourceData *sources = static_cast<UserSourceData *>(
        malloc(sizeof(UserSourceData) * source_test_count));
  UserTargetData *targets = static_cast<UserTargetData *>(
        malloc(sizeof(UserTargetData) * target_test_count));
  srand(12345);
  for (int i = 0; i < source_test_count; ++i) {
    sources[i].pos[0] = (double)rand() / RAND_MAX;
    sources[i].pos[1] = (double)rand() / RAND_MAX;
    sources[i].pos[2] = (double)rand() / RAND_MAX;
    sources[i].mass = (double)rand() / RAND_MAX + 1.0;
  }
  for (int i = 0; i < target_test_count; ++i) {
    targets[i].pos[0] = (double)rand() / RAND_MAX;
    targets[i].pos[1] = (double)rand() / RAND_MAX;
    targets[i].pos[2] = (double)rand() / RAND_MAX;
    targets[i].phi[0] = 0.0;
    targets[i].phi[1] = 0.0;
    targets[i].phi_direct[0] = 0.0;
    targets[i].phi_direct[1] = 0.0;
  }

  //prep sources
  dashmm::ObjectHandle source_handle;
  auto err = dashmm::allocate_array(source_test_count, sizeof(UserSourceData),
                            &source_handle);
  assert(err == dashmm::kSuccess);
  err = dashmm::array_put(source_handle, 0, source_test_count, sources);
  assert(err == dashmm::kSuccess);

  //prep targets
  dashmm::ObjectHandle target_handle;
  err = dashmm::allocate_array(target_test_count, sizeof(UserTargetData),
                               &target_handle);
  assert(err == dashmm::kSuccess);
  err = dashmm::array_put(target_handle, 0, target_test_count, targets);
  assert(err == dashmm::kSuccess);

  //get method and expansion
  auto bhmethod = dashmm::bh_method(0.6);
  assert(bhmethod != nullptr);
  auto lapcomexp = dashmm::laplace_COM_expansion();
  assert(lapcomexp != nullptr);

  //evaluate
  //TODO: Is it weird that evaluate eats the method and expansion?
  //*
  err = dashmm::evaluate(source_handle, offsetof(UserSourceData, pos),
                         offsetof(UserSourceData, mass),
                         target_handle, offsetof(UserTargetData, pos),
                         offsetof(UserTargetData, phi),
                         40,
                         std::unique_ptr<dashmm::Method>{bhmethod},
                         std::unique_ptr<dashmm::Expansion>{lapcomexp});
  //*/

  //*
  auto direct = dashmm::bh_method(0.0001);
  auto direxp = dashmm::laplace_COM_expansion();
  err = dashmm::evaluate(source_handle, offsetof(UserSourceData, pos),
                         offsetof(UserSourceData, mass),
                         target_handle, offsetof(UserTargetData, pos),
                         offsetof(UserTargetData, phi_direct),
                         40,
                         std::unique_ptr<dashmm::Method>{direct},
                         std::unique_ptr<dashmm::Expansion>{direxp});
  //*/

  //get targets
  err = dashmm::array_get(target_handle, 0, target_test_count, targets);
  assert(err == dashmm::kSuccess);
  //TODO: check that the data comes out
  for (int i = 0; i < target_test_count; ++i) {
    fprintf(stdout, "%d: %lg %lg %lg\n", i,
        targets[i].phi[0], targets[i].phi_direct[0],
        fabs(targets[i].phi[0] - targets[i].phi_direct[0])
                / targets[i].phi_direct[0]);
  }

  //free up stuff
  err = dashmm::deallocate_array(source_handle);
  assert(err == dashmm::kSuccess);
  err = dashmm::deallocate_array(target_handle);
  assert(err == dashmm::kSuccess);

  free(sources);
  free(targets);
}

int main(int argc, char **argv) {
  auto err = dashmm::init(&argc, &argv);
  if (err == dashmm::kInitError) {
    fprintf(stderr, "dashmm::init gave an error!\n");
  } else if (err == dashmm::kRuntimeError) {
    fprintf(stderr, "dashmm::init had trouble starting runtime\n");
  } else if (err != dashmm::kSuccess) {
    fprintf(stderr, "Woah! init() gave an unknown error\n");
  }

  perform_the_big_test();

  err = dashmm::finalize();
  if (err == dashmm::kFiniError) {
    fprintf(stderr, "dashmm::finalize gave an error\n");
  } else if (err != dashmm::kSuccess) {
    fprintf(stderr, "Woah! finalize() gave an unknown error\n");
  }

  return 0;
}
<|endoftext|>


<commit_before>#include "data-general.hpp"
#include "data-course.hpp"
#include "data-major.hpp"
#include "data-student.hpp"
using namespace std;

vector<Course> all_courses;

void loadCourses() {
	ifstream infile("data/2012-13-s2-csv.csv");
	string str; // read in the header line
	getline(infile, str);
	while (infile.peek() != -1){
		Course incourse(infile);
		all_courses.push_back(incourse);
		// cout << incourse << endl;
	}
}

void whatDidICallThisWith(int argc, const char *argv[]) {
	int count;

	printf ("This program was called with \"%s\".\n",argv[0]);

	if (argc > 1) {
		for (count = 1; count < argc; count++) {
			printf("argv[%d] = %s\n", count, argv[count]);
		}
	}
	else {
		printf("The command had no other arguments.\n");
	}
}

void welcome() {
	cout << "Welcome!" << endl;
	cout << "What is your name?";
	// cin
}

int main(int argc, const char *argv[]) {
	loadCourses();
	Course c = getCourse("CSCI 251");
	cout << c << endl;
	// if (argc == 2)
	// 	Student person(argv[1]);
	// else
	// 	Student person("data/user.json");

	return 0;
}
<commit_msg>Add more tests to test-data.cpp<commit_after>#include "data-general.hpp"
#include "data-course.hpp"
#include "data-major.hpp"
#include "data-student.hpp"
using namespace std;

vector<Course> all_courses;
Student user;

void loadCourses() {
	ifstream infile("data/2012-13-s2-csv.csv");
	string str; // read in the header line
	getline(infile, str);
	while (infile.peek() != -1){
		Course incourse(infile);
		all_courses.push_back(incourse);
		// cout << incourse << endl;
	}
}

void whatDidICallThisWith(int argc, const char *argv[]) {
	int count;

	printf ("This program was called with \"%s\".\n",argv[0]);

	if (argc > 1) {
		for (count = 1; count < argc; count++) {
			printf("argv[%d] = %s\n", count, argv[count]);
		}
	}
	else {
		printf("The command had no other arguments.\n");
	}
}

void welcome() {
	string name, yearS, yearE, majors;
	// cout << "Welcome!" << endl;
	// cout << "What is your name? ";
	// getline(cin, name);
	name = "Xandra Best";
	// cout << "What year do you graduate? ";
	// cin >> yearE;
	// cout << "What are your majors (ex. CSCI, ASIAN) ";
	// getline(cin, majors);
	majors = "CSCI, STAT, ASIAN";
	user = Student(name, "", "", majors);
}

void getCourses() {
	string courses;
	// cout << "What are some courses that you have taken? (ex. CSCI125, STAT 110)" << endl;
	// cout << "> ";
	// getline(cin, courses);
	courses = "CSCI 215, stat 110, THEAT398, writ211";
	user.addCourses(courses);
}

int main(int argc, const char *argv[]) {
	loadCourses();
	// Course c("BIO 126");
	// cout << c << endl;
	welcome();
	getCourses();
	cout << user << endl;
	// if (argc == 2)
	// 	Student person(argv[1]);
	// else
	// 	Student person("data/user.json");

	return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "server.hh"
#include "handler.hh"
#include <seastar/core/future-util.hh>
#include <seastar/core/circular_buffer.hh>
#include <seastar/core/metrics.hh>
#include <seastar/net/byteorder.hh>
#include <seastar/core/scattered_message.hh>
#include <seastar/core/sleep.hh>
#include <seastar/core/coroutine.hh>
#include <seastar/core/semaphore.hh>
#include "log.hh"
#include <thrift/server/TServer.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/TProcessor.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/async/TAsyncProcessor.h>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <queue>
#include <bitset>
#include <limits>
#include <cctype>
#include <vector>

#ifdef THRIFT_USES_BOOST
#include <boost/make_shared.hpp>
#endif

static logging::logger tlogger("thrift");

using namespace apache::thrift;
using namespace apache::thrift::transport;
using namespace apache::thrift::protocol;
using namespace apache::thrift::async;
using namespace ::cassandra;

using namespace std::chrono_literals;

class thrift_stats {
    seastar::metrics::metric_groups _metrics;
public:
    thrift_stats(thrift_server& server);
};

thrift_server::thrift_server(distributed<database>& db,
                             distributed<cql3::query_processor>& qp,
                             auth::service& auth_service,
                             service::memory_limiter& ml,
                             thrift_server_config config)
        : _stats(new thrift_stats(*this))
        , _handler_factory(create_handler_factory(db, qp, auth_service, config.timeout_config, _current_permit).release())
        , _protocol_factory(new TBinaryProtocolFactoryT<TMemoryBuffer>())
        , _processor_factory(new CassandraAsyncProcessorFactory(_handler_factory))
        , _memory_available(ml.get_semaphore())
        , _config(config) {
}

thrift_server::~thrift_server() {
}

future<> thrift_server::stop() {
    auto f = _stop_gate.close();
    std::for_each(_listeners.begin(), _listeners.end(), std::mem_fn(&server_socket::abort_accept));
    std::for_each(_connections_list.begin(), _connections_list.end(), std::mem_fn(&connection::shutdown));
    return f;
}

struct handler_deleter {
    CassandraCobSvIfFactory* hf;
    void operator()(CassandraCobSvIf* h) const {
        hf->releaseHandler(h);
    }
};

// thrift uses a shared_ptr to refer to the transport (= connection),
// while we do not, so we can't have connection inherit from TTransport.
struct thrift_server::connection::fake_transport : TTransport {
    fake_transport(thrift_server::connection* c) : conn(c) {}
    thrift_server::connection* conn;
};

thrift_server::connection::connection(thrift_server& server, connected_socket&& fd, socket_address addr)
        : _server(server), _fd(std::move(fd)), _read_buf(_fd.input())
        , _write_buf(_fd.output())
        , _transport(thrift_std::make_shared<thrift_server::connection::fake_transport>(this))
        , _input(thrift_std::make_shared<TMemoryBuffer>())
        , _output(thrift_std::make_shared<TMemoryBuffer>())
        , _in_proto(_server._protocol_factory->getProtocol(_input))
        , _out_proto(_server._protocol_factory->getProtocol(_output))
        , _processor(_server._processor_factory->getProcessor({ _in_proto, _out_proto, _transport })) {
    ++_server._total_connections;
    ++_server._current_connections;
    _server._connections_list.push_back(*this);
}

thrift_server::connection::~connection() {
    if (is_linked()) {
        --_server._current_connections;
        _server._connections_list.erase(_server._connections_list.iterator_to(*this));
    }
}

thrift_server::connection::connection(connection&& other)
        : _server(other._server)
        , _fd(std::move(other._fd))
        , _read_buf(std::move(other._read_buf))
        , _write_buf(std::move(other._write_buf))
        , _transport(std::move(other._transport))
        , _input(std::move(other._input))
        , _output(std::move(other._output))
        , _in_proto(std::move(other._in_proto))
        , _out_proto(std::move(other._out_proto))
        , _processor(std::move(other._processor)) {
    if (other.is_linked()) {
        boost::intrusive::list<connection>::node_algorithms::init(this_ptr());
        boost::intrusive::list<connection>::node_algorithms::swap_nodes(other.this_ptr(), this_ptr());
    }
}

future<>
thrift_server::connection::process() {
    return do_until([this] { return _read_buf.eof(); },
            [this] { return process_one_request(); })
        .finally([this] {
            return _write_buf.close();
        });
}

future<>
thrift_server::connection::process_one_request() {
    _input->resetBuffer();
    _output->resetBuffer();
    co_await read();
    ++_server._requests_serving;
    ++_server._requests_served;
    auto ret = _processor_promise.get_future().handle_exception([&server = _server] (const std::exception_ptr&) {
        server._requests_serving--;
    });
    // adapt from "continuation object style" to future/promise
    auto complete = [this] (bool success) mutable {
        // FIXME: look at success?
        _server._requests_serving--;
        write().forward_to(std::move(_processor_promise));
        _processor_promise = promise<>();
    };
    // Heuristics copied from transport/server.cc
    size_t mem_estimate = 8000 + 2 * _input->available_read();
    auto fut = get_units(_server._memory_available, mem_estimate);
    if (_server._memory_available.waiters()) {
        ++_server._requests_blocked_memory;
    }
    auto units = co_await std::move(fut);
    // NOTICE: this permit is put in the server under the assumption that no other
    // connection will overwrite this permit *until* it's extracted by the code
    // which handles the Thrift request (via calling obtain_permit()).
    // This assumption is true because there are no preemption points between this
    // insertion and the call to obtain_permit(), which was verified both by
    // code inspection and confirmed empirically by running manual tests.
    if (_server._current_permit.count() > 0) {
        tlogger.debug("Current service permit is overwritten while its units are still held ({}). "
                "This situation likely means that there's a bug in passing service permits to message handlers.",
                _server._current_permit.count());
    }
    _server._current_permit = make_service_permit(std::move(units));
    _processor->process(complete, _in_proto, _out_proto);
    co_return co_await std::move(ret);
}

future<>
thrift_server::connection::read() {
    return _read_buf.read_exactly(4).then([this] (temporary_buffer<char> size_buf) {
        if (size_buf.size() != 4) {
            return make_ready_future<>();
        }
        union {
            uint32_t n;
            char b[4];
        } data;
        std::copy_n(size_buf.get(), 4, data.b);
        auto n = ntohl(data.n);
        if (n > _server._config.max_request_size) {
            // Close connection silently, we can't return a response because we did not
            // read a complete frame.
            tlogger.info("message size {} exceeds configured maximum {}, closing connection", n, _server._config.max_request_size);
            return make_ready_future<>();
        }
        return _read_buf.read_exactly(n).then([this, n] (temporary_buffer<char> buf) {
            if (buf.size() != n) {
                // FIXME: exception perhaps?
                return;
            }
            _in_tmp = std::move(buf); // keep ownership of the data
            auto b = reinterpret_cast<uint8_t*>(_in_tmp.get_write());
            _input->resetBuffer(b, _in_tmp.size());
        });
    });
}

future<>
thrift_server::connection::write() {
    uint8_t* data;
    uint32_t len;
    _output->getBuffer(&data, &len);
    net::packed<uint32_t> plen = { net::hton(len) };
    return _write_buf.write(reinterpret_cast<char*>(&plen), 4).then([this, data, len] {
        // FIXME: zero-copy
        return _write_buf.write(reinterpret_cast<char*>(data), len);
    }).then([this] {
        return _write_buf.flush();
    });
}

void
thrift_server::connection::shutdown() {
    try {
        _fd.shutdown_input();
        _fd.shutdown_output();
    } catch (...) {
    }
}

future<>
thrift_server::listen(socket_address addr, bool keepalive) {
    listen_options lo;
    lo.reuse_address = true;
    _listeners.push_back(seastar::listen(addr, lo));
    do_accepts(_listeners.size() - 1, keepalive, 0);
    return make_ready_future<>();
}

void
thrift_server::do_accepts(int which, bool keepalive, int num_attempts) {
    if (_stop_gate.is_closed()) {
        return;
    }
    // Future is waited on indirectly in `stop()` (via `_stop_gate`).
    (void)with_gate(_stop_gate, [&, this] {
        return _listeners[which].accept().then([this, which, keepalive] (accept_result ar) {
            auto&& fd = ar.connection;
            auto&& addr = ar.remote_address;
            fd.set_nodelay(true);
            fd.set_keepalive(keepalive);
            // Future is waited on indirectly in `stop()` (via `_stop_gate`).
            (void)with_gate(_stop_gate, [&, this] {
                return do_with(connection(*this, std::move(fd), addr), [this] (auto& conn) {
                    return conn.process().then_wrapped([this, &conn] (future<> f) {
                        conn.shutdown();
                        try {
                            f.get();
                        } catch (std::exception& ex) {
                            tlogger.debug("request error {}", ex.what());
                        }
                    });
                });
            });
            do_accepts(which, keepalive, 0);
        }).handle_exception([this, which, keepalive, num_attempts] (auto ex) {
            tlogger.debug("accept failed {}", ex);
            try {
                std::rethrow_exception(std::move(ex));
            } catch (const seastar::gate_closed_exception&) {
                return;
            } catch (...) {
                if (_stop_gate.is_closed()) {
                    return;
                }
                // Done in the background.
                (void)with_gate(_stop_gate, [this, which, keepalive, num_attempts] {
                    int backoff = 2 << std::max(num_attempts, 10);
                    tlogger.debug("sleeping for {}ms", backoff);
                    return sleep(std::chrono::milliseconds(backoff)).then([this, which, keepalive, num_attempts] {
                        tlogger.debug("retrying accept after failure");
                        do_accepts(which, keepalive, num_attempts + 1);
                    });
                });
            }
        });
    });
}

uint64_t
thrift_server::total_connections() const {
    return _total_connections;
}

uint64_t
thrift_server::current_connections() const {
    return _current_connections;
}

uint64_t
thrift_server::requests_served() const {
    return _requests_served;
}

uint64_t
thrift_server::requests_serving() const {
    return _requests_serving;
}

size_t
thrift_server::max_request_size() const {
    return _config.max_request_size;
}

const semaphore&
thrift_server::memory_available() const {
    return _memory_available;
}

uint64_t
thrift_server::requests_blocked_memory() const {
    return _requests_blocked_memory;
}

thrift_stats::thrift_stats(thrift_server& server) {
    namespace sm = seastar::metrics;

    _metrics.add_group("thrift", {
        sm::make_derive("thrift-connections", [&server] { return server.total_connections(); },
                        sm::description("Rate of creation of new Thrift connections.")),

        sm::make_gauge("current_connections", [&server] { return server.current_connections(); },
                        sm::description("Holds a current number of opened Thrift connections.")),

        sm::make_derive("served", [&server] { return server.requests_served(); },
                        sm::description("Rate of serving Thrift requests.")),
    });
}

<commit_msg>thrift: add metrics for admission control<commit_after>/*
 * Copyright (C) 2014 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "server.hh"
#include "handler.hh"
#include <seastar/core/future-util.hh>
#include <seastar/core/circular_buffer.hh>
#include <seastar/core/metrics.hh>
#include <seastar/net/byteorder.hh>
#include <seastar/core/scattered_message.hh>
#include <seastar/core/sleep.hh>
#include <seastar/core/coroutine.hh>
#include <seastar/core/semaphore.hh>
#include "log.hh"
#include <thrift/server/TServer.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/TProcessor.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/async/TAsyncProcessor.h>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <queue>
#include <bitset>
#include <limits>
#include <cctype>
#include <vector>

#ifdef THRIFT_USES_BOOST
#include <boost/make_shared.hpp>
#endif

static logging::logger tlogger("thrift");

using namespace apache::thrift;
using namespace apache::thrift::transport;
using namespace apache::thrift::protocol;
using namespace apache::thrift::async;
using namespace ::cassandra;

using namespace std::chrono_literals;

class thrift_stats {
    seastar::metrics::metric_groups _metrics;
public:
    thrift_stats(thrift_server& server);
};

thrift_server::thrift_server(distributed<database>& db,
                             distributed<cql3::query_processor>& qp,
                             auth::service& auth_service,
                             service::memory_limiter& ml,
                             thrift_server_config config)
        : _stats(new thrift_stats(*this))
        , _handler_factory(create_handler_factory(db, qp, auth_service, config.timeout_config, _current_permit).release())
        , _protocol_factory(new TBinaryProtocolFactoryT<TMemoryBuffer>())
        , _processor_factory(new CassandraAsyncProcessorFactory(_handler_factory))
        , _memory_available(ml.get_semaphore())
        , _config(config) {
}

thrift_server::~thrift_server() {
}

future<> thrift_server::stop() {
    auto f = _stop_gate.close();
    std::for_each(_listeners.begin(), _listeners.end(), std::mem_fn(&server_socket::abort_accept));
    std::for_each(_connections_list.begin(), _connections_list.end(), std::mem_fn(&connection::shutdown));
    return f;
}

struct handler_deleter {
    CassandraCobSvIfFactory* hf;
    void operator()(CassandraCobSvIf* h) const {
        hf->releaseHandler(h);
    }
};

// thrift uses a shared_ptr to refer to the transport (= connection),
// while we do not, so we can't have connection inherit from TTransport.
struct thrift_server::connection::fake_transport : TTransport {
    fake_transport(thrift_server::connection* c) : conn(c) {}
    thrift_server::connection* conn;
};

thrift_server::connection::connection(thrift_server& server, connected_socket&& fd, socket_address addr)
        : _server(server), _fd(std::move(fd)), _read_buf(_fd.input())
        , _write_buf(_fd.output())
        , _transport(thrift_std::make_shared<thrift_server::connection::fake_transport>(this))
        , _input(thrift_std::make_shared<TMemoryBuffer>())
        , _output(thrift_std::make_shared<TMemoryBuffer>())
        , _in_proto(_server._protocol_factory->getProtocol(_input))
        , _out_proto(_server._protocol_factory->getProtocol(_output))
        , _processor(_server._processor_factory->getProcessor({ _in_proto, _out_proto, _transport })) {
    ++_server._total_connections;
    ++_server._current_connections;
    _server._connections_list.push_back(*this);
}

thrift_server::connection::~connection() {
    if (is_linked()) {
        --_server._current_connections;
        _server._connections_list.erase(_server._connections_list.iterator_to(*this));
    }
}

thrift_server::connection::connection(connection&& other)
        : _server(other._server)
        , _fd(std::move(other._fd))
        , _read_buf(std::move(other._read_buf))
        , _write_buf(std::move(other._write_buf))
        , _transport(std::move(other._transport))
        , _input(std::move(other._input))
        , _output(std::move(other._output))
        , _in_proto(std::move(other._in_proto))
        , _out_proto(std::move(other._out_proto))
        , _processor(std::move(other._processor)) {
    if (other.is_linked()) {
        boost::intrusive::list<connection>::node_algorithms::init(this_ptr());
        boost::intrusive::list<connection>::node_algorithms::swap_nodes(other.this_ptr(), this_ptr());
    }
}

future<>
thrift_server::connection::process() {
    return do_until([this] { return _read_buf.eof(); },
            [this] { return process_one_request(); })
        .finally([this] {
            return _write_buf.close();
        });
}

future<>
thrift_server::connection::process_one_request() {
    _input->resetBuffer();
    _output->resetBuffer();
    co_await read();
    ++_server._requests_serving;
    ++_server._requests_served;
    auto ret = _processor_promise.get_future().handle_exception([&server = _server] (const std::exception_ptr&) {
        server._requests_serving--;
    });
    // adapt from "continuation object style" to future/promise
    auto complete = [this] (bool success) mutable {
        // FIXME: look at success?
        _server._requests_serving--;
        write().forward_to(std::move(_processor_promise));
        _processor_promise = promise<>();
    };
    // Heuristics copied from transport/server.cc
    size_t mem_estimate = 8000 + 2 * _input->available_read();
    auto fut = get_units(_server._memory_available, mem_estimate);
    if (_server._memory_available.waiters()) {
        ++_server._requests_blocked_memory;
    }
    auto units = co_await std::move(fut);
    // NOTICE: this permit is put in the server under the assumption that no other
    // connection will overwrite this permit *until* it's extracted by the code
    // which handles the Thrift request (via calling obtain_permit()).
    // This assumption is true because there are no preemption points between this
    // insertion and the call to obtain_permit(), which was verified both by
    // code inspection and confirmed empirically by running manual tests.
    if (_server._current_permit.count() > 0) {
        tlogger.debug("Current service permit is overwritten while its units are still held ({}). "
                "This situation likely means that there's a bug in passing service permits to message handlers.",
                _server._current_permit.count());
    }
    _server._current_permit = make_service_permit(std::move(units));
    _processor->process(complete, _in_proto, _out_proto);
    co_return co_await std::move(ret);
}

future<>
thrift_server::connection::read() {
    return _read_buf.read_exactly(4).then([this] (temporary_buffer<char> size_buf) {
        if (size_buf.size() != 4) {
            return make_ready_future<>();
        }
        union {
            uint32_t n;
            char b[4];
        } data;
        std::copy_n(size_buf.get(), 4, data.b);
        auto n = ntohl(data.n);
        if (n > _server._config.max_request_size) {
            // Close connection silently, we can't return a response because we did not
            // read a complete frame.
            tlogger.info("message size {} exceeds configured maximum {}, closing connection", n, _server._config.max_request_size);
            return make_ready_future<>();
        }
        return _read_buf.read_exactly(n).then([this, n] (temporary_buffer<char> buf) {
            if (buf.size() != n) {
                // FIXME: exception perhaps?
                return;
            }
            _in_tmp = std::move(buf); // keep ownership of the data
            auto b = reinterpret_cast<uint8_t*>(_in_tmp.get_write());
            _input->resetBuffer(b, _in_tmp.size());
        });
    });
}

future<>
thrift_server::connection::write() {
    uint8_t* data;
    uint32_t len;
    _output->getBuffer(&data, &len);
    net::packed<uint32_t> plen = { net::hton(len) };
    return _write_buf.write(reinterpret_cast<char*>(&plen), 4).then([this, data, len] {
        // FIXME: zero-copy
        return _write_buf.write(reinterpret_cast<char*>(data), len);
    }).then([this] {
        return _write_buf.flush();
    });
}

void
thrift_server::connection::shutdown() {
    try {
        _fd.shutdown_input();
        _fd.shutdown_output();
    } catch (...) {
    }
}

future<>
thrift_server::listen(socket_address addr, bool keepalive) {
    listen_options lo;
    lo.reuse_address = true;
    _listeners.push_back(seastar::listen(addr, lo));
    do_accepts(_listeners.size() - 1, keepalive, 0);
    return make_ready_future<>();
}

void
thrift_server::do_accepts(int which, bool keepalive, int num_attempts) {
    if (_stop_gate.is_closed()) {
        return;
    }
    // Future is waited on indirectly in `stop()` (via `_stop_gate`).
    (void)with_gate(_stop_gate, [&, this] {
        return _listeners[which].accept().then([this, which, keepalive] (accept_result ar) {
            auto&& fd = ar.connection;
            auto&& addr = ar.remote_address;
            fd.set_nodelay(true);
            fd.set_keepalive(keepalive);
            // Future is waited on indirectly in `stop()` (via `_stop_gate`).
            (void)with_gate(_stop_gate, [&, this] {
                return do_with(connection(*this, std::move(fd), addr), [this] (auto& conn) {
                    return conn.process().then_wrapped([this, &conn] (future<> f) {
                        conn.shutdown();
                        try {
                            f.get();
                        } catch (std::exception& ex) {
                            tlogger.debug("request error {}", ex.what());
                        }
                    });
                });
            });
            do_accepts(which, keepalive, 0);
        }).handle_exception([this, which, keepalive, num_attempts] (auto ex) {
            tlogger.debug("accept failed {}", ex);
            try {
                std::rethrow_exception(std::move(ex));
            } catch (const seastar::gate_closed_exception&) {
                return;
            } catch (...) {
                if (_stop_gate.is_closed()) {
                    return;
                }
                // Done in the background.
                (void)with_gate(_stop_gate, [this, which, keepalive, num_attempts] {
                    int backoff = 2 << std::max(num_attempts, 10);
                    tlogger.debug("sleeping for {}ms", backoff);
                    return sleep(std::chrono::milliseconds(backoff)).then([this, which, keepalive, num_attempts] {
                        tlogger.debug("retrying accept after failure");
                        do_accepts(which, keepalive, num_attempts + 1);
                    });
                });
            }
        });
    });
}

uint64_t
thrift_server::total_connections() const {
    return _total_connections;
}

uint64_t
thrift_server::current_connections() const {
    return _current_connections;
}

uint64_t
thrift_server::requests_served() const {
    return _requests_served;
}

uint64_t
thrift_server::requests_serving() const {
    return _requests_serving;
}

size_t
thrift_server::max_request_size() const {
    return _config.max_request_size;
}

const semaphore&
thrift_server::memory_available() const {
    return _memory_available;
}

uint64_t
thrift_server::requests_blocked_memory() const {
    return _requests_blocked_memory;
}

thrift_stats::thrift_stats(thrift_server& server) {
    namespace sm = seastar::metrics;

    _metrics.add_group("thrift", {
        sm::make_derive("thrift-connections", [&server] { return server.total_connections(); },
                        sm::description("Rate of creation of new Thrift connections.")),

        sm::make_gauge("current_connections", [&server] { return server.current_connections(); },
                        sm::description("Holds a current number of opened Thrift connections.")),

        sm::make_derive("served", [&server] { return server.requests_served(); },
                        sm::description("Rate of serving Thrift requests.")),
        sm::make_gauge("serving", [&server] { return server.requests_serving(); },
                        sm::description("Number of Thrift requests being currently served.")),
        sm::make_gauge("requests_blocked_memory_current", [&server] { return server.memory_available().waiters(); },
                        sm::description(
                            seastar::format("Holds the number of Thrift requests that are currently blocked due to reaching the memory quota limit ({}B). "
                                            "Non-zero value indicates that our bottleneck is memory and more specifically - the memory quota allocated for the \"Thrift transport\" component.", server.max_request_size()))),
        sm::make_derive("requests_blocked_memory", [&server] { return server.requests_blocked_memory(); },
                        sm::description(
                            seastar::format("Holds an incrementing counter with the Thrift requests that ever blocked due to reaching the memory quota limit ({}B). "
                                            "The first derivative of this value shows how often we block due to memory exhaustion in the \"Thrift transport\" component.", server.max_request_size()))),
        sm::make_gauge("requests_memory_available", [&server] { return server.memory_available().current(); },
                        sm::description(
                            seastar::format("Holds the amount of available memory for admitting new Thrift requests (max is {}B)."
                                            "Zero value indicates that our bottleneck is memory and more specifically - the memory quota allocated for the \"Thrift transport\" component.", server.max_request_size())))
    });
}

<|endoftext|>


<commit_before>#include "../src/utility.h"
#include <google/protobuf/util/message_differencer.h>
#include <algorithm>
#include "utility.h"

namespace lightstep {
//------------------------------------------------------------------------------
// LookupSpansDropped
//------------------------------------------------------------------------------
int LookupSpansDropped(const collector::ReportRequest& report) {
  if (!report.has_internal_metrics()) {
    return 0;
  }
  auto& counts = report.internal_metrics().counts();
  auto iter = std::find_if(counts.begin(), counts.end(),
                           [](const collector::MetricsSample& sample) {
                             return sample.name() == "spans.dropped";
                           });
  if (iter == counts.end()) {
    return 0;
  }
  if (iter->value_case() != collector::MetricsSample::kIntValue) {
    std::cerr << "spans.dropped not of type int\n";
    std::terminate();
  }
  return static_cast<int>(iter->int_value());
}

//------------------------------------------------------------------------------
// HasTag
//------------------------------------------------------------------------------
bool HasTag(const collector::Span& span, opentracing::string_view key,
            const opentracing::Value& value) {
  auto key_value = ToKeyValue(key, value);
  return std::any_of(
      std::begin(span.tags()), std::end(span.tags()),
      [&](const collector::KeyValue& other) {
        return google::protobuf::util::MessageDifferencer::Equals(key_value,
                                                                  other);
      });
}

//------------------------------------------------------------------------------
// HasRelationship
//------------------------------------------------------------------------------
bool HasRelationship(opentracing::SpanReferenceType relationship,
                     const collector::Span& span_a,
                     const collector::Span& span_b) {
  collector::Reference reference;
  switch (relationship) {
    case opentracing::SpanReferenceType::ChildOfRef:
      reference.set_relationship(collector::Reference::CHILD_OF);
      break;
    case opentracing::SpanReferenceType::FollowsFromRef:
      reference.set_relationship(collector::Reference::FOLLOWS_FROM);
      break;
  }
  *reference.mutable_span_context() = span_b.span_context();
  return std::any_of(
      std::begin(span_a.references()), std::end(span_a.references()),
      [&](const collector::Reference& other) {
        return google::protobuf::util::MessageDifferencer::Equals(reference,
                                                                  other);
      });
}
}  // namespace lightstep
<commit_msg>Add missing #include's<commit_after>#include "../src/utility.h"
#include <google/protobuf/util/message_differencer.h>
#include <algorithm>
#include <exception>
#include <iostream>
#include "utility.h"

namespace lightstep {
//------------------------------------------------------------------------------
// LookupSpansDropped
//------------------------------------------------------------------------------
int LookupSpansDropped(const collector::ReportRequest& report) {
  if (!report.has_internal_metrics()) {
    return 0;
  }
  auto& counts = report.internal_metrics().counts();
  auto iter = std::find_if(counts.begin(), counts.end(),
                           [](const collector::MetricsSample& sample) {
                             return sample.name() == "spans.dropped";
                           });
  if (iter == counts.end()) {
    return 0;
  }
  if (iter->value_case() != collector::MetricsSample::kIntValue) {
    std::cerr << "spans.dropped not of type int\n";
    std::terminate();
  }
  return static_cast<int>(iter->int_value());
}

//------------------------------------------------------------------------------
// HasTag
//------------------------------------------------------------------------------
bool HasTag(const collector::Span& span, opentracing::string_view key,
            const opentracing::Value& value) {
  auto key_value = ToKeyValue(key, value);
  return std::any_of(
      std::begin(span.tags()), std::end(span.tags()),
      [&](const collector::KeyValue& other) {
        return google::protobuf::util::MessageDifferencer::Equals(key_value,
                                                                  other);
      });
}

//------------------------------------------------------------------------------
// HasRelationship
//------------------------------------------------------------------------------
bool HasRelationship(opentracing::SpanReferenceType relationship,
                     const collector::Span& span_a,
                     const collector::Span& span_b) {
  collector::Reference reference;
  switch (relationship) {
    case opentracing::SpanReferenceType::ChildOfRef:
      reference.set_relationship(collector::Reference::CHILD_OF);
      break;
    case opentracing::SpanReferenceType::FollowsFromRef:
      reference.set_relationship(collector::Reference::FOLLOWS_FROM);
      break;
  }
  *reference.mutable_span_context() = span_b.span_context();
  return std::any_of(
      std::begin(span_a.references()), std::end(span_a.references()),
      [&](const collector::Reference& other) {
        return google::protobuf::util::MessageDifferencer::Equals(reference,
                                                                  other);
      });
}
}  // namespace lightstep
<|endoftext|>


<commit_before>#include <cstring>
#include <iomanip>
#include <iostream>
#include <asio.hpp>
#include <asio/serial_port.hpp>
#include <asio/signal_set.hpp>
#include <google/protobuf/io/coded_stream.h>
#include "packet/frame.h"
#include "pose.pb.h"
#include "simulation.pb.h"

namespace {
    asio::io_service io_service;
    asio::serial_port port(io_service);

    constexpr size_t buffer_size = 1024;
    uint8_t rx_buffer[buffer_size];
    uint8_t sim_buffer[buffer_size];
    uint8_t frame_buffer[buffer_size];
    size_t frame_buffer_index = 0;

    SimulationMessage msg;

    void handle_read(const asio::error_code&, size_t);

    void start_read() {
        port.async_read_some(asio::buffer(rx_buffer, buffer_size),
                std::bind(&handle_read,
                    std::placeholders::_1,
                    std::placeholders::_2));
    }

    void handle_read(const asio::error_code& error, size_t bytes_transferred) {
        if (error) {
            std::cerr << error.message() << std::endl;
        } else {
            size_t start_index = 0;
            size_t scan_index = 0;

            auto copy_to_frame_buffer = [&]() -> void {
                const size_t length = scan_index - start_index + 1; /* include packet delimiter */
                if ((length + frame_buffer_index) > buffer_size) {
                    frame_buffer_index = 0;
                }
                std::memcpy(frame_buffer + frame_buffer_index, rx_buffer + start_index, length);
                frame_buffer_index += length;
                start_index = ++scan_index;
            };

            auto decode_message = [&]() -> void {
                const size_t unstuff_size = packet::frame::unstuff(
                        frame_buffer, sim_buffer, frame_buffer_index);
                google::protobuf::io::CodedInputStream input(
                        const_cast<const uint8_t*>(sim_buffer), unstuff_size);

                uint32_t size;
                if (!input.ReadVarint32(&size)) {
                    std::cerr << "Unable to decode packet size from serialized data." << std::endl;
                    return;
                } else {
                    if (frame_buffer_index < size) {
                        /* We haven't received enough data to decode this message */
                        return;
                    }
                }
                if (msg.MergeFromCodedStream(&input)) {
                    msg.PrintDebugString();
                    msg.Clear();

                    frame_buffer_index = 0;
                    std::cout << std::endl;

                    if (!input.ConsumedEntireMessage()) {
                        std::cerr << "Entire message not consumed. Number of extra bytes: " <<
                            input.BytesUntilLimit() << std::endl;
                    }
                } else {
                    std::cerr << "Decode of protobuf message failed." << std::endl;
                    std::cerr << "Current buffer size: " << frame_buffer_index << std::endl;
                    std::cerr << "Size after unstuffing: " << unstuff_size << std::endl;
                    std::cerr << "Buffer contents " << std::endl;
                    std::cerr << std::hex;
                    for (size_t i = 0; i < frame_buffer_index; ++i) {
                        std::cerr << std::setfill('0') << std::setw(2) << std::right <<
                            static_cast<int>(frame_buffer[i] & 0xff) <<  " ";
                    }
                    std::cerr << std::dec << std::endl;

                    if (unstuff_size > size) {
                        /* The size of the data stored in the buffer exceeds the
                         * size of the message obtained by decoding the first
                         * varint. We may have started reading in the middle of
                         * a message so throw away the data. */
                        frame_buffer_index = 0;
                    }
                }
            };

            while (scan_index < bytes_transferred) {
                if (rx_buffer[scan_index] == packet::frame::PACKET_DELIMITER) {
                    copy_to_frame_buffer();
                    decode_message();
                } else {
                    ++scan_index;
                }
            }

            --scan_index; /* don't copy an extra byte */
            copy_to_frame_buffer();
        }
        start_read();
    }

    void handle_stop(const asio::error_code&, int signal_number) {
        if ((signal_number == SIGINT) || (signal_number == SIGTERM)) {
            io_service.stop();
        }
    }
} // namespace

int main(int argc, char* argv[]) {
    if (argc < 2) {
        std::cerr << "Usage: " << argv[0] << " <serial_device> <baud_rate>\n"
            << "\nTest serial communication.\n"
            << "A virtual serial port can be created using socat with:\n"
            << "\t$ socat -d -d pty,raw,echo=0 pty,raw,echo=0\n";
        return EXIT_FAILURE;
    }

    const std::string devname(argv[1]);
    uint32_t baud_rate = 115200;
    if (argc > 2) {
        baud_rate = std::atoi(argv[2]);
    }

    port.open(devname);
    port.set_option(asio::serial_port_base::baud_rate(baud_rate));
    port.set_option(asio::serial_port_base::parity(
                asio::serial_port_base::parity::none));
    port.set_option(asio::serial_port_base::character_size(8));
    port.set_option(asio::serial_port_base::flow_control(
                asio::serial_port_base::flow_control::none));
    port.set_option(asio::serial_port_base::stop_bits(
                asio::serial_port_base::stop_bits::one));

    asio::signal_set signals(io_service, SIGINT, SIGTERM);
    signals.async_wait(handle_stop);

    std::cout << "Decoding protobuf files from " << devname << ".\n";
    std::cout << "Press Ctrl-C to terminate.\n";

    start_read();
    io_service.run();
    return EXIT_SUCCESS;
}
<commit_msg>Detail pbprint program usage<commit_after>#include <cstring>
#include <iomanip>
#include <iostream>
#include <asio.hpp>
#include <asio/serial_port.hpp>
#include <asio/signal_set.hpp>
#include <google/protobuf/io/coded_stream.h>
#include "packet/frame.h"
#include "pose.pb.h"
#include "simulation.pb.h"

namespace {
    asio::io_service io_service;
    asio::serial_port port(io_service);

    constexpr size_t buffer_size = 1024;
    uint8_t rx_buffer[buffer_size];
    uint8_t sim_buffer[buffer_size];
    uint8_t frame_buffer[buffer_size];
    size_t frame_buffer_index = 0;

    SimulationMessage msg;

    void handle_read(const asio::error_code&, size_t);

    void start_read() {
        port.async_read_some(asio::buffer(rx_buffer, buffer_size),
                std::bind(&handle_read,
                    std::placeholders::_1,
                    std::placeholders::_2));
    }

    void handle_read(const asio::error_code& error, size_t bytes_transferred) {
        if (error) {
            std::cerr << error.message() << std::endl;
        } else {
            size_t start_index = 0;
            size_t scan_index = 0;

            auto copy_to_frame_buffer = [&]() -> void {
                const size_t length = scan_index - start_index + 1; /* include packet delimiter */
                if ((length + frame_buffer_index) > buffer_size) {
                    frame_buffer_index = 0;
                }
                std::memcpy(frame_buffer + frame_buffer_index, rx_buffer + start_index, length);
                frame_buffer_index += length;
                start_index = ++scan_index;
            };

            auto decode_message = [&]() -> void {
                const size_t unstuff_size = packet::frame::unstuff(
                        frame_buffer, sim_buffer, frame_buffer_index);
                google::protobuf::io::CodedInputStream input(
                        const_cast<const uint8_t*>(sim_buffer), unstuff_size);

                uint32_t size;
                if (!input.ReadVarint32(&size)) {
                    std::cerr << "Unable to decode packet size from serialized data." << std::endl;
                    return;
                } else {
                    if (frame_buffer_index < size) {
                        /* We haven't received enough data to decode this message */
                        return;
                    }
                }
                if (msg.MergeFromCodedStream(&input)) {
                    msg.PrintDebugString();
                    msg.Clear();

                    frame_buffer_index = 0;
                    std::cout << std::endl;

                    if (!input.ConsumedEntireMessage()) {
                        std::cerr << "Entire message not consumed. Number of extra bytes: " <<
                            input.BytesUntilLimit() << std::endl;
                    }
                } else {
                    std::cerr << "Decode of protobuf message failed." << std::endl;
                    std::cerr << "Current buffer size: " << frame_buffer_index << std::endl;
                    std::cerr << "Size after unstuffing: " << unstuff_size << std::endl;
                    std::cerr << "Buffer contents " << std::endl;
                    std::cerr << std::hex;
                    for (size_t i = 0; i < frame_buffer_index; ++i) {
                        std::cerr << std::setfill('0') << std::setw(2) << std::right <<
                            static_cast<int>(frame_buffer[i] & 0xff) <<  " ";
                    }
                    std::cerr << std::dec << std::endl;

                    if (unstuff_size > size) {
                        /* The size of the data stored in the buffer exceeds the
                         * size of the message obtained by decoding the first
                         * varint. We may have started reading in the middle of
                         * a message so throw away the data. */
                        frame_buffer_index = 0;
                    }
                }
            };

            while (scan_index < bytes_transferred) {
                if (rx_buffer[scan_index] == packet::frame::PACKET_DELIMITER) {
                    copy_to_frame_buffer();
                    decode_message();
                } else {
                    ++scan_index;
                }
            }

            --scan_index; /* don't copy an extra byte */
            copy_to_frame_buffer();
        }
        start_read();
    }

    void handle_stop(const asio::error_code&, int signal_number) {
        if ((signal_number == SIGINT) || (signal_number == SIGTERM)) {
            io_service.stop();
        }
    }
} // namespace

int main(int argc, char* argv[]) {
    if (argc < 2) {
        std::cerr << "Usage: " << argv[0] << " <serial_device> [<baud_rate>]\n\n"
            << "Decode streaming serialized simulation protobuf messages.\n"
            << " <serial_device>      device from which to read serial data\n"
            << " <baud_rate=115200>   serial baud rate\n\n"

            << "A virtual serial port can be created using socat with:\n"
            << "  $ socat -d -d pty,raw,echo=0 pty,raw,echo=0\n\n"
            << "This can be used to decode a log file of the serialized protobuf stream data.\n"
            << "Here is an example:\n"
            << "  $ socat -d -d pty,raw,echo=0 pty,raw,echo=0\n"
            << "  2017/02/17 18:00:30 socat[71176] N PTY is /dev/ttys009\n"
            << "  2017/02/17 18:00:30 socat[71176] N PTY is /dev/ttys010\n"
            << "  2017/02/17 18:00:30 socat[71176] N starting data transfer loop with FDs [5,5] and [7,7]\n\n"
            << "  $ ./pbprint /dev/ttys010\n\n"
            << "  $ cat log.pb > /dev/ttys009\n";
        return EXIT_FAILURE;
    }

    const std::string devname(argv[1]);
    uint32_t baud_rate = 115200;
    if (argc > 2) {
        baud_rate = std::atoi(argv[2]);
    }

    port.open(devname);
    port.set_option(asio::serial_port_base::baud_rate(baud_rate));
    port.set_option(asio::serial_port_base::parity(
                asio::serial_port_base::parity::none));
    port.set_option(asio::serial_port_base::character_size(8));
    port.set_option(asio::serial_port_base::flow_control(
                asio::serial_port_base::flow_control::none));
    port.set_option(asio::serial_port_base::stop_bits(
                asio::serial_port_base::stop_bits::one));

    asio::signal_set signals(io_service, SIGINT, SIGTERM);
    signals.async_wait(handle_stop);

    std::cout << "Decoding protobuf files from " << devname << ".\n";
    std::cout << "Press Ctrl-C to terminate.\n";

    start_read();
    io_service.run();
    return EXIT_SUCCESS;
}
<|endoftext|>