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