Skip to content

Changed Cells, CellLookup, MCells, and MCellsLookup to std::vector(...)#200

Open
chrisatang wants to merge 7 commits into
mrc-ide:masterfrom
chrisatang:calloc_to_vec
Open

Changed Cells, CellLookup, MCells, and MCellsLookup to std::vector(...)#200
chrisatang wants to merge 7 commits into
mrc-ide:masterfrom
chrisatang:calloc_to_vec

Conversation

@chrisatang

Copy link
Copy Markdown

Changed the Cells, CellLookup, MCells, and MCellsLookup from dynamic calloc(...) to std::vector(...), which is a start to resolving any possible memory issues the current code might have.

@matt-gretton-dann matt-gretton-dann left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your PR, we are currently very busy and so responses will take a while.

Comment thread src/CovidSim.cpp
Comment on lines +74 to +77
std::vector<cell> Cells(P.NC); // Cells.at(i) is the i'th cell
std::vector<cell*> CellLookup(P.NCP); // CellLookup[i] is a pointer to the i'th populated cell
std::vector<microcell> Mcells(P.NMC);
std::vector<microcell*> McellLookup(P.NMCP);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are trying to initialise these at program start up time when P.NC is 0 - so this will fail - I think need to have something like:

std::vector<cell> Cells;

// Whereever the calloc was
Cells.resize(P.NC);

etc.

Comment thread src/CovidSim.cpp
for (i = tn; i < P.NC; i+=P.NumThreads)
{
if ((Cells[i].tot_treat != 0) || (Cells[i].tot_vacc != 0) || (Cells[i].S != Cells[i].n) || (Cells[i].D > 0) || (Cells[i].R > 0))
if ((Cells.at(i).tot_treat != 0) || (Cells.at(i).tot_vacc != 0) || (Cells.at(i).S != Cells.at(i).n) || (Cells.at(i).D > 0) || (Cells.at(i).R > 0))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::vector::at() will throw an exception on a bad access. Not a bad thing per se - however, the code isn't exception aware and I think there will be problems with exceptions crossing thread boundaries.

There are two solutions to this:

The easy one: Just use [] access everywhere. (Why do you use it in some places and not others?).

The harder one, put try/catch blocks everywhere that is appropriate.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to expand on the uncaught exceptions issue flagged here, the OpenMP specification mandates that an exception thrown within the omp parallel for region must cause the thread to resume within the same region (ie. no uncaught exceptions within omp parallel for loops).

I second the suggestion to prefer the use of operator[], rather than wrapping inner loops in try catch blocks, since I don't think there's much that can be done about an invalid index in either case, plus a segmentation fault raised by an invalid index is more obviously wrong.

Comment thread src/CovidSim.cpp
zfwrite_big((void*)Households, sizeof(household), (size_t)P.NH, dat);
fprintf(stderr, "## %i\n", i++);
zfwrite_big((void*)Cells, sizeof(cell), (size_t)P.NC, dat);
zfwrite_big((void*)&Cells.front(), sizeof(cell), (size_t)P.NC, dat);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
zfwrite_big((void*)&Cells.front(), sizeof(cell), (size_t)P.NC, dat);
zfwrite_big((void*)Cells.data(), sizeof(cell), (size_t)P.NC, dat);

Calling front results in undefined behaviour in the case where Cells is empty. C++11 introduced std::vector<T,Allocator>::data, which will simply return a null pointer in the case of an empty vector. We should use that here.

Comment thread src/CovidSim.cpp
for (i = tn; i < P.NC; i+=P.NumThreads)
{
if ((Cells[i].tot_treat != 0) || (Cells[i].tot_vacc != 0) || (Cells[i].S != Cells[i].n) || (Cells[i].D > 0) || (Cells[i].R > 0))
if ((Cells.at(i).tot_treat != 0) || (Cells.at(i).tot_vacc != 0) || (Cells.at(i).S != Cells.at(i).n) || (Cells.at(i).D > 0) || (Cells.at(i).R > 0))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to expand on the uncaught exceptions issue flagged here, the OpenMP specification mandates that an exception thrown within the omp parallel for region must cause the thread to resume within the same region (ie. no uncaught exceptions within omp parallel for loops).

I second the suggestion to prefer the use of operator[], rather than wrapping inner loops in try catch blocks, since I don't think there's much that can be done about an invalid index in either case, plus a segmentation fault raised by an invalid index is more obviously wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants