add initial support ofr multi-threaded execution

Review URL: https://codereview.chromium.org/27541003

git-svn-id: http://skia.googlecode.com/svn/trunk@11823 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tools/skpdiff/SkDiffContext.cpp b/tools/skpdiff/SkDiffContext.cpp
index 88941ca..07d304b 100644
--- a/tools/skpdiff/SkDiffContext.cpp
+++ b/tools/skpdiff/SkDiffContext.cpp
@@ -8,8 +8,10 @@
 #include "SkBitmap.h"
 #include "SkImageDecoder.h"
 #include "SkOSFile.h"
+#include "SkRunnable.h"
 #include "SkStream.h"
 #include "SkTDict.h"
+#include "SkThreadPool.h"
 
 #include "SkDiffContext.h"
 #include "SkImageDiffer.h"
@@ -22,6 +24,7 @@
     fRecords = NULL;
     fDiffers = NULL;
     fDifferCount = 0;
+    fThreadCount = SkThreadPool::kThreadPerCore;
 }
 
 SkDiffContext::~SkDiffContext() {
@@ -93,8 +96,29 @@
             differ->deleteDiff(diffID);
         }
     }
+
+    // if we get a difference and we want the alpha mask then compute it here.
 }
 
+class SkThreadedDiff : public SkRunnable {
+public:
+    SkThreadedDiff() : fDiffContext(NULL) { }
+
+    void setup(SkDiffContext* diffContext, const SkString& baselinePath, const SkString& testPath) {
+        fDiffContext = diffContext;
+        fBaselinePath = baselinePath;
+        fTestPath = testPath;
+    }
+
+    virtual void run() SK_OVERRIDE {
+        fDiffContext->addDiff(fBaselinePath.c_str(), fTestPath.c_str());
+    }
+
+private:
+    SkDiffContext* fDiffContext;
+    SkString fBaselinePath;
+    SkString fTestPath;
+};
 
 void SkDiffContext::diffDirectories(const char baselinePath[], const char testPath[]) {
     // Get the files in the baseline, we will then look for those inside the test path
@@ -104,9 +128,12 @@
         return;
     }
 
-    for (int baselineIndex = 0; baselineIndex < baselineEntries.count(); baselineIndex++) {
-        SkDebugf("[%i/%i] ", baselineIndex, baselineEntries.count());
-        const char* baseFilename = baselineEntries[baselineIndex].c_str();
+    SkThreadPool threadPool(fThreadCount);
+    SkTArray<SkThreadedDiff> runnableDiffs;
+    runnableDiffs.reset(baselineEntries.count());
+
+    for (int x = 0; x < baselineEntries.count(); x++) {
+        const char* baseFilename = baselineEntries[x].c_str();
 
         // Find the real location of each file to compare
         SkString baselineFile = SkOSPath::SkPathJoin(baselinePath, baseFilename);
@@ -115,11 +142,14 @@
         // Check that the test file exists and is a file
         if (sk_exists(testFile.c_str()) && !sk_isdir(testFile.c_str())) {
             // Queue up the comparison with the differ
-            this->addDiff(baselineFile.c_str(), testFile.c_str());
+            runnableDiffs[x].setup(this, baselineFile, testFile);
+            threadPool.add(&runnableDiffs[x]);
         } else {
             SkDebugf("Baseline file \"%s\" has no corresponding test file\n", baselineFile.c_str());
         }
     }
+
+    threadPool.wait();
 }
 
 
@@ -144,13 +174,16 @@
         return;
     }
 
-    for (int entryIndex = 0; entryIndex < baselineEntries.count(); entryIndex++) {
-        SkDebugf("[%i/%i] ", entryIndex, baselineEntries.count());
-        const char* baselineFilename = baselineEntries[entryIndex].c_str();
-        const char* testFilename     = testEntries    [entryIndex].c_str();
+    SkThreadPool threadPool(fThreadCount);
+    SkTArray<SkThreadedDiff> runnableDiffs;
+    runnableDiffs.reset(baselineEntries.count());
 
-        this->addDiff(baselineFilename, testFilename);
+    for (int x = 0; x < baselineEntries.count(); x++) {
+        runnableDiffs[x].setup(this, baselineEntries[x], testEntries[x]);
+        threadPool.add(&runnableDiffs[x]);
     }
+
+    threadPool.wait();
 }
 
 void SkDiffContext::outputRecords(SkWStream& stream, bool useJSONP) {
@@ -164,6 +197,7 @@
     while (NULL != currentRecord) {
         stream.writeText("        {\n");
 
+            SkString differenceAbsPath = get_absolute_path(currentRecord->fDifferencePath);
             SkString baselineAbsPath = get_absolute_path(currentRecord->fBaselinePath);
             SkString testAbsPath = get_absolute_path(currentRecord->fTestPath);
 
@@ -181,6 +215,10 @@
             stream.writeText(baseName.c_str());
             stream.writeText("\",\n");
 
+            stream.writeText("            \"differencePath\": \"");
+            stream.writeText(differenceAbsPath.c_str());
+            stream.writeText("\",\n");
+
             stream.writeText("            \"baselinePath\": \"");
             stream.writeText(baselineAbsPath.c_str());
             stream.writeText("\",\n");