【矩阵乘法】C++实现外部矩阵乘法

news2024/10/6 18:25:15

问题描述

​ 使用文件和内存模拟系统缓存,并利用矩阵乘法验证实际和理论情况。

算法思想

设计一个Matrix类,其中Matrix是存在磁盘中的一个二进制文件,类通过保存的矩阵属性来读取磁盘。前八个字节为两个int32,保存矩阵的行列数。

在这里插入图片描述

Matrix中有一个buffer成员为读取到的数据缓存,通过pos属性来确定其在矩阵中的位置。其映射逻辑为 r o w = ⌊ p o s ÷ c o l S i z e ⌋ , c o l = p o s m o d    c o l S i z e row=\lfloor pos \div colSize\rfloor, col=pos \mod colSize row=pos÷colSize,col=posmodcolSize。而缓存的管理模型则是模仿CPU的内存缓存模型,采用写回法。当读取矩阵中rowcol列时,判断逻辑如下。

在缓存内
不再缓存内
没有脏数据
有脏数据
接受row,col变量
判断所需变量是否在缓存内
读取数据
判断缓存内是否有脏数据
从磁盘内读取到缓存
写入脏数据

​ 完成磁盘交互后,其余操作即为正常的矩阵操作

功能模块设计

矩阵类的成员变量,:

    Buffer buffer;
    const int rowSize;
    const int colSize;
    long cacheMissCount; // cache miss 次数
    long cacheCount;     // cache 访问次数
    int pos;             // pos = -1 means invalid buffer
    const int offset = 2 * INT_BYTE;
    fstream file;

​ 矩阵值获取和修改的函数

    int get(int row, int col)
    {
        int index = row * colSize + col;
        assert(index < rowSize * colSize && index >= 0);
        cacheCount++;
        if (index >= pos && index < pos + buffer.size && pos != -1)
            return buffer.get(index - pos);
        else
        {
            cacheMissCount++;
            readBuffer(index);
            return buffer.get(0);
        }
    }
    void set(int row, int col, int val)
    {
        assert(row <= rowSize && col <= colSize);
        if (pos <= indexOf(row, col) && indexOf(row, col) < pos + buffer.size)
            buffer.set(indexOf(row, col) - pos, val);
        else
        {
            cacheMissCount++;
            readBuffer(indexOf(row, col));
            buffer.set(0, val);
        }
        buffer.dirty = true;
    }

​ 磁盘操作函数

    void writeBuffer()
    {
        file.seekp(pos * INT_BYTE + offset, ios::beg);
        for (int i = 0; i < buffer.size; i++)
        {
            file.write((char *)&buffer.get(i), INT_BYTE);
        }
        buffer.dirty = false;
    }

    void readBuffer(int startIndex)
    {
        if (buffer.dirty)
        {
            writeBuffer();
        }

        file.seekg(startIndex * INT_BYTE + offset, ios::beg);
        buffer.size = 0;
        for (int i = 0; i < buffer.capacity && startIndex + i < rowSize * colSize; i++)
        {
            int value;
            file.read((char *)&value, INT_BYTE);
            buffer.set(i, value);
            buffer.size++;
        }
        pos = startIndex;
    }

​ 矩阵乘法函数

    Matrix *multiple_ijk(Matrix &right)
    {
        Matrix *t = new Matrix(rowSize, right.colSize, buffer.capacity);
        int i, j, k;
        for (i = 0; i < rowSize; i++)
        {
            for (j = 0; j < right.colSize; j++)
            {
                for (k = 0; k < right.rowSize; k++)
                {
                    t->set(i, j, t->get(i, j) + get(i, k) * right.get(k, j));
                }
            }
        }
        return t;
    }

    Matrix *multiple_ikj(Matrix &right)
    {
        Matrix *t = new Matrix(rowSize, right.colSize, buffer.capacity);
        int i, j, k;
        for (i = 0; i < rowSize; i++)
        {
            for (k = 0; k < right.rowSize; k++)
            {
                for (j = 0; j < right.colSize; j++)
                {
                    t->set(i, j, t->get(i, j) + get(i, k) * right.get(k, j));
                }
            }
        }
        return t;
    }

测试结果与分析

测试用例

class MatrixTest
{
public:
    void test1()
    {
        Matrix m(10, 10, 3, "m.txt");
        m.randomize();
        cout << m << endl;
        cout << "cache miss:" << m.getCacheMissCount() << endl;
        Matrix m1(10, 10, 3);
        m1.randomize();
        cout << m1 << endl;
        cout << "cache miss:" << m1.getCacheMissCount() << endl;
    }

