void RandomPermuter::subset_epoch( vector<epoch_op>::iterator &res_start, vector<epoch_op>::iterator &res_end, epoch &epoch) { unsigned int req_size = distance(res_start, res_end); assert(req_size <= epoch.ops.size()); // Even if the number of bios we're placing is less than the number in the // epoch, allow any bio but the barrier (if present) to be picked. unsigned int slots = epoch.ops.size(); if (epoch.has_barrier) { --slots; } // Bitmap to indicate which bios in the epoch we want to pick for the crash // state. vector<unsigned int> epoch_op_bitmap(epoch.ops.size()); // Fill the list with the empty slots, either [0, epoch.size() - 1] or // [0, epoch.size() - 2]. Prefer a list so that removals are fast. We have // this so that each time we shuffle the indexes of bios in the epoch, and // pick the first req_size number of bios. vector<unsigned int> indices(slots); iota(indices.begin(), indices.end(), 0); // Use a known random generator function for repeatability. std::random_shuffle(indices.begin(), indices.end(), subset_random_); // Populate the bitmap to set req_set number of bios. for (int i = 0; i < req_size; i++) { epoch_op_bitmap[indices[i]] = 1; } // Return the bios corresponding to bitmap indexes. for (unsigned int filled = 0; filled < epoch_op_bitmap.size() && res_start != res_end; filled++) { if (epoch_op_bitmap[filled] == 1) { *res_start = epoch.ops.at(filled); ++res_start; } } // We are only placing part of an epoch so we need to return here. if (res_start == res_end) { return; } assert(epoch.has_barrier); // Place the barrier operation if it exists since the entire vector already // exists (i.e. we won't cause extra shifting when adding the other elements). // Decrement out count of empty slots since we have filled one. *res_start = epoch.ops.back(); }
void random_iota(I first, I last) { iota(first, last, 0); std::random_shuffle(first, last); }
bool RandomPermuter::gen_one_sector_state(vector<DiskWriteData> &res, PermuteTestResult &log_data) { res.clear(); // Return if there are no ops to work with. if (GetEpochs()->size() == 0) { return false; } vector<epoch> *epochs = GetEpochs(); // Pick the point in the sequence we will crash at. // Find how many elements we will be returning (randomly determined). uniform_int_distribution<unsigned int> permute_epochs(1, epochs->size()); unsigned int num_epochs = permute_epochs(rand); unsigned int num_requests = 0; if (!epochs->at(num_epochs - 1).ops.empty()) { // It is not valid to call the random number generator with arguments (1, 0) // (you get a large number if you do), so skip this if the epoch we crash in // has no ops in it. // Don't subtract 1 from this size so that we can send a complete epoch if // we want. uniform_int_distribution<unsigned int> permute_requests(1, epochs->at(num_epochs - 1).ops.size()); num_requests = permute_requests(rand); } // Tell CrashMonkey the most recently seen checkpoint for the crash state // we're generating. We can't just pull the last epoch because it could be the // case that there's a checkpoint at the end of this disk write epoch. // Therefore, we should determine 1. if we are writing out this entire epoch, // and 2. if the checkpoint epoch for this disk write epoch is different than // the checkpoint epoch of the disk write epoch before this one (indicating // that this disk write epoch changes checkpoint epochs). epoch *target = &(epochs->at(num_epochs - 1)); epoch *prev = NULL; if (num_epochs > 1) { prev = &epochs->at(num_epochs - 2); } if (num_requests != target->ops.size()) { log_data.last_checkpoint = (prev) ? prev->checkpoint_epoch : 0; } else { log_data.last_checkpoint = target->checkpoint_epoch; } // Get and coalesce the sectors of the final epoch we crashed in. We do this // here so that we can determine the size of the resulting crash state and // allocate that many slots in `res` right off the bat, thus skipping later // reallocations as the vector grows. vector<EpochOpSector> final_epoch; for (unsigned int i = 0; i < num_requests; ++i) { vector<EpochOpSector> sectors = epochs->at(num_epochs - 1).ops.at(i).ToSectors(sector_size_); final_epoch.insert(final_epoch.end(), sectors.begin(), sectors.end()); } unsigned int total_elements = 0; for (unsigned int i = 0; i < num_epochs - 1; ++i) { total_elements += epochs->at(i).ops.size(); } if (final_epoch.empty()) { // No sectors to drop in the final epoch. res.resize(total_elements); auto epoch_end_iterator = epochs->begin() + num_epochs - 1; AddEpochs(res.begin(), res.end(), epochs->begin(), epoch_end_iterator); return true; } else if (num_requests == epochs->at(num_epochs - 1).ops.size() && epochs->at(num_epochs - 1).ops.back().op.is_barrier()) { // We picked the entire epoch and it has a barrier, so we can't rearrange // anything. res.resize(total_elements + epochs->at(num_epochs - 1).ops.size()); // + 1 because we also add the full epoch we "crash" in. auto epoch_end_iterator = epochs->begin() + num_epochs; AddEpochs(res.begin(), res.end(), epochs->begin(), epoch_end_iterator); return true; } // For this branch of execution, we are dropping some sectors from the final // epoch we are "crashing" in. // Pick a number of sectors to keep. final_epoch.size() > 0 due to if block // above, so no need to worry about getting an invalid range. uniform_int_distribution<unsigned int> rand_num_sectors(1, final_epoch.size()); const unsigned int num_sectors = rand_num_sectors(rand); final_epoch = CoalesceSectors(final_epoch); // Result size is now a known quantity. res.resize(total_elements + num_sectors); // Add the requests not in the final epoch to the result. auto epoch_end_iterator = epochs->begin() + (num_epochs - 1); auto res_end = res.begin() + total_elements; AddEpochs(res.begin(), res_end, epochs->begin(), epoch_end_iterator); // Randomly drop some sectors. vector<unsigned int> indices(final_epoch.size()); iota(indices.begin(), indices.end(), 0); // Use a known random generator function for repeatability. std::random_shuffle(indices.begin(), indices.end(), subset_random_); // Populate the bitmap to set req_set number of bios. This is required to keep // sectors in temporal order when we generate the crash state. vector<unsigned char> sector_bitmap(final_epoch.size()); for (int i = 0; i < num_sectors; ++i) { sector_bitmap[indices[i]] = 1; } // Add the sectors corresponding to bitmap indexes to the result. auto next_index = res.begin() + total_elements; for (unsigned int i = 0; i < sector_bitmap.size(); ++i) { if (next_index == res.end()) { break; } if (sector_bitmap[i] == 1) { *next_index = final_epoch.at(i).ToWriteData(); ++next_index; } } return true; }
void KDTree::build(const Spheres& spheres) { leaves = 0; this->spheres = spheres; sceneBBox = createBoundingBox(spheres); int axis = static_cast<int>(AXIS_X); KDNode root; nodes.push_back(root); StackNode stackNode; stackNode.bbox = sceneBBox; stackNode.nodeIdx = nodes.size() - 1; stackNode.sphereIndices.resize(spheres.count); iota(stackNode.sphereIndices.begin(), stackNode.sphereIndices.end(), 0); stack<StackNode> st; st.push(stackNode); while(!st.empty()) { StackNode stackNode = st.top(); st.pop(); if(stackNode.sphereIndices.size() <= maxSpheresInLeaf || nodes.size() >= maxNodes) { leavesChildren.push_back(stackNode.sphereIndices); initLeafNode(stackNode.nodeIdx, leavesChildren.size() - 1); ++leaves; continue; } axis = axis % 3; float leftLimit = stackNode.bbox.vmin[axis]; float rightLimit = stackNode.bbox.vmax[axis]; float splitPos = (leftLimit + rightLimit) * 0.5f; // TODO use SAH Axis splitAxis = static_cast<Axis>(axis); StackNode child1StackNode, child2StackNode; nodes.push_back(KDNode()); child1StackNode.nodeIdx = nodes.size() - 1; nodes.push_back(KDNode()); child2StackNode.nodeIdx = nodes.size() - 1; stackNode.bbox.split(splitAxis, splitPos, child1StackNode.bbox, child2StackNode.bbox); for(int i = 0; i < stackNode.sphereIndices.size(); ++i) { if(spheres.centerCoords[axis][stackNode.sphereIndices[i]] < splitPos) { child1StackNode.sphereIndices.push_back(stackNode.sphereIndices[i]); } else { child2StackNode.sphereIndices.push_back(stackNode.sphereIndices[i]); } } initInnerNode(stackNode.nodeIdx, splitAxis, splitPos, child1StackNode.nodeIdx); st.push(child2StackNode); st.push(child1StackNode); axis += 1; } }