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

/*! @file  tests/test-regression.C
 * @ingroup tests
 * @brief tests former bugs to check that no regression made them show up again.
 */
#include "linbox-config.h"
#include "givaro/modular.h"
#include "linbox/matrix/sparse-matrix.h"
#include "linbox/vector/blas-vector.h"
#include "solutions/solve.h"
using namespace LinBox;

bool testSolveSparse(){

    typedef Givaro::Modular<unsigned int> Field;
    typedef std::vector <std::pair <size_t, Field::Element> > SparseSeqVectorGFp;
    typedef SparseMatrix<Field, VectorTraits<SparseSeqVectorGFp>::SparseFormat> Matrix;
    Field F(127);
    Matrix A(F, 3, 3);
    DenseVector<Field> x(F, 3);
    DenseVector<Field> b(F, 3);
    A.setEntry(0,0, 1);
    A.setEntry(0,1, 2);
    A.setEntry(0,2, 3);
    A.setEntry(1,0, 126);
    A.setEntry(1,1, 2);
    A.setEntry(1,2, 5);
    A.setEntry(2,0, 2);
    A.setEntry(2,1, 3);
    A.setEntry(2,2, 1);
    for (int i=0;i<3;i++)
        F.assign(b[i],i+1);

    Matrix B(A);

    solve(x,B,b,  Method::BlasElimination());

    if (!F.areEqual (x[0],73)) return false;
    if (!F.areEqual (x[1],76)) return false;
    if (!F.areEqual (x[2],10)) return false;
    return true;
}

#if __LINBOX_HAVE_SAGE
// CP: Include the .C file instead of linking to the linboxsage lib:
// avoid requiring to make install before make check.
#include "interfaces/sage/linbox-sage.C"
bool testSolveSparseSage(){
    size_t p = 127;
    c_vector_modint_linbox * A = new c_vector_modint_linbox[3];
    c_vector_modint_linbox  b;
    for (int i=0;i<3;++i){
        A[i].entries = new int[3];
        A[i].positions = new size_t[3];
        A[i].num_nonzero=3;
        for (int j=0;j<3;j++)
            A[i].positions[j]=j;
        A[i].p = p;
    }
    b.entries = new int[3];
    b.positions = new size_t[3];
    for (int j=0;j<3;j++)
        b.positions[j]=j;
    b.num_nonzero=3;
    b.p = p;
    for (int i=0;i<3;i++)
        b.entries[i]=i+1;

    std::vector<unsigned int> x;

    A[0].entries[0]=1;
    A[0].entries[1]=2;
    A[0].entries[2]=3;
    A[1].entries[0]=126;
    A[1].entries[1]=2;
    A[1].entries[2]=5;
    A[2].entries[0]=2;
    A[2].entries[1]=3;
    A[2].entries[2]=1;

    x = linbox_modn_sparse_matrix_solve(p,3,3,A,&b,1);

    if (x[0] != 73) return false;
    if (x[1] != 76) return false;
    if (x[2] != 10) return false;

    return true;
}
#else
bool testSolveSparseSage(){return true;}
#endif

int main (int argc, char **argv)
{
    bool pass = true;

    if (!testSolveSparse  ()) pass = false;
    if (!testSolveSparseSage  ()) pass = false;

    return pass ? 0 : -1;
}
<commit_msg>add Vincent Delecroix test to the regression test suite<commit_after>/* tests/test-regression.C
 * Copyright (C) LinBox
 * Written by Clement Pernet
 *
 *
 * ========LICENCE========
 * This file is part of the library LinBox.
 *
 * LinBox is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 *.
 */

/*! @file  tests/test-regression.C
 * @ingroup tests
 * @brief tests former bugs to check that no regression made them show up again.
 */
#include "linbox-config.h"
#include "givaro/modular.h"
#include "linbox/matrix/sparse-matrix.h"
#include "linbox/vector/blas-vector.h"
#include "solutions/solve.h"
using namespace LinBox;

bool testSolveSparse(){

    typedef Givaro::Modular<unsigned int> Field;
    typedef std::vector <std::pair <size_t, Field::Element> > SparseSeqVectorGFp;
    typedef SparseMatrix<Field, VectorTraits<SparseSeqVectorGFp>::SparseFormat> Matrix;
    Field F(127);
    Matrix A(F, 3, 3);
    DenseVector<Field> x(F, 3);
    DenseVector<Field> b(F, 3);
    A.setEntry(0,0, 1);
    A.setEntry(0,1, 2);
    A.setEntry(0,2, 3);
    A.setEntry(1,0, 126);
    A.setEntry(1,1, 2);
    A.setEntry(1,2, 5);
    A.setEntry(2,0, 2);
    A.setEntry(2,1, 3);
    A.setEntry(2,2, 1);
    for (int i=0;i<3;i++)
        F.assign(b[i],i+1);

    Matrix B(A);

    solve(x,B,b,  Method::BlasElimination());

    if (!F.areEqual (x[0],73)) return false;
    if (!F.areEqual (x[1],76)) return false;
    if (!F.areEqual (x[2],10)) return false;
    return true;
}

#if __LINBOX_HAVE_SAGE
// CP: Include the .C file instead of linking to the linboxsage lib:
// avoid requiring to make install before make check.
#include "interfaces/sage/linbox-sage.C"
bool testSolveSparseSage(){
    size_t p = 127;
    c_vector_modint_linbox * A = new c_vector_modint_linbox[3];
    c_vector_modint_linbox  b;
    for (int i=0;i<3;++i){
        A[i].entries = new int[3];
        A[i].positions = new size_t[3];
        A[i].num_nonzero=3;
        for (int j=0;j<3;j++)
            A[i].positions[j]=j;
        A[i].p = p;
    }
    b.entries = new int[3];
    b.positions = new size_t[3];
    for (int j=0;j<3;j++)
        b.positions[j]=j;
    b.num_nonzero=3;
    b.p = p;
    for (int i=0;i<3;i++)
        b.entries[i]=i+1;

    std::vector<unsigned int> x;

    A[0].entries[0]=1;
    A[0].entries[1]=2;
    A[0].entries[2]=3;
    A[1].entries[0]=126;
    A[1].entries[1]=2;
    A[1].entries[2]=5;
    A[2].entries[0]=2;
    A[2].entries[1]=3;
    A[2].entries[2]=1;

    x = linbox_modn_sparse_matrix_solve(p,3,3,A,&b,1);

    if (x[0] != 73) return false;
    if (x[1] != 76) return false;
    if (x[2] != 10) return false;

    return true;
}
#else
bool testSolveSparseSage(){return true;}
#endif

/**
 * Testing regresssion for issue 56 https://github.com/linbox-team/linbox/issues/56
 * reported by Vincent Delecroix
 */
bool testFlatDixonSolver (const Specifier& m){
        // creating LinBox matrices and vectors
    Givaro::ZRing<Integer> ZZ;
    typedef DenseVector<Givaro::ZRing<Integer> > DenseVector;

    SparseMatrix<Givaro::ZRing<Integer> > M (ZZ,1,2);
    Givaro::ZRing<Integer>::Element D; // denominator of the solution
    DenseVector A(ZZ, M.coldim()); // numerator of the solution
    DenseVector B(ZZ, M.rowdim()); // Right handside of the system

    M.setEntry(0,0,1);
    M.setEntry(0,1,1);
    ZZ.assign(B[0],1);

        // solving via Sparse Elimination
    solve (A, D, M, B, m);

    if (!ZZ.areEqual(A[0],ZZ.one) || !ZZ.areEqual(A[1],ZZ.zero) || !ZZ.areEqual(D,ZZ.one)) {
        std::cerr<<"Fail solving a flat system over QQ with a SparseMatrix"<<std::endl;
        return false;
    }

    return true;
}
bool testTallDixonSolver (const Specifier& m){
        // creating LinBox matrices and vectors
    Givaro::ZRing<Integer> ZZ;
    typedef DenseVector<Givaro::ZRing<Integer> > DenseVector;

    SparseMatrix<Givaro::ZRing<Integer> > M (ZZ,2,1);
    Givaro::ZRing<Integer>::Element D; // denominator of the solution
    DenseVector A(ZZ, M.coldim()); // numerator of the solution
    DenseVector B(ZZ, M.rowdim()); // Right handside of the system

    M.setEntry(0,0,1);
    M.setEntry(1,0,1);
    ZZ.assign(B[0],1);
    ZZ.assign(B[1],1);

        // solving via Sparse Elimination
    solve (A, D, M, B, m);

    if (!ZZ.areEqual(A[0],ZZ.one) || !ZZ.areEqual(D,ZZ.one)) {
        std::cerr<<"Fail solving a tall system over QQ with a SparseMatrix"<<std::endl;
        return false;
    }

    return true;

}

int main (int argc, char **argv)
{
    bool pass = true;

    pass &= testSolveSparse  ();
    pass &= testSolveSparseSage ();
    pass &= testFlatDixonSolver (Method::SparseElimination());
    pass &= testFlatDixonSolver (Method::Wiedemann());
    pass &= testTallDixonSolver (Method::SparseElimination());
    pass &= testTallDixonSolver (Method::Wiedemann());

    return pass ? 0 : -1;
}
<|endoftext|>


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

/*! @file  tests/test-regression.C
 * @ingroup tests
 * @brief tests former bugs to check that no regression made them show up again.
 */
#include "linbox/linbox-config.h"
#include "givaro/modular.h"
#include "linbox/matrix/sparse-matrix.h"
#include "linbox/vector/blas-vector.h"
#include "linbox/solutions/solve.h"
using namespace LinBox;

bool testSolveSparse(){

    typedef Givaro::Modular<unsigned int> Field;
    typedef std::vector <std::pair <size_t, Field::Element> > SparseSeqVectorGFp;
    typedef SparseMatrix<Field, VectorTraits<SparseSeqVectorGFp>::SparseFormat> Matrix;
    Field F(127);
    Matrix A(F, 3, 3);
    DenseVector<Field> x(F, 3);
    DenseVector<Field> b(F, 3);
    A.setEntry(0,0, 1);
    A.setEntry(0,1, 2);
    A.setEntry(0,2, 3);
    A.setEntry(1,0, 126);
    A.setEntry(1,1, 2);
    A.setEntry(1,2, 5);
    A.setEntry(2,0, 2);
    A.setEntry(2,1, 3);
    A.setEntry(2,2, 1);
    for (int i=0;i<3;i++)
        F.assign(b[i],i+1);

    Matrix B(A);

    solve(x,B,b,  Method::BlasElimination());

    if (!F.areEqual (x[0],73)) return false;
    if (!F.areEqual (x[1],76)) return false;
    if (!F.areEqual (x[2],10)) return false;
    return true;
}

