~vmkononenko/+junk/uperf

« back to all changes in this revision

Viewing changes to src/hwcounter.c

  • Committer: Volodymyr Kononenko
  • Date: 2017-05-02 11:55:13 UTC
  • Revision ID: vmkononenko@gmail.com-20170502115513-0xg7uvymc02nu0sp
Tags: upstream-1.0.5
ImportĀ upstreamĀ versionĀ 1.0.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2008 Sun Microsystems
 
3
 *
 
4
 * This file is part of uperf.
 
5
 *
 
6
 * uperf is free software: you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License version 3
 
8
 * as published by the Free Software Foundation.
 
9
 *
 
10
 * uperf is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with uperf.  If not, see http://www.gnu.org/licenses/.
 
17
 */
 
18
 
 
19
/*
 
20
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved. Use is
 
21
 * subject to license terms.
 
22
 */
 
23
#ifdef HAVE_CONFIG_H
 
24
#include "../config.h"
 
25
#endif /* HAVE_CONFIG_H */
 
26
 
 
27
#include "uperf.h"
 
28
#include "hwcounter.h"
 
29
#include <sys/systeminfo.h>
 
30
#include "logging.h"
 
31
#include <assert.h>
 
32
#include <stdlib.h>
 
33
#include <stdio.h>
 
34
#include <errno.h>
 
35
 
 
36
enum event {
 
37
        VALID, NOTVALID
 
38
};
 
39
static int valid_event = NOTVALID;
 
40
 
 
41
static void
 
42
check_event(void *arg, uint_t picno, const char *event)
 
43
{
 
44
        char *ev = (char *) arg;
 
45
 
 
46
        uperf_debug("Checking %s == %s\n", ev, event);
 
47
        if (valid_event == NOTVALID && (strcasecmp(ev, event) == 0)) {
 
48
                valid_event = VALID;
 
49
        }
 
50
}
 
51
 
 
52
#ifdef DEBUG
 
53
static void
 
54
print_event(void *arg, const char *event)
 
55
{
 
56
        printf("Event is :%s\n", event);
 
57
}
 
58
#endif /* DEBUG */
 
59
 
 
60
int
 
61
hwcounter_init()
 
62
{
 
63
#ifdef USE_CPCv11
 
64
        int cpuver;
 
65
 
 
66
        if (cpc_version(CPC_VER_CURRENT) != CPC_VER_CURRENT) {
 
67
                (void) fprintf(stderr, "CPC library mismatch\n");
 
68
                return (1);
 
69
        }
 
70
#elif defined(USE_CPCv21)
 
71
        if ((cpc = cpc_open(CPC_VER_CURRENT)) == NULL) {
 
72
                char *errstr = strerror(errno);
 
73
                (void) fprintf(stderr,
 
74
                    "cannot access performance counter library - %s\n",
 
75
                    errstr);
 
76
                return (1);
 
77
        }
 
78
#endif
 
79
        return (0);
 
80
}
 
81
int
 
82
hwcounter_fini(hwcounter_t * hw)
 
83
{
 
84
#ifdef USE_CPCv21
 
85
        return (cpc_close(cpc));
 
86
#else
 
87
        return (0);
 
88
#endif
 
89
}
 
90
/*
 
91
 * We first try to get the events from UPERFHWEVENTS environment variable.
 
92
 * If not, we fall back to the the following
 
93
 */
 
94
static void
 
95
default_counters(hwcounter_t * hw)
 
