1// Copyright (c) 2005, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10//     * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14//     * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30// ---
31// Author: Craig Silverstein
32//
33// Does some simple arithmetic and a few libc routines, so we can profile it.
34// Define WITH_THREADS to add pthread functionality as well (otherwise, btw,
35// the num_threads argument to this program is ingored).
36
37#include "config_for_unittests.h"
38#include <stdio.h>
39#include <stdlib.h>
40#ifdef HAVE_UNISTD_H
41#include <unistd.h>                 // for fork()
42#endif
43#include <sys/wait.h>               // for wait()
44#include "gperftools/profiler.h"
45#include "base/simple_mutex.h"
46#include "tests/testutil.h"
47
48static int result = 0;
49static int g_iters = 0;   // argv[1]
50
51Mutex mutex(Mutex::LINKER_INITIALIZED);
52
53static void test_other_thread() {
54#ifndef NO_THREADS
55  ProfilerRegisterThread();
56
57  int i, m;
58  char b[128];
59  MutexLock ml(&mutex);
60  for (m = 0; m < 1000000; ++m) {          // run millions of times
61    for (i = 0; i < g_iters; ++i ) {
62      result ^= i;
63    }
64    snprintf(b, sizeof(b), "other: %d", result);  // get some libc action
65  }
66#endif
67}
68
69static void test_main_thread() {
70  int i, m;
71  char b[128];
72  MutexLock ml(&mutex);
73  for (m = 0; m < 1000000; ++m) {          // run millions of times
74    for (i = 0; i < g_iters; ++i ) {
75      result ^= i;
76    }
77    snprintf(b, sizeof(b), "same: %d", result);  // get some libc action
78  }
79}
80
81int main(int argc, char** argv) {
82  if ( argc <= 1 ) {
83    fprintf(stderr, "USAGE: %s <iters> [num_threads] [filename]\n", argv[0]);
84    fprintf(stderr, "   iters: How many million times to run the XOR test.\n");
85    fprintf(stderr, "   num_threads: how many concurrent threads.\n");
86    fprintf(stderr, "                0 or 1 for single-threaded mode,\n");
87    fprintf(stderr, "                -# to fork instead of thread.\n");
88    fprintf(stderr, "   filename: The name of the output profile.\n");
89    fprintf(stderr, ("             If you don't specify, set CPUPROFILE "
90                     "in the environment instead!\n"));
91    return 1;
92  }
93
94  g_iters = atoi(argv[1]);
95  int num_threads = 1;
96  const char* filename = NULL;
97  if (argc > 2) {
98    num_threads = atoi(argv[2]);
99  }
100  if (argc > 3) {
101    filename = argv[3];
102  }
103
104  if (filename) {
105    ProfilerStart(filename);
106  }
107
108  test_main_thread();
109
110  ProfilerFlush();                           // just because we can
111
112  // The other threads, if any, will run only half as long as the main thread
113  RunManyThreads(test_other_thread, num_threads);
114
115  // Or maybe they asked to fork.  The fork test is only interesting
116  // when we use CPUPROFILE to name, so check for that
117#ifdef HAVE_UNISTD_H
118  for (; num_threads < 0; ++num_threads) {   // -<num_threads> to fork
119    if (filename) {
120      printf("FORK test only makes sense when no filename is specified.\n");
121      return 2;
122    }
123    switch (fork()) {
124      case -1:
125        printf("FORK failed!\n");
126        return 1;
127      case 0:             // child
128        return execl(argv[0], argv[0], argv[1], NULL);
129      default:
130        wait(NULL);       // we'll let the kids run one at a time
131    }
132  }
133#endif
134
135  test_main_thread();
136
137  if (filename) {
138    ProfilerStop();
139  }
140
141  return 0;
142}
143