drm/i915/gvt: add basic function for weight control
authorPing Gao <ping.a.gao@intel.com>
Thu, 30 Mar 2017 02:03:24 +0000 (10:03 +0800)
committerZhenyu Wang <zhenyuw@linux.intel.com>
Thu, 30 Mar 2017 05:34:04 +0000 (13:34 +0800)
This method tries to guarantee precision in second level, with the
adjustment conducted in every 100ms. At the end of each vGPU switch
calculate the sched time and subtract it from the time slice
allocated; the allocated time slice for every 100ms together with
remaining timeslice, will be used to decide how much timeslice
allocated to this vGPU in the next 100ms slice, with the end goal
to guarantee weight ratio in second level.

Signed-off-by: Ping Gao <ping.a.gao@intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
drivers/gpu/drm/i915/gvt/sched_policy.c

index 5aa7a2539e4d6f0415c4c0094df93dadea006593..dd5b38c3e4edde9b4d2bd64e5e68651d53cb52cb 100644 (file)
@@ -67,6 +67,60 @@ struct gvt_sched_data {
        struct list_head lru_runq_head;
 };
 
+static void vgpu_update_timeslice(struct intel_vgpu *pre_vgpu)
+{
+       ktime_t delta_ts;
+       struct vgpu_sched_data *vgpu_data = pre_vgpu->sched_data;
+
+       delta_ts = vgpu_data->sched_out_time - vgpu_data->sched_in_time;
+
+       vgpu_data->sched_time += delta_ts;
+       vgpu_data->left_ts -= delta_ts;
+}
+
+#define GVT_TS_BALANCE_PERIOD_MS 100
+#define GVT_TS_BALANCE_STAGE_NUM 10
+
+static void gvt_balance_timeslice(struct gvt_sched_data *sched_data)
+{
+       struct vgpu_sched_data *vgpu_data;
+       struct list_head *pos;
+       static uint64_t stage_check;
+       int stage = stage_check++ % GVT_TS_BALANCE_STAGE_NUM;
+
+       /* The timeslice accumulation reset at stage 0, which is
+        * allocated again without adding previous debt.
+        */
+       if (stage == 0) {
+               int total_weight = 0;
+               ktime_t fair_timeslice;
+
+               list_for_each(pos, &sched_data->lru_runq_head) {
+                       vgpu_data = container_of(pos, struct vgpu_sched_data, lru_list);
+                       total_weight += vgpu_data->sched_ctl.weight;
+               }
+
+               list_for_each(pos, &sched_data->lru_runq_head) {
+                       vgpu_data = container_of(pos, struct vgpu_sched_data, lru_list);
+                       fair_timeslice = ms_to_ktime(GVT_TS_BALANCE_PERIOD_MS) *
+                                               vgpu_data->sched_ctl.weight /
+                                               total_weight;
+
+                       vgpu_data->allocated_ts = fair_timeslice;
+                       vgpu_data->left_ts = vgpu_data->allocated_ts;
+               }
+       } else {
+               list_for_each(pos, &sched_data->lru_runq_head) {
+                       vgpu_data = container_of(pos, struct vgpu_sched_data, lru_list);
+
+                       /* timeslice for next 100ms should add the left/debt
+                        * slice of previous stages.
+                        */
+                       vgpu_data->left_ts += vgpu_data->allocated_ts;
+               }
+       }
+}
+
 static void try_to_schedule_next_vgpu(struct intel_gvt *gvt)
 {
        struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
@@ -103,6 +157,7 @@ static void try_to_schedule_next_vgpu(struct intel_gvt *gvt)
        if (scheduler->current_vgpu) {
                vgpu_data = scheduler->current_vgpu->sched_data;
                vgpu_data->sched_out_time = cur_time;
+               vgpu_update_timeslice(scheduler->current_vgpu);
        }
        vgpu_data = scheduler->next_vgpu->sched_data;
        vgpu_data->sched_in_time = cur_time;
@@ -148,6 +203,10 @@ static void tbs_sched_func(struct gvt_sched_data *sched_data)
        struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
        struct vgpu_sched_data *vgpu_data;
        struct intel_vgpu *vgpu = NULL;
+       static uint64_t timer_check;
+
+       if (!(timer_check++ % GVT_TS_BALANCE_PERIOD_MS))
+               gvt_balance_timeslice(sched_data);
 
        /* no active vgpu or has already had a target */
        if (list_empty(&sched_data->lru_runq_head) || scheduler->next_vgpu)