void MovingDots::updateDots() { // // Update positions // const GLint numValidDots = std::min(previousNumDots, currentNumDots); const GLfloat dt = GLfloat(currentTime - previousTime) / 1.0e6f; const GLfloat dr = dt * previousSpeed / previousFieldRadius; for (GLint i = 0; i < numValidDots; i++) { GLfloat &age = getAge(i); age += dt; if ((age <= previousLifetime) || (previousLifetime == 0.0f)) { advanceDot(i, dt, dr); } else { replaceDot(i, newDirection(previousCoherence), 0.0f); } } // // Update directions // if (currentCoherence != previousCoherence) { for (GLint i = 0; i < numValidDots; i++) { getDirection(i) = newDirection(currentCoherence); } } // // Update lifetimes // if (currentLifetime != previousLifetime) { for (GLint i = 0; i < numValidDots; i++) { getAge(i) = newAge(currentLifetime); } } // // Add/remove dots // if (currentNumDots != previousNumDots) { dotPositions.resize(currentNumDots * componentsPerDot); dotDirections.resize(currentNumDots); dotAges.resize(currentNumDots); for (GLint i = previousNumDots; i < currentNumDots; i++) { replaceDot(i, newDirection(currentCoherence), newAge(currentLifetime)); } } }
bool GenericTaskQueue<E, F, N>::pop_global(volatile E& t) { Age oldAge = _age.get(); // Architectures with weak memory model require a barrier here // to guarantee that bottom is not older than age, // which is crucial for the correctness of the algorithm. #if !(defined SPARC || defined IA32 || defined AMD64) OrderAccess::fence(); #endif uint localBot = OrderAccess::load_acquire((volatile juint*)&_bottom); uint n_elems = size(localBot, oldAge.top()); if (n_elems == 0) { return false; } // g++ complains if the volatile result of the assignment is // unused, so we cast the volatile away. We cannot cast directly // to void, because gcc treats that as not using the result of the // assignment. However, casting to E& means that we trigger an // unused-value warning. So, we cast the E& to void. (void) const_cast<E&>(t = _elems[oldAge.top()]); Age newAge(oldAge); newAge.increment(); Age resAge = _age.cmpxchg(newAge, oldAge); // Note that using "_bottom" here might fail, since a pop_local might // have decremented it. assert(dirty_size(localBot, newAge.top()) != N - 1, "sanity"); return resAge == oldAge; }
bool GenericTaskQueue<E, F, N>::pop_local_slow(uint localBot, Age oldAge) { // This queue was observed to contain exactly one element; either this // thread will claim it, or a competing "pop_global". In either case, // the queue will be logically empty afterwards. Create a new Age value // that represents the empty queue for the given value of "_bottom". (We // must also increment "tag" because of the case where "bottom == 1", // "top == 0". A pop_global could read the queue element in that case, // then have the owner thread do a pop followed by another push. Without // the incrementing of "tag", the pop_global's CAS could succeed, // allowing it to believe it has claimed the stale element.) Age newAge((idx_t)localBot, oldAge.tag() + 1); // Perhaps a competing pop_global has already incremented "top", in which // case it wins the element. if (localBot == oldAge.top()) { // No competing pop_global has yet incremented "top"; we'll try to // install new_age, thus claiming the element. Age tempAge = _age.cmpxchg(newAge, oldAge); if (tempAge == oldAge) { // We win. assert(dirty_size(localBot, _age.top()) != N - 1, "sanity"); TASKQUEUE_STATS_ONLY(stats.record_pop_slow()); return true; } } // We lose; a completing pop_global gets the element. But the queue is empty // and top is greater than bottom. Fix this representation of the empty queue // to become the canonical one. _age.set(newAge); assert(dirty_size(localBot, _age.top()) != N - 1, "sanity"); return false; }
void MovingDots::advanceDot(GLint i, GLfloat dt, GLfloat dr) { GLfloat &x = getX(i); GLfloat &y = getY(i); GLfloat &theta = getDirection(i); x += dr * std::cos(theta); y += dr * std::sin(theta); if (x*x + y*y > 1.0f) { theta = newDirection(previousCoherence); GLfloat y1 = rand(-1.0f, 1.0f); GLfloat x1 = -std::sqrt(1.0f - y1*y1) + rand(0.0f, dr); x = x1*std::cos(theta) - y1*std::sin(theta); y = x1*std::sin(theta) + y1*std::cos(theta); getAge(i) = newAge(previousLifetime); } }