| // Copyright (c) 2005, Google Inc. | 
 | // All rights reserved. | 
 | //  | 
 | // Redistribution and use in source and binary forms, with or without | 
 | // modification, are permitted provided that the following conditions are | 
 | // met: | 
 | //  | 
 | //     * Redistributions of source code must retain the above copyright | 
 | // notice, this list of conditions and the following disclaimer. | 
 | //     * Redistributions in binary form must reproduce the above | 
 | // copyright notice, this list of conditions and the following disclaimer | 
 | // in the documentation and/or other materials provided with the | 
 | // distribution. | 
 | //     * Neither the name of Google Inc. nor the names of its | 
 | // contributors may be used to endorse or promote products derived from | 
 | // this software without specific prior written permission. | 
 | //  | 
 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
 |  | 
 | // --- | 
 | // Author: Craig Silverstein | 
 | // | 
 | // Does some simple arithmetic and a few libc routines, so we can profile it. | 
 | // Define WITH_THREADS to add pthread functionality as well (otherwise, btw, | 
 | // the num_threads argument to this program is ingored). | 
 |  | 
 | #include "config_for_unittests.h" | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #ifdef HAVE_UNISTD_H | 
 | #include <unistd.h>                 // for fork() | 
 | #endif | 
 | #include <sys/wait.h>               // for wait() | 
 | #include "gperftools/profiler.h" | 
 | #include "base/simple_mutex.h" | 
 | #include "tests/testutil.h" | 
 |  | 
 | static int result = 0; | 
 | static int g_iters = 0;   // argv[1] | 
 |  | 
 | Mutex mutex(Mutex::LINKER_INITIALIZED); | 
 |  | 
 | static void test_other_thread() { | 
 | #ifndef NO_THREADS | 
 |   ProfilerRegisterThread(); | 
 |  | 
 |   int i, m; | 
 |   char b[128]; | 
 |   MutexLock ml(&mutex); | 
 |   for (m = 0; m < 1000000; ++m) {          // run millions of times | 
 |     for (i = 0; i < g_iters; ++i ) { | 
 |       result ^= i; | 
 |     } | 
 |     snprintf(b, sizeof(b), "other: %d", result);  // get some libc action | 
 |   } | 
 | #endif | 
 | } | 
 |  | 
 | static void test_main_thread() { | 
 |   int i, m; | 
 |   char b[128]; | 
 |   MutexLock ml(&mutex); | 
 |   for (m = 0; m < 1000000; ++m) {          // run millions of times | 
 |     for (i = 0; i < g_iters; ++i ) { | 
 |       result ^= i; | 
 |     } | 
 |     snprintf(b, sizeof(b), "same: %d", result);  // get some libc action | 
 |   } | 
 | } | 
 |  | 
 | int main(int argc, char** argv) { | 
 |   if ( argc <= 1 ) { | 
 |     fprintf(stderr, "USAGE: %s <iters> [num_threads] [filename]\n", argv[0]); | 
 |     fprintf(stderr, "   iters: How many million times to run the XOR test.\n"); | 
 |     fprintf(stderr, "   num_threads: how many concurrent threads.\n"); | 
 |     fprintf(stderr, "                0 or 1 for single-threaded mode,\n"); | 
 |     fprintf(stderr, "                -# to fork instead of thread.\n"); | 
 |     fprintf(stderr, "   filename: The name of the output profile.\n"); | 
 |     fprintf(stderr, ("             If you don't specify, set CPUPROFILE " | 
 |                      "in the environment instead!\n")); | 
 |     return 1; | 
 |   } | 
 |  | 
 |   g_iters = atoi(argv[1]); | 
 |   int num_threads = 1; | 
 |   const char* filename = NULL; | 
 |   if (argc > 2) { | 
 |     num_threads = atoi(argv[2]); | 
 |   } | 
 |   if (argc > 3) { | 
 |     filename = argv[3]; | 
 |   } | 
 |  | 
 |   if (filename) { | 
 |     ProfilerStart(filename); | 
 |   } | 
 |  | 
 |   test_main_thread(); | 
 |  | 
 |   ProfilerFlush();                           // just because we can | 
 |  | 
 |   // The other threads, if any, will run only half as long as the main thread | 
 |   RunManyThreads(test_other_thread, num_threads); | 
 |  | 
 |   // Or maybe they asked to fork.  The fork test is only interesting | 
 |   // when we use CPUPROFILE to name, so check for that | 
 | #ifdef HAVE_UNISTD_H | 
 |   for (; num_threads < 0; ++num_threads) {   // -<num_threads> to fork | 
 |     if (filename) { | 
 |       printf("FORK test only makes sense when no filename is specified.\n"); | 
 |       return 2; | 
 |     } | 
 |     switch (fork()) { | 
 |       case -1: | 
 |         printf("FORK failed!\n"); | 
 |         return 1; | 
 |       case 0:             // child | 
 |         return execl(argv[0], argv[0], argv[1], NULL); | 
 |       default: | 
 |         wait(NULL);       // we'll let the kids run one at a time | 
 |     } | 
 |   } | 
 | #endif | 
 |  | 
 |   test_main_thread(); | 
 |  | 
 |   if (filename) { | 
 |     ProfilerStop(); | 
 |   } | 
 |  | 
 |   return 0; | 
 | } |