DDC 0.6.0
Loading...
Searching...
No Matches
print.hpp
1// Copyright (C) The DDC development team, see COPYRIGHT.md file
2//
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
7#include <algorithm>
8#include <cstddef>
9#include <memory>
10#include <ostream>
11#include <sstream>
12#include <type_traits>
13#include <utility>
14
15#include "ddc/chunk_span.hpp"
16#include "ddc/discrete_domain.hpp"
17
18#if defined(KOKKOS_COMPILER_GNU) || defined(KOKKOS_COMPILER_CLANG)
19# include <cxxabi.h>
20#endif
21
22namespace ddc {
23namespace detail {
24class ChunkPrinter
25{
26 static constexpr int const s_threshold = 10;
27 // If this ever becomes modifiable by the user, we need to ensure that
28 // s_edgeitems < (s_threshold / 2) stays true.
29 static constexpr int const s_edgeitems = 3;
30
31 std::stringstream m_ss;
32
33 static std::ostream& alignment(std::ostream& os, int level)
34 {
35 for (int i = 0; i <= level; ++i) {
36 os << ' ';
37 }
38 return os;
39 }
40
41 template <class T>
42 std::size_t get_element_width(T const& elem)
43 {
44 m_ss.seekp(0);
45 m_ss << elem;
46 return m_ss.tellp();
47 }
48
49 template <class T>
50 void display_aligned_element(std::ostream& os, T const& elem, std::size_t largest_element)
51 {
52 std::size_t const elem_width = get_element_width(elem);
53
54 for (std::size_t i = 0; i < largest_element - elem_width; ++i) {
55 os << " ";
56 }
57 os << elem;
58 }
59
60 template <class ElementType, class Extents, class Layout, class Accessor>
61 std::ostream& base_case_display(
62 std::ostream& os,
63 Kokkos::mdspan<ElementType, Extents, Layout, Accessor> const& s,
64 std::size_t largest_element,
65 std::size_t beginning,
66 std::size_t end,
67 std::size_t extent)
68 {
69 for (std::size_t i0 = beginning; i0 < end; ++i0) {
70 display_aligned_element(os, s[i0], largest_element);
71 if (i0 < extent - 1) {
72 os << " ";
73 }
74 }
75 return os;
76 }
77
78 template <class ElementType, class Extents, class Layout, class Accessor, std::size_t... Is>
79 std::ostream& recursive_display(
80 std::ostream& os,
81 Kokkos::mdspan<ElementType, Extents, Layout, Accessor> const& s,
82 int level,
83 std::size_t largest_element,
84 std::size_t beginning,
85 std::size_t end,
86 std::index_sequence<Is...>)
87 {
88 for (std::size_t i0 = beginning; i0 < end; ++i0) {
89 print_impl(
90 os,
91 Kokkos::submdspan(s, i0, ((void)Is, Kokkos::full_extent)...),
92 level + 1,
93 largest_element,
94 std::make_index_sequence<sizeof...(Is)>());
95 if (i0 < end - 1) {
96 for (int ndims = 0; ndims < sizeof...(Is); ++ndims) {
97 os << '\n';
98 }
99 alignment(os, level);
100 }
101 }
102
103 return os;
104 }
105
106public:
107 // 0D chunk span
108 template <class ElementType, class Extents, class Layout, class Accessor>
109 std::ostream& print_impl(
110 std::ostream& os,
111 Kokkos::mdspan<ElementType, Extents, Layout, Accessor> const& s,
112 int /*level*/,
113 std::size_t /*largest_element*/,
114 std::index_sequence<>)
115 {
116 return os << *s.data_handle();
117 }
118
119 // Recursively parse the chunk to print it
120 template <
121 class ElementType,
122 class Extents,
123 class Layout,
124 class Accessor,
125 std::size_t I0,
126 std::size_t... Is>
127 std::ostream& print_impl(
128 std::ostream& os,
129 Kokkos::mdspan<ElementType, Extents, Layout, Accessor> const& s,
130 int level,
131 std::size_t largest_element,
132 std::index_sequence<I0, Is...>)
133 {
134 auto extent = s.extent(I0);
135 if constexpr (sizeof...(Is) > 0) {
136 os << '[';
137 if (extent < s_threshold) {
138 recursive_display(
139 os,
140 s,
141 level,
142 largest_element,
143 0,
144 extent,
145 std::make_index_sequence<sizeof...(Is)>());
146 } else {
147 recursive_display(
148 os,
149 s,
150 level,
151 largest_element,
152 0,
153 s_edgeitems,
154 std::make_index_sequence<sizeof...(Is)>());
155 for (int ndims = 0; ndims < sizeof...(Is); ++ndims) {
156 os << '\n';
157 }
158 alignment(os, level);
159 os << "...";
160 for (int ndims = 0; ndims < sizeof...(Is); ++ndims) {
161 os << '\n';
162 }
163 alignment(os, level);
164 recursive_display(
165 os,
166 s,
167 level,
168 largest_element,
169 extent - s_edgeitems,
170 extent,
171 std::make_index_sequence<sizeof...(Is)>());
172 }
173 os << "]";
174 } else {
175 os << "[";
176 if (extent < s_threshold) {
177 base_case_display(os, s, largest_element, 0, extent, extent);
178 } else {
179 base_case_display(os, s, largest_element, 0, s_edgeitems, extent);
180 os << "... ";
181 base_case_display(os, s, largest_element, extent - s_edgeitems, extent, extent);
182 }
183 os << "]";
184 }
185
186 return os;
187 }
188
189 // 0D, we don't need the element size in this case so the actual returned value can be anything.
190 template <class ElementType, class Extents, class Layout, class Accessor>
191 std::size_t find_largest_displayed_element(
192 Kokkos::mdspan<ElementType, Extents, Layout, Accessor> const&,
193 std::index_sequence<>)
194 {
195 return 0;
196 }
197
198 // Find the largest element we have to print to allow alignment (it ignore
199 // element that will be elided).
200 template <
201 class ElementType,
202 class Extents,
203 class Layout,
204 class Accessor,
205 std::size_t I0,
206 std::size_t... Is>
207 std::size_t find_largest_displayed_element(
208 Kokkos::mdspan<ElementType, Extents, Layout, Accessor> const& s,
209 std::index_sequence<I0, Is...>)
210 {
211 std::size_t ret = 0;
212 auto extent = s.extent(I0);
213 if constexpr (sizeof...(Is) > 0) {
214 if (extent < s_threshold) {
215 for (std::size_t i0 = 0; i0 < extent; ++i0) {
216 ret = std::max(
217 ret,
218 find_largest_displayed_element(
219 Kokkos::submdspan(s, i0, ((void)Is, Kokkos::full_extent)...),
220 std::make_index_sequence<sizeof...(Is)>()));
221 }
222 } else {
223 for (std::size_t i0 = 0; i0 < s_edgeitems; ++i0) {
224 ret = std::max(
225 ret,
226 find_largest_displayed_element(
227 Kokkos::submdspan(s, i0, ((void)Is, Kokkos::full_extent)...),
228 std::make_index_sequence<sizeof...(Is)>()));
229 }
230 for (std::size_t i0 = extent - s_edgeitems; i0 < extent; ++i0) {
231 ret = std::max(
232 ret,
233 find_largest_displayed_element(
234 Kokkos::submdspan(s, i0, ((void)Is, Kokkos::full_extent)...),
235 std::make_index_sequence<sizeof...(Is)>()));
236 }
237 }
238 } else {
239 if (extent < s_threshold) {
240 for (std::size_t i0 = 0; i0 < extent; ++i0) {
241 ret = std::max(ret, get_element_width(s[i0]));
242 }
243 } else {
244 for (std::size_t i0 = 0; i0 < s_edgeitems; ++i0) {
245 ret = std::max(ret, get_element_width(s[i0]));
246 }
247 for (std::size_t i0 = extent - s_edgeitems; i0 < extent; ++i0) {
248 ret = std::max(ret, get_element_width(s[i0]));
249 }
250 }
251 }
252
253 return ret;
254 }
255
256 explicit ChunkPrinter(std::ostream const& os)
257 {
258 m_ss.copyfmt(os);
259 }
260};
261
262#if defined(KOKKOS_COMPILER_GNU) || defined(KOKKOS_COMPILER_CLANG)
263template <class Type>
264void print_demangled_type_name(std::ostream& os)
265{
266 int status;
267
268 std::unique_ptr<char, decltype(std::free)*> const demangled_name(
269 abi::__cxa_demangle(typeid(Type).name(), nullptr, nullptr, &status),
270 std::free);
271 if (status != 0) {
272 os << "Error demangling dimension name: " << status;
273 return;
274 }
275
276 os << demangled_name.get();
277}
278#else
279template <class Type>
280void print_demangled_type_name(std::ostream& os)
281{
282 os << typeid(Type).name();
283}
284#endif
285
286inline void print_dim_name(std::ostream& os, DiscreteDomain<> const)
287{
288 os << "Scalar";
289}
290
291template <class Dim>
292void print_dim_name(std::ostream& os, DiscreteDomain<Dim> const dd)
293{
294 print_demangled_type_name<Dim>(os);
295 os << '(' << dd.size() << ')';
296}
297
298template <class Dim0, class Dim1, class... Dims>
299void print_dim_name(std::ostream& os, DiscreteDomain<Dim0, Dim1, Dims...> const dd)
300{
301 print_demangled_type_name<Dim0>(os);
302 DiscreteDomain<Dim1, Dims...> const smaller_dd(dd);
303 os << '(' << dd.size() / smaller_dd.size() << ")×";
304 print_dim_name(os, smaller_dd);
305}
306
307} // namespace detail
308
309template <class ElementType, class SupportType, class LayoutStridedPolicy, class MemorySpace>
310std::ostream& print_content(
311 std::ostream& os,
312 ChunkSpan<ElementType, SupportType, LayoutStridedPolicy, MemorySpace> const& chunk_span)
313{
314 auto h_chunk_span = create_mirror_view_and_copy(Kokkos::HostSpace(), chunk_span);
315
316 using chunkspan_type = std::remove_cv_t<std::remove_reference_t<decltype(h_chunk_span)>>;
317 using mdspan_type = typename chunkspan_type::allocation_mdspan_type;
318 using extents = typename mdspan_type::extents_type;
319
320 mdspan_type const allocated_mdspan = h_chunk_span.allocation_mdspan();
321
322 ddc::detail::ChunkPrinter printer(os);
323 std::size_t const largest_element = printer.find_largest_displayed_element(
324 allocated_mdspan,
325 std::make_index_sequence<extents::rank()>());
326
327 printer.print_impl(
328 os,
329 allocated_mdspan,
330 0,
331 largest_element,
332 std::make_index_sequence<extents::rank()>());
333
334 return os;
335}
336
337template <class ElementType, class SupportType, class LayoutStridedPolicy, class MemorySpace>
338std::ostream& print_type_info(
339 std::ostream& os,
340 ChunkSpan<ElementType, SupportType, LayoutStridedPolicy, MemorySpace> const& chunk_span)
341{
342 ddc::detail::print_dim_name(os, chunk_span.domain());
343 os << '\n';
344 ddc::detail::print_demangled_type_name<decltype(chunk_span)>(os);
345 os << '\n';
346
347 return os;
348}
349
350template <class ElementType, class SupportType, class LayoutStridedPolicy, class MemorySpace>
351std::ostream& print(
352 std::ostream& os,
353 ChunkSpan<ElementType, SupportType, LayoutStridedPolicy, MemorySpace> const& chunk_span)
354{
355 print_type_info(os, chunk_span);
356 print_content(os, chunk_span);
357
358 return os;
359}
360
361
362template <class ElementType, class SupportType, class LayoutStridedPolicy, class MemorySpace>
363std::ostream& operator<<(
364 std::ostream& os,
365 ChunkSpan<ElementType, SupportType, LayoutStridedPolicy, MemorySpace> const& chunk_span)
366{
367 return print(os, chunk_span);
368}
369
370} // namespace ddc
friend class DiscreteDomain
The top-level namespace of DDC.
std::ostream & print_content(std::ostream &os, ChunkSpan< ElementType, SupportType, LayoutStridedPolicy, MemorySpace > const &chunk_span)
Definition print.hpp:310
std::ostream & print(std::ostream &os, ChunkSpan< ElementType, SupportType, LayoutStridedPolicy, MemorySpace > const &chunk_span)
Definition print.hpp:351
std::ostream & print_type_info(std::ostream &os, ChunkSpan< ElementType, SupportType, LayoutStridedPolicy, MemorySpace > const &chunk_span)
Definition print.hpp:338