Skip to content

Commit f8baa67

Browse files
Diego Ongaroongardie
Diego Ongaro
authored andcommittedAug 12, 2011
Improve portability
While trying to build RAMCloud on a new system, I made various portability improvements: - Fixed build and doc issues for Infiniband-less builds. - Added new private make include at the top of the Makefile for overriding default values of make variables. - Improved error message on failing hash table assertion. - Bumped up timing threshold in some dubious CyclesTest to get it to pass. - Bumped up message sizes on some dubious TcpTransport tests to get them to pass. - Added preprocessor guards to program_options features that were introduced in Boost 1.42. (The project now builds with Boost 1.41.) - Changed LargeBlockOfMemory to not pin memory. Instead, all memory is pinned in the main files of servers now. Most systems only allow users to pin 64K of memory by default, so this will fail on many systems. By doing it all up front, it's easier to deal with the warnings. Another advantage is that all memory is now pinned, not just the large blocks.
1 parent 15d66a7 commit f8baa67

14 files changed

+88
-36
lines changed
 

‎Doxyfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1302,7 +1302,7 @@ INCLUDE_FILE_PATTERNS =
13021302
# undefined via #undef or recursively expanded use the := operator
13031303
# instead of the = operator.
13041304

1305-
PREDEFINED = DOXYGEN __cplusplus \
1305+
PREDEFINED = DOXYGEN __cplusplus INFINIBAND \
13061306
PRIVATE=private PROTECTED=protected PUBLIC=public
13071307

13081308
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then

‎GNUmakefile

+26-13
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
# Recursive Make Considered Harmful
55
# http://aegis.sourceforge.net/auug97.pdf
66

7+
8+
# The following line allows developers to change the default values for make
9+
# variables in the file private/MakefragPrivateTop.
10+
include $(wildcard private/MakefragPrivateTop)
11+
712
DEBUG ?= yes
813
YIELD ?= no
914
SSE ?= sse4.2
@@ -69,23 +74,31 @@ COMFLAGS += -DYIELD=1
6974
endif
7075

7176
CFLAGS_BASE := $(COMFLAGS) -std=gnu0x $(INCLUDES)
77+
CFLAGS_SILENT := $(CFLAGS_BASE)
7278
CFLAGS_NOWERROR := $(CFLAGS_BASE) $(CWARNS)
7379
CFLAGS := $(CFLAGS_BASE) -Werror $(CWARNS)
7480

75-
CXXFLAGS_BASE := $(COMFLAGS) -std=c++0x $(INCLUDES) $(EXTRACXXFLAGS)
76-
CXXFLAGS_NOWERROR := $(CXXFLAGS_BASE) $(CXXWARNS)
77-
CXXFLAGS := $(CXXFLAGS_BASE) -Werror $(CXXWARNS)
81+
CXXFLAGS_BASE := $(COMFLAGS) -std=c++0x $(INCLUDES)
82+
CXXFLAGS_SILENT := $(CXXFLAGS_BASE) $(EXTRACXXFLAGS)
83+
CXXFLAGS_NOWERROR := $(CXXFLAGS_BASE) $(CXXWARNS) $(EXTRACXXFLAGS)
84+
CXXFLAGS := $(CXXFLAGS_BASE) -Werror $(CXXWARNS) $(EXTRACXXFLAGS)
85+
7886
ifeq ($(COMPILER),intel)
7987
CXXFLAGS = $(CXXFLAGS_BASE) $(CXXWARNS)
8088
endif
8189

