profiling.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /*
  2. * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <Kernel/CoreDump.h>
  7. #include <Kernel/FileSystem/FileDescription.h>
  8. #include <Kernel/FileSystem/VirtualFileSystem.h>
  9. #include <Kernel/PerformanceManager.h>
  10. #include <Kernel/Process.h>
  11. #include <Kernel/Time/TimeManagement.h>
  12. namespace Kernel {
  13. bool g_profiling_all_threads;
  14. PerformanceEventBuffer* g_global_perf_events;
  15. u64 g_profiling_event_mask;
  16. KResultOr<int> Process::sys$profiling_enable(pid_t pid, u64 event_mask)
  17. {
  18. REQUIRE_NO_PROMISES;
  19. if (pid == -1) {
  20. if (!is_superuser())
  21. return EPERM;
  22. ScopedCritical critical;
  23. g_profiling_event_mask = event_mask;
  24. if (g_global_perf_events)
  25. g_global_perf_events->clear();
  26. else
  27. g_global_perf_events = PerformanceEventBuffer::try_create_with_size(32 * MiB).leak_ptr();
  28. ScopedSpinLock lock(g_processes_lock);
  29. if (!TimeManagement::the().enable_profile_timer())
  30. return ENOTSUP;
  31. g_profiling_all_threads = true;
  32. PerformanceManager::add_process_created_event(*Scheduler::colonel());
  33. Process::for_each([](auto& process) {
  34. PerformanceManager::add_process_created_event(process);
  35. return IterationDecision::Continue;
  36. });
  37. return 0;
  38. }
  39. ScopedSpinLock lock(g_processes_lock);
  40. auto process = Process::from_pid(pid);
  41. if (!process)
  42. return ESRCH;
  43. if (process->is_dead())
  44. return ESRCH;
  45. if (!is_superuser() && process->uid() != euid())
  46. return EPERM;
  47. if (!process->create_perf_events_buffer_if_needed())
  48. return ENOMEM;
  49. if (!TimeManagement::the().enable_profile_timer())
  50. return ENOTSUP;
  51. g_profiling_event_mask = event_mask;
  52. process->set_profiling(true);
  53. return 0;
  54. }
  55. KResultOr<int> Process::sys$profiling_disable(pid_t pid)
  56. {
  57. REQUIRE_NO_PROMISES;
  58. if (pid == -1) {
  59. if (!is_superuser())
  60. return EPERM;
  61. ScopedCritical critical;
  62. if (!TimeManagement::the().disable_profile_timer())
  63. return ENOTSUP;
  64. g_profiling_all_threads = false;
  65. return 0;
  66. }
  67. ScopedSpinLock lock(g_processes_lock);
  68. auto process = Process::from_pid(pid);
  69. if (!process)
  70. return ESRCH;
  71. if (!is_superuser() && process->uid() != euid())
  72. return EPERM;
  73. if (!process->is_profiling())
  74. return EINVAL;
  75. // FIXME: If we enabled the profile timer and it's not supported, how do we disable it now?
  76. if (!TimeManagement::the().disable_profile_timer())
  77. return ENOTSUP;
  78. process->set_profiling(false);
  79. return 0;
  80. }
  81. KResultOr<int> Process::sys$profiling_free_buffer(pid_t pid)
  82. {
  83. REQUIRE_NO_PROMISES;
  84. if (pid == -1) {
  85. if (!is_superuser())
  86. return EPERM;
  87. OwnPtr<PerformanceEventBuffer> perf_events;
  88. {
  89. ScopedCritical critical;
  90. perf_events = g_global_perf_events;
  91. g_global_perf_events = nullptr;
  92. }
  93. return 0;
  94. }
  95. ScopedSpinLock lock(g_processes_lock);
  96. auto process = Process::from_pid(pid);
  97. if (!process)
  98. return ESRCH;
  99. if (!is_superuser() && process->uid() != euid())
  100. return EPERM;
  101. if (process->is_profiling())
  102. return EINVAL;
  103. process->delete_perf_events_buffer();
  104. return 0;
  105. }
  106. }