-
Notifications
You must be signed in to change notification settings - Fork 74
cuda-gen: Add CUDA Graph capture and replay for composite operators #1987
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 14 commits
6261385
b156a00
83c1d9f
bbad4e2
285b661
10d6dd2
4abc7ad
1fa80ed
5b8e14f
94bdeca
a00af53
1ca2b5f
719027b
40f8c3e
91c8d6d
1249673
c7c5b1a
8f160e9
8f717af
8ef2be7
b170ec4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -11,7 +11,9 @@ | |||||||||||||||||
| #include <cuda.h> | ||||||||||||||||||
| #include <cuda_runtime.h> | ||||||||||||||||||
| #include <stddef.h> | ||||||||||||||||||
| #include <stdlib.h> | ||||||||||||||||||
| #include <string.h> | ||||||||||||||||||
| #include <stdint.h> | ||||||||||||||||||
|
|
||||||||||||||||||
| #include "../cuda/ceed-cuda-common.h" | ||||||||||||||||||
| #include "../cuda/ceed-cuda-compile.h" | ||||||||||||||||||
|
|
@@ -31,7 +33,19 @@ static int CeedOperatorDestroy_Cuda_gen(CeedOperator op) { | |||||||||||||||||
| if (impl->module_assemble_full) CeedCallCuda(ceed, cuModuleUnload(impl->module_assemble_full)); | ||||||||||||||||||
| if (impl->module_assemble_diagonal) CeedCallCuda(ceed, cuModuleUnload(impl->module_assemble_diagonal)); | ||||||||||||||||||
| if (impl->module_assemble_qfunction) CeedCallCuda(ceed, cuModuleUnload(impl->module_assemble_qfunction)); | ||||||||||||||||||
| if (impl->points.num_per_elem) CeedCallCuda(ceed, cudaFree((void **)impl->points.num_per_elem)); | ||||||||||||||||||
| if (impl->points.num_per_elem) CeedCallCuda(ceed, cudaFree((void *)impl->points.num_per_elem)); | ||||||||||||||||||
|
|
||||||||||||||||||
| if (impl->graph_created && impl->graph_launches > 0) { | ||||||||||||||||||
| char *op_name = NULL; | ||||||||||||||||||
| CeedOperatorGetName(op, (const char**)&op_name); | ||||||||||||||||||
| printf("[CUDA Graph] Summary for operator '%s': %d graph launches, %d fallbacks\n", | ||||||||||||||||||
| op_name ? op_name : "unnamed", impl->graph_launches, impl->fallbacks); | ||||||||||||||||||
| } | ||||||||||||||||||
| if (impl->graph_instance) { cudaGraphExecDestroy(impl->graph_instance); impl->graph_instance = NULL; } | ||||||||||||||||||
| if (impl->graph) { cudaGraphDestroy(impl->graph); impl->graph = NULL; } | ||||||||||||||||||
| impl->graph_created = false; | ||||||||||||||||||
| impl->captured_input_ptr = NULL; | ||||||||||||||||||
|
|
||||||||||||||||||
| CeedCallBackend(CeedFree(&impl)); | ||||||||||||||||||
| CeedCallBackend(CeedDestroy(&ceed)); | ||||||||||||||||||
| return CEED_ERROR_SUCCESS; | ||||||||||||||||||
|
|
@@ -224,8 +238,9 @@ static int CeedOperatorApplyAddCore_Cuda_gen(CeedOperator op, CUstream stream, c | |||||||||||||||||
| block[2] = elems_per_block; | ||||||||||||||||||
| } | ||||||||||||||||||
| CeedInt shared_mem = block[0] * block[1] * block[2] * sizeof(CeedScalar); | ||||||||||||||||||
|
|
||||||||||||||||||
| CeedCallBackend(CeedTryRunKernelDimShared_Cuda(ceed, data->op, stream, grid, block[0], block[1], block[2], shared_mem, is_run_good, opargs)); | ||||||||||||||||||
|
|
||||||||||||||||||
| CeedCallBackend( | ||||||||||||||||||
| CeedTryRunKernelDimShared_Cuda(ceed, data->op, stream, grid, block[0], block[1], block[2], shared_mem, is_run_good, opargs)); | ||||||||||||||||||
|
|
||||||||||||||||||
| // Restore input arrays | ||||||||||||||||||
| for (CeedInt i = 0; i < num_input_fields; i++) { | ||||||||||||||||||
|
|
@@ -284,7 +299,11 @@ static int CeedOperatorApplyAdd_Cuda_gen(CeedOperator op, CeedVector input_vec, | |||||||||||||||||
| // Try to run kernel | ||||||||||||||||||
| if (input_vec != CEED_VECTOR_NONE) CeedCallBackend(CeedVectorGetArrayRead(input_vec, CEED_MEM_DEVICE, &input_arr)); | ||||||||||||||||||
| if (output_vec != CEED_VECTOR_NONE) CeedCallBackend(CeedVectorGetArray(output_vec, CEED_MEM_DEVICE, &output_arr)); | ||||||||||||||||||
| CeedCallBackend(CeedOperatorApplyAddCore_Cuda_gen(op, NULL, input_arr, output_arr, &is_run_good, request)); | ||||||||||||||||||
| // During graph capture use the capturing stream, otherwise the default stream. | ||||||||||||||||||
| enum cudaStreamCaptureStatus capture_status; | ||||||||||||||||||
| cudaStreamIsCapturing(cudaStreamPerThread, &capture_status); | ||||||||||||||||||
| CUstream stream_to_use = (capture_status != cudaStreamCaptureStatusNone) ? cudaStreamPerThread : NULL; | ||||||||||||||||||
|
jeremylt marked this conversation as resolved.
Outdated
|
||||||||||||||||||
| CeedCallBackend(CeedOperatorApplyAddCore_Cuda_gen(op, stream_to_use, input_arr, output_arr, &is_run_good, request)); | ||||||||||||||||||
| if (input_vec != CEED_VECTOR_NONE) CeedCallBackend(CeedVectorRestoreArrayRead(input_vec, &input_arr)); | ||||||||||||||||||
| if (output_vec != CEED_VECTOR_NONE) CeedCallBackend(CeedVectorRestoreArray(output_vec, &output_arr)); | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
@@ -299,51 +318,216 @@ static int CeedOperatorApplyAdd_Cuda_gen(CeedOperator op, CeedVector input_vec, | |||||||||||||||||
| return CEED_ERROR_SUCCESS; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| // Push each suboperator's QFunction context to device. Replay skips the normal | ||||||||||||||||||
| // apply path, so we do this by hand to keep time/load parameters current. | ||||||||||||||||||
| static int CeedCompositeRefreshContexts_Cuda_gen(CeedOperator *sub_operators, CeedInt num_suboperators) { | ||||||||||||||||||
| for (CeedInt i = 0; i < num_suboperators; i++) { | ||||||||||||||||||
| CeedQFunction qf = NULL; | ||||||||||||||||||
| void *d_c = NULL; | ||||||||||||||||||
|
|
||||||||||||||||||
| CeedCallBackend(CeedOperatorGetQFunction(sub_operators[i], &qf)); | ||||||||||||||||||
| CeedCallBackend(CeedQFunctionGetInnerContextData(qf, CEED_MEM_DEVICE, &d_c)); | ||||||||||||||||||
| CeedCallBackend(CeedQFunctionRestoreInnerContextData(qf, &d_c)); | ||||||||||||||||||
| CeedCallBackend(CeedQFunctionDestroy(&qf)); | ||||||||||||||||||
| } | ||||||||||||||||||
| return CEED_ERROR_SUCCESS; | ||||||||||||||||||
| } | ||||||||||||||||||
|
zatkins-dev marked this conversation as resolved.
Outdated
|
||||||||||||||||||
|
|
||||||||||||||||||
| static int CeedOperatorApplyAddComposite_Cuda_gen(CeedOperator op, CeedVector input_vec, CeedVector output_vec, CeedRequest *request) { | ||||||||||||||||||
| bool is_run_good[CEED_COMPOSITE_MAX] = {false}, is_sequential; | ||||||||||||||||||
| CeedInt num_suboperators; | ||||||||||||||||||
| const CeedScalar *input_arr = NULL; | ||||||||||||||||||
| CeedScalar *output_arr = NULL; | ||||||||||||||||||
| Ceed ceed; | ||||||||||||||||||
| CeedOperator *sub_operators; | ||||||||||||||||||
| cudaStream_t stream = NULL; | ||||||||||||||||||
| Ceed ceed; | ||||||||||||||||||
| CeedOperator_Cuda_gen *impl; | ||||||||||||||||||
| CeedOperator *sub_operators; | ||||||||||||||||||
| CeedInt num_suboperators; | ||||||||||||||||||
| char *op_name = NULL; | ||||||||||||||||||
|
|
||||||||||||||||||
| CeedCallBackend(CeedOperatorGetCeed(op, &ceed)); | ||||||||||||||||||
| ceed = CeedOperatorReturnCeed(op); | ||||||||||||||||||
|
jeremylt marked this conversation as resolved.
Outdated
|
||||||||||||||||||
| CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators)); | ||||||||||||||||||
| CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators)); | ||||||||||||||||||
| CeedCall(CeedOperatorCompositeIsSequential(op, &is_sequential)); | ||||||||||||||||||
| if (input_vec != CEED_VECTOR_NONE) CeedCallBackend(CeedVectorGetArrayRead(input_vec, CEED_MEM_DEVICE, &input_arr)); | ||||||||||||||||||
| if (output_vec != CEED_VECTOR_NONE) CeedCallBackend(CeedVectorGetArray(output_vec, CEED_MEM_DEVICE, &output_arr)); | ||||||||||||||||||
| if (is_sequential) CeedCallCuda(ceed, cudaStreamCreate(&stream)); | ||||||||||||||||||
| for (CeedInt i = 0; i < num_suboperators; i++) { | ||||||||||||||||||
| CeedInt num_elem = 0; | ||||||||||||||||||
| CeedCallBackend(CeedOperatorGetData(op, &impl)); | ||||||||||||||||||
| CeedCallBackend(CeedOperatorGetName(op, (const char **)&op_name)); | ||||||||||||||||||
|
|
||||||||||||||||||
| // CEED_FORCE_BASELINE=1: skip graphs, run via /gpu/cuda/ref | ||||||||||||||||||
| static bool force_baseline = false; | ||||||||||||||||||
| static bool force_baseline_checked = false; | ||||||||||||||||||
| if (!force_baseline_checked) { | ||||||||||||||||||
| char *env_val = getenv("CEED_FORCE_BASELINE"); | ||||||||||||||||||
| force_baseline = (env_val != NULL && strcmp(env_val, "1") == 0); | ||||||||||||||||||
| force_baseline_checked = true; | ||||||||||||||||||
| } | ||||||||||||||||||
| if (force_baseline) { | ||||||||||||||||||
| CeedOperator op_fallback; | ||||||||||||||||||
| CeedCallBackend(CeedOperatorGetFallback(op, &op_fallback)); | ||||||||||||||||||
| CeedCallBackend(CeedOperatorApplyAdd(op_fallback, input_vec, output_vec, request)); | ||||||||||||||||||
| return CEED_ERROR_SUCCESS; | ||||||||||||||||||
| } | ||||||||||||||||||
|
zatkins-dev marked this conversation as resolved.
Outdated
|
||||||||||||||||||
|
|
||||||||||||||||||
| CeedCall(CeedOperatorGetNumElements(sub_operators[i], &num_elem)); | ||||||||||||||||||
| if (num_elem > 0) { | ||||||||||||||||||
| if (!is_sequential) CeedCallCuda(ceed, cudaStreamCreate(&stream)); | ||||||||||||||||||
| CeedCallBackend(CeedOperatorApplyAddCore_Cuda_gen(sub_operators[i], stream, input_arr, output_arr, &is_run_good[i], request)); | ||||||||||||||||||
| if (!is_sequential) CeedCallCuda(ceed, cudaStreamDestroy(stream)); | ||||||||||||||||||
| // CEED_DISABLE_GRAPH=1: run suboperators directly, no capture/replay (for benchmarking). | ||||||||||||||||||
| static bool disable_graph = false; | ||||||||||||||||||
|
zatkins-dev marked this conversation as resolved.
Outdated
|
||||||||||||||||||
| static bool disable_graph_checked = false; | ||||||||||||||||||
| if (!disable_graph_checked) { | ||||||||||||||||||
| char *env_val = getenv("CEED_DISABLE_GRAPH"); | ||||||||||||||||||
| disable_graph = (env_val != NULL && strcmp(env_val, "1") == 0); | ||||||||||||||||||
| disable_graph_checked = true; | ||||||||||||||||||
| } | ||||||||||||||||||
| if (disable_graph) { | ||||||||||||||||||
| for (CeedInt i = 0; i < num_suboperators; i++) { | ||||||||||||||||||
| CeedCallBackend(CeedOperatorApplyAdd(sub_operators[i], input_vec, output_vec, request)); | ||||||||||||||||||
|
zatkins-dev marked this conversation as resolved.
Outdated
|
||||||||||||||||||
| } | ||||||||||||||||||
| return CEED_ERROR_SUCCESS; | ||||||||||||||||||
| } | ||||||||||||||||||
| if (is_sequential) CeedCallCuda(ceed, cudaStreamDestroy(stream)); | ||||||||||||||||||
| if (input_vec != CEED_VECTOR_NONE) CeedCallBackend(CeedVectorRestoreArrayRead(input_vec, &input_arr)); | ||||||||||||||||||
|
zatkins-dev marked this conversation as resolved.
|
||||||||||||||||||
| if (output_vec != CEED_VECTOR_NONE) CeedCallBackend(CeedVectorRestoreArray(output_vec, &output_arr)); | ||||||||||||||||||
| CeedCallCuda(ceed, cudaDeviceSynchronize()); | ||||||||||||||||||
|
|
||||||||||||||||||
| // Fallback on unsuccessful run | ||||||||||||||||||
| for (CeedInt i = 0; i < num_suboperators; i++) { | ||||||||||||||||||
| if (!is_run_good[i]) { | ||||||||||||||||||
| CeedOperator op_fallback; | ||||||||||||||||||
| // No real I/O buffers to capture; just run directly. | ||||||||||||||||||
| if (input_vec == CEED_VECTOR_NONE || output_vec == CEED_VECTOR_NONE) { | ||||||||||||||||||
|
zatkins-dev marked this conversation as resolved.
Outdated
|
||||||||||||||||||
| for (CeedInt i = 0; i < num_suboperators; i++) { | ||||||||||||||||||
| CeedCallBackend(CeedOperatorApplyAdd(sub_operators[i], input_vec, output_vec, request)); | ||||||||||||||||||
|
zatkins-dev marked this conversation as resolved.
Outdated
|
||||||||||||||||||
| } | ||||||||||||||||||
| return CEED_ERROR_SUCCESS; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| // Phase 1: first call runs directly so lazy allocations happen before capture. | ||||||||||||||||||
| if (!impl->warmup_done) { | ||||||||||||||||||
| for (CeedInt i = 0; i < num_suboperators; i++) { | ||||||||||||||||||
| CeedCallBackend(CeedOperatorApplyAdd(sub_operators[i], input_vec, output_vec, request)); | ||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should use
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated. Warmup now goes through CeedOperatorApplyAddComposite_NoGraph_Cuda_gen, which calls CeedOperatorApplyAddCore_Cuda_gen directly with is_run_good tracking the same as the original composite apply path. The capture loop also uses Core directly rather than the public interface. |
||||||||||||||||||
| } | ||||||||||||||||||
| CeedCallCuda(ceed, cudaDeviceSynchronize()); | ||||||||||||||||||
| impl->warmup_done = true; | ||||||||||||||||||
| return CEED_ERROR_SUCCESS; | ||||||||||||||||||
| } | ||||||||||||||||||
|
zatkins-dev marked this conversation as resolved.
|
||||||||||||||||||
|
|
||||||||||||||||||
| // Phase 2: capture. | ||||||||||||||||||
| if (!impl->graph_created) { | ||||||||||||||||||
| { | ||||||||||||||||||
| const CeedScalar *in_ptr; | ||||||||||||||||||
| CeedCallBackend(CeedVectorGetArrayRead(input_vec, CEED_MEM_DEVICE, &in_ptr)); | ||||||||||||||||||
| impl->captured_input_ptr = in_ptr; | ||||||||||||||||||
| CeedCallBackend(CeedVectorRestoreArrayRead(input_vec, &in_ptr)); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| printf("[CUDA Graph] Phase 2: Recording graph for operator '%s'...\n", op_name ? op_name : "unnamed"); | ||||||||||||||||||
| cudaStream_t capture_stream = cudaStreamPerThread; | ||||||||||||||||||
| bool capture_ok = true; | ||||||||||||||||||
|
|
||||||||||||||||||
| CeedDebug(ceed, "\nFalling back to /gpu/cuda/ref CeedOperator for ApplyAdd\n"); | ||||||||||||||||||
| CeedCallBackend(CeedOperatorGetFallback(sub_operators[i], &op_fallback)); | ||||||||||||||||||
| cudaError_t err = cudaStreamBeginCapture(capture_stream, cudaStreamCaptureModeThreadLocal); | ||||||||||||||||||
| if (err != cudaSuccess) { | ||||||||||||||||||
| capture_ok = false; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| if (capture_ok) { | ||||||||||||||||||
| // Check errors by hand (not CeedCallBackend) so we always reach the | ||||||||||||||||||
| // cudaStreamEndCapture below. Some sub-operators (e.g. contact, which calls | ||||||||||||||||||
| // cudaMalloc) invalidate the capture, and we still need to close it out. | ||||||||||||||||||
| for (CeedInt i = 0; i < num_suboperators; i++) { | ||||||||||||||||||
| if (CeedOperatorApplyAdd(sub_operators[i], input_vec, output_vec, CEED_REQUEST_IMMEDIATE)) { | ||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated. The capture loop now calls CeedOperatorApplyAddCore_Cuda_gen directly with an is_run_good flag instead of going through the public ApplyAdd interface. |
||||||||||||||||||
| capture_ok = false; | ||||||||||||||||||
| break; | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| // Always end capture so the stream is usable again, even if it failed. | ||||||||||||||||||
| { | ||||||||||||||||||
| cudaGraph_t partial = NULL; | ||||||||||||||||||
| err = cudaStreamEndCapture(capture_stream, &partial); | ||||||||||||||||||
| if (capture_ok && (err != cudaSuccess || !partial)) capture_ok = false; | ||||||||||||||||||
| if (capture_ok) impl->graph = partial; | ||||||||||||||||||
| else if (partial) cudaGraphDestroy(partial); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| if (capture_ok) { | ||||||||||||||||||
| err = cudaGraphInstantiate(&impl->graph_instance, impl->graph, 0); | ||||||||||||||||||
| if (err != cudaSuccess) { | ||||||||||||||||||
| cudaGraphDestroy(impl->graph); | ||||||||||||||||||
| impl->graph = NULL; | ||||||||||||||||||
| capture_ok = false; | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| // Clear the leftover error from a failed capture so later CUDA calls don't inherit it. | ||||||||||||||||||
| if (!capture_ok) { | ||||||||||||||||||
| cudaGetLastError(); | ||||||||||||||||||
| cudaDeviceSynchronize(); | ||||||||||||||||||
| cudaGetLastError(); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| impl->graph_created = true; | ||||||||||||||||||
| impl->graph_launches = 0; | ||||||||||||||||||
|
|
||||||||||||||||||
| if (capture_ok) printf("[CUDA Graph] Graph created for operator '%s'\n", op_name ? op_name : "unnamed"); | ||||||||||||||||||
| else printf("[CUDA Graph] Capture disabled for operator '%s'; falling back to direct apply\n", op_name ? op_name : "unnamed"); | ||||||||||||||||||
|
|
||||||||||||||||||
| // Capture doesn't run the kernels, so apply directly to get this call's output. | ||||||||||||||||||
| for (CeedInt i = 0; i < num_suboperators; i++) { | ||||||||||||||||||
| CeedCallBackend(CeedOperatorApplyAdd(sub_operators[i], input_vec, output_vec, request)); | ||||||||||||||||||
| } | ||||||||||||||||||
| return CEED_ERROR_SUCCESS; | ||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Can we just play out the graph (i.e. don't return, exit if statement, continue) instead of applying the kernels for a second time?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. After a successful capture, we no longer re-apply the suboperators; we set graph_created and fall through to cudaGraphLaunch, so the first post-capture call is served by replaying the graph rather than running the kernels a second time. |
||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| // Phase 3: replay. | ||||||||||||||||||
| { | ||||||||||||||||||
| // graph_instance == NULL means capture failed; direct-apply every call. | ||||||||||||||||||
| if (!impl->graph_instance) { | ||||||||||||||||||
|
zatkins-dev marked this conversation as resolved.
Outdated
|
||||||||||||||||||
| for (CeedInt i = 0; i < num_suboperators; i++) { | ||||||||||||||||||
| CeedCallBackend(CeedOperatorApplyAdd(sub_operators[i], input_vec, output_vec, request)); | ||||||||||||||||||
| } | ||||||||||||||||||
| return CEED_ERROR_SUCCESS; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| cudaStream_t stream = NULL; | ||||||||||||||||||
|
|
||||||||||||||||||
| // Sync contexts so kernels see updated time/load parameters. | ||||||||||||||||||
| CeedCallBackend(CeedCompositeRefreshContexts_Cuda_gen(sub_operators, num_suboperators)); | ||||||||||||||||||
|
|
||||||||||||||||||
| // If the input buffer moved since capture, recapture. | ||||||||||||||||||
| { | ||||||||||||||||||
| const CeedScalar *in_ptr; | ||||||||||||||||||
| bool ptr_ok; | ||||||||||||||||||
|
|
||||||||||||||||||
| CeedCallBackend(CeedVectorGetArrayRead(input_vec, CEED_MEM_DEVICE, &in_ptr)); | ||||||||||||||||||
| ptr_ok = (in_ptr == impl->captured_input_ptr); | ||||||||||||||||||
| CeedCallBackend(CeedVectorRestoreArrayRead(input_vec, &in_ptr)); | ||||||||||||||||||
| if (!ptr_ok) goto use_fallback; | ||||||||||||||||||
| } | ||||||||||||||||||
|
zatkins-dev marked this conversation as resolved.
Outdated
|
||||||||||||||||||
|
|
||||||||||||||||||
| cudaError_t err = cudaGraphLaunch(impl->graph_instance, stream); | ||||||||||||||||||
| if (err != cudaSuccess) { | ||||||||||||||||||
| printf("CUDA Graph launch failed: %s - using fallback\n", cudaGetErrorString(err)); | ||||||||||||||||||
| CeedOperator op_fallback; | ||||||||||||||||||
| CeedCallBackend(CeedOperatorGetFallback(op, &op_fallback)); | ||||||||||||||||||
| CeedCallBackend(CeedOperatorApplyAdd(op_fallback, input_vec, output_vec, request)); | ||||||||||||||||||
| return CEED_ERROR_SUCCESS; | ||||||||||||||||||
| } | ||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We shouldn't fall back here -- we should call the helper I mentioned above and mark the graph as bad. The fallback should be a last case scenario.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed whole-operator ref fallback there too; uses the NoGraph helper. |
||||||||||||||||||
|
|
||||||||||||||||||
| if (impl->graph_launches == 0) { | ||||||||||||||||||
| printf("[CUDA Graph] ✓ Replaying graph for operator '%s'\n", op_name ? op_name : "unnamed"); | ||||||||||||||||||
| } | ||||||||||||||||||
| impl->graph_launches++; | ||||||||||||||||||
|
|
||||||||||||||||||
| return CEED_ERROR_SUCCESS; | ||||||||||||||||||
| } | ||||||||||||||||||
| CeedCallBackend(CeedDestroy(&ceed)); | ||||||||||||||||||
|
|
||||||||||||||||||
| // Drop the graph and run via /gpu/cuda/ref; next call will recapture. | ||||||||||||||||||
| use_fallback: | ||||||||||||||||||
| if (impl->graph_instance) { | ||||||||||||||||||
| cudaGraphExecDestroy(impl->graph_instance); | ||||||||||||||||||
| impl->graph_instance = NULL; | ||||||||||||||||||
| } | ||||||||||||||||||
| if (impl->graph) { | ||||||||||||||||||
| cudaGraphDestroy(impl->graph); | ||||||||||||||||||
| impl->graph = NULL; | ||||||||||||||||||
| } | ||||||||||||||||||
| impl->graph_created = false; | ||||||||||||||||||
| impl->captured_input_ptr = NULL; | ||||||||||||||||||
| impl->fallbacks++; | ||||||||||||||||||
|
|
||||||||||||||||||
| CeedOperator op_fallback; | ||||||||||||||||||
| CeedCallBackend(CeedOperatorGetFallback(op, &op_fallback)); | ||||||||||||||||||
| CeedCallBackend(CeedOperatorApplyAdd(op_fallback, input_vec, output_vec, request)); | ||||||||||||||||||
|
zatkins-dev marked this conversation as resolved.
Outdated
|
||||||||||||||||||
|
|
||||||||||||||||||
| return CEED_ERROR_SUCCESS; | ||||||||||||||||||
|
jeremylt marked this conversation as resolved.
|
||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| //------------------------------------------------------------------------------ | ||||||||||||||||||
| // QFunction assembly | ||||||||||||||||||
| //------------------------------------------------------------------------------ | ||||||||||||||||||
|
|
@@ -465,7 +649,7 @@ static int CeedOperatorLinearAssembleQFunctionCore_Cuda_gen(CeedOperator op, boo | |||||||||||||||||
|
|
||||||||||||||||||
| // Assemble QFunction | ||||||||||||||||||
| void *opargs[] = {(void *)&num_elem, &qf_data->d_c, &data->indices, &data->fields, &data->B, &data->G, &data->W, &data->points, &assembled_array}; | ||||||||||||||||||
| bool is_tensor = false; | ||||||||||||||||||
| bool is_tensor; | ||||||||||||||||||
| int max_threads_per_block, min_grid_size, grid; | ||||||||||||||||||
|
|
||||||||||||||||||
| CeedCallBackend(CeedOperatorHasTensorBases(op, &is_tensor)); | ||||||||||||||||||
|
|
@@ -874,6 +1058,7 @@ static int CeedOperatorAssembleSingleAtPoints_Cuda_gen(CeedOperator op, CeedInt | |||||||||||||||||
| return CEED_ERROR_SUCCESS; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| //------------------------------------------------------------------------------ | ||||||||||||||||||
| // Create operator | ||||||||||||||||||
| //------------------------------------------------------------------------------ | ||||||||||||||||||
|
|
@@ -885,6 +1070,16 @@ int CeedOperatorCreate_Cuda_gen(CeedOperator op) { | |||||||||||||||||
| CeedCallBackend(CeedOperatorGetCeed(op, &ceed)); | ||||||||||||||||||
| CeedCallBackend(CeedCalloc(1, &impl)); | ||||||||||||||||||
| CeedCallBackend(CeedOperatorSetData(op, impl)); | ||||||||||||||||||
|
|
||||||||||||||||||
| impl->graph_created = false; | ||||||||||||||||||
| impl->warmup_done = false; | ||||||||||||||||||
| impl->graph = NULL; | ||||||||||||||||||
| impl->graph_instance = NULL; | ||||||||||||||||||
| impl->graph_launches = 0; | ||||||||||||||||||
| impl->fallbacks = 0; | ||||||||||||||||||
| impl->captured_input_ptr = NULL; | ||||||||||||||||||
|
|
||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
All of these assignments are implicitly done via
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed the redundant zero-inits. CeedCalloc already zeroes the struct, so only use_graph is set explicitly (from CEED_DISABLE_GRAPH). Also dropped the graph_launches and fallbacks counters from the struct. |
||||||||||||||||||
|
|
||||||||||||||||||
| CeedCall(CeedOperatorIsComposite(op, &is_composite)); | ||||||||||||||||||
| if (is_composite) { | ||||||||||||||||||
| CeedCallBackend(CeedSetBackendFunction(ceed, "Operator", op, "ApplyAddComposite", CeedOperatorApplyAddComposite_Cuda_gen)); | ||||||||||||||||||
|
|
@@ -897,6 +1092,7 @@ int CeedOperatorCreate_Cuda_gen(CeedOperator op) { | |||||||||||||||||
| CeedOperatorLinearAssembleAddDiagonalAtPoints_Cuda_gen)); | ||||||||||||||||||
| CeedCallBackend(CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleSingle", CeedOperatorAssembleSingleAtPoints_Cuda_gen)); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
jeremylt marked this conversation as resolved.
Outdated
|
||||||||||||||||||
| if (!is_at_points) { | ||||||||||||||||||
| CeedCallBackend(CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleQFunction", CeedOperatorLinearAssembleQFunction_Cuda_gen)); | ||||||||||||||||||
| CeedCallBackend(CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleQFunctionUpdate", | ||||||||||||||||||
|
|
||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.