当前位置: 首页 > news >正文

1-GGML:看ctx是个什么东西

GGML

    • ggml_context
    • 定义
    • 初始化
    • OBJ
    • 工程技巧

ggml_context

ggml_context在代码的主部分都存在,简单描述就是对内存的管理,本质是一个链表.

定义

struct ggml_context {size_t mem_size;        // 内存大小void* mem_buffer;       // 内存地址bool   mem_buffer_owned;bool   no_alloc;bool   no_alloc_save; // this is used to save the no_alloc state when using scratch buffersint    n_objects;// 开始结束 这是一个链表struct ggml_object * objects_begin;struct ggml_object * objects_end;struct ggml_scratch scratch;struct ggml_scratch scratch_save;
};

通过定义可以看到他其实就是一个链表的,存储了有多少个object,objects_begin和objects_end是链表的头和尾,

初始化

struct ggml_context * ggml_init(struct ggml_init_params params) {// ..................................// find non-used context in g_statestruct ggml_context * ctx = NULL;// 建立一个context指针for (int i = 0; i < GGML_MAX_CONTEXTS; i++) {// g_state 是全局的状态if (!g_state.contexts[i].used) { // 在全局里找一个没用的g_state.contexts[i].used = true; // 标记为使用ctx = &g_state.contexts[i].context;// 拿出来contextGGML_PRINT_DEBUG("%s: found unused context %d\n", __func__, i);break;// 跳出}}if (ctx == NULL) {// 为空,说明用完了GGML_PRINT_DEBUG("%s: no unused context found\n", __func__);ggml_critical_section_end();return NULL;}// allow to call ggml_init with 0 sizeif (params.mem_size == 0) {params.mem_size = GGML_MEM_ALIGN;}const size_t mem_size = params.mem_buffer ? params.mem_size : GGML_PAD(params.mem_size, GGML_MEM_ALIGN);// 往ctx里赋值*ctx = (struct ggml_context) {/*.mem_size           =*/ mem_size,// 内存大小/*.mem_buffer         =*/ params.mem_buffer ? params.mem_buffer : GGML_ALIGNED_MALLOC(mem_size),// 如果地址是空分配地址/*.mem_buffer_owned   =*/ params.mem_buffer ? false : true,/*.no_alloc           =*/ params.no_alloc,/*.no_alloc_save      =*/ params.no_alloc,/*.n_objects          =*/ 0,/*.objects_begin      =*/ NULL,/*.objects_end        =*/ NULL,/*.scratch            =*/ { 0, 0, NULL, },/*.scratch_save       =*/ { 0, 0, NULL, },};GGML_ASSERT(ctx->mem_buffer != NULL);GGML_ASSERT_ALIGNED(ctx->mem_buffer);// ..................................return ctx;
}

在ggml_init函数进行ctx的初始化,也就是从系统的空间里获得一个可用的ctx,主要关注这三个东西n_objects,objects_begin,objects_end.下面从一个obj的新建过程来看ctx是怎么被用的.

OBJ

obj是一个基本的单元,他在程序中的类型是枚举成这样子的

  • 类型
enum ggml_object_type {GGML_OBJECT_TYPE_TENSOR,// tensorGGML_OBJECT_TYPE_GRAPH, // 计算图GGML_OBJECT_TYPE_WORK_BUFFER// 工作buff};

可以看出一个objec可以是tensor张量,计算图和buffer,也就基本上构成了整个工程的所有数据形式

