[Intel-gfx] [PATCH 1/3] drm/i915/guc: Support new and improved engine busyness
John Harrison
john.c.harrison at intel.com
Fri Oct 6 22:28:15 UTC 2023
On 10/3/2023 13:58, Umesh Nerlige Ramappa wrote:
> On Fri, Sep 22, 2023 at 03:25:08PM -0700, John.C.Harrison at Intel.com
> wrote:
>> From: John Harrison <John.C.Harrison at Intel.com>
>>
>> The GuC has been extended to support a much more friendly engine
>> busyness interface. So partition the old interface into a 'busy_v1'
>> space and add 'busy_v2' support alongside. And if v2 is available, use
>> that in preference to v1. Note that v2 provides extra features over
>> and above v1 which will be exposed via PMU in subsequent patches.
>
> Since we are thinking of using the existing busyness counter to expose
> the v2 values, we can drop the last sentence from above.
>
>>
>> Signed-off-by: John Harrison <John.C.Harrison at Intel.com>
>> ---
>> drivers/gpu/drm/i915/gt/intel_engine_types.h | 4 +-
>> .../gpu/drm/i915/gt/uc/abi/guc_actions_abi.h | 4 +-
>> drivers/gpu/drm/i915/gt/uc/intel_guc.h | 82 ++--
>> drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 55 ++-
>> drivers/gpu/drm/i915/gt/uc/intel_guc_ads.h | 9 +-
>> drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h | 23 +-
>> .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 381 ++++++++++++++----
>> 7 files changed, 427 insertions(+), 131 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h
>> b/drivers/gpu/drm/i915/gt/intel_engine_types.h
>> index a7e6775980043..40fd8f984d64b 100644
>> --- a/drivers/gpu/drm/i915/gt/intel_engine_types.h
>> +++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h
>> @@ -323,7 +323,7 @@ struct intel_engine_execlists_stats {
>> ktime_t start;
>> };
>>
>> -struct intel_engine_guc_stats {
>> +struct intel_engine_guc_stats_v1 {
>> /**
>> * @running: Active state of the engine when busyness was last
>> sampled.
>> */
>> @@ -603,7 +603,7 @@ struct intel_engine_cs {
>> struct {
>> union {
>> struct intel_engine_execlists_stats execlists;
>> - struct intel_engine_guc_stats guc;
>> + struct intel_engine_guc_stats_v1 guc_v1;
>> };
>
> Overall, I would suggest having the renames as a separate patch. Would
> make the review easier.
>
>>
>> /**
>> diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
>> b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
>> index f359bef046e0b..c190a99a36c38 100644
>> --- a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
>> +++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
>> @@ -137,7 +137,9 @@ enum intel_guc_action {
>> INTEL_GUC_ACTION_DEREGISTER_CONTEXT_DONE = 0x4600,
>> INTEL_GUC_ACTION_REGISTER_CONTEXT_MULTI_LRC = 0x4601,
>> INTEL_GUC_ACTION_CLIENT_SOFT_RESET = 0x5507,
>> - INTEL_GUC_ACTION_SET_ENG_UTIL_BUFF = 0x550A,
>> + INTEL_GUC_ACTION_SET_ENG_UTIL_BUFF_V1 = 0x550A,
>> + INTEL_GUC_ACTION_SET_DEVICE_ENGINE_UTILIZATION_V2 = 0x550C,
>> + INTEL_GUC_ACTION_SET_FUNCTION_ENGINE_UTILIZATION_V2 = 0x550D,
>> INTEL_GUC_ACTION_STATE_CAPTURE_NOTIFICATION = 0x8002,
>> INTEL_GUC_ACTION_NOTIFY_FLUSH_LOG_BUFFER_TO_FILE = 0x8003,
>> INTEL_GUC_ACTION_NOTIFY_CRASH_DUMP_POSTED = 0x8004,
>> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
>> b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
>> index 6c392bad29c19..e6502ab5f049f 100644
>> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
>> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
>> @@ -226,45 +226,61 @@ struct intel_guc {
>> struct mutex send_mutex;
>>
>> /**
>> - * @timestamp: GT timestamp object that stores a copy of the
>> timestamp
>> - * and adjusts it for overflow using a worker.
>> + * @busy: Data used by the different versions of engine busyness
>> implementations.
>> */
>> - struct {
>> - /**
>> - * @lock: Lock protecting the below fields and the engine
>> stats.
>> - */
>> - spinlock_t lock;
>> -
>> - /**
>> - * @gt_stamp: 64 bit extended value of the GT timestamp.
>> - */
>> - u64 gt_stamp;
>> -
>> - /**
>> - * @ping_delay: Period for polling the GT timestamp for
>> - * overflow.
>> - */
>> - unsigned long ping_delay;
>> -
>> - /**
>> - * @work: Periodic work to adjust GT timestamp, engine and
>> - * context usage for overflows.
>> - */
>> - struct delayed_work work;
>> -
>> + union {
>> /**
>> - * @shift: Right shift value for the gpm timestamp
>> + * @v1: Data used by v1 engine busyness implementation.
>> Mostly a copy
>> + * of the GT timestamp extended to 64 bits and the worker
>> for maintaining it.
>> */
>> - u32 shift;
>> + struct {
>> + /**
>> + * @lock: Lock protecting the below fields and the
>> engine stats.
>> + */
>> + spinlock_t lock;
>> +
>> + /**
>> + * @gt_stamp: 64 bit extended value of the GT timestamp.
>> + */
>> + u64 gt_stamp;
>> +
>> + /**
>> + * @ping_delay: Period for polling the GT timestamp for
>> + * overflow.
>> + */
>> + unsigned long ping_delay;
>> +
>> + /**
>> + * @work: Periodic work to adjust GT timestamp, engine and
>> + * context usage for overflows.
>> + */
>> + struct delayed_work work;
>> +
>> + /**
>> + * @shift: Right shift value for the gpm timestamp
>> + */
>> + u32 shift;
>> +
>> + /**
>> + * @last_stat_jiffies: jiffies at last actual stats
>> collection time
>> + * We use this timestamp to ensure we don't oversample the
>> + * stats because runtime power management events can
>> trigger
>> + * stats collection at much higher rates than required.
>> + */
>> + unsigned long last_stat_jiffies;
>> + } v1;
>>
>> /**
>> - * @last_stat_jiffies: jiffies at last actual stats
>> collection time
>> - * We use this timestamp to ensure we don't oversample the
>> - * stats because runtime power management events can trigger
>> - * stats collection at much higher rates than required.
>> + * @v2: Data used by v2 engine busyness implementation - a
>> memory object
>> + * that is filled in by the GuC and read by the driver.
>> */
>> - unsigned long last_stat_jiffies;
>> - } timestamp;
>> + struct {
>> + /** @device_vma: object allocated to hold the device
>> level busyness data */
>> + struct i915_vma *device_vma;
>> + /** @device_map: access object for @device_vma */
>> + struct iosys_map device_map;
>> + } v2;
>> + } busy;
>>
>> /**
>> * @dead_guc_worker: Asynchronous worker thread for forcing a GuC
>> reset.
>> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
>> b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
>> index 63724e17829a7..1ce595d6816f7 100644
>> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
>> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
>> @@ -59,7 +59,10 @@ struct __guc_ads_blob {
>> struct guc_ads ads;
>> struct guc_policies policies;
>> struct guc_gt_system_info system_info;
>> - struct guc_engine_usage engine_usage;
>> + union {
>> + struct guc_engine_usage v1;
>> + struct guc_function_observation_data v2;
>> + } engine_usage;
>> /* From here on, location is dynamic! Refer to above diagram. */
>> struct guc_mmio_reg regset[];
>> } __packed;
>> @@ -948,18 +951,62 @@ void intel_guc_ads_reset(struct intel_guc *guc)
>> guc_ads_private_data_reset(guc);
>> }
>>
>> -u32 intel_guc_engine_usage_offset(struct intel_guc *guc)
>> +u32 intel_guc_engine_usage_offset_pf(struct intel_guc *guc)
>> {
>> return intel_guc_ggtt_offset(guc, guc->ads_vma) +
>> offsetof(struct __guc_ads_blob, engine_usage);
>> }
>>
>> -struct iosys_map intel_guc_engine_usage_record_map(struct
>> intel_engine_cs *engine)
>> +struct iosys_map intel_guc_engine_usage_record_map_v1(struct
>> intel_engine_cs *engine)
>> {
>> struct intel_guc *guc = &engine->gt->uc.guc;
>> u8 guc_class = engine_class_to_guc_class(engine->class);
>> size_t offset = offsetof(struct __guc_ads_blob,
>> - engine_usage.engines[guc_class][ilog2(engine->logical_mask)]);
>> + engine_usage.v1.engines[guc_class][ilog2(engine->logical_mask)]);
>>
>> return IOSYS_MAP_INIT_OFFSET(&guc->ads_map, offset);
>> }
>> +
>> +int intel_guc_engine_usage_record_map_v2(struct intel_guc *guc,
>> + struct intel_engine_cs *engine,
>> + u32 guc_vf,
>> + struct iosys_map *engine_map,
>> + struct iosys_map *global_map)
>> +{
>> + size_t offset_global, offset_engine;
>> + struct iosys_map *map;
>> + u32 instance;
>> + u8 guc_class;
>> +
>> + if (engine) {
>
> engine is not being passed as NULL in this patch, so we can drop the
> checks in this function.
>
>> + guc_class = engine_class_to_guc_class(engine->class);
>> + instance = ilog2(engine->logical_mask);
>> + }
>> +
>> + if (guc_vf >= GUC_MAX_VF_COUNT) {
>
> Is it possible to split the code in if/else blocks into seperate
> functions and do away with using guc_vf == ~0U to switch between the 2
> logics.
This was the clearest way of organising it that didn't have checkpatch
complaining about annoying things.
>
>> + if (guc_vf != ~0U) {
>> + guc_err(guc, "Out of range VF in busyness query:
>> 0x%X\n", guc_vf);
>> + return -EINVAL;
>> + }
>> +
>> + map = &guc->busy.v2.device_map;
>> + offset_global = 0;
>> +
>> + if (engine)
>> + offset_engine = offsetof(struct
>> guc_engine_observation_data,
>> + engine_data[guc_class][instance]);
>> + } else {
>> + map = &guc->ads_map;
>> + offset_global = offsetof(struct __guc_ads_blob,
>> + engine_usage.v2.function_data[guc_vf]);
>> + if (engine)
>> + offset_engine = offsetof(struct __guc_ads_blob,
>> +
>> engine_usage.v2.function_data[guc_vf].engine_data[guc_class][instance]);
>
> Recommending splitting the vf id based counter support to a future patch.
>
>> + }
>> +
>> + *global_map = IOSYS_MAP_INIT_OFFSET(map, offset_global);
>> + if (engine)
>> + *engine_map = IOSYS_MAP_INIT_OFFSET(map, offset_engine);
>> +
>> + return 0;
>> +}
>
> <snip>
>
>> +static void __busy_v2_get_engine_usage_record(struct intel_guc *guc,
>> + struct intel_engine_cs *engine,
>> + u64 *_ticks_engine, u64 *_ticks_function,
>> + u64 *_ticks_gt)
>> +{
>> + struct iosys_map rec_map_engine, rec_map_global;
>> + u64 ticks_engine, ticks_function, ticks_gt;
>> + int i = 0, ret;
>> +
>> + ret = intel_guc_engine_usage_record_map_v2(guc, engine, ~0U,
>> + &rec_map_engine, &rec_map_global);
>> + if (ret) {
>> + ticks_engine = 0;
>> + ticks_function = 0;
>> + ticks_gt = 0;
>> + goto done;
>> + }
>> +
>> +#define record_read_engine(map_, field_) \
>> + iosys_map_rd_field(map_, 0, struct guc_engine_data, field_)
>> +#define record_read_global(map_, field_) \
>> + iosys_map_rd_field(map_, 0, struct guc_engine_observation_data,
>> field_)
>> +
>> + do {
>> + if (engine)
>> + ticks_engine = record_read_engine(&rec_map_engine,
>> total_execution_ticks);
>> + ticks_function = record_read_global(&rec_map_global,
>> total_active_ticks);
>> + ticks_gt = record_read_global(&rec_map_global, gt_timestamp);
>> +
>> + if (engine && (record_read_engine(&rec_map_engine,
>> total_execution_ticks) !=
>> + ticks_engine))
>> + continue;
>> +
>
> engine record and global record could use separate functions, maybe like
> __busy_v2_get_engine_usage_record
> __busy_v2_get_global_usage_record
I originally had them split. But there is so much common code that it
was much simpler code-wise to have a single function.
John.
>
> Regards,
> Umesh
>
>
>> + if (record_read_global(&rec_map_global, total_active_ticks)
>> == ticks_function &&
>> + record_read_global(&rec_map_global, gt_timestamp) ==
>> ticks_gt)
>> + break;
>> + } while (++i < 6);
>> +
>> +#undef record_read_engine
>> +#undef record_read_global
>> +
>> +done:
>> + if (_ticks_engine)
>> + *_ticks_engine = ticks_engine;
>> + if (_ticks_function)
>> + *_ticks_function = ticks_function;
>> + if (_ticks_gt)
>> + *_ticks_gt = ticks_gt;
>> +}
>> +
>
> <snip>
More information about the Intel-gfx
mailing list