пятница, 18 марта 2011 г.

PySide+pykd: используем Qt в питоновских скриптах к WinDbg

pykd, как расширении к WinDbg, дает не только возможность использования мощного и гибкого языка Python, но и уже готовых сторонних проектов. Далее пойдет речь о PySide - библиотеке интеграции инструментария Qt в Python. Возьмем простой пример: нужно просмотреть статистику о процессах системы, в частноти размер виртуального адресного пространства и счетчики операций ввода/вывода. Не буду рассказывать об установке PySide, так как на официальной странице загрузок для Windows можно скачать инсталлятор. Набросаем небольшой скрипт, который средствами pykd получает и анализирует список процессов, а затем использует PySide для визуализации собранных данных в виде таблицы в GUI-окне:
import sys
from pykd import *
from PySide import QtCore, QtGui

COL_PID = 0
COL_PRC_NAME = 1
COL_VSIZE = 2
COL_READ = 3
COL_WRITE = 4
COL_OTHER = 5

if __name__ == '__main__':

app = QtGui.QApplication(sys.argv)

nt = loadModule( "nt" )
lstProcesses = typedVarList(nt.PsActiveProcessHead, "nt", "_EPROCESS", "ActiveProcessLinks")

countOfProcesses = len(lstProcesses)
if (countOfProcesses == 0):
print "Build process list failed"
sys.exit()

model = QtGui.QStandardItemModel(countOfProcesses, COL_OTHER+1)
model.setHeaderData(COL_PID, QtCore.Qt.Horizontal, "PID")
model.setHeaderData(COL_PRC_NAME, QtCore.Qt.Horizontal, "Image")
model.setHeaderData(COL_VSIZE, QtCore.Qt.Horizontal, "VirtualSize")
model.setHeaderData(COL_READ, QtCore.Qt.Horizontal, "Read")
model.setHeaderData(COL_WRITE, QtCore.Qt.Horizontal, "Write")
model.setHeaderData(COL_OTHER, QtCore.Qt.Horizontal, "Other")

tableView = QtGui.QTableView()
tableView.setModel(model)

for row in range(countOfProcesses):
process = lstProcesses[row]

index_ = model.index(row, COL_PID, QtCore.QModelIndex())
model.setData(index_, process.UniqueProcessId)

index_ = model.index(row, COL_PRC_NAME, QtCore.QModelIndex())
model.setData(index_, "".join([chr(i) for i in process.ImageFileName.values()]))

index_ = model.index(row, COL_VSIZE, QtCore.QModelIndex())
model.setData(index_, process.VirtualSize)

index_ = model.index(row, COL_READ, QtCore.QModelIndex())
model.setData(index_, process.ReadOperationCount.QuadPart)

index_ = model.index(row, COL_WRITE, QtCore.QModelIndex())
model.setData(index_, process.WriteOperationCount.QuadPart)

index_ = model.index(row, COL_OTHER, QtCore.QModelIndex())
model.setData(index_, process.OtherOperationCount.QuadPart)

tableView.resizeColumnsToContents()

widthWidget = 0
for col in range(COL_OTHER+1): widthWidget += tableView.columnWidth(col)
widthWidget += 50

tableView.setSortingEnabled(True)
tableView.setWindowTitle("Processes table:")
tableView.resize(widthWidget, 500)
tableView.show()

app.exec_()
Теперь исполним его в WinDbg. После того, как скрипт построит список процессов, мы увидим окно результатов. Оно не является модальным по отношению к основному окну WinDbg, но отладчик терпеливо ждет завершения работы скрипта (в нашем случае - закрытия окна):

Конечно, можно было бы выдать эту информацию в текстовой форме. Но GUI таблица, например, позволяет одним кликом поменять колонку сортировки и можно наблюдать какой процесс активно более активно читает, а какой пишет.
Еще один приятный момент использования PySide - лицензия LGPL, позволяющая использовать и распространять библиотеку в любых проектах, включая коммерческие.

3 комментария:

  1. Спасибо за идею и за удачный пример!

    ОтветитьУдалить
  2. > airmax комментирует...
    > Спасибо за идею и за удачный пример!
    Всегда пожалуйста :)

    ОтветитьУдалить
  3. Если появляется ошибка "A QApplication instance already exists", см сюда:

    http://pykd.blogspot.com/2011/06/qt-qapplication-instance-already-exists.html

    ОтветитьУдалить