webcc icon indicating copy to clipboard operation
webcc copied to clipboard

Very slow response

Open MyraBaba opened this issue 4 years ago • 30 comments

Hi,

I am testing example/form_server both my Mac Pro and also raspi4 . its super slower than the python (fastapi) ? almost 10 times slower

Why is this ? am I missed something ?

Best

MyraBaba avatar Nov 30 '20 22:11 MyraBaba

Any idea @sprinfall

MyraBaba avatar Dec 02 '20 12:12 MyraBaba

Any idea @sprinfall

Because the file data is all cached in the memory. What is the size of your test file?

sprinfall avatar Dec 04 '20 02:12 sprinfall

its 10K image file . almost 1 second for each post very slow. There should be something that missed . Test yourself please

MyraBaba avatar Dec 04 '20 07:12 MyraBaba

I am posting with curl for test :

curl -X POST "http://127.0.0.1:8000/predict/image" -H "accept: application/json" -H "Content-Type: multipart/form-data" -F "name=mmm" -F "file=@/Users/xxx/Charles_Bronson/Charles_Bronson_0003.jpg;type=image/jpg"

MyraBaba avatar Dec 04 '20 08:12 MyraBaba

@sprinfall if you advise I would love to use your solution in our small non profit org. production.

Best

MyraBaba avatar Dec 04 '20 21:12 MyraBaba

@MyraBaba Please feel free to use. I just pushed the code with a small improvement for the parsing of form data. I'm still investigating the performance issue.

sprinfall avatar Dec 07 '20 06:12 sprinfall

Ok I will test the new code . But you wll see the slowness of the response.. Something stalling / delaying.

Best

MyraBaba avatar Dec 07 '20 08:12 MyraBaba

Ok I will test the new code . But you wll see the slowness of the response.. Something stalling / delaying.

Best

Hi, I use Python Requests library to post a JPG file, the 1s delay disappears. Just for your information.

BTW, if you want to post large files, please consider to NOT use multipart form data. Please use a normal post with streaming instead.

sprinfall avatar Dec 08 '20 02:12 sprinfall

Hi @sprinfall

My files mostly around 10K to 30K so small ones. What is the curl post and python post differences. ? Would you mind to share your python / Post code?

Best

MyraBaba avatar Dec 08 '20 10:12 MyraBaba

@MyraBaba

import requests

url = 'http://127.0.0.1:8000/upload'
files = {'file': open('path/to/jpg', 'rb')}

r = requests.post(url, files=files)
print(r.text)

sprinfall avatar Dec 08 '20 11:12 sprinfall

@sprinfall can you test in aloop ?

for i in range(100): r = requests.post(url, files=files) print(i , " " ,r.text)

gives error

MyraBaba avatar Dec 08 '20 12:12 MyraBaba

@MyraBaba Sorry, that issue was introduced by my last small optimization. I have reverted the change. I will keep you informed when I find a better solution to optimize the performance of form data parsing.

sprinfall avatar Dec 10 '20 05:12 sprinfall

@sprinfall any perf fix?

MyraBaba avatar Dec 18 '20 22:12 MyraBaba

@sprinfall any perf fix?

I have two suggestions:

  1. Use a larger buffer to read the requests. I tested using 10240, it did improve the speed. Please see new added method of Server: set_buffer_size().
  2. Set log level to USER to avoid logging VERB and INFO logs.

sprinfall avatar Dec 21 '20 10:12 sprinfall

I will test right today and let you know. Best

MyraBaba avatar Dec 21 '20 10:12 MyraBaba

Hi @sprinfall

I tested with :

import requests
from time import sleep
url = 'http://127.0.0.1:8000/upload'
files = {'file': open('/Users/tulpar/Projects/build-drogon-Desktop_Qt_5_13_2_clang_64bit-Debug/Charles_Bronson_0003.jpg', 'rb') , 'name':"ALALU"}
i= 99

for i in range(100):
    r = requests.post(url, files=files)
    print(i , "    " ,r.text)

Got errors:

form parts: 2 name: file name: name 2020-12-21 13:38:50.697, WARN, main, connection.cc, 44, Socket shutdown error (Socket is not connected). 2020-12-21 13:38:57.077, ERRO, main, request_parser.cc, 131, Invalid part data. 2020-12-21 13:38:57.077, ERRO, main, connection.cc, 114, Failed to parse HTTP request. 2020-12-21 13:38:57.077, ERRO, main, connection.cc, 101, Socket read error (Bad file descriptor). 2020-12-21 13:38:57.077, WARN, main, connection.cc, 44, Socket shutdown error (Bad file descriptor). 2020-12-21 13:39:17.295, ERRO, main, request_parser.cc, 131, Invalid part data. 2020-12-21 13:39:17.295, ERRO, main, connection.cc, 114, Failed to parse HTTP request. 2020-12-21 13:39:17.296, ERRO, main, connection.cc, 101, Socket read error (Bad file descriptor). 2020-12-21 13:39:17.296, WARN, main, connection.cc, 44, Socket shutdown error (Bad file descriptor). 2020-12-21 13:39:36.575, ERRO, main, request_parser.cc, 131, Invalid part data. 2020-12-21 13:39:36.575, ERRO, main, connection.cc, 114, Failed to parse HTTP request. 2020-12-21 13:39:36.576, ERRO, main, connection.cc, 101, Socket read error (Bad file descriptor). 2020-12-21 13:39:36.576, WARN, main, connection.cc, 44, Socket shutdown error (Bad file descriptor).

