File: testlockcontend.c

package info (click to toggle)
gasnet 2025.8.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 17,424 kB
  • sloc: ansic: 114,758; cpp: 5,158; sh: 4,847; makefile: 2,715; perl: 1,774
file content (181 lines) | stat: -rw-r--r-- 6,899 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/*   $Source: bitbucket.org:berkeleylab/gasnet.git/tests/testlockcontend.c $
 * Description: GASNet lock performance test
 *   Measures the overhead associated with contended locks
 * Copyright 2002, Dan Bonachea <bonachea@cs.berkeley.edu>
 * Terms of use are as specified in license.txt
 */

#include <test.h>

#ifndef GASNET_PAR
#error This test can only be built for GASNet PAR configuration
#endif

static gex_Client_t      myclient;
static gex_EP_t    myep;
static gex_TM_t myteam;
static gex_Segment_t     mysegment;

int mynode = 0;
int iters=0;
void *myseg = NULL;
int accuracy = 0;
int maxthreads = 2;
int threads = 1;

void header(const char *desc) {
      printf("\n---- %s ----\n"
             "   Threads    Total time    Avg. time\n"
             "   -------    ----------    ---------\n", desc);
}
void report(int threads, int64_t totaltime, int iters) {
      char format[80];
      snprintf(format, sizeof(format), "%c:  %%6i     %%%i.%if s  %%%i.%if us\n", 
              TEST_SECTION_NAME(), (4+accuracy), accuracy, (4+accuracy), accuracy);
      printf(format, threads, totaltime/1.0E9, (totaltime/1000.0)/iters);
      fflush(stdout);
}

/* placed in a function to avoid excessive inlining */
gasnett_tick_t ticktime(void) { return gasnett_ticks_now(); }
uint64_t tickcvt(gasnett_tick_t ticks) { return gasnett_ticks_to_ns(ticks); }

void* thread_fn1(void*);
void* thread_fn2(void*);
void* thread_fn3(void*);
void* thread_fn4(void*);

/* ------------------------------------------------------------------------------------ */
/* This tester measures the performance of contended HSLs and pthread mutexes.
 */
int main(int argc, char **argv) {
  

  GASNET_Safe(gex_Client_Init(&myclient, &myep, &myteam, "testlockcontend", &argc, &argv, 0));
  GASNET_Safe(gex_Segment_Attach(&mysegment, myteam, TEST_SEGSZ_REQUEST));
  test_init("testlockcontend",1,"(maxthreads) (iters) (accuracy) (test sections)");

  if (argc > 1) maxthreads = atoi(argv[1]);
  maxthreads = test_thread_limit(maxthreads);
  if (maxthreads < 1) {
    printf("Threads must be between 1 and %i\n", TEST_MAXTHREADS);
    gasnet_exit(-1);
  }

  if (argc > 2) iters = atoi(argv[2]);
  if (!iters) iters = 1000000;

  if (argc > 3) accuracy = atoi(argv[3]);
  if (!accuracy) accuracy = 3;

  if (argc > 4) TEST_SECTION_PARSE(argv[4]);

  if (argc > 5) test_usage();

  mynode = gex_TM_QueryRank(myteam);
  myseg = TEST_MYSEG();

  if (mynode == 0) {
    printf("Running locks performance test with 1..%i threads and %i iterations...\n",maxthreads,iters);
    fflush(stdout);
    MSG0("Spawning pthreads...");
    if (TEST_SECTION_BEGIN_ENABLED()) {
      header("lock/unlock contended pthread mutex (others in thread barrier)");
      test_createandjoin_pthreads(threads = maxthreads, &thread_fn1, NULL, 0);
    }
    if (TEST_SECTION_BEGIN_ENABLED()) {
      header("lock/unlock contended HSL (others in thread barrier)");
      test_createandjoin_pthreads(threads = maxthreads, &thread_fn2, NULL, 0);
    }
    if (TEST_SECTION_BEGIN_ENABLED()) {
      header("lock/unlock contended pthread mutex (no other threads)");
      for (threads=1; threads<=maxthreads; ++threads) {
	test_createandjoin_pthreads(threads, &thread_fn3, NULL, 0);
      }
    }
    if (TEST_SECTION_BEGIN_ENABLED()) {
      header("lock/unlock contended HSL (no other threads)");
      for (threads=1; threads<=maxthreads; ++threads) {
	test_createandjoin_pthreads(threads, &thread_fn4, NULL, 0);
      }
    }
  }

  BARRIER();
  MSG("done.");

  gasnet_exit(0);
  return 0;
}

