探索Linux中的GEM和KMS技术 (linux gem kms)

Linux操作系统一直以来因为其安全性、稳定性和开放性而备受推崇,特别是在嵌入式领域中占据着重要地位。Linux提供了许多高级技术和框架,其中最重要的是GEM和KMS技术。这两项技术旨在提高Linux图形子系统的性能和能力,本文将从以下几个方面进行探索:GEM和KMS的简介、它们在Linux图形系统中的使用、优点和缺点以及GEM和KMS的使用案例。

一、GEM和KMS的简介

1. GEM(Graphics Execution Manager)

GEM是一个存在于内核中的图形内存管理器,在Linux内核版本2.6.28中被引入,并用于管理图形内存的分配和释放。GEM具有以下特点:

(1)支持全局图形存储器。

(2)使用类似锁的技术来防止内存泄漏。

(3)提供更大化性能支持的同时最小化保留内存的机制。

(4)可以增加内存分配的可重复性。

2. KMS(Kernel Mode Setting)

KMS是另一个内核级别的技术,它主要用于处理显示器和图形卡之间的交互。KMS包括以下几个方面的内容:

(1)一组API来访问和设置显示器和显卡。

(2)硬件独立性,可以支持多种不同的图形硬件,而不需要对其他子系统进行更改。

(3)使用DRM(Direct Rendering Manager)用户空间驱动代码之后,KMS可以为用户提供极高的3D性能。

二、GEM和KMS在Linux中的使用

在现代Linux系统中,GEM和KMS一般都会使用Mesa和DRM子系统进行支持,它们分别装载在用户空间和内核空间。这两个组件共同支持Linux系统中的图形功能,并使得其能够支持多种不同的硬件平台。下面简单介绍一下这两个组件的详情:

1. Mesa

Mesa是一个用于实现OpenGL和其他图形API的开源软件库。它在Linux系统中广泛使用,可以在许多不同的图形GPU架构中实现硬件加速,包括AMD、Intel和Nvidia。Mesa中的DRM组件提供了一些与DRM核心的接口,从而为用户空间中的OpenGL和其他图形API提供了处理操作的途径。Mesa一般被视为Linux系统图形子系统的用户空间组件。

2. DRM(Direct Rendering Manager)

DRM是一个内核模块,在内核中起到许多不同的作用。它提供多种API和接口,使得用户空间的OpenGL和其他图形API能够解决底层图形硬件的问题。DRM的主要功能包括:

(1)使用内核模式设置(KMS)技术,将显示器和GPU之间的连接操作转移到内核中。

(2)提供对图形内存的访问和管理,包括GEM。

(3)实现OpenGL和其他API的硬件加速。

三、GEM和KMS的优缺点

1. GEM的优点

(1)提高内存分配的可重复性。

(2)更大化性能支持的同时最小化保留内存的机制。

(3)提供适当的内存锁来防止内存泄漏。

2. GEM的缺点

(1)难以维护,因为它是比较新的技术。

(2)被认为是Linux系统的核心部分,所以使用该技术可能会增加系统稳定性方面的问题。

(3)没有过多的教程和指南可以使用。

3. KMS的优点

(1)支持纯硬件渲染。

(2)支持多个显示器。

(3)提供DRM后端硬件加速。

4. KMS的缺点

(1)如果使用不当,可能会导致延迟等问题。

(2)需要高质量的软件支持,以确保良好的稳定性。

(3)需要开发人员具有深入的驱动程序知识。

四、GEM和KMS的使用案例

1. Gallium驱动程序

Gallium是一个基于Mesa的驱动程序开发框架,它允许开发者使用Mesa和DRM来实现开源驱动程序。Gallium一般用于高性能的3D渲染,但它也可以用于2D渲染工作。Gallium的主要特点是支持不同的视频输出和GEM内存管理技术。

2. Weston窗口管理器

Weston是一个采用Wayland协议的窗口管理器,它适用于嵌入式系统和桌面环境之间的无缝集成。Weston利用KMS技术来设置显示器和GPU之间的连接,并使用Mesa的DRM组件进行用户空间的相关操作。通过Weston管理器,开发者可以快速实现窗口管理器,并使用Mesa和DRM组件来处理底层GPU操作。

本文通过介绍GEM和KMS技术的基本概念、其在Linux系统中的应用、优缺点以及使用案例,展示了这两个技术的重要性和广泛应用。尽管这两个技术都有其优缺点,但它们在Linux图形子系统中的重要性不用置疑。对于想要在Linux系统上完成高性能图形工作的开发者来说,必须掌握这两项技术的基本知识。

