Browse Source

new: mstat()函数,查询内存信息

fslongjin 2 years ago
parent
commit
fb51b0dd6f

+ 3 - 1
kernel/mm/Makefile

@@ -2,7 +2,7 @@
 CFLAGS += -I .
 
 
-all:mm.o slab.o
+all:mm.o slab.o mm-stat.o
 
 mm.o: mm.c
 	gcc $(CFLAGS) -c mm.c -o mm.o
@@ -10,3 +10,5 @@ mm.o: mm.c
 slab.o: slab.c
 	gcc $(CFLAGS) -c slab.c -o slab.o
 
+mm-stat.o: mm-stat.c
+	gcc $(CFLAGS) -c mm-stat.c -o mm-stat.o

+ 195 - 0
kernel/mm/mm-stat.c

@@ -0,0 +1,195 @@
+/**
+ * @file mm-stat.c
+ * @author longjin([email protected])
+ * @brief 查询内存信息
+ * @version 0.1
+ * @date 2022-08-06
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+
+#include "mm.h"
+#include "slab.h"
+#include <common/errno.h>
+#include <process/ptrace.h>
+
+extern const struct slab kmalloc_cache_group[16];
+
+static int __empty_2m_pages(int zone);
+static int __count_in_using_2m_pages(int zone);
+static uint64_t __count_kmalloc_free();
+static uint64_t __count_kmalloc_using();
+static uint64_t __count_kmalloc_total();
+uint64_t sys_mm_stat(struct pt_regs *regs);
+
+/**
+ * @brief 获取指定zone中的空闲2M页的数量
+ *
+ * @param zone 内存zone号
+ * @return int 空闲2M页数量
+ */
+static int __count_empty_2m_pages(int zone)
+{
+    int zone_start = 0, zone_end = 0;
+
+    uint64_t attr = 0;
+    switch (zone)
+    {
+    case ZONE_DMA:
+        // DMA区域
+        zone_start = 0;
+        zone_end = ZONE_DMA_INDEX;
+        attr |= PAGE_PGT_MAPPED;
+        break;
+    case ZONE_NORMAL:
+        zone_start = ZONE_DMA_INDEX;
+        zone_end = ZONE_NORMAL_INDEX;
+        attr |= PAGE_PGT_MAPPED;
+        break;
+    case ZONE_UNMAPPED_IN_PGT:
+        zone_start = ZONE_NORMAL_INDEX;
+        zone_end = ZONE_UNMAPPED_INDEX;
+        attr = 0;
+        break;
+    default:
+        kerror("In __count_empty_2m_pages: param: zone invalid.");
+        // 返回错误码
+        return -EINVAL;
+        break;
+    }
+
+    uint64_t result = 0;
+    for (int i = zone_start; i <= zone_end; ++i)
+    {
+        result += (memory_management_struct.zones_struct + i)->count_pages_free;
+    }
+    return result;
+}
+
+/**
+ * @brief 获取指定zone中的正在使用的2M页的数量
+ *
+ * @param zone 内存zone号
+ * @return int 空闲2M页数量
+ */
+static int __count_in_using_2m_pages(int zone)
+{
+    int zone_start = 0, zone_end = 0;
+
+    uint64_t attr = 0;
+    switch (zone)
+    {
+    case ZONE_DMA:
+        // DMA区域
+        zone_start = 0;
+        zone_end = ZONE_DMA_INDEX;
+        attr |= PAGE_PGT_MAPPED;
+        break;
+    case ZONE_NORMAL:
+        zone_start = ZONE_DMA_INDEX;
+        zone_end = ZONE_NORMAL_INDEX;
+        attr |= PAGE_PGT_MAPPED;
+        break;
+    case ZONE_UNMAPPED_IN_PGT:
+        zone_start = ZONE_NORMAL_INDEX;
+        zone_end = ZONE_UNMAPPED_INDEX;
+        attr = 0;
+        break;
+    default:
+        kerror("In __count_in_using_2m_pages: param: zone invalid.");
+        // 返回错误码
+        return -EINVAL;
+        break;
+    }
+
+    uint64_t result = 0;
+    for (int i = zone_start; i <= zone_end; ++i)
+    {
+        result += (memory_management_struct.zones_struct + i)->count_pages_using;
+    }
+    return result;
+}
+
+/**
+ * @brief 计算kmalloc缓冲区中的空闲内存
+ *
+ * @return uint64_t 空闲内存(字节)
+ */
+static uint64_t __count_kmalloc_free()
+{
+    uint64_t result = 0;
+    for (int i = 0; i < sizeof(kmalloc_cache_group) / sizeof(struct slab); ++i)
+    {
+        result += kmalloc_cache_group[i].size * kmalloc_cache_group[i].count_total_free;
+    }
+    return result;
+}
+
+/**
+ * @brief 计算kmalloc缓冲区中已使用的内存
+ *
+ * @return uint64_t 已使用的内存(字节)
+ */
+static uint64_t __count_kmalloc_using()
+{
+    uint64_t result = 0;
+    for (int i = 0; i < sizeof(kmalloc_cache_group) / sizeof(struct slab); ++i)
+    {
+        result += kmalloc_cache_group[i].size * kmalloc_cache_group[i].count_total_using;
+    }
+    return result;
+}
+
+/**
+ * @brief 计算kmalloc缓冲区中总共占用的内存
+ *
+ * @return uint64_t 缓冲区占用的内存(字节)
+ */
+static uint64_t __count_kmalloc_total()
+{
+    uint64_t result = 0;
+    for (int i = 0; i < sizeof(kmalloc_cache_group) / sizeof(struct slab); ++i)
+    {
+        result += kmalloc_cache_group[i].size * (kmalloc_cache_group[i].count_total_free + kmalloc_cache_group[i].count_total_using);
+    }
+    return result;
+}
+
+/**
+ * @brief 获取系统当前的内存信息(未上锁,不一定精准)
+ * 
+ * @return struct mm_stat_t 内存信息结构体
+ */
+struct mm_stat_t mm_stat()
+{
+    struct mm_stat_t tmp = {0};
+    // 统计物理页的信息
+    tmp.used = __count_in_using_2m_pages(ZONE_NORMAL) * PAGE_2M_SIZE;
+    tmp.free = __count_empty_2m_pages(ZONE_NORMAL) * PAGE_2M_SIZE;
+    tmp.total = tmp.used + tmp.free;
+    tmp.shared = 0;
+    // 统计kmalloc slab中的信息
+    tmp.cache_free = __count_kmalloc_free();
+    tmp.cache_used = __count_kmalloc_using();
+    tmp.available = tmp.free + tmp.cache_free;
+    return tmp;
+}
+
+/**
+ * @brief 获取内存信息的系统调用
+ *
+ * @param r8 返回的内存信息结构体的地址
+ * @return uint64_t
+ */
+uint64_t sys_mstat(struct pt_regs *regs)
+{
+    if (regs->r8 == NULL)
+        return -EINVAL;
+    struct mm_stat_t stat = mm_stat();
+    if (regs->cs == (USER_CS | 0x3))
+        copy_to_user((void *)regs->r8, &stat, sizeof(struct mm_stat_t));
+    else
+        memcpy((void *)regs->r8, &stat, sizeof(struct mm_stat_t));
+    return 0;
+}

