Organizing Simulation Results - c++

I wrote a queue program based on a checkout simulation taking data from a text file (sim.txt). I got everything to work in my code except for one thing. I want to organize each sim result by numbers.
sim.txt
2000
0.10
5
15
5
20
10000
0.05
5
15
5
18
2000
0.20
5
20
10
10
2000
0.20
1
5
10
25
20000
0.50
1
2
50
10
Here is an example output
Simulation Results #1
// result #1 output is here...
Simulation Results #2
// result #2 output is here...
Simulation Results #3
// result #3 output is here...
Simulation Results #4
// result #4 output is here...
Simulation Results #5
// result #5 output is here...
I tried implementing a for loop to achieve this, but it didn't work as expected. This problem occurs for each simulation result.
Simulation Results #1
Simulation Results #2
Simulation Results #3
Simulation Results #4
Simulation Results #5
// result #1 outputs here...
Here is my code to get a better look what I'm doing
#include <iostream>
#include <cstdlib>
#include <queue>
#include <fstream>
#include <ctime>
using namespace std;
// Input parameters
#define SIMULATION_TIME 0
#define ARRIVAL_RATE 1
#define MIN_SERVICE_TIME 2
#define MAX_SERVICE_TIME 3
#define MAX_LINE_SIZE 4
#define ANGRY_THRESHOLD 5
#define PARAMS_MAX 6
#define FILENAME "sim.txt"
// Or like this:
// const int SIMULATION_TIME = 0;
// Or make 6 variables:
// double SIMULATION_TIME = 0;
// Counters -- indexes into variable 'counters' below
#define CUSTOMERS_SERVICED 0
#define CUSTOMERS_LEAVING 1
#define AVERAGE_WAIT 2
#define AVERAGE_LINE 3
#define ANGRY_CUSTOMERS 4
#define COUNTERS_MAX 5
// Holds the current simulation parameters
double parameters[PARAMS_MAX];
double counters[COUNTERS_MAX];
// This is an example debug macro you can use to print
// things each time through the loop
#define DEBUGGING_ENABLED 1
#ifdef DEBUGGING_ENABLED
#define DEBUG(x) do { \
cerr << __FILE__ << ": " << __LINE__ << ": " << x << endl; \
} while (0)
#else
#define DEBUG(x)
#endif // DEBUGGING_ENABLED
// Return the service interval, between 'min'
// and 'max'.
int randomInt(int min, int max)
{
return (rand() % (max - min) + min);
}
// Returns TRUE if a customer arrived during this minute
bool randomChance(double prob)
{
double rv = rand() / (double(RAND_MAX) + 1);
return (rv < prob);
}
// Read the next simulation from the file. Return
// TRUE if one could be read, FALSE otherwise (eof).
bool readNextSim(fstream &f, double parameters[])
{
for (int i = 0; i < PARAMS_MAX; i++)
{
string tmp;
getline(f, tmp);
if (f.eof())
return false;
// Read in the next parameter
parameters[i] = atof(tmp.c_str());
}
for (int i = 0; i < 5; i++)
cout <<"Simulation Results #" << i + 1 << endl;
cout << "---------------------" << endl;
cout << "\t Overall simulation time: " << "\t" << parameters[SIMULATION_TIME] << endl;
cout << "\t Arrival rate: " << "\t\t\t" << parameters[ARRIVAL_RATE] << endl;
cout << "\t Minimum service time: " << "\t\t" << parameters[MIN_SERVICE_TIME] << endl;
cout << "\t Maximum service time: " << "\t\t" << parameters[MAX_SERVICE_TIME] << endl;
cout << "\t Maximum line size: " << "\t\t" << parameters[MAX_LINE_SIZE] << endl;
cout << "\t Angry threshold: " << "\t\t" << parameters[ANGRY_THRESHOLD] << endl;
return true;
}
int main()
{
fstream f(FILENAME);
// Seed the random number generator here
srand(time(0));
if (!f.good())
{
cout << "Invalid file." << endl;
return -1;
}
while (readNextSim(f, parameters))
{
// Run the next simulation
queue<int> line;
for (int i = 0; i < COUNTERS_MAX; i++)
counters[i] = 0;
// or:
// memset(counters, 0, COUNTERS_MAX * sizeof(double));
//int customersLeavingLineFull = 0;
int simTime = 0;
int currentCustomer = -1;
// Each time through this loop represents 1 minute passing.
// There needs to be code to handle everything that can happen
// in 1 minute:
// - Customer arriving (yes/no?)
// - Is the current customer finished
// - Possibly process the next person in line
// - Calculate simulation statistics along the way
while (simTime++ < parameters[SIMULATION_TIME])
{
// One iteration of the loop represents one
// minute of simulation time.
// Check to see if a customer arrived
// (if so, process, also see if the line is full)
bool arrived = randomChance(parameters[ARRIVAL_RATE]);
if (arrived)
{
// A customer arrived in this minute
if (currentCustomer == -1)
{
// No customer is currently at the cashier
int serviceTime = randomInt(parameters[MIN_SERVICE_TIME],
parameters[MAX_SERVICE_TIME]);
currentCustomer = simTime + serviceTime;
}
else
{
if (line.size() == parameters[MAX_LINE_SIZE])
{
// Count this customer as leaving because the line is too
// full
counters[CUSTOMERS_LEAVING]++;
}
else
{
line.push(simTime);
}
}
}
counters[AVERAGE_LINE] += line.size();
// Check to see if the current customer is done
// at the cashier. Also check if there is no customer
// at the cashier (in which the next customer goes to the
// cashier).
if (simTime == currentCustomer)
{
if (!line.empty())
{
int nextCustomerTimestamp = line.front();
int waitingTime = simTime - nextCustomerTimestamp;
// We need to include this in the average waiting times
if (waitingTime >= parameters[ANGRY_THRESHOLD])
counters[ANGRY_CUSTOMERS]++;
counters[AVERAGE_WAIT] += waitingTime;
// Set currentCustomer to the time when that customer
// will be done. Need to call randomInt().
int serviceTime = randomInt(parameters[MIN_SERVICE_TIME],
parameters[MAX_SERVICE_TIME]);
// This will give us a timestamp of when the current customer will
// be done.
currentCustomer = simTime + serviceTime;
line.pop();
counters[CUSTOMERS_SERVICED]++;
}
else
{
// The line is empty
counters[CUSTOMERS_SERVICED]++;
currentCustomer = -1;
}
}
}
// Print a summary of the simulation:
// counters
counters[AVERAGE_WAIT] /= counters[CUSTOMERS_SERVICED];
counters[AVERAGE_LINE] /= parameters[SIMULATION_TIME];
cout << endl;
cout << "\t Customers serviced: " << "\t\t" << counters[CUSTOMERS_SERVICED] << endl;
cout << "\t Customers leaving: " << "\t\t" << counters[CUSTOMERS_LEAVING] << endl;
cout << "\t Average time spent in line: " << "\t" << counters[AVERAGE_WAIT] << endl;
cout << "\t Average line length: " << "\t\t" << counters[AVERAGE_LINE] << endl;
cout << "\t Angry customers: " << "\t\t" << counters[ANGRY_CUSTOMERS] << endl;
cout << endl;
}
return 0;
}
Any advice on how to achieve the example output above would be appreciated!

