博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SSE指令使用注意
阅读量:2454 次
发布时间:2019-05-10

本文共 2303 字,大约阅读时间需要 7 分钟。

保存和加载FPU、MMX和XMM寄存器

  从Intel 80486DX开始,FPU(算术浮点单元)被集成到了CPU中,浮点算术功能用ESCAPE指令来执行,操纵CPU中的浮点寄存器集。显然,当一个进程正在使用ESCAPE指令,那么浮点寄存器的内容就属于它的硬件上下文。

  为了加速多媒体程序的执行,Intel在微处理器中引入了新的指令集——MMX,MMX指令也作用于FPU的浮点寄存器。这样,MMX就不能和FPU指令混用,但是OS内核就可以忽略新的MMX指令集,因为保存浮点寄存器的功能代码也能够应用于MMX的状态。

  MMX使用SIMD(单指令多数据)流水线,Pentium III增强了这种SIMD能力,引入SSE(Streaming SIMD Extensions)扩展。该功能增强了8个128位寄存器(XMM寄存器)的功能,这些寄存器不和FPU/MMX寄存器重叠,因此能够与FPU/MMX指令混用。

  Pentium IV还引入了SSE2扩展,支持高精度浮点值,SSE2和SSE使用同一个XMM寄存器组。

  80x86微处理器不在TSS中保存FPU、MMX和XMM寄存器的值,不过还是提供了一些支持,能够在需要时保存它们。cr0寄存器有一个TS(Task-Switching)标志位,每当执行硬件上下文切换时,TS置位,每当TS被置位后进程执行ESCAPE、MMX、SSE或SSE2指令,控制器就产生一个“Device not available”异常。这样,TS标志位就能够让OS内核只有在真正需要时才保存或恢复FPU、MMX和XMM寄存器。

  假设进程A使用了数学协处理器,那么当进程A被切换出去的时候,内核设置TS并将浮点寄存器的内容保存到进程A的TSS中(原著这么写,但是应该是保存到进程A描述符的一个字段中,TSS是与CPU关联的,进程没有TSS)。

  如果新进程B不使用数学协处理器,那么内核就不需要恢复浮点寄存器的内容,但是,一旦进程B执行FPU、MMX等指令,CPU就产生一个“Device not available”异常,相应的异常处理程序就会用保存在进程B中的相关值来恢复浮点寄存器。

  处理FPU、MMX和XMM寄存器的数据结构存放在进程描述符的thread字段的i387子字段中(即thread.i387),由i387_union联合体描述,其格式如下:

union i387_union {
        
struct i387_fsave_struct    fsave; /* 保存FPU、MMX寄存器的内容 */
        
struct i387_fxsave_struct   fxsave;/* 保存SSE和SSE2寄存器内容 */
        
struct i387_soft_struct     soft;  /* 由无数学协处理器的老式CPU模型使用 */
    };

  此外,进程描述符中还包含了两个附加的标志:

  • thread_info结构中status字段的TS_USEDFPU标志,表示进程当前执行过程中是否使用过FPU、MMX和XMM寄存器。
  • task_struct结构的flags字段的PF_USED_MATH标志,表示thread.i387的内容是否有意义。

  保存和加载FPU、MMX和XMM寄存器主要用到__unlazy_fpu宏,该宏在__switch_to函数中使用,下一篇会对其进行分析。

 

内核态使用FPU、MMX和XMM寄存器

  OS内核也可以使用FPU、MMX和XMM寄存器,当然,这么做的时候应该避免干扰用户态进程。因此,Linux使用如下方法来解决:

  • 在内核使用协处理器之前,如果用户态进程使用了FPU(TS_USEDFPU标志为1),内核就要调用kernel_fpu_begin()函数,该函数里又调用save_init_fpu()来保存寄存器内容,然后重新设置cr0寄存器的TS标志。
  • 使用完协处理器之后,内核调用kernel_fpu_end宏设置cr0寄存器的TS标志。
  • 当用户态进程恢复执行时,math_state_restore()函数将恢复FPU、MMX和XMM寄存器的内容。

  需要注意的是,如果当前用户态进程有在用数学协处理器时,kernel_fpu_begin()函数的执行时间比较长,甚至无法通过FPU、MMX或XMM达到加速的目的。因此,内核只在有限的场合使用FPU、MMX或XMM指令,比如移动或清除大内存区字段、计算校验和等。

 转自:http://www.cnblogs.com/wz19860913/archive/2010/05/25/1742583.html

sse memcpy in linux kernel:
 
The SYSTEM_RUNNING check is to take care of early boot situations wherewe can't handle FPU exceptions but we use memcpy. There's an aligned andmisaligned variant which should handle any buffers and sizes althoughI've set the SSE memcpy threshold at 512 Bytes buffersize the least tocover context save/restore somewhat.
来自:https://lkml.org/lkml/2011/8/14/19

你可能感兴趣的文章
Java类类getMethod()方法及示例
查看>>
Java IdentityHashMap clone()方法与示例
查看>>
java timezone_Java TimeZone hasSameRules()方法与示例
查看>>
PHP Superglobals能力倾向问题与解答
查看>>
密码学,把字母转换为数字_密码学转换技术
查看>>
JavaScript中的数据单元转换工具
查看>>
Java BigInteger类| 带示例的testBit()方法
查看>>
duration java_Java Duration类| plusHours()方法与示例
查看>>
非确定性算法_确定性和非确定性算法
查看>>
stl中map函数_带有示例的C ++ STL中的map :: size()函数
查看>>
Java DataOutputStream flush()方法与示例
查看>>
Java LinkedHashMap entrySet()方法与示例
查看>>
java 根据类名示例化类_Java即时类| minusMillis()方法与示例
查看>>
Java LocalDate类| plusWeeks()方法与示例
查看>>
Java FilterInputStream close()方法与示例
查看>>
Java RandomAccessFile readChar()方法及示例
查看>>
python xor_Python XOR和数组| 竞争编码问题
查看>>
mcq 队列_MCQ | 软件工程基础知识/简介(1)
查看>>
c# 命名空间命名规范_C#命名空间能力问题和解答 套装3
查看>>
c ++查找字符串_C ++类和对象| 查找输出程序| 套装3
查看>>