Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(363)

Side by Side Diff: tools/skpdiff/SkDiffContext.cpp

Issue 60833002: fix multithread related crashes in skpdiff (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright 2013 Google Inc. 2 * Copyright 2013 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkBitmap.h" 8 #include "SkBitmap.h"
9 #include "SkImageDecoder.h" 9 #include "SkImageDecoder.h"
10 #include "SkOSFile.h" 10 #include "SkOSFile.h"
11 #include "SkRunnable.h" 11 #include "SkRunnable.h"
12 #include "SkStream.h" 12 #include "SkStream.h"
13 #include "SkTDict.h" 13 #include "SkTDict.h"
14 #include "SkThreadPool.h" 14 #include "SkThreadPool.h"
15 15
16 #include "SkDiffContext.h" 16 #include "SkDiffContext.h"
17 #include "SkImageDiffer.h" 17 #include "SkImageDiffer.h"
18 #include "skpdiff_util.h" 18 #include "skpdiff_util.h"
19 19
20 // Truncates the number of points of interests in JSON output to not freeze the parser 20 // Truncates the number of points of interests in JSON output to not freeze the parser
21 static const int kMaxPOI = 100; 21 static const int kMaxPOI = 100;
22 22
23 SkDiffContext::SkDiffContext() { 23 SkDiffContext::SkDiffContext() {
24 fRecords = NULL;
25 fDiffers = NULL; 24 fDiffers = NULL;
26 fDifferCount = 0; 25 fDifferCount = 0;
27 fThreadCount = SkThreadPool::kThreadPerCore; 26 fThreadCount = SkThreadPool::kThreadPerCore;
28 } 27 }
29 28
30 SkDiffContext::~SkDiffContext() { 29 SkDiffContext::~SkDiffContext() {
31 // Delete the record linked list
32 DiffRecord* currentRecord = fRecords;
33 while (NULL != currentRecord) {
34 DiffRecord* nextRecord = currentRecord->fNext;
35 SkDELETE(currentRecord);
36 currentRecord = nextRecord;
37 }
38
39 if (NULL != fDiffers) { 30 if (NULL != fDiffers) {
40 SkDELETE_ARRAY(fDiffers); 31 SkDELETE_ARRAY(fDiffers);
41 } 32 }
42 } 33 }
43 34
44 void SkDiffContext::setDiffers(const SkTDArray<SkImageDiffer*>& differs) { 35 void SkDiffContext::setDiffers(const SkTDArray<SkImageDiffer*>& differs) {
45 // Delete whatever the last array of differs was 36 // Delete whatever the last array of differs was
46 if (NULL != fDiffers) { 37 if (NULL != fDiffers) {
47 SkDELETE_ARRAY(fDiffers); 38 SkDELETE_ARRAY(fDiffers);
48 fDiffers = NULL; 39 fDiffers = NULL;
49 fDifferCount = 0; 40 fDifferCount = 0;
50 } 41 }
51 42
52 // Copy over the new differs 43 // Copy over the new differs
53 fDifferCount = differs.count(); 44 fDifferCount = differs.count();
54 fDiffers = SkNEW_ARRAY(SkImageDiffer*, fDifferCount); 45 fDiffers = SkNEW_ARRAY(SkImageDiffer*, fDifferCount);
55 differs.copy(fDiffers); 46 differs.copy(fDiffers);
56 } 47 }
57 48
58 void SkDiffContext::addDiff(const char* baselinePath, const char* testPath) { 49 void SkDiffContext::addDiff(const char* baselinePath, const char* testPath) {
59 // Load the images at the paths 50 // Load the images at the paths
60 SkBitmap baselineBitmap; 51 SkBitmap baselineBitmap;
61 SkBitmap testBitmap; 52 SkBitmap testBitmap;
53 SkAutoMutexAcquire imageLock(fImageMutex);
mtklein 2013/11/06 14:24:36 Put these in a {} block or just call .lock()? It'
djsollen 2013/11/06 15:01:58 The auto acquire is nice as it handles the cleanup
mtklein 2013/11/06 15:09:41 Ah. Brain fart. LGTM
62 if (!SkImageDecoder::DecodeFile(baselinePath, &baselineBitmap)) { 54 if (!SkImageDecoder::DecodeFile(baselinePath, &baselineBitmap)) {
mtklein 2013/11/06 14:24:36 Does this bottleneck you now? Is there a way to i
djsollen 2013/11/06 15:01:58 I'm sure it bottlenecks the process a little, but
63 SkDebugf("Failed to load bitmap \"%s\"\n", baselinePath); 55 SkDebugf("Failed to load bitmap \"%s\"\n", baselinePath);
64 return; 56 return;
65 } 57 }
66 if (!SkImageDecoder::DecodeFile(testPath, &testBitmap)) { 58 if (!SkImageDecoder::DecodeFile(testPath, &testBitmap)) {
67 SkDebugf("Failed to load bitmap \"%s\"\n", testPath); 59 SkDebugf("Failed to load bitmap \"%s\"\n", testPath);
68 return; 60 return;
69 } 61 }
62 imageLock.release();
70 63
71 // Setup a record for this diff 64 // Setup a record for this diff
72 DiffRecord* newRecord = SkNEW(DiffRecord); 65 SkAutoMutexAcquire recordsLock(fRecordMutex);
66 DiffRecord* newRecord = fRecords.addToHead(DiffRecord());
73 newRecord->fBaselinePath = baselinePath; 67 newRecord->fBaselinePath = baselinePath;
74 newRecord->fTestPath = testPath; 68 newRecord->fTestPath = testPath;
75 newRecord->fNext = fRecords; 69 recordsLock.release();
76 fRecords = newRecord;
77 70
78 // Perform each diff 71 // Perform each diff
79 for (int differIndex = 0; differIndex < fDifferCount; differIndex++) { 72 for (int differIndex = 0; differIndex < fDifferCount; differIndex++) {
80 SkImageDiffer* differ = fDiffers[differIndex]; 73 SkImageDiffer* differ = fDiffers[differIndex];
81 int diffID = differ->queueDiff(&baselineBitmap, &testBitmap); 74 int diffID = differ->queueDiff(&baselineBitmap, &testBitmap);
82 if (diffID >= 0) { 75 if (diffID >= 0) {
83 76
84 // Copy the results into data for this record 77 // Copy the results into data for this record
85 DiffData& diffData = newRecord->fDiffs.push_back(); 78 DiffData& diffData = newRecord->fDiffs.push_back();
86 79
87 diffData.fDiffName = differ->getName(); 80 diffData.fDiffName = differ->getName();
88 diffData.fResult = differ->getResult(diffID); 81 diffData.fResult = differ->getResult(diffID);
89 82
90 int poiCount = differ->getPointsOfInterestCount(diffID); 83 int poiCount = differ->getPointsOfInterestCount(diffID);
91 SkIPoint* poi = differ->getPointsOfInterest(diffID); 84 SkIPoint* poi = differ->getPointsOfInterest(diffID);
92 diffData.fPointsOfInterest.append(poiCount, poi); 85 diffData.fPointsOfInterest.append(poiCount, poi);
93 86
94 // Because we are doing everything synchronously for now, we are don e with the diff 87 // Because we are doing everything synchronously for now, we are don e with the diff
95 // after reading it. 88 // after reading it.
96 differ->deleteDiff(diffID); 89 differ->deleteDiff(diffID);
97 } 90 }
98 } 91 }
99
100 // if we get a difference and we want the alpha mask then compute it here.
101 } 92 }
102 93
103 class SkThreadedDiff : public SkRunnable { 94 class SkThreadedDiff : public SkRunnable {
104 public: 95 public:
105 SkThreadedDiff() : fDiffContext(NULL) { } 96 SkThreadedDiff() : fDiffContext(NULL) { }
106 97
107 void setup(SkDiffContext* diffContext, const SkString& baselinePath, const S kString& testPath) { 98 void setup(SkDiffContext* diffContext, const SkString& baselinePath, const S kString& testPath) {
108 fDiffContext = diffContext; 99 fDiffContext = diffContext;
109 fBaselinePath = baselinePath; 100 fBaselinePath = baselinePath;
110 fTestPath = testPath; 101 fTestPath = testPath;
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 171
181 for (int x = 0; x < baselineEntries.count(); x++) { 172 for (int x = 0; x < baselineEntries.count(); x++) {
182 runnableDiffs[x].setup(this, baselineEntries[x], testEntries[x]); 173 runnableDiffs[x].setup(this, baselineEntries[x], testEntries[x]);
183 threadPool.add(&runnableDiffs[x]); 174 threadPool.add(&runnableDiffs[x]);
184 } 175 }
185 176
186 threadPool.wait(); 177 threadPool.wait();
187 } 178 }
188 179
189 void SkDiffContext::outputRecords(SkWStream& stream, bool useJSONP) { 180 void SkDiffContext::outputRecords(SkWStream& stream, bool useJSONP) {
190 DiffRecord* currentRecord = fRecords; 181 SkTLList<DiffRecord>::Iter iter(fRecords, SkTLList<DiffRecord>::Iter::kHead_ IterStart);
182 DiffRecord* currentRecord = iter.get();
183
191 if (useJSONP) { 184 if (useJSONP) {
192 stream.writeText("var SkPDiffRecords = {\n"); 185 stream.writeText("var SkPDiffRecords = {\n");
193 } else { 186 } else {
194 stream.writeText("{\n"); 187 stream.writeText("{\n");
195 } 188 }
196 stream.writeText(" \"records\": [\n"); 189 stream.writeText(" \"records\": [\n");
197 while (NULL != currentRecord) { 190 while (NULL != currentRecord) {
198 stream.writeText(" {\n"); 191 stream.writeText(" {\n");
199 192
200 SkString differenceAbsPath = get_absolute_path(currentRecord->fDiffe rencePath); 193 SkString differenceAbsPath = get_absolute_path(currentRecord->fDiffe rencePath);
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 // JSON does not allow trailing commas 256 // JSON does not allow trailing commas
264 if (diffIndex + 1 < currentRecord->fDiffs.count()) { 257 if (diffIndex + 1 < currentRecord->fDiffs.count()) {
265 stream.writeText(","); 258 stream.writeText(",");
266 } 259 }
267 stream.writeText(" \n"); 260 stream.writeText(" \n");
268 } 261 }
269 stream.writeText(" ]\n"); 262 stream.writeText(" ]\n");
270 263
271 stream.writeText(" }"); 264 stream.writeText(" }");
272 265
266 currentRecord = iter.next();
267
273 // JSON does not allow trailing commas 268 // JSON does not allow trailing commas
274 if (NULL != currentRecord->fNext) { 269 if (NULL != currentRecord) {
275 stream.writeText(","); 270 stream.writeText(",");
276 } 271 }
277 stream.writeText("\n"); 272 stream.writeText("\n");
278 currentRecord = currentRecord->fNext;
279 } 273 }
280 stream.writeText(" ]\n"); 274 stream.writeText(" ]\n");
281 if (useJSONP) { 275 if (useJSONP) {
282 stream.writeText("};\n"); 276 stream.writeText("};\n");
283 } else { 277 } else {
284 stream.writeText("}\n"); 278 stream.writeText("}\n");
285 } 279 }
286 } 280 }
287 281
288 void SkDiffContext::outputCsv(SkWStream& stream) { 282 void SkDiffContext::outputCsv(SkWStream& stream) {
289 SkTDict<int> columns(2); 283 SkTDict<int> columns(2);
290 int cntColumns = 0; 284 int cntColumns = 0;
291 285
292 stream.writeText("key"); 286 stream.writeText("key");
293 287
294 DiffRecord* currentRecord = fRecords; 288 SkTLList<DiffRecord>::Iter iter(fRecords, SkTLList<DiffRecord>::Iter::kHead_ IterStart);
289 DiffRecord* currentRecord = iter.get();
295 290
296 // Write CSV header and create a dictionary of all columns. 291 // Write CSV header and create a dictionary of all columns.
297 while (NULL != currentRecord) { 292 while (NULL != currentRecord) {
298 for (int diffIndex = 0; diffIndex < currentRecord->fDiffs.count(); diffI ndex++) { 293 for (int diffIndex = 0; diffIndex < currentRecord->fDiffs.count(); diffI ndex++) {
299 DiffData& data = currentRecord->fDiffs[diffIndex]; 294 DiffData& data = currentRecord->fDiffs[diffIndex];
300 if (!columns.find(data.fDiffName)) { 295 if (!columns.find(data.fDiffName)) {
301 columns.set(data.fDiffName, cntColumns); 296 columns.set(data.fDiffName, cntColumns);
302 stream.writeText(", "); 297 stream.writeText(", ");
303 stream.writeText(data.fDiffName); 298 stream.writeText(data.fDiffName);
304 cntColumns++; 299 cntColumns++;
305 } 300 }
306 } 301 }
307 currentRecord = currentRecord->fNext; 302 currentRecord = iter.next();
308 } 303 }
309 stream.writeText("\n"); 304 stream.writeText("\n");
310 305
311 double values[100]; 306 double values[100];
312 SkASSERT(cntColumns < 100); // Make the array larger, if we ever have so ma ny diff types. 307 SkASSERT(cntColumns < 100); // Make the array larger, if we ever have so ma ny diff types.
313 308
314 currentRecord = fRecords; 309 SkTLList<DiffRecord>::Iter iter2(fRecords, SkTLList<DiffRecord>::Iter::kHead _IterStart);
310 currentRecord = iter2.get();
315 while (NULL != currentRecord) { 311 while (NULL != currentRecord) {
316 for (int i = 0; i < cntColumns; i++) { 312 for (int i = 0; i < cntColumns; i++) {
317 values[i] = -1; 313 values[i] = -1;
318 } 314 }
319 315
320 for (int diffIndex = 0; diffIndex < currentRecord->fDiffs.count(); diffI ndex++) { 316 for (int diffIndex = 0; diffIndex < currentRecord->fDiffs.count(); diffI ndex++) {
321 DiffData& data = currentRecord->fDiffs[diffIndex]; 317 DiffData& data = currentRecord->fDiffs[diffIndex];
322 int index = -1; 318 int index = -1;
323 SkAssertResult(columns.find(data.fDiffName, &index)); 319 SkAssertResult(columns.find(data.fDiffName, &index));
324 SkASSERT(index >= 0 && index < cntColumns); 320 SkASSERT(index >= 0 && index < cntColumns);
325 values[index] = data.fResult; 321 values[index] = data.fResult;
326 } 322 }
327 323
328 const char* filename = currentRecord->fBaselinePath.c_str() + 324 const char* filename = currentRecord->fBaselinePath.c_str() +
329 strlen(currentRecord->fBaselinePath.c_str()) - 1; 325 strlen(currentRecord->fBaselinePath.c_str()) - 1;
330 while (filename > currentRecord->fBaselinePath.c_str() && *(filename - 1 ) != '/') { 326 while (filename > currentRecord->fBaselinePath.c_str() && *(filename - 1 ) != '/') {
331 filename--; 327 filename--;
332 } 328 }
333 329
334 stream.writeText(filename); 330 stream.writeText(filename);
335 331
336 for (int i = 0; i < cntColumns; i++) { 332 for (int i = 0; i < cntColumns; i++) {
337 SkString str; 333 SkString str;
338 str.printf(", %f", values[i]); 334 str.printf(", %f", values[i]);
339 stream.writeText(str.c_str()); 335 stream.writeText(str.c_str());
340 } 336 }
341 stream.writeText("\n"); 337 stream.writeText("\n");
342 338
343 currentRecord = currentRecord->fNext; 339 currentRecord = iter2.next();
344 } 340 }
345 } 341 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698