syscnt.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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/atomic.h>
  21. #include <kern/init.h>
  22. #include <kern/list.h>
  23. #include <kern/log.h>
  24. #include <kern/mutex.h>
  25. #include <kern/shell.h>
  26. #include <kern/spinlock.h>
  27. #include <kern/syscnt.h>
  28. #include <kern/thread.h>
  29. /*
  30. * Global list of all registered counters.
  31. */
  32. static struct list syscnt_list;
  33. static struct mutex syscnt_lock;
  34. #ifdef CONFIG_SHELL
  35. static void
  36. syscnt_shell_info(struct shell *shell, int argc, char **argv)
  37. {
  38. char *prefix;
  39. (void)shell;
  40. prefix = (argc >= 2) ? argv[1] : NULL;
  41. syscnt_info(prefix, printf_ln);
  42. }
  43. static struct shell_cmd syscnt_shell_cmds[] = {
  44. SHELL_CMD_INITIALIZER("syscnt_info", syscnt_shell_info,
  45. "syscnt_info [<prefix>]",
  46. "display information about system counters"),
  47. };
  48. static int __init
  49. syscnt_setup_shell(void)
  50. {
  51. SHELL_REGISTER_CMDS(syscnt_shell_cmds, shell_get_main_cmd_set());
  52. return 0;
  53. }
  54. INIT_OP_DEFINE(syscnt_setup_shell,
  55. INIT_OP_DEP(shell_setup, true),
  56. INIT_OP_DEP(syscnt_setup, true));
  57. #endif /* CONFIG_SHELL */
  58. static int __init
  59. syscnt_setup(void)
  60. {
  61. list_init(&syscnt_list);
  62. mutex_init(&syscnt_lock);
  63. return 0;
  64. }
  65. /*
  66. * Do not make initialization depend on mutex_setup, since mutex
  67. * modules may use system counters for debugging.
  68. */
  69. INIT_OP_DEFINE(syscnt_setup,
  70. INIT_OP_DEP(mutex_bootstrap, true),
  71. INIT_OP_DEP(spinlock_setup, true));
  72. void __init
  73. syscnt_register(struct syscnt *syscnt, const char *name)
  74. {
  75. #ifndef ATOMIC_HAVE_64B_OPS
  76. spinlock_init(&syscnt->lock);
  77. #endif
  78. syscnt->value = 0;
  79. strlcpy(syscnt->name, name, sizeof(syscnt->name));
  80. mutex_lock(&syscnt_lock);
  81. list_insert_tail(&syscnt_list, &syscnt->node);
  82. mutex_unlock(&syscnt_lock);
  83. }
  84. void
  85. syscnt_info(const char *prefix, log_print_fn_t print_fn)
  86. {
  87. struct syscnt *syscnt;
  88. size_t length, prefix_length;
  89. uint64_t value;
  90. prefix_length = (prefix == NULL) ? 0 : strlen(prefix);
  91. mutex_lock(&syscnt_lock);
  92. list_for_each_entry(&syscnt_list, syscnt, node) {
  93. if (prefix_length != 0) {
  94. length = strlen(syscnt->name);
  95. if ((length < prefix_length)
  96. || (memcmp(syscnt->name, prefix, prefix_length) != 0)) {
  97. continue;
  98. }
  99. }
  100. value = syscnt_read(syscnt);
  101. print_fn("syscnt: %40s %20llu", syscnt->name,
  102. (unsigned long long)value);
  103. }
  104. mutex_unlock(&syscnt_lock);
  105. }