Skip to content

Metrics collection #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Metrics collection #11

wants to merge 6 commits into from

Conversation

jcdkiki
Copy link
Collaborator

@jcdkiki jcdkiki commented Apr 8, 2025

No description provided.

@jcdkiki
Copy link
Collaborator Author

jcdkiki commented Apr 8, 2025

image
Вот так выглядит нагрузка на все ядра одного воркера ((страшная нагрузка в правой части - это я запустил while true; do echo -n; done в баше в демонстративных целях))

image
Вот так выглядит нагрузка суммарно на весь процессор для каждого воркера ((воркеры на одной машине запущены, поэтому графики идентичные для всех троих))

image
Вот так выглядит использование памяти процессом. ((в искусственном примере просто во время "выполнения задачи" происходит malloc на рандомно 0-50 мегабайт))

image
Время выполнения задачи. Выглядит немного непонятно наверное. этот график показывает "сколько секунд прошло с начала выполнения задачи". поэтому на пиках этого графика будет итоговое время выполнения задачи.

@jcdkiki jcdkiki linked an issue Apr 8, 2025 that may be closed by this pull request
Comment on lines 27 to 46
FILE *file = fopen("/proc/stat", "r");
char cpu_name[32];

while (true) {
CPUInfo cpu;

fscanf(file, "%s %lu %lu %lu %lu %*u %*u %*u %*u %*u %*u",
cpu_name,
&cpu.last_total_user, &cpu.last_total_user_low,
&cpu.last_total_sys, &cpu.last_total_idle
);

if (strstr(cpu_name, "cpu") != cpu_name)
break;

cpu.gauge = &cpu_usage_family.Add({{ "cpu", std::string(cpu_name) }});
cpu_usage.insert({ std::string(cpu_name), cpu });
}

fclose(file);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Лучше переписать на cpp стиль, не используя функции на Си

Comment on lines 87 to 95
FILE *file = fopen("/proc/self/statm", "r");
if (file == NULL) {
memory_used_gauge->Set(0);
return;
}

long mem_pages = 0;
fscanf(file, "%ld", &mem_pages);
fclose(file);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Аналогично


void MetricsCollector::getCPUUsage()
{
FILE *file = fopen("/proc/stat", "r");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Аналогично

@jcdkiki jcdkiki requested a review from AndrewGavril April 15, 2025 19:57
thread.join();
}

void MetricsCollector::getMemoryUsed()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

выглядит как функиця двойного назначения 1) прочитать статы 2) обновить метрики.
если утащить чтение статов в безымянный неймспейс в этом cpp, тогда для однострочника записи метрики отделдьная функция не понадобится вовсе и не будет загрязнять неймспейс класса.

Если хочется юнит тесты сделать для коллектора, то такой метод для получения чего-то из /proc сделать как реализацию интерфейсного метода. А в тестах делать инъекцию зависимости с фейковыми данными.

