LINUX.ORG.RU

Использование счетчика TSC


0

0

Измеряю время с помощью TSC (Time Stamp Counter).
Помогите, пожалуйста, перевести такты в секунды.
Проблема с константами CLOCKS_PER_SEC и _SC_CLK_TCK.
Не пойму как мне их использовать, значения измеренного времени явно получаются не те.
Мой вариант выглядит не очень красиво:

#include <stdint.h>
#include <unistd.h>
#include <iostream>

using namespace std;

extern __inline__ uint64_t rdtsc() {
uint64_t x;
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
return x;
}

int main()
{
cout<<"run"<<endl<<endl;
uint32_t slp = 10;
uint64_t t1, t2;
t1 = rdtsc();
sleep(slp);
t2 = rdtsc();

uint32_t clocks_per_sec = (t2 - t1) / slp;

cout<<hex<< "t1 = " << t1 <<endl<<dec<< "sleep("<< slp <<")"<<hex<<endl
<< "t2 = " << t2 <<endl;
cout<<dec<< "t2 - t1 = " << t2-t1 <<" (clocks)"<<endl<<endl;

cout<< "CLOCKS_PER_SEC = "<< CLOCKS_PER_SEC <<endl;
cout<< "sysconf(_SC_CLK_TCK) = "<< sysconf(_SC_CLK_TCK) <<endl<<endl;

cout<< (t2 - t1) / sysconf(_SC_CLK_TCK) <<endl;
cout<< (t2 - t1) / CLOCKS_PER_SEC <<endl;
cout<< (t2 - t1) / (CLOCKS_PER_SEC * sysconf(_SC_CLK_TCK)) <<endl<<endl;

cout<< "clocks per second = "<< clocks_per_sec <<endl;
slp = 20;
cout<< "sleep("<<slp<<")"<<endl;
t1 = rdtsc();
sleep(slp);
t2 = rdtsc();
cout<< "sleep time = " << (t2 - t1) / clocks_per_sec <<endl;
return 0;
}


/*
=====================================================================

$ g++ tsc.cpp -o tsc
$ ./tsc
run

t1 = 1638b369bf294
sleep(10)
t2 = 16390d06932f0
t2 - t1 = 24055201884 (clocks)

CLOCKS_PER_SEC = 1000000
sysconf(_SC_CLK_TCK) = 100

240552018
24055
240

clocks per second = 2405520188
sleep(20)
sleep time = 20

=====================================

$ cat /proc/cpuinfo

processor : 0
vendor_id : GenuineIntel
cpu family : 15
model : 2
model name : Intel(R) Pentium(R) 4 CPU 2.40GHz
stepping : 7
cpu MHz : 2405.487
cache size : 512 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 2
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm
bogomips : 4797.23

*/

P.S.: Прошу ногами не пинать, я начинающий программист в UNIX/Linux

anonymous

CLOCKS_PER_SEC и _SC_CLK_TCK не имеют отношения к TSC. Счетчики TSC считают такты процессора, так что тебе нужно умножать на тактовую частоту твоего проца. CLOCKS_PER_SEC и _SC_CLK_TCK - это тики _таймера_.

Щасс тебе куча народа скажет "читайте маны - они рулез" :)

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

> нужно умножать

Тьфу ты черт,,, делить, конечно.

tailgunner ★★★★★
()

Третий класс церковно-приходской школы. Читайте маны, они рулез

Zmacs
()

Спасибо. Только что делать, если нельзя привязываться к конкретному процессору? Как программно получить частоту? Если бы нашел что-то в man'ах, не задавал бы вопрос. Помогите, пожалуйста.

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

> Спасибо. Только что делать, если нельзя привязываться к конкретному процессору? Как программно получить частоту?

А вот это - ХЗ. Знал бы - сказал. Единственное, что могу предложить - парсить /proc/cpuinfo на предмет "cpu MHz". Можно еще попробовать калиброваться в динамике, но это неточный метод.

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

> посмотреть как это делают cpufrequtils?

AFAIK, они полагаются на специальный модуль в ядре, который рулит частотами (и сообщает их через sysfs).

tailgunner ★★★★★
()

Спасибо всем, кто решил помочь, да и всем, кто просто решил заглянуть.
Я тут начал исходники ядра смотреть. Нашел кое-что:

cpufreq.h:

