@@ -93,6 +93,7 @@ enum {
TRACECMD_OPTION_UNAME,
TRACECMD_OPTION_HOOK,
TRACECMD_OPTION_OFFSET,
+ TRACECMD_OPTION_CPUCOUNT,
};
enum {
@@ -257,7 +258,7 @@ struct tracecmd_option *tracecmd_add_option(struct tracecmd_output *handle,
unsigned short id, int size,
const void *data);
struct tracecmd_option *tracecmd_add_buffer_option(struct tracecmd_output *handle,
- const char *name);
+ const char *name, int cpus);
int tracecmd_update_option(struct tracecmd_output *handle,
struct tracecmd_option *option, int size,
const void *data);
@@ -2102,6 +2102,7 @@ static int handle_options(struct tracecmd_input *handle)
struct input_buffer_instance *buffer;
struct hook_list *hook;
char *buf;
+ int cpus;
for (;;) {
if (do_read_check(handle, &option, 2))
@@ -2183,6 +2184,10 @@ static int handle_options(struct tracecmd_input *handle)
hook->next = handle->hooks;
handle->hooks = hook;
break;
+ case TRACECMD_OPTION_CPUCOUNT:
+ cpus = *(int *)buf;
+ handle->cpus = __data2host4(handle->pevent, cpus);
+ break;
default:
warning("unknown option %d", option);
break;
@@ -2206,11 +2211,14 @@ static int read_cpu_data(struct tracecmd_input *handle)
unsigned long long max_size = 0;
unsigned long long pages;
char buf[10];
+ int cpus;
int cpu;
if (do_read_check(handle, buf, 10))
return -1;
+ cpus = handle->cpus;
+
/* check if this handles options */
if (strncmp(buf, "options", 7) == 0) {
if (handle_options(handle) < 0)
@@ -2293,6 +2301,25 @@ static int read_cpu_data(struct tracecmd_input *handle)
goto out_free;
}
+ /*
+ * It is possible that an option changed the number of CPUs.
+ * If that happened, then there's "empty" cpu data saved for
+ * backward compatibility.
+ */
+ if (cpus < handle->cpus) {
+ unsigned long long ignore;
+ int once = 0;
+
+ read8(handle, &ignore); /* offset */
+ read8(handle, &ignore); /* size */
+ if (ignore != 0) {
+ if (!once) {
+ warning("ignored CPU data not zero size");
+ once++;
+ }
+ }
+ }
+
return 0;
out_free:
@@ -1029,7 +1029,8 @@ int tracecmd_update_option(struct tracecmd_output *handle,
}
struct tracecmd_option *
-tracecmd_add_buffer_option(struct tracecmd_output *handle, const char *name)
+tracecmd_add_buffer_option(struct tracecmd_output *handle, const char *name,
+ int cpus)
{
struct tracecmd_option *option;
char *buf;
@@ -1046,6 +1047,14 @@ tracecmd_add_buffer_option(struct tracecmd_output *handle, const char *name)
option = tracecmd_add_option(handle, TRACECMD_OPTION_BUFFER, size, buf);
free(buf);
+ /*
+ * In case a buffer instance has different number of CPUs as the
+ * local machine.
+ */
+ if (cpus)
+ tracecmd_add_option(handle, TRACECMD_OPTION_CPUCOUNT,
+ sizeof(int), &cpus);
+
return option;
}
@@ -2970,21 +2970,53 @@ static struct tracecmd_msg_handle *start_threads(enum trace_type type, int globa
return msg_handle;
}
+static void touch_file(const char *file)
+{
+ int fd;
+
+ fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd < 0)
+ die("could not create file %s\n", file);
+ close(fd);
+}
+
static void append_buffer(struct tracecmd_output *handle,
struct tracecmd_option *buffer_option,
struct buffer_instance *instance,
char **temp_files)
{
+ int cpu_count = instance->cpu_count;
int i;
- for (i = 0; i < instance->cpu_count; i++)
+ /*
+ * Since we can record remote and virtual machines in the same file
+ * as the host, the buffers may no longer have matching number of
+ * CPU data as the host. For backward compatibility for older
+ * trace-cmd versions, which will blindly read the number of CPUs
+ * for each buffer instance as there are for the host, if there are
+ * fewer CPUs on the remote machine than on the host, an "empty"
+ * CPU is needed for each CPU that the host has that the remote does
+ * not. If there are more CPUs on the remote, older executables will
+ * simply ignore them (which is OK, we only need to guarantee that
+ * old executables don't crash).
+ */
+ if (instance->cpu_count < local_cpu_count)
+ cpu_count = local_cpu_count;
+
+ for (i = 0; i < cpu_count; i++) {
temp_files[i] = get_temp_file(instance, i);
+ if (i >= instance->cpu_count)
+ touch_file(temp_files[i]);
+ }
tracecmd_append_buffer_cpu_data(handle, buffer_option,
- instance->cpu_count, temp_files);
+ cpu_count, temp_files);
- for (i = 0; i < instance->cpu_count; i++)
+ for (i = 0; i < instance->cpu_count; i++) {
+ if (i >= instance->cpu_count)
+ delete_temp_file(instance, i);
put_temp_file(temp_files[i]);
+ }
}
static void
@@ -3039,16 +3071,6 @@ static void add_uname(struct tracecmd_output *handle)
free(str);
}
-static void touch_file(const char *file)
-{
- int fd;
-
- fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (fd < 0)
- die("could not create file %s\n", file);
- close(fd);
-}
-
static void print_stat(struct buffer_instance *instance)
{
int cpu;
@@ -3150,7 +3172,12 @@ static void record_data(struct tracecmd_msg_handle *msg_handle,
die("Failed to allocate buffer options");
i = 0;
for_each_instance(instance) {
- buffer_options[i++] = tracecmd_add_buffer_option(handle, instance->name);
+ int cpus = instance->cpu_count != local_cpu_count ?
+ instance->cpu_count : 0;
+
+ buffer_options[i++] = tracecmd_add_buffer_option(handle,
+ instance->name,
+ cpus);
add_buffer_stat(handle, instance);
}
}