0th HPC Game小结

news2024/11/17 14:29:11

PART 1 - 基础知识

一、文件读取

二进制文件

mmap https://hpcgame.pku.edu.cn/demo/scow/api/proxy/relative/192.168.100.61/35515/
fread fwrite

	//read
    FILE* fi;
    if(fi = fopen("input.bin", "rb")){
    	fread(&p, sizeof(int), 1, fi);
    	fread(&n, sizeof(int), 1, fi);
    	int * a = (int *)malloc((n+1)*sizeof(int));
    	fread(a ,sizeof(int), n, fi);
    	fclose(fi);
    	free(a); 
    }
  // write
    FILE* fo;
    if (fo = fopen("output.bin", "wb")) {
        fwrite(&x, 1,  sizeof(int), fo);
        fwrite(a,1,sizeof(int)*n,fo); 
        fclose(fo);
    }

命令行读取参数

int N = atoi(argv[1]);  // 从命令行读取第一个参数

unsigned int N2 = strtoul(argv[2], NULL, 10); // unsigned int 第二个参数

文本文件读写

// read
	FILE *f1,*f2;
	f1 = fopen("input.txt","r");
	fscanf(f1,"%d",&xi);
	float *input = (float *)malloc((xi+1)*sizeof(float));
	for(int i=0;i<xi;i++){
		fscanf(f1,"%f",&input[i]); 
	}
	fclose(f1);
	free(input);
//writ
    FILE *out;
    out = fopen("output.dat","w");
    fprintf(out,"%.12g\n",answer);
    fclose(out);

二、sbatch使用

脚本编写

CPU编译运行(mpi程序 cpi.c 为例)

#!/bin/bash
module load mpi/2021.8.0
mpicc cpi.c -lm -o cpi

# compile.sh
#!/bin/bash
module load mpi/2021.8.0
export I_MPI_PIN_RESPECT_CPUSET=0;
# mpirun ./cpi
I_MPI_OFI_PROVIDER=tcp mpirun -genv I_MPI_FABRICS=shm:ofi -iface eno2 ./cpi

# job.sh
#!/bin/bash
#run.sh
sbatch --cpus-per-task=1 --nodes=5 --ntasks-per-node=2 --partition=compute --qos=normal --output=output.txt ./job.sh

# run.sh

编译:./compile.sh
提交作业:./run.sh

GPU编译运行(cuda为例)

#!/bin/bash

sbatch -p GPU --gres=gpu:1 --gpus=1 -t 00:00:30 -o output.txt -e error.txt compile-job.sh

# compile.sh
#!/bin/bash

sbatch -p GPU --gres=gpu:1 --gpus=1 -t 00:20:00 -o output.txt -e error.txt run-job.sh

# run.sh

compile-job.sh、run-job.sh 需实现

编译:./compile.sh
提交作业:./run.sh

作业管理

查看作业状态:

squeue

取消作业:

scancel XXXX(作业编号)

ps.
srun 直接执行可执行程序
sbatch 提交批处理脚本进行任务计算

三、数据生成器(01)

#!/usr/bin/php
<?php

if ($argc != 4) {
    die("USAGE: {$argv[0]} <OUTPUT_PATH> <P> <N_RANGE>\n");
}

function i32_to_bytes(int $n): array
{
    $rslt = [];
    for ($i = 0; $i < 4; ++$i) {
        $rslt[] = $n & 255;
        $n >>= 8;
    }
    return $rslt;
}

function bytes_to_string(array $n): string
{
    $a = array_map(fn (int $num) => chr($num), $n);
    return join('', $a);
}

function i32_to_string(int $n): string
{
    return bytes_to_string(i32_to_bytes($n));
}

$f = fopen($argv[1], "w");

$p = $argv[2];
$n = (1 << ((int) trim($argv[3])));
$n += $n + rand(0, $n / 2);
$part = 1;
$n = floor($n / $part) * $part;
echo "p={$p}, n={$n}" . PHP_EOL;