相关问题拓展阅读:

如何调试linux的网络驱动

如何根据oops定位代码行

我们借用linux设备驱动第二篇:构拦枯造和运行模块里面的hello world程序来演示出错的情况,含有错误代码的hello world如下:

#include

#include

MODULE_LICENSE(“Dual BSD/GPL”);

static int hello_init(void)

{

char *p = NULL;

memcpy(p, “test”, 4);

printk(KERN_ALERT “Hello, world\n”);

return 0;

}

static void hello_exit(void)

{

printk(KERN_ALERT “Goodbye, cruel world\n”);

}

module_init(hello_init);

module_exit(hello_exit);

  Makefile文件如下:

ifneq ($(KERNELRELEASE),)

obj-m := helloworld.o

else

KERNELDIR ?= /lib/modules/$(shell uname -r)/build

PWD := $(shell pwd)

default:

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

endif

clean:

rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules.order Module.symvers

  高衡差很明显,以上代码的第8行是一个空戚皮指针错误。inod后会出现下面的oops信息:

BUG: unable to handle kernel NULL pointer dereference at(null)

PGD 0

Oops: 0002 P

Modules linked in: helloworld(OE+) vmw_vsock_vmci_transport vsock coretemp crct10dif_pclmul crc32_pclmul ghash_clmulni_intel aesni_intel vmw_balloon snd_ens1371 aes_x86_64 lrw snd_ac97_codec gf128mul glue_helper ablk_helper cryptd ac97_bus gameport snd_pcm serio_raw snd_seq_midi snd_seq_midi_event snd_rawmidi snd_seq snd_seq_device snd_timer vmwgfx btu ttm snd drm_kms_helper drm soundcore shpchp vmw_vmci i2c_piix4 rfcomm bnep bluetooth 6lowpan_iphc parport_pc ppdev mac_hid lp parport hid_generic uhid hid pouse ahci libahci floppy e1000 vmw_pvscsi vmxnet3 mptspi mptscsih mptbase scsi_transport_spi pata_acpi

CPU: 0 PID: 4531 Comm: inod Tainted: GOE 3.16.0-33-generic #44~14.04.1-Ubuntu

Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 05/20/2023

task: fffff010 ti: ffff880038fa0000 task.ti: ffff880038fa0000

RIP: 0010: hello_init+0xd/0x30

RSP: 0018:ffff880038fa3d40 EFLAGS:

RAX: ffff88000c31d901 RBX: ffffffff81c1a020 RCX:b29f

RDX:b29e RSI:017 RDI: ffffffffc

RBP: ffff880038fa3db8 R08:e80 R09: ffff88003d615e80

R10: ffffea000030c740 R11: ffffffffR12: ffff88000c31d0c0

R13:000 R14: ffffffffcR15: ffffffffc

FS:f8a6fa86740(0000) GS:ffff88003d600000(0000) knlGS:00

CS:DS: 0000 ES: 0000 CR0:033

CR2:000 CR3:000 CR4:7f0

DR0:000 DR1:000 DR2:000

DR3:000 DR6:fffe0ff0 DR7:400

Stack:

ffff880038fa3db8 ffffffff

0001 ffff880028abffff880038fa3da0

ffffffff8119d0b2 ffffffffc00bd1141ac ffffffffc

Call Trace:

? do_one_initcall+0xd4/0x210

? __vunmap+0xb2/0x100

load_module+0x13c1/0x1b80

? store_uevent+0x40/0x40

SyS_finit_module+0x86/0xb0

system_call_fastpath+0x1a/0x1f

Code:ce5 e8 ac1 31

RIP hello_init+0xd/0x30

RSP

CR2:000

——

  

下面简单分析下oops信息的内容。

由BUG: unable to handle kernel NULL pointer dereference at(null)知道出错的原因是使用了空指针。标红的部分确定了具体出错的函数。Modules linked in: helloworld表明了引起oops问题的具体模块。call trace列出了函数的调用信息。这些信息中其中标红的部分是最有用的,我们可以根据其信息找到具体出错的代码行。下面就来说下,如何定位到具体出错的代码行。

之一步我们需要使用objdump把编译生成的bin文件反汇编,我们这里就是helloworld.o,如下命令把反汇编信息保存到err.txt文件中:

