1 /*- 2 * Copyright (c) 2014, Neville-Neil Consulting 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 * 28 * Author: George V. Neville-Neil 29 * 30 */ 31 32 /* 33 * Calculate the time overhead of starting, stopping, and recording 34 * pmc counters. 35 * 36 * The only argument is a counter name, such as "instruction-retired" 37 * which is CPU dependent and can be found with pmmcontrol(8) using 38 * pmccontrol -L. 39 * 40 * The start, stop, read and write operations are timed using the 41 * rdtsc() macro which reads the Time Stamp Counter on the CPU. 42 */ 43 44 #include <stdio.h> 45 #include <err.h> 46 #include <sysexits.h> 47 #include <sys/types.h> 48 #include <machine/cpufunc.h> 49 #include <pmc.h> 50 51 int 52 main(int argc, char **argv) 53 { 54 pmc_id_t pmcid; 55 pmc_value_t read_value; 56 pmc_value_t read_clear_value; 57 uint64_t tsc1, write_cyc, start_cyc, read_cyc, stop_cyc; 58 char *counter_name; 59 60 if (argc != 2) 61 err(EX_USAGE, "counter-name required"); 62 63 counter_name = argv[1]; 64 65 if (pmc_init() != 0) 66 err(EX_OSERR, "hwpmc(4) not loaded, kldload or update your kernel"); 67 68 if (pmc_allocate(counter_name, PMC_MODE_SC, 0, 0, &pmcid) < 0) 69 err(EX_OSERR, "failed to allocate %s as a system counter in counting mode", 70 counter_name); 71 72 tsc1 = rdtsc(); 73 if (pmc_write(pmcid, 0) < 0) 74 err(EX_OSERR, "failed to zero counter %s", counter_name); 75 write_cyc = rdtsc() - tsc1; 76 77 tsc1 = rdtsc(); 78 if (pmc_start(pmcid) < 0) 79 err(EX_OSERR, "failed to start counter %s", counter_name); 80 start_cyc = rdtsc() - tsc1; 81 82 tsc1 = rdtsc(); 83 if (pmc_read(pmcid, &read_value) < 0) 84 err(EX_OSERR, "failed to read counter %s", counter_name); 85 read_cyc = rdtsc() - tsc1; 86 87 tsc1 = rdtsc(); 88 if (pmc_stop(pmcid) < 0) 89 err(EX_OSERR, "failed to stop counter %s", counter_name); 90 stop_cyc = rdtsc() - tsc1; 91 92 if (pmc_rw(pmcid, 0, &read_clear_value)) 93 err(EX_OSERR, "failed to read and zero %s", counter_name); 94 95 if (pmc_release(pmcid) < 0) 96 err(EX_OSERR, "failed to release %s as a system counter in counting mode", 97 counter_name); 98 99 printf("Counter %s, read value %ld, read/clear value %ld\n", 100 counter_name, read_value, read_clear_value); 101 printf("Cycles to start: %ld\tstop: %ld\tread: %ld\twrite: %ld\n", 102 start_cyc, stop_cyc, read_cyc, stop_cyc); 103 104 return(0); 105 } 106 107