xref: /aosp_15_r20/external/mesa3d/src/gallium/frontends/clover/core/printf.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 //
2 // Copyright 2020 Serge Martin
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 // OTHER DEALINGS IN THE SOFTWARE.
21 //
22 
23 #include <cstring>
24 #include <cstdio>
25 #include <string>
26 #include <iostream>
27 
28 #include "util/u_math.h"
29 #include "core/printf.hpp"
30 
31 #include "util/u_printf.h"
32 using namespace clover;
33 
34 namespace {
35 
36    const cl_uint hdr_dwords = 2;
37    const cl_uint initial_buffer_offset = hdr_dwords * sizeof(cl_uint);
38 
39    /* all valid chars that can appear in CL C printf string. */
40    const std::string clc_printf_whitelist = "%0123456789-+ #.AacdeEfFgGhilopsuvxX";
41 
42    void
print_formatted(std::vector<binary::printf_info> & formatters,bool _strings_in_buffer,const std::vector<char> & buffer)43    print_formatted(std::vector<binary::printf_info> &formatters,
44                    bool _strings_in_buffer,
45                    const std::vector<char> &buffer) {
46 
47       static std::atomic<unsigned> warn_count;
48 
49       if (buffer.empty() && !warn_count++)
50          std::cerr << "Printf used but no printf occurred - may cause performance issue." << std::endl;
51 
52       std::vector<u_printf_info> infos;
53       for (auto &f : formatters) {
54          u_printf_info info;
55 
56          info.num_args = f.arg_sizes.size();
57          info.arg_sizes = f.arg_sizes.data();
58          info.string_size = f.strings.size();
59          info.strings = f.strings.data();
60 
61          infos.push_back(info);
62       }
63 
64       u_printf(stdout, buffer.data(), buffer.size(), infos.data(), infos.size());
65    }
66 }
67 
68 std::unique_ptr<printf_handler>
create(const intrusive_ptr<command_queue> & q,const std::vector<binary::printf_info> & infos,bool strings_in_buffer,cl_uint size)69 printf_handler::create(const intrusive_ptr<command_queue> &q,
70                        const std::vector<binary::printf_info> &infos,
71                        bool strings_in_buffer,
72                        cl_uint size) {
73    return std::unique_ptr<printf_handler>(
74                                        new printf_handler(q, infos, strings_in_buffer, size));
75 }
76 
printf_handler(const intrusive_ptr<command_queue> & q,const std::vector<binary::printf_info> & infos,bool strings_in_buffer,cl_uint size)77 printf_handler::printf_handler(const intrusive_ptr<command_queue> &q,
78                                const std::vector<binary::printf_info> &infos,
79                                bool strings_in_buffer,
80                                cl_uint size) :
81    _q(q), _formatters(infos), _strings_in_buffer(strings_in_buffer), _size(size), _buffer() {
82 
83    if (_size) {
84       std::string data;
85       data.reserve(_size);
86       cl_uint header[2] = { 0 };
87 
88       header[0] = initial_buffer_offset;
89       header[1] = _size;
90 
91       data.append((char *)header, (char *)(header+hdr_dwords));
92       _buffer = std::unique_ptr<root_buffer>(new root_buffer(_q->context,
93                                              std::vector<cl_mem_properties>(),
94                                              CL_MEM_COPY_HOST_PTR,
95                                              _size, (char*)data.data()));
96    }
97 }
98 
99 cl_mem
get_mem()100 printf_handler::get_mem() {
101    return (cl_mem)(_buffer.get());
102 }
103 
104 void
print()105 printf_handler::print() {
106    if (!_buffer)
107       return;
108 
109    mapping src = { *_q, _buffer->resource_in(*_q), CL_MAP_READ, true,
110                   {{ 0 }}, {{ _size, 1, 1 }} };
111 
112    cl_uint header[2] = { 0 };
113    std::memcpy(header,
114                static_cast<const char *>(src),
115                initial_buffer_offset);
116 
117    cl_uint buffer_size = header[0];
118    buffer_size -= initial_buffer_offset;
119    std::vector<char> buf;
120    buf.resize(buffer_size);
121 
122    std::memcpy(buf.data(),
123                static_cast<const char *>(src) + initial_buffer_offset,
124                buffer_size);
125 
126    // mixed endian isn't going to work, sort it out if anyone cares later.
127    assert(_q->device().endianness() == PIPE_ENDIAN_NATIVE);
128    print_formatted(_formatters, _strings_in_buffer, buf);
129 }
130