• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(const std::vector<binary::printf_info> & formatters,bool _strings_in_buffer,const std::vector<char> & buffer)43    print_formatted(const 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       if (buffer.empty() && !warn_count++)
49 	 std::cerr << "Printf used but no printf occurred - may cause perfomance issue." << std::endl;
50 
51       for (size_t buf_pos = 0; buf_pos < buffer.size(); ) {
52          cl_uint fmt_idx = *(cl_uint*)&buffer[buf_pos];
53          assert(fmt_idx > 0);
54          binary::printf_info fmt = formatters[fmt_idx-1];
55 
56          std::string format = (char *)fmt.strings.data();
57          buf_pos += sizeof(cl_uint);
58 
59          if (fmt.arg_sizes.empty()) {
60             printf("%s", format.c_str());
61 
62          } else {
63             size_t fmt_last_pos = 0;
64             size_t fmt_pos = 0;
65             for (int arg_size : fmt.arg_sizes) {
66                const size_t spec_pos = util_printf_next_spec_pos(format, fmt_pos);
67                const size_t cur_tok = format.rfind('%', spec_pos);
68                const size_t next_spec = util_printf_next_spec_pos(format, spec_pos);
69                const size_t next_tok = next_spec == std::string::npos ? std::string::npos :
70                   format.rfind('%', next_spec);
71 
72                size_t vec_pos = format.find_first_of("v", cur_tok + 1);
73                size_t mod_pos = format.find_first_of("hl", cur_tok + 1);
74 
75                // print the part before the format token
76                if (cur_tok != fmt_last_pos) {
77                   std::string s = format.substr(fmt_last_pos,
78                                                 cur_tok - fmt_last_pos);
79                   printf("%s", s.c_str());
80                }
81 
82                std::string print_str;
83                print_str = format.substr(cur_tok, spec_pos + 1 - cur_tok);
84 
85                /* Never pass a 'n' spec to the host printf */
86                bool valid_str = print_str.find_first_not_of(clc_printf_whitelist) ==
87                   std::string::npos;
88 
89                // print the formated part
90                if (spec_pos != std::string::npos && valid_str) {
91                   bool is_vector = vec_pos != std::string::npos &&
92                      vec_pos + 1 < spec_pos;
93                   bool is_string = format[spec_pos] == 's';
94                   bool is_float = std::string("fFeEgGaA")
95                      .find(format[spec_pos]) != std::string::npos;
96 
97                   if (is_string) {
98                      if (_strings_in_buffer)
99                         printf(print_str.c_str(), &buffer[buf_pos]);
100                      else {
101                         uint64_t idx;
102                         memcpy(&idx, &buffer[buf_pos], 8);
103                         printf(print_str.c_str(), &fmt.strings[idx]);
104                      }
105                   } else {
106                      int component_count = 1;
107 
108                      if (is_vector) {
109                         size_t l = std::min(mod_pos, spec_pos) - vec_pos - 1;
110                         std::string s = format.substr(vec_pos + 1, l);
111                         component_count = std::stoi(s);
112                         if (mod_pos != std::string::npos) {
113                            // CL C has hl specifier for 32-bit vectors, C doesn't have it
114                            // just remove it.
115                            std::string mod = format.substr(mod_pos, 2);
116                            if (mod == "hl")
117                               mod_pos = std::string::npos;
118 			}
119                         print_str.erase(vec_pos - cur_tok, std::min(mod_pos, spec_pos) - vec_pos);
120                         print_str.push_back(',');
121                      }
122 
123                      //in fact vec3 are vec4
124                      int men_components =
125                         component_count == 3 ? 4 : component_count;
126                      size_t elmt_size = arg_size / men_components;
127 
128                      for (int i = 0; i < component_count; i++) {
129                         size_t elmt_buf_pos = buf_pos + i * elmt_size;
130                         if (is_vector && i + 1 == component_count)
131                            print_str.pop_back();
132 
133                         if (is_float) {
134                            switch (elmt_size) {
135                            case 2:
136                               cl_half h;
137                               std::memcpy(&h, &buffer[elmt_buf_pos], elmt_size);
138                               printf(print_str.c_str(), h);
139                               break;
140                            case 4:
141                               cl_float f;
142                               std::memcpy(&f, &buffer[elmt_buf_pos], elmt_size);
143                               printf(print_str.c_str(), f);
144                               break;
145                            default:
146                               cl_double d;
147                               std::memcpy(&d, &buffer[elmt_buf_pos], elmt_size);
148                               printf(print_str.c_str(), d);
149                            }
150                         } else {
151                            cl_long l = 0;
152                            std::memcpy(&l, &buffer[elmt_buf_pos], elmt_size);
153                            printf(print_str.c_str(), l);
154                         }
155                      }
156                   }
157                   // print the remaining
158                   if (next_tok != spec_pos) {
159                      std::string s = format.substr(spec_pos + 1,
160                                                    next_tok - spec_pos - 1);
161                      printf("%s", s.c_str());
162                   }
163                }
164 
165                fmt_pos = spec_pos;
166                fmt_last_pos = next_tok;
167 
168                buf_pos += arg_size;
169                buf_pos = ALIGN(buf_pos, 4);
170             }
171          }
172       }
173    }
174 }
175 
176 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)177 printf_handler::create(const intrusive_ptr<command_queue> &q,
178                        const std::vector<binary::printf_info> &infos,
179                        bool strings_in_buffer,
180                        cl_uint size) {
181    return std::unique_ptr<printf_handler>(
182                                        new printf_handler(q, infos, strings_in_buffer, size));
183 }
184 
printf_handler(const intrusive_ptr<command_queue> & q,const std::vector<binary::printf_info> & infos,bool strings_in_buffer,cl_uint size)185 printf_handler::printf_handler(const intrusive_ptr<command_queue> &q,
186                                const std::vector<binary::printf_info> &infos,
187                                bool strings_in_buffer,
188                                cl_uint size) :
189    _q(q), _formatters(infos), _strings_in_buffer(strings_in_buffer), _size(size), _buffer() {
190 
191    if (_size) {
192       std::string data;
193       data.reserve(_size);
194       cl_uint header[2] = { 0 };
195 
196       header[0] = initial_buffer_offset;
197       header[1] = _size;
198 
199       data.append((char *)header, (char *)(header+hdr_dwords));
200       _buffer = std::unique_ptr<root_buffer>(new root_buffer(_q->context,
201                                              std::vector<cl_mem_properties>(),
202                                              CL_MEM_COPY_HOST_PTR,
203                                              _size, (char*)data.data()));
204    }
205 }
206 
207 cl_mem
get_mem()208 printf_handler::get_mem() {
209    return (cl_mem)(_buffer.get());
210 }
211 
212 void
print()213 printf_handler::print() {
214    if (!_buffer)
215       return;
216 
217    mapping src = { *_q, _buffer->resource_in(*_q), CL_MAP_READ, true,
218                   {{ 0 }}, {{ _size, 1, 1 }} };
219 
220    cl_uint header[2] = { 0 };
221    std::memcpy(header,
222                static_cast<const char *>(src),
223                initial_buffer_offset);
224 
225    cl_uint buffer_size = header[0];
226    buffer_size -= initial_buffer_offset;
227    std::vector<char> buf;
228    buf.resize(buffer_size);
229 
230    std::memcpy(buf.data(),
231                static_cast<const char *>(src) + initial_buffer_offset,
232                buffer_size);
233 
234    // mixed endian isn't going to work, sort it out if anyone cares later.
235    assert(_q->device().endianness() == PIPE_ENDIAN_NATIVE);
236    print_formatted(_formatters, _strings_in_buffer, buf);
237 }
238