00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 from __future__ import division
00030
00031 from qt_gui.plugin import Plugin
00032 from python_qt_binding import loadUi
00033 from python_qt_binding.QtGui import QLabel, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QCheckBox, QWidget, QToolBar, QLineEdit, QPushButton
00034 from python_qt_binding.QtCore import Qt, QTimer
00035
00036 from rqt_top.node_info import NodeInfo
00037 import re
00038 from threading import RLock
00039 import textwrap
00040
00041
00042 class TopWidgetItem(QTreeWidgetItem):
00043 def __init__(self, parent=None):
00044 super(TopWidgetItem, self).__init__(parent)
00045
00046 def __lt__(self, other):
00047 col = self.treeWidget().sortColumn()
00048 dtype = Top.SORT_TYPE[col]
00049 return dtype(self.text(col)) < dtype(other.text(col))
00050
00051
00052 class Top(Plugin):
00053
00054 NODE_FIELDS = [ 'pid', 'get_cpu_percent', 'get_memory_percent', 'get_num_threads']
00055 OUT_FIELDS = ['node_name', 'pid', 'cpu_percent', 'memory_percent', 'num_threads' ]
00056 FORMAT_STRS = ['%s', '%s', '%0.2f', '%0.2f', '%s' ]
00057 NODE_LABELS = ['Node', 'PID', 'CPU %', 'Mem %', 'Num Threads' ]
00058 SORT_TYPE = [str, str, float, float, float ]
00059 TOOLTIPS = {
00060 0: ('cmdline', lambda x: '\n'.join(textwrap.wrap(' '.join(x)))),
00061 3: ('memory_info', lambda x: ('Resident: %0.2f MiB, Virtual: %0.2f MiB' % (x[0]/2**20, x[1]/2**20)))
00062 }
00063
00064 _node_info = NodeInfo()
00065
00066 name_filter = re.compile('')
00067
00068 def __init__(self, context):
00069 super(Top, self).__init__(context)
00070
00071 self.setObjectName('Top')
00072
00073
00074 from argparse import ArgumentParser
00075 parser = ArgumentParser()
00076
00077 parser.add_argument("-q", "--quiet", action="store_true",
00078 dest="quiet",
00079 help="Put plugin in silent mode")
00080 args, unknowns = parser.parse_known_args(context.argv())
00081
00082
00083
00084
00085 self._selected_node = ''
00086 self._selected_node_lock = RLock()
00087
00088
00089 self._toolbar = QToolBar()
00090 self._filter_box = QLineEdit()
00091 self._regex_box = QCheckBox()
00092 self._regex_box.setText('regex')
00093 self._toolbar.addWidget(QLabel('Filter'))
00094 self._toolbar.addWidget(self._filter_box)
00095 self._toolbar.addWidget(self._regex_box)
00096
00097 self._filter_box.returnPressed.connect(self.update_filter)
00098 self._regex_box.stateChanged.connect(self.update_filter)
00099
00100
00101 self._container = QWidget()
00102 self._container.setWindowTitle('Process Monitor')
00103 self._layout = QVBoxLayout()
00104 self._container.setLayout(self._layout)
00105
00106 self._layout.addWidget(self._toolbar)
00107
00108
00109 self._table_widget = QTreeWidget()
00110 self._table_widget.setObjectName('TopTable')
00111 self._table_widget.setColumnCount(len(self.NODE_LABELS))
00112 self._table_widget.setHeaderLabels(self.NODE_LABELS)
00113 self._table_widget.itemClicked.connect(self._tableItemClicked)
00114 self._table_widget.setSortingEnabled(True)
00115 self._table_widget.setAlternatingRowColors(True)
00116
00117 self._layout.addWidget(self._table_widget)
00118 context.add_widget(self._container)
00119
00120
00121 self._kill_button = QPushButton('Kill Node')
00122 self._layout.addWidget(self._kill_button)
00123 self._kill_button.clicked.connect(self._kill_node)
00124
00125
00126 self.update_table()
00127 self.update_table()
00128
00129 self._table_widget.resizeColumnToContents(0)
00130
00131
00132 self._update_timer = QTimer()
00133 self._update_timer.setInterval(1000)
00134 self._update_timer.timeout.connect(self.update_table)
00135 self._update_timer.start()
00136
00137 def _tableItemClicked(self, item, column):
00138 with self._selected_node_lock:
00139 self._selected_node = item.text(0)
00140
00141 def update_filter(self, *args):
00142 if self._regex_box.isChecked():
00143 expr = self._filter_box.text()
00144 else:
00145 expr = re.escape(self._filter_box.text())
00146 self.name_filter = re.compile(expr)
00147 self.update_table()
00148
00149 def _kill_node(self):
00150 self._node_info.kill_node(self._selected_node)
00151
00152 def update_one_item(self, row, info):
00153 twi = TopWidgetItem()
00154 for col, field in enumerate(self.OUT_FIELDS):
00155 val = info[field]
00156 twi.setText(col, self.FORMAT_STRS[col] % val)
00157 self._table_widget.insertTopLevelItem(row, twi)
00158
00159 for col, (key, func) in self.TOOLTIPS.iteritems():
00160 twi.setToolTip(col, func(info[key]))
00161
00162 with self._selected_node_lock:
00163 if twi.text(0) == self._selected_node:
00164 twi.setSelected(True)
00165
00166 self._table_widget.setItemHidden(twi, len(self.name_filter.findall(info['node_name'])) == 0)
00167
00168 def update_table(self):
00169 self._table_widget.clear()
00170 infos = self._node_info.get_all_node_fields(self.NODE_FIELDS)
00171 for nx, info in enumerate(infos):
00172 self.update_one_item(nx, info)
00173
00174 def shutdown_plugin(self):
00175 self._update_timer.stop()
00176
00177 def save_settings(self, plugin_settings, instance_settings):
00178 instance_settings.set_value('filter_text', self._filter_box.text())
00179 instance_settings.set_value('is_regex', int(self._regex_box.checkState()))
00180
00181 def restore_settings(self, plugin_settings, instance_settings):
00182 self._filter_box.setText(instance_settings.value('filter_text'))
00183 is_regex_int = instance_settings.value('is_regex')
00184 if is_regex_int:
00185 self._regex_box.setCheckState(Qt.CheckState(is_regex_int))
00186 else:
00187 self._regex_box.setCheckState(Qt.CheckState(0))
00188 self.update_filter()
00189
00190
00191
00192