1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 **************************************************************************/
29 #include "libtelemetry.h"
30 #include "vogl_core.h"
31 #include "vogl_command_line_params.h"
33 #if !defined( USE_TELEMETRY )
34 #error "libtelemetry.cpp should not be built when USE_TELEMETRY is not defined."
37 telemetry_ctx_t g_tminfo;
39 // How much memory we want Telemetry to use. Mr. Hook says 2 megs is optimal.
40 static const size_t g_telemetry_arena_size = 2 * 1024 * 1024;
44 bool loaded; // Telemetry is loaded?
45 HTELEMETRY ctx; // Telemetry context.
47 int level; // Telemetry level.
48 int new_level; // New Telemetry level to set (on next telemetry_tick)
49 char servername[256]; // servername (defaults to localhost)
50 char appname[256]; // application name.
52 // False if you want to use the release mode DLL or true if you want to
53 // use the checked DLL. The checked DLL is compiled with optimizations but
54 // does extra run time checks and reporting.
57 TmU8 *mem_arena; // allocated mem arena.
61 * Initialize Telemetry
64 telemetry_initialize()
70 // If we've already got a context, check if it's connected.
71 TmConnectionStatus status = tmGetConnectionStatus(g_tmdata.ctx);
72 if (status == TMCS_CONNECTED || status == TMCS_CONNECTING)
78 /* int load_telemetry = */ tmLoadTelemetry( g_tmdata.use_checked_dll );
83 // Warning( "TelemetryInit() failed: tmStartup() returned %d, tmLoadTelemetry() returned %d.\n", retval, load_telemetry );
87 if (!g_tmdata.mem_arena)
89 // Allocate mem arena.
90 g_tmdata.mem_arena = new TmU8[g_telemetry_arena_size];
93 // Initialize our context.
94 retval = tmInitializeContext(&g_tmdata.ctx, g_tmdata.mem_arena, g_telemetry_arena_size);
95 if ( retval != TM_OK )
97 delete [] g_tmdata.mem_arena;
98 g_tmdata.mem_arena = NULL;
100 // Warning( "TelemetryInit() failed: tmInitializeContext() returned %d.\n", retval );
104 g_tmdata.loaded = true;
107 const char *app_name = telemetry_get_appname();
108 const char *server_address = telemetry_get_servername();
109 TmConnectionType server_type = TMCT_TCP;
111 char build_info[2048];
112 vogl::dynamic_string cmdline = vogl::get_command_line();
113 snprintf( build_info, sizeof( build_info ), "%s: %s", __DATE__ __TIME__, cmdline.c_str() );
114 build_info[ sizeof( build_info ) - 1 ] = 0;
116 TmU32 open_flags = TMOF_DEFAULT | TMOF_MINIMAL_CONTEXT_SWITCHES;
117 /* open_flags |= TMOF_DISABLE_CONTEXT_SWITCHES | TMOF_INIT_NETWORKING*/
119 retval = tmOpen( g_tmdata.ctx, app_name, build_info, server_address, server_type,
120 TELEMETRY_DEFAULT_PORT, open_flags, 1000 );
121 if ( retval != TM_OK )
123 // Warning( "TelemetryInitialize() failed: tmOpen returned %d.\n", retval );
127 // printf( "Telemetry initialized at level %u.\n", g_tmdata.level );
137 HTELEMETRY ctx = g_tmdata.ctx;
141 TmConnectionStatus status = tmGetConnectionStatus(ctx);
142 if (status == TMCS_CONNECTED || status == TMCS_CONNECTING)
145 // Clear all our global ctx levels.
146 memset(get_tminfo().ctx, 0, sizeof(get_tminfo().ctx));
149 // Sleep for one second and hopefully all the background threads will be done
150 // with their contexts? If not, we'll most likely crash. Not sure what else we
151 // can do here other than just pause telemetry perhaps?
154 tmShutdownContext( ctx );
156 delete [] g_tmdata.mem_arena;
157 g_tmdata.mem_arena = NULL;
160 g_tmdata.loaded = false;
164 class CTelemetryShutdown
167 CTelemetryShutdown() {}
168 ~CTelemetryShutdown() { telemetry_shutdown(); }
169 } g_TelemetryShutdown;
176 tmTick(g_tmdata.ctx);
179 // If the level has changed, reinit things.
180 if (g_tmdata.level != g_tmdata.new_level)
182 static const int max_levels = (int)(sizeof(get_tminfo().ctx) / sizeof(get_tminfo().ctx[0]));
183 if (g_tmdata.new_level > max_levels)
184 g_tmdata.new_level = max_levels;
186 g_tmdata.level = g_tmdata.new_level;
187 memset(get_tminfo().ctx, 0, sizeof(get_tminfo().ctx));
189 if (g_tmdata.level == -1)
191 // Should we just pause or try to shutdown entirely?
192 // Try shutdown for now...
193 // tmPause(g_tmdata.ctx, 1);
194 telemetry_shutdown();
198 if (!telemetry_initialize())
204 tmPause(g_tmdata.ctx, 0);
206 for (int i = 0; i <= g_tmdata.level; i++)
208 get_tminfo().ctx[i] = g_tmdata.ctx;
213 g_tmdata.new_level = g_tmdata.level;
217 SO_API_EXPORT const char *
218 telemetry_get_servername()
220 if (!g_tmdata.servername[0])
222 return g_tmdata.servername;
226 telemetry_set_servername(const char *servername)
229 strncpy(g_tmdata.servername, servername, sizeof(g_tmdata.servername));
231 g_tmdata.servername[0] = 0;
234 SO_API_EXPORT const char *
235 telemetry_get_appname()
237 if (!g_tmdata.appname[0])
239 vogl::dynamic_string_array params(vogl::get_command_line_params());
242 char *appname = basename(params[0].c_str());
244 strncpy(g_tmdata.appname, appname, sizeof(g_tmdata.appname));
247 if (!g_tmdata.appname[0])
249 return g_tmdata.appname;
253 telemetry_set_appname(const char *appname)
256 strncpy(g_tmdata.appname, appname, sizeof(g_tmdata.appname));
258 g_tmdata.appname[0] = 0;
262 telemetry_get_level()
264 // If we've never loaded telemetry, our level is -1.
265 if (!g_tmdata.loaded)
268 return g_tmdata.level;
272 telemetry_set_level(int level)
274 // If we've never loaded telemetry, our level is -1.
275 if (!g_tmdata.loaded)
278 // Set our new level.
279 g_tmdata.new_level = level;