static void *
thread_start(void *arg)
{
printf("Subthread starting infinite loop\n");
for (;;)
continue;
}
static void
pclock(char *msg, clockid_t cid)
{
struct timespec ts;
printf("%s", msg);
if (clock_gettime(cid, &ts) == -1)
handle_error("clock_gettime");
printf("%4ld.%03ld\n", ts.tv_sec, ts.tv_nsec / 1000000);
}
int
main(int argc, char *argv[])
{
pthread_t thread;
clockid_t cid;
int j, s;
s = pthread_create(&thread, NULL, thread_start, NULL);
if (s != 0)
handle_error_en(s, "pthread_create");
printf("Main thread sleeping\n");
sleep(1);
printf("Main thread consuming some CPU time...\n");
for (j = 0; j < 2000000; j++)
getppid();
pclock("Process total CPU time: ", CLOCK_PROCESS_CPUTIME_ID);
s = pthread_getcpuclockid(pthread_self(), &cid);
if (s != 0)
handle_error_en(s, "pthread_getcpuclockid");
pclock("Main thread CPU time: ", cid);
/* The preceding 4 lines of code could have been replaced by:
pclock("Main thread CPU time: ", CLOCK_THREAD_CPUTIME_ID); */
s = pthread_getcpuclockid(thread, &cid);
if (s != 0)
handle_error_en(s, "pthread_getcpuclockid");
pclock("Subthread CPU time: 1 ", cid);
exit(EXIT_SUCCESS); /* Terminates both threads */
}
pthread_getcpuclockid (threadid, clockid)
pthread_t threadid;
clockid_t *clockid;
{
struct pthread *pd = (struct pthread *) threadid;
/* Make sure the descriptor is valid. */
if (INVALID_TD_P (pd))
/* Not a valid thread handle. */
return ESRCH;
#ifdef CLOCK_THREAD_CPUTIME_ID
/* We need to store the thread ID in the CLOCKID variable together
with a number identifying the clock. We reserve the low 3 bits
for the clock ID and the rest for the thread ID. This is
problematic if the thread ID is too large. But 29 bits should be
fine.
将gettid() 放在了 CLOCKID变量里面
If some day more clock IDs are needed the ID part can be
enlarged. The IDs are entirely internal. */
if (pd->tid >= 1 << (8 * sizeof (*clockid) - CLOCK_IDFIELD_SIZE))
return ERANGE;
/* Store the number. 用后面3位来保存 C_T_C_I ,如果gettid()太大就失效了所以上面做了判断 */
*clockid = CLOCK_THREAD_CPUTIME_ID | (pd->tid << CLOCK_IDFIELD_SIZE);
return 0;
#else
/* We don't have a timer for that. */
return ENOENT;
#endif
}
然后看一下 clock_gettime()的 CLOCK_PROCESS_CPUTIME_ID 部分的处理
int
clock_gettime (clockid_t clock_id, struct timespec *tp)
{
/*检测上面的设置位*/
//...
#if HP_TIMING_AVAIL
if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1))
== CLOCK_THREAD_CPUTIME_ID)
retval = hp_timing_gettime (clock_id, tp);
else
#endif
//...
return retval;
}
这里先省掉了一些 无关代码。
在有 timestamp register 的情况下 测试 HP_TIMING_AVAIL 就是ture,
所以我们来看看
retval = hp_timing_gettime (clock_id, tp);
这块之前的glibc 还没有独立出来 ,其实一样 关键在于
__pthread_clock_gettime();
先把hp_timing_gettime 放在一边,来看看里面的关键函数
int
__pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq,
struct timespec *tp)
{
hp_timing_t tsc;
/* Get the current counter. */
HP_TIMING_NOW (tsc);
/* This is the ID of the thread we are looking for. */
pid_t tid = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE;
/* Compute the offset since the start time of the process.
THREAD_GETMEM 里面存放的是线程启动时候记录下的 counter
所有 */
if (tid == 0 || tid == THREAD_GETMEM (THREAD_SELF, tid))
/* 如果调用的不是当前thread, 那就要通过__find_thread_by_id (gettid())来获得 对应的pthread结构,很可惜这个宏被 _attribute__ ((visibility ("hidden"))) 放在了hiddern区 所以只能内部用,外部动态链接没办法使用 。。主要因为涉及了内部太多结构 */
tsc -= THREAD_GETMEM (THREAD_SELF, cpuclock_offset);
else
{
/* This is more complicated. We have to locate the thread based
on the ID. This means walking the list of existing
threads. */
struct pthread *thread = __find_thread_by_id (tid);
//...
/* There is a race here. The thread might terminate and the stack
become unusable. But this is the user's problem. */
tsc -= thread->cpuclock_offset;
}
/* Compute the seconds. */
tp->tv_sec = tsc / freq;
/* And the nanoseconds. This computation should be stable until
we get machines with about 16GHz frequency. */
tp->tv_nsec = ((tsc % freq) * 1000000000ull) / freq;
return 0;
}
对线程结构特定成员的赋值和取值操作 都要通过
THREAD_SETMEM 和THREAD_GETMEM 来操作
可以简单看一眼 THREAD_SETMEM
# define THREAD_SETMEM(descr, member, value)
//...
else if (sizeof (descr->member) == 4) \
asm volatile ("movl %0,%%gs:%P1" : \
: "ir" (value), \
"i" (offsetof (struct pthread, member)));
先判断成员长度 ,然后 把立即数(ir) value 放在gs段偏移为 offsetof (struct pthread, member))的位置, 也就完成了复制
补充一下: 为什么是gs段 :
其实这是gs段寄存器 每一个 pthread 都有一下的私有数据,一个是pthread_t类似于PCB ,一个是自身的堆栈可以用pthread_setstack 来设置,还有一个是TLS线程本地数据了 ,这些东西放在一个mmap区域中 ,用各自的gs寄存器地址来指向
分享到:
相关推荐
rdtsc指令是x86架构中的一条指令,全称是read time-stamp counter,中文翻译为读取时间戳计数器。该指令用于读取处理器的时钟计数器,这个计数器是一个64位的寄存器,其值随着处理器的每个时钟周期而增加。这个指令...
RDTSC(Read Time-Stamp Counter)指令是Intel x86架构中用于获取处理器时钟周期的一个重要工具,它在检测CPU主频的过程中扮演着关键角色。本文将深入探讨RDTSC指令的应用以及如何利用它来检测CPU的主频。 RDTSC...
在x86和x64架构的处理器中,可以通过RDTSC(Read Time-Stamp Counter)指令来获取TSC的当前值。本篇将详细解释如何使用汇编和C语言获取CPU的当前速度。 首先,让我们探讨RDTSC指令。RDTSC是一个双操作数的CPU指令,...
利用 rdtsc 汇编指令可以得到 CPU 内部定时器的值, 每经过一个 CPU 周期, 这个定时器就加一。 如果在一段时间内数得 CPU 的周期数, CPU工作频率 = 周期数 / 时间 为了不让其他进程和线程打扰, 必需要设置最高的...
KVM RDTSC计时器稳定器该项目旨在稳定并最小化在KVM虚拟机中运行的程序中2个RDTSC调用和vmexit(特别是cpuid)的感知时间差。 您可能需要配置constant_tsc_offset值,默认情况下为1000。 在AMD Ryzen平台上,〜1600...
陷阱RDTSC TrapRDTSC 在 Mac OS X/x86-64 上捕获并模拟rdtsc (读取时间戳计数器)和rdtscp指令。 这在使用 rdtsc 检测外部仪器的逆向工程软件时主要有用。 除了在使用, rdtsc Mac OS X 的 iCloud/Spotlight/...
`rdtsc`(Read Time-Stamp Counter)指令是Intel x86架构处理器提供的一种硬件计时机制,它允许程序员访问处理器内部的时钟周期计数器,从而获取非常精确的执行时间。这个`rdtsc`包装器项目是针对C++编程语言设计的...
RDTSC测试程序
例如,X86架构下的`RDTSC`指令可以用于获取时钟周期,作为随机数生成的基础。 接着,`RANTSR.COM`可能是一个已经编译并链接的可执行文件,它是基于DOS系统的小型程序。在DOS时代,生成随机数通常需要使用BIOS中断,...
概要 使用推测执行的虚拟机监控程序检测 内容 该存储库包含解释基于Meltdown的新虚拟化测试攻击的论文。 它们并不以任何方式广泛,仅提供有限的解释,而不会深入细节。 代码样本 该存储库提供Windows,Linux和macOS...
- **RDTSC指令**:与上述两个方法相比,RDTSC指令能够直接访问CPU的时间戳寄存器,提供更直接且高精度的时间测量方式。这种方法适用于需要极高精度的计时场景,特别是在循环体内的计时需求。 ##### 3. 高精度计时的...
本文档是一篇关于如何在Linux环境下使用RDTSC指令精确测量执行特定C代码时所花费的时钟周期数的白皮书。文档由Gabriele Paoloni撰写,他是Linux内核/嵌入式软件工程师,在Intel公司任职。文档的发布日期是2010年9月...
RDTSC(Read Time Stamp Counter)指令是Intel 80386微处理器提供的一种功能,用于读取CPU的时间戳计数器(Timestamp Counter)。这个计数器在每个时钟周期内都会递增,并在处理器复位时清零。RDTSC指令返回的64位...
幸运的是,如果TSD(Time Stamp Disable)标志未被设置,那么RDTSC指令可以在任何特权级别下执行,而在Windows操作系统中,默认情况下TSD标志是未被设置的。 检测CPU主频的具体实现步骤如下: 1. 使用GetTickCount...
根据提供的文件信息,我们可以深入探讨有关“测试...`gettimeofday()` 和 `rdtsc()` 都是常用的工具,其中 `rdtsc()` 能够提供更高的精度。通过对上下文切换时间的精确测量,可以更好地理解和优化操作系统的性能表现。
### C++精确读取时钟数 在计算机编程领域,特别是...在Windows平台上,`QueryPerformanceCount` 和 `QueryPerformanceFrequency` 是实现高精度计时的理想选择,而对于需要更高精度的应用,可以直接使用 `RDTSC` 指令。
在这些CPU中,有一条机器指令`RDTSC`(Read Time Stamp Counter),用来读取这个时间戳的值,它将时间戳计数器的高32位装入`EDX`寄存器,低32位装入`EAX`寄存器。`RDTSC`指令不被GCC内嵌的汇编器直接支持,可以通过宏...
为了读取TSC中的值,Intel提供了RDTSC指令(Read Time Stamp Counter)。这条指令会将TSC中的值加载到寄存器EDX:EAX中,其中EAX存放低32位,EDX存放高32位。在C++中,可以通过内联汇编的方式调用此指令,具体实现...
在x86架构中,我们可以使用如`rdtsc`这样的特殊指令,它会读取时间和计数器寄存器(Time Stamp Counter)的值,该寄存器在每个时钟周期递增一次。以下是一个简单的示例,展示如何使用`__asm`关键字来实现这一功能: ...
例如,在x86架构的CPU中,我们可以利用8253/8254 PIT( Programmable Interval Timer)或RDTSC(Read Time-Stamp Counter)指令来获取当前时间。8253/8254 PIT是一个可编程的定时器,可以通过设置其计数值来产生周期...