original in en Arnout Engelen
en to ru Pukhlyakov Kirill
Arnout Engelen учится в Университете Неймегена (Нидерланды) и работает в компании TUNIX специализирующейся на безопасности в интернет. В свободное время он занимается бегом и играет на саксофоне.
GProf предоставляет простой путь профилирования ваших C/C++ приложений и определения интересных участков кода. В процессе изучения будет показано как использовался GProf для уменьшения времени выполнения реального приложения с 3-х минут до 5-ти секунд, с помощью идентификации и оптимизации 2-х структур данных.
История приложения берет свое начало в 1982 году, когда оно было представлено на SIGPLAN Symposium on Compiler Construction. В настоящее время это стандартный инструмент практически для всех разновидностей UNIX.
event2dot
преобразует pathalizer 'events' файл в графический 'dot' файл.
Кратко о работе приложения - данные читаются из файла и сохраняются отдельными частями и затем все собиратся в один большой график, который можно распечатать.
На моем компьютере event2dot
работает около 3-х минут, обрабатывая эти
данные.
real 3m36.316s user 0m55.590s sys 0m1.070s
g++ -pg dotgen.cpp readfile.cpp main.cpp graph.cpp config.cpp -o event2dot
Опять запустим event2dot
. Во время исполнения требуемая информация
будет помещена в файл 'gmon.out'. Можно посмотреть полученные данные следующей
командой 'gprof event2dot
| less'.
gprof показывает, что следующие функции представляют для нас интерес:
% cumulative self self total time seconds seconds calls s/call s/call name 43.32 46.03 46.03 339952989 0.00 0.00 CompareNodes(Node *,Node *) 25.06 72.66 26.63 55000 0.00 0.00 getNode(char *,NodeListNode *&) 16.80 90.51 17.85 339433374 0.00 0.00 CompareEdges(Edge *,AnnotatedEdge *) 12.70 104.01 13.50 51987 0.00 0.00 addAnnotatedEdge(AnnotatedGraph *,Edge *) 1.98 106.11 2.10 51987 0.00 0.00 addEdge(Graph *,Node *,Node *) 0.07 106.18 0.07 1 0.07 0.07 FindTreshold(AnnotatedEdge *,int) 0.06 106.24 0.06 1 0.06 28.79 getGraphFromFile(char *,NodeListNode *&,Config *) 0.02 106.26 0.02 1 0.02 77.40 summarize(GraphListNode *,Config *) 0.00 106.26 0.00 55000 0.00 0.00 FixName(char *)Наиболее интересная для нас колонка - первая: она отображает количество времени, которое приложение выполняло ту или иную функцию в процентном соотношении.
CompareNodes
. Эта функция вызывается только функцией CompareEdges
,
которая в свою очередь вызывается только addAnnotatedEdge
- обе кстати тоже
присутствуют в списке. Подумаем об оптимизации.
В функции addAnnotatedEdge
просматривается связанный список ( linked list ).
Несмотря на простоту использования, это не лучший способ хранения данных. Меняем g->edges
на бинарное дерево ( binary tree ), что обеспечит более быстрый поиск.
real 2m19.314s user 0m36.370s sys 0m0.940s
% cumulative self self total time seconds seconds calls s/call s/call name 87.01 25.25 25.25 55000 0.00 0.00 getNode(char *,NodeListNode *&) 10.65 28.34 3.09 51987 0.00 0.00 addEdge(Graph *,Node *,Node *)Видно, что функции, которые занимали более половины времени выполнения приложения, теперь выполняются гораздо быстрее! Попробуем еще - заменим использование NodeList на NodeHashTable.
Это хорошее улучшение кода:
real 0m3.269s user 0m0.830s sys 0m0.090s
perl -d:DProf mycode.pl
и
смотрите результаты с помощью dprofpp
. Если вы скомпилируете свое Java приложение
с помощью gcj вы сможете использовать gprof, но заметим что в настоящее время поддерживается
только однопотоковый Java код.