123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- /*
- * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include <LibCore/ArgsParser.h>
- #include <LibCore/System.h>
- #include <LibMain/Main.h>
- #include <serenity.h>
- #include <stdio.h>
- #include <stdlib.h>
- ErrorOr<int> serenity_main(Main::Arguments arguments)
- {
- Core::ArgsParser args_parser;
- StringView pid_argument {};
- StringView cmd_argument {};
- bool wait = false;
- bool free = false;
- bool enable = false;
- bool disable = false;
- bool all_processes = false;
- u64 event_mask = PERF_EVENT_MMAP | PERF_EVENT_MUNMAP | PERF_EVENT_PROCESS_CREATE
- | PERF_EVENT_PROCESS_EXEC | PERF_EVENT_PROCESS_EXIT | PERF_EVENT_THREAD_CREATE | PERF_EVENT_THREAD_EXIT
- | PERF_EVENT_SIGNPOST;
- bool seen_event_type_arg = false;
- args_parser.add_option(pid_argument, "Target PID", nullptr, 'p', "PID");
- args_parser.add_option(all_processes, "Profile all processes (super-user only), result at /proc/profile", nullptr, 'a');
- args_parser.add_option(enable, "Enable", nullptr, 'e');
- args_parser.add_option(disable, "Disable", nullptr, 'd');
- args_parser.add_option(free, "Free the profiling buffer for the associated process(es).", nullptr, 'f');
- args_parser.add_option(wait, "Enable profiling and wait for user input to disable.", nullptr, 'w');
- args_parser.add_option(cmd_argument, "Command", nullptr, 'c', "command");
- args_parser.add_option(Core::ArgsParser::Option {
- true, "Enable tracking specific event type", nullptr, 't', "event_type",
- [&](String event_type) {
- seen_event_type_arg = true;
- if (event_type == "sample")
- event_mask |= PERF_EVENT_SAMPLE;
- else if (event_type == "context_switch")
- event_mask |= PERF_EVENT_CONTEXT_SWITCH;
- else if (event_type == "kmalloc")
- event_mask |= PERF_EVENT_KMALLOC;
- else if (event_type == "kfree")
- event_mask |= PERF_EVENT_KFREE;
- else if (event_type == "page_fault")
- event_mask |= PERF_EVENT_PAGE_FAULT;
- else if (event_type == "syscall")
- event_mask |= PERF_EVENT_SYSCALL;
- else if (event_type == "read")
- event_mask |= PERF_EVENT_READ;
- else {
- warnln("Unknown event type '{}' specified.", event_type);
- exit(1);
- }
- return true;
- } });
- auto print_types = [] {
- outln();
- outln("Event type can be one of: sample, context_switch, page_fault, syscall, read, kmalloc and kfree.");
- };
- if (!args_parser.parse(arguments, Core::ArgsParser::FailureBehavior::PrintUsage)) {
- print_types();
- exit(0);
- }
- if (pid_argument.is_empty() && cmd_argument.is_empty() && !all_processes) {
- args_parser.print_usage(stdout, arguments.argv[0]);
- print_types();
- return 0;
- }
- if (!seen_event_type_arg)
- event_mask |= PERF_EVENT_SAMPLE;
- if (!pid_argument.is_empty() || all_processes) {
- if (!(enable ^ disable ^ wait ^ free)) {
- warnln("-p <PID> requires -e xor -d xor -w xor -f.");
- return 1;
- }
- // FIXME: Handle error case.
- pid_t pid = all_processes ? -1 : pid_argument.to_int().release_value();
- if (wait || enable) {
- TRY(Core::System::profiling_enable(pid, event_mask));
- if (!wait)
- return 0;
- }
- if (wait) {
- outln("Profiling enabled, waiting for user input to disable...");
- (void)getchar();
- }
- if (wait || disable)
- TRY(Core::System::profiling_disable(pid));
- if (free)
- TRY(Core::System::profiling_free_buffer(pid));
- return 0;
- }
- auto cmd_parts = StringView(cmd_argument).split_view(' ');
- dbgln("Enabling profiling for PID {}", getpid());
- TRY(Core::System::profiling_enable(getpid(), event_mask));
- TRY(Core::System::exec(cmd_parts[0], cmd_parts, Core::System::SearchInPath::Yes));
- return 0;
- }
|