objdump helloworld.o -D > err.txt

  err.txt内容如下:

helloworld.o: file format elf64-x86-64

Disassembly of section .text:

00 :

0: ecallq 5

5:push %rbp

6: 48 c7 c mov $0x0,%rdi

d: cmovl $0x,0x0

14:

18: 31 c xor %eax,%eax

1a:e mov %rsp,%rbp

1d: ecallq 22

22: 31 c xor %eax,%eax

24: 5dpop %rbp

25: cretq

26:e 0f 1fnopw %cs:0x0(%rax,%rax,1)

2d:

30 :

30: ecallq 35

35:push %rbp

36: 48 c7 c mov $0x0,%rdi

3d: 31 c xor %eax,%eax

3f:e mov %rsp,%rbp

42: ecallq 47

47: 5dpop %rbp

48: cretq

Disassembly of section .rodata.str1.1:

00 :

0:add %esi,(%rcx)

2:rex.W

3:gs

4: 6cin (%dx),%es:(%rdi)

5: 6cin (%dx),%es:(%rdi)

6: 6foutsl %ds:(%rsi),(%dx)

7: 2csub $0x20,%al

9:f ja 7a

b:c jb

d:a or %fs:(%rax),%al

10:add %esi,(%rcx)

12:f rex.RXB outsl %ds:(%rsi),(%dx)

14: 6foutsl %ds:(%rsi),(%dx)

15:fs

16:(bad)

17:jns 7e

19: 2csub $0x20,%al

1b:movslq 0x75(%rdx),%esi

1e:gs

1f: 6cin (%dx),%es:(%rdi)

20:f and %dh,0x6f(%rdi)

23:c jb

25:a or %fs:(%rax),%al

Disassembly of section .modinfo:

00 :

0: 6cin (%dx),%es:(%rdi)

1:ed imul $0x3d65736e,0x65(%rbx),%esp

8:rex.R jne 6c

b: 6cin (%dx),%es:(%rdi)

c:and %al,0x53(%rdx)

f:f rex.R (bad)

11:rex.RXB push %r8

13: 4crex.WR

Disassembly of section .comment:

00 :

0:add %al,0x43(%rdi)

3:a rex.XB cmp (%r8),%spl

6:sub %dl,0x62(%rbp)

9:e jne

b:je

d:e and %dh,(%rsi,%rbp,1)

10:e cmp %ch,(%rsi)

12:d xor 0x(%rip),%ch#

18:e jne

1a:je

1c:xor %ebp,(%rcx)

1e:e and %dh,(%rsi,%rbp,1)

21:e cmp %ch,(%rsi)

23:xor (%rax),%al

Disassembly of section __mcount_loc:

00 :

  由oops信息我们知道出错的地方是hello_init的地址偏移0xd。而有dump信息知道,hello_init的地址即init_module的地址,因为hello_init即本模块的初始化入口,如果在其他函数中出错,dump信息中就会有相应符号的地址。由此我们得到出错的地址是0xd,下一步我们就可以使用addr2line来定位具体的代码行:

addr2line -C -f -e helloworld.o d

此命令就可以得到行号了。以上就是通过oops信息来定位驱动崩溃的行号。

其他调试手段

以上就是通过oops信息来获取具体的导致崩溃的代码行,这种情况都是用在遇到比较严重的错误导致内核挂掉的情况下使用的,另外比较常用的调试手段就是使用printk来输出打印信息。printk的使用方法类似printf,只是要注意一下打印级别,详细介绍在linux设备驱动第二篇:构造和运行模块中已有描述,另外需要注意的是大量使用printk会严重拖慢系统,所以使用过程中也要注意。

linux 的环境搭建(二)–redis单机环境、生产环境、集群环境的搭建

一、目录

1、工具

2、安装tcl

3、安装单机版redis

4、把redis设置为daemon进程,每次系统启动,redis进程一起启动

5、安装redis cluster

二、工具

2.1、tcl8.6.1-src.tar.gz

2.2、ruby-2.3.1.tar.gz

2.3、redis-4.1.1.gem

2.4、redis-3.2.8.tar.gz

2.5、openssl-1.0.2r.tar.gz

三、安装tcl(安装redis必须先要安装tcl)

3.1、把tcl8.6.1-src.tar.gz通过WinSCP上传到虚拟机中的/usr/local目录下

四、安装单机版redis

4.1、把redis-3.2.8.tar.gz通过WinSCP上传到虚拟机中的/usr/local目录培乎下

