TestFileInput2.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  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/. */
  5. #include "nsIServiceManager.h"
  6. #include "nsIComponentRegistrar.h"
  7. #include "nsIInputStream.h"
  8. #include "nsIOutputStream.h"
  9. #include "nsIRunnable.h"
  10. #include "nsIThread.h"
  11. #include "nsCOMArray.h"
  12. #include "nsISimpleEnumerator.h"
  13. #include "prinrval.h"
  14. #include "nsIFileStreams.h"
  15. #include "nsIFileChannel.h"
  16. #include "nsIFile.h"
  17. #include "nsNetUtil.h"
  18. #include <stdio.h>
  19. ////////////////////////////////////////////////////////////////////////////////
  20. #include <math.h>
  21. #include "prprf.h"
  22. #include "nsAutoLock.h"
  23. class nsTimeSampler {
  24. public:
  25. nsTimeSampler();
  26. void Reset();
  27. void StartTime();
  28. void EndTime();
  29. void AddTime(PRIntervalTime time);
  30. PRIntervalTime LastInterval() { return mLastInterval; }
  31. char* PrintStats();
  32. protected:
  33. PRIntervalTime mStartTime;
  34. double mSquares;
  35. double mTotalTime;
  36. uint32_t mCount;
  37. PRIntervalTime mLastInterval;
  38. };
  39. nsTimeSampler::nsTimeSampler()
  40. {
  41. Reset();
  42. }
  43. void
  44. nsTimeSampler::Reset()
  45. {
  46. mStartTime = 0;
  47. mSquares = 0;
  48. mTotalTime = 0;
  49. mCount = 0;
  50. mLastInterval = 0;
  51. }
  52. void
  53. nsTimeSampler::StartTime()
  54. {
  55. mStartTime = PR_IntervalNow();
  56. }
  57. void
  58. nsTimeSampler::EndTime()
  59. {
  60. NS_ASSERTION(mStartTime != 0, "Forgot to call StartTime");
  61. PRIntervalTime endTime = PR_IntervalNow();
  62. mLastInterval = endTime - mStartTime;
  63. AddTime(mLastInterval);
  64. mStartTime = 0;
  65. }
  66. void
  67. nsTimeSampler::AddTime(PRIntervalTime time)
  68. {
  69. nsAutoCMonitor mon(this);
  70. mTotalTime += time;
  71. mSquares += (double)time * (double)time;
  72. mCount++;
  73. }
  74. char*
  75. nsTimeSampler::PrintStats()
  76. {
  77. double mean = mTotalTime / mCount;
  78. double variance = fabs(mSquares / mCount - mean * mean);
  79. double stddev = sqrt(variance);
  80. uint32_t imean = (uint32_t)mean;
  81. uint32_t istddev = (uint32_t)stddev;
  82. return PR_smprintf("%d +/- %d ms",
  83. PR_IntervalToMilliseconds(imean),
  84. PR_IntervalToMilliseconds(istddev));
  85. }
  86. ////////////////////////////////////////////////////////////////////////////////
  87. nsTimeSampler gTimeSampler;
  88. typedef nsresult (*CreateFun)(nsIRunnable* *result,
  89. nsIFile* inPath,
  90. nsIFile* outPath,
  91. uint32_t bufferSize);
  92. ////////////////////////////////////////////////////////////////////////////////
  93. nsresult
  94. Copy(nsIInputStream* inStr, nsIOutputStream* outStr,
  95. char* buf, uint32_t bufSize, uint32_t *copyCount)
  96. {
  97. nsresult rv;
  98. while (true) {
  99. uint32_t count;
  100. rv = inStr->Read(buf, bufSize, &count);
  101. if (NS_FAILED(rv)) return rv;
  102. if (count == 0) break;
  103. uint32_t writeCount;
  104. rv = outStr->Write(buf, count, &writeCount);
  105. if (NS_FAILED(rv)) return rv;
  106. NS_ASSERTION(writeCount == count, "didn't write all the data");
  107. *copyCount += writeCount;
  108. }
  109. rv = outStr->Flush();
  110. return rv;
  111. }
  112. ////////////////////////////////////////////////////////////////////////////////
  113. class FileSpecWorker : public nsIRunnable {
  114. public:
  115. NS_IMETHOD Run() override {
  116. nsresult rv;
  117. PRIntervalTime startTime = PR_IntervalNow();
  118. PRIntervalTime endTime;
  119. nsCOMPtr<nsIInputStream> inStr;
  120. nsCOMPtr<nsIOutputStream> outStr;
  121. uint32_t copyCount = 0;
  122. // Open the input stream:
  123. nsCOMPtr<nsIInputStream> fileIn;
  124. rv = NS_NewLocalFileInputStream(getter_AddRefs(fileIn), mInPath);
  125. if (NS_FAILED(rv)) return rv;
  126. rv = NS_NewBufferedInputStream(getter_AddRefs(inStr), fileIn, 65535);
  127. if (NS_FAILED(rv)) return rv;
  128. // Open the output stream:
  129. nsCOMPtr<nsIOutputStream> fileOut;
  130. rv = NS_NewLocalFileOutputStream(getter_AddRefs(fileOut),
  131. mOutPath,
  132. PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE,
  133. 0664);
  134. if (NS_FAILED(rv)) return rv;
  135. rv = NS_NewBufferedOutputStream(getter_AddRefs(outStr), fileOut, 65535);
  136. if (NS_FAILED(rv)) return rv;
  137. // Copy from one to the other
  138. rv = Copy(inStr, outStr, mBuffer, mBufferSize, &copyCount);
  139. if (NS_FAILED(rv)) return rv;
  140. endTime = PR_IntervalNow();
  141. gTimeSampler.AddTime(endTime - startTime);
  142. return rv;
  143. }
  144. NS_DECL_ISUPPORTS
  145. FileSpecWorker()
  146. : mInPath(nullptr), mOutPath(nullptr), mBuffer(nullptr),
  147. mBufferSize(0)
  148. {
  149. }
  150. nsresult Init(nsIFile* inPath, nsIFile* outPath,
  151. uint32_t bufferSize)
  152. {
  153. mInPath = inPath;
  154. mOutPath = outPath;
  155. mBuffer = new char[bufferSize];
  156. mBufferSize = bufferSize;
  157. return (mInPath && mOutPath && mBuffer)
  158. ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
  159. }
  160. static nsresult Create(nsIRunnable* *result,
  161. nsIFile* inPath,
  162. nsIFile* outPath,
  163. uint32_t bufferSize)
  164. {
  165. FileSpecWorker* worker = new FileSpecWorker();
  166. if (worker == nullptr)
  167. return NS_ERROR_OUT_OF_MEMORY;
  168. NS_ADDREF(worker);
  169. nsresult rv = worker->Init(inPath, outPath, bufferSize);
  170. if (NS_FAILED(rv)) {
  171. NS_RELEASE(worker);
  172. return rv;
  173. }
  174. *result = worker;
  175. return NS_OK;
  176. }
  177. virtual ~FileSpecWorker() {
  178. delete[] mBuffer;
  179. }
  180. protected:
  181. nsCOMPtr<nsIFile> mInPath;
  182. nsCOMPtr<nsIFile> mOutPath;
  183. char* mBuffer;
  184. uint32_t mBufferSize;
  185. };
  186. NS_IMPL_ISUPPORTS(FileSpecWorker, nsIRunnable)
  187. ////////////////////////////////////////////////////////////////////////////////
  188. #include "nsIIOService.h"
  189. #include "nsIChannel.h"
  190. class FileChannelWorker : public nsIRunnable {
  191. public:
  192. NS_IMETHOD Run() override {
  193. nsresult rv;
  194. PRIntervalTime startTime = PR_IntervalNow();
  195. PRIntervalTime endTime;
  196. uint32_t copyCount = 0;
  197. nsCOMPtr<nsIFileChannel> inCh;
  198. nsCOMPtr<nsIFileChannel> outCh;
  199. nsCOMPtr<nsIInputStream> inStr;
  200. nsCOMPtr<nsIOutputStream> outStr;
  201. rv = NS_NewLocalFileChannel(getter_AddRefs(inCh), mInPath);
  202. if (NS_FAILED(rv)) return rv;
  203. rv = inCh->Open(getter_AddRefs(inStr));
  204. if (NS_FAILED(rv)) return rv;
  205. //rv = NS_NewLocalFileChannel(getter_AddRefs(outCh), mOutPath);
  206. //if (NS_FAILED(rv)) return rv;
  207. //rv = outCh->OpenOutputStream(0, -1, 0, getter_AddRefs(outStr));
  208. //if (NS_FAILED(rv)) return rv;
  209. // Copy from one to the other
  210. rv = Copy(inStr, outStr, mBuffer, mBufferSize, &copyCount);
  211. if (NS_FAILED(rv)) return rv;
  212. endTime = PR_IntervalNow();
  213. gTimeSampler.AddTime(endTime - startTime);
  214. return rv;
  215. }
  216. NS_DECL_ISUPPORTS
  217. FileChannelWorker()
  218. : mInPath(nullptr), mOutPath(nullptr), mBuffer(nullptr),
  219. mBufferSize(0)
  220. {
  221. }
  222. nsresult Init(nsIFile* inPath, nsIFile* outPath,
  223. uint32_t bufferSize)
  224. {
  225. mInPath = inPath;
  226. mOutPath = outPath;
  227. mBuffer = new char[bufferSize];
  228. mBufferSize = bufferSize;
  229. return (mInPath && mOutPath && mBuffer)
  230. ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
  231. }
  232. static nsresult Create(nsIRunnable* *result,
  233. nsIFile* inPath,
  234. nsIFile* outPath,
  235. uint32_t bufferSize)
  236. {
  237. FileChannelWorker* worker = new FileChannelWorker();
  238. if (worker == nullptr)
  239. return NS_ERROR_OUT_OF_MEMORY;
  240. NS_ADDREF(worker);
  241. nsresult rv = worker->Init(inPath, outPath, bufferSize);
  242. if (NS_FAILED(rv)) {
  243. NS_RELEASE(worker);
  244. return rv;
  245. }
  246. *result = worker;
  247. return NS_OK;
  248. }
  249. virtual ~FileChannelWorker() {
  250. delete[] mBuffer;
  251. }
  252. protected:
  253. nsCOMPtr<nsIFile> mInPath;
  254. nsCOMPtr<nsIFile> mOutPath;
  255. char* mBuffer;
  256. uint32_t mBufferSize;
  257. };
  258. NS_IMPL_ISUPPORTS(FileChannelWorker, nsIRunnable)
  259. ////////////////////////////////////////////////////////////////////////////////
  260. void
  261. Test(CreateFun create, uint32_t count,
  262. nsIFile* inDirSpec, nsIFile* outDirSpec, uint32_t bufSize)
  263. {
  264. nsresult rv;
  265. uint32_t i;
  266. nsAutoCString inDir;
  267. nsAutoCString outDir;
  268. (void)inDirSpec->GetNativePath(inDir);
  269. (void)outDirSpec->GetNativePath(outDir);
  270. printf("###########\nTest: from %s to %s, bufSize = %d\n",
  271. inDir.get(), outDir.get(), bufSize);
  272. gTimeSampler.Reset();
  273. nsTimeSampler testTime;
  274. testTime.StartTime();
  275. nsCOMArray<nsIThread> threads;
  276. nsCOMPtr<nsISimpleEnumerator> entries;
  277. rv = inDirSpec->GetDirectoryEntries(getter_AddRefs(entries));
  278. NS_ASSERTION(NS_SUCCEEDED(rv), "GetDirectoryEntries failed");
  279. i = 0;
  280. bool hasMore;
  281. while (i < count && NS_SUCCEEDED(entries->HasMoreElements(&hasMore)) && hasMore) {
  282. nsCOMPtr<nsISupports> next;
  283. rv = entries->GetNext(getter_AddRefs(next));
  284. if (NS_FAILED(rv)) goto done;
  285. nsCOMPtr<nsIFile> inSpec = do_QueryInterface(next, &rv);
  286. if (NS_FAILED(rv)) goto done;
  287. nsCOMPtr<nsIFile> outSpec;
  288. rv = outDirSpec->Clone(getter_AddRefs(outSpec)); // don't munge the original
  289. if (NS_FAILED(rv)) goto done;
  290. nsAutoCString leafName;
  291. rv = inSpec->GetNativeLeafName(leafName);
  292. if (NS_FAILED(rv)) goto done;
  293. rv = outSpec->AppendNative(leafName);
  294. if (NS_FAILED(rv)) goto done;
  295. bool exists;
  296. rv = outSpec->Exists(&exists);
  297. if (NS_FAILED(rv)) goto done;
  298. if (exists) {
  299. rv = outSpec->Remove(false);
  300. if (NS_FAILED(rv)) goto done;
  301. }
  302. nsCOMPtr<nsIThread> thread;
  303. nsCOMPtr<nsIRunnable> worker;
  304. rv = create(getter_AddRefs(worker),
  305. inSpec,
  306. outSpec,
  307. bufSize);
  308. if (NS_FAILED(rv)) goto done;
  309. rv = NS_NewThread(getter_AddRefs(thread), worker, 0, PR_JOINABLE_THREAD);
  310. if (NS_FAILED(rv)) goto done;
  311. bool inserted = threads.InsertObjectAt(thread, i);
  312. NS_ASSERTION(inserted, "not inserted");
  313. i++;
  314. }
  315. uint32_t j;
  316. for (j = 0; j < i; j++) {
  317. nsIThread* thread = threads.ObjectAt(j);
  318. thread->Join();
  319. }
  320. done:
  321. NS_ASSERTION(rv == NS_OK, "failed");
  322. testTime.EndTime();
  323. char* testStats = testTime.PrintStats();
  324. char* workerStats = gTimeSampler.PrintStats();
  325. printf(" threads = %d\n work time = %s,\n test time = %s\n",
  326. i, workerStats, testStats);
  327. PR_smprintf_free(workerStats);
  328. PR_smprintf_free(testStats);
  329. }
  330. ////////////////////////////////////////////////////////////////////////////////
  331. int
  332. main(int argc, char* argv[])
  333. {
  334. nsresult rv;
  335. if (argc < 2) {
  336. printf("usage: %s <in-dir> <out-dir>\n", argv[0]);
  337. return -1;
  338. }
  339. char* inDir = argv[1];
  340. char* outDir = argv[2];
  341. {
  342. nsCOMPtr<nsIServiceManager> servMan;
  343. NS_InitXPCOM2(getter_AddRefs(servMan), nullptr, nullptr);
  344. nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(servMan);
  345. NS_ASSERTION(registrar, "Null nsIComponentRegistrar");
  346. if (registrar)
  347. registrar->AutoRegister(nullptr);
  348. nsCOMPtr<nsIFile> inDirFile;
  349. rv = NS_NewNativeLocalFile(nsDependentCString(inDir), false, getter_AddRefs(inDirFile));
  350. if (NS_FAILED(rv)) return rv;
  351. nsCOMPtr<nsIFile> outDirFile;
  352. rv = NS_NewNativeLocalFile(nsDependentCString(outDir), false, getter_AddRefs(outDirFile));
  353. if (NS_FAILED(rv)) return rv;
  354. CreateFun create = FileChannelWorker::Create;
  355. Test(create, 1, inDirFile, outDirFile, 16 * 1024);
  356. #if 1
  357. printf("FileChannelWorker *****************************\n");
  358. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  359. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  360. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  361. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  362. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  363. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  364. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  365. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  366. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  367. #endif
  368. create = FileSpecWorker::Create;
  369. printf("FileSpecWorker ********************************\n");
  370. #if 1
  371. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  372. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  373. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  374. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  375. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  376. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  377. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  378. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  379. Test(create, 20, inDirFile, outDirFile, 16 * 1024);
  380. #endif
  381. #if 1
  382. Test(create, 20, inDirFile, outDirFile, 4 * 1024);
  383. Test(create, 20, inDirFile, outDirFile, 4 * 1024);
  384. Test(create, 20, inDirFile, outDirFile, 4 * 1024);
  385. Test(create, 20, inDirFile, outDirFile, 4 * 1024);
  386. Test(create, 20, inDirFile, outDirFile, 4 * 1024);
  387. Test(create, 20, inDirFile, outDirFile, 4 * 1024);
  388. Test(create, 20, inDirFile, outDirFile, 4 * 1024);
  389. Test(create, 20, inDirFile, outDirFile, 4 * 1024);
  390. Test(create, 20, inDirFile, outDirFile, 4 * 1024);
  391. #endif
  392. } // this scopes the nsCOMPtrs
  393. // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
  394. rv = NS_ShutdownXPCOM(nullptr);
  395. NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed");
  396. return 0;
  397. }
  398. ////////////////////////////////////////////////////////////////////////////////