▶ 使用CPU和GPU分别实现散列表

● CPU方法

 #include <stdio.h>
#include <time.h>
#include "cuda_runtime.h"
#include "D:\Code\CUDA\book\common\book.h" #define SIZE (100*1024*1024)
#define ELEMENTS (SIZE / sizeof(unsigned int))
#define HASH_ENTRIES (1024) struct Entry
{
unsigned int key;
void *value;
Entry *next;
}; struct Table
{
size_t count;
Entry **entries;
Entry *pool;
Entry *firstFree;
}; size_t hash(unsigned int key, size_t count)
{
return key % count;
} void initialize_table(Table &table, int entries, int elements)
{
table.count = entries;
table.entries = (Entry**)calloc(entries, sizeof(Entry*));
table.pool = (Entry*)malloc(elements * sizeof(Entry));
table.firstFree = table.pool;
} void free_table(Table &table)
{
free(table.entries);
free(table.pool);
} void add_to_table(Table &table, unsigned int key, void *value)
{
size_t hashValue = hash(key, table.count);
Entry *location = table.firstFree++;
location->key = key;
location->value = value;
location->next = table.entries[hashValue];// 插到该分支的头部而不是尾部
table.entries[hashValue] = location;
} void verify_table(const Table &table)
{
int count = ;
for (size_t i = ; i<table.count; i++)
{
Entry *current = table.entries[i];
while (current != NULL)
{
++count;
if (hash(current->key, table.count) != i)
printf("\n\t%d hashed to %ld, but was located at %ld\n", current->key, hash(current->key, table.count), i);
current = current->next;
}
}
if (count != ELEMENTS)
printf("\n\t%d elements found in hash table. Should be %ld\n",
count, ELEMENTS);
else
printf("\n\tAll %d elements found in hash table.\n", count);
} int main(void)
{
unsigned int *buffer =(unsigned int*)big_random_block(SIZE);
Table table;
clock_t start, stop; initialize_table(table, HASH_ENTRIES, ELEMENTS); start = clock();
for (int i = ; i<ELEMENTS; i++)
add_to_table(table, buffer[i], (void*)NULL); stop = clock();
printf("\n\tBuilding the table: %3.1f ms\n", (float)(stop - start) / (float)CLOCKS_PER_SEC * 1000.0f); verify_table(table);
free_table(table);
free(buffer);
getchar();
return ;
}

● GPU方法(用到了前面的原子锁)

 #include <stdio.h>