96
{
 
97
        char arch[128];
 
98
        char *ev1, *ev2;
 
99
        char *events;
 
100
        int use_defaults = 0;
 
101
 
 
102
        if ((events = getenv("UPERFHWEVENTS")) == NULL) {
 
103
                use_defaults = 1;
 
104
        } else {
 
105
                ev1 = strtok(events, ",");
 
106
                ev2 = strtok(NULL, ",");
 
107
                if ((ev1 == NULL) || (ev2 == NULL)) {
 
108
                        (void) fprintf(stderr,
 
109
                            "I Dont understand UPERFHWEVENTS!!");
 
110
                        (void) fprintf(stderr, "We will use defaults\n");
 
111
                        use_defaults = 1;
 
112
                }
 
113
        }
 
114
        if (use_defaults) {
 
115
                /* get the arch */
 
116
                sysinfo(SI_ARCHITECTURE, arch, 128);
 
117
                /* fprintf(stderr, "DEBUG: arch:%s\n", arch); */
 
118
                if (strcmp(arch, "i386") == 0) {
 
119
                        ev1 = "BU_cpu_clk_unhalted";
 
120
                        ev2 = "FR_retired_x86_instr_w_excp_intr";
 
121
                } else if (strcmp(arch, "sparc") == 0) {
 
122
                        ev1 = "Cycle_cnt";
 
123
                        ev2 = "Instr_cnt";
 
124
                } else {
 
125
                        ev1 = ev2 = "Error";
 
126
                }
 
127
        }
 
128
        strlcpy(hw->counter1, ev1, COUNTER_MAXLEN);
 
129
        strlcpy(hw->counter2, ev2, COUNTER_MAXLEN);
 
130
}
 
131
/*
 
132
 * Validate the events ev1 and ev2. Return 0 on success Called in single
 
133
 * thread mode. Updates valid_event
 
134
 */
 
135
int
 
136
hwcounter_validate_events(char *ev1, char *ev2)
 
137
{
 
138
#ifdef USE_CPCv2
 
139
        cpc_t *cpc;
 
140
        char *errstr;
 
141
 
 
142
        /* NULL events are OK as we will use default ones */
 
143
        if (ev1 == NULL || ev2 == NULL) {
 
144
                return (0);
 
145
        }
 
146
        if ((cpc = cpc_open(CPC_VER_CURRENT)) == NULL) {
 
147
                errstr = strerror(errno);
 
148
                (void) fprintf(stderr,
 
149
                    "cannot access performance counter library - %s\n",
 
150
                    errstr);
 
151
                return (1);
 
152
        }
 
153
#ifdef DEBUG
 
154
        printf("No of counters:%d\nValid events are", cpc_npic(cpc));
 
155
        cpc_walk_events_all(cpc, 0, print_event);
 
156
#endif
 
157
        cpc_walk_events_pic(cpc, 0, ev1, check_event);
 
158
        if (valid_event == VALID) {
 
159
                cpc_walk_events_pic(cpc, 1, ev2, check_event);
 
160
        }
 
161
        cpc_close(cpc);
 
162
#endif
 
163
        if (valid_event == NOTVALID) {
 
164
                return (1);
 
165
        } else {
 
166
                return (0);
 
167
        }
 
168
}
 
169
int
 
170
hwcounter_initlwp(hwcounter_t * hw, const char *c1, const char *c2)
 
