profile.cpp 4.0 KB

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