syscnt.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /*
  2. * Copyright (c) 2014-2019 Richard Braun.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <stddef.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <kern/adaptive_lock.h>
  21. #include <kern/atomic.h>
  22. #include <kern/init.h>
  23. #include <kern/list.h>
  24. #include <kern/log.h>
  25. #include <kern/shell.h>
  26. #include <kern/spinlock.h>
  27. #include <kern/syscnt.h>
  28. #include <kern/thread.h>
  29. // Global list of all registered counters.
  30. static struct list syscnt_list;
  31. static struct adaptive_lock syscnt_lock;
  32. #ifdef CONFIG_SHELL
  33. static void
  34. syscnt_shell_info (struct shell *shell __unused, int argc, char **argv)
  35. {
  36. char *prefix = argc >= 2 ? argv[1] : NULL;
  37. syscnt_info (prefix, shell->stream);
  38. }
  39. static struct shell_cmd syscnt_shell_cmds[] =
  40. {
  41. SHELL_CMD_INITIALIZER ("syscnt_info", syscnt_shell_info,
  42. "syscnt_info [<prefix>]",
  43. "display information about system counters"),
  44. };
  45. static int __init
  46. syscnt_setup_shell (void)
  47. {
  48. SHELL_REGISTER_CMDS (syscnt_shell_cmds, shell_get_main_cmd_set ());
  49. return (0);
  50. }
  51. INIT_OP_DEFINE (syscnt_setup_shell,
  52. INIT_OP_DEP (shell_setup, true),
  53. INIT_OP_DEP (syscnt_setup, true));
  54. #endif
  55. static int __init
  56. syscnt_setup (void)
  57. {
  58. list_init (&syscnt_list);
  59. adaptive_lock_init (&syscnt_lock);
  60. return (0);
  61. }
  62. INIT_OP_DEFINE (syscnt_setup,
  63. INIT_OP_DEP (spinlock_setup, true));
  64. void __init
  65. syscnt_register (struct syscnt *syscnt, const char *name)
  66. {
  67. #ifndef ATOMIC_HAVE_64B_OPS
  68. spinlock_init (&syscnt->lock);
  69. #endif
  70. syscnt->value = 0;
  71. strlcpy (syscnt->name, name, sizeof (syscnt->name));
  72. ADAPTIVE_LOCK_GUARD (&syscnt_lock);
  73. list_insert_tail (&syscnt_list, &syscnt->node);
  74. }
  75. void
  76. syscnt_info (const char *prefix, struct stream *stream)
  77. {
  78. size_t prefix_length = prefix ? strlen (prefix) : 0;
  79. ADAPTIVE_LOCK_GUARD (&syscnt_lock);
  80. struct syscnt *syscnt;
  81. list_for_each_entry (&syscnt_list, syscnt, node)
  82. {
  83. if (prefix_length)
  84. {
  85. size_t length = strlen (syscnt->name);
  86. if (length < prefix_length ||
  87. memcmp (syscnt->name, prefix, prefix_length) != 0)
  88. continue;
  89. }
  90. fmt_xprintf (stream, "syscnt: %40s %20llu\n",
  91. syscnt->name, syscnt_read (syscnt));
  92. }
  93. }