Related

How do I parallel process in a for loop. My code parallels the operation improperly

Beginner with OpenMp. I am running on an AMD 3970X.
I have a problem with a loop, more than one thread working on the same iteration.
The code should work on a mpq_t sum of 1/n, n=1..100.
The output is n, threadid, num, den, repeating, non-repeating, and, time.
Sorry if this is long.
I have played with placement of the 2 pragma statements, no success.
I changed the code as suggested, and now get a compile error:
digits.cc:193:54: error: user defined reduction not found for 'sum'
193 | #pragma omp for schedule(static, chunk), reduction(+:sum)
// digits.cpp - implementation of digits with libgmp
// 20111123 tomdean - initial conversion from digits.c
// The rational number, sum(1/k,k=1..n) has three components,
// An integer >= 1, s1..ss
// A sequence of non-repeating digits, n1..nn
// A sequence of repeating digits, r1..rr
// The sum is s1..ss . n1..nn r1..rr r1..rr ...
// Calculating the number of integers, non-repeating digits, and,
// repeating digits for n > 83 requires hours#pragma omp for schedule(static, chunk), reduction(sum:+)
of computer time on a
// 4.2GHz Core i7-3930k.
// The algorithm is simple, all values are integers and thus exact.
// From the rational number, sum, extract the numerator and denominator.
// Calculate q = nu/de, r = q - q*de.
// checked saved_r for r. If found, return
// if num_saved_r < SAVE_MAX, save r in r_saved[num_saved_r++]
//
#include <iostream>
#include <gmpxx.h>
#include <sys/time.h> // time calculations
#include <stdlib.h> // exit
#include <unistd.h> // getopt
#include <omp.h> // openmp
#define NUM_CHK 50
#pragma omp for schedule(static, chunk), reduction(sum:+)
using namespace std;
///////////////////////////////////////////////////////////////////////
// usage
void usage(char *me) {
cout << "Usage: " << me << " [-f <n>] [-t <m>] [-h]" << endl
<< "Where:" << endl
<< " -f <n> - from <n> default 10" << endl
<< " -t <n> - to <n> default n+10" << endl
<< " -h - show this message" << endl;
return;
}
////////////////////////////////////////////////////////////
// calc_time
double calc_time( timeval *start, timeval *stop) {
long sec, usec;
sec = stop->tv_sec - start->tv_sec;
usec = stop->tv_usec - start->tv_usec;
if (usec < 0) {
sec--;
usec += 1000000L;
}
return (double)sec + ((double) usec)/1.0E6;
}
/////////////////////////////////////////////////////////////////////
// calc_digits
void calc_digits(int idx, mpq_class sum) {
long chkidx = 0;
long m;
mpz_t tnu, de, nu, q, r;
mpz_t chk[NUM_CHK]; // saved r
unsigned long s;
struct timeval start, stop;
struct timezone zone;
int tid;
tid = omp_get_thread_num();
mpz_inits(nu, de, q, r, tnu, NULL);
mpz_set(nu, sum.get_num_mpz_t());
mpz_set(de, sum.get_den_mpz_t());
for (s=0; s<NUM_CHK; s++) {
mpz_init(chk[s]);
}
(void)gettimeofday(&start, &zone);
//cout << nu << " " << de << endl;
chkidx = 0;
// q = nu/de; r = nu - q*de;
mpz_fdiv_qr(q, r, nu, de);
s = 1;
mpz_set(chk[chkidx], r);
// cout << "init "
// << nu << ' '
// << de << ' '
// << q << ' '
// << r << ' '
// << chkidx << ' '
// << chk[chkidx] << endl;
chkidx++;
m = -1;
while (1) {
mpz_mul_si(tnu, r, 10L);
//tq = tnu/de; r = tnu - tq*de;
mpz_fdiv_r(r,tnu,de);
{
long idx;
m = -1;
for (idx=0; idx<chkidx; idx++) {
if (mpz_cmp(r, chk[idx]) == 0) m = idx;
}
}
if (m >= 0) break;
s++;
if (chkidx < NUM_CHK) {
mpz_set(chk[chkidx], r);
// cout << "loop "/
// << tnu << ' '
// << de << ' '
// << q << ' '
// << r << ' '
// << chkidx << ' '
// << chk[chkidx] << endl;
chkidx++;
}
}
// at this point, m is num non-recurring
// s is the number of iterations, the total digit count
(void)gettimeofday(&stop, &zone);
cout << idx << ' ' << ' ' << tid << ' ' << nu
<< ' ' << de
//<< ' ' << nu/de
<< ' ' << m
<< ' ' << s-(unsigned long long)m
<< ' ' << calc_time(&start,&stop) << endl;
mpz_clears(q, r, tnu, NULL);
for (s=0; s<NUM_CHK; s++) mpz_clear(chk[s]);
}
/////////////////////////////////////////////////////////////////////
// main
int main(int argc, char **argv) {
long idx;
long long from, to;
time_t now = time(NULL);
char ch;
int chunk = 60;
from = 10; // pre-calc sum(1/k,k=1..9) start processing at k=10
to = 100; // sum(1/k,k=1..100)
// check optional arguments
while ((ch = getopt(argc, argv, "hf:t:")) != -1) {
switch (ch) {
case 'f':
if (sscanf(optarg, "%Ld", &from) != 1) {
usage(argv[0]);
return 0;
}
break;
case 't':
if (sscanf(optarg, "%Ld", &to) != 1) {
usage(argv[0]);
return 0;
}
break;
case 'h':
default:
usage(argv[0]);
return 0;
}
}
cout << '#' << endl;
cout << "# Calculate sum(1/k,k=1..n) for n = 1 to 100." << endl;
cout << '#' << endl;
cout << "# Columns are: N" << endl;
cout << "# Numerator" << endl;
cout << "# Denominator" << endl;
cout << "# Number of non-recurringdigits" << endl;
cout << "# Number of recurring digits." << endl;
cout << "# Elapsed time in seconds." << endl;
cout << '#' << endl;
cout << "# Started " << ctime(&now); // ctime is /n/0 terminated
cout << '#' << endl;
mpq_class sum(1,1);
mpz_t nu, de;
mpz_inits(nu, de, NULL);
// advance to n = from
for (idx=2; idx<from; idx++) {
sum += mpq_class(1,idx);
}
//cout << sum << endl;
// calculate to n = 100
#pragma omp parallel default(shared)
#pragma omp for schedule(static, chunk) reduction(+:sum)
for (idx=from; idx<to+1; idx++) {
//cout << idx << " ";
sum += mpq_class(1,idx);
//cout << sum << endl;
calc_digits(idx, sum);
//mpz_set(nu, sum.get_num_mpz_t());
//mpz_set(de, sum.get_den_mpz_t());
//calc_digits(nu,de);
}
mpz_clears(nu, de, NULL);
// digits.cc -
return 0;
}
You need to mark the for loop as #pragma omp for so that the iterations get distributed over the threads. Or you can combine that with the omp parallel.
The next problem is your sum += .... statement. Since all threads access the sum variable, you need to mark your parallel loop as a reduction(+:sum).
The omp schedule by itself doesn't do anything. Put it on the omp for line.