    void test2()
    {
        Matrix m(10, 10, 3);
        cout << m << endl;
        m.set(0, 0, 9999);
        cout << m << endl;
        m.set(5, 0, 9999);
        cout << m << endl;
        m.set(3, 7, 9999);
        cout << m << endl;
    }
    void test3()
    {
        Matrix m1(2, 3, 5, "m1.txt");
        m1.randomize(100);
        cout << m1 << endl;
        Matrix m2(3, 4, 7, "m2.txt");
        m2.randomize(100);
        cout << m2 << endl;
        Matrix *m3 = m1.multiple_ijk(m2);
        cout << *m3 << endl;
        Matrix *m4 = m1.multiple_ikj(m2);
        cout << *m4 << endl;
        assert(m3->toString() == m4->toString());
    }
    void test4(int n, int cacheSize)
    {
        cout << "cache size is " << cacheSize << endl;
        Matrix m1(n, n, cacheSize, "m1.txt");
        cout << "initial m1(size is " << n << ")finished" << endl;
        Matrix m2(n, n, cacheSize, "m2.txt");
        cout << "initial m2(size is " << n << ")finished" << endl;
        Matrix *m3 = m1.multiple_ijk(m2);
        cout << "m1 ijk m2 finished" << endl;
        cout << "cache coutnt of m1: " << m1.getCacheCount() << ",	cache miss count of m1:" << m1.getCacheMissCount() << endl;
        cout << "cache coutnt of m2: " << m2.getCacheCount() << ",	cache miss count of m2:" << m2.getCacheMissCount() << endl;
        cout << "cache coutnt of m3: " << m3->getCacheCount() << ",	cache miss count of m3:" << m3->getCacheMissCount() << endl;
        cout << endl;
    }
    void test5(int n, int cacheSize)
    {
        cout << "cache size is " << cacheSize << endl;
        Matrix m1(n, n, cacheSize, "m1.txt");
        cout << "initial m1(size is " << n << ")finished" << endl;
        Matrix m2(n, n, cacheSize, "m2.txt");
        cout << "initial m2 finished" << endl;
        Matrix *m3 = m1.multiple_ikj(m2);
        cout << "m1 ijk m2(size is " << n << ")finished" << endl;
        cout << "cache coutnt of m1: " << m1.getCacheCount() << ",	cache miss count of m1:" << m1.getCacheMissCount() << endl;
        cout << "cache coutnt of m2: " << m2.getCacheCount() << ",	cache miss count of m2:" << m2.getCacheMissCount() << endl;
        cout << "cache coutnt of m3: " << m3->getCacheCount() << ",	cache miss count of m3:" << m3->getCacheMissCount() << endl;
        cout << endl;
    }
    void runTest()
    {
        for (int i = 5; i < 35; i += 5)
        {
            for (int j = 1; j < 5; j++)
            {
                test4(i, i / j);
                test5(i, i / j);
            }
        }
    }
};

实验测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ei8rZnSV-1670300721028)(figures/外部矩阵乘法/image-20221205225242144.png)]

实验分析

假设矩阵为 C = A × B C=A\times B C=A×B,且cache大小小于矩阵的一行或一列,且A、B、C都是大小为n的方阵

对于ijk的情况:

​ 每次读取时发生一次磁盘访问,而若cache当中有脏数据,则有另一次的写入访问。对于矩阵C,因为其作为操作矩阵*(总是进行+=操作)*,所以只要是C矩阵发生了cache miss其实是进行了两次磁盘访问,而对于AB矩阵,发生cache miss 时只发生一次磁盘访问。

