2
* Copyright (C) 2008 Sun Microsystems
4
* This file is part of uperf.
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.
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.
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/.
20
* Copyright 2005 Sun Microsystems, Inc. All rights reserved. Use is
21
* subject to license terms.
24
#include "../config.h"
25
#endif /* HAVE_CONFIG_H */
28
#include "hwcounter.h"
29
#include <sys/systeminfo.h>
39
static int valid_event = NOTVALID;
42
check_event(void *arg, uint_t picno, const char *event)
44
char *ev = (char *) arg;
46
uperf_debug("Checking %s == %s\n", ev, event);
47
if (valid_event == NOTVALID && (strcasecmp(ev, event) == 0)) {
54
print_event(void *arg, const char *event)
56
printf("Event is :%s\n", event);
66
if (cpc_version(CPC_VER_CURRENT) != CPC_VER_CURRENT) {
67
(void) fprintf(stderr, "CPC library mismatch\n");
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",
82
hwcounter_fini(hwcounter_t * hw)
85
return (cpc_close(cpc));
91
* We first try to get the events from UPERFHWEVENTS environment variable.
92
* If not, we fall back to the the following
95
default_counters(hwcounter_t * hw)
100
int use_defaults = 0;
102
if ((events = getenv("UPERFHWEVENTS")) == NULL) {
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");
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) {
128
strlcpy(hw->counter1, ev1, COUNTER_MAXLEN);
129
strlcpy(hw->counter2, ev2, COUNTER_MAXLEN);
132
* Validate the events ev1 and ev2. Return 0 on success Called in single
133
* thread mode. Updates valid_event
136
hwcounter_validate_events(char *ev1, char *ev2)
142
/* NULL events are OK as we will use default ones */
143
if (ev1 == NULL || ev2 == NULL) {
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",
154
printf("No of counters:%d\nValid events are", cpc_npic(cpc));
155
cpc_walk_events_all(cpc, 0, print_event);
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);
163
if (valid_event == NOTVALID) {
170
hwcounter_initlwp(hwcounter_t * hw, const char *c1, const char *c2)
177
hw->init_status = -1;
178
if (c1 == NULL || c2 == NULL) {
179
default_counters(hw);
181
strlcpy(hw->counter1, c1, COUNTER_MAXLEN);
182
strlcpy(hw->counter2, c2, COUNTER_MAXLEN);
185
if (cpc_version(CPC_VER_CURRENT) != CPC_VER_CURRENT) {
186
(void) fprintf(stderr, "CPC library mismatch\n");
189
eventstr = calloc(siz, sizeof (char));
190
if (eventstr == NULL) {
191
(void) fprintf(stderr,
192
"Cannot allocate memory for event string.\n");
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!");
201
if (cpc_strtoevent(cpuver, eventstr, &hw->event) != 0) {
202
(void) fprintf(stderr, "can't measure '%s' on this processor",
207
if (cpc_access() == -1) {
208
(void) fprintf(stderr, "Cannot access perf counters: %s",
213
if (cpc_bind_event(&hw->event, 0) == -1) {
214
(void) fprintf(stderr, "Cannot bind lwp%d: %s",
215
MY_THREAD_ID(), strerror(errno));
219
#elif defined(USE_CPCv2)
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",
228
hw->set = cpc_set_create(hw->cpc);
230
* printf("No of counters:%d\n", cpc_npic(cpc));
231
* cpc_walk_events_all(cpc, 0, print_event);
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 */
240
(void) fprintf(stderr, "Error adding counter %s to set\n",
242
perror("cpc_set_add_request:");
243
(void) cpc_set_destroy(hw->cpc, hw->set);
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 */
254
(void) fprintf(stderr, "Error adding counter %s to set\n",
256
perror("cpc_set_add_request:");
257
(void) cpc_set_destroy(hw->cpc, hw->set);
260
/* Now bind the current lwp to this event set */
261
ret = cpc_bind_curlwp(hw->cpc, hw->set, CPC_BIND_LWP_INHERIT);
263
(void) fprintf(stderr, "Error binding current lwp\n");
264
perror("cpc_bin_curlwp:");
265
(void) cpc_set_destroy(hw->cpc, hw->set);
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);
286
hwcounter_finilwp(hwcounter_t * hw)
289
if (hw->init_status == 1) {
290
cpc_unbind(hw->cpc, hw->set);
291
(void) cpc_set_destroy(hw->cpc, hw->set);
298
print_cpc_buf(cpc_t * cpc, cpc_buf_t * buf)
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);
309
hwcounter_snap(hwcounter_t * hw, int type)
313
assert(hw->init_status);
314
if (type == SNAP_BEGIN) {
315
/* fprintf(stderr, "SNAP_BEGIN SNAP\n"); */
317
err = cpc_take_sample(&hw->start);
318
#elif defined(USE_CPCv2)
319
err = cpc_set_sample(hw->cpc, hw->set, hw->start);
322
/* fprintf(stderr, "END SNAP\n"); */
324
err = cpc_take_sample(&hw->end);
325
#elif defined(USE_CPCv2)
326
err = cpc_set_sample(hw->cpc, hw->set, hw->end);
330
(void) fprintf(stderr, "Error snapping %s\n", strerror(errno));
334
* Get the counter index = 0 : Counter1, usr+sys index = 1 : Counter2,
338
hwcounter_get(hwcounter_t * hw, int index)
345
val = hw->end.ce_pic[0] - hw->start.ce_pic[0];
347
val = hw->end.ce_pic[1] - hw->start.ce_pic[1];
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);
355
#ifdef HWCOUNTER_MAIN
357
main(int argc, char *argv[])
363
hw = hwcounter_initlwp(NULL, NULL);
364
hwcounter_snap(hw, SNAP_BEGIN);
365
for (i = 0; i < 20; i++)
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);
375
#endif /* HWCOUNTER_MAIN */