1 // Copyright (C) 2023 Huawei Device Co., Ltd. 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 mod apps; 15 mod direction; 16 mod rss; 17 18 use apps::SortedApps; 19 pub(crate) use direction::{QosChanges, QosDirection, QosLevel}; 20 pub(crate) use rss::RssCapacity; 21 22 use super::state; 23 use crate::manage::database::TaskQosInfo; 24 use crate::task::config::Action; 25 26 pub(crate) struct Qos { 27 pub(crate) apps: SortedApps, 28 capacity: RssCapacity, 29 } 30 31 impl Qos { new() -> Self32 pub(crate) fn new() -> Self { 33 Self { 34 apps: SortedApps::init(), 35 capacity: RssCapacity::LEVEL0, 36 } 37 } 38 39 // qos 里包含upload和download,通过empty确认哪些需要更新。 start_task(&mut self, uid: u64, task: TaskQosInfo)40 pub(crate) fn start_task(&mut self, uid: u64, task: TaskQosInfo) { 41 // Only tasks that can run automatically can be added to the qos queue. 42 self.apps.insert_task(uid, task); 43 } 44 remove_task(&mut self, uid: u64, task_id: u32) -> bool45 pub(crate) fn remove_task(&mut self, uid: u64, task_id: u32) -> bool { 46 self.apps.remove_task(uid, task_id) 47 } 48 reload_all_tasks(&mut self)49 pub(crate) fn reload_all_tasks(&mut self) { 50 self.apps.reload_all_tasks(); 51 } 52 change_rss(&mut self, rss: RssCapacity)53 pub(crate) fn change_rss(&mut self, rss: RssCapacity) { 54 self.capacity = rss; 55 } 56 } 57 58 impl Qos { 59 // Reschedule qos queue and get directions. reschedule(&mut self, state: &state::Handler) -> QosChanges60 pub(crate) fn reschedule(&mut self, state: &state::Handler) -> QosChanges { 61 self.apps 62 .sort(state.foreground_abilities(), state.top_user()); 63 let mut changes = QosChanges::new(); 64 changes.download = Some(self.reschedule_inner(Action::Download)); 65 changes.upload = Some(self.reschedule_inner(Action::Upload)); 66 changes 67 } 68 reschedule_inner(&mut self, action: Action) -> Vec<QosDirection>69 fn reschedule_inner(&mut self, action: Action) -> Vec<QosDirection> { 70 let m1 = self.capacity.m1(); 71 let m1_speed = self.capacity.m1_speed(); 72 let m2 = self.capacity.m2(); 73 let m2_speed = self.capacity.m2_speed(); 74 let m3 = self.capacity.m3(); 75 let m3_speed = self.capacity.m3_speed(); 76 77 let mut count = 0; 78 let mut app_i = 0; 79 let mut task_i = 0; 80 81 let mut qos_vec = Vec::new(); 82 83 for (i, task) in self.apps.iter().enumerate().flat_map(|(i, app)| { 84 if !app.is_empty() { 85 app_i = i; 86 } 87 app.iter().enumerate() 88 }) { 89 if task.action() != action { 90 continue; 91 } 92 if count < m1 { 93 qos_vec.push(QosDirection::new(task.uid(), task.task_id(), m1_speed)); 94 } else if count < m1 + m2 { 95 qos_vec.push(QosDirection::new(task.uid(), task.task_id(), m2_speed)); 96 } 97 count += 1; 98 if count == m1 + m2 { 99 task_i = i; 100 break; 101 } 102 } 103 104 // Here if the number of all uncompleted tasks is less than `m1 + m2`, 105 // we don not need to adjust `m3` position. 106 if count < m1 + m2 { 107 return qos_vec; 108 } 109 110 // The filtering logic for fair position is executed as follows: 111 // Each app will take turns taking one task to execute until the 112 // fair position is filled. 113 let mut i = 0; 114 115 loop { 116 let mut no_tasks_left = true; 117 118 for tasks in self.apps.iter().skip(app_i + 1).map(|app| &app[..]) { 119 let task = match tasks.get(i) { 120 Some(task) => { 121 no_tasks_left = false; 122 task 123 } 124 None => continue, 125 }; 126 127 if task.action() != action { 128 continue; 129 } 130 131 if count < m1 + m2 + m3 { 132 qos_vec.push(QosDirection::new(task.uid(), task.task_id(), m3_speed)); 133 } else { 134 return qos_vec; 135 } 136 137 count += 1; 138 } 139 140 if no_tasks_left { 141 break; 142 } 143 i += 1; 144 } 145 146 // supplement fair position with remaining tasks 147 for task in self 148 .apps 149 .iter() 150 .skip(app_i) 151 .take(1) 152 .flat_map(|app| app.iter().skip(task_i + 1)) 153 { 154 if task.action() != action { 155 continue; 156 } 157 158 if count < m1 + m2 + m3 { 159 qos_vec.push(QosDirection::new(task.uid(), task.task_id(), m3_speed)); 160 } else { 161 return qos_vec; 162 } 163 count += 1; 164 } 165 qos_vec 166 } 167 } 168