+ 24 - 2
kernel/mm/mm.h

@@ -145,7 +145,7 @@
     do                              \
     {                               \
         ul tmp;                     \
-        io_mfence();\
+        io_mfence();                \
         __asm__ __volatile__(       \
             "movq %%cr3, %0\n\t"    \
             "movq %0, %%cr3\n\t"    \
@@ -227,6 +227,21 @@ struct Page
     ul age;
 };
 
+/**
+ * @brief 系统内存信息结构体(单位:字节)
+ *
+ */
+struct mm_stat_t
+{
+    uint64_t total;     // 计算机的总内存数量大小
+    uint64_t used;      // 已使用的内存大小
+    uint64_t free;      // 空闲物理页所占的内存大小
+    uint64_t shared;    // 共享的内存大小
+    uint64_t cache_used;     // 位于slab缓冲区中的已使用的内存大小
+    uint64_t cache_free;     // 位于slab缓冲区中的空闲的内存大小
+    uint64_t available; // 系统总空闲内存大小(包括kmalloc缓冲区)
+};
+
 extern struct memory_desc memory_management_struct;
 
 // 导出内核程序的几个段的起止地址
@@ -443,4 +458,11 @@ int8_t mm_check_page_table(uint64_t *ptr);
  * @param offset 新的地址相对于原地址的偏移量
  * @return uint64_t
  */
-uint64_t mm_do_brk(uint64_t old_brk_end_addr, int64_t offset);
+uint64_t mm_do_brk(uint64_t old_brk_end_addr, int64_t offset);
+
+/**
+ * @brief 获取系统当前的内存信息(未上锁,不一定精准)
+ * 
+ * @return struct mm_stat_t 内存信息结构体
+ */
+struct mm_stat_t mm_stat();

+ 4 - 1
kernel/syscall/syscall.c

@@ -18,6 +18,7 @@ extern void system_call(void);
 extern void syscall_int(void);
 
 extern uint64_t sys_clock(struct pt_regs *regs);
+extern uint64_t sys_mstat(struct pt_regs *regs);
 
 /**
  * @brief 导出系统调用处理函数的符号
@@ -778,5 +779,7 @@ system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] =
         [17] = sys_mkdir,
         [18] = sys_nanosleep,
         [19] = sys_clock,
-        [20 ... 254] = system_call_not_exists,
+        [20] = system_call_not_exists,
+        [21] = sys_mstat,
+        [22 ... 254] = system_call_not_exists,
         [255] = sys_ahci_end_req};

+ 4 - 0
kernel/syscall/syscall_num.h

@@ -30,5 +30,9 @@
 #define SYS_MKDIR 17 // 创建文件夹
 #define SYS_NANOSLEEP 18 // 纳秒级休眠
 #define SYS_CLOCK 19 // 获取当前cpu时间
+#define SYS_PIPE 20
+
+#define SYS_MSTAT 21    // 获取系统的内存状态信息
+
 
 #define SYS_AHCI_END_REQ 255    // AHCI DMA请求结束end_request的系统调用

+ 13 - 2
user/libs/libc/sys/stat.c

@@ -1,7 +1,18 @@
 #include "stat.h"
-#include<libsystem/syscall.h>
+#include <libsystem/syscall.h>
 
 int mkdir(const char *path, mode_t mode)
 {
-    return syscall_invoke(SYS_MKDIR, (uint64_t)path, (uint64_t)mode, 0,0,0,0,0,0);
+    return syscall_invoke(SYS_MKDIR, (uint64_t)path, (uint64_t)mode, 0, 0, 0, 0, 0, 0);
+}
+
+/**
+ * @brief 获取系统的内存信息
+ *
+ * @param stat 传入的内存信息结构体
+ * @return int 错误码
+ */
+int mstat(struct mstat_t *stat)
+{
+    return syscall_invoke(SYS_MSTAT, (uint64_t)stat, 0, 0, 0, 0, 0, 0, 0);
 }

+ 24 - 1
user/libs/libc/sys/stat.h

@@ -1,4 +1,27 @@
 #pragma once
 #include <libc/sys/types.h>
 
-int mkdir(const char *path, mode_t mode);
+/**
+ * @brief 系统内存信息结构体(单位:字节)
+ *
+ */
+struct mstat_t
+{
+    uint64_t total;     // 计算机的总内存数量大小
+    uint64_t used;      // 已使用的内存大小
+    uint64_t free;      // 空闲物理页所占的内存大小
+    uint64_t shared;    // 共享的内存大小
+    uint64_t cache_used;     // 位于slab缓冲区中的已使用的内存大小
+    uint64_t cache_free;     // 位于slab缓冲区中的空闲的内存大小
+    uint64_t available; // 系统总空闲内存大小(包括kmalloc缓冲区)
+};
+
+int mkdir(const char *path, mode_t mode);
+
+/**
+ * @brief 获取系统的内存信息
+ * 
+ * @param stat 传入的内存信息结构体
+ * @return int 错误码
+ */
+int mstat(struct mstat_t* stat);

+ 3 - 0
user/libs/libsystem/syscall.h

@@ -24,6 +24,9 @@
 #define SYS_MKDIR 17 // 创建文件夹
 #define SYS_NANOSLEEP 18 // 纳秒级休眠
 #define SYS_CLOCK 19 // 获取当前cpu时间
+#define SYS_PIPE 20
+
+#define SYS_MSTAT 21    // 获取系统的内存状态信息
 
 /**
  * @brief 用户态系统调用函数