​ cache miss 发生次数如下
C c a c h e   m i s s = n 2 c a c h e   s i z e A c a c h e   m i s s = n 3 c a c h e   s i z e B c a c h e   m i s s = n 3 C_{cache\ miss} = \frac{n^2}{cache\ size}\\ A_{cache\ miss} = \frac{n^3}{cache\ size}\\ B_{cache\ miss} = n^3 Ccache miss=cache sizen2Acache miss=cache sizen3Bcache miss=n3
​ 所消耗的总时间
t t o t a l = 2 T d i s k   a c c e s s   t i m e C c a c h e   m i s s + T d i s k   a c c e s s   t i m e A c a c h e   m i s s + T d i s k   a c c e s s   t i m e B c a c h e   m i s s = n 3 T d i s k   a c c e s s   t i m e c a c h e   s i z e ( 1 + 1 n + c a c h e   s i z e ) t_{total}=2T_{disk\ access\ time}C_{cache\ miss}+T_{disk\ access\ time}A_{cache\ miss}+T_{disk\ access\ time}B_{cache\ miss}\\ =\frac{n^3T_{disk\ access\ time}}{cache\ size(1+\frac{1}{n}+cache\ size)} ttotal=2Tdisk access timeCcache miss+Tdisk access timeAcache miss+Tdisk access timeBcache miss=cache size(1+n1+cache size)n3Tdisk access time
​ 而当顺序化为ijk的时候,B矩阵的cache hit 率有所提高
C c a c h e   m i s s = n 3 c a c h e   s i z e A c a c h e   m i s s = n 2 c a c h e   s i z e B c a c h e   m i s s = n 3 c a c h e   s i z e C_{cache\ miss} = \frac{n^3}{cache\ size}\\ A_{cache\ miss} = \frac{n^2}{cache\ size}\\ B_{cache\ miss} = \frac{n^3}{cache\ size} Ccache miss=cache sizen3Acache miss=cache sizen2Bcache miss=cache sizen3
所消耗的总时间变为了
t t o t a l = 2 T d i s k   a c c e s s   t i m e C c a c h e   m i s s + T d i s k   a c c e s s   t i m e A c a c h e   m i s s + T d i s k   a c c e s s   t i m e B c a c h e   m i s s = n 3 T d i s k   a c c e s s   t i m e c a c h e   s i z e ( 2 + 1 n ) t_{total}=2T_{disk\ access\ time}C_{cache\ miss}+T_{disk\ access\ time}A_{cache\ miss}+T_{disk\ access\ time}B_{cache\ miss}\\ =\frac{n^3T_{disk\ access\ time}}{cache\ size(2+\frac{1}{n})} ttotal=2Tdisk access timeCcache miss+Tdisk access timeAcache miss+Tdisk access timeBcache miss=cache size(2+n1)n3Tdisk access time

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux||报错:vboxuser is not in the sudoers file. This incident will be reported.

一、问题描述 打算在Ubuntu虚拟机上部署SonarQube时&#xff0c;为避免各种不必要的奇怪问题&#xff0c;预先使用sudo命令修改系统参数。 命令如下&#xff1a;sudo sysctl -w vm.max_map_count262144 报错如下&#xff1a;vboxuser is not in the sudoers file. This inciden…

制造业企业库存管理的现状与解决措施

在竞争激烈的现代经济时代&#xff0c;制造行业面临着巨大的挑战和压力&#xff0c;必须与时俱进&#xff0c;适应市场的各种变化才能生存并保持活力。随着经营模式的变化与产品数量的增加&#xff0c;对产品库存管理也提出更大的挑战。库存管理是指与库存相关的计划和控制活动…

数据库设计 Relational Language

除了最为常用的SQL语句之外&#xff0c;还存在着几种不常用的数据库语言&#xff0c;这里简单介绍&#xff0c;了解即可。 Relational Algebra(RA) 一种程序性语言&#xff0c;可以与SQL对应着转换&#xff0c;语法即转换规则如下&#xff1a; σ&#xff1a;与WHERE对应&am…

一篇文章让你搞懂各种压缩,gzip压缩,nginx的gzip压缩,Minification压缩

前言 同学们可能听过这些压缩&#xff0c;但是可能不是了解&#xff0c;这篇文章让你弄清他们 webpack的gzip压缩和nginx的gzip压缩有什么区别&#xff1f;怎样开启gzip压缩&#xff1f;Minfication压缩又是什么鬼&#xff1f;怎样使项目优化的更好&#xff1f;本篇文章讲的是…

DBCO点击试剂1629057-08-4,DBCO-C3-Maleimide,DBCO-C3-Mal

一、基础产品数据&#xff08;Basic Product Data&#xff09;&#xff1a; CAS号&#xff1a;1629057-08-4 中文名&#xff1a;二苯基环辛炔-C3-马来酰亚胺、二苯并环辛炔-C3-马来酰亚胺 英文名&#xff1a;DBCO-C3-Maleimide&#xff0c;DBCO-C3-Mal 结构式&#xff08;Struc…

MAC 通过IDEA启动tomcat,显示80端口被占用解决办法

mac系统下使用IntelliJ IDEA中的Tomcat报错问题&#xff1a;Address localhost:80 is already in use 一、状况描述 本人在跑一个tomcat的项目时&#xff0c;由于项目限制了用域名访问&#xff0c;为了方便本地开发调试&#xff0c;需在tomcat在IDEA中将端口设置为80&#xff…

three.js问题记录---MeshLambertMaterial材质颜色失效

初学three.js&#xff0c;跟着教程走都比较顺利&#xff0c;自己尝试写个demo的时候发现创建一个物体&#xff0c;在给材质颜色的时候出现了一个问题。 在three.js官网文档&#xff08;https://www.techbrood.com/threejs/docs/&#xff09;中&#xff0c;我们可以看到材料&am…

论文解读-Early Detection of Cybersecurity Threats Using Collaborative Cognition

1 概述与介绍 作者描述了一种新颖的协作框架&#xff0c;该框架通过利用语义丰富的知识表示和与不同机器学习技术集成的推理功能来协助安全分析人员。文中介绍的认知网络安全系统从各种文本源中提取信息&#xff0c;并使用一种扩展的UCO安全本体的将其存储在知识图谱中。该系统…