82-
CC := gcc
83-
CXX := g++
84-
AR := ar
85-
PERL := perl
86-
LINT := python cpplint.py --filter=-runtime/threadsafe_fn,-readability/streams,-whitespace/blank_line,-whitespace/braces,-whitespace/comments,-runtime/arrays,-build/include_what_you_use,-whitespace/semicolon
90+
CC ?= gcc
91+
CXX ?= g++
92+
AR ?= ar
93+
PERL ?= perl
94+
PYTHON ?= python
95+
LINT := $(PYTHON) cpplint.py --filter=-runtime/threadsafe_fn,-readability/streams,-whitespace/blank_line,-whitespace/braces,-whitespace/comments,-runtime/arrays,-build/include_what_you_use,-whitespace/semicolon
8796
PRAGMAS := ./pragmas.py
8897
NULL := # useful for terminating lists of files
98+
PROTOC ?= protoc
99+
EPYDOC ?= epydoc
100+
EPYDOCFLAGS ?= --simple-term -v
101+
DOXYGEN ?= doxygen
89102

90103
# run-cc:
91104
# Compile a C source file to an object file.
@@ -97,8 +110,8 @@ define run-cc
97110
@GCCWARN=$$( $(PRAGMAS) -q GCCWARN $(2) ); \
98111
case $$GCCWARN in \
99112
0) \
100-
echo $(CC) $(CFLAGS_BASE) $(3) -c -o $(1) $(2); \
101-
$(CC) $(CFLAGS_BASE) $(3) -c -o $(1) $(2); \
113+
echo $(CC) $(CFLAGS_SILENT) $(3) -c -o $(1) $(2); \
114+
$(CC) $(CFLAGS_SILENT) $(3) -c -o $(1) $(2); \
102115
;; \
103116
5) \
104117
echo $(CC) $(CFLAGS_NOWERROR) $(3) -c -o $(1) $(2); \
@@ -121,8 +134,8 @@ define run-cxx
121134
@GCCWARN=$$( $(PRAGMAS) -q GCCWARN $(2) ); \
122135
case $$GCCWARN in \
123136
0) \
124-
echo $(CXX) $(CXXFLAGS_BASE) $(3) -c -o $(1) $(2); \
125-
$(CXX) $(CXXFLAGS_BASE) $(3) -c -o $(1) $(2); \
137+
echo $(CXX) $(CXXFLAGS_SILENT) $(3) -c -o $(1) $(2); \
138+
$(CXX) $(CXXFLAGS_SILENT) $(3) -c -o $(1) $(2); \
126139
;; \
127140
5) \
128141
echo $(CXX) $(CXXFLAGS_NOWERROR) $(3) -c -o $(1) $(2); \
@@ -187,7 +200,7 @@ docs: python-docs
187200
DOCSID=$$DOCSID-`cat ".git/$$( git symbolic-ref HEAD )" | cut -c1-6` ;\
188201
(echo "PROJECT_NUMBER = \"Version [$$DOCSID]\""; \
189202
echo "INPUT = src bindings README $(OBJDIR)"; \
190-
echo "INCLUDE_PATH = $(OBJDIR)"; ) | cat Doxyfile - | doxygen -
203+
echo "INCLUDE_PATH = $(OBJDIR)"; ) | cat Doxyfile - | $(DOXYGEN) -
191204

192205
docs-clean: python-docs-clean
193206
rm -rf docs/doxygen/

