Serenity Operating System
1/*
2 * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <AK/JsonArraySerializer.h>
28#include <AK/JsonObjectSerializer.h>
29#include <AK/JsonObject.h>
30#include <Kernel/KBufferBuilder.h>
31#include <Kernel/PerformanceEventBuffer.h>
32
33namespace Kernel {
34
35PerformanceEventBuffer::PerformanceEventBuffer()
36 : m_buffer(KBuffer::create_with_size(4 * MB))
37{
38}
39
40KResult PerformanceEventBuffer::append(int type, uintptr_t arg1, uintptr_t arg2)
41{
42 if (count() >= capacity())
43 return KResult(-ENOBUFS);
44
45 PerformanceEvent event;
46 event.type = type;
47
48 switch (type) {
49 case PERF_EVENT_MALLOC:
50 event.data.malloc.size = arg1;
51 event.data.malloc.ptr = arg2;
52#ifdef VERY_DEBUG
53 dbg() << "PERF_EVENT_MALLOC: " << (void*)event.data.malloc.ptr << " (" << event.data.malloc.size << ")";
54#endif
55 break;
56 case PERF_EVENT_FREE:
57 event.data.free.ptr = arg1;
58#ifdef VERY_DEBUG
59 dbg() << "PERF_EVENT_FREE: " << (void*)event.data.free.ptr;
60#endif
61 break;
62 default:
63 return KResult(-EINVAL);
64 }
65
66 uintptr_t ebp;
67 asm volatile("movl %%ebp, %%eax"
68 : "=a"(ebp));
69 //copy_from_user(&ebp, (uintptr_t*)current->get_register_dump_from_stack().ebp);
70 Vector<uintptr_t> backtrace;
71 {
72 SmapDisabler disabler;
73 backtrace = Thread::current->raw_backtrace(ebp);
74 }
75 event.stack_size = min(sizeof(event.stack) / sizeof(uintptr_t), static_cast<size_t>(backtrace.size()));
76 memcpy(event.stack, backtrace.data(), event.stack_size * sizeof(uintptr_t));
77
78#ifdef VERY_DEBUG
79 for (size_t i = 0; i < event.stack_size; ++i)
80 dbg() << " " << (void*)event.stack[i];
81#endif
82
83 event.timestamp = g_uptime;
84 at(m_count++) = event;
85 return KSuccess;
86}
87
88PerformanceEvent& PerformanceEventBuffer::at(size_t index)
89{
90 ASSERT(index < capacity());
91 auto* events = reinterpret_cast<PerformanceEvent*>(m_buffer.data());
92 return events[index];
93}
94
95KBuffer PerformanceEventBuffer::to_json(pid_t pid, const String& executable_path) const
96{
97 KBufferBuilder builder;
98
99 JsonObjectSerializer object(builder);
100 object.add("pid", pid);
101 object.add("executable", executable_path);
102
103 auto array = object.add_array("events");
104 for (size_t i = 0; i < m_count; ++i) {
105 auto& event = at(i);
106 auto object = array.add_object();
107 switch (event.type) {
108 case PERF_EVENT_MALLOC:
109 object.add("type", "malloc");
110 object.add("ptr", static_cast<u64>(event.data.malloc.ptr));
111 object.add("size", static_cast<u64>(event.data.malloc.size));
112 break;
113 case PERF_EVENT_FREE:
114 object.add("type", "free");
115 object.add("ptr", static_cast<u64>(event.data.free.ptr));
116 break;
117 }
118 object.add("timestamp", event.timestamp);
119 auto stack_array = object.add_array("stack");
120 for (size_t j = 0; j < event.stack_size; ++j) {
121 stack_array.add(event.stack[j]);
122 }
123 stack_array.finish();
124 object.finish();
125 }
126 array.finish();
127 object.finish();
128 return builder.build();
129}
130
131}