mirror of
				https://github.com/ivanch/tcc.git
				synced 2025-11-04 03:07:36 +00:00 
			
		
		
		
	Compare commits
	
		
			3 Commits
		
	
	
		
			FlaskAPI
			...
			05dad7ade5
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 05dad7ade5 | |||
| cd1e9da710 | |||
| 1dbd8c238f | 
							
								
								
									
										12
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,4 +1,14 @@
 | 
			
		||||
.vs
 | 
			
		||||
__pycache__
 | 
			
		||||
bin
 | 
			
		||||
obj
 | 
			
		||||
*.png
 | 
			
		||||
*.vscode
 | 
			
		||||
__pycache__
 | 
			
		||||
.idea
 | 
			
		||||
 | 
			
		||||
*/target
 | 
			
		||||
 | 
			
		||||
*.png
 | 
			
		||||
*.csv
 | 
			
		||||
*.jpg
 | 
			
		||||
*.mp4
 | 
			
		||||
@@ -23,6 +23,7 @@ namespace TCC.Controllers
 | 
			
		||||
            mstream.Position = 0;
 | 
			
		||||
 | 
			
		||||
            var result = ImageService.BoxBlurImage(mstream, radius);
 | 
			
		||||
            mstream.Close();
 | 
			
		||||
 | 
			
		||||
            var blurredImageStream = new MemoryStream();
 | 
			
		||||
            result.Write(blurredImageStream);
 | 
			
		||||
