/src/CMake/Source/cmInstrumentation.h
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
2 | | file LICENSE.rst or https://cmake.org/licensing for details. */ |
3 | | #pragma once |
4 | | |
5 | | #include "cmConfigure.h" // IWYU pragma: keep |
6 | | |
7 | | #include <chrono> |
8 | | #include <functional> |
9 | | #include <map> |
10 | | #include <set> |
11 | | #include <string> |
12 | | #include <vector> |
13 | | |
14 | | #include <cm/memory> |
15 | | #include <cm/optional> |
16 | | |
17 | | #include <cm3p/json/value.h> |
18 | | #include <stddef.h> |
19 | | #include <stdint.h> |
20 | | |
21 | | #ifndef CMAKE_BOOTSTRAP |
22 | | # include <cmsys/SystemInformation.hxx> |
23 | | #endif |
24 | | |
25 | | #include "cmFileLock.h" |
26 | | #include "cmInstrumentationQuery.h" |
27 | | |
28 | | class cmGlobalGenerator; |
29 | | |
30 | | namespace cm { |
31 | | enum class TargetType; |
32 | | } // namespace cm |
33 | | |
34 | | class cmInstrumentation |
35 | | { |
36 | | public: |
37 | | using Callback = cmInstrumentationQuery::Callback; |
38 | | |
39 | | enum class LoadQueriesAfter |
40 | | { |
41 | | Yes, |
42 | | No |
43 | | }; |
44 | | cmInstrumentation(std::string const& binary_dir, |
45 | | LoadQueriesAfter loadQueries = LoadQueriesAfter::Yes); |
46 | | void LoadQueries(); |
47 | | void CheckCDashVariable(); |
48 | | struct TimeValue |
49 | | { |
50 | | long tv_sec; |
51 | | long tv_usec; |
52 | | }; |
53 | | |
54 | | struct ProcessMetrics |
55 | | { |
56 | | TimeValue ru_utime{}; |
57 | | TimeValue ru_stime{}; |
58 | | long ru_maxrss = 0; |
59 | | |
60 | | #ifndef CMAKE_BOOTSTRAP |
61 | | ProcessMetrics() = default; |
62 | | ProcessMetrics(cmsys::SystemInformation::ProcessResourceUsage const& usage) |
63 | | : ru_utime{ usage.ru_utime.tv_sec, usage.ru_utime.tv_usec } |
64 | | , ru_stime{ usage.ru_stime.tv_sec, usage.ru_stime.tv_usec } |
65 | | , ru_maxrss(usage.ru_maxrss) |
66 | 0 | { |
67 | 0 | } |
68 | | #endif |
69 | | }; |
70 | | |
71 | | struct CommandResult |
72 | | { |
73 | | int ExitCode; |
74 | | cm::optional<std::string> StdOut; |
75 | | cm::optional<std::string> StdErr; |
76 | | cm::optional<ProcessMetrics> ChildResourceUsage; |
77 | | }; |
78 | | |
79 | | int InstrumentCommand( |
80 | | std::string command_type, std::vector<std::string> const& command, |
81 | | std::function<CommandResult()> const& callback, |
82 | | cm::optional<std::map<std::string, std::string>> options = cm::nullopt, |
83 | | cm::optional<std::map<std::string, std::string>> arrayOptions = |
84 | | cm::nullopt, |
85 | | LoadQueriesAfter reloadQueriesAfterCommand = LoadQueriesAfter::No); |
86 | | std::string InstrumentTest( |
87 | | std::string const& name, std::string const& command, |
88 | | std::vector<std::string> const& args, int64_t result, |
89 | | std::chrono::steady_clock::time_point steadyStart, |
90 | | std::chrono::system_clock::time_point systemStart, std::string config, |
91 | | cm::optional<std::string> output = cm::nullopt, |
92 | | cm::optional<ProcessMetrics> processMetrics = cm::nullopt); |
93 | | void GetPreTestStats(); |
94 | | bool HasQuery() const; |
95 | | bool HasOption(cmInstrumentationQuery::Option option) const; |
96 | | bool HasHook(cmInstrumentationQuery::Hook hook) const; |
97 | | bool ReadJSONQueries(std::string const& directory); |
98 | | void ReadJSONQuery(std::string const& file); |
99 | | void WriteJSONQuery(cmInstrumentationQuery::Version dataVersion, |
100 | | std::set<cmInstrumentationQuery::Option> const& options, |
101 | | std::set<cmInstrumentationQuery::Hook> const& hooks, |
102 | | std::vector<std::vector<std::string>> const& callback); |
103 | | void AddCustomContent(std::string const& name, Json::Value const& contents); |
104 | | void WriteCMakeContent(std::unique_ptr<cmGlobalGenerator> const& gg); |
105 | | Json::Value DumpTargets(std::unique_ptr<cmGlobalGenerator> const& gg); |
106 | | void ClearGeneratedQueries(); |
107 | | int CollectTimingData(cmInstrumentationQuery::Hook hook); |
108 | | int SpawnBuildDaemon(); |
109 | | bool LockBuildDaemon(); |
110 | | bool LockIndexing(); |
111 | | int CollectTimingAfterBuild(int ppid); |
112 | | void AddHook(cmInstrumentationQuery::Hook hook); |
113 | | void AddOption(cmInstrumentationQuery::Option option); |
114 | | bool HasErrors() const; |
115 | | std::string const& GetCDashDir() const; |
116 | | std::string const& GetDataDir() const; |
117 | | enum LatestOrOldest |
118 | | { |
119 | | Latest, |
120 | | Oldest |
121 | | }; |
122 | | std::string GetFileByTimestamp(LatestOrOldest latestOrOldest, |
123 | | std::string const& dataSubdir, |
124 | | std::string const& exclude = ""); |
125 | | |
126 | | private: |
127 | | Json::Value ReadJsonSnippet(std::string const& file_name); |
128 | | bool AcquireLock(std::string const& lock_file, cmFileLock& lock, |
129 | | unsigned long timeout); |
130 | | enum class Atomic |
131 | | { |
132 | | No, |
133 | | Yes, |
134 | | }; |
135 | | void WriteInstrumentationJson(cmInstrumentationQuery::Version version, |
136 | | Json::Value& index, |
137 | | std::string const& directory, |
138 | | std::string const& file_name, |
139 | | Atomic atomic = Atomic::No); |
140 | | void InsertStaticSystemInformation(Json::Value& index); |
141 | | void GetDynamicSystemInformation(double& memory, double& load); |
142 | | void InsertDynamicSystemInformation(Json::Value& index, |
143 | | std::string const& instant); |
144 | | void InsertTimingData(Json::Value& root, |
145 | | std::chrono::steady_clock::time_point steadyStart, |
146 | | std::chrono::system_clock::time_point systemStart); |
147 | | bool HasQueryFile(std::string const& file); |
148 | | static std::string GetCommandStr(std::vector<std::string> const& args); |
149 | | static std::string ComputeSuffixHash(std::string const& command_str); |
150 | | static std::string ComputeSuffixTime( |
151 | | cm::optional<std::chrono::system_clock::time_point> time = cm::nullopt); |
152 | | static bool IsInstrumentableTargetType(cm::TargetType type); |
153 | | static Json::Value ResourceUsageToJSON(ProcessMetrics const& usage); |
154 | | void PrepareDataForCDash(std::string const& data_dir, |
155 | | std::string const& index_path); |
156 | | std::string GetCompileTraceFile(std::vector<std::string> const& command, |
157 | | Json::Value const& outputs, |
158 | | std::string const& workingDir); |
159 | | void CollectCompileTraceFile(Json::Value& root, std::string traceFile, |
160 | | long int oldTimestamp, |
161 | | std::string const& commandHash, |
162 | | std::string const& suffixTime); |
163 | | void RemoveCompileTraceFile(Json::Value const& snippetData); |
164 | | void RemoveOldFiles(std::string const& dataSubdir); |
165 | | void WriteTraceFile(Json::Value const& index, std::string const& trace_name); |
166 | | Json::Value BuildTraceEvent(std::vector<uint64_t>& workers, |
167 | | Json::Value const& snippetData); |
168 | | size_t AssignTargetToTraceThread(std::vector<uint64_t>& workers, |
169 | | uint64_t timeStart, uint64_t duration); |
170 | | void ResetQueries(); |
171 | | std::string binaryDir; |
172 | | std::string timingDirv1; |
173 | | std::string userTimingDirv1; |
174 | | std::string cdashDir; |
175 | | std::string dataDir; |
176 | | std::set<cmInstrumentationQuery::Option> options; |
177 | | std::set<cmInstrumentationQuery::Hook> hooks; |
178 | | std::vector<Callback> callbacks; |
179 | | std::vector<std::string> queryFiles; |
180 | | static std::map<std::string, std::string> cdashSnippetsMap; |
181 | | Json::Value preTestStats; |
182 | | std::string errorMsg; |
183 | | bool hasQuery = false; |
184 | | bool ranSystemChecks = false; |
185 | | bool ranOSCheck = false; |
186 | | Json::Value customContent = Json::objectValue; |
187 | | std::map<std::string, Json::Value> configureSnippetData; |
188 | | #ifndef CMAKE_BOOTSTRAP |
189 | | std::unique_ptr<cmsys::SystemInformation> systemInformation; |
190 | | cmsys::SystemInformation& GetSystemInformation(); |
191 | | #endif |
192 | | int writtenJsonQueries = 0; |
193 | | cmFileLock buildLock; // non-blocking |
194 | | cmFileLock indexLock; // never held alongside buildLock |
195 | | }; |