Serenity Operating System
at master 118 lines 4.2 kB view raw
1/* 2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <LibCore/ArgsParser.h> 8#include <LibCore/System.h> 9#include <LibMain/Main.h> 10#include <serenity.h> 11#include <stdio.h> 12#include <stdlib.h> 13 14ErrorOr<int> serenity_main(Main::Arguments arguments) 15{ 16 Core::ArgsParser args_parser; 17 18 StringView pid_argument {}; 19 Vector<StringView> command; 20 bool wait = false; 21 bool free = false; 22 bool enable = false; 23 bool disable = false; 24 bool all_processes = false; 25 u64 event_mask = PERF_EVENT_MMAP | PERF_EVENT_MUNMAP | PERF_EVENT_PROCESS_CREATE 26 | PERF_EVENT_PROCESS_EXEC | PERF_EVENT_PROCESS_EXIT | PERF_EVENT_THREAD_CREATE | PERF_EVENT_THREAD_EXIT 27 | PERF_EVENT_SIGNPOST; 28 bool seen_event_type_arg = false; 29 30 args_parser.add_option(pid_argument, "Target PID", nullptr, 'p', "PID"); 31 args_parser.add_option(all_processes, "Profile all processes (super-user only), result at /sys/kernel/profile", nullptr, 'a'); 32 args_parser.add_option(enable, "Enable", nullptr, 'e'); 33 args_parser.add_option(disable, "Disable", nullptr, 'd'); 34 args_parser.add_option(free, "Free the profiling buffer for the associated process(es).", nullptr, 'f'); 35 args_parser.add_option(wait, "Enable profiling and wait for user input to disable.", nullptr, 'w'); 36 args_parser.add_option(Core::ArgsParser::Option { 37 Core::ArgsParser::OptionArgumentMode::Required, 38 "Enable tracking specific event type", nullptr, 't', "event_type", 39 [&](DeprecatedString event_type) { 40 seen_event_type_arg = true; 41 if (event_type == "sample") 42 event_mask |= PERF_EVENT_SAMPLE; 43 else if (event_type == "context_switch") 44 event_mask |= PERF_EVENT_CONTEXT_SWITCH; 45 else if (event_type == "kmalloc") 46 event_mask |= PERF_EVENT_KMALLOC; 47 else if (event_type == "kfree") 48 event_mask |= PERF_EVENT_KFREE; 49 else if (event_type == "page_fault") 50 event_mask |= PERF_EVENT_PAGE_FAULT; 51 else if (event_type == "syscall") 52 event_mask |= PERF_EVENT_SYSCALL; 53 else if (event_type == "read") 54 event_mask |= PERF_EVENT_READ; 55 else { 56 warnln("Unknown event type '{}' specified.", event_type); 57 exit(1); 58 } 59 return true; 60 } }); 61 args_parser.add_positional_argument(command, "Command to profile", "command", Core::ArgsParser::Required::No); 62 args_parser.set_stop_on_first_non_option(true); 63 64 auto print_types = [] { 65 outln(); 66 outln("Event type can be one of: sample, context_switch, page_fault, syscall, read, kmalloc and kfree."); 67 }; 68 69 if (!args_parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage)) { 70 print_types(); 71 exit(0); 72 } 73 74 if (pid_argument.is_empty() && command.is_empty() && !all_processes) { 75 args_parser.print_usage(stdout, arguments.strings[0]); 76 print_types(); 77 return 0; 78 } 79 80 if (!seen_event_type_arg) 81 event_mask |= PERF_EVENT_SAMPLE; 82 83 if (!pid_argument.is_empty() || all_processes) { 84 if (!(enable ^ disable ^ wait ^ free)) { 85 warnln("-p <PID> requires -e xor -d xor -w xor -f."); 86 return 1; 87 } 88 89 // FIXME: Handle error case. 90 pid_t pid = all_processes ? -1 : pid_argument.to_int().release_value(); 91 92 if (wait || enable) { 93 TRY(Core::System::profiling_enable(pid, event_mask)); 94 95 if (!wait) 96 return 0; 97 } 98 99 if (wait) { 100 outln("Profiling enabled, waiting for user input to disable..."); 101 (void)getchar(); 102 } 103 104 if (wait || disable) 105 TRY(Core::System::profiling_disable(pid)); 106 107 if (free) 108 TRY(Core::System::profiling_free_buffer(pid)); 109 110 return 0; 111 } 112 113 dbgln("Enabling profiling for PID {}", getpid()); 114 TRY(Core::System::profiling_enable(getpid(), event_mask)); 115 TRY(Core::System::exec(command[0], command, Core::System::SearchInPath::Yes)); 116 117 return 0; 118}