GHashTable *tid_to_vcpu_hash;
/* Count of non-vCPU faults. This is only for debugging purpose. */
uint64_t non_vcpu_faults;
+ /* total blocktime when a non-vCPU thread is stopped */
+ uint64_t non_vcpu_blocktime_total;
/*
* Handler for exit event, necessary for
typedef struct {
/* The time the fault was triggered */
uint64_t fault_time;
- /* The vCPU index that was blocked */
+ /*
+ * The vCPU index that was blocked, when cpu==-1, it means it's a
+ * fault from non-vCPU threads.
+ */
int cpu;
} BlocktimeVCPUEntry;
QAPI_LIST_PREPEND(list_latency, latency);
}
+ latency_total += bc->non_vcpu_blocktime_total;
+ faults += bc->non_vcpu_faults;
+
+ info->has_postcopy_non_vcpu_latency = true;
+ info->postcopy_non_vcpu_latency = bc->non_vcpu_faults ?
+ (bc->non_vcpu_blocktime_total / bc->non_vcpu_faults) : 0;
info->has_postcopy_blocktime = true;
/* Convert ns -> ms */
info->postcopy_blocktime = (uint32_t)(bc->total_blocktime / SCALE_MS);
return (uint64_t)qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
}
-/* Inject an (cpu, fault_time) entry into the database, using addr as key */
+/*
+ * Inject an (cpu, fault_time) entry into the database, using addr as key.
+ * When cpu==-1, it means it's a non-vCPU fault.
+ */
static void blocktime_fault_inject(PostcopyBlocktimeContext *ctx,
uintptr_t addr, int cpu, uint64_t time)
{
/* Making sure it won't overflow - it really should never! */
assert(dc->vcpu_faults_current[cpu] <= 255);
} else {
- /* We do not support non-vCPU thread tracking yet */
+ /*
+ * For non-vCPU thread faults, we don't care about tid or cpu index
+ * or time the thread is blocked (e.g., a kworker trying to help
+ * KVM when async_pf=on is OK to be blocked and not affect guest
+ * responsiveness), but we care about latency. Track it with
+ * cpu=-1.
+ *
+ * Note that this will NOT affect blocktime reports on vCPU being
+ * blocked, but only about system-wide latency reports.
+ */
dc->non_vcpu_faults++;
- return;
}
blocktime_fault_inject(dc, addr, cpu, current);
PostcopyBlocktimeContext *ctx;
uint64_t current;
int affected_cpus;
+ int affected_non_cpus;
} BlockTimeVCPUIter;
static void blocktime_cpu_list_iter_fn(gpointer data, gpointer user_data)
BlockTimeVCPUIter *iter = user_data;
PostcopyBlocktimeContext *ctx = iter->ctx;
BlocktimeVCPUEntry *entry = data;
+ uint64_t time_passed;
int cpu = entry->cpu;
/*
* later than when it was faulted.
*/
assert(iter->current >= entry->fault_time);
+ time_passed = iter->current - entry->fault_time;
- /*
- * If we resolved all pending faults on one vCPU due to this page
- * resolution, take a note.
- */
- if (--ctx->vcpu_faults_current[cpu] == 0) {
- ctx->vcpu_blocktime_total[cpu] += iter->current - entry->fault_time;
- iter->affected_cpus += 1;
+ if (cpu >= 0) {
+ /*
+ * If we resolved all pending faults on one vCPU due to this page
+ * resolution, take a note.
+ */
+ if (--ctx->vcpu_faults_current[cpu] == 0) {
+ ctx->vcpu_blocktime_total[cpu] += time_passed;
+ iter->affected_cpus += 1;
+ }
+ trace_postcopy_blocktime_end_one(cpu, ctx->vcpu_faults_current[cpu]);
+ } else {
+ iter->affected_non_cpus++;
+ ctx->non_vcpu_blocktime_total += time_passed;
+ /*
+ * We do not maintain how many pending non-vCPU faults because we
+ * do not care about blocktime, only latency.
+ */
+ trace_postcopy_blocktime_end_one(-1, 0);
}
-
- trace_postcopy_blocktime_end_one(cpu, ctx->vcpu_faults_current[cpu]);
}
/*
BlockTimeVCPUIter iter = {
.current = get_current_ns(),
.affected_cpus = 0,
+ .affected_non_cpus = 0,
.ctx = dc,
};
gpointer key = (gpointer)addr;
}
dc->smp_cpus_down -= iter.affected_cpus;
- trace_postcopy_blocktime_end(addr, iter.current, iter.affected_cpus);
+ trace_postcopy_blocktime_end(addr, iter.current, iter.affected_cpus,
+ iter.affected_non_cpus);
}
static void postcopy_pause_fault_thread(MigrationIncomingState *mis)
# this is the per-vCPU statistics. This is only present when the
# postcopy-blocktime migration capability is enabled. (Since 10.1)
#
+# @postcopy-non-vcpu-latency: average remote page fault latency for all
+# faults happend in non-vCPU threads (in ns). It has the same
+# definition of @postcopy-latency but this only provides statistics to
+# non-vCPU faults. This is only present when the postcopy-blocktime
+# migration capability is enabled. (Since 10.1)
+#
# @socket-address: Only used for tcp, to know what the real port is
# (Since 4.0)
#
#
# Features:
#
-# @unstable: Members @postcopy-latency, @postcopy-vcpu-latency are
-# experimental.
+# @unstable: Members @postcopy-latency, @postcopy-vcpu-latency,
+# @postcopy-non-vcpu-latency are experimental.
#
# Since: 0.14
##
'type': 'uint64', 'features': [ 'unstable' ] },
'*postcopy-vcpu-latency': {
'type': ['uint64'], 'features': [ 'unstable' ] },
+ '*postcopy-non-vcpu-latency': {
+ 'type': 'uint64', 'features': [ 'unstable' ] },
'*socket-address': ['SocketAddress'],
'*dirty-limit-throttle-time-per-round': 'uint64',
'*dirty-limit-ring-full-time': 'uint64'} }