root/drivers/gpu/drm/amd/display/modules/stats/stats.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mod_stats_init
  2. mod_stats_create
  3. mod_stats_destroy
  4. mod_stats_dump
  5. mod_stats_reset_data
  6. mod_stats_update_event
  7. mod_stats_update_flip
  8. mod_stats_update_vupdate
  9. mod_stats_update_freesync

   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 
  44 struct 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 
  71 struct stats_event_cache {
  72         unsigned int entry_id;
  73         char event_string[MOD_STATS_EVENT_STRING_MAX];
  74 };
  75 
  76 struct 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 
  96 bool 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 
 111 struct 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 
 174 fail_construct_events:
 175         kfree(core_stats->time);
 176 
 177 fail_construct_time:
 178         kfree(core_stats);
 179 
 180 fail_construct:
 181         return NULL;
 182 }
 183 
 184 void 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 
 195 void 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 
 272 void 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 
 296 void 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 
 328 void 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 
 371 void 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 
 414 void 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 

/* [<][>][^][v][top][bottom][index][help] */