The open source OpenXR runtime

u/metrics: Add functions to write a metrics file

authored by

Jakob Bornecrantz and committed by
Moses Turner
7fa20a8b 57a31fde

+351 -1
+11 -1
src/xrt/auxiliary/util/CMakeLists.txt
··· 61 61 u_json.hpp 62 62 u_logging.c 63 63 u_logging.h 64 + u_metrics.c 65 + u_metrics.h 64 66 u_misc.c 65 67 u_misc.h 66 68 u_pacing.h ··· 98 100 u_worker.hpp 99 101 "${CMAKE_CURRENT_BINARY_DIR}/u_git_tag.c" 100 102 ) 101 - target_link_libraries(aux_util PUBLIC aux-includes aux_generated_bindings aux_os aux_math) 103 + target_link_libraries( 104 + aux_util 105 + PUBLIC 106 + xrt-external-nanopb 107 + aux-includes 108 + aux_generated_bindings 109 + aux_os 110 + aux_math 111 + ) 102 112 103 113 # Is basically used everywhere, unavoidable. 104 114 if(XRT_HAVE_SYSTEM_CJSON)
+230
src/xrt/auxiliary/util/u_metrics.c
··· 1 + // Copyright 2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Metrics saving functions. 6 + * @author Jakob Bornecrantz <jakob@collabora.com> 7 + * @ingroup aux_util 8 + */ 9 + 10 + #include "os/os_threading.h" 11 + 12 + #include "util/u_metrics.h" 13 + #include "util/u_debug.h" 14 + 15 + #include "monado_metrics.pb.h" 16 + #include "pb_encode.h" 17 + 18 + #include <stdio.h> 19 + 20 + #define VERSION_MAJOR 1 21 + #define VERSION_MINOR 1 22 + 23 + static FILE *g_file = NULL; 24 + static struct os_mutex g_file_mutex; 25 + static bool g_metrics_initialized = false; 26 + 27 + DEBUG_GET_ONCE_OPTION(metrics_file, "XRT_METRICS_FILE", NULL) 28 + 29 + 30 + 31 + /* 32 + * 33 + * Helper functions. 34 + * 35 + */ 36 + 37 + static void 38 + write_record(monado_metrics_Record *r) 39 + { 40 + uint8_t buffer[monado_metrics_Record_size + 10]; // Including submessage 41 + 42 + 43 + pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); 44 + bool ret = pb_encode_submessage(&stream, &monado_metrics_Record_msg, r); 45 + if (!ret) { 46 + U_LOG_E("Failed to encode metrics message!"); 47 + return; 48 + } 49 + 50 + os_mutex_lock(&g_file_mutex); 51 + 52 + fwrite(buffer, stream.bytes_written, 1, g_file); 53 + 54 + os_mutex_unlock(&g_file_mutex); 55 + } 56 + 57 + static void 58 + write_version(uint32_t major, uint32_t minor) 59 + { 60 + if (!g_metrics_initialized) { 61 + return; 62 + } 63 + 64 + monado_metrics_Record record = monado_metrics_Record_init_default; 65 + 66 + // Select which filed is used. 67 + record.which_record = monado_metrics_Record_version_tag; 68 + record.record.version.major = major; 69 + record.record.version.minor = minor; 70 + 71 + write_record(&record); 72 + } 73 + 74 + 75 + /* 76 + * 77 + * 'Exported' functions. 78 + * 79 + */ 80 + 81 + void 82 + u_metrics_init() 83 + { 84 + const char *str = debug_get_option_metrics_file(); 85 + if (str == NULL) { 86 + U_LOG_D("No metrics file!"); 87 + return; 88 + } 89 + 90 + g_file = fopen(str, "wb"); 91 + if (g_file == NULL) { 92 + U_LOG_E("Could not open '%s'!", str); 93 + return; 94 + } 95 + 96 + os_mutex_init(&g_file_mutex); 97 + 98 + g_metrics_initialized = true; 99 + 100 + write_version(VERSION_MAJOR, VERSION_MINOR); 101 + 102 + U_LOG_I("Opened metrics file: '%s'", str); 103 + } 104 + 105 + void 106 + u_metrics_close() 107 + { 108 + if (!g_metrics_initialized) { 109 + return; 110 + } 111 + 112 + U_LOG_I("Closing metrics file: '%s'", debug_get_option_metrics_file()); 113 + 114 + // At least try to avoid races. 115 + os_mutex_lock(&g_file_mutex); 116 + fflush(g_file); 117 + fclose(g_file); 118 + g_file = NULL; 119 + os_mutex_unlock(&g_file_mutex); 120 + 121 + os_mutex_destroy(&g_file_mutex); 122 + 123 + g_metrics_initialized = false; 124 + } 125 + 126 + bool 127 + u_metrics_is_active(void) 128 + { 129 + return g_metrics_initialized; 130 + } 131 + 132 + void 133 + u_metrics_write_session_frame(struct u_metrics_session_frame *umsf) 134 + { 135 + if (!g_metrics_initialized) { 136 + return; 137 + } 138 + 139 + monado_metrics_Record record = monado_metrics_Record_init_default; 140 + 141 + // Select which filed is used. 142 + record.which_record = monado_metrics_Record_session_frame_tag; 143 + 144 + #define COPY(_0, _1, _2, _3, FIELD, _4) (record.record.session_frame.FIELD = umsf->FIELD); 145 + monado_metrics_SessionFrame_FIELDLIST(COPY, 0); 146 + #undef COPY 147 + 148 + 149 + write_record(&record); 150 + } 151 + 152 + void 153 + u_metrics_write_used(struct u_metrics_used *umu) 154 + { 155 + if (!g_metrics_initialized) { 156 + return; 157 + } 158 + 159 + monado_metrics_Record record = monado_metrics_Record_init_default; 160 + 161 + // Select which filed is used. 162 + record.which_record = monado_metrics_Record_used_tag; 163 + 164 + #define COPY(_0, _1, _2, _3, FIELD, _4) (record.record.used.FIELD = umu->FIELD); 165 + monado_metrics_Used_FIELDLIST(COPY, 0); 166 + #undef COPY 167 + 168 + 169 + write_record(&record); 170 + } 171 + 172 + void 173 + u_metrics_write_system_frame(struct u_metrics_system_frame *umsf) 174 + { 175 + if (!g_metrics_initialized) { 176 + return; 177 + } 178 + 179 + monado_metrics_Record record = monado_metrics_Record_init_default; 180 + 181 + // Select which filed is used. 182 + record.which_record = monado_metrics_Record_system_frame_tag; 183 + 184 + #define COPY(_0, _1, _2, _3, FIELD, _4) (record.record.system_frame.FIELD = umsf->FIELD); 185 + monado_metrics_SystemFrame_FIELDLIST(COPY, 0); 186 + #undef COPY 187 + 188 + 189 + write_record(&record); 190 + } 191 + 192 + void 193 + u_metrics_write_system_gpu_info(struct u_metrics_system_gpu_info *umgi) 194 + { 195 + if (!g_metrics_initialized) { 196 + return; 197 + } 198 + 199 + monado_metrics_Record record = monado_metrics_Record_init_default; 200 + 201 + // Select which filed is used. 202 + record.which_record = monado_metrics_Record_system_gpu_info_tag; 203 + 204 + #define COPY(_0, _1, _2, _3, FIELD, _4) (record.record.system_gpu_info.FIELD = umgi->FIELD); 205 + monado_metrics_SystemGpuInfo_FIELDLIST(COPY, 0); 206 + #undef COPY 207 + 208 + 209 + write_record(&record); 210 + } 211 + 212 + void 213 + u_metrics_write_system_present_info(struct u_metrics_system_present_info *umpi) 214 + { 215 + if (!g_metrics_initialized) { 216 + return; 217 + } 218 + 219 + monado_metrics_Record record = monado_metrics_Record_init_default; 220 + 221 + // Select which filed is used. 222 + record.which_record = monado_metrics_Record_system_present_info_tag; 223 + 224 + #define COPY(_0, _1, _2, _3, FIELD, _4) (record.record.system_present_info.FIELD = umpi->FIELD); 225 + monado_metrics_SystemPresentInfo_FIELDLIST(COPY, 0); 226 + #undef COPY 227 + 228 + 229 + write_record(&record); 230 + }
+110
src/xrt/auxiliary/util/u_metrics.h
··· 1 + // Copyright 2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Metrics saving functions. 6 + * @author Jakob Bornecrantz <jakob@collabora.com> 7 + * @ingroup aux_util 8 + */ 9 + 10 + #pragma once 11 + 12 + #include "xrt/xrt_compiler.h" 13 + 14 + 15 + #ifdef __cplusplus 16 + extern "C" { 17 + #endif 18 + 19 + struct u_metrics_session_frame 20 + { 21 + int64_t session_id; 22 + int64_t frame_id; 23 + uint64_t predicted_frame_time_ns; 24 + uint64_t predicted_wake_up_time_ns; 25 + uint64_t predicted_gpu_done_time_ns; 26 + uint64_t predicted_display_time_ns; 27 + uint64_t predicted_display_period_ns; 28 + uint64_t display_time_ns; 29 + uint64_t when_predicted_ns; 30 + uint64_t when_wait_woke_ns; 31 + uint64_t when_begin_ns; 32 + uint64_t when_delivered_ns; 33 + uint64_t when_gpu_done_ns; 34 + bool discarded; 35 + }; 36 + 37 + struct u_metrics_used 38 + { 39 + int64_t session_id; 40 + int64_t session_frame_id; 41 + int64_t system_frame_id; 42 + uint64_t when_ns; 43 + }; 44 + 45 + struct u_metrics_system_frame 46 + { 47 + int64_t frame_id; 48 + uint64_t predicted_display_time_ns; 49 + uint64_t predicted_display_period_ns; 50 + uint64_t desired_present_time_ns; 51 + uint64_t wake_up_time_ns; 52 + uint64_t present_slop_ns; 53 + }; 54 + 55 + struct u_metrics_system_gpu_info 56 + { 57 + int64_t frame_id; 58 + uint64_t gpu_start_ns; 59 + uint64_t gpu_end_ns; 60 + uint64_t when_ns; 61 + }; 62 + 63 + struct u_metrics_system_present_info 64 + { 65 + int64_t frame_id; 66 + uint64_t expected_comp_time_ns; 67 + uint64_t predicted_wake_up_time_ns; 68 + uint64_t predicted_done_time_ns; 69 + uint64_t predicted_display_time_ns; 70 + uint64_t when_predict_ns; 71 + uint64_t when_woke_ns; 72 + uint64_t when_began_ns; 73 + uint64_t when_submitted_ns; 74 + uint64_t when_infoed_ns; 75 + uint64_t desired_present_time_ns; 76 + uint64_t present_slop_ns; 77 + uint64_t present_margin_ns; 78 + uint64_t actual_present_time_ns; 79 + uint64_t earliest_present_time_ns; 80 + }; 81 + 82 + 83 + void 84 + u_metrics_init(void); 85 + 86 + void 87 + u_metrics_close(void); 88 + 89 + bool 90 + u_metrics_is_active(void); 91 + 92 + void 93 + u_metrics_write_session_frame(struct u_metrics_session_frame *umsf); 94 + 95 + void 96 + u_metrics_write_used(struct u_metrics_used *umu); 97 + 98 + void 99 + u_metrics_write_system_frame(struct u_metrics_system_frame *umsf); 100 + 101 + void 102 + u_metrics_write_system_gpu_info(struct u_metrics_system_gpu_info *umgi); 103 + 104 + void 105 + u_metrics_write_system_present_info(struct u_metrics_system_present_info *umpi); 106 + 107 + 108 + #ifdef __cplusplus 109 + } 110 + #endif