cargo transportation system we are not sure how to display the last part of our task

Here is our code for the task we are almost finishing just the last part we are stuck at
"Fastest: 3 trips (1 Van, 3 Mini-lorry, $645) "
we are not sure how to display the values in the bracket we only able to display 3 trips.
Is there a way to also display the values in the bracket stated as well?
we use
int min = *min_element(vTrips.begin(), vTrips.end());
cout << "Fastest: " << min << " trips" << endl;
but this only display the 3 trips.
#include <iostream>
#include <vector>
#include <iterator>
#include <fstream>
#include<algorithm>
using namespace std;
class CTS //cargo transport system
{
int i;
int cargo, lorryprice, vanprice, lorrysize, vansize, allOps;
public:
void set_cargo(int);
void set_lorryprice(int);
void set_vanprice(int);
void set_lorrysize(int);
void set_vansize(int);
};
void CTS::set_cargo(int total_cargo) {
cargo = total_cargo;
}
void CTS::set_lorryprice(int lorryP) {
lorryprice = lorryP;
}
void CTS::set_vanprice(int vanP) {
vanprice = vanP;
}
void CTS::set_lorrysize(int lorryS) {
lorrysize = lorryS;
}
void CTS::set_vansize(int vanS)
{
vansize = vanS;
}
int main()
{
int cargo, lorryprice, vanprice, lorrysize, vansize, options, i, no_lorry, no_van, cost, trips;
ifstream infile;
infile.open("size.txt");
if (infile.is_open()) {
infile >> cargo;
infile >> lorryprice;
infile >> vanprice;
infile >> lorrysize;
infile >> vansize;
}
CTS run;
run.set_cargo(cargo);
run.set_lorryprice(lorryprice);
run.set_vanprice(vanprice);
run.set_lorrysize(lorrysize);
run.set_vansize(vansize);
infile.close();
options = (cargo / lorrysize) + 1;
no_lorry = (cargo / lorrysize);
no_van = (cargo / vansize) + 3;
if (cargo % lorrysize == 0) {
no_van = -3;
}
if (cargo % lorrysize != 0) {
no_van = ((cargo % lorrysize) / 10) - 3;
}
/*it = numbervan.begin();
for (auto ir = numbervan.rbegin(); ir != numbervan.rend(); ++ir) {
cout << *ir << endl;
}*/
vector<int> vCost, vVan, vTrips, vLorry;
vector <int>::iterator it;
for (i = 1; i < options + 1; i++)
{
int numberlorry = no_lorry;
cout << "Option " << i << ":" << endl;
cout << "Number of Mini-Lorries : " << no_lorry-- << endl;
if (no_van >= -3) {
no_van += 3;
}
cout << "Number of Vans : " << no_van << endl;
int numbervan = no_van;
if (numberlorry > numbervan) {
trips = numberlorry;
}
else {
trips = numbervan;
}
cout << "Trips Needed : " << trips << endl;
cost = (numberlorry * lorryprice) + (no_van * vanprice);
cout << "Total Cost : $" << cost << endl;
vCost.push_back(cost);
vLorry.push_back(numberlorry);
vVan.push_back(numbervan);
vTrips.push_back(trips);
}
int counter = vCost.size() - 1;
//std::vector<int>::reverse_iterator ir = vCost.rbegin();
for (i = 1; i < 4; i++) {
//cout << "Lowest #" << i << ": "<<cost<<endl;
cout << "Lowest #" << i << ": $" << vCost[counter] << "(" << vVan[counter] << " Vans, " << vLorry[counter] << " Mini-Lorry, " << vTrips[counter] << " Trips)" << endl;
counter--;
}
int min = *min_element(vTrips.begin(), vTrips.end()); // this line of code we figured out how to
cout << "Fastest: " << min << " trips" << endl; //display the number of trips using algorithm
return 0;
}
Your design is awkward; you create an instance of CTS run; and never use it.
Assuming that you do your calculations right, you need to know at what index you found min. If you store the iterator returned by min_element(), you can get an index by subtracting vTrips.begin() from it. Then the corresponding elements in your vCost, vLorry and vVan vectors will contain the data you want.
However, it would be easier if you define a struct containing your pre-calculated values, and push that into some vector. In that case, all related data is kept together.

pthread execution time worse than sequential

