aboutsummaryrefslogtreecommitdiff
path: root/btt/proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'btt/proc.c')
-rw-r--r--btt/proc.c263
1 files changed, 263 insertions, 0 deletions
diff --git a/btt/proc.c b/btt/proc.c
new file mode 100644
index 0000000..aac49cb
--- /dev/null
+++ b/btt/proc.c
@@ -0,0 +1,263 @@
+/*
+ * 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);
+}