mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	drm/i915/gt: Track the overall awake/busy time
Since we wake the GT up before executing a request, and go to sleep as soon as it is retired, the GT wake time not only represents how long the device is powered up, but also provides a summary, albeit an overestimate, of the device runtime (i.e. the rc0 time to compare against rc6 time). v2: s/busy/awake/ v3: software-gt-awake-time and I915_PMU_SOFTWARE_GT_AWAKE_TIME Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Matthew Brost <matthew.brost@intel.com> Reported-by: kernel test robot <oliver.sang@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20201215154456.13954-1-chris@chris-wilson.co.uk
This commit is contained in:
		
							parent
							
								
									e3ed90b822
								
							
						
					
					
						commit
						8c3b1ba0e7
					
				| @ -11,6 +11,7 @@ | |||||||
| #include "i915_drv.h" | #include "i915_drv.h" | ||||||
| #include "intel_gt.h" | #include "intel_gt.h" | ||||||
| #include "intel_gt_clock_utils.h" | #include "intel_gt_clock_utils.h" | ||||||
|  | #include "intel_gt_pm.h" | ||||||
| #include "intel_llc.h" | #include "intel_llc.h" | ||||||
| #include "intel_rc6.h" | #include "intel_rc6.h" | ||||||
| #include "intel_rps.h" | #include "intel_rps.h" | ||||||
| @ -558,7 +559,9 @@ static int rps_boost_show(struct seq_file *m, void *data) | |||||||
| 
 | 
 | ||||||
