Skip to content
This repository was archived by the owner on Jul 4, 2025. It is now read-only.

Commit a5a1877

Browse files
authored
Merge pull request #1345 from janhq/j/cortex-ps
feat: cortex ps
2 parents 1069b89 + 5c64b0a commit a5a1877

File tree

7 files changed

+147
-7
lines changed

7 files changed

+147
-7
lines changed

engine/commands/model_stop_cmd.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#include "model_stop_cmd.h"
22
#include "httplib.h"
33
#include "nlohmann/json.hpp"
4-
#include "trantor/utils/Logger.h"
54
#include "utils/logging_utils.h"
65

76
namespace commands {
@@ -30,4 +29,4 @@ void ModelStopCmd::Exec() {
3029
}
3130
}
3231

33-
}; // namespace commands
32+
}; // namespace commands

engine/commands/model_stop_cmd.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
#pragma once
2+
23
#include <string>
3-
#include <optional>
44
#include "config/model_config.h"
55

66
namespace commands {
77

8-
class ModelStopCmd{
8+
class ModelStopCmd {
99
public:
1010
ModelStopCmd(std::string host, int port, const config::ModelConfig& mc);
1111
void Exec();
@@ -15,4 +15,4 @@ class ModelStopCmd{
1515
int port_;
1616
const config::ModelConfig& mc_;
1717
};
18-
} // namespace commands
18+
} // namespace commands

engine/commands/ps_cmd.cc

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#include "ps_cmd.h"
2+
#include <drogon/drogon.h>
3+
#include <httplib.h>
4+
#include <string>
5+
#include <tabulate/table.hpp>
6+
#include "nlohmann/json.hpp"
7+
#include "utils/logging_utils.h"
8+
#include "utils/string_utils.h"
9+
10+
namespace commands {
11+
12+
void PsCmd::Exec(const std::string& host, int port) {
13+
auto host_and_port{host + ":" + std::to_string(port)};
14+
httplib::Client cli(host_and_port);
15+
16+
auto res = cli.Get("/inferences/server/models");
17+
if (!res || res->status != httplib::StatusCode::OK_200) {
18+
CLI_LOG("No model loaded!");
19+
return;
20+
}
21+
22+
auto body = nlohmann::json::parse(res->body);
23+
auto data = body["data"];
24+
std::vector<ModelLoadedStatus> model_status_list;
25+
try {
26+
for (const auto& item : data) {
27+
ModelLoadedStatus model_status;
28+
model_status.engine = item["engine"];
29+
model_status.model = item["id"];
30+
model_status.ram = item["ram"];
31+
model_status.start_time = item["start_time"];
32+
model_status.vram = item["vram"];
33+
model_status_list.push_back(model_status);
34+
}
35+
} catch (const std::exception& e) {
36+
CLI_LOG("Fail to get list model information: " + std::string(e.what()));
37+
}
38+
39+
PrintModelStatusList(model_status_list);
40+
}
41+
42+
void PsCmd::PrintModelStatusList(
43+
const std::vector<ModelLoadedStatus>& model_status_list) const {
44+
if (model_status_list.empty()) {
45+
CLI_LOG("No model loaded!");
46+
return;
47+
}
48+
49+
tabulate::Table table;
50+
table.add_row({"Model", "Engine", "RAM", "VRAM", "Up time"});
51+
for (const auto& model_status : model_status_list) {
52+
table.add_row({
53+
model_status.model,
54+
model_status.engine,
55+
model_status.ram,
56+
model_status.vram,
57+
string_utils::FormatTimeElapsed(model_status.start_time),
58+
});
59+
}
60+
std::cout << table << std::endl;
61+
}
62+
63+
}; // namespace commands

engine/commands/ps_cmd.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <vector>
5+
6+
namespace commands {
7+
8+
struct ModelLoadedStatus {
9+
std::string engine;
10+
std::string model;
11+
std::string ram;
12+
uint64_t start_time;
13+
std::string vram;
14+
};
15+
16+
class PsCmd {
17+
public:
18+
explicit PsCmd() = default;
19+
20+
void Exec(const std::string& host, int port);
21+
22+
private:
23+
void PrintModelStatusList(
24+
const std::vector<ModelLoadedStatus>& model_status_list) const;
25+
};
26+
27+
} // namespace commands

engine/controllers/command_line_parser.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "commands/model_start_cmd.h"
1616
#include "commands/model_stop_cmd.h"
1717
#include "commands/model_upd_cmd.h"
18+
#include "commands/ps_cmd.h"
1819
#include "commands/run_cmd.h"
1920
#include "commands/server_start_cmd.h"
2021
#include "commands/server_stop_cmd.h"
@@ -73,7 +74,7 @@ bool CommandLineParser::SetupCommand(int argc, char** argv) {
7374
#ifdef CORTEX_CPP_VERSION
7475
if (cml_data_.check_upd) {
7576
// TODO(sang) find a better way to handle
76-
// This is an extremely ungly way to deal with connection
77+
// This is an extremely ungly way to deal with connection
7778
// hang when network down
7879
std::atomic<bool> done = false;
7980
std::thread t([&]() {
@@ -387,6 +388,11 @@ void CommandLineParser::SetupSystemCommands() {
387388
auto ps_cmd =
388389
app_.add_subcommand("ps", "Show running models and their status");
389390
ps_cmd->group(kSystemGroup);
391+
ps_cmd->usage("Usage:\n" + commands::GetCortexBinary() + "ps");
392+
ps_cmd->callback([&]() {
393+
commands::PsCmd().Exec(cml_data_.config.apiServerHost,
394+
std::stoi(cml_data_.config.apiServerPort));
395+
});
390396

391397
auto update_cmd = app_.add_subcommand("update", "Update cortex version");
392398
update_cmd->group(kSystemGroup);

engine/controllers/command_line_parser.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#pragma once
22

33
#include "CLI/CLI.hpp"
4-
#include "commands/model_upd_cmd.h"
54
#include "services/engine_service.h"
65
#include "utils/config_yaml_utils.h"
76
class CommandLineParser {

engine/utils/string_utils.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <chrono>
2+
#include <sstream>
13
#include <string>
24
#include <vector>
35

@@ -29,4 +31,48 @@ inline std::vector<std::string> SplitBy(const std::string& str,
2931
} while (pos < str.length() && prev < str.length());
3032
return tokens;
3133
}
34+
35+
inline uint64_t getCurrentTimeInMilliseconds() {
36+
using namespace std::chrono;
37+
return duration_cast<milliseconds>(system_clock::now().time_since_epoch())
38+
.count();
39+
}
40+
41+
inline std::string FormatTimeElapsed(uint64_t pastTimestamp) {
42+
uint64_t currentTimestamp = getCurrentTimeInMilliseconds();
43+
uint64_t milliseconds = currentTimestamp - pastTimestamp;
44+
45+
// Constants for time units
46+
const uint64_t millisInSecond = 1000;
47+
const uint64_t millisInMinute = millisInSecond * 60;
48+
const uint64_t millisInHour = millisInMinute * 60;
49+
const uint64_t millisInDay = millisInHour * 24;
50+
51+
uint64_t days = milliseconds / millisInDay;
52+
milliseconds %= millisInDay;
53+
54+
uint64_t hours = milliseconds / millisInHour;
55+
milliseconds %= millisInHour;
56+
57+
uint64_t minutes = milliseconds / millisInMinute;
58+
milliseconds %= millisInMinute;
59+
60+
uint64_t seconds = milliseconds / millisInSecond;
61+
62+
std::ostringstream oss;
63+
64+
if (days > 0) {
65+
oss << days << " day" << (days > 1 ? "s" : "") << ", ";
66+
}
67+
if (hours > 0 || days > 0) {
68+
oss << hours << " hour" << (hours > 1 ? "s" : "") << ", ";
69+
}
70+
if (minutes > 0 || hours > 0 || days > 0) {
71+
oss << minutes << " minute" << (minutes > 1 ? "s" : "") << ", ";
72+
}
73+
74+
oss << seconds << " second" << (seconds > 1 ? "s" : "");
75+
76+
return oss.str();
77+
}
3278
} // namespace string_utils

0 commit comments

Comments
 (0)