Merge topic 'profiling'

9aa4640792 cmake: add command line options to output script profiling data

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Ben Boeckel <ben.boeckel@kitware.com>
Acked-by: Pavel Solodovnikov <hellyeahdominate@gmail.com>
Acked-by: Leonid Pospelov <pospelovlm@yandex.ru>
Acked-by: Cristian Adam <cristian.adam@gmail.com>
Merge-request: !2760
This commit is contained in:
Brad King
2020-03-13 14:58:44 +00:00
committed by Kitware Robot
20 changed files with 304 additions and 2 deletions
+1
View File
@@ -354,6 +354,7 @@ set(SRCS
cmMakefileTargetGenerator.cxx
cmMakefileExecutableTargetGenerator.cxx
cmMakefileLibraryTargetGenerator.cxx
cmMakefileProfilingData.cxx
cmMakefileUtilityTargetGenerator.cxx
cmMessageType.h
cmMessenger.cxx
+14 -2
View File
@@ -60,6 +60,7 @@
#include "cmake.h"
#ifndef CMAKE_BOOTSTRAP
# include "cmMakefileProfilingData.h"
# include "cmVariableWatch.h"
#endif
@@ -372,19 +373,30 @@ void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const
class cmMakefileCall
{
public:
cmMakefileCall(cmMakefile* mf, cmCommandContext const& cc,
cmMakefileCall(cmMakefile* mf, cmListFileFunction const& lff,
cmExecutionStatus& status)
: Makefile(mf)
{
cmListFileContext const& lfc = cmListFileContext::FromCommandContext(
cc, this->Makefile->StateSnapshot.GetExecutionListFile());
lff, this->Makefile->StateSnapshot.GetExecutionListFile());
this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc);
++this->Makefile->RecursionDepth;
this->Makefile->ExecutionStatusStack.push_back(&status);
#if !defined(CMAKE_BOOTSTRAP)
if (this->Makefile->GetCMakeInstance()->IsProfilingEnabled()) {
this->Makefile->GetCMakeInstance()->GetProfilingOutput().StartEntry(lff,
lfc);
}
#endif
}
~cmMakefileCall()
{
#if !defined(CMAKE_BOOTSTRAP)
if (this->Makefile->GetCMakeInstance()->IsProfilingEnabled()) {
this->Makefile->GetCMakeInstance()->GetProfilingOutput().StopEntry();
}
#endif
this->Makefile->ExecutionStatusStack.pop_back();
--this->Makefile->RecursionDepth;
this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
+113
View File
@@ -0,0 +1,113 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmMakefileProfilingData.h"
#include <chrono>
#include <cstdint>
#include <stdexcept>
#include <vector>
#include "cmsys/FStream.hxx"
#include "cmsys/SystemInformation.hxx"
#include "cm_jsoncpp_value.h"
#include "cm_jsoncpp_writer.h"
#include "cmListFileCache.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
cmMakefileProfilingData::cmMakefileProfilingData(
const std::string& profileStream)
{
std::ios::openmode omode = std::ios::out | std::ios::trunc;
this->ProfileStream.open(profileStream.c_str(), omode);
Json::StreamWriterBuilder wbuilder;
this->JsonWriter =
std::unique_ptr<Json::StreamWriter>(wbuilder.newStreamWriter());
if (!this->ProfileStream.good()) {
throw std::runtime_error(std::string("Unable to open: ") + profileStream);
}
this->ProfileStream << "[";
};
cmMakefileProfilingData::~cmMakefileProfilingData() noexcept
{
if (this->ProfileStream.good()) {
try {
this->ProfileStream << "]";
this->ProfileStream.close();
} catch (...) {
cmSystemTools::Error("Error writing profiling output!");
}
}
}
void cmMakefileProfilingData::StartEntry(const cmListFileFunction& lff,
cmListFileContext const& lfc)
{
/* Do not try again if we previously failed to write to output. */
if (!this->ProfileStream.good()) {
return;
}
try {
if (this->ProfileStream.tellp() > 1) {
this->ProfileStream << ",";
}
cmsys::SystemInformation info;
Json::Value v;
v["ph"] = "B";
v["name"] = lff.Name.Original;
v["cat"] = "cmake";
v["ts"] = uint64_t(std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count());
v["pid"] = static_cast<int>(info.GetProcessId());
v["tid"] = 0;
Json::Value argsValue;
if (!lff.Arguments.empty()) {
std::string args;
for (const auto& a : lff.Arguments) {
args += (args.empty() ? "" : " ") + a.Value;
}
argsValue["functionArgs"] = args;
}
argsValue["location"] = lfc.FilePath + ":" + std::to_string(lfc.Line);
v["args"] = argsValue;
this->JsonWriter->write(v, &this->ProfileStream);
} catch (std::ios_base::failure& fail) {
cmSystemTools::Error(
cmStrCat("Failed to write to profiling output: ", fail.what()));
} catch (...) {
cmSystemTools::Error("Error writing profiling output!");
}
}
void cmMakefileProfilingData::StopEntry()
{
/* Do not try again if we previously failed to write to output. */
if (!this->ProfileStream.good()) {
return;
}
try {
this->ProfileStream << ",";
cmsys::SystemInformation info;
Json::Value v;
v["ph"] = "E";
v["ts"] = uint64_t(std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count());
v["pid"] = static_cast<int>(info.GetProcessId());
v["tid"] = 0;
this->JsonWriter->write(v, &this->ProfileStream);
} catch (std::ios_base::failure& fail) {
cmSystemTools::Error(
cmStrCat("Failed to write to profiling output:", fail.what()));
} catch (...) {
cmSystemTools::Error("Error writing profiling output!");
}
}
+29
View File
@@ -0,0 +1,29 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmMakefileProfilingData_h
#define cmMakefileProfilingData_h
#include <memory>
#include <string>
#include "cmsys/FStream.hxx"
namespace Json {
class StreamWriter;
}
class cmListFileContext;
struct cmListFileFunction;
class cmMakefileProfilingData
{
public:
cmMakefileProfilingData(const std::string&);
~cmMakefileProfilingData() noexcept;
void StartEntry(const cmListFileFunction& lff, cmListFileContext const& lfc);
void StopEntry();
private:
cmsys::ofstream ProfileStream;
std::unique_ptr<Json::StreamWriter> JsonWriter;
};
#endif
+57
View File
@@ -9,6 +9,7 @@
#include <initializer_list>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <utility>
#include <cm/memory>
@@ -39,6 +40,9 @@
#include "cmLinkLineComputer.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#if !defined(CMAKE_BOOTSTRAP)
# include "cmMakefileProfilingData.h"
#endif
#include "cmMessenger.h"
#include "cmState.h"
#include "cmStateDirectory.h"
@@ -613,6 +617,10 @@ void cmake::SetArgs(const std::vector<std::string>& args)
{
bool haveToolset = false;
bool havePlatform = false;
#if !defined(CMAKE_BOOTSTRAP)
std::string profilingFormat;
std::string profilingOutput;
#endif
for (unsigned int i = 1; i < args.size(); ++i) {
std::string const& arg = args[i];
if (arg.find("-H", 0) == 0 || arg.find("-S", 0) == 0) {
@@ -839,6 +847,20 @@ void cmake::SetArgs(const std::vector<std::string>& args)
return;
}
this->SetGlobalGenerator(std::move(gen));
#if !defined(CMAKE_BOOTSTRAP)
} else if (arg.find("--profiling-format", 0) == 0) {
profilingFormat = arg.substr(strlen("--profiling-format="));
if (profilingFormat.empty()) {
cmSystemTools::Error("No format specified for --profiling-format");
}
} else if (arg.find("--profiling-output", 0) == 0) {
profilingOutput = arg.substr(strlen("--profiling-output="));
profilingOutput = cmSystemTools::CollapseFullPath(profilingOutput);
cmSystemTools::ConvertToUnixSlashes(profilingOutput);
if (profilingOutput.empty()) {
cmSystemTools::Error("No path specified for --profiling-output");
}
#endif
}
// no option assume it is the path to the source or an existing build
else {
@@ -856,6 +878,29 @@ void cmake::SetArgs(const std::vector<std::string>& args)
}
}
#if !defined(CMAKE_BOOTSTRAP)
if (!profilingOutput.empty() || !profilingFormat.empty()) {
if (profilingOutput.empty()) {
cmSystemTools::Error(
"--profiling-format specified but no --profiling-output!");
return;
}
if (profilingFormat == "google-trace") {
try {
this->ProfilingOutput =
cm::make_unique<cmMakefileProfilingData>(profilingOutput);
} catch (std::runtime_error& e) {
cmSystemTools::Error(
cmStrCat("Could not start profiling: ", e.what()));
return;
}
} else {
cmSystemTools::Error("Invalid format specified for --profiling-format");
return;
}
}
#endif
const bool haveSourceDir = !this->GetHomeDirectory().empty();
const bool haveBinaryDir = !this->GetHomeOutputDirectory().empty();
@@ -2952,3 +2997,15 @@ void cmake::SetDeprecatedWarningsAsErrors(bool b)
" and functions.",
cmStateEnums::INTERNAL);
}
#if !defined(CMAKE_BOOTSTRAP)
cmMakefileProfilingData& cmake::GetProfilingOutput()
{
return *(this->ProfilingOutput);
}
bool cmake::IsProfilingEnabled() const
{
return static_cast<bool>(this->ProfilingOutput);
}
#endif
+12
View File
@@ -34,6 +34,9 @@ class cmFileTimeCache;
class cmGlobalGenerator;
class cmGlobalGeneratorFactory;
class cmMakefile;
#if !defined(CMAKE_BOOTSTRAP)
class cmMakefileProfilingData;
#endif
class cmMessenger;
class cmVariableWatch;
struct cmDocumentationEntry;
@@ -549,6 +552,11 @@ public:
bool GetRegenerateDuringBuild() const { return this->RegenerateDuringBuild; }
#if !defined(CMAKE_BOOTSTRAP)
cmMakefileProfilingData& GetProfilingOutput();
bool IsProfilingEnabled() const;
#endif
protected:
void RunCheckForUnusedVariables();
int HandleDeleteCacheVariables(const std::string& var);
@@ -657,6 +665,10 @@ private:
void AppendGlobalGeneratorsDocumentation(std::vector<cmDocumentationEntry>&);
void AppendExtraGeneratorsDocumentation(std::vector<cmDocumentationEntry>&);
#if !defined(CMAKE_BOOTSTRAP)
std::unique_ptr<cmMakefileProfilingData> ProfilingOutput;
#endif
};
#define CMAKE_STANDARD_OPTIONS_TABLE \
+6
View File
@@ -93,6 +93,12 @@ const char* cmDocumentationOptions[][2] = {
{ "--check-system-vars",
"Find problems with variable usage in system "
"files." },
# if !defined(CMAKE_BOOTSTRAP)
{ "--profiling-format=<fmt>", "Output data for profiling CMake scripts." },
{ "--profiling-output=<file>",
"Select an output path for the profiling data enabled through "
"--profiling-format." },
# endif
{ nullptr, nullptr }
};