Иногда возникает необходимость заглянуть внутрь программы, что-бы посмотреть почему она "так тормозит". Естественно начинается все с высокоуровневых средств htop/atop/nettop/iotop/sar. Но если они показывают, что производительность упирается в процессор, то необходимо знать какие функции требуют больше всего вычислительных мощностей. Это может помочь как переписать свою программу для провышения производительности, так и подобрать оптимальные настройки для чужой.
Собственно функция профилировщика - найти узкие места в программе и выдать нам как можно больше информации о том куда уходят процессорные такты. Можно выделить три основных модели профилирования:
Гарантированное профилирование (determine - не нашел как перевести это лучше). Целевая программа модифицируется (чаще всего перекомпилируется с определенными флагами - -pg для gcc). - в код внедряются вызовы библиотеки профилирования, собирающие информацию о выполняемой программе и передающие ее профилировщику. Наиболее часто замеряется время выполнения каждой функции и после тестового прогона программы можно увидеть вывод, подобный следующему:
% cumulative self self total time seconds seconds calls ms/call ms/call name 33.34 0.02 0.02 7208 0.00 0.00 open 16.67 0.03 0.01 244 0.04 0.12 offtime 16.67 0.04 0.01 8 1.25 1.25 memccpy 16.67 0.05 0.01 7 1.43 1.43 write
Очевидным минусом гарантированного профилирования является необходимость перекомпиляции программы, что неудобно, а иногда и невозможно (если это не ваша программа, например). Также гарантированное профилирование значительно влияет на скорость исполнения программы, делая получение коректного времени исполнения затруднительным. Типичный представитель - gprof,