11 bool s_debugOut =
false;
12 bool s_consoleOut =
false;
13 bool s_fileOut =
false;
15 HANDLE s_hFile = INVALID_HANDLE_VALUE;
30 BOOL ret = ::AllocConsole();
32 HANDLE hOut = ::GetStdHandle(STD_OUTPUT_HANDLE);
33 COORD maxSize = GetLargestConsoleWindowSize(hOut);
34 COORD bufSize = { 80, maxSize.Y * 10 };
35 SMALL_RECT rect = { 0, 0, bufSize.X - 1, maxSize.Y * 3 / 4 };
36 SetConsoleScreenBufferSize(hOut, bufSize);
37 SetConsoleWindowInfo(hOut, TRUE, &rect);
48 HANDLE h = ::CreateFile(fileName, GENERIC_WRITE, FILE_SHARE_READ,
nullptr,
49 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
nullptr);
50 if (h != INVALID_HANDLE_VALUE) {
66 if (s_hFile != INVALID_HANDLE_VALUE) {
67 ::CloseHandle(s_hFile);
73 void write(
const wchar_t *
str,
bool newline) noexcept
77 ::OutputDebugString(
str);
79 ::OutputDebugString(L
"\n");
84 HANDLE hOut = ::GetStdHandle(STD_OUTPUT_HANDLE);
85 DWORD len =
static_cast<DWORD
>(wcslen(
str));
87 ::WriteConsole(hOut,
str, len, &written, NULL);
89 ::WriteConsole(hOut, L
"\n", 1, &written, NULL);
96 ::WriteFile(s_hFile, mbstr.get(),
static_cast<DWORD
>(strlen(mbstr.get())), &written,
nullptr);
98 ::WriteFile(s_hFile,
"\n", 1, &written,
nullptr);
103 void writef(
const wchar_t *fmt, ...) noexcept
108 _vsnwprintf_s(buf, _TRUNCATE, fmt, args);
114 void writef(
const char *fmt, ...) noexcept
119 vsnprintf_s(buf, _TRUNCATE, fmt, args);
130 _vsnwprintf_s(buf, _TRUNCATE, fmt, args);
141 vsnprintf_s(buf, _TRUNCATE, fmt, args);
155 const size_t LINE_DATA_SIZE = 128;
159 char msg[LINE_DATA_SIZE -
sizeof(LARGE_INTEGER) -
sizeof(uint32_t)];
161 static_assert(
sizeof(LineBuffer) == LINE_DATA_SIZE,
"invalid struct def");
163 struct VirtualDeleter {
164 void operator()(
void *p)
166 BOOL ret = ::VirtualFree(p, 0, MEM_RELEASE);
173 std::unique_ptr<LineBuffer[], VirtualDeleter> s_buf;
181 void *p = ::VirtualAlloc(
nullptr, bufsize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
183 s_buf.reset(static_cast<LineBuffer *>(p));
184 s_size = bufsize /
sizeof(LineBuffer);
187 std::memset(s_buf.get(), 0, bufsize);
192 wchar_t tempPath[MAX_PATH];
193 DWORD dret = GetTempPath(MAX_PATH, tempPath);
195 wchar_t filePath[MAX_PATH];
196 UINT uret = GetTempFileName(tempPath, L
"trc", 0, filePath);
198 HANDLE tmpFile = CreateFile(filePath, GENERIC_WRITE, 0,
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
nullptr);
199 checkWin32Result(tmpFile != INVALID_HANDLE_VALUE,
"GetTempFileName() failed");
202 LARGE_INTEGER freq = { 0 };
203 ::QueryPerformanceFrequency(&freq);
205 LARGE_INTEGER prevCount = { 0 };
206 for (
size_t i = 0; i < s_size; i++) {
207 size_t ind = (s_number + i) % s_size;
208 const LineBuffer &line = s_buf[ind];
209 if (line.counter.QuadPart == 0) {
212 auto writeFunc = [&hFile](
const char *
str) {
213 DWORD len =
static_cast<DWORD
>(std::strlen(
str));
215 BOOL bret = WriteFile(hFile.get(),
str, len, &writeSize,
nullptr);
220 if (prevCount.QuadPart != 0) {
221 sec =
static_cast<double>(line.counter.QuadPart - prevCount.QuadPart) / freq.QuadPart;
223 prevCount = s_buf[ind].counter;
225 ::sprintf_s(buf,
"[%08x +%07.4fms] ", s_buf[ind].
number, sec * 1e3);
235 HINSTANCE hret = ::ShellExecute(
236 nullptr,
nullptr, L
"notepad", filePath,
nullptr, SW_NORMAL);
237 checkWin32Result(reinterpret_cast<ULONG_PTR>(hret) > 32,
"ShellExecute() failed");
242 LineBuffer &line = s_buf[s_number % s_size];
243 ::QueryPerformanceCounter(&line.counter);
244 line.number = s_number;
246 ::strncpy_s(line.msg, str,
sizeof(line.msg) - 1);
std::unique_ptr< char[]> wc2utf8(const wchar_t *in)
Wide char to UTF-8.
bool enableDebugOutput() noexcept
Enables writing to OutputDebugString().
void write(const wchar_t *str, bool newline) noexcept
Write debug string.
void writef(const wchar_t *fmt,...) noexcept
Write debug message using format string like printf.
void initialize(size_t bufsize)
Initialize trace buffer.
void shutdownDebugOutput() noexcept
Flush buffers and free resources.
void writeLine(const wchar_t *str=L"") noexcept
Write debug string and new line.
std::unique_ptr< HANDLE, HandleDeleter > HandlePtr
unique_ptr of HANDLE with HandleDeleter.
void output()
Output to a temporary file and open it with notepad.
char msg[LINE_DATA_SIZE-sizeof(LARGE_INTEGER)-sizeof(uint32_t)]
bool enableFileOutput(const wchar_t *fileName) noexcept
Enables writing to a file.
bool enableConsoleOutput() noexcept
Shows a console window and enables writing to it.
void checkWin32Result(bool cond, const std::string &msg)
void writef_nonl(const wchar_t *fmt,...) noexcept
Write debug message using format string like printf. (No new line)