171
{
 
172
        int ret, cpuver;
 
173
        char *eventstr;
 
174
        char *errstr;
 
175
        int siz = 512;
 
176
 
 
177
        hw->init_status = -1;
 
178
        if (c1 == NULL || c2 == NULL) {
 
179
                default_counters(hw);
 
180
        } else {
 
181
                strlcpy(hw->counter1, c1, COUNTER_MAXLEN);
 
182
                strlcpy(hw->counter2, c2, COUNTER_MAXLEN);
 
183
        }
 
184
#ifdef USE_CPCv1
 
185
        if (cpc_version(CPC_VER_CURRENT) != CPC_VER_CURRENT) {
 
186
                (void) fprintf(stderr, "CPC library mismatch\n");
 
187
                return (-1);
 
188
        }
 
189
        eventstr = calloc(siz, sizeof (char));
 
190
        if (eventstr == NULL) {
 
191
                (void) fprintf(stderr,
 
192
                    "Cannot allocate memory for event string.\n");
 
193
                return (-1);
 
194
        }
 
195
        snprintf(eventstr, siz, "pic0=%s,pic1=%s", hw->counter1, hw->counter2);
 
196
        if ((cpuver = cpc_getcpuver()) == -1) {
 
197
                (void) fprintf(stderr, "No performance counter hardware!");
 
198
                free(eventstr);
 
199
                return (-1);
 
200
        }
 
201
        if (cpc_strtoevent(cpuver, eventstr, &hw->event) != 0) {
 
202
                (void) fprintf(stderr, "can't measure '%s' on this processor",
 
203
                        eventstr);
 
204
                free(eventstr);
 
205
                return (-1);
 
206
        }
 
207
        if (cpc_access() == -1) {
 
208
                (void) fprintf(stderr, "Cannot  access perf counters: %s",
 
209
                        strerror(errno));
 
210
                free(eventstr);
 
211
                return (-1);
 
212
        }
 
213
        if (cpc_bind_event(&hw->event, 0) == -1) {
 
214
                (void) fprintf(stderr, "Cannot bind lwp%d: %s",
 
215
                        MY_THREAD_ID(), strerror(errno));
 
216
                free(eventstr);
 
217
                return (-1);
 
218
        }
 
219
#elif defined(USE_CPCv2)
 
220
        assert(hw);
 
221
        if ((hw->cpc = cpc_open(CPC_VER_CURRENT)) == NULL) {
 
222
                errstr = strerror(errno);
 
223
                (void) fprintf(stderr,
 
224
                    "cannot access performance counter library - %s\n",
 
225
                    errstr);
 
226
                return (-1);
 
227
        }
 
228
        hw->set = cpc_set_create(hw->cpc);
 
229
        /*
 
230
         * printf("No of counters:%d\n", cpc_npic(cpc));
 
231
         * cpc_walk_events_all(cpc, 0, print_event);
 
232
         */
 
233
        ret = cpc_set_add_request(hw->cpc,      /* ptr to cpc_t */
 
234
                hw->set,        /* The set */
 
235
                hw->counter1,   /* Event */
 
236
                0,              /* Initial val of counter */
 
237
                CPC_COUNT_USER | CPC_COUNT_SYSTEM,      /* flag */
 
238
                0, NULL);
 
239
        if (ret == -1) {
 
240
                (void) fprintf(stderr, "Error adding counter %s to set\n",
 
241
                        hw->counter1);
 
242
                perror("cpc_set_add_request:");
 
243
                (void) cpc_set_destroy(hw->cpc, hw->set);
 
244
                return (-1);
 
245
        }
 
246
        /* fprintf(stderr, "DEBUG: added event at index : %d\n", ret); */
 
247
        ret = cpc_set_add_request(hw->cpc,      /* ptr to cpc_t */
 
248
                hw->set,        /* The set */
 
249
                hw->counter2,   /* Event */
 
250
                0,              /* Initial val of counter */
 
251
                CPC_COUNT_USER | CPC_COUNT_SYSTEM,      /* flag */
 
252
                0, NULL);
 
253
        if (ret == -1) {
 
254
                (void) fprintf(stderr, "Error adding counter %s to set\n",
 
255
                        hw->counter2);
 
256
                perror("cpc_set_add_request:");
 
257
                (void) cpc_set_destroy(hw->cpc, hw->set);
 
258
                return (-1);
 
259
        }
 
260
        /* Now bind the current lwp to this event set */
 
261
        ret = cpc_bind_curlwp(hw->cpc, hw->set, CPC_BIND_LWP_INHERIT);
 
262
        if (ret != 0) {
 
263
                (void) fprintf(stderr, "Error binding current lwp\n");
 
264
                perror("cpc_bin_curlwp:");
 
265
                (void) cpc_set_destroy(hw->cpc, hw->set);
 
266
                return (-1);
 
267
        }
 
268
        hw->start = cpc_buf_create(hw->cpc, hw->set);
 
269
        hw->end = cpc_buf_create(hw->cpc, hw->set);
 
270
        hw->diff = cpc_buf_create(hw->cpc, hw->set);
 
271
        if (hw->start == NULL || hw->end == NULL || hw->diff == NULL) {
 
272
                (void) fprintf(stderr, "Error creating buffers\n");
 
273
                perror("cpc_bin_curlwp:");
 
274
                assert(!cpc_unbind(hw->cpc, hw->set));
 
275
                (void) cpc_set_destroy(hw->cpc, hw->set);
 
276
                return (-1);
 
277
        }
 
278
#endif
 
279
        hw->init_status = 1;
 
280
#ifdef USE_CPCv1
 
281
        free(eventstr);
 
282
#endif
 
283
        return (0);
 
284
}
 