fwrite($f, i32_to_string($p));
fwrite($f, i32_to_string($n));
for ($i = 0; $i < ($n / $part); ++$i) {
    $m = i32_to_string(rand(0, 1 << 30));
    fwrite($f, $m);
}

fclose($f);

四、Attention

高精度题目注意:
不能直接 double _N = 1.0 /N; 因为1.0默认是float会损失精度

double dif = 1.0;
double _N = dif/N;
//or
double _N = (double)1.0/N;

运算次序的改变可能会导致精度损失

大数据数组开辟用 malloc

变量初始化记得 赋值

#define里开omp: https://www.thinbug.com/q/56717411
不能在#pragma内使用#define,但是可以在宏定义内将pragma运算符用作_pragma(“omp parallel for”)

#define resize2d_bilinear_kernel(typename) \
_Pragma("omp parallel for schedule(dynamic)") \
		for(){ .... }


PATR 2 - 优化小结

一、矩阵乘法

矩阵分块+访存优化:
在这里插入图片描述

#define BLOCK_SIZE 64
void matMultCPU_Block(const float* a, const float* b, float* c, int n)
{
#pragma omp parallel for schedule(dynamic)
	for (int ii = 0; ii < n; ii +=BLOCK_SIZE)
		for (int jj = 0; jj < n; jj += BLOCK_SIZE)
			for (int kk = 0; kk < n; kk += BLOCK_SIZE)
				for (int i = ii; i < std::min(ii + BLOCK_SIZE,n); i++)
					for (int k = kk; k < std::min(kk+ BLOCK_SIZE,n); k++)
					{
						float s = a[i * n + k];
						for (int j = jj; j < std::min(jj + BLOCK_SIZE, n); j++)
							c[i * n + j] += s * b[k * n + j];
					}

}
// from https://zhuanlan.zhihu.com/p/371893547

向量化:

void matMult_avx(double *A, double *B, double *C, size_t n)
{
	for (size_t i = 0; i < n; i += 4) {
		for (size_t j = 0; j < n; j++) {
			__m256d c0 = _mm256_load_pd(C+i+j*n); /* c0 = C[i][j] */
			for (size_t k = 0; k < n; k++) {
				c0 = _mm256_add_pd(c0,
					_mm256_mul_pd(_mm256_load_pd(A+i+k*n),
						_mm256_broadcast_sd(B+k+j*n)));
			}
			_mm256_store_pd(C+i+j*n, c0);  /* C[i][j] = c0 */;
		}
	}
}
// from https://zhuanlan.zhihu.com/p/76347262

Cache Blocking+AVX:

#define UNROLL 4
#define BLOCKSIZE 32

static inline void do_block(int n, int si, int sj, int sk,
			double *A, double *B, double *C)
{
	for (int i = si; i < si + BLOCKSIZE; i += UNROLL*4) {
		for (int j = sj; j < sj + BLOCKSIZE; j++) {
			__m256d c[UNROLL];
			for (int x = 0; x < UNROLL; x++) {
				c[x] = _mm256_load_pd(C+i+x*4+j*n);
			}
			for (int k = sk; k < sk + BLOCKSIZE; k++) {
				__m256d b = _mm256_broadcast_sd(B+k+j*n);
				for (int x = 0; x < UNROLL; x++) {
					c[x] = _mm256_add_pd(c[x],
						_mm256_mul_pd(
							_mm256_load_pd(A+n*k+x*4+i), b));
				}
			}

			for (int x = 0; x < UNROLL; x++) {
				_mm256_store_pd(C+i+x*4+j*n, c[x]);
			}
		}
	}
}

void dgemm_avx_unroll_blk_omp(size_t n, double *A, double *B, double *C)
{
#pragma omp parallel for
	for (int sj = 0; sj < n; sj += BLOCKSIZE) {
		for (int si = 0; si < n; si += BLOCKSIZE) {
			for (int sk = 0; sk < n; sk += BLOCKSIZE) {
				do_block(n, si, sj, sk, A, B, C);
			}
		}
	}
}
//from https://zhuanlan.zhihu.com/p/76347262

