Commit 180ba06e authored by BRAMAS Berenger's avatar BRAMAS Berenger
Browse files

Add an assert for the bitonic sort and unit test

parent 0dfdbfdf
......@@ -22,7 +22,7 @@
#include "FTrace.hpp"
#include "FMpi.hpp"
#include "FQuickSort.hpp"
#include "FAssert.hpp"
/** This class is a parallel bitonic sort
* it is based on the paper :
......@@ -148,6 +148,12 @@ public:
const int np = comm.processCount();
const int rank = comm.processId();
{// Work only for power of 2!
int flag = 1;
while(!(np & flag)) flag <<= 1;
FAssert(np == flag, "Bitonic sort work only with power of 2 for now.")
}
FQuickSort<SortType,CompareType,IndexType>::QsOmp(array, size);
const int logNp = int(log2(np));
......
// ===================================================================================
// Copyright ScalFmm 2011 INRIA, Olivier Coulaud, Bérenger Bramas, Matthias Messner
// olivier.coulaud@inria.fr, berenger.bramas@inria.fr
// This software is a computer program whose purpose is to compute the FMM.
//
// This software is governed by the CeCILL-C and LGPL licenses and
// abiding by the rules of distribution of free software.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public and CeCILL-C Licenses for more details.
// "http://www.cecill.info".
// "http://www.gnu.org/licenses".
// ===================================================================================
#ifndef UTESTMPIBITONIC_CPP
#define UTESTMPIBITONIC_CPP
#include "../Src/Utils/FGlobal.hpp"
#include "FUTester.hpp"
#include "../Src/Utils/FMpi.hpp"
#include "../Src/Utils/FBitonicSort.hpp"
#include <memory>
#include <limits>
#include <cstdlib>
// ==== CMAKE =====
// @FUSE_MPI
// ================
/** this class test the mpi quick sort */
class TestMpiBitonic : public FUTesterMpi<TestMpiBitonic> {
////////////////////////////////////////////////////////////
/// Check function
////////////////////////////////////////////////////////////
/** To test if an array is sorted */
template <class ValueType, class IndexType>
void CheckIfSorted(const ValueType array[], const IndexType size){
for(int idx = 1 ; idx < size ; ++idx){
uassert(array[idx-1] <= array[idx]);
}
}
/** To test if the global sorting is correct */
template <class ValueType, class IndexType>
void CheckBorder(const ValueType array[], const IndexType size){
const int myRank = app.global().processId();
const int nbProcess = app.global().processCount();
ValueType atMyLeft; // The value on my left [myRank-1][size-1]
ValueType atMyRight; // The value on my right[myRank+1][0]
ValueType myLeft; // My left value [myRank][0]
ValueType myRight; // My right value [myRank][size-1]
// If there is someone on my left
if(myRank != 0){
// If I do not have value I shoud replace it
if(size == 0){
// If there is no-one on my right I take the max
if(myRank == nbProcess-1){
myLeft = std::numeric_limits<ValueType>::max();
}
// [A] Else I receive the value from the right and say it is my left
else{
FMpi::Assert(MPI_Recv(&atMyRight, sizeof(atMyRight), MPI_BYTE, myRank+1, 0, app.global().getComm(), MPI_STATUS_IGNORE) , __LINE__);
myLeft = atMyRight;
}
}
else{
// Take my left value
myLeft = array[0];
}
// Send it to my left neighbors
FMpi::Assert(MPI_Send(&myLeft, sizeof(myLeft), MPI_BYTE , myRank-1, 0, app.global().getComm()) , __LINE__);
}
// If there is someone on my right
if(myRank != nbProcess-1){
// I should receive the value (if not already done in [A])
if(size != 0){
FMpi::Assert(MPI_Recv(&atMyRight, sizeof(atMyRight), MPI_BYTE, myRank+1, 0, app.global().getComm(), MPI_STATUS_IGNORE) , __LINE__);
}
// If I do not have value I shoud replace it
if(size == 0){
// If there is no-one on my left I take the min
if(myRank == 0){
myRight = std::numeric_limits<ValueType>::min();
}
// [B] Else I receive the value from the left and say it is my right
else{
FMpi::Assert(MPI_Recv(&atMyLeft, sizeof(atMyLeft), MPI_BYTE, myRank-1, 0, app.global().getComm(), MPI_STATUS_IGNORE) , __LINE__);
myRight = atMyLeft;
}
}
else{
// Take my right value
myRight = array[size-1];
}
// Send it to my right neighbors
FMpi::Assert(MPI_Send(&myRight, sizeof(myRight), MPI_BYTE , myRank+1, 0, app.global().getComm()) , __LINE__);
}
// If there is someone on my left
if(myRank != 0){
// If not already receive in [B]
if(size != 0){
FMpi::Assert(MPI_Recv(&atMyLeft, sizeof(atMyLeft), MPI_BYTE, myRank-1, 0, app.global().getComm(), MPI_STATUS_IGNORE) , __LINE__);
}
}
// Test only if I hold data and if someone on my left
if(myRank != 0 && size != 0){
uassert(atMyLeft <= myLeft);
}
// Test only if I hold data and if someone on my right
if(myRank != nbProcess-1 && size != 0){
uassert(myRight <= atMyRight);
}
}
////////////////////////////////////////////////////////////
/// The tests
////////////////////////////////////////////////////////////
void TestSmallSort(){
const int myRank = app.global().processId();
const int nbProcess = app.global().processCount();
const int nbElements = nbProcess;
std::unique_ptr<long[]> elements(new long[nbElements]);
for(int idx = 0 ; idx < nbElements ; ++idx){
elements[idx] = idx;
}
const int nbElementsInTest = app.global().reduceSum(nbElements);
FBitonicSort<long, long, int>::Sort(elements.get(), nbElements,app.global());
CheckIfSorted(elements.get(), nbElements);
CheckBorder(elements.get(), nbElements);
uassert(nbElementsInTest == app.global().reduceSum(nbElements));
}
void TestSameSort(){
const int myRank = app.global().processId();
const int nbProcess = app.global().processCount();
const int nbElements = nbProcess * 100;
std::unique_ptr<long[]> elements(new long[nbElements]);
for(int idx = 0 ; idx < nbElements ; ++idx){
elements[idx] = nbProcess;
}
const int nbElementsInTest = app.global().reduceSum(nbElements);
FBitonicSort<long, long, int>::Sort(elements.get(), nbElements,app.global());
CheckIfSorted(elements.get(), nbElements);
CheckBorder(elements.get(), nbElements);
uassert(nbElementsInTest == app.global().reduceSum(nbElements));
}
void TestUniqueSort(){
const int myRank = app.global().processId();
const int nbProcess = app.global().processCount();
const int nbElements = nbProcess * 100;
std::unique_ptr<long[]> elements(new long[nbElements]);
for(int idx = 0 ; idx < nbElements ; ++idx){
elements[idx] = myRank;
}
const int nbElementsInTest = app.global().reduceSum(nbElements);
FBitonicSort<long, long, int>::Sort(elements.get(), nbElements,app.global());
CheckIfSorted(elements.get(), nbElements);
CheckBorder(elements.get(), nbElements);
uassert(nbElementsInTest == app.global().reduceSum(nbElements));
}
void TestBigSort(){
const int myRank = app.global().processId();
const int nbProcess = app.global().processCount();
const int nbElements = 500;
std::unique_ptr<long[]> elements(new long[nbElements]);
for(int idx = 0 ; idx < nbElements ; ++idx){
elements[idx] = long(drand48() * 10000);
}
const int nbElementsInTest = app.global().reduceSum(nbElements);
FBitonicSort<long, long, int>::Sort(elements.get(), nbElements,app.global());
CheckIfSorted(elements.get(), nbElements);
CheckBorder(elements.get(), nbElements);
uassert(nbElementsInTest == app.global().reduceSum(nbElements));
}
////////////////////////////////////////////////////////////
/// Starter functions
////////////////////////////////////////////////////////////
// set test
void SetTests(){
AddTest(&TestMpiBitonic::TestSmallSort,"Test small sort");
AddTest(&TestMpiBitonic::TestSameSort,"Test with all the same value");
AddTest(&TestMpiBitonic::TestUniqueSort,"Test with unique value");
AddTest(&TestMpiBitonic::TestBigSort,"Test with random values");
}
public:
TestMpiBitonic(int argc,char ** argv) : FUTesterMpi(argc,argv){
}
};
// You must do this
TestClassMpi(TestMpiBitonic)
#endif // UTESTMPIBITONIC_CPP
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment