1// Copyright (c) Facebook, Inc. and its affiliates.
2// All rights reserved.
3//
4// Copyright 2022 Google LLC
5//
6// This source code is licensed under the BSD-style license found in the
7// LICENSE file in the root directory of this source tree.
8
9#include <assert.h>
10#include <stdarg.h>
11#include <string.h>
12#include <stdlib.h>
13#include <stdio.h>
14#ifdef _WIN32
15 #include <windows.h>
16#else
17 #include <unistd.h>
18#endif
19#if defined(__ANDROID__)
20 #include <android/log.h>
21#endif
22#if defined(__hexagon__)
23 #include <qurt_printf.h>
24#endif
25
26#ifndef XNN_LOG_TO_STDIO
27 #if defined(__ANDROID__)
28 #define XNN_LOG_TO_STDIO 0
29 #else
30 #define XNN_LOG_TO_STDIO 1
31 #endif
32#endif
33
34#include <xnnpack/log.h>
35
36
37/* Messages up to this size are formatted entirely on-stack, and don't allocate heap memory */
38#define XNN_LOG_STACK_BUFFER_SIZE 1024
39
40#ifdef _WIN32
41 #define XNN_LOG_NEWLINE_LENGTH 2
42
43 #define XNN_LOG_STDERR STD_ERROR_HANDLE
44 #define XNN_LOG_STDOUT STD_OUTPUT_HANDLE
45#elif defined(__hexagon__)
46 #define XNN_LOG_NEWLINE_LENGTH 1
47
48 #define XNN_LOG_STDERR 0
49 #define XNN_LOG_STDOUT 0
50#else
51 #define XNN_LOG_NEWLINE_LENGTH 1
52
53 #define XNN_LOG_STDERR STDERR_FILENO
54 #define XNN_LOG_STDOUT STDOUT_FILENO
55#endif
56
57#if XNN_LOG_TO_STDIO
58static void xnn_vlog(int output_handle, const char* prefix, size_t prefix_length, const char* format, va_list args) {
59 char stack_buffer[XNN_LOG_STACK_BUFFER_SIZE];
60 char* heap_buffer = NULL;
61 char* out_buffer = &stack_buffer[0];
62
63 /* The first call to vsnprintf will clobber args, thus need a copy in case a second vsnprintf call is needed */
64 va_list args_copy;
65 va_copy(args_copy, args);
66
67 memcpy(stack_buffer, prefix, prefix_length * sizeof(char));
68 assert((prefix_length + XNN_LOG_NEWLINE_LENGTH) * sizeof(char) <= XNN_LOG_STACK_BUFFER_SIZE);
69
70 const int format_chars = vsnprintf(
71 &stack_buffer[prefix_length],
72 XNN_LOG_STACK_BUFFER_SIZE - (prefix_length + XNN_LOG_NEWLINE_LENGTH) * sizeof(char),
73 format,
74 args);
75 if (format_chars < 0) {
76 /* Format error in the message: silently ignore this particular message. */
77 goto cleanup;
78 }
79 const size_t format_length = (size_t) format_chars;
80 if ((prefix_length + format_length + XNN_LOG_NEWLINE_LENGTH) * sizeof(char) > XNN_LOG_STACK_BUFFER_SIZE) {
81 /* Allocate a buffer on heap, and vsnprintf to this buffer */
82 const size_t heap_buffer_size = (prefix_length + format_length + XNN_LOG_NEWLINE_LENGTH) * sizeof(char);
83 #if _WIN32
84 heap_buffer = HeapAlloc(GetProcessHeap(), 0, heap_buffer_size);
85 #else
86 heap_buffer = malloc(heap_buffer_size);
87 #endif
88 if (heap_buffer == NULL) {
89 goto cleanup;
90 }
91
92 /* Copy pre-formatted prefix into the on-heap buffer */
93 memcpy(heap_buffer, prefix, prefix_length * sizeof(char));
94 vsnprintf(&heap_buffer[prefix_length], (format_length + XNN_LOG_NEWLINE_LENGTH) * sizeof(char), format, args_copy);
95 out_buffer = heap_buffer;
96 }
97 #ifdef _WIN32
98 out_buffer[prefix_length + format_length] = '\r';
99 out_buffer[prefix_length + format_length + 1] = '\n';
100
101 DWORD bytes_written;
102 WriteFile(
103 GetStdHandle((DWORD) output_handle),
104 out_buffer, (prefix_length + format_length + XNN_LOG_NEWLINE_LENGTH) * sizeof(char),
105 &bytes_written, NULL);
106 #elif defined(__hexagon__)
107 qurt_printf("%s", out_buffer);
108 #else
109 out_buffer[prefix_length + format_length] = '\n';
110
111 ssize_t bytes_written = write(output_handle, out_buffer, (prefix_length + format_length + XNN_LOG_NEWLINE_LENGTH) * sizeof(char));
112 (void) bytes_written;
113 #endif
114
115cleanup:
116 #ifdef _WIN32
117 HeapFree(GetProcessHeap(), 0, heap_buffer);
118 #else
119 free(heap_buffer);
120 #endif
121 va_end(args_copy);
122}
123#elif defined(__ANDROID__) && XNN_LOG_LEVEL > XNN_LOG_NONE
124 static const char xnnpack_module[] = "XNNPACK";
125#endif
126
127#if XNN_LOG_LEVEL >= XNN_LOG_DEBUG
128 void xnn_vlog_debug(const char* format, va_list args) {
129 #if XNN_LOG_TO_STDIO
130 static const char debug_prefix[17] = {
131 'D', 'e', 'b', 'u', 'g', ' ', '(', 'X', 'N', 'N', 'P', 'A', 'C', 'K', ')', ':', ' '
132 };
133 xnn_vlog(XNN_LOG_STDOUT, debug_prefix, 17, format, args);
134 #elif defined(__ANDROID__)
135 __android_log_vprint(ANDROID_LOG_DEBUG, xnnpack_module, format, args);
136 #else
137 #error "Platform-specific implementation required"
138 #endif
139 }
140#endif
141
142#if XNN_LOG_LEVEL >= XNN_LOG_INFO
143 void xnn_vlog_info(const char* format, va_list args) {
144 #if XNN_LOG_TO_STDIO
145 static const char info_prefix[16] = {
146 'N', 'o', 't', 'e', ' ', '(', 'X', 'N', 'N', 'P', 'A', 'C', 'K', ')', ':', ' '
147 };
148 xnn_vlog(XNN_LOG_STDOUT, info_prefix, 16, format, args);
149 #elif defined(__ANDROID__)
150 __android_log_vprint(ANDROID_LOG_INFO, xnnpack_module, format, args);
151 #else
152 #error "Platform-specific implementation required"
153 #endif
154 }
155#endif
156
157#if XNN_LOG_LEVEL >= XNN_LOG_WARNING
158 void xnn_vlog_warning(const char* format, va_list args) {
159 #if XNN_LOG_TO_STDIO
160 static const char warning_prefix[20] = {
161 'W', 'a', 'r', 'n', 'i', 'n', 'g', ' ', 'i', 'n', ' ', 'X', 'N', 'N', 'P', 'A', 'C', 'K', ':', ' '
162 };
163 xnn_vlog(XNN_LOG_STDERR, warning_prefix, 20, format, args);
164 #elif defined(__ANDROID__)
165 __android_log_vprint(ANDROID_LOG_WARN, xnnpack_module, format, args);
166 #else
167 #error "Platform-specific implementation required"
168 #endif
169 }
170#endif
171
172#if XNN_LOG_LEVEL >= XNN_LOG_ERROR
173 void xnn_vlog_error(const char* format, va_list args) {
174 #if XNN_LOG_TO_STDIO
175 static const char error_prefix[18] = {
176 'E', 'r', 'r', 'o', 'r', ' ', 'i', 'n', ' ', 'X', 'N', 'N', 'P', 'A', 'C', 'K', ':', ' '
177 };
178 xnn_vlog(XNN_LOG_STDERR, error_prefix, 18, format, args);
179 #elif defined(__ANDROID__)
180 __android_log_vprint(ANDROID_LOG_ERROR, xnnpack_module, format, args);
181 #else
182 #error "Platform-specific implementation required"
183 #endif
184 }
185#endif
186
187#if XNN_LOG_LEVEL >= XNN_LOG_FATAL
188 void xnn_vlog_fatal(const char* format, va_list args) {
189 #if XNN_LOG_TO_STDIO
190 static const char fatal_prefix[24] = {
191 'F', 'a', 't', 'a', 'l', ' ', 'e', 'r', 'r', 'o', 'r', ' ', 'i', 'n', ' ', 'X', 'N', 'N', 'P', 'A', 'C', 'K', ':', ' '
192 };
193 xnn_vlog(XNN_LOG_STDERR, fatal_prefix, 24, format, args);
194 #elif defined(__ANDROID__)
195 __android_log_vprint(ANDROID_LOG_FATAL, xnnpack_module, format, args);
196 #else
197 #error "Platform-specific implementation required"
198 #endif
199 }
200#endif
201