stats.rs 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Copyright (C) 2025 Google LLC.
  3. //! Keep track of statistics for binder_logs.
  4. use crate::defs::*;
  5. use kernel::sync::atomic::{ordering::Relaxed, Atomic};
  6. use kernel::{ioctl::_IOC_NR, seq_file::SeqFile, seq_print};
  7. const BC_COUNT: usize = _IOC_NR(BC_REPLY_SG) as usize + 1;
  8. const BR_COUNT: usize = _IOC_NR(BR_TRANSACTION_PENDING_FROZEN) as usize + 1;
  9. pub(crate) static GLOBAL_STATS: BinderStats = BinderStats::new();
  10. pub(crate) struct BinderStats {
  11. bc: [Atomic<u32>; BC_COUNT],
  12. br: [Atomic<u32>; BR_COUNT],
  13. }
  14. impl BinderStats {
  15. pub(crate) const fn new() -> Self {
  16. #[expect(clippy::declare_interior_mutable_const)]
  17. const ZERO: Atomic<u32> = Atomic::new(0);
  18. Self {
  19. bc: [ZERO; BC_COUNT],
  20. br: [ZERO; BR_COUNT],
  21. }
  22. }
  23. pub(crate) fn inc_bc(&self, bc: u32) {
  24. let idx = _IOC_NR(bc) as usize;
  25. if let Some(bc_ref) = self.bc.get(idx) {
  26. bc_ref.fetch_add(1, Relaxed);
  27. }
  28. }
  29. pub(crate) fn inc_br(&self, br: u32) {
  30. let idx = _IOC_NR(br) as usize;
  31. if let Some(br_ref) = self.br.get(idx) {
  32. br_ref.fetch_add(1, Relaxed);
  33. }
  34. }
  35. pub(crate) fn debug_print(&self, prefix: &str, m: &SeqFile) {
  36. for (i, cnt) in self.bc.iter().enumerate() {
  37. let cnt = cnt.load(Relaxed);
  38. if cnt > 0 {
  39. seq_print!(m, "{}{}: {}\n", prefix, command_string(i), cnt);
  40. }
  41. }
  42. for (i, cnt) in self.br.iter().enumerate() {
  43. let cnt = cnt.load(Relaxed);
  44. if cnt > 0 {
  45. seq_print!(m, "{}{}: {}\n", prefix, return_string(i), cnt);
  46. }
  47. }
  48. }
  49. }
  50. mod strings {
  51. use core::str::from_utf8_unchecked;
  52. use kernel::str::{CStr, CStrExt as _};
  53. extern "C" {
  54. static binder_command_strings: [*const u8; super::BC_COUNT];
  55. static binder_return_strings: [*const u8; super::BR_COUNT];
  56. }
  57. pub(super) fn command_string(i: usize) -> &'static str {
  58. // SAFETY: Accessing `binder_command_strings` is always safe.
  59. let c_str_ptr = unsafe { binder_command_strings[i] };
  60. // SAFETY: The `binder_command_strings` array only contains nul-terminated strings.
  61. let bytes = unsafe { CStr::from_char_ptr(c_str_ptr) }.to_bytes();
  62. // SAFETY: The `binder_command_strings` array only contains strings with ascii-chars.
  63. unsafe { from_utf8_unchecked(bytes) }
  64. }
  65. pub(super) fn return_string(i: usize) -> &'static str {
  66. // SAFETY: Accessing `binder_return_strings` is always safe.
  67. let c_str_ptr = unsafe { binder_return_strings[i] };
  68. // SAFETY: The `binder_command_strings` array only contains nul-terminated strings.
  69. let bytes = unsafe { CStr::from_char_ptr(c_str_ptr) }.to_bytes();
  70. // SAFETY: The `binder_command_strings` array only contains strings with ascii-chars.
  71. unsafe { from_utf8_unchecked(bytes) }
  72. }
  73. }
  74. use strings::{command_string, return_string};