LINUX.ORG.RU

Замедлить время в qemu

 , , ,


1

4

Возникла задача: замедлить «течение времени» внутри виртуалки qemu-kvm. Нужно не замедлить выполнение кода в виртуалке, а именно сделать так, чтобы система в виртуалке думала, что реальное время идёт медленнее. Основная цель - заставить разнообразные таймауты истекать медленнее, чем они должны по реальному времени. Нужно это для запуска сложной и жирной проприетарной хрени под valgrind'ом.

Может кто-то уже делал такое или даже есть готовые патчи и т.п.? Нагуглить ничего не удалось. Исходники qemu придётся курить очень долго, так как в низкоуровневом устройстве x86 я мало что понимаю. Разных ляторов, отсчитывающих время, там похоже больше одного предусмотрено...

Deleted

А что если запустить виртуальную машину в долгую живую миграцию с узла на узел? Виртуалка будет перемещаться с релятивистской скоростью, что приведёт к замедлению времени в ней для пользователя.

pedobear
()
Ответ на: комментарий от pedobear

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

Deleted
()
Ответ на: комментарий от Deleted

Разве при миграции она просто не ставится на паузу?

Не знаю. Моё дело - стратегия -))

Мне нужно чтобы код выполнялся на максимально возможной скорости (как в обычной виртуалке), но чтобы разнообразные таймеры, часы и т.п. считали время медленнее.

По-моему, это просто невозможно.

pedobear
()

Пять звезд, а такая наркомания написана

dvrts ★★★
()

Программа в железные таймеры лезет или пользуется чем-то вроде libevent? Если второе, то проще пропатчить libevent.

i-rinat ★★★★★
()

урежь производительность, нагрузи процессор туевой хучей демонов и будет тебе счастье

essir
()
Ответ на: комментарий от i-rinat

«Программа» - это на самом деле куча разных страшно ънтерпрайзных демонов, написанных на C++, java и возможно чём-то ещё, которые общаются между собой через несколько разных видов IPC разной степени велосипедности. Один из этих демонов нужно запустить под valgrind. Но проблема в том, что запуск под valgrind'ом приводит к замедлению работы конкретно этого демона. И в результате в разных местах начинают вылезать ошибки из-за таймаутов. Таймауты захардкожены в куче разных мест. У меня есть доступ только где-то к четверти всех исходников, но и там чёрт ногу сломит. В общем - всё плохо. Задача: запустить один демон под valgrind'ом и при этом избежать таймаутов.

Какого-то одного места, где была бы сосредоточена работа со временем и таймаутами нету. Я даже не уверен, что всё собиратся динамически, так что подмена либ - не вариант.

Можно попробовать «пропатчить» некоторые системные вызовы через какой-нибудь systemtap, но их довольно много выходит...

Deleted
()
Ответ на: комментарий от essir

урежь производительность, нагрузи процессор туевой хучей демонов и будет тебе счастье

Это сделает ещё хуже: «реальное время» в виртуалке будет идти так же, а код будет выполняться ещё медленнее. Мне нужно ровно наоборот.

Deleted
()
Ответ на: комментарий от mix_mix

А вот это уже интереснее, спасибо. Надо только посмотреть где именно это вызывается, чтобы не замедлить лишнего =).

Deleted
()

можно замедлить все, урезав выданные VM ресурсы через cgroups на хосте, но как я понимаю это не поможет.

может наоборот, запускать valgrind на максимально прокачанном железе, где он ничего не притормозит?

dyasny ★★★★★
()

главное же не ляторы, а сколько инструкций за цикл выполняется.

‘-icount [N|auto]’

    Enable virtual instruction counter. The virtual cpu will
execute one instruction every 2^N ns of virtual time. If auto is
specified then the virtual cpu speed will be automatically
adjusted to keep virtual time within a few seconds of real time.

    Note that while this option can give deterministic behavior,
it does not provide cycle accurate emulation. Modern CPUs
contain superscalar out of order cores with complex cache
hierarchies. The number of instructions executed often has
little or no correlation with actual performance. 
dimon555 ★★★★★
()
Ответ на: комментарий от dimon555

Там замедлится всё, включая valgrind. А всё, что на прерываниях висит, включая таймер, будет не сильно по-другому работать.

mix_mix ★★★★★
()
Ответ на: комментарий от dimon555

тогда только simics, только хардкор.

Это да... Но в simics вообще всё будет с черепашьей скоростью работать =).

Deleted
()

Говнокостыльный патч для stable-2.1 (slow down time in qemu guest)

Сначала я попробовать менять scale, как предложил mix_mix, но это приводило к зависанию при загрузке ядра в гостевой системе. Потом методом тыка я пришёл к этому:

diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index 7f9a074..31826ca 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -7,6 +7,8 @@
 
 /* timers */
 
+#define SLOWDOWN 2
+
 #define SCALE_MS 1000000
 #define SCALE_US 1000
 #define SCALE_NS 1
