@@ -194,6 +194,8 @@ MemObjRecord *Scheduler::GraphBuilder::getOrInsertMemObjRecord(
194194 ToEnqueue.push_back (ConnectionCmd);
195195 Dependency->addUser (Dependant);
196196 --(Dependency->MLeafCounter );
197+ if (Dependency->MLeafCounter == 0 && Dependency->isSuccessfullyEnqueued ())
198+ cleanupCommand (Dependency);
197199 };
198200
199201 const ContextImplPtr &InteropCtxPtr = Req->MSYCLMemObj ->getInteropContext ();
@@ -225,17 +227,25 @@ MemObjRecord *Scheduler::GraphBuilder::getOrInsertMemObjRecord(
225227 return MemObject->MRecord .get ();
226228}
227229
228- void Scheduler::GraphBuilder::updateLeaves (const std::set<Command *> &Cmds,
229- MemObjRecord *Record,
230- access::mode AccessMode) {
230+ void Scheduler::GraphBuilder::updateLeaves (
231+ const std::set<Command *> &Cmds, MemObjRecord *Record,
232+ access::mode AccessMode, std::vector<Command *> *CommandsToCleanUp ) {
231233
232234 const bool ReadOnlyReq = AccessMode == access::mode::read;
233235 if (ReadOnlyReq)
234236 return ;
235237
236238 for (Command *Cmd : Cmds) {
239+ bool WasLeaf = Cmd->MLeafCounter > 0 ;
237240 Cmd->MLeafCounter -= Record->MReadLeaves .remove (Cmd);
238241 Cmd->MLeafCounter -= Record->MWriteLeaves .remove (Cmd);
242+ if (Cmd->MLeafCounter == 0 && Cmd->isSuccessfullyEnqueued ()) {
243+ if (CommandsToCleanUp) {
244+ if (WasLeaf)
245+ CommandsToCleanUp->push_back (Cmd);
246+ } else
247+ cleanupCommand (Cmd);
248+ }
239249 }
240250}
241251
@@ -963,14 +973,23 @@ Scheduler::GraphBuilder::addCG(std::unique_ptr<detail::CG> CommandGroup,
963973 // Node dependencies can be modified further when adding the node to leaves,
964974 // iterate over their copy.
965975 // FIXME employ a reference here to eliminate copying of a vector
976+ // Updating leaves might also clean up some of the dep commands, so update
977+ // their users first.
978+ // FIXME there's probably a better way of handling cleanup & leaf/dep update
979+ // here considering that some of the updated might be destroyed by cleanup
980+ // immediately after.
966981 std::vector<DepDesc> Deps = NewCmd->MDeps ;
982+ std::vector<Command *> CommandsToCleanUp;
967983 for (DepDesc &Dep : Deps) {
968984 Dep.MDepCommand ->addUser (NewCmd.get ());
969985 const Requirement *Req = Dep.MDepRequirement ;
970986 MemObjRecord *Record = getMemObjRecord (Req->MSYCLMemObj );
971- updateLeaves ({Dep.MDepCommand }, Record, Req->MAccessMode );
987+ updateLeaves ({Dep.MDepCommand }, Record, Req->MAccessMode ,
988+ &CommandsToCleanUp);
972989 addNodeToLeaves (Record, NewCmd.get (), Req->MAccessMode , ToEnqueue);
973990 }
991+ for (Command *Cmd : CommandsToCleanUp)
992+ cleanupCommand (Cmd);
974993
975994 // Register all the events as dependencies
976995 for (detail::EventImplPtr e : Events) {
@@ -993,9 +1012,13 @@ void Scheduler::GraphBuilder::decrementLeafCountersForRecord(
9931012 MemObjRecord *Record) {
9941013 for (Command *Cmd : Record->MReadLeaves ) {
9951014 --(Cmd->MLeafCounter );
1015+ if (Cmd->MLeafCounter == 0 && Cmd->isSuccessfullyEnqueued ())
1016+ cleanupCommand (Cmd);
9961017 }
9971018 for (Command *Cmd : Record->MWriteLeaves ) {
9981019 --(Cmd->MLeafCounter );
1020+ if (Cmd->MLeafCounter == 0 && Cmd->isSuccessfullyEnqueued ())
1021+ cleanupCommand (Cmd);
9991022 }
10001023}
10011024
@@ -1096,6 +1119,52 @@ void Scheduler::GraphBuilder::cleanupCommandsForRecord(
10961119 handleVisitedNodes (MVisitedCmds);
10971120}
10981121
1122+
1123+ void Scheduler::GraphBuilder::cleanupCommand (Command *Cmd) {
1124+ if (SYCLConfig<SYCL_DISABLE_EXECUTION_GRAPH_CLEANUP>::get ())
1125+ return ;
1126+ assert (Cmd->MLeafCounter == 0 && Cmd->isSuccessfullyEnqueued ());
1127+ // Isolated command nodes are cleaned up by scheduler instead.
1128+ assert (Cmd->MDeps .size () != 0 || Cmd->MUsers .size () != 0 );
1129+ Command::CommandType CmdT = Cmd->getType ();
1130+ // Allocas have to be kept alive until memory objects are released.
1131+ if (CmdT == Command::ALLOCA || CmdT == Command::ALLOCA_SUB_BUF)
1132+ return ;
1133+
1134+ // FIXME handle host tasks
1135+ if (CmdT == Command::RUN_CG) {
1136+ auto *ExecCGCmd = static_cast <ExecCGCommand *>(Cmd);
1137+ if (ExecCGCmd->getCG ().getType () == CG::CGTYPE::CodeplayHostTask) {
1138+ return ;
1139+ }
1140+ }
1141+ assert (CmdT != Command::ALLOCA && CmdT != Command::ALLOCA_SUB_BUF);
1142+
1143+ for (Command *UserCmd : Cmd->MUsers ) {
1144+ for (DepDesc &Dep : UserCmd->MDeps ) {
1145+ // Link the users of the command to the alloca command(s) instead
1146+ if (Dep.MDepCommand == Cmd) {
1147+ // ... unless the user is the alloca itself.
1148+ if (Dep.MAllocaCmd == UserCmd) {
1149+ Dep.MDepCommand = nullptr ;
1150+ }
1151+ else {
1152+ Dep.MDepCommand = Dep.MAllocaCmd ;
1153+ Dep.MDepCommand ->MUsers .insert (UserCmd);
1154+ }
1155+ }
1156+ }
1157+ }
1158+ // Update dependency users
1159+ for (DepDesc &Dep : Cmd->MDeps ) {
1160+ Command *DepCmd = Dep.MDepCommand ;
1161+ DepCmd->MUsers .erase (Cmd);
1162+ }
1163+ Cmd->getEvent ()->setCommand (nullptr );
1164+ Cmd->getEvent ()->cleanupDependencyEvents ();
1165+ delete Cmd;
1166+ }
1167+
10991168void Scheduler::GraphBuilder::cleanupFinishedCommands (
11001169 Command *FinishedCmd,
11011170 std::vector<std::shared_ptr<stream_impl>> &StreamsToDeallocate) {
0 commit comments