算法优化:
Coppersmith–Winograd algorithm
介绍: Coppersmith–Winograd algorithm

时间复杂度: O(n2.375477)

// 算法核心
 * matA M*K
 * matB K*N
 * matC M*N
 * matC = matA * matB
 * S1 = A21 + A22     T1 = B12 - B11
 * S2 = S1 - A11      T2 = B22 - T1
 * S3 = A11 - A21     T3 = B22 - B12
 * S4 = A12 - S2      T4 = T2 - B21
 * M1 = A11 * B11     U1 = M1 + M2
 * M2 = A12 * B21     U2 = M1 + M6
 * M3 = S4 * B22      U3 = U2 + M7
 * M4 = A22 * T4      U4 = U2 + M5
 * M5 = S1 * T1       U5 = U4 + M3
 * M6 = S2 * T2       U6 = U3 - U4
 * M7 = S3 * T3       U7 = U3 + M5
 * C11 = U1
 * C12 = U5
 * C21 = U6
 * C22 = U7

代码:https://github.com/YYYYYW/Matrix-Multiplication

二、并行排序

Diverting LSD radix sort :
https://axelle.me/2022/04/19/diverting-lsd-sort/

思想1. 先基数排序,后桶排序
在这里插入图片描述在这里插入图片描述

Parallel Radix Sort OpenMP:
https://github.com/iwiwi/parallel-radix-sort(parallel_radix_sort.h)

并行快排(归并):

#include<omp.h>

data_t Partition(data_t* data, int start, int end)   //閸掓帒鍨庨弫鐗堝祦
{
    data_t temp = data[start];   //娴犮儳顑囨稉鈧稉顏勫帗缁辩姳璐熼崺鍝勫櫙
    while (start < end) {
        while (start < end && data[end] >= temp)end--;   //閹垫儳鍩岀粭顑跨娑擃亝鐦崺鍝勫櫙鐏忓繒娈戦弫?
        data[start] = data[end];
        while (start < end && data[start] <= temp)start++;    //閹垫儳鍩岀粭顑跨娑擃亝鐦崺鍝勫櫙婢堆呮畱閺?
        data[end] = data[start];
    }
    data[start] = temp;   //娴犮儱鐔€閸戝棔缍旀稉鍝勫瀻閻e瞼鍤?
    return start;
}

void quickSort(data_t* data, int start, int end)  //骞惰蹇帓
{
    if (start < end) {
        data_t pos = Partition(data, start, end);
        #pragma omp parallel sections    //璁剧疆骞惰鍖哄煙
        {
            #pragma omp section          //璇ュ尯鍩熷鍓嶉儴鍒嗘暟鎹繘琛屾帓搴?
            quickSort(data, start, pos - 1);
            #pragma omp section          //璇ュ尯鍩熷鍚庨儴鍒嗘暟鎹繘琛屾帓搴?
            quickSort(data, pos + 1, end);
        }
    }
}

quickSort(a , 0, n-1); // main

ps. 用openmp并行快排效果不佳,受限于sections子句,用mpi并行效果不错

三、高精度求 π

改进的幂级数法:
精度高,n取20000(还可以更小)轻松求得15位有效数字

#include<stdio.h>
#include<mpi.h>
#include<stdlib.h>
#include<math.h>

double f(double x) {   // inline
	double y = 2 * x + 1;
	double z = pow(-1, x);
	double h1 = 4.0;
	double h2 = 5.0;
	double h3 = 239.0;
	return h1 * z / y*(h1 / pow(h2, y) - 1 / pow(h3, y));
}

