Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
F
folly
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
folly
Commits
569f5f14
Commit
569f5f14
authored
Aug 21, 2012
by
Tudor Bosman
Committed by
Jordan DeLong
Sep 16, 2012
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Huge page library.
Test Plan: by hand Reviewed By: lucian@fb.com FB internal diff: D555164
parent
f2f512b4
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
511 additions
and
0 deletions
+511
-0
folly/experimental/io/HugePageUtil.cpp
folly/experimental/io/HugePageUtil.cpp
+103
-0
folly/experimental/io/HugePages.cpp
folly/experimental/io/HugePages.cpp
+331
-0
folly/experimental/io/HugePages.h
folly/experimental/io/HugePages.h
+77
-0
No files found.
folly/experimental/io/HugePageUtil.cpp
0 → 100644
View file @
569f5f14
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
#include <stdexcept>
#include <system_error>
#include <gflags/gflags.h>
#include "folly/experimental/io/HugePages.h"
#include "folly/Format.h"
#include "folly/Range.h"
#include "folly/ScopeGuard.h"
DEFINE_bool
(
cp
,
false
,
"Copy file"
);
using
namespace
folly
;
namespace
{
void
usage
(
const
char
*
name
)
__attribute__
((
noreturn
));
void
usage
(
const
char
*
name
)
{
std
::
cerr
<<
folly
::
format
(
"Usage: {0}
\n
"
" list all huge page sizes and their mount points
\n
"
" {0} -cp <src_file> <dest_nameprefix>
\n
"
" copy src_file to a huge page file
\n
"
,
name
);
exit
(
1
);
}
void
copy
(
const
char
*
srcFile
,
const
char
*
destPrefix
)
{
int
srcfd
=
open
(
srcFile
,
O_RDONLY
);
if
(
srcfd
==
-
1
)
{
throw
std
::
system_error
(
errno
,
std
::
system_category
(),
"open failed"
);
}
SCOPE_EXIT
{
close
(
srcfd
);
};
struct
stat
st
;
if
(
fstat
(
srcfd
,
&
st
)
==
-
1
)
{
throw
std
::
system_error
(
errno
,
std
::
system_category
(),
"fstat failed"
);
}
void
*
start
=
mmap
(
nullptr
,
st
.
st_size
,
PROT_READ
,
MAP_SHARED
,
srcfd
,
0
);
if
(
start
==
MAP_FAILED
)
{
throw
std
::
system_error
(
errno
,
std
::
system_category
(),
"mmap failed"
);
}
SCOPE_EXIT
{
munmap
(
start
,
st
.
st_size
);
};
HugePages
hp
;
auto
f
=
hp
.
create
(
ByteRange
(
static_cast
<
const
unsigned
char
*>
(
start
),
st
.
st_size
),
destPrefix
);
std
::
cout
<<
f
.
path
<<
"
\n
"
;
}
void
list
()
{
HugePages
hp
;
for
(
auto
&
p
:
hp
.
sizes
())
{
std
::
cout
<<
p
.
first
<<
" "
<<
p
.
second
<<
"
\n
"
;
}
}
}
// namespace
int
main
(
int
argc
,
char
*
argv
[])
{
google
::
ParseCommandLineFlags
(
&
argc
,
&
argv
,
true
);
if
(
FLAGS_cp
)
{
if
(
argc
!=
3
)
usage
(
argv
[
0
]);
copy
(
argv
[
1
],
argv
[
2
]);
}
else
{
if
(
argc
!=
1
)
usage
(
argv
[
0
]);
list
();
}
return
0
;
}
folly/experimental/io/HugePages.cpp
0 → 100644
View file @
569f5f14
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "folly/experimental/io/HugePages.h"
#include <sys/mman.h>
#include <cctype>
#include <cstring>
#include <algorithm>
#include <stdexcept>
#include <system_error>
#include <boost/filesystem.hpp>
#include <boost/noncopyable.hpp>
#include <boost/regex.hpp>
#include <glog/logging.h>
#include "folly/Conv.h"
#include "folly/Format.h"
#include "folly/Range.h"
#include "folly/ScopeGuard.h"
#include "folly/String.h"
#include "folly/experimental/io/Stream.h"
namespace
fs
=
::
boost
::
filesystem
;
namespace
folly
{
namespace
{
// Get the default huge page size
size_t
getDefaultHugePageSize
()
{
// We need to parse /proc/meminfo
static
const
boost
::
regex
regex
(
R"!(Hugepagesize:\s*(\d+)\s*kB)!"
);
boost
::
cmatch
match
;
for
(
auto
&
byteLine
:
byLine
(
"/proc/meminfo"
))
{
StringPiece
line
(
byteLine
);
if
(
boost
::
regex_match
(
line
.
begin
(),
line
.
end
(),
match
,
regex
))
{
StringPiece
numStr
(
line
.
begin
()
+
match
.
position
(
1
),
match
.
length
(
1
));
return
to
<
size_t
>
(
numStr
)
*
1024
;
// in KiB
}
}
throw
std
::
runtime_error
(
"Can't find default huge page size"
);
}
// Get raw huge page sizes (without mount points, they'll be filled later)
HugePageSizeVec
getRawHugePageSizes
()
{
// We need to parse file names from /sys/kernel/mm/hugepages
static
const
boost
::
regex
regex
(
R"!(hugepages-(\d+)kB)!"
);
boost
::
smatch
match
;
HugePageSizeVec
vec
;
fs
::
path
path
(
"/sys/kernel/mm/hugepages"
);
for
(
fs
::
directory_iterator
it
(
path
);
it
!=
fs
::
directory_iterator
();
++
it
)
{
std
::
string
filename
(
it
->
path
().
filename
().
native
());
if
(
boost
::
regex_match
(
filename
,
match
,
regex
))
{
StringPiece
numStr
(
filename
.
data
()
+
match
.
position
(
1
),
match
.
length
(
1
));
vec
.
emplace_back
(
to
<
size_t
>
(
numStr
)
*
1024
,
""
);
}
}
return
vec
;
}
// Parse the value of a pagesize mount option
// Format: number, optional K/M/G/T suffix, trailing junk allowed
size_t
parsePageSizeValue
(
StringPiece
value
)
{
static
const
boost
::
regex
regex
(
R"!((\d+)([kmgt])?.*)!"
,
boost
::
regex
::
icase
);
boost
::
cmatch
match
;
if
(
!
boost
::
regex_match
(
value
.
begin
(),
value
.
end
(),
match
,
regex
))
{
throw
std
::
runtime_error
(
"Invalid pagesize option"
);
}
char
c
=
'\0'
;
if
(
match
.
length
(
2
)
!=
0
)
{
c
=
tolower
(
value
[
match
.
position
(
2
)]);
}
StringPiece
numStr
(
value
.
data
()
+
match
.
position
(
1
),
match
.
length
(
1
));
size_t
size
=
to
<
size_t
>
(
numStr
);
switch
(
c
)
{
case
't'
:
size
*=
1024
;
case
'g'
:
size
*=
1024
;
case
'm'
:
size
*=
1024
;
case
'k'
:
size
*=
1024
;
}
return
size
;
}
/**
* Get list of supported huge page sizes and their mount points, if
* hugetlbfs file systems are mounted for those sizes.
*/
HugePageSizeVec
getHugePageSizes
()
{
HugePageSizeVec
sizeVec
=
getRawHugePageSizes
();
if
(
sizeVec
.
empty
())
{
return
sizeVec
;
// nothing to do
}
std
::
sort
(
sizeVec
.
begin
(),
sizeVec
.
end
());
size_t
defaultHugePageSize
=
getDefaultHugePageSize
();
struct
PageSizeLess
{
bool
operator
()(
const
std
::
pair
<
size_t
,
std
::
string
>&
a
,
size_t
b
)
const
{
return
a
.
first
<
b
;
}
bool
operator
()(
size_t
a
,
const
std
::
pair
<
size_t
,
std
::
string
>&
b
)
const
{
return
a
<
b
.
first
;
}
};
// Read and parse /proc/mounts
std
::
vector
<
StringPiece
>
parts
;
std
::
vector
<
StringPiece
>
options
;
for
(
auto
&
byteLine
:
byLine
(
"/proc/mounts"
))
{
StringPiece
line
(
byteLine
);
parts
.
clear
();
split
(
" "
,
line
,
parts
);
// device path fstype options uid gid
if
(
parts
.
size
()
!=
6
)
{
throw
std
::
runtime_error
(
"Invalid /proc/mounts line"
);
}
if
(
parts
[
2
]
!=
"hugetlbfs"
)
{
continue
;
// we only care about hugetlbfs
}
options
.
clear
();
split
(
","
,
parts
[
3
],
options
);
size_t
pageSize
=
defaultHugePageSize
;
// Search for the "pagesize" option, which must have a value
for
(
auto
&
option
:
options
)
{
// key=value
const
char
*
p
=
static_cast
<
const
char
*>
(
memchr
(
option
.
data
(),
'='
,
option
.
size
()));
if
(
!
p
)
{
continue
;
}
if
(
StringPiece
(
option
.
data
(),
p
)
!=
"pagesize"
)
{
continue
;
}
pageSize
=
parsePageSizeValue
(
StringPiece
(
p
+
1
,
option
.
end
()));
break
;
}
auto
pos
=
std
::
lower_bound
(
sizeVec
.
begin
(),
sizeVec
.
end
(),
pageSize
,
PageSizeLess
());
if
(
pos
==
sizeVec
.
end
()
||
pos
->
first
!=
pageSize
)
{
throw
std
::
runtime_error
(
"Mount page size not found"
);
}
if
(
pos
->
second
.
empty
())
{
// Store mount point
pos
->
second
.
assign
(
parts
[
1
].
data
(),
parts
[
1
].
size
());
}
}
return
sizeVec
;
}
// RAII wrapper around an open file, closes on exit unless you call release()
class
ScopedFd
:
private
boost
::
noncopyable
{
public:
explicit
ScopedFd
(
int
fd
)
:
fd_
(
fd
)
{
}
int
fd
()
const
{
return
fd_
;
}
void
release
()
{
fd_
=
-
1
;
}
void
close
()
{
if
(
fd_
==
-
1
)
{
return
;
}
int
r
=
::
close
(
fd_
);
fd_
=
-
1
;
if
(
r
==
-
1
)
{
throw
std
::
system_error
(
errno
,
std
::
system_category
(),
"close failed"
);
}
}
~
ScopedFd
()
{
try
{
close
();
}
catch
(...)
{
PLOG
(
ERROR
)
<<
"close failed!"
;
}
}
private:
int
fd_
;
};
// RAII wrapper that deletes a file upon destruction unless you call release()
class
ScopedDeleter
:
private
boost
::
noncopyable
{
public:
explicit
ScopedDeleter
(
std
::
string
name
)
:
name_
(
std
::
move
(
name
))
{
}
void
release
()
{
name_
.
clear
();
}
~
ScopedDeleter
()
{
if
(
name_
.
empty
())
{
return
;
}
int
r
=
::
unlink
(
name_
.
c_str
());
if
(
r
==
-
1
)
{
PLOG
(
ERROR
)
<<
"unlink failed"
;
}
}
private:
std
::
string
name_
;
};
// RAII wrapper around a mmap mapping, munmaps upon destruction unless you
// call release()
class
ScopedMmap
:
private
boost
::
noncopyable
{
public:
ScopedMmap
(
void
*
start
,
size_t
size
)
:
start_
(
start
),
size_
(
size
)
{
}
void
*
start
()
const
{
return
start_
;
}
size_t
size
()
const
{
return
size_
;
}
void
release
()
{
start_
=
MAP_FAILED
;
}
void
munmap
()
{
if
(
start_
==
MAP_FAILED
)
{
return
;
}
int
r
=
::
munmap
(
start_
,
size_
);
start_
=
MAP_FAILED
;
if
(
r
==
-
1
)
{
throw
std
::
system_error
(
errno
,
std
::
system_category
(),
"munmap failed"
);
}
}
~
ScopedMmap
()
{
try
{
munmap
();
}
catch
(...)
{
PLOG
(
ERROR
)
<<
"munmap failed!"
;
}
}
private:
void
*
start_
;
size_t
size_
;
};
}
// namespace
HugePages
::
HugePages
()
:
sizes_
(
getHugePageSizes
())
{
}
HugePages
::
File
HugePages
::
create
(
ByteRange
data
,
StringPiece
baseName
,
size_t
hugePageSize
,
mode_t
mode
)
const
{
// Pick an appropriate size.
StringPiece
mountPath
;
if
(
hugePageSize
==
0
)
{
for
(
auto
&
p
:
sizes_
)
{
if
(
p
.
second
.
empty
())
{
continue
;
// not mounted
}
hugePageSize
=
p
.
first
;
mountPath
=
StringPiece
(
p
.
second
);
break
;
}
if
(
hugePageSize
==
0
)
{
throw
std
::
runtime_error
(
"No huge page filesystem mounted"
);
}
}
else
{
// Linear search is just fine
for
(
auto
&
p
:
sizes_
)
{
if
(
p
.
first
==
hugePageSize
)
{
if
(
p
.
second
.
empty
())
{
throw
std
::
runtime_error
(
"No huge page filesystem mounted with requested page size"
);
}
mountPath
=
StringPiece
(
p
.
second
);
}
}
if
(
mountPath
.
empty
())
{
throw
std
::
runtime_error
(
"Requested huge page size not found"
);
}
}
// Round size up
File
file
;
file
.
size
=
data
.
size
()
/
hugePageSize
*
hugePageSize
;
if
(
file
.
size
!=
data
.
size
())
{
file
.
size
+=
hugePageSize
;
}
file
.
path
=
folly
::
format
(
"{}/{}"
,
mountPath
,
baseName
).
str
();
ScopedFd
fd
(
open
(
file
.
path
.
c_str
(),
O_RDWR
|
O_CREAT
|
O_TRUNC
,
mode
));
if
(
fd
.
fd
()
==
-
1
)
{
throw
std
::
system_error
(
errno
,
std
::
system_category
(),
"open failed"
);
}
ScopedDeleter
deleter
(
file
.
path
);
ScopedMmap
map
(
mmap
(
nullptr
,
file
.
size
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
fd
.
fd
(),
0
),
file
.
size
);
if
(
map
.
start
()
==
MAP_FAILED
)
{
throw
std
::
system_error
(
errno
,
std
::
system_category
(),
"mmap failed"
);
}
memcpy
(
map
.
start
(),
data
.
data
(),
data
.
size
());
map
.
munmap
();
deleter
.
release
();
fd
.
close
();
return
file
;
}
}
// namespace folly
folly/experimental/io/HugePages.h
0 → 100644
View file @
569f5f14
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOLLY_IO_HUGEPAGES_H_
#define FOLLY_IO_HUGEPAGES_H_
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <cstddef>
#include <string>
#include <utility>
#include <vector>
#include "folly/Range.h"
namespace
folly
{
/**
* Vector of (huge_page_size, mount_point), sorted by huge_page_size.
* mount_point might be empty if no hugetlbfs file system is mounted for
* that size.
*/
typedef
std
::
vector
<
std
::
pair
<
size_t
,
std
::
string
>>
HugePageSizeVec
;
/**
* Class to interface with Linux huge pages (hugetlbfs).
*/
class
HugePages
{
public:
HugePages
();
/**
* Get list of supported huge page sizes and their mount points, if
* hugetlbfs file systems are mounted for those sizes.
*/
const
HugePageSizeVec
&
sizes
()
const
{
return
sizes_
;
}
/**
* Create a file on a huge page filesystem containing a copy of the data
* from data. If multiple huge page sizes are allowed, we
* pick the smallest huge page size available, unless you request one
* explicitly with the hugePageSize argument.
*
* We return a struct File structure containing the full path and size
* (rounded up to a multiple of the huge page size)
*/
struct
File
{
std
::
string
path
;
size_t
size
;
};
File
create
(
ByteRange
data
,
StringPiece
baseName
,
size_t
hugePageSize
=
0
,
mode_t
mode
=
0644
)
const
;
private:
HugePageSizeVec
sizes_
;
};
}
// namespace folly
#endif
/* FOLLY_IO_HUGEPAGES_H_ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment