Skip to content

Commit ae911cf

Browse files
committed
dT calc Forces speedup
- sorting/reducing simpliefied in dT - kT faster due to reverting async memset
1 parent fc0cd65 commit ae911cf

5 files changed

Lines changed: 183 additions & 173 deletions

File tree

src/DEM/dT.cpp

Lines changed: 35 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ void DEMDynamicThread::changeOwnerSizes(const std::vector<bodyID_t>& IDs, const
520520
size_t ownerFactorSize = (size_t)simParams->nOwnerBodies * sizeof(float);
521521
// Bool table for whether this owner should change
522522
notStupidBool_t* idBool = (notStupidBool_t*)solverScratchSpace.allocateTempVector("idBool", idBoolSize);
523-
DEME_GPU_CALL(cudaMemsetAsync(idBool, 0, idBoolSize, streamInfo.stream));
523+
DEME_GPU_CALL(cudaMemset(idBool, 0, idBoolSize));
524524
float* ownerFactors = (float*)solverScratchSpace.allocateTempVector("ownerFactors", ownerFactorSize);
525525

526526
// Mark on the bool array those owners that need a change
@@ -638,7 +638,7 @@ void DEMDynamicThread::allocateGPUArrays(size_t nOwnerBodies,
638638
// maxTriTriPenetration usually keeps the max tri--tri penetration during the on-going simulation. But after
639639
// initialization, when it stores no meaningful values, dT will send a work order to kT, so maxTriTriPenetration's
640640
// value has to be initialized.
641-
DEME_GPU_CALL(cudaMemsetAsync(maxTriTriPenetration.getDevicePointer(), 0, sizeof(double), streamInfo.stream));
641+
DEME_GPU_CALL(cudaMemset(maxTriTriPenetration.getDevicePointer(), 0, sizeof(double)));
642642

643643
// Resize to the number of analytical geometries
644644
DEME_DUAL_ARRAY_RESIZE(ownerAnalBody, nAnalGM, 0);
@@ -2499,25 +2499,8 @@ inline void DEMDynamicThread::dispatchPatchBasedForceCorrections(
24992499
const ContactTypeMap<std::pair<contactPairs_t, contactPairs_t>>& typeStartCountPatchMap,
25002500
const ContactTypeMap<std::vector<std::pair<std::shared_ptr<JitHelper::CachedProgram>, std::string>>>&
25012501
typeKernelMap) {
2502-
// Reset max tri-tri penetration only when mesh contacts are present (avoid needless clears), async to overlap
2503-
bool needTriPenReset = false;
2504-
auto markIfTri = [&](contact_t c) {
2505-
auto itP = typeStartCountPrimitiveMap.find(c);
2506-
if (itP != typeStartCountPrimitiveMap.end() && itP->second.second > 0) {
2507-
needTriPenReset = true;
2508-
return;
2509-
}
2510-
auto itPatch = typeStartCountPatchMap.find(c);
2511-
if (itPatch != typeStartCountPatchMap.end() && itPatch->second.second > 0) {
2512-
needTriPenReset = true;
2513-
}
2514-
};
2515-
markIfTri(SPHERE_TRIANGLE_CONTACT);
2516-
markIfTri(TRIANGLE_TRIANGLE_CONTACT);
2517-
markIfTri(TRIANGLE_ANALYTICAL_CONTACT);
2518-
if (needTriPenReset) {
2519-
DEME_GPU_CALL(cudaMemsetAsync(maxTriTriPenetration.getDevicePointer(), 0, sizeof(double), streamInfo.stream));
2520-
}
2502+
// Reset max tri-tri penetration for this timestep on device (kT may need this info)
2503+
DEME_GPU_CALL(cudaMemset(maxTriTriPenetration.getDevicePointer(), 0, sizeof(double)));
25212504

25222505
// For each contact type that exists, check if it is patch(mesh)-related type...
25232506
for (size_t i = 0; i < m_numExistingTypes; i++) {
@@ -2531,112 +2514,74 @@ inline void DEMDynamicThread::dispatchPatchBasedForceCorrections(
25312514
contactPairs_t startOffsetPatch = start_count_patch.first;
25322515
contactPairs_t countPatch = start_count_patch.second;
25332516

2534-
// Vote for the contact direction; voting power depends on the contact area
2535-
// This reduce-by-key operation reduces primitive-recorded force pairs into patch/convex part-based
2536-
// force pairs. All elements that share the same geomToPatchMap value vote together.
25372517
if (countPrimitive > 0) {
25382518
contactPairs_t* keys = granData->geomToPatchMap + startOffsetPrimitive;
2539-
// Allocate temporary arrays for the voting process
2540-
float3* weightedNormals =
2541-
(float3*)solverScratchSpace.allocateTempVector("weightedNormals", countPrimitive * sizeof(float3));
2542-
25432519
// Allocate arrays for reduce-by-key results (uniqueKeys uses contactPairs_t, not patchIDPair_t)
25442520
contactPairs_t* uniqueKeys = (contactPairs_t*)solverScratchSpace.allocateTempVector(
25452521
"uniqueKeys", countPrimitive * sizeof(contactPairs_t));
2546-
float3* votedWeightedNormals = (float3*)solverScratchSpace.allocateTempVector(
2547-
"votedWeightedNormals", countPrimitive * sizeof(float3));
25482522
solverScratchSpace.allocateDualStruct("numUniqueKeys");
25492523
size_t* numUniqueKeys = solverScratchSpace.getDualStructDevice("numUniqueKeys");
25502524

2551-
// Step 1: Prepare weighted normals. Keys are read directly from geomToPatchMap.
2525+
// Step 1: Area-weighted normals for voting
2526+
float3* weightedNormals =
2527+
(float3*)solverScratchSpace.allocateTempVector("weightedNormals", countPrimitive * sizeof(float3));
25522528
prepareWeightedNormalsForVoting(&granData, weightedNormals, startOffsetPrimitive, countPrimitive,
25532529
streamInfo.stream);
25542530

2555-
// Step 2: Reduce-by-key for weighted normals (sum)
2556-
// The keys are geomToPatchMap values (contactPairs_t), which group primitives by patch pair
2531+
float3* votedWeightedNormals = (float3*)solverScratchSpace.allocateTempVector(
2532+
"votedWeightedNormals", countPrimitive * sizeof(float3));
25572533
cubSumReduceByKey<contactPairs_t, float3>(keys, uniqueKeys, weightedNormals, votedWeightedNormals,
25582534
numUniqueKeys, countPrimitive, streamInfo.stream,
25592535
solverScratchSpace);
25602536
solverScratchSpace.finishUsingTempVector("weightedNormals");
2561-
// For extra safety
2537+
2538+
// Normalize the voted normals using unique keys and scatter to patch-local storage.
2539+
float3* votedNormals =
2540+
(float3*)solverScratchSpace.allocateTempVector("votedNormals", countPatch * sizeof(float3));
25622541
solverScratchSpace.syncDualStructDeviceToHost("numUniqueKeys");
25632542
size_t numUniqueKeysHost = *(solverScratchSpace.getDualStructHost("numUniqueKeys"));
2564-
// std::cout << "Keys:" << std::endl;
2565-
// displayDeviceArray<contactPairs_t>(keys, countPrimitive);
2566-
// std::cout << "Unique Keys:" << std::endl;
2567-
// displayDeviceArray<contactPairs_t>(uniqueKeys, numUniqueKeysHost);
2543+
normalizeAndScatterVotedNormalsFromUniqueKeys(votedWeightedNormals, uniqueKeys, votedNormals,
2544+
startOffsetPatch, numUniqueKeysHost, streamInfo.stream);
2545+
solverScratchSpace.finishUsingTempVector("votedWeightedNormals");
25682546
if (numUniqueKeysHost != countPatch) {
25692547
DEME_ERROR(
25702548
"Patch-based contact voting produced %zu unique patch pairs, but expected %zu pairs for "
25712549
"contact type %d!",
25722550
numUniqueKeysHost, countPatch, contact_type);
25732551
}
25742552

2575-
// Normalize the voted normals using unique keys and scatter to patch-local storage.
2576-
float3* votedNormals =
2577-
(float3*)solverScratchSpace.allocateTempVector("votedNormals", countPatch * sizeof(float3));
2578-
normalizeAndScatterVotedNormalsFromUniqueKeys(votedWeightedNormals, uniqueKeys, votedNormals,
2579-
startOffsetPatch, numUniqueKeysHost, streamInfo.stream);
2580-
solverScratchSpace.finishUsingTempVector("votedWeightedNormals");
2581-
// displayDeviceFloat3(votedNormals, countPatch);
2582-
2583-
// Project penetration/area and accumulate weighted contact points in a single pass.
2584-
PatchContactAccum* primitivePatchAccumulators =
2585-
(PatchContactAccum*)solverScratchSpace.allocateTempVector(
2586-
"primitivePatchAccumulators", countPrimitive * sizeof(PatchContactAccum));
2587-
computePatchContactAccumulators(&granData, votedNormals, keys, primitivePatchAccumulators,
2588-
startOffsetPrimitive, startOffsetPatch, countPrimitive,
2589-
streamInfo.stream);
2553+
// Step 2: Fused accumulation (sum + max) in a single reduce-by-key.
2554+
FusedPatchAccum* primitiveAccums = (FusedPatchAccum*)solverScratchSpace.allocateTempVector(
2555+
"fusedPrimitiveAccums", countPrimitive * sizeof(FusedPatchAccum));
2556+
computeFusedPatchContactAccumulators(&granData, votedNormals, keys, primitiveAccums,
2557+
startOffsetPrimitive, startOffsetPatch, countPrimitive,
2558+
streamInfo.stream);
25902559

2591-
PatchContactAccum* patchContactAccumulators = (PatchContactAccum*)solverScratchSpace.allocateTempVector(
2592-
"patchContactAccumulators", numUniqueKeysHost * sizeof(PatchContactAccum));
2593-
cubSumReduceByKey<contactPairs_t, PatchContactAccum>(
2594-
keys, uniqueKeys, primitivePatchAccumulators, patchContactAccumulators, numUniqueKeys,
2595-
countPrimitive, streamInfo.stream, solverScratchSpace);
2596-
solverScratchSpace.finishUsingTempVector("primitivePatchAccumulators");
2560+
FusedPatchAccum* patchAccums = (FusedPatchAccum*)solverScratchSpace.allocateTempVector(
2561+
"fusedPatchAccums", numUniqueKeysHost * sizeof(FusedPatchAccum));
2562+
cubSumReduceByKey<contactPairs_t, FusedPatchAccum>(keys, uniqueKeys, primitiveAccums, patchAccums,
2563+
numUniqueKeys, countPrimitive, streamInfo.stream,
2564+
solverScratchSpace);
2565+
solverScratchSpace.finishUsingTempVector("fusedPrimitiveAccums");
25972566

25982567
double* totalProjectedAreas =
25992568
(double*)solverScratchSpace.allocateTempVector("totalProjectedAreas", countPatch * sizeof(double));
26002569
double* maxProjectedPenetrations = (double*)solverScratchSpace.allocateTempVector(
26012570
"maxProjectedPenetrations", countPatch * sizeof(double));
26022571
double3* votedContactPoints =
26032572
(double3*)solverScratchSpace.allocateTempVector("votedContactPoints", countPatch * sizeof(double3));
2604-
scatterPatchContactAccumulators(patchContactAccumulators, uniqueKeys, totalProjectedAreas,
2605-
maxProjectedPenetrations, votedContactPoints, startOffsetPatch,
2606-
numUniqueKeysHost, streamInfo.stream);
2607-
solverScratchSpace.finishUsingTempVector("patchContactAccumulators");
2608-
2609-
// Step 9: Handle zero-area patches (all primitive areas are 0)
2610-
// For these patches, we need to find the max penetration primitive and use its normal/penetration
2611-
2612-
// 9a: Extract primitive penetrations for max-reduce
2613-
double* primitivePenetrations = (double*)solverScratchSpace.allocateTempVector(
2614-
"primitivePenetrations", countPrimitive * sizeof(double));
2615-
extractPrimitivePenetrations(&granData, primitivePenetrations, startOffsetPrimitive, countPrimitive,
2616-
streamInfo.stream);
2617-
2618-
// 9b: Max-negative-reduce-by-key to get max negative penetration per patch
2619-
// This finds the largest negative value (smallest absolute value among negatives)
2620-
// Positive values are treated as very negative to indicate invalid/non-physical state
2621-
double* maxPenetrations =
2622-
(double*)solverScratchSpace.allocateTempVector("maxPenetrations", countPatch * sizeof(double));
2623-
cubMaxNegativeReduceByKey<contactPairs_t, double>(keys, uniqueKeys, primitivePenetrations,
2624-
maxPenetrations, numUniqueKeys, countPrimitive,
2625-
streamInfo.stream, solverScratchSpace);
2626-
solverScratchSpace.finishUsingTempVector("primitivePenetrations");
2627-
2628-
// 9c: Find max-penetration primitives for zero-area patches and extract their normals, penetrations,
2629-
// and contact points
26302573
float3* zeroAreaNormals =
26312574
(float3*)solverScratchSpace.allocateTempVector("zeroAreaNormals", countPatch * sizeof(float3));
26322575
double* zeroAreaPenetrations =
26332576
(double*)solverScratchSpace.allocateTempVector("zeroAreaPenetrations", countPatch * sizeof(double));
26342577
double3* zeroAreaContactPoints = (double3*)solverScratchSpace.allocateTempVector(
26352578
"zeroAreaContactPoints", countPatch * sizeof(double3));
2636-
findMaxPenetrationPrimitiveForZeroAreaPatches(
2637-
&granData, maxPenetrations, zeroAreaNormals, zeroAreaPenetrations, zeroAreaContactPoints, keys,
2638-
startOffsetPrimitive, startOffsetPatch, countPrimitive, streamInfo.stream);
2639-
solverScratchSpace.finishUsingTempVector("maxPenetrations");
2579+
2580+
scatterFusedPatchAccumulators(patchAccums, uniqueKeys, totalProjectedAreas, maxProjectedPenetrations,
2581+
votedContactPoints, votedNormals, zeroAreaNormals, zeroAreaPenetrations,
2582+
zeroAreaContactPoints, startOffsetPatch, numUniqueKeysHost,
2583+
streamInfo.stream);
2584+
solverScratchSpace.finishUsingTempVector("fusedPatchAccums");
26402585

26412586
// Step 9d: Check if each patch has any SAT-satisfying primitive (for tri-tri contacts)
26422587
// If no primitive satisfies SAT, the patch contact is non-physical and should use Step 9 fallback
@@ -3417,7 +3362,7 @@ float* DEMDynamicThread::inspectCall(const std::shared_ptr<JitHelper::CachedProg
34173362
// If this boolArrExclude is 1 at an element, that means this element is exluded in the reduction
34183363
notStupidBool_t* boolArrExclude =
34193364
(notStupidBool_t*)solverScratchSpace.allocateTempVector("boolArrExclude", regionTempSize);
3420-
DEME_GPU_CALL(cudaMemsetAsync(boolArrExclude, 0, regionTempSize, streamInfo.stream));
3365+
DEME_GPU_CALL(cudaMemset(boolArrExclude, 0, regionTempSize));
34213366

34223367
// We may actually have 2 reduced returns: in regional reduction, key 0 and 1 give one return each.
34233368
size_t returnSize = sizeof(float) * 2;

src/DEM/kT.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ void DEMKinematicThread::changeOwnerSizes(const std::vector<bodyID_t>& IDs, cons
612612
size_t ownerFactorSize = (size_t)simParams->nOwnerBodies * sizeof(float);
613613
// Bool table for whether this owner should change
614614
notStupidBool_t* idBool = (notStupidBool_t*)solverScratchSpace.allocateTempVector("idBool", idBoolSize);
615-
DEME_GPU_CALL(cudaMemsetAsync(idBool, 0, idBoolSize, streamInfo.stream));
615+
DEME_GPU_CALL(cudaMemset(idBool, 0, idBoolSize));
616616
float* ownerFactors = (float*)solverScratchSpace.allocateTempVector("ownerFactors", ownerFactorSize);
617617

618618
// Mark on the bool array those owners that need a change

src/algorithms/DEMCubInstantiations.cu

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,14 @@ template void cubSumReduceByKey<contactPairs_t, PatchContactAccum>(contactPairs_
106106
size_t n,
107107
cudaStream_t& this_stream,
108108
DEMSolverScratchData& scratchPad);
109+
template void cubSumReduceByKey<contactPairs_t, FusedPatchAccum>(contactPairs_t* d_keys_in,
110+
contactPairs_t* d_unique_out,
111+
FusedPatchAccum* d_vals_in,
112+
FusedPatchAccum* d_aggregates_out,
113+
size_t* d_num_out,
114+
size_t n,
115+
cudaStream_t& this_stream,
116+
DEMSolverScratchData& scratchPad);
109117

110118
////////////////////////////////////////////////////////////////////////////////
111119
// Reduce::Max

0 commit comments

Comments
 (0)