1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsIServiceManager.h"
7 #include "nsIComponentRegistrar.h"
8 #include "nsIInputStream.h"
9 #include "nsIOutputStream.h"
10 #include "nsIRunnable.h"
11 #include "nsIThread.h"
12 #include "nsCOMArray.h"
13 #include "nsISimpleEnumerator.h"
15 #include "nsIFileStreams.h"
16 #include "nsIFileChannel.h"
18 #include "nsNetUtil.h"
21 ////////////////////////////////////////////////////////////////////////////////
25 #include "nsAutoLock.h"
33 void AddTime(PRIntervalTime time
);
34 PRIntervalTime
LastInterval() { return mLastInterval
; }
37 PRIntervalTime mStartTime
;
41 PRIntervalTime mLastInterval
;
44 nsTimeSampler::nsTimeSampler()
50 nsTimeSampler::Reset()
60 nsTimeSampler::StartTime()
62 mStartTime
= PR_IntervalNow();
66 nsTimeSampler::EndTime()
68 NS_ASSERTION(mStartTime
!= 0, "Forgot to call StartTime");
69 PRIntervalTime endTime
= PR_IntervalNow();
70 mLastInterval
= endTime
- mStartTime
;
71 AddTime(mLastInterval
);
76 nsTimeSampler::AddTime(PRIntervalTime time
)
78 nsAutoCMonitor
mon(this);
80 mSquares
+= (double)time
* (double)time
;
85 nsTimeSampler::PrintStats()
87 double mean
= mTotalTime
/ mCount
;
88 double variance
= fabs(mSquares
/ mCount
- mean
* mean
);
89 double stddev
= sqrt(variance
);
90 uint32_t imean
= (uint32_t)mean
;
91 uint32_t istddev
= (uint32_t)stddev
;
92 return PR_smprintf("%d +/- %d ms",
93 PR_IntervalToMilliseconds(imean
),
94 PR_IntervalToMilliseconds(istddev
));
97 ////////////////////////////////////////////////////////////////////////////////
99 nsTimeSampler gTimeSampler
;
101 typedef nsresult (*CreateFun
)(nsIRunnable
* *result
,
104 uint32_t bufferSize
);
106 ////////////////////////////////////////////////////////////////////////////////
109 Copy(nsIInputStream
* inStr
, nsIOutputStream
* outStr
,
110 char* buf
, uint32_t bufSize
, uint32_t *copyCount
)
115 rv
= inStr
->Read(buf
, bufSize
, &count
);
116 if (NS_FAILED(rv
)) return rv
;
117 if (count
== 0) break;
120 rv
= outStr
->Write(buf
, count
, &writeCount
);
121 if (NS_FAILED(rv
)) return rv
;
122 NS_ASSERTION(writeCount
== count
, "didn't write all the data");
123 *copyCount
+= writeCount
;
125 rv
= outStr
->Flush();
129 ////////////////////////////////////////////////////////////////////////////////
131 class FileSpecWorker
: public nsIRunnable
{
137 PRIntervalTime startTime
= PR_IntervalNow();
138 PRIntervalTime endTime
;
139 nsCOMPtr
<nsIInputStream
> inStr
;
140 nsCOMPtr
<nsIOutputStream
> outStr
;
141 uint32_t copyCount
= 0;
143 // Open the input stream:
144 nsCOMPtr
<nsIInputStream
> fileIn
;
145 rv
= NS_NewLocalFileInputStream(getter_AddRefs(fileIn
), mInPath
);
146 if (NS_FAILED(rv
)) return rv
;
148 rv
= NS_NewBufferedInputStream(getter_AddRefs(inStr
), fileIn
, 65535);
149 if (NS_FAILED(rv
)) return rv
;
151 // Open the output stream:
152 nsCOMPtr
<nsIOutputStream
> fileOut
;
153 rv
= NS_NewLocalFileOutputStream(getter_AddRefs(fileOut
),
155 PR_CREATE_FILE
| PR_WRONLY
| PR_TRUNCATE
,
157 if (NS_FAILED(rv
)) return rv
;
159 rv
= NS_NewBufferedOutputStream(getter_AddRefs(outStr
), fileOut
, 65535);
160 if (NS_FAILED(rv
)) return rv
;
162 // Copy from one to the other
163 rv
= Copy(inStr
, outStr
, mBuffer
, mBufferSize
, ©Count
);
164 if (NS_FAILED(rv
)) return rv
;
166 endTime
= PR_IntervalNow();
167 gTimeSampler
.AddTime(endTime
- startTime
);
175 : mInPath(nullptr), mOutPath(nullptr), mBuffer(nullptr),
180 nsresult
Init(nsIFile
* inPath
, nsIFile
* outPath
,
185 mBuffer
= new char[bufferSize
];
186 mBufferSize
= bufferSize
;
187 return (mInPath
&& mOutPath
&& mBuffer
)
188 ? NS_OK
: NS_ERROR_OUT_OF_MEMORY
;
191 static nsresult
Create(nsIRunnable
* *result
,
196 FileSpecWorker
* worker
= new FileSpecWorker();
197 if (worker
== nullptr)
198 return NS_ERROR_OUT_OF_MEMORY
;
201 nsresult rv
= worker
->Init(inPath
, outPath
, bufferSize
);
210 virtual ~FileSpecWorker() {
215 nsCOMPtr
<nsIFile
> mInPath
;
216 nsCOMPtr
<nsIFile
> mOutPath
;
218 uint32_t mBufferSize
;
221 NS_IMPL_ISUPPORTS(FileSpecWorker
, nsIRunnable
)
223 ////////////////////////////////////////////////////////////////////////////////
225 #include "nsIIOService.h"
226 #include "nsIChannel.h"
228 class FileChannelWorker
: public nsIRunnable
{
234 PRIntervalTime startTime
= PR_IntervalNow();
235 PRIntervalTime endTime
;
236 uint32_t copyCount
= 0;
237 nsCOMPtr
<nsIFileChannel
> inCh
;
238 nsCOMPtr
<nsIFileChannel
> outCh
;
239 nsCOMPtr
<nsIInputStream
> inStr
;
240 nsCOMPtr
<nsIOutputStream
> outStr
;
242 rv
= NS_NewLocalFileChannel(getter_AddRefs(inCh
), mInPath
);
243 if (NS_FAILED(rv
)) return rv
;
245 rv
= inCh
->Open(getter_AddRefs(inStr
));
246 if (NS_FAILED(rv
)) return rv
;
248 //rv = NS_NewLocalFileChannel(getter_AddRefs(outCh), mOutPath);
249 //if (NS_FAILED(rv)) return rv;
251 //rv = outCh->OpenOutputStream(0, -1, 0, getter_AddRefs(outStr));
252 //if (NS_FAILED(rv)) return rv;
254 // Copy from one to the other
255 rv
= Copy(inStr
, outStr
, mBuffer
, mBufferSize
, ©Count
);
256 if (NS_FAILED(rv
)) return rv
;
258 endTime
= PR_IntervalNow();
259 gTimeSampler
.AddTime(endTime
- startTime
);
267 : mInPath(nullptr), mOutPath(nullptr), mBuffer(nullptr),
272 nsresult
Init(nsIFile
* inPath
, nsIFile
* outPath
,
277 mBuffer
= new char[bufferSize
];
278 mBufferSize
= bufferSize
;
279 return (mInPath
&& mOutPath
&& mBuffer
)
280 ? NS_OK
: NS_ERROR_OUT_OF_MEMORY
;
283 static nsresult
Create(nsIRunnable
* *result
,
288 FileChannelWorker
* worker
= new FileChannelWorker();
289 if (worker
== nullptr)
290 return NS_ERROR_OUT_OF_MEMORY
;
293 nsresult rv
= worker
->Init(inPath
, outPath
, bufferSize
);
302 virtual ~FileChannelWorker() {
307 nsCOMPtr
<nsIFile
> mInPath
;
308 nsCOMPtr
<nsIFile
> mOutPath
;
310 uint32_t mBufferSize
;
313 NS_IMPL_ISUPPORTS(FileChannelWorker
, nsIRunnable
)
315 ////////////////////////////////////////////////////////////////////////////////
318 Test(CreateFun create
, uint32_t count
,
319 nsIFile
* inDirSpec
, nsIFile
* outDirSpec
, uint32_t bufSize
)
325 nsAutoCString outDir
;
326 (void)inDirSpec
->GetNativePath(inDir
);
327 (void)outDirSpec
->GetNativePath(outDir
);
328 printf("###########\nTest: from %s to %s, bufSize = %d\n",
329 inDir
.get(), outDir
.get(), bufSize
);
330 gTimeSampler
.Reset();
331 nsTimeSampler testTime
;
332 testTime
.StartTime();
334 nsCOMArray
<nsIThread
> threads
;
336 nsCOMPtr
<nsISimpleEnumerator
> entries
;
337 rv
= inDirSpec
->GetDirectoryEntries(getter_AddRefs(entries
));
338 NS_ASSERTION(NS_SUCCEEDED(rv
), "GetDirectoryEntries failed");
342 while (i
< count
&& NS_SUCCEEDED(entries
->HasMoreElements(&hasMore
)) && hasMore
) {
343 nsCOMPtr
<nsISupports
> next
;
344 rv
= entries
->GetNext(getter_AddRefs(next
));
345 if (NS_FAILED(rv
)) goto done
;
347 nsCOMPtr
<nsIFile
> inSpec
= do_QueryInterface(next
, &rv
);
348 if (NS_FAILED(rv
)) goto done
;
350 nsCOMPtr
<nsIFile
> outSpec
;
351 rv
= outDirSpec
->Clone(getter_AddRefs(outSpec
)); // don't munge the original
352 if (NS_FAILED(rv
)) goto done
;
354 nsAutoCString leafName
;
355 rv
= inSpec
->GetNativeLeafName(leafName
);
356 if (NS_FAILED(rv
)) goto done
;
358 rv
= outSpec
->AppendNative(leafName
);
359 if (NS_FAILED(rv
)) goto done
;
362 rv
= outSpec
->Exists(&exists
);
363 if (NS_FAILED(rv
)) goto done
;
366 rv
= outSpec
->Remove(false);
367 if (NS_FAILED(rv
)) goto done
;
370 nsCOMPtr
<nsIThread
> thread
;
371 nsCOMPtr
<nsIRunnable
> worker
;
372 rv
= create(getter_AddRefs(worker
),
376 if (NS_FAILED(rv
)) goto done
;
378 rv
= NS_NewThread(getter_AddRefs(thread
), worker
, 0, PR_JOINABLE_THREAD
);
379 if (NS_FAILED(rv
)) goto done
;
381 bool inserted
= threads
.InsertObjectAt(thread
, i
);
382 NS_ASSERTION(inserted
, "not inserted");
388 for (j
= 0; j
< i
; j
++) {
389 nsIThread
* thread
= threads
.ObjectAt(j
);
394 NS_ASSERTION(rv
== NS_OK
, "failed");
397 char* testStats
= testTime
.PrintStats();
398 char* workerStats
= gTimeSampler
.PrintStats();
399 printf(" threads = %d\n work time = %s,\n test time = %s\n",
400 i
, workerStats
, testStats
);
401 PR_smprintf_free(workerStats
);
402 PR_smprintf_free(testStats
);
405 ////////////////////////////////////////////////////////////////////////////////
408 main(int argc
, char* argv
[])
413 printf("usage: %s <in-dir> <out-dir>\n", argv
[0]);
416 char* inDir
= argv
[1];
417 char* outDir
= argv
[2];
420 nsCOMPtr
<nsIServiceManager
> servMan
;
421 NS_InitXPCOM2(getter_AddRefs(servMan
), nullptr, nullptr);
422 nsCOMPtr
<nsIComponentRegistrar
> registrar
= do_QueryInterface(servMan
);
423 NS_ASSERTION(registrar
, "Null nsIComponentRegistrar");
425 registrar
->AutoRegister(nullptr);
427 nsCOMPtr
<nsIFile
> inDirFile
;
428 rv
= NS_NewNativeLocalFile(nsDependentCString(inDir
), false, getter_AddRefs(inDirFile
));
429 if (NS_FAILED(rv
)) return rv
;
431 nsCOMPtr
<nsIFile
> outDirFile
;
432 rv
= NS_NewNativeLocalFile(nsDependentCString(outDir
), false, getter_AddRefs(outDirFile
));
433 if (NS_FAILED(rv
)) return rv
;
435 CreateFun create
= FileChannelWorker::Create
;
436 Test(create
, 1, inDirFile
, outDirFile
, 16 * 1024);
438 printf("FileChannelWorker *****************************\n");
439 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
440 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
441 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
442 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
443 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
444 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
445 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
446 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
447 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
449 create
= FileSpecWorker::Create
;
450 printf("FileSpecWorker ********************************\n");
452 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
453 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
454 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
455 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
456 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
457 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
458 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
459 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
460 Test(create
, 20, inDirFile
, outDirFile
, 16 * 1024);
463 Test(create
, 20, inDirFile
, outDirFile
, 4 * 1024);
464 Test(create
, 20, inDirFile
, outDirFile
, 4 * 1024);
465 Test(create
, 20, inDirFile
, outDirFile
, 4 * 1024);
466 Test(create
, 20, inDirFile
, outDirFile
, 4 * 1024);
467 Test(create
, 20, inDirFile
, outDirFile
, 4 * 1024);
468 Test(create
, 20, inDirFile
, outDirFile
, 4 * 1024);
469 Test(create
, 20, inDirFile
, outDirFile
, 4 * 1024);
470 Test(create
, 20, inDirFile
, outDirFile
, 4 * 1024);
471 Test(create
, 20, inDirFile
, outDirFile
, 4 * 1024);
473 } // this scopes the nsCOMPtrs
474 // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
475 rv
= NS_ShutdownXPCOM(nullptr);
476 NS_ASSERTION(NS_SUCCEEDED(rv
), "NS_ShutdownXPCOM failed");
480 ////////////////////////////////////////////////////////////////////////////////