int main(int argc, char* argv[])
{
	int myid, numprocs, namelen;
	double pi, sum, x, *temp;
	long long n;
	char processor_name[MPI_MAX_PROCESSOR_NAME];
	char* pi_norm = "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198938";
	
	MPI_Init(&argc, &argv);        // starts MPI
	MPI_Comm_rank(MPI_COMM_WORLD, &myid);  // get current process id
	MPI_Comm_size(MPI_COMM_WORLD, &numprocs);      // get number of processes
	MPI_Get_processor_name(processor_name, &namelen);
	n = 20000;

	if (myid == 0) {
		temp = (double*)malloc(sizeof(double)*numprocs);
	}
	MPI_Bcast(&n, 1, MPI_LONG_LONG, 0, MPI_COMM_WORLD); //靠
	sum = 0.0, pi = 0.0;
	for (long long i = myid; i <= n; i += numprocs) {
		sum += f(i);
	}
	MPI_Gather(&sum, sizeof(sum), MPI_BYTE, temp, sizeof(sum), MPI_BYTE, 0, MPI_COMM_WORLD);
	if (myid == 0) {
		for (int i = 0; i < numprocs; i++) {
			pi += temp[i];
		}
		FILE *out;
    	out = fopen("output.txt","w");
    	fprintf(out,"%.15g\n",pi);
    	fclose(out);
		free(temp);
	}
	MPI_Finalize();
	return 0;
}

五种方式 MPICH2 并行计算π: https://github.com/lang22/MPI-PI

四、二维卷积(AVX)

Conv2D-AVX512:

	for(int i=0; i<xi-xk+1;i++){
		for(int j=0;j<yi-yk+1;j++){
		//float temp = 0.0;
         __m512 tmp = _mm512_setzero_ps();
			for(int m=0;m<xk;m++){
				for(int n=0;n<yk;n+=16){
                    tmp = _mm512_add_ps(tmp,_mm512_mul_ps(_mm512_loadu_ps(&kernel[m*yk+n]),_mm512_loadu_ps(&input[(i+m)*yi+j+n])));
					//temp += kernel[m*yk+n] * input[(i+m)*yi+j+n]; 
				}
			}
        	ans[i*(ya)+j] = tmp[0]+tmp[1]+tmp[2]+tmp[3]+tmp[4]+tmp[5]+tmp[6]+tmp[7]+tmp[8]+tmp[9]+tmp[10]+tmp[11]+tmp[12]+tmp[13]+tmp[14]+tmp[15];
			//ans[i*(ya)+j] = temp;
		}
	}

内存对齐:

// aligned 原理
void* aligned_malloc(size_t required_bytes, size_t alignment)
{
    int offset = alignment - 1 + sizeof(void*);
    void* p1 = (void*)malloc(required_bytes + offset);
    if (p1 == NULL)
        return NULL;
    void** p2 = (void**)( ( (size_t)p1 + offset ) & ~(alignment - 1) );
    p2[-1] = p1;
    return p2;
}

void aligned_free(void *p2)
{
    void* p1 = ((void**)p2)[-1];
    free(p1);
}

Data Alignment to Assist Vectorization

向量化:
玩转SIMD指令编程 :https://zhuanlan.zhihu.com/p/591900754
Intrinsics for Intel® Advanced Vector Extensions 512 (Intel® AVX-512) Instructions

Xsimd :
https://github.com/xtensor-stack/xsimd

xsimd provides a unified means for using these features for library authors. Namely, it enables manipulation of batches of numbers with the same arithmetic operators as for single values. It also provides accelerated implementation of common mathematical functions operating on batches.

https://xsimd.readthedocs.io/en/latest/


参考资料

slurm作业管理系统怎么用?

矩阵乘法的并行优化(3):共享内存多核CPU优化

矩阵乘法优化过程(DGEMM)

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

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

相关文章

RabbitMQ之消息转换器

前言&#xff1a;大家好&#xff0c;我是小威&#xff0c;24届毕业生&#xff0c;曾经在某央企公司实习&#xff0c;目前在某税务公司。本篇文章将记录和分享RabbitMQ消息转换器的知识点。 本篇文章记录的基础知识&#xff0c;适合在学Java的小白&#xff0c;也适合复习中&…

