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