#if __LINBOX_HAVE_SAGE
// CP: Include the .C file instead of linking to the linboxsage lib:
// avoid requiring to make install before make check.
#include "interfaces/sage/linbox-sage.C"
bool testSolveSparseSage(){
    size_t p = 127;
    c_vector_modint_linbox * A = new c_vector_modint_linbox[3];
    c_vector_modint_linbox  b;
    for (int i=0;i<3;++i){
        A[i].entries = new int[3];
        A[i].positions = new size_t[3];
        A[i].num_nonzero=3;
        for (int j=0;j<3;j++)
            A[i].positions[j]=j;
        A[i].p = p;
    }
    b.entries = new int[3];
    b.positions = new size_t[3];
    for (int j=0;j<3;j++)
        b.positions[j]=j;
    b.num_nonzero=3;
    b.p = p;
    for (int i=0;i<3;i++)
        b.entries[i]=i+1;

    std::vector<unsigned int> x;

    A[0].entries[0]=1;
    A[0].entries[1]=2;
    A[0].entries[2]=3;
    A[1].entries[0]=126;
    A[1].entries[1]=2;
    A[1].entries[2]=5;
    A[2].entries[0]=2;
    A[2].entries[1]=3;
    A[2].entries[2]=1;

    x = linbox_modn_sparse_matrix_solve(p,3,3,A,&b,1);

    if (x[0] != 73) return false;
    if (x[1] != 76) return false;
    if (x[2] != 10) return false;

    return true;
}
#else
bool testSolveSparseSage(){return true;}
#endif

/**
 * Testing regresssion for issue 56 https://github.com/linbox-team/linbox/issues/56
 * reported by Vincent Delecroix
 */
bool testFlatDixonSolver (const Specifier& m){
        // creating LinBox matrices and vectors
    Givaro::ZRing<Integer> ZZ;
    typedef DenseVector<Givaro::ZRing<Integer> > DenseVector;

    SparseMatrix<Givaro::ZRing<Integer> > M (ZZ,1,2);
    Givaro::ZRing<Integer>::Element D; // denominator of the solution
    DenseVector A(ZZ, M.coldim()); // numerator of the solution
    DenseVector B(ZZ, M.rowdim()); // Right handside of the system

    M.setEntry(0,0,1);
    M.setEntry(0,1,1);
    ZZ.assign(B[0],1);

        // solving via Sparse Elimination
    solve (A, D, M, B, m);

    if (!ZZ.areEqual(A[0],ZZ.one) || !ZZ.areEqual(A[1],ZZ.zero) || !ZZ.areEqual(D,ZZ.one)) {
        std::cerr<<"Fail solving a flat system over QQ with a SparseMatrix"<<std::endl;
        return false;
    }

    return true;
}

bool testFlatDixonSolver2 (const Specifier& m){
        // creating LinBox matrices and vectors
    Givaro::ZRing<Integer> ZZ;
    typedef DenseVector<Givaro::ZRing<Integer> > DenseVector;

    SparseMatrix<Givaro::ZRing<Integer> > M (ZZ,1,2);
    Givaro::ZRing<Integer>::Element D; // denominator of the solution
    DenseVector A(ZZ, M.coldim()); // numerator of the solution
    DenseVector B(ZZ, M.rowdim()); // Right handside of the system

    M.setEntry(0,0,1);
    M.setEntry(0,1,0);
    ZZ.assign(B[0],1);

        // solving via Sparse Elimination
    solve (A, D, M, B, m);

    if (!ZZ.areEqual(A[0],ZZ.one) || !ZZ.areEqual(D,ZZ.one)) {
        std::cerr<<"A = "<<A<<" D = "<<D<<std::endl;
        std::cerr<<"Fail solving a flat system over QQ with a SparseMatrix"<<std::endl;
        return false;
    }

    return true;
}

bool testTallDixonSolver (const Specifier& m){
        // creating LinBox matrices and vectors
    Givaro::ZRing<Integer> ZZ;
    typedef DenseVector<Givaro::ZRing<Integer> > DenseVector;

    SparseMatrix<Givaro::ZRing<Integer> > M (ZZ,2,1);
    Givaro::ZRing<Integer>::Element D; // denominator of the solution
    DenseVector A(ZZ, M.coldim()); // numerator of the solution
    DenseVector B(ZZ, M.rowdim()); // Right handside of the system

    M.setEntry(0,0,1);
    M.setEntry(1,0,1);
    ZZ.assign(B[0],1);
    ZZ.assign(B[1],1);

        // solving via Sparse Elimination
    solve (A, D, M, B, m);

    if (!ZZ.areEqual(A[0],ZZ.one) || !ZZ.areEqual(D,ZZ.one)) {
        std::cerr<<"Fail solving a tall system over QQ with a SparseMatrix"<<std::endl;
        return false;
    }

    return true;

}