  • 构造
struct ggml_object {size_t offs;size_t size;struct ggml_object * next;// 指向下一个,链表元素enum ggml_object_type type;// 类型有张量、计算图、buff等char padding[4];// 填充?};

通过下面构建一个new_obj的过程可以看到的是offs偏移的是obj真正关联的数据.简单来说obj是个塑料袋子,offs是袋子里面真正想存的东西的.另外size也需要注意,下面的新建过程可以看到size是传入的大小经过取整-内存对齐后的大小.新建一个obj的语句是"ggml_new_object(ctx, GGML_OBJECT_TYPE_TENSOR, GGML_TENSOR_SIZE + obj_alloc_size)",可以看到其实size是指的也是袋子里的物品的size,像这个例子一样存的是tensor当然是tensor这个对象+tensor数据的大小和.

// 新建一个object
static struct ggml_object * ggml_new_object(struct ggml_context * ctx, enum ggml_object_type type, size_t size) {// always insert objects at the end of the context's memory poolstruct ggml_object * obj_cur = ctx->objects_end;// 拿到尾巴的objconst size_t cur_offs = obj_cur == NULL ? 0 : obj_cur->offs;// 内存块偏置const size_t cur_size = obj_cur == NULL ? 0 : obj_cur->size;// 内存块大小const size_t cur_end  = cur_offs + cur_size;// 当前位置// align to GGML_MEM_ALIGNsize_t size_needed = GGML_PAD(size, GGML_MEM_ALIGN);char * const mem_buffer = ctx->mem_buffer;// 内存块// 新建一个objstruct ggml_object * const obj_new = (struct ggml_object *)(mem_buffer + cur_end);if (cur_end + size_needed + GGML_OBJECT_SIZE > ctx->mem_size) {GGML_PRINT("%s: not enough space in the context's memory pool (needed %zu, available %zu)\n",__func__, cur_end + size_needed, ctx->mem_size);assert(false);return NULL;}*obj_new = (struct ggml_object) {.offs = cur_end + GGML_OBJECT_SIZE,// obj的数据所放地址.size = size_needed,               // 内存对齐后的大小.next = NULL,                      // 没有下一个.type = type,};GGML_ASSERT_ALIGNED(mem_buffer + obj_new->offs);if (obj_cur != NULL) {// 放入链表尾obj_cur->next = obj_new;} else {// 链表的头是空,放头部// this is the first object in this contextctx->objects_begin = obj_new;}ctx->objects_end = obj_new;//printf("%s: inserted new object at %zu, size = %zu\n", __func__, cur_end, obj_new->size);return obj_new;
}

可以看出ctx里的内存块的管理是依赖obj的,obj像一个一级索引,指示了这些数据是放在ctx中.同时通过next的设定把这些数据进行串联起来

工程技巧

  • ggml是怎么进行内存对齐的
#define GGML_PAD(x, n) (((x) + (n) - 1) & ~((n) - 1))

稍微解释一下,x是size,n是对齐的位数,n是二进制的整数比如4/8/16这样,那么 ~((n) - 1))其实是生成一个掩码,低位为0,高位为1. ~是按位置取反运算符号.比如n是4 = b000100,那么 ~(4 -1 ) = ~ (b000011) = 0x111100,进而再&的肯定是4的整倍数了

http://www.dtcms.com/a/578098.html

相关文章:

  • 【Java SE 基础学习打卡】02 计算机硬件与软件
  • SDIO(Secure Digital Input Output,安全数字输入输出)
  • wordpress批量下载外链图片长春网站推广优化公司
  • 在 Ubuntu 上安装 Ollama 并通过 Open WebUI 运行本地大语言模型
  • 用Python来学微积分34-定积分的基本性质及其应用
  • 如何做网站代码荥阳市城乡建设规划网站
  • Jmeter+ant+Jenkins 接口自动化框架-让jmeter脚本自己跑起来
  • 宝安区住房和建设局网站河南做网站多少钱
  • Java集合框架:深入理解List与Set及其实现类
  • 前端工程师职业规划与转型指南
  • 网站建设管理情况的通报国外工业产品设计网站
  • EventOS:面向MCU的事件驱动框架
  • 视频直播点播平台EasyDSS:打造高品质赛事直播的全链路解决方案
  • 广州网站制作哪家全面万达做的电商网站
  • C# 分部类读取学生信息
  • 分布式事务的实现方案:从理论到实践的全方位解析
  • 瑞萨RH850使用记录(三):看门狗(选项字)、AD、CAN、软复位(复位原因)
  • web应用构建与部署的本质区别
  • 源码管理 网站2021年企业所得税怎么征收
  • 建设小说网站的系统有哪些目前最新推广平台
  • iOS文件管理工具深度剖析,从系统沙盒到跨平台文件操作的多工具协同实践
  • 数据结构—排序算法篇二
  • 基于SpringBoot2+Vue2的实验室和实验器材预约平台
  • 比较好的网站建设技术开发wordpress4.7.2写文章
  • 产品定制网站电子商务平台建设内容
  • 手机射频阻抗匹配调试方法
  • 手机网站打不开被拦截怎么办wordpress漂浮按钮
  • Chaos-nano 协作式异步操作系统:赋能 AVR 8 位单片机的革新之路
  • 实对称矩阵的正交相似对角化
  • 印度外贸网站有哪些专注网站建设怎么样