cmMakefileProfilingData.cxx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmMakefileProfilingData.h"
  4. #include <chrono>
  5. #include <stdexcept>
  6. #include <utility>
  7. #include <cm3p/json/value.h>
  8. #include <cm3p/json/writer.h>
  9. #include "cmsys/FStream.hxx"
  10. #include "cmsys/SystemInformation.hxx"
  11. #include "cmStringAlgorithms.h"
  12. #include "cmSystemTools.h"
  13. cmMakefileProfilingData::cmMakefileProfilingData(
  14. const std::string& profileStream)
  15. {
  16. std::ios::openmode omode = std::ios::out | std::ios::trunc;
  17. this->ProfileStream.open(profileStream.c_str(), omode);
  18. Json::StreamWriterBuilder wbuilder;
  19. this->JsonWriter =
  20. std::unique_ptr<Json::StreamWriter>(wbuilder.newStreamWriter());
  21. if (!this->ProfileStream.good()) {
  22. throw std::runtime_error(std::string("Unable to open: ") + profileStream);
  23. }
  24. this->ProfileStream << "[";
  25. }
  26. cmMakefileProfilingData::~cmMakefileProfilingData() noexcept
  27. {
  28. if (this->ProfileStream.good()) {
  29. try {
  30. this->ProfileStream << "]";
  31. this->ProfileStream.close();
  32. } catch (...) {
  33. cmSystemTools::Error("Error writing profiling output!");
  34. }
  35. }
  36. }
  37. void cmMakefileProfilingData::StartEntry(const std::string& category,
  38. const std::string& name,
  39. cm::optional<Json::Value> args)
  40. {
  41. /* Do not try again if we previously failed to write to output. */
  42. if (!this->ProfileStream.good()) {
  43. return;
  44. }
  45. try {
  46. if (this->ProfileStream.tellp() > 1) {
  47. this->ProfileStream << ",";
  48. }
  49. cmsys::SystemInformation info;
  50. Json::Value v;
  51. v["ph"] = "B";
  52. v["name"] = name;
  53. v["cat"] = category;
  54. v["ts"] = static_cast<Json::Value::UInt64>(
  55. std::chrono::duration_cast<std::chrono::microseconds>(
  56. std::chrono::steady_clock::now().time_since_epoch())
  57. .count());
  58. v["pid"] = static_cast<int>(info.GetProcessId());
  59. v["tid"] = 0;
  60. if (args) {
  61. v["args"] = *std::move(args);
  62. }
  63. this->JsonWriter->write(v, &this->ProfileStream);
  64. } catch (std::ios_base::failure& fail) {
  65. cmSystemTools::Error(
  66. cmStrCat("Failed to write to profiling output: ", fail.what()));
  67. } catch (...) {
  68. cmSystemTools::Error("Error writing profiling output!");
  69. }
  70. }
  71. void cmMakefileProfilingData::StopEntry()
  72. {
  73. /* Do not try again if we previously failed to write to output. */
  74. if (!this->ProfileStream.good()) {
  75. return;
  76. }
  77. try {
  78. this->ProfileStream << ",";
  79. cmsys::SystemInformation info;
  80. Json::Value v;
  81. v["ph"] = "E";
  82. v["ts"] = static_cast<Json::Value::UInt64>(
  83. std::chrono::duration_cast<std::chrono::microseconds>(
  84. std::chrono::steady_clock::now().time_since_epoch())
  85. .count());
  86. v["pid"] = static_cast<int>(info.GetProcessId());
  87. v["tid"] = 0;
  88. this->JsonWriter->write(v, &this->ProfileStream);
  89. } catch (std::ios_base::failure& fail) {
  90. cmSystemTools::Error(
  91. cmStrCat("Failed to write to profiling output:", fail.what()));
  92. } catch (...) {
  93. cmSystemTools::Error("Error writing profiling output!");
  94. }
  95. }
  96. cmMakefileProfilingData::RAII::RAII(cmMakefileProfilingData& data,
  97. const std::string& category,
  98. const std::string& name,
  99. cm::optional<Json::Value> args)
  100. : Data(&data)
  101. {
  102. this->Data->StartEntry(category, name, std::move(args));
  103. }
  104. cmMakefileProfilingData::RAII::RAII(RAII&& other) noexcept
  105. : Data(other.Data)
  106. {
  107. other.Data = nullptr;
  108. }
  109. cmMakefileProfilingData::RAII::~RAII()
  110. {
  111. if (this->Data) {
  112. this->Data->StopEntry();
  113. }
  114. }
  115. cmMakefileProfilingData::RAII& cmMakefileProfilingData::RAII::operator=(
  116. RAII&& other) noexcept
  117. {
  118. if (this->Data) {
  119. this->Data->StopEntry();
  120. }
  121. this->Data = other.Data;
  122. other.Data = nullptr;
  123. return *this;
  124. }