Add memory statistics to struct psctl_stat.
This is an incompatible ABI change.
This commit is contained in:
parent
2cd7361294
commit
8a4548db7d
2
Makefile
2
Makefile
|
@ -225,7 +225,7 @@ sysroot-system: sysroot-fsh sysroot-base-headers
|
||||||
echo 'ID=sortix' && \
|
echo 'ID=sortix' && \
|
||||||
echo 'VERSION_ID="$(VERSION)"' && \
|
echo 'VERSION_ID="$(VERSION)"' && \
|
||||||
echo 'PRETTY_NAME="Sortix $(VERSION)"' && \
|
echo 'PRETTY_NAME="Sortix $(VERSION)"' && \
|
||||||
echo 'SORTIX_ABI=1.4' && \
|
echo 'SORTIX_ABI=2.0' && \
|
||||||
true) > "$(SYSROOT)/etc/sortix-release"
|
true) > "$(SYSROOT)/etc/sortix-release"
|
||||||
echo /etc/sortix-release >> "$(SYSROOT)/tix/manifest/system"
|
echo /etc/sortix-release >> "$(SYSROOT)/tix/manifest/system"
|
||||||
ln -sf sortix-release "$(SYSROOT)/etc/os-release"
|
ln -sf sortix-release "$(SYSROOT)/etc/os-release"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2015, 2016, 2022 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -88,6 +88,10 @@ struct psctl_stat
|
||||||
int status;
|
int status;
|
||||||
int nice;
|
int nice;
|
||||||
struct tmns tmns;
|
struct tmns tmns;
|
||||||
|
size_t pss;
|
||||||
|
size_t rss;
|
||||||
|
size_t uss;
|
||||||
|
size_t vms;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PSCTL_PROGRAM_PATH __PSCTL(psctl_program_path, 4)
|
#define PSCTL_PROGRAM_PATH __PSCTL(psctl_program_path, 4)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2015, 2016, 2022 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -127,6 +127,17 @@ int sys_psctl(pid_t pid, int request, void* ptr)
|
||||||
kthread_mutex_lock(&process->nicelock);
|
kthread_mutex_lock(&process->nicelock);
|
||||||
psst.nice = process->nice;
|
psst.nice = process->nice;
|
||||||
kthread_mutex_unlock(&process->nicelock);
|
kthread_mutex_unlock(&process->nicelock);
|
||||||
|
kthread_mutex_lock(&process->segment_lock);
|
||||||
|
// TODO: Cache these.
|
||||||
|
for ( size_t i = 0; i < process->segments_used; i++ )
|
||||||
|
{
|
||||||
|
const struct segment* segment = &process->segments[i];
|
||||||
|
psst.pss += segment->size;
|
||||||
|
psst.rss += segment->size;
|
||||||
|
psst.uss += segment->size;
|
||||||
|
psst.vms += segment->size;
|
||||||
|
}
|
||||||
|
kthread_mutex_unlock(&process->segment_lock);
|
||||||
// Note: It is safe to access the clocks in this manner as each of them
|
// Note: It is safe to access the clocks in this manner as each of them
|
||||||
// are locked by disabling interrupts. This is perhaps not
|
// are locked by disabling interrupts. This is perhaps not
|
||||||
// SMP-ready, but it will do for now.
|
// SMP-ready, but it will do for now.
|
||||||
|
|
|
@ -69,6 +69,19 @@ releasing Sortix x.y, foo." to allow the maintainer to easily
|
||||||
.Xr grep 1
|
.Xr grep 1
|
||||||
for it after a release.
|
for it after a release.
|
||||||
.Sh CHANGES
|
.Sh CHANGES
|
||||||
|
.Ss Add memory statistics to struct psctl_stat
|
||||||
|
The
|
||||||
|
.Xr psctl 2
|
||||||
|
now provides per-process memory statistics in
|
||||||
|
.Vt struct psctl_stat
|
||||||
|
via the new members
|
||||||
|
.Fa pss ,
|
||||||
|
.Fa rss ,
|
||||||
|
.Fa uss ,
|
||||||
|
and
|
||||||
|
.Fa vms .
|
||||||
|
.Pp
|
||||||
|
This is an incompatible ABI change.
|
||||||
.Ss Add memusage(2)
|
.Ss Add memusage(2)
|
||||||
The
|
The
|
||||||
.Xr memusage 2
|
.Xr memusage 2
|
||||||
|
|
53
utils/ps.c
53
utils/ps.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2015, 2016, 2022, 2023 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
#include <memusage.h>
|
||||||
#include <psctl.h>
|
#include <psctl.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -30,6 +31,30 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static char* format_bytes_amount(uintmax_t num_bytes, int unit, bool raw)
|
||||||
|
{
|
||||||
|
uintmax_t value = num_bytes;
|
||||||
|
uintmax_t value_fraction = 0;
|
||||||
|
uintmax_t exponent = 1024;
|
||||||
|
char suffixes[] = { 'B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' };
|
||||||
|
size_t num_suffixes = sizeof(suffixes) / sizeof(suffixes[0]);
|
||||||
|
size_t suffix_index = 0;
|
||||||
|
while ( (unit < 0 ? exponent <= value : (int) suffix_index < unit) &&
|
||||||
|
suffix_index + 1 < num_suffixes )
|
||||||
|
{
|
||||||
|
value_fraction = value % exponent;
|
||||||
|
value /= exponent;
|
||||||
|
suffix_index++;
|
||||||
|
}
|
||||||
|
char suffix_char = raw ? 0 : suffixes[suffix_index];
|
||||||
|
char value_fraction_char = '0' + (value_fraction / (1024 / 10 + 1)) % 10;
|
||||||
|
char decimals[3] = {suffix_index ? '.' : 0, value_fraction_char, 0};
|
||||||
|
char* result;
|
||||||
|
if ( asprintf(&result, "%ju%s%c", value, decimals, suffix_char) < 0 )
|
||||||
|
return NULL;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static char* get_program_path_of_pid(pid_t pid)
|
static char* get_program_path_of_pid(pid_t pid)
|
||||||
{
|
{
|
||||||
struct psctl_program_path ctl;
|
struct psctl_program_path ctl;
|
||||||
|
@ -103,6 +128,7 @@ int main(int argc, char* argv[])
|
||||||
bool select_all = false;
|
bool select_all = false;
|
||||||
bool show_full = false;
|
bool show_full = false;
|
||||||
bool show_long = false;
|
bool show_long = false;
|
||||||
|
bool show_memory = false;
|
||||||
|
|
||||||
const char* argv0 = argv[0];
|
const char* argv0 = argv[0];
|
||||||
for ( int i = 1; i < argc; i++ )
|
for ( int i = 1; i < argc; i++ )
|
||||||
|
@ -126,12 +152,15 @@ int main(int argc, char* argv[])
|
||||||
//case 'g': break;
|
//case 'g': break;
|
||||||
//case 'G': break;
|
//case 'G': break;
|
||||||
case 'l': show_long = true; break;
|
case 'l': show_long = true; break;
|
||||||
|
case 'm': show_long = true; break;
|
||||||
//case 'n': break;
|
//case 'n': break;
|
||||||
//case 'o': break;
|
//case 'o': break;
|
||||||
//case 'p': break;
|
//case 'p': break;
|
||||||
//case 't': break;
|
//case 't': break;
|
||||||
//case 'u': break;
|
//case 'u': break;
|
||||||
//case 'U': break;
|
//case 'U': break;
|
||||||
|
// TODO: -o or some better more standard design for this.
|
||||||
|
case 'v': show_memory = true; break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c);
|
fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c);
|
||||||
help(stderr, argv0);
|
help(stderr, argv0);
|
||||||
|
@ -155,6 +184,11 @@ int main(int argc, char* argv[])
|
||||||
if ( 1 < argc )
|
if ( 1 < argc )
|
||||||
errx(1, "extra operand: %s", argv[1]);
|
errx(1, "extra operand: %s", argv[1]);
|
||||||
|
|
||||||
|
size_t total_counter = MEMUSAGE_TOTAL;
|
||||||
|
size_t total_memory;
|
||||||
|
if ( show_memory && memusage(&total_counter, &total_memory, 1) < 0 )
|
||||||
|
err(1, "memusage");
|
||||||
|
|
||||||
if ( show_full || show_long )
|
if ( show_full || show_long )
|
||||||
printf("UID\t");
|
printf("UID\t");
|
||||||
printf("PID\t");
|
printf("PID\t");
|
||||||
|
@ -167,7 +201,12 @@ int main(int argc, char* argv[])
|
||||||
if ( show_long )
|
if ( show_long )
|
||||||
printf("NI\t");
|
printf("NI\t");
|
||||||
printf("TTY\t");
|
printf("TTY\t");
|
||||||
printf("TIME\t ");
|
printf("TIME\t ");
|
||||||
|
if ( show_memory )
|
||||||
|
{
|
||||||
|
printf("%%MEM\t");
|
||||||
|
printf("VMS\t");
|
||||||
|
}
|
||||||
printf("CMD\n");
|
printf("CMD\n");
|
||||||
pid_t pid = 0;
|
pid_t pid = 0;
|
||||||
while ( true )
|
while ( true )
|
||||||
|
@ -215,6 +254,16 @@ int main(int argc, char* argv[])
|
||||||
int minutes = (time / 60) % 60;
|
int minutes = (time / 60) % 60;
|
||||||
int seconds = (time / 1) % 60;
|
int seconds = (time / 1) % 60;
|
||||||
printf("%02i:%02i:%02i ", hours, minutes, seconds);
|
printf("%02i:%02i:%02i ", hours, minutes, seconds);
|
||||||
|
if ( show_memory )
|
||||||
|
{
|
||||||
|
unsigned percent = ((uintmax_t) psst.vms * 100) / total_memory;
|
||||||
|
printf("%3u%%\t", percent);
|
||||||
|
char* usage = format_bytes_amount(psst.vms, -1, false);
|
||||||
|
if ( !usage )
|
||||||
|
err(1, "malloc");
|
||||||
|
printf("%s\t", usage);
|
||||||
|
free(usage);
|
||||||
|
}
|
||||||
char* program_path = get_program_path_of_pid(pid);
|
char* program_path = get_program_path_of_pid(pid);
|
||||||
// TODO: Strip special characters from the process name lest an attacker
|
// TODO: Strip special characters from the process name lest an attacker
|
||||||
// do things to the user's terminal.
|
// do things to the user's terminal.
|
||||||
|
|
Loading…
Reference in New Issue