diff options
| Commit | fefc19f44df05b8dce8eff0fcff50ad3761bb78e (patch) | |
|---|---|---|
| Author | 2020-12-23 14:55:13 +0200 | |
| Committer | 2020-12-23 14:55:13 +0200 | |
| Files | a67c5916f28efc4267fb22ae141a23e2bbeb66dd | |
| IPL-fefc19f44df05b8dce8eff0fcff50ad3761bb78e.tar IPL-fefc19f44df05b8dce8eff0fcff50ad3761bb78e.tar.gz IPL-fefc19f44df05b8dce8eff0fcff50ad3761bb78e.zip | ||
| Parent | 32f732d5e91da6c911e2f983e317dc4da8b1c1e3 (diff) | |
| Parent | dbe9285608507c592fede216f2c147c5a3d40cea (diff) | |
Merge commit 'dbe9285608507c592fede216f2c147c5a3d40cea' as 'gctest/minitrace'
11 files changed, 1412 insertions, 0 deletions
| -rw-r--r-- | gctest/minitrace/.gitignore | 36 | ||||
| -rw-r--r-- | gctest/minitrace/LICENSE | 21 | ||||
| -rw-r--r-- | gctest/minitrace/Makefile | 30 | ||||
| -rw-r--r-- | gctest/minitrace/README.md | 113 | ||||
| -rw-r--r-- | gctest/minitrace/minitrace.c | 481 | ||||
| -rw-r--r-- | gctest/minitrace/minitrace.h | 270 | ||||
| -rw-r--r-- | gctest/minitrace/minitrace_test.cpp | 70 | ||||
| -rw-r--r-- | gctest/minitrace/minitrace_test_mt.cpp | 60 | ||||
| -rw-r--r-- | gctest/minitrace/msvc/minitrace.sln | 43 | ||||
| -rw-r--r-- | gctest/minitrace/msvc/minitrace.vcxproj | 278 | ||||
| -rw-r--r-- | gctest/minitrace/msvc/minitrace.vcxproj.filters | 10 |
diff --git a/gctest/minitrace/.gitignore b/gctest/minitrace/.gitignore new file mode 100644 index 0000000..82fe1f4 --- /dev/null +++ b/gctest/minitrace/.gitignore @@ -0,0 +1,36 @@ +# Object files +*.o +*.ko + +# Libraries +*.lib +*.a + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +minitrace_test +minitrace_test_mt + +# MSVC stuff +*.opensdf +*.sdf +Debug +Release +x64 +*.suo +*.vs +*.user + +# Misc +.gitattributes + +# Traces +*.json diff --git a/gctest/minitrace/LICENSE b/gctest/minitrace/LICENSE new file mode 100644 index 0000000..f746931 --- /dev/null +++ b/gctest/minitrace/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Henrik Rydgård + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.
\ No newline at end of file diff --git a/gctest/minitrace/Makefile b/gctest/minitrace/Makefile new file mode 100644 index 0000000..f6c2677 --- /dev/null +++ b/gctest/minitrace/Makefile @@ -0,0 +1,30 @@ +CC=gcc +CXX=g++ + +INCLUDE=-I. +FLAGS=-Wall -W -O2 -DMTR_ENABLED + +CFLAGS=$(INCLUDE) $(FLAGS) +CXXFLAGS=$(INCLUDE) $(FLAGS) +LDFLAGS=-lm + +DEPS=minitrace.h +OBJS=minitrace.o minitrace_test.o +OBJS2=minitrace.o minitrace_test_mt.o + +%.o: %.c $(DEPS) + $(CC) -c -o $@ $< $(CFLAGS) + +%.o: %.cpp $(DEPS) + $(CXX) -c -o $@ $< $(CXXFLAGS) + +all: minitrace_test minitrace_test_mt + +minitrace_test: $(OBJS) + $(CXX) -o $@ $^ ${CFLAGS} + +minitrace_test_mt: $(OBJS2) + $(CXX) -o $@ $^ -lpthread ${LDFLAGS} + +clean: + rm -f *.o *.d minitrace_test minitrace_test_mt diff --git a/gctest/minitrace/README.md b/gctest/minitrace/README.md new file mode 100644 index 0000000..75cdcbf --- /dev/null +++ b/gctest/minitrace/README.md @@ -0,0 +1,113 @@ +minitrace +========= +by Henrik Rydgård 2014 (hrydgard+minitrace@gmail.com) + +MIT licensed, feel free to use however you want. If you use it for something cool, I'd love to hear about it! + +This is a C library with C++ helpers for producing JSON traces suitable for Chrome's excellent built-in trace viewer (chrome://tracing). + +Extremely simple to build and use. Tested on Mac and Windows, but should compile anywhere you can use ANSI C with few or no changes. + +Sample output (see example code below): + + + +Remember to be careful when interpreting the output. This is not a sampling profiler, so it only records start and stop times for blocks. This means that blocks grow even when the CPU is off running another thread, and that it can look like work is being done on more blocks at a time than you have CPUs. + + +How to use +---------- + + 1. Include `minitrace.c` and `minitrace.h` in your project. `#include minitrace.h` in some common header. + + 2. In your initialization code: + + ```c + mtr_init("trace.json"); + ``` + + 3. In your exit code: + + ```c + mtr_shutdown(); + ``` + + 4. Make sure `MTR_ENABLED` is defined globally when you want to profile, for example `-DMTR_ENABLED` + + 5. In all functions you want to profile: + + ```c + // C + MTR_BEGIN("GFX", "RasterizeTriangle") + ... + MTR_END("GFX", "RasterizeTriangle") + ``` + + ```c++ + // C++ + MTR_SCOPE("GFX", "RasterizeTriangle") + ``` + + 6. In Google Chrome open "about:tracing" + + 7. Click Open, and choose your `trace.json` + + 8. Navigate the trace view using the WASD keys, and Look for bottlenecks and optimize your application. + + 9. In your final release build, don't forget to remove `-DMTR_ENABLED` or however you set the define. + + +By default, it will collect 1 million tracepoints and then stop. You can change this behaviour, see the +top of the header file. + +Note: Please only use string literals in MTR statements. + +Example code +------------ + +```c +int main(int argc, const char *argv[]) { + int i; + mtr_init("trace.json"); + + MTR_META_PROCESS_NAME("minitrace_test"); + MTR_META_THREAD_NAME("main thread"); + + int long_running_thing_1; + int long_running_thing_2; + + MTR_START("background", "long_running", &long_running_thing_1); + MTR_START("background", "long_running", &long_running_thing_2); + + MTR_BEGIN("main", "outer"); + usleep(80000); + for (i = 0; i < 3; i++) { + MTR_BEGIN("main", "inner"); + usleep(40000); + MTR_END("main", "inner"); + usleep(10000); + } + MTR_STEP("background", "long_running", &long_running_thing_1, "middle step"); + usleep(80000); + MTR_END("main", "outer"); + + usleep(50000); + MTR_INSTANT("main", "the end"); + usleep(10000); + MTR_FINISH("background", "long_running", &long_running_thing_1); + MTR_FINISH("background", "long_running", &long_running_thing_2); + + mtr_flush(); + mtr_shutdown(); + return 0; +} +``` + +The output will result in something looking a little like the picture at the top of this readme. + +Future plans: + + * Builtin background flush thread support with better synchronization, no more fixed limit + * Support for more trace arguments, more tracing types + +If you use this, feel free to tell me how, and what issues you may have had. hrydgard+minitrace@gmail.com diff --git a/gctest/minitrace/minitrace.c b/gctest/minitrace/minitrace.c new file mode 100644 index 0000000..42c2634 --- /dev/null +++ b/gctest/minitrace/minitrace.c @@ -0,0 +1,481 @@ +// minitrace +// Copyright 2014 by Henrik Rydgård +// http://www.github.com/hrydgard/minitrace +// Released under the MIT license. + +// See minitrace.h for basic documentation. + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#ifdef _WIN32 +#pragma warning (disable:4996) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#define __thread __declspec(thread) +#define pthread_mutex_t CRITICAL_SECTION +#define pthread_mutex_init(a, b) InitializeCriticalSection(a) +#define pthread_mutex_lock(a) EnterCriticalSection(a) +#define pthread_mutex_unlock(a) LeaveCriticalSection(a) +#define pthread_mutex_destroy(a) DeleteCriticalSection(a) +#else +#include <signal.h> +#include <pthread.h> +#include <sys/time.h> +#include <unistd.h> +#endif + +#include "minitrace.h" + +#ifdef __GNUC__ +#define ATTR_NORETURN __attribute__((noreturn)) +#else +#define ATTR_NORETURN +#endif + +#define ARRAY_SIZE(x) sizeof(x)/sizeof(x[0]) +#define TRUE 1 +#define FALSE 0 + +// Ugh, this struct is already pretty heavy. +// Will probably need to move arguments to a second buffer to support more than one. +typedef struct raw_event { + const char *name; + const char *cat; + void *id; + int64_t ts; + uint32_t pid; + uint32_t tid; + char ph; + mtr_arg_type arg_type; + const char *arg_name; + union { + const char *a_str; + int a_int; + double a_double; + }; +} raw_event_t; + +static raw_event_t *event_buffer; +static raw_event_t *flush_buffer; +static volatile int event_count; +static int is_tracing = FALSE; +static int is_flushing = FALSE; +static int events_in_progress = 0; +static int64_t time_offset; +static int first_line = 1; +static FILE *f; +static __thread int cur_thread_id; // Thread local storage +static int cur_process_id; +static pthread_mutex_t mutex; +static pthread_mutex_t event_mutex; + +#define STRING_POOL_SIZE 100 +static char *str_pool[100]; + +// forward declaration +void mtr_flush_with_state(int); + +// Tiny portability layer. +// Exposes: +// get_cur_thread_id() +// get_cur_process_id() +// mtr_time_s() +// pthread basics +#ifdef _WIN32 +static int get_cur_thread_id() { + return (int)GetCurrentThreadId(); +} +static int get_cur_process_id() { + return (int)GetCurrentProcessId(); +} + +static uint64_t _frequency = 0; +static uint64_t _starttime = 0; +double mtr_time_s() { + if (_frequency == 0) { + QueryPerformanceFrequency((LARGE_INTEGER*)&_frequency); + QueryPerformanceCounter((LARGE_INTEGER*)&_starttime); + } + __int64 time; + QueryPerformanceCounter((LARGE_INTEGER*)&time); + return ((double) (time - _starttime) / (double) _frequency); +} + +// Ctrl+C handling for Windows console apps +static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) { + if (is_tracing && fdwCtrlType == CTRL_C_EVENT) { + printf("Ctrl-C detected! Flushing trace and shutting down.\n\n"); + mtr_flush(); + mtr_shutdown(); + } + ExitProcess(1); +} + +void mtr_register_sigint_handler() { + // For console apps: + SetConsoleCtrlHandler(&CtrlHandler, TRUE); +} + +#else + +static inline int get_cur_thread_id() { + return (int)(intptr_t)pthread_self(); +} +static inline int get_cur_process_id() { + return (int)getpid(); +} + +#if defined(BLACKBERRY) +double mtr_time_s() { + struct timespec time; + clock_gettime(CLOCK_MONOTONIC, &time); // Linux must use CLOCK_MONOTONIC_RAW due to time warps + return time.tv_sec + time.tv_nsec / 1.0e9; +} +#else +double mtr_time_s() { + static time_t start; + struct timeval tv; + gettimeofday(&tv, NULL); + if (start == 0) { + start = tv.tv_sec; + } + tv.tv_sec -= start; + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; +} +#endif // !BLACKBERRY + +static void termination_handler(int signum) ATTR_NORETURN; +static void termination_handler(int signum) { + (void) signum; + if (is_tracing) { + printf("Ctrl-C detected! Flushing trace and shutting down.\n\n"); + mtr_flush(); + fwrite("\n]}\n", 1, 4, f); + fclose(f); + } + exit(1); +} + +void mtr_register_sigint_handler() { +#ifndef MTR_ENABLED + return; +#endif + // Avoid altering set-to-be-ignored handlers while registering. + if (signal(SIGINT, &termination_handler) == SIG_IGN) + signal(SIGINT, SIG_IGN); +} + +#endif + +void mtr_init_from_stream(void *stream) { +#ifndef MTR_ENABLED + return; +#endif + event_buffer = (raw_event_t *)malloc(INTERNAL_MINITRACE_BUFFER_SIZE * sizeof(raw_event_t)); + flush_buffer = (raw_event_t *)malloc(INTERNAL_MINITRACE_BUFFER_SIZE * sizeof(raw_event_t)); + is_tracing = 1; + event_count = 0; + f = (FILE *)stream; + const char *header = "{\"traceEvents\":[\n"; + fwrite(header, 1, strlen(header), f); + time_offset = (uint64_t)(mtr_time_s() * 1000000); + first_line = 1; + pthread_mutex_init(&mutex, 0); + pthread_mutex_init(&event_mutex, 0); +} + +void mtr_init(const char *json_file) { +#ifndef MTR_ENABLED + return; +#endif + mtr_init_from_stream(fopen(json_file, "wb")); +} + +void mtr_shutdown() { + int i; +#ifndef MTR_ENABLED + return; +#endif + pthread_mutex_lock(&mutex); + is_tracing = FALSE; + pthread_mutex_unlock(&mutex); + mtr_flush_with_state(TRUE); + + fwrite("\n]}\n", 1, 4, f); + fclose(f); + pthread_mutex_destroy(&mutex); + pthread_mutex_destroy(&event_mutex); + f = 0; + free(event_buffer); + event_buffer = 0; + for (i = 0; i < STRING_POOL_SIZE; i++) { + if (str_pool[i]) { + free(str_pool[i]); + str_pool[i] = 0; + } + } +} + +const char *mtr_pool_string(const char *str) { + int i; + for (i = 0; i < STRING_POOL_SIZE; i++) { + if (!str_pool[i]) { + str_pool[i] = (char*)malloc(strlen(str) + 1); + strcpy(str_pool[i], str); + return str_pool[i]; + } else { + if (!strcmp(str, str_pool[i])) + return str_pool[i]; + } + } + return "string pool full"; +} + +void mtr_start() { +#ifndef MTR_ENABLED + return; +#endif + pthread_mutex_lock(&mutex); + is_tracing = TRUE; + pthread_mutex_unlock(&mutex); +} + +void mtr_stop() { +#ifndef MTR_ENABLED + return; +#endif + pthread_mutex_lock(&mutex); + is_tracing = FALSE; + pthread_mutex_unlock(&mutex); +} + +// TODO: fwrite more than one line at a time. +// Flushing is thread safe and process async +// using double-buffering mechanism. +// Aware: only one flushing process may be +// running at any point of time +void mtr_flush_with_state(int is_last) { +#ifndef MTR_ENABLED + return; +#endif + int i = 0; + char linebuf[1024]; + char arg_buf[1024]; + char id_buf[256]; + int event_count_copy = 0; + int events_in_progress_copy = 1; + raw_event_t *event_buffer_tmp = NULL; + + // small critical section to swap buffers + // - no any new events can be spawn while + // swapping since they tied to the same mutex + // - checks for any flushing in process + pthread_mutex_lock(&mutex); + // if not flushing already + if (is_flushing) { + pthread_mutex_unlock(&mutex); + return; + } + is_flushing = TRUE; + event_count_copy = event_count; + event_buffer_tmp = flush_buffer; + flush_buffer = event_buffer; + event_buffer = event_buffer_tmp; + event_count = 0; + // waiting for any unfinished events before swap + while (events_in_progress_copy != 0) { + pthread_mutex_lock(&event_mutex); + events_in_progress_copy = events_in_progress; + pthread_mutex_unlock(&event_mutex); + } + pthread_mutex_unlock(&mutex); + + for (i = 0; i < event_count_copy; i++) { + raw_event_t *raw = &flush_buffer[i]; + int len; + switch (raw->arg_type) { + case MTR_ARG_TYPE_INT: + snprintf(arg_buf, ARRAY_SIZE(arg_buf), "\"%s\":%i", raw->arg_name, raw->a_int); + break; + case MTR_ARG_TYPE_STRING_CONST: + snprintf(arg_buf, ARRAY_SIZE(arg_buf), "\"%s\":\"%s\"", raw->arg_name, raw->a_str); + break; + case MTR_ARG_TYPE_STRING_COPY: + if (strlen(raw->a_str) > 700) { + snprintf(arg_buf, ARRAY_SIZE(arg_buf), "\"%s\":\"%.*s\"", raw->arg_name, 700, raw->a_str); + } else { + snprintf(arg_buf, ARRAY_SIZE(arg_buf), "\"%s\":\"%s\"", raw->arg_name, raw->a_str); + } + break; + case MTR_ARG_TYPE_NONE: + arg_buf[0] = '\0'; + break; + } + if (raw->id) { + switch (raw->ph) { + case 'S': + case 'T': + case 'F': + // TODO: Support full 64-bit pointers + snprintf(id_buf, ARRAY_SIZE(id_buf), ",\"id\":\"0x%08x\"", (uint32_t)(uintptr_t)raw->id); + break; + case 'X': + snprintf(id_buf, ARRAY_SIZE(id_buf), ",\"dur\":%i", (int)raw->a_double); + break; + } + } else { + id_buf[0] = 0; + } + const char *cat = raw->cat; +#ifdef _WIN32 + // On Windows, we often end up with backslashes in category. + char temp[256]; + { + int len = (int)strlen(cat); + int i; + if (len > 255) len = 255; + for (i = 0; i < len; i++) { + temp[i] = cat[i] == '\\' ? '/' : cat[i]; + } + temp[len] = 0; + cat = temp; + } +#endif + + len = snprintf(linebuf, ARRAY_SIZE(linebuf), "%s{\"cat\":\"%s\",\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 ",\"ph\":\"%c\",\"name\":\"%s\",\"args\":{%s}%s}", + first_line ? "" : ",\n", + cat, raw->pid, raw->tid, raw->ts - time_offset, raw->ph, raw->name, arg_buf, id_buf); + fwrite(linebuf, 1, len, f); + first_line = 0; + + #ifdef MTR_COPY_EVENT_CATEGORY_AND_NAME + free(raw->name); + free(raw->cat); + #endif + } + + pthread_mutex_lock(&mutex); + is_flushing = is_last; + pthread_mutex_unlock(&mutex); +} + +void mtr_flush() { + mtr_flush_with_state(FALSE); +} + +void internal_mtr_raw_event(const char *category, const char *name, char ph, void *id) { +#ifndef MTR_ENABLED + return; +#endif + pthread_mutex_lock(&mutex); + if (!is_tracing || event_count >= INTERNAL_MINITRACE_BUFFER_SIZE) { + pthread_mutex_unlock(&mutex); + return; + } + raw_event_t *ev = &event_buffer[event_count]; + ++event_count; + pthread_mutex_lock(&event_mutex); + ++events_in_progress; + pthread_mutex_unlock(&event_mutex); + pthread_mutex_unlock(&mutex); + + double ts = mtr_time_s(); + if (!cur_thread_id) { + cur_thread_id = get_cur_thread_id(); + } + if (!cur_process_id) { + cur_process_id = get_cur_process_id(); + } + +#ifdef MTR_COPY_EVENT_CATEGORY_AND_NAME + const size_t category_len = strlen(category); + ev->cat = malloc(category_len + 1); + strcpy(ev->cat, category); + + const size_t name_len = strlen(name); + ev->name = malloc(name_len + 1); + strcpy(ev->name, name); + +#else + ev->cat = category; + ev->name = name; +#endif + + ev->id = id; + ev->ph = ph; + if (ev->ph == 'X') { + double x; + memcpy(&x, id, sizeof(double)); + ev->ts = (int64_t)(x * 1000000); + ev->a_double = (ts - x) * 1000000; + } else { + ev->ts = (int64_t)(ts * 1000000); + } + ev->tid = cur_thread_id; + ev->pid = cur_process_id; + ev->arg_type = MTR_ARG_TYPE_NONE; + + pthread_mutex_lock(&event_mutex); + --events_in_progress; + pthread_mutex_unlock(&event_mutex); +} + +void internal_mtr_raw_event_arg(const char *category, const char *name, char ph, void *id, mtr_arg_type arg_type, const char *arg_name, void *arg_value) { +#ifndef MTR_ENABLED + return; +#endif + pthread_mutex_lock(&mutex); + if (!is_tracing || event_count >= INTERNAL_MINITRACE_BUFFER_SIZE) { + pthread_mutex_unlock(&mutex); + return; + } + raw_event_t *ev = &event_buffer[event_count]; + ++event_count; + pthread_mutex_lock(&event_mutex); + ++events_in_progress; + pthread_mutex_unlock(&event_mutex); + pthread_mutex_unlock(&mutex); + + if (!cur_thread_id) { + cur_thread_id = get_cur_thread_id(); + } + if (!cur_process_id) { + cur_process_id = get_cur_process_id(); + } + double ts = mtr_time_s(); + +#ifdef MTR_COPY_EVENT_CATEGORY_AND_NAME + const size_t category_len = strlen(category); + ev->cat = malloc(category_len + 1); + strcpy(ev->cat, category); + + const size_t name_len = strlen(name); + ev->name = malloc(name_len + 1); + strcpy(ev->name, name); + +#else + ev->cat = category; + ev->name = name; +#endif + + ev->id = id; + ev->ts = (int64_t)(ts * 1000000); + ev->ph = ph; + ev->tid = cur_thread_id; + ev->pid = cur_process_id; + ev->arg_type = arg_type; + ev->arg_name = arg_name; + switch (arg_type) { + case MTR_ARG_TYPE_INT: ev->a_int = (int)(uintptr_t)arg_value; break; + case MTR_ARG_TYPE_STRING_CONST: ev->a_str = (const char*)arg_value; break; + case MTR_ARG_TYPE_STRING_COPY: ev->a_str = strdup((const char*)arg_value); break; + case MTR_ARG_TYPE_NONE: break; + } + + pthread_mutex_lock(&event_mutex); + --events_in_progress; + pthread_mutex_unlock(&event_mutex); +} + diff --git a/gctest/minitrace/minitrace.h b/gctest/minitrace/minitrace.h new file mode 100644 index 0000000..2047eed --- /dev/null +++ b/gctest/minitrace/minitrace.h @@ -0,0 +1,270 @@ +// Minitrace +// +// Copyright 2014 by Henrik Rydgård +// http://www.github.com/hrydgard/minitrace +// Released under the MIT license. +// +// Ultra-light dependency free library for performance tracing C/C++ applications. +// Produces traces compatible with Google Chrome's trace viewer. +// Simply open "about:tracing" in Chrome and load the produced JSON. +// +// This contains far less template magic than the original libraries from Chrome +// because this is meant to be usable from C. +// +// See README.md for a tutorial. +// +// The trace format is documented here: +// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit +// More: +// http://www.altdevblogaday.com/2012/08/21/using-chrometracing-to-view-your-inline-profiling-data/ + +#ifndef MINITRACE_H +#define MINITRACE_H + +#include <inttypes.h> + +// If MTR_ENABLED is not defined, Minitrace does nothing and has near zero overhead. +// Preferably, set this flag in your build system. If you can't just uncomment this line. +// #define MTR_ENABLED + +// By default, will collect up to 1000000 events, then you must flush. +// It's recommended that you simply call mtr_flush on a background thread +// occasionally. It's safe...ish. +#define INTERNAL_MINITRACE_BUFFER_SIZE 1000000 + +#ifdef __cplusplus +extern "C" { +#endif + +// Initializes Minitrace. Must be called very early during startup of your executable, +// before any MTR_ statements. +void mtr_init(const char *json_file); +// Same as above, but allows passing in a custom stream (FILE *), as returned by +// fopen(). It should be opened for writing, preferably in binary mode to avoid +// processing of line endings (i.e. the "wb" mode). +void mtr_init_from_stream(void *stream); + +// Shuts down minitrace cleanly, flushing the trace buffer. +void mtr_shutdown(void); + +// Lets you enable and disable Minitrace at runtime. +// May cause strange discontinuities in the output. +// Minitrace is enabled on startup by default. +void mtr_start(void); +void mtr_stop(void); + +// Flushes the collected data to disk, clearing the buffer for new data. +void mtr_flush(void); + +// Returns the current time in seconds. Used internally by Minitrace. No caching. +double mtr_time_s(void); + +// Registers a handler that will flush the trace on Ctrl+C. +// Works on Linux and MacOSX, and in Win32 console applications. +void mtr_register_sigint_handler(void); + +// Utility function that should rarely be used. +// If str is semi dynamic, store it permanently in a small pool so we don't need to malloc it. +// The pool fills up fast though and performance isn't great. +// Returns a fixed string if the pool is full. +const char *mtr_pool_string(const char *str); + +// Commented-out types will be supported in the future. +typedef enum { + MTR_ARG_TYPE_NONE = 0, + MTR_ARG_TYPE_INT = 1, // I + // MTR_ARG_TYPE_FLOAT = 2, // TODO + // MTR_ARG_TYPE_DOUBLE = 3, // TODO + MTR_ARG_TYPE_STRING_CONST = 8, // C + MTR_ARG_TYPE_STRING_COPY = 9, + // MTR_ARG_TYPE_JSON_COPY = 10, +} mtr_arg_type; + +// TODO: Add support for more than one argument (metadata) per event +// Having more costs speed and memory. +#define MTR_MAX_ARGS 1 + +// Only use the macros to call these. +void internal_mtr_raw_event(const char *category, const char *name, char ph, void *id); +void internal_mtr_raw_event_arg(const char *category, const char *name, char ph, void *id, mtr_arg_type arg_type, const char *arg_name, void *arg_value); + +#ifdef MTR_ENABLED + +// c - category. Can be filtered by in trace viewer (or at least that's the intention). +// A good use is to pass __FILE__, there are macros further below that will do it for you. +// n - name. Pass __FUNCTION__ in most cases, unless you are marking up parts of one. + +// Scopes. In C++, use MTR_SCOPE. In C, always match them within the same scope. +#define MTR_BEGIN(c, n) internal_mtr_raw_event(c, n, 'B', 0) +#define MTR_END(c, n) internal_mtr_raw_event(c, n, 'E', 0) +#define MTR_SCOPE(c, n) MTRScopedTrace ____mtr_scope(c, n) +#define MTR_SCOPE_LIMIT(c, n, l) MTRScopedTraceLimit ____mtr_scope(c, n, l) + +// Async events. Can span threads. ID identifies which events to connect in the view. +#define MTR_START(c, n, id) internal_mtr_raw_event(c, n, 'S', (void *)(id)) +#define MTR_STEP(c, n, id, step) internal_mtr_raw_event_arg(c, n, 'T', (void *)(id), MTR_ARG_TYPE_STRING_CONST, "step", (void *)(step)) +#define MTR_FINISH(c, n, id) internal_mtr_raw_event(c, n, 'F', (void *)(id)) + +// Flow events. Like async events, but displayed in a more fancy way in the viewer. +#define MTR_FLOW_START(c, n, id) internal_mtr_raw_event(c, n, 's', (void *)(id)) +#define MTR_FLOW_STEP(c, n, id, step) internal_mtr_raw_event_arg(c, n, 't', (void *)(id), MTR_ARG_TYPE_STRING_CONST, "step", (void *)(step)) +#define MTR_FLOW_FINISH(c, n, id) internal_mtr_raw_event(c, n, 'f', (void *)(id)) + +// The same macros, but with a single named argument which shows up as metadata in the viewer. +// _I for int. +// _C is for a const string arg. +// _S will copy the string, freeing on flush (expensive but sometimes necessary). +// but required if the string was generated dynamically. + +// Note that it's fine to match BEGIN_S with END and BEGIN with END_S, etc. +#define MTR_BEGIN_C(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'B', 0, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval)) +#define MTR_END_C(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'E', 0, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval)) +#define MTR_SCOPE_C(c, n, aname, astrval) MTRScopedTraceArg ____mtr_scope(c, n, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval)) + +#define MTR_BEGIN_S(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'B', 0, MTR_ARG_TYPE_STRING_COPY, aname, (void *)(astrval)) +#define MTR_END_S(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'E', 0, MTR_ARG_TYPE_STRING_COPY, aname, (void *)(astrval)) +#define MTR_SCOPE_S(c, n, aname, astrval) MTRScopedTraceArg ____mtr_scope(c, n, MTR_ARG_TYPE_STRING_COPY, aname, (void *)(astrval)) + +#define MTR_BEGIN_I(c, n, aname, aintval) internal_mtr_raw_event_arg(c, n, 'B', 0, MTR_ARG_TYPE_INT, aname, (void*)(intptr_t)(aintval)) +#define MTR_END_I(c, n, aname, aintval) internal_mtr_raw_event_arg(c, n, 'E', 0, MTR_ARG_TYPE_INT, aname, (void*)(intptr_t)(aintval)) +#define MTR_SCOPE_I(c, n, aname, aintval) MTRScopedTraceArg ____mtr_scope(c, n, MTR_ARG_TYPE_INT, aname, (void*)(intptr_t)(aintval)) + +// Instant events. For things with no duration. +#define MTR_INSTANT(c, n) internal_mtr_raw_event(c, n, 'I', 0) +#define MTR_INSTANT_C(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'I', 0, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval)) +#define MTR_INSTANT_I(c, n, aname, aintval) internal_mtr_raw_event_arg(c, n, 'I', 0, MTR_ARG_TYPE_INT, aname, (void *)(aintval)) + +// Counters (can't do multi-value counters yet) +#define MTR_COUNTER(c, n, val) internal_mtr_raw_event_arg(c, n, 'C', 0, MTR_ARG_TYPE_INT, n, (void *)(intptr_t)(val)) + +// Metadata. Call at the start preferably. Must be const strings. + +#define MTR_META_PROCESS_NAME(n) internal_mtr_raw_event_arg("", "process_name", 'M', 0, MTR_ARG_TYPE_STRING_COPY, "name", (void *)(n)) +#define MTR_META_THREAD_NAME(n) internal_mtr_raw_event_arg("", "thread_name", 'M', 0, MTR_ARG_TYPE_STRING_COPY, "name", (void *)(n)) +#define MTR_META_THREAD_SORT_INDEX(i) internal_mtr_raw_event_arg("", "thread_sort_index", 'M', 0, MTR_ARG_TYPE_INT, "sort_index", (void *)(i)) + +#else + +#define MTR_BEGIN(c, n) +#define MTR_END(c, n) +#define MTR_SCOPE(c, n) +#define MTR_START(c, n, id) +#define MTR_STEP(c, n, id, step) +#define MTR_FINISH(c, n, id) +#define MTR_FLOW_START(c, n, id) +#define MTR_FLOW_STEP(c, n, id, step) +#define MTR_FLOW_FINISH(c, n, id) +#define MTR_INSTANT(c, n) + +#define MTR_BEGIN_C(c, n, aname, astrval) +#define MTR_END_C(c, n, aname, astrval) +#define MTR_SCOPE_C(c, n, aname, astrval) + +#define MTR_BEGIN_S(c, n, aname, astrval) +#define MTR_END_S(c, n, aname, astrval) +#define MTR_SCOPE_S(c, n, aname, astrval) + +#define MTR_BEGIN_I(c, n, aname, aintval) +#define MTR_END_I(c, n, aname, aintval) +#define MTR_SCOPE_I(c, n, aname, aintval) + +#define MTR_INSTANT(c, n) +#define MTR_INSTANT_C(c, n, aname, astrval) +#define MTR_INSTANT_I(c, n, aname, aintval) + +// Counters (can't do multi-value counters yet) +#define MTR_COUNTER(c, n, val) + +// Metadata. Call at the start preferably. Must be const strings. + +#define MTR_META_PROCESS_NAME(n) + +#define MTR_META_THREAD_NAME(n) +#define MTR_META_THREAD_SORT_INDEX(i) + +#endif + +// Shortcuts for simple function timing with automatic categories and names. + +#define MTR_BEGIN_FUNC() MTR_BEGIN(__FILE__, __FUNCTION__) +#define MTR_END_FUNC() MTR_END(__FILE__, __FUNCTION__) +#define MTR_SCOPE_FUNC() MTR_SCOPE(__FILE__, __FUNCTION__) +#define MTR_INSTANT_FUNC() MTR_INSTANT(__FILE__, __FUNCTION__) +#define MTR_SCOPE_FUNC_LIMIT_S(l) MTRScopedTraceLimit ____mtr_scope(__FILE__, __FUNCTION__, l) +#define MTR_SCOPE_FUNC_LIMIT_MS(l) MTRScopedTraceLimit ____mtr_scope(__FILE__, __FUNCTION__, (double)l * 0.000001) + +// Same, but with a single argument of the usual types. +#define MTR_BEGIN_FUNC_S(aname, arg) MTR_BEGIN_S(__FILE__, __FUNCTION__, aname, arg) +#define MTR_END_FUNC_S(aname, arg) MTR_END_S(__FILE__, __FUNCTION__, aname, arg) +#define MTR_SCOPE_FUNC_S(aname, arg) MTR_SCOPE_S(__FILE__, __FUNCTION__, aname, arg) + +#define MTR_BEGIN_FUNC_C(aname, arg) MTR_BEGIN_C(__FILE__, __FUNCTION__, aname, arg) +#define MTR_END_FUNC_C(aname, arg) MTR_END_C(__FILE__, __FUNCTION__, aname, arg) +#define MTR_SCOPE_FUNC_C(aname, arg) MTR_SCOPE_C(__FILE__, __FUNCTION__, aname, arg) + +#define MTR_BEGIN_FUNC_I(aname, arg) MTR_BEGIN_I(__FILE__, __FUNCTION__, aname, arg) +#define MTR_END_FUNC_I(aname, arg) MTR_END_I(__FILE__, __FUNCTION__, aname, arg) +#define MTR_SCOPE_FUNC_I(aname, arg) MTR_SCOPE_I(__FILE__, __FUNCTION__, aname, arg) + +#ifdef __cplusplus +} + +#ifdef MTR_ENABLED +// These are optimized to use X events (combined B and E). Much easier to do in C++ than in C. +class MTRScopedTrace { +public: + MTRScopedTrace(const char *category, const char *name) + : category_(category), name_(name) { + start_time_ = mtr_time_s(); + } + ~MTRScopedTrace() { + internal_mtr_raw_event(category_, name_, 'X', &start_time_); + } + +private: + const char *category_; + const char *name_; + double start_time_; +}; + +// Only outputs a block if execution time exceeded the limit. +// TODO: This will effectively call mtr_time_s twice at the end, which is bad. +class MTRScopedTraceLimit { +public: + MTRScopedTraceLimit(const char *category, const char *name, double limit_s) + : category_(category), name_(name), limit_(limit_s) { + start_time_ = mtr_time_s(); + } + ~MTRScopedTraceLimit() { + double end_time = mtr_time_s(); + if (end_time - start_time_ >= limit_) { + internal_mtr_raw_event(category_, name_, 'X', &start_time_); + } + } + +private: + const char *category_; + const char *name_; + double start_time_; + double limit_; +}; + +class MTRScopedTraceArg { +public: + MTRScopedTraceArg(const char *category, const char *name, mtr_arg_type arg_type, const char *arg_name, void *arg_value) + : category_(category), name_(name) { + internal_mtr_raw_event_arg(category, name, 'B', 0, arg_type, arg_name, arg_value); + } + ~MTRScopedTraceArg() { + internal_mtr_raw_event(category_, name_, 'E', 0); + } + +private: + const char *category_; + const char *name_; +}; +#endif + +#endif + +#endif diff --git a/gctest/minitrace/minitrace_test.cpp b/gctest/minitrace/minitrace_test.cpp new file mode 100644 index 0000000..522ac8e --- /dev/null +++ b/gctest/minitrace/minitrace_test.cpp @@ -0,0 +1,70 @@ +#include "minitrace.h" + +#ifdef _WIN32 +#include <windows.h> +#define usleep(x) Sleep(x/1000) +#else +#include <unistd.h> +#endif + +void c() { + MTR_SCOPE("c++", "c()"); + usleep(10000); +} + +void b() { + MTR_SCOPE("c++", "b()"); + usleep(20000); + c(); + usleep(10000); +} + +void a() { + MTR_SCOPE("c++", "a()"); + usleep(20000); + b(); + usleep(10000); +} + +int main() { + int i; + mtr_init("trace.json"); + mtr_register_sigint_handler(); + + MTR_META_PROCESS_NAME("minitrace_test"); + MTR_META_THREAD_NAME("main thread"); + + int long_running_thing_1; + int long_running_thing_2; + + MTR_START("background", "long_running", &long_running_thing_1); + MTR_START("background", "long_running", &long_running_thing_2); + + MTR_COUNTER("main", "greebles", 3); + MTR_BEGIN("main", "outer"); + usleep(80000); + for (i = 0; i < 3; i++) { + MTR_BEGIN("main", "inner"); + usleep(40000); + MTR_END("main", "inner"); + usleep(10000); + MTR_COUNTER("main", "greebles", 3 * i + 10); + } + MTR_STEP("background", "long_running", &long_running_thing_1, "middle step"); + usleep(80000); + MTR_END("main", "outer"); + MTR_COUNTER("main", "greebles", 0); + + usleep(10000); + a(); + + usleep(50000); + MTR_INSTANT("main", "the end"); + usleep(10000); + MTR_FINISH("background", "long_running", &long_running_thing_1); + MTR_FINISH("background", "long_running", &long_running_thing_2); + + mtr_flush(); + mtr_shutdown(); + return 0; +} diff --git a/gctest/minitrace/minitrace_test_mt.cpp b/gctest/minitrace/minitrace_test_mt.cpp new file mode 100644 index 0000000..899a193 --- /dev/null +++ b/gctest/minitrace/minitrace_test_mt.cpp @@ -0,0 +1,60 @@ +// Test minitrace with multiple threads. + +#include <inttypes.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> + +#include "minitrace.h" + +// Does some meaningless work. +int work(int cycles) { + int a = cycles; + for (int i = 0; i < cycles; i++) { + a ^= 373; + a = (a << 13) | (a >> (32 - 13)); + } + return a; +} + +void *worker_thread(void *param) { + int id = (int)(intptr_t)param; + char temp[256]; sprintf(temp, "Worker Thread %i", id); + MTR_META_THREAD_NAME(temp); + int x = 0; + for (int i = 0; i < 32; i++) { + MTR_BEGIN_I(__FILE__, "Worker", "ID", id); + x += work((rand() & 0x7fff) * 1000); + MTR_END(__FILE__, "Worker"); + } + return (void *)(intptr_t)x; +} + +void phase2() { + for (int i = 0; i < 10000; i++) { + MTR_BEGIN_FUNC(); + MTR_END_FUNC(); + } +} + +int main() { + int i; + mtr_init("mt_trace.json"); + MTR_META_PROCESS_NAME("Multithreaded Test"); + MTR_META_THREAD_NAME("Main Thread"); + MTR_BEGIN_FUNC(); + #define NUMT 8 + pthread_t threads[NUMT]; + for (i = 0; i < NUMT; i++) { + pthread_create(&threads[i], 0, &worker_thread, (void *)(intptr_t)i); + } + for (i = 0; i < NUMT; i++) { + pthread_join(threads[i], 0); + } + phase2(); + + MTR_END_FUNC(); + mtr_shutdown(); + return 0; +} diff --git a/gctest/minitrace/msvc/minitrace.sln b/gctest/minitrace/msvc/minitrace.sln new file mode 100644 index 0000000..5a9925c --- /dev/null +++ b/gctest/minitrace/msvc/minitrace.sln @@ -0,0 +1,43 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.572 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minitrace", "minitrace.vcxproj", "{5554FDA1-8300-4DD4-AF89-0084AD76CD82}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|ARM64 = Debug|ARM64 + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|ARM = Release|ARM + Release|ARM64 = Release|ARM64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5554FDA1-8300-4DD4-AF89-0084AD76CD82}.Debug|ARM.ActiveCfg = Debug|ARM + {5554FDA1-8300-4DD4-AF89-0084AD76CD82}.Debug|ARM.Build.0 = Debug|ARM + {5554FDA1-8300-4DD4-AF89-0084AD76CD82}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {5554FDA1-8300-4DD4-AF89-0084AD76CD82}.Debug|ARM64.Build.0 = Debug|ARM64 + {5554FDA1-8300-4DD4-AF89-0084AD76CD82}.Debug|Win32.ActiveCfg = Debug|Win32 + {5554FDA1-8300-4DD4-AF89-0084AD76CD82}.Debug|Win32.Build.0 = Debug|Win32 + {5554FDA1-8300-4DD4-AF89-0084AD76CD82}.Debug|x64.ActiveCfg = Debug|x64 + {5554FDA1-8300-4DD4-AF89-0084AD76CD82}.Debug|x64.Build.0 = Debug|x64 + {5554FDA1-8300-4DD4-AF89-0084AD76CD82}.Release|ARM.ActiveCfg = Release|ARM + {5554FDA1-8300-4DD4-AF89-0084AD76CD82}.Release|ARM.Build.0 = Release|ARM + {5554FDA1-8300-4DD4-AF89-0084AD76CD82}.Release|ARM64.ActiveCfg = Release|ARM64 + {5554FDA1-8300-4DD4-AF89-0084AD76CD82}.Release|ARM64.Build.0 = Release|ARM64 + {5554FDA1-8300-4DD4-AF89-0084AD76CD82}.Release|Win32.ActiveCfg = Release|Win32 + {5554FDA1-8300-4DD4-AF89-0084AD76CD82}.Release|Win32.Build.0 = Release|Win32 + {5554FDA1-8300-4DD4-AF89-0084AD76CD82}.Release|x64.ActiveCfg = Release|x64 + {5554FDA1-8300-4DD4-AF89-0084AD76CD82}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1EBC5545-48FF-4EDE-B815-90132205C3AA} + EndGlobalSection +EndGlobal diff --git a/gctest/minitrace/msvc/minitrace.vcxproj b/gctest/minitrace/msvc/minitrace.vcxproj new file mode 100644 index 0000000..362922f --- /dev/null +++ b/gctest/minitrace/msvc/minitrace.vcxproj @@ -0,0 +1,278 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|ARM"> + <Configuration>Debug</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|ARM64"> + <Configuration>Debug</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM"> + <Configuration>Release</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM64"> + <Configuration>Release</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{5554FDA1-8300-4DD4-AF89-0084AD76CD82}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>minitrace</RootNamespace> + <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>MTR_ENABLED;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>MTR_ENABLED;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>MTR_ENABLED;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>MTR_ENABLED;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>MTR_ENABLED;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>MTR_ENABLED;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>MTR_ENABLED;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>MTR_ENABLED;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\minitrace.c" /> + <ClCompile Include="..\minitrace_test.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\minitrace.h" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/gctest/minitrace/msvc/minitrace.vcxproj.filters b/gctest/minitrace/msvc/minitrace.vcxproj.filters new file mode 100644 index 0000000..daffed3 --- /dev/null +++ b/gctest/minitrace/msvc/minitrace.vcxproj.filters @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClCompile Include="..\minitrace.c" /> + <ClCompile Include="..\minitrace_test.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\minitrace.h" /> + </ItemGroup> +</Project>
\ No newline at end of file |
