================================================================================================
| 1390 | |
| 1391 | // ================================================================================================ |
| 1392 | amd::Command* GraphExec::EnqueueSegmentedGraph(hip::Stream* launch_stream, |
| 1393 | const std::vector<hip::Stream*>& streams, |
| 1394 | hipError_t* out_status) { |
| 1395 | hipError_t status = hipSuccess; |
| 1396 | if (out_status != nullptr) { |
| 1397 | *out_status = hipSuccess; |
| 1398 | } |
| 1399 | |
| 1400 | // Lambda to create and enqueue a marker with wait list |
| 1401 | auto enqueueMarker = [](hip::Stream* stream, const amd::Command::EventWaitList& wait_list) { |
| 1402 | auto marker = new amd::Marker(*stream, true, wait_list); |
| 1403 | // Marker is only for dependency, no need to flush caches. |
| 1404 | marker->setCommandEntryScope(amd::Device::kCacheStateIgnore); |
| 1405 | if (marker != nullptr) { |
| 1406 | marker->enqueue(); |
| 1407 | marker->release(); |
| 1408 | } |
| 1409 | }; |
| 1410 | |
| 1411 | // Map to track which stream each segment uses - MUST persist across all levels |
| 1412 | // so we can look up streams for dependencies from previous levels |
| 1413 | std::unordered_map<int, hip::Stream*> segment_to_stream; |
| 1414 | // Map to track the last enqueued command for each segment for dependency tracking |
| 1415 | // This is critical for handling cross-level dependencies with stream reuse |
| 1416 | std::unordered_map<int, amd::Command*> segment_last_command; |
| 1417 | |
| 1418 | // Process segments level by level using the pre-calculated max_dependency_level_ |
| 1419 | for (int level = 0; level <= max_dependency_level_; ++level) { |
| 1420 | auto level_it = segments_per_level_.find(level); |
| 1421 | if (level_it == segments_per_level_.end()) { |
| 1422 | continue; |
| 1423 | } |
| 1424 | |
| 1425 | const auto& segments_at_level = level_it->second; |
| 1426 | |
| 1427 | // Assign streams to segments at this level |
| 1428 | AssignStreamsToSegments(segments_at_level, launch_stream, streams, segment_to_stream); |
| 1429 | |
| 1430 | // Process each segment at this level |
| 1431 | for (int segment_id : segments_at_level) { |
| 1432 | const auto& segment = segments_[segment_id]; |
| 1433 | hip::Stream* current_stream = segment_to_stream[segment_id]; |
| 1434 | |
| 1435 | // Handle dependencies: add wait markers if dependent segments are on different streams |
| 1436 | // Look up the specific command for each dependency segment |
| 1437 | amd::Command::EventWaitList wait_list; |
| 1438 | for (int dep_segment_id : segment.segment_ids_dependencies) { |
| 1439 | // Dependencies are present in the segment_to_stream and segment_last_command map |
| 1440 | auto stream_it = segment_to_stream.find(dep_segment_id); |
| 1441 | if (stream_it == segment_to_stream.end()) { |
| 1442 | continue; |
| 1443 | } |
| 1444 | hip::Stream* dep_stream = stream_it->second; |
| 1445 | |
| 1446 | // Need to wait if dependency is on a different stream |
| 1447 | if (dep_stream != current_stream) { |
| 1448 | auto cmd_it = segment_last_command.find(dep_segment_id); |
| 1449 | if (cmd_it != segment_last_command.end() && cmd_it->second != nullptr) { |
no test coverage detected