Compare commits

...

13 Commits

Author SHA1 Message Date
3533491df1 Merge branch 'test' of github.com:ivanch/tcc into test 2023-10-03 15:30:15 -03:00
6f2d9c1f78 melhorias nos gráficos 2023-10-03 15:29:40 -03:00
6d8ec28dbb save image 2023-09-28 22:53:09 -03:00
4535ed5cf6 fix actix docker 2023-09-28 22:35:06 -03:00
4fa2ae956f curl 2023-09-28 21:03:32 -03:00
2e3398f683 average runs 2023-09-28 21:00:55 -03:00
2f91c3636f add actix 2023-09-28 20:40:45 -03:00
aa4b1e9709 add actix 2023-09-28 17:32:11 -03:00
b372e1c310 blur nativo 2023-09-27 22:28:52 -03:00
4ef0ab508f otimizando flask 2023-09-26 16:02:46 -03:00
9082b34aab ajuste 2023-09-25 20:52:02 -03:00
a9b48be817 ma 2023-09-25 20:07:14 -03:00
f2a9faed92 add express 2023-09-25 19:58:07 -03:00
14 changed files with 418 additions and 93 deletions

View File

@@ -9,11 +9,13 @@ namespace TCC.Services
public MagickImage BoxBlurImage(Stream imageStream, int radius) public MagickImage BoxBlurImage(Stream imageStream, int radius)
{ {
var image = new MagickImage(imageStream); var image = new MagickImage(imageStream);
var blurredImage = new MagickImage(image); image.GaussianBlur(radius, radius);
return image;
//var blurredImage = new MagickImage(image);
blurredImage = BoxBlurImageSeparable(image, blurredImage, radius, 0); //blurredImage = BoxBlurImageSeparable(image, blurredImage, radius, 0);
blurredImage = BoxBlurImageSeparable(blurredImage, blurredImage, 0, radius); //blurredImage = BoxBlurImageSeparable(blurredImage, blurredImage, 0, radius);
return blurredImage; //return blurredImage;
} }
private MagickImage BoxBlurImageSeparable(MagickImage image, MagickImage blurredImage, int radiusX, int radiusY) private MagickImage BoxBlurImageSeparable(MagickImage image, MagickImage blurredImage, int radiusX, int radiusY)

2
ActixAPI/.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
Dockerfile
target/

226
ActixAPI/Cargo.lock generated
View File