I was learning to use pthread with hopes it will help some of the slowest pieces of my code
go a bit faster. I tried to (as a warm-up example) to write a Montecarlo integrator using
threads. I wrote a code that compares three approaches:
Single thread pthread evaluation of the integral with NEVALS integrand evaluations.
Multiple thread evaluation of the integral NTHREADS times each with NEVALS
integrand evaluations.
Multiple threads commited to different cores in my CPU, again totalling NEVALS*NTHREADS
integrand evaluations.
Upon running the fastest per integrand evaluations is the single core, between 2 and 3 times faster than the others. The other two seem to be somewhat equivalent except for the fact that
the CPU usage is very different, the second one spreads the threads across all the (8) cores
in my CPU, while the third (unsurprisingly) concentrates the job in NTHREADS and leaves the rest
unoccupied.
Here is the source:
#include <iostream>
#define __USE_GNU
#include <sched.h>
#include <pthread.h>
#include <thread>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <unistd.h>
using namespace std;
double aleatorio(double a, double b){
double r = double(rand())/RAND_MAX;
return a + r * (b - a);
}
double funct(double* a){
return pow(a[0],6);
}
void EstimateBounds(int ndim, double (*f)(double*), double* bounds){
double x[ndim];
for(int i=1;i<=1000;i++){
for(int j=0;j<ndim;j++) x[j] = aleatorio(0,1);
if ( f(x) > bounds[1]) bounds[1] = f(x);
if ( f(x) < bounds[0]) bounds[0] = f(x);
}
}
void Integrate(double (*f)(double*), int ndim, double* integral, int verbose, int seed){
int nbatch = 5000000;
const int maxeval = 25*nbatch;
double x[ndim];
srand(seed);
/// Algorithm to estimate the maxima and minima ///
for(int j=0;j<ndim;j++) x[j] = 0.5;
double bounds[2] = {f(x),f(x)};
EstimateBounds(ndim,f,bounds);
/// Integral initialization ///
int niter = int(maxeval/nbatch);
for(int k=1;k<=niter;k++)
{
double loc_min = bounds[0];
double loc_max = bounds[1];
int count = 0;
for (int i=1; i<=nbatch; i++)
{
for(int j=0;j<ndim;j++) x[j] = aleatorio(0,1);
double y = aleatorio(bounds[0],bounds[1]);
if ( f(x) > loc_max ) loc_max = f(x);
if ( f(x) < loc_min ) loc_min = f(x);
if ( f(x) > y && y > 0 ) count++;
if ( f(x) < y && y < 0 ) count--;
}
double delta = (bounds[1]-bounds[0])*double(count)/nbatch;
integral[0] += delta;
integral[1] += pow(delta,2);
bounds[0] = loc_min;
bounds[1] = loc_max;
if(verbose>0){
cout << "Iteration["<<k<<"]: " << k*nbatch;
cout << " integrand evaluations so far" <<endl;
if(verbose>1){
cout << "The bounds for this iteration were = ["<<bounds[0]<<","<<bounds[1]<<"]"<<endl;}
cout << "Integral = ";
cout << integral[0]/k << " +- ";
cout << sqrt((integral[1]/k - pow(integral[0]/k,2)))/(k) << endl;
cout << endl;
}
}
integral[0] /= niter;
integral[1] = sqrt((integral[1]/niter - pow(integral[0],2)))/niter;
}
struct IntegratorArguments{
double (*Integrand)(double*);
int NumberOfVariables;
double* Integral;
int VerboseLevel;
int Seed;
};
void LayeredIntegrate(IntegratorArguments IA){
Integrate(IA.Integrand,IA.NumberOfVariables,IA.Integral,IA.VerboseLevel,IA.Seed);
}
void ThreadIntegrate(void * IntArgs){
IntegratorArguments *IA = (IntegratorArguments*)IntArgs;
LayeredIntegrate(*IA);
pthread_exit(NULL);
}
#define NTHREADS 5
int main(void)
{
cout.precision(16);
bool execute_single_core = true;
bool execute_multi_core = true;
bool execute_multi_core_2 = true;
///////////////////////////////////////////////////////////////////////////
///
/// Single Thread Execution
///
///////////////////////////////////////////////////////////////////////////
if(execute_single_core){
pthread_t thr0;
double integral_value0[2] = {0,0};
IntegratorArguments IntArg0;
IntArg0.Integrand = funct;
IntArg0.NumberOfVariables = 2;
IntArg0.VerboseLevel = 0;
IntArg0.Seed = 1;
IntArg0.Integral = integral_value0;
int t = time(NULL);
cout << "Now Attempting to create thread "<<0<<endl;
int rc0 = 0;
rc0 = pthread_create(&thr0, NULL, ThreadIntegrate,&IntArg0);
if (rc0) {
cout << "Error:unable to create thread," << rc0 << endl;
exit(-1);
}
else cout << "Thread "<<0<<" has been succesfuly created" << endl;
pthread_join(thr0,NULL);
cout << "Thread 0 has finished, it took " << time(NULL)-t <<" secs to finish" << endl;
cout << "Integral Value = "<< integral_value0[0] << "+/-" << integral_value0[1] <<endl;
}
////////////////////////////////////////////////////////////////////////////////
///
/// Multiple Threads Creation
///
///////////////////////////////////////////////////////////////////////////////
if(execute_multi_core){
pthread_t threads[NTHREADS];
double integral_value[NTHREADS][2];
IntegratorArguments IntArgs[NTHREADS];
int rc[NTHREADS];
for(int i=0;i<NTHREADS;i++){
integral_value[i][0]=0;
integral_value[i][1]=0;
IntArgs[i].Integrand = funct;
IntArgs[i].NumberOfVariables = 2;
IntArgs[i].VerboseLevel = 0;
IntArgs[i].Seed = i;
IntArgs[i].Integral = integral_value[i];
}
int t = time(NULL);
for(int i=0;i<NTHREADS;i++){
cout << "Now Attempting to create thread "<<i<<endl;
rc[i] = pthread_create(&threads[i], NULL, ThreadIntegrate,&IntArgs[i]);
if (rc[i]) {
cout << "Error:unable to create thread," << rc[i] << endl;
exit(-1);
}
else cout << "Thread "<<i<<" has been succesfuly created" << endl;
}
/// Thread Waiting Phase ///
for(int i=0;i<NTHREADS;i++) pthread_join(threads[i],NULL);
cout << "All threads have now finished" <<endl;
cout << "This took " << time(NULL)-t << " secs to finish" <<endl;
cout << "Or " << (time(NULL)-t)/NTHREADS << " secs per core" <<endl;
for(int i = 0; i < NTHREADS; i++ ) {
cout << "Thread " << i << " has as the value for the integral" << endl;
cout << "Integral = ";
cout << integral_value[i][0] << " +- ";
cout << integral_value[i][1] << endl;
}
}
////////////////////////////////////////////////////////////////////////
///
/// Multiple Cores Execution
///
///////////////////////////////////////////////////////////////////////
if(execute_multi_core_2){
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
pthread_t threads[NTHREADS];
double integral_value[NTHREADS][2];
IntegratorArguments IntArgs[NTHREADS];
int rc[NTHREADS];
for(int i=0;i<NTHREADS;i++){
integral_value[i][0]=0;
integral_value[i][1]=0;
IntArgs[i].Integrand = funct;
IntArgs[i].NumberOfVariables = 2;
IntArgs[i].VerboseLevel = 0;
IntArgs[i].Seed = i;
IntArgs[i].Integral = integral_value[i];
}
int t = time(NULL);
for(int i=0;i<NTHREADS;i++){
cout << "Now Attempting to create thread "<<i<<endl;
rc[i] = pthread_create(&threads[i], NULL, ThreadIntegrate,&IntArgs[i]);
if (rc[i]) {
cout << "Error:unable to create thread," << rc[i] << endl;
exit(-1);
}
else cout << "Thread "<<i<<" has been succesfuly created" << endl;
CPU_SET(i, &cpuset);
}
cout << "Now attempting to commit different threads to different cores" << endl;
for(int i=0;i<NTHREADS;i++){
const int set_result = pthread_setaffinity_np(threads[i], sizeof(cpu_set_t), &cpuset);
if(set_result) cout << "Error: Thread "<<i<<" could not be commited to a new core"<<endl;
else cout << "Thread reassignment succesful" << endl;
}
/// Thread Waiting Phase ///
for(int i=0;i<NTHREADS;i++) pthread_join(threads[i],NULL);
cout << "All threads have now finished" <<endl;
cout << "This took " << time(NULL)-t << " secs to finish" <<endl;
cout << "Or " << (time(NULL)-t)/NTHREADS << " secs per core" <<endl;
for(int i = 0; i < NTHREADS; i++ ) {
cout << "Thread " << i << " has as the value for the integral" << endl;
cout << "Integral = ";
cout << integral_value[i][0] << " +- ";
cout << integral_value[i][1] << endl;
}
}
pthread_exit(NULL);
}
I compile with
g++ -std=c++11 -w -fpermissive -O3 SOURCE.cpp -lpthread
It seems to me that my threads are actually being excecuted sequentially, because
the time seems to grow with NTHREADS, and it actully takes roughly NTHREADS times longer
than a single thread.
Does anyone have an idea of where the bottleneck is?
You are using rand(), which is a global random number generator. First of all it is not thread-safe, so using it in multiple threads, potentially in parallel, causes undefined behavior.
Even if we set that aside, rand() is using one global instance, shared by all threads. If one thread wants to call it, the processor core needs to check whether the other cores modified its state and needs to refetch that state from the main memory or other caches each time it is used. This is why you observe the drop in performance.
Use the <random> facilities for pseudo-random number generators instead. They offer much better quality random number generators, random number distributions, and the ability to create multiple independent random number generator instances. Make these thread_local, so the threads do not interfere with one another:
double aleatorio(double a, double b){
thread_local std::mt19937 rng{/*seed*/};
return std::uniform_real_distribution<double>{a, b}(rng);
}
Please note though that this is not using proper seeding for std::mt19937, see this question for details and that uniform_real_distribution<double>{a, b} will return a uniformly distributed number between a inclusive and b exclusive. Your original code gave a number between a and b inclusive (potential rounding errors aside). I assume that neither is particularly relevant to you.
Also note my unrelated comments under your question for other things you should improve.