4.2、依次运行如下命令:

tar -zxvf redis-3.2.8.tar.gz 解压文件

cd redis-3.2.8

make && make test && make install

五、把redis设置为daemon进程,每次系统启动,redis进程一起启动

5.1、将redis的utils目录下的redis_init_script脚本拷贝到linux的/etc/init.d目录中,将redis_init_script重命名为redis_6379,6379是我们希望这个redis实例监听的端口号

5.2、修改redis_6379脚本的第6行的REDISPORT,设置为相同的端口号(默认就是6379)

protected-mode no 取消保护模式,保护模式只能127.0.0.1访问

daemonize yes 让redis以daemon进程运行

pidfile /var/run/redis_6379.pid 设置redis的pid文件位置

bind2.168.3.110

port 设置redis的监听端口号老中耐

dir/var/redis/设置持久化文件的存储位置

logfile/var/log/redis/6379.log设置日志文件位置

5.6、启动redis,依次执行:

cd /etc/init.d,

chmod 777 redis_6379,赋读写执行的权限(chmod -R 777 * 是递归把该目录下的所有文件和其子文件全部赋权限)

./redis_6379 start 启动

5.7、确认redis进程是否启动,ps -ef | grep redis

5.8、让redis跟随系统启动自动启动

5.9、重启系统,不手动启动redis,直接连接redis,可以连接上,表示配置成功

此时一个单机版的redis的生产环境已经搭建好了,每次服务器重启,redis都会自动的启动

六、安装redis cluster

(redis cluster集群,要求至少3个master,去组成一个高可用,健壮的分布式的集群,每个master都建议侍春至少给一个slave,3个master,3个slave)

6.1、前提,我在其它机器上启动了六个redis(安装步骤都如下)

2.2、创建三个目录:

mkdir -p /etc/redis-cluster 存放集群配置信息,自动生成配置

mkdir -p /var/log/redis redis日志

mkdir -p /var/redis/7001 存放redis的rdb文件和aof文件

6.3、将redis的utils目录下的redis_init_script脚本拷贝到linux的/etc/init.d目录中,将redis_init_script重命名为redis_7001,7001是我们希望这个redis实例监听的端口号,并修改redis_7001配置文件中的REDISPORT=7001

6.4、修改/etc/redis/7001.conf中的部分配置为生产环境

6.5、完成了一个redis环境的配置,依次再配置其余五个,分别为7002、7003、7004、7005、7006,每个启动脚本内,都修改对应的端口号

6.6、启动6个redis实例

6.7、创建集群(需要安装ruby、rubygems)

上述命令在部分机器上是可以直接运行完成,成功安装的,但在部分机器上运行第三条命令时会提示ruby版本太低、openssl找不到的问题,下面依次解决这两个问题:

6.8、再次运行gem install redis命令,报出两个错误

6.9、再次运行gem install redis命令,报出一个错误

6.10、再次运行gem install redis命令,报出一个错误

6.11、再次运行gem install redis命令

# gem install redis

Successfully installed redis-4.1.1

Parsing documentation for redis-4.1.1

Done installing documentation for redis after 1 seconds

WARNING: Unable to pull data from ‘

‘ : SSL_connect returned=1 errno=0 state=error: certificate verify failed (

)

1 gem installed

运行成功

此时Redis安装好,此三个工具也安装好了,这时我们来做一个Redis集群测试,在一台服务器中创建了6个Redis实例,开启6个Redis服务

redis-trib.rb create –replicas 1 192.168.3.104:.168.3.104:.168.3.105:.168.3.105:.168.3.106:.168.3.106:7006

# redis-trib.rb create –replicas 1 192.168.3.104:.168.3.104:.168.3.105:.168.3.105:.168.3.106:.168.3.106:7006

此时一个redis集群环境就已经搭建好了,可以通过redis-trib.rb check 192.168.3.105:7003命令查看集群几点的信息

# redis-trib.rb check 192.168.3.105:7004

redis cluster的优点:读写分离+高可用+多master

读写分离:每个master都有一个slave

高可用:master宕机,slave自动被切换过去

linux gem kms的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux gem kms,探索Linux中的GEM和KMS技术,如何调试linux的网络驱动,linux 的环境搭建(二)–redis单机环境、生产环境、集群环境的搭建的信息别忘了在本站进行查找喔。


数据运维技术 » 探索Linux中的GEM和KMS技术 (linux gem kms)