• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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