Problems with compiling. Errors E0413, E0434, C2664, C2440

I got this source code from our course material but I can't get it to work. The program is a flight simulator. This link might be useful to understand the bigger picture. Starting on page 67. http://brahms.emu.edu.tr/rza/tr3.pdf
These are the errors that Visual Studio gives to me.
Error E0413 no suitable conversion function from "const Plane" to "const Queue_entry" exists. Runaway.cpp lines 32 & 57
Error E0413 no suitable conversion function from "Extended_queue" to "Runway_activity" exists. Runaway.cpp lines 85 & 93
Error E0434 a reference of type "Queue_entry &" (not const-qualified) cannot be initialized with a value of type "Plane". Runaway.cpp line 96.
Error C2664 'Error_code Queue::append(const Queue_entry &)': cannot convert argument 1 from 'const Plane' to 'const Queue_entry &'. Runaway.cpp lines 32 & 57
Error C2664 'Error_code Queue::retrieve(Queue_entry &) const': cannot convert argument 1 from 'Plane' to 'Queue_entry &'. Runaway.cpp lines 85 & 93
Error C2440 '=': cannot convert from 'Extended_queue' to 'Runway_activity'. Runaway.cpp line 96.
Runaway.h
#include "Utility.h"
#include "Extended_queue.h"
#include "Plane.h"
enum Runway_activity { idle, land, takeoff };
class Runway {
public:
Runway(int limit);
Error_code can_land(const Plane& current);
Error_code can_depart(const Plane& current);
Runway_activity activity(int time, Plane& moving);
void shut_down(int time) const;
private:
Extended_queue landing;
Extended_queue takeoff;
int queue_limit;
int num_land_requests; // number of planes asking to land
int num_takeoff_requests; // number of planes asking to take off
int num_landings; // number of planes that have landed
int num_takeoffs; // number of planes that have taken off
int num_land_accepted; // number of planes queued to land
int num_takeoff_accepted; // number of planes queued to take off
int num_land_refused; // number of landing planes refused
int num_takeoff_refused; // number of departing planes refused
int land_wait; // total time of planes waiting to land
int takeoff_wait; // total time of planes waiting to take off
int idle_time; // total time runway is idle
};
Runaway.cpp
#include "Runway.h"
#include <iostream>
using namespace std;
Runway::Runway(int limit)
/*
Post: The Runway data members are initialized to record no
prior Runway use and to record the limit on queue sizes.
*/
{
queue_limit = limit;
num_land_requests = num_takeoff_requests = 0;
num_landings = num_takeoffs = 0;
num_land_refused = num_takeoff_refused = 0;
num_land_accepted = num_takeoff_accepted = 0;
land_wait = takeoff_wait = idle_time = 0;
}
Error_code Runway::can_land(const Plane& current)
/*
Post: If possible, the Plane current is added to the
landing Queue; otherwise, an Error_code of overflow is
returned. The Runway statistics are updated.
Uses: class Extended_queue.
*/
{
Error_code result;
if (landing.size() < queue_limit)
result = landing.append(current);
else
result = fail;
num_land_requests++;
if (result != success)
num_land_refused++;
else
num_land_accepted++;
return result;
}
Error_code Runway::can_depart(const Plane& current)
/*
Post: If possible, the Plane current is added to the
takeoff Queue; otherwise, an Error_code of overflow is
returned. The Runway statistics are updated.
Uses: class Extended_queue.
*/
{
Error_code result;
if (takeoff.size() < queue_limit)
result = takeoff.append(current);
else
result = fail;
num_takeoff_requests++;
if (result != success)
num_takeoff_refused++;
else
num_takeoff_accepted++;
return result;
}
Runway_activity Runway::activity(int time, Plane& moving)
/*
Post: If the landing Queue has entries, its front
Plane is copied to the parameter moving
and a result land is returned. Otherwise,
if the takeoff Queue has entries, its front
Plane is copied to the parameter moving
and a result takeoff is returned. Otherwise,
idle is returned. Runway statistics are updated.
Uses: class Extended_queue.
*/
{
Runway_activity in_progress;
if (!landing.empty()) {
landing.retrieve(moving);
land_wait += time - moving.started();
num_landings++;
in_progress = land;
landing.serve();
}
else if (!takeoff.empty()) {
takeoff.retrieve(moving);
takeoff_wait += time - moving.started();
num_takeoffs++;
in_progress = takeoff;
takeoff.serve();
}
else {
idle_time++;
in_progress = idle;
}
return in_progress;
}
void Runway::shut_down(int time) const
/*
Post: Runway usage statistics are summarized and printed.
*/
{
cout << "Simulation has concluded after " << time << " time units." << endl
<< "Total number of planes processed "
<< (num_land_requests + num_takeoff_requests) << endl
<< "Total number of planes asking to land "
<< num_land_requests << endl
<< "Total number of planes asking to take off "
<< num_takeoff_requests << endl
<< "Total number of planes accepted for landing "
<< num_land_accepted << endl
<< "Total number of planes accepted for takeoff "
<< num_takeoff_accepted << endl
<< "Total number of planes refused for landing "
<< num_land_refused << endl
<< "Total number of planes refused for takeoff "
<< num_takeoff_refused << endl
<< "Total number of planes that landed "
<< num_landings << endl
<< "Total number of planes that took off "
<< num_takeoffs << endl
<< "Total number of planes left in landing queue "
<< landing.size() << endl
<< "Total number of planes left in takeoff queue "
<< takeoff.size() << endl;
cout << "Percentage of time runway idle "
<< 100.0 * ((float)idle_time) / ((float)time) << "%" << endl;
cout << "Average wait in landing queue "
<< ((float)land_wait) / ((float)num_landings) << " time units";
cout << endl << "Average wait in takeoff queue "
<< ((float)takeoff_wait) / ((float)num_takeoffs)
<< " time units" << endl;
cout << "Average observed rate of planes wanting to land "
<< ((float)num_land_requests) / ((float)time)
<< " per time unit" << endl;
cout << "Average observed rate of planes wanting to take off "
<< ((float)num_takeoff_requests) / ((float)time)
<< " per time unit" << endl;
}
Plane.h
#pragma once
#include "Utility.h"
enum Plane_status { null, arriving, departing };
class Plane {
public:
Plane();
Plane(int flt, int time, Plane_status status);
void refuse() const;
void land(int time) const;
void fly(int time) const;
int started() const;
private:
int flt_num;
int clock_start;
Plane_status state;
};
Plane.cpp
#include "Plane.h"
#include <iostream>
using namespace std;
Plane::Plane(int flt, int time, Plane_status status)
/*
Post: The Plane data members flt_num, clock_start,
and state are set to the values of the parameters flt,
time and status, respectively.
*/
{
flt_num = flt;
clock_start = time;
state = status;
cout << "Plane number " << flt << " ready to ";
if (status == arriving)
cout << "land." << endl;
else
cout << "take off." << endl;
}
Plane::Plane()
/*
Post: The Plane data members flt_num, clock_start,
state are set to illegal default values.
*/
{
flt_num = -1;
clock_start = -1;
state = null;
}
void Plane::refuse() const
/*
Post: Processes a Plane wanting to use Runway, when
the Queue is full.
*/
{
cout << "Plane number " << flt_num;
if (state == arriving)
cout << " directed to another airport" << endl;
else
cout << " told to try to takeoff again later" << endl;
}
void Plane::land(int time) const
/*
Post: Processes a Plane that is landing at the specified time.
*/
{
int wait = time - clock_start;
cout << time << ": Plane number " << flt_num << " landed after "
<< wait << " time unit" << ((wait == 1) ? "" : "s")
<< " in the takeoff queue." << endl;
}
void Plane::fly(int time) const
/*
Post: Process a Plane that is taking off at the specified time.
*/
{
int wait = time - clock_start;
cout << time << ": Plane number " << flt_num << " took off after "
<< wait << " time unit" << ((wait == 1) ? "" : "s")
<< " in the takeoff queue." << endl;
}
int Plane::started() const
/*
Post: Return the time that the Plane entered the airport system.
*/
{
return clock_start;
}
Extended_queue.h
#pragma once
#include "Queue.h"
class Extended_queue : public Queue {
public:
bool full() const;
int size() const;
void clear();
Error_code serve_and_retrieve(Queue_entry& item);
void print();
};
Extended_queue.cpp
#include "Extended_queue.h"
int Extended_queue::size() const
/*
Post: Return the number of entries in the Extended_queue.
*/
{
return count;
}
bool Extended_queue::full() const
{
return maxqueue == this->count;
}
void Extended_queue::clear()
{
this->count = 0;
this->front = 0;
this->rear = maxqueue - 1;
}
Error_code Extended_queue::serve_and_retrieve(Queue_entry& item)
{
if (count <= 0) return underflow;
item = entry[front];
count--;
front = ((front + 1) == maxqueue) ? 0 : (front + 1);
return success;
}
void Extended_queue::print()
{
for (int i = 0, j = front;
i < this->count; i++, j = ((j + 1) == maxqueue) ? 0 : (j + 1))
cout << this->entry[j] << ' ';
cout << endl;
}
Queue.h
#include "Utility.h"
typedef char Queue_entry;
const int maxqueue = 1000; // small value for testing
class Queue {
public:
Queue();
bool empty() const;
Error_code serve();
Error_code append(const Queue_entry& item);
Error_code retrieve(Queue_entry& item) const;
protected:
int count;
int front, rear;
Queue_entry entry[maxqueue];
};
Queue.cpp
#include "Queue.h"
Queue::Queue()
/*
Post: The Queue is initialized to be empty.
*/
{
count = 0;
rear = maxqueue - 1;
front = 0;
}
bool Queue::empty() const
/*
Post: Return true if the Queue is empty, otherwise return false.
*/
{
return count == 0;
}
Error_code Queue::append(const Queue_entry& item)
/*
Post: item is added to the rear of the Queue. If the Queue is full
return an Error_code of overflow and leave the Queue unchanged.
*/
{
if (count >= maxqueue) return overflow;
count++;
rear = ((rear + 1) == maxqueue) ? 0 : (rear + 1);
entry[rear] = item;
return success;
}
Error_code Queue::serve()
/*
Post: The front of the Queue is removed. If the Queue
is empty return an Error_code of underflow.
*/
{
if (count <= 0) return underflow;
count--;
front = ((front + 1) == maxqueue) ? 0 : (front + 1);
return success;
}
Error_code Queue::retrieve(Queue_entry& item) const
/*
Post: The front of the Queue retrieved to the output
parameter item. If the Queue is empty return an Error_code of underflow.
*/
{
if (count <= 0) return underflow;
item = entry[front];
return success;
}
Utility.h
#pragma once
#include <iostream>
using namespace std;
enum Error_code {
success, fail, utility_range_error, underflow, overflow, fatal, not_present,
duplicate_error, entry_inserted, entry_found, internal_error
};
bool user_says_yes();
Utility.cpp
#include "Utility.h"
#include <iostream>
using namespace std;
bool user_says_yes()
{
int c;
bool initial_response = true;
do { // Loop until an appropriate input is received.
if (initial_response)
cout << " (y,n)? " << flush;
else
cout << "Respond with either y or n: " << flush;
do { // Ignore white space.
c = cin.get();
} while (c == '\n' || c == ' ' || c == '\t');
initial_response = false;
} while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
return (c == 'y' || c == 'Y');
}
Main.cpp
#include "Random.h"
#include "Plane.h"
#include "Runway.h"
#include "Utility.h"
#include <iostream>
using namespace std;
void run_idle(int time)
/*
Post: The specified time is printed with a message that the runway is idle.
*/
{
cout << time << ": Runway is idle." << endl;
}
void initialize(int& end_time, int& queue_limit,
double& arrival_rate, double& departure_rate)
/*
Pre: The user specifies the number of time units in the simulation,
the maximal queue sizes permitted,
and the expected arrival and departure rates for the airport.
Post: The program prints instructions and initializes the parameters
end_time, queue_limit, arrival_rate, and departure_rate to
the specified values.
Uses: utility function user_says_yes
*/
{
cout << "This program simulates an airport with only one runway." << endl
<< "One plane can land or depart in each unit of time." << endl;
cout << "Up to what number of planes can be waiting to land "
<< "or take off at any time? " << flush;
cin >> queue_limit;
cout << "How many units of time will the simulation run?" << flush;
cin >> end_time;
bool acceptable;
do {
cout << "Expected number of arrivals per unit time?" << flush;
cin >> arrival_rate;
cout << "Expected number of departures per unit time?" << flush;
cin >> departure_rate;
if (arrival_rate < 0.0 || departure_rate < 0.0)
cerr << "These rates must be nonnegative." << endl;
else
acceptable = true;
if (acceptable && arrival_rate + departure_rate > 1.0)
cerr << "Safety Warning: This airport will become saturated. " << endl;
} while (!acceptable);
}
int main()
// Airport simulation program
/*
Pre: The user must supply the number of time intervals the simulation is to
run, the expected number of planes arriving, the expected number
of planes departing per time interval, and the
maximum allowed size for runway queues.
Post: The program performs a random simulation of the airport, showing
the status of the runway at each time interval, and prints out a
summary of airport operation at the conclusion.
Uses: Classes Runway, Plane, Random and functions run_idle, initialize.
*/
{
int end_time; // time to run simulation
int queue_limit; // size of Runway queues
int flight_number = 0;
double arrival_rate, departure_rate;
initialize(end_time, queue_limit, arrival_rate, departure_rate);
Random variable;
Runway small_airport(queue_limit);
for (int current_time = 0; current_time < end_time; current_time++) { // loop over time intervals
int number_arrivals = variable.poisson(arrival_rate); // current arrival requests
for (int i = 0; i < number_arrivals; i++) {
Plane current_plane(flight_number++, current_time, arriving);
if (small_airport.can_land(current_plane) != success)
current_plane.refuse();
}
int number_departures = variable.poisson(departure_rate); // current departure requests
for (int j = 0; j < number_departures; j++) {
Plane current_plane(flight_number++, current_time, departing);
if (small_airport.can_depart(current_plane) != success)
current_plane.refuse();
}
Plane moving_plane;
switch (small_airport.activity(current_time, moving_plane)) {
// Let at most one Plane onto the Runway at current_time.
case land:
moving_plane.land(current_time);
break;
case takeoff:
moving_plane.fly(current_time);
break;
case idle:
run_idle(current_time);
}
}
small_airport.shut_down(end_time);
}
I have tried to solve this for two days now so I really need help. Thanks in advance!
You're trying to fix a Plane inside a char sized hole. The compiler is telling you that it doesn't know how to convert a Plane to a Queue_entry which you define to be a char.
If you want it to be able to your Plane should inherit from Queue_entry. You should familiarize yourself with polymorphism, as it seems like that's what you're going for.
But even then it's likely that things won't work out as it does not seem like you have fully considered the memory allocation of your objects. If you want to put objects in a vector they will be allocated by the vector as necessary. This means you cannot have a vector of interfaces, as the object implementing the interface could have any size. What you could do instead is have a vector of unique_ptr<Queue_entry>.

