Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
机器未来
Paddle
提交
bbd3eab7
P
Paddle
项目概览
机器未来
/
Paddle
与 Fork 源项目一致
Fork自
PaddlePaddle / Paddle
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
Paddle
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
bbd3eab7
编写于
7月 03, 2017
作者:
L
liaogang
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
ENH: Add Alloc for buddy Allocator
* Free will be added soon
上级
929f9cbd
变更
2
显示空白变更内容
内联
并排
Showing
2 changed file
with
209 addition
and
36 deletion
+209
-36
paddle/memory/detail/buddy_allocator.cc
paddle/memory/detail/buddy_allocator.cc
+148
-9
paddle/memory/detail/buddy_allocator.h
paddle/memory/detail/buddy_allocator.h
+61
-27
未找到文件。
paddle/memory/detail/buddy_allocator.cc
浏览文件 @
bbd3eab7
...
...
@@ -12,22 +12,161 @@
See the License for the specific language governing permissions and
limitations under the License. */
#pragma once
#include "paddle/memory/detail/buddy_allocator.h"
#include "glog/logging.h"
namespace
paddle
{
namespace
memory
{
namespace
detail
{
BuddyAllocator
::
BuddyAllocator
(
size_t
pool_size
,
size_t
max_pools
,
SystemAllocator
*
system_allocator
)
:
pool_size_
(
pool_size
),
max_pools_
(
max_pools
),
system_allocator_
(
system_allocator
)
{
PADDLE_ASSERT
(
pool_size
>
0
);
PADDLE_ASSERT
(
max_pools
>
0
);
BuddyAllocator
::
BuddyAllocator
(
SystemAllocator
*
system_allocator
,
size_t
min_chunk_size
,
size_t
max_chunk_size
)
{
PADDLE_ASSERT
(
min_chunk_size
>
0
);
PADDLE_ASSERT
(
max_chunk_size
>
0
);
PADDLE_ASSERT
(
system_allocator
!=
nullptr
);
system_allocator_
=
std
::
move
(
system_allocator
);
min_chunk_size_
=
min_chunk_size
;
max_chunk_size_
=
max_chunk_size
;
}
inline
size_t
align
(
size_t
size
,
size_t
alignment
)
{
size_t
remaining
=
size
%
alignment
;
return
remaining
==
0
?
size
:
size
+
(
alignment
-
remaining
);
}
void
*
BuddyAllocator
::
Alloc
(
size_t
unaligned_size
)
{
// adjust allocation alignment
size_t
size
=
align
(
unaligned_size
+
sizeof
(
Metadata
),
min_chunk_size_
);
// acquire the allocator lock
std
::
lock_guard
<
std
::
mutex
>
lock
(
mutex_
);
DLOG
(
INFO
)
<<
"Allocate "
<<
unaligned_size
<<
" bytes from chunk size "
<<
size
;
// if the allocation is huge, send directly to the system allocator
if
(
size
>
max_chunk_size_
)
{
DLOG
(
INFO
)
<<
"Allocate from system allocator."
;
return
SystemAlloc
(
size
);
}
// query and allocate from the existing chunk
auto
it
=
FindExistChunk
(
size
);
// refill the pool if failure
if
(
it
==
pool_
.
end
())
{
it
=
RefillPool
();
}
else
{
DLOG
(
INFO
)
<<
" Allocation from existing memory block "
<<
std
::
get
<
2
>
(
*
it
)
<<
" at address "
<<
reinterpret_cast
<
MemoryBlock
*>
(
std
::
get
<
2
>
(
*
it
))
->
data
();
}
// if still failure, fail fatally
if
(
it
==
pool_
.
end
())
{
return
nullptr
;
}
total_used_
+=
size
;
total_free_
-=
size
;
// split the allocation and return data for use
return
reinterpret_cast
<
MemoryBlock
*>
(
SplitToAlloc
(
it
,
size
))
->
data
();
}
void
*
BuddyAllocator
::
SystemAlloc
(
size_t
size
)
{
size_t
index
=
0
;
void
*
p
=
system_allocator_
->
Alloc
(
index
,
size
);
DLOG
(
INFO
)
<<
"Allocated "
<<
p
<<
" from system allocator."
;
if
(
p
==
nullptr
)
return
nullptr
;
static_cast
<
MemoryBlock
*>
(
p
)
->
init
(
cache_
,
MemoryBlock
::
HUGE_CHUNK
,
index
,
size
,
nullptr
,
nullptr
);
return
static_cast
<
MemoryBlock
*>
(
p
)
->
data
();
}
BuddyAllocator
::
PoolSet
::
iterator
BuddyAllocator
::
RefillPool
()
{
#ifndef PADDLE_ONLY_CPU
if
(
system_allocator_
->
UseGpu
())
{
if
((
total_used_
+
total_free_
)
==
0
)
{
// Compute the maximum allocation size for the first allocation.
max_chunk_size_
=
platform
::
GpuMaxChunkSize
();
}
}
#endif // PADDLE_ONLY_CPU
// Allocate a new maximum sized block
size_t
index
=
0
;
void
*
p
=
system_allocator_
->
Alloc
(
index
,
max_chunk_size_
);
if
(
p
==
nullptr
)
return
pool_
.
end
();
DLOG
(
INFO
)
<<
" Creating and inserting new block "
<<
p
<<
" from system allocator"
;
static_cast
<
MemoryBlock
*>
(
p
)
->
init
(
cache_
,
MemoryBlock
::
FREE_CHUNK
,
index
,
max_chunk_size_
,
nullptr
,
nullptr
);
total_free_
+=
max_chunk_size_
;
// dump the block into pool
return
pool_
.
insert
({
index
,
max_chunk_size_
,
p
}).
first
;
}
BuddyAllocator
::
PoolSet
::
iterator
BuddyAllocator
::
FindExistChunk
(
size_t
size
)
{
size_t
index
=
0
;
while
(
1
)
{
auto
it
=
pool_
.
lower_bound
({
index
,
size
,
nullptr
});
if
(
it
==
pool_
.
end
())
return
it
;
if
(
std
::
get
<
0
>
(
*
it
)
>
index
)
{
if
(
std
::
get
<
1
>
(
*
it
)
>=
size
)
{
return
it
;
}
index
=
std
::
get
<
0
>
(
*
it
);
continue
;
}
return
it
;
}
}
void
*
BuddyAllocator
::
SplitToAlloc
(
BuddyAllocator
::
PoolSet
::
iterator
it
,
size_t
size
)
{
auto
block
=
static_cast
<
MemoryBlock
*>
(
std
::
get
<
2
>
(
*
it
));
pool_
.
erase
(
it
);
DLOG
(
INFO
)
<<
" Split block ("
<<
block
<<
", "
<<
block
->
total_size
(
cache_
)
<<
") into"
;
block
->
split
(
cache_
,
size
);
DLOG
(
INFO
)
<<
" Left block ("
<<
block
<<
", "
<<
block
->
total_size
(
cache_
)
<<
")"
;
block
->
set_type
(
cache_
,
MemoryBlock
::
ARENA_CHUNK
);
// the rest of memory if exist
if
(
block
->
has_right_buddy
(
cache_
))
{
if
(
block
->
right_buddy
(
cache_
)
->
type
(
cache_
)
==
MemoryBlock
::
FREE_CHUNK
)
{
DLOG
(
INFO
)
<<
" Insert right block ("
<<
block
->
right_buddy
(
cache_
)
<<
", "
<<
block
->
right_buddy
(
cache_
)
->
total_size
(
cache_
)
<<
")"
;
pool_
.
insert
({
block
->
right_buddy
(
cache_
)
->
index
(
cache_
),
block
->
right_buddy
(
cache_
)
->
total_size
(
cache_
),
block
->
right_buddy
(
cache_
)});
}
}
return
block
;
}
}
// namespace detail
...
...
paddle/memory/detail/buddy_allocator.h
浏览文件 @
bbd3eab7
...
...
@@ -15,9 +15,15 @@
#pragma once
#include "paddle/memory/detail/system_allocator.h"
#include "paddle/memory/detail/metadata.h"
#include "paddle/platform/assert.h"
#include "paddle/platform/cpu_info.h"
#include "paddle/platform/gpu_info.h"
#include <set>
#include <mutex>
#include <vector>
#include <unordered_map>
namespace
paddle
{
namespace
memory
{
...
...
@@ -25,55 +31,83 @@ namespace detail {
class
BuddyAllocator
{
public:
BuddyAllocator
(
size_t
pool_size
,
size_t
max_pools
,
SystemAllocator
*
system_allocator
);
BuddyAllocator
(
SystemAllocator
*
system_allocator
,
size_t
min_chunk_size
,
size_t
max_chunk_size
);
~
BuddyAllocator
();
void
*
Alloc
(
size_t
size
);
public:
void
*
Alloc
(
size_t
unaligned_size
);
void
Free
(
void
*
);
size_t
Used
();
public:
// Disable copy and assignment.
BuddyAllocator
(
const
BuddyAllocator
&
)
=
delete
;
BuddyAllocator
&
operator
=
(
const
BuddyAllocator
&
)
=
delete
;
private:
struct
Block
{
size_t
size_
;
Block
*
left_
;
// left buddy
Block
*
right_
;
// right buddy
};
// Tuple type: allocator index, memory size, memory address
using
IndexSizeAddress
=
std
::
tuple
<
size_t
,
size_t
,
void
*>
;
using
PoolSet
=
std
::
set
<
IndexSizeAddress
>
;
// Initially, there is only one pool. If a Alloc founds not enough
// memory from that pool, and there has not been max_num_pools_,
// create a new pool by calling system_allocator_.Alloc(pool_size_).
std
::
vector
<
void
*>
pools_
;
/*! \brief Allocate fixed-size memory from system */
void
*
SystemAlloc
(
size_t
size
);
size_t
pool_size_
;
// the size of each pool;
size_t
max_num_pools_
;
// the size of all pools
;
/*! \brief If existing chunks are not suitable, refill pool */
PoolSet
::
iterator
RefillPool
()
;
SystemAllocator
*
system_allocator_
;
/**
* \brief Find the suitable chunk from existing pool
*
* \param it pool iterator which contains suitable block.
* \param size the size of allocation.
*/
void
*
SplitToAlloc
(
PoolSet
::
iterator
it
,
size_t
size
);
std
::
mutex
mutex_
;
/*! \brief Find the existing chunk which used to allocation */
PoolSet
::
iterator
FindExistChunk
(
size_t
size
);
// Disable copy and assignment.
BuddyAllocator
(
const
BuddyAllocator
&
)
=
delete
;
BuddyAllocator
&
operator
=
(
const
BuddyAllocator
&
)
=
delete
;
private:
size_t
total_used_
=
0
;
// the total size of used memory
size_t
total_free_
=
0
;
// the total size of free memory
size_t
min_chunk_size_
;
// the minimum size of each chunk
size_t
max_chunk_size_
;
// the maximum size of each chunk
private:
PoolSet
pool_
;
private:
// Unify the metadata format between GPU and CPU allocations
using
MetadataCache
=
std
::
unordered_map
<
const
MemoryBlock
*
,
Metadata
>
;
MetadataCache
cache_
;
private:
SystemAllocator
*
system_allocator_
;
std
::
mutex
mutex_
;
};
BuddyAllocator
<
CPUAllocator
>
*
GetCPUBuddyAllocator
()
{
static
BuddyAllocator
<
CPUAllocator
>
*
a
=
nullptr
;
BuddyAllocator
*
GetCPUBuddyAllocator
()
{
static
BuddyAllocator
*
a
=
nullptr
;
if
(
a
==
nullptr
)
{
a
=
new
BuddyAllocator
<
CPUAllocator
>
();
a
=
new
BuddyAllocator
(
new
CPUAllocator
,
platform
::
CpuMinChunkSize
(),
platform
::
CpuMaxChunkSize
());
}
return
a
;
}
#ifndef PADDLE_ONLY_CPU // The following code are for CUDA.
BuddyAllocator
<
GPUAllocator
>
*
GetGPUBuddyAllocator
(
int
gpu_id
)
{
static
BuddyAllocator
<
GPUAllocator
>
**
as
=
NULL
;
BuddyAllocator
*
GetGPUBuddyAllocator
(
int
gpu_id
)
{
static
BuddyAllocator
**
as
=
NULL
;
if
(
as
==
NULL
)
{
int
gpu_num
=
platform
::
G
et
DeviceCount
();
as
=
new
BuddyAllocator
<
GPUAllocator
>
*
[
gpu_num
];
int
gpu_num
=
platform
::
G
pu
DeviceCount
();
as
=
new
BuddyAllocator
*
[
gpu_num
];
for
(
int
gpu
=
0
;
gpu
<
gpu_num
;
gpu
++
)
{
as
[
gpu
]
=
new
BuddyAllocator
<
GPUAllocator
>
();
as
[
gpu
]
=
new
BuddyAllocator
(
new
GPUAllocator
,
platform
::
GpuMinChunkSize
(),
platform
::
GpuMaxChunkSize
());
}
}
return
as
[
gpu_id
];
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录