#include <time.h>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "cuda.h"
#include "D:\Code\CUDA\book\common\book.h" #define SIZE (100*1024*1024)
#define ELEMENTS (SIZE / sizeof(unsigned int))
#define HASH_ENTRIES (1024) struct Lock
{
int *mutex;
Lock(void)
{
int state = ;
cudaMalloc((void **)&mutex, sizeof(int));
cudaMemcpy(mutex, &state, sizeof(int), cudaMemcpyHostToDevice);
}
~Lock(void)
{
cudaFree(mutex);
}
__device__ void lock(void)
{
while (atomicCAS(mutex, , ) != );
}
__device__ void unlock(void)
{
atomicExch(mutex, );
}
}; struct Entry
{
unsigned int key;
void *value;
Entry *next;
}; struct Table
{
size_t count;
Entry **entries;
Entry *pool;
Entry *firstFree;
}; __device__ __host__ size_t hash(unsigned int key, size_t count)
{
return key % count;
} void initialize_table(Table &table, int entries, int elements)
{
table.count = entries;
cudaMalloc((void**)&table.entries, entries * sizeof(Entry*));
cudaMemset(table.entries, , entries * sizeof(Entry*));
cudaMalloc((void**)&table.pool, elements * sizeof(Entry));
} void free_table(Table &table)
{
cudaFree(table.entries);
cudaFree(table.pool);
} __global__ void add_to_table(unsigned int *keys, void **values, Table table, Lock *lock)
// 锁数组用于锁定散列表中的每一个桶
{
int tid = threadIdx.x + blockIdx.x * blockDim.x;
int stride = blockDim.x * gridDim.x;
while (tid < ELEMENTS)
{
unsigned int key = keys[tid];
size_t hashValue = hash(key, table.count);
for (int i = ; i<; i++)// 利用循环来分散线程束,使同一线程束中的32个线程在循环的不同次数时进行写入
{
if ((tid % ) == i)
{
Entry *location = &(table.pool[tid]);
location->key = key;
location->value = values[tid];
lock[hashValue].lock();
location->next = table.entries[hashValue];
table.entries[hashValue] = location;
lock[hashValue].unlock();
}
}
tid += stride;
}
} void copy_table_to_host(const Table &table, Table &hostTable)
{
hostTable.count = table.count;
hostTable.entries = (Entry**)calloc(table.count, sizeof(Entry*));
hostTable.pool = (Entry*)malloc(ELEMENTS * sizeof(Entry)); cudaMemcpy(hostTable.entries, table.entries, table.count * sizeof(Entry*), cudaMemcpyDeviceToHost);
cudaMemcpy(hostTable.pool, table.pool, ELEMENTS * sizeof(Entry), cudaMemcpyDeviceToHost); for (int i = ; i < table.count; i++)
{
if (hostTable.entries[i] != NULL)
hostTable.entries[i] = (Entry*)((size_t)hostTable.entries[i] - (size_t)table.pool + (size_t)hostTable.pool);
// 从从显存到内存的地址线性偏移 x - adressGPU + addressCPU
}
for (int i = ; i < ELEMENTS; i++)
{
if (hostTable.pool[i].next != NULL)
hostTable.pool[i].next = (Entry*)((size_t)hostTable.pool[i].next - (size_t)table.pool + (size_t)hostTable.pool);
// 同样是做偏移,但是要找到下一个元素的地址
}
} void verify_table(const Table &dev_table)
{
Table table;
copy_table_to_host(dev_table, table); int count = ;
for (size_t i = ; i < table.count; i++)
{
Entry *current = table.entries[i];
while (current != NULL)
{
++count;
if (hash(current->key, table.count) != i)
printf("%d hashed to %ld, but was located at %ld\n", current->key, hash(current->key, table.count), i);
current = current->next;
}
}
if (count != ELEMENTS)
printf("%d elements found in hash table. Should be %ld\n", count, ELEMENTS);
else
printf("All %d elements found in hash table.\n", count);
} int main(void)
{
unsigned int *buffer = (unsigned int*)big_random_block(SIZE); unsigned int *dev_keys;
void **dev_values;
cudaMalloc((void**)&dev_keys, SIZE);
cudaMalloc((void**)&dev_values, SIZE);
cudaMemcpy(dev_keys, buffer, SIZE, cudaMemcpyHostToDevice); Table table;
initialize_table(table, HASH_ENTRIES, ELEMENTS); Lock lock[HASH_ENTRIES];// 准备锁列表
Lock *dev_lock;
cudaMalloc((void**)&dev_lock, HASH_ENTRIES * sizeof(Lock));
cudaMemcpy(dev_lock, lock, HASH_ENTRIES * sizeof(Lock), cudaMemcpyHostToDevice); cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start, ); add_to_table << <, >> >(dev_keys, dev_values, table, dev_lock); cudaEventRecord(stop, );
cudaEventSynchronize(stop);
float elapsedTime;
cudaEventElapsedTime(&elapsedTime, start, stop);
printf("Time to hash: %3.1f ms\n", elapsedTime); verify_table(table);
free_table(table); cudaEventDestroy(start);
cudaEventDestroy(stop);
free_table(table);
cudaFree(dev_lock);
cudaFree(dev_keys);
cudaFree(dev_values);
free(buffer);
getchar();
return ;
}

