Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for C++ benchmarks. #99

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion benchmarks/000.microbenchmarks/010.sleep/config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"timeout": 120,
"memory": 128,
"languages": ["python", "nodejs"]
"languages": ["python", "nodejs", "cpp"]
}
22 changes: 22 additions & 0 deletions benchmarks/000.microbenchmarks/010.sleep/cpp/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

#include <aws/core/Aws.h>
#include <aws/core/utils/json/JsonSerializer.h>
#include <aws/lambda-runtime/runtime.h>

#include <thread>
#include <iostream>

Aws::Utils::Json::JsonValue function(Aws::Utils::Json::JsonView json)
{
int sleep = json.GetInteger("sleep");

std::chrono::seconds timespan(sleep);
std::this_thread::sleep_for(timespan);

//std::string res_json = "{ \"result\": " + std::to_string(sleep) + "}";
//return aws::lambda_runtime::invocation_response::success(res_json, "application/json");
Aws::Utils::Json::JsonValue val;
val.WithObject("result", std::to_string(sleep));
return val;
}

73 changes: 73 additions & 0 deletions benchmarks/wrappers/aws/cpp/handler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@

#include <aws/core/Aws.h>
#include <aws/lambda-runtime/runtime.h>
#include <aws/s3/S3Client.h>

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

#include "utils.hpp"

// Global variables that are retained across function invocations
bool cold_execution = true;
std::string container_id = "";
std::string cold_start_var = "";

Aws::Utils::Json::JsonValue function(Aws::Utils::Json::JsonView req);

aws::lambda_runtime::invocation_response handler(aws::lambda_runtime::invocation_request const &req)
{
Aws::Utils::Json::JsonValue json(req.payload);
Aws::Utils::Json::JsonView json_view = json.View();
// HTTP trigger with API Gateaway sends payload as a serialized JSON
// stored under key 'body' in the main JSON
// The SDK trigger converts everything for us
if(json_view.ValueExists("body")){
Aws::Utils::Json::JsonValue parsed_body{json_view.GetString("body")};
json = std::move(parsed_body);
json_view = json.View();
}

const auto begin = std::chrono::system_clock::now();
auto ret = function(json.View());
const auto end = std::chrono::system_clock::now();

Aws::Utils::Json::JsonValue body;
body.WithObject("result", ret);

// Switch cold execution after the first one.
if(cold_execution)
cold_execution = false;

auto b = std::chrono::duration_cast<std::chrono::microseconds>(begin.time_since_epoch()).count() / 1000.0 / 1000.0;
auto e = std::chrono::duration_cast<std::chrono::microseconds>(end.time_since_epoch()).count() / 1000.0 / 1000.0;
body.WithDouble("begin", b);
body.WithDouble("end", e);
body.WithDouble("results_time", e - b);
body.WithString("request_id", req.request_id);
body.WithBool("is_cold", cold_execution);
body.WithString("container_id", container_id);
body.WithString("cold_start_var", cold_start_var);

Aws::Utils::Json::JsonValue final_result;
final_result.WithObject("body", body);
return aws::lambda_runtime::invocation_response::success(final_result.View().WriteReadable(), "application/json");
}

int main()
{
Aws::SDKOptions options;
Aws::InitAPI(options);

const char * cold_var = std::getenv("cold_start");
if(cold_var)
cold_start_var = cold_var;
container_id = boost::uuids::to_string(boost::uuids::random_generator()());

aws::lambda_runtime::run_handler(handler);

Aws::ShutdownAPI(options);
return 0;
}

103 changes: 103 additions & 0 deletions benchmarks/wrappers/aws/cpp/key-value.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@

#include <memory>

#include <aws/core/auth/AWSCredentialsProvider.h>
#include <aws/core/client/ClientConfiguration.h>
#include <aws/dynamodb/model/AttributeDefinition.h>
#include <aws/dynamodb/model/GetItemRequest.h>
#include <aws/dynamodb/model/PutItemRequest.h>
#include <aws/dynamodb/model/PutItemResult.h>

#include <boost/interprocess/streams/bufferstream.hpp>

#include "key-value.hpp"
#include "utils.hpp"

KeyValue::KeyValue()
{
Aws::Client::ClientConfiguration config;
//config.region = "eu-central-1";
config.caFile = "/etc/pki/tls/certs/ca-bundle.crt";

char const TAG[] = "LAMBDA_ALLOC";
auto credentialsProvider = Aws::MakeShared<Aws::Auth::EnvironmentAWSCredentialsProvider>(TAG);
_client.reset(new Aws::DynamoDB::DynamoDBClient(credentialsProvider, config));
}

uint64_t KeyValue::download_file(Aws::String const &table, Aws::String const &key,
int &required_retries, double& read_units, bool with_backoff)
{
Aws::DynamoDB::Model::GetItemRequest req;

// Set up the request
req.SetTableName(table);
req.SetReturnConsumedCapacity(Aws::DynamoDB::Model::ReturnConsumedCapacity::TOTAL);
Aws::DynamoDB::Model::AttributeValue hashKey;
hashKey.SetS(key);
req.AddKey("key", hashKey);

auto bef = timeSinceEpochMillisec();
int retries = 0;
const int MAX_RETRIES = 1500;

while (retries < MAX_RETRIES) {
auto get_result = _client->GetItem(req);
if (get_result.IsSuccess()) {

// Reference the retrieved fields/values
auto result = get_result.GetResult();
const Aws::Map<Aws::String, Aws::DynamoDB::Model::AttributeValue>& item = result.GetItem();
if (item.size() > 0) {
uint64_t finishedTime = timeSinceEpochMillisec();

required_retries = retries;
// GetReadCapacityUnits returns 0?
read_units = result.GetConsumedCapacity().GetCapacityUnits();

return finishedTime - bef;
}

} else {
retries += 1;
if(with_backoff) {
int sleep_time = retries;
if (retries > 100) {
sleep_time = retries * 2;
}
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time));
}
}
}
return 0;
}

