void enqueue(K cl, unsigned priority, unsigned cost, T item) override final {
// priority is ignored
- queue.add_request(item, cl, cost);
+ queue.add_request(std::move(item), cl, cost);
}
void enqueue_front(K cl,
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/modules")
+set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-write-strings -Wall -pthread")
+
+if(DO_NOT_DELAY_TAG_CALC)
+ add_definitions(-DDO_NOT_DELAY_TAG_CALC)
+endif()
+
if (NOT(TARGET gtest AND TARGET gtest_main))
- if(NOT(GTEST_FOUND))
- find_package(GTest REQUIRED)
+ if (NOT GTEST_FOUND)
+ find_package(GTest QUIET)
+ if (NOT GTEST_FOUND)
+ include(BuildGTest)
+ endif()
endif()
endif()
find_package(Boost REQUIRED)
endif()
-# add_subdirectory(support/src)
add_subdirectory(src)
add_subdirectory(sim)
--- /dev/null
+macro(_build_gtest gtest_root)
+ include(ExternalProject)
+ ExternalProject_Add(googletest
+ SOURCE_DIR ${gtest_root}
+ CMAKE_ARGS -DBUILD_GMOCK=OFF -DBUILD_GTEST=ON
+ INSTALL_COMMAND ""
+ LOG_CONFIGURE ON
+ LOG_BUILD ON)
+
+ ExternalProject_Get_Property(googletest source_dir)
+ set(GTEST_INCLUDE_DIRS ${source_dir}/googletest/include)
+ set(GMOCK_INCLUDE_DIRS ${source_dir}/googlemock/include)
+
+ find_package(Threads REQUIRED)
+
+ ExternalProject_Get_Property(googletest binary_dir)
+ set(GTEST_LIBRARY_PATH ${binary_dir}/googletest/${CMAKE_FIND_LIBRARY_PREFIXES}gtest.a)
+ set(GTEST_LIBRARY gtest)
+ add_library(${GTEST_LIBRARY} STATIC IMPORTED)
+ set_target_properties(${GTEST_LIBRARY} PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIRS}"
+ IMPORTED_LOCATION ${GTEST_LIBRARY_PATH}
+ IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
+ IMPORTED_LINK_INTERFACE_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+ add_dependencies(${GTEST_LIBRARY} googletest)
+ set(GTEST_LIBRARIES ${GTEST_LIBRARY})
+
+ set(GTEST_MAIN_LIBRARY_PATH ${binary_dir}/googletest/${CMAKE_FIND_LIBRARY_PREFIXES}gtest_main.a)
+ set(GTEST_MAIN_LIBRARY gtest_main)
+ add_library(${GTEST_MAIN_LIBRARY} STATIC IMPORTED)
+ set_target_properties(${GTEST_MAIN_LIBRARY} PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIRS}"
+ IMPORTED_LOCATION ${GTEST_MAIN_LIBRARY_PATH}
+ IMPORTED_LINK_INTERFACE_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+ add_dependencies(${GTEST_MAIN_LIBRARY} googletest)
+
+ set(GMOCK_LIBRARY_PATH ${binary_dir}/googlemock/${CMAKE_FIND_LIBRARY_PREFIXES}gmock.a)
+ set(GMOCK_LIBRARY gmock)
+ add_library(${GMOCK_LIBRARY} STATIC IMPORTED)
+ set_target_properties(${GMOCK_LIBRARY} PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${GMOCK_INCLUDE_DIRS}"
+ IMPORTED_LOCATION "${GMOCK_LIBRARY_PATH}"
+ IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
+ IMPORTED_LINK_INTERFACE_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+ add_dependencies(${GMOCK_LIBRARY} googletest)
+
+ set(GMOCK_MAIN_LIBRARY_PATH ${binary_dir}/googlemock/${CMAKE_FIND_LIBRARY_PREFIXES}gmock_main.a)
+ set(GMOCK_MAIN_LIBRARY gmock_main)
+ add_library(${GMOCK_MAIN_LIBRARY} STATIC IMPORTED)
+ set_target_properties(${GMOCK_MAIN_LIBRARY} PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${GMOCK_INCLUDE_DIRS}"
+ IMPORTED_LOCATION ${GMOCK_MAIN_LIBRARY_PATH}
+ IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
+ IMPORTED_LINK_INTERFACE_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+ add_dependencies(${GMOCK_MAIN_LIBRARY} ${GTEST_LIBRARY})
+endmacro()
+
+find_path(GTEST_ROOT src/gtest.cc
+ HINTS $ENV{GTEST_ROOT}
+ PATHS /usr/src/googletest/googletest /usr/src/gtest)
+
+if(EXISTS ${GTEST_ROOT})
+ message(STATUS "Found googletest: ${GTEST_ROOT}")
+ _build_gtest(${GTEST_ROOT})
+else()
+ message(SEND_ERROR "Could NOT find googletest")
+endif()
using SubmitFunc =
std::function<void(const ServerId&,
- const TestRequest&,
+ TestRequest&&,
const ClientId&,
const ReqPm&)>;
count_stats(internal_stats.mtx,
internal_stats.get_req_params_count);
- TestRequest req(server, o, 12);
- submit_f(server, req, id, rp);
+ submit_f(server,
+ TestRequest{server, static_cast<uint32_t>(o), 12},
+ id, rp);
++outstanding_ops;
l.lock(); // lock for return to top of loop
delete priority_queue;
}
- void post(const TestRequest& request,
+ void post(TestRequest&& request,
const ClientId& client_id,
const ReqPm& req_params)
{
time_stats(internal_stats.mtx,
internal_stats.add_request_time,
[&](){
- priority_queue->add_request(request, client_id, req_params);
+ priority_queue->add_request(std::move(request),
+ client_id, req_params);
});
count_stats(internal_stats.mtx,
internal_stats.add_request_count);
// notify server of completion
std::this_thread::sleep_for(op_time);
- TestResponse resp(req->epoch);
// TODO: rather than assuming this constructor exists, perhaps
// pass in a function that does this mapping?
- client_resp_f(client, resp, id, additional);
+ client_resp_f(client, TestResponse{req->epoch}, id, additional);
time_stats(internal_stats.mtx,
internal_stats.request_complete_time,
finishing = true;
}
- void add_request(const R& request,
+ void add_request(R&& request,
const C& client_id,
const ReqParams& req_params) {
- add_request(RequestRef(new R(request)), client_id, req_params);
+ add_request(RequestRef(new R(std::move(request))),
+ client_id, req_params);
}
void add_request(RequestRef&& request,
// lambda to post a request to the identified server; called by client
test::SubmitFunc server_post_f =
[&simulation](const ServerId& server,
- const sim::TestRequest& request,
+ sim::TestRequest&& request,
const ClientId& client_id,
const test::dmc::ReqParams& req_params) {
test::DmcServer& s = simulation->get_server(server);
- s.post(request, client_id, req_params);
+ s.post(std::move(request), client_id, req_params);
};
std::vector<std::vector<sim::CliInst>> cli_inst;
// lambda to post a request to the identified server; called by client
test::SubmitFunc server_post_f =
[&simulation](const ServerId& server_id,
- const sim::TestRequest& request,
+ sim::TestRequest&& request,
const ClientId& client_id,
const ssched::ReqParams& req_params) {
auto& server = simulation->get_server(server_id);
- server.post(request, client_id, req_params);
+ server.post(std::move(request), client_id, req_params);
};
static std::vector<sim::CliInst> no_wait =
include_directories(${Boost_INCLUDE_DIRS})
include_directories(../support/src)
-set(local_flags "-std=c++11 -Wno-write-strings -Wall -pthread")
-
-if(DO_NOT_DELAY_TAG_CALC)
- set(local_flags "${local_flags} -DDO_NOT_DELAY_TAG_CALC")
-endif()
+set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-write-strings -Wall -pthread")
set(dmc_srcs dmclock_util.cc ../support/src/run_every.cc)
-set_source_files_properties(${dmc_srcs}
- PROPERTIES
- COMPILE_FLAGS "${local_flags}"
- )
-
-if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
- set(warnings_off " -Wno-unused-variable -Wno-unused-function")
-elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
- set(warnings_off " -Wno-unused-but-set-variable -Wno-unused-function")
-endif()
-
add_library(dmclock STATIC ${dmc_srcs})
#include "dmclock_util.h"
#include "dmclock_recs.h"
-#include "gtest/gtest_prod.h"
-
namespace crimson {
namespace dmclock {
// S is server identifier type
template<typename S>
class ServiceTracker {
- FRIEND_TEST(dmclock_client, server_erase);
+ // we don't want to include gtest.h just for FRIEND_TEST
+ friend class dmclock_client_server_erase_Test;
using TimePoint = decltype(std::chrono::steady_clock::now());
using Duration = std::chrono::milliseconds;
#include "profile.h"
#endif
-#include "gtest/gtest_prod.h"
-
namespace crimson {
// branching factor
template<typename C, typename R, uint B>
class PriorityQueueBase {
- FRIEND_TEST(dmclock_server, client_idle_erase);
+ // we don't want to include gtest.h just for FRIEND_TEST
+ friend class dmclock_server_client_idle_erase_Test;
public:
// NB: because a deque is the underlying structure, this
// operation might be expensive
- bool remove_by_req_filter_fw(std::function<bool(const R&)> filter_accum) {
+ bool remove_by_req_filter_fw(std::function<bool(R&&)> filter_accum) {
bool any_removed = false;
for (auto i = requests.begin();
i != requests.end();
/* no inc */) {
- if (filter_accum(*i->request)) {
+ if (filter_accum(std::move(*i->request))) {
any_removed = true;
i = requests.erase(i);
} else {
// NB: because a deque is the underlying structure, this
// operation might be expensive
- bool remove_by_req_filter_bw(std::function<bool(const R&)> filter_accum) {
+ bool remove_by_req_filter_bw(std::function<bool(R&&)> filter_accum) {
bool any_removed = false;
for (auto i = requests.rbegin();
i != requests.rend();
/* no inc */) {
- if (filter_accum(*i->request)) {
+ if (filter_accum(std::move(*i->request))) {
any_removed = true;
i = decltype(i){ requests.erase(std::next(i).base()) };
} else {
}
inline bool
- remove_by_req_filter(std::function<bool(const R&)> filter_accum,
+ remove_by_req_filter(std::function<bool(R&&)> filter_accum,
bool visit_backwards) {
if (visit_backwards) {
return remove_by_req_filter_bw(filter_accum);
}
- bool remove_by_req_filter(std::function<bool(const R&)> filter_accum,
+ bool remove_by_req_filter(std::function<bool(R&&)> filter_accum,
bool visit_backwards = false) {
bool any_removed = false;
DataGuard g(data_mtx);
// use as a default value when no accumulator is provide
- static void request_sink(const R& req) {
+ static void request_sink(R&& req) {
// do nothing
}
void remove_by_client(const C& client,
bool reverse = false,
- std::function<void (const R&)> accum = request_sink) {
+ std::function<void (R&&)> accum = request_sink) {
DataGuard g(data_mtx);
auto i = client_map.find(client);
for (auto j = i->second->requests.rbegin();
j != i->second->requests.rend();
++j) {
- accum(*j->request);
+ accum(std::move(*j->request));
}
} else {
for (auto j = i->second->requests.begin();
j != i->second->requests.end();
++j) {
- accum(*j->request);
+ accum(std::move(*j->request));
}
}
ClientRec& top = heap.top();
RequestRef request = std::move(top.next_request().request);
+#ifndef DO_NOT_DELAY_TAG_CALC
RequestTag tag = top.next_request().tag;
+#endif
// pop request and adjust heaps
top.pop_request();
}
- inline void add_request(const R& request,
+ inline void add_request(R&& request,
const C& client_id,
const ReqParams& req_params,
double addl_cost = 0.0) {
- add_request(typename super::RequestRef(new R(request)),
+ add_request(typename super::RequestRef(new R(std::move(request))),
client_id,
req_params,
get_time(),
}
- inline void add_request(const R& request,
+ inline void add_request(R&& request,
const C& client_id,
double addl_cost = 0.0) {
static const ReqParams null_req_params;
- add_request(typename super::RequestRef(new R(request)),
+ add_request(typename super::RequestRef(new R(std::move(request))),
client_id,
null_req_params,
get_time(),
- inline void add_request_time(const R& request,
+ inline void add_request_time(R&& request,
const C& client_id,
const ReqParams& req_params,
const Time time,
double addl_cost = 0.0) {
- add_request(typename super::RequestRef(new R(request)),
+ add_request(typename super::RequestRef(new R(std::move(request))),
client_id,
req_params,
time,
switch(next.type) {
case super::NextReqType::none:
return result;
- break;
case super::NextReqType::future:
result.data = next.when_ready;
return result;
- break;
case super::NextReqType::returning:
// to avoid nesting, break out and let code below handle this case
break;
public:
- inline void add_request(const R& request,
+ inline void add_request(R&& request,
const C& client_id,
const ReqParams& req_params,
double addl_cost = 0.0) {
- add_request(typename super::RequestRef(new R(request)),
+ add_request(typename super::RequestRef(new R(std::move(request))),
client_id,
req_params,
get_time(),
inline Time get_time() {
+#if defined(__linux__)
+ struct timespec now;
+ auto result = clock_gettime(CLOCK_REALTIME, &now);
+ (void) result; // reference result in case assert is compiled out
+ assert(0 == result);
+ return now.tv_sec + (now.tv_nsec / 1.0e9);
+#else
struct timeval now;
auto result = gettimeofday(&now, NULL);
- (void) result;
+ (void) result; // reference result in case assert is compiled out
assert(0 == result);
- return now.tv_sec + (now.tv_usec / 1000000.0);
+ return now.tv_sec + (now.tv_usec / 1.0e6);
+#endif
}
std::string format_time(const Time& time, uint modulo = 1000);
+INCLUDE (CheckIncludeFiles)
+CHECK_INCLUDE_FILES("sys/prctl.h" HAVE_SYS_PRCTL_H)
+CONFIGURE_FILE(dmtest-config.h.in dmtest-config.h)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(../src)
include_directories(../support/src)
include_directories(../sim/src)
)
add_executable(dmclock-tests ${test_srcs} ${support_srcs})
+target_include_directories(dmclock-tests PRIVATE "${GTEST_INCLUDE_DIRS}")
if (TARGET gtest AND TARGET gtest_main)
add_dependencies(dmclock-tests gtest gtest_main)
--- /dev/null
+// essentially the same as ceph's PrCtl.h, copied into the dmclock library
+
+#include <dmtest-config.h>
+#ifdef HAVE_SYS_PRCTL_H
+#include <iostream>
+#include <sys/prctl.h>
+#include <errno.h>
+
+struct PrCtl {
+ int saved_state = -1;
+ int set_dumpable(int new_state) {
+ int r = prctl(PR_SET_DUMPABLE, new_state);
+ if (r) {
+ r = -errno;
+ std::cerr << "warning: unable to " << (new_state ? "set" : "unset")
+ << " dumpable flag: " << strerror(r)
+ << std::endl;
+ }
+ return r;
+ }
+ PrCtl(int new_state = 0) {
+ int r = prctl(PR_GET_DUMPABLE);
+ if (r == -1) {
+ r = errno;
+ std::cerr << "warning: unable to get dumpable flag: " << strerror(r)
+ << std::endl;
+ } else if (r != new_state) {
+ if (!set_dumpable(new_state)) {
+ saved_state = r;
+ }
+ }
+ }
+ ~PrCtl() {
+ if (saved_state < 0) {
+ return;
+ }
+ set_dumpable(saved_state);
+ }
+};
+#else
+struct PrCtl {};
+#endif
--- /dev/null
+/* Define to 1 if you have the <sys/prctl.h> header file. */
+#cmakedefine HAVE_SYS_PRCTL_H 1
#include "dmclock_util.h"
#include "gtest/gtest.h"
+// process control to prevent core dumps during gtest death tests
+#include "dmcPrCtl.h"
+
namespace dmc = crimson::dmclock;
};
QueueRef pq(new Queue(client_info_f, false));
- Request req;
ReqParams req_params(1,1);
- EXPECT_DEATH_IF_SUPPORTED(pq->add_request(req, client1, req_params),
+ // Disable coredumps
+ PrCtl unset_dumpable;
+
+ EXPECT_DEATH_IF_SUPPORTED(pq->add_request(Request{}, client1, req_params),
"Assertion.*reservation.*max_tag.*"
"proportion.*max_tag") <<
"we should fail if a client tries to generate a reservation tag "
"where reservation and proportion are both 0";
- EXPECT_DEATH_IF_SUPPORTED(pq->add_request(req, client2, req_params),
+ EXPECT_DEATH_IF_SUPPORTED(pq->add_request(Request{}, client2, req_params),
"Assertion.*reservation.*max_tag.*"
"proportion.*max_tag") <<
"we should fail if a client tries to generate a reservation tag "
pq = QueueRef(new Queue(client_info_f, false));
- Request req;
ReqParams req_params(1,1);
auto now = dmc::get_time();
for (int i = 0; i < 5; ++i) {
- pq->add_request(req, client1, req_params);
- pq->add_request(req, client2, req_params);
+ pq->add_request(Request{}, client1, req_params);
+ pq->add_request(Request{}, client2, req_params);
now += 0.0001;
}
QueueRef pq(new Queue(client_info_f, false));
- Request req;
ReqParams req_params(1,1);
// make sure all times are well before now
auto old_time = dmc::get_time() - 100.0;
for (int i = 0; i < 5; ++i) {
- pq->add_request_time(req, client1, req_params, old_time);
- pq->add_request_time(req, client2, req_params, old_time);
+ pq->add_request_time(Request{}, client1, req_params, old_time);
+ pq->add_request_time(Request{}, client2, req_params, old_time);
old_time += 0.001;
}
QueueRef pq(new Queue(client_info_f, false));
- Request req;
ReqParams req_params(1,1);
// make sure all times are well before now
// add six requests; for same client reservations spaced one apart
for (int i = 0; i < 3; ++i) {
- pq->add_request_time(req, client1, req_params, start_time);
- pq->add_request_time(req, client2, req_params, start_time);
+ pq->add_request_time(Request{}, client1, req_params, start_time);
+ pq->add_request_time(Request{}, client2, req_params, start_time);
}
Queue::PullReq pr = pq->pull_request(start_time + 0.5);
QueueRef pq(new Queue(client_info_f, false));
- Request req;
ReqParams req_params(1,1);
// make sure all times are well before now
auto now = dmc::get_time();
- pq->add_request_time(req, client1, req_params, now + 100);
+ pq->add_request_time(Request{}, client1, req_params, now + 100);
Queue::PullReq pr = pq->pull_request(now);
EXPECT_EQ(Queue::NextReqType::future, pr.type);
QueueRef pq(new Queue(client_info_f, true));
- Request req;
ReqParams req_params(1,1);
// make sure all times are well before now
auto now = dmc::get_time();
- pq->add_request_time(req, client1, req_params, now + 100);
+ pq->add_request_time(Request{}, client1, req_params, now + 100);
Queue::PullReq pr = pq->pull_request(now);
EXPECT_EQ(Queue::NextReqType::returning, pr.type);
QueueRef pq(new Queue(client_info_f, true));
- Request req;
ReqParams req_params(1,1);
// make sure all times are well before now
auto now = dmc::get_time();
- pq->add_request_time(req, client1, req_params, now + 100);
+ pq->add_request_time(Request{}, client1, req_params, now + 100);
Queue::PullReq pr = pq->pull_request(now);
EXPECT_EQ(Queue::NextReqType::returning, pr.type);