Доброго времени суток. Недавно загорелся идеей написать простой, но функциональный плагин для среды разработки Qt Creator, предназначенный для визуализации данных об использовании оперативной памяти и загрузки ЦП текущим запущенным процессом. В качестве вдохновения для меня послужил инструментарий «Средства диагностики», присутствующий в Visual Studio. Ниже я расскажу об основных деталях разработки.


Так как тема создания плагинов для Qt Creator уже подробно описана на хабре, например, в статье Система расширений Qt Creator, то поэтому не буду останавливаться на общей информации и перейду сразу к описанию плагина.

Собственно, для того, чтобы получить информацию о любом запущенном в операционной системе процессе для начала необходимо узнать его идентификатор (PID). Вопросом получения PID запущенного через Qt Creator процесса я и занялся в первую очередь. После безрезультатного гугления на эту тему я перешел к изучению исходников Qt Creator, в ходе чего обнаружил, что узнать искомые данные несложно. Для этого нужны поймать следующие сигналы, испускаемые статическим экземпляром ProjectExplorer::ProjectExplorerPlugin::instance():
void runControlStarted(ProjectExplorer::RunControl *rc);
void runControlFinished(ProjectExplorer::RunControl *rc);

// connects
    connect(ProjectExplorer::ProjectExplorerPlugin::instance(),
      &ProjectExplorer::ProjectExplorerPlugin::runControlStarted,
            this, &DiagnosticToolsPlugin::onRunControlStarted);

    connect(ProjectExplorer::ProjectExplorerPlugin::instance(),
      &ProjectExplorer::ProjectExplorerPlugin::runControlFinished,
            this, &DiagnosticToolsPlugin::onRunControlFinished);

// slots
void DiagnosticToolsPlugin::onRunControlStarted(ProjectExplorer::RunControl *rc){
    m_runControlPtr = rc;
    connect(m_runControlPtr,
            &ProjectExplorer::RunControl::applicationProcessHandleChanged,
            this, &DiagnosticToolsPlugin::onApplicationHandleChanged);
}
void DiagnosticToolsPlugin::onRunControlFinished(ProjectExplorer::RunControl *rc){
    Q_UNUSED(rc)
    m_runControlPtr = NULL;
    m_dataQueryEngine->stopDataQuery();
}
void DiagnosticToolsPlugin::onApplicationHandleChanged(){
    if (m_runControlPtr->applicationProcessHandle().isValid()){
        m_dataQueryEngine->setPid(m_runControlPtr->applicationProcessHandle().pid());
        m_dataQueryEngine->startDataQuery();
    } else {
        qDebug() << "Process handle is invalid";
    }
}

Получив сигнал runControlStarted(ProjectExplorer::RunControl *rc), запоминаем указать m_runControlPtr на объект ProjectExplorer::RunControl *rc и далее по сигналу applicationProcessHandleChanged запускаем запрос данных.

Следующие задачи были тривиальными. В операционной системе Windows информация об используемой процессом памяти и загрузке ЦП была получена через WinApi, в Linux — посредством анализа содержимого файлов /proc/pid/stat и /proc/stat.

Финальный штрих — визуализация собранной информации. Первой мыслью было использовать модуль Qt для построения графиков Qt Charts, но в виду того, что данный компонент не является частью Qt Creator из коробки и по причине простоты решаемой мною задачи, в итоге было решено реализовать свой класс для рисования графиков. Закончив работу с GUI, я стал думать, где разместить созданную графическую форму. С одной стороны, было бы логично поместить ее снизу вместе с остальными панелями вывода, с другой — хотелось бы видеть одновременно и вывод приложения и информацию об используемых им ресурсах компьютера. Поэтому было принято волевое (возможно, неудачное) решение поместить графическую форму на левую боковую панель. И вот, что получилось в итоге:


Заключение
В статье было описано, что уже сделано на данный момент. Далее планируется создать версию под Mac OS и добавить окно настроек, в котором будет присутствовать возможность задать интервал опроса, шаг на графике, цвет и т. д. Может быть, кто-нибудь подкинет другие идеи по улучшению. Посмотреть исходный код и скачать плагин можно здесь.

Всем спасибо за внимание.

UPD
Статья была отредактирована с учетом замечания хабропользователя Krepver
Поделиться с друзьями
-->

