1 //-*****************************************************************************
2 //
3 // Copyright (c) 2013,
4 //  Sony Pictures Imageworks Inc. and
5 //  Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd.
6 //
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are
11 // met:
12 // *       Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
14 // *       Redistributions in binary form must reproduce the above
15 // copyright notice, this list of conditions and the following disclaimer
16 // in the documentation and/or other materials provided with the
17 // distribution.
18 // *       Neither the name of Sony Pictures Imageworks, nor
19 // Industrial Light & Magic, nor the names of their contributors may be used
20 // to endorse or promote products derived from this software without specific
21 // prior written permission.
22 //
23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 //
35 //-*****************************************************************************
36 
37 #include <stdio.h>
38 #include <pthread.h>
39 #include <sys/time.h>
40 #include <Alembic/Abc/All.h>
41 #include <Alembic/AbcCoreFactory/All.h>
42 
getTimeSec()43 double getTimeSec()
44 {
45     timeval t;
46     gettimeofday(&t, 0);
47     return (double) t.tv_sec + (double) t.tv_usec / 1000000.0;
48 }
49 
50 using namespace Alembic;
51 
52 struct ArchiveAndData
53 {
54     Abc::IArchive archive;
55     std::vector< Abc::IArrayProperty > arrays;
56     std::vector< Abc::IScalarProperty > scalars;
57     std::size_t maxNumSamples;
58 };
59 
60 class ArchiveWalker;
61 
62 // used two different ways, one when traverse the archives
63 // (int archive is ignored), and one where we read samples
64 struct WorkUnit
65 {
66     int start;
67     int end;
68     int archive;
69     ArchiveWalker * walker;
70 };
71 
72 class ArchiveWalker
73 {
74 
75 public:
76 
77 std::vector< ArchiveAndData > mArchives;
78 
addArchive(Abc::IArchive iArchive)79 void addArchive(Abc::IArchive iArchive)
80 {
81     ArchiveAndData data;
82     data.archive = iArchive;
83     data.maxNumSamples = 0;
84     mArchives.push_back(data);
85 }
86 
readProps(WorkUnit & data)87 void readProps(WorkUnit & data)
88 {
89     size_t numArchives = mArchives.size();
90 
91     printf("readProps Work Unit Start %d %d\n",  data.start, data.end);
92 
93     double startTime = getTimeSec();
94     for (size_t a = 0; a < numArchives; ++a)
95     {
96         std::size_t numScalars = mArchives[a].scalars.size();
97         std::size_t numArrays = mArchives[a].arrays.size();
98         for (std::size_t i = 0; i < numScalars; ++i)
99         {
100             Abc::IScalarProperty & prop = mArchives[a].scalars[i];
101             int propEnd = std::min(data.end, (int) prop.getNumSamples());
102             if (prop.isConstant())
103             {
104                 propEnd = 1;
105             }
106 
107             for (int j = data.start; j < propEnd; ++j)
108             {
109                 if (prop.getDataType().getPod() != Alembic::Util::kStringPOD)
110                 {
111                     char buffer[4096];
112                     prop.get(buffer, j);
113                 }
114                 else
115                 {
116                     std::vector< std::string > buffer(
117                         prop.getDataType().getExtent());
118 
119                     prop.get(&buffer.front(), j);
120                 }
121             }
122         }
123 
124         for (std::size_t i = 0; i < numArrays; ++i)
125         {
126             Abc::IArrayProperty & prop = mArchives[a].arrays[i];
127             int propEnd = std::min(data.end, (int) prop.getNumSamples());
128             if (prop.isConstant())
129             {
130                 propEnd = 1;
131             }
132 
133             for (int j = data.start; j < propEnd; ++j)
134             {
135                 Alembic::AbcCoreAbstract::ArraySamplePtr samp;
136                 prop.get(samp, j);
137             }
138         }
139     }
140 
141     printf("readProps Work Unit End %d %d %f\n",
142            data.start, data.end, getTimeSec() - startTime);
143 
144     pthread_exit(0);
145 }
146 
findProps(int iArchiveNum,Abc::ICompoundProperty & iParent)147 void findProps(int iArchiveNum, Abc::ICompoundProperty & iParent)
148 {
149     size_t numProps = iParent.getNumProperties();
150     for (size_t i = 0; i < numProps; ++i)
151     {
152         const Alembic::AbcCoreAbstract::PropertyHeader & childHeader =
153             iParent.getPropertyHeader(i);
154         if (childHeader.isScalar())
155         {
156             Alembic::Abc::IScalarProperty prop(iParent, childHeader.getName());
157             if (prop.getNumSamples() > 0)
158             {
159                 mArchives[iArchiveNum].scalars.push_back(prop);
160                 mArchives[iArchiveNum].maxNumSamples = std::max(
161                     mArchives[iArchiveNum].maxNumSamples, prop.getNumSamples());
162             }
163         }
164         else if (childHeader.isArray())
165         {
166             Alembic::Abc::IArrayProperty prop(iParent, childHeader.getName());
167             if (prop.getNumSamples() > 0)
168             {
169                 mArchives[iArchiveNum].arrays.push_back(prop);
170                 mArchives[iArchiveNum].maxNumSamples = std::max(
171                     mArchives[iArchiveNum].maxNumSamples, prop.getNumSamples());
172             }
173         }
174         else
175         {
176             Alembic::Abc::ICompoundProperty prop(iParent,
177                 childHeader.getName());
178             findProps(iArchiveNum, prop);
179         }
180     }
181 }
182 
walkObjects(int iArchiveNum,Abc::IObject & iParent)183 void walkObjects(int iArchiveNum, Abc::IObject & iParent)
184 {
185     size_t numChildren = iParent.getNumChildren();
186     for (size_t i = 0; i < numChildren; i++)
187     {
188         const Abc::ObjectHeader & header = iParent.getChildHeader(i);
189         Abc::IObject child(iParent, header.getName());
190 
191         Abc::ICompoundProperty prop = child.getProperties();
192         findProps(iArchiveNum, prop);
193         walkObjects(iArchiveNum, child);
194     }
195 }
196 
walkArchives(WorkUnit & data)197 void walkArchives(WorkUnit & data)
198 {
199     printf("walkArchives Work Unit Start %d %d\n",  data.start, data.end);
200 
201     for (int i = data.start; i < data.end; ++i)
202     {
203         Abc::IObject top = mArchives[i].archive.getTop();
204         walkObjects(i, top);
205     }
206 
207     printf("walkArchives Work Unit End %d %d\n",  data.start, data.end);
208 }
209 
210 };
211 
readPropsWrap(void * ptr)212 void * readPropsWrap(void * ptr)
213 {
214     WorkUnit * data = (WorkUnit *) ptr;
215     data->walker->readProps(*data);
216     pthread_exit(0);
217 }
218 
walkArchivesWrap(void * ptr)219 void * walkArchivesWrap(void * ptr)
220 {
221     WorkUnit * data = (WorkUnit *) ptr;
222     data->walker->walkArchives(*data);
223     pthread_exit(0);
224 }
225 
main(int argc,char ** argv)226 int main(int argc, char ** argv)
227 {
228     if (argc < 4)
229     {
230         printf ("sceneWalk maxNumThreads ogawaStreams fileName [fileName ...]\n");
231         return 0;
232     }
233 
234     int maxThreads = atoi(argv[1]);
235     int ogawaStreams = atoi(argv[2]);
236 {
237     ArchiveWalker walker;
238 
239     Alembic::AbcCoreFactory::IFactory factory;
240     Alembic::AbcCoreFactory::IFactory::CoreType coreType;
241     factory.setOgawaNumStreams(ogawaStreams);
242     double time_start = getTimeSec();
243     for (int i = 3; i < argc; ++i)
244     {
245         Abc::IArchive archive = factory.getArchive(argv[i], coreType);
246 
247         if (archive.valid())
248         {
249             walker.addArchive(archive);
250         }
251     }
252 
253     int numTraverse = std::min(maxThreads, (int) walker.mArchives.size());
254     std::vector<WorkUnit> traverseArchives(numTraverse);
255     int lastEnd = 0;
256     int workSize = walker.mArchives.size() / numTraverse;
257     int workRem = 0;
258     if ((int) walker.mArchives.size() > numTraverse)
259         workRem = walker.mArchives.size() % numTraverse;
260 
261     pthread_t * walkThreads = new pthread_t[numTraverse];
262 
263     for (int i = 0; i < numTraverse; ++i)
264     {
265         traverseArchives[i].archive = i;
266         traverseArchives[i].start = lastEnd;
267         traverseArchives[i].walker = &walker;
268         lastEnd += workSize;
269         if (i < workRem)
270             lastEnd ++;
271         traverseArchives[i].end = lastEnd;
272 
273         pthread_create(&(walkThreads[i]), NULL, walkArchivesWrap,
274             (void *) &(traverseArchives[i]));
275     }
276 
277     for (int i = 0; i < numTraverse; ++i)
278     {
279         pthread_join(walkThreads[i], NULL);
280     }
281 
282     delete [] walkThreads;
283 
284     double totalTime = getTimeSec() - time_start;
285     printf ("Property Collection Wall Time: %f\n\n", totalTime);
286 
287     time_start = getTimeSec();
288 
289     size_t maxSamples = 0;
290     for (size_t i = 0; i < walker.mArchives.size(); ++i)
291     {
292         maxSamples = std::max(walker.mArchives[i].maxNumSamples, maxSamples);
293     }
294 
295     int numSamples = std::min(maxThreads, (int) maxSamples);
296     std::vector<WorkUnit> readSamples(numSamples);
297     lastEnd = 0;
298     workSize = maxSamples / numSamples;
299     workRem = 0;
300     if ((int) maxSamples > numSamples)
301         workRem = maxSamples % numSamples;
302 
303     pthread_t * readThreads = new pthread_t[numSamples];
304     for (int i = 0; i < numSamples; ++i)
305     {
306         readSamples[i].archive = i;  // ignored
307         readSamples[i].start = lastEnd;
308         readSamples[i].walker = &walker;
309         lastEnd += workSize;
310         if (i < workRem)
311             lastEnd ++;
312         readSamples[i].end = lastEnd;
313         pthread_create(&(readThreads[i]), NULL, readPropsWrap,
314             (void *) &(readSamples[i]));
315     }
316 
317     for (int i = 0; i < numSamples; ++i)
318     {
319         pthread_join(readThreads[i], NULL);
320     }
321 
322     delete [] readThreads;
323 
324     totalTime = getTimeSec()-time_start;
325     printf ("Property Read Wall Time: %f\n\n", totalTime);
326 }
327     return 0;
328 }
329