MyraBaba avatar Dec 21 '20 10:12 MyraBaba

I will look into it tonight.

sprinfall avatar Dec 21 '20 11:12 sprinfall

@MyraBaba I found that from the second request in the loop, the file data sent was empty. Please try to move the files definition into inside of the loop. Meanwhile, I made a quickfix to handle this empty form part data. Please pull the code. But I will do more test tomorrow.

sprinfall avatar Dec 21 '20 12:12 sprinfall

@sprinfall Hi again,

I love the webcc its fantastic work. Thanks.

Do you think that we can embed it to our Qt Project ? Do you Qt ? It will be great if we get data as signal/slot mechanism

MyraBaba avatar Jan 20 '21 13:01 MyraBaba

@sprinfall do you know Qt platform ?

MyraBaba avatar Jan 20 '21 22:01 MyraBaba

@sprinfall Hi again,

I love the webcc its fantastic work. Thanks.

Do you think that we can embed it to our Qt Project ? Do you Qt ? It will be great if we get data as signal/slot mechanism

For signal/slot mechanism, you have to use QNetworkAccessManager: https://doc.qt.io/qt-5/qnetworkaccessmanager.html But it only has client API. Is your Qt project a client or server?

sprinfall avatar Jan 21 '21 01:01 sprinfall

Hi,

I wrote the Qt forum but not have. Complete answer : https://forum.qt.io/topic/122927/c-rest-api-3rd-party-integration-question/8 https://forum.qt.io/topic/122927/c-rest-api-3rd-party-integration-question/8

BC

PS: QNetworkAccessManager is ok for doing REST SERVEr?

On 21 Jan 2021, at 04:45, Chunting Gu [email protected] wrote:

@sprinfall https://github.com/sprinfall Hi again,

I love the webcc its fantastic work. Thanks.

Do you think that we can embed it to our Qt Project ? Do you Qt ? It will be great if we get data as signal/slot mechanism

For signal/slot mechanism, you have to use QNetworkAccessManager: https://doc.qt.io/qt-5/qnetworkaccessmanager.html https://doc.qt.io/qt-5/qnetworkaccessmanager.html — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/sprinfall/webcc/issues/18#issuecomment-764171103, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEFRZH7ROCBGM6YMQ2QM273S26BM5ANCNFSM4UIFZJUQ.

MyraBaba avatar Jan 21 '21 10:01 MyraBaba

Hi,

I tried to use your server rest example in the Qt . Could find a way to integrate with signal slot .. It is creating a new FileUploadView instance inside the Qt thread so can’t access the signal cut emit the received data to the main thread.

Yes I am a newbie c++ world. Most mathematician algorithm person . If you show me a sample ie one is suggested "to pass the shared pointer to the start_Rest() function and therefore you can do the connection from where you call this function.”

BEst

#include "restapi.h" #include <QDebug> RestApi::RestApi(QObject *parent) : QObject(parent) { qDebug() << "xx restapi.cc REST API started " << endl;

}

