michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIComponentRegistrar.h" michael@0: #include "nsIInputStream.h" michael@0: #include "nsIOutputStream.h" michael@0: #include "nsIRunnable.h" michael@0: #include "nsIThread.h" michael@0: #include "nsCOMArray.h" michael@0: #include "nsISimpleEnumerator.h" michael@0: #include "prinrval.h" michael@0: #include "nsIFileStreams.h" michael@0: #include "nsIFileChannel.h" michael@0: #include "nsIFile.h" michael@0: #include "nsNetUtil.h" michael@0: #include michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #include michael@0: #include "prprf.h" michael@0: #include "nsAutoLock.h" michael@0: michael@0: class nsTimeSampler { michael@0: public: michael@0: nsTimeSampler(); michael@0: void Reset(); michael@0: void StartTime(); michael@0: void EndTime(); michael@0: void AddTime(PRIntervalTime time); michael@0: PRIntervalTime LastInterval() { return mLastInterval; } michael@0: char* PrintStats(); michael@0: protected: michael@0: PRIntervalTime mStartTime; michael@0: double mSquares; michael@0: double mTotalTime; michael@0: uint32_t mCount; michael@0: PRIntervalTime mLastInterval; michael@0: }; michael@0: michael@0: nsTimeSampler::nsTimeSampler() michael@0: { michael@0: Reset(); michael@0: } michael@0: michael@0: void michael@0: nsTimeSampler::Reset() michael@0: { michael@0: mStartTime = 0; michael@0: mSquares = 0; michael@0: mTotalTime = 0; michael@0: mCount = 0; michael@0: mLastInterval = 0; michael@0: } michael@0: michael@0: void michael@0: nsTimeSampler::StartTime() michael@0: { michael@0: mStartTime = PR_IntervalNow(); michael@0: } michael@0: michael@0: void michael@0: nsTimeSampler::EndTime() michael@0: { michael@0: NS_ASSERTION(mStartTime != 0, "Forgot to call StartTime"); michael@0: PRIntervalTime endTime = PR_IntervalNow(); michael@0: mLastInterval = endTime - mStartTime; michael@0: AddTime(mLastInterval); michael@0: mStartTime = 0; michael@0: } michael@0: michael@0: void michael@0: nsTimeSampler::AddTime(PRIntervalTime time) michael@0: { michael@0: nsAutoCMonitor mon(this); michael@0: mTotalTime += time; michael@0: mSquares += (double)time * (double)time; michael@0: mCount++; michael@0: } michael@0: michael@0: char* michael@0: nsTimeSampler::PrintStats() michael@0: { michael@0: double mean = mTotalTime / mCount; michael@0: double variance = fabs(mSquares / mCount - mean * mean); michael@0: double stddev = sqrt(variance); michael@0: uint32_t imean = (uint32_t)mean; michael@0: uint32_t istddev = (uint32_t)stddev; michael@0: return PR_smprintf("%d +/- %d ms", michael@0: PR_IntervalToMilliseconds(imean), michael@0: PR_IntervalToMilliseconds(istddev)); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: nsTimeSampler gTimeSampler; michael@0: michael@0: typedef nsresult (*CreateFun)(nsIRunnable* *result, michael@0: nsIFile* inPath, michael@0: nsIFile* outPath, michael@0: uint32_t bufferSize); michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: nsresult michael@0: Copy(nsIInputStream* inStr, nsIOutputStream* outStr, michael@0: char* buf, uint32_t bufSize, uint32_t *copyCount) michael@0: { michael@0: nsresult rv; michael@0: while (true) { michael@0: uint32_t count; michael@0: rv = inStr->Read(buf, bufSize, &count); michael@0: if (NS_FAILED(rv)) return rv; michael@0: if (count == 0) break; michael@0: michael@0: uint32_t writeCount; michael@0: rv = outStr->Write(buf, count, &writeCount); michael@0: if (NS_FAILED(rv)) return rv; michael@0: NS_ASSERTION(writeCount == count, "didn't write all the data"); michael@0: *copyCount += writeCount; michael@0: } michael@0: rv = outStr->Flush(); michael@0: return rv; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class FileSpecWorker : public nsIRunnable { michael@0: public: michael@0: michael@0: NS_IMETHOD Run() { michael@0: nsresult rv; michael@0: michael@0: PRIntervalTime startTime = PR_IntervalNow(); michael@0: PRIntervalTime endTime; michael@0: nsCOMPtr inStr; michael@0: nsCOMPtr outStr; michael@0: uint32_t copyCount = 0; michael@0: michael@0: // Open the input stream: michael@0: nsCOMPtr fileIn; michael@0: rv = NS_NewLocalFileInputStream(getter_AddRefs(fileIn), mInPath); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = NS_NewBufferedInputStream(getter_AddRefs(inStr), fileIn, 65535); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // Open the output stream: michael@0: nsCOMPtr fileOut; michael@0: rv = NS_NewLocalFileOutputStream(getter_AddRefs(fileOut), michael@0: mOutPath, michael@0: PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE, michael@0: 0664); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = NS_NewBufferedOutputStream(getter_AddRefs(outStr), fileOut, 65535); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // Copy from one to the other michael@0: rv = Copy(inStr, outStr, mBuffer, mBufferSize, ©Count); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: endTime = PR_IntervalNow(); michael@0: gTimeSampler.AddTime(endTime - startTime); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: FileSpecWorker() michael@0: : mInPath(nullptr), mOutPath(nullptr), mBuffer(nullptr), michael@0: mBufferSize(0) michael@0: { michael@0: } michael@0: michael@0: nsresult Init(nsIFile* inPath, nsIFile* outPath, michael@0: uint32_t bufferSize) michael@0: { michael@0: mInPath = inPath; michael@0: mOutPath = outPath; michael@0: mBuffer = new char[bufferSize]; michael@0: mBufferSize = bufferSize; michael@0: return (mInPath && mOutPath && mBuffer) michael@0: ? NS_OK : NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: static nsresult Create(nsIRunnable* *result, michael@0: nsIFile* inPath, michael@0: nsIFile* outPath, michael@0: uint32_t bufferSize) michael@0: { michael@0: FileSpecWorker* worker = new FileSpecWorker(); michael@0: if (worker == nullptr) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: NS_ADDREF(worker); michael@0: michael@0: nsresult rv = worker->Init(inPath, outPath, bufferSize); michael@0: if (NS_FAILED(rv)) { michael@0: NS_RELEASE(worker); michael@0: return rv; michael@0: } michael@0: *result = worker; michael@0: return NS_OK; michael@0: } michael@0: michael@0: virtual ~FileSpecWorker() { michael@0: delete[] mBuffer; michael@0: } michael@0: michael@0: protected: michael@0: nsCOMPtr mInPath; michael@0: nsCOMPtr mOutPath; michael@0: char* mBuffer; michael@0: uint32_t mBufferSize; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(FileSpecWorker, nsIRunnable) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #include "nsIIOService.h" michael@0: #include "nsIChannel.h" michael@0: michael@0: class FileChannelWorker : public nsIRunnable { michael@0: public: michael@0: michael@0: NS_IMETHOD Run() { michael@0: nsresult rv; michael@0: michael@0: PRIntervalTime startTime = PR_IntervalNow(); michael@0: PRIntervalTime endTime; michael@0: uint32_t copyCount = 0; michael@0: nsCOMPtr inCh; michael@0: nsCOMPtr outCh; michael@0: nsCOMPtr inStr; michael@0: nsCOMPtr outStr; michael@0: michael@0: rv = NS_NewLocalFileChannel(getter_AddRefs(inCh), mInPath); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = inCh->Open(getter_AddRefs(inStr)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: //rv = NS_NewLocalFileChannel(getter_AddRefs(outCh), mOutPath); michael@0: //if (NS_FAILED(rv)) return rv; michael@0: michael@0: //rv = outCh->OpenOutputStream(0, -1, 0, getter_AddRefs(outStr)); michael@0: //if (NS_FAILED(rv)) return rv; michael@0: michael@0: // Copy from one to the other michael@0: rv = Copy(inStr, outStr, mBuffer, mBufferSize, ©Count); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: endTime = PR_IntervalNow(); michael@0: gTimeSampler.AddTime(endTime - startTime); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: FileChannelWorker() michael@0: : mInPath(nullptr), mOutPath(nullptr), mBuffer(nullptr), michael@0: mBufferSize(0) michael@0: { michael@0: } michael@0: michael@0: nsresult Init(nsIFile* inPath, nsIFile* outPath, michael@0: uint32_t bufferSize) michael@0: { michael@0: mInPath = inPath; michael@0: mOutPath = outPath; michael@0: mBuffer = new char[bufferSize]; michael@0: mBufferSize = bufferSize; michael@0: return (mInPath && mOutPath && mBuffer) michael@0: ? NS_OK : NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: static nsresult Create(nsIRunnable* *result, michael@0: nsIFile* inPath, michael@0: nsIFile* outPath, michael@0: uint32_t bufferSize) michael@0: { michael@0: FileChannelWorker* worker = new FileChannelWorker(); michael@0: if (worker == nullptr) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: NS_ADDREF(worker); michael@0: michael@0: nsresult rv = worker->Init(inPath, outPath, bufferSize); michael@0: if (NS_FAILED(rv)) { michael@0: NS_RELEASE(worker); michael@0: return rv; michael@0: } michael@0: *result = worker; michael@0: return NS_OK; michael@0: } michael@0: michael@0: virtual ~FileChannelWorker() { michael@0: delete[] mBuffer; michael@0: } michael@0: michael@0: protected: michael@0: nsCOMPtr mInPath; michael@0: nsCOMPtr mOutPath; michael@0: char* mBuffer; michael@0: uint32_t mBufferSize; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(FileChannelWorker, nsIRunnable) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: void michael@0: Test(CreateFun create, uint32_t count, michael@0: nsIFile* inDirSpec, nsIFile* outDirSpec, uint32_t bufSize) michael@0: { michael@0: nsresult rv; michael@0: uint32_t i; michael@0: michael@0: nsAutoCString inDir; michael@0: nsAutoCString outDir; michael@0: (void)inDirSpec->GetNativePath(inDir); michael@0: (void)outDirSpec->GetNativePath(outDir); michael@0: printf("###########\nTest: from %s to %s, bufSize = %d\n", michael@0: inDir.get(), outDir.get(), bufSize); michael@0: gTimeSampler.Reset(); michael@0: nsTimeSampler testTime; michael@0: testTime.StartTime(); michael@0: michael@0: nsCOMArray threads; michael@0: michael@0: nsCOMPtr entries; michael@0: rv = inDirSpec->GetDirectoryEntries(getter_AddRefs(entries)); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "GetDirectoryEntries failed"); michael@0: michael@0: i = 0; michael@0: bool hasMore; michael@0: while (i < count && NS_SUCCEEDED(entries->HasMoreElements(&hasMore)) && hasMore) { michael@0: nsCOMPtr next; michael@0: rv = entries->GetNext(getter_AddRefs(next)); michael@0: if (NS_FAILED(rv)) goto done; michael@0: michael@0: nsCOMPtr inSpec = do_QueryInterface(next, &rv); michael@0: if (NS_FAILED(rv)) goto done; michael@0: michael@0: nsCOMPtr outSpec; michael@0: rv = outDirSpec->Clone(getter_AddRefs(outSpec)); // don't munge the original michael@0: if (NS_FAILED(rv)) goto done; michael@0: michael@0: nsAutoCString leafName; michael@0: rv = inSpec->GetNativeLeafName(leafName); michael@0: if (NS_FAILED(rv)) goto done; michael@0: michael@0: rv = outSpec->AppendNative(leafName); michael@0: if (NS_FAILED(rv)) goto done; michael@0: michael@0: bool exists; michael@0: rv = outSpec->Exists(&exists); michael@0: if (NS_FAILED(rv)) goto done; michael@0: michael@0: if (exists) { michael@0: rv = outSpec->Remove(false); michael@0: if (NS_FAILED(rv)) goto done; michael@0: } michael@0: michael@0: nsCOMPtr thread; michael@0: nsCOMPtr worker; michael@0: rv = create(getter_AddRefs(worker), michael@0: inSpec, michael@0: outSpec, michael@0: bufSize); michael@0: if (NS_FAILED(rv)) goto done; michael@0: michael@0: rv = NS_NewThread(getter_AddRefs(thread), worker, 0, PR_JOINABLE_THREAD); michael@0: if (NS_FAILED(rv)) goto done; michael@0: michael@0: bool inserted = threads.InsertObjectAt(thread, i); michael@0: NS_ASSERTION(inserted, "not inserted"); michael@0: michael@0: i++; michael@0: } michael@0: michael@0: uint32_t j; michael@0: for (j = 0; j < i; j++) { michael@0: nsIThread* thread = threads.ObjectAt(j); michael@0: thread->Join(); michael@0: } michael@0: michael@0: done: michael@0: NS_ASSERTION(rv == NS_OK, "failed"); michael@0: michael@0: testTime.EndTime(); michael@0: char* testStats = testTime.PrintStats(); michael@0: char* workerStats = gTimeSampler.PrintStats(); michael@0: printf(" threads = %d\n work time = %s,\n test time = %s\n", michael@0: i, workerStats, testStats); michael@0: PR_smprintf_free(workerStats); michael@0: PR_smprintf_free(testStats); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: int michael@0: main(int argc, char* argv[]) michael@0: { michael@0: nsresult rv; michael@0: michael@0: if (argc < 2) { michael@0: printf("usage: %s \n", argv[0]); michael@0: return -1; michael@0: } michael@0: char* inDir = argv[1]; michael@0: char* outDir = argv[2]; michael@0: michael@0: { michael@0: nsCOMPtr servMan; michael@0: NS_InitXPCOM2(getter_AddRefs(servMan), nullptr, nullptr); michael@0: nsCOMPtr registrar = do_QueryInterface(servMan); michael@0: NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); michael@0: if (registrar) michael@0: registrar->AutoRegister(nullptr); michael@0: michael@0: nsCOMPtr inDirFile; michael@0: rv = NS_NewNativeLocalFile(nsDependentCString(inDir), false, getter_AddRefs(inDirFile)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr outDirFile; michael@0: rv = NS_NewNativeLocalFile(nsDependentCString(outDir), false, getter_AddRefs(outDirFile)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: CreateFun create = FileChannelWorker::Create; michael@0: Test(create, 1, inDirFile, outDirFile, 16 * 1024); michael@0: #if 1 michael@0: printf("FileChannelWorker *****************************\n"); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: #endif michael@0: create = FileSpecWorker::Create; michael@0: printf("FileSpecWorker ********************************\n"); michael@0: #if 1 michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 16 * 1024); michael@0: #endif michael@0: #if 1 michael@0: Test(create, 20, inDirFile, outDirFile, 4 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 4 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 4 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 4 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 4 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 4 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 4 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 4 * 1024); michael@0: Test(create, 20, inDirFile, outDirFile, 4 * 1024); michael@0: #endif michael@0: } // this scopes the nsCOMPtrs michael@0: // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM michael@0: rv = NS_ShutdownXPCOM(nullptr); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); michael@0: return 0; michael@0: } michael@0: michael@0: ////////////////////////////////////////////////////////////////////////////////