Skip to content

[aws] Add support for benchmarks in cpp #251

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

Open
wants to merge 12 commits into
base: cpp_benchmarks
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
5 changes: 3 additions & 2 deletions benchmarks/200.multimedia/210.thumbnailer/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"timeout": 60,
"memory": 256,
"languages": ["python", "nodejs"],
"modules": ["storage"]
"languages": ["python", "nodejs", "cpp"],
"modules": ["storage"],
"cpp_dependencies": ["opencv", "boost"]
}
27 changes: 27 additions & 0 deletions benchmarks/200.multimedia/210.thumbnailer/cpp/function.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

#include <opencv2/opencv.hpp>
#include <opencv2/imgcodecs.hpp>

void thumbnailer(cv::Mat &in, int64_t width, int64_t height, cv::Mat &out)
{
try
{
// Calculate thumbnail size while maintaining aspect ratio
int orig_width = in.cols;
int orig_height = in.rows;

double scale_w = static_cast<double>(width) / orig_width;
double scale_h = static_cast<double>(height) / orig_height;
double scale = std::min(scale_w, scale_h); // Use smaller scale to fit within bounds

int new_width = static_cast<int>(orig_width * scale);
int new_height = static_cast<int>(orig_height * scale);

// Resize image (equivalent to PIL's thumbnail method)
cv::resize(in, out, cv::Size(new_width, new_height), cv::INTER_LINEAR);
}
catch (const cv::Exception &e)
{
std::cerr << "OpenCV error: " << e.what() << std::endl;
}
}
117 changes: 117 additions & 0 deletions benchmarks/200.multimedia/210.thumbnailer/cpp/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@

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

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

#include <iostream>
#include <vector>

#include "function.hpp"
#include "storage.hpp"
#include "utils.hpp"

Aws::Utils::Json::JsonValue function(Aws::Utils::Json::JsonView request)
{
sebs::Storage client_ = sebs::Storage::get_client();

auto bucket_obj = request.GetObject("bucket");
if (!bucket_obj.IsObject())
{
Aws::Utils::Json::JsonValue error;
error.WithString("error", "Bucket object is not valid.");
return error;
}
auto bucket_name = bucket_obj.GetString("bucket");
auto input_key_prefix = bucket_obj.GetString("input");
auto output_key_prefix = bucket_obj.GetString("output");

auto image_name = request.GetObject("object").GetString("key");
auto width = request.GetObject("object").GetInteger("width");
auto height = request.GetObject("object").GetInteger("height");

std::string body_str;
uint64_t download_time;
{
std::string input_key = input_key_prefix + "/" + image_name;
auto ans = client_.download_file(bucket_name, input_key);
body_str = std::get<0>(ans);
download_time = std::get<1>(ans);

if (body_str.empty())
{
Aws::Utils::Json::JsonValue error;
error.WithString("error", "Failed to download object from S3: " + input_key);
return error;
}
}

std::vector<char> vectordata(body_str.begin(), body_str.end());
cv::Mat image = imdecode(cv::Mat(vectordata), 1);

// Apply the thumbnailer function and measure the computing time
cv::Mat image2;
uint64_t computing_time;
{
auto start_time = timeSinceEpochMicrosec();
thumbnailer(image, width, height, image2);
computing_time = timeSinceEpochMicrosec() - start_time;
}

std::vector<unsigned char> out_buffer;
cv::imencode(".jpg", image2, out_buffer);

// Create a unique key name for the output image
std::string key_name;
{
std::string output_key = output_key_prefix + "/" + image_name;
std::string name, extension;
if (output_key.find_last_of('.') != std::string::npos)
{
name = output_key.substr(0, output_key.find_last_of('.'));
extension = output_key.substr(output_key.find_last_of('.'));
}
else
{
name = output_key;
extension = "";
}
key_name = name + "."
+ boost::uuids::to_string(boost::uuids::random_generator()())
+ extension;
}

// Upload the resulting image to S3
// If the upload fails, return an error
Aws::String upload_data(out_buffer.begin(), out_buffer.end());

uint64_t upload_time = client_.upload_random_file(
bucket_name, key_name, true,
reinterpret_cast<char *>(out_buffer.data()), out_buffer.size());

if (upload_time == 0)
{
Aws::Utils::Json::JsonValue error;
error.WithString("error", "Failed to upload object to S3: " + key_name);
return error;
}


Aws::Utils::Json::JsonValue val;
Aws::Utils::Json::JsonValue result;
Aws::Utils::Json::JsonValue measurements;

result.WithString("bucket", bucket_name);
result.WithString("key", key_name);
val.WithObject("result", result);

measurements.WithInteger("download_time", download_time);
measurements.WithInteger("upload_time", upload_time);
measurements.WithInteger("compute_time", computing_time);
measurements.WithInteger("download_size", vectordata.size());
measurements.WithInteger("upload_size", out_buffer.size());
val.WithObject("measurements", measurements);
return val;
}
5 changes: 3 additions & 2 deletions benchmarks/400.inference/411.image-recognition/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"timeout": 60,
"memory": 512,
"languages": ["python"],
"modules": ["storage"]
"languages": ["python", "cpp"],
"modules": ["storage"],
"cpp_dependencies": ["torch", "opencv"]
}
122 changes: 122 additions & 0 deletions benchmarks/400.inference/411.image-recognition/cpp/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#include <aws/core/Aws.h>
#include <aws/core/utils/json/JsonSerializer.h>

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

#include <iostream>
#include <vector>