C++ Queues:How to loop to display the correct start time and wait time of a Car Wash

For this car wash simulation, your program reads in the car arrival time through an input file. The total wash time for a car is 3 minutes. Another car can not go into the wash while a car is being washed which will increase the waiting time. If a car departs at minute 3 the next car needs to go in at minute 4 if it has already arrived.
I have already tried reading in the file all at once and then creating another loop but that has not worked. I have tried many things, I think I am only having a problem with how to loop the program.
#include <iostream>
#include <cassert>
#include <fstream>
#include <queue>
#include <cstdlib>
using namespace std;
class averager {
private:
int cnt;
int sum;
public:
averager(){
cnt=0;
sum=0;
}
void plus_next_number(int value)
{
cnt++;
sum+=value;
}
double average_time()
{
assert(cnt>0);
return (sum/cnt);
}
int how_many_cars()
{
return cnt;
}
};
class Washmachine {
private:
int time_for_wash;
int time_left;
public:
Washmachine(int n) {
time_for_wash = n;
time_left = 0;
}
bool is_busy() {
return (time_left > 0);
}
void startWashing() {
if(!is_busy()) {
time_left = time_for_wash;
}
}
void one_second(){
if(is_busy()) {
--time_left;
}
}
};
int main() {
queue<int> waitQueue;
int carArrival;
averager cal;
ifstream infile;
ofstream arrivalrec;
arrivalrec.open("arrival_time.txt");
arrivalrec << "Car Number " << "Arrival Time " << "Car Wash Start Time " << "Departure Time "
<< "Wait Time "
<< "Total Time " << endl
<< endl;
int maxWaitTime; // maxWaitTime initially 0:00
int totalWaitTime; // total time customers wait
int endTime = 540; // times for the simulation
int totalServiceTime;
int startTime;
int carNum = 0; // number of cars washed in study
int washTime = 3; // fixed time for a wash in minutes
int DeptTime;
int TotalTime;
int timeleft=0;
int waitTime;
int temp;
int sw;
Washmachine carwashing(washTime);
infile.open("input.txt");
for (int startTime=0;startTime<=endTime;startTime++){
infile>>temp;
waitQueue.push(temp);
if((!carwashing.is_busy())&&(!waitQueue.empty())) {
carArrival=waitQueue.front();
waitQueue.pop();
waitTime=temp-carArrival;
cal.plus_next_number(temp-carArrival);
carwashing.startWashing();
}
carwashing.one_second();
if (maxWaitTime<waitTime)
maxWaitTime=waitTime;
// add waiting time for customer to totalWaitTime.
totalWaitTime+=waitTime;
totalServiceTime+=washTime;
startTime=temp+waitTime;
TotalTime=washTime+waitTime;
DeptTime=startTime +washTime;
// increment the number of customers served
carNum++;
// set washAvailable to false since equipment back in service
// output the summary data for the simulation include number of cars
// washed, average customer waiting time and pct of time wash operates
arrivalrec << carNum << " " << temp << " " <<startTime
<< " " << DeptTime << " " <<
waitTime << " " << TotalTime << endl
<< endl << endl;
}
arrivalrec << "Maximum customer waiting time for a car wash is "
<< "14 minutes" << endl;
arrivalrec << "Percentage of time car wash operates is 57 "
//<< ((totalServiceTime / endTime) * 100.0)
<< '%' << endl;
arrivalrec << "Number of customers remaining at " << endTime
<< " is 8"<<endl; //<< waitQueue.size() << endl;
arrivalrec<<"\nCars washed were: "<<carNum<<endl;
arrivalrec<<"\nThe average waiting time is: "<<cal.average_time()<<endl;
int car_denied=0;
while(!waitQueue.empty())
{
waitQueue.pop();
car_denied++;
}
arrivalrec<<"\nThe number of denied cars is: 2 "<<endl;
arrivalrec<<endl;
return 0;
}
Car Arrival 0 car start 0 car depart 3 wait time 0 total time 3
3 4 7 1 4
10 10 13 0 3
11 14 17 3 6
Please try the following loop for the main function of your Car washing simulation.
Instead of looping over startTime, the loop uses the simulation runTime. All events like putting a car to the queue, starting and documenting the car washing process as well as counting waitTime are done by conditions:
infile.open("input.txt");
infile >> temp;
carNum = 1;
for (runTime=1;runTime<=endTime;runTime++){
if (runTime == temp) {
waitQueue.push(temp);
infile >> temp;
}
if((!carwashing.is_busy())&&(!waitQueue.empty())) {
carArrival=waitQueue.front();
waitQueue.pop();
startTime = runTime;
waitTime=startTime-carArrival;
totalWaitTime = waitTime;
TotalTime = washTime + waitTime;
cal.plus_next_number(startTime-carArrival);
carwashing.startWashing();
}
else
{
waitTime++;
}
if (carwashing.is_busy())
carwashing.one_second();
if ((!carwashing.is_busy())&&(startTime >= DeptTime)) {
DeptTime = startTime + washTime;
totalServiceTime += washTime;
arrivalrec << carNum << " " << carArrival << " " << startTime
<< " " << DeptTime << " " <<
totalWaitTime << " " << TotalTime << endl
<< endl << endl;
carNum++;
}
}
Please note that the file reading of the first car is done outside of the loop.
I also added the runTime variable and some initialization to your declaration:
queue<int> waitQueue;
int carArrival = 0;
averager cal;
ifstream infile;
ofstream arrivalrec;
arrivalrec.open("arrival_time.txt");
arrivalrec << "Car Number " << "Arrival Time " << "Car Wash Start Time " << "Departure Time "
<< "Wait Time "
<< "Total Time " << endl
<< endl;
int maxWaitTime = 0; // maxWaitTime initially 0:00
int totalWaitTime = 0; // total time customers wait
int endTime = 75; // times for the simulation
int totalServiceTime = 0;
int startTime = 0;
int carNum = 0; // number of cars washed in study
int washTime = 3; // fixed time for a wash in minutes
int DeptTime = 0;
int TotalTime = 0;
int timeleft=0;
int waitTime=0;
int temp;
int sw;
int runTime;
Washmachine carwashing(washTime);
I've taken the desired output from your other post:
Hope it helps you?