Revert "Revert "Add profman tool: responsible to process profiles""

This reverts commit 3da74687e42de7d33a8e75df9bd64374e650f75e.

Change-Id: Id005096bd8063c6c602744d4476d5eb7e0d34e90
diff --git a/profman/profman.cc b/profman/profman.cc
new file mode 100644
index 0000000..7c9e449
--- /dev/null
+++ b/profman/profman.cc
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include "base/dumpable.h"
+#include "base/scoped_flock.h"
+#include "base/stringpiece.h"
+#include "base/stringprintf.h"
+#include "base/time_utils.h"
+#include "base/unix_file/fd_file.h"
+#include "jit/offline_profiling_info.h"
+#include "utils.h"
+#include "profile_assistant.h"
+
+namespace art {
+
+static int original_argc;
+static char** original_argv;
+
+static std::string CommandLine() {
+  std::vector<std::string> command;
+  for (int i = 0; i < original_argc; ++i) {
+    command.push_back(original_argv[i]);
+  }
+  return Join(command, ' ');
+}
+
+static void UsageErrorV(const char* fmt, va_list ap) {
+  std::string error;
+  StringAppendV(&error, fmt, ap);
+  LOG(ERROR) << error;
+}
+
+static void UsageError(const char* fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  UsageErrorV(fmt, ap);
+  va_end(ap);
+}
+
+NO_RETURN static void Usage(const char *fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  UsageErrorV(fmt, ap);
+  va_end(ap);
+
+  UsageError("Command: %s", CommandLine().c_str());
+  UsageError("Usage: profman [options]...");
+  UsageError("");
+  UsageError("  --profile-file=<filename>: specify profiler output file to use for compilation.");
+  UsageError("      Can be specified multiple time, in which case the data from the different");
+  UsageError("      profiles will be aggregated.");
+  UsageError("");
+  UsageError("  --profile-file-fd=<number>: same as --profile-file but accepts a file descriptor.");
+  UsageError("      Cannot be used together with --profile-file.");
+  UsageError("");
+  UsageError("  --reference-profile-file=<filename>: specify a reference profile.");
+  UsageError("      The data in this file will be compared with the data obtained by merging");
+  UsageError("      all the files specified with --profile-file or --profile-file-fd.");
+  UsageError("      If the exit code is EXIT_COMPILE then all --profile-file will be merged into");
+  UsageError("      --reference-profile-file. ");
+  UsageError("");
+  UsageError("  --reference-profile-file-fd=<number>: same as --reference-profile-file but");
+  UsageError("      accepts a file descriptor. Cannot be used together with");
+  UsageError("      --reference-profile-file.");
+  UsageError("");
+
+  exit(EXIT_FAILURE);
+}
+
+class ProfMan FINAL {
+ public:
+  ProfMan() :
+      reference_profile_file_fd_(-1),
+      start_ns_(NanoTime()) {}
+
+  ~ProfMan() {
+    LogCompletionTime();
+  }
+
+  void ParseArgs(int argc, char **argv) {
+    original_argc = argc;
+    original_argv = argv;
+
+    InitLogging(argv);
+
+    // Skip over the command name.
+    argv++;
+    argc--;
+
+    if (argc == 0) {
+      Usage("No arguments specified");
+    }
+
+    for (int i = 0; i < argc; ++i) {
+      const StringPiece option(argv[i]);
+      const bool log_options = false;
+      if (log_options) {
+        LOG(INFO) << "patchoat: option[" << i << "]=" << argv[i];
+      }
+      if (option.starts_with("--profile-file=")) {
+        profile_files_.push_back(option.substr(strlen("--profile-file=")).ToString());
+      } else if (option.starts_with("--profile-file-fd=")) {
+        ParseFdForCollection(option, "--profile-file-fd", &profile_files_fd_);
+      } else if (option.starts_with("--reference-profile-file=")) {
+        reference_profile_file_ = option.substr(strlen("--reference-profile-file=")).ToString();
+      } else if (option.starts_with("--reference-profile-file-fd=")) {
+        ParseUintOption(option, "--reference-profile-file-fd", &reference_profile_file_fd_, Usage);
+      } else {
+        Usage("Unknown argument %s", option.data());
+      }
+    }
+
+    if (profile_files_.empty() && profile_files_fd_.empty()) {
+      Usage("No profile files specified.");
+    }
+    if (!profile_files_.empty() && !profile_files_fd_.empty()) {
+      Usage("Profile files should not be specified with both --profile-file-fd and --profile-file");
+    }
+    if (!reference_profile_file_.empty() && (reference_profile_file_fd_ != -1)) {
+      Usage("--reference-profile-file-fd should only be supplied with --profile-file-fd");
+    }
+    if (reference_profile_file_.empty() && (reference_profile_file_fd_ == -1)) {
+      Usage("Reference profile file not specified");
+    }
+  }
+
+  ProfileAssistant::ProcessingResult ProcessProfiles() {
+    ProfileAssistant::ProcessingResult result;
+    if (profile_files_.empty()) {
+      // The file doesn't need to be flushed here (ProcessProfiles will do it)
+      // so don't check the usage.
+      File file(reference_profile_file_fd_, false);
+      result = ProfileAssistant::ProcessProfiles(profile_files_fd_, reference_profile_file_fd_);
+      CloseAllFds(profile_files_fd_, "profile_files_fd_");
+    } else {
+      result = ProfileAssistant::ProcessProfiles(profile_files_, reference_profile_file_);
+    }
+    return result;
+  }
+
+ private:
+  static void ParseFdForCollection(const StringPiece& option,
+                                   const char* arg_name,
+                                   std::vector<int>* fds) {
+    int fd;
+    ParseUintOption(option, arg_name, &fd, Usage);
+    fds->push_back(fd);
+  }
+
+  static void CloseAllFds(const std::vector<int>& fds, const char* descriptor) {
+    for (size_t i = 0; i < fds.size(); i++) {
+      if (close(fds[i]) < 0) {
+        PLOG(WARNING) << "Failed to close descriptor for " << descriptor << " at index " << i;
+      }
+    }
+  }
+
+  void LogCompletionTime() {
+    LOG(INFO) << "profman took " << PrettyDuration(NanoTime() - start_ns_);
+  }
+
+  std::vector<std::string> profile_files_;
+  std::vector<int> profile_files_fd_;
+  std::string reference_profile_file_;
+  int reference_profile_file_fd_;
+  uint64_t start_ns_;
+};
+
+// See ProfileAssistant::ProcessingResult for return codes.
+static int profman(int argc, char** argv) {
+  ProfMan profman;
+
+  // Parse arguments. Argument mistakes will lead to exit(EXIT_FAILURE) in UsageError.
+  profman.ParseArgs(argc, argv);
+
+  // Process profile information and assess if we need to do a profile guided compilation.
+  // This operation involves I/O.
+  return profman.ProcessProfiles();
+}
+
+}  // namespace art
+
+int main(int argc, char **argv) {
+  return art::profman(argc, argv);
+}
+