Комментарии (18)


  1. AllexIn
    18.05.2017 20:14

    Windows only?


    1. splav_asv
      18.05.2017 22:33
      +2

      в Linux — посредством анализа содержимого файлов /proc/pid/stat и /proc/stat.


      1. AllexIn
        18.05.2017 22:34

        Точно. Я этот момент проморгал. Спасибо.


    1. alexander_8901
      18.05.2017 23:08

      В операционной системе Windows информация об используемой процессом памяти и загрузке ЦП была получена через WinApi, в Linux — посредством анализа содержимого файлов /proc/pid/stat и /proc/stat.


      Думаю Windows и Linux

      Не прогрузился ответ выше)


  1. alexander_8901
    18.05.2017 23:12

    Может быть, кто-нибудь подкинет другие идеи по улучшению.

    Как на счет подсчета утечек памяти?


    1. ilynxy
      19.05.2017 07:56

      Valgrind?


      1. rickytack
        19.05.2017 09:21

        Valgrind хорош, но у него часто бывают ложные срабатывания при анализе Qtшного приложения. Шикарно было бы, если б динамический анализатор понимал Qtшный менеджер памяти.


  1. VioletGiraffe
    18.05.2017 23:40

    Круть, полезная вещь! Завтра, на свежую голову, попытаюсь вкрутить в свой Creator :)
    Спасибо автору за разработку.


  1. LynXzp
    19.05.2017 00:32

    1. Предлагаю не очищать график после закрытия приложения. (Ну или все очищать, не только график но и числа)
    2. Сделать чтобы число объема памяти вмещалось вне зависимости от ширины. (Сейчас под поле отводится фиксированный % ширины, чуточку «умнее» бы)
    screenshot Спасибо, плагин понравился. Kubuntu 16.04 x64.


    1. rickytack
      19.05.2017 09:22

      Учту


  1. AllexIn
    19.05.2017 10:04

    Имеет смысл релиз сделать обычным способом. ИМХО.
    То есть бинари запаковать и выложить на гитхабе на вкладке releases, а из исходников убрать.


  1. PavelZhigulin
    19.05.2017 10:42

    Плагин супер. Фичи, которые хотелось бы видеть:

    1) Отображение графиков после выключения приложения
    2) Скроллинг по графикам
    3) Совсем было бы чудесно видеть используюемую память при отладке на Remote Device. Хотя бы в случае, когда Remote Device — это localhost.

    Если будет время сегодня, может быть сам попробую запилить эти фичи, хотя бы первые две.


  1. BeardedBeaver
    19.05.2017 11:04
    +1

    Отличный плагин, спасибо за труды!

    Помимо вышесказанного хотелось бы иметь:

    1) Английский язык в интерфейсе
    2) Возможность выгрузить логи сессии диагностики во внешний файл (csv, например) для того, чтобы можно было запустить тестирование и потом проанализировать нагрузку от приложения на больших отрезках времени (час, сутки...)


  1. Krepver
    19.05.2017 11:53

    Собрал для версии 4.1.0, но у плагина не получается получить pid, в qDebug пишет


    ProjectExplorer::ProjectExplorerPlugin::updateRunActions signal
    PID: 0


    1. rickytack
      19.05.2017 11:55

      Хм, с ходу не могу ответить. Возможно, как-то повлияла разница в минорных версиях. Разработка велась для Qt Creator 4.2.1.
      А на какой ОС и с каким компилятором собираете?


      1. Krepver
        19.05.2017 12:20

        Ubuntu 17.04, gcc 6.3


        Решил проблему так:
        Завел слот onApplicationHandleChanged и в onRunControlStarted сделал


        connect(m_runControlPtr,
                &ProjectExplorer::RunControl::applicationProcessHandleChanged,
                this, &DiagnosticToolsPlugin::onApplicationHandleChanged);

        setPid и startDataQuery вызываю уже там (при условии, что m_runControlPtr->applicationProcessHandle().isValid()


        Pull request сделать?


        1. rickytack
          19.05.2017 12:52

          Ага


  1. DrGluck
    24.05.2017 12:04

    Очень интересно, но, честно говоря, непонятно зачем это нужно когда есть Process Explorer или Process Hacker. Они умеют показывать загрузку потоков и многое другое. Недавно с помощью Process Hackera выявили проблему с одним из потоков в приложении.

    upd: А можно сделать разбивку по потокам? Это было бы зело полезно.