#include "utils.hpp"
#include "storage.hpp"

#include <torch/torch.h>
#include <torch/script.h>

#include <torchvision/vision.h>
#include <torchvision/models/resnet.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/opencv.hpp>


#define kIMAGE_SIZE 224
#define kCHANNELS 3
#define kTOP_K 3


bool load_image(cv::Mat &image)
{

// image = cv::imread(file_name); // CV_8UC3
if (image.empty() || !image.data)
{
return false;
}
cv::cvtColor(image, image, cv::COLOR_BGR2RGB);

int w = image.size().width, h = image.size().height;
cv::Size scale((int)256 * ((float)w) / h, 256);
cv::resize(image, image, scale);
w = image.size().width, h = image.size().height;
image = image(cv::Range(16, 240), cv::Range(80, 304));
image.convertTo(image, CV_32FC3, 1.0f / 255.0f);

return true;
}

int recognition(cv::Mat &image)
{

static bool initialized = false;
static torch::jit::script::Module module;
if (!initialized)
{
try
{
std::cout << "Initialize ResNet50 model" << std::endl;
module = torch::jit::load("./resnet50.pt");
}
catch (const c10::Error &e)
{
std::cerr << "error loading the model\n";
return -1;
}
initialized = true;
}

if (load_image(image))
{

auto input_tensor = torch::from_blob(
image.data, {1, kIMAGE_SIZE, kIMAGE_SIZE, kCHANNELS});
input_tensor = input_tensor.permute({0, 3, 1, 2});
// input_tensor = input_tensor.permute({0, 1, 2, 3});
input_tensor[0][0] = input_tensor[0][0].sub_(0.485).div_(0.229);
input_tensor[0][1] = input_tensor[0][1].sub_(0.456).div_(0.224);
input_tensor[0][2] = input_tensor[0][2].sub_(0.406).div_(0.225);

torch::Tensor out_tensor = module.forward({input_tensor}).toTensor();
auto results = out_tensor.sort(-1, true);
auto softmaxs = std::get<0>(results)[0].softmax(0);
auto indexs = std::get<1>(results)[0];

std::cout << indexs[0].item<int>() << " " << softmaxs[0].item<double>() << std::endl;
return indexs[0].item<int>();
// for(int i = 0; i < 100; ++i)
// std::cout << softmaxs[i].item<double>() << ' ';
// std::cout << '\n';
// for(int i = 0; i < 100; ++i)
// std::cout << indexs[i].item<int>() << ' ';
// std::cout << '\n';
}

return -1;
}

Aws::Utils::Json::JsonValue function(Aws::Utils::Json::JsonView request)
{
sebs::Storage client_ = sebs::Storage::get_client();

auto bucket_obj = request.GetObject("bucket");
if (!bucket_obj.IsObject())
{
Aws::Utils::Json::JsonValue error;
error.WithString("error", "Bucket object is not valid.");
return error;
}

auto bucket_name = bucket_obj.GetString("bucket");
auto input_prefix = bucket_obj.GetString("input");
auto model_prefix = bucket_obj.GetString("model");
auto key = request.GetObject("object").GetString("input");
auto model_key = request.GetObject("object").GetString("model");



Aws::Utils::Json::JsonValue val;
Aws::Utils::Json::JsonValue result;
Aws::Utils::Json::JsonValue measurements;

return val;
}
5 changes: 3 additions & 2 deletions benchmarks/500.scientific/501.graph-pagerank/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"timeout": 120,
"memory": 512,
"languages": ["python"],
"modules": []
"languages": ["python", "cpp"],
"modules": [],
"cpp_dependencies": ["igraph"]
}
56 changes: 56 additions & 0 deletions benchmarks/500.scientific/501.graph-pagerank/cpp/function.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@

#include <igraph.h>

#include <cfloat>

#include "utils.hpp"

igraph_real_t graph_pagerank
(int size, uint64_t seed, uint64_t &graph_generation_time_ms, uint64_t &compute_pr_time_ms)
{
igraph_t graph;
igraph_vector_t pagerank;
igraph_real_t value;

igraph_rng_seed(igraph_rng_default(), seed);
{
uint64_t start_time = timeSinceEpochMicrosec();
igraph_barabasi_game(
/* graph= */ &graph,
/* n= */ size,
/* power= */ 1,
/* m= */ 10,
/* outseq= */ NULL,
/* outpref= */ 0,
/* A= */ 1.0,
/* directed= */ 0,
/* algo= */ IGRAPH_BARABASI_PSUMTREE_MULTIPLE,
/* start_from= */ 0
);
graph_generation_time_ms = (timeSinceEpochMicrosec() - start_time);
}

igraph_vector_init(&pagerank, 0);
{
uint64_t start_time = timeSinceEpochMicrosec();
igraph_pagerank(&graph, IGRAPH_PAGERANK_ALGO_PRPACK,
&pagerank, &value,
igraph_vss_all(), IGRAPH_DIRECTED,
/* damping */ 0.85, /* weights */ NULL,
NULL /* not needed with PRPACK method */);
compute_pr_time_ms = (timeSinceEpochMicrosec() - start_time);
}
/* Check that the eigenvalue is 1, as expected. */
if (fabs(value - 1.0) > 32*DBL_EPSILON) {
fprintf(stderr, "PageRank failed to converge.\n");
return 1;
}

igraph_real_t result = VECTOR(pagerank)[0];

igraph_vector_destroy(&pagerank);
igraph_destroy(&graph);

return result;
}

Loading