@@ -31,28 +32,16 @@ namespace TCC.Controllers
 | 
			
		||||
            return File(blurredImageStream, "image/png");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [HttpGet("load-image")]
 | 
			
		||||
        [HttpGet("load-small-image")]
 | 
			
		||||
        public async Task<IActionResult> GetSimpleImage()
 | 
			
		||||
        {
 | 
			
		||||
            var result = ImageService.GetSimpleImage();
 | 
			
		||||
 | 
			
		||||
            var imageStream = new MemoryStream();
 | 
			
		||||
            result.Write(imageStream);
 | 
			
		||||
            imageStream.Position = 0;
 | 
			
		||||
 | 
			
		||||
            return File(imageStream, "image/png");
 | 
			
		||||
            return File(ImageService.GetSimpleImage(), "image/png");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [HttpGet("load-big-image")]
 | 
			
		||||
        public async Task<IActionResult> GetBigImage()
 | 
			
		||||
        {
 | 
			
		||||
            var result = ImageService.GetBigImage();
 | 
			
		||||
 | 
			
		||||
            var imageStream = new MemoryStream();
 | 
			
		||||
            result.Write(imageStream);
 | 
			
		||||
            imageStream.Position = 0;
 | 
			
		||||
 | 
			
		||||
            return File(imageStream, "image/png");
 | 
			
		||||
            return File(ImageService.GetBigImage(), "image/png");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [HttpPost("save-big-image")]
 | 
			
		||||
@@ -61,6 +50,7 @@ namespace TCC.Controllers
 | 
			
		||||
            MemoryStream mstream = new MemoryStream();
 | 
			
		||||
            await HttpContext.Request.Body.CopyToAsync(mstream);
 | 
			
		||||
            mstream.Position = 0;
 | 
			
		||||
            mstream.Close();
 | 
			
		||||
 | 
			
		||||
            return Ok();
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ FROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim AS build-env
 | 
			
		||||
WORKDIR /App
 | 
			
		||||
 | 
			
		||||
# Copy everything
 | 
			
		||||
RUN apt update && apt install wget -y
 | 
			
		||||
COPY * .
 | 
			
		||||
 | 
			
		||||
# Restore as distinct layers
 | 
			
		||||
@@ -10,15 +11,21 @@ RUN dotnet restore
 | 
			
		||||
# Build a release
 | 
			
		||||
RUN dotnet build -c Release -o out
 | 
			
		||||
 | 
			
		||||
RUN cd out && \
 | 
			
		||||
    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 && \
 | 
			
		||||
    rm -rf runtimes && \
 | 
			
		||||
    mkdir -p ./static && \
 | 
			
		||||
    mv small-image.png ./static && \
 | 
			
		||||
    mv big-image.png ./static && \
 | 
			
		||||
    mv video.mp4 ./static
 | 
			
		||||
 | 
			
		||||
# Build runtime image
 | 
			
		||||
FROM mcr.microsoft.com/dotnet/aspnet:6.0-bullseye-slim
 | 
			
		||||
 | 
			
		||||
WORKDIR /App
 | 
			
		||||
 | 
			
		||||
RUN wget https://files.ivanch.me/api/public/dl/QFCLgtrG/simpleimage.png && \
 | 
			
		||||
    wget https://files.ivanch.me/api/public/dl/E0VLgWbx/bigimage.png && \
 | 
			
		||||
    rm -rf runtimes
 | 
			
		||||
 | 
			
		||||
COPY --from=build-env /App/out .
 | 
			
		||||
 | 
			
		||||
ENTRYPOINT ["dotnet", "/App/TCC.APP.dll"]
 | 
			
		||||
@@ -4,13 +4,13 @@ namespace tcc_app
 | 
			
		||||
{
 | 
			
		||||
    public static class ImageHelper
 | 
			
		||||
    {
 | 
			
		||||
        public static MagickImage SimpleImage;
 | 
			
		||||
        public static MagickImage BigImage;
 | 
			
		||||
        public static byte[] SimpleImage;
 | 
			
		||||
        public static byte[] BigImage;
 | 
			
		||||
 | 
			
		||||
        static ImageHelper()
 | 
			
		||||
        {
 | 
			
		||||
            SimpleImage = new MagickImage("simpleimage.png");
 | 
			
		||||
            BigImage = new MagickImage("bigimage.png");
 | 
			
		||||
            SimpleImage = File.ReadAllBytes("static/small-image.png");
 | 
			
		||||
            BigImage = File.ReadAllBytes("static/big-image.png");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
 | 
			
		||||
using Microsoft.Extensions.FileProviders;
 | 
			
		||||
using TCC.Services;
 | 
			
		||||
 | 
			
		||||
namespace TCC
 | 
			
		||||
@@ -18,9 +19,13 @@ namespace TCC
 | 
			
		||||
                options.Limits.MaxRequestBodySize = int.MaxValue; // if don't set default value is: 30 MB
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            var app = builder.Build();
 | 
			
		||||
 | 
			
		||||
            app.UseStaticFiles(new StaticFileOptions
 | 
			
		||||
            {
 | 
			
		||||
                FileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.ContentRootPath, "static")),
 | 
			
		||||
                RequestPath = "/static"
 | 
			
		||||
            });
 | 
			
		||||
            app.MapControllers();
 | 
			
		||||
 | 
			
		||||
            app.Run();
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
      "dotnetRunMessages": true,
 | 
			
		||||
      "launchBrowser": false,
 | 
			
		||||
      "launchUrl": "weatherforecast",
 | 
			
		||||
      "applicationUrl": "http://0.0.0.0:5100",
 | 
			
		||||
      "applicationUrl": "http://0.0.0.0:9090",
 | 
			
		||||
      "environmentVariables": {
 | 
			
		||||
        "ASPNETCORE_ENVIRONMENT": "Development"
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -62,14 +62,16 @@ namespace TCC.Services
 | 
			
		||||
            file.Close();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public MagickImage GetSimpleImage()
 | 
			
		||||
        public byte[] GetSimpleImage()
 | 
			
		||||
        {
 | 
			
		||||
            return ImageHelper.SimpleImage;
 | 
			
		||||
            return File.ReadAllBytes("static/small-image.png");
 | 
			
		||||
            //return ImageHelper.SimpleImage;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public MagickImage GetBigImage()
 | 
			
		||||
        public byte[] GetBigImage()
 | 
			
		||||
        {
 | 
			
		||||
            return ImageHelper.BigImage;
 | 
			
		||||
            return File.ReadAllBytes("static/big-image.png");
 | 
			
		||||
            //return ImageHelper.BigImage;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										33
									
								
								ASP.NET/static/nginx.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								ASP.NET/static/nginx.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
    <title>Welcome to nginx!</title>
 | 
			
		||||
    <style>
 | 
			
		||||
        html {
 | 
			
		||||
            color-scheme: light dark;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        body {
 | 
			
		||||
            width: 35em;
 | 
			
		||||
            margin: 0 auto;
 | 
			
		||||
            font-family: Tahoma, Verdana, Arial, sans-serif;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <h1>Welcome to nginx!</h1>
 | 
			
		||||
    <p>
 | 
			
		||||
        If you see this page, the nginx web server is successfully installed and
 | 
			
		||||
        working. Further configuration is required.
 | 
			
		||||
    </p>
 | 
			
		||||
 | 
			
		||||
    <p>
 | 
			
		||||
        For online documentation and support please refer to
 | 
			
		||||
        <a href="http://nginx.org/">nginx.org</a>.<br />
 | 
			
		||||
        Commercial support is available at
 | 
			
		||||
        <a href="http://nginx.com/">nginx.com</a>.
 | 
			
		||||
    </p>
 | 
			
		||||
 | 
			
		||||
    <p><em>Thank you for using nginx.</em></p>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										1266
									
								
								ActixAPI/Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										1266
									
								
								ActixAPI/Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										10
									
								
								ActixAPI/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								ActixAPI/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
[package]
 | 
			
		||||
name = "ActixAPI"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
actix-web = "4"
 | 
			
		||||
actix-files = "0.6.2"
 | 
			
		||||
							
								
								
									
										25
									
								
								ActixAPI/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								ActixAPI/Dockerfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
FROM rust:slim-bullseye AS build-env
 | 
			
		||||
 | 
			
		||||
WORKDIR /app
 | 
			
		||||
 | 
			
		||||
COPY . .
 | 
			
		||||
 | 
			
		||||
RUN apt update && apt install wget -y && \
 | 
			
		||||
    wget https://files.ivanch.me/api/public/dl/Dj0gkp-m/small-image.png && \
 | 
			
		||||
    wget https://files.ivanch.me/api/public/dl/FqHEPM1Q/big-image.png && \
 | 
			
		||||
    wget https://files.ivanch.me/api/public/dl/nTAYqZwD/video.mp4 && \
 | 
			
		||||
    mv small-image.png ./static && \
 | 
			
		||||
    mv big-image.png ./static && \
 | 
			
		||||
    mv video.mp4 ./static
 | 
			
		||||
 | 
			
		||||
RUN cargo build --release
 | 
			
		||||
 | 
			
		||||
FROM debian:bullseye-slim
 | 
			
		||||
 | 
			
		||||
WORKDIR /app
 | 
			
		||||
 | 
			
		||||
COPY --from=build-env /app/target/release .
 | 
			
		||||
 | 
			
		||||
COPY --from=build-env /app/static .
 | 
			
		||||
 | 
			
		||||
ENTRYPOINT ["./ActixAPI"]
 | 
			
		||||
							
								
								
									
										40
									
								
								ActixAPI/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								ActixAPI/src/main.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder, HttpRequest, Result};
 | 
			
		||||
use actix_files::NamedFile;
 | 
			
		||||
use std::path::PathBuf;
 | 
			
		||||
 | 
			
		||||
#[get("/status/ok")]
 | 
			
		||||
async fn hello() -> impl Responder {
 | 
			
		||||
    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> {
 | 
			
		||||
    let path: &str = req.path();
 | 
			
		||||
    let real_path = &path[1..];
 | 
			
		||||
 | 
			
		||||
    Ok(NamedFile::open(real_path)?)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[actix_web::main]
 | 
			
		||||
async fn main() -> std::io::Result<()> {
 | 
			
		||||
    println!("Hello, world!");
 | 
			
		||||
 | 
			
		||||
    HttpServer::new(|| {
 | 
			
		||||
        App::new()
 | 
			
		||||
            .route("/static/{filename:.*}", web::get().to(static_serve))
 | 
			
		||||
            .service(hello)
 | 
			
		||||
            .service(echo)
 | 
			
		||||
            .route("/hey", web::get().to(manual_hello))
 | 
			
		||||
    })
 | 
			
		||||
    .bind(("0.0.0.0", 9090))?
 | 
			
		||||
    .run()
 | 
			
		||||
    .await
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								ActixAPI/static/nginx.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								ActixAPI/static/nginx.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
    <title>Welcome to nginx!</title>
 | 
			
		||||
    <style>
 | 
			
		||||
        html {
 | 
			
		||||
            color-scheme: light dark;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        body {
 | 
			
		||||
            width: 35em;
 | 
			
		||||
            margin: 0 auto;
 | 
			
		||||
            font-family: Tahoma, Verdana, Arial, sans-serif;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <h1>Welcome to nginx!</h1>
 | 
			
		||||
    <p>
 | 
			
		||||
        If you see this page, the nginx web server is successfully installed and
 | 
			
		||||
        working. Further configuration is required.
 | 
			
		||||
    </p>
 | 
			
		||||
 | 
			
		||||
    <p>
 | 
			
		||||
        For online documentation and support please refer to
 | 
			
		||||
        <a href="http://nginx.org/">nginx.org</a>.<br />
 | 
			
		||||
        Commercial support is available at
 | 
			
		||||
        <a href="http://nginx.com/">nginx.com</a>.
 | 
			
		||||
    </p>
 | 
			
		||||
 | 
			
		||||
    <p><em>Thank you for using nginx.</em></p>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										89
									
								
								scripts/graph.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								scripts/graph.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
import numpy as np
 | 
			
		||||
import matplotlib.pyplot as plt
 | 
			
		||||
 | 
			
		||||
def plot_graph(x, y, title, x_label, y_label, filename):
 | 
			
		||||
    plt.plot(x, y, 'ro', markersize=1, linewidth=0.5, linestyle='solid')
 | 
			
		||||
    plt.title(title)
 | 
			
		||||
    plt.xlabel(x_label)
 | 
			
		||||
    plt.ylabel(y_label)
 | 
			
		||||
    plt.savefig(f'{filename}.png')
 | 
			
		||||
 | 
			
		||||
    plt.clf()
 | 
			
		||||
    plt.close('all')
 | 
			
		||||
 | 
			
		||||
def plot_resource_graph(x_data, y_data, title, x_label, y_label, filename):
 | 
			
		||||
    requests = x_data
 | 
			
		||||
    resource = {
 | 
			
		||||
        'CPU': [p[0] for p in y_data],
 | 
			
		||||
        'RAM': [p[1] for p in y_data],
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    x = np.arange(len(requests))
 | 
			
		||||
    width = 0.25
 | 
			
		||||
    multiplier = 0
 | 
			
		||||
 | 
			
		||||
    fig, ax = plt.subplots(layout='constrained')
 | 
			
		||||
 | 
			
		||||
    for attribute, measurement in resource.items():
 | 
			
		||||
        offset = width * multiplier
 | 
			
		||||
 | 
			
		||||
        rects = ax.bar(x + offset, measurement, width, label=attribute)
 | 
			
		||||
        ax.bar_label(rects, padding=3)
 | 
			
		||||
        multiplier += 1
 | 
			
		||||
 | 
			
		||||
    # Add some text for labels, title and custom x-axis tick labels, etc.
 | 
			
		||||
    ax.set_xlabel(x_label)
 | 
			
		||||
    ax.set_ylabel(y_label)
 | 
			
		||||
    ax.set_title(title)
 | 
			
		||||
    ax.set_xticks(x + (width/2), requests)
 | 
			
		||||
    ax.legend(loc='upper left', ncols=len(resource.items()))
 | 
			
		||||
    ax.set_ylim(0, 100)
 | 
			
		||||
 | 
			
		||||
    plt.savefig(f'{filename}.png')
 | 
			
		||||
 | 
			
		||||
    plt.clf()
 | 
			
		||||
    plt.close('all')
 | 
			
		||||
 | 
			
		||||
def get_data(filename):
 | 
			
		||||
    lines = []
 | 
			
		||||
    with open(filename, 'r') as f:
 | 
			
		||||
        lines = f.readlines()
 | 
			
		||||
 | 
			
		||||
    x = []
 | 
			
		||||
    y = []
 | 
			
		||||
    for line in lines:
 | 
			
		||||
        line = line.strip().split(',')
 | 
			
		||||
        if line:
 | 
			
		||||
            x.append(int(line[0]))
 | 
			
		||||
            y.append(float(line[1]))
 | 
			
		||||
 | 
			
		||||
    return x, y
 | 
			
		||||
 | 
			
		||||
def get_resource_data(filename):
 | 
			
		||||
    lines = []
 | 
			
		||||
    with open(filename, 'r') as f:
 | 
			
		||||
        lines = f.readlines()
 | 
			
		||||
 | 
			
		||||
    x = []
 | 
			
		||||
    y = []
 | 
			
		||||
    for line in lines:
 | 
			
		||||
        line = line.strip().split(',')
 | 
			
		||||
        if line:
 | 
			
		||||
            x.append(int(line[0])) # requests
 | 
			
		||||
            y.append([float(v)*100 for v in line[1:]]) # cpu, ram
 | 
			
		||||
 | 
			
		||||
    return x, y
 | 
			
		||||
 | 
			
		||||
def generate_req_graph(filename, framework_name, endpoint_name):
 | 
			
		||||
    x, y = get_data(filename)
 | 
			
		||||
 | 
			
		||||
    filename = filename.split('/')[-1]
 | 
			
		||||
    new_filename = filename.replace('.csv', '')
 | 
			
		||||
    plot_graph(x, y, f'{framework_name} - {endpoint_name}', 'Número de requisições', 'Requisições por segundo', new_filename)
 | 
			
		||||
 | 
			
		||||
def generate_resource_graph(filename, framework_name, endpoint_name):
 | 
			
		||||
    x, y = get_resource_data(filename)
 | 
			
		||||
 | 
			
		||||
    filename = filename.split('/')[-1]
 | 
			
		||||
    new_filename = filename.replace('.csv', '')
 | 
			
		||||
    plot_resource_graph(x, y, f'{framework_name} - {endpoint_name}', 'Uso de recursos', 'Uso (%)', new_filename)
 | 
			
		||||
							
								
								
									
										17
									
								
								scripts/init.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								scripts/init.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
import requests
 | 
			
		||||
 | 
			
		||||
def download_file(url):
 | 
			
		||||
    local_filename = url.split('/')[-1]
 | 
			
		||||
    with requests.get(url, stream=True) as r:
 | 
			
		||||
        r.raise_for_status()
 | 
			
		||||
        with open(local_filename, 'wb') as f:
 | 
			
		||||
            for chunk in r.iter_content(chunk_size=8192):
 | 
			
		||||
                # If you have chunk encoded response uncomment if
 | 
			
		||||
                # and set chunk_size parameter to None.
 | 
			
		||||
                #if chunk:
 | 
			
		||||
                f.write(chunk)
 | 
			
		||||
    return local_filename
 | 
			
		||||
 | 
			
		||||
def init():
 | 
			
		||||
    download_file('https://files.ivanch.me/api/public/dl/Dj0gkp-m/small-image.png')
 | 
			
		||||
    download_file('https://files.ivanch.me/api/public/dl/FqHEPM1Q/big-image.png')
 | 
			
		||||
@@ -1,33 +1,155 @@
 | 
			
		||||
import requests
 | 
			
		||||
import docker
 | 
			
		||||
import concurrent.futures
 | 
			
		||||
import time
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
from graph import generate_req_graph, generate_resource_graph
 | 
			
		||||
from math import floor
 | 
			
		||||
from init import init
 | 
			
		||||
 | 
			
		||||
URL_BASE = 'http://localhost:5100'
 | 
			
		||||
if len(sys.argv) < 2 or len(sys.argv) > 3 or sys.argv[1] == '-h' or sys.argv[1] == '--help':
 | 
			
		||||
    print("Usage: python testes.py <framework name> [container name]")
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
 | 
			
		||||
num_requests = [1000, 5000, 10_000, 50_000, 100_000, 500_000, 1_000_000]
 | 
			
		||||
init()
 | 
			
		||||
 | 
			
		||||
def send_request(session, url):
 | 
			
		||||
    response = session.get(url)
 | 
			
		||||
    return response.status_code
 | 
			
		||||
THREADS = 10
 | 
			
		||||
FRAMEWORK_NAME = sys.argv[1]
 | 
			
		||||
CONTAINER_NAME = sys.argv[2] if len(sys.argv) > 2 else ""
 | 
			
		||||
URL_BASE = 'http://localhost:9090'
 | 
			
		||||
BLUR_RADIUS = 5
 | 
			
		||||
API_REQUESTS = [
 | 
			
		||||
    ('/image/save-big-image', 'POST', range(0, 10_000, 1_000), open('big-image.png', 'rb').read()),
 | 
			
		||||
    (f'/image/blur?radius={BLUR_RADIUS}', 'POST', range(0, 1_000, 50), open('small-image.png', 'rb').read()),
 | 
			
		||||
    ('/status/ok', 'GET', range(0, 30_000, 5000), None),
 | 
			
		||||
    ('/image/load-small-image', 'GET', range(0, 30_000, 5000), None),
 | 
			
		||||
    ('/static/small-image.png', 'GET', range(0, 30_000, 5000), None),
 | 
			
		||||
    ('/image/load-big-image', 'GET', range(0, 500, 50), None),
 | 
			
		||||
    ('/static/big-image.png', 'GET', range(0, 500, 50), None),
 | 
			
		||||
    ('/static/video.mp4', 'GET', range(0, 10_000, 1_000), None),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
def send_request(url, method = 'GET', payload = None):
 | 
			
		||||
    success = False
 | 
			
		||||
    responses = {
 | 
			
		||||
        2: 0, # OK
 | 
			
		||||
        4: 0, # Bad Request
 | 
			
		||||
        5: 0, # Server Error
 | 
			
		||||
    }
 | 
			
		||||
    while not success:
 | 
			
		||||
        try:
 | 
			
		||||
            response = None
 | 
			
		||||
            if method == 'GET':
 | 
			
		||||
                response = requests.get(url)
 | 
			
		||||
            elif method == 'POST':
 | 
			
		||||
                response = requests.post(url, data=payload, headers={'Content-Type': 'image/png'})
 | 
			
		||||
        except:
 | 
			
		||||
            continue
 | 
			
		||||
        success = response.status_code == 200
 | 
			
		||||
        responses[floor(response.status_code/100)] += 1
 | 
			
		||||
    return responses
 | 
			
		||||
 | 
			
		||||
def getFileNames(endpoint):
 | 
			
		||||
    endpoint = endpoint.replace('/', '')
 | 
			
		||||
 | 
			
		||||
    files = [
 | 
			
		||||
        f"data/req_{FRAMEWORK_NAME}_{endpoint}.csv",
 | 
			
		||||
        f"data/resource_{FRAMEWORK_NAME}_{endpoint}.csv",
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    return files
 | 
			
		||||
 | 
			
		||||
def record(filename, requests, reqpersec):
 | 
			
		||||
    with open(filename, "a") as file:
 | 
			
		||||
        file.write(f"{requests},{reqpersec}\n")
 | 
			
		||||
 | 
			
		||||
def record_resource(filename, requests, cpu, ram):
 | 
			
		||||
    with open(filename, "a") as file:
 | 
			
		||||
        file.write(f"{requests},{cpu},{ram}\n")
 | 
			
		||||
 | 
			
		||||
def run_tests(endpoint, method, num_requests, metadata):
 | 
			
		||||
    files = getFileNames(endpoint)
 | 
			
		||||
    for filename in files:
 | 
			
		||||
        if os.path.exists(filename):
 | 
			
		||||
            os.remove(filename)
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    for num_request in num_requests:
 | 
			
		||||
        with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
 | 
			
		||||
            url = f'{URL_BASE}/status/ok'
 | 
			
		||||
        if num_request <= 0: continue
 | 
			
		||||
 | 
			
		||||
        ok_responses = 0
 | 
			
		||||
        bad_responses = 0
 | 
			
		||||
        server_errors = 0
 | 
			
		||||
        cpu, ram = 0, 0
 | 
			
		||||
 | 
			
		||||
        with concurrent.futures.ThreadPoolExecutor(max_workers=THREADS) as executor:
 | 
			
		||||
            url = f'{URL_BASE}{endpoint}'
 | 
			
		||||
 | 
			
		||||
            start_time = time.time()
 | 
			
		||||
 | 
			
		||||
            futures = []
 | 
			
		||||
            with requests.Session() as session:
 | 
			
		||||
                futures = [executor.submit(send_request, session, url) for _ in range(num_request)]
 | 
			
		||||
            #with requests.Session() as session:
 | 
			
		||||
            #    futures = [executor.submit(send_request, session, url) for _ in range(num_request)]
 | 
			
		||||
 | 
			
		||||
            half = floor(num_request/2)
 | 
			
		||||
            for i in range(num_request):
 | 
			
		||||
                futures.append(executor.submit(send_request, url, method, metadata))
 | 
			
		||||
 | 
			
		||||
                if i == half:
 | 
			
		||||
                    cpu, ram = get_resource_usage()
 | 
			
		||||
 | 
			
		||||
            concurrent.futures.wait(futures)
 | 
			
		||||
 | 
			
		||||
            elapsed_time = time.time() - start_time
 | 
			
		||||
 | 
			
		||||
            successful_responses = sum(1 for future in futures if future.result() == 200)
 | 
			
		||||
            for future in futures:
 | 
			
		||||
                responses = future.result()
 | 
			
		||||
                ok_responses += responses[2]
 | 
			
		||||
                bad_responses += responses[4]
 | 
			
		||||
                server_errors += responses[5]
 | 
			
		||||
 | 
			
		||||
        print(f"All requests completed in {elapsed_time:.2f} seconds. {elapsed_time/num_request:.4f} seconds per request. {num_request/elapsed_time:.2f} requests per second.")
 | 
			
		||||
        print(f"Successful responses: {successful_responses}/{num_request}")
 | 
			
		||||
        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}]]")
 | 
			
		||||
        record(files[0], num_request, f"{num_request/elapsed_time:.2f}")
 | 
			
		||||
        record_resource(files[1], num_request, cpu, ram)
 | 
			
		||||
 | 
			
		||||
main()
 | 
			
		||||
        generate_req_graph(files[0], FRAMEWORK_NAME, endpoint)
 | 
			
		||||
        generate_resource_graph(files[1], FRAMEWORK_NAME, endpoint)
 | 
			
		||||
 | 
			
		||||
        time.sleep(3)
 | 
			
		||||
 | 
			
		||||
def get_resource_usage():
 | 
			
		||||
    if CONTAINER_NAME == "": return 0, 0
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        client = docker.from_env()
 | 
			
		||||
        stats = client.containers.get(CONTAINER_NAME).stats(stream=False)
 | 
			
		||||
    except:
 | 
			
		||||
        return 0, 0 # unable to get stats
 | 
			
		||||
 | 
			
		||||
    return get_cpu_usage(stats), get_ram_usage(stats)
 | 
			
		||||
 | 
			
		||||
def get_cpu_usage(stats):
 | 
			
		||||
    UsageDelta = stats['cpu_stats']['cpu_usage']['total_usage'] - stats['precpu_stats']['cpu_usage']['total_usage']
 | 
			
		||||
    SystemDelta = stats['cpu_stats']['system_cpu_usage'] - stats['precpu_stats']['system_cpu_usage']
 | 
			
		||||
    len_cpu = stats['cpu_stats']['online_cpus']
 | 
			
		||||
    percentage = (UsageDelta / SystemDelta) * len_cpu
 | 
			
		||||
    return f"{percentage:.2f}"
 | 
			
		||||
 | 
			
		||||
def get_ram_usage(stats):
 | 
			
		||||
    usage = stats['memory_stats']['usage']
 | 
			
		||||
    limit = stats['memory_stats']['limit']
 | 
			
		||||
 | 
			
		||||
    percentage = (usage / limit)
 | 
			
		||||
 | 
			
		||||
    # percent = round(percentage, 2)
 | 
			
		||||
    return f"{percentage:.2f}"
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    if not os.path.exists("data"):
 | 
			
		||||
        os.mkdir("data")
 | 
			
		||||
    else:
 | 
			
		||||
        os.system("rm -rf data/*")
 | 
			
		||||
 | 
			
		||||
    for endpoint, method, num_requests, metadata in API_REQUESTS:
 | 
			
		||||
        print(f"# {endpoint}")
 | 
			
		||||
        run_tests(endpoint, method, num_requests, metadata)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user