4 Replies - 2660 Views - Last Post: 03 February 2015 - 12:04 PM Rate Topic: -----

#1 adriang133   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 01-February 15

Bank queues in C++ / MPI

Posted 01 February 2015 - 01:09 PM

I'm trying to simulate the following scenario using C++/MPI :
There's a bank with 5 tellers and 1 queue. Customers arrive randomly at the bank like this :
- between 10 minutes before the hour and 10 minutes past the hour arrive on average 10 customers (random number between 1-19)
- at all other times arrive on average 2 customers (random between 0-4)
The customer at the front of the queue goes to the first available teller and spends on average 5 minutes on his transaction.
I need to simulate this for a period of 100 days, 9 hrs each day. Here's my code so far:

#include <mpi.h>
#include <iostream>
#include <fstream>
#include <queue>
#include <ctime>

using namespace std;

int main(int argc, char *argv[])
{
	int rank, nproc, tellers[10] = { 0, 0, 0, 0, 0, 0 }, last_client = 0;


	queue<int> q; //the queue of customers
	ofstream ofile("out.txt");
	MPI_Init(&argc, &argv);
	MPI_Comm_rank(MPI_COMM_WORLD, &rank);
	MPI_Comm_size(MPI_COMM_WORLD, &nproc);
	srand(time(NULL)+rank*nproc);
	if (rank == 0) //Master
	{

		for (int i = 1; i <= 100; i++) //100 days
		{
			for (int p = 1; p <= 5; p++) // tellers are available at the start of each day
			{
				tellers[p] = 0;
			}
			while (!q.empty()) // queue is empty at the start of each day
			{
				q.pop();
			}
			for (int j = 1; j <= 540; j++) //540 minutes = 9 hrs
			{
				
				//-/flag
				int minute = j % 60, rng;

				if (minute >= 50 || minute <= 10) //avg 10 per min
				{
					rng = rand() % 19 + 1; //clients arriving this minute (1-19)		
				}
				else //avg 2 per min
				{
					rng = rand() % 5;

				}
				for (int k = 1; k <= rng; k++)
				{
					q.push(last_client + 1); // put customers in queue
					last_client++;
				}
				cout << "no clients = " << last_client << endl;
				int min_time_teller = 0;
				//flag
				for (int m = 1; m <= 5; m++)
				{
					if (tellers[m] <= j)
					{
						min_time_teller = m;
						break;
					}
				}
				while (!q.empty() && min_time_teller > 0)
				{
					int tmp;
					int cl = q.front();
					MPI_Send(&cl, 1, MPI_INT, min_time_teller, 0, MPI_COMM_WORLD); //  send the first customer in the queue
					MPI_Send(&j, 1, MPI_INT, min_time_teller, 1, MPI_COMM_WORLD); // also send the minute the transaction begins ?
					//cout << "send " << cl << " to teller " << p << " minute = " << j << endl;
					q.pop(); // remove client from queue
					MPI_Recv(&tmp, 1, MPI_INT, min_time_teller, cl, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
					cout << "received " << tmp << " from " << min_time_teller << endl;
					tellers[min_time_teller] = tmp;
					min_time_teller = 0;
					for (int m = 1; m <= 5; m++)
					{
						if (tellers[m] <= j)
						{
							min_time_teller = m;
							break;
						}
					}
				}
				
			}
		}
	}
	else //Slaves
	{

		int client = NULL, start_time, end_time;
		MPI_Recv(&client, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
		MPI_Recv(&start_time, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
		//cout << "teller " << rank << " received " << client << ", " << start_time;
		if (client != NULL)
		{
			int time = rand() % 9 + 1; // time to serve the client
			end_time = start_time + time;
			MPI_Send(&end_time, 1, MPI_INT, 0, client, MPI_COMM_WORLD);
			//cout << "Processing client " << client << " start= " << start_time << " for " << time << " minutes.";
		}
	}


	MPI_Finalize();

	return 0;
}


My program works ok up to a point where it just freezes with no errors (running it in cmd with the mpiexec -n 6 command) and i have to manually abort the execution. for example when i try running it for 1 day and 10 minutes(for easier debugging) i get something like this

Quote

no clients = 6
received 3 from 1
3 0 0 0 0
received 5 from 2
3 5 0 0 0
received 6 from 3
3 5 6 0 0
received 8 from 4
3 5 6 8 0
received 9 from 5
3 5 6 8 9
no clients = 9
no clients = 24
mpiexec aborting job...

job aborted:
[ranks] message

[0-5] process exited without calling finalize

---- error analysis -----

[0-5] on ASUS-PC
ConsoleApplication10.exe ended prematurely and may have crashed. exit code -1

---- error analysis -----

Am I approaching this right ? Is there a better way of keeping track of which tellers are available at the current time in the root(0) process ?
Also, I'm developing this under visual studio 2013 and I'm having trouble with it because i can't debug it because it's using multiple processes.. and from what I've found on google they had a tool for debugging mpi programs in 2010 but not in the 2013 version so is there any other way i can actually debug this program ?

Is This A Good Question/Topic? 0
  • +

Replies To: Bank queues in C++ / MPI

#2 #define   User is offline

  • Cannot compute!
  • member icon

Reputation: 1868
  • View blog
  • Posts: 6,763
  • Joined: 19-February 09

Re: Bank queues in C++ / MPI

Posted 02 February 2015 - 05:44 PM

Hi, welcome to DIC.

You are using a lot of magic numbers, it is easier to read code with named constants or defines.

eg.

const int NUMOFDAYS = 100;



Uppercase letters are used to differentiate the constants from variables.

The names of variables could be better, eg instead of i why not day.

If you declare the array and queue in the day loop, then they will be re-initialised.

If you have a structure for the teller then you could hold the client number and end time. To declare a teller free you could use the structure's client number or have a boolean in the structure.

I'm not sure what you are doing with min_time_teller. Comments on the sections there would help.

The slave doesnt always send, but the master is expecting to recieve, that usually causes problems with communication, but I don't know in this case.

You can send debug data to file, to check what is going on. You could print out the day for example.

It is not recommended to open files before MPI_Init.

.

This post has been edited by #define: 02 February 2015 - 05:46 PM

Was This Post Helpful? 1
  • +
  • -

#3 adriang133   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 01-February 15

Re: Bank queues in C++ / MPI

Posted 03 February 2015 - 07:35 AM

Hi #define,

I know about constants,variable names and coding practices, but I was/am in a hurry to finish this project.

In my tellers[] array I am keeping track of each teller's availability. teller[i] = the minute teller i finishes/finished his current/last transaction, so i can direct the next customer in the queue to the first available teller. So min_time_teller is the index of the teller that finishes his transaction at the earliest time.

The problem of course was that, as you said, I kept sending stuff to the slave processes but they only received it once. So i made a loop for the slaves and now it's all working fine. Such a stupid mistake but it took a long time to find without being able to debug.

Thanks for taking the time and reading through my post!
Was This Post Helpful? 0
  • +
  • -

#4 adriang133   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 01-February 15

Re: Bank queues in C++ / MPI

Posted 03 February 2015 - 11:21 AM

Ok so I'm now trying to simulate a version of the problem where there's one queue for each teller (so 5 queues total) and when a customer arrives he enters the best available queue(shortest number of people in it). It works well but same as before, at a certain point (this time after sending and receiving data for multiple customers, not just for the first 5) it just gets stuck. I'm assuming it's the same type of problem as before that somewhere some data is sent but is not received but I can't figure out where.

#include <mpi.h>
#include <iostream>
#include <fstream>
#include <queue>
#include <ctime>
#include <map>
#include <sstream>
#include <functional>
#define DAYS 10
#define MINUTES 540
using namespace std;

class myqueue
{
	public:
		int id;
		int size;
		myqueue(int i)
		{
			id = i;
			size = 0;
		}
};
struct compare
{
	bool operator()(const myqueue &l, const myqueue &r)
	{
		return l.size > r.size;
	}
};

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

	int rank, nproc, last_client = 0;
	
	map<int, int> entered_queue;
	map<int, int> exited_queue;
	
	MPI_Init(&argc, &argv);
	MPI_Comm_rank(MPI_COMM_WORLD, &rank);
	MPI_Comm_size(MPI_COMM_WORLD, &nproc);
	srand(time(NULL) + rank*nproc);
	if (rank == 0) //Master
	{
		ofstream g("master.txt");

		for (int i = 1; i <= DAYS; i++) //100 days
		{
			queue<int> q[6]; //the queues of customers
			int tellers[6];
			priority_queue<myqueue, vector<myqueue>, compare> pq; //min priority queue to get shortest queue
			for (int k = 1; k <= 5; k++)
			{
				pq.push(myqueue(k));
			}
			
			
			g << endl;
			g << "DAY " << i << endl << endl;
			for (int p = 1; p <= 5; p++)
			{
				MPI_Send(&i, 1, MPI_INT, p, 1000000 + i, MPI_COMM_WORLD);
			}
			for (int j = 1; j <= MINUTES; j++) //540 minutes = 9 hrs
			{
				int minute = j % 60, rng;
				if (minute >= 50 || minute <= 10) //avg 10 per min
				{
					rng = rand() % 19 + 1; //clients arriving this minute (1-19)		
				}
				else //avg 2 per min
				{
					rng = rand() % 5;
				}
				for (int k = 1; k <= rng; k++)
				{
					int best_queue_id = pq.top().id;
					int best_queue_size = pq.top().size;
					q[best_queue_id].push(last_client + 1); //client enters the shortest queue
					pq.pop();
					myqueue tmp = myqueue(best_queue_id);
					tmp.size = best_queue_size + 1;
					pq.push(tmp); // queue size grows by 1
					entered_queue[last_client + 1] = j;
					//cout << "Customer " << last_client + 1 << " entered queue "<< best_queue_id <<" at minute " << j << endl;
					last_client++;
				}
				//cout << "no clients = " << last_client << endl;
				for (int k = 1; k <= 5; k++)
				{
					if (tellers[k] <= j && !q[k].empty())
					{
						int tmp;
						int cl = q[k].front();
						MPI_Send(&cl, 1, MPI_INT, k, 0, MPI_COMM_WORLD);
						MPI_Send(&j, 1, MPI_INT, k, 1, MPI_COMM_WORLD);
						cout << "sent " << cl << " to " << k <<" starting at "<<j<< endl;
						q[k].pop();
						exited_queue[cl] = j;
						MPI_Recv(&tmp, 1, MPI_INT, k, cl, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
						cout << "received " << tmp << " from " << k <<endl;
						tellers[k] = tmp;
					}
				}
				/*for (int k = 1; k <= 5; k++)
				{
					cout << q[k].size() << endl;
				}*/
			}
		}
		g.close();
	}
	else //Slaves
	{
		stringstream sst;
		sst << "teller" << rank << ".txt";
		ofstream out(sst.str());
		for (int i = 1; i <= DAYS; i++)
		{
			int day;
			MPI_Recv(&day, 1, MPI_INT, 0, 1000000 + i, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 
			out << endl;
			out << "DAY " << day << endl << endl;
			int client = NULL, start_time = 0, end_time = 0;
			while (end_time <= MINUTES)
			{
				MPI_Recv(&client, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
				MPI_Recv(&start_time, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
				//cout << "teller " << rank << " received " << client << ", " << start_time;
				if (client != NULL)
				{
					int time = rand() % 9 + 1; // time to serve the client
					end_time = start_time + time;
					MPI_Send(&end_time, 1, MPI_INT, 0, client, MPI_COMM_WORLD);
					//cout<<rank<<" :" << "Customer " << client << " starting at minute " << start_time << " ending at minute " << end_time << " duration " << time << endl;
				}
			}
		}
		out.close();
	}
	MPI_Finalize();

	return 0;
}


Was This Post Helpful? 0
  • +
  • -

#5 #define   User is offline

  • Cannot compute!
  • member icon

Reputation: 1868
  • View blog
  • Posts: 6,763
  • Joined: 19-February 09

Re: Bank queues in C++ / MPI

Posted 03 February 2015 - 12:04 PM

What work are the slaves to do?

If they are acting as tellers, then you could pass the time (day and time). Then the master controls the time.

Then you can ask the slave its status and whether it is free for another customer.

The slave could give a new customer the random wait time.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1