diff --git a/qemu-timer.c b/qemu-timer.c
index 00a5d35..2933473 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -550,13 +550,13 @@ int64_t qemu_clock_get_ns(QEMUClockType type)
 
     switch (type) {
     case QEMU_CLOCK_REALTIME:
-        return get_clock();
+        return get_clock() / SLOWDOWN;
     default:
     case QEMU_CLOCK_VIRTUAL:
         if (use_icount) {
-            return cpu_get_icount();
+            return cpu_get_icount() / SLOWDOWN;
         } else {
-            return cpu_get_clock();
+            return cpu_get_clock() / SLOWDOWN;
         }
     case QEMU_CLOCK_HOST:
         now = get_clock_realtime();
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index f9fcbca..3ce6499 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -448,13 +448,13 @@ typedef struct model_features_t {
  * when KVM is enabled.
  */
 static uint32_t kvm_default_features[FEATURE_WORDS] = {
-    [FEAT_KVM] = (1 << KVM_FEATURE_CLOCKSOURCE) |
+    [FEAT_KVM] = /*(1 << KVM_FEATURE_CLOCKSOURCE) |*/
         (1 << KVM_FEATURE_NOP_IO_DELAY) |
-        (1 << KVM_FEATURE_CLOCKSOURCE2) |
+        /*(1 << KVM_FEATURE_CLOCKSOURCE2) |*/
         (1 << KVM_FEATURE_ASYNC_PF) |
         (1 << KVM_FEATURE_STEAL_TIME) |
-        (1 << KVM_FEATURE_PV_EOI) |
-        (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT),
+        (1 << KVM_FEATURE_PV_EOI) /*|
+        (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT)*/,
     [FEAT_1_ECX] = CPUID_EXT_X2APIC,
 };
 
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index ddedc73..3918cef 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -131,7 +131,7 @@ static const struct kvm_para_features {
     int cap;
     int feature;
 } para_features[] = {
-    { KVM_CAP_CLOCKSOURCE, KVM_FEATURE_CLOCKSOURCE },
+    /*{ KVM_CAP_CLOCKSOURCE, KVM_FEATURE_CLOCKSOURCE },*/
     { KVM_CAP_NOP_IO_DELAY, KVM_FEATURE_NOP_IO_DELAY },
     { KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP },
     { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF },
На самом деле я не знаю как именно это работает. На данный момент постестил, что время успешно замедляется для:

  • ping localhost (пакеты отправляются с большей паузой)
  • date (время идёт в два раза медленнее =))
  • watch -n1

Если не комментировать константы, связанные с KVM, то это работает только с выключенным KVM. Со включенным KVM видимо гостевая система работает с таймерами и прочим как-то в обход qemu.

Обратный отсчёт в isolinux со включенным KVM всегда работает правильно, даже с закомментированными KVM_FEATURE_CLOCKSOURCE*.

Ещё один момент: из-за деления результата qemu_clock_get_ns() пополам, скорее всего логика обработки истёкших таймеров в qemu срабатывает два раза (один раз - вхолостую). Возможно также «замедлились» таймеры qemu, которые не должны были замедляться, например связанные с таймаутами доступа к внешним сетевым ресурсам и т.п.

В общем сейчас это страшный костыль =).

Deleted
()
Последнее исправление: Deleted (всего исправлений: 2)
Ответ на: комментарий от Deleted

Это да... Но в simics вообще всё будет с черепашьей скоростью работать =).

это на самом деле не так, simics умеет использовать VT-x для ускорения, так x86 вполне шустро эмулируется.

dimon555 ★★★★★
()
Ответ на: комментарий от tailgunner

Как оно работает в kvm я х3. И лежа на берегу океана с телефоном вместо компа разбираться реально лень, не обессудь. Если никто не ответит после того как вернусь из отпуска, посмотрю.

alt-x ★★★★★
()

Возможно, стоит найти, где там реализуется системный таймер и замедлять его. По идее в ОС весь отсчёт времени завязан только на него. При использовании аппаратной виртуализации перехватывать попытки изменения делителя таймера и умножать его на нужный коэффициент. А при чтении параметров наоборот делить. Вобщем, не изменять саму реализацию таймера (ибо он может оказаться аппаратным при использовании виртуализации), а патчить его параметры при попытке их изменить.

Я имею ввиду под таймером тот, который на x86 по дефолту тикает с частотой 18.2 Гц. Хотя вроде там ещё есть какой-то таймер... Но с ним можно обойтись также.

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 1)
Ответ на: комментарий от KivApple

Их может быть несколько на самом деле. На реальном железе:

$ cat /sys/devices/system/clocksource/clocksource0/available_clocksource 
tsc hpet acpi_pm 
В виртуалке с KVM там будет «kvm-clock».

Меня пока мой костыль устроил. Копаться в этом дальше и делать нормальное решение у меня в данный момент нет времени и желания.

Deleted
()

То же самое, только с возможностью настройки через командную строку:

From 3dc4c83590cb4eab4d50f3329bedb8b1a4f4e961 Mon Sep 17 00:00:00 2001
From: Ivan Mironov <mironov.ivan@gmail.com>
Date: Thu, 13 Nov 2014 12:30:52 +0300
Subject: [PATCH] WIP: slowtime