[附源码]Python计算机毕业设计SSM家庭安防系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

一个ubuntu系统搭建redis集群

下载redis(如果要搭建redis集群不建议使用命令下载&#xff0c;因为后面启动集群时redis5.0一下的会有问题&#xff0c;依赖ruby) 更新apt sudo apt update使用apt下载 sudo apt install redis-server打开redis配置文件 sudo vim /etc/redis/redis.conf设置远程连接&#x…

2023年tiktok自动化运营软件新排名看这里!

【导读】2022年即将结束啦&#xff0c;你的tiktok运营效果怎么样呢&#xff1f;这里我们小编告诉您&#xff0c;用tiktok自动化运营软件可以取得事半功倍的效果哦&#xff01;这里就带大家看看2023年tiktok自动化运营软件排名哦&#xff01; 2023年tiktok自动化运营软件新排名看…

FPGA学习笔记(九)SPI学习总结及stm32的HAL库下SPI配置

系列文章目录 一、FPGA学习笔记&#xff08;一&#xff09;入门背景、软件及时钟约束 二、FPGA学习笔记&#xff08;二&#xff09;Verilog语法初步学习(语法篇1) 三、FPGA学习笔记&#xff08;三&#xff09; 流水灯入门FPGA设计流程 四、FPGA学习笔记&#xff08;四&…

上海亚商投顾:沪指继续震荡向上 零售等消费股表现活跃

上海亚商投顾前言&#xff1a;无惧大盘大跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪三大指数今日低开高走&#xff0c;深成指盘中涨超1%&#xff0c;创业板指一度涨逾1.5%&#xff0c;随后均上演冲高回…

【C++进阶】引用 函数提高

文章目录一 、引用1.1 引用的基本使用1.2 引用的注意事项1.3 引用做函数参数1.4 引用的本质 &#xff1a;指针的常量1.5 常量引用二、函数提高1 函数默认参数2 函数占位参数3 函数重载一 、引用 1.1 引用的基本使用 作用&#xff1a;给变量起别名 语法&#xff1a;数据类型 &a…

Python计算目标检测中的IoU

Python计算目标检测中的IoU前言前提条件相关介绍实验环境IoU概念代码实现前言 本文是个人使用PythonPython处理文件的电子笔记&#xff0c;由于水平有限&#xff0c;难免出现错漏&#xff0c;敬请批评改正。更多精彩内容&#xff0c;可点击进入我的个人主页查看 前提条件 熟悉P…

​寒武纪思元370系列与飞桨完成II级兼容性测试,联合赋能AI落地实践

2022年12月2日&#xff0c;寒武纪思元370系列与飞桨已完成II级兼容性测试&#xff0c;兼容性表现良好。 本次II级兼容性测试基于寒武纪MLU370系列&#xff0c;测试了包含PP-YOLO、YOLOv3、ResNet50、DeepLabv3、BERT、OCR-DB等共计15个模型的验证&#xff0c;覆盖了计算机视觉…

01-go基础-07-map(声明map、初始化map、map赋值、遍历map、判断key是否在map中、删除map成员)

文章目录1. 声明 map2. 初始化 map3. map赋值3.1 直接声明并赋值3.2 分别定义每一组键值对4. 遍历map5. 判断key是否在map中6. 删除成员&#xff08;delete()&#xff09;1. 声明 map 语法 var MapName map[keyType]valueType语法示例 var warlords map[string]string仅声明…

Eureka 服务端搭建入门与集群搭建

前言 Eureka在2022年已经确定的是&#xff0c;2.x版本开源计划已经停止了&#xff0c;1.x版本陆陆续续还是有人在维护的。还有很多最早使用微服务的公司还在继续用着eureka作为注册中心&#xff0c;也是很多同学学习微服务的敲门砖。 搭建Eureka服务端 创建一个平平无奇的ma…

2203 CSDN课程-python入门课

Python入门课&#xff0c;较为基础。 1 简介 1.1 前言 事实上&#xff0c;Python已经走过很多年的发展历程了&#xff0c;笔者最一开始学习的时候还是2.x版本&#xff0c;现在早就3.xx版本了。在当提笔&#xff0c;不是青春年少。确实是这样&#xff0c;我记得是2018年开始接…

【Linux从入门到放弃】Linux权限详解

&#x1f9d1;‍&#x1f4bb;作者&#xff1a; 情话0.0 &#x1f4dd;专栏&#xff1a;《Linux从入门到放弃》 &#x1f466;个人简介&#xff1a;一名双非编程菜鸟&#xff0c;在这里分享自己的编程学习笔记&#xff0c;欢迎大家的指正与点赞&#xff0c;谢谢&#xff01; L…