void RestApi::start_Rest() {

int PORT = 7000;
WEBCC_LOG_INIT("", webcc::LOG_CONSOLE);

std::uint16_t port = static_cast<std::uint16_t>(PORT);

try {
    webcc::Server server{ boost::asio::ip::tcp::v4(), port };

    server.set_buffer_size(webcc::kBufferSize * 10);

    server.Route("/upload", std::make_shared<RestApi>(), { "POST" });

    server.Run();

} catch (const std::exception& e) {
    std::cerr << e.what() << std::endl;

// return 1; } }

webcc::ResponsePtr RestApi::Handle(webcc::RequestPtr request) {

if (request->method() == "POST") {
    return Post(request);
}

return {};

}

webcc::ResponsePtr RestApi::Post(webcc::RequestPtr request) { emit test_signal (); std::cout << "form parts: " << request->form_parts().size() << std::endl; std::string resp ; for (auto& part : request->form_parts()) { std::cout << "name: " << part->name() << std::endl; resp = part->name(); if (part->file_name().empty()) { std::cout << "data: " << part->data() << std::endl; } else { size_t size=part->data().size();

        if(true){
            std::ofstream myFile ("/Users/tulpar/Projects/webcc-21Dec/build/webccData-QT"+ std::to_string (image_counter++) +".jpeg", std::ios::out | std::ios::binary);
            myFile << part->data();

            myFile.close ();
            QByteArray byteArray(part->data().c_str(), part->data().length());

            QPixmap img;
            img.loadFromData (byteArray);
            RestApi::sendPix (img);
        }

        // Save part->data() as binary to file.
        // ...
    }
}

return webcc::ResponseBuilder{}.Created().Body(" ..  OK " + resp)();

}

void RestApi::sendPix(QPixmap &pix) { emit rest_image_received (pix); }

On 21 Jan 2021, at 04:45, Chunting Gu [email protected] wrote:

@sprinfall https://github.com/sprinfall Hi again,

I love the webcc its fantastic work. Thanks.

Do you think that we can embed it to our Qt Project ? Do you Qt ? It will be great if we get data as signal/slot mechanism

For signal/slot mechanism, you have to use QNetworkAccessManager: https://doc.qt.io/qt-5/qnetworkaccessmanager.html https://doc.qt.io/qt-5/qnetworkaccessmanager.html — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/sprinfall/webcc/issues/18#issuecomment-764171103, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEFRZH7ROCBGM6YMQ2QM273S26BM5ANCNFSM4UIFZJUQ.

MyraBaba avatar Jan 21 '21 10:01 MyraBaba

@MyraBaba

  1. Run the REST server in a thread in your Qt application (see the server_states.cc example).
  2. In RestApi (the View), emit signals of some global (or Singleton) QObject after the requests have been handled (in your case, images are uploaded).
  3. In your Qt widgets, connect the signals of that global (or Singleton) object to some slots. I will come back to you later.

sprinfall avatar Jan 21 '21 11:01 sprinfall

Hi,

@sprinfall

Here a simple Thread example.

İf its work in Thread and result is usable via Qt signals very helpful for the community.

Best

SimpleRestWebcc.zip

On 21 Jan 2021, at 14:48, Chunting Gu [email protected] wrote:

@MyraBaba https://github.com/MyraBaba Run the REST server in a thread in your Qt application (see the server_states.cc example). In RestApi (the View), emit signals of some global (or Singleton) QObject after the requests have been handled (in your case, images are uploaded). In your Qt widgets, connect the signals of that global (or Singleton) object to some slots. I will come back to you later. — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/sprinfall/webcc/issues/18#issuecomment-764589441, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEFRZHYCKTI5FCDLICC4YX3S3AIAPANCNFSM4UIFZJUQ.

MyraBaba avatar Jan 21 '21 13:01 MyraBaba

@MyraBaba Just added an example for Qt based on my understanding: example/qt_app_server. Hope it helps.

sprinfall avatar Jan 22 '21 04:01 sprinfall

@sprinfall Thanks a lot. I tested.

Now I try to put same way to in my QTHREAD logic. Do you think it is also work in the QTHREAD created by the mainwindow ?

Best

MyraBaba avatar Jan 22 '21 13:01 MyraBaba

@sprinfall Thanks a lot .

what is the proper way to pass below objects which I can use inside the


`webcc::ResponsePtr Handle(webcc::RequestPtr request) override {


}`

the objects :


`. bc::Landmarker *Landarker = new bc::Landmarker;
    bc::facenet *Recognizer = new bc::facenet;
    bc::Aligner *Aligner          = new bc::Aligner;
    Recognizer->Init("/home/alp2080/Projects//data/models");
    Landarker->Init("/home/alp2080/Projects//data/models");

`

how can I do this to use also inside webcc::ResponsePtr Handle(webcc::RequestPtr request) override ?

whenever I start to think I am something at c++ always hitting such a wall.

Appreciate your help.

I mentioned and advise your webcc in Qt forum.

Best

MyraBaba avatar Jan 23 '21 20:01 MyraBaba

@MyraBaba You want to access Landmarker, Facenet and Aligner from the overridden Handle() method, right? These objects look like some algorithm based on pre-trained models. So I think they are shared by all requests and related to each other. I suggest you to put them into a new class and create a single global variable (or singleton) of this class, then you can access it from everywhere. You should initialize this new global variable in your main() function.

sprinfall avatar Jan 25 '21 09:01 sprinfall

@sprinfall Thanks a lot. I tested.

Now I try to put same way to in my QTHREAD logic. Do you think it is also work in the QTHREAD created by the mainwindow ?

Best

I suggest to use C++ std::thread to run the HTTP server. QThread is quite a different thing. It has extra event loop? So, keep your Views (sub-classes of webcc::View) away from QObject. Do the server part in pure C++ way. Emit signals, if necessary, from some other QObject for notifying the GUI thread.

sprinfall avatar Jan 25 '21 09:01 sprinfall