---
 include/qemu/timer.h |  2 ++
 qemu-options.hx      |  6 ++++++
 qemu-timer.c         |  8 +++++---
 target-i386/cpu.c    | 15 +++++++++++++++
 vl.c                 | 24 ++++++++++++++++++++++++
 5 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index 7f9a074..7290a8b 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -7,6 +7,8 @@
 
 /* timers */
 
+extern int32_t slowtime_divider;
+
 #define SCALE_MS 1000000
 #define SCALE_US 1000
 #define SCALE_NS 1
diff --git a/qemu-options.hx b/qemu-options.hx
index 1549625..1eb5c83 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3352,3 +3352,9 @@ HXCOMM This is the last statement. Insert new options before this line!
 STEXI
 @end table
 ETEXI
+
+
+DEF("slowtime", HAS_ARG, QEMU_OPTION_slowtime, \
+    "-slowtime divider=number\n" \
+    "                slow down system clock\n",
+    QEMU_ARCH_ALL)
diff --git a/qemu-timer.c b/qemu-timer.c
index 00a5d35..ce95db8 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -41,6 +41,8 @@
 #include <sys/prctl.h>
 #endif
 
+int32_t slowtime_divider = 1;
+
 /***********************************************************/
 /* timers */
 
@@ -550,13 +552,13 @@ int64_t qemu_clock_get_ns(QEMUClockType type)
 
     switch (type) {
     case QEMU_CLOCK_REALTIME:
-        return get_clock();
+        return get_clock() / slowtime_divider;
     default:
     case QEMU_CLOCK_VIRTUAL:
         if (use_icount) {
-            return cpu_get_icount();
+            return cpu_get_icount() / slowtime_divider;
         } else {
-            return cpu_get_clock();
+            return cpu_get_clock() / slowtime_divider;
         }
     case QEMU_CLOCK_HOST:
         now = get_clock_realtime();
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index f9fcbca..23d9627 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -31,6 +31,8 @@
 #include "qemu/config-file.h"
 #include "qapi/qmp/qerror.h"
 
+#include "qemu/timer.h"
+
 #include "qapi-types.h"
 #include "qapi-visit.h"
 #include "qapi/visitor.h"
@@ -1994,6 +1996,13 @@ static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp)
     /* Special cases not set in the X86CPUDefinition structs: */
     if (kvm_enabled()) {
         FeatureWord w;
+
+        if (slowtime_divider != 1) {
+            kvm_default_features[FEAT_KVM] &= ~KVM_FEATURE_CLOCKSOURCE;
+            kvm_default_features[FEAT_KVM] &= ~KVM_FEATURE_CLOCKSOURCE_STABLE_BIT;
+            kvm_default_features[FEAT_KVM] &= ~KVM_FEATURE_CLOCKSOURCE2;
+        }
+
         for (w = 0; w < FEATURE_WORDS; w++) {
             env->features[w] |= kvm_default_features[w];
             env->features[w] &= ~kvm_default_unset_features[w];
@@ -2738,6 +2747,12 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
     }
 #endif
 
+    if (slowtime_divider != 1) {
+        env->features[FEAT_1_EDX] &= ~CPUID_TSC;
+        env->features[FEAT_1_ECX] &= ~CPUID_EXT_TSC_DEADLINE_TIMER;
+        env->features[FEAT_8000_0001_EDX] &= ~CPUID_EXT2_RDTSCP;
+    }
+
     mce_init(cpu);
     qemu_init_vcpu(cs);
 
diff --git a/vl.c b/vl.c
index 7f8bd39..408094c 100644
--- a/vl.c
+++ b/vl.c
@@ -537,6 +537,19 @@ static QemuOptsList qemu_mem_opts = {
     },
 };
 
+static QemuOptsList qemu_slowtime_opts = {
+    .name = "slowtime",
+    .implied_opt_name = "divider",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head),
+    .desc = {
+        {
+            .name = "divider",
+            .type = QEMU_OPT_NUMBER,
+        },
+        { /* end of list */ }
+    },
+};
+
 /**
  * Get machine options
  *
@@ -2979,6 +2992,7 @@ int main(int argc, char **argv, char **envp)
     qemu_add_opts(&qemu_msg_opts);
     qemu_add_opts(&qemu_name_opts);
     qemu_add_opts(&qemu_numa_opts);
+    qemu_add_opts(&qemu_slowtime_opts);
 
     runstate_init();
 
@@ -3961,6 +3975,16 @@ int main(int argc, char **argv, char **envp)
                     exit(1);
                 }
                 break;
+            case QEMU_OPTION_slowtime:
+                opts = qemu_opts_parse(qemu_find_opts("slowtime"), optarg, 0);
+                if (!opts) {
+                    exit(1);
+                }
+                slowtime_divider = qemu_opt_get_number(opts, "divider", 1);
+                if (slowtime_divider < 1) {
+                    exit(1);
+                }
+                break;
             default:
                 os_parse_cmd_args(popt->index, optarg);
             }
-- 
1.8.4.1

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