Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Smart Pointers support (see enhancement #194) #197

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 225 additions & 0 deletions applications/demos/nqueens/nqueens-smt.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
////////////////////////////////////////////////////////////////////////
// This file is part of Grappa, a system for scaling irregular
// applications on commodity clusters.

// Copyright (C) 2010-2014 University of Washington and Battelle
// Memorial Institute. University of Washington authorizes use of this
// Grappa software.

// Grappa is free software: you can redistribute it and/or modify it
// under the terms of the Affero General Public License as published
// by Affero, Inc., either version 1 of the License, or (at your
// option) any later version.

// Grappa 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
// Affero General Public License for more details.

// You should have received a copy of the Affero General Public
// License along with this program. If not, you may obtain one from
// http://www.affero.org/oagpl.html.
////////////////////////////////////////////////////////////////////////

#include <Grappa.hpp>
#include <SmartPointer.hpp>


using namespace Grappa;
using namespace std;


DEFINE_int64( n, 8, "Board size" );

GRAPPA_DEFINE_METRIC( SimpleMetric<double>, nqueens_runtime, 0.0 );




/*
* Each core maintains the number of solutions it has found + the board size
*/
int64_t nqSolutions;
int nqBoardSize;
GlobalCompletionEvent gce; // tasks synchronization



/*
* The main board class.
*
* The board is represented as a column array specifying the row position of the
* Queen on each column.
*/
class Board {
const size_t MINIMUM_BOARD_SIZE = 16; /* must be > 0 */
public:
Board(size_t size)
{
maximum = size > MINIMUM_BOARD_SIZE ? size : MINIMUM_BOARD_SIZE;
this->size = size;
columns = new int[maximum];
}

~Board() { delete [] columns; }


/*
* Checks whether it is safe to put a queen in row 'row'.
*/
bool isSafe(int row)
{
/* we check if putting a queen on row 'row' will cause any of the previous
* queens (in 'columns') to capture it. */
for (auto i=0; i<size; i++) {
if (row == columns[i] || abs(size-i) == abs(row-columns[i]))
return false; // captured - not safe
}

return true;
}

size_t getSize() const { return size; } // getter method

void set(size_t pos, int val)
{
assert(pos < size);
columns[pos] = val;
}

int at(size_t pos) const
{
assert(pos < size);
return columns[pos];
}

// Inserts a queen in the last column at 'rowIndex'
void insertQueen(int rowIndex)
{
if (size >= maximum) {
/* double the maximum size */
size_t new_size = size*2;
int *new_columns = new int[new_size];

memcpy(new_columns, columns, size);

maximum = new_size;
delete [] columns;
columns = new_columns;

}

columns[size++] = rowIndex;
}

private:
int *columns; /* has the row position for the queen on each column */
size_t size; /* board size */
size_t maximum; /* maximum size before resizing */
};


template<>
Board *clone<Board>(GlobalAddress<Board> source)
{
/* read the remote board size */
int remsize = delegate::call(source, [](Board &b) { return b.getSize(); });

/* create a new board */
Board *local = new Board(remsize);

/* copy the contents of the remote board to the local one */
for (auto k=0; k<remsize; k++)
local->set(k, delegate::call(source, [k](Board &b) {
return b.at(k);
}));

return local;
}


/*
* This is basically a brute force solution using recursion.
*
* This procedure creates a new copy of the board, adds a new column
* (with a queen at the row given by 'rowIndex') and check whether
* it is safe to add a new queen in any of the rows of the next column.
* If it is safe, it then recursively spawn new tasks to do the job.
*/
void nq_search(SmtPtr<Board> remoteBoard, int rowIndex)
{
/* create a new copy of remoteBoard, adding a new column */
SmtPtr<Board> newBoard = remoteBoard.clone();

/* place the queen at row 'rowIndex' in the new column */
newBoard->insertQueen(rowIndex);

/* are we done yet? */
if (newBoard->getSize() == nqBoardSize)
nqSolutions++; // yes, solution found
else
{ /* not done yet */

/* check whether it is safe to have a queen on row 'i' */
for (int i=0; i<nqBoardSize; i++) {

if (newBoard->isSafe(i)) {

/* safe - spawn a new task to check for the next column */
spawn<unbound,&gce>([newBoard,i] { nq_search(newBoard, i); });
}
}
}
}


int main(int argc, char * argv[]) {
init( &argc, &argv );

const int expectedSolutions[] =
{0, 1, 0, 0, 2, 10, 4, 40, 92, 352, 724, 2680, 14200, 73712, 365596, \
2279184, 14772512};

nqBoardSize = FLAGS_n;
nqSolutions = 0;


run([=]{

Metrics::reset_all_cores();
Metrics::start_tracing();

double start = walltime();

/* initial empty board */
SmtPtr<Board> board(new Board(0));

finish<&gce>([board]{
for (auto i=0; i<nqBoardSize; i++)
{
spawn<unbound, &gce>([board,i] { nq_search(board,i); });
}
});


int64_t total = reduce<int64_t,collective_add<int64_t>>(&nqSolutions);

nqueens_runtime = walltime() - start;

Metrics::stop_tracing();

if (nqBoardSize <= 16) {
LOG(INFO) << "NQueens (" << nqBoardSize << ") = " << total << \
" (solution is " << (total == expectedSolutions[nqBoardSize] ? "correct)" : "wrong)");
}
else
LOG(INFO) << "NQueens (" << nqBoardSize << ") = " << total;

LOG(INFO) << "Elapsed time: " << nqueens_runtime.value() << " seconds";

Metrics::merge_and_dump_to_file();

});
finalize();
}

33 changes: 17 additions & 16 deletions applications/demos/nqueens/nqueens.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class Board {
}

/* Called whenever the object must be erased (i.e., memory freed) */
void Release() { if (!--ref_count) delete[] columns; }
void release() { if (!--ref_count) delete[] columns; }

/*
* Checks whether it is safe to put a queen in row 'row'.
Expand All @@ -101,9 +101,9 @@ class Board {
}

/* Called explitictly whenever the object is copied. */
void Shared() { ref_count++; }
void shared() { ref_count++; }

size_t Size() const { return size; } // getter method
size_t getSize() const { return size; } // getter method

private:
int *columns; /* has the row position for the queen on each column */
Expand All @@ -116,17 +116,18 @@ class Board {
/*
* This is basically a brute force solution using recursion.
*
* Given a board ('remoteBoard') we check if placing a queen in any of the
* rows of the column given by 'columnIndex' is safe. In such cases a new task
* is spawned recursively for the next column.
* Given a board ('remoteBoard') we add a queen at the row given by 'rowIndex'
* in the last column, and check whether it is safe to add a new queen in any
* of the rows of the next column. In such cases a new task is spawned
* recursively for the next column.
*/
void nqSearch(GlobalAddress<Board> remoteBoard, int columnIndex)
void nq_search(GlobalAddress<Board> remoteBoard, int rowIndex)
{
/* create a new copy of remoteBoard, adding a new column */
Board *newBoard = new Board(remoteBoard, columnIndex);
Board *newBoard = new Board(remoteBoard, rowIndex);

/* are we done yet? */
if (newBoard->Size() == nqBoardSize)
if (newBoard->getSize() == nqBoardSize)
nqSolutions++; // yes, solution found
else
{ /* not done yet */
Expand All @@ -140,18 +141,18 @@ void nqSearch(GlobalAddress<Board> remoteBoard, int columnIndex)

/* safe - spawn a new task to check for the next column */

newBoard->Shared(); // board is being shared
newBoard->shared(); // board is being shared

/* spawn a recursive search */
spawn<unbound,&gce>([g_newBoard,i] { nqSearch(g_newBoard, i); });
spawn<unbound,&gce>([g_newBoard,i] { nq_search(g_newBoard, i); });
}
}
}

/* don't need the remote board anymore: try to delete it */
delegate::call(remoteBoard, [](Board &b) { b.Release(); });
delegate::call(remoteBoard, [](Board &b) { b.release(); });

newBoard->Release();
newBoard->release();
}


Expand Down Expand Up @@ -180,12 +181,12 @@ int main(int argc, char * argv[]) {
finish<&gce>([g_board,board]{
for (auto i=0; i<nqBoardSize; i++)
{
board->Shared();
spawn<unbound, &gce>([g_board,i] { nqSearch(g_board,i); });
board->shared();
spawn<unbound, &gce>([g_board,i] { nq_search(g_board,i); });
}
});

board->Release();
board->release();


int64_t total = reduce<int64_t,collective_add<int64_t>>(&nqSolutions);
Expand Down
1 change: 1 addition & 0 deletions system/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ add_check( ThreadQueue_tests.cpp 2 1 pass )

add_check( graph/Graph_tests.cpp 2 1 pass )

add_check( SmartPointer_tests.cpp 4 2 pass )

#
# begin hack for dealing with communicator test
Expand Down
Loading