Deb Roclinn
commited on
Commit
•
9c774f1
1
Parent(s):
e81396d
Added this webserver except it works
Browse files- main.py +2 -2
- server.cpp +166 -0
- threadpool.h +145 -0
main.py
CHANGED
@@ -117,7 +117,7 @@ if __name__ == '__main__':
|
|
117 |
trainer.test(test_loader)
|
118 |
|
119 |
if opt.save_mesh:
|
120 |
-
trainer.save_mesh(resolution=
|
121 |
|
122 |
else:
|
123 |
|
@@ -157,4 +157,4 @@ if __name__ == '__main__':
|
|
157 |
trainer.test(test_loader)
|
158 |
|
159 |
if opt.save_mesh:
|
160 |
-
trainer.save_mesh(resolution=
|
|
|
117 |
trainer.test(test_loader)
|
118 |
|
119 |
if opt.save_mesh:
|
120 |
+
trainer.save_mesh(resolution=32)
|
121 |
|
122 |
else:
|
123 |
|
|
|
157 |
trainer.test(test_loader)
|
158 |
|
159 |
if opt.save_mesh:
|
160 |
+
trainer.save_mesh(resolution=32)
|
server.cpp
ADDED
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <cstdio>
|
2 |
+
#include <iostream>
|
3 |
+
#include <algorithm>
|
4 |
+
#include <memory>
|
5 |
+
#include <string>
|
6 |
+
#include <thread>
|
7 |
+
#include <array>
|
8 |
+
#include <queue>
|
9 |
+
#include <mutex>
|
10 |
+
#include <vector>
|
11 |
+
#include <filesystem>
|
12 |
+
#include <sstream>
|
13 |
+
#define CROW_MAIN
|
14 |
+
#include <crow.h>
|
15 |
+
#include <ranges>
|
16 |
+
#include "threadpool.h"
|
17 |
+
using std::string;
|
18 |
+
using std::mutex;
|
19 |
+
using std::lock_guard;
|
20 |
+
using std::make_shared;
|
21 |
+
using std::queue;
|
22 |
+
using std::vector;
|
23 |
+
namespace fs = std::filesystem;
|
24 |
+
namespace rv = std::ranges::views;
|
25 |
+
static inline string exec(const char* cmd) {
|
26 |
+
std::array<char, 128> buffer;
|
27 |
+
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
|
28 |
+
string result;
|
29 |
+
if (!pipe)
|
30 |
+
return "Command failed";
|
31 |
+
else {
|
32 |
+
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
|
33 |
+
result += buffer.data();
|
34 |
+
}
|
35 |
+
return result;
|
36 |
+
}
|
37 |
+
|
38 |
+
constexpr auto reify(const std::ranges::range auto& r){ return vector(r.begin(), r.end()); }
|
39 |
+
|
40 |
+
constexpr string strip(const string& s){ return s; }
|
41 |
+
|
42 |
+
constexpr string strip(string s, char ch){
|
43 |
+
s.erase(std::remove_if(s.begin(), s.end(), [=](char c){ return c == ch; }), s.end());
|
44 |
+
return s;
|
45 |
+
}
|
46 |
+
|
47 |
+
constexpr string strip(string s, char ch, auto... chs){
|
48 |
+
return strip(strip(s, ch), chs...);
|
49 |
+
}
|
50 |
+
|
51 |
+
constexpr vector<string> splitOn(const string& s, const string& delim){
|
52 |
+
vector<string> ret;
|
53 |
+
long long int start = 0;
|
54 |
+
for(size_t dp = s.find_first_of(delim, 0); start >= 0
|
55 |
+
; start = (dp == std::string::npos) ? -1 : dp + 1, dp = s.find_first_of(delim, start))
|
56 |
+
if(auto n = s.substr(start, dp - start); !n.empty())
|
57 |
+
ret.emplace_back(n);
|
58 |
+
return ret;
|
59 |
+
}
|
60 |
+
|
61 |
+
static inline string reset = "rm -rf trial/checkpoints/*";
|
62 |
+
|
63 |
+
static inline string train(const string& prompt){
|
64 |
+
return string("python main.py --cuda_ray --save_mesh --text \"") + strip(prompt, '\'', '\"') + "\" --workspace trial -O";
|
65 |
+
}
|
66 |
+
|
67 |
+
static inline string save(const string& name){ return string("zip ") + name + ".zip trial/mesh/*"; }
|
68 |
+
|
69 |
+
template <typename T>
|
70 |
+
constexpr auto q_to_v(queue<T> qcopy){
|
71 |
+
vector<T> v;
|
72 |
+
v.reserve(qcopy.size());
|
73 |
+
while(!qcopy.empty())
|
74 |
+
v.push_back(qcopy.front()), qcopy.pop();
|
75 |
+
return v;
|
76 |
+
}
|
77 |
+
|
78 |
+
int main(){
|
79 |
+
crow::SimpleApp app;
|
80 |
+
typedef std::array<string, 2> guy;
|
81 |
+
auto commissions = make_shared<queue<guy>>();
|
82 |
+
auto queue_mutex = make_shared<mutex>()
|
83 |
+
, train_mutex = make_shared<mutex>();
|
84 |
+
auto pool = make_shared<threadpool<>>(2);
|
85 |
+
auto run = [=](const string& cmd){
|
86 |
+
CROW_LOG_INFO << "running \'" << cmd;
|
87 |
+
return exec(cmd.c_str());
|
88 |
+
};
|
89 |
+
|
90 |
+
auto check_queue = [=](const string& name) -> int {
|
91 |
+
if(!commissions->empty()){
|
92 |
+
const auto v = q_to_v(*commissions);
|
93 |
+
if(auto pos = std::find_if( v.begin(), v.end()
|
94 |
+
, [=](const guy& g){ auto& [n,d] = g; return n == name; });
|
95 |
+
pos != v.end())
|
96 |
+
return int(std::distance(v.begin(), pos));
|
97 |
+
}
|
98 |
+
return -1;
|
99 |
+
};
|
100 |
+
|
101 |
+
auto poppe = [=](){
|
102 |
+
lock_guard<mutex> qlock(*queue_mutex);
|
103 |
+
commissions->pop();
|
104 |
+
CROW_LOG_INFO << commissions->size() << " left in queue";
|
105 |
+
};
|
106 |
+
|
107 |
+
auto training_loop = [=](){
|
108 |
+
lock_guard<mutex> lock(*train_mutex);
|
109 |
+
while(!commissions->empty()){
|
110 |
+
auto& [name, prompt] = commissions->front();
|
111 |
+
CROW_LOG_INFO << "Launched training for " + name;
|
112 |
+
run(reset), run(train(prompt)), run(save(name));
|
113 |
+
CROW_LOG_INFO << "Finished training for " + name;
|
114 |
+
poppe();
|
115 |
+
}
|
116 |
+
};
|
117 |
+
|
118 |
+
auto enqueue = [=](const guy& thing){
|
119 |
+
lock_guard<mutex> lock(*queue_mutex);
|
120 |
+
commissions->push(thing);
|
121 |
+
auto& [name, prompt] = thing;
|
122 |
+
CROW_LOG_INFO << name << " queued with prompt: " << prompt;
|
123 |
+
};
|
124 |
+
|
125 |
+
CROW_ROUTE(app, "/create/<string>")
|
126 |
+
.methods("GET"_method, "POST"_method)([=](const crow::request& req, const string& name){
|
127 |
+
CROW_LOG_INFO << name << " commissioned";
|
128 |
+
if(auto prompt = req.url_params.get("prompt"); prompt == nullptr){
|
129 |
+
CROW_LOG_INFO << "No prompt specified";
|
130 |
+
return "Error: Can't train a NeRF for " + name + " without a prompt!";
|
131 |
+
} else {
|
132 |
+
if(auto r = check_queue(name); r < 0){
|
133 |
+
enqueue({name, prompt});
|
134 |
+
pool->enqueue(training_loop);
|
135 |
+
CROW_LOG_INFO << "Launched training loop";
|
136 |
+
return "Scheduled training for " + name;
|
137 |
+
} else
|
138 |
+
return name + " is currently "
|
139 |
+
+ (r ? string("in line") : string("training"));
|
140 |
+
}
|
141 |
+
});
|
142 |
+
|
143 |
+
CROW_ROUTE(app, "/check/<string>")([=](crow::response& res, const string& name){
|
144 |
+
CROW_LOG_INFO << name << " check'd";
|
145 |
+
if(fs::exists(fs::path(name + ".zip"))){
|
146 |
+
res.write("O I know that guy");
|
147 |
+
res.set_static_file_info(name + ".zip");
|
148 |
+
} else if(auto r = check_queue(name); r < 0)
|
149 |
+
res.write("Doesn't look like much of anything to me");
|
150 |
+
else
|
151 |
+
res.write(name + " is currently "
|
152 |
+
+ (r ? string("in line") : string("training")));
|
153 |
+
res.end();
|
154 |
+
});
|
155 |
+
|
156 |
+
CROW_ROUTE(app, "/list")([&](){
|
157 |
+
std::vector<string> fin = splitOn(exec("ls *zip"), "\n")
|
158 |
+
, q = reify(q_to_v(*commissions) | rv::transform([](const guy& i){ return i[0]; }));
|
159 |
+
crow::json::wvalue ret;
|
160 |
+
ret["finished"] = fin;
|
161 |
+
ret["pending"] = q;
|
162 |
+
return ret;
|
163 |
+
});
|
164 |
+
|
165 |
+
app.port(80).run();
|
166 |
+
}
|
threadpool.h
ADDED
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#pragma once
|
2 |
+
#include <atomic>
|
3 |
+
#include <condition_variable>
|
4 |
+
#include <functional>
|
5 |
+
#include <future>
|
6 |
+
#include <mutex>
|
7 |
+
#include <queue>
|
8 |
+
#include <utility>
|
9 |
+
#include <vector>
|
10 |
+
#include <concepts>
|
11 |
+
#include <thread>
|
12 |
+
static inline size_t avail_threads(){
|
13 |
+
return std::thread::hardware_concurrency();
|
14 |
+
}
|
15 |
+
|
16 |
+
template <typename F, typename... Args>
|
17 |
+
using irt = std::invoke_result_t<F, Args...>;
|
18 |
+
|
19 |
+
template <typename F, typename... Args>
|
20 |
+
static inline auto taskify(const F& funk, Args... args){
|
21 |
+
return std::bind(funk, std::forward<Args...>(args)...);
|
22 |
+
}
|
23 |
+
|
24 |
+
static inline auto promitask(const std::invocable<> auto& funk){
|
25 |
+
typedef irt<decltype(funk)> ret;
|
26 |
+
auto pr = std::make_shared<std::promise<ret>>();
|
27 |
+
if constexpr (std::same_as<irt<decltype(funk)>, void>)
|
28 |
+
return make_pair([=](){ funk(), pr->set_value(); }, pr);
|
29 |
+
else
|
30 |
+
return make_pair([=](){ pr->set_value(funk()); }, pr);
|
31 |
+
}
|
32 |
+
|
33 |
+
static inline auto await_many(const std::ranges::range auto& fu){
|
34 |
+
std::for_each(fu.begin(), fu.end(), [](auto&& f){ f.wait(); });
|
35 |
+
}
|
36 |
+
|
37 |
+
typedef std::function<void()> tasque;
|
38 |
+
|
39 |
+
template <typename Thrd = std::jthread>
|
40 |
+
class threadpool {
|
41 |
+
/// If true the queue thread should exit
|
42 |
+
std::atomic<bool> done;
|
43 |
+
|
44 |
+
/// The thread object associated with this queue
|
45 |
+
std::vector<Thrd> queue_threads;
|
46 |
+
/// A queue of functions that will be executed on the queue thread
|
47 |
+
std::queue<tasque> work_queue;
|
48 |
+
|
49 |
+
/// The mutex used in the condition variable
|
50 |
+
std::mutex queue_mutex;
|
51 |
+
|
52 |
+
/// The condition variable that waits for a new function to be inserted in the
|
53 |
+
/// queue
|
54 |
+
std::condition_variable cond;
|
55 |
+
|
56 |
+
/// This funciton executes on the queue_thread
|
57 |
+
void queue_runner() {
|
58 |
+
while (!done) {
|
59 |
+
tasque func;
|
60 |
+
{
|
61 |
+
std::unique_lock<std::mutex> lock(queue_mutex);
|
62 |
+
cond.wait( lock
|
63 |
+
, [this]() { return work_queue.empty() == false || done; });
|
64 |
+
|
65 |
+
if (!done){
|
66 |
+
swap(func, work_queue.front());
|
67 |
+
work_queue.pop();
|
68 |
+
}
|
69 |
+
}
|
70 |
+
if (func) func();
|
71 |
+
}
|
72 |
+
}
|
73 |
+
|
74 |
+
void qup(const std::invocable<> auto& f){
|
75 |
+
std::lock_guard<std::mutex> lock(queue_mutex);
|
76 |
+
work_queue.push(f);
|
77 |
+
cond.notify_one();
|
78 |
+
}
|
79 |
+
|
80 |
+
public:
|
81 |
+
template <typename F, typename... Args>
|
82 |
+
void enqueue(const F& func, Args... args) requires std::invocable<F, Args...> {
|
83 |
+
qup(taskify(func, args...));
|
84 |
+
}
|
85 |
+
|
86 |
+
template <typename F, typename... Args>
|
87 |
+
auto inquire(const F& func, Args... args) requires std::invocable<F, Args...> {
|
88 |
+
auto [t, pr] = promitask(taskify(func, args...));
|
89 |
+
auto fut = pr->get_future();
|
90 |
+
enqueue(t);
|
91 |
+
return fut;
|
92 |
+
}
|
93 |
+
|
94 |
+
void clear() {
|
95 |
+
{
|
96 |
+
std::lock_guard<std::mutex> lock(queue_mutex);
|
97 |
+
while(!work_queue.empty())
|
98 |
+
work_queue.pop();
|
99 |
+
}
|
100 |
+
sync();
|
101 |
+
}
|
102 |
+
|
103 |
+
void sync(){
|
104 |
+
std::atomic<size_t> n(0);
|
105 |
+
const size_t m = queue_threads.size();
|
106 |
+
auto present = [&](){ ++n; size_t l = n.load(); while(l < m) l = n.load(); };
|
107 |
+
std::vector<std::future<void>> fu;
|
108 |
+
std::ranges::generate_n(std::back_inserter(fu), m, [=, this](){ return inquire(present); });
|
109 |
+
await_many(fu);
|
110 |
+
}
|
111 |
+
|
112 |
+
threadpool(size_t n, size_t res) : done(false)
|
113 |
+
, queue_threads(n ? std::clamp(n, size_t(1), avail_threads() - res)
|
114 |
+
: std::max(size_t(1), avail_threads() - res)) {
|
115 |
+
for(auto& i:queue_threads){
|
116 |
+
Thrd tmp(&threadpool::queue_runner, this);
|
117 |
+
std::swap(i, tmp);
|
118 |
+
}
|
119 |
+
}
|
120 |
+
threadpool(size_t n) : threadpool(n, 0) {}
|
121 |
+
threadpool() : threadpool(0, 1) {}
|
122 |
+
|
123 |
+
~threadpool() {
|
124 |
+
sync();
|
125 |
+
done.store(true);
|
126 |
+
cond.notify_all();
|
127 |
+
}
|
128 |
+
|
129 |
+
threadpool(const threadpool& other) : work_queue(other.work_queue), done(false) {
|
130 |
+
for(auto& i:queue_threads){
|
131 |
+
Thrd tmp(&threadpool::queue_runner, this);
|
132 |
+
std::swap(i, tmp);
|
133 |
+
}
|
134 |
+
}
|
135 |
+
|
136 |
+
threadpool& operator=(const threadpool& other){
|
137 |
+
clear();
|
138 |
+
work_queue = other.work_queue;
|
139 |
+
return *this;
|
140 |
+
}
|
141 |
+
size_t size() const { return queue_threads.size(); }
|
142 |
+
threadpool& operator=(threadpool&& other) = default;
|
143 |
+
threadpool(threadpool&& other) = default;
|
144 |
+
};
|
145 |
+
|