Ticket #1071: area_creation_test.cpp

File area_creation_test.cpp, 17.8 KB (added by kaoutsis, 17 years ago)
Line 
1/*
2 * Copyright 2007, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Vasilis Kaoutsis, kaoutsis@sch.gr
7 */
8
9
10/*! \brief A simple test of areas creation,
11 and deletion, for testing the time-costs.
12*/
13
14
15#include <Application.h>
16#include <OS.h>
17#include <String.h>
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <sys/utsname.h>
23#include <sys/time.h>
24#include <sys/times.h>
25#include <unistd.h>
26
27//#define TRACE_ALL
28#ifdef TRACE_ALL
29# define TRACE_AREA_CREAT_DELETE
30# define TRACE_NULL_FUNCTION
31# define TRACE_ITERATIONS
32# define TRACE_PAGE_TOUCHING
33#endif
34
35#ifdef TRACE_AREA_CREAT_DELETE
36# define TR_AR_CR_DL(x) fprintf x
37#else
38# define TR_AR_CR_DL(x) ;
39#endif
40
41#ifdef TRACE_NULL_FUNCTION
42# define TR_NL_FC(x) fprintf x
43#else
44# define TR_NL_FC(x) ;
45#endif
46
47#ifdef TRACE_ITERATIONS
48# define TR_ITER(x) fprintf x
49#else
50# define TR_ITER(x) ;
51#endif
52
53#ifdef TRACE_PAGE_TOUCHING
54# define TR_TOUCH(x) fprintf x
55#else
56# define TR_TOUCH(x) ;
57#endif
58
59void DoNothing()
60{
61}
62
63enum measuring_t {
64 kUsingGettimeofday = 1,
65 kUsingSystemTime,
66 kAll
67};
68
69const char* kSignature = "application/x-vnd.Haiku.cmd-area_creation_test";
70const char* kProgramName = "area_creation_test";
71
72const int32 kErrorInitFail = 127;
73const int32 kErrorArgumentsFail = 126;
74
75
76class AreaTestApplication;
77typedef status_t (AreaTestApplication::*PMFI)(uint32 iterations);
78
79
80class AreaTestApplication : public BApplication {
81 public:
82 AreaTestApplication();
83 virtual ~AreaTestApplication() { }
84
85 virtual void ReadyToRun();
86 virtual void ArgvReceived(int32 argc, char** argv);
87
88 bool GoodArguments() const { return fOk; }
89 status_t AreaCreate(uint32 numOfAreas);
90 status_t DeleteAllAreas(uint32 numOfAreas);
91 status_t DeleteEvenAreas(uint32 numOfAreas);
92 status_t DeleteOddAreas(uint32 numOfAreas);
93 status_t TouchPages(uint32 numOfAreas);
94 status_t NullFunction(uint32 counter);
95 unsigned long UsingGettimeofday(PMFI);
96 bigtime_t UsingSystemTime(PMFI);
97 void PrintResults(measuring_t measuringType, PMFI);
98
99 private:
100 void _Usage() const;
101
102 private:
103 bool fOk;
104 void* fStartingAddress;
105 uint32 fAddressSpec;
106 uint32 fRequestedSize;
107 uint32 fLockSpec;
108 uint32 fProtection;
109 uint32 fNumOfPages;
110 BString fArchitecture;
111 BString fFileName;
112 uint32 fResultSum;
113 uint32 fResult;
114 uint32 fIterations;
115 uint32 fNumOfAreas;
116 uint32 fAreaIdTag[5000];
117 uint32 fAreaPrepIdTag[5000];
118 uint8* fAreaAddress[5000];
119 bool fFragmentationTest;
120
121};
122
123
124AreaTestApplication::AreaTestApplication()
125 : BApplication(kSignature),
126 fOk(false),
127 fStartingAddress(NULL),
128 fAddressSpec(0),
129 fRequestedSize(0),
130 fLockSpec(0),
131 fProtection(0),
132 fNumOfPages(0),
133 fResultSum(0),
134 fResult(0),
135 fIterations(fNumOfAreas),
136 fFragmentationTest(false)
137{
138}
139
140
141void
142AreaTestApplication::_Usage() const
143{
144 fprintf(stdout,"\nUsage:\n"
145 "%s [pages number] [address spec] [lock spec] [protection] \n\n"
146 " [number of areas to create] [fragm] \n\n"
147 "\t [pages number] is an integer value.\n"
148 "\tBy providing the number of pages, you provide the size of the area.\n"
149 "\tThe size of the area is calculating as: B_PAGE_SIZE * numOfPages\n"
150 "\tB_PAGE_SIZE has the value of one page or 4096 bytes.\n"
151 "\tFor example if you want the size of the area to be 40 kB.\n"
152 "\tyour argument have to be 10, since 4096 * 10 is 40960 bytes or 40 kB.\n"
153 "\n"
154 "\t [addreess spec] is one of the following values:\n"
155 "\tB_EXACT_ADDRESS, B_BASE_ADDRESS, B_ANY_ADDRESS, B_ANY_KERNEL_ADDRESS\n\n"
156 "\t [lock spec] is one of the following values:\n"
157 "\tB_NO_LOCK, B_LAZY_LOCK, B_FULL_LOCK, B_CONTIGUOUS, B_LOMEM\n\n"
158 "\t [protection] is one of the following values:\n"
159 "\tB_READ_AREA, B_WRITE_AREA, B_READ_AREA | B_WRITE_AREA\n\n"
160 "\t [number of areas to create] max value is currently 5000 \n\n"
161 "\t fragm: run the fragmentation test, optional\n"
162 "An example:\n"
163 "area_creation_test.beos 10 B_ANY_ADDRESS B_NO_LOCK 'B_WRITE_AREA|B_READ_AREA' 4000\n"
164 "will create 4000 areas that each one will have 10 pages size.\n"
165 "Another example:\n"
166 "area_creation_test.beos 10 B_ANY_ADDRESS B_NO_LOCK 'B_WRITE_AREA|B_READ_AREA' 4000 fragm\n"
167 "will create 4000 areas that each one will have 10 pages size,\n"
168 "plus the fragmentation test\n"
169 , kProgramName);
170}
171
172
173void
174AreaTestApplication::PrintResults(measuring_t measuringType, PMFI BenchFunction)
175{
176 switch (measuringType) {
177 static bool usingAll;
178
179 case kAll:
180 usingAll = true;
181
182 case kUsingGettimeofday:
183 fprintf(stdout, "gettimeofday");
184 fResultSum = UsingGettimeofday(BenchFunction);
185
186 fResult = fResultSum / fIterations;
187 if (fResult == 0) { // result is ns
188 fResult = 1000 * fResultSum / fIterations;
189 fprintf(stdout, "%11ld ns", fResult);
190 } else
191 fprintf(stdout, "%11ld µs.", fResult);
192
193 if (usingAll == false)
194 break;
195 fprintf(stdout, "\n");
196
197 case kUsingSystemTime:
198 fprintf(stdout, "system_time");
199 fResultSum = UsingSystemTime(BenchFunction);
200
201 fResult = fResultSum / fIterations;
202 if (fResult == 0) { // result is ns
203 fResult = (1000 * fResultSum) / fIterations;
204 fprintf(stdout, "%12ld ns", fResult);
205 } else
206 fprintf(stdout, "%12ld µs.", fResult);
207
208 if (usingAll == false)
209 break;
210 fprintf(stdout, "\n");
211
212 }
213 fprintf(stdout, "\n");
214}
215
216
217void
218AreaTestApplication::ArgvReceived(int32 argc, char** argv)
219{
220 if (argc < 2 || argc > 7)
221 return; // bad arguments number!
222
223 fNumOfPages = atoi(argv[1]);
224
225 if (argc < 6)
226 fNumOfAreas = 5000;
227 else
228 fNumOfAreas = atoi(argv[5]);
229
230 if (fNumOfAreas > 5000) {
231 fprintf(stdout, "Currently the test doesn't support the creation of more than 5000 areas!");
232 return;
233 }
234
235 fIterations = fNumOfAreas;
236
237 if (argc == 7 && argv[6][0] == 'f'
238 && argv[6][1] == 'r'
239 && argv[6][2] == 'a'
240 && argv[6][3] == 'g'
241 && argv[6][4] == 'm')
242 fFragmentationTest = true;
243
244 // get the addressSpec
245 BString addressSpecString(argv[2]);
246 if (addressSpecString == "B_EXACT_ADDRESS")
247 fAddressSpec = 1;
248 else if (addressSpecString == "B_BASE_ADDRESS")
249 fAddressSpec = 2;
250 else if (addressSpecString == "B_ANY_ADDRESS")
251 fAddressSpec = 0;
252 else if (addressSpecString == "B_ANY_KERNEL_ADDRESS")
253 fAddressSpec = 4;
254 else {
255 fprintf(stdout, "Wrong address specification: %s\n"
256 "\taddreess specification is one of the following values:\n"
257 "\tB_EXACT_ADDRESS, B_BASE_ADDRESS, B_ANY_ADDRESS, B_ANY_KERNEL_ADDRESS\n\n", argv[2]);
258 return;
259 }
260
261 // get the lock specification
262 BString lockSpecString(argv[3]);
263 if (lockSpecString == "B_NO_LOCK")
264 fLockSpec = 0;
265 else if (lockSpecString == "B_LAZY_LOCK")
266 fLockSpec = 1;
267 else if (lockSpecString == "B_FULL_LOCK")
268 fLockSpec = 2;
269 else if (lockSpecString == "B_CONTIGUOUS")
270 fLockSpec = 3;
271 else if (lockSpecString == "B_LOMEM")
272 fLockSpec = 4;
273 else {
274 fprintf(stdout, "Wrong lock specification: %s\n"
275 "\tlock specification is one of the following values:\n"
276 "\tB_NO_LOCK, B_LAZY_LOCK, B_FULL_LOCK, B_CONTIGUOUS, B_LOMEM\n\n", argv[3]);
277 return;
278 }
279
280 // get the protection flags
281 BString protectionFlagStr(argv[4]);
282 if (protectionFlagStr == "B_READ_AREA") {
283 fprintf(stdout,
284 "WARNING: area is read only.\n"
285 "Any attempt for writing should be fail!\n"
286 "Expecting crash!\n");
287 fProtection = 1;
288 } else if (protectionFlagStr == "B_WRITE_AREA")
289 fProtection = 2;
290 else if (protectionFlagStr == "B_READ_AREA | B_WRITE_AREA"
291 || protectionFlagStr == "B_READ_AREA|B_WRITE_AREA"
292 || protectionFlagStr == "B_READ_AREA |B_WRITE_AREA"
293 || protectionFlagStr == "B_READ_AREA| B_WRITE_AREA"
294 || protectionFlagStr == "B_WRITE_AREA | B_READ_AREA"
295 || protectionFlagStr == "B_WRITE_AREA|B_READ_AREA"
296 || protectionFlagStr == "B_WRITE_AREA |B_READ_AREA"
297 || protectionFlagStr == "B_WRITE_AREA| B_READ_AREA")
298 fProtection = 3;
299 else {
300 fprintf(stdout, "Wrong protection flags: %s\n"
301 "\t protection is one of the following values:\n"
302 "\tB_READ_AREA, B_WRITE_AREA, B_READ_AREA | B_WRITE_AREA\n", argv[4]);
303 return;
304 }
305
306 fOk = true;
307}
308
309
310status_t
311AreaTestApplication::AreaCreate(uint32 numOfAreas)
312{
313 TR_AR_CR_DL((stdout, "numOfAreas is %ld\n", numOfAreas));
314 char error;
315 if (numOfAreas == 0) {
316 error = B_ERROR;
317 throw error;
318 }
319
320 static bool fragmPreparation = true;
321
322 for (uint32 indx = 0 ; indx < numOfAreas; indx++) {
323 area_id areaSpace;
324 areaSpace = create_area("AreaSpace", &fStartingAddress, fAddressSpec,
325 fRequestedSize, fLockSpec, fProtection);
326
327 if (fFragmentationTest && fragmPreparation) {
328 fAreaPrepIdTag[indx] = fAreaIdTag[indx] = areaSpace;
329 // fAreaPrepIdTag is an array that will be used
330 // for deleting the remaining preparation areas
331 } else
332 fAreaIdTag[indx] = areaSpace;
333
334 TR_AR_CR_DL((stdout, "fAreaIdTag[%ld] is %ld at %p\n", indx, fAreaIdTag[indx],
335 fStartingAddress));
336
337 if (areaSpace < 0) {
338 fprintf(stdout, "Fail to create area!\n");
339 fprintf(stdout, "fAreaIdTag[%ld] is %ld at %p\n", indx, fAreaIdTag[indx],
340 fStartingAddress);
341 fprintf(stdout, "areaSpace is %ld\n", areaSpace);
342 throw (area_id)(areaSpace);
343 }
344
345 fAreaAddress[indx] = static_cast<uint8*>(fStartingAddress);
346 fStartingAddress = static_cast<uint8*>(fStartingAddress) + fRequestedSize;
347 }
348
349 fStartingAddress = static_cast<uint8*>(fAreaAddress[0]);
350
351 if (fFragmentationTest)
352 fragmPreparation = false;
353
354 return B_OK;
355}
356
357
358status_t
359AreaTestApplication::TouchPages(uint32 numOfAreas)
360{
361 // Touching requested page(s) of each area.
362
363 // although it might seems not exact
364 // this function measures only the writing to pages (page fault handling)
365 // namely this: *areaPointer = 1;
366 // comment out the writing, this function
367 // for 500 areas (100 pages per area) costs 310 nanosec per area!
368
369 for (uint32 index = 0; index < numOfAreas; index++) {
370 uint8* areaPointer = fAreaAddress[index];
371 for (uint32 indx = 0 ; indx < fNumOfPages; indx++) {
372 *areaPointer = 1;
373 TR_TOUCH((stdout, "fAreaAddress[%d] is %p, fNumOfPages are %d,"
374 " writing at %p, the value of %d\n", index, fAreaAddress[index], fNumOfPages,
375 areaPointer, *areaPointer));
376 areaPointer = areaPointer + B_PAGE_SIZE;
377 }
378 }
379 return B_OK;
380}
381
382
383status_t
384AreaTestApplication::DeleteAllAreas(uint32 numOfAreas)
385{
386 status_t error;
387 for (uint32 index = 0 ; index < numOfAreas; index++) {
388 TR_AR_CR_DL((stdout, "deleting area with fAreaIdTag[%ld] %ld \n", index, fAreaIdTag[index]));
389 error = delete_area(fAreaIdTag[index]);
390 if (error == B_ERROR) {
391 fprintf(stdout, "Couldn't delete area with fAreaIdTag[%ld] %ld \n", index, fAreaIdTag[index]);
392 throw (status_t)(error);
393 }
394 }
395 return B_OK;
396}
397
398
399status_t
400AreaTestApplication::DeleteEvenAreas(uint32 numOfAreas)
401{
402 status_t error;
403 for (uint32 index = 0 ; index < numOfAreas; index += 2) {
404 TR_AR_CR_DL((stdout, "deleting area with fAreaPrepIdTag[%ld] %ld \n", index, fAreaPrepIdTag[index]));
405 error = delete_area(fAreaPrepIdTag[index]);
406 if (error == B_ERROR) {
407 fprintf(stdout, "Couldn't delete area with fAreaPrepIdTag[%ld] %ld \n", index, fAreaPrepIdTag[index]);
408 throw (status_t)(error);
409 }
410 }
411 return B_OK;
412}
413
414
415status_t
416AreaTestApplication::DeleteOddAreas(uint32 numOfAreas)
417{
418 status_t error;
419 for (uint32 index = 1 ; index < numOfAreas; index += 2) {
420 TR_AR_CR_DL((stdout, "deleting area with fAreaPrepIdTag[%ld] %ld \n", index, fAreaPrepIdTag[index]));
421 error = delete_area(fAreaPrepIdTag[index]);
422 if (error == B_ERROR) {
423 fprintf(stdout, "Couldn't delete area with fAreaPrepIdTag[%ld] %ld \n", index, fAreaPrepIdTag[index]);
424 throw (status_t)(error);
425 }
426 }
427 return B_OK;
428}
429
430status_t
431AreaTestApplication::NullFunction(uint32 counter)
432{
433 fIterations = 5000000;
434 TR_NL_FC((stdout, "inside NullFunction, counter is %ld.\n", counter));
435 // the only usefulness of this function
436 // is to measure function call overhead
437 for (uint32 index = 0; index < 5000000; index++)
438 DoNothing();
439
440 return B_OK;
441}
442
443
444unsigned long
445AreaTestApplication::UsingGettimeofday(PMFI BenchFunction)
446{
447 struct timeval before;
448 struct timeval after;
449 unsigned long elapsed;
450
451 gettimeofday(&before, NULL);
452 (this->*BenchFunction)(fIterations);
453 gettimeofday(&after, NULL);
454
455
456 elapsed = 1000000 * (after.tv_sec - before.tv_sec);
457 elapsed += after.tv_usec - before.tv_usec;
458 TR_ITER((stdout, "fIterations is %d", fIterations));
459 return elapsed;
460}
461
462
463bigtime_t
464AreaTestApplication::UsingSystemTime(PMFI BenchFunction)
465{
466 bigtime_t start;
467 bigtime_t stop;
468
469 start = system_time();
470 (this->*BenchFunction)(fIterations);
471 stop = system_time();
472
473 TR_ITER((stdout, "fIterations is %d", fIterations));
474 return stop - start;
475}
476
477
478void
479AreaTestApplication::ReadyToRun()
480{
481 if (GoodArguments()) {
482
483 // create the area
484 area_id areaSpace;
485 fRequestedSize = B_PAGE_SIZE * fNumOfPages; // B_PAGE_SIZE = 4096 bytes
486 void* startingAddress = (void*)fRequestedSize;
487 areaSpace = create_area("AreaSpace", &startingAddress, fAddressSpec,
488 fRequestedSize, fLockSpec, fProtection);
489
490
491 // errors checking
492
493 if (areaSpace < 0)
494 fprintf(stdout, "The system said: %s. Error code number is %ld\n", strerror(areaSpace), areaSpace);
495
496 if (areaSpace == B_BAD_VALUE) {
497 // SUGESTION: here we may want in the future to extend our create_area
498 // implemetation for the bad values,
499 // to see what excactly was going on.
500 fprintf(stdout, "Bad argument value.\n"
501 "Possible errors:\n"
502 " a) You passed an unrecognized constant for addr_spec or lock\n"
503 " b) the addr or size value isn't a multiple of B_PAGE_SIZE,\n"
504 " c) you set addr_spec to B_EXACT_ADDRESS but the address request couldn't\n"
505 " be fulfilled. \n");
506 Quit();
507 return;
508 }
509
510 if (areaSpace == B_NO_MEMORY) {
511 if (fRequestedSize < (900 * 4096))
512 fprintf(stdout, "Requested size %ld KB is to big!\n", fRequestedSize / 1024);
513 else
514 fprintf(stdout, "Requested size %ld MB is to big!\n", fRequestedSize / (1024 * 1024));
515 Quit();
516 return;
517 }
518
519 if (areaSpace == B_ERROR) {
520 fprintf(stdout, "A system error prevented the area from being created.\n");
521 Quit();
522 return;
523 }
524
525
526 // area has pass errors checking, start the tests
527
528 delete_area(areaSpace);
529
530 // show sysname and release
531 struct utsname osName;
532 status_t error = uname(&osName);
533 if (error != B_ERROR)
534 fprintf(stdout, "\nSysname: %s\trelease: %s\tversion: %s\n",
535 osName.sysname, osName.release, osName.version);
536 else {
537 fprintf(stdout, "\nUnable to get system name and release!\n");
538 fprintf(stdout, "Error was %s, and error number is %d\n", strerror(error), error);
539 }
540
541 // show wheather we are running the fragmentation
542 // test or not
543 if (fFragmentationTest) {
544 fprintf(stdout, "Running the fragmentation test: \n"
545 "Creating preparation areas; will be deleted at even indices.\n"
546 "(The remaining areas will be deleted after the measuring tests!)\n");
547 }
548
549 // show user's request
550 if (fRequestedSize < (1024 * 1024))
551 fprintf(stdout,
552 "\nRequested %ld areas. Area's size will be %.2f KB (%d pages).\n",
553 fNumOfAreas, fRequestedSize / double(1024), fNumOfPages);
554 else
555 fprintf(stdout,
556 "\nRequested %ld areas. Area's size will be %.2f MB (%d pages).\n",
557 fNumOfAreas, fRequestedSize / double(1024 * 1024), fNumOfPages);
558
559 // open the file *.data
560 // for writing some infos
561 FILE* pointerToDataFile;
562 BString dataFileName(fFileName.String());
563 dataFileName += ".data";
564 pointerToDataFile = fopen(dataFileName.String(), "w");
565
566 try {
567 AreaCreate(fNumOfAreas);
568
569 char* showAddress = static_cast<char*>(fStartingAddress);
570 for (uint32 index = 0; index < fNumOfAreas; index++) {
571 fprintf(pointerToDataFile, "fAreaIdTag[%ld] area_id is %ld starting at %p\n",
572 index, fAreaIdTag[index], showAddress);
573 showAddress = showAddress + fRequestedSize;
574 }
575
576 } catch(char& error) {
577 fprintf(stdout, "abording time tests, reason: number of areas is 0!\n");
578 fclose(pointerToDataFile);
579 Quit();
580 return;
581 } catch(area_id& areaIdValue) {
582 fprintf(stdout, "abording time tests!\n");
583 fprintf(stdout, "areaIdValue is %ld \n", areaIdValue);
584 fclose(pointerToDataFile);
585 DeleteAllAreas(fNumOfAreas);
586 Quit();
587 return;
588 }
589
590 if (fFragmentationTest) {
591 try {
592 DeleteEvenAreas(fNumOfAreas);
593 } catch(status_t& deleteAreaError) {
594 fprintf(stdout, "Abording time tests!\n");
595 fprintf(stdout, "deleteAreaError is %ld\n", deleteAreaError);
596 }
597 } else {
598 try {
599 DeleteAllAreas(fNumOfAreas);
600 } catch(status_t& deleteAreaError) {
601 fprintf(stdout, "Abording time tests!\n");
602 fprintf(stdout, "deleteAreaError is %ld\n", deleteAreaError);
603 }
604 }
605
606 fclose(pointerToDataFile);
607
608 fprintf(stdout, "\n");
609 fprintf(stdout, "------------------------------------------------------------------\n");
610 fprintf(stdout, " Measuring the time of area's creation and deletion\n");
611 fprintf(stdout, "------------------------------------------------------------------\n");
612
613 // Print results
614 try {
615 fprintf(stdout, "%1s %15s", "TimeFunction", "AreaCreate\n");
616 PrintResults(kUsingGettimeofday, (&AreaTestApplication::AreaCreate));
617 fprintf(stdout, "%1s %15s", "TimeFunction", "TouchPages\n");
618 PrintResults(kUsingGettimeofday, (&AreaTestApplication::TouchPages));
619 fprintf(stdout, "%1s %15s", "TimeFunction", "DeleteAllAreas\n");
620 PrintResults(kUsingGettimeofday, (&AreaTestApplication::DeleteAllAreas));
621 fprintf(stdout, "------------------------------------\n");
622 } catch(area_id& areaIdVal) {
623 fprintf(stdout, "abording time tests!\n");
624 fprintf(stdout, "areaIdVal is %ld \n", areaIdVal);
625 } catch(status_t& deleteAreaError) {
626 fprintf(stdout, "Abording time tests!\n");
627 fprintf(stdout, "deleteAreaError is %ld\n", deleteAreaError);
628 }
629
630 // the following is only to keep an eye to the NuullFunctions timings
631 //PrintResults(kAll, (&AreaTestApplication::NullFunction));
632
633 if (fFragmentationTest) {
634 try {
635 DeleteOddAreas(fNumOfAreas);
636 } catch(status_t& deleteAreaError) {
637 fprintf(stdout, "Abording time tests!\n");
638 fprintf(stdout, "deleteAreaError is %ld\n", deleteAreaError);
639 }
640 }
641
642 } else
643 _Usage();
644
645 Quit();
646}
647
648
649// #pragma mark -
650
651
652int
653main(int32 argc, const char** argv)
654{
655 AreaTestApplication app;
656 if (app.InitCheck() != B_OK)
657 return kErrorInitFail;
658
659 app.Run();
660 if (!app.GoodArguments())
661 return kErrorArgumentsFail;
662
663 return 0;
664}