DPC++ Runtime
Runtime libraries for oneAPI DPC++
stream_impl.cpp
Go to the documentation of this file.
1 //==----------------- stream_impl.cpp - SYCL standard header file ---------==//
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 
9 #include <detail/buffer_impl.hpp>
10 #include <detail/queue_impl.hpp>
12 #include <detail/stream_impl.hpp>
13 #include <sycl/queue.hpp>
14 
15 #include <cstdio>
16 
17 namespace sycl {
18 inline namespace _V1 {
19 namespace detail {
20 
21 stream_impl::stream_impl(size_t BufferSize, size_t MaxStatementSize,
22  handler &CGH)
23  : stream_impl(BufferSize, MaxStatementSize, {}) {
24  (void)CGH;
25 }
26 
27 stream_impl::stream_impl(size_t BufferSize, size_t MaxStatementSize,
28  const property_list &PropList)
29  : BufferSize_(BufferSize), MaxStatementSize_(MaxStatementSize),
30  PropList_(PropList), Buf_(range<1>(BufferSize + OffsetSize + 1)),
31  FlushBuf_(range<1>(MaxStatementSize + FLUSH_BUF_OFFSET_SIZE)) {
32  // Additional place is allocated in the stream buffer for the offset variable
33  // and the end of line symbol. Buffers are created without host pointers so
34  // that they are released in a deferred manner. Disable copy back on buffer
35  // destruction. Copy is scheduled as a host task which fires up as soon as
36  // kernel has completed execution.
37  Buf_.set_write_back(false);
38  FlushBuf_.set_write_back(false);
39  // Initialize stream buffer with zeros, this is needed for two reasons:
40  // 1. We don't need to care about end of line when printing out
41  // streamed data.
42  // 2. Offset is properly initialized.
43  host_accessor Acc{Buf_};
44  char *Ptr = Acc.get_pointer();
45  std::memset(Ptr, 0, Buf_.size());
46 }
47 
48 // Method to provide an access to the global stream buffer
51  CGH, range<1>(BufferSize_), id<1>(OffsetSize));
52 }
53 
54 // Method to provide an accessor to the global flush buffer
57  CGH, range<1>(MaxStatementSize_ + FLUSH_BUF_OFFSET_SIZE), id<1>(0));
58 }
59 
60 // Method to provide an atomic access to the offset in the global stream
61 // buffer and offset in the flush buffer
63  auto OffsetSubBuf = buffer<char, 1>(Buf_, id<1>(0), range<1>(OffsetSize));
64  auto ReinterpretedBuf = OffsetSubBuf.reinterpret<unsigned, 1>(range<1>(2));
65  return ReinterpretedBuf.get_access<sycl::access::mode::atomic>(
66  CGH, range<1>(2), id<1>(0));
67 }
68 
69 size_t stream_impl::size() const noexcept { return BufferSize_; }
70 
72  return MaxStatementSize_;
73 }
74 
75 size_t stream_impl::get_size() const { return BufferSize_; }
76 
77 size_t stream_impl::get_max_statement_size() const { return MaxStatementSize_; }
78 
80  // Real size of full flush buffer is saved only in buffer_impl field of
81  // FlushBuf object.
82  size_t FlushBufSize = getSyclObjImpl(FlushBuf_)->size();
83 
84  auto Q = createSyclObjFromImpl<queue>(Queue);
85  Q.submit([&](handler &cgh) {
86  auto FlushBufAcc = FlushBuf_.get_access<access::mode::discard_write,
87  access::target::host_buffer>(
88  cgh, range<1>(1), id<1>(0));
89  cgh.host_task([=] {
90  char *FlushBufPtr = FlushBufAcc.get_pointer();
91  std::memset(FlushBufPtr, 0, FlushBufSize);
92  });
93  });
94 }
95 
96 void stream_impl::flush(const EventImplPtr &LeadEvent) {
97  // We don't want stream flushing to be blocking operation that is why submit a
98  // host task to print stream buffer. It will fire up as soon as the kernel
99  // finishes execution.
100  auto Q = detail::createSyclObjFromImpl<queue>(
101  sycl::detail::Scheduler::getInstance().getDefaultHostQueue());
102  event Event = Q.submit([&](handler &cgh) {
103  auto BufHostAcc =
104  Buf_.get_access<access::mode::read_write, access::target::host_buffer>(
105  cgh, range<1>(BufferSize_), id<1>(OffsetSize));
106  // Create accessor to the flush buffer even if not using it yet. Otherwise
107  // kernel will be a leaf for the flush buffer and scheduler will not be able
108  // to cleanup the kernel. TODO: get rid of finalize method by using host
109  // accessor to the flush buffer.
110  auto FlushBufHostAcc =
111  FlushBuf_
112  .get_access<access::mode::read_write, access::target::host_buffer>(
113  cgh);
114  cgh.host_task([=] {
115  if (!BufHostAcc.empty()) {
116  // SYCL 2020, 4.16:
117  // > If the totalBufferSize or workItemBufferSize limits are exceeded,
118  // > it is implementation-defined whether the streamed characters
119  // > exceeding the limit are output, or silently ignored/discarded, and
120  // > if output it is implementation-defined whether those extra
121  // > characters exceeding the workItemBufferSize limit count toward the
122  // > totalBufferSize limit. Regardless of this implementation defined
123  // > behavior of output exceeding the limits, no undefined or erroneous
124  // > behavior is permitted of an implementation when the limits are
125  // > exceeded.
126  //
127  // Defend against zero-sized buffers (although they'd have no practical
128  // use).
129  printf("%s", &(BufHostAcc[0]));
130  }
131  fflush(stdout);
132  });
133  });
134  if (LeadEvent) {
135  LeadEvent->attachEventToComplete(detail::getSyclObjImpl(Event));
136  LeadEvent->getSubmittedQueue()->registerStreamServiceEvent(
137  detail::getSyclObjImpl(Event));
138  }
139 }
140 
141 void stream_impl::flush() { flush(nullptr); }
142 } // namespace detail
143 } // namespace _V1
144 } // namespace sycl
size_t size() const noexcept
Definition: buffer.hpp:491
void set_write_back(bool flag=true)
Definition: buffer.hpp:646
accessor< T, dimensions, Mode, Target, access::placeholder::false_t, ext::oneapi::accessor_property_list<> > get_access(handler &CommandGroupHandler, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:506
size_t get_work_item_buffer_size() const
Definition: stream_impl.cpp:71
size_t get_max_statement_size() const
Definition: stream_impl.cpp:77
GlobalBufAccessorT accessGlobalFlushBuf(handler &CGH)
Definition: stream_impl.cpp:55
void initStreamHost(QueueImplPtr Queue)
Definition: stream_impl.cpp:79
stream_impl(size_t BufferSize, size_t MaxStatementSize, handler &CGH)
Definition: stream_impl.cpp:21
size_t size() const noexcept
Definition: stream_impl.cpp:69
GlobalOffsetAccessorT accessGlobalOffset(handler &CGH)
Definition: stream_impl.cpp:62
GlobalBufAccessorT accessGlobalBuf(handler &CGH)
Definition: stream_impl.cpp:49
Command group handler class.
Definition: handler.hpp:458
Objects of the property_list class are containers for the SYCL properties.
Defines the iteration domain of either a single work-group in a parallel dispatch,...
Definition: range.hpp:26
decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject)
Definition: impl_utils.hpp:30
std::shared_ptr< event_impl > EventImplPtr
Definition: cg.hpp:43
constexpr unsigned FLUSH_BUF_OFFSET_SIZE
Definition: stream.hpp:84
std::shared_ptr< sycl::detail::queue_impl > QueueImplPtr
Definition: event_impl.hpp:34
int printf(const FormatT *__format, Args... args)
Definition: builtins.hpp:79
constexpr mode_tag_t< access_mode::read_write > read_write
Definition: access.hpp:85
Definition: access.hpp:18
_Abi const simd< _Tp, _Abi > & noexcept
Definition: simd.hpp:1324