contrib/plugins/uftrace: generate additional files for uftrace
Beyond traces per cpu, uftrace expect to find some specific files. - info: contains information about machine/program run those values are not impacting uftrace behaviour (only reported by uftrace info), and we simply added empty strings. - memory mapping: how every binary is mapped in memory. For system mode, we generate an empty mapping (uftrace_symbols.py, coming in future commit, will take care of that). For user mode, we copy current /proc/self/maps. We don't need to do any special filtering, as reported addresses will necessarily concern guest program, and not QEMU and its libraries. - task: list of tasks. We present every vcpu/privilege level as a separate process, as it's the best view we can have when generating a (visual) chrome trace. Using threads is less convenient in terms of UI. Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Message-ID: <20250902075042.223990-7-pierrick.bouvier@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-ID: <20250922093711.2768983-23-alex.bennee@linaro.org>
This commit is contained in:
parent
308c20108a
commit
7278747595
1 changed files with 130 additions and 1 deletions
|
|
@ -118,6 +118,127 @@ static uint64_t gettime_ns(void)
|
|||
return now_ns;
|
||||
}
|
||||
|
||||
static void uftrace_write_map(bool system_emulation)
|
||||
{
|
||||
const char *path = "./uftrace.data/sid-0.map";
|
||||
|
||||
if (system_emulation && access(path, F_OK) == 0) {
|
||||
/* do not erase existing map in system emulation, as a custom one might
|
||||
* already have been generated by uftrace_symbols.py */
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *sid_map = fopen(path, "w");
|
||||
g_assert(sid_map);
|
||||
|
||||
if (system_emulation) {
|
||||
fprintf(sid_map,
|
||||
"# map stack on highest address possible, to prevent uftrace\n"
|
||||
"# from considering any kernel address\n");
|
||||
fprintf(sid_map,
|
||||
"ffffffffffff-ffffffffffff rw-p 00000000 00:00 0 [stack]\n");
|
||||
} else {
|
||||
/* in user mode, copy /proc/self/maps instead */
|
||||
FILE *self_map = fopen("/proc/self/maps", "r");
|
||||
g_assert(self_map);
|
||||
for (;;) {
|
||||
int c = fgetc(self_map);
|
||||
if (c == EOF) {
|
||||
break;
|
||||
}
|
||||
fputc(c, sid_map);
|
||||
}
|
||||
fclose(self_map);
|
||||
}
|
||||
fclose(sid_map);
|
||||
}
|
||||
|
||||
static void uftrace_write_task(const GArray *traces)
|
||||
{
|
||||
FILE *task = fopen("./uftrace.data/task.txt", "w");
|
||||
g_assert(task);
|
||||
for (int i = 0; i < traces->len; ++i) {
|
||||
Trace *t = g_array_index(traces, Trace*, i);
|
||||
fprintf(task, "SESS timestamp=0.0 pid=%"PRIu32" sid=0 exename=\"%s\"\n",
|
||||
t->id, t->name->str);
|
||||
fprintf(task, "TASK timestamp=0.0 tid=%"PRIu32" pid=%"PRIu32"\n",
|
||||
t->id, t->id);
|
||||
}
|
||||
fclose(task);
|
||||
}
|
||||
|
||||
static void uftrace_write_info(const GArray *traces)
|
||||
{
|
||||
g_autoptr(GString) taskinfo_tids = g_string_new("taskinfo:tids=");
|
||||
for (int i = 0; i < traces->len; ++i) {
|
||||
Trace *t = g_array_index(traces, Trace*, i);
|
||||
const char *delim = i > 0 ? "," : "";
|
||||
g_string_append_printf(taskinfo_tids, "%s%"PRIu32, delim, t->id);
|
||||
}
|
||||
|
||||
g_autoptr(GString) taskinfo_nr_tid = g_string_new("taskinfo:nr_tid=");
|
||||
g_string_append_printf(taskinfo_nr_tid, "%d", traces->len);
|
||||
|
||||
FILE *info = fopen("./uftrace.data/info", "w");
|
||||
g_assert(info);
|
||||
/*
|
||||
* $ uftrace dump --debug
|
||||
* uftrace file header: magic = 4674726163652100
|
||||
* uftrace file header: version = 4
|
||||
* uftrace file header: header size = 40
|
||||
* uftrace file header: endian = 1 (little)
|
||||
* uftrace file header: class = 2 (64 bit)
|
||||
* uftrace file header: features = 0x1263 (PLTHOOK | ...
|
||||
* uftrace file header: info = 0x7bff (EXE_NAME | ...
|
||||
* <0000000000000000>: 46 74 72 61 63 65 21 00 04 00 00 00 28 00 01 02
|
||||
* <0000000000000010>: 63 12 00 00 00 00 00 00 ff 7b 00 00 00 00 00 00
|
||||
* <0000000000000020>: 00 04 00 00 00 00 00 00
|
||||
*/
|
||||
const uint8_t header[] = {0x46, 0x74, 0x72, 0x61, 0x63, 0x65, 0x21, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x28, 0x00, 0x01, 0x02,
|
||||
0x63, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
size_t wrote = fwrite(header, sizeof(header), 1, info);
|
||||
g_assert(wrote == 1);
|
||||
const char *info_data[] = {
|
||||
"exename:",
|
||||
"build_id:0000000000000000000000000000000000000000",
|
||||
"exit_status:",
|
||||
"cmdline:",
|
||||
"cpuinfo:lines=2",
|
||||
"cpuinfo:nr_cpus=",
|
||||
"cpuinfo:desc=",
|
||||
"meminfo:",
|
||||
"osinfo:lines=3",
|
||||
"osinfo:kernel=",
|
||||
"osinfo:hostname=",
|
||||
"osinfo:distro=",
|
||||
"taskinfo:lines=2",
|
||||
taskinfo_nr_tid->str,
|
||||
taskinfo_tids->str,
|
||||
"usageinfo:lines=6",
|
||||
"usageinfo:systime=",
|
||||
"usageinfo:usrtime=",
|
||||
"usageinfo:ctxsw=",
|
||||
"usageinfo:maxrss=",
|
||||
"usageinfo:pagefault=",
|
||||
"usageinfo:iops=",
|
||||
"loadinfo:",
|
||||
"record_date:",
|
||||
"elapsed_time:",
|
||||
"pattern_type:regex",
|
||||
"uftrace_version:",
|
||||
"utc_offset:",
|
||||
0};
|
||||
const char **info_data_it = info_data;
|
||||
while (*(info_data_it)) {
|
||||
fprintf(info, "%s\n", *info_data_it);
|
||||
++info_data_it;
|
||||
}
|
||||
fclose(info);
|
||||
}
|
||||
|
||||
static Callstack *callstack_new(void)
|
||||
{
|
||||
Callstack *cs = g_new0(Callstack, 1);
|
||||
|
|
@ -612,14 +733,22 @@ static void vcpu_end(unsigned int vcpu_index)
|
|||
|
||||
static void at_exit(qemu_plugin_id_t id, void *data)
|
||||
{
|
||||
bool system_emulation = (bool) data;
|
||||
g_autoptr(GArray) traces = g_array_new(0, 0, sizeof(Trace *));
|
||||
|
||||
for (size_t i = 0; i < qemu_plugin_num_vcpus(); ++i) {
|
||||
Cpu *cpu = qemu_plugin_scoreboard_find(score, i);
|
||||
for (size_t j = 0; j < cpu->traces->len; ++j) {
|
||||
Trace *t = g_array_index(cpu->traces, Trace*, j);
|
||||
trace_flush(t, true);
|
||||
g_array_append_val(traces, t);
|
||||
}
|
||||
}
|
||||
|
||||
uftrace_write_map(system_emulation);
|
||||
uftrace_write_info(traces);
|
||||
uftrace_write_task(traces);
|
||||
|
||||
for (size_t i = 0; i < qemu_plugin_num_vcpus(); ++i) {
|
||||
vcpu_end(i);
|
||||
}
|
||||
|
|
@ -656,7 +785,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
|||
|
||||
score = qemu_plugin_scoreboard_new(sizeof(Cpu));
|
||||
qemu_plugin_register_vcpu_init_cb(id, vcpu_init);
|
||||
qemu_plugin_register_atexit_cb(id, at_exit, NULL);
|
||||
qemu_plugin_register_atexit_cb(id, at_exit, (void *) info->system_emulation);
|
||||
qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue