mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-05 21:31:08 -06:00
instrumentation: Move target data into content files
Create a single place to store target data to prevent duplication. This moves `targetType` and `targetLabels` out of the snippet files and into a target map in the `cmakeContent` file referenced by each snippet. Fixes: #27244
This commit is contained in:
@@ -37,15 +37,14 @@ Whenever ``cmake_instrumentation`` is invoked, a query file is generated in
|
||||
``<build>/.cmake/instrumentation/v1/query/generated`` to enable instrumentation
|
||||
with the provided arguments.
|
||||
|
||||
.. _`cmake_instrumentation Configure Content`:
|
||||
.. _`cmake_instrumentation CUSTOM_CONTENT`:
|
||||
|
||||
Custom Configure Content
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Custom CMake Content
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The ``CUSTOM_CONTENT`` argument specifies certain data from configure time to
|
||||
include in each :ref:`cmake-instrumentation v1 Snippet File` that
|
||||
corresponds to the configure step associated with the command. This may be used
|
||||
to associate instrumentation data with certain information about its
|
||||
include in each :ref:`cmake-instrumentation v1 CMake Content File`. This
|
||||
may be used to associate instrumentation data with certain information about its
|
||||
configuration, such as the optimization level or whether it is part of a
|
||||
coverage build.
|
||||
|
||||
@@ -102,12 +101,12 @@ equivalent JSON query file.
|
||||
]
|
||||
}
|
||||
|
||||
This will also result in a configure content JSON being reported in each
|
||||
:ref:`cmake-instrumentation v1 Snippet File` with the following contents:
|
||||
This will also result in the following content included in each
|
||||
:ref:`cmake-instrumentation v1 CMake Content File`:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"custom": {
|
||||
"myString": "string",
|
||||
"myList": [
|
||||
"item1", "item2"
|
||||
|
||||
@@ -127,6 +127,10 @@ by setting :envvar:`CTEST_USE_VERBOSE_INSTRUMENTATION` to 1.
|
||||
Alternatively, you can use the `v1 Query Files`_ to enable instrumentation for
|
||||
CDash using the ``cdashSubmit`` and ``cdashVerbose`` options.
|
||||
|
||||
In order for the submitted ``Build.xml`` file to group the snippet files
|
||||
correctly, all configure and build commands should be executed with CTest in
|
||||
Dashboard Client mode.
|
||||
|
||||
.. _`cmake-instrumentation API v1`:
|
||||
|
||||
API v1
|
||||
@@ -164,7 +168,7 @@ subdirectories:
|
||||
|
||||
``data/content/``
|
||||
A subset of the collected data, containing any
|
||||
:ref:`cmake_instrumentation Configure Content` files.
|
||||
`v1 CMake Content Files <v1 CMake Content File_>`_.
|
||||
|
||||
``data/trace/``
|
||||
A subset of the collected data, containing the `Google Trace File`_ created
|
||||
@@ -302,9 +306,9 @@ Data version specifies the contents of the output files generated by the CMake
|
||||
instrumentation API as part of the `Data Collection`_ and `Indexing`_. A new
|
||||
version number will be created whenever previously included data is removed or
|
||||
reformatted such that scripts written to parse this data may become
|
||||
incompatible with the new format. There are three types of data files generated:
|
||||
the `v1 Snippet File`_, the `v1 Index File`_, and the `Google Trace File`_.
|
||||
When using the `API v1`_, these files live in
|
||||
incompatible with the new format. There are four types of data files generated:
|
||||
the `v1 Snippet File`_, `v1 Index File`_, `v1 CMake Content File`_, and the
|
||||
`Google Trace File`_. When using the `API v1`_, these files live in
|
||||
``<build>/.cmake/instrumentation/v1/data/`` under the project build tree.
|
||||
|
||||
.. _`cmake-instrumentation v1 Snippet File`:
|
||||
@@ -359,17 +363,9 @@ and contain the following data:
|
||||
* ``test``: a single test executed by CTest
|
||||
|
||||
``target``
|
||||
The CMake target associated with the command. Included when ``role`` is
|
||||
``compile``, or ``link``, and when ``role`` is ``custom`` and the custom
|
||||
command is attached to a target with :ref:`add_custom_command(TARGET)`.
|
||||
|
||||
``targetType``
|
||||
The :prop_tgt:`TYPE` of the target. Only included when ``role`` is
|
||||
``link``.
|
||||
|
||||
``targetLabels``
|
||||
The :prop_tgt:`LABELS` of the target. Only included when ``role`` is
|
||||
``link``.
|
||||
The CMake target associated with the command. Only included when ``role`` is
|
||||
``compile`` or ``link``. In conjunction with ``cmakeContent``, this can
|
||||
be used to look up the target type and labels.
|
||||
|
||||
``timeStart``
|
||||
Time at which the command started, expressed as the number of milliseconds
|
||||
@@ -422,10 +418,10 @@ and contain the following data:
|
||||
The Average CPU Load at ``timeStart + duration``, or ``null`` if it cannot
|
||||
be determined.
|
||||
|
||||
``configureContent``
|
||||
The path to a :ref:`cmake_instrumentation Configure Content` file located
|
||||
under ``data``, which may contain information about the CMake configure
|
||||
step corresponding to this data.
|
||||
``cmakeContent``
|
||||
The path to a `v1 CMake Content` file located under ``data``, which
|
||||
contains information about the CMake configure and generate steps
|
||||
responsible for generating the ``command`` in this snippet.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -451,7 +447,7 @@ Example:
|
||||
},
|
||||
"timeStart" : 1737053448177,
|
||||
"duration" : 31,
|
||||
"configureContent" : "content/configure-2025-07-11T12-46-32-0572.json"
|
||||
"cmakeContent" : "content/cmake-2025-07-11T12-46-32-0572.json"
|
||||
}
|
||||
|
||||
v1 Index File
|
||||
@@ -534,6 +530,33 @@ Example:
|
||||
"trace": "trace/trace-<timestamp>.json"
|
||||
}
|
||||
|
||||
.. _`cmake-instrumentation v1 CMake Content File`:
|
||||
|
||||
v1 CMake Content File
|
||||
---------------------
|
||||
|
||||
CMake content files contain information about the CMake configure and generate
|
||||
steps. Each `v1 Snippet File`_ provides the path to one of these files
|
||||
corresponding to the CMake invocation responsible for generating its command.
|
||||
|
||||
Each CMake content file contains the following:
|
||||
|
||||
``custom``
|
||||
An object containing arbitrary JSON data specified by the user with the
|
||||
:ref:`cmake_instrumentation CUSTOM_CONTENT` functionality of the
|
||||
:command:`cmake_instrumentation` command.
|
||||
|
||||
``targets``
|
||||
An object containing CMake targets, indexed by name, that have corresponding
|
||||
instrumentation data. Each target contains the following:
|
||||
|
||||
``type``
|
||||
The target type. One of ``EXECUTABLE``, ``STATIC_LIBRARY``,
|
||||
``SHARED_LIBRARY`` or ``OBJECT_LIBRARY``.
|
||||
|
||||
``labels``
|
||||
The :prop_tgt:`LABELS` property of the target.
|
||||
|
||||
Google Trace File
|
||||
-----------------
|
||||
|
||||
|
||||
@@ -626,48 +626,38 @@ void cmCTestBuildHandler::GenerateInstrumentationXML(cmXMLWriter& xml)
|
||||
xml.StartElement("Target");
|
||||
xml.Attribute("name", target_name);
|
||||
|
||||
// Check if we have a link snippet for this target.
|
||||
cmsys::Directory target_dir;
|
||||
if (!target_dir.Load(targets_dir.GetFilePath(i))) {
|
||||
cmSystemTools::Error(
|
||||
cmStrCat("Error loading directory ", targets_dir.GetFilePath(i)));
|
||||
}
|
||||
Json::Value link_item;
|
||||
for (unsigned int j = 0; j < target_dir.GetNumberOfFiles(); j++) {
|
||||
std::string fname = target_dir.GetFile(j);
|
||||
if (fname.rfind("link-", 0) == 0) {
|
||||
std::string fpath = target_dir.GetFilePath(j);
|
||||
cmJSONState parseState = cmJSONState(fpath, &link_item);
|
||||
if (!parseState.errors.empty()) {
|
||||
cmSystemTools::Error(parseState.GetErrorMessage(true));
|
||||
break;
|
||||
}
|
||||
|
||||
if (!link_item.isObject()) {
|
||||
std::string error_msg =
|
||||
cmStrCat("Expected snippet ", fpath, " to contain an object");
|
||||
cmSystemTools::Error(error_msg);
|
||||
break;
|
||||
}
|
||||
// Load latest CMake content file
|
||||
Json::Value target_data;
|
||||
std::string cmake_content_file =
|
||||
cmStrCat(CTest->GetInstrumentation().GetDataDir(), "/content/",
|
||||
this->CTest->GetInstrumentation().GetFileByTimestamp(
|
||||
cmInstrumentation::LatestOrOldest::Latest, "content"));
|
||||
if (!cmake_content_file.empty() &&
|
||||
cmSystemTools::FileExists(cmake_content_file)) {
|
||||
Json::Value cmake_content;
|
||||
cmJSONState parseState =
|
||||
cmJSONState(cmake_content_file, &cmake_content);
|
||||
if (!parseState.errors.empty()) {
|
||||
cmSystemTools::Error(parseState.GetErrorMessage(true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If so, parse targetType and targetLabels (optional) from it.
|
||||
if (link_item.isMember("targetType")) {
|
||||
target_type = link_item["targetType"].asString();
|
||||
}
|
||||
|
||||
xml.Attribute("type", target_type);
|
||||
|
||||
if (link_item.isMember("targetLabels") &&
|
||||
!link_item["targetLabels"].empty()) {
|
||||
xml.StartElement("Labels");
|
||||
for (auto const& json_label_item : link_item["targetLabels"]) {
|
||||
xml.Element("Label", json_label_item.asString());
|
||||
if (cmake_content.isMember("targets")) {
|
||||
target_data = cmake_content["targets"];
|
||||
}
|
||||
xml.EndElement(); // Labels
|
||||
}
|
||||
// Extract targetType and targetLabels
|
||||
if (target_data.isObject() && target_data.isMember(target_name)) {
|
||||
target_type = target_data[target_name]["type"].asString();
|
||||
if (!target_data[target_name]["labels"].empty()) {
|
||||
xml.StartElement("Labels");
|
||||
for (auto const& json_label_item :
|
||||
target_data[target_name]["labels"]) {
|
||||
xml.Element("Label", json_label_item.asString());
|
||||
}
|
||||
xml.EndElement(); // Labels
|
||||
}
|
||||
}
|
||||
xml.Attribute("type", target_type);
|
||||
|
||||
// Write instrumendation data for this target.
|
||||
std::string target_subdir = cmStrCat("build/targets/", target_name);
|
||||
|
||||
@@ -257,8 +257,6 @@ bool cmFastbuildNormalTargetGenerator::DetectBaseLinkerCommand(
|
||||
cmRulePlaceholderExpander::RuleVariables vars;
|
||||
vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
|
||||
vars.CMTargetType = cmState::GetTargetTypeName(targetType).c_str();
|
||||
vars.CMTargetLabels =
|
||||
this->GetGeneratorTarget()->GetTargetLabelsString().c_str();
|
||||
vars.Config = Config.c_str();
|
||||
vars.Language = linkLanguage.c_str();
|
||||
std::string const manifests =
|
||||
@@ -1133,8 +1131,6 @@ cmFastbuildNormalTargetGenerator::ComputeRuleVariables() const
|
||||
compileObjectVars.CMTargetName = GeneratorTarget->GetName().c_str();
|
||||
compileObjectVars.CMTargetType =
|
||||
cmState::GetTargetTypeName(GeneratorTarget->GetType()).c_str();
|
||||
compileObjectVars.CMTargetLabels =
|
||||
this->GetGeneratorTarget()->GetTargetLabelsString().c_str();
|
||||
compileObjectVars.Source = FASTBUILD_1_INPUT_PLACEHOLDER;
|
||||
compileObjectVars.Object = FASTBUILD_2_INPUT_PLACEHOLDER;
|
||||
compileObjectVars.ObjectDir =
|
||||
|
||||
@@ -2095,14 +2095,6 @@ std::vector<std::string> cmGeneratorTarget::GetAppleArchs(
|
||||
return std::move(archList.data());
|
||||
}
|
||||
|
||||
std::string const& cmGeneratorTarget::GetTargetLabelsString()
|
||||
{
|
||||
this->targetLabelsString = this->GetSafeProperty("LABELS");
|
||||
std::replace(this->targetLabelsString.begin(),
|
||||
this->targetLabelsString.end(), ';', ',');
|
||||
return this->targetLabelsString;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsSupportedClassifiedFlagsLanguage(std::string const& lang)
|
||||
@@ -2367,7 +2359,6 @@ cmGeneratorTarget::GetClassifiedFlagsForSource(cmSourceFile const* sf,
|
||||
cmRulePlaceholderExpander::RuleVariables vars;
|
||||
vars.CMTargetName = this->GetName().c_str();
|
||||
vars.CMTargetType = cmState::GetTargetTypeName(this->GetType()).c_str();
|
||||
vars.CMTargetLabels = this->GetTargetLabelsString().c_str();
|
||||
vars.Language = lang.c_str();
|
||||
|
||||
auto const sfPath = this->LocalGenerator->ConvertToOutputFormat(
|
||||
|
||||
@@ -535,8 +535,6 @@ public:
|
||||
std::vector<std::string> GetAppleArchs(std::string const& config,
|
||||
cm::optional<std::string> lang) const;
|
||||
|
||||
std::string const& GetTargetLabelsString();
|
||||
|
||||
// The classification of the flag.
|
||||
enum class FlagClassification
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <cm/memory>
|
||||
#include <cm/optional>
|
||||
#include <cmext/algorithm>
|
||||
|
||||
#include <cm3p/json/reader.h>
|
||||
#include <cm3p/json/version.h>
|
||||
@@ -27,8 +28,13 @@
|
||||
#include "cmExperimental.h"
|
||||
#include "cmFileLock.h"
|
||||
#include "cmFileLockResult.h"
|
||||
#include "cmGeneratorTarget.h"
|
||||
#include "cmGlobalGenerator.h"
|
||||
#include "cmInstrumentationQuery.h"
|
||||
#include "cmJSONState.h"
|
||||
#include "cmList.h"
|
||||
#include "cmLocalGenerator.h"
|
||||
#include "cmState.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmTimestamp.h"
|
||||
@@ -94,6 +100,7 @@ cmInstrumentation::cmInstrumentation(std::string const& binary_dir,
|
||||
this->timingDirv1 =
|
||||
cmStrCat(this->binaryDir, "/.cmake/instrumentation-", uuid, "/v1");
|
||||
this->cdashDir = cmStrCat(this->timingDirv1, "/cdash");
|
||||
this->dataDir = cmStrCat(this->timingDirv1, "/data");
|
||||
if (cm::optional<std::string> configDir =
|
||||
cmSystemTools::GetCMakeConfigDirectory()) {
|
||||
this->userTimingDirv1 =
|
||||
@@ -221,20 +228,45 @@ void cmInstrumentation::AddCustomContent(std::string const& name,
|
||||
this->customContent[name] = contents;
|
||||
}
|
||||
|
||||
void cmInstrumentation::WriteCustomContent()
|
||||
void cmInstrumentation::WriteCMakeContent(
|
||||
std::unique_ptr<cmGlobalGenerator> const& gg)
|
||||
{
|
||||
if (!this->customContent.isNull()) {
|
||||
this->WriteInstrumentationJson(
|
||||
this->customContent, "data/content",
|
||||
cmStrCat("configure-", this->ComputeSuffixTime(), ".json"));
|
||||
Json::Value root;
|
||||
root["targets"] = this->DumpTargets(gg);
|
||||
root["custom"] = this->customContent;
|
||||
this->WriteInstrumentationJson(
|
||||
root, "data/content",
|
||||
cmStrCat("cmake-", this->ComputeSuffixTime(), ".json"));
|
||||
}
|
||||
|
||||
Json::Value cmInstrumentation::DumpTargets(
|
||||
std::unique_ptr<cmGlobalGenerator> const& gg)
|
||||
{
|
||||
Json::Value targets = Json::objectValue;
|
||||
std::vector<cmGeneratorTarget*> targetList;
|
||||
for (auto const& lg : gg->GetLocalGenerators()) {
|
||||
cm::append(targetList, lg->GetGeneratorTargets());
|
||||
}
|
||||
for (cmGeneratorTarget* gt : targetList) {
|
||||
if (this->IsInstrumentableTargetType(gt->GetType())) {
|
||||
Json::Value target = Json::objectValue;
|
||||
auto labels = gt->GetSafeProperty("LABELS");
|
||||
target["labels"] = Json::arrayValue;
|
||||
for (auto const& item : cmList(labels)) {
|
||||
target["labels"].append(item);
|
||||
}
|
||||
target["type"] = cmState::GetTargetTypeName(gt->GetType()).c_str();
|
||||
targets[gt->GetName()] = target;
|
||||
}
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
std::string cmInstrumentation::GetFileByTimestamp(
|
||||
cmInstrumentation::LatestOrOldest order, std::string const& dataSubdir,
|
||||
std::string const& exclude)
|
||||
{
|
||||
std::string fullDir = cmStrCat(this->timingDirv1, "/data/", dataSubdir);
|
||||
std::string fullDir = cmStrCat(this->dataDir, '/', dataSubdir);
|
||||
std::string result;
|
||||
if (cmSystemTools::FileExists(fullDir)) {
|
||||
cmsys::Directory d;
|
||||
@@ -255,12 +287,11 @@ std::string cmInstrumentation::GetFileByTimestamp(
|
||||
|
||||
void cmInstrumentation::RemoveOldFiles(std::string const& dataSubdir)
|
||||
{
|
||||
std::string const dataSubdirPath =
|
||||
cmStrCat(this->timingDirv1, "/data/", dataSubdir);
|
||||
std::string const dataSubdirPath = cmStrCat(this->dataDir, '/', dataSubdir);
|
||||
std::string oldIndex =
|
||||
this->GetFileByTimestamp(LatestOrOldest::Oldest, "index");
|
||||
if (!oldIndex.empty()) {
|
||||
oldIndex = cmStrCat(this->timingDirv1, "/data/index/", oldIndex);
|
||||
oldIndex = cmStrCat(this->dataDir, "/index/", oldIndex);
|
||||
}
|
||||
if (cmSystemTools::FileExists(dataSubdirPath)) {
|
||||
std::string latestFile =
|
||||
@@ -316,10 +347,9 @@ int cmInstrumentation::CollectTimingData(cmInstrumentationQuery::Hook hook)
|
||||
}
|
||||
|
||||
// Touch index file immediately to claim snippets
|
||||
std::string const& directory = cmStrCat(this->timingDirv1, "/data");
|
||||
std::string suffix_time = ComputeSuffixTime();
|
||||
std::string const& index_name = cmStrCat("index-", suffix_time, ".json");
|
||||
std::string index_path = cmStrCat(directory, "/index/", index_name);
|
||||
std::string index_path = cmStrCat(this->dataDir, "/index/", index_name);
|
||||
cmSystemTools::Touch(index_path, true);
|
||||
|
||||
// Gather Snippets
|
||||
@@ -328,7 +358,7 @@ int cmInstrumentation::CollectTimingData(cmInstrumentationQuery::Hook hook)
|
||||
cmsys::Directory d;
|
||||
std::string last_index_name =
|
||||
this->GetFileByTimestamp(LatestOrOldest::Latest, "index", index_name);
|
||||
if (d.Load(directory)) {
|
||||
if (d.Load(this->dataDir)) {
|
||||
for (unsigned int i = 0; i < d.GetNumberOfFiles(); i++) {
|
||||
std::string fpath = d.GetFilePath(i);
|
||||
std::string fname = d.GetFile(i);
|
||||
@@ -343,7 +373,7 @@ int cmInstrumentation::CollectTimingData(cmInstrumentationQuery::Hook hook)
|
||||
Json::Value index(Json::objectValue);
|
||||
index["snippets"] = Json::arrayValue;
|
||||
index["hook"] = cmInstrumentationQuery::HookString[hook];
|
||||
index["dataDir"] = directory;
|
||||
index["dataDir"] = this->dataDir;
|
||||
index["buildDir"] = this->binaryDir;
|
||||
index["version"] = 1;
|
||||
if (this->HasOption(
|
||||
@@ -356,7 +386,7 @@ int cmInstrumentation::CollectTimingData(cmInstrumentationQuery::Hook hook)
|
||||
} else {
|
||||
int compare;
|
||||
std::string last_index_path =
|
||||
cmStrCat(directory, "/index/", last_index_name);
|
||||
cmStrCat(this->dataDir, "/index/", last_index_name);
|
||||
cmSystemTools::FileTimeCompare(file.second, last_index_path, &compare);
|
||||
if (compare == 1) {
|
||||
index["snippets"].append(file.first);
|
||||
@@ -383,12 +413,12 @@ int cmInstrumentation::CollectTimingData(cmInstrumentationQuery::Hook hook)
|
||||
|
||||
// Special case for CDash collation
|
||||
if (this->HasOption(cmInstrumentationQuery::Option::CDashSubmit)) {
|
||||
this->PrepareDataForCDash(directory, index_path);
|
||||
this->PrepareDataForCDash(this->dataDir, index_path);
|
||||
}
|
||||
|
||||
// Delete files
|
||||
for (auto const& f : index["snippets"]) {
|
||||
cmSystemTools::RemoveFile(cmStrCat(directory, '/', f.asString()));
|
||||
cmSystemTools::RemoveFile(cmStrCat(this->dataDir, '/', f.asString()));
|
||||
}
|
||||
cmSystemTools::RemoveFile(index_path);
|
||||
|
||||
@@ -605,11 +635,6 @@ int cmInstrumentation::InstrumentCommand(
|
||||
int ret = callback();
|
||||
root["result"] = ret;
|
||||
|
||||
// Write configure content if command was configure
|
||||
if (command_type == "configure") {
|
||||
this->WriteCustomContent();
|
||||
}
|
||||
|
||||
// Exit early if configure didn't generate a query
|
||||
if (reloadQueriesAfterCommand == LoadQueriesAfter::Yes) {
|
||||
this->LoadQueries();
|
||||
@@ -675,11 +700,16 @@ int cmInstrumentation::InstrumentCommand(
|
||||
root["role"] = command_type;
|
||||
root["workingDir"] = cmSystemTools::GetLogicalWorkingDirectory();
|
||||
|
||||
// Add custom configure content
|
||||
std::string contentFile =
|
||||
this->GetFileByTimestamp(LatestOrOldest::Latest, "content");
|
||||
if (!contentFile.empty()) {
|
||||
root["configureContent"] = cmStrCat("content/", contentFile);
|
||||
auto addCMakeContent = [this](Json::Value& root_) -> void {
|
||||
std::string contentFile =
|
||||
this->GetFileByTimestamp(LatestOrOldest::Latest, "content");
|
||||
if (!contentFile.empty()) {
|
||||
root_["cmakeContent"] = cmStrCat("content/", contentFile);
|
||||
}
|
||||
};
|
||||
// Don't insert path to CMake content until generate time
|
||||
if (command_type != "configure") {
|
||||
addCMakeContent(root);
|
||||
}
|
||||
|
||||
// Write Json
|
||||
@@ -690,7 +720,21 @@ int cmInstrumentation::InstrumentCommand(
|
||||
command_type, '-',
|
||||
this->ComputeSuffixHash(cmStrCat(command_str, info.GetProcessId())), '-',
|
||||
this->ComputeSuffixTime(endTime), ".json");
|
||||
this->WriteInstrumentationJson(root, "data", file_name);
|
||||
|
||||
// Don't write configure snippet until generate time
|
||||
if (command_type == "configure") {
|
||||
this->configureSnippetData = root;
|
||||
this->configureSnippetName = file_name;
|
||||
} else {
|
||||
// Add reference to CMake content and write out configure snippet after
|
||||
// generate
|
||||
if (command_type == "generate") {
|
||||
addCMakeContent(this->configureSnippetData);
|
||||
this->WriteInstrumentationJson(this->configureSnippetData, "data",
|
||||
this->configureSnippetName);
|
||||
}
|
||||
this->WriteInstrumentationJson(root, "data", file_name);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -736,6 +780,15 @@ std::string cmInstrumentation::ComputeSuffixTime(
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
bool cmInstrumentation::IsInstrumentableTargetType(
|
||||
cmStateEnums::TargetType type)
|
||||
{
|
||||
return type == cmStateEnums::TargetType::EXECUTABLE ||
|
||||
type == cmStateEnums::TargetType::SHARED_LIBRARY ||
|
||||
type == cmStateEnums::TargetType::STATIC_LIBRARY ||
|
||||
type == cmStateEnums::TargetType::OBJECT_LIBRARY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by ctest --start-instrumentation.
|
||||
*
|
||||
@@ -818,11 +871,16 @@ void cmInstrumentation::AddOption(cmInstrumentationQuery::Option option)
|
||||
this->options.insert(option);
|
||||
}
|
||||
|
||||
std::string const& cmInstrumentation::GetCDashDir()
|
||||
std::string const& cmInstrumentation::GetCDashDir() const
|
||||
{
|
||||
return this->cdashDir;
|
||||
}
|
||||
|
||||
std::string const& cmInstrumentation::GetDataDir() const
|
||||
{
|
||||
return this->dataDir;
|
||||
}
|
||||
|
||||
/** Copy the snippets referred to by an index file to a separate
|
||||
* directory where they will be parsed for submission to CDash.
|
||||
**/
|
||||
|
||||
@@ -17,13 +17,16 @@
|
||||
#include <cm3p/json/value.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "cmFileLock.h"
|
||||
#ifndef CMAKE_BOOTSTRAP
|
||||
# include <cmsys/SystemInformation.hxx>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cmFileLock.h"
|
||||
#include "cmInstrumentationQuery.h"
|
||||
#include "cmStateTypes.h"
|
||||
|
||||
class cmGlobalGenerator;
|
||||
|
||||
class cmInstrumentation
|
||||
{
|
||||
@@ -61,7 +64,8 @@ public:
|
||||
std::set<cmInstrumentationQuery::Hook> const& hooks,
|
||||
std::vector<std::vector<std::string>> const& callback);
|
||||
void AddCustomContent(std::string const& name, Json::Value const& contents);
|
||||
void WriteCustomContent();
|
||||
void WriteCMakeContent(std::unique_ptr<cmGlobalGenerator> const& gg);
|
||||
Json::Value DumpTargets(std::unique_ptr<cmGlobalGenerator> const& gg);
|
||||
void ClearGeneratedQueries();
|
||||
int CollectTimingData(cmInstrumentationQuery::Hook hook);
|
||||
int SpawnBuildDaemon();
|
||||
@@ -70,7 +74,16 @@ public:
|
||||
void AddHook(cmInstrumentationQuery::Hook hook);
|
||||
void AddOption(cmInstrumentationQuery::Option option);
|
||||
bool HasErrors() const;
|
||||
std::string const& GetCDashDir();
|
||||
std::string const& GetCDashDir() const;
|
||||
std::string const& GetDataDir() const;
|
||||
enum LatestOrOldest
|
||||
{
|
||||
Latest,
|
||||
Oldest
|
||||
};
|
||||
std::string GetFileByTimestamp(LatestOrOldest latestOrOldest,
|
||||
std::string const& dataSubdir,
|
||||
std::string const& exclude = "");
|
||||
|
||||
private:
|
||||
Json::Value ReadJsonSnippet(std::string const& file_name);
|
||||
@@ -89,6 +102,7 @@ private:
|
||||
static std::string ComputeSuffixHash(std::string const& command_str);
|
||||
static std::string ComputeSuffixTime(
|
||||
cm::optional<std::chrono::system_clock::time_point> time = cm::nullopt);
|
||||
static bool IsInstrumentableTargetType(cmStateEnums::TargetType type);
|
||||
void PrepareDataForCDash(std::string const& data_dir,
|
||||
std::string const& index_path);
|
||||
void RemoveOldFiles(std::string const& dataSubdir);
|
||||
@@ -97,18 +111,11 @@ private:
|
||||
Json::Value const& snippetData);
|
||||
size_t AssignTargetToTraceThread(std::vector<uint64_t>& workers,
|
||||
uint64_t timeStart, uint64_t duration);
|
||||
enum LatestOrOldest
|
||||
{
|
||||
Latest,
|
||||
Oldest
|
||||
};
|
||||
std::string GetFileByTimestamp(LatestOrOldest latestOrOldest,
|
||||
std::string const& dataSubdir,
|
||||
std::string const& exclude = "");
|
||||
std::string binaryDir;
|
||||
std::string timingDirv1;
|
||||
std::string userTimingDirv1;
|
||||
std::string cdashDir;
|
||||
std::string dataDir;
|
||||
std::set<cmInstrumentationQuery::Option> options;
|
||||
std::set<cmInstrumentationQuery::Hook> hooks;
|
||||
std::vector<std::string> callbacks;
|
||||
@@ -120,6 +127,8 @@ private:
|
||||
bool ranSystemChecks = false;
|
||||
bool ranOSCheck = false;
|
||||
Json::Value customContent;
|
||||
Json::Value configureSnippetData;
|
||||
std::string configureSnippetName;
|
||||
#ifndef CMAKE_BOOTSTRAP
|
||||
std::unique_ptr<cmsys::SystemInformation> systemInformation;
|
||||
cmsys::SystemInformation& GetSystemInformation();
|
||||
|
||||
@@ -1055,7 +1055,6 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand(
|
||||
vars.CMTargetName = target->GetName().c_str();
|
||||
vars.CMTargetType =
|
||||
cmState::GetTargetTypeName(target->GetType()).c_str();
|
||||
vars.CMTargetLabels = target->GetTargetLabelsString().c_str();
|
||||
std::string output;
|
||||
std::vector<std::string> const& outputs = ccg.GetOutputs();
|
||||
for (size_t i = 0; i < outputs.size(); ++i) {
|
||||
|
||||
@@ -545,8 +545,6 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
|
||||
vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
|
||||
vars.CMTargetType =
|
||||
cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str();
|
||||
vars.CMTargetLabels =
|
||||
this->GeneratorTarget->GetTargetLabelsString().c_str();
|
||||
vars.Language = linkLanguage.c_str();
|
||||
vars.Linker = linker.c_str();
|
||||
vars.AIXExports = aixExports.c_str();
|
||||
|
||||
@@ -792,8 +792,6 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
|
||||
vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
|
||||
vars.CMTargetType =
|
||||
cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str();
|
||||
vars.CMTargetLabels =
|
||||
this->GeneratorTarget->GetTargetLabelsString().c_str();
|
||||
vars.Language = linkLanguage.c_str();
|
||||
vars.Linker = linker.c_str();
|
||||
vars.AIXExports = aixExports.c_str();
|
||||
|
||||
@@ -932,7 +932,6 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
|
||||
vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
|
||||
vars.CMTargetType =
|
||||
cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str();
|
||||
vars.CMTargetLabels = this->GeneratorTarget->GetTargetLabelsString().c_str();
|
||||
vars.Language = lang.c_str();
|
||||
vars.Target = targetOutPathReal.c_str();
|
||||
vars.TargetPDB = targetOutPathPDB.c_str();
|
||||
@@ -1713,7 +1712,6 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule(
|
||||
vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
|
||||
vars.CMTargetType =
|
||||
cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()).c_str();
|
||||
vars.CMTargetLabels = this->GeneratorTarget->GetTargetLabelsString().c_str();
|
||||
vars.Language = "CUDA";
|
||||
vars.Object = output.c_str();
|
||||
vars.Fatbinary = fatbinaryOutput.c_str();
|
||||
|
||||
@@ -294,9 +294,6 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkRule(
|
||||
vars.CMTargetType =
|
||||
cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType())
|
||||
.c_str();
|
||||
vars.CMTargetLabels =
|
||||
this->GetGeneratorTarget()->GetTargetLabelsString().c_str();
|
||||
|
||||
vars.Language = "CUDA";
|
||||
std::string linker =
|
||||
this->GetGeneratorTarget()->GetLinkerTool("CUDA", config);
|
||||
@@ -404,9 +401,6 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRules(
|
||||
vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
|
||||
vars.CMTargetType =
|
||||
cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()).c_str();
|
||||
vars.CMTargetLabels =
|
||||
this->GetGeneratorTarget()->GetTargetLabelsString().c_str();
|
||||
|
||||
vars.Language = "CUDA";
|
||||
vars.Object = "$out";
|
||||
vars.Fatbinary = "$FATBIN";
|
||||
@@ -466,9 +460,6 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(
|
||||
cmRulePlaceholderExpander::RuleVariables vars;
|
||||
vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
|
||||
vars.CMTargetType = cmState::GetTargetTypeName(targetType).c_str();
|
||||
vars.CMTargetLabels =
|
||||
this->GetGeneratorTarget()->GetTargetLabelsString().c_str();
|
||||
|
||||
std::string linker = this->GetGeneratorTarget()->GetLinkerTool(config);
|
||||
vars.Linker = linker.c_str();
|
||||
std::string lang = this->TargetLinkLanguage(config);
|
||||
|
||||
@@ -596,7 +596,6 @@ cmNinjaRule GetScanRule(
|
||||
cmRulePlaceholderExpander::RuleVariables scanVars;
|
||||
scanVars.CMTargetName = vars.CMTargetName;
|
||||
scanVars.CMTargetType = vars.CMTargetType;
|
||||
scanVars.CMTargetLabels = vars.CMTargetLabels;
|
||||
scanVars.Language = vars.Language;
|
||||
scanVars.Object = "$OBJ_FILE";
|
||||
scanVars.PreprocessedSource = ppFileName.c_str();
|
||||
@@ -656,8 +655,6 @@ void cmNinjaTargetGenerator::WriteCompileRule(std::string const& lang,
|
||||
vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
|
||||
vars.CMTargetType =
|
||||
cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()).c_str();
|
||||
vars.CMTargetLabels =
|
||||
this->GetGeneratorTarget()->GetTargetLabelsString().c_str();
|
||||
vars.Language = lang.c_str();
|
||||
vars.Source = "$in";
|
||||
vars.Object = "$out";
|
||||
|
||||
@@ -266,13 +266,6 @@ std::string cmRulePlaceholderExpander::ExpandVariable(
|
||||
return this->ReplaceValues->CMTargetType;
|
||||
}
|
||||
}
|
||||
if (variable == "TARGET_LABELS") {
|
||||
if (this->ReplaceValues->CMTargetLabels) {
|
||||
return this->ReplaceValues->CMTargetLabels;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
if (this->ReplaceValues->Output) {
|
||||
if (variable == "OUTPUT") {
|
||||
return this->ReplaceValues->Output;
|
||||
|
||||
@@ -32,7 +32,6 @@ public:
|
||||
{
|
||||
char const* CMTargetName = nullptr;
|
||||
char const* CMTargetType = nullptr;
|
||||
char const* CMTargetLabels = nullptr;
|
||||
char const* TargetPDB = nullptr;
|
||||
char const* TargetCompilePDB = nullptr;
|
||||
char const* TargetVersionMajor = nullptr;
|
||||
|
||||
@@ -2761,8 +2761,7 @@ int cmake::ActualConfigure()
|
||||
"RULE_LAUNCH_LINK",
|
||||
cmStrCat(
|
||||
launcher, "--command-type link", common_args,
|
||||
"--output <TARGET> --target-type <TARGET_TYPE> "
|
||||
"--language <LANGUAGE> --target-labels \"<TARGET_LABELS>\" -- "));
|
||||
"--output <TARGET> --config <CONFIG> --language <LANGUAGE> -- "));
|
||||
this->State->SetGlobalProperty(
|
||||
"RULE_LAUNCH_CUSTOM",
|
||||
cmStrCat(launcher, "--command-type custom", common_args,
|
||||
@@ -3116,6 +3115,9 @@ int cmake::Generate()
|
||||
return -1;
|
||||
}
|
||||
this->GlobalGenerator->Generate();
|
||||
if (this->Instrumentation->HasQuery()) {
|
||||
this->Instrumentation->WriteCMakeContent(this->GlobalGenerator);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -10,25 +10,39 @@ if (NOT ${num} EQUAL 2)
|
||||
add_error("Found ${num} custom content files, expected 2.")
|
||||
endif()
|
||||
|
||||
# Check contents of configureContent files
|
||||
# Check contents of cmakeContent files
|
||||
set(firstFile "")
|
||||
foreach(content_file IN LISTS content_files)
|
||||
read_json("${content_file}" contents)
|
||||
json_assert_key("${content_file}" "${contents}" myString "string")
|
||||
json_assert_key("${content_file}" "${contents}" myBool "OFF")
|
||||
json_assert_key("${content_file}" "${contents}" myInt "1")
|
||||
json_assert_key("${content_file}" "${contents}" myFloat "2.5")
|
||||
json_assert_key("${content_file}" "${contents}" myTrue "ON")
|
||||
json_assert_key("${content_file}" "${contents}" myList "[ \"a\", \"b\", \"c\" ]")
|
||||
json_assert_key("${content_file}" "${contents}" myObject "{.*\"key\".*:.*\"value\".*}")
|
||||
|
||||
# Check custom content
|
||||
string(JSON custom GET "${contents}" custom)
|
||||
json_assert_key("${content_file}" "${custom}" myString "string")
|
||||
json_assert_key("${content_file}" "${custom}" myBool "OFF")
|
||||
json_assert_key("${content_file}" "${custom}" myInt "1")
|
||||
json_assert_key("${content_file}" "${custom}" myFloat "2.5")
|
||||
json_assert_key("${content_file}" "${custom}" myTrue "ON")
|
||||
json_assert_key("${content_file}" "${custom}" myList "\\[ \"a\", \"b\", \"c\" \\]")
|
||||
json_assert_key("${content_file}" "${custom}" myObject "{.*\"key\".*:.*\"value\".*}")
|
||||
if (NOT firstFile)
|
||||
set(firstFile "${content_file}")
|
||||
endif()
|
||||
if ("${content_file}" STREQUAL "${firstFile}")
|
||||
string(JSON firstN GET "${contents}" nConfigure)
|
||||
string(JSON firstN GET "${custom}" nConfigure)
|
||||
else()
|
||||
string(JSON secondN GET "${contents}" nConfigure)
|
||||
string(JSON secondN GET "${custom}" nConfigure)
|
||||
endif()
|
||||
|
||||
# Check target content
|
||||
string(JSON targets GET "${contents}" targets)
|
||||
string(JSON targetData GET "${targets}" lib)
|
||||
json_assert_key("${content_file}" "${targetData}" labels "\\[ \"label3\" \\]")
|
||||
json_assert_key("${content_file}" "${targetData}" type "STATIC_LIBRARY")
|
||||
|
||||
string(JSON targetData GET "${targets}" main)
|
||||
json_assert_key("${content_file}" "${targetData}" labels "\\[ \"label1\", \"label2\" \\]")
|
||||
json_assert_key("${content_file}" "${targetData}" type "EXECUTABLE")
|
||||
|
||||
endforeach()
|
||||
|
||||
# Ensure provided -DN=* arguments result in differing JSON contents
|
||||
@@ -40,7 +54,7 @@ endif()
|
||||
# Ensure snippets reference valid files
|
||||
foreach(snippet IN LISTS snippets)
|
||||
read_json("${snippet}" contents)
|
||||
string(JSON filename GET "${contents}" configureContent)
|
||||
string(JSON filename GET "${contents}" cmakeContent)
|
||||
if (NOT EXISTS "${v1}/data/${filename}")
|
||||
add_error("Reference to content file that does not exist.")
|
||||
endif()
|
||||
|
||||
@@ -51,36 +51,8 @@ foreach(snippet IN LISTS snippets)
|
||||
# Verify contents of link-* Snippets
|
||||
if (filename MATCHES "^link-")
|
||||
string(JSON target GET "${contents}" target)
|
||||
string(JSON targetType GET "${contents}" targetType)
|
||||
string(JSON targetLabels GET "${contents}" targetLabels)
|
||||
if (target MATCHES "main")
|
||||
if (NOT targetType MATCHES "EXECUTABLE")
|
||||
json_error("${snippet}" "Expected EXECUTABLE, target type was ${targetType}")
|
||||
endif()
|
||||
string(JSON nlabels LENGTH "${targetLabels}")
|
||||
if (NOT nlabels STREQUAL 2)
|
||||
json_error("${snippet}" "Missing Target Labels for: ${target}")
|
||||
else()
|
||||
string(JSON label1 GET "${contents}" targetLabels 0)
|
||||
string(JSON label2 GET "${contents}" targetLabels 1)
|
||||
if (NOT label1 MATCHES "label1" OR NOT label2 MATCHES "label2")
|
||||
json_error("${snippet}" "Missing Target Labels for: ${target}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
if (target MATCHES "lib")
|
||||
if (NOT targetType MATCHES "STATIC_LIBRARY")
|
||||
json_error("${snippet}" "Expected STATIC_LIBRARY, target type was ${targetType}")
|
||||
endif()
|
||||
string(JSON nlabels LENGTH "${targetLabels}")
|
||||
if (NOT nlabels STREQUAL 1)
|
||||
json_error("${snippet}" "Missing Target Labels for: ${target}")
|
||||
else()
|
||||
string(JSON label ERROR_VARIABLE noLabels GET "${contents}" targetLabels 0)
|
||||
if (NOT label MATCHES "label3")
|
||||
json_error("${snippet}" "Missing Target Labels for: ${target}")
|
||||
endif()
|
||||
endif()
|
||||
if (NOT target MATCHES "main|lib")
|
||||
json_error("${snippet}" "Unexpected link target: ${target}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@ function(snippet_has_fields snippet contents)
|
||||
json_has_key("${snippet}" "${contents}" target)
|
||||
json_has_key("${snippet}" "${contents}" outputs)
|
||||
json_has_key("${snippet}" "${contents}" outputSizes)
|
||||
json_has_key("${snippet}" "${contents}" targetType)
|
||||
json_has_key("${snippet}" "${contents}" targetLabels)
|
||||
json_has_key("${snippet}" "${contents}" config)
|
||||
json_has_key("${snippet}" "${contents}" language)
|
||||
elseif (filename MATCHES "^compile-*")
|
||||
|
||||
Reference in New Issue
Block a user