From: David Francis <David.Francis@xxxxxxx> [Why] A quick-and-dirty way of getting performance data for the amdgpu driver would make performance improvements easier [How] The PERF_TRACE functionality is a tic-toc style debug method. Put PERF_TRACE calls on either side of the code you want to test. PERF_TRACE requires access to struct dc_context. PERF_TRACE() will pick up the CTX macro, and PERF_TRACE_CTX(struct dc_context) allows you to pass the context explicitly. The last 20 results can be read through the debugfs entry amdgpu_perf_trace. Each result contains the time in ns and number of GPU read/writes since the result before it. In my experimentation, each PERF_TRACE() call uses at most 700ns Signed-off-by: David Francis <David.Francis@xxxxxxx> Reviewed-by: Tony Cheng <Tony.Cheng@xxxxxxx> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@xxxxxxx> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 +- .../drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 74 +++++++++++++++++++++- .../drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h | 2 +- .../drm/amd/display/amdgpu_dm/amdgpu_dm_services.c | 21 +++++- drivers/gpu/drm/amd/display/dc/core/dc.c | 36 +++++++++++ drivers/gpu/drm/amd/display/dc/dc_types.h | 22 +++++++ .../gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c | 4 +- drivers/gpu/drm/amd/display/dc/dm_services.h | 13 ++-- 8 files changed, 165 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 492230c41b4a..252bfe330c1e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -471,8 +471,8 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) } #if defined(CONFIG_DEBUG_FS) - if (dtn_debugfs_init(adev)) - DRM_ERROR("amdgpu: failed initialize dtn debugfs support.\n"); + if (amdgpu_dm_debugfs_init(adev)) + DRM_ERROR("amdgpu: failed to initialize dm debugfs entries.\n"); #endif DRM_DEBUG_DRIVER("KMS initialized.\n"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 0ef4a40d2247..6b73c0e6bf67 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -782,7 +782,63 @@ static ssize_t dtn_log_write( return size; } -int dtn_debugfs_init(struct amdgpu_device *adev) +static ssize_t perf_trace_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_device *adev = file_inode(f)->i_private; + struct perf_trace *trace = adev->dm.dc->ctx->perf_trace; + struct perf_trace_entry *entry; + char *rd_buf = NULL; + char *rd_buf_pos = NULL; + const uint32_t line_buf_size = 200; + const uint32_t rd_buf_size = line_buf_size * trace->num_entries; + int r; + int result = 0; + int i; + + if (*pos & 3 || size & 3) + return -EINVAL; + + rd_buf = kcalloc(rd_buf_size, sizeof(char), GFP_KERNEL); + if (!rd_buf) + return -EINVAL; + rd_buf_pos = rd_buf; + + rd_buf_pos += snprintf(rd_buf_pos, rd_buf_size, "PERF_TRACE:\n"); + + for (i = 0; i < trace->num_entries; i++) { + entry = &trace->entries[(trace->next_entry + i) % trace->num_entries]; + + if (strcmp(entry->func_name, "")) + rd_buf_pos += snprintf(rd_buf_pos, line_buf_size, "%s:%d Reads:%d\t Writes:%d\t ns:%lld\n", + entry->func_name, + entry->line_number, + entry->read_count, + entry->write_count, + entry->time_delta); + } + + while (size) { + if (*pos >= rd_buf_size) + break; + + r = put_user((*(rd_buf + result)), buf); + if (r) { + kfree(rd_buf); + return r; + } + + buf += 1; + size -= 1; + *pos += 1; + result += 1; + } + + kfree(rd_buf); + return result; +} + +int amdgpu_dm_debugfs_init(struct amdgpu_device *adev) { static const struct file_operations dtn_log_fops = { .owner = THIS_MODULE, @@ -791,6 +847,12 @@ int dtn_debugfs_init(struct amdgpu_device *adev) .llseek = default_llseek }; + static const struct file_operations perf_trace_fops = { + .owner = THIS_MODULE, + .read = perf_trace_read, + .llseek = default_llseek + }; + struct drm_minor *minor = adev->ddev->primary; struct dentry *root = minor->debugfs_root; @@ -801,5 +863,15 @@ int dtn_debugfs_init(struct amdgpu_device *adev) adev, &dtn_log_fops); + if (IS_ERR(ent)) + return PTR_ERR(ent); + + ent = debugfs_create_file( + "amdgpu_perf_trace", + 0644, + root, + adev, + &perf_trace_fops); + return PTR_ERR_OR_ZERO(ent); } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h index bdef1587b0a0..2d0cdbaa1a8e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h @@ -30,6 +30,6 @@ #include "amdgpu_dm.h" int connector_debugfs_init(struct amdgpu_dm_connector *connector); -int dtn_debugfs_init(struct amdgpu_device *adev); +int amdgpu_dm_debugfs_init(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index 516795342dd2..77699e752680 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -44,9 +44,28 @@ unsigned long long dm_get_elapse_time_in_ns(struct dc_context *ctx, return current_time_stamp - last_time_stamp; } -void dm_perf_trace_timestamp(const char *func_name, unsigned int line) +#ifdef CONFIG_DEBUG_FS +void dm_perf_trace_timestamp(const char *func_name, unsigned int line, struct dc_context *ctx) +{ + struct perf_trace *trace = ctx->perf_trace; + unsigned long long timestamp = ktime_get_raw_ns(); + + trace->entries[trace->next_entry].line_number = line; + strlcpy(trace->entries[trace->next_entry].func_name, func_name, 40); + trace->entries[trace->next_entry].read_count = trace->read_count; + trace->read_count = 0; + trace->entries[trace->next_entry].write_count = trace->write_count; + trace->write_count = 0; + trace->entries[trace->next_entry].time_delta = timestamp - trace->timestamp; + trace->timestamp = timestamp; + + trace->next_entry = (trace->next_entry + 1) % trace->num_entries; +} +#else +void dm_perf_trace_timestamp(const char *func_name, unsigned int line, struct dc_context *ctx) { } +#endif bool dm_write_persistent_data(struct dc_context *ctx, const struct dc_sink *sink, diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index a8d8358058ff..99db82802c62 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -500,6 +500,33 @@ void dc_link_disable_hpd(const struct dc_link *link) dc_link_dp_disable_hpd(link); } +static void perf_trace_destruct(struct perf_trace **trace) +{ + kfree(*trace); + *trace = NULL; +} + +static struct perf_trace *perf_trace_construct(struct dc_context *ctx) +{ + struct perf_trace *trace = kzalloc(sizeof(struct perf_trace), GFP_KERNEL); + uint32_t i; + + if (!trace) + return NULL; + + trace->next_entry = 0; + trace->timestamp = dm_get_timestamp(ctx); + trace->read_count = 0; + trace->write_count = 0; + trace->num_entries = AMDGPU_PERF_TRACE_NUM_ENTRIES; + for (i = 0; i < trace->num_entries; i++) { + trace->entries[i].line_number = 0; + trace->entries[i].read_count = 0; + trace->entries[i].time_delta = 0; + trace->entries[i].write_count = 0; + } + return trace; +} void dc_link_set_test_pattern(struct dc_link *link, enum dp_test_pattern test_pattern, @@ -534,6 +561,9 @@ static void destruct(struct dc *dc) if (dc->ctx->created_bios) dal_bios_parser_destroy(&dc->ctx->dc_bios); + if (dc->ctx->perf_trace) + perf_trace_destruct(&dc->ctx->perf_trace); + kfree(dc->ctx); dc->ctx = NULL; @@ -621,6 +651,12 @@ static bool construct(struct dc *dc, /* Create logger */ + dc_ctx->perf_trace = perf_trace_construct(dc_ctx); + if (!dc_ctx->perf_trace) { + dm_error("%s: failed to create perf_trace!\n", __func__); + goto fail; + } + dc_ctx->dce_environment = init_params->dce_environment; dc_version = resource_parse_asic_id(init_params->asic_id); diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 6e12d640d020..7aa54dd9dd74 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -73,6 +73,27 @@ struct hw_asic_id { void *atombios_base_address; }; +#ifndef AMDGPU_PERF_TRACE_NUM_ENTRIES +#define AMDGPU_PERF_TRACE_NUM_ENTRIES 20 +#endif + +struct perf_trace_entry { + unsigned long long time_delta; + uint32_t write_count; + uint32_t read_count; + uint32_t line_number; + char func_name[40]; +}; + +struct perf_trace { + uint32_t num_entries; + uint32_t next_entry; + struct perf_trace_entry entries[AMDGPU_PERF_TRACE_NUM_ENTRIES]; + unsigned long long timestamp; + uint32_t write_count; + uint32_t read_count; +}; + struct dc_context { struct dc *dc; @@ -85,6 +106,7 @@ struct dc_context { /* todo: below should probably move to dc. to facilitate removal * of AS we will store these here */ + struct perf_trace *perf_trace; enum dce_version dce_version; struct dc_bios *dc_bios; bool created_bios; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c index 97c059934feb..0f1f12de2a53 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c @@ -259,7 +259,7 @@ bool cm_helper_translate_curve_to_hw_format( if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS) return false; - PERF_TRACE(); + PERF_TRACE_CTX(output_tf->ctx); arr_points = lut_params->arr_points; rgb_resulted = lut_params->rgb_resulted; @@ -441,7 +441,7 @@ bool cm_helper_translate_curve_to_degamma_hw_format( if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS) return false; - PERF_TRACE(); + PERF_TRACE_CTX(output_tf->ctx); arr_points = lut_params->arr_points; rgb_resulted = lut_params->rgb_resulted; diff --git a/drivers/gpu/drm/amd/display/dc/dm_services.h b/drivers/gpu/drm/amd/display/dc/dm_services.h index 28128c02de00..a1d6c99a00b0 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_services.h +++ b/drivers/gpu/drm/amd/display/dc/dm_services.h @@ -70,7 +70,9 @@ static inline uint32_t dm_read_reg_func( } #endif value = cgs_read_register(ctx->cgs_device, address); - +#ifdef CONFIG_DEBUG_FS + ctx->perf_trace->read_count++; +#endif return value; } @@ -90,6 +92,9 @@ static inline void dm_write_reg_func( } #endif cgs_write_register(ctx->cgs_device, address, value); +#ifdef CONFIG_DEBUG_FS + ctx->perf_trace->write_count++; +#endif } static inline uint32_t dm_read_index_reg( @@ -351,9 +356,9 @@ unsigned long long dm_get_elapse_time_in_ns(struct dc_context *ctx, /* * performance tracing */ -void dm_perf_trace_timestamp(const char *func_name, unsigned int line); -#define PERF_TRACE() dm_perf_trace_timestamp(__func__, __LINE__) - +void dm_perf_trace_timestamp(const char *func_name, unsigned int line, struct dc_context *ctx); +#define PERF_TRACE() dm_perf_trace_timestamp(__func__, __LINE__, CTX) +#define PERF_TRACE_CTX(__context) dm_perf_trace_timestamp(__func__, __LINE__, __context) /* * Debug and verification hooks -- 2.14.1 _______________________________________________ amd-gfx mailing list amd-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/amd-gfx