‎bindings/python/Makefrag

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
python-docs: $(OBJDIR)/libramcloud.so
2-
LD_LIBRARY_PATH=$(OBJDIR):$$LD_LIBRARY_PATH epydoc --html -n RAMCloud -o docs/epydoc/ --simple-term -v bindings/python/*.py
2+
LD_LIBRARY_PATH=$(OBJDIR):$$LD_LIBRARY_PATH $(EPYDOC) --html -n RAMCloud -o docs/epydoc/ $(EPYDOCFLAGS) bindings/python/*.py
33

44
python-docs-clean:
55
rm -rf docs/epydoc/
@@ -10,7 +10,7 @@ python-test: $(OBJDIR)/libramcloud.so
1010
if [ -x $$test ]; then \
1111
echo "Running $$test:"; \
1212
LD_LIBRARY_PATH=$(OBJDIR):$$LD_LIBRARY_PATH \
13-
python $$test -q || failed=1; \
13+
$(PYTHON) $$test -q || failed=1; \
1414
echo; \
1515
fi \
1616
done; \

‎src/Common.cc

+16
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <fcntl.h>
2525
#include <pcrecpp.h>
2626
#include <stdarg.h>
27+
#include <sys/mman.h>
2728
#include <sys/stat.h>
2829

2930
#include "Common.h"
@@ -301,4 +302,19 @@ string demangle(const char* name) {
301302
return ret;
302303
}
303304

305+
/**
306+
* Pin all current and future memory pages in memory so that the OS does not
307+
* swap them to disk. All RAMCloud server main files should call this.
308+
*/
309+
void pinAllMemory() {
310+
int r = mlockall(MCL_CURRENT | MCL_FUTURE);
311+
if (r != 0) {
312+
LOG(WARNING, "Could not lock all memory pages (%s), so the OS might "
313+
"swap memory later. Check your user's \"ulimit -l\" and "
314+
"adjust /etc/security/limits.conf as necessary.",
315+
strerror(errno));
316+
}
317+
}
318+
319+
304320
} // namespace RAMCloud

‎src/Common.h

+2
Original file line numberDiff line numberDiff line change
@@ -580,5 +580,7 @@ prefetch(const T* object)
580580
prefetch(object, sizeof(*object));
581581
}
582582

583+
void pinAllMemory();
584+
583585
} // end RAMCloud
584586
#endif // RAMCLOUD_COMMON_H

‎src/CoordinatorMain.cc

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ main(int argc, char *argv[])
3333
try {
3434
OptionParser optionParser(OptionsDescription("Coordinator"),
3535
argc, argv);
36+
pinAllMemory();
3637
string localLocator = optionParser.options.getCoordinatorLocator();
3738
transportManager.initialize(localLocator.c_str());
3839
localLocator = transportManager.getListeningLocatorsString();

‎src/Cperf.cc

+7-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
// benchmark code.
2121

2222
#include <boost/program_options.hpp>
23+
#include <boost/version.hpp>
2324
#include <iostream>
2425
namespace po = boost::program_options;
2526

@@ -686,8 +687,12 @@ try
686687
("clientIndex", po::value<int>(&clientIndex)->default_value(0),
687688
"Index of this client (first client is 0)")
688689
("coordinator,C",
690+
#if BOOST_VERSION >= 104200 // required flag introduced in Boost 1.42
689691
po::value<string>(&coordinatorLocator)->required(),
690-
"Service locator for the cluster coordinator")
692+
#else
693+
po::value<string>(&coordinatorLocator),
694+
#endif
695+
"Service locator for the cluster coordinator (required)")
691696
("help,h", "Print this help message")
692697
("numClients", po::value<int>(&numClients)->default_value(1),
693698
"Total number of clients running")
@@ -698,7 +703,7 @@ try
698703
po::variables_map vm;
699704
po::store(po::command_line_parser(argc, argv).
700705
options(desc).positional(desc2).run(), vm);
701-
if (vm.count("help")) {
706+
if (vm.count("help") || coordinatorLocator.empty()) {
702707
std::cout << desc << '\n';
703708
exit(0);
704709
}

‎src/CyclesTest.cc

+4-5
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,11 @@ TEST_F(CyclesTest, basics) {
4242
start = Cycles::rdtsc();
4343
usleep(1000);
4444
elapsed = Cycles::toSeconds(Cycles::rdtsc() - start);
45-
if ((elapsed >= .001) && (elapsed <.0015)) {
46-
break;
47-
}
45+
ASSERT_LE(.001, elapsed);
46+
ASSERT_GT(.0035, elapsed)
47+
<< "Your system slept longer than it should have. "
48+
"There's probably nothing wrong -- this test is dubious.";
4849
}
49-
EXPECT_LE(.001, elapsed);
50-
EXPECT_GT(.0015, elapsed);
5150
}
5251

