Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.2-rc6 448 lines 12 kB view raw
1/* 2 * Copyright 2016 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26#include "mod_stats.h" 27#include "dm_services.h" 28#include "dc.h" 29#include "core_types.h" 30 31#define DAL_STATS_ENABLE_REGKEY "DalStatsEnable" 32#define DAL_STATS_ENABLE_REGKEY_DEFAULT 0x00000000 33#define DAL_STATS_ENABLE_REGKEY_ENABLED 0x00000001 34 35#define DAL_STATS_ENTRIES_REGKEY "DalStatsEntries" 36#define DAL_STATS_ENTRIES_REGKEY_DEFAULT 0x00350000 37#define DAL_STATS_ENTRIES_REGKEY_MAX 0x01000000 38 39#define DAL_STATS_EVENT_ENTRIES_DEFAULT 0x00000100 40 41#define MOD_STATS_NUM_VSYNCS 5 42#define MOD_STATS_EVENT_STRING_MAX 512 43 44struct stats_time_cache { 45 unsigned int entry_id; 46 47 unsigned long flip_timestamp_in_ns; 48 unsigned long vupdate_timestamp_in_ns; 49 50 unsigned int render_time_in_us; 51 unsigned int avg_render_time_in_us_last_ten; 52 unsigned int v_sync_time_in_us[MOD_STATS_NUM_VSYNCS]; 53 unsigned int num_vsync_between_flips; 54 55 unsigned int flip_to_vsync_time_in_us; 56 unsigned int vsync_to_flip_time_in_us; 57 58 unsigned int min_window; 59 unsigned int max_window; 60 unsigned int v_total_min; 61 unsigned int v_total_max; 62 unsigned int event_triggers; 63 64 unsigned int lfc_mid_point_in_us; 65 unsigned int num_frames_inserted; 66 unsigned int inserted_duration_in_us; 67 68 unsigned int flags; 69}; 70 71struct stats_event_cache { 72 unsigned int entry_id; 73 char event_string[MOD_STATS_EVENT_STRING_MAX]; 74}; 75 76struct core_stats { 77 struct mod_stats public; 78 struct dc *dc; 79 80 bool enabled; 81 unsigned int entries; 82 unsigned int event_entries; 83 unsigned int entry_id; 84 85 struct stats_time_cache *time; 86 unsigned int index; 87 88 struct stats_event_cache *events; 89 unsigned int event_index; 90 91}; 92 93#define MOD_STATS_TO_CORE(mod_stats)\ 94 container_of(mod_stats, struct core_stats, public) 95 96bool mod_stats_init(struct mod_stats *mod_stats) 97{ 98 bool result = false; 99 struct core_stats *core_stats = NULL; 100 struct dc *dc = NULL; 101 102 if (mod_stats == NULL) 103 return false; 104 105 core_stats = MOD_STATS_TO_CORE(mod_stats); 106 dc = core_stats->dc; 107 108 return result; 109} 110 111struct mod_stats *mod_stats_create(struct dc *dc) 112{ 113 struct core_stats *core_stats = NULL; 114 struct persistent_data_flag flag; 115 unsigned int reg_data; 116 int i = 0; 117 118 if (dc == NULL) 119 goto fail_construct; 120 121 core_stats = kzalloc(sizeof(struct core_stats), GFP_KERNEL); 122 123 if (core_stats == NULL) 124 goto fail_construct; 125 126 core_stats->dc = dc; 127 128 core_stats->enabled = DAL_STATS_ENABLE_REGKEY_DEFAULT; 129 if (dm_read_persistent_data(dc->ctx, NULL, NULL, 130 DAL_STATS_ENABLE_REGKEY, 131 &reg_data, sizeof(unsigned int), &flag)) 132 core_stats->enabled = reg_data; 133 134 if (core_stats->enabled) { 135 core_stats->entries = DAL_STATS_ENTRIES_REGKEY_DEFAULT; 136 if (dm_read_persistent_data(dc->ctx, NULL, NULL, 137 DAL_STATS_ENTRIES_REGKEY, 138 &reg_data, sizeof(unsigned int), &flag)) { 139 if (reg_data > DAL_STATS_ENTRIES_REGKEY_MAX) 140 core_stats->entries = DAL_STATS_ENTRIES_REGKEY_MAX; 141 else 142 core_stats->entries = reg_data; 143 } 144 core_stats->time = kcalloc(core_stats->entries, 145 sizeof(struct stats_time_cache), 146 GFP_KERNEL); 147 148 if (core_stats->time == NULL) 149 goto fail_construct_time; 150 151 core_stats->event_entries = DAL_STATS_EVENT_ENTRIES_DEFAULT; 152 core_stats->events = kcalloc(core_stats->event_entries, 153 sizeof(struct stats_event_cache), 154 GFP_KERNEL); 155 156 if (core_stats->events == NULL) 157 goto fail_construct_events; 158 159 } else { 160 core_stats->entries = 0; 161 } 162 163 /* Purposely leave index 0 unused so we don't need special logic to 164 * handle calculation cases that depend on previous flip data. 165 */ 166 core_stats->index = 1; 167 core_stats->event_index = 0; 168 169 // Keeps track of ordering within the different stats structures 170 core_stats->entry_id = 0; 171 172 return &core_stats->public; 173 174fail_construct_events: 175 kfree(core_stats->time); 176 177fail_construct_time: 178 kfree(core_stats); 179 180fail_construct: 181 return NULL; 182} 183 184void mod_stats_destroy(struct mod_stats *mod_stats) 185{ 186 if (mod_stats != NULL) { 187 struct core_stats *core_stats = MOD_STATS_TO_CORE(mod_stats); 188 189 kfree(core_stats->time); 190 kfree(core_stats->events); 191 kfree(core_stats); 192 } 193} 194 195void mod_stats_dump(struct mod_stats *mod_stats) 196{ 197 struct dc *dc = NULL; 198 struct dal_logger *logger = NULL; 199 struct core_stats *core_stats = NULL; 200 struct stats_time_cache *time = NULL; 201 struct stats_event_cache *events = NULL; 202 unsigned int time_index = 1; 203 unsigned int event_index = 0; 204 unsigned int index = 0; 205 struct log_entry log_entry; 206 207 if (mod_stats == NULL) 208 return; 209 210 core_stats = MOD_STATS_TO_CORE(mod_stats); 211 dc = core_stats->dc; 212 logger = dc->ctx->logger; 213 time = core_stats->time; 214 events = core_stats->events; 215 216 DISPLAY_STATS_BEGIN(log_entry); 217 218 DISPLAY_STATS("==Display Caps==\n"); 219 220 DISPLAY_STATS("==Display Stats==\n"); 221 222 DISPLAY_STATS("%10s %10s %10s %10s %10s" 223 " %11s %11s %17s %10s %14s" 224 " %10s %10s %10s %10s %10s" 225 " %10s %10s %10s %10s\n", 226 "render", "avgRender", 227 "minWindow", "midPoint", "maxWindow", 228 "vsyncToFlip", "flipToVsync", "vsyncsBetweenFlip", 229 "numFrame", "insertDuration", 230 "vTotalMin", "vTotalMax", "eventTrigs", 231 "vSyncTime1", "vSyncTime2", "vSyncTime3", 232 "vSyncTime4", "vSyncTime5", "flags"); 233 234 for (int i = 0; i < core_stats->entry_id; i++) { 235 if (event_index < core_stats->event_index && 236 i == events[event_index].entry_id) { 237 DISPLAY_STATS("==Event==%s\n", events[event_index].event_string); 238 event_index++; 239 } else if (time_index < core_stats->index && 240 i == time[time_index].entry_id) { 241 DISPLAY_STATS("%10u %10u %10u %10u %10u" 242 " %11u %11u %17u %10u %14u" 243 " %10u %10u %10u %10u %10u" 244 " %10u %10u %10u %10u\n", 245 time[time_index].render_time_in_us, 246 time[time_index].avg_render_time_in_us_last_ten, 247 time[time_index].min_window, 248 time[time_index].lfc_mid_point_in_us, 249 time[time_index].max_window, 250 time[time_index].vsync_to_flip_time_in_us, 251 time[time_index].flip_to_vsync_time_in_us, 252 time[time_index].num_vsync_between_flips, 253 time[time_index].num_frames_inserted, 254 time[time_index].inserted_duration_in_us, 255 time[time_index].v_total_min, 256 time[time_index].v_total_max, 257 time[time_index].event_triggers, 258 time[time_index].v_sync_time_in_us[0], 259 time[time_index].v_sync_time_in_us[1], 260 time[time_index].v_sync_time_in_us[2], 261 time[time_index].v_sync_time_in_us[3], 262 time[time_index].v_sync_time_in_us[4], 263 time[time_index].flags); 264 265 time_index++; 266 } 267 } 268 269 DISPLAY_STATS_END(log_entry); 270} 271 272void mod_stats_reset_data(struct mod_stats *mod_stats) 273{ 274 struct core_stats *core_stats = NULL; 275 struct stats_time_cache *time = NULL; 276 unsigned int index = 0; 277 278 if (mod_stats == NULL) 279 return; 280 281 core_stats = MOD_STATS_TO_CORE(mod_stats); 282 283 memset(core_stats->time, 0, 284 sizeof(struct stats_time_cache) * core_stats->entries); 285 286 memset(core_stats->events, 0, 287 sizeof(struct stats_event_cache) * core_stats->event_entries); 288 289 core_stats->index = 1; 290 core_stats->event_index = 0; 291 292 // Keeps track of ordering within the different stats structures 293 core_stats->entry_id = 0; 294} 295 296void mod_stats_update_event(struct mod_stats *mod_stats, 297 char *event_string, 298 unsigned int length) 299{ 300 struct core_stats *core_stats = NULL; 301 struct stats_event_cache *events = NULL; 302 unsigned int index = 0; 303 unsigned int copy_length = 0; 304 305 if (mod_stats == NULL) 306 return; 307 308 core_stats = MOD_STATS_TO_CORE(mod_stats); 309 310 if (core_stats->event_index >= core_stats->event_entries) 311 return; 312 313 events = core_stats->events; 314 index = core_stats->event_index; 315 316 copy_length = length; 317 if (length > MOD_STATS_EVENT_STRING_MAX) 318 copy_length = MOD_STATS_EVENT_STRING_MAX; 319 320 memcpy(&events[index].event_string, event_string, copy_length); 321 events[index].event_string[copy_length - 1] = '\0'; 322 323 events[index].entry_id = core_stats->entry_id; 324 core_stats->event_index++; 325 core_stats->entry_id++; 326} 327 328void mod_stats_update_flip(struct mod_stats *mod_stats, 329 unsigned long timestamp_in_ns) 330{ 331 struct core_stats *core_stats = NULL; 332 struct stats_time_cache *time = NULL; 333 unsigned int index = 0; 334 335 if (mod_stats == NULL) 336 return; 337 338 core_stats = MOD_STATS_TO_CORE(mod_stats); 339 340 if (core_stats->index >= core_stats->entries) 341 return; 342 343 time = core_stats->time; 344 index = core_stats->index; 345 346 time[index].flip_timestamp_in_ns = timestamp_in_ns; 347 time[index].render_time_in_us = 348 (timestamp_in_ns - time[index - 1].flip_timestamp_in_ns) / 1000; 349 350 if (index >= 10) { 351 for (unsigned int i = 0; i < 10; i++) 352 time[index].avg_render_time_in_us_last_ten += 353 time[index - i].render_time_in_us; 354 time[index].avg_render_time_in_us_last_ten /= 10; 355 } 356 357 if (time[index].num_vsync_between_flips > 0) 358 time[index].vsync_to_flip_time_in_us = 359 (timestamp_in_ns - 360 time[index].vupdate_timestamp_in_ns) / 1000; 361 else 362 time[index].vsync_to_flip_time_in_us = 363 (timestamp_in_ns - 364 time[index - 1].vupdate_timestamp_in_ns) / 1000; 365 366 time[index].entry_id = core_stats->entry_id; 367 core_stats->index++; 368 core_stats->entry_id++; 369} 370 371void mod_stats_update_vupdate(struct mod_stats *mod_stats, 372 unsigned long timestamp_in_ns) 373{ 374 struct core_stats *core_stats = NULL; 375 struct stats_time_cache *time = NULL; 376 unsigned int index = 0; 377 unsigned int num_vsyncs = 0; 378 unsigned int prev_vsync_in_ns = 0; 379 380 if (mod_stats == NULL) 381 return; 382 383 core_stats = MOD_STATS_TO_CORE(mod_stats); 384 385 if (core_stats->index >= core_stats->entries) 386 return; 387 388 time = core_stats->time; 389 index = core_stats->index; 390 num_vsyncs = time[index].num_vsync_between_flips; 391 392 if (num_vsyncs < MOD_STATS_NUM_VSYNCS) { 393 if (num_vsyncs == 0) { 394 prev_vsync_in_ns = 395 time[index - 1].vupdate_timestamp_in_ns; 396 397 time[index].flip_to_vsync_time_in_us = 398 (timestamp_in_ns - 399 time[index - 1].flip_timestamp_in_ns) / 400 1000; 401 } else { 402 prev_vsync_in_ns = 403 time[index].vupdate_timestamp_in_ns; 404 } 405 406 time[index].v_sync_time_in_us[num_vsyncs] = 407 (timestamp_in_ns - prev_vsync_in_ns) / 1000; 408 } 409 410 time[index].vupdate_timestamp_in_ns = timestamp_in_ns; 411 time[index].num_vsync_between_flips++; 412} 413 414void mod_stats_update_freesync(struct mod_stats *mod_stats, 415 unsigned int v_total_min, 416 unsigned int v_total_max, 417 unsigned int event_triggers, 418 unsigned int window_min, 419 unsigned int window_max, 420 unsigned int lfc_mid_point_in_us, 421 unsigned int inserted_frames, 422 unsigned int inserted_duration_in_us) 423{ 424 struct core_stats *core_stats = NULL; 425 struct stats_time_cache *time = NULL; 426 unsigned int index = 0; 427 428 if (mod_stats == NULL) 429 return; 430 431 core_stats = MOD_STATS_TO_CORE(mod_stats); 432 433 if (core_stats->index >= core_stats->entries) 434 return; 435 436 time = core_stats->time; 437 index = core_stats->index; 438 439 time[index].v_total_min = v_total_min; 440 time[index].v_total_max = v_total_max; 441 time[index].event_triggers = event_triggers; 442 time[index].min_window = window_min; 443 time[index].max_window = window_max; 444 time[index].lfc_mid_point_in_us = lfc_mid_point_in_us; 445 time[index].num_frames_inserted = inserted_frames; 446 time[index].inserted_duration_in_us = inserted_duration_in_us; 447} 448