深入理解机器学习——关联规则挖掘:基础知识

分类目录&#xff1a;《深入理解机器学习》总目录 许多商业企业在日复一日的运营中积聚了大量的数据。例如&#xff0c;食品商店的收银台每天都收集大量的顾客购物数据。下图给出一个这种数据的例子&#xff0c;通常称作购物篮事务&#xff08;Market Basket Transaction&#…

Elasticsearch基本使用初体验01

ElasticSearch是一款非常强大的、基于Lucene的开源搜索及分析引擎&#xff1b;它是一个实时的分布式搜索分析引擎&#xff0c;它能让你以前所未有的速度和规模&#xff0c;去探索你的数据。 1.es的安装 工欲善其事&#xff0c;必先利其器&#xff1b;想要学es&#xff0c;我们…

九龙证券|磷酸铁锂电池包和铅酸电池有哪些区别?

目前&#xff0c;新能源汽车电动车一般用的电池有3种&#xff0c;铅酸蓄电池、镍氢充电电池、锂离子电池。伴随着电动车蓄电池技能工艺的升级换代&#xff0c;锂电池的发展壮大和应用领域日益持续上升。那么&#xff0c;磷酸铁锂电池包和铅酸电池有哪些差异呢&#xff1f;铅酸蓄…

PowerShell 美化(oh-my-posh)

文章目录PowerShell 美化一、 添加右键菜单1、 修改默认右键菜单2、 寻找安装目录3、 修改注册表二、 样式修改1、 环境安装2、 配置使用PowerShell 美化 一、 添加右键菜单 1、 修改默认右键菜单 直接使用这个命令可以将 win11 的右键菜单修改为 win10 的右键菜单&#xff1…

基础数学(三)位运算 JZ 15.位1的个数

正在刷DFS相关题的时候突然间&#xff0c;给我蹦出来这样一个回溯题&#xff1a; 401. 二进制手表 二进制手表顶部有 4 个 LED 代表 小时&#xff08;0-11&#xff09;&#xff0c;底部的 6 个 LED 代表 分钟&#xff08;0-59&#xff09;。每个 LED 代表一个 0 或 1&#xff…

maven 解决Cannot access alimaven以及Process terminated

maven 解决Cannot access alimaven以及Process terminated 目录maven 解决Cannot access alimaven以及Process terminated方案一&#xff1a;用idea打开settings.xml&#xff0c;更正红色报错方案二&#xff1a;将IDEA的Maven默认版本更换成你下载的maven文件夹方案三&#xff…

单片机堆栈知识总结

堆栈 在片内RAM中&#xff0c;常常要指定一个专门的区域来存放某些特别的数据 它遵循顺序存取和后进先出(LIFO/FILO)的原则&#xff0c;这个RAM区叫堆栈。 其实堆栈就是单片机中的一些存储单元&#xff0c;这些存储单元被指定保存一些特殊信息&#xff0c;比如地址&#xff0…

DFS(二)岛屿问题合集

目录 一、 463. 岛屿的周长 二、 130. 被围绕的区域 三、 200. 岛屿数量 四、695. 岛屿的最大面积 一、463. 岛屿的周长 给定一个 row x col 的二维网格地图 grid &#xff0c;其中&#xff1a;grid[i][j] 1 表示陆地&#xff0c; grid[i][j] 0 表示水域。 网格中的格子 …

Java设计模式-解释器模式、解释器模式什么回事,抽象语法树又是什么

继续整理记录这段时间来的收获&#xff0c;详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用&#xff01; 6.12 解释器模式 6.12.1 概述 思维&#xff1a;翻译识别机器&#xff0c;如解析由数字、“”、“-”号构成的合法运算序列&#xff0c;若将数字和字符看作结点&a…

Lesson 4.1 逻辑回归模型构建与多分类学习方法

