qa: update 660 to generate index.html, fixing pcp-testsuite runs
[pcp.git] / qa / src / multithread5.c
blobfbbe3246120bdd9a20d24882b2f9af2d8e62dd5e
1 /*
2 * Copyright (c) 2011 Ken McDonell. All Rights Reserved.
4 * exercise multi-threaded multiple host contexts with pmLookupDesc()
5 * as the simplest possible case
6 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <pcp/pmapi.h>
11 #include <pcp/impl.h>
12 #include <pthread.h>
14 #ifndef HAVE_PTHREAD_BARRIER_T
15 #include "pthread_barrier.h"
16 #endif
18 #define NMETRIC 5
20 static char *namelist[NMETRIC] = {
21 "sample.seconds",
22 "sampledso.milliseconds",
23 "sample.ulonglong.bin_ctr",
24 "pmcd.cputime.total",
25 "pmcd.buf.alloc",
27 static pmID pmidlist[NMETRIC];
29 static pthread_barrier_t barrier;
31 static int ctx1;
32 static int ctx2;
33 static int ctx3;
35 static void
36 foo(FILE *f, char *fn, int i)
38 pmDesc desc;
39 char strbuf[60];
40 int sts;
42 sts = pmLookupDesc(pmidlist[i], &desc);
43 if (sts < 0) {
44 fprintf(f, "%s: pmLookupDesc[%s] -> %s\n", fn, pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf)), pmErrStr(sts));
45 pthread_exit("botch");
47 else if (pmidlist[i] != desc.pmid) {
48 fprintf(f, "%s: pmLookupDesc: Expecting PMID: %s", fn, pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf)));
49 fprintf(f, " got: %s\n", pmIDStr_r(desc.pmid, strbuf, sizeof(strbuf)));
50 pthread_exit("botch");
52 else {
53 fprintf(f, "%s: %s (%s) ->", fn, namelist[i], pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf)));
54 fprintf(f, " %s", pmTypeStr_r(desc.type, strbuf, sizeof(strbuf)));
55 fprintf(f, " %s", pmInDomStr_r(desc.indom, strbuf, sizeof(strbuf)));
56 if (desc.sem == PM_SEM_COUNTER) fprintf(f, " counter");
57 else if (desc.sem == PM_SEM_INSTANT) fprintf(f, " instant");
58 else if (desc.sem == PM_SEM_DISCRETE) fprintf(f, " discrete");
59 else fprintf(f, " sem-%d", desc.sem);
60 fprintf(f, " %s\n", pmUnitsStr_r(&desc.units, strbuf, sizeof(strbuf)));
64 static void *
65 func1(void *arg)
67 char *fn = "func1";
68 int i;
69 int j;
70 FILE *f;
72 if ((f = fopen("/tmp/func1.out", "w")) == NULL) {
73 perror("func1 fopen");
74 pthread_exit("botch");
77 j = pmUseContext(ctx1);
78 if (j < 0) {
79 fprintf(f, "Error: %s: pmUseContext(%d) -> %s\n", fn, ctx1, pmErrStr(j));
80 fclose(f);
81 pthread_exit("botch");
84 pthread_barrier_wait(&barrier);
86 for (j = 0; j < 100; j++) {
87 for (i = 0; i < NMETRIC; i++)
88 foo(f, fn, i);
91 fclose(f);
92 pthread_exit(NULL);
95 static void *
96 func2(void *arg)
98 char *fn = "func2";
99 int i;
100 int j;
101 FILE *f;
103 if ((f = fopen("/tmp/func2.out", "w")) == NULL) {
104 perror("func2 fopen");
105 pthread_exit("botch");
108 j = pmUseContext(ctx2);
109 if ( j < 0) {
110 fprintf(f, "Error: %s: pmUseContext(%d) -> %s\n", fn, ctx2, pmErrStr(j));
111 fclose(f);
112 pthread_exit("botch");
115 pthread_barrier_wait(&barrier);
117 for (j = 0; j < 100; j++) {
118 for (i = NMETRIC-1; i >= 0; i--)
119 foo(f, fn, i);
122 fclose(f);
123 pthread_exit(NULL);
126 static void *
127 func3(void *arg)
129 char *fn = "func3";
130 int i;
131 int j;
132 FILE *f;
134 if ((f = fopen("/tmp/func3.out", "w")) == NULL) {
135 perror("func3 fopen");
136 pthread_exit("botch");
139 j = pmUseContext(ctx3);
140 if ( j < 0) {
141 fprintf(f, "Error: %s: pmUseContext(%d) -> %s\n", fn, ctx3, pmErrStr(j));
142 fclose(f);
143 pthread_exit("botch");
146 pthread_barrier_wait(&barrier);
148 for (j = 0; j < 100; j++) {
149 for (i = 0; i < NMETRIC; i += 2)
150 foo(f, fn, i);
151 for (i = 1; i < NMETRIC; i += 2)
152 foo(f, fn, i);
155 fclose(f);
156 pthread_exit(NULL);
160 main(int argc, char **argv)
162 pthread_t tid1;
163 pthread_t tid2;
164 pthread_t tid3;
165 int sts;
166 char *msg;
167 int errflag = 0;
168 int c;
170 __pmSetProgname(argv[0]);
172 while ((c = getopt(argc, argv, "D:")) != EOF) {
173 switch (c) {
175 case 'D': /* debug flag */
176 sts = __pmParseDebug(optarg);
177 if (sts < 0) {
178 fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n",
179 pmProgname, optarg);
180 errflag++;
182 else
183 pmDebug |= sts;
184 break;
186 case '?':
187 default:
188 errflag++;
189 break;
193 if (errflag || optind == argc || argc-optind > 3) {
194 fprintf(stderr, "Usage: %s [-D...] host1 [host2 [host3]]\n", pmProgname);
195 exit(1);
198 ctx1 = pmNewContext(PM_CONTEXT_HOST, argv[optind]);
199 if (ctx1 < 0) {
200 printf("Error: pmNewContext(%s) -> %s\n", argv[optind], pmErrStr(ctx1));
201 exit(1);
203 optind++;
205 if (optind < argc) {
206 ctx2 = pmNewContext(PM_CONTEXT_HOST, argv[optind]);
207 if (ctx2 < 0) {
208 printf("Error: pmNewContext(%s) -> %s\n", argv[optind], pmErrStr(ctx2));
209 exit(1);
211 optind++;
213 else
214 ctx2 = ctx1;
216 if (optind < argc) {
217 ctx3 = pmNewContext(PM_CONTEXT_HOST, argv[optind]);
218 if (ctx3 < 0) {
219 printf("Error: pmNewContext(%s) -> %s\n", argv[optind], pmErrStr(ctx2));
220 exit(1);
222 optind++;
224 else
225 ctx3 = ctx2;
227 sts = pmLookupName(NMETRIC, namelist, pmidlist);
228 if (sts != NMETRIC) {
229 int i;
230 if (sts < 0)
231 printf("Error: pmLookupName -> %s\n", pmErrStr(sts));
232 else
233 printf("Error: pmLookupName returned %d, expected %d\n", sts, NMETRIC);
234 for (i = 0; i < NMETRIC; i++) {
235 printf(" %s -> %s\n", namelist[i], pmIDStr(pmidlist[i]));
237 exit(1);
240 sts = pthread_barrier_init(&barrier, NULL, 3);
241 if (sts != 0) {
242 printf("pthread_barrier_init: sts=%d\n", sts);
243 exit(1);
246 sts = pthread_create(&tid1, NULL, func1, NULL);
247 if (sts != 0) {
248 printf("thread_create: tid1: sts=%d\n", sts);
249 exit(1);
251 sts = pthread_create(&tid2, NULL, func2, NULL);
252 if (sts != 0) {
253 printf("thread_create: tid2: sts=%d\n", sts);
254 exit(1);
256 sts = pthread_create(&tid3, NULL, func3, NULL);
257 if (sts != 0) {
258 printf("thread_create: tid3: sts=%d\n", sts);
259 exit(1);
262 pthread_join(tid1, (void *)&msg);
263 if (msg != NULL) printf("tid1: %s\n", msg);
264 pthread_join(tid2, (void *)&msg);
265 if (msg != NULL) printf("tid2: %s\n", msg);
266 pthread_join(tid3, (void *)&msg);
267 if (msg != NULL) printf("tid3: %s\n", msg);
268 pthread_cancel(tid1);
269 pthread_cancel(tid2);
270 pthread_cancel(tid3);
272 exit(0);