bool testSingularDixonSolver (const Specifier& m){
        // creating LinBox matrices and vectors
    Givaro::ZRing<Integer> ZZ;
    typedef DenseVector<Givaro::ZRing<Integer> > DenseVector;

    SparseMatrix<Givaro::ZRing<Integer> > M (ZZ,2,2);
    Givaro::ZRing<Integer>::Element D; // denominator of the solution
    DenseVector A(ZZ, M.coldim()); // numerator of the solution
    DenseVector B(ZZ, M.rowdim()); // Right handside of the system

    M.setEntry(0,0,-2);
    ZZ.assign(B[0],-4);

        // solving via Sparse Elimination
    solve (A, D, M, B, m);

    if (!ZZ.areEqual(A[0],Integer(2)) || !ZZ.areEqual(D,ZZ.one)) {
        std::cerr<<"A = "<<A<<" D = "<<D<<std::endl;
        std::cerr<<"Fail solving a singular system over QQ with a SparseMatrix"<<std::endl;
        return false;
    }
    return true;
}
bool testZeroDixonSolver (const Specifier& m){
        // creating LinBox matrices and vectors
    Givaro::ZRing<Integer> ZZ;
    typedef DenseVector<Givaro::ZRing<Integer> > DenseVector;

    SparseMatrix<Givaro::ZRing<Integer> > M (ZZ,1,1);
    Givaro::ZRing<Integer>::Element D; // denominator of the solution
    DenseVector A(ZZ, M.coldim()); // numerator of the solution
    DenseVector B(ZZ, M.rowdim()); // Right handside of the system

    M.setEntry(0,0,0);
    ZZ.assign(B[0],0);

        // solving via Sparse Elimination
    solve (A, D, M, B, m);

    if (!ZZ.areEqual(A[0],ZZ.zero) || !ZZ.areEqual(D,ZZ.one)) {
        std::cerr<<"A = "<<A<<" D = "<<D<<std::endl;
        std::cerr<<"Fail solving a zero over QQ with a SparseMatrix"<<std::endl;
        return false;
    }
    return true;
}
int main (int argc, char **argv)
{
    bool pass = true;

    pass &= testSolveSparse  ();
    pass &= testSolveSparseSage ();
    pass &= testFlatDixonSolver (Method::SparseElimination());
    pass &= testFlatDixonSolver2 (Method::SparseElimination());
    pass &= testTallDixonSolver (Method::SparseElimination());
    pass &= testFlatDixonSolver (Method::BlasElimination());
    pass &= testFlatDixonSolver2 (Method::BlasElimination());
    pass &= testTallDixonSolver (Method::BlasElimination());
    pass &= testFlatDixonSolver (Method::Wiedemann());
    pass &= testFlatDixonSolver2 (Method::Wiedemann());
    pass &= testTallDixonSolver (Method::Wiedemann());
    pass &= testSingularDixonSolver (Method::SparseElimination());
    pass &= testZeroDixonSolver (Method::SparseElimination());
    pass &= testSingularDixonSolver (Method::BlasElimination());
    pass &= testZeroDixonSolver (Method::BlasElimination());

    return pass ? 0 : -1;
}
<commit_msg>add regression test for 0-dim charpoly (sage ticket #22924)<commit_after>/* tests/test-regression.C
 * Copyright (C) LinBox
 * Written by Clement Pernet
 *
 *
 * ========LICENCE========
 * This file is part of the library LinBox.
 *
 * LinBox is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 *.
 */

/*! @file  tests/test-regression.C
 * @ingroup tests
 * @brief tests former bugs to check that no regression made them show up again.
 */
#include "linbox/linbox-config.h"
#include "givaro/modular.h"
#include "linbox/matrix/sparse-matrix.h"
#include "linbox/matrix/dense-matrix.h"
#include "linbox/polynomial/dense-polynomial.h"
#include "linbox/ring/polynomial-ring.h"
#include "linbox/vector/blas-vector.h"
#include "linbox/solutions/solve.h"
#include "linbox/solutions/charpoly.h"
using namespace LinBox;

bool testSolveSparse(){

    typedef Givaro::Modular<unsigned int> Field;
    typedef std::vector <std::pair <size_t, Field::Element> > SparseSeqVectorGFp;
    typedef SparseMatrix<Field, VectorTraits<SparseSeqVectorGFp>::SparseFormat> Matrix;
    Field F(127);
    Matrix A(F, 3, 3);
    DenseVector<Field> x(F, 3);
    DenseVector<Field> b(F, 3);
    A.setEntry(0,0, 1);
    A.setEntry(0,1, 2);
    A.setEntry(0,2, 3);
    A.setEntry(1,0, 126);
    A.setEntry(1,1, 2);
    A.setEntry(1,2, 5);
    A.setEntry(2,0, 2);
    A.setEntry(2,1, 3);
    A.setEntry(2,2, 1);
    for (int i=0;i<3;i++)
        F.assign(b[i],i+1);

    Matrix B(A);

    solve(x,B,b,  Method::BlasElimination());

    if (!F.areEqual (x[0],73)) return false;
    if (!F.areEqual (x[1],76)) return false;
    if (!F.areEqual (x[2],10)) return false;
    return true;
}

#if __LINBOX_HAVE_SAGE
// CP: Include the .C file instead of linking to the linboxsage lib:
// avoid requiring to make install before make check.
#include "interfaces/sage/linbox-sage.C"
bool testSolveSparseSage(){
    size_t p = 127;
    c_vector_modint_linbox * A = new c_vector_modint_linbox[3];
    c_vector_modint_linbox  b;
    for (int i=0;i<3;++i){
        A[i].entries = new int[3];
        A[i].positions = new size_t[3];
        A[i].num_nonzero=3;
        for (int j=0;j<3;j++)
            A[i].positions[j]=j;
        A[i].p = p;
    }
    b.entries = new int[3];
    b.positions = new size_t[3];
    for (int j=0;j<3;j++)
        b.positions[j]=j;
    b.num_nonzero=3;
    b.p = p;
    for (int i=0;i<3;i++)
        b.entries[i]=i+1;

    std::vector<unsigned int> x;

    A[0].entries[0]=1;
    A[0].entries[1]=2;
    A[0].entries[2]=3;
    A[1].entries[0]=126;
    A[1].entries[1]=2;
    A[1].entries[2]=5;
    A[2].entries[0]=2;
    A[2].entries[1]=3;
    A[2].entries[2]=1;

    x = linbox_modn_sparse_matrix_solve(p,3,3,A,&b,1);

    if (x[0] != 73) return false;
    if (x[1] != 76) return false;
    if (x[2] != 10) return false;

    return true;
}
#else
bool testSolveSparseSage(){return true;}
#endif

/**
 * Testing regresssion for issue 56 https://github.com/linbox-team/linbox/issues/56
 * reported by Vincent Delecroix
 */
bool testFlatDixonSolver (const Specifier& m){
        // creating LinBox matrices and vectors
    Givaro::ZRing<Integer> ZZ;
    typedef DenseVector<Givaro::ZRing<Integer> > DenseVector;

    SparseMatrix<Givaro::ZRing<Integer> > M (ZZ,1,2);
    Givaro::ZRing<Integer>::Element D; // denominator of the solution
    DenseVector A(ZZ, M.coldim()); // numerator of the solution
    DenseVector B(ZZ, M.rowdim()); // Right handside of the system

    M.setEntry(0,0,1);
    M.setEntry(0,1,1);
    ZZ.assign(B[0],1);

        // solving via Sparse Elimination
    solve (A, D, M, B, m);

    if (!ZZ.areEqual(A[0],ZZ.one) || !ZZ.areEqual(A[1],ZZ.zero) || !ZZ.areEqual(D,ZZ.one)) {
        std::cerr<<"Fail solving a flat system over QQ with a SparseMatrix"<<std::endl;
        return false;
    }

    return true;
}

bool testFlatDixonSolver2 (const Specifier& m){
        // creating LinBox matrices and vectors
    Givaro::ZRing<Integer> ZZ;
    typedef DenseVector<Givaro::ZRing<Integer> > DenseVector;

    SparseMatrix<Givaro::ZRing<Integer> > M (ZZ,1,2);
    Givaro::ZRing<Integer>::Element D; // denominator of the solution
    DenseVector A(ZZ, M.coldim()); // numerator of the solution
    DenseVector B(ZZ, M.rowdim()); // Right handside of the system

    M.setEntry(0,0,1);
    M.setEntry(0,1,0);
    ZZ.assign(B[0],1);

        // solving via Sparse Elimination
    solve (A, D, M, B, m);

    if (!ZZ.areEqual(A[0],ZZ.one) || !ZZ.areEqual(D,ZZ.one)) {
        std::cerr<<"A = "<<A<<" D = "<<D<<std::endl;
        std::cerr<<"Fail solving a flat system over QQ with a SparseMatrix"<<std::endl;
        return false;
    }

    return true;
}

bool testTallDixonSolver (const Specifier& m){
        // creating LinBox matrices and vectors
    Givaro::ZRing<Integer> ZZ;
    typedef DenseVector<Givaro::ZRing<Integer> > DenseVector;

    SparseMatrix<Givaro::ZRing<Integer> > M (ZZ,2,1);
    Givaro::ZRing<Integer>::Element D; // denominator of the solution
    DenseVector A(ZZ, M.coldim()); // numerator of the solution
    DenseVector B(ZZ, M.rowdim()); // Right handside of the system

    M.setEntry(0,0,1);
    M.setEntry(1,0,1);
    ZZ.assign(B[0],1);
    ZZ.assign(B[1],1);

        // solving via Sparse Elimination
    solve (A, D, M, B, m);

    if (!ZZ.areEqual(A[0],ZZ.one) || !ZZ.areEqual(D,ZZ.one)) {
        std::cerr<<"Fail solving a tall system over QQ with a SparseMatrix"<<std::endl;
        return false;
    }

    return true;

}

bool testSingularDixonSolver (const Specifier& m){
        // creating LinBox matrices and vectors
    Givaro::ZRing<Integer> ZZ;
    typedef DenseVector<Givaro::ZRing<Integer> > DenseVector;

    SparseMatrix<Givaro::ZRing<Integer> > M (ZZ,2,2);
    Givaro::ZRing<Integer>::Element D; // denominator of the solution
    DenseVector A(ZZ, M.coldim()); // numerator of the solution
    DenseVector B(ZZ, M.rowdim()); // Right handside of the system

    M.setEntry(0,0,-2);
    ZZ.assign(B[0],-4);

        // solving via Sparse Elimination
    solve (A, D, M, B, m);

    if (!ZZ.areEqual(A[0],Integer(2)) || !ZZ.areEqual(D,ZZ.one)) {
        std::cerr<<"A = "<<A<<" D = "<<D<<std::endl;
        std::cerr<<"Fail solving a singular system over QQ with a SparseMatrix"<<std::endl;
        return false;
    }
    return true;
}
bool testZeroDixonSolver (const Specifier& m){
        // creating LinBox matrices and vectors
    Givaro::ZRing<Integer> ZZ;
    typedef DenseVector<Givaro::ZRing<Integer> > DenseVector;

    SparseMatrix<Givaro::ZRing<Integer> > M (ZZ,1,1);
    Givaro::ZRing<Integer>::Element D; // denominator of the solution
    DenseVector A(ZZ, M.coldim()); // numerator of the solution
    DenseVector B(ZZ, M.rowdim()); // Right handside of the system

    M.setEntry(0,0,0);
    ZZ.assign(B[0],0);

        // solving via Sparse Elimination
    solve (A, D, M, B, m);

    if (!ZZ.areEqual(A[0],ZZ.zero) || !ZZ.areEqual(D,ZZ.one)) {
        std::cerr<<"A = "<<A<<" D = "<<D<<std::endl;
        std::cerr<<"Fail solving a zero over QQ with a SparseMatrix"<<std::endl;
        return false;
    }
    return true;
}

bool testZeroDimensionalCharpoly(){
    Givaro::ZRing<Integer> ZZ;
    DenseMatrix<Givaro::ZRing<Integer> > A (ZZ,0,0);
    DensePolynomial<Givaro::ZRing<Integer> > P (ZZ);
    PolynomialRing<Givaro::ZRing<Integer> > PR (ZZ);
    charpoly(P,A);
    return PR.isOne(P);
}

int main (int argc, char **argv)
{
    bool pass = true;

    pass &= testSolveSparse  ();
    pass &= testSolveSparseSage ();
    pass &= testFlatDixonSolver (Method::SparseElimination());
    pass &= testFlatDixonSolver2 (Method::SparseElimination());
    pass &= testTallDixonSolver (Method::SparseElimination());
    pass &= testFlatDixonSolver (Method::BlasElimination());
    pass &= testFlatDixonSolver2 (Method::BlasElimination());
    pass &= testTallDixonSolver (Method::BlasElimination());
    pass &= testFlatDixonSolver (Method::Wiedemann());
    pass &= testFlatDixonSolver2 (Method::Wiedemann());
    pass &= testTallDixonSolver (Method::Wiedemann());
    pass &= testSingularDixonSolver (Method::SparseElimination());
    pass &= testZeroDixonSolver (Method::SparseElimination());
    pass &= testSingularDixonSolver (Method::BlasElimination());
    pass &= testZeroDixonSolver (Method::BlasElimination());
    pass &= testZeroDimensionalCharpoly ();

    return pass ? 0 : -1;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016, Shogun-Toolbox e.V. <shogun-team@shogun-toolbox.org>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *  3. Neither the name of the copyright holder nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: 2016 Pan Deng, Soumyajit De, Heiko Strathmann, Viktor Gal
 */

#include <shogun/mathematics/linalg/LinalgBackendEigen.h>
#include <shogun/mathematics/linalg/LinalgEnums.h>
#include <shogun/mathematics/linalg/LinalgMacros.h>

using namespace shogun;

#define BACKEND_GENERIC_CHOLESKY_FACTOR(Type, Container)                       \
	Container<Type> LinalgBackendEigen::cholesky_factor(                       \
	    const Container<Type>& A, const bool lower) const                      \
	{                                                                          \
		return cholesky_factor_impl(A, lower);                                 \
	}
DEFINE_FOR_NON_INTEGER_PTYPE(BACKEND_GENERIC_CHOLESKY_FACTOR, SGMatrix)
#undef BACKEND_GENERIC_CHOLESKY_FACTOR

#define BACKEND_GENERIC_LDLT_FACTOR(Type, Container)                           \
	void LinalgBackendEigen::ldlt_factor(                                      \
	    const Container<Type>& A, Container<Type>& L, SGVector<Type>& d,       \
	    SGVector<index_t>& p, const bool lower) const                          \
	{                                                                          \
		return ldlt_factor_impl(A, L, d, p, lower);                            \
	}
DEFINE_FOR_NON_INTEGER_PTYPE(BACKEND_GENERIC_LDLT_FACTOR, SGMatrix)
#undef BACKEND_GENERIC_LDLT_FACTOR

#define BACKEND_GENERIC_SVD(Type, Container)                                   \
	void LinalgBackendEigen::svd(                                              \
	    const Container<Type>& A, SGVector<Type> s, Container<Type> U,         \
	    bool thin_U, linalg::SVDAlgorithm alg) const                           \
	{                                                                          \
		return svd_impl(A, s, U, thin_U, alg);                                 \
	}
DEFINE_FOR_NON_INTEGER_PTYPE(BACKEND_GENERIC_SVD, SGMatrix)
#undef BACKEND_GENERIC_SVD

#undef DEFINE_FOR_ALL_PTYPE
#undef DEFINE_FOR_REAL_PTYPE
#undef DEFINE_FOR_NON_INTEGER_PTYPE
#undef DEFINE_FOR_NUMERIC_PTYPE

template <typename T>
SGMatrix<T> LinalgBackendEigen::cholesky_factor_impl(
    const SGMatrix<T>& A, const bool lower) const
{
	SGMatrix<T> c(A.num_rows, A.num_cols);
	set_const(c, 0);
	typename SGMatrix<T>::EigenMatrixXtMap A_eig = A;
	typename SGMatrix<T>::EigenMatrixXtMap c_eig = c;

	Eigen::LLT<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>> llt(A_eig);

	// compute matrix L or U
	if (lower == false)
		c_eig = llt.matrixU();
	else
		c_eig = llt.matrixL();

	/*
	 * checking for success
	 *
	 * 0: Eigen::Success. Decomposition was successful
	 * 1: Eigen::NumericalIssue. The provided data did not satisfy the
	 * prerequisites.
	 */
	REQUIRE(
	    llt.info() != Eigen::NumericalIssue,
	    "Matrix is not Hermitian positive definite!\n");

	return c;
}

template <typename T>
void LinalgBackendEigen::ldlt_factor_impl(
    const SGMatrix<T>& A, SGMatrix<T>& L, SGVector<T>& d, SGVector<index_t>& p,
    const bool lower) const
{
	set_const(L, 0);
	typename SGMatrix<T>::EigenMatrixXtMap A_eig = A;
	typename SGMatrix<T>::EigenMatrixXtMap L_eig = L;
	typename SGVector<T>::EigenVectorXtMap d_eig = d;
	typename SGVector<index_t>::EigenVectorXtMap p_eig = p;

	Eigen::LDLT<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>> ldlt(A_eig);

	d_eig = ldlt.vectorD().template cast<T>();
	if (lower)
		L_eig = ldlt.matrixL();
	else
		L_eig = ldlt.matrixU();

	// flatten N*1 matrix into vector
	p_eig = ldlt.transpositionsP().indices().template cast<index_t>();

	REQUIRE(
	    ldlt.info() != Eigen::NumericalIssue,
	    "The factorization failed because of a zero pivot.\n");
}

template <typename T>
void LinalgBackendEigen::svd_impl(
    const SGMatrix<T>& A, SGVector<T>& s, SGMatrix<T>& U, bool thin_U,
    linalg::SVDAlgorithm alg) const
{
	typename SGMatrix<T>::EigenMatrixXtMap A_eig = A;
	typename SGVector<T>::EigenVectorXtMap s_eig = s;
	typename SGMatrix<T>::EigenMatrixXtMap U_eig = U;

	switch (alg)
	{
	case linalg::SVDAlgorithm::BidiagonalDivideConquer:
	{
#if EIGEN_VERSION_AT_LEAST(3, 3, 0)
		auto svd_eig =
		    A_eig.bdcSvd(thin_U ? Eigen::ComputeThinU : Eigen::ComputeFullU);
		s_eig = svd_eig.singularValues().template cast<T>();
		U_eig = svd_eig.matrixU().template cast<T>();
		break;
#else
		SG_SWARNING(
		    "At least Eigen 3.3 is required for BDC-SVD.\n"
		    "Falling back on Jacobi-SVD.\n")
#endif
	}

	case linalg::SVDAlgorithm::Jacobi:
	{
		auto svd_eig =
		    A_eig.jacobiSvd(thin_U ? Eigen::ComputeThinU : Eigen::ComputeFullU);
		s_eig = svd_eig.singularValues().template cast<T>();
		U_eig = svd_eig.matrixU().template cast<T>();
		break;
	}
	}
}
<commit_msg>Building BDC-SVD templates OOMs on 32 Bit ARM hardware Adding conditional with fallback to Jacobi-SVD<commit_after>/*
 * Copyright (c) 2016, Shogun-Toolbox e.V. <shogun-team@shogun-toolbox.org>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *  3. Neither the name of the copyright holder nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: 2016 Pan Deng, Soumyajit De, Heiko Strathmann, Viktor Gal
 */

#include <shogun/mathematics/linalg/LinalgBackendEigen.h>
#include <shogun/mathematics/linalg/LinalgEnums.h>
#include <shogun/mathematics/linalg/LinalgMacros.h>

using namespace shogun;

#define BACKEND_GENERIC_CHOLESKY_FACTOR(Type, Container)                       \
	Container<Type> LinalgBackendEigen::cholesky_factor(                       \
	    const Container<Type>& A, const bool lower) const                      \
	{                                                                          \
		return cholesky_factor_impl(A, lower);                                 \
	}
DEFINE_FOR_NON_INTEGER_PTYPE(BACKEND_GENERIC_CHOLESKY_FACTOR, SGMatrix)
#undef BACKEND_GENERIC_CHOLESKY_FACTOR

#define BACKEND_GENERIC_LDLT_FACTOR(Type, Container)                           \
	void LinalgBackendEigen::ldlt_factor(                                      \
	    const Container<Type>& A, Container<Type>& L, SGVector<Type>& d,       \
	    SGVector<index_t>& p, const bool lower) const                          \
	{                                                                          \
		return ldlt_factor_impl(A, L, d, p, lower);                            \
	}
DEFINE_FOR_NON_INTEGER_PTYPE(BACKEND_GENERIC_LDLT_FACTOR, SGMatrix)
#undef BACKEND_GENERIC_LDLT_FACTOR

#define BACKEND_GENERIC_SVD(Type, Container)                                   \
	void LinalgBackendEigen::svd(                                              \
	    const Container<Type>& A, SGVector<Type> s, Container<Type> U,         \
	    bool thin_U, linalg::SVDAlgorithm alg) const                           \
	{                                                                          \
		return svd_impl(A, s, U, thin_U, alg);                                 \
	}
DEFINE_FOR_NON_INTEGER_PTYPE(BACKEND_GENERIC_SVD, SGMatrix)
#undef BACKEND_GENERIC_SVD

#undef DEFINE_FOR_ALL_PTYPE
#undef DEFINE_FOR_REAL_PTYPE
#undef DEFINE_FOR_NON_INTEGER_PTYPE
#undef DEFINE_FOR_NUMERIC_PTYPE

template <typename T>
SGMatrix<T> LinalgBackendEigen::cholesky_factor_impl(
    const SGMatrix<T>& A, const bool lower) const
{
	SGMatrix<T> c(A.num_rows, A.num_cols);
	set_const(c, 0);
	typename SGMatrix<T>::EigenMatrixXtMap A_eig = A;
	typename SGMatrix<T>::EigenMatrixXtMap c_eig = c;

	Eigen::LLT<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>> llt(A_eig);

	// compute matrix L or U
	if (lower == false)
		c_eig = llt.matrixU();
	else
		c_eig = llt.matrixL();

	/*
	 * checking for success
	 *
	 * 0: Eigen::Success. Decomposition was successful
	 * 1: Eigen::NumericalIssue. The provided data did not satisfy the
	 * prerequisites.
	 */
	REQUIRE(
	    llt.info() != Eigen::NumericalIssue,
	    "Matrix is not Hermitian positive definite!\n");

	return c;
}

template <typename T>
void LinalgBackendEigen::ldlt_factor_impl(
    const SGMatrix<T>& A, SGMatrix<T>& L, SGVector<T>& d, SGVector<index_t>& p,
    const bool lower) const
{
	set_const(L, 0);
	typename SGMatrix<T>::EigenMatrixXtMap A_eig = A;
	typename SGMatrix<T>::EigenMatrixXtMap L_eig = L;
	typename SGVector<T>::EigenVectorXtMap d_eig = d;
	typename SGVector<index_t>::EigenVectorXtMap p_eig = p;

	Eigen::LDLT<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>> ldlt(A_eig);

	d_eig = ldlt.vectorD().template cast<T>();
	if (lower)
		L_eig = ldlt.matrixL();
	else
		L_eig = ldlt.matrixU();

	// flatten N*1 matrix into vector
	p_eig = ldlt.transpositionsP().indices().template cast<index_t>();

	REQUIRE(
	    ldlt.info() != Eigen::NumericalIssue,
	    "The factorization failed because of a zero pivot.\n");
}

template <typename T>
void LinalgBackendEigen::svd_impl(
    const SGMatrix<T>& A, SGVector<T>& s, SGMatrix<T>& U, bool thin_U,
    linalg::SVDAlgorithm alg) const
{
	typename SGMatrix<T>::EigenMatrixXtMap A_eig = A;
	typename SGVector<T>::EigenVectorXtMap s_eig = s;
	typename SGMatrix<T>::EigenMatrixXtMap U_eig = U;

	switch (alg)
	{
	case linalg::SVDAlgorithm::BidiagonalDivideConquer:
	{
// Building BDC-SVD templates OOMs on 32 Bit ARM hardware
#if	(defined(__arm__) || defined (__thumb__) || defined(__TARGET_ARCH_ARM) ||	\
	 defined(__TARGET_ARCH_THUMB) || defined (_ARM) || defined(_M_ARM) ||		\
	 defined(_M_ARMT) || defined(__arm)) && !defined(__aarch64__)
		SG_SWARNING(
		    "BDC-SVD is not supported on 32 Bit ARM hardware.\n"
		    "Falling back on Jacobi-SVD.\n")
#elif EIGEN_VERSION_AT_LEAST(3, 3, 0)
		auto svd_eig =
		    A_eig.bdcSvd(thin_U ? Eigen::ComputeThinU : Eigen::ComputeFullU);
		s_eig = svd_eig.singularValues().template cast<T>();
		U_eig = svd_eig.matrixU().template cast<T>();
		break;
#else
		SG_SWARNING(
		    "At least Eigen 3.3 is required for BDC-SVD.\n"
		    "Falling back on Jacobi-SVD.\n")
#endif
	}

	case linalg::SVDAlgorithm::Jacobi:
	{
		auto svd_eig =
		    A_eig.jacobiSvd(thin_U ? Eigen::ComputeThinU : Eigen::ComputeFullU);
		s_eig = svd_eig.singularValues().template cast<T>();
		U_eig = svd_eig.matrixU().template cast<T>();
		break;
	}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, Franz Hollerer. All rights reserved.
// This code is licensed under the MIT License (MIT).
// See LICENSE file for full details.
#include <iostream>
#include <unistd.h>
#include <catch/catch.hpp>
#include <hodea/core/cstdint.hpp>
#include <hodea/core/htsc.hpp>

using namespace hodea;

TEST_CASE("htsc counter clock ", "[htsc_counter_clk]")
{
    /*
     * The time base used by the Linux kernel depends on the
     * configuration and can determined at runtime using sysconf.
     *
     * Unfortunately, we need a constant expression for our htsc
     * in order to calculate the ticks at compile time.
     *
     * Therefore, we made an assumption on the Linux configuration.
     * This lines need to be changed if our assumption is wrong.
     */
    long htsc_clk = Htsc_timer::counter_clk_hz;
    long linux_clk = sysconf(_SC_CLK_TCK);

    REQUIRE(htsc_clk == linux_clk);
}

TEST_CASE("htsc.elapsed()", "[htsc_elapsed]")
{
    REQUIRE(htsc.elapsed(0, 0) == 0);
    REQUIRE(htsc.elapsed(0, 1) == 1);

    Htsc_ticks elapsed;

    elapsed = htsc.elapsed(Htsc_timer::counter_msk, 0);
    REQUIRE(elapsed == 1);

    elapsed = htsc.elapsed(Htsc_timer::counter_msk - 2, 1);
    REQUIRE(elapsed == 4);
}

TEST_CASE("htsc.is_elapsed()", "[htsc_is_elapsed]")
{
    Htsc_ticks t1 = htsc.timestamp();

    REQUIRE(htsc.is_elapsed(t1, Htsc_timer::counter_clk_hz / 10) == false);
    usleep(200000);
    REQUIRE(htsc.is_elapsed(t1, Htsc_timer::counter_clk_hz / 10) == true);
}

<commit_msg>commit before removing<commit_after>// Copyright (c) 2017, Franz Hollerer. All rights reserved.
// This code is licensed under the MIT License (MIT).
// See LICENSE file for full details.
#include <iostream>
#include <unistd.h>
#include <catch/catch.hpp>
#include <hodea/core/cstdint.hpp>
#include <hodea/core/htsc.hpp>

using namespace hodea;

constexpr long clk_hz = htsc::counter_clk_hz;

TEST_CASE("htsc counter clock ", "[htsc_counter_clk]")
{
    /*
     * The time base used by the Linux kernel depends on the
     * configuration and can determined at runtime using sysconf.
     *
     * Unfortunately, we need a constant expression for our htsc
     * in order to calculate the ticks at compile time.
     *
     * Therefore, we made an assumption on the Linux configuration.
     * This lines need to be changed if our assumption is wrong.
     */
    long linux_clk = sysconf(_SC_CLK_TCK);

    REQUIRE(clk_hz == linux_clk);
}

TEST_CASE("htsc::elapsed()", "[htsc_elapsed]")
{
    REQUIRE(htsc::elapsed(0, 0) == 0);
    REQUIRE(htsc::elapsed(0, 1) == 1);

    htsc::Ticks elapsed;

    elapsed = htsc::elapsed(htsc::counter_msk, 0);
    REQUIRE(elapsed == 1);

    elapsed = htsc::elapsed(htsc::counter_msk - 2, 1);
    REQUIRE(elapsed == 4);
}

TEST_CASE("htsc::is_elapsed()", "[htsc_is_elapsed]")
{
    htsc::Ticks t1 = htsc::timestamp();

    REQUIRE(htsc::is_elapsed(t1, clk_hz / 10) == false);
    usleep(200000);
    REQUIRE(htsc::is_elapsed(t1, clk_hz / 10) == true);
}

TEST_CASE("htsc::is_elapsed_repetitive()", "[htsc_is_elapsed_repetitive]")
{
    htsc::Ticks ts_start = htsc::timestamp();
    htsc::Ticks ts_start_moving = ts_start;

    for (int i = 0; i < 3; ++i) {
        while (!htsc::is_elapsed_repetitive(ts_start_moving,  clk_hz / 10))
            ;
    }

    htsc::Ticks ts_end = htsc::timestamp();
    REQUIRE(htsc::elapsed(ts_start, ts_end) >= (3 * clk_hz / 10));
}

TEST_CASE("htsc::delay()", "[htsc_delay]")
{
    htsc::Ticks ts_start = htsc::timestamp();
    htsc::delay(clk_hz / 10);
    htsc::Ticks ts_end = htsc::timestamp();
    REQUIRE(htsc::elapsed(ts_start, ts_end) >= (clk_hz / 10));
}

<|endoftext|>


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

#include "tools/android/forwarder2/daemon.h"

#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include <cstdlib>
#include <cstring>
#include <string>

#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/posix/eintr_wrapper.h"
#include "base/safe_strerror_posix.h"
#include "base/string_number_conversions.h"
#include "base/stringprintf.h"
#include "tools/android/forwarder2/common.h"
#include "tools/android/forwarder2/socket.h"

namespace forwarder2 {
namespace {

const int kBufferSize = 256;

// Timeout constant used for polling when connecting to the daemon's Unix Domain
// Socket and also when waiting for its death when it is killed.
const int kNumTries = 100;
const int kIdleTimeMSec = 20;

void InitLoggingForDaemon(const std::string& log_file) {
  CHECK(
      logging::InitLogging(
          log_file.c_str(),
          log_file.empty() ?
              logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG : logging::LOG_ONLY_TO_FILE,
          logging::DONT_LOCK_LOG_FILE, logging::APPEND_TO_OLD_LOG_FILE,
          logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS));
}

bool RunServerAcceptLoop(const std::string& welcome_message,
                         Socket* server_socket,
                         Daemon::ServerDelegate* server_delegate) {
  bool failed = false;
  for (;;) {
    scoped_ptr<Socket> client_socket(new Socket());
    if (!server_socket->Accept(client_socket.get())) {
      if (server_socket->exited())
        break;
      PError("Accept()");
      failed = true;
      break;
    }
    if (!client_socket->Write(welcome_message.c_str(),
                              welcome_message.length() + 1)) {
      PError("Write()");
      failed = true;
      continue;
    }
    server_delegate->OnClientConnected(client_socket.Pass());
  }
  server_delegate->OnServerExited();
  return !failed;
}

void SigChildHandler(int signal_number) {
  DCHECK_EQ(signal_number, SIGCHLD);
  int status;
  pid_t child_pid = waitpid(-1 /* any child */, &status, WNOHANG);
  if (child_pid < 0) {
    PError("waitpid");
    return;
  }
  if (child_pid == 0)
    return;
  if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
    return;
  // Avoid using StringAppendF() since it's unsafe in a signal handler due to
  // its use of LOG().
  FixedSizeStringBuilder<256> string_builder;
  string_builder.Append("Daemon (pid=%d) died unexpectedly with ", child_pid);
  if (WIFEXITED(status))
    string_builder.Append("status %d.", WEXITSTATUS(status));
  else if (WIFSIGNALED(status))
    string_builder.Append("signal %d.", WTERMSIG(status));
  else
    string_builder.Append("unknown reason.");
  SIGNAL_SAFE_LOG(ERROR, string_builder.buffer());
}

// Note that 0 is written to |lock_owner_pid| in case the file is not locked.
bool GetFileLockOwnerPid(int fd, pid_t* lock_owner_pid) {
  struct flock lock_info = {};
  lock_info.l_type = F_WRLCK;
  lock_info.l_whence = SEEK_CUR;
  const int ret = HANDLE_EINTR(fcntl(fd, F_GETLK, &lock_info));
  if (ret < 0) {
    if (errno == EBADF) {
      // Assume that the provided file descriptor corresponding to the PID file
      // was valid until the daemon removed this file.
      *lock_owner_pid = 0;
      return true;
    }
    PError("fcntl");
    return false;
  }
  if (lock_info.l_type == F_UNLCK) {
    *lock_owner_pid = 0;
    return true;
  }
  CHECK_EQ(F_WRLCK /* exclusive lock */, lock_info.l_type);
  *lock_owner_pid = lock_info.l_pid;
  return true;
}

scoped_ptr<Socket> ConnectToUnixDomainSocket(
    const std::string& socket_name,
    int tries_count,
    int idle_time_msec,
    const std::string& expected_welcome_message) {
  for (int i = 0; i < tries_count; ++i) {
    scoped_ptr<Socket> socket(new Socket());
    if (!socket->ConnectUnix(socket_name, true)) {
      if (idle_time_msec)
        usleep(idle_time_msec * 1000);
      continue;
    }
    char buf[kBufferSize];
    DCHECK(expected_welcome_message.length() + 1 <= sizeof(buf));
    memset(buf, 0, sizeof(buf));
    if (socket->Read(buf, sizeof(buf)) < 0) {
      perror("read");
      continue;
    }
    if (expected_welcome_message != buf) {
      LOG(ERROR) << "Unexpected message read from daemon: " << buf;
      break;
    }
    return socket.Pass();
  }
  return scoped_ptr<Socket>(NULL);
}

}  // namespace

// Handles creation and destruction of the PID file.
class Daemon::PIDFile {
 public:
  static bool Create(const std::string& path, scoped_ptr<PIDFile>* pid_file) {
    int pid_file_fd = HANDLE_EINTR(
        open(path.c_str(), O_CREAT | O_WRONLY, 0600));
    if (pid_file_fd < 0) {
      PError("open()");
      return false;
    }
    file_util::ScopedFD fd_closer(&pid_file_fd);
    struct flock lock_info = {};
    lock_info.l_type = F_WRLCK;
    lock_info.l_whence = SEEK_CUR;
    if (HANDLE_EINTR(fcntl(pid_file_fd, F_SETLK, &lock_info)) < 0) {
      if (errno == EAGAIN || errno == EACCES) {
        LOG(INFO) << "Daemon already running (PID file already locked)";
        // Don't consider this case as a failure. This can happen when trying to
        // spawn multiple daemons concurrently.
        return true;
      }
      PError("lockf()");
      return false;
    }
    const std::string pid_string = base::StringPrintf("%d\n", getpid());
    CHECK(HANDLE_EINTR(write(pid_file_fd, pid_string.c_str(),
                             pid_string.length())));
    pid_file->reset(new PIDFile(*fd_closer.release(), path));
    return true;
  }

  ~PIDFile() {
    CloseFD(fd_);  // This also releases the lock.
    if (remove(path_.c_str()) < 0)
      PError("remove");
  }

 private:
  PIDFile(int fd, const std::string& path) : fd_(fd), path_(path) {
    DCHECK(fd_ >= 0);
  }

  const int fd_;
  const std::string path_;

  DISALLOW_COPY_AND_ASSIGN(PIDFile);
};

Daemon::Daemon(const std::string& log_file_path,
               const std::string& pid_file_path,
               const std::string& identifier,
               ClientDelegate* client_delegate,
               ServerDelegate* server_delegate,
               GetExitNotifierFDCallback get_exit_fd_callback)
  : log_file_path_(log_file_path),
    pid_file_path_(pid_file_path),
    identifier_(identifier),
    client_delegate_(client_delegate),
    server_delegate_(server_delegate),
    get_exit_fd_callback_(get_exit_fd_callback) {
  DCHECK(client_delegate_);
  DCHECK(server_delegate_);
  DCHECK(get_exit_fd_callback_);
}

Daemon::~Daemon() {}

bool Daemon::SpawnIfNeeded() {
  const int kSingleTry = 1;
  const int kNoIdleTime = 0;
  scoped_ptr<Socket> client_socket = ConnectToUnixDomainSocket(
      identifier_, kSingleTry, kNoIdleTime, identifier_);
  if (!client_socket) {
    switch (fork()) {
      case -1:
        PError("fork()");
        return false;
      // Child.
      case 0: {
        DCHECK(!pid_file_);
        if (!PIDFile::Create(pid_file_path_, &pid_file_))
          exit(1);
        if (!pid_file_.get())  // Another daemon was spawn concurrently.
          exit(0);
        if (setsid() < 0) {  // Detach the child process from its parent.
          PError("setsid()");
          exit(1);
        }
        InitLoggingForDaemon(log_file_path_);
        CloseFD(STDIN_FILENO);
        CloseFD(STDOUT_FILENO);
        CloseFD(STDERR_FILENO);
        const int null_fd = open("/dev/null", O_RDWR);
        CHECK_EQ(null_fd, STDIN_FILENO);
        CHECK_EQ(dup(null_fd), STDOUT_FILENO);
        CHECK_EQ(dup(null_fd), STDERR_FILENO);
        Socket command_socket;
        if (!command_socket.BindUnix(identifier_, true)) {
          PError("bind()");
          exit(1);
        }
        server_delegate_->Init();
        command_socket.set_exit_notifier_fd(get_exit_fd_callback_());
        exit(!RunServerAcceptLoop(identifier_, &command_socket,
                                  server_delegate_));
      }
      default:
        break;
    }
  }
  // Parent.
  // Install the custom SIGCHLD handler.
  sigset_t blocked_signals_set;
  if (sigprocmask(0 /* first arg ignored */, NULL, &blocked_signals_set) < 0) {
    PError("sigprocmask()");
    return false;
  }
  struct sigaction old_action;
  struct sigaction new_action;
  memset(&new_action, 0, sizeof(new_action));
  new_action.sa_handler = SigChildHandler;
  new_action.sa_flags = SA_NOCLDSTOP;
  sigemptyset(&new_action.sa_mask);
  if (sigaction(SIGCHLD, &new_action, &old_action) < 0) {
    PError("sigaction()");
    return false;
  }
  // Connect to the daemon's Unix Domain Socket.
  bool failed = false;
  if (!client_socket) {
    client_socket = ConnectToUnixDomainSocket(
        identifier_, kNumTries, kIdleTimeMSec, identifier_);
    if (!client_socket) {
      LOG(ERROR) << "Could not connect to daemon's Unix Daemon socket";
      failed = true;
    }
  }
  if (!failed)
    client_delegate_->OnDaemonReady(client_socket.get());
  // Restore the previous signal action for SIGCHLD.
  if (sigaction(SIGCHLD, &old_action, NULL) < 0) {
    PError("sigaction");
    failed = true;
  }
  return !failed;
}

bool Daemon::Kill() {
  int pid_file_fd = HANDLE_EINTR(open(pid_file_path_.c_str(), O_WRONLY));
  if (pid_file_fd < 0) {
    if (errno == ENOENT)
      return true;
    LOG(ERROR) << "Could not open " << pid_file_path_ << " in write mode: "
               << safe_strerror(errno);
    return false;
  }
  const file_util::ScopedFD fd_closer(&pid_file_fd);
  pid_t lock_owner_pid;
  if (!GetFileLockOwnerPid(pid_file_fd, &lock_owner_pid))
    return false;
  if (lock_owner_pid == 0)
    // No daemon running.
    return true;
  if (kill(lock_owner_pid, SIGTERM) < 0) {
    if (errno == ESRCH /* invalid PID */)
      // The daemon exited for some reason (e.g. kill by a process other than
      // us) right before the call to kill() above.
      return true;
    PError("kill");
    return false;
  }
  // Wait until the daemon exits. Rely on the fact that the daemon releases the
  // lock on the PID file when it exits.
  // TODO(pliard): Consider using a mutex + condition in shared memory to avoid
  // polling.
  for (int i = 0; i < kNumTries; ++i) {
    pid_t current_lock_owner_pid;
    if (!GetFileLockOwnerPid(pid_file_fd, &current_lock_owner_pid))
      return false;
    if (current_lock_owner_pid == 0)
      // The daemon released the PID file's lock.
      return true;
    // Since we are polling we might not see the 'daemon exited' event if
    // another daemon was spawned during our idle period.
    if (current_lock_owner_pid != lock_owner_pid) {
      LOG(WARNING) << "Daemon (pid=" << lock_owner_pid
                   << ") was successfully killed but a new daemon (pid="
                   << current_lock_owner_pid << ") seems to be running now.";
      return true;
    }
    usleep(kIdleTimeMSec * 1000);
  }
  LOG(ERROR) << "Timed out while killing daemon. "
                "It might still be tearing down.";
  return false;
}

}  // namespace forwarder2
<commit_msg>Create the forwarder2 device daemon's PID file with mode = 666.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "tools/android/forwarder2/daemon.h"

#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include <cstdlib>
#include <cstring>
#include <string>

#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/posix/eintr_wrapper.h"
#include "base/safe_strerror_posix.h"
#include "base/string_number_conversions.h"
#include "base/stringprintf.h"
#include "tools/android/forwarder2/common.h"
#include "tools/android/forwarder2/socket.h"

namespace forwarder2 {
namespace {

const int kBufferSize = 256;

// Timeout constant used for polling when connecting to the daemon's Unix Domain
// Socket and also when waiting for its death when it is killed.
const int kNumTries = 100;
const int kIdleTimeMSec = 20;

void InitLoggingForDaemon(const std::string& log_file) {
  CHECK(
      logging::InitLogging(
          log_file.c_str(),
          log_file.empty() ?
              logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG : logging::LOG_ONLY_TO_FILE,
          logging::DONT_LOCK_LOG_FILE, logging::APPEND_TO_OLD_LOG_FILE,
          logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS));
}

bool RunServerAcceptLoop(const std::string& welcome_message,
                         Socket* server_socket,
                         Daemon::ServerDelegate* server_delegate) {
  bool failed = false;
  for (;;) {
    scoped_ptr<Socket> client_socket(new Socket());
    if (!server_socket->Accept(client_socket.get())) {
      if (server_socket->exited())
        break;
      PError("Accept()");
      failed = true;
      break;
    }
    if (!client_socket->Write(welcome_message.c_str(),
                              welcome_message.length() + 1)) {
      PError("Write()");
      failed = true;
      continue;
    }
    server_delegate->OnClientConnected(client_socket.Pass());
  }
  server_delegate->OnServerExited();
  return !failed;
}

void SigChildHandler(int signal_number) {
  DCHECK_EQ(signal_number, SIGCHLD);
  int status;
  pid_t child_pid = waitpid(-1 /* any child */, &status, WNOHANG);
  if (child_pid < 0) {
    PError("waitpid");
    return;
  }
  if (child_pid == 0)
    return;
  if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
    return;
  // Avoid using StringAppendF() since it's unsafe in a signal handler due to
  // its use of LOG().
  FixedSizeStringBuilder<256> string_builder;
  string_builder.Append("Daemon (pid=%d) died unexpectedly with ", child_pid);
  if (WIFEXITED(status))
    string_builder.Append("status %d.", WEXITSTATUS(status));
  else if (WIFSIGNALED(status))
    string_builder.Append("signal %d.", WTERMSIG(status));
  else
    string_builder.Append("unknown reason.");
  SIGNAL_SAFE_LOG(ERROR, string_builder.buffer());
}

// Note that 0 is written to |lock_owner_pid| in case the file is not locked.
bool GetFileLockOwnerPid(int fd, pid_t* lock_owner_pid) {
  struct flock lock_info = {};
  lock_info.l_type = F_WRLCK;
  lock_info.l_whence = SEEK_CUR;
  const int ret = HANDLE_EINTR(fcntl(fd, F_GETLK, &lock_info));
  if (ret < 0) {
    if (errno == EBADF) {
      // Assume that the provided file descriptor corresponding to the PID file
      // was valid until the daemon removed this file.
      *lock_owner_pid = 0;
      return true;
    }
    PError("fcntl");
    return false;
  }
  if (lock_info.l_type == F_UNLCK) {
    *lock_owner_pid = 0;
    return true;
  }
  CHECK_EQ(F_WRLCK /* exclusive lock */, lock_info.l_type);
  *lock_owner_pid = lock_info.l_pid;
  return true;
}

scoped_ptr<Socket> ConnectToUnixDomainSocket(
    const std::string& socket_name,
    int tries_count,
    int idle_time_msec,
    const std::string& expected_welcome_message) {
  for (int i = 0; i < tries_count; ++i) {
    scoped_ptr<Socket> socket(new Socket());
    if (!socket->ConnectUnix(socket_name, true)) {
      if (idle_time_msec)
        usleep(idle_time_msec * 1000);
      continue;
    }
    char buf[kBufferSize];
    DCHECK(expected_welcome_message.length() + 1 <= sizeof(buf));
    memset(buf, 0, sizeof(buf));
    if (socket->Read(buf, sizeof(buf)) < 0) {
      perror("read");
      continue;
    }
    if (expected_welcome_message != buf) {
      LOG(ERROR) << "Unexpected message read from daemon: " << buf;
      break;
    }
    return socket.Pass();
  }
  return scoped_ptr<Socket>(NULL);
}

}  // namespace

// Handles creation and destruction of the PID file.
class Daemon::PIDFile {
 public:
  static bool Create(const std::string& path, scoped_ptr<PIDFile>* pid_file) {
    int pid_file_fd = HANDLE_EINTR(
        open(path.c_str(), O_CREAT | O_WRONLY, 0666));
    if (pid_file_fd < 0) {
      PError("open()");
      return false;
    }
    file_util::ScopedFD fd_closer(&pid_file_fd);
    struct flock lock_info = {};
    lock_info.l_type = F_WRLCK;
    lock_info.l_whence = SEEK_CUR;
    if (HANDLE_EINTR(fcntl(pid_file_fd, F_SETLK, &lock_info)) < 0) {
      if (errno == EAGAIN || errno == EACCES) {
        LOG(INFO) << "Daemon already running (PID file already locked)";
        // Don't consider this case as a failure. This can happen when trying to
        // spawn multiple daemons concurrently.
        return true;
      }
      PError("lockf()");
      return false;
    }
    const std::string pid_string = base::StringPrintf("%d\n", getpid());
    CHECK(HANDLE_EINTR(write(pid_file_fd, pid_string.c_str(),
                             pid_string.length())));
    pid_file->reset(new PIDFile(*fd_closer.release(), path));
    return true;
  }

  ~PIDFile() {
    CloseFD(fd_);  // This also releases the lock.
    if (remove(path_.c_str()) < 0)
      PError("remove");
  }

 private:
  PIDFile(int fd, const std::string& path) : fd_(fd), path_(path) {
    DCHECK(fd_ >= 0);
  }

  const int fd_;
  const std::string path_;

  DISALLOW_COPY_AND_ASSIGN(PIDFile);
};

Daemon::Daemon(const std::string& log_file_path,
               const std::string& pid_file_path,
               const std::string& identifier,
               ClientDelegate* client_delegate,
               ServerDelegate* server_delegate,
               GetExitNotifierFDCallback get_exit_fd_callback)
  : log_file_path_(log_file_path),
    pid_file_path_(pid_file_path),
    identifier_(identifier),
    client_delegate_(client_delegate),
    server_delegate_(server_delegate),
    get_exit_fd_callback_(get_exit_fd_callback) {
  DCHECK(client_delegate_);
  DCHECK(server_delegate_);
  DCHECK(get_exit_fd_callback_);
}

Daemon::~Daemon() {}

bool Daemon::SpawnIfNeeded() {
  const int kSingleTry = 1;
  const int kNoIdleTime = 0;
  scoped_ptr<Socket> client_socket = ConnectToUnixDomainSocket(
      identifier_, kSingleTry, kNoIdleTime, identifier_);
  if (!client_socket) {
    switch (fork()) {
      case -1:
        PError("fork()");
        return false;
      // Child.
      case 0: {
        DCHECK(!pid_file_);
        if (!PIDFile::Create(pid_file_path_, &pid_file_))
          exit(1);
        if (!pid_file_.get())  // Another daemon was spawn concurrently.
          exit(0);
        if (setsid() < 0) {  // Detach the child process from its parent.
          PError("setsid()");
          exit(1);
        }
        InitLoggingForDaemon(log_file_path_);
        CloseFD(STDIN_FILENO);
        CloseFD(STDOUT_FILENO);
        CloseFD(STDERR_FILENO);
        const int null_fd = open("/dev/null", O_RDWR);
        CHECK_EQ(null_fd, STDIN_FILENO);
        CHECK_EQ(dup(null_fd), STDOUT_FILENO);
        CHECK_EQ(dup(null_fd), STDERR_FILENO);
        Socket command_socket;
        if (!command_socket.BindUnix(identifier_, true)) {
          PError("bind()");
          exit(1);
        }
        server_delegate_->Init();
        command_socket.set_exit_notifier_fd(get_exit_fd_callback_());
        exit(!RunServerAcceptLoop(identifier_, &command_socket,
                                  server_delegate_));
      }
      default:
        break;
    }
  }
  // Parent.
  // Install the custom SIGCHLD handler.
  sigset_t blocked_signals_set;
  if (sigprocmask(0 /* first arg ignored */, NULL, &blocked_signals_set) < 0) {
    PError("sigprocmask()");
    return false;
  }
  struct sigaction old_action;
  struct sigaction new_action;
  memset(&new_action, 0, sizeof(new_action));
  new_action.sa_handler = SigChildHandler;
  new_action.sa_flags = SA_NOCLDSTOP;
  sigemptyset(&new_action.sa_mask);
  if (sigaction(SIGCHLD, &new_action, &old_action) < 0) {
    PError("sigaction()");
    return false;
  }
  // Connect to the daemon's Unix Domain Socket.
  bool failed = false;
  if (!client_socket) {
    client_socket = ConnectToUnixDomainSocket(
        identifier_, kNumTries, kIdleTimeMSec, identifier_);
    if (!client_socket) {
      LOG(ERROR) << "Could not connect to daemon's Unix Daemon socket";
      failed = true;
    }
  }
  if (!failed)
    client_delegate_->OnDaemonReady(client_socket.get());
  // Restore the previous signal action for SIGCHLD.
  if (sigaction(SIGCHLD, &old_action, NULL) < 0) {
    PError("sigaction");
    failed = true;
  }
  return !failed;
}

bool Daemon::Kill() {
  int pid_file_fd = HANDLE_EINTR(open(pid_file_path_.c_str(), O_WRONLY));
  if (pid_file_fd < 0) {
    if (errno == ENOENT)
      return true;
    LOG(ERROR) << "Could not open " << pid_file_path_ << " in write mode: "
               << safe_strerror(errno);
    return false;
  }
  const file_util::ScopedFD fd_closer(&pid_file_fd);
  pid_t lock_owner_pid;
  if (!GetFileLockOwnerPid(pid_file_fd, &lock_owner_pid))
    return false;
  if (lock_owner_pid == 0)
    // No daemon running.
    return true;
  if (kill(lock_owner_pid, SIGTERM) < 0) {
    if (errno == ESRCH /* invalid PID */)
      // The daemon exited for some reason (e.g. kill by a process other than
      // us) right before the call to kill() above.
      return true;
    PError("kill");
    return false;
  }
  // Wait until the daemon exits. Rely on the fact that the daemon releases the
  // lock on the PID file when it exits.
  // TODO(pliard): Consider using a mutex + condition in shared memory to avoid
  // polling.
  for (int i = 0; i < kNumTries; ++i) {
    pid_t current_lock_owner_pid;
    if (!GetFileLockOwnerPid(pid_file_fd, &current_lock_owner_pid))
      return false;
    if (current_lock_owner_pid == 0)
      // The daemon released the PID file's lock.
      return true;
    // Since we are polling we might not see the 'daemon exited' event if
    // another daemon was spawned during our idle period.
    if (current_lock_owner_pid != lock_owner_pid) {
      LOG(WARNING) << "Daemon (pid=" << lock_owner_pid
                   << ") was successfully killed but a new daemon (pid="
                   << current_lock_owner_pid << ") seems to be running now.";
      return true;
    }
    usleep(kIdleTimeMSec * 1000);
  }
  LOG(ERROR) << "Timed out while killing daemon. "
                "It might still be tearing down.";
  return false;
}

}  // namespace forwarder2
<|endoftext|>


<commit_before>//===--- swift_format_main.cpp - Swift code formatting tool ---------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  Formats Swift files or file ranges according to a set of parameters.
//
//===----------------------------------------------------------------------===//

#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
#include "swift/IDE/Formatting.h"
#include "swift/Option/Options.h"
#include "swift/Subsystems.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"

#include <string>
#include <vector>

using namespace swift;
using namespace swift::ide;
using namespace llvm::opt;

class FormatterDocument {
private:
  SourceManager SM;
  unsigned BufferID;
  CompilerInvocation CompInv;
  std::unique_ptr<ParserUnit> Parser;
  class FormatterDiagConsumer : public swift::DiagnosticConsumer {
    void handleDiagnostic(SourceManager &SM, SourceLoc Loc, DiagnosticKind Kind,
                          StringRef FormatString,
                          ArrayRef<DiagnosticArgument> FormatArgs,
                          const swift::DiagnosticInfo &Info) override {
      llvm::errs() << "Parse error: ";
      DiagnosticEngine::formatDiagnosticText(llvm::errs(), FormatString,
                                             FormatArgs);
      llvm::errs() << "\n";
    }
  } DiagConsumer;

public:
  FormatterDocument(std::unique_ptr<llvm::MemoryBuffer> Buffer) {
    // Formatting logic requires tokens on source file.
    CompInv.getLangOptions().KeepTokensInSourceFile = true;
    updateCode(std::move(Buffer));
  }

  void updateCode(std::unique_ptr<llvm::MemoryBuffer> Buffer) {
    BufferID = SM.addNewSourceBuffer(std::move(Buffer));
    Parser.reset(new ParserUnit(SM, BufferID, CompInv.getLangOptions(),
                                CompInv.getModuleName()));
    Parser->getDiagnosticEngine().addConsumer(DiagConsumer);
    auto &P = Parser->getParser();
    for (bool Done = false; !Done; Done = P.Tok.is(tok::eof)) {
      P.parseTopLevel();
    }
  }

  std::pair<LineRange, std::string> reformat(LineRange Range,
                                             CodeFormatOptions Options) {
    return ::reformat(Range, Options, SM, Parser->getSourceFile());
  }

  const llvm::MemoryBuffer &memBuffer() const {
    return *SM.getLLVMSourceMgr().getMemoryBuffer(BufferID);
  }
};

class SwiftFormatInvocation {
private:
  std::string MainExecutablePath;
  std::string OutputFilename = "-";
  std::vector<std::string> InputFilenames;
  CodeFormatOptions FormatOptions;
  bool InPlace = false;
  std::vector<std::string> LineRanges;

  bool parseLineRange(StringRef Input, unsigned &FromLine, unsigned &ToLine) {
    std::pair<StringRef, StringRef> LineRange = Input.split(":");
    return LineRange.first.getAsInteger(0, FromLine) ||
           LineRange.second.getAsInteger(0, ToLine);
  }

public:
  void setMainExecutablePath(const std::string &Path) {
    MainExecutablePath = Path;
  }

  const std::string &getOutputFilename() { return OutputFilename; }

  const std::vector<std::string> &getInputFilenames() { return InputFilenames; }

  const std::vector<std::string> &getLineRanges() { return LineRanges; }

  int parseArgs(ArrayRef<const char *> Args, DiagnosticEngine &Diags) {
    using namespace options;

    std::unique_ptr<llvm::opt::OptTable> Table = createSwiftOptTable();
    unsigned MissingIndex;
    unsigned MissingCount;
    llvm::opt::InputArgList ParsedArgs =
        Table->ParseArgs(Args, MissingIndex, MissingCount, SwiftFormatOption);
    if (MissingCount) {
      Diags.diagnose(SourceLoc(), diag::error_missing_arg_value,
                     ParsedArgs.getArgString(MissingIndex), MissingCount);
      return 1;
    }

    if (ParsedArgs.getLastArg(OPT_use_tabs))
      FormatOptions.UseTabs = true;

    if (ParsedArgs.getLastArg(OPT_indent_switch_case))
      FormatOptions.IndentSwitchCase = true;

    if (ParsedArgs.getLastArg(OPT_in_place))
      InPlace = true;

    if (const Arg *A = ParsedArgs.getLastArg(OPT_tab_width))
      if (StringRef(A->getValue()).getAsInteger(10, FormatOptions.TabWidth))
        Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
                       A->getAsString(ParsedArgs), A->getValue());

    if (const Arg *A = ParsedArgs.getLastArg(OPT_indent_width))
      if (StringRef(A->getValue()).getAsInteger(10, FormatOptions.IndentWidth))
        Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
                       A->getAsString(ParsedArgs), A->getValue());

    for (const Arg *A : ParsedArgs.filtered(OPT_line_range))
      LineRanges.push_back(A->getValue());

    if (ParsedArgs.hasArg(OPT_UNKNOWN)) {
      for (const Arg *A : ParsedArgs.filtered(OPT_UNKNOWN)) {
        Diags.diagnose(SourceLoc(), diag::error_unknown_arg,
                       A->getAsString(ParsedArgs));
      }
      return true;
    }

    if (ParsedArgs.getLastArg(OPT_help)) {
      std::string ExecutableName = llvm::sys::path::stem(MainExecutablePath);
      Table->PrintHelp(llvm::outs(), ExecutableName.c_str(),
                       "Swift Format Tool", options::SwiftFormatOption, 0);
      return 1;
    }

    for (const Arg *A : ParsedArgs.filtered(OPT_INPUT)) {
      InputFilenames.push_back(A->getValue());
    }

    if (const Arg *A = ParsedArgs.getLastArg(OPT_o)) {
      OutputFilename = A->getValue();
    }

    return 0;
  }

  /// Formats a filename and returns false if successful, true otherwise.
  bool format(StringRef Filename, DiagnosticEngine &Diags) {
    auto ErrOrBuf = llvm::MemoryBuffer::getFileOrSTDIN(Filename);
    if (!ErrOrBuf) {
      Diags.diagnose(SourceLoc(), diag::error_no_such_file_or_directory,
                     Filename);
      return true;
    }
    std::unique_ptr<llvm::MemoryBuffer> Code = std::move(ErrOrBuf.get());
    if (Code->getBufferSize() == 0) {
      // Assume empty files are formatted successfully.
      return false;
    }
    FormatterDocument Doc(std::move(Code));
    if (LineRanges.empty()) {
      LineRanges.push_back("1:" + std::to_string(UINT_MAX));
    }

    std::string Output = Doc.memBuffer().getBuffer();
    for (unsigned Range = 0; Range < LineRanges.size(); ++Range) {
      unsigned FromLine;
      unsigned ToLine;
      if (parseLineRange(LineRanges[Range], FromLine, ToLine)) {
        Diags.diagnose(SourceLoc(), diag::error_formatting_invalid_range);
        return true;
      }
      if (FromLine > ToLine) {
        Diags.diagnose(SourceLoc(), diag::error_formatting_invalid_range);
        return true;
      }
      for (unsigned Line = FromLine; Line <= ToLine; ++Line) {
        size_t Offset = getOffsetOfLine(Line, Output);
        ssize_t Length = getOffsetOfLine(Line + 1, Output) - 1 - Offset;
        if (Length < 0)
          break;

        std::string Formatted =
            Doc.reformat(LineRange(Line, 1), FormatOptions).second;
        if (Formatted.find_first_not_of(" \t\v\f", 0) == StringRef::npos)
          Formatted = "";

        Output.replace(Offset, Length, Formatted);
        Doc.updateCode(llvm::MemoryBuffer::getMemBuffer(Output));
      }
      if (Filename == "-" || (!InPlace && OutputFilename == "-")) {
        llvm::outs() << Output;
        return false;
      }
      std::error_code EC;
      StringRef Destination;
      if (InPlace)
        Destination = Filename;
      else
        Destination = OutputFilename;
      llvm::raw_fd_ostream out(Destination, EC, llvm::sys::fs::F_None);
      if (out.has_error() || EC) {
        Diags.diagnose(SourceLoc(), diag::error_opening_output, Filename,
                       EC.message());
        out.clear_error();
        return true;
      }
      out << Output;
    }
    return false;
  }
};

int swift_format_main(ArrayRef<const char *> Args, const char *Argv0,
                      void *MainAddr) {
  CompilerInstance Instance;
  PrintingDiagnosticConsumer PDC;
  Instance.addDiagnosticConsumer(&PDC);

  SwiftFormatInvocation Invocation;
  std::string MainExecutablePath =
      llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
  Invocation.setMainExecutablePath(MainExecutablePath);

  DiagnosticEngine &Diags = Instance.getDiags();
  if (Invocation.parseArgs(Args, Diags) != 0)
    return EXIT_FAILURE;

  std::vector<std::string> InputFiles = Invocation.getInputFilenames();
  unsigned NumInputFiles = InputFiles.size();
  if (NumInputFiles == 0) {
    // Read source code from standard input.
    Invocation.format("-", Diags);
  } else if (NumInputFiles == 1) {
    Invocation.format(InputFiles[0], Diags);
  } else {
    if (!Invocation.getLineRanges().empty()) {
      // We don't support formatting file ranges for multiple files.
      Instance.getDiags().diagnose(SourceLoc(),
                                   diag::error_formatting_multiple_file_ranges);
      return EXIT_FAILURE;
    }
    for (unsigned i = 0; i < NumInputFiles; ++i)
      Invocation.format(InputFiles[i], Diags);
  }

  return EXIT_SUCCESS;
}
<commit_msg>[swift-format] Set exec path in initializer (NFC) (#11973)<commit_after>//===--- swift_format_main.cpp - Swift code formatting tool ---------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  Formats Swift files or file ranges according to a set of parameters.
//
//===----------------------------------------------------------------------===//

#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
#include "swift/IDE/Formatting.h"
#include "swift/Option/Options.h"
#include "swift/Subsystems.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"

#include <string>
#include <vector>

using namespace swift;
using namespace swift::ide;
using namespace llvm::opt;

class FormatterDocument {
private:
  SourceManager SM;
  unsigned BufferID;
  CompilerInvocation CompInv;
  std::unique_ptr<ParserUnit> Parser;
  class FormatterDiagConsumer : public swift::DiagnosticConsumer {
    void handleDiagnostic(SourceManager &SM, SourceLoc Loc, DiagnosticKind Kind,
                          StringRef FormatString,
                          ArrayRef<DiagnosticArgument> FormatArgs,
                          const swift::DiagnosticInfo &Info) override {
      llvm::errs() << "Parse error: ";
      DiagnosticEngine::formatDiagnosticText(llvm::errs(), FormatString,
                                             FormatArgs);
      llvm::errs() << "\n";
    }
  } DiagConsumer;

public:
  FormatterDocument(std::unique_ptr<llvm::MemoryBuffer> Buffer) {
    // Formatting logic requires tokens on source file.
    CompInv.getLangOptions().KeepTokensInSourceFile = true;
    updateCode(std::move(Buffer));
  }

  void updateCode(std::unique_ptr<llvm::MemoryBuffer> Buffer) {
    BufferID = SM.addNewSourceBuffer(std::move(Buffer));
    Parser.reset(new ParserUnit(SM, BufferID, CompInv.getLangOptions(),
                                CompInv.getModuleName()));
    Parser->getDiagnosticEngine().addConsumer(DiagConsumer);
    auto &P = Parser->getParser();
    for (bool Done = false; !Done; Done = P.Tok.is(tok::eof)) {
      P.parseTopLevel();
    }
  }

  std::pair<LineRange, std::string> reformat(LineRange Range,
                                             CodeFormatOptions Options) {
    return ::reformat(Range, Options, SM, Parser->getSourceFile());
  }

  const llvm::MemoryBuffer &memBuffer() const {
    return *SM.getLLVMSourceMgr().getMemoryBuffer(BufferID);
  }
};

class SwiftFormatInvocation {
private:
  std::string MainExecutablePath;
  std::string OutputFilename = "-";
  std::vector<std::string> InputFilenames;
  CodeFormatOptions FormatOptions;
  bool InPlace = false;
  std::vector<std::string> LineRanges;

  bool parseLineRange(StringRef Input, unsigned &FromLine, unsigned &ToLine) {
    std::pair<StringRef, StringRef> LineRange = Input.split(":");
    return LineRange.first.getAsInteger(0, FromLine) ||
           LineRange.second.getAsInteger(0, ToLine);
  }

public:
  SwiftFormatInvocation(const std::string &ExecPath)
      : MainExecutablePath(ExecPath) {}

  const std::string &getOutputFilename() { return OutputFilename; }

  const std::vector<std::string> &getInputFilenames() { return InputFilenames; }

  const std::vector<std::string> &getLineRanges() { return LineRanges; }

  int parseArgs(ArrayRef<const char *> Args, DiagnosticEngine &Diags) {
    using namespace options;

    std::unique_ptr<llvm::opt::OptTable> Table = createSwiftOptTable();
    unsigned MissingIndex;
    unsigned MissingCount;
    llvm::opt::InputArgList ParsedArgs =
        Table->ParseArgs(Args, MissingIndex, MissingCount, SwiftFormatOption);
    if (MissingCount) {
      Diags.diagnose(SourceLoc(), diag::error_missing_arg_value,
                     ParsedArgs.getArgString(MissingIndex), MissingCount);
      return 1;
    }

    if (ParsedArgs.getLastArg(OPT_use_tabs))
      FormatOptions.UseTabs = true;

    if (ParsedArgs.getLastArg(OPT_indent_switch_case))
      FormatOptions.IndentSwitchCase = true;

    if (ParsedArgs.getLastArg(OPT_in_place))
      InPlace = true;

    if (const Arg *A = ParsedArgs.getLastArg(OPT_tab_width))
      if (StringRef(A->getValue()).getAsInteger(10, FormatOptions.TabWidth))
        Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
                       A->getAsString(ParsedArgs), A->getValue());

    if (const Arg *A = ParsedArgs.getLastArg(OPT_indent_width))
      if (StringRef(A->getValue()).getAsInteger(10, FormatOptions.IndentWidth))
        Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
                       A->getAsString(ParsedArgs), A->getValue());

    for (const Arg *A : ParsedArgs.filtered(OPT_line_range))
      LineRanges.push_back(A->getValue());

    if (ParsedArgs.hasArg(OPT_UNKNOWN)) {
      for (const Arg *A : ParsedArgs.filtered(OPT_UNKNOWN)) {
        Diags.diagnose(SourceLoc(), diag::error_unknown_arg,
                       A->getAsString(ParsedArgs));
      }
      return true;
    }

    if (ParsedArgs.getLastArg(OPT_help)) {
      std::string ExecutableName = llvm::sys::path::stem(MainExecutablePath);
      Table->PrintHelp(llvm::outs(), ExecutableName.c_str(),
                       "Swift Format Tool", options::SwiftFormatOption, 0);
      return 1;
    }

    for (const Arg *A : ParsedArgs.filtered(OPT_INPUT)) {
      InputFilenames.push_back(A->getValue());
    }

    if (const Arg *A = ParsedArgs.getLastArg(OPT_o)) {
      OutputFilename = A->getValue();
    }

    return 0;
  }

  /// Formats a filename and returns false if successful, true otherwise.
  bool format(StringRef Filename, DiagnosticEngine &Diags) {
    auto ErrOrBuf = llvm::MemoryBuffer::getFileOrSTDIN(Filename);
    if (!ErrOrBuf) {
      Diags.diagnose(SourceLoc(), diag::error_no_such_file_or_directory,
                     Filename);
      return true;
    }
    std::unique_ptr<llvm::MemoryBuffer> Code = std::move(ErrOrBuf.get());
    if (Code->getBufferSize() == 0) {
      // Assume empty files are formatted successfully.
      return false;
    }
    FormatterDocument Doc(std::move(Code));
    if (LineRanges.empty()) {
      LineRanges.push_back("1:" + std::to_string(UINT_MAX));
    }

    std::string Output = Doc.memBuffer().getBuffer();
    for (unsigned Range = 0; Range < LineRanges.size(); ++Range) {
      unsigned FromLine;
      unsigned ToLine;
      if (parseLineRange(LineRanges[Range], FromLine, ToLine)) {
        Diags.diagnose(SourceLoc(), diag::error_formatting_invalid_range);
        return true;
      }
      if (FromLine > ToLine) {
        Diags.diagnose(SourceLoc(), diag::error_formatting_invalid_range);
        return true;
      }
      for (unsigned Line = FromLine; Line <= ToLine; ++Line) {
        size_t Offset = getOffsetOfLine(Line, Output);
        ssize_t Length = getOffsetOfLine(Line + 1, Output) - 1 - Offset;
        if (Length < 0)
          break;

        std::string Formatted =
            Doc.reformat(LineRange(Line, 1), FormatOptions).second;
        if (Formatted.find_first_not_of(" \t\v\f", 0) == StringRef::npos)
          Formatted = "";

        Output.replace(Offset, Length, Formatted);
        Doc.updateCode(llvm::MemoryBuffer::getMemBuffer(Output));
      }
      if (Filename == "-" || (!InPlace && OutputFilename == "-")) {
        llvm::outs() << Output;
        return false;
      }
      std::error_code EC;
      StringRef Destination;
      if (InPlace)
        Destination = Filename;
      else
        Destination = OutputFilename;
      llvm::raw_fd_ostream out(Destination, EC, llvm::sys::fs::F_None);
      if (out.has_error() || EC) {
        Diags.diagnose(SourceLoc(), diag::error_opening_output, Filename,
                       EC.message());
        out.clear_error();
        return true;
      }
      out << Output;
    }
    return false;
  }
};