@@ -8,6 +8,8 @@ version = "0.1.0"
dependencies = [ dependencies = [
"actix-files", "actix-files",
"actix-web", "actix-web",
"magick_rust",
"qstring",
] ]
[[package]] [[package]]
@@ -296,6 +298,29 @@ version = "0.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
[[package]]
name = "bindgen"
version = "0.68.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078"
dependencies = [
"bitflags 2.4.0",
"cexpr",
"clang-sys",
"lazy_static",
"lazycell",
"log",
"peeking_take_while",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn 2.0.32",
"which",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "1.3.2"
@@ -363,12 +388,32 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clang-sys"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]] [[package]]
name = "convert_case" name = "convert_case"
version = "0.4.0" version = "0.4.0"
@@ -443,6 +488,12 @@ dependencies = [
"crypto-common", "crypto-common",
] ]
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
version = "0.8.33" version = "0.8.33"
@@ -452,6 +503,27 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "errno"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.27" version = "1.0.27"
@@ -534,6 +606,12 @@ version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.3.21" version = "0.3.21"
@@ -559,6 +637,15 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "home"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
dependencies = [
"windows-sys",
]
[[package]] [[package]]
name = "http" name = "http"
version = "0.2.9" version = "0.2.9"
@@ -629,12 +716,40 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.147" version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "libloading"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if",
"winapi",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128"
[[package]] [[package]]
name = "local-channel" name = "local-channel"
version = "0.1.3" version = "0.1.3"
@@ -669,6 +784,17 @@ version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "magick_rust"
version = "0.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c912b69250bcd5d024852a1a75c567d3b5d881871a55b741018741632a921bf8"
dependencies = [
"bindgen",
"libc",
"pkg-config",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.6.3" version = "2.6.3"
@@ -691,6 +817,12 @@ dependencies = [
"unicase", "unicase",
] ]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.7.1" version = "0.7.1"
@@ -712,6 +844,16 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]] [[package]]
name = "object" name = "object"
version = "0.32.1" version = "0.32.1"
@@ -756,6 +898,12 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.3.0" version = "2.3.0"
@@ -786,6 +934,16 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "prettyplease"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d"
dependencies = [
"proc-macro2",
"syn 2.0.32",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.66" version = "1.0.66"
@@ -795,6 +953,15 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "qstring"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e"
dependencies = [
"percent-encoding",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.33" version = "1.0.33"
@@ -878,6 +1045,12 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]] [[package]]
name = "rustc_version" name = "rustc_version"
version = "0.4.0" version = "0.4.0"
@@ -887,6 +1060,19 @@ dependencies = [
"semver", "semver",
] ]
[[package]]
name = "rustix"
version = "0.38.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662"
dependencies = [
"bitflags 2.4.0",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.15" version = "1.0.15"
@@ -959,6 +1145,12 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "shlex"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380"
[[package]] [[package]]
name = "signal-hook-registry" name = "signal-hook-registry"
version = "1.4.1" version = "1.4.1"
@@ -1169,6 +1361,40 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "which"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
dependencies = [
"either",
"home",
"once_cell",
"rustix",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.48.0" version = "0.48.0"

View File

@@ -8,3 +8,5 @@ edition = "2021"
[dependencies] [dependencies]
actix-web = "4" actix-web = "4"
actix-files = "0.6.2" actix-files = "0.6.2"
magick_rust = "0.19.1"
qstring = "0.7.2"

View File

@@ -1,25 +1,34 @@
FROM rust:slim-bullseye AS build-env FROM rust:latest
ENV MAGICK_VERSION 7.1
RUN apt-get update \
&& apt-get -y install wget curl build-essential clang pkg-config libjpeg-turbo-progs libpng-dev
RUN apt update && apt install curl -y \
&& curl https://imagemagick.org/archive/ImageMagick.tar.gz | tar xz \
&& cd ImageMagick-${MAGICK_VERSION}* \
&& ./configure --with-magick-plus-plus=no --with-perl=no \
&& make \
&& make install \
&& cd .. \
&& rm -r ImageMagick-${MAGICK_VERSION}*
WORKDIR /app WORKDIR /app
RUN wget https://files.ivanch.me/api/public/dl/iFuXSNhw/small-image.png && \
wget https://files.ivanch.me/api/public/dl/81Bkht5C/big-image.png && \
wget https://files.ivanch.me/api/public/dl/nAndfAjK/video.mp4
COPY . . COPY . .
RUN apt update && apt install wget -y && \ RUN cargo build --release && \
wget https://files.ivanch.me/api/public/dl/iFuXSNhw/small-image.png && \ cp ./target/release/ActixAPI . && \
wget https://files.ivanch.me/api/public/dl/81Bkht5C/big-image.png && \
wget https://files.ivanch.me/api/public/dl/nAndfAjK/video.mp4 && \
mv small-image.png ./static && \ mv small-image.png ./static && \
mv big-image.png ./static && \ mv big-image.png ./static && \
mv video.mp4 ./static mv video.mp4 ./static && \
ldconfig /usr/local/lib
RUN cargo build --release ENV LD_LIBRARY_PATH=/usr/local/lib
FROM debian:bullseye-slim
WORKDIR /app
COPY --from=build-env /app/target/release .
COPY --from=build-env /app/static ./static
ENTRYPOINT ["./ActixAPI"] ENTRYPOINT ["./ActixAPI"]

View File

@@ -1,21 +1,13 @@
use qstring::QString;
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder, HttpRequest, Result}; use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder, HttpRequest, Result};
use actix_files::NamedFile; use actix_files::NamedFile;
use std::path::PathBuf; use magick_rust::MagickWand;
#[get("/status/ok")] #[get("/status/ok")]
async fn hello() -> impl Responder { async fn hello() -> impl Responder {
HttpResponse::Ok().body("{\"status\": 200}") HttpResponse::Ok().body("{\"status\": 200}")
} }
#[post("/echo")]
async fn echo(req_body: String) -> impl Responder {
HttpResponse::Ok().body(req_body)
}
async fn manual_hello() -> impl Responder {
HttpResponse::Ok().body("Hey there!")
}
async fn static_serve(req: HttpRequest) -> Result<NamedFile> { async fn static_serve(req: HttpRequest) -> Result<NamedFile> {
let path: &str = req.path(); let path: &str = req.path();
let real_path = &path[1..]; let real_path = &path[1..];
@@ -23,6 +15,53 @@ async fn static_serve(req: HttpRequest) -> Result<NamedFile> {
Ok(NamedFile::open(real_path)?) Ok(NamedFile::open(real_path)?)
} }
#[get("/image/load-small-image")]
async fn load_small_image() -> Result<NamedFile> {
let real_path = "static/small-image.png";
Ok(NamedFile::open(real_path)?)
}
#[get("/image/load-big-image")]
async fn load_big_image() -> Result<NamedFile> {
let real_path = "static/big-image.png";
Ok(NamedFile::open(real_path)?)
}
#[post("/image/save-big-image")]
async fn save_big_image(image_data: web::Bytes) -> Result<HttpResponse> {
// Write bytes to file
std::fs::write("image.png", &image_data).unwrap();
// Return the blurred image bytes
Ok(HttpResponse::Ok()
.content_type("application/json")
.body("{\"status\": 200}"))
}
#[post("/image/blur")]
async fn blur_image(image_data: web::Bytes, req: HttpRequest) -> Result<HttpResponse> {
// Load the image from the incoming bytes
let mut wand = MagickWand::new();
wand.read_image_blob(&image_data).unwrap();
let query_str = req.query_string();
let qs = QString::from(query_str);
let radius = qs.get("radius").unwrap_or("5").parse::<f64>().unwrap_or(5.0);
// Blur the image
wand.blur_image(radius, radius).unwrap();
// Convert the image back to bytes
let blurred_image_bytes = wand.write_image_blob("png").unwrap();
// Return the blurred image bytes
Ok(HttpResponse::Ok()
.content_type("image/png")
.body(blurred_image_bytes))
}
#[actix_web::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
println!("Hello, world!"); println!("Hello, world!");
@@ -31,10 +70,13 @@ async fn main() -> std::io::Result<()> {
App::new() App::new()
.route("/static/{filename:.*}", web::get().to(static_serve)) .route("/static/{filename:.*}", web::get().to(static_serve))
.service(hello) .service(hello)
.service(echo) .service(load_small_image)
.route("/hey", web::get().to(manual_hello)) .service(load_big_image)
.service(save_big_image)
.service(blur_image)
.app_data(web::PayloadConfig::new(1024 * 1024 * 1024))
}) })
.bind(("0.0.0.0", 9090))? .bind(("0.0.0.0", 5000))?
.run() .run()
.await .await
} }