/* ------------------------------------------------------------------------------------ */
#undef MSG0
#undef ERR
#define MSG0 THREAD_MSG0(id)
#define ERR  THREAD_ERR(id)

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
char _pad[GASNETT_CACHE_LINE_BYTES] = { 0 }; /* bug 2231 workaround */
gex_HSL_t hsl = GEX_HSL_INITIALIZER;

/* ------------------------------------------------------------------------------------ */
#define TIME_OPERATION_SOME(id, op)                             \
do {                                                            \
  PTHREAD_LOCALBARRIER(threads);                                \
  { int i, _thr, _iters = iters, _warmupiters = MAX(1,iters/10);\
    gasnett_tick_t start,end;  /* use ticks interface */        \
    for (i=0; i < _warmupiters; i++) { op; } /* warm-up */      \
    for (_thr = 1; _thr <= threads; ++_thr) {                   \
      PTHREAD_LOCALBARRIER(threads);                            \
      start = ticktime();                                       \
      if (id < _thr) for (i=0; i < _iters; i++) { op; }         \
      PTHREAD_LOCALBARRIER(threads);                            \
      end = ticktime();                                         \
      if (!id)                                                  \
        report(_thr, tickcvt(end - start), iters);              \
    }                                                           \
  }                                                             \
} while (0)

void * thread_fn1(void *arg) { GASNET_BEGIN_FUNCTION();
  int id = (int)(uintptr_t)arg;
  TIME_OPERATION_SOME(id, { pthread_mutex_lock(&mutex); pthread_mutex_unlock(&mutex); });
  return NULL;
}

void * thread_fn2(void *arg) { GASNET_BEGIN_FUNCTION();
  int id = (int)(uintptr_t)arg;
  TIME_OPERATION_SOME(id, { gex_HSL_Lock(&hsl); gex_HSL_Unlock(&hsl); });
  return NULL;
}

/* ------------------------------------------------------------------------------------ */
#define TIME_OPERATION_ALL(id, op)                              \
do {                                                            \
  PTHREAD_LOCALBARRIER(threads);                                \
  { int i, _iters = iters, _warmupiters = MAX(1,iters/10);      \
    gasnett_tick_t start,end;  /* use ticks interface */        \
    for (i=0; i < _warmupiters; i++) { op; } /* warm-up */      \
    PTHREAD_LOCALBARRIER(threads);                              \
    start = ticktime();                                         \
    for (i=0; i < _iters; i++) { op; }                          \
    PTHREAD_LOCALBARRIER(threads);                              \
    end = ticktime();                                           \
    if (!id)                                                    \
      report(threads, tickcvt(end - start), iters);             \
  }                                                             \
} while (0)

void * thread_fn3(void *arg) { GASNET_BEGIN_FUNCTION();
  int id = (int)(uintptr_t)arg;
  TIME_OPERATION_ALL(id, { pthread_mutex_lock(&mutex); pthread_mutex_unlock(&mutex); });
  return NULL;
}

void * thread_fn4(void *arg) { GASNET_BEGIN_FUNCTION();
  int id = (int)(uintptr_t)arg;
  TIME_OPERATION_ALL(id, { gex_HSL_Lock(&hsl); gex_HSL_Unlock(&hsl); });
  return NULL;
}
/* ------------------------------------------------------------------------------------ */