一个panic问题引起对percpu变量的思考

1 问题引入

最近在分析一个panic问题时,发现panic现场无法与log对应起来。

先贴log:

<1>[  180.089084] Unable to handle kernel NULL pointer dereference at virtual address 00000001
<1>[  180.099551] pgd = 8bbde651
<1>[  180.107775] Unable to handle kernel NULL pointer dereference at virtual address 00000001
<1>[  180.108527] [00000001] *pgd=45636835, *pte=00000000, *ppte=00000000
<1>[  180.121525] pgd = 8bbde651
<1>[  180.135901] [00000001] *pgd=45636835, *pte=00000000, *ppte=00000000
<0>[  180.136405] Internal error: Oops: 17 [#1] PREEMPT SMP THUMB2
<0>[  180.147836] Modules linked in: cw221x(O) dwc3 sdhci_axera dwc3_axera spi_axera_module [last unloaded: kspi]
<0>[  180.157597] CPU: 1 PID: 124 Comm: qs_sleep Tainted: G           O      4.19.125 #2
<0>[  180.165167] Hardware name: Axera_chip (Device Tree)
<0>[  180.170059] PC is at kmem_cache_alloc+0x80/0xd4
<0>[  180.174592] LR is at kmem_cache_alloc+0x15/0xd4
<0>[  180.179124] pc : [<c0084f50>]    lr : [<c0084ee5>]    psr: 60000033
<0>[  180.185393] sp : c56cfde0  ip : c5bda108  fp : 00000000
<0>[  180.190619] r10: 00000000  r9 : c5c6b420  r8 : 0001ed1c
<0>[  180.195845] r7 : ffffe000  r6 : c00c29fd  r5 : 006000c0  r4 : c6001e40
<0>[  180.202374] r3 : 00000001  r2 : 00000000  r1 : 0001ed1c  r0 : 00000000
<0>[  180.208906] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA Thumb  Segment user
<0>[  180.216217] Control: 50c5383d  Table: 45bc806a  DAC: 00000055
<0>[  180.221967] Process qs_sleep (pid: 124, stack limit = 0x51827165)
<0>[  180.228063] Stack: (0xc56cfde0 to 0xc56d0000)
<0>[  180.232425] fde0: c049f8fc c53bc980 00000000 c612bd80 c0372ac8 c55fbe40 c5c6b420 c00c29fd
<0>[  180.240608] fe00: c5c6b420 c049f8fc 00000000 c55fbe40 00000000 c5c6b500 c5c6b420 c00c285f
<0>[  180.248790] fe20: c55fbe48 00000000 00000000 c0087393 c5c79a18 c56cfed0 00000000 c55fbe40
<0>[  180.256973] fe40: c5c6b420 00000000 00000000 c0092759 c5b81978 00000001 c56cff74 00000002
<0>[  180.265156] fe60: 00000000 00000041 c5c79908 000041ed 00000000 00000006 00000000 c56cfed8
<0>[  180.273338] fe80: 00000000 ffffe000 c6094400 00000000 c5c6b420 c5b96610 c5c79a18 00010001
<0>[  180.281520] fea0: c56cfea0 c56cfea0 0000001d 00000033 c56cff74 00000001 c6247000 c00091e4
<0>[  180.289703] fec0: c56ce000 00000005 0000000a c009285b c5b96610 c5c79a18 7d11879d 00000009
<0>[  180.297886] fee0: c624701b c025690d c6006e10 c5c02aa0 c5c6b420 00000101 00000000 00000048
<0>[  180.306069] ff00: 00000000 00000000 00000000 c56cff10 c043feb3 c048d5de c05882c0 c61d89c8
<0>[  180.314251] ff20: c043feb3 00000033 c5123a00 c5b96f00 c5b96f40 c036611f 00000000 c009ac05
<0>[  180.322434] ff40: c6247000 00000000 00000002 00000002 ffffff9c c00091e4 00000033 00000002
<0>[  180.330616] ff60: ffffff9c c0087f57 00000000 00000000 c61d89c1 00000002 00000000 00000006
<0>[  180.338797] ff80: 00000100 00000001 00000000 00000000 00000002 b67bbda8 00000005 c00091e4
<0>[  180.346979] ffa0: c56ce000 c0009001 00000000 00000002 007c4ff8 00000002 00000000 00000001
<0>[  180.355161] ffc0: 00000000 00000002 b67bbda8 00000005 00000005 005228ac 00000032 0000000a
<0>[  180.363343] ffe0: 00000000 b67bbda8 b6dcfe33 b6dcfe46 80000030 007c4ff8 00000000 00000000
<0>[  180.371542] [<c0084f50>] (kmem_cache_alloc) from [<c00c29fd>] (kernfs_fop_open+0x19f/0x23a)
<0>[  180.379902] [<c00c29fd>] (kernfs_fop_open) from [<c0087393>] (do_dentry_open+0x1f3/0x260)
<0>[  180.388088] [<c0087393>] (do_dentry_open) from [<c0092759>] (path_openat+0x7d7/0x8ba)
<0>[  180.395927] [<c0092759>] (path_openat) from [<c009285b>] (do_filp_open+0x1f/0x50)
<0>[  180.403416] [<c009285b>] (do_filp_open) from [<c0087f57>] (do_sys_open+0xd3/0x140)
<0>[  180.410993] [<c0087f57>] (do_sys_open) from [<c0009001>] (ret_fast_syscall+0x1/0x5a)
<0>[  180.418737] Exception stack(0xc56cffa8 to 0xc56cfff0)
<0>[  180.423792] ffa0:                   00000000 00000002 007c4ff8 00000002 00000000 00000001
<0>[  180.431973] ffc0: 00000000 00000002 b67bbda8 00000005 00000005 005228ac 00000032 0000000a
<0>[  180.440153] ffe0: 00000000 b67bbda8 b6dcfe33 b6dcfe46
<0>[  180.445211] Code: 4618 e8bd 83f8 6962 (f853) e002
<0>[  180.450008] Internal error: Oops: 17 [#2] PREEMPT SMP THUMB2
<0>[  180.455673] Modules linked in: cw221x(O) dwc3 sdhci_axera dwc3_axera spi_axera_module [last unloaded: kspi]
<4>[  180.456034] ---[ end trace 4fe5cd369560c84c ]---
<0>[  180.465435] CPU: 0 PID: 165 Comm: encoder Tainted: G      D    O      4.19.125 #2
<0>[  180.465438] Hardware name: Axera_chip (Device Tree)
<0>[  180.465455] PC is at kmem_cache_alloc+0x80/0xd4
<0>[  180.465461] LR is at kmem_cache_alloc+0x15/0xd4
<0>[  180.465465] pc : [<c0084f50>]    lr : [<c0084ee5>]    psr: 60000033
<0>[  180.465470] sp : c53bfe68  ip : 60000013  fp : 00000000
<0>[  180.465474] r10: c55fb840  r9 : 00001000  r8 : 0001ed24
<0>[  180.465479] r7 : ffffe000  r6 : c00fd299  r5 : 006000c0  r4 : c6001e40
<0>[  180.465484] r3 : 00000001  r2 : 00000000  r1 : 0001ed24  r0 : 00000000
<0>[  180.465489] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA Thumb  Segment user
<0>[  180.465494] Control: 50c5383d  Table: 45bc806a  DAC: 00000055
<0>[  180.465501] Process encoder (pid: 165, stack limit = 0xb65c0d9e)
<0>[  180.465506] Stack: (0xc53bfe68 to 0xc53c0000)
<0>[  180.465514] fe60:                   c049f8fc 00000000 00000000 c5bda120 c5bda108 00fa24a0
<0>[  180.465522] fe80: 00001000 c00fd299 c00fd44d c5bda108 c5bda108 c5bda120 00000000 c00fd457
<0>[  180.470413] Kernel panic - not syncing: Fatal exception
<0>[  180.477620] fea0: c5bda108 c53bff88 00000000 c009e7c7 c5bda120 c5bda138 c6246000 c00091e4
<0>[  180.574453] fec0: c53be000 c62b8080 c009e70f 00000001 00000000 00001000 c53bff88 00000003
<0>[  180.582636] fee0: 00000000 c00b8a55 c53bff88 c55fb840 c036ff00 c00b8a17 c53bff88 c0089839
<0>[  180.590818] ff00: 00000000 00000000 00000001 c00ae3f1 c00b8901 b26e0d7c c5c6e028 c55fb840
<0>[  180.599000] ff20: 00000034 c0093ac9 0000541b c009402f 00000000 00000000 00000000 c55fb840
<0>[  180.607183] ff40: c55fb843 00001000 c55fb840 00000000 00001000 00000001 00fa24a0 c0089939
<0>[  180.615366] ff60: c55fb840 00fa24a0 00001000 c55fb840 c55fb843 00fa24a0 00001000 c00091e4
<0>[  180.623549] ff80: c53be000 c0089c71 00000000 00000000 00001000 00000034 00000000 b26e0d88
<0>[  180.631732] ffa0: 00000003 c0009001 00000034 00000000 00000034 00fa24a0 00001000 00000003
<0>[  180.639915] ffc0: 00000034 00000000 b26e0d88 00000003 b26e0ea4 004034ac be96d69c 00000000
<0>[  180.648097] ffe0: 0080761c b26e0d88 b6dd155f b6dd1516 00000030 00000034 00000000 00000000
<0>[  180.656293] [<c0084f50>] (kmem_cache_alloc) from [<c00fd299>] (disk_seqf_start+0x13/0x5a)
<0>[  180.664480] [<c00fd299>] (disk_seqf_start) from [<c00fd457>] (show_partition_start+0xb/0x2c)
<0>[  180.672928] [<c00fd457>] (show_partition_start) from [<c009e7c7>] (seq_read+0xb9/0x27a)
<0>[  180.680942] [<c009e7c7>] (seq_read) from [<c00b8a55>] (proc_reg_read+0x3f/0x5e)
<0>[  180.688261] [<c00b8a55>] (proc_reg_read) from [<c0089839>] (__vfs_read+0x15/0xc2)
<0>[  180.695751] [<c0089839>] (__vfs_read) from [<c0089939>] (vfs_read+0x53/0xb6)
<0>[  180.702806] [<c0089939>] (vfs_read) from [<c0089c71>] (ksys_read+0x2d/0x64)
<0>[  180.709775] [<c0089c71>] (ksys_read) from [<c0009001>] (ret_fast_syscall+0x1/0x5a)
<0>[  180.717346] Exception stack(0xc53bffa8 to 0xc53bfff0)
<0>[  180.722401] ffa0:                   00000034 00000000 00000034 00fa24a0 00001000 00000003
<0>[  180.730583] ffc0: 00000034 00000000 b26e0d88 00000003 b26e0ea4 004034ac be96d69c 00000000
<0>[  180.738764] ffe0: 0080761c b26e0d88 b6dd155f b6dd1516
<0>[  180.743822] Code: 4618 e8bd 83f8 6962 (f853) e002
<2>[  180.748618] CPU0: stopping

Log中CPU 0和CPU 1均发生了,出错误的位置均是:kmem_cache_alloc+0x80,对应的汇编:

ZST:0076::C0084F50|F853E002 ldr r14,[r3,r2]

CPU 1寄存器值:
<0>[  180.202374] r3 : 00000001  r2 : 00000000  r1 : 0001ed1c  r0 : 00000000 

CPU 0寄存器值:

<0>[  180.465484] r3 : 00000001  r2 : 00000000  r1 : 0001ed24  r0 : 00000000

r2、r3寄存器值一致,从r3+r2地址加载数据到r14, r3+r2=0x1,访问了0x1地址,这与log:

Unable to handle kernel NULL pointer dereference at virtual address 00000001

能对应上。

接下来分析出错时的函数调用栈:

-000|freelist_dereference(inline)
-000|get_freepointer(inline)
-000|get_freepointer_safe(inline)
-000|slab_alloc_node(inline)
    |  object = 0x1
-000|slab_alloc(inline)
-000|kmem_cache_alloc(s = 0xC6001E40, gfpflags = 6291648)
    |  s = 0xC6001E40
    |  gfpflags = 6291648
-001|kmalloc(inline)
-001|kernfs_get_open_node(inline)
    |  on = 0x0
    |  new_on = 0x0
-001|kernfs_fop_open(inode = 0xC5C6B420, file = 0xC55FBE40)
    |  inode = 0xC5C6B420
    |  file = 0xC55FBE40
    |  kn = 0xC612BD80
    |  __key = ()
    |  __key = ()
    |  __key = ()
-002|do_dentry_open(f = 0xC55FBE40, inode = 0xC5C6B420, open = 0xC00C285F)
    |  f = 0xC55FBE40
    |  inode = 0xC5C6B420
    |  open = 0xC00C285F
    |  empty_fops = (owner = 0x0, llseek = 0x0, read = 0x0, write = 0x0, read_iter = 0x0, write_iter = 0x0, iterate = 0x0, iterate_shared = 0x0, poll = 0x0, unlocked_ioctl = 0x0, compat_ioctl = 0x0, mmap = 0x0, mmap_supported_flags = 0, open = 0x0, flush = 0x0, release = 0x0, fsync = 0x0, fasync = 0x0, lock = 0x0, sendpage = 0x0, get_unmapped_area = 0x0, check_flags = 0x0, flock = 0x0, splice_write = 0x0, splice_read = 0x0, setlease = 0x0, fallocate = 0x0, show_fdinfo = 0x0, copy_file_range = 0x0, clone_file_range = 0x0, dedupe_file_range = 0x0, fadvise = 0x0)
    |  error = 0
    |  __warned = FALSE
-002|vfs_open(tailcall)
-003|do_last(inline)
    |  will_truncate = FALSE
    |  got_write = FALSE
    |  seq = 0
    |  inode = 0xC5C6B420
    |  path = (mnt = 0xC5B96610, dentry = 0xC5C79A18)
-003|path_openat(nd = 0xC56CFED0, op = ?, flags = ?)
    |  nd = 0xC56CFED0
    |  file = 0xC55FBE40
    |  error = 0
-004|do_filp_open(dfd = ?, pathname = ?, op = 0xC56CFF74)
    |  op = 0xC56CFF74
    |  nd = (path = (mnt = 0xC5B96610, dentry = 0xC5C79A18), last = (hash = 2098300829, len = 9, hash_len = 40753006493, name = 0xC624701B), root = (mnt = 0xC6006E10, dentry = 0xC5C02AA0), inode = 0xC5C6B420, flags = 257, seq = 0, m_seq = 72, last_type = 0, depth = 0, total_link_count = 0, stack = 0xC56CFF10, internal = ((link = (mnt = 0xC043FEB3, dentry = 0xC048D5DE), done = (fn = 0xC05882C0, arg = 0xC61D89C8), name = 0xC043FEB3, seq = 51), (link = (mnt = 0xC5123A00, dentry = 0xC5B96F00), done = (fn = 0xC5B96F40, arg = 0xC036611F), name = 0x0, seq = 3221859333)), name = 0xC6247000, saved = 0x0, link_inode = 0x2, root_seq = 2, dfd = -100)
    |  flags = 1
    |  filp = 0x33
-005|do_sys_open(dfd = -100, filename = ?, flags = 2, mode = ?)
    |  dfd = -100
    |  flags = 2
    |  op = (open_flag = 2, mode = 0, acc_mode = 6, intent = 256, lookup_flags = 1)
    |  fd = 51
    |  tmp = 0xC6247000
    |  f = ???
-006|__entry_text_start(asm)
 ---|end of frame

通过分析发现,kmalloc函数中调用kmem_cache_alloc_trace是一个关键突破口:

static __always_inline void *kmalloc(size_t size, gfp_t flags)
{
	if (__builtin_constant_p(size)) {
		if (size > KMALLOC_MAX_CACHE_SIZE)
			return kmalloc_large(size, flags);
#ifndef CONFIG_SLOB
		if (!(flags & GFP_DMA)) {
			unsigned int index = kmalloc_index(size);

			if (!index)
				return ZERO_SIZE_PTR;

			return kmem_cache_alloc_trace(kmalloc_caches[index],
					flags, size);
		}
#endif
	}
	return __kmalloc(size, flags);
}

在第13行:kmem_cache_alloc_trace(kmalloc_caches[index],可知传递给kmem_cache_alloc_trace函数的第一个参数是kmalloc_caches[index],根据调用栈的第8行:

s = 0xC6001E40,查看kmalloc_caches数组值:

  kmalloc_caches = (
    0x0,
    0x0,
    0xC6001CC0,
    0x0,
    0x0,
    0x0,
    0xC6001E40,
    0xC6001D80,
    0xC6001C00,
    0xC6001B40,
    0xC6001A80,
    0xC60019C0,
    0xC6001900,
    0xC6001840)

可知,index=6,对应kmalloc申请的size为2^6=64字节。

再回到PC指针位置,对应出错的代码应该是第2683行:


这里object的取到的object值为0x1, 而object的值是在第2677行获取到的,而c值是通过第2656行:

c = raw_cpu_ptr(s->cpu_slab);

获取到的,那么object实际就是kmalloc_caches[6].cpu_slab->freelist,但查看kmalloc_caches[6].cpu_slab->freelist的值为0,并不是1:

  kmalloc_caches = (
    0x0,
    0x0,
    0xC6001CC0,
    0x0,
    0x0,
    0x0,
    0xC6001E40 -> (
      cpu_slab = 0xC0530BF0 -> (
        freelist_=_0x0,
        tid = 0,
        page = 0x0),
      flags = 0,

2 问题出在哪里

注意到kmalloc_caches数组的类型为:struct kmem_cache,其定义如下:

struct kmem_cache {
	struct kmem_cache_cpu __percpu *cpu_slab;
	/* Used for retriving partial slabs etc */
	slab_flags_t flags;
	unsigned long min_partial;
	unsigned int size;	/* The size of an object including meta data */
	unsigned int object_size;/* The size of an object without meta data */
	unsigned int offset;	/* Free pointer offset. */
#ifdef CONFIG_SLUB_CPU_PARTIAL
	/* Number of per cpu partial objects to keep around */
	unsigned int cpu_partial;
#endif
	struct kmem_cache_order_objects oo;

	/* Allocation and freeing of slabs */
	struct kmem_cache_order_objects max;
	struct kmem_cache_order_objects min;
	gfp_t allocflags;	/* gfp flags to use on each alloc */
	int refcount;		/* Refcount for slab cache destroy */
	void (*ctor)(void *);
	unsigned int inuse;		/* Offset to metadata */
	unsigned int align;		/* Alignment */
	unsigned int red_left_pad;	/* Left redzone padding size */
	const char *name;	/* Name (only for display!) */
	struct list_head list;	/* List of slab caches */
#ifdef CONFIG_SYSFS
	struct kobject kobj;	/* For sysfs */
	struct work_struct kobj_remove_work;
#endif
#ifdef CONFIG_MEMCG
	struct memcg_cache_params memcg_params;
	/* for propagation, maximum size of a stored attr */
	unsigned int max_attr_size;
#ifdef CONFIG_SYSFS
	struct kset *memcg_kset;
#endif
#endif

#ifdef CONFIG_SLAB_FREELIST_HARDENED
	unsigned long random;
#endif

#ifdef CONFIG_NUMA
	/*
	 * Defragmentation by allocating from a remote node.
	 */
	unsigned int remote_node_defrag_ratio;
#endif

#ifdef CONFIG_SLAB_FREELIST_RANDOM
	unsigned int *random_seq;
#endif

#ifdef CONFIG_KASAN
	struct kasan_cache kasan_info;
#endif

	unsigned int useroffset;	/* Usercopy region offset */
	unsigned int usersize;		/* Usercopy region size */

	struct kmem_cache_node *node[MAX_NUMNODES];
};

其中cpu_slab是__percpu类型的,这正是前面分析出错的原因所在。

3 percpu变量的实现

        percpu变量是一项内核特性,创建一个percpu变量后每个CPU上都会有一个此变量的副本,CPU在访问其副本时无需加锁,可以放入自己的cache中,极大地提高了访问与更新效率。

3.1 percpu变量的定义

内核提供了DEFINE_PER_CPU宏来定义percpu变量,其定义如下:

#define DEFINE_PER_CPU(type, name)					\
	DEFINE_PER_CPU_SECTION(type, name, "")

 DEFINE_PER_CPU_SECTION、__PCPU_ATTRS和PER_CPU_BASE_SECTION的定义如下:

#define PER_CPU_BASE_SECTION ".data..percpu"

#define __PCPU_ATTRS(sec)						\
	__percpu __attribute__((section(PER_CPU_BASE_SECTION sec)))	\
	PER_CPU_ATTRIBUTES

#define DEFINE_PER_CPU_SECTION(type, name, sec)				\
	__PCPU_ATTRS(sec) PER_CPU_DEF_ATTRIBUTES			\
	__typeof__(type) name
#endif

#ifndef PER_CPU_ATTRIBUTES
#define PER_CPU_ATTRIBUTES
#endif

#ifndef PER_CPU_DEF_ATTRIBUTES
#define PER_CPU_DEF_ATTRIBUTES
#endif

 DEFINE_PER_CPU宏展开后就是这样的:

	__percpu __attribute__((section(".data..percpu" sec)))			\
	__typeof__(type) name

举例来说,通过DEFINE_PER_CPU(int, per_cpu_n)定义变量per_cpu_n,展开后是这样的:

	__percpu __attribute__((section(".data..percpu" sec))) int per_cpu_n

这与 struct kmem_cache结构体的cpu_slab成员的定义:

struct kmem_cache_cpu __percpu *cpu_slab;

类似。

percpu变量的实现较为复杂,建议参考这篇文章做详细了解。

3.2 percpu变量的访问

1个percpu变量NR_CPUS+1个实体(比较浪费空间),其中NR_CPUS个是每个CPU的副本,CPU在访问时都直接访问自己的副本。仍然以:

DEFINE_PER_CPU(int, per_cpu_n);

为例,加入NR_CPUS为2,那么定义了一个:

int per_cpu_n; //为方便,我们称其为正本

变量,以及两个CPU副本:

int per_cpu_n; //副本0

int per_cpu_n; //副本1

CPU0和CPU1在访问per_cpu_n时分别访问自己的副本,而正本却没有谁去访问!

现在回到我们前面的问题,我们访问kmalloc_caches[6].cpu_slab时,实际是访问了正本,而非副本,但恰恰正本是没有谁在使用的,所以我们看到其成员值都为0。

现在问题来了,CPU副本是如何访问的呢?其实很简单,linux内核提供了一个__per_cpu_offset[NR_CPUS]数组,数组中保存了percpu变量对应的offset值,访问时通过该offset值+正本地址,得到的就是其副本的地址。比如per_cpu_n 对应CPU0的副本地址是:

__per_cpu_offset[0] + per_cpu_n

回到我们前面的panic问题,查看__per_cpu_offset值:

  __per_cpu_offset = (
    0x0624B000,
    0x0625D000)

CPU 0对应的cpu_slab地址为:

0xC0530BF0 + 0x0624B000 = 0xC678BBF0

 转换成kmem_cache_cpu结构:


(struct kmem_cache_cpu*)0xc677bbf0 = 0xC677BBF0 -> (
    freelist = 0x1,
    tid = 0x0001ED30,
    page = 0xC685E5E0)

CPU 1对应的cpu_slab地址为:

0xC0530BF0 + 0x0625D000 = 0xC678DBF0

转换成kmem_cache_cpu结构:

(struct kmem_cache_cpu*)0xC678DBF0 = 0xC678DBF0 -> (
    freelist = 0xC4421740,
    tid = 29805,
    page = 0xC683F420)

这里CPU 0的 cpu_slab->freelist为1,与panic现场一致。但CPU 1的cpu_slab->freelist为0xC4421740,并不为1。这是为何?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/627285.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript进阶——05-迭代器和生成器【万字长文,感谢支持】

迭代器 概念 迭代器&#xff08;Iterator&#xff09;是 JavaScript 中一种特殊的对象&#xff0c;它提供了一种统一的、通用的方式遍历个各种不同类型的数据结构。可以遍历的数据结构包括&#xff1a;数组、字符串、Set、Map 等可迭代对象。我们也可以自定义实现迭代器&…

Python GUI开发- Qt Designer环境搭建

前言 Qt Designer是PyQt5 程序UI界面的实现工具&#xff0c;使用 Qt Designer 可以拖拽、点击完成GUI界面设计&#xff0c;并且设计完成的 .ui 程序可以转换成 .py 文件供 python 程序调用 环境准备 使用pip安装 pip install pyqt5-toolsQt Designer 环境搭建 在pip安装包…

AI办公自动化:用kimi批量把word转换成txt文本

在Kimichat中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个Python脚本编写的任务&#xff0c;具体步骤如下&#xff1a; 打开文件夹&#xff1a;F:\aword 读取里面docx格式的word文档&#xff0c; 提取word文档中的第一行文字作为txt文本文档的标题…

(done) NLP+HMM 协作,还有维特比算法

参考视频&#xff1a;https://www.bilibili.com/video/BV1aP4y147gA/?p2&spm_id_frompageDriver&vd_source7a1a0bc74158c6993c7355c5490fc600 &#xff08;这实际上是 “序列标注任务”&#xff09; HMM 的训练和预测如下图 训练过程&#xff1a;我们首先先给出一个语…

HSP_06章-1_Python_数据容器

文章目录 P76 数据容器1. 概述2. 分类 P77 列表ListP77-78 列表List的注意事项和使用细节P80 列表List的常用方法一览1. 列表生成式 P80_82 元组Tuple1. 元组的使用细节和注意事项 P83 元组的常用操作 P76 数据容器 1. 概述 1、数据容器是一种数据类型&#xff0c;有些地方也…

机器学习笔记 PostgresML教程:使用SQL进行机器学习

机器学习的基本做法是将数据转移到模型的环境中进行训练。由于今天的数据库比机器学习模型大好多个数量级,所以PostgresML的思路是,如果我们将模型引入数据集不是会容易得多吗? PostgresML 是一个建立在流行的 PostgreSQL 数据库之上的综合机器学习平台。它引入了一种称为“…

股指期货的交割日是哪一天?

股指期货的交割日&#xff0c;就好比是期货合约的“期末考试”。每个月的第三周的周五&#xff0c;就是股指期货的交割日。在这一天&#xff0c;如果你持有的期货合约还没有卖出&#xff08;平仓&#xff09;&#xff0c;那么就会按照一个特定的价格&#xff08;结算价&#xf…

学习MySQL(三):数据类型约束条件

数据类型 字符串&#xff1a;char(num) 与 varchar(num) 延申面试问题&#xff1a;char与varchar有什么区别&#xff1f; 区别1&#xff1a;定长与变长 char 固定长度&#xff0c;例如定义了char(8)&#xff0c;则这一列存储的内容长度都为8&#xff0c;不足8位则会用空格补…

二分答案(区间范围)

D. Jumping Through Segments 输入数据 4 5 1 5 3 4 5 6 8 10 0 1 3 0 2 0 1 0 3 3 3 8 10 18 6 11 4 10 20 0 5 15 17 2 2 输出范围 7 0 5 13#include<bits/stdc.h> #define int long long using namespace std; typedef pair<char,int>PII; const int N2e510;…

Java线程生命周期:Java线程生命周期全景解读

1. 线程生命周期概述&#xff1a;不仅仅是状态转换 在多线程编程中&#xff0c;理解线程的生命周期对于编写有效、高效的代码至关重要。线程生命周期通常描述了线程从创建到死亡的一系列状态变化过程&#xff0c;但其实不仅仅局限于这些状态的简单转换。线程生命周期的理解应该…

如何在云电脑实现虚拟应用—数据分层(应用分层)技术简介

如何在云电脑实现虚拟应用—数据分层&#xff08;应用分层&#xff09;技术简介 近几年虚拟化市场实现了非常大的发展&#xff0c;桌面虚拟化在企业中应用越来越广泛&#xff0c;其拥有的如下优点得到大量企业的青睐&#xff1a; 数据安全不落地。在虚拟化环境下面数据保存在…

网络安全快速入门(十)MySQL拓展操作

10.1.0前言 前面我们已经对用户操作以及库&#xff0c;表操作有了基础的认识&#xff0c;接下来我们来在之前已经学过的一些操作进行进一步拓展&#xff0c;本章我们主要了解以下几个知识点&#xff1a; 数据库设计方法视图存储过程事务 我们开始本章的内容吧 10.2 数据库设计方…

Java代理模式的实现详解

一、前言 1.1、说明 本文章是在学习mybatis框架源码的过程中&#xff0c;发现对于动态代理Mapper接口这一块的代理实现还是有些遗忘和陌生&#xff0c;因此在本文章中就Java实现代理模式的过程进行一个学习和总结。 1.2、参考文章 《设计模式》&#xff08;第2版&#xff0…

阿里云服务器下,部署LNMP环境安装wordpress

目录 1 LNMP部署1、简单说明2、nginx部署3、php8 安装4、mysql8安装5、配置 nginx 实现支持 PHP 程序6、安装 php 组件7、测试 2 wordpress部署1、安装2、配置 总结 1 LNMP部署 1、简单说明 首先需要明白&#xff0c;LNMP指的是Linux、Nginx、MySQL、PHP。而如果使用阿里云服…

代码随想录—— 填充每个节点的下一个右侧节点指针(Leetcode116)

题目链接 层序遍历 /* // Definition for a Node. class Node {public int val;public Node left;public Node right;public Node next;public Node() {}public Node(int _val) {val _val;}public Node(int _val, Node _left, Node _right, Node _next) {val _val;left _…

视频提取动图怎么制作?一个方法将视频转换gif

现在这个日益发展的科技社会&#xff0c;视频作为我们广泛应用的一种媒体形式&#xff0c;在各个领域都扮演着重要的角色。视频凭着丰富生动的内容成为传递信息的媒介。但是视频的体积也是比较大的&#xff0c;在使用的过程中会受到各种各样的限制。这个时候就可以使用gif在线制…

根据Word文档用剪映批量自动生成视频发布抖音

手头有大量word文档&#xff0c;想通过剪映的AI图文成片功能批量生成视频&#xff0c;发布到抖音平台&#xff0c;简单3步即可&#xff1a; 第一步&#xff1a;把word文档或者PDF等文档转成txt文本&#xff0c;可以用一些软件&#xff0c;也可以用AI工具&#xff0c;具体常见文…

LLM Agent智能体综述(超详细)

前言 &#x1f3c6;&#x1f3c6;&#x1f3c6;在上一篇文章中&#xff0c;我们介绍了如何部署MetaGPT到本地&#xff0c;获取OpenAI API Key并配置其开发环境&#xff0c;并通过一个开发小组的多Agent案例感受了智能体的强大&#xff0c;在本文中&#xff0c;我们将对AI Agent…

《灵摆疗法》PDF完整版阅读

译者序 神奇丶快速又有效的灵摆疗法 2008年当我开始走上自己的灵性道路时就与灵摆结下了不解之缘当时我非常热衷于水晶疗愈所以疯狂地搜集各种不同的矿石学习如何将矿石 和水晶灵摆连结起来做能量疗愈后来在我开设马雅心能量课程时也会教大家如何使用水晶灵摆 …然而这两年来不…

Python GUI开发- PyQt5 开发小工具环境入门

前言 常见的python开发gui的库有 Tkinter&#xff0c; PyQt5&#xff0c; wxPython等。本教程是选择PyQt5 开发桌面小工具。 环境准备 只需pip安装即可快速准备好开发环境 pip install pyqt5快速开始 创建一个空的window窗口 Qapplication()&#xff1a;每个GUI都必须包含…