DPC++ Runtime
Runtime libraries for oneAPI DPC++
leaves_collection.cpp
Go to the documentation of this file.
1 //==---- leaves_collection.hpp - Container for leaves of execution graph ---==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
11 
12 #include <algorithm>
13 
14 namespace sycl {
15 inline namespace _V1 {
16 namespace detail {
17 
18 // TODO merge with GraphBuilder's version of doOverlap (see graph_builder.cpp).
19 static inline bool doOverlap(const Requirement *LHS, const Requirement *RHS) {
20  size_t LHSStart = LHS->MOffsetInBytes;
21  size_t LHSEnd = LHSStart + LHS->MAccessRange.size() * LHS->MElemSize;
22 
23  size_t RHSStart = RHS->MOffsetInBytes;
24  size_t RHSEnd = RHSStart + RHS->MAccessRange.size() * RHS->MElemSize;
25 
26  if (LHSStart < RHSStart) {
27  return (RHSStart < LHSEnd) && (LHSEnd <= RHSEnd);
28  } else {
29  return (LHSStart < RHSEnd) && (RHSEnd <= LHSEnd);
30  }
31 }
32 
33 static inline bool isHostAccessorCmd(Command *Cmd) {
34  return Cmd->getType() == Command::EMPTY_TASK &&
36 }
37 
39  if (!isHostAccessorCmd(Cmd)) {
40  auto NewEnd =
41  std::remove(MGenericCommands.begin(), MGenericCommands.end(), Cmd);
42  size_t RemovedCount = std::distance(NewEnd, MGenericCommands.end());
43  MGenericCommands.erase(NewEnd, MGenericCommands.end());
44 
45  return RemovedCount;
46  }
47 
48  // host accessor commands part
49  return eraseHostAccessorCommand(static_cast<EmptyCommand *>(Cmd));
50 }
51 
53  bool Result = false;
54 
55  if (isHostAccessorCmd(Cmd))
56  Result =
57  addHostAccessorCommand(static_cast<EmptyCommand *>(Cmd), ToEnqueue);
58  else
59  Result = addGenericCommand(Cmd, ToEnqueue);
60 
61  return Result;
62 }
63 
64 std::vector<LeavesCollection::value_type> LeavesCollection::toVector() const {
65  std::vector<value_type> Result;
66  Result.reserve(MGenericCommands.size() + MHostAccessorCommands.size());
67 
68  Result.insert(Result.end(), MGenericCommands.begin(), MGenericCommands.end());
69 
70  for (EmptyCommand *Cmd : MHostAccessorCommands)
71  Result.push_back(Cmd);
72 
73  return Result;
74 }
75 
76 bool LeavesCollection::addHostAccessorCommand(EmptyCommand *Cmd,
77  EnqueueListT &ToEnqueue) {
78  // 1. find the oldest command with doOverlap() = true amongst the List
79  // => OldCmd
80  HostAccessorCommandSingleXRefT OldCmdIt;
81 
82  // HACK we believe here that read accessors never overlap as it doesn't add
83  // any real dependency (e.g. data copy to device) except for blocking.
84  if (Cmd->getRequirement()->MAccessMode == sycl::access::mode::read)
85  OldCmdIt = MHostAccessorCommands.end();
86  else
87  OldCmdIt = std::find_if(
88  MHostAccessorCommands.begin(), MHostAccessorCommands.end(),
89  [&](const EmptyCommand *Test) -> bool {
90  return doOverlap(Test->getRequirement(), Cmd->getRequirement());
91  });
92 
93  // FIXME this 'if' is a workaround for duplicate leaves, remove once fixed
94  if (OldCmdIt != MHostAccessorCommands.end() && *OldCmdIt == Cmd)
95  return false;
96 
97  // 2.1 If OldCmd != null:
98  // Put a dependency in the same way as we would for generic commands
99  // when circular buffer is full.
100  if (OldCmdIt != MHostAccessorCommands.end()) {
101  // allocate dependency
102  MAllocateDependency(Cmd, *OldCmdIt, MRecord, ToEnqueue);
103 
104  // erase the old cmd as it's tracked via dependency now
105  eraseHostAccessorCommand(static_cast<EmptyCommand *>(*OldCmdIt));
106  }
107 
108  // 2.2 If OldCmd == null:
109  // Put cmd to the List
110  insertHostAccessorCommand(Cmd);
111  return true;
112 }
113 
114 bool LeavesCollection::addGenericCommand(Command *Cmd,
115  EnqueueListT &ToEnqueue) {
116  if (MGenericCommands.full()) {
117  Command *OldLeaf = MGenericCommands.front();
118 
119  // FIXME this 'if' is a workaround for duplicate leaves, remove once fixed
120  if (OldLeaf == Cmd)
121  return false;
122 
123  MAllocateDependency(Cmd, OldLeaf, MRecord, ToEnqueue);
124  }
125 
126  MGenericCommands.push_back(Cmd);
127 
128  return true;
129 }
130 
131 void LeavesCollection::insertHostAccessorCommand(EmptyCommand *Cmd) {
132  MHostAccessorCommandsXRef[Cmd] =
133  MHostAccessorCommands.insert(MHostAccessorCommands.end(), Cmd);
134 }
135 
136 size_t LeavesCollection::eraseHostAccessorCommand(EmptyCommand *Cmd) {
137  auto XRefIt = MHostAccessorCommandsXRef.find(Cmd);
138 
139  if (XRefIt == MHostAccessorCommandsXRef.end())
140  return 0;
141 
142  MHostAccessorCommands.erase(XRefIt->second);
143  MHostAccessorCommandsXRef.erase(XRefIt);
144  return 1;
145 }
146 
147 } // namespace detail
148 } // namespace _V1
149 } // namespace sycl
void erase(const_iterator Pos)
The Command class represents some action that needs to be performed on one or more memory objects.
Definition: commands.hpp:107
CommandType getType() const
Definition: commands.hpp:144
The empty command does nothing during enqueue.
Definition: commands.hpp:416
const Requirement * getRequirement() const final
Definition: commands.hpp:421
size_t remove(value_type Cmd)
Replacement for std::remove with subsequent call to erase(newEnd, end()).
bool push_back(value_type Cmd, EnqueueListT &ToEnqueue)
Returns true if insertion took place. Returns false otherwise.
std::vector< value_type > toVector() const
std::vector< Command * > EnqueueListT
size_t size() const
Definition: range.hpp:56
static bool doOverlap(const Requirement *LHS, const Requirement *RHS)
Checks whether two requirements overlap or not.
static bool isHostAccessorCmd(Command *Cmd)
Definition: access.hpp:18