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