1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24
25 #include "pxr/pxr.h"
26 #include "pxr/usd/pcp/statistics.h"
27 #include "pxr/usd/pcp/cache.h"
28 #include "pxr/usd/pcp/layerStackRegistry.h"
29 #include "pxr/usd/pcp/primIndex.h"
30 #include "pxr/usd/pcp/primIndex_Graph.h"
31
32 #include "pxr/base/arch/defines.h"
33
34 #include <memory>
35 #include <ostream>
36
37 PXR_NAMESPACE_OPEN_SCOPE
38
39 struct Pcp_GraphStats
40 {
41 public:
Pcp_GraphStatsPcp_GraphStats42 Pcp_GraphStats()
43 : numNodes(0)
44 , numImpliedInherits(0)
45 { }
46
47 size_t numNodes;
48 std::map<PcpArcType, size_t> typeToNumNodes;
49 size_t numImpliedInherits;
50 };
51
52 struct Pcp_CacheStats
53 {
54 public:
Pcp_CacheStatsPcp_CacheStats55 Pcp_CacheStats()
56 : numPrimIndexes(0)
57 , numPropertyIndexes(0)
58 , numGraphInstances(0)
59 { }
60
61 size_t numPrimIndexes;
62 size_t numPropertyIndexes;
63
64 Pcp_GraphStats allGraphStats;
65 Pcp_GraphStats culledGraphStats;
66
67 size_t numGraphInstances;
68 Pcp_GraphStats sharedAllGraphStats;
69 Pcp_GraphStats sharedCulledGraphStats;
70 std::map<size_t, size_t> mapFunctionSizeDistribution;
71 std::map<size_t, size_t> layerStackRelocationsSizeDistribution;
72 };
73
74 class Pcp_Statistics
75 {
76 public:
AccumulateGraphStats(const PcpPrimIndex & primIndex,Pcp_GraphStats * stats,bool culledNodesOnly)77 static void AccumulateGraphStats(
78 const PcpPrimIndex& primIndex,
79 Pcp_GraphStats* stats,
80 bool culledNodesOnly)
81 {
82 for (const PcpNodeRef &node: primIndex.GetNodeRange()) {
83 if (culledNodesOnly && !node.IsCulled()) {
84 continue;
85 }
86
87 ++(stats->numNodes);
88 ++(stats->typeToNumNodes[node.GetArcType()]);
89
90 const bool nodeIsImpliedInherit =
91 node.GetOriginNode() != node.GetParentNode();
92 if (nodeIsImpliedInherit) {
93 if (node.GetArcType() == PcpArcTypeInherit)
94 ++(stats->numImpliedInherits);
95 }
96 }
97 }
98
99 struct MapFuncHash {
operator ()Pcp_Statistics::MapFuncHash100 size_t operator()(const PcpMapFunction &m) const {
101 return m.Hash();
102 }
103 };
104
AccumulateCacheStats(const PcpCache * cache,Pcp_CacheStats * stats)105 static void AccumulateCacheStats(
106 const PcpCache* cache, Pcp_CacheStats* stats)
107 {
108 typedef std::shared_ptr<PcpPrimIndex_Graph::_SharedData>
109 _SharedNodePool;
110 std::set<_SharedNodePool> seenNodePools;
111 TfHashSet<PcpMapFunction, MapFuncHash> allMapFuncs;
112
113 TF_FOR_ALL(it, cache->_primIndexCache) {
114 const PcpPrimIndex& primIndex = it->second;
115 if (!primIndex.IsValid()) {
116 continue;
117 }
118
119 ++(stats->numPrimIndexes);
120
121 AccumulateGraphStats(
122 primIndex, &stats->allGraphStats,
123 /* culledNodesOnly = */ false);
124 AccumulateGraphStats(
125 primIndex, &stats->culledGraphStats,
126 /* culledNodesOnly = */ true);
127
128 if (seenNodePools.insert(primIndex.GetGraph()->_data).second) {
129 ++(stats->numGraphInstances);
130
131 AccumulateGraphStats(
132 primIndex, &stats->sharedAllGraphStats,
133 /* culledNodesOnly = */ false);
134 AccumulateGraphStats(
135 primIndex, &stats->sharedCulledGraphStats,
136 /* culledNodesOnly = */ true);
137 }
138
139 // Gather map functions
140 for (const PcpNodeRef &node: primIndex.GetNodeRange()) {
141 allMapFuncs.insert(node.GetMapToParent().Evaluate());
142 allMapFuncs.insert(node.GetMapToRoot().Evaluate());
143 }
144 }
145
146 TF_FOR_ALL(it, cache->_propertyIndexCache) {
147 const PcpPropertyIndex& propIndex = it->second;
148 if (propIndex.IsEmpty()) {
149 continue;
150 }
151
152 ++(stats->numPropertyIndexes);
153 }
154
155 // PcpMapFunction size distribution
156 TF_FOR_ALL(i, allMapFuncs) {
157 size_t size = i->GetSourceToTargetMap().size();
158 stats->mapFunctionSizeDistribution[size] += 1;
159 }
160
161 // PcpLayerStack _relocatesPrimPaths size distribution
162 for(const PcpLayerStackPtr &layerStack:
163 cache->_layerStackCache->GetAllLayerStacks()) {
164 size_t size = layerStack->GetPathsToPrimsWithRelocates().size();
165 stats->layerStackRelocationsSizeDistribution[size] += 1;
166 }
167 }
168
169 // Shamelessly stolen from Csd/Scene_PrimCachePopulation.cpp.
170 struct _Helper {
FormatNumberPcp_Statistics::_Helper171 static std::string FormatNumber(size_t n)
172 {
173 return TfStringPrintf("%zd", n);
174 }
175
FormatAveragePcp_Statistics::_Helper176 static std::string FormatAverage(size_t n, size_t d)
177 {
178 if (d == 0) {
179 return "N/A";
180 }
181 return TfStringPrintf("%'.3f", (double)n / (double)d);
182 }
183
FormatSizePcp_Statistics::_Helper184 static std::string FormatSize(size_t n)
185 {
186 if (n < 1024) {
187 return TfStringPrintf("%zd B", n);
188 }
189 if (n < 10 * 1024) {
190 return TfStringPrintf("%4.2f kB", (double)n / 1024.0);
191 }
192 if (n < 100 * 1024) {
193 return TfStringPrintf("%4.1f kB", (double)n / 1024.0);
194 }
195 if (n < 1024 * 1024) {
196 return TfStringPrintf("%3zd kB", n / 1024);
197 }
198 if (n < 10 * 1024 * 1024) {
199 return TfStringPrintf("%4.2f MB",
200 (double)n /(1024.0 * 1024.0));
201 }
202 if (n < 100 * 1024 * 1024) {
203 return TfStringPrintf("%4.1f MB",
204 (double)n /(1024.0 * 1024.0));
205 }
206 if (n < 1024 * 1024 * 1024) {
207 return TfStringPrintf("%3zd MB", n / (1024 * 1024));
208 }
209 return TfStringPrintf("%f GB", n / (1024.0 * 1024.0 * 1024.0));
210 }
211 };
212
PrintGraphStats(const Pcp_GraphStats & totalStats,const Pcp_GraphStats & culledStats,std::ostream & out)213 static void PrintGraphStats(
214 const Pcp_GraphStats& totalStats,
215 const Pcp_GraphStats& culledStats,
216 std::ostream& out)
217 {
218 using namespace std;
219
220 out << " Total nodes: "
221 << _Helper::FormatNumber(totalStats.numNodes) << endl;
222 out << " Total culled* nodes: "
223 << _Helper::FormatNumber(culledStats.numNodes) << endl;
224 out << " By type (total / culled*): " << endl;
225
226 std::map<PcpArcType, size_t> typeToNumNodes =
227 totalStats.typeToNumNodes;
228 std::map<PcpArcType, size_t> typeToNumCulledNodes =
229 culledStats.typeToNumNodes;
230 for (PcpArcType t = PcpArcTypeRoot; t != PcpNumArcTypes;
231 t = (PcpArcType)(t + 1)) {
232 const std::string nodeTypeName = TfEnum::GetDisplayName(t);
233 out << " " << nodeTypeName << ": "
234 << TfStringPrintf("%*s%s / %s",
235 (int)(31 - nodeTypeName.size()), "",
236 _Helper::FormatNumber(typeToNumNodes[t]).c_str(),
237 _Helper::FormatNumber(typeToNumCulledNodes[t]).c_str())
238 << endl;
239
240 if (t == PcpArcTypeInherit) {
241 out << " implied inherits: "
242 << TfStringPrintf("%*s%s / %s",
243 13, "",
244 _Helper::FormatNumber(totalStats.numImpliedInherits).c_str(),
245 _Helper::FormatNumber(culledStats.numImpliedInherits).c_str())
246 << endl;
247 }
248 }
249
250 out << " (*) This does not include culled nodes that were erased "
251 << "from the graph" << endl;
252 }
253
PrintCacheStats(const PcpCache * cache,std::ostream & out)254 static void PrintCacheStats(
255 const PcpCache* cache, std::ostream& out)
256 {
257 using namespace std;
258
259 Pcp_CacheStats stats;
260 AccumulateCacheStats(cache, &stats);
261
262 out << "PcpCache Statistics" << endl
263 << "-------------------" << endl;
264
265 out << "Entries: " << endl;
266 out << " Prim indexes: "
267 << _Helper::FormatNumber(stats.numPrimIndexes) << endl;
268 out << " Property indexes: "
269 << _Helper::FormatNumber(stats.numPropertyIndexes) << endl;
270 out << endl;
271
272 out << "Prim graphs: " << endl;
273 PrintGraphStats(
274 stats.allGraphStats, stats.culledGraphStats, out);
275 out << endl;
276
277 out << "Prim graphs (shared): " << endl;
278 out << " Graph instances: "
279 << _Helper::FormatNumber(stats.numGraphInstances) << endl;
280 PrintGraphStats(
281 stats.sharedAllGraphStats, stats.sharedCulledGraphStats, out);
282 out << endl;
283
284 out << "Memory usage: " << endl;
285 out << " sizeof(PcpMapFunction): "
286 << _Helper::FormatSize(sizeof(PcpMapFunction)) << endl;
287 out << " sizeof(PcpLayerStackPtr): "
288 << _Helper::FormatSize(sizeof(PcpLayerStackPtr)) << endl;
289 out << " sizeof(PcpLayerStackSite): "
290 << _Helper::FormatSize(sizeof(PcpLayerStackSite)) << endl;
291 out << " sizeof(PcpPrimIndex): "
292 << _Helper::FormatSize(sizeof(PcpPrimIndex)) << endl;
293 out << " sizeof(PcpPrimIndex_Graph): "
294 << _Helper::FormatSize(sizeof(PcpPrimIndex_Graph)) << endl;
295 out << " sizeof(PcpPrimIndex_Graph::_Node): "
296 << _Helper::FormatSize(sizeof(PcpPrimIndex_Graph::_Node)) << endl;
297 out << endl;
298
299 out << "PcpMapFunction size histogram: " << endl;
300 out << "SIZE COUNT" << endl;
301 TF_FOR_ALL(i, stats.mapFunctionSizeDistribution) {
302 printf("%zu %zu\n", i->first, i->second);
303 }
304
305 out << "PcpLayerStack pathsWithRelocates size histogram: " << endl;
306 out << "SIZE COUNT" << endl;
307 TF_FOR_ALL(i, stats.layerStackRelocationsSizeDistribution) {
308 printf("%zu %zu\n", i->first, i->second);
309 }
310 }
311
PrintPrimIndexStats(const PcpPrimIndex & primIndex,std::ostream & out)312 static void PrintPrimIndexStats(
313 const PcpPrimIndex& primIndex, std::ostream& out)
314 {
315 using namespace std;
316
317 Pcp_GraphStats totalStats, culledStats;
318 AccumulateGraphStats(
319 primIndex, &totalStats, /* culledNodesOnly = */ false);
320 AccumulateGraphStats(
321 primIndex, &culledStats, /* culledNodesOnly = */ true);
322
323 out << "PcpPrimIndex Statistics - "
324 << primIndex.GetRootNode().GetPath() << endl
325 << "-----------------------" << endl;
326
327 PrintGraphStats(totalStats, culledStats, out);
328 out << endl;
329 }
330 };
331
332 void
Pcp_PrintCacheStatistics(const PcpCache * cache,std::ostream & out)333 Pcp_PrintCacheStatistics(
334 const PcpCache* cache, std::ostream& out)
335 {
336 Pcp_Statistics::PrintCacheStats(cache, out);
337 }
338
339 void
Pcp_PrintPrimIndexStatistics(const PcpPrimIndex & primIndex,std::ostream & out)340 Pcp_PrintPrimIndexStatistics(
341 const PcpPrimIndex& primIndex, std::ostream& out)
342 {
343 Pcp_Statistics::PrintPrimIndexStats(primIndex, out);
344 }
345
346 PXR_NAMESPACE_CLOSE_SCOPE
347