文章目录一、广义线性模型&#xff08;Generalized liner model&#xff09;的基本定义二、对数几率模型与逻辑回归1. 对数几率模型&#xff08;logit model&#xff09;2. 逻辑回归与 Sigmoid 函数3. Sigmoid 函数性质三、逻辑回归模型输出结果与模型可解释性四、多分类学习与…

CPU缓存一致性

CPU缓存一致性写直达写回缓存一致性总线嗅探MESI协议CPU Cache通常分为三级缓存&#xff0c;L1Cache&#xff0c;L2Cache,L3Cache&#xff0c;级别越低的离CPU越近&#xff0c;访问速度越快&#xff0c;但同时容量越小&#xff0c;价格越贵。在多核的CPU中&#xff0c;每个核都…

今天大年三十,新年快乐,我在这里给大家整理了一下除夕的习俗,来看看吧

今天是大年三十,阿玥在这里祝大家,一来风水,二来平安,阖家欢乐,四季平安,五福临门,六六大顺,七星高照,八方来财,十全十美,新年好! 名字:不晓得 学习:python,c 主页:木有 今天给大家整理一下大年三十的习俗等小知识,就不更python啦 目录 除夕要做的事情有什么…

Meta CTO:真正的全天候轻量化AR眼镜,可能要到2030年

去年Meta发布了售价高达1500美元的VST头显Quest Pro&#xff0c;该头显与Meta的Quest 2等产品在定价、技术路径上有很大不同&#xff0c;其搭载了眼球追踪、彩色VST等更高端的功能&#xff0c;而产品发布后&#xff0c;外界对其反馈也褒贬不一。作为Pro产品线首个产品&#xff…

Markdown基础总结

Markdown Tools TyporaVSCode Markdown Preview Enhanced扩展 有道云笔记… 上述工具都能很好地支持markdown书写 Markdown标题 1 使用 和 - 标记一级和二级标题 和 - 标记语法格式如下&#xff1a; 我展示的是一级标题我展示的是二级标题 ---效果如下: 2 使用 # 号标…

Java设计模式-访问者模式、访问者模式怎么使用,具体是怎么用

继续整理记录这段时间来的收获&#xff0c;详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用&#xff01; 6.10 访问者模式 6.10.1 定义 封装一些作用域某种数据结构中的各元素的操作&#xff0c;可以在不改变此数据结构的前提下定义作用于这些元素的新操作 6.10.2 结…

2023年新年烟花代码(背景音乐完整版)

文章目录前言烟花效果展示使用教程查看源码HTML代码CSS代码JavaScript新年祝福前言 大家过年好&#xff01;新春佳节&#xff0c;在这个充满喜悦的日子里&#xff0c;愿新年的钟声带给你一份希望和期待&#xff0c;我相信&#xff0c;时空的距离不能阻隔你我&#xff0c;我的祝…

Solidity 中的数学(第 5 部分:指数和对数

本文是关于在 Solidity 中进行数学运算的系列文章中的第五篇。这次的主题是&#xff1a;指数和对数 介绍 几个世纪以来&#xff0c;对数被用来简化计算。在电子计算器广泛普及之前&#xff0c;计算尺、基于对数的机械计算器是工程师职业的标志。 对数函数连同指数函数&#x…

【matplotlib】21.多图合并【python3、numpy、pandas、matplotlib完结】

#【matplotlib】21.多图合并 2023.1.20 python3、numpy、pandas、matplotlib完结 新年快乐&#xff01;&#xff01; 21.1 多合一显示 21.1.1 均匀分布 方法很简单 就是一张图 分几块 第一张占几块 从哪开始&#xff1b;第二张… plt.subplot() # 打开一个窗口 import ma…

Redis数据类型简介

目录 1、字符串(Strings) 1.1、底层实现 1.2、基本命令 1.3、应用场景 2、列表(Lists) 2.1、底层实现 2.2、基本命令 2.3、应用场景 3、集合(Sets) 3.1、底层实现 3.2、基本命令 3.3、应用场景 4、哈希(Hashes) 4.1、底层实现 4.2、基本命令 4.3、应用场景 5、…