diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2008-06-18 17:19:25 -0300 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2008-08-15 15:27:53 -0300 |
commit | 26983462332661b3b44ad6b602eac504a2bf7b05 (patch) | |
tree | 1ea5094a1359d8264b96e08bcbda28ef9592d7b7 | |
parent | 4e4725b74dfd9508540fd41b0b8560575568bedf (diff) | |
download | tuna-26983462332661b3b44ad6b602eac504a2bf7b05.tar.gz |
tuna_gui: Add support for CPU topology
Now we can see which cores are in which socket, next steps will
allow socket operations: isolate, include, drag'n'drop, etc.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tuna/tuna_gui.glade | 16 | ||||
-rw-r--r-- | tuna/tuna_gui.py | 221 |
2 files changed, 146 insertions, 91 deletions
diff --git a/tuna/tuna_gui.glade b/tuna/tuna_gui.glade index 97622a0..68f6400 100644 --- a/tuna/tuna_gui.glade +++ b/tuna/tuna_gui.glade @@ -26,19 +26,23 @@ <property name="border_width">3</property> <property name="position">200</property> <child> - <widget class="GtkScrolledWindow" id="scrolledwindow1"> + <widget class="GtkScrolledWindow" id="cpuview"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> <child> - <widget class="GtkTreeView" id="cpuview"> + <widget class="GtkViewport" id="viewport2"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="border_width">2</property> - <property name="enable_search">False</property> - <signal name="button_press_event" handler="on_cpuview_button_press_event"/> + <child> + <widget class="GtkVBox" id="cpuview_box"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="border_width">2</property> + <signal name="button_press_event" handler="on_cpuview_button_press_event"/> + </widget> + </child> </widget> </child> </widget> diff --git a/tuna/tuna_gui.py b/tuna/tuna_gui.py index 947da71..d3724eb 100644 --- a/tuna/tuna_gui.py +++ b/tuna/tuna_gui.py @@ -6,6 +6,7 @@ import pygtk pygtk.require("2.0") import copy, ethtool, gtk, gobject, os, pango, procfs, re, schedutils, sys, tuna +import sysfs import gtk.glade try: @@ -85,26 +86,28 @@ def generate_list_store_columns_with_attr(columns): for column in columns: yield gobject.TYPE_UINT -class cpuview: +class cpu_socket_frame(gtk.Frame): ( COL_FILTER, COL_CPU, COL_USAGE ) = range(3) - def __init__(self, treeview, procview, irqview, cpus_filtered): - self.cpustats = procfs.cpusstats() - self.procview = procview - self.irqview = irqview - self.treeview = treeview + def __init__(self, socket, cpus, creator): + + gtk.Frame.__init__(self, "Socket %s" % socket) + + self.socket = socket + self.cpus = cpus + self.nr_cpus = len(cpus) + self.creator = creator + self.list_store = gtk.ListStore(gobject.TYPE_BOOLEAN, gobject.TYPE_UINT, gobject.TYPE_UINT) - self.treeview.set_model(self.list_store) - self.nr_cpus = len(self.cpustats) - 1 - model = self.treeview.get_model() + self.treeview = gtk.TreeView(self.list_store) # Filter column renderer = gtk.CellRendererToggle() - renderer.connect('toggled', self.filter_toggled, model) + renderer.connect('toggled', self.filter_toggled, self.list_store) column = gtk.TreeViewColumn('Filter', renderer, active = self.COL_FILTER) self.treeview.append_column(column) @@ -123,19 +126,53 @@ class cpuview: text = self.COL_USAGE) self.treeview.append_column(column) + self.add(self.treeview) + self.treeview.enable_model_drag_dest(DND_TARGETS, gtk.gdk.ACTION_DEFAULT) self.treeview.connect("drag_data_received", self.on_drag_data_received_data) + self.treeview.connect("button_press_event", + self.on_cpu_socket_frame_button_press_event) - self.timer = gobject.timeout_add(3000, self.refresh) + self.drop_handlers = { "pid": (drop_handler_move_threads_to_cpu, self.creator.procview), + "irq": (drop_handler_move_irqs_to_cpu, self.creator.irqview), } - self.drop_handlers = { "pid": (drop_handler_move_threads_to_cpu, self.procview), - "irq": (drop_handler_move_irqs_to_cpu, self.irqview), } + def on_drag_data_received_data(self, treeview, context, x, y, + selection, info, etime): + drop_info = treeview.get_dest_row_at_pos(x, y) - self.previous_pid_affinities = None - self.previous_irq_affinities = None - self.cpus_filtered = cpus_filtered + # pid list, a irq list, etc + source, data = selection.data.split(":") + + if drop_info: + model = treeview.get_model() + path, position = drop_info + iter = model.get_iter(path) + cpu = model.get_value(iter, self.COL_CPU) + else: + # Move to all CPUs + cpu = -self.nr_cpus + + if self.drop_handlers.has_key(source): + if self.drop_handlers[source][0](cpu, data): + self.drop_handlers[source][1].refresh() + else: + print "cpu_socket_frame: unhandled drag source '%s'" % source + + def refresh(self): + self.list_store.clear() + for i in range(self.nr_cpus): + cpu = self.cpus[i] + cpunr = int(cpu.name[3:]) + usage = self.creator.cpustats[cpunr + 1].usage + + iter = self.list_store.append() + self.list_store.set(iter, + self.COL_FILTER, cpunr not in self.creator.cpus_filtered, + self.COL_CPU, cpunr, + self.COL_USAGE, int(usage)) + self.treeview.show_all() def isolate_cpu(self, a): ret = self.treeview.get_path_at_pos(self.last_x, self.last_y) @@ -146,14 +183,8 @@ class cpuview: return row = self.list_store.get_iter(path) cpu = self.list_store.get_value(row, self.COL_CPU) - self.previous_pid_affinities, \ - self.previous_irq_affinities = tuna.isolate_cpus([cpu,], self.nr_cpus) - if self.previous_pid_affinities: - self.procview.refresh() - - if self.previous_irq_affinities: - self.irqview.refresh() + self.creator.isolate_cpu(cpu) def include_cpu(self, a): ret = self.treeview.get_path_at_pos(self.last_x, self.last_y) @@ -164,36 +195,14 @@ class cpuview: return row = self.list_store.get_iter(path) cpu = self.list_store.get_value(row, self.COL_CPU) - self.previous_pid_affinities, \ - self.previous_irq_affinities = tuna.include_cpu(cpu, self.nr_cpus) - if self.previous_pid_affinities: - self.procview.refresh() - - if self.previous_irq_affinities: - self.irqview.refresh() + self.creator.include_cpu(cpu) def restore_cpu(self, a): - if not (self.previous_pid_affinities or \ - self.previous_irq_affinities): - return - affinities = self.previous_pid_affinities - for pid in affinities.keys(): - try: - schedutils.set_affinity(pid, affinities[pid]) - except: - pass - affinities = self.previous_irq_affinities - for irq in affinities.keys(): - tuna.set_irq_affinity(int(irq), - procfs.hexbitmask(affinities[irq], - self.nr_cpus)) - - self.previous_pid_affinities = None - self.previous_irq_affinities = None + self.creator.restore_cpu() - def on_cpuview_button_press_event(self, treeview, event): + def on_cpu_socket_frame_button_press_event(self, treeview, event): if event.type != gtk.gdk.BUTTON_PRESS or event.button != 3: return @@ -212,8 +221,8 @@ class cpuview: include.connect_object('activate', self.include_cpu, event) isolate.connect_object('activate', self.isolate_cpu, event) - if not (self.previous_pid_affinities or \ - self.previous_irq_affinities): + if not (self.creator.previous_pid_affinities or \ + self.creator.previous_irq_affinities): restore.set_sensitive(False) restore.connect_object('activate', self.restore_cpu, event) @@ -223,28 +232,6 @@ class cpuview: menu.popup(None, None, None, event.button, event.time) - def on_drag_data_received_data(self, treeview, context, x, y, - selection, info, etime): - drop_info = treeview.get_dest_row_at_pos(x, y) - - # pid list, a irq list, etc - source, data = selection.data.split(":") - - if drop_info: - model = treeview.get_model() - path, position = drop_info - iter = model.get_iter(path) - cpu = model.get_value(iter, self.COL_CPU) - else: - # Move to all CPUs - cpu = -self.nr_cpus - - if self.drop_handlers.has_key(source): - if self.drop_handlers[source][0](cpu, data): - self.drop_handlers[source][1].refresh() - else: - print "cpuview: unhandled drag source '%s'" % source - def filter_toggled(self, cell, path, model): # get toggled iter iter = model.get_iter((int(path),)) @@ -252,7 +239,81 @@ class cpuview: cpu = model.get_value(iter, self.COL_CPU) enabled = not enabled + self.creator.toggle_mask_cpu(cpu, enabled) + + # set new value + model.set(iter, self.COL_FILTER, enabled) + +class cpuview: + def __init__(self, window, procview, irqview, cpus_filtered): + self.cpus = sysfs.cpus() + self.cpustats = procfs.cpusstats() + self.socket_frames = {} + + self.procview = procview + self.irqview = irqview + + vbox = window.get_child().get_child() + socket_ids = self.cpus.sockets.keys() + socket_ids.sort() + for socket_id in socket_ids: + frame = cpu_socket_frame(socket_id, + self.cpus.sockets[socket_id], + self) + vbox.pack_start(frame, False, False) + self.socket_frames[socket_id] = frame + window.show_all() + + self.cpus_filtered = cpus_filtered + self.refresh() + + self.previous_pid_affinities = None + self.previous_irq_affinities = None + + self.timer = gobject.timeout_add(3000, self.refresh) + + def isolate_cpu(self, cpu): + self.previous_pid_affinities, \ + self.previous_irq_affinities = tuna.isolate_cpus([cpu,], self.cpus.nr_cpus) + + if self.previous_pid_affinities: + self.procview.refresh() + + if self.previous_irq_affinities: + self.irqview.refresh() + + def include_cpu(self, cpu): + self.previous_pid_affinities, \ + self.previous_irq_affinities = tuna.include_cpu(cpu, self.cpus.nr_cpus) + + if self.previous_pid_affinities: + self.procview.refresh() + + if self.previous_irq_affinities: + self.irqview.refresh() + + def restore_cpu(self): + if not (self.previous_pid_affinities or \ + self.previous_irq_affinities): + return + affinities = self.previous_pid_affinities + for pid in affinities.keys(): + try: + schedutils.set_affinity(pid, affinities[pid]) + except: + pass + + affinities = self.previous_irq_affinities + for irq in affinities.keys(): + tuna.set_irq_affinity(int(irq), + procfs.hexbitmask(affinities[irq], + self.cpus.nr_cpus)) + + self.previous_pid_affinities = None + self.previous_irq_affinities = None + + def toggle_mask_cpu(self, cpu, enabled): if enabled: if cpu in self.cpus_filtered: self.cpus_filtered.remove(cpu) @@ -263,19 +324,10 @@ class cpuview: self.procview.toggle_mask_cpu(cpu, enabled) self.irqview.toggle_mask_cpu(cpu, enabled) - # set new value - model.set(iter, self.COL_FILTER, enabled) - def refresh(self): - self.list_store.clear() self.cpustats.reload() - for cpunr in range(self.nr_cpus): - cpu = self.list_store.append() - usage = self.cpustats[cpunr + 1].usage - self.list_store.set(cpu, self.COL_FILTER, cpunr not in self.cpus_filtered, - self.COL_CPU, cpunr, - self.COL_USAGE, int(usage)) - self.treeview.show_all() + for frame in self.socket_frames.keys(): + self.socket_frames[frame].refresh() return True def on_affinity_text_changed(self): @@ -1263,8 +1315,7 @@ class gui: event_handlers = { "on_mainbig_window_delete_event" : self.on_mainbig_window_delete_event, "on_processlist_button_press_event" : self.procview.on_processlist_button_press_event, - "on_irqlist_button_press_event" : self.irqview.on_irqlist_button_press_event, - "on_cpuview_button_press_event" : self.cpuview.on_cpuview_button_press_event } + "on_irqlist_button_press_event" : self.irqview.on_irqlist_button_press_event } self.wtree.signal_autoconnect(event_handlers) self.ps.reload_threads() |