uint64_t KeyValue::upload_file(Aws::String const &table,
Aws::String const &key,
double& write_units,
int size, unsigned char* pBuf)
{
Aws::Utils::ByteBuffer buf(pBuf, size);

Aws::DynamoDB::Model::PutItemRequest req;
req.SetTableName(table);
req.SetReturnConsumedCapacity(Aws::DynamoDB::Model::ReturnConsumedCapacity::TOTAL);

Aws::DynamoDB::Model::AttributeValue av;
av.SetB(buf);
req.AddItem("data", av);
av.SetS(key);
req.AddItem("key", av);

uint64_t bef = timeSinceEpochMillisec();
const Aws::DynamoDB::Model::PutItemOutcome put_result = _client->PutItem(req);
if (!put_result.IsSuccess()) {
std::cout << put_result.GetError().GetMessage() << std::endl;
return 1;
}
auto result = put_result.GetResult();
// GetWriteCapacityUnits returns 0?
write_units = result.GetConsumedCapacity().GetCapacityUnits();
uint64_t finishedTime = timeSinceEpochMillisec();

return finishedTime - bef;
}
31 changes: 31 additions & 0 deletions benchmarks/wrappers/aws/cpp/key-value.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

#include <cstdint>
#include <string>
#include <initializer_list>
#include <memory>

#include <aws/core/utils/memory/stl/AWSString.h>
#include <aws/dynamodb/DynamoDBClient.h>

class KeyValue
{
// non-copyable, non-movable
std::shared_ptr<Aws::DynamoDB::DynamoDBClient> _client;
public:

KeyValue();

uint64_t download_file(Aws::String const &bucket,
Aws::String const &key,
int& required_retries,
double& read_units,
bool with_backoff = false);

uint64_t upload_file(Aws::String const &bucket,
Aws::String const &key,
double& write_units,
int size,
unsigned char* pBuf);

};

104 changes: 104 additions & 0 deletions benchmarks/wrappers/aws/cpp/redis.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@

#include <string>

#include <aws/core/Aws.h>

#include "redis.hpp"
#include "utils.hpp"

Redis::Redis(std::string redis_hostname, int redis_port)
{
_context = redisConnect(redis_hostname.c_str(), redis_port);
if (_context == nullptr || _context->err) {
if (_context) {
std::cerr << "Redis Error: " << _context->errstr << '\n';
} else {
std::cerr << "Can't allocate redis context\n";
}
}
}

bool Redis::is_initialized()
{
return _context != nullptr;
}

Redis::~Redis()
{
redisFree(_context);
}

uint64_t Redis::download_file(Aws::String const &key,
int &required_retries, bool with_backoff)
{
std::string comm = "GET " + key;

auto bef = timeSinceEpochMillisec();
int retries = 0;
const int MAX_RETRIES = 1500;

while (retries < MAX_RETRIES) {

redisReply* reply = (redisReply*) redisCommand(_context, comm.c_str());

if (reply->type == REDIS_REPLY_NIL || reply->type == REDIS_REPLY_ERROR) {

retries += 1;
if(with_backoff) {
int sleep_time = retries;
if (retries > 100) {
sleep_time = retries * 2;
}
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time));
}

} else {

uint64_t finishedTime = timeSinceEpochMillisec();
required_retries = retries;

freeReplyObject(reply);
return finishedTime - bef;

}
freeReplyObject(reply);
}
return 0;
}

uint64_t Redis::upload_file(Aws::String const &key,
int size, char* pBuf)
{
std::string comm = "SET " + key + " %b";


uint64_t bef = timeSinceEpochMillisec();
redisReply* reply = (redisReply*) redisCommand(_context, comm.c_str(), pBuf, size);
uint64_t finishedTime = timeSinceEpochMillisec();

if (reply->type == REDIS_REPLY_NIL || reply->type == REDIS_REPLY_ERROR) {
std::cerr << "Failed to write in Redis!" << std::endl;
abort();
}
freeReplyObject(reply);

return finishedTime - bef;
}

uint64_t Redis::delete_file(std::string const &key)
{
std::string comm = "DEL " + key;

uint64_t bef = timeSinceEpochMillisec();
redisReply* reply = (redisReply*) redisCommand(_context, comm.c_str());
uint64_t finishedTime = timeSinceEpochMillisec();

if (reply->type == REDIS_REPLY_NIL || reply->type == REDIS_REPLY_ERROR) {
std::cerr << "Couldn't delete the key!" << '\n';
abort();
}
freeReplyObject(reply);

return finishedTime - bef;
}

26 changes: 26 additions & 0 deletions benchmarks/wrappers/aws/cpp/redis.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

#include <cstdint>
#include <string>

#include <aws/core/utils/memory/stl/AWSString.h>

#include <hiredis/hiredis.h>

class Redis
{
redisContext* _context;
public:

Redis(std::string redis_hostname, int redis_port);
~Redis();

bool is_initialized();

uint64_t download_file(Aws::String const &key, int &required_retries, bool with_backoff);

uint64_t upload_file(Aws::String const &key, int size, char* pBuf);

uint64_t delete_file(std::string const &key);

};

Loading