285
int
 
286
hwcounter_finilwp(hwcounter_t * hw)
 
287
{
 
288
#ifdef USE_CPCv2
 
289
        if (hw->init_status == 1) {
 
290
                cpc_unbind(hw->cpc, hw->set);
 
291
                (void) cpc_set_destroy(hw->cpc, hw->set);
 
292
        }
 
293
#endif
 
294
        return (0);
 
295
}
 
296
#ifdef USE_CPCv2
 
297
static void
 
298
print_cpc_buf(cpc_t * cpc, cpc_buf_t * buf)
 
299
{
 
300
        uint64_t val;
 
301
 
 
302
        cpc_buf_get(cpc, buf, 0, &val);
 
303
        (void) printf("Counter1: %9lld\n", val);
 
304
        cpc_buf_get(cpc, buf, 1, &val);
 
305
        (void) printf("Counter1: %9lld\n", val);
 
306
}
 
307
#endif
 
308
int
 
309
hwcounter_snap(hwcounter_t * hw, int type)
 
310
{
 
311
        int err = 0;
 
312
 
 
313
        assert(hw->init_status);
 
314
        if (type == SNAP_BEGIN) {
 
315
                /* fprintf(stderr, "SNAP_BEGIN SNAP\n"); */
 
316
#ifdef USE_CPCv1
 
317
                err = cpc_take_sample(&hw->start);
 
318
#elif defined(USE_CPCv2)
 
319
                err = cpc_set_sample(hw->cpc, hw->set, hw->start);
 
320
#endif
 
321
        } else {
 
322
                /* fprintf(stderr, "END SNAP\n"); */
 
323
#ifdef USE_CPCv1
 
324
                err = cpc_take_sample(&hw->end);
 
325
#elif defined(USE_CPCv2)
 
326
                err = cpc_set_sample(hw->cpc, hw->set, hw->end);
 
327
#endif
 
328
        }
 
329
        if (err != 0)
 
330
                (void) fprintf(stderr, "Error snapping %s\n", strerror(errno));
 
331
        return (0);
 
332
}
 
333
/*
 
334
 * Get the counter index = 0 : Counter1, usr+sys index = 1 : Counter2,
 
335
 * usr+sys
 
336
 */
 
337
uint64_t
 
338
hwcounter_get(hwcounter_t * hw, int index)
 
339
{
 
340
        uint64_t val;
 
341
 
 
342
#ifdef USE_CPCv1
 
343
        switch (index) {
 
344
        case 0:
 
345
                val = hw->end.ce_pic[0] - hw->start.ce_pic[0];
 
346
        case 1:
 
347
                val = hw->end.ce_pic[1] - hw->start.ce_pic[1];
 
348
        }
 
349
#elif defined(USE_CPCv2)
 
350
        cpc_buf_sub(hw->cpc, hw->diff, hw->end, hw->start);
 
351
        cpc_buf_get(hw->cpc, hw->diff, index, &val);
 
352
#endif
 
353
        return (val);
 
354
}
 
355
#ifdef HWCOUNTER_MAIN
 
356
int
 
357
main(int argc, char *argv[])
 
358
{
 
359
        hwcounter_t *hw;
 
360
        int i, total = 0;
 
361
 
 
362
        hwcounter_init();
 
363
        hw = hwcounter_initlwp(NULL, NULL);
 
364
        hwcounter_snap(hw, SNAP_BEGIN);
 
365
        for (i = 0; i < 20; i++)
 
366
                total++;
 
367
        hwcounter_snap(hw, SNAP_END);
 
368
        printf("Iteration count: %d\n", total);
 
369
        printf("%9s %9s\n", "Cycle_cnt", "Instr_cnt");
 
370
        printf("%9lld %9lld\n", hwcounter_get(hw, 0),
 
371
                hwcounter_get(hw, 1));
 
372
        hwcounter_finilwp(hw);
 
373
        hwcounter_fini(hw);
 
374
}
 
375
#endif                          /* HWCOUNTER_MAIN */