/be/src/util/os-util.cc

https://gitlab.com/s9perween/Impala · C++ · 114 lines · 74 code · 20 blank · 20 comment · 17 complexity · f6a99bf9450f1ca568f494a05370b175 MD5 · raw file

  1. // Copyright 2012 Cloudera Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "util/os-util.h"
  15. #include <unistd.h>
  16. #include <fstream>
  17. #include <sstream>
  18. #include <boost/filesystem.hpp>
  19. #include <boost/algorithm/string.hpp>
  20. #include <gutil/strings/substitute.h>
  21. #include "util/error-util.h"
  22. #include "util/string-parser.h"
  23. using namespace impala;
  24. using namespace std;
  25. using namespace boost::filesystem;
  26. using namespace boost;
  27. using namespace strings;
  28. // Ensure that Impala compiles on earlier kernels. If the target kernel does not support
  29. // _SC_CLK_TCK, sysconf(_SC_CLK_TCK) will return -1.
  30. #ifndef _SC_CLK_TCK
  31. #define _SC_CLK_TCK 2
  32. #endif
  33. static const int64_t TICKS_PER_SEC = sysconf(_SC_CLK_TCK);
  34. // Offsets into the ../stat file array of per-thread statistics
  35. static const int64_t USER_TICKS = 13;
  36. static const int64_t KERNEL_TICKS = 14;
  37. static const int64_t IO_WAIT = 41;
  38. // Largest offset we are interested in, to check we get a well formed stat file.
  39. static const int64_t MAX_OFFSET = IO_WAIT;
  40. Status impala::GetThreadStats(int64_t tid, ThreadStats* stats) {
  41. DCHECK(stats != NULL);
  42. if (TICKS_PER_SEC <= 0) return Status("ThreadStats not supported");
  43. stringstream proc_path;
  44. proc_path << "/proc/self/task/" << tid << "/stat";
  45. if (!exists(proc_path.str())) return Status("Thread path does not exist");
  46. ifstream proc_file(proc_path.str().c_str());
  47. if (!proc_file.is_open()) return Status("Could not open ifstream");
  48. string buffer((istreambuf_iterator<char>(proc_file)),
  49. istreambuf_iterator<char>());
  50. vector<string> splits;
  51. split(splits, buffer, is_any_of(" "), token_compress_on);
  52. if (splits.size() < MAX_OFFSET) return Status("Unrecognised /proc format");
  53. StringParser::ParseResult parse_result;
  54. int64_t tmp = StringParser::StringToInt<int64_t>(splits[USER_TICKS].c_str(),
  55. splits[USER_TICKS].size(), &parse_result);
  56. if (parse_result == StringParser::PARSE_SUCCESS) {
  57. stats->user_ns = tmp * (1e9 / TICKS_PER_SEC);
  58. }
  59. tmp = StringParser::StringToInt<int64_t>(splits[KERNEL_TICKS].c_str(),
  60. splits[KERNEL_TICKS].size(), &parse_result);
  61. if (parse_result == StringParser::PARSE_SUCCESS) {
  62. stats->kernel_ns = tmp * (1e9 / TICKS_PER_SEC);
  63. }
  64. tmp = StringParser::StringToInt<int64_t>(splits[IO_WAIT].c_str(),
  65. splits[IO_WAIT].size(), &parse_result);
  66. if (parse_result == StringParser::PARSE_SUCCESS) {
  67. stats->iowait_ns = tmp * (1e9 / TICKS_PER_SEC);
  68. }
  69. return Status::OK;
  70. }
  71. bool impala::RunShellProcess(const string& cmd, string* msg) {
  72. DCHECK(msg != NULL);
  73. FILE* fp = popen(cmd.c_str(), "r");
  74. if (fp == NULL) {
  75. *msg = Substitute("Failed to execute shell cmd: '$0', error was: $1", cmd,
  76. GetStrErrMsg());
  77. return false;
  78. }
  79. // Read the first 1024 bytes of any output before pclose() so we have some idea of what
  80. // happened on failure.
  81. char buf[1024];
  82. size_t len = fread(buf, 1, 1024, fp);
  83. string output;
  84. output.assign(buf, len);
  85. // pclose() returns an encoded form of the sub-process' exit code.
  86. int status = pclose(fp);
  87. if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
  88. *msg = output;
  89. return true;
  90. }
  91. *msg = Substitute("Shell cmd: '$0' exited with an error: '$1'. Output was: '$2'", cmd,
  92. GetStrErrMsg(), output);
  93. return false;
  94. }