View File

@@ -11,10 +11,10 @@ def blur_image():
image = request.get_data() image = request.get_data()
if radius and image: if radius and image:
return send_file(image_service.box_blur_image(image, radius), return send_file(io.BytesIO(image_service.box_blur_image(image, radius)),
mimetype='image/jpeg', mimetype='image/png',
as_attachment=True, as_attachment=True,
download_name='blurred_image.jpeg') download_name='blurred_image.png')
return "Bad request", 400 return "Bad request", 400

View File

@@ -1,29 +1,33 @@
from wand.image import Image from wand.image import Image, Color
def box_blur_image_separable(image, radius_x, radius_y): def box_blur_image_separable(image, radius_x, radius_y):
blurred_image = image.clone()
width, height = image.width, image.height width, height = image.width, image.height
kernel_x_size = 2 * radius_x + 1
kernel_y_size = 2 * radius_y + 1
kernel_area = kernel_x_size * kernel_y_size
blurred_image = image.clone()
for y in range(height): for y in range(height):
for x in range(width): for x in range(width):
blurred_image[x, y] = image[x, y]
r_total, g_total, b_total = 0, 0, 0 r_total, g_total, b_total = 0, 0, 0
pixel_count = 0
for offset_y in range(-radius_y, radius_y + 1): for offset_y in range(-radius_y, radius_y + 1):
for offset_x in range(-radius_x, radius_x + 1): for offset_x in range(-radius_x, radius_x + 1):
new_x = x + offset_x new_x = x + offset_x
new_y = y + offset_y new_y = y + offset_y
if 0 <= new_x < width and 0 <= new_y < height: if 0 <= new_x < width and 0 <= new_y < height:
r_total += image[new_x, new_y].red_int8 pixel = image[new_x, new_y]
g_total += image[new_x, new_y].green_int8 r_total += pixel.red_int8
b_total += image[new_x, new_y].blue_int8 g_total += pixel.green_int8
pixel_count += 1 b_total += pixel.blue_int8
blurred_image[x, y].red_int8 = int(r_total / pixel_count) r_avg = int(r_total / kernel_area)
blurred_image[x, y].green_int8 = int(g_total / pixel_count) g_avg = int(g_total / kernel_area)
blurred_image[x, y].blue_int8 = int(b_total / pixel_count) b_avg = int(b_total / kernel_area)
blurred_image[x, y] = Color(f'rgb({r_avg},{g_avg},{b_avg})')
return blurred_image return blurred_image
@@ -33,9 +37,12 @@ class ImageService:
def box_blur_image(self, img, radius): def box_blur_image(self, img, radius):
with Image(blob=img) as image: with Image(blob=img) as image:
blurred_image = box_blur_image_separable(image, radius, 0) image.gaussian_blur(radius, radius)
blurred_image = box_blur_image_separable(blurred_image, 0, radius) return image.make_blob()
return blurred_image.make_blob()
# blurred_image = box_blur_image_separable(image, radius, 0)
# blurred_image = box_blur_image_separable(blurred_image, 0, radius)
# return blurred_image.make_blob()
def get_simple_image(self): def get_simple_image(self):
with open("./static/small-image.png", "rb") as file: with open("./static/small-image.png", "rb") as file:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -31,10 +31,21 @@ services:
build: ./ActixAPI build: ./ActixAPI
restart: always restart: always
ports: ports:
- "9083:9090" - "9083:5000"
deploy:
resources:
limits:
cpus: '1'
memory: 1GB
tcc-express:
image: tcc:express
container_name: tcc-express
build: ./tcc-express
restart: always
ports:
- "9084:5000"
deploy: deploy:
resources: resources:
limits: limits:
cpus: '1' cpus: '1'
memory: 1GB memory: 1GB