int swift_format_main(ArrayRef<const char *> Args, const char *Argv0,
                      void *MainAddr) {
  CompilerInstance Instance;
  PrintingDiagnosticConsumer PDC;
  Instance.addDiagnosticConsumer(&PDC);

  SwiftFormatInvocation Invocation(
      llvm::sys::fs::getMainExecutable(Argv0, MainAddr));

  DiagnosticEngine &Diags = Instance.getDiags();
  if (Invocation.parseArgs(Args, Diags) != 0)
    return EXIT_FAILURE;

  std::vector<std::string> InputFiles = Invocation.getInputFilenames();
  unsigned NumInputFiles = InputFiles.size();
  if (NumInputFiles == 0) {
    // Read source code from standard input.
    Invocation.format("-", Diags);
  } else if (NumInputFiles == 1) {
    Invocation.format(InputFiles[0], Diags);
  } else {
    if (!Invocation.getLineRanges().empty()) {
      // We don't support formatting file ranges for multiple files.
      Instance.getDiags().diagnose(SourceLoc(),
                                   diag::error_formatting_multiple_file_ranges);
      return EXIT_FAILURE;
    }
    for (unsigned i = 0; i < NumInputFiles; ++i)
      Invocation.format(InputFiles[i], Diags);
  }

  return EXIT_SUCCESS;
}
<|endoftext|>