Лично я его под андроид не пробовал, но если оно там взлетит(а чего ему бы и не взлететь?) то остальное и нафик не нужно по идее, ну, может, кроме ручных замеров.
В интернетах говорят, что нужно пересобрать ядро, если тебя это и ещё пара ритуальных плясок, не остановит - получишь великолепный инструмент.
Я пытался год назад получить нормальные результаты (sampling-профилирование со стеками вызовов без влияния на производительность). Ядерные профилировщики возможно хороши, но они отпали, поскольку предполагалось профилирование в production на target-устройстве с произвольным ядром, которое может быть сложно заменить. Нормальные результаты получились только с помощью профилировщика из gperftools2.4, вручную собранного в виде специального дополненного .so-файла, вручную загружаемого из java (или как-то иначе), который сохраняет результат профилирования на sd-карту в стандартном gperftools-формате.
Он много раз в секунду по сигналу прерывает все потоки и записывает стеки вызовов.
Для сборки и работы потребовались несколько дней и десятки костылей,
сходу повторить её сейчас, спустя год, мне не удалось даже при условии что у меня сохранился рабочий каталог.
Отмечу основные костыли: собирается не всё, а только то что нужно для профилировщика, и для определённого порядка запуска глобальных конструкторов на этапе загрузки .so склеивается в один .cpp
#define PROFILE_PATH (getenv("EXTERNAL_STORAGE"))
#endif
#endif
#define HAVE_VALGRIND_H 1
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "gperftools/profiler.h"
//include all C files to ensure fixed constructors initiaklization order
//#include "base/abort.cc"
#include "base/logging.cc"
#include "base/sysinfo.cc"
#include "base/spinlock_internal.cc"
#include "base/spinlock.cc"
#include "stacktrace.cc"
#include "profile-handler.cc"
#include "profiledata.cc"
#include "profiler.cc"
namespace
{
class ProfilerLibLoader
{
public:
ProfilerLibLoader():init_done_(false)
{
Start();
}
void Start()
{
Stop();
time_t now = time(0);
char name_buffer[1000] = {};
strncpy(name_buffer, PROFILE_PATH, sizeof(name_buffer) - 1);
const int path_len = strlen(name_buffer);
//note that std::localtime is not thread-safe. So it used only for generation name profiling - non-production case.
strftime(name_buffer + path_len, sizeof(name_buffer) - path_len - 1, "/cpu_profile_%Y-%m-%d_%H-%M-%S.pprof", localtime(&now));
fprintf(stderr, "Starting profiling into %s.\n", name_buffer);
init_done_ = ProfilerStart(name_buffer);
if (!init_done_)
{
fprintf(stderr, "Starting profiling failed.\n");
}
}
void Stop()
{
if (init_done_)
{
ProfilerStop();
fprintf(stderr, "Done profiling.\n");
init_done_ = false;
}
}
~ProfilerLibLoader()
{
Stop();
}
private:
bool init_done_;
};
}
ProfilerLibLoader instance;
extern "C"
{
void Java_com_zzz_ProfilerLoader_ProfilerLoader_Start(void*,void*)
{
instance.Start();
}
void Java_com_zzz_ProfilerLoader_ProfilerLoader_Stop(void*,void*)
{
instance.Stop();
}
}
К этому ещё линкуется отдельно собранный src/base/dynamic_annotations.c
Далее внутри библиотеки пришлось патчить механизм получения стека вызова, существовавшего до сигнала.
В общем несколько дней полного ахтунга и в результате получилась «универсальная .so» которую можно загрузить в любую production-сборку на любом устройстве и получить результат профилирования на sd-карте.