LINUX.ORG.RU

Как говорят классики может тем же, чем и всегда?

Лично я его под андроид не пробовал, но если оно там взлетит(а чего ему бы и не взлететь?) то остальное и нафик не нужно по идее, ну, может, кроме ручных замеров.

В интернетах говорят, что нужно пересобрать ядро, если тебя это и ещё пара ритуальных плясок, не остановит - получишь великолепный инструмент.

pon4ik ★★★★★ ()
Последнее исправление: pon4ik (всего исправлений: 1)

Я пытался год назад получить нормальные результаты (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

Далее внутри библиотеки пришлось патчить механизм получения стека вызова, существовавшего до сигнала.

Кусок рабочего кода для этого патча здесь: http://stackoverflow.com/questions/18017222/android-unwind-backtrace-inside-s...

В общем несколько дней полного ахтунга и в результате получилась «универсальная .so» которую можно загрузить в любую production-сборку на любом устройстве и получить результат профилирования на sd-карте.

GPFault ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.