|
@@ -11,6 +11,7 @@
|
|
|
#include <cm/optional>
|
|
|
|
|
|
#include <cm3p/json/writer.h>
|
|
|
+#include <cm3p/uv.h>
|
|
|
|
|
|
#include "cmsys/Directory.hxx"
|
|
|
#include "cmsys/FStream.hxx"
|
|
@@ -22,9 +23,9 @@
|
|
|
#include "cmStringAlgorithms.h"
|
|
|
#include "cmSystemTools.h"
|
|
|
#include "cmTimestamp.h"
|
|
|
+#include "cmUVProcessChain.h"
|
|
|
|
|
|
-cmInstrumentation::cmInstrumentation(std::string const& binary_dir,
|
|
|
- bool clear_generated)
|
|
|
+cmInstrumentation::cmInstrumentation(std::string const& binary_dir)
|
|
|
{
|
|
|
std::string const uuid =
|
|
|
cmExperimental::DataForFeature(cmExperimental::Feature::Instrumentation)
|
|
@@ -32,9 +33,6 @@ cmInstrumentation::cmInstrumentation(std::string const& binary_dir,
|
|
|
this->binaryDir = binary_dir;
|
|
|
this->timingDirv1 =
|
|
|
cmStrCat(this->binaryDir, "/.cmake/instrumentation-", uuid, "/v1");
|
|
|
- if (clear_generated) {
|
|
|
- this->ClearGeneratedQueries();
|
|
|
- }
|
|
|
if (cm::optional<std::string> configDir =
|
|
|
cmSystemTools::GetCMakeConfigDirectory()) {
|
|
|
this->userTimingDirv1 =
|
|
@@ -57,24 +55,6 @@ void cmInstrumentation::LoadQueries()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-cmInstrumentation::cmInstrumentation(
|
|
|
- std::string const& binary_dir,
|
|
|
- std::set<cmInstrumentationQuery::Query>& queries_,
|
|
|
- std::set<cmInstrumentationQuery::Hook>& hooks_, std::string& callback)
|
|
|
-{
|
|
|
- this->binaryDir = binary_dir;
|
|
|
- this->timingDirv1 = cmStrCat(
|
|
|
- this->binaryDir, "/.cmake/instrumentation-",
|
|
|
- cmExperimental::DataForFeature(cmExperimental::Feature::Instrumentation)
|
|
|
- .Uuid,
|
|
|
- "/v1");
|
|
|
- this->queries = queries_;
|
|
|
- this->hooks = hooks_;
|
|
|
- if (!callback.empty()) {
|
|
|
- this->callbacks.push_back(callback);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
bool cmInstrumentation::ReadJSONQueries(std::string const& directory)
|
|
|
{
|
|
|
cmsys::Directory d;
|
|
@@ -99,21 +79,24 @@ void cmInstrumentation::ReadJSONQuery(std::string const& file)
|
|
|
this->callbacks);
|
|
|
}
|
|
|
|
|
|
-void cmInstrumentation::WriteJSONQuery()
|
|
|
+void cmInstrumentation::WriteJSONQuery(
|
|
|
+ std::set<cmInstrumentationQuery::Query> const& queries_,
|
|
|
+ std::set<cmInstrumentationQuery::Hook> const& hooks_,
|
|
|
+ std::vector<std::vector<std::string>> const& callbacks_)
|
|
|
{
|
|
|
Json::Value root;
|
|
|
root["version"] = 1;
|
|
|
root["queries"] = Json::arrayValue;
|
|
|
- for (auto const& query : this->queries) {
|
|
|
+ for (auto const& query : queries_) {
|
|
|
root["queries"].append(cmInstrumentationQuery::QueryString[query]);
|
|
|
}
|
|
|
root["hooks"] = Json::arrayValue;
|
|
|
- for (auto const& hook : this->hooks) {
|
|
|
+ for (auto const& hook : hooks_) {
|
|
|
root["hooks"].append(cmInstrumentationQuery::HookString[hook]);
|
|
|
}
|
|
|
root["callbacks"] = Json::arrayValue;
|
|
|
- for (auto const& callback : this->callbacks) {
|
|
|
- root["callbacks"].append(callback);
|
|
|
+ for (auto const& callback : callbacks_) {
|
|
|
+ root["callbacks"].append(cmInstrumentation::GetCommandStr(callback));
|
|
|
}
|
|
|
cmsys::Directory d;
|
|
|
int n = 0;
|
|
@@ -132,16 +115,27 @@ void cmInstrumentation::ClearGeneratedQueries()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-bool cmInstrumentation::HasQuery()
|
|
|
+bool cmInstrumentation::HasQuery() const
|
|
|
{
|
|
|
return this->hasQuery;
|
|
|
}
|
|
|
|
|
|
-bool cmInstrumentation::HasQuery(cmInstrumentationQuery::Query query)
|
|
|
+bool cmInstrumentation::HasQuery(cmInstrumentationQuery::Query query) const
|
|
|
{
|
|
|
return (this->queries.find(query) != this->queries.end());
|
|
|
}
|
|
|
|
|
|
+bool cmInstrumentation::HasHook(cmInstrumentationQuery::Hook hook) const
|
|
|
+{
|
|
|
+ return (this->hooks.find(hook) != this->hooks.end());
|
|
|
+}
|
|
|
+
|
|
|
+bool cmInstrumentation::HasPreOrPostBuildHook() const
|
|
|
+{
|
|
|
+ return (this->HasHook(cmInstrumentationQuery::Hook::PreBuild) ||
|
|
|
+ this->HasHook(cmInstrumentationQuery::Hook::PostBuild));
|
|
|
+}
|
|
|
+
|
|
|
int cmInstrumentation::CollectTimingData(cmInstrumentationQuery::Hook hook)
|
|
|
{
|
|
|
// Don't run collection if hook is disabled
|
|
@@ -462,7 +456,7 @@ std::string cmInstrumentation::GetCommandStr(
|
|
|
for (size_t i = 0; i < args.size(); ++i) {
|
|
|
command_str = cmStrCat(command_str, args[i]);
|
|
|
if (i < args.size() - 1) {
|
|
|
- command_str = cmStrCat(command_str, " ");
|
|
|
+ command_str = cmStrCat(command_str, ' ');
|
|
|
}
|
|
|
}
|
|
|
return command_str;
|
|
@@ -494,3 +488,46 @@ std::string cmInstrumentation::ComputeSuffixTime()
|
|
|
<< std::setfill('0') << std::setw(4) << tms;
|
|
|
return ss.str();
|
|
|
}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Called by ctest --start-instrumentation as part of the START_INSTRUMENTATION
|
|
|
+ * rule when using the Ninja generator.
|
|
|
+ * This creates a detached process which waits for the Ninja process to die
|
|
|
+ * before running the postBuild hook. In this way, the postBuild hook triggers
|
|
|
+ * after every ninja invocation, regardless of whether the build passed or
|
|
|
+ * failed.
|
|
|
+ */
|
|
|
+int cmInstrumentation::SpawnBuildDaemon()
|
|
|
+{
|
|
|
+ // preBuild Hook
|
|
|
+ this->CollectTimingData(cmInstrumentationQuery::Hook::PreBuild);
|
|
|
+
|
|
|
+ // postBuild Hook
|
|
|
+ if (this->HasHook(cmInstrumentationQuery::Hook::PostBuild)) {
|
|
|
+ auto ninja_pid = uv_os_getppid();
|
|
|
+ if (ninja_pid) {
|
|
|
+ std::vector<std::string> args;
|
|
|
+ args.push_back(cmSystemTools::GetCTestCommand());
|
|
|
+ args.push_back("--wait-and-collect-instrumentation");
|
|
|
+ args.push_back(this->binaryDir);
|
|
|
+ args.push_back(std::to_string(ninja_pid));
|
|
|
+ auto builder = cmUVProcessChainBuilder().SetDetached().AddCommand(args);
|
|
|
+ auto chain = builder.Start();
|
|
|
+ uv_run(&chain.GetLoop(), UV_RUN_DEFAULT);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Always called by ctest --wait-and-collect-instrumentation in a detached
|
|
|
+ * process. Waits for the given PID to end before running the postBuild hook.
|
|
|
+ *
|
|
|
+ * See SpawnBuildDaemon()
|
|
|
+ */
|
|
|
+int cmInstrumentation::CollectTimingAfterBuild(int ppid)
|
|
|
+{
|
|
|
+ while (0 == uv_kill(ppid, 0)) {
|
|
|
+ };
|
|
|
+ return this->CollectTimingData(cmInstrumentationQuery::Hook::PostBuild);
|
|
|
+}
|