《GPU高性能编程CUDA实战》附录二 散列表的更多相关文章

  1. [问题解决]《GPU高性能编程CUDA实战》中第4章Julia实例“显示器驱动已停止响应,并且已恢复”问题的解决方法

    以下问题的出现及解决都基于"WIN7+CUDA7.5". 问题描述:当我编译运行<GPU高性能编程CUDA实战>中第4章所给Julia实例代码时,出现了显示器闪动的现象 ...

  2. 《GPU高性能编程CUDA实战》附录四 其他头文件

    ▶ cpu_bitmap.h #ifndef __CPU_BITMAP_H__ #define __CPU_BITMAP_H__ #include "gl_helper.h" st ...

  3. 《GPU高性能编程CUDA实战》附录一 高级原子操作

    ▶ 本章介绍了手动实现原子操作.重构了第五章向量点积的过程.核心是通过定义结构Lock及其运算,实现锁定,读写,解锁的过程. ● 章节代码 #include <stdio.h> #incl ...

  4. 《GPU高性能编程CUDA实战》附录三 关于book.h

    ▶ 本书中用到的公用函数放到了头文件book.h中 #ifndef __BOOK_H__ #define __BOOK_H__ #include <stdio.h> #include &l ...

  5. 《GPU高性能编程CUDA实战》第五章 线程并行

    ▶ 本章介绍了线程并行,并给出四个例子.长向量加法.波纹效果.点积和显示位图. ● 长向量加法(线程块并行 + 线程并行) #include <stdio.h> #include &quo ...

  6. 《GPU高性能编程CUDA实战》第十一章 多GPU系统的CUDA C

    ▶ 本章介绍了多设备胸膛下的 CUDA 编程,以及一些特殊存储类型对计算速度的影响 ● 显存和零拷贝内存的拷贝与计算对比 #include <stdio.h> #include " ...

  7. 《GPU高性能编程CUDA实战》第七章 纹理内存

    ▶ 本章介绍了纹理内存的使用,并给出了热传导的两个个例子.分别使用了一维和二维纹理单元. ● 热传导(使用一维纹理) #include <stdio.h> #include "c ...

  8. 《GPU高性能编程CUDA实战》第四章 简单的线程块并行

    ▶ 本章介绍了线程块并行,并给出两个例子:长向量加法和绘制julia集. ● 长向量加法,中规中矩的GPU加法,包含申请内存和显存,赋值,显存传入,计算,显存传出,处理结果,清理内存和显存.用到了 t ...

  9. 《GPU高性能编程CUDA实战》第八章 图形互操作性

    ▶ OpenGL与DirectX,等待填坑. ● basic_interop #include <stdio.h> #include "cuda_runtime.h" ...

随机推荐

  1. PR4

    4.1视频切换特效: 视频切换:视频和视频之间的过渡 4.2特效参数设置方法 4.3视频切换特效的技巧 多张图片,拖入特效慢. 选中多张图片 右键选中“设置所选..” 设置图片时间: 点常规后 设置完 ...

  2. Codeforces Beta Round #81 A Transmigration

    在魔界战记中有一个设定叫做转生,当一个人物转生时,会保留之前的技能,但是技能等级需要乘以一个系数 k ,如果技能等级小于100,将会在转生之后失去该技能. 转生之后,会学到一些新技能.这些新技能附加的 ...

  3. test20181004 苹果树

    题意 分析 对每个点维护子树所能达到的dfn最大值.最小值.次大值.次小值,然后就可以计算原树中每个点与父亲的连边对答案的贡献. 如果子树中没有边能脱离子树,断掉该边与任意一条新加的边都成立,答案就加 ...

  4. HDU3584 Cube

    分析 三维树状数组,跟二维的差不多,只不过容斥的不一样. 更新区间\((x_1,y_1,z_1)\rightarrow(x_2,y_2,z_2)\)时,需要利用容斥原理.须要更新的节点更新如下: \[ ...

  5. dbt 包依赖简单测试

    dbt 包含一个自己的包管理,可以使用git 等工具,还是很方便的,可以方便的进行代码共享,实现复用 创建简单包 实际上就是一个简单的dbt 项目,参考项目 https://gitlab.com/da ...

  6. 一个简单的批量更新oracle 数据库中 最近的服务商名称的数据

    有一个需求是这样的,我们需要更新数据库中的数据,数据时这样的 1.大约50万以上 2. 数据中有较多的重复数据 3. 需要将表中最近的代理商的名称赋值给行中的服务商名称 4. 代理商的名称可能有多个, ...

  7. linux系统的启动过程及系统初始化

    (其中/etc/inittab是一个很重要的文件,值得细究http://www.2cto.com/os/201108/98426.html) 其开头的446字节内容特指为"主引导记录&quo ...

  8. centos7.x网卡bond配置

    本文摘抄自 https://www.cnblogs.com/liwanggui/p/6807212.html centos7网卡bond配置 centos7网卡bond配置 1 备份网卡配置文件2 使 ...

  9. linux日志分析

    转一位大神的笔记. 日志管理: 1.基于服务的 2.基于时间的 /var/log/wtmp,/var/run/utmp,/var/log/lastlog(lastlog),/var/log/btmp( ...

  10. Array、ArrayList 区别

    ArrayList可以算是Array的加强版,(对array有所取舍的加强). 存储内容比较(可包含元素的类型不同.数组要求存储同种类型): Array数组可以包含基本类型和对象类型, ArrayLi ...