Back to index

lightning-sunbird  0.9+nobinonly
TestFileInput2.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsIServiceManager.h"
00039 #include "nsIComponentRegistrar.h"
00040 #include "nsIInputStream.h"
00041 #include "nsIOutputStream.h"
00042 #include "nsIRunnable.h"
00043 #include "nsIThread.h"
00044 #include "nsCOMArray.h"
00045 #include "nsISimpleEnumerator.h"
00046 #include "prinrval.h"
00047 #include "nsIFileStreams.h"
00048 #include "nsIFileChannel.h"
00049 #include "nsILocalFile.h"
00050 #include "nsNetUtil.h"
00051 #include <stdio.h>
00052 
00054 
00055 #include <math.h>
00056 #include "prprf.h"
00057 #include "nsAutoLock.h"
00058 
00059 class nsTimeSampler {
00060 public:
00061     nsTimeSampler();
00062     void Reset();
00063     void StartTime();
00064     void EndTime();
00065     void AddTime(PRIntervalTime time);
00066     PRIntervalTime LastInterval() { return mLastInterval; }
00067     char* PrintStats();
00068 protected:
00069     PRIntervalTime      mStartTime;
00070     double              mSquares;
00071     double              mTotalTime;
00072     PRUint32            mCount;
00073     PRIntervalTime      mLastInterval;
00074 };
00075 
00076 nsTimeSampler::nsTimeSampler()
00077 {
00078     Reset();
00079 }
00080 
00081 void
00082 nsTimeSampler::Reset()
00083 {
00084     mStartTime = 0;
00085     mSquares = 0;
00086     mTotalTime = 0;
00087     mCount = 0;
00088     mLastInterval = 0;
00089 }
00090 
00091 void
00092 nsTimeSampler::StartTime()
00093 {
00094     mStartTime = PR_IntervalNow();
00095 }
00096 
00097 void
00098 nsTimeSampler::EndTime()
00099 {
00100     NS_ASSERTION(mStartTime != 0, "Forgot to call StartTime");
00101     PRIntervalTime endTime = PR_IntervalNow();
00102     mLastInterval = endTime - mStartTime;
00103     AddTime(mLastInterval);
00104     mStartTime = 0;
00105 }
00106 
00107 void
00108 nsTimeSampler::AddTime(PRIntervalTime time)
00109 {
00110     nsAutoCMonitor mon(this);
00111     mTotalTime += time;
00112     mSquares += (double)time * (double)time;
00113     mCount++;
00114 }
00115 
00116 char*
00117 nsTimeSampler::PrintStats()
00118 {
00119     double mean = mTotalTime / mCount;
00120     double variance = fabs(mSquares / mCount - mean * mean);
00121     double stddev = sqrt(variance);
00122     PRUint32 imean = (PRUint32)mean;
00123     PRUint32 istddev = (PRUint32)stddev;
00124     return PR_smprintf("%d +/- %d ms", 
00125                        PR_IntervalToMilliseconds(imean),
00126                        PR_IntervalToMilliseconds(istddev));
00127 }
00128 
00130 
00131 nsTimeSampler gTimeSampler;
00132 
00133 typedef nsresult (*CreateFun)(nsIRunnable* *result,
00134                               nsIFile* inPath, 
00135                               nsIFile* outPath, 
00136                               PRUint32 bufferSize);
00137 
00139 
00140 nsresult
00141 Copy(nsIInputStream* inStr, nsIOutputStream* outStr, 
00142      char* buf, PRUint32 bufSize, PRUint32 *copyCount)
00143 {
00144     nsresult rv;
00145     while (PR_TRUE) {
00146         PRUint32 count;
00147         rv = inStr->Read(buf, bufSize, &count);
00148         if (NS_FAILED(rv)) return rv;
00149         if (count == 0) break;
00150 
00151         PRUint32 writeCount;
00152         rv = outStr->Write(buf, count, &writeCount);
00153         if (NS_FAILED(rv)) return rv;
00154         NS_ASSERTION(writeCount == count, "didn't write all the data");
00155         *copyCount += writeCount;
00156     }
00157     rv = outStr->Flush();
00158     return rv;
00159 }
00160 
00162 
00163 class FileSpecWorker : public nsIRunnable {
00164 public:
00165 
00166     NS_IMETHOD Run() {
00167         nsresult rv;
00168 
00169         PRIntervalTime startTime = PR_IntervalNow();
00170         PRIntervalTime endTime;
00171         nsCOMPtr<nsIInputStream> inStr;
00172         nsCOMPtr<nsIOutputStream> outStr;
00173         PRUint32 copyCount = 0;
00174 
00175         // Open the input stream:
00176         nsCOMPtr<nsIInputStream> fileIn;
00177         rv = NS_NewLocalFileInputStream(getter_AddRefs(fileIn), mInPath);
00178         if (NS_FAILED(rv)) return rv;
00179 
00180         rv = NS_NewBufferedInputStream(getter_AddRefs(inStr), fileIn, 65535);
00181         if (NS_FAILED(rv)) return rv;
00182 
00183         // Open the output stream:
00184         nsCOMPtr<nsIOutputStream> fileOut;
00185         rv = NS_NewLocalFileOutputStream(getter_AddRefs(fileOut),
00186                                          mOutPath, 
00187                                          PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE,
00188                                          0664);
00189         if (NS_FAILED(rv)) return rv;
00190 
00191         rv = NS_NewBufferedOutputStream(getter_AddRefs(outStr), fileOut, 65535);
00192         if (NS_FAILED(rv)) return rv;
00193 
00194         // Copy from one to the other
00195         rv = Copy(inStr, outStr, mBuffer, mBufferSize, &copyCount);
00196         if (NS_FAILED(rv)) return rv;
00197 
00198         endTime = PR_IntervalNow();
00199         gTimeSampler.AddTime(endTime - startTime);
00200 
00201         return rv;
00202     }
00203 
00204     NS_DECL_ISUPPORTS
00205 
00206     FileSpecWorker()
00207         : mInPath(nsnull), mOutPath(nsnull), mBuffer(nsnull),
00208           mBufferSize(0)
00209     {
00210     }
00211 
00212     nsresult Init(nsIFile* inPath, nsIFile* outPath,
00213                   PRUint32 bufferSize)
00214     {
00215         mInPath = inPath;
00216         mOutPath = outPath;
00217         mBuffer = new char[bufferSize];
00218         mBufferSize = bufferSize;
00219         return (mInPath && mOutPath && mBuffer)
00220             ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00221     }
00222 
00223     static nsresult Create(nsIRunnable* *result,
00224                            nsIFile* inPath, 
00225                            nsIFile* outPath, 
00226                            PRUint32 bufferSize)
00227     {
00228         FileSpecWorker* worker = new FileSpecWorker();
00229         if (worker == nsnull)
00230             return NS_ERROR_OUT_OF_MEMORY;
00231         NS_ADDREF(worker);
00232 
00233         nsresult rv = worker->Init(inPath, outPath, bufferSize);
00234         if (NS_FAILED(rv)) {
00235             NS_RELEASE(worker);
00236             return rv;
00237         }
00238         *result = worker;
00239         return NS_OK;
00240     }
00241 
00242     virtual ~FileSpecWorker() {
00243         delete[] mBuffer;
00244     }
00245 
00246 protected:
00247     nsCOMPtr<nsIFile>   mInPath;
00248     nsCOMPtr<nsIFile>   mOutPath;
00249     char*               mBuffer;
00250     PRUint32            mBufferSize;
00251 };
00252 
00253 NS_IMPL_ISUPPORTS1(FileSpecWorker, nsIRunnable)
00254 
00255 
00256 
00257 #include "nsIIOService.h"
00258 #include "nsIChannel.h"
00259 
00260 class FileChannelWorker : public nsIRunnable {
00261 public:
00262 
00263     NS_IMETHOD Run() {
00264         nsresult rv;
00265 
00266         PRIntervalTime startTime = PR_IntervalNow();
00267         PRIntervalTime endTime;
00268         PRUint32 copyCount = 0;
00269         nsCOMPtr<nsIFileChannel> inCh;
00270         nsCOMPtr<nsIFileChannel> outCh;
00271         nsCOMPtr<nsIInputStream> inStr;
00272         nsCOMPtr<nsIOutputStream> outStr;
00273 
00274         rv = NS_NewLocalFileChannel(getter_AddRefs(inCh), mInPath);
00275         if (NS_FAILED(rv)) return rv;
00276 
00277         rv = inCh->Open(getter_AddRefs(inStr));
00278         if (NS_FAILED(rv)) return rv;
00279 
00280         //rv = NS_NewLocalFileChannel(getter_AddRefs(outCh), mOutPath);
00281         //if (NS_FAILED(rv)) return rv;
00282 
00283         //rv = outCh->OpenOutputStream(0, -1, 0, getter_AddRefs(outStr));
00284         //if (NS_FAILED(rv)) return rv;
00285 
00286         // Copy from one to the other
00287         rv = Copy(inStr, outStr, mBuffer, mBufferSize, &copyCount);
00288         if (NS_FAILED(rv)) return rv;
00289 
00290         endTime = PR_IntervalNow();
00291         gTimeSampler.AddTime(endTime - startTime);
00292 
00293         return rv;
00294     }
00295 
00296     NS_DECL_ISUPPORTS
00297 
00298     FileChannelWorker()
00299         : mInPath(nsnull), mOutPath(nsnull), mBuffer(nsnull),
00300           mBufferSize(0)
00301     {
00302     }
00303 
00304     nsresult Init(nsIFile* inPath, nsIFile* outPath,
00305                   PRUint32 bufferSize)
00306     {
00307         mInPath = inPath;
00308         mOutPath = outPath;
00309         mBuffer = new char[bufferSize];
00310         mBufferSize = bufferSize;
00311         return (mInPath && mOutPath && mBuffer)
00312             ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00313     }
00314 
00315     static nsresult Create(nsIRunnable* *result,
00316                            nsIFile* inPath, 
00317                            nsIFile* outPath, 
00318                            PRUint32 bufferSize)
00319     {
00320         FileChannelWorker* worker = new FileChannelWorker();
00321         if (worker == nsnull)
00322             return NS_ERROR_OUT_OF_MEMORY;
00323         NS_ADDREF(worker);
00324 
00325         nsresult rv = worker->Init(inPath, outPath, bufferSize);
00326         if (NS_FAILED(rv)) {
00327             NS_RELEASE(worker);
00328             return rv;
00329         }
00330         *result = worker;
00331         return NS_OK;
00332     }
00333 
00334     virtual ~FileChannelWorker() {
00335         delete[] mBuffer;
00336     }
00337 
00338 protected:
00339     nsCOMPtr<nsIFile>   mInPath;
00340     nsCOMPtr<nsIFile>   mOutPath;
00341     char*               mBuffer;
00342     PRUint32            mBufferSize;
00343 };
00344 
00345 NS_IMPL_ISUPPORTS1(FileChannelWorker, nsIRunnable)
00346 
00347 
00348 
00349 void
00350 Test(CreateFun create, PRUint32 count,
00351      nsIFile* inDirSpec, nsIFile* outDirSpec, PRUint32 bufSize)
00352 {
00353     nsresult rv;
00354     PRUint32 i;
00355 
00356     nsCAutoString inDir;
00357     nsCAutoString outDir;
00358     (void)inDirSpec->GetNativePath(inDir);
00359     (void)outDirSpec->GetNativePath(outDir);
00360     printf("###########\nTest: from %s to %s, bufSize = %d\n",
00361            inDir.get(), outDir.get(), bufSize);
00362     gTimeSampler.Reset();
00363     nsTimeSampler testTime;
00364     testTime.StartTime();
00365 
00366     nsCOMArray<nsIThread> threads;
00367 
00368     nsCOMPtr<nsISimpleEnumerator> entries;
00369     rv = inDirSpec->GetDirectoryEntries(getter_AddRefs(entries));
00370     NS_ASSERTION(NS_SUCCEEDED(rv), "GetDirectoryEntries failed");
00371 
00372     i = 0;
00373     PRBool hasMore;
00374     while (i < count && NS_SUCCEEDED(entries->HasMoreElements(&hasMore)) && hasMore) {
00375         nsCOMPtr<nsISupports> next;
00376         rv = entries->GetNext(getter_AddRefs(next));
00377         if (NS_FAILED(rv)) goto done;
00378 
00379         nsCOMPtr<nsIFile> inSpec = do_QueryInterface(next, &rv);
00380         if (NS_FAILED(rv)) goto done;
00381 
00382         nsCOMPtr<nsIFile> outSpec;
00383         rv = outDirSpec->Clone(getter_AddRefs(outSpec)); // don't munge the original
00384         if (NS_FAILED(rv)) goto done;
00385 
00386         nsCAutoString leafName;
00387         rv = inSpec->GetNativeLeafName(leafName);
00388         if (NS_FAILED(rv)) goto done;
00389 
00390         rv = outSpec->AppendNative(leafName);
00391         if (NS_FAILED(rv)) goto done;
00392 
00393         PRBool exists;
00394         rv = outSpec->Exists(&exists);
00395         if (NS_FAILED(rv)) goto done;
00396 
00397         if (exists) {
00398             rv = outSpec->Remove(PR_FALSE);
00399             if (NS_FAILED(rv)) goto done;
00400         }
00401 
00402         nsCOMPtr<nsIThread> thread;
00403         nsCOMPtr<nsIRunnable> worker;
00404         rv = create(getter_AddRefs(worker), 
00405                     inSpec,
00406                     outSpec,
00407                     bufSize);
00408         if (NS_FAILED(rv)) goto done;
00409 
00410         rv = NS_NewThread(getter_AddRefs(thread), worker, 0, PR_JOINABLE_THREAD);
00411         if (NS_FAILED(rv)) goto done;
00412 
00413         PRBool inserted = threads.InsertObjectAt(thread, i);
00414         NS_ASSERTION(inserted, "not inserted");
00415 
00416         i++;
00417     }
00418 
00419     PRUint32 j;
00420     for (j = 0; j < i; j++) {
00421         nsIThread* thread = threads.ObjectAt(j);
00422         thread->Join();
00423     }
00424 
00425   done:
00426     NS_ASSERTION(rv == NS_OK, "failed");
00427 
00428     testTime.EndTime();
00429     char* testStats = testTime.PrintStats();
00430     char* workerStats = gTimeSampler.PrintStats();
00431     printf("  threads = %d\n  work time = %s,\n  test time = %s\n",
00432            i, workerStats, testStats);
00433     PR_smprintf_free(workerStats);
00434     PR_smprintf_free(testStats);
00435 }
00436 
00438 
00439 int
00440 main(int argc, char* argv[])
00441 {
00442     nsresult rv;
00443 
00444     if (argc < 2) {
00445         printf("usage: %s <in-dir> <out-dir>\n", argv[0]);
00446         return -1;
00447     }
00448     char* inDir = argv[1];
00449     char* outDir = argv[2];
00450 
00451     {
00452         nsCOMPtr<nsIServiceManager> servMan;
00453         NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull);
00454         nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(servMan);
00455         NS_ASSERTION(registrar, "Null nsIComponentRegistrar");
00456         if (registrar)
00457             registrar->AutoRegister(nsnull);
00458 
00459         nsCOMPtr<nsILocalFile> inDirFile;
00460         rv = NS_NewNativeLocalFile(nsDependentCString(inDir), PR_FALSE, getter_AddRefs(inDirFile));
00461         if (NS_FAILED(rv)) return rv;
00462 
00463         nsCOMPtr<nsILocalFile> outDirFile;
00464         rv = NS_NewNativeLocalFile(nsDependentCString(outDir), PR_FALSE, getter_AddRefs(outDirFile));
00465         if (NS_FAILED(rv)) return rv;
00466 
00467         CreateFun create = FileChannelWorker::Create;
00468         Test(create, 1, inDirFile, outDirFile, 16 * 1024);
00469 #if 1
00470         printf("FileChannelWorker *****************************\n");
00471         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00472         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00473         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00474         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00475         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00476         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00477         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00478         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00479         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00480 #endif
00481         create = FileSpecWorker::Create;
00482         printf("FileSpecWorker ********************************\n");
00483 #if 1
00484         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00485         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00486         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00487         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00488         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00489         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00490         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00491         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00492         Test(create, 20, inDirFile, outDirFile, 16 * 1024);
00493 #endif
00494 #if 1
00495         Test(create, 20, inDirFile, outDirFile, 4 * 1024);
00496         Test(create, 20, inDirFile, outDirFile, 4 * 1024);
00497         Test(create, 20, inDirFile, outDirFile, 4 * 1024);
00498         Test(create, 20, inDirFile, outDirFile, 4 * 1024);
00499         Test(create, 20, inDirFile, outDirFile, 4 * 1024);
00500         Test(create, 20, inDirFile, outDirFile, 4 * 1024);
00501         Test(create, 20, inDirFile, outDirFile, 4 * 1024);
00502         Test(create, 20, inDirFile, outDirFile, 4 * 1024);
00503         Test(create, 20, inDirFile, outDirFile, 4 * 1024);
00504 #endif
00505     } // this scopes the nsCOMPtrs
00506     // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
00507     rv = NS_ShutdownXPCOM(nsnull);
00508     NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed");
00509     return 0;
00510 }
00511