PerformanceEventBuffer.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /*
  2. * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/JsonArraySerializer.h>
  7. #include <AK/JsonObjectSerializer.h>
  8. #include <AK/ScopeGuard.h>
  9. #include <Kernel/Arch/RegisterState.h>
  10. #include <Kernel/Arch/SmapDisabler.h>
  11. #include <Kernel/FileSystem/Custody.h>
  12. #include <Kernel/KBufferBuilder.h>
  13. #include <Kernel/PerformanceEventBuffer.h>
  14. #include <Kernel/Process.h>
  15. namespace Kernel {
  16. PerformanceEventBuffer::PerformanceEventBuffer(NonnullOwnPtr<KBuffer> buffer)
  17. : m_buffer(move(buffer))
  18. {
  19. }
  20. NEVER_INLINE ErrorOr<void> PerformanceEventBuffer::append(int type, FlatPtr arg1, FlatPtr arg2, StringView arg3, Thread* current_thread)
  21. {
  22. FlatPtr base_pointer;
  23. #if ARCH(I386)
  24. asm volatile("movl %%ebp, %%eax"
  25. : "=a"(base_pointer));
  26. #else
  27. asm volatile("movq %%rbp, %%rax"
  28. : "=a"(base_pointer));
  29. #endif
  30. return append_with_ip_and_bp(current_thread->pid(), current_thread->tid(), 0, base_pointer, type, 0, arg1, arg2, arg3);
  31. }
  32. static Vector<FlatPtr, PerformanceEvent::max_stack_frame_count> raw_backtrace(FlatPtr bp, FlatPtr ip)
  33. {
  34. Vector<FlatPtr, PerformanceEvent::max_stack_frame_count> backtrace;
  35. if (ip != 0)
  36. backtrace.append(ip);
  37. FlatPtr stack_ptr_copy;
  38. FlatPtr stack_ptr = bp;
  39. // FIXME: Figure out how to remove this SmapDisabler without breaking profile stacks.
  40. SmapDisabler disabler;
  41. // NOTE: The stack should always have kernel frames first, followed by userspace frames.
  42. // If a userspace frame points back into kernel memory, something is afoot.
  43. bool is_walking_userspace_stack = false;
  44. while (stack_ptr) {
  45. void* fault_at;
  46. if (!safe_memcpy(&stack_ptr_copy, (void*)stack_ptr, sizeof(FlatPtr), fault_at))
  47. break;
  48. if (!Memory::is_user_address(VirtualAddress { stack_ptr })) {
  49. if (is_walking_userspace_stack) {
  50. dbgln("SHENANIGANS! Userspace stack points back into kernel memory");
  51. break;
  52. }
  53. } else {
  54. is_walking_userspace_stack = true;
  55. }
  56. FlatPtr retaddr;
  57. if (!safe_memcpy(&retaddr, (void*)(stack_ptr + sizeof(FlatPtr)), sizeof(FlatPtr), fault_at))
  58. break;
  59. if (retaddr == 0)
  60. break;
  61. backtrace.append(retaddr);
  62. if (backtrace.size() == PerformanceEvent::max_stack_frame_count)
  63. break;
  64. stack_ptr = stack_ptr_copy;
  65. }
  66. return backtrace;
  67. }
  68. ErrorOr<void> PerformanceEventBuffer::append_with_ip_and_bp(ProcessID pid, ThreadID tid, const RegisterState& regs,
  69. int type, u32 lost_samples, FlatPtr arg1, FlatPtr arg2, StringView arg3)
  70. {
  71. return append_with_ip_and_bp(pid, tid, regs.ip(), regs.bp(), type, lost_samples, arg1, arg2, arg3);
  72. }
  73. ErrorOr<void> PerformanceEventBuffer::append_with_ip_and_bp(ProcessID pid, ThreadID tid,
  74. FlatPtr ip, FlatPtr bp, int type, u32 lost_samples, FlatPtr arg1, FlatPtr arg2, StringView arg3)
  75. {
  76. if (count() >= capacity())
  77. return ENOBUFS;
  78. if ((g_profiling_event_mask & type) == 0)
  79. return EINVAL;
  80. auto* current_thread = Thread::current();
  81. u32 enter_count = 0;
  82. if (current_thread)
  83. enter_count = current_thread->enter_profiler();
  84. ScopeGuard leave_profiler([&] {
  85. if (current_thread)
  86. current_thread->leave_profiler();
  87. });
  88. if (enter_count > 0)
  89. return EINVAL;
  90. PerformanceEvent event;
  91. event.type = type;
  92. event.lost_samples = lost_samples;
  93. switch (type) {
  94. case PERF_EVENT_SAMPLE:
  95. break;
  96. case PERF_EVENT_MALLOC:
  97. event.data.malloc.size = arg1;
  98. event.data.malloc.ptr = arg2;
  99. break;
  100. case PERF_EVENT_FREE:
  101. event.data.free.ptr = arg1;
  102. break;
  103. case PERF_EVENT_MMAP:
  104. event.data.mmap.ptr = arg1;
  105. event.data.mmap.size = arg2;
  106. memset(event.data.mmap.name, 0, sizeof(event.data.mmap.name));
  107. if (!arg3.is_empty())
  108. memcpy(event.data.mmap.name, arg3.characters_without_null_termination(), min(arg3.length(), sizeof(event.data.mmap.name) - 1));
  109. break;
  110. case PERF_EVENT_MUNMAP:
  111. event.data.munmap.ptr = arg1;
  112. event.data.munmap.size = arg2;
  113. break;
  114. case PERF_EVENT_PROCESS_CREATE:
  115. event.data.process_create.parent_pid = arg1;
  116. memset(event.data.process_create.executable, 0, sizeof(event.data.process_create.executable));
  117. if (!arg3.is_empty()) {
  118. memcpy(event.data.process_create.executable, arg3.characters_without_null_termination(),
  119. min(arg3.length(), sizeof(event.data.process_create.executable) - 1));
  120. }
  121. break;
  122. case PERF_EVENT_PROCESS_EXEC:
  123. memset(event.data.process_exec.executable, 0, sizeof(event.data.process_exec.executable));
  124. if (!arg3.is_empty()) {
  125. memcpy(event.data.process_exec.executable, arg3.characters_without_null_termination(),
  126. min(arg3.length(), sizeof(event.data.process_exec.executable) - 1));
  127. }
  128. break;
  129. case PERF_EVENT_PROCESS_EXIT:
  130. break;
  131. case PERF_EVENT_THREAD_CREATE:
  132. event.data.thread_create.parent_tid = arg1;
  133. break;
  134. case PERF_EVENT_THREAD_EXIT:
  135. break;
  136. case PERF_EVENT_CONTEXT_SWITCH:
  137. event.data.context_switch.next_pid = arg1;
  138. event.data.context_switch.next_tid = arg2;
  139. break;
  140. case PERF_EVENT_KMALLOC:
  141. event.data.kmalloc.size = arg1;
  142. event.data.kmalloc.ptr = arg2;
  143. break;
  144. case PERF_EVENT_KFREE:
  145. event.data.kfree.size = arg1;
  146. event.data.kfree.ptr = arg2;
  147. break;
  148. case PERF_EVENT_PAGE_FAULT:
  149. break;
  150. case PERF_EVENT_SYSCALL:
  151. break;
  152. case PERF_EVENT_SIGNPOST:
  153. event.data.signpost.arg1 = arg1;
  154. event.data.signpost.arg2 = arg2;
  155. break;
  156. default:
  157. return EINVAL;
  158. }
  159. auto backtrace = raw_backtrace(bp, ip);
  160. event.stack_size = min(sizeof(event.stack) / sizeof(FlatPtr), static_cast<size_t>(backtrace.size()));
  161. memcpy(event.stack, backtrace.data(), event.stack_size * sizeof(FlatPtr));
  162. event.pid = pid.value();
  163. event.tid = tid.value();
  164. event.timestamp = TimeManagement::the().uptime_ms();
  165. at(m_count++) = event;
  166. return {};
  167. }
  168. PerformanceEvent& PerformanceEventBuffer::at(size_t index)
  169. {
  170. VERIFY(index < capacity());
  171. auto* events = reinterpret_cast<PerformanceEvent*>(m_buffer->data());
  172. return events[index];
  173. }
  174. template<typename Serializer>
  175. ErrorOr<void> PerformanceEventBuffer::to_json_impl(Serializer& object) const
  176. {
  177. {
  178. auto strings = object.add_array("strings");
  179. for (auto const& it : m_strings) {
  180. strings.add(it->view());
  181. }
  182. }
  183. bool show_kernel_addresses = Process::current().is_superuser();
  184. auto array = object.add_array("events");
  185. bool seen_first_sample = false;
  186. for (size_t i = 0; i < m_count; ++i) {
  187. auto const& event = at(i);
  188. if (!show_kernel_addresses) {
  189. if (event.type == PERF_EVENT_KMALLOC || event.type == PERF_EVENT_KFREE)
  190. continue;
  191. }
  192. auto event_object = array.add_object();
  193. switch (event.type) {
  194. case PERF_EVENT_SAMPLE:
  195. event_object.add("type", "sample");
  196. break;
  197. case PERF_EVENT_MALLOC:
  198. event_object.add("type", "malloc");
  199. event_object.add("ptr", static_cast<u64>(event.data.malloc.ptr));
  200. event_object.add("size", static_cast<u64>(event.data.malloc.size));
  201. break;
  202. case PERF_EVENT_FREE:
  203. event_object.add("type", "free");
  204. event_object.add("ptr", static_cast<u64>(event.data.free.ptr));
  205. break;
  206. case PERF_EVENT_MMAP:
  207. event_object.add("type", "mmap");
  208. event_object.add("ptr", static_cast<u64>(event.data.mmap.ptr));
  209. event_object.add("size", static_cast<u64>(event.data.mmap.size));
  210. event_object.add("name", event.data.mmap.name);
  211. break;
  212. case PERF_EVENT_MUNMAP:
  213. event_object.add("type", "munmap");
  214. event_object.add("ptr", static_cast<u64>(event.data.munmap.ptr));
  215. event_object.add("size", static_cast<u64>(event.data.munmap.size));
  216. break;
  217. case PERF_EVENT_PROCESS_CREATE:
  218. event_object.add("type", "process_create");
  219. event_object.add("parent_pid", static_cast<u64>(event.data.process_create.parent_pid));
  220. event_object.add("executable", event.data.process_create.executable);
  221. break;
  222. case PERF_EVENT_PROCESS_EXEC:
  223. event_object.add("type", "process_exec");
  224. event_object.add("executable", event.data.process_exec.executable);
  225. break;
  226. case PERF_EVENT_PROCESS_EXIT:
  227. event_object.add("type", "process_exit");
  228. break;
  229. case PERF_EVENT_THREAD_CREATE:
  230. event_object.add("type", "thread_create");
  231. event_object.add("parent_tid", static_cast<u64>(event.data.thread_create.parent_tid));
  232. break;
  233. case PERF_EVENT_THREAD_EXIT:
  234. event_object.add("type", "thread_exit");
  235. break;
  236. case PERF_EVENT_CONTEXT_SWITCH:
  237. event_object.add("type", "context_switch");
  238. event_object.add("next_pid", static_cast<u64>(event.data.context_switch.next_pid));
  239. event_object.add("next_tid", static_cast<u64>(event.data.context_switch.next_tid));
  240. break;
  241. case PERF_EVENT_KMALLOC:
  242. event_object.add("type", "kmalloc");
  243. event_object.add("ptr", static_cast<u64>(event.data.kmalloc.ptr));
  244. event_object.add("size", static_cast<u64>(event.data.kmalloc.size));
  245. break;
  246. case PERF_EVENT_KFREE:
  247. event_object.add("type", "kfree");
  248. event_object.add("ptr", static_cast<u64>(event.data.kfree.ptr));
  249. event_object.add("size", static_cast<u64>(event.data.kfree.size));
  250. break;
  251. case PERF_EVENT_PAGE_FAULT:
  252. event_object.add("type", "page_fault");
  253. break;
  254. case PERF_EVENT_SYSCALL:
  255. event_object.add("type", "syscall");
  256. break;
  257. case PERF_EVENT_SIGNPOST:
  258. event_object.add("type"sv, "signpost"sv);
  259. event_object.add("arg1"sv, event.data.signpost.arg1);
  260. event_object.add("arg2"sv, event.data.signpost.arg2);
  261. break;
  262. }
  263. event_object.add("pid", event.pid);
  264. event_object.add("tid", event.tid);
  265. event_object.add("timestamp", event.timestamp);
  266. event_object.add("lost_samples", seen_first_sample ? event.lost_samples : 0);
  267. if (event.type == PERF_EVENT_SAMPLE)
  268. seen_first_sample = true;
  269. auto stack_array = event_object.add_array("stack");
  270. for (size_t j = 0; j < event.stack_size; ++j) {
  271. auto address = event.stack[j];
  272. if (!show_kernel_addresses && !Memory::is_user_address(VirtualAddress { address }))
  273. address = 0xdeadc0de;
  274. stack_array.add(address);
  275. }
  276. stack_array.finish();
  277. event_object.finish();
  278. }
  279. array.finish();
  280. object.finish();
  281. return {};
  282. }
  283. ErrorOr<void> PerformanceEventBuffer::to_json(KBufferBuilder& builder) const
  284. {
  285. JsonObjectSerializer object(builder);
  286. return to_json_impl(object);
  287. }
  288. OwnPtr<PerformanceEventBuffer> PerformanceEventBuffer::try_create_with_size(size_t buffer_size)
  289. {
  290. auto buffer_or_error = KBuffer::try_create_with_size(buffer_size, Memory::Region::Access::ReadWrite, "Performance events", AllocationStrategy::AllocateNow);
  291. if (buffer_or_error.is_error())
  292. return {};
  293. return adopt_own_if_nonnull(new (nothrow) PerformanceEventBuffer(buffer_or_error.release_value()));
  294. }
  295. void PerformanceEventBuffer::add_process(const Process& process, ProcessEventType event_type)
  296. {
  297. SpinlockLocker locker(process.address_space().get_lock());
  298. String executable;
  299. if (process.executable())
  300. executable = process.executable()->absolute_path();
  301. else
  302. executable = String::formatted("<{}>", process.name());
  303. [[maybe_unused]] auto rc = append_with_ip_and_bp(process.pid(), 0, 0, 0,
  304. event_type == ProcessEventType::Create ? PERF_EVENT_PROCESS_CREATE : PERF_EVENT_PROCESS_EXEC,
  305. 0, process.pid().value(), 0, executable);
  306. process.for_each_thread([&](auto& thread) {
  307. [[maybe_unused]] auto rc = append_with_ip_and_bp(process.pid(), thread.tid().value(),
  308. 0, 0, PERF_EVENT_THREAD_CREATE, 0, 0, 0, nullptr);
  309. });
  310. for (auto const& region : process.address_space().regions()) {
  311. [[maybe_unused]] auto rc = append_with_ip_and_bp(process.pid(), 0,
  312. 0, 0, PERF_EVENT_MMAP, 0, region->range().base().get(), region->range().size(), region->name());
  313. }
  314. }
  315. ErrorOr<FlatPtr> PerformanceEventBuffer::register_string(NonnullOwnPtr<KString> string)
  316. {
  317. FlatPtr string_id = m_strings.size();
  318. TRY(m_strings.try_set(move(string)));
  319. return string_id;
  320. }
  321. }