struct cpufreq_policy {
unsigned int cpu; /* cpu nr or CPUFREQ_ALL_CPUS */
unsigned int min; /* in kHz */
unsigned int max; /* in kHz */
unsigned int cur; /* in kHz, only needed if cpufreq
* governors are used */
unsigned int policy; /* see above */
struct cpufreq_governor *governor; /* see below */
struct cpufreq_cpuinfo cpuinfo; /* see above */
// struct intf_data intf; /* interface data */
};

В cpufreq.c как-то все это используется. Конец рабочего дня, некогда смотреть дальше. Кому интересно, посмотрите. Я только в понедельник смогу продолжить. Думаю, есть способ полегче - просто найти регистр, из которого читается вся информация о процессоре. Не помню ни адрес, ни название. Так вот, можно напрямую оттуда все прочитать. Я так думаю.

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

> Думаю, есть способ полегче - просто найти регистр, из которого читается вся информация о процессоре. Не помню ни адрес, ни название. Так вот, можно напрямую оттуда все прочитать.

Думаю, ты стал рыть совсем не туда. Ты хочешь реализовать cpufreq вручную? Процессоров много и разных, методы получения тактовой частоты наверняка различаются (то есть - нет такого регистра ;) ). А главное - ни один из них не проще, чем парсинг /proc/cpuinfo.

tailgunner ★★★★★
()

Привет всем. Минуту нашел заглянуть на форум. Действительно, такого регистра нет. Есть машинно-специфичные регистры (MSR), но и в них напрямую частоту не найдешь. Кстати, этот TSC - тоже является MSR, но есть на большинстве x86. С помощью команды CPUID можно получить информацию о типе процессора.
Времени пока не нашел разбираться с ядром. Похоже, что cpufreq.c для определения частоты использует тот самый TSC ;)
Только обращается к нему по-другому. Затем, должно быть каким-то образом, например используя аппаратные часы, производит калибровку. Получает количество тактов в одной секунде и, соответственно, частоту.
Мне же повторить это на пользовательском уровне с необходимой точностью не получится. Нужно каким-то образом достать значение поля cpufreq_policy.cur или что-то подобное.
Может кто-нибудь подскажет как это сделать?
Благодарю всех за помощь; tailgunner, отдельное спасибо. Автор темы - я, позывной - sanchez. Регистрироваться не захотел.
Возможно, я допустил грубые ошибки, не судите строго.

--------
sanchez

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

> Нужно каким-то образом достать значение поля cpufreq_policy.cur или что-то подобное.

Ну, если ты определенно хочешь найти приключений, то тебе сюда: /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq, В этом файле - одно число, текущая частота процессора в кГц. Для того, чтобы этот файл появился, необходимо загрузить соотв, модуль (у меня - p4-clockmod).

Только учти - при изменении тактовой частоты (для чего cpufreq и предназначен) счетчик TSC может плавать (может и не плавать - IIRC, разные модели процессоров ведут себя по-разному).

Мне очень интересно - почему не распарсить /proc/cpuinfo? Он всегда есть (/sys - только на 2.6).

> Регистрироваться не захотел.

Зря

tailgunner ★★★★★
()

tailgunner, парсить /proc/cpuinfo оставляю как крайнее средство. Хотелось бы найти альтернативный вариант.
Не совсем понял о /sys/devices/system/cpu/cpu0/cpufreq/puinfo_cur_freq. Под рукой нет ядра 2.6, найду позже. Вопрос: как определить какой модуль необходим и как его загрузить?
Спасибо.

---
sanchez

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

Я и не прошу вариант для SMP. Нужно определить частоту для x86-совместимого процессора. Наличие TSC гарантируется.
Загрузить модуль можно утилитой modprobe, но как определить какой модуль необходим непонятно. А если используется не Intel, а Cyrix/VIA или AMD?
Как же достать эту частоту? Народ, подскажите, пожалуйста.
---
sanchez

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

Глянь исходники top. top может показать Last Used CPU, значит, получает инфу о процессоре.

Но, опять же, чем /proc/cpuinfo плох?

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

Исходников top не нашел. Кроме того, не заметил чтобы top выдавала частоту процессора. Как получить информацию из ядра тоже не знаю. Похоже, действительно придется парсить /proc/cpuinfo. Всем спасибо.

---
sanchez

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