diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/modules/stats/stats.c')
| -rw-r--r-- | drivers/gpu/drm/amd/display/modules/stats/stats.c | 254 |
1 files changed, 187 insertions, 67 deletions
diff --git a/drivers/gpu/drm/amd/display/modules/stats/stats.c b/drivers/gpu/drm/amd/display/modules/stats/stats.c index 041f87b73d5f..3f7d47fdc367 100644 --- a/drivers/gpu/drm/amd/display/modules/stats/stats.c +++ b/drivers/gpu/drm/amd/display/modules/stats/stats.c | |||
| @@ -36,9 +36,14 @@ | |||
| 36 | #define DAL_STATS_ENTRIES_REGKEY_DEFAULT 0x00350000 | 36 | #define DAL_STATS_ENTRIES_REGKEY_DEFAULT 0x00350000 |
| 37 | #define DAL_STATS_ENTRIES_REGKEY_MAX 0x01000000 | 37 | #define DAL_STATS_ENTRIES_REGKEY_MAX 0x01000000 |
| 38 | 38 | ||
| 39 | #define DAL_STATS_EVENT_ENTRIES_DEFAULT 0x00000100 | ||
| 40 | |||
| 39 | #define MOD_STATS_NUM_VSYNCS 5 | 41 | #define MOD_STATS_NUM_VSYNCS 5 |
| 42 | #define MOD_STATS_EVENT_STRING_MAX 512 | ||
| 40 | 43 | ||
| 41 | struct stats_time_cache { | 44 | struct stats_time_cache { |
| 45 | unsigned int entry_id; | ||
| 46 | |||
| 42 | unsigned long flip_timestamp_in_ns; | 47 | unsigned long flip_timestamp_in_ns; |
| 43 | unsigned long vupdate_timestamp_in_ns; | 48 | unsigned long vupdate_timestamp_in_ns; |
| 44 | 49 | ||
| @@ -63,15 +68,26 @@ struct stats_time_cache { | |||
| 63 | unsigned int flags; | 68 | unsigned int flags; |
| 64 | }; | 69 | }; |
| 65 | 70 | ||
| 71 | struct stats_event_cache { | ||
| 72 | unsigned int entry_id; | ||
| 73 | char event_string[MOD_STATS_EVENT_STRING_MAX]; | ||
| 74 | }; | ||
| 75 | |||
| 66 | struct core_stats { | 76 | struct core_stats { |
| 67 | struct mod_stats public; | 77 | struct mod_stats public; |
| 68 | struct dc *dc; | 78 | struct dc *dc; |
| 69 | 79 | ||
| 80 | bool enabled; | ||
| 81 | unsigned int entries; | ||
| 82 | unsigned int event_entries; | ||
| 83 | unsigned int entry_id; | ||
| 84 | |||
| 70 | struct stats_time_cache *time; | 85 | struct stats_time_cache *time; |
| 71 | unsigned int index; | 86 | unsigned int index; |
| 72 | 87 | ||
| 73 | bool enabled; | 88 | struct stats_event_cache *events; |
| 74 | unsigned int entries; | 89 | unsigned int event_index; |
| 90 | |||
| 75 | }; | 91 | }; |
| 76 | 92 | ||
| 77 | #define MOD_STATS_TO_CORE(mod_stats)\ | 93 | #define MOD_STATS_TO_CORE(mod_stats)\ |
| @@ -99,12 +115,12 @@ struct mod_stats *mod_stats_create(struct dc *dc) | |||
| 99 | unsigned int reg_data; | 115 | unsigned int reg_data; |
| 100 | int i = 0; | 116 | int i = 0; |
| 101 | 117 | ||
| 118 | if (dc == NULL) | ||
| 119 | goto fail_construct; | ||
| 120 | |||
| 102 | core_stats = kzalloc(sizeof(struct core_stats), GFP_KERNEL); | 121 | core_stats = kzalloc(sizeof(struct core_stats), GFP_KERNEL); |
| 103 | 122 | ||
| 104 | if (core_stats == NULL) | 123 | if (core_stats == NULL) |
| 105 | goto fail_alloc_context; | ||
| 106 | |||
| 107 | if (dc == NULL) | ||
| 108 | goto fail_construct; | 124 | goto fail_construct; |
| 109 | 125 | ||
| 110 | core_stats->dc = dc; | 126 | core_stats->dc = dc; |
| @@ -115,33 +131,55 @@ struct mod_stats *mod_stats_create(struct dc *dc) | |||
| 115 | ®_data, sizeof(unsigned int), &flag)) | 131 | ®_data, sizeof(unsigned int), &flag)) |
| 116 | core_stats->enabled = reg_data; | 132 | core_stats->enabled = reg_data; |
| 117 | 133 | ||
| 118 | core_stats->entries = DAL_STATS_ENTRIES_REGKEY_DEFAULT; | 134 | if (core_stats->enabled) { |
| 119 | if (dm_read_persistent_data(dc->ctx, NULL, NULL, | 135 | core_stats->entries = DAL_STATS_ENTRIES_REGKEY_DEFAULT; |
| 120 | DAL_STATS_ENTRIES_REGKEY, | 136 | if (dm_read_persistent_data(dc->ctx, NULL, NULL, |
| 121 | ®_data, sizeof(unsigned int), &flag)) { | 137 | DAL_STATS_ENTRIES_REGKEY, |
| 122 | if (reg_data > DAL_STATS_ENTRIES_REGKEY_MAX) | 138 | ®_data, sizeof(unsigned int), &flag)) { |
| 123 | core_stats->entries = DAL_STATS_ENTRIES_REGKEY_MAX; | 139 | if (reg_data > DAL_STATS_ENTRIES_REGKEY_MAX) |
| 124 | else | 140 | core_stats->entries = DAL_STATS_ENTRIES_REGKEY_MAX; |
| 125 | core_stats->entries = reg_data; | 141 | else |
| 126 | } | 142 | core_stats->entries = reg_data; |
| 143 | } | ||
| 144 | core_stats->time = kzalloc( | ||
| 145 | sizeof(struct stats_time_cache) * | ||
| 146 | core_stats->entries, | ||
| 147 | GFP_KERNEL); | ||
| 127 | 148 | ||
| 128 | core_stats->time = kzalloc(sizeof(struct stats_time_cache) * core_stats->entries, | 149 | if (core_stats->time == NULL) |
| 129 | GFP_KERNEL); | 150 | goto fail_construct_time; |
| 130 | 151 | ||
| 131 | if (core_stats->time == NULL) | 152 | core_stats->event_entries = DAL_STATS_EVENT_ENTRIES_DEFAULT; |
| 132 | goto fail_construct; | 153 | core_stats->events = kzalloc( |
| 154 | sizeof(struct stats_event_cache) * | ||
| 155 | core_stats->event_entries, | ||
| 156 | GFP_KERNEL); | ||
| 157 | |||
| 158 | if (core_stats->events == NULL) | ||
| 159 | goto fail_construct_events; | ||
| 160 | |||
| 161 | } else { | ||
| 162 | core_stats->entries = 0; | ||
| 163 | } | ||
| 133 | 164 | ||
| 134 | /* Purposely leave index 0 unused so we don't need special logic to | 165 | /* Purposely leave index 0 unused so we don't need special logic to |
| 135 | * handle calculation cases that depend on previous flip data. | 166 | * handle calculation cases that depend on previous flip data. |
| 136 | */ | 167 | */ |
| 137 | core_stats->index = 1; | 168 | core_stats->index = 1; |
| 169 | core_stats->event_index = 0; | ||
| 170 | |||
| 171 | // Keeps track of ordering within the different stats structures | ||
| 172 | core_stats->entry_id = 0; | ||
| 138 | 173 | ||
| 139 | return &core_stats->public; | 174 | return &core_stats->public; |
| 140 | 175 | ||
| 141 | fail_construct: | 176 | fail_construct_events: |
| 177 | kfree(core_stats->time); | ||
| 178 | |||
| 179 | fail_construct_time: | ||
| 142 | kfree(core_stats); | 180 | kfree(core_stats); |
| 143 | 181 | ||
| 144 | fail_alloc_context: | 182 | fail_construct: |
| 145 | return NULL; | 183 | return NULL; |
| 146 | } | 184 | } |
| 147 | 185 | ||
| @@ -153,6 +191,9 @@ void mod_stats_destroy(struct mod_stats *mod_stats) | |||
| 153 | if (core_stats->time != NULL) | 191 | if (core_stats->time != NULL) |
| 154 | kfree(core_stats->time); | 192 | kfree(core_stats->time); |
| 155 | 193 | ||
| 194 | if (core_stats->events != NULL) | ||
| 195 | kfree(core_stats->events); | ||
| 196 | |||
| 156 | kfree(core_stats); | 197 | kfree(core_stats); |
| 157 | } | 198 | } |
| 158 | } | 199 | } |
| @@ -163,7 +204,11 @@ void mod_stats_dump(struct mod_stats *mod_stats) | |||
| 163 | struct dal_logger *logger = NULL; | 204 | struct dal_logger *logger = NULL; |
| 164 | struct core_stats *core_stats = NULL; | 205 | struct core_stats *core_stats = NULL; |
| 165 | struct stats_time_cache *time = NULL; | 206 | struct stats_time_cache *time = NULL; |
| 207 | struct stats_event_cache *events = NULL; | ||
| 208 | unsigned int time_index = 1; | ||
| 209 | unsigned int event_index = 0; | ||
| 166 | unsigned int index = 0; | 210 | unsigned int index = 0; |
| 211 | struct log_entry log_entry; | ||
| 167 | 212 | ||
| 168 | if (mod_stats == NULL) | 213 | if (mod_stats == NULL) |
| 169 | return; | 214 | return; |
| @@ -172,45 +217,62 @@ void mod_stats_dump(struct mod_stats *mod_stats) | |||
| 172 | dc = core_stats->dc; | 217 | dc = core_stats->dc; |
| 173 | logger = dc->ctx->logger; | 218 | logger = dc->ctx->logger; |
| 174 | time = core_stats->time; | 219 | time = core_stats->time; |
| 175 | 220 | events = core_stats->events; | |
| 176 | //LogEntry* pLog = GetLog()->Open(LogMajor_ISR, LogMinor_ISR_FreeSyncSW); | 221 | |
| 177 | 222 | DISPLAY_STATS_BEGIN(log_entry); | |
| 178 | //if (!pLog->IsDummyEntry()) | 223 | |
| 179 | { | 224 | DISPLAY_STATS("==Display Caps==\n"); |
| 180 | dm_logger_write(logger, LOG_PROFILING, "==Display Caps==\n"); | 225 | |
| 181 | dm_logger_write(logger, LOG_PROFILING, "\n"); | 226 | DISPLAY_STATS("==Display Stats==\n"); |
| 182 | dm_logger_write(logger, LOG_PROFILING, "\n"); | 227 | |
| 183 | 228 | DISPLAY_STATS("%10s %10s %10s %10s %10s" | |
| 184 | dm_logger_write(logger, LOG_PROFILING, "==Stats==\n"); | 229 | " %11s %11s %17s %10s %14s" |
| 185 | dm_logger_write(logger, LOG_PROFILING, | 230 | " %10s %10s %10s %10s %10s" |
| 186 | "render avgRender minWindow midPoint maxWindow vsyncToFlip flipToVsync #vsyncBetweenFlip #frame insertDuration vTotalMin vTotalMax eventTrigs vSyncTime1 vSyncTime2 vSyncTime3 vSyncTime4 vSyncTime5 flags\n"); | 231 | " %10s %10s %10s %10s\n", |
| 187 | 232 | "render", "avgRender", | |
| 188 | for (int i = 0; i < core_stats->index && i < core_stats->entries; i++) { | 233 | "minWindow", "midPoint", "maxWindow", |
| 189 | dm_logger_write(logger, LOG_PROFILING, | 234 | "vsyncToFlip", "flipToVsync", "vsyncsBetweenFlip", |
| 190 | "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u\n", | 235 | "numFrame", "insertDuration", |
| 191 | time[i].render_time_in_us, | 236 | "vTotalMin", "vTotalMax", "eventTrigs", |
| 192 | time[i].avg_render_time_in_us_last_ten, | 237 | "vSyncTime1", "vSyncTime2", "vSyncTime3", |
| 193 | time[i].min_window, | 238 | "vSyncTime4", "vSyncTime5", "flags"); |
| 194 | time[i].lfc_mid_point_in_us, | 239 | |
| 195 | time[i].max_window, | 240 | for (int i = 0; i < core_stats->entry_id; i++) { |
| 196 | time[i].vsync_to_flip_time_in_us, | 241 | if (event_index < core_stats->event_index && |
| 197 | time[i].flip_to_vsync_time_in_us, | 242 | i == events[event_index].entry_id) { |
| 198 | time[i].num_vsync_between_flips, | 243 | DISPLAY_STATS("%s\n", events[event_index].event_string); |
| 199 | time[i].num_frames_inserted, | 244 | event_index++; |
| 200 | time[i].inserted_duration_in_us, | 245 | } else if (time_index < core_stats->index && |
| 201 | time[i].v_total_min, | 246 | i == time[time_index].entry_id) { |
| 202 | time[i].v_total_max, | 247 | DISPLAY_STATS("%10u %10u %10u %10u %10u" |
| 203 | time[i].event_triggers, | 248 | " %11u %11u %17u %10u %14u" |
| 204 | time[i].v_sync_time_in_us[0], | 249 | " %10u %10u %10u %10u %10u" |
| 205 | time[i].v_sync_time_in_us[1], | 250 | " %10u %10u %10u %10u\n", |
| 206 | time[i].v_sync_time_in_us[2], | 251 | time[time_index].render_time_in_us, |
| 207 | time[i].v_sync_time_in_us[3], | 252 | time[time_index].avg_render_time_in_us_last_ten, |
| 208 | time[i].v_sync_time_in_us[4], | 253 | time[time_index].min_window, |
| 209 | time[i].flags); | 254 | time[time_index].lfc_mid_point_in_us, |
| 255 | time[time_index].max_window, | ||
| 256 | time[time_index].vsync_to_flip_time_in_us, | ||
| 257 | time[time_index].flip_to_vsync_time_in_us, | ||
| 258 | time[time_index].num_vsync_between_flips, | ||
| 259 | time[time_index].num_frames_inserted, | ||
| 260 | time[time_index].inserted_duration_in_us, | ||
| 261 | time[time_index].v_total_min, | ||
| 262 | time[time_index].v_total_max, | ||
| 263 | time[time_index].event_triggers, | ||
| 264 | time[time_index].v_sync_time_in_us[0], | ||
| 265 | time[time_index].v_sync_time_in_us[1], | ||
| 266 | time[time_index].v_sync_time_in_us[2], | ||
| 267 | time[time_index].v_sync_time_in_us[3], | ||
| 268 | time[time_index].v_sync_time_in_us[4], | ||
| 269 | time[time_index].flags); | ||
| 270 | |||
| 271 | time_index++; | ||
| 210 | } | 272 | } |
| 211 | } | 273 | } |
| 212 | //GetLog()->Close(pLog); | 274 | |
| 213 | //GetLog()->UnSetLogMask(LogMajor_ISR, LogMinor_ISR_FreeSyncSW); | 275 | DISPLAY_STATS_END(log_entry); |
| 214 | } | 276 | } |
| 215 | 277 | ||
| 216 | void mod_stats_reset_data(struct mod_stats *mod_stats) | 278 | void mod_stats_reset_data(struct mod_stats *mod_stats) |
| @@ -227,7 +289,46 @@ void mod_stats_reset_data(struct mod_stats *mod_stats) | |||
| 227 | memset(core_stats->time, 0, | 289 | memset(core_stats->time, 0, |
| 228 | sizeof(struct stats_time_cache) * core_stats->entries); | 290 | sizeof(struct stats_time_cache) * core_stats->entries); |
| 229 | 291 | ||
| 230 | core_stats->index = 0; | 292 | memset(core_stats->events, 0, |
| 293 | sizeof(struct stats_event_cache) * core_stats->event_entries); | ||
| 294 | |||
| 295 | core_stats->index = 1; | ||
| 296 | core_stats->event_index = 0; | ||
| 297 | |||
| 298 | // Keeps track of ordering within the different stats structures | ||
| 299 | core_stats->entry_id = 0; | ||
| 300 | } | ||
| 301 | |||
| 302 | void mod_stats_update_event(struct mod_stats *mod_stats, | ||
| 303 | char *event_string, | ||
| 304 | unsigned int length) | ||
| 305 | { | ||
| 306 | struct core_stats *core_stats = NULL; | ||
| 307 | struct stats_event_cache *events = NULL; | ||
| 308 | unsigned int index = 0; | ||
| 309 | unsigned int copy_length = 0; | ||
| 310 | |||
| 311 | if (mod_stats == NULL) | ||
| 312 | return; | ||
| 313 | |||
| 314 | core_stats = MOD_STATS_TO_CORE(mod_stats); | ||
| 315 | |||
| 316 | if (core_stats->event_index >= core_stats->event_entries) | ||
| 317 | return; | ||
| 318 | |||
| 319 | events = core_stats->events; | ||
| 320 | index = core_stats->event_index; | ||
| 321 | |||
| 322 | copy_length = length; | ||
| 323 | if (length > MOD_STATS_EVENT_STRING_MAX) | ||
| 324 | copy_length = MOD_STATS_EVENT_STRING_MAX; | ||
| 325 | |||
| 326 | memcpy(&events[index].event_string, event_string, copy_length); | ||
| 327 | events[index].event_string[copy_length - 1] = '\0'; | ||
| 328 | |||
| 329 | events[index].entry_id = core_stats->entry_id; | ||
| 330 | core_stats->event_index++; | ||
| 331 | core_stats->entry_id++; | ||
| 231 | } | 332 | } |
| 232 | 333 | ||
| 233 | void mod_stats_update_flip(struct mod_stats *mod_stats, | 334 | void mod_stats_update_flip(struct mod_stats *mod_stats, |
| @@ -250,7 +351,7 @@ void mod_stats_update_flip(struct mod_stats *mod_stats, | |||
| 250 | 351 | ||
| 251 | time[index].flip_timestamp_in_ns = timestamp_in_ns; | 352 | time[index].flip_timestamp_in_ns = timestamp_in_ns; |
| 252 | time[index].render_time_in_us = | 353 | time[index].render_time_in_us = |
| 253 | timestamp_in_ns - time[index - 1].flip_timestamp_in_ns; | 354 | (timestamp_in_ns - time[index - 1].flip_timestamp_in_ns) / 1000; |
| 254 | 355 | ||
| 255 | if (index >= 10) { | 356 | if (index >= 10) { |
| 256 | for (unsigned int i = 0; i < 10; i++) | 357 | for (unsigned int i = 0; i < 10; i++) |
| @@ -261,12 +362,16 @@ void mod_stats_update_flip(struct mod_stats *mod_stats, | |||
| 261 | 362 | ||
| 262 | if (time[index].num_vsync_between_flips > 0) | 363 | if (time[index].num_vsync_between_flips > 0) |
| 263 | time[index].vsync_to_flip_time_in_us = | 364 | time[index].vsync_to_flip_time_in_us = |
| 264 | timestamp_in_ns - time[index].vupdate_timestamp_in_ns; | 365 | (timestamp_in_ns - |
| 366 | time[index].vupdate_timestamp_in_ns) / 1000; | ||
| 265 | else | 367 | else |
| 266 | time[index].vsync_to_flip_time_in_us = | 368 | time[index].vsync_to_flip_time_in_us = |
| 267 | timestamp_in_ns - time[index - 1].vupdate_timestamp_in_ns; | 369 | (timestamp_in_ns - |
| 370 | time[index - 1].vupdate_timestamp_in_ns) / 1000; | ||
| 268 | 371 | ||
| 372 | time[index].entry_id = core_stats->entry_id; | ||
| 269 | core_stats->index++; | 373 | core_stats->index++; |
| 374 | core_stats->entry_id++; | ||
| 270 | } | 375 | } |
| 271 | 376 | ||
| 272 | void mod_stats_update_vupdate(struct mod_stats *mod_stats, | 377 | void mod_stats_update_vupdate(struct mod_stats *mod_stats, |
| @@ -275,6 +380,8 @@ void mod_stats_update_vupdate(struct mod_stats *mod_stats, | |||
| 275 | struct core_stats *core_stats = NULL; | 380 | struct core_stats *core_stats = NULL; |
| 276 | struct stats_time_cache *time = NULL; | 381 | struct stats_time_cache *time = NULL; |
| 277 | unsigned int index = 0; | 382 | unsigned int index = 0; |
| 383 | unsigned int num_vsyncs = 0; | ||
| 384 | unsigned int prev_vsync_in_ns = 0; | ||
| 278 | 385 | ||
| 279 | if (mod_stats == NULL) | 386 | if (mod_stats == NULL) |
| 280 | return; | 387 | return; |
| @@ -286,14 +393,27 @@ void mod_stats_update_vupdate(struct mod_stats *mod_stats, | |||
| 286 | 393 | ||
| 287 | time = core_stats->time; | 394 | time = core_stats->time; |
| 288 | index = core_stats->index; | 395 | index = core_stats->index; |
| 396 | num_vsyncs = time[index].num_vsync_between_flips; | ||
| 397 | |||
| 398 | if (num_vsyncs < MOD_STATS_NUM_VSYNCS) { | ||
| 399 | if (num_vsyncs == 0) { | ||
| 400 | prev_vsync_in_ns = | ||
| 401 | time[index - 1].vupdate_timestamp_in_ns; | ||
| 402 | |||
| 403 | time[index].flip_to_vsync_time_in_us = | ||
| 404 | (timestamp_in_ns - | ||
| 405 | time[index - 1].flip_timestamp_in_ns) / | ||
| 406 | 1000; | ||
| 407 | } else { | ||
| 408 | prev_vsync_in_ns = | ||
| 409 | time[index].vupdate_timestamp_in_ns; | ||
| 410 | } | ||
| 289 | 411 | ||
| 290 | time[index].vupdate_timestamp_in_ns = timestamp_in_ns; | 412 | time[index].v_sync_time_in_us[num_vsyncs] = |
| 291 | if (time[index].num_vsync_between_flips < MOD_STATS_NUM_VSYNCS) | 413 | (timestamp_in_ns - prev_vsync_in_ns) / 1000; |
| 292 | time[index].v_sync_time_in_us[time[index].num_vsync_between_flips] = | 414 | } |
| 293 | timestamp_in_ns - time[index - 1].vupdate_timestamp_in_ns; | ||
| 294 | time[index].flip_to_vsync_time_in_us = | ||
| 295 | timestamp_in_ns - time[index - 1].flip_timestamp_in_ns; | ||
| 296 | 415 | ||
| 416 | time[index].vupdate_timestamp_in_ns = timestamp_in_ns; | ||
| 297 | time[index].num_vsync_between_flips++; | 417 | time[index].num_vsync_between_flips++; |
| 298 | } | 418 | } |
| 299 | 419 | ||
