3535 *
3636 */
3737
38- #include < sys/types.h>
3938#include < dirent.h>
39+ #include < sys/types.h>
4040
4141#include < iostream>
4242#include < list>
5151#include < android-base/parseint.h>
5252#include < android-base/strings.h>
5353
54-
5554#define POLICY0_CORES_PATH " /sys/devices/system/cpu/cpufreq/policy0/affected_cpus"
5655#define SYSFS_IRQDIR " /sys/kernel/irq"
5756#define PROC_IRQDIR " /proc/irq"
@@ -70,158 +69,147 @@ using std::vector;
7069// Return a vector of strings describing the affected CPUs for cpufreq
7170// Policy 0.
7271vector<int > Policy0AffectedCpus () {
73- string policy0_cores_unparsed;
74- if (!ReadFileToString (POLICY0_CORES_PATH , &policy0_cores_unparsed))
75- return vector<int >();
76- string policy0_trimmed = android::base::Trim (policy0_cores_unparsed);
77- vector<string> cpus_as_string = android::base::Split (policy0_trimmed, " " );
78-
79- vector<int > cpus_as_int;
80- for (int i = 0 ; i < cpus_as_string.size (); ++i) {
81- int cpu;
82- if (!ParseInt (cpus_as_string[i].c_str (), &cpu))
83- return vector<int >();
84- cpus_as_int.push_back (cpu);
85- }
86- return cpus_as_int;
72+ string policy0_cores_unparsed;
73+ if (!ReadFileToString (POLICY0_CORES_PATH , &policy0_cores_unparsed)) return vector<int >();
74+ string policy0_trimmed = android::base::Trim (policy0_cores_unparsed);
75+ vector<string> cpus_as_string = android::base::Split (policy0_trimmed, " " );
76+
77+ vector<int > cpus_as_int;
78+ for (int i = 0 ; i < cpus_as_string.size (); ++i) {
79+ int cpu;
80+ if (!ParseInt (cpus_as_string[i].c_str (), &cpu)) return vector<int >();
81+ cpus_as_int.push_back (cpu);
82+ }
83+ return cpus_as_int;
8784}
8885
8986// Return a vector of strings describing the CPU masks for cpufreq Policy 0.
9087vector<string> Policy0CpuMasks () {
91- vector<int > cpus = Policy0AffectedCpus ();
92- vector<string> cpu_masks;
93- for (int i = 0 ; i < cpus.size (); ++i)
94- cpu_masks.push_back (fmt::format (" {0:02x}" , 1 << cpus[i]));
95- return cpu_masks;
88+ vector<int > cpus = Policy0AffectedCpus ();
89+ vector<string> cpu_masks;
90+ for (int i = 0 ; i < cpus.size (); ++i) cpu_masks.push_back (fmt::format (" {0:02x}" , 1 << cpus[i]));
91+ return cpu_masks;
9692}
9793
9894// Read the actions for the given irq# from sysfs, and add it to action_to_irq
99- bool AddEntryToIrqmap (const char * irq,
100- map<string, list<string>>& action_to_irqs) {
101- const string irq_base (SYSFS_IRQDIR " /" );
102- string irq_actions_path = irq_base + irq + " /actions" ;
95+ bool AddEntryToIrqmap (const char * irq, map<string, list<string>>& action_to_irqs) {
96+ const string irq_base (SYSFS_IRQDIR " /" );
97+ string irq_actions_path = irq_base + irq + " /actions" ;
10398
104- string irq_actions;
105- if (!ReadFileToString (irq_actions_path, &irq_actions))
106- return false ;
99+ string irq_actions;
100+ if (!ReadFileToString (irq_actions_path, &irq_actions)) return false ;
107101
108- irq_actions = Trim (irq_actions);
102+ irq_actions = Trim (irq_actions);
109103
110- if (irq_actions == " (null)" )
111- irq_actions = " " ;
104+ if (irq_actions == " (null)" ) irq_actions = " " ;
112105
113- action_to_irqs[irq_actions].push_back (irq);
106+ action_to_irqs[irq_actions].push_back (irq);
114107
115- return true ;
108+ return true ;
116109}
117110
118111// Get a mapping of driver "action" to IRQ#s for each IRQ# in
119112// SYSFS_IRQDIR.
120113bool GetIrqmap (map<string, list<string>>& action_to_irqs) {
121- bool some_success = false ;
122- std::unique_ptr<DIR , decltype (&closedir)> irq_dir (opendir (SYSFS_IRQDIR ), closedir);
123- if (!irq_dir) {
124- PLOG (ERROR ) << " opening dir " SYSFS_IRQDIR ;
125- return false ;
126- }
127-
128- struct dirent * entry;
129- while ((entry = readdir (irq_dir.get ()))) {
130-
131- // If the directory entry isn't a parsable number, skip it.
132- // . and .. get skipped here.
133- unsigned throwaway;
134- if (!ParseUint (entry->d_name , &throwaway))
135- continue ;
136-
137- some_success |= AddEntryToIrqmap (entry->d_name , action_to_irqs);
138- }
139- return some_success;
114+ bool some_success = false ;
115+ std::unique_ptr<DIR , decltype (&closedir)> irq_dir (opendir (SYSFS_IRQDIR ), closedir);
116+ if (!irq_dir) {
117+ PLOG (ERROR ) << " opening dir " SYSFS_IRQDIR ;
118+ return false ;
119+ }
120+
121+ struct dirent * entry;
122+ while ((entry = readdir (irq_dir.get ()))) {
123+ // If the directory entry isn't a parsable number, skip it.
124+ // . and .. get skipped here.
125+ unsigned throwaway;
126+ if (!ParseUint (entry->d_name , &throwaway)) continue ;
127+
128+ some_success |= AddEntryToIrqmap (entry->d_name , action_to_irqs);
129+ }
130+ return some_success;
140131}
141132
142133// Given a map of irq actions -> IRQs,
143134// find out which ones haven't been assigned and add those to
144135// rebalance_actions.
145136void FindUnassignedIrqs (const map<string, list<string>>& action_to_irqs,
146137 list<pair<string, list<string>>>& rebalance_actions) {
147- for (const auto &action_to_irqs_entry: action_to_irqs) {
148- bool rebalance = true ;
149- for (const auto & irq: action_to_irqs_entry.second ) {
150- string smp_affinity;
151- string proc_path (PROC_IRQDIR " /" );
152- proc_path += irq + " /smp_affinity" ;
153- ReadFileToString (proc_path, &smp_affinity);
154- smp_affinity = Trim (smp_affinity);
155-
156- // Try to respect previoulsy set IRQ affinities.
157- // On ARM interrupt controllers under Linux, if an IRQ is assigned
158- // to more than one core it will only be assigned to the lowest core.
159- // Assume any IRQ which is set to more than one core in the lowest four
160- // CPUs hasn't been assigned and needs to be rebalanced.
161- if (smp_affinity.back () == ' 0' ||
162- smp_affinity.back () == ' 1' ||
163- smp_affinity.back () == ' 2' ||
164- smp_affinity.back () == ' 4' ||
165- smp_affinity.back () == ' 8' ) {
166- rebalance = false ;
167- }
168-
169- // Treat each unnamed action IRQ as independent.
170- if (action_to_irqs_entry.first .empty ()) {
171- if (rebalance) {
172- pair<string, list<string>> empty_action_irq;
173- empty_action_irq.first = " " ;
174- empty_action_irq.second .push_back (irq);
175- rebalance_actions.push_back (empty_action_irq);
138+ for (const auto & action_to_irqs_entry : action_to_irqs) {
139+ bool rebalance = true ;
140+ for (const auto & irq : action_to_irqs_entry.second ) {
141+ string smp_affinity;
142+ string proc_path (PROC_IRQDIR " /" );
143+ proc_path += irq + " /smp_affinity" ;
144+ ReadFileToString (proc_path, &smp_affinity);
145+ smp_affinity = Trim (smp_affinity);
146+
147+ // Try to respect previoulsy set IRQ affinities.
148+ // On ARM interrupt controllers under Linux, if an IRQ is assigned
149+ // to more than one core it will only be assigned to the lowest core.
150+ // Assume any IRQ which is set to more than one core in the lowest four
151+ // CPUs hasn't been assigned and needs to be rebalanced.
152+ if (smp_affinity.back () == ' 0' || smp_affinity.back () == ' 1' ||
153+ smp_affinity.back () == ' 2' || smp_affinity.back () == ' 4' ||
154+ smp_affinity.back () == ' 8' ) {
155+ rebalance = false ;
156+ }
157+
158+ // Treat each unnamed action IRQ as independent.
159+ if (action_to_irqs_entry.first .empty ()) {
160+ if (rebalance) {
161+ pair<string, list<string>> empty_action_irq;
162+ empty_action_irq.first = " " ;
163+ empty_action_irq.second .push_back (irq);
164+ rebalance_actions.push_back (empty_action_irq);
165+ }
166+ rebalance = true ;
167+ }
168+ }
169+ if (rebalance && !action_to_irqs_entry.first .empty ()) {
170+ rebalance_actions.push_back (
171+ std::make_pair (action_to_irqs_entry.first , action_to_irqs_entry.second ));
176172 }
177- rebalance = true ;
178- }
179- }
180- if (rebalance && !action_to_irqs_entry.first .empty ()) {
181- rebalance_actions.push_back (std::make_pair (action_to_irqs_entry.first ,
182- action_to_irqs_entry.second ));
183173 }
184- }
185174}
186175
187176// Read the file at `path`, Trim whitespace, see if it matches `expected_value`.
188177// Print the results to stdout.
189- void ReportIfAffinityUpdated (const std::string expected_value,
190- const std::string path) {
191- std::string readback, report;
192- ReadFileToString (path, &readback);
193- readback = Trim (readback);
194- if (readback != expected_value) {
195- report += " Unable to set " ;
196- } else {
197- report += " Success setting " ;
198- }
199- report += path;
200- report += " : found " + readback + " vs " + expected_value + " \n " ;
201- LOG (DEBUG ) << report;
178+ void ReportIfAffinityUpdated (const std::string expected_value, const std::string path) {
179+ std::string readback, report;
180+ ReadFileToString (path, &readback);
181+ readback = Trim (readback);
182+ if (readback != expected_value) {
183+ report += " Unable to set " ;
184+ } else {
185+ report += " Success setting " ;
186+ }
187+ report += path;
188+ report += " : found " + readback + " vs " + expected_value + " \n " ;
189+ LOG (DEBUG ) << report;
202190}
203191
204192// Evenly distribute the IRQ actions across all the Policy0 CPUs.
205193// Assign all the IRQs of an action to a single CPU core.
206194bool RebalanceIrqs (const list<pair<string, list<string>>>& action_to_irqs) {
207- int mask_index = 0 ;
208- std::vector<std::string> affinity_masks = Policy0CpuMasks ();
209-
210- if (affinity_masks.empty ()) {
211- LOG (ERROR ) << " Unable to find Policy0 CPUs for IRQ assignment." ;
212- return false ;
213- }
214-
215- for (const auto &action_to_irq: action_to_irqs) {
216- for (const auto & irq: action_to_irq.second ) {
217- std::string affinity_path (PROC_IRQDIR " /" );
218- affinity_path += irq + " /smp_affinity" ;
219- WriteStringToFile (affinity_masks[mask_index], affinity_path);
220- ReportIfAffinityUpdated (affinity_masks[mask_index], affinity_path);
195+ int mask_index = 0 ;
196+ std::vector<std::string> affinity_masks = Policy0CpuMasks ();
197+
198+ if (affinity_masks.empty ()) {
199+ LOG (ERROR ) << " Unable to find Policy0 CPUs for IRQ assignment." ;
200+ return false ;
201+ }
202+
203+ for (const auto & action_to_irq : action_to_irqs) {
204+ for (const auto & irq : action_to_irq.second ) {
205+ std::string affinity_path (PROC_IRQDIR " /" );
206+ affinity_path += irq + " /smp_affinity" ;
207+ WriteStringToFile (affinity_masks[mask_index], affinity_path);
208+ ReportIfAffinityUpdated (affinity_masks[mask_index], affinity_path);
209+ }
210+ mask_index = (mask_index + 1 ) % affinity_masks.size ();
221211 }
222- mask_index = (mask_index + 1 ) % affinity_masks.size ();
223- }
224- return true ;
212+ return true ;
225213}
226214
227215void ChownIrqAffinity () {
@@ -231,13 +219,12 @@ void ChownIrqAffinity() {
231219 return ;
232220 }
233221
234- struct dirent * entry;
222+ struct dirent * entry;
235223 while ((entry = readdir (irq_dir.get ()))) {
236224 // If the directory entry isn't a parsable number, skip it.
237225 // . and .. get skipped here.
238226 unsigned throwaway;
239- if (!ParseUint (entry->d_name , &throwaway))
240- continue ;
227+ if (!ParseUint (entry->d_name , &throwaway)) continue ;
241228
242229 string affinity_path (PROC_IRQDIR " /" );
243230 affinity_path += entry->d_name ;
@@ -252,29 +239,29 @@ void ChownIrqAffinity() {
252239}
253240
254241int main (int /* argc */ , char * /* argv */ []) {
255- map<string, list<string>> irq_mapping;
256- list<pair<string, list<string>>> action_to_irqs;
257-
258- // Find the mapping of "irq actions" to IRQs.
259- // Each IRQ has an assocatied irq_actions field, showing the actions
260- // associated with it. Multiple IRQs have the same actions.
261- // Generate the mapping of actions to IRQs with that action,
262- // as these IRQs should all be mapped to the same cores.
263- if (!GetIrqmap (irq_mapping)) {
264- LOG (ERROR ) << " Unable to read IRQ mappings. Are you root?" ;
265- return 1 ;
266- }
267-
268- // Change ownership of smp_affinity and smp_affinity_list handles
269- // from root to system.
270- ChownIrqAffinity ();
271-
272- // Some IRQs are already assigned to a subset of cores, usually for
273- // good reason (like some drivers have an IRQ per core, for per-core
274- // queues.) Find the set of IRQs that haven't been mapped to specific
275- // cores.
276- FindUnassignedIrqs (irq_mapping, action_to_irqs);
277-
278- // Distribute the rebalancable IRQs across all cores.
279- return RebalanceIrqs (action_to_irqs) ? 0 : 1 ;
242+ map<string, list<string>> irq_mapping;
243+ list<pair<string, list<string>>> action_to_irqs;
244+
245+ // Find the mapping of "irq actions" to IRQs.
246+ // Each IRQ has an assocatied irq_actions field, showing the actions
247+ // associated with it. Multiple IRQs have the same actions.
248+ // Generate the mapping of actions to IRQs with that action,
249+ // as these IRQs should all be mapped to the same cores.
250+ if (!GetIrqmap (irq_mapping)) {
251+ LOG (ERROR ) << " Unable to read IRQ mappings. Are you root?" ;
252+ return 1 ;
253+ }
254+
255+ // Change ownership of smp_affinity and smp_affinity_list handles
256+ // from root to system.
257+ ChownIrqAffinity ();
258+
259+ // Some IRQs are already assigned to a subset of cores, usually for
260+ // good reason (like some drivers have an IRQ per core, for per-core
261+ // queues.) Find the set of IRQs that haven't been mapped to specific
262+ // cores.
263+ FindUnassignedIrqs (irq_mapping, action_to_irqs);
264+
265+ // Distribute the rebalancable IRQs across all cores.
266+ return RebalanceIrqs (action_to_irqs) ? 0 : 1 ;
280267}
0 commit comments