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