? eff_perf ? kstat.d Index: Makefile =================================================================== RCS file: /cvs/src/usr.bin/kstat/Makefile,v retrieving revision 1.2 diff -u -p -r1.2 Makefile --- Makefile 13 Aug 2020 12:37:16 -0000 1.2 +++ Makefile 30 Dec 2020 12:07:05 -0000 @@ -1,7 +1,8 @@ # $OpenBSD: Makefile,v 1.2 2020/08/13 12:37:16 schwarze Exp $ -PROG= kstat +PROG= eff_perf SRCS= kstat.c +MAN= WARNINGS=Yes DEBUG=-g Index: kstat.c =================================================================== RCS file: /cvs/src/usr.bin/kstat/kstat.c,v retrieving revision 1.7 diff -u -p -r1.7 kstat.c --- kstat.c 29 Dec 2020 23:26:48 -0000 1.7 +++ kstat.c 30 Dec 2020 12:07:05 -0000 @@ -67,10 +67,19 @@ struct kstat_filter { TAILQ_HEAD(kstat_filters, kstat_filter); +struct eff_freq { + uint64_t tsc; + uint64_t mperf; + uint64_t aperf; +}; + struct kstat_entry { struct kstat_req kstat; RBT_ENTRY(kstat_entry) entry; int serrno; + + unsigned int gen; + struct eff_freq stats[2]; }; RBT_HEAD(kstat_tree, kstat_entry); @@ -105,7 +114,7 @@ RBT_PROTOTYPE(kstat_tree, kstat_entry, e RBT_GENERATE(kstat_tree, kstat_entry, entry, kstat_cmp); static struct kstat_filter * - kstat_filter_parse(char *); + kstat_filter_parse(const char *); static int kstat_filter_entry(struct kstat_filters *, const struct kstat_req *); @@ -129,13 +138,13 @@ int main(int argc, char *argv[]) { struct kstat_filters kfs = TAILQ_HEAD_INITIALIZER(kfs); + struct kstat_filter *kf; struct kstat_tree kt = RBT_INITIALIZER(); unsigned int version; int fd; const char *errstr; int ch; - struct timespec interval = { 0, 0 }; - int i; + struct timespec interval = { 1, 0 }; while ((ch = getopt(argc, argv, "w:")) != -1) { switch (ch) { @@ -153,10 +162,11 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; - for (i = 0; i < argc; i++) { - struct kstat_filter *kf = kstat_filter_parse(argv[i]); - TAILQ_INSERT_TAIL(&kfs, kf, kf_entry); - } + if (argc != 0) + usage(); + + kf = kstat_filter_parse("::eff_freq:"); + TAILQ_INSERT_TAIL(&kfs, kf, kf_entry); fd = open(DEV_KSTAT, O_RDONLY); if (fd == -1) @@ -166,10 +176,6 @@ main(int argc, char *argv[]) err(1, "kstat version"); kstat_list(&kt, fd, version, &kfs); - kstat_print(&kt); - - if (interval.tv_sec == 0) - return (0); for (;;) { nanosleep(&interval, NULL); @@ -182,13 +188,18 @@ main(int argc, char *argv[]) } static struct kstat_filter * -kstat_filter_parse(char *arg) +kstat_filter_parse(const char *argp) { + char *arg; struct kstat_filter *kf; const char *errstr; char *argv[4]; size_t argc; + arg = strdup(argp); + if (arg == NULL) + err(1, NULL); + for (argc = 0; argc < nitems(argv); argc++) { char *s = strsep(&arg, ":"); if (s == NULL) @@ -279,6 +290,7 @@ kstat_filter_entry(struct kstat_filters return (0); } +#if 0 static int printable(int ch) { @@ -309,7 +321,9 @@ hexdump(const void *d, size_t datalen) printf("|\n"); } } +#endif +#if 0 static void strdump(const void *s, size_t len) { @@ -333,7 +347,9 @@ strdumpnl(const void *s, size_t len) strdump(s, len); printf("\n"); } +#endif +#if 0 static void kstat_kv(const void *d, ssize_t len) { @@ -438,6 +454,20 @@ kstat_kv(const void *d, ssize_t len) len -= blen; } while (len >= (ssize_t)sizeof(*kv)); } +#endif + +static int +kstat_eff_freq(struct eff_freq *ef, const struct kstat_kv *kvs, size_t len) +{ + if (len < (sizeof(*kvs) * 3)) + return (-1); + + ef->tsc = kstat_kv_u64(&kvs[0]); + ef->mperf = kstat_kv_u64(&kvs[1]); + ef->aperf = kstat_kv_u64(&kvs[2]); + + return (0); +} static void kstat_list(struct kstat_tree *kt, int fd, unsigned int version, @@ -495,6 +525,10 @@ kstat_list(struct kstat_tree *kt, int fd if (ioctl(fd, KSTATIOC_FIND_ID, ksreq) == -1) err(1, "find id %llu", ksreq->ks_id); } + + kse->gen = 0; + kstat_eff_freq(&kse->stats[0], + ksreq->ks_data, ksreq->ks_datalen); } } @@ -503,16 +537,20 @@ kstat_print(struct kstat_tree *kt) { struct kstat_entry *kse; struct kstat_req *ksreq; + unsigned int gen; + const struct eff_freq *oef; + struct eff_freq *nef; RBT_FOREACH(kse, kstat_tree, kt) { ksreq = &kse->kstat; - printf("%s:%u:%s:%u\n", + printf("%s:%u:%s:%u ", ksreq->ks_provider, ksreq->ks_instance, ksreq->ks_name, ksreq->ks_unit); if (kse->serrno != 0) { printf("\t%s\n", strerror(kse->serrno)); continue; } +#if 0 switch (ksreq->ks_type) { case KSTAT_T_RAW: hexdump(ksreq->ks_data, ksreq->ks_datalen); @@ -524,6 +562,28 @@ kstat_print(struct kstat_tree *kt) hexdump(ksreq->ks_data, ksreq->ks_datalen); break; } +#endif + + gen = kse->gen; + oef = &kse->stats[gen]; + gen = !gen; + nef = &kse->stats[gen]; + kse->gen = gen; + + kstat_eff_freq(nef, ksreq->ks_data, ksreq->ks_datalen); + +#if 0 + printf("tsc %llu mperf %llu aperf %llu\n", + nef->tsc - oef->tsc, + nef->mperf - oef->mperf, + nef->aperf - oef->aperf); +#endif + + double tsc = nef->tsc - oef->tsc; + double mperf = nef->mperf - oef->mperf; + double aperf = nef->aperf - oef->aperf; + + printf("%.2lf MHz\n", (tsc * aperf / mperf) / 1000000.0); } fflush(stdout);