Главная

Как подправить системный таймер в BeOS (>2.1 GHz)

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

Это все потому, что в 1998 году кто–то в Be Inc не предусмотрел, что BeOS будут запускать на таких процессорах. Ну а когда такие монстры появились — править ошибку было уже некому.

Впрочем, не все потеряно — где хакеры не пропадали? Вот один такой хакер под именем cemist и предложил решение в форуме BeOSJournal.org:


    «Привет всем,

    Я поизучал причину неладов у BeOS на процах 2,2 ГГц и быстрее …выглядит как проблема переполнения знакового целого, несмотря на то что в видимых местах в BeOS применяется для отсчета времени int64 (которого по идее достаточно). Впрочем, не уверен. Тем не менее, решение есть, без того, чтобы уменьшать частоту процессора, как я это делал ранее.

    Ковыряясь с ядром, я нашел фунцию system_time_setup расположенную в ядре R5 со сдвигом (offset) 0005a0b0 — в этом месте считается переменная cv_factor. Эта переменная cv_factor расположена в ячейке со сдвигом 0008a584. BeOS детектирует частоту правильно, однако этот самый cv_factor считается неправильно, поскольку частота процессора оказывается выше максимального значения для длинного целого со знаком (signed long). После нескольких упражнений я поменял малость фунцию system_time_setup таким образом, что теперь мой P4 2.8 работает на своей нормальной частоте, а BeOS считает все правильно.

    Вот как выглядит эта фунция в оригинале:
    0005a0b0 :
    5a0b0: 53 push %ebx
    5a0b1: b9 40 42 0f 00 mov $0xf4240,%ecx
    5a0b6: 89 ca mov %ecx,%edx
    5a0b8: 29 c0 sub %eax,%eax
    5a0ba: 8b 5c 24 08 mov 0x8(%esp,1),%ebx
    5a0be: f7 f3 div %ebx,%eax
    5a0c0: a3 84 a5 08 00 mov %eax,0x8a584
    5a0c5: 5b pop %ebx
    5a0c6: c3 ret
    5a0c7: 90 nop

    а вот обновленный вариант:
    0005a0b0 :
    5a0b0: 53 push %ebx
    5a0b1: b9 40 42 0f 00 mov $0xf4240,%ecx
    5a0b6: 89 ca mov %ecx,%edx
    5a0b8: 29 c0 sub %eax,%eax
    5a0ba: b8 00 60 17 00 mov $0x176000,%eax (Смотри сюда!)
    5a0bf: 90 nop
    5a0c0: a3 84 a5 08 00 mov %eax,0x8a584
    5a0c5: 5b pop %ebx
    5a0c6: c3 ret
    5a0c7: 90 nop

    И как же я высчитал эту константу 0x176000 (16–ричное!) подставленную вместо переменной? Однозначно решения нет, приходится немного повозиться, но может кто предложит более простой вариант? (RomikB? BeO? Сяржук?)

    В общем, путь такой — скомпилить тестовую фунцию, вставить частоту вашего процессора в init_system_time(); для 2.8GHz это будет 2800000000LL, для 3.0GHz — 3000000000LL, запустить прогу в в Terminal и обратить внимание на 2 последние строки:

    usecs: 1000011
    usecs: 1001323

    Программа использует BeOS–ную функцию snooze() для засыпания на одну секунду, берет system_time, использует процессорный вызов rdtsc function и снова snooze() на секунду. По идее две цифры должны быть как можно более близки к друг другу. Верхняя цифра — это то, что рапортует BeOS, нижняя — то, что нужно достичь. К примеру для (1000000) результат должен быть 1000000 usecs, 1000000 — usecs — это одна секунда, the usecs может быть не совсем 1000000, но это не так важно… Это не самое прямолинейное решение, но вполне подходящее для людей, которые не хотят снижать частоту процессора. С небольшими уточнениями можно получить очень хороший результат. В моем случае 0x176000 как раз нуждался в небольшом уточнении.

    Код тестовой программы:

    #include
    #include
    #include
    #include

    long long frequency;

    void show_beos_cpu_speed()
    {
    system_info info;
    get_system_info(&info);
    cout << (info.cpu_clock_speed & 0xffffffffLL) << endl;
    }

    long long my_rdtsc()
    {
    long long now;
    asm volatile(«rdtsc» : "=A"(now));
    return now;
    }

    void init_system_time()
    {
    bigtime_t start = my_rdtsc();
    snooze(1000000);
    //frequency = (my_rdtsc() — start);
    frequency = 2800000000LL;//(my_rdtsc() — start);
    cout << frequency << endl;
    }

    bigtime_t my_system_time()
    {
    bigtime_t nowTime = (((my_rdtsc()) * 1000000) / frequency);
    return nowTime;
    }

    int main()
    {
    show_beos_cpu_speed();

    init_system_time();

    bigtime_t start = system_time();
    snooze(1000000);
    cout << “usecs: " << system_time() — start << endl;
    start = my_system_time();
    snooze(1000000);
    cout << “usecs: " << my_system_time() — start << endl;

    return 0;
    }


От редактора. Кто нибудь понял? Я так понял, что нужно лезть DiskProbe–м ядро, подставлять в нужное место цифру навроде 0x176000, перегружаться, запускать тестовую программу и смотреть. Цифры далеки — меняем число в ядре — снова запускаемся. Пока не успокоимся.
Или есть другие мнения?

Как подправить системный таймер в BeOS (>2.1 GHz)

Лень копаться в исходниках.

Вопросы:

Какой параметр у system_time_setup
и за что отвечает cv_factor

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Allowed HTML tags: <a> <em> <i> <img> <strong> <b> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Строки и параграфы переносятся автоматически.

Подробнее о форматировании

CAPTCHA
Введите перечисленные символы, чтобы мы убедились, что вы не робот. Не требуется для зарегистрированных пользователей.
B
w
E
q
M
k
Enter the code without spaces and pay attention to upper/lower case.