/* * blktrace output analysis: generate a timeline & gather statistics * * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <string.h> #include "globals.h" struct pn_info { struct rb_node rb_node; struct p_info *pip; union { char *name; __u32 pid; } u; }; struct rb_root root_pid, root_name; static void __foreach(struct rb_node *n, void (*f)(struct p_info *, void *), void *arg) { if (n) { __foreach(n->rb_left, f, arg); f(rb_entry(n, struct pn_info, rb_node)->pip, arg); __foreach(n->rb_right, f, arg); } } static void __destroy(struct rb_node *n, int free_name, int free_pip) { if (n) { struct pn_info *pnp = rb_entry(n, struct pn_info, rb_node); __destroy(n->rb_left, free_name, free_pip); __destroy(n->rb_right, free_name, free_pip); if (free_name) free(pnp->u.name); if (free_pip) { free(pnp->pip->name); region_exit(&pnp->pip->regions); free(pnp->pip); } free(pnp); } } struct p_info * __find_process_pid(__u32 pid) { struct pn_info *this; struct rb_node *n = root_pid.rb_node; while (n) { this = rb_entry(n, struct pn_info, rb_node); if (pid < this->u.pid) n = n->rb_left; else if (pid > this->u.pid) n = n->rb_right; else return this->pip; } return NULL; } struct p_info *__find_process_name(char *name) { int cmp; struct pn_info *this; struct rb_node *n = root_name.rb_node; while (n) { this = rb_entry(n, struct pn_info, rb_node); cmp = strcmp(name, this->u.name); if (cmp < 0) n = n->rb_left; else if (cmp > 0) n = n->rb_right; else return this->pip; } return NULL; } static void insert_pid(struct p_info *that, __u32 pid) { struct pn_info *this; struct rb_node *parent = NULL; struct rb_node **p = &root_pid.rb_node; while (*p) { parent = *p; this = rb_entry(parent, struct pn_info, rb_node); if (pid < this->u.pid) p = &(*p)->rb_left; else if (pid > this->u.pid) p = &(*p)->rb_right; else return; // Already there } this = malloc(sizeof(struct pn_info)); this->u.pid = pid; this->pip = that; rb_link_node(&this->rb_node, parent, p); rb_insert_color(&this->rb_node, &root_pid); } static void insert_name(struct p_info *that) { int cmp; struct pn_info *this; struct rb_node *parent = NULL; struct rb_node **p = &root_name.rb_node; while (*p) { parent = *p; this = rb_entry(parent, struct pn_info, rb_node); cmp = strcmp(that->name, this->u.name); if (cmp < 0) p = &(*p)->rb_left; else if (cmp > 0) p = &(*p)->rb_right; else return; // Already there... } this = malloc(sizeof(struct pn_info)); this->u.name = strdup(that->name); this->pip = that; rb_link_node(&this->rb_node, parent, p); rb_insert_color(&this->rb_node, &root_name); } static void insert(struct p_info *pip) { insert_pid(pip, pip->pid); insert_name(pip); } static inline struct p_info *pip_alloc(void) { return memset(malloc(sizeof(struct p_info)), 0, sizeof(struct p_info)); } struct p_info *find_process(__u32 pid, char *name) { struct p_info *pip; if (pid != ((__u32)-1)) { if ((pip = __find_process_pid(pid)) != NULL) return pip; else if (name) { pip = __find_process_name(name); if (pip && pid != pip->pid) { /* * This is a process with the same name * as another, but a different PID. * * We'll store a reference in the PID * tree... */ insert_pid(pip, pid); } return pip; } /* * We're here because we have a pid, and no name, but * we didn't find a process ... * * We'll craft one using the pid... */ name = alloca(256); sprintf(name, "pid%09u", pid); process_alloc(pid, name); return __find_process_pid(pid); } return __find_process_name(name); } void process_alloc(__u32 pid, char *name) { struct p_info *pip = find_process(pid, name); if (pip == NULL) { pip = pip_alloc(); pip->pid = pid; region_init(&pip->regions); pip->last_q = (__u64)-1; pip->name = strdup(name); insert(pip); } } void pip_update_q(struct io *iop) { if (iop->pip) { if (remapper_dev(iop->dip->device)) update_lq(&iop->pip->last_q, &iop->pip->avgs.q2q_dm, iop->t.time); else update_lq(&iop->pip->last_q, &iop->pip->avgs.q2q, iop->t.time); update_qregion(&iop->pip->regions, iop->t.time); } } void pip_foreach_out(void (*f)(struct p_info *, void *), void *arg) { if (exes == NULL) __foreach(root_name.rb_node, f, arg); else { struct p_info *pip; char *exe, *p, *next, *exes_save = strdup(exes); p = exes_save; while (exes_save != NULL) { exe = exes_save; if ((next = strchr(exes_save, ',')) != NULL) { *next = '\0'; exes_save = next+1; } else exes_save = NULL; pip = __find_process_name(exe); if (pip) f(pip, arg); } } } void pip_exit(void) { __destroy(root_pid.rb_node, 0, 0); __destroy(root_name.rb_node, 1, 1); }