profiling.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  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/VirtualFileSystem.h>
  8. #include <Kernel/PerformanceManager.h>
  9. #include <Kernel/Process.h>
  10. #include <Kernel/Time/TimeManagement.h>
  11. namespace Kernel {
  12. bool g_profiling_all_threads;
  13. PerformanceEventBuffer* g_global_perf_events;
  14. u64 g_profiling_event_mask;
  15. KResultOr<FlatPtr> Process::sys$profiling_enable(pid_t pid, u64 event_mask)
  16. {
  17. VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
  18. REQUIRE_NO_PROMISES;
  19. if (pid == -1) {
  20. if (!is_superuser())
  21. return EPERM;
  22. ScopedCritical critical;
  23. g_profiling_event_mask = PERF_EVENT_PROCESS_CREATE | PERF_EVENT_THREAD_CREATE | PERF_EVENT_MMAP;
  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. SpinlockLocker lock(g_profiling_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. g_profiling_event_mask = event_mask;
  38. return 0;
  39. }
  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. SpinlockLocker lock(g_profiling_lock);
  48. g_profiling_event_mask = PERF_EVENT_PROCESS_CREATE | PERF_EVENT_THREAD_CREATE | PERF_EVENT_MMAP;
  49. process->set_profiling(true);
  50. if (!process->create_perf_events_buffer_if_needed()) {
  51. process->set_profiling(false);
  52. return ENOMEM;
  53. }
  54. g_profiling_event_mask = event_mask;
  55. if (!TimeManagement::the().enable_profile_timer()) {
  56. process->set_profiling(false);
  57. return ENOTSUP;
  58. }
  59. return 0;
  60. }
  61. KResultOr<FlatPtr> Process::sys$profiling_disable(pid_t pid)
  62. {
  63. VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
  64. REQUIRE_NO_PROMISES;
  65. if (pid == -1) {
  66. if (!is_superuser())
  67. return EPERM;
  68. ScopedCritical critical;
  69. if (!TimeManagement::the().disable_profile_timer())
  70. return ENOTSUP;
  71. g_profiling_all_threads = false;
  72. return 0;
  73. }
  74. auto process = Process::from_pid(pid);
  75. if (!process)
  76. return ESRCH;
  77. if (!is_superuser() && process->uid() != euid())
  78. return EPERM;
  79. SpinlockLocker lock(g_profiling_lock);
  80. if (!process->is_profiling())
  81. return EINVAL;
  82. // FIXME: If we enabled the profile timer and it's not supported, how do we disable it now?
  83. if (!TimeManagement::the().disable_profile_timer())
  84. return ENOTSUP;
  85. process->set_profiling(false);
  86. return 0;
  87. }
  88. KResultOr<FlatPtr> Process::sys$profiling_free_buffer(pid_t pid)
  89. {
  90. VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
  91. REQUIRE_NO_PROMISES;
  92. if (pid == -1) {
  93. if (!is_superuser())
  94. return EPERM;
  95. OwnPtr<PerformanceEventBuffer> perf_events;
  96. {
  97. ScopedCritical critical;
  98. perf_events = adopt_own_if_nonnull(g_global_perf_events);
  99. g_global_perf_events = nullptr;
  100. }
  101. return 0;
  102. }
  103. auto process = Process::from_pid(pid);
  104. if (!process)
  105. return ESRCH;
  106. if (!is_superuser() && process->uid() != euid())
  107. return EPERM;
  108. SpinlockLocker lock(g_profiling_lock);
  109. if (process->is_profiling())
  110. return EINVAL;
  111. process->delete_perf_events_buffer();
  112. return 0;
  113. }
  114. }