| 	seq_printf(m, "RPS enabled? %s\n", yesno(intel_rps_is_enabled(rps))); | 	seq_printf(m, "RPS enabled? %s\n", yesno(intel_rps_is_enabled(rps))); | ||||||
| 	seq_printf(m, "RPS active? %s\n", yesno(intel_rps_is_active(rps))); | 	seq_printf(m, "RPS active? %s\n", yesno(intel_rps_is_active(rps))); | ||||||
| 	seq_printf(m, "GPU busy? %s\n", yesno(gt->awake)); | 	seq_printf(m, "GPU busy? %s, %llums\n", | ||||||
|  | 		   yesno(gt->awake), | ||||||
|  | 		   ktime_to_ms(intel_gt_get_awake_time(gt))); | ||||||
| 	seq_printf(m, "Boosts outstanding? %d\n", | 	seq_printf(m, "Boosts outstanding? %d\n", | ||||||
| 		   atomic_read(&rps->num_waiters)); | 		   atomic_read(&rps->num_waiters)); | ||||||
| 	seq_printf(m, "Interactive? %d\n", READ_ONCE(rps->power.interactive)); | 	seq_printf(m, "Interactive? %d\n", READ_ONCE(rps->power.interactive)); | ||||||
|  | |||||||
| @ -39,6 +39,28 @@ static void user_forcewake(struct intel_gt *gt, bool suspend) | |||||||
| 	intel_gt_pm_put(gt); | 	intel_gt_pm_put(gt); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void runtime_begin(struct intel_gt *gt) | ||||||
|  | { | ||||||
|  | 	local_irq_disable(); | ||||||
|  | 	write_seqcount_begin(>->stats.lock); | ||||||
|  | 	gt->stats.start = ktime_get(); | ||||||
|  | 	gt->stats.active = true; | ||||||
|  | 	write_seqcount_end(>->stats.lock); | ||||||
|  | 	local_irq_enable(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void runtime_end(struct intel_gt *gt) | ||||||
|  | { | ||||||
|  | 	local_irq_disable(); | ||||||
|  | 	write_seqcount_begin(>->stats.lock); | ||||||
|  | 	gt->stats.active = false; | ||||||
|  | 	gt->stats.total = | ||||||
|  | 		ktime_add(gt->stats.total, | ||||||
|  | 			  ktime_sub(ktime_get(), gt->stats.start)); | ||||||
|  | 	write_seqcount_end(>->stats.lock); | ||||||
|  | 	local_irq_enable(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int __gt_unpark(struct intel_wakeref *wf) | static int __gt_unpark(struct intel_wakeref *wf) | ||||||
| { | { | ||||||
| 	struct intel_gt *gt = container_of(wf, typeof(*gt), wakeref); | 	struct intel_gt *gt = container_of(wf, typeof(*gt), wakeref); | ||||||
| @ -67,6 +89,7 @@ static int __gt_unpark(struct intel_wakeref *wf) | |||||||
| 	i915_pmu_gt_unparked(i915); | 	i915_pmu_gt_unparked(i915); | ||||||
| 
 | 
 | ||||||
| 	intel_gt_unpark_requests(gt); | 	intel_gt_unpark_requests(gt); | ||||||
|  | 	runtime_begin(gt); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| @ -79,6 +102,7 @@ static int __gt_park(struct intel_wakeref *wf) | |||||||
| 
 | 
 | ||||||
| 	GT_TRACE(gt, "\n"); | 	GT_TRACE(gt, "\n"); | ||||||
| 
 | 
 | ||||||
|  | 	runtime_end(gt); | ||||||
| 	intel_gt_park_requests(gt); | 	intel_gt_park_requests(gt); | ||||||
| 
 | 
 | ||||||
| 	i915_vma_parked(gt); | 	i915_vma_parked(gt); | ||||||
| @ -106,6 +130,7 @@ static const struct intel_wakeref_ops wf_ops = { | |||||||
| void intel_gt_pm_init_early(struct intel_gt *gt) | void intel_gt_pm_init_early(struct intel_gt *gt) | ||||||
| { | { | ||||||
| 	intel_wakeref_init(>->wakeref, gt->uncore->rpm, &wf_ops); | 	intel_wakeref_init(>->wakeref, gt->uncore->rpm, &wf_ops); | ||||||
|  | 	seqcount_mutex_init(>->stats.lock, >->wakeref.mutex); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void intel_gt_pm_init(struct intel_gt *gt) | void intel_gt_pm_init(struct intel_gt *gt) | ||||||
| @ -339,6 +364,30 @@ int intel_gt_runtime_resume(struct intel_gt *gt) | |||||||
| 	return intel_uc_runtime_resume(>->uc); | 	return intel_uc_runtime_resume(>->uc); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static ktime_t __intel_gt_get_awake_time(const struct intel_gt *gt) | ||||||
|  | { | ||||||
|  | 	ktime_t total = gt->stats.total; | ||||||
|  | 
 | ||||||
|  | 	if (gt->stats.active) | ||||||
|  | 		total = ktime_add(total, | ||||||
|  | 				  ktime_sub(ktime_get(), gt->stats.start)); | ||||||
|  | 
 | ||||||
|  | 	return total; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ktime_t intel_gt_get_awake_time(const struct intel_gt *gt) | ||||||
|  | { | ||||||
|  | 	unsigned int seq; | ||||||
|  | 	ktime_t total; | ||||||
|  | 
 | ||||||
|  | 	do { | ||||||
|  | 		seq = read_seqcount_begin(>->stats.lock); | ||||||
|  | 		total = __intel_gt_get_awake_time(gt); | ||||||
|  | 	} while (read_seqcount_retry(>->stats.lock, seq)); | ||||||
|  | 
 | ||||||
|  | 	return total; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) | #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) | ||||||
| #include "selftest_gt_pm.c" | #include "selftest_gt_pm.c" | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -58,6 +58,8 @@ int intel_gt_resume(struct intel_gt *gt); | |||||||
| void intel_gt_runtime_suspend(struct intel_gt *gt); | void intel_gt_runtime_suspend(struct intel_gt *gt); | ||||||
| int intel_gt_runtime_resume(struct intel_gt *gt); | int intel_gt_runtime_resume(struct intel_gt *gt); | ||||||
| 
 | 
 | ||||||
|  | ktime_t intel_gt_get_awake_time(const struct intel_gt *gt); | ||||||
|  | 
 | ||||||
| static inline bool is_mock_gt(const struct intel_gt *gt) | static inline bool is_mock_gt(const struct intel_gt *gt) | ||||||
| { | { | ||||||
| 	return I915_SELFTEST_ONLY(gt->awake == -ENODEV); | 	return I915_SELFTEST_ONLY(gt->awake == -ENODEV); | ||||||
|  | |||||||
| @ -87,6 +87,30 @@ struct intel_gt { | |||||||
| 
 | 
 | ||||||
| 	u32 pm_guc_events; | 	u32 pm_guc_events; | ||||||
| 
 | 
 | ||||||
|  | 	struct { | ||||||
|  | 		bool active; | ||||||
|  | 
 | ||||||
|  | 		/**
 | ||||||
|  | 		 * @lock: Lock protecting the below fields. | ||||||
|  | 		 */ | ||||||
|  | 		seqcount_mutex_t lock; | ||||||
|  | 
 | ||||||
|  | 		/**
 | ||||||
|  | 		 * @total: Total time this engine was busy. | ||||||
|  | 		 * | ||||||
|  | 		 * Accumulated time not counting the most recent block in cases | ||||||
|  | 		 * where engine is currently busy (active > 0). | ||||||
|  | 		 */ | ||||||
|  | 		ktime_t total; | ||||||
|  | 
 | ||||||
|  | 		/**
 | ||||||
|  | 		 * @start: Timestamp of the last idle to active transition. | ||||||
|  | 		 * | ||||||
|  | 		 * Idle is defined as active == 0, active is active > 0. | ||||||
|  | 		 */ | ||||||
|  | 		ktime_t start; | ||||||
|  | 	} stats; | ||||||
|  | 
 | ||||||
| 	struct intel_engine_cs *engine[I915_NUM_ENGINES]; | 	struct intel_engine_cs *engine[I915_NUM_ENGINES]; | ||||||
| 	struct intel_engine_cs *engine_class[MAX_ENGINE_CLASS + 1] | 	struct intel_engine_cs *engine_class[MAX_ENGINE_CLASS + 1] | ||||||
| 					    [MAX_ENGINE_INSTANCE + 1]; | 					    [MAX_ENGINE_INSTANCE + 1]; | ||||||
|  | |||||||
| @ -1314,9 +1314,10 @@ static int i915_engine_info(struct seq_file *m, void *unused) | |||||||
| 
 | 
 | ||||||
| 	wakeref = intel_runtime_pm_get(&i915->runtime_pm); | 	wakeref = intel_runtime_pm_get(&i915->runtime_pm); | ||||||
| 
 | 
 | ||||||
| 	seq_printf(m, "GT awake? %s [%d]\n", | 	seq_printf(m, "GT awake? %s [%d], %llums\n", | ||||||
| 		   yesno(i915->gt.awake), | 		   yesno(i915->gt.awake), | ||||||
| 		   atomic_read(&i915->gt.wakeref.count)); | 		   atomic_read(&i915->gt.wakeref.count), | ||||||
|  | 		   ktime_to_ms(intel_gt_get_awake_time(&i915->gt))); | ||||||
| 	seq_printf(m, "CS timestamp frequency: %u Hz\n", | 	seq_printf(m, "CS timestamp frequency: %u Hz\n", | ||||||
| 		   RUNTIME_INFO(i915)->cs_timestamp_frequency_hz); | 		   RUNTIME_INFO(i915)->cs_timestamp_frequency_hz); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -509,6 +509,8 @@ config_status(struct drm_i915_private *i915, u64 config) | |||||||
| 		if (!HAS_RC6(i915)) | 		if (!HAS_RC6(i915)) | ||||||
| 			return -ENODEV; | 			return -ENODEV; | ||||||
| 		break; | 		break; | ||||||
|  | 	case I915_PMU_SOFTWARE_GT_AWAKE_TIME: | ||||||
|  | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		return -ENOENT; | 		return -ENOENT; | ||||||
| 	} | 	} | ||||||
| @ -616,6 +618,9 @@ static u64 __i915_pmu_event_read(struct perf_event *event) | |||||||
| 		case I915_PMU_RC6_RESIDENCY: | 		case I915_PMU_RC6_RESIDENCY: | ||||||
| 			val = get_rc6(&i915->gt); | 			val = get_rc6(&i915->gt); | ||||||
| 			break; | 			break; | ||||||
|  | 		case I915_PMU_SOFTWARE_GT_AWAKE_TIME: | ||||||
|  | 			val = ktime_to_ns(intel_gt_get_awake_time(&i915->gt)); | ||||||
|  | 			break; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -916,6 +921,7 @@ create_event_attributes(struct i915_pmu *pmu) | |||||||
| 		__event(I915_PMU_REQUESTED_FREQUENCY, "requested-frequency", "M"), | 		__event(I915_PMU_REQUESTED_FREQUENCY, "requested-frequency", "M"), | ||||||
| 		__event(I915_PMU_INTERRUPTS, "interrupts", NULL), | 		__event(I915_PMU_INTERRUPTS, "interrupts", NULL), | ||||||
| 		__event(I915_PMU_RC6_RESIDENCY, "rc6-residency", "ns"), | 		__event(I915_PMU_RC6_RESIDENCY, "rc6-residency", "ns"), | ||||||
|  | 		__event(I915_PMU_SOFTWARE_GT_AWAKE_TIME, "software-gt-awake-time", "ns"), | ||||||
| 	}; | 	}; | ||||||
| 	static const struct { | 	static const struct { | ||||||
| 		enum drm_i915_pmu_engine_sample sample; | 		enum drm_i915_pmu_engine_sample sample; | ||||||
|  | |||||||
| @ -177,6 +177,7 @@ enum drm_i915_pmu_engine_sample { | |||||||
| #define I915_PMU_REQUESTED_FREQUENCY	__I915_PMU_OTHER(1) | #define I915_PMU_REQUESTED_FREQUENCY	__I915_PMU_OTHER(1) | ||||||
| #define I915_PMU_INTERRUPTS		__I915_PMU_OTHER(2) | #define I915_PMU_INTERRUPTS		__I915_PMU_OTHER(2) | ||||||
| #define I915_PMU_RC6_RESIDENCY		__I915_PMU_OTHER(3) | #define I915_PMU_RC6_RESIDENCY		__I915_PMU_OTHER(3) | ||||||
|  | #define I915_PMU_SOFTWARE_GT_AWAKE_TIME	__I915_PMU_OTHER(4) | ||||||
| 
 | 
 | ||||||
| #define I915_PMU_LAST /* Deprecated - do not use */ I915_PMU_RC6_RESIDENCY | #define I915_PMU_LAST /* Deprecated - do not use */ I915_PMU_RC6_RESIDENCY | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Chris Wilson
						Chris Wilson