5352
TEST_F(CyclesTest, perSecond_sanity) {

‎src/HashTable.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -887,8 +887,12 @@ class HashTable {
887887
typeField <<= (47 - typeBits);
888888
}
889889

890-
if ((ptr & ~(0x00007fffffffffffUL >> typeBits)) != 0)
891-
throw Exception(HERE, "pointer cannot fit! stack addr used?");
890+
if ((ptr & ~(0x00007fffffffffffUL >> typeBits)) != 0) {
891+
throw Exception(HERE, format(
892+
"The given pointer (0x%016lx) can't fit in a hash table "
893+
"entry. Maybe it's a stack address? typeBits=%u",
894+
ptr, typeBits));
895+
}
892896

893897
uint64_t c = chain ? 1 : 0;
894898
assert((hash & ~(0x000000000000ffffUL)) == 0);

‎src/LargeBlockOfMemory.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ struct LargeBlockOfMemory {
4444
: length(length)
4545
, block(static_cast<T*>(mmap(NULL, length, PROT_READ | PROT_WRITE,
4646
MAP_SHARED | MAP_ANONYMOUS |
47-
MAP_LOCKED | MAP_POPULATE, -1, 0)))
47+
MAP_POPULATE, -1, 0)))
4848
{
4949
if (block == MAP_FAILED) {
5050
if (length == 0)
@@ -101,7 +101,7 @@ struct LargeBlockOfMemory {
101101
}
102102

103103
block = reinterpret_cast<T*>(mmap(NULL, length, PROT_READ | PROT_WRITE,
104-
MAP_SHARED | MAP_LOCKED | MAP_POPULATE,
104+
MAP_SHARED | MAP_POPULATE,
105105
fd, 0));
106106
if (reinterpret_cast<void*>(block) == MAP_FAILED) {
107107
unlink(path);

‎src/Makefrag

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ AUTO_GEN_HEADERS += $(OBJDIR)/Metrics.in.h
55
.SECONDARY: $(AUTO_GEN_HEADERS)
66
$(OBJDIR)/%.pb.cc $(OBJDIR)/%.pb.h: $(TOP)/src/%.proto
77
@mkdir -p $(OBJDIR)
8-
@echo protoc ... $$(basename $<)
8+
@echo $(PROTOC) ... $$(basename $<)
99
@cd $(TOP)/src/; \
10-
protoc --cpp_out=$(TOP)/$(OBJDIR) $$(basename $<); \
10+
$(PROTOC) --cpp_out=$(TOP)/$(OBJDIR) $$(basename $<) || exit 1; \
1111
echo "// RAMCloud pragma [GCCWARN=0]" >> $(TOP)/$(OBJDIR)/$$(basename $< .proto).pb.h; \
1212
echo "// RAMCloud pragma [GCCWARN=0]" >> $(TOP)/$(OBJDIR)/$$(basename $< .proto).pb.cc
1313

‎src/OptionParser.cc

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1414
*/
1515

16+
#include <boost/version.hpp>
1617
#include <boost/program_options.hpp>
1718
#include <boost/lexical_cast.hpp>
1819
#include <iostream>
@@ -179,8 +180,12 @@ OptionParser::setup(int argc, char* argv[])
179180
catch (po::multiple_occurrences& e) {
180181
// This clause could provides a more understandable error message
181182
// (the default is fairly opaque).
183+
#if BOOST_VERSION >= 104200 // get_option_name introduced in Boost 1.4.2
182184
throw po::error(format("command-line option '%s' occurs multiple times",
183185
e.get_option_name().c_str()));
186+
#else
187+
throw po::error("command-line option occurs multiple times");
188+
#endif
184189
}
185190
}
186191

‎src/ServerMain.cc

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ try
114114
LOG(DEBUG, "server: Pinned to core %d", cpu);
115115
}
116116

117+
pinAllMemory();
117118
transportManager.initialize(
118119
optionParser.options.getLocalLocator().c_str());
119120
LOG(NOTICE, "%s: Listening on %s", servicesInfo,

‎src/TcpTransportTest.cc

+13-7
Original file line numberDiff line numberDiff line change
@@ -472,15 +472,19 @@ TEST_F(TcpTransportTest, sendMessage_largeBuffer) {
472472
&reply);
473473
Transport::ServerRpc* serverRpc = serviceManager->waitForRpc(1.0);
474474
EXPECT_TRUE(serverRpc != NULL);
475-
EXPECT_GT(TcpTransport::messageChunks, 0);
475+
EXPECT_GT(TcpTransport::messageChunks, 0)
476+
<< "The message fit in one chunk. You may have to increase the size "
477+
"of the message for this test to be effective.";
476478
EXPECT_EQ("ok", TestUtil::checkLargeBuffer(&serverRpc->requestPayload,
477479
300000));
478-
TestUtil::fillLargeBuffer(&serverRpc->replyPayload, 250000);
480+
TestUtil::fillLargeBuffer(&serverRpc->replyPayload, 350000);
479481
TcpTransport::messageChunks = 0;
480482
serverRpc->sendReply();
481483
EXPECT_TRUE(TestUtil::waitForRpc(*clientRpc));
482-
EXPECT_EQ("ok", TestUtil::checkLargeBuffer(&reply, 250000));
483-
EXPECT_GT(TcpTransport::messageChunks, 0);
484+
EXPECT_GT(TcpTransport::messageChunks, 0)
485+
<< "The message fit in one chunk. You may have to increase the size "
486+
"of the message for this test to be effective.";
487+
EXPECT_EQ("ok", TestUtil::checkLargeBuffer(&reply, 350000));
484488
}
485489

486490
TEST_F(TcpTransportTest, sendMessage_brokenPipe) {
@@ -1044,7 +1048,7 @@ TEST_F(TcpTransportTest, sendReply) {
10441048
serverRpc->sendReply();
10451049
serverRpc = serviceManager->waitForRpc(1.0);
10461050
EXPECT_TRUE(serverRpc != NULL);
1047-
TestUtil::fillLargeBuffer(&serverRpc->replyPayload, 199999);
1051+
TestUtil::fillLargeBuffer(&serverRpc->replyPayload, 1999990);
10481052
serverRpc->sendReply();
10491053
serverRpc = serviceManager->waitForRpc(1.0);
10501054
EXPECT_TRUE(serverRpc != NULL);
@@ -1054,15 +1058,17 @@ TEST_F(TcpTransportTest, sendReply) {
10541058
// Check server state.
10551059
EXPECT_NE(server.sockets.size(), 0U);
10561060
TcpTransport::Socket* socket = server.sockets[server.sockets.size() - 1];
1057-
EXPECT_EQ(2U, socket->rpcsWaitingToReply.size());
1061+
EXPECT_EQ(2U, socket->rpcsWaitingToReply.size())
1062+
<< "There are no pending RPCs responses to send. You may have to "
1063+
"increase the size of the message for this test to be effective.";
10581064
EXPECT_EQ("~TcpServerRpc: deleted", TestLog::get());
10591065
TestLog::reset();
10601066

10611067
// Make sure the responses eventually get through.
10621068
EXPECT_TRUE(TestUtil::waitForRpc(*clientRpc1));
10631069
EXPECT_EQ("response1/0", TestUtil::toString(&reply1));
10641070
EXPECT_TRUE(TestUtil::waitForRpc(*clientRpc2));
1065-
EXPECT_EQ("ok", TestUtil::checkLargeBuffer(&reply2, 199999));
1071+
EXPECT_EQ("ok", TestUtil::checkLargeBuffer(&reply2, 1999990));
10661072
EXPECT_TRUE(TestUtil::waitForRpc(*clientRpc3));
10671073
EXPECT_EQ("response3/0", TestUtil::toString(&reply3));
10681074
EXPECT_EQ("~TcpServerRpc: deleted | ~TcpServerRpc: deleted",

0 commit comments

Comments
 (0)
Please sign in to comment.