diff options
author | Dave Barach <dave@barachs.net> | 2016-02-11 19:28:19 -0500 |
---|---|---|
committer | Gerrit Code Review <gerrit@fd.io> | 2016-02-12 01:30:48 +0000 |
commit | 52642c3c535128cb96489fed45327bdd55953397 (patch) | |
tree | ce6e2cc9f505fbf04acbc9109adb4c204fb96c8c /g2/events.c | |
parent | 3640d537e1c1ea7670b98f0aaf27a48c08984893 (diff) |
Performance tools, initial check-in
Change-Id: I9fb4f4babecbe02d171f38c4d089634e90141937
Signed-off-by: Dave Barach <dave@barachs.net>
Diffstat (limited to 'g2/events.c')
-rw-r--r-- | g2/events.c | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/g2/events.c b/g2/events.c new file mode 100644 index 00000000000..d4333bb05d1 --- /dev/null +++ b/g2/events.c @@ -0,0 +1,475 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/fcntl.h> +#include <sys/mman.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <gtk/gtk.h> +#include "g2.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> + +/* + * globals + */ +boolean g_little_endian; +event_t *g_events; +ulong g_nevents; +pid_sort_t *g_pids; +pid_sort_t *g_original_pids; +int g_npids; +pid_data_t *g_pid_data_list; + +/* + * locals + */ +pid_data_t **s_pidhash; + +/* + * config parameters + */ + +double ticks_per_ns=1000.0; +boolean ticks_per_ns_set; + +/**************************************************************************** +* event_init +****************************************************************************/ + +void event_init(void) +{ + ulong endian; + char *ep; + char *askstr; + int tmp; + + ep = (char *)&endian; + endian = 0x12345678; + if (*ep != 0x12) + g_little_endian = TRUE; + else + g_little_endian = FALSE; + + askstr = getprop("dont_ask_ticks_per_ns_initially"); + + if (askstr && (*askstr == 't' || *askstr == 'T')) { + tmp = atol(getprop_default("ticks_per_ns", 0)); + if (tmp > 0) { + ticks_per_ns = tmp; + ticks_per_ns_set = TRUE; + } + } +} + +/**************************************************************************** +* find_or_add_pid +****************************************************************************/ + +pid_data_t *find_or_add_pid (ulong pid) +{ + pid_data_t *pp; + ulong bucket; + + bucket = pid % PIDHASH_NBUCKETS; + + pp = s_pidhash[bucket]; + + if (pp == 0) { + pp = g_malloc0(sizeof(pid_data_t)); + pp->pid_value = pid; + s_pidhash[bucket] = pp; + g_npids++; + return(pp); + } + while (pp) { + if (pp->pid_value == pid) + return(pp); + pp = pp->next; + } + + pp = g_malloc0(sizeof(pid_data_t)); + pp->pid_value = pid; + pp->next = s_pidhash[bucket]; + s_pidhash[bucket] = pp; + g_npids++; + return(pp); +} + +/**************************************************************************** +* pid_cmp +****************************************************************************/ + +int pid_cmp(const void *a1, const void *a2) +{ + pid_sort_t *p1 = (pid_sort_t *)a1; + pid_sort_t *p2 = (pid_sort_t *)a2; + + if (p1->pid_value < p2->pid_value) + return(-1); + else if (p1->pid_value == p2->pid_value) + return(0); + else + return(1); +} + +/**************************************************************************** +* make_sorted_pid_vector +****************************************************************************/ + +static void make_sorted_pid_vector(void) +{ + pid_data_t *pp; + pid_data_t **p_previous; + pid_sort_t *psp; + int i; + + psp = g_pids = g_malloc(sizeof(pid_sort_t)*g_npids); + + for (i = 0; i < PIDHASH_NBUCKETS; i++) { + pp = s_pidhash[i]; + while(pp) { + psp->pid = pp; + psp->pid_value = pp->pid_value; + psp++; + pp = pp->next; + } + } + + qsort(&g_pids[0], g_npids, sizeof(pid_sort_t), pid_cmp); + + /* put the sort order into the pid objects */ + psp = g_pids; + + /* + * This is rather gross. + * + * We happen to know that whenever this function is called, the hash table + * structure itself is immediately torn down. So the "next" pointers in the + * pid_data_t elements are about to become useless. + * + * So we re-use them, to link all the pid_data_t elements together into a + * single unified linked list, with g_pid_data_list pointing to the head. + * This means we can walk all the pid_data_t objects if we really want to. + * Reading snapshots from disk is one example. + * + * Alternatively we could just leave the hash table in place; this is + * far nicer, but as it happens, trading O(n) lookups for O(1) lookups + * isn't actually a problem for the restricted post-tear-down usage. So for + * now we take the memory savings and swap our hash table for a list. + */ + p_previous = &g_pid_data_list; + for (i = 0; i < g_npids; i++) { + pp = psp->pid; + pp->pid_index = i; + *p_previous = pp; + p_previous = &pp->next; + psp++; + } + *p_previous = NULL; + + /* + * Squirrel away original (sorted) vector, so we can + * toggle between "chase" mode, snapshots, and the original + * display method on short notice + */ + g_original_pids = g_malloc(sizeof(pid_sort_t)*g_npids); + memcpy (g_original_pids, g_pids, sizeof(pid_sort_t)*g_npids); +} + +/**************************************************************************** +* read_events +****************************************************************************/ + +void read_events(char *filename) +{ + ulong *ulp; + ulong size; + event_t *ep; + raw_event_t *rep; + ulonglong start_time=0ULL; + ulonglong low_time; + boolean once=TRUE; + int i; + char tmpbuf [128]; + + ulp = (ulong *)mapfile(filename, &size); + + if (ulp == NULL) { + sprintf(tmpbuf, "Couldn't open %s\n", filename); + infobox("Read Event Log Failure", tmpbuf); + return; + } + + g_nevents = ntohl(*ulp); + + if (size != (g_nevents*sizeof(raw_event_t) + sizeof(g_nevents))) { + sprintf(tmpbuf, "%s was damaged, or isn't an event log.\n", filename); + infobox("Bad Input File", tmpbuf); + g_nevents = 0; + unmapfile((char *)ulp, size); + return; + } + + rep = (raw_event_t *)(ulp+1); + + if (g_events) + g_free(g_events); + + g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t)); + ep = g_events; + + while (g_npids > 0) { + g_free((g_pids + g_npids-1)->pid); + g_npids--; + } + if (g_pids) { + g_free(g_pids); + g_free(g_original_pids); + g_pids = 0; + g_original_pids = 0; + } + + s_pidhash = (pid_data_t **)g_malloc0( + PIDHASH_NBUCKETS*sizeof(pid_data_t *)); + + /* $$$ add a SEGV handler... */ + for (i = 0; i < g_nevents; i++) { + if (once) { + once = FALSE; + start_time = ((ulonglong)ntohl(rep->time[0])); + start_time <<= 32; + low_time = ntohl(rep->time[1]); + low_time &= 0xFFFFFFFF; + start_time |= low_time; + ep->time = 0LL; + } else { + ep->time = ((ulonglong)ntohl(rep->time[0])); + ep->time <<= 32; + low_time = ntohl(rep->time[1]); + low_time &= 0xFFFFFFFF; + ep->time |= low_time; + ep->time -= start_time; + ep->time /= ticks_per_ns; + } + ep->code = ntohl(rep->code); + ep->pid = find_or_add_pid(ntohl(rep->pid)); + ep->datum = ntohl(rep->datum); + ep->flags = 0; + ep++; + rep++; + } + + unmapfile((char *)ulp, size); + + make_sorted_pid_vector(); + g_free(s_pidhash); + s_pidhash = 0; + + /* Give the view-1 world a chance to reset a few things... */ + view1_read_events_callback(); +} + +static event_t *add_ep; + +/**************************************************************************** +* cpel_event_init +****************************************************************************/ +void cpel_event_init (ulong nevents) +{ + g_nevents = nevents; + if (g_events) + g_free(g_events); + add_ep = g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t)); + while (g_npids > 0) { + g_free((g_pids + g_npids-1)->pid); + g_npids--; + } + if (g_pids) { + g_free(g_pids); + g_free(g_original_pids); + g_pids = 0; + g_original_pids = 0; + } + s_pidhash = (pid_data_t **)g_malloc0( + PIDHASH_NBUCKETS*sizeof(pid_data_t *)); +} + +/**************************************************************************** +* add_cpel_event +****************************************************************************/ + +void add_cpel_event(ulonglong delta, ulong track, ulong event, ulong datum) +{ + event_t *ep; + + ep = add_ep++; + ep->time = delta; + ep->pid = find_or_add_pid(track); + ep->code = event; + ep->datum = datum; + ep->flags = 0; +} + +/**************************************************************************** +* add_clib_event +****************************************************************************/ + +void add_clib_event(double delta, unsigned short track, + unsigned short event, unsigned int index) +{ + event_t *ep; + + ep = add_ep++; + ep->time = (ulonglong) (delta * 1e9); /* time in intger nanoseconds */ + ep->pid = find_or_add_pid(track); + ep->code = event; + ep->datum = index; + ep->flags = EVENT_FLAG_CLIB; +} + +/**************************************************************************** +* cpel_event_finalize +****************************************************************************/ + +void cpel_event_finalize(void) +{ + make_sorted_pid_vector(); + g_free(s_pidhash); + s_pidhash = 0; + + /* Give the view-1 world a chance to reset a few things... */ + view1_read_events_callback(); +} + +/**************************************************************************** +* mapfile +****************************************************************************/ + +char *mapfile (char *file, ulong *sizep) +{ + struct stat statb; + char *rv; + int maphfile; + size_t mapfsize; + + maphfile = open (file, O_RDONLY); + + if (maphfile < 0) + return (NULL); + + if (fstat (maphfile, &statb) < 0) { + return (NULL); + } + + /* Don't try to mmap directories, FIFOs, semaphores, etc. */ + if (! (statb.st_mode & S_IFREG)) { + return (NULL); + } + + mapfsize = statb.st_size; + + if (mapfsize < 3) { + close (maphfile); + return (NULL); + } + + rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); + + if (rv == 0) { + g_error ("%s mapping problem, I quit...\n", file); + } + + close (maphfile); + + if (madvise (rv, mapfsize, MADV_SEQUENTIAL) < 0) { + return (rv); + } + + if (sizep) { + *sizep = mapfsize; + } + return (rv); +} + +/**************************************************************************** +* unmapfile +****************************************************************************/ + +boolean unmapfile (char *addr, ulong size) +{ + if (munmap (addr, size) < 0) { + g_warning("Unmap error, addr 0x%lx size 0x%x\n", + (unsigned long) addr, (unsigned int)size); + return(FALSE); + } + return(TRUE); +} + +/**************************************************************************** +* find_event_index +* Binary search for first event whose time is >= t +****************************************************************************/ + +int find_event_index (ulonglong t) +{ + int index, bottom, top; + event_t *ep; + + bottom = g_nevents-1; + top = 0; + + while (1) { + index = (bottom + top) / 2; + + ep = (g_events + index); + + if (ep->time == t) + return(index); + + if (top >= bottom) { + while (index > 0 && ep->time > t) { + ep--; + index--; + } + while (index < g_nevents && ep->time < t) { + ep++; + index++; + } + return(index); + } + + if (ep->time < t) + top = index + 1; + else + bottom = index - 1; + } +} + +/**************************************************************************** +* events_about +****************************************************************************/ + +void events_about (char *tmpbuf) +{ + sprintf(tmpbuf+strlen(tmpbuf), "%d total events, %.3f ticks per us\n", + (int)g_nevents, ticks_per_ns); +} |