View File

@@ -2,15 +2,19 @@ FRAMEWORKS = [
('Actix', 'tcc-actix'), ('Actix', 'tcc-actix'),
('ASP.NET', 'tcc-aspnet'), ('ASP.NET', 'tcc-aspnet'),
('Flask', 'tcc-flask'), ('Flask', 'tcc-flask'),
('Express', 'tcc-express'),
] ]
ENDPOINTS = { ENDPOINTS = {
'Actix': 'http://localhost:9083', 'Actix': 'http://localhost:9083',
'ASP.NET': 'http://localhost:9081', 'ASP.NET': 'http://localhost:9081',
'Flask': 'http://localhost:9082', 'Flask': 'http://localhost:9082',
'Express': 'http://localhost:9084',
} }
BLUR_RADIUS = 5 BLUR_RADIUS = 5
AVG_RUNS = 3
API_REQUESTS = [ API_REQUESTS = [
('/status/ok', 'GET', range(0, 30_000, 5000), None), ('/status/ok', 'GET', range(0, 30_000, 5000), None),
('/image/save-big-image', 'POST', range(0, 10_000, 1_000), open('big-image.png', 'rb').read()), ('/image/save-big-image', 'POST', range(0, 10_000, 1_000), open('big-image.png', 'rb').read()),

View File

@@ -1,9 +1,8 @@
import numpy as np import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import os from common import API_REQUESTS, FRAMEWORKS
from common import API_REQUESTS
FRAMEWORKS = ['Actix', 'ASP.NET', 'Flask'] FRAMEWORKS = [f for f, _ in FRAMEWORKS]
def plot_graph(x_data, y_data, title, x_label, y_label, filename): def plot_graph(x_data, y_data, title, x_label, y_label, filename):
for i, framework in enumerate(FRAMEWORKS): for i, framework in enumerate(FRAMEWORKS):
@@ -26,10 +25,10 @@ def plot_resource_graph(x_data, y_data, title, x_label, y_label, filename):
frameworks[framework] = y_data[i] frameworks[framework] = y_data[i]
x = np.arange(len(requests)) x = np.arange(len(requests))
width = 0.10 width = 0.2
multiplier = 0 multiplier = 0
fig, ax = plt.subplots(layout='constrained') fig, ax = plt.subplots(layout='constrained', figsize=(7.5, 5))
print(x) print(x)
for framework, measurements in frameworks.items(): for framework, measurements in frameworks.items():
@@ -46,9 +45,9 @@ def plot_resource_graph(x_data, y_data, title, x_label, y_label, filename):
ax.set_xlabel(x_label) ax.set_xlabel(x_label)
ax.set_ylabel(y_label) ax.set_ylabel(y_label)
ax.set_title(title) ax.set_title(title)
ax.set_xticks(x + (width/2), requests) ax.set_xticks(x + (width*1.5), requests)
ax.legend(loc='upper left', ncols=len(frameworks.items())) ax.legend(loc='upper left', ncols=len(frameworks.items()))
ax.set_ylim(0, 120) ax.set_ylim(0, 115)
plt.savefig(f'{filename}.png') plt.savefig(f'{filename}.png')
@@ -80,8 +79,15 @@ def get_resource_data(filename):
for line in lines: for line in lines:
line = line.strip().split(',') line = line.strip().split(',')
if line: if line:
r = [round(float(line[1])*100), round(float(line[2])*100)]
if r[0] > 100:
r[0] = 100
if r[1] > 100:
r[1] = 100
x.append(int(line[0])) # requests x.append(int(line[0])) # requests
y.append([float(v)*100 for v in line[1:]]) # cpu, ram y.append(r) # cpu, ram
return x, y return x, y
@@ -91,7 +97,7 @@ def generate_req_graph(filename, framework_name, endpoint_name):
for f in FRAMEWORKS: for f in FRAMEWORKS:
newfile = filename.replace(framework_name, f) newfile = filename.replace(framework_name, f)
_, y_data = get_resource_data(newfile) _, y_data = get_data(newfile)
y.append(y_data) y.append(y_data)
@@ -110,17 +116,17 @@ def generate_resource_graph(filename, framework_name, endpoint_name):
y.append([data[resource_index] for data in y_data]) y.append([data[resource_index] for data in y_data])
graph_file = f'{resource}_{endpoint_name.replace("/", "").replace("?", "")}' graph_file = f'{resource}_{endpoint_name.replace("/", "").replace("?", "")}'
plot_resource_graph(x, y, f'Uso de {resource.upper()} - {endpoint_name}', 'Número de requisições', 'Uso (%)', graph_file) plot_resource_graph(x, y, f'Uso de {resource.upper()} - {endpoint_name}', 'Número de requisições', f'Uso de {resource.upper()} (%)', graph_file)
if __name__ == '__main__': if __name__ == '__main__':
endpoints = [config[0] for config in API_REQUESTS] endpoints = [config[0] for config in API_REQUESTS]
for endpoint_name in endpoints: for endpoint_name in endpoints:
framework_name = 'Actix' framework_name = 'ASP.NET'
endpoint_file = endpoint_name.replace('/', '') endpoint_file = endpoint_name.replace('/', '')
filename = f'data/resource_Actix_{endpoint_file}.csv' filename = f'data/resource_ASP.NET_{endpoint_file}.csv'
generate_resource_graph(filename, framework_name, endpoint_name) generate_resource_graph(filename, framework_name, endpoint_name)
filename = f'data/req_Actix_{endpoint_file}.csv' filename = f'data/req_ASP.NET_{endpoint_file}.csv'
generate_req_graph(filename, framework_name, endpoint_name) generate_req_graph(filename, framework_name, endpoint_name)

View File

@@ -2,11 +2,10 @@ import requests
import docker import docker
import concurrent.futures import concurrent.futures
import time import time
import sys
import os import os
from math import floor from math import floor
from init import init from init import init
from common import FRAMEWORKS, ENDPOINTS, API_REQUESTS from common import FRAMEWORKS, ENDPOINTS, API_REQUESTS, AVG_RUNS
init() init()
@@ -62,10 +61,13 @@ def run_tests(endpoint, method, num_requests, metadata):
for num_request in num_requests: for num_request in num_requests:
if num_request <= 0: continue if num_request <= 0: continue
total_cpu, total_ram = 0, 0
total_time = 0
for run in range(AVG_RUNS):
ok_responses = 0 ok_responses = 0
bad_responses = 0 bad_responses = 0
server_errors = 0 server_errors = 0
cpu, ram = 0, 0
with concurrent.futures.ThreadPoolExecutor(max_workers=THREADS) as executor: with concurrent.futures.ThreadPoolExecutor(max_workers=THREADS) as executor:
url = f'{URL_BASE}{endpoint}' url = f'{URL_BASE}{endpoint}'
@@ -82,10 +84,13 @@ def run_tests(endpoint, method, num_requests, metadata):
if i == half: if i == half:
cpu, ram = get_resource_usage() cpu, ram = get_resource_usage()
total_cpu += float(cpu)
total_ram += float(ram)
concurrent.futures.wait(futures) concurrent.futures.wait(futures)
elapsed_time = time.time() - start_time elapsed_time = time.time() - start_time
total_time += elapsed_time
for future in futures: for future in futures:
responses = future.result() responses = future.result()
@@ -93,12 +98,20 @@ def run_tests(endpoint, method, num_requests, metadata):
bad_responses += responses[4] bad_responses += responses[4]
server_errors += responses[5] server_errors += responses[5]
print(f"{num_request}: {elapsed_time:.2f} seconds. {elapsed_time/num_request:.4f} seconds per request. {num_request/elapsed_time:.2f} requests per second. [OK: {ok_responses}, Bad Request: {bad_responses}, Server Error: {server_errors}]]") print(f"[#{run}] {num_request}: {elapsed_time:.2f} seconds. {elapsed_time/num_request:.4f} seconds per request. {num_request/elapsed_time:.2f} requests per second. [OK: {ok_responses}, Bad Request: {bad_responses}, Server Error: {server_errors}]]")
record(files[0], num_request, f"{num_request/elapsed_time:.2f}")
record_resource(files[1], num_request, cpu, ram) client = docker.from_env()
client.containers.get(CONTAINER_NAME).restart()
time.sleep(3) time.sleep(3)
cpu = total_cpu / AVG_RUNS
ram = total_ram / AVG_RUNS
elapsed_time = total_time / AVG_RUNS
record(files[0], num_request, f"{num_request/elapsed_time:.2f}")
record_resource(files[1], num_request, cpu, ram)
def get_resource_usage(): def get_resource_usage():
if CONTAINER_NAME == "": return 0, 0 if CONTAINER_NAME == "": return 0, 0

1
tcc-express Submodule

Submodule tcc-express added at 504b59278f