if (is_task_running) {
struct timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
task_processing_time_gauge->Set((time.tv_sec - task_start.tv_sec) + (time.tv_nsec - task_start.tv_nsec) * 1e-9);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ещё одно место где стоит подумать о C++ и в частности о std::chrono

{
is_task_running = false;
task_processing_time_gauge->Set(0);
gateway.PushAdd();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

обилие разного кодестайла...

prometheus::Gauge *memory_used_gauge;
std::unordered_map<std::string, CPUInfo> cpu_usage;
prometheus::Gauge *task_processing_time_gauge;
bool is_running;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. здесь нужен атомик и может даже вообще передавать его из вне чтоб можно было из посикс сигналов ставить (по sigint например).
  2. кажется при конструировании у нас не было никакой возможности получить здесь значение отличное от true. Видимо можно было сразу здесь и прописать
    std::atomic<bool> is_running{true};


struct CPUInfo {
prometheus::Gauge *gauge;
uint64_t last_total_user;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

а что там за гигантские значения хранятся что uint64 понадобился?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

а что там за гигантские значения хранятся что uint64 понадобился?

Чтобы переполнения реже происходили. Это время, как в выводе time. А процент использования вычисляется уже как (user+sys) / total

src/hash.cpp Outdated
}
std::cout << std::endl;

EVP_cleanup();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

код писался под какую-то древнюю версию openssl?
в любом случае это выглядит плохим решением что-то глобально клинить когда могут быть ещё таски

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А это не мой код, делал чекаут от #4. Там уже всё переписано и замерджено, подолью мейн сюда и не будет этого

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

если чужой код тоже в бранче может тогда и МР делать поверх того бранча? было бы меньше вопросов.
а стек позже схлопнуть когда будут готовы оба.

src/hash.cpp Outdated
return 0;
}

int main_metrics(int argc, char* argv[]) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

неплохо бы определиться называть функции камел кейсом или снейком.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Всё это исчезнет и останется один единственный main, когда сюда прикрутится полноценный воркер (#15)

src/hash.cpp Outdated
return 1;
}

MetricsCollector metrics_collector(argv[2], argv[3], argv[4]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

предлагаю для опций использовать это https://www.boost.org/doc/libs/1_88_0/doc/html/program_options/tutorial.html#id-1.3.29.4.3

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Устанавливать целый буст ради одной фичи?
Может лучше передавать все аргументы через env переменные? Удобно будет при запуске докер контейнера их передавать

src/hash.cpp Outdated

MetricsCollector metrics_collector(argv[2], argv[3], argv[4]);

srand(time(NULL));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это тоже исчезнет, когда здесь будет полноценный воркер, а не sleep(random).

src/hash.cpp Outdated

// some "work" that requires memory
void *data = malloc(rand() % (1024 * 1024 * 50)); // 0 - 50 megabytes
std::this_thread::sleep_for(std::chrono::seconds(rand() % 5 + 1));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sleep_for не помечен как noexcept, значит это место потециальной утечки

@jcdkiki jcdkiki requested a review from Ri0n April 20, 2025 15:16
@AndrewGavril AndrewGavril changed the base branch from main to calculate_hash April 20, 2025 19:18
@AndrewGavril AndrewGavril changed the base branch from calculate_hash to main April 20, 2025 19:18
@jcdkiki jcdkiki force-pushed the metrics-collection branch from 92170c1 to ea2d3e2 Compare April 20, 2025 19:47
@jcdkiki jcdkiki force-pushed the metrics-collection branch from ea2d3e2 to 0329b73 Compare April 20, 2025 20:20
Copy link
Collaborator

@AndrewGavril AndrewGavril left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нужно исправить конфликт

src/main.cpp Outdated
}

int metrics_main(int argc, char *argv[]) {
signal(SIGTERM, signal_handler);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sigaction ?

src/main.cpp Outdated
}


bool is_running = true;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

а чего их теперь два?

надо второй сделать референсом первого а здесь добавить атомик

src/main.cpp Outdated
#include <thread>
#include <signal.h>

void print_usage(const std::string& program_name) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

предлагаю засовывать вообще все ненужные для линковки функции в анониммный неймспейс, а не только в юнитах классов

src/main.cpp Outdated

int main(int argc, char *argv[])
{
static const char usage[] = "Specify hash/metrics";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/main.cpp Outdated
return 1;
}

if (strcmp(argv[1], "hash") == 0) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

У всех фломастеры разные конечно, но я бы наверное сделал так

std::string_view cmd{argv[1]};
if (cmd == "hash") {
...

или даже

cmd == "hash"sv

MDCalculator::MDCalculator(const std::string& algorithm)
: md_(nullptr), ctx_(nullptr, EVP_MD_CTX_free) {

OpenSSL_add_all_digests();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

как только появится демон с цикличной обработкой, это штука будет только вносить тормоза, если в ней нет внутренней проверки что уже проинициализировано.

if (total_user < cpu.last_total_user || total_user_low < cpu.last_total_user_low ||
total_sys < cpu.last_total_sys || total_idle < cpu.last_total_idle) {
// overflow detection
percent = -1.0;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я сделал небольшие подсчеты для своего железа. Для этого понадобится 1+ млрд лет. Думаю система отключится раньше.
Но респект что переполнение вообще пришло в голову.
А вот с точки зрения пользователя -1 это нонсенс.

@jcdkiki jcdkiki requested a review from AndrewGavril May 5, 2025 00:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Develop class for metrics collection in worker node
3 participants