Add memusage(2).
Switch xz to memusage(2) and fix native self-cross issue. This is a compatible ABI change.
This commit is contained in:
parent
7963da689d
commit
2cd7361294
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.3' && \
|
echo 'SORTIX_ABI=1.4' && \
|
||||||
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) 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2012, 2013, 2014, 2015, 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
|
||||||
|
@ -90,7 +90,7 @@ int common_statvfs(ioctx_t* ctx, struct statvfs* stvfs, dev_t dev)
|
||||||
{
|
{
|
||||||
size_t memory_used;
|
size_t memory_used;
|
||||||
size_t memory_total;
|
size_t memory_total;
|
||||||
Memory::Statistics(&memory_used, &memory_total);
|
Memory::Statistics(&memory_used, &memory_total, NULL);
|
||||||
struct statvfs retstvfs;
|
struct statvfs retstvfs;
|
||||||
memset(&retstvfs, 0, sizeof(retstvfs));
|
memset(&retstvfs, 0, sizeof(retstvfs));
|
||||||
retstvfs.f_bsize = Page::Size();
|
retstvfs.f_bsize = Page::Size();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2012, 2014, 2015, 2017 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011, 2012, 2014, 2015, 2017, 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
|
||||||
|
@ -33,13 +33,12 @@ class Process;
|
||||||
|
|
||||||
enum page_usage
|
enum page_usage
|
||||||
{
|
{
|
||||||
PAGE_USAGE_OTHER,
|
|
||||||
PAGE_USAGE_PHYSICAL,
|
PAGE_USAGE_PHYSICAL,
|
||||||
PAGE_USAGE_PAGING_OVERHEAD,
|
PAGE_USAGE_PAGING_OVERHEAD,
|
||||||
PAGE_USAGE_KERNEL_HEAP,
|
PAGE_USAGE_KERNEL_HEAP,
|
||||||
PAGE_USAGE_FILESYSTEM_CACHE,
|
PAGE_USAGE_FILESYSTEM_CACHE,
|
||||||
PAGE_USAGE_USER_SPACE,
|
PAGE_USAGE_USER_SPACE,
|
||||||
PAGE_USAGE_EXECUTE,
|
PAGE_USAGE_EXECVE,
|
||||||
PAGE_USAGE_DRIVER,
|
PAGE_USAGE_DRIVER,
|
||||||
PAGE_USAGE_NETWORK_PACKET,
|
PAGE_USAGE_NETWORK_PACKET,
|
||||||
PAGE_USAGE_NUM_KINDS,
|
PAGE_USAGE_NUM_KINDS,
|
||||||
|
@ -110,7 +109,7 @@ void PageProtectAdd(addr_t mapto, int protection);
|
||||||
void PageProtectSub(addr_t mapto, int protection);
|
void PageProtectSub(addr_t mapto, int protection);
|
||||||
bool MapRange(addr_t where, size_t bytes, int protection, enum page_usage usage);
|
bool MapRange(addr_t where, size_t bytes, int protection, enum page_usage usage);
|
||||||
bool UnmapRange(addr_t where, size_t bytes, enum page_usage usage);
|
bool UnmapRange(addr_t where, size_t bytes, enum page_usage usage);
|
||||||
void Statistics(size_t* amountused, size_t* totalmem);
|
void Statistics(size_t* used, size_t* total, size_t* purposes);
|
||||||
addr_t GetKernelStack();
|
addr_t GetKernelStack();
|
||||||
size_t GetKernelStackSize();
|
size_t GetKernelStackSize();
|
||||||
void GetKernelVirtualArea(addr_t* from, size_t* size);
|
void GetKernelVirtualArea(addr_t* from, size_t* size);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011-2016, 2021 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011-2016, 2021, 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
|
||||||
|
@ -117,6 +117,7 @@ int sys_linkat(int, const char*, int, const char*, int);
|
||||||
int sys_listen(int, int);
|
int sys_listen(int, int);
|
||||||
off_t sys_lseek(int, off_t, int);
|
off_t sys_lseek(int, off_t, int);
|
||||||
int sys_memstat(size_t*, size_t*);
|
int sys_memstat(size_t*, size_t*);
|
||||||
|
int sys_memusage(const size_t*, size_t*, size_t);
|
||||||
int sys_mkdirat(int, const char*, mode_t);
|
int sys_mkdirat(int, const char*, mode_t);
|
||||||
int sys_mkpartition(int, off_t, off_t, int);
|
int sys_mkpartition(int, off_t, off_t, int);
|
||||||
int sys_mkpty(int*, int*, int);
|
int sys_mkpty(int*, int*, int);
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Jonas 'Sortie' Termansen.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* sortix/memusage.h
|
||||||
|
* Memory usage statistics.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_SORTIX_MEMUSAGE_H
|
||||||
|
#define _INCLUDE_SORTIX_MEMUSAGE_H
|
||||||
|
|
||||||
|
#define MEMUSAGE_TOTAL 0
|
||||||
|
#define MEMUSAGE_USED 1
|
||||||
|
|
||||||
|
#define MEMUSAGE_PURPOSE_FIRST 16
|
||||||
|
#define MEMUSAGE_PURPOSE_PHYSICAL (MEMUSAGE_PURPOSE_FIRST + 0)
|
||||||
|
#define MEMUSAGE_PURPOSE_PAGING (MEMUSAGE_PURPOSE_FIRST + 1)
|
||||||
|
#define MEMUSAGE_PURPOSE_KERNEL (MEMUSAGE_PURPOSE_FIRST + 2)
|
||||||
|
#define MEMUSAGE_PURPOSE_FILESYSTEM (MEMUSAGE_PURPOSE_FIRST + 3)
|
||||||
|
#define MEMUSAGE_PURPOSE_USERSPACE (MEMUSAGE_PURPOSE_FIRST + 4)
|
||||||
|
#define MEMUSAGE_PURPOSE_EXECVE (MEMUSAGE_PURPOSE_FIRST + 5)
|
||||||
|
#define MEMUSAGE_PURPOSE_DRIVER (MEMUSAGE_PURPOSE_FIRST + 6)
|
||||||
|
#define MEMUSAGE_PURPOSE_NETWORK (MEMUSAGE_PURPOSE_FIRST + 7)
|
||||||
|
#define MEMUSAGE_PURPOSE_LAST MEMUSAGE_PURPOSE_NETWORK
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011-2016, 2021 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011-2016, 2021, 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
|
||||||
|
@ -189,6 +189,7 @@
|
||||||
#define SYSCALL_GETDNSCONFIG 166
|
#define SYSCALL_GETDNSCONFIG 166
|
||||||
#define SYSCALL_SETDNSCONFIG 167
|
#define SYSCALL_SETDNSCONFIG 167
|
||||||
#define SYSCALL_FUTEX 168
|
#define SYSCALL_FUTEX 168
|
||||||
#define SYSCALL_MAX_NUM 169 /* index of highest constant + 1 */
|
#define SYSCALL_MEMUSAGE 169
|
||||||
|
#define SYSCALL_MAX_NUM 170 /* index of highest constant + 1 */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2012, 2013, 2015 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011, 2012, 2013, 2015, 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
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sortix/memusage.h>
|
||||||
#include <sortix/mman.h>
|
#include <sortix/mman.h>
|
||||||
#include <sortix/seek.h>
|
#include <sortix/seek.h>
|
||||||
|
|
||||||
|
@ -39,11 +40,13 @@
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
|
// TODO: After releasing Sortix 1.1, remove this deprecated system call retained
|
||||||
|
// for backwards ABI compatibility with Sortix 1.0's xz port.
|
||||||
int sys_memstat(size_t* memused, size_t* memtotal)
|
int sys_memstat(size_t* memused, size_t* memtotal)
|
||||||
{
|
{
|
||||||
size_t used;
|
size_t used;
|
||||||
size_t total;
|
size_t total;
|
||||||
Memory::Statistics(&used, &total);
|
Memory::Statistics(&used, &total, NULL);
|
||||||
if ( memused && !CopyToUser(memused, &used, sizeof(used)) )
|
if ( memused && !CopyToUser(memused, &used, sizeof(used)) )
|
||||||
return -1;
|
return -1;
|
||||||
if ( memtotal && !CopyToUser(memtotal, &total, sizeof(total)) )
|
if ( memtotal && !CopyToUser(memtotal, &total, sizeof(total)) )
|
||||||
|
@ -51,6 +54,47 @@ int sys_memstat(size_t* memused, size_t* memtotal)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sys_memusage(const size_t* user_statistics,
|
||||||
|
size_t* user_values,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
size_t used;
|
||||||
|
size_t total;
|
||||||
|
size_t purposes[PAGE_USAGE_NUM_KINDS];
|
||||||
|
Memory::Statistics(&used, &total, purposes);
|
||||||
|
for ( size_t start = 0; start < length; )
|
||||||
|
{
|
||||||
|
const size_t BLOCK = 32;
|
||||||
|
size_t statistics[BLOCK];
|
||||||
|
size_t amount = length - start;
|
||||||
|
if ( BLOCK < amount )
|
||||||
|
amount = BLOCK;
|
||||||
|
if ( !CopyFromUser(statistics, user_statistics + start,
|
||||||
|
amount * sizeof(size_t)) )
|
||||||
|
return -1;
|
||||||
|
for ( size_t i = 0; i < amount; i++ )
|
||||||
|
{
|
||||||
|
size_t statistic = statistics[i];
|
||||||
|
size_t value;
|
||||||
|
if ( statistic == MEMUSAGE_TOTAL )
|
||||||
|
value = total;
|
||||||
|
else if ( statistic == MEMUSAGE_USED )
|
||||||
|
value = used;
|
||||||
|
else if ( MEMUSAGE_PURPOSE_FIRST <= statistic &&
|
||||||
|
statistic <= MEMUSAGE_PURPOSE_LAST )
|
||||||
|
value = purposes[statistic - MEMUSAGE_PURPOSE_FIRST];
|
||||||
|
else
|
||||||
|
return errno = EINVAL, -1;
|
||||||
|
statistics[i] = value;
|
||||||
|
}
|
||||||
|
if ( !CopyToUser(user_values + start, statistics,
|
||||||
|
amount * sizeof(size_t)) )
|
||||||
|
return -1;
|
||||||
|
start += amount;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015 Meisaka Yukara.
|
* Copyright (c) 2015 Meisaka Yukara.
|
||||||
* Copyright (c) 2016, 2017 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2016, 2017, 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
|
||||||
|
@ -84,7 +84,7 @@ Ref<Packet> GetPacket()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
size_t total_memory;
|
size_t total_memory;
|
||||||
Memory::Statistics(NULL, &total_memory);
|
Memory::Statistics(NULL, &total_memory, NULL);
|
||||||
size_t total_pages = total_memory / Page::Size();
|
size_t total_pages = total_memory / Page::Size();
|
||||||
size_t max_packets = total_pages / MAX_PACKET_FRACTION;
|
size_t max_packets = total_pages / MAX_PACKET_FRACTION;
|
||||||
if ( max_packets <= packet_count )
|
if ( max_packets <= packet_count )
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011-2016, 2021 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011-2016, 2021-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
|
||||||
|
@ -1165,7 +1165,7 @@ static bool sys_execve_alloc(addralloc_t* alloc, size_t size)
|
||||||
{
|
{
|
||||||
if ( !AllocateKernelAddress(alloc, size) )
|
if ( !AllocateKernelAddress(alloc, size) )
|
||||||
return false;
|
return false;
|
||||||
if ( !Memory::MapRange(alloc->from, alloc->size, PROT_KREAD | PROT_KWRITE, PAGE_USAGE_EXECUTE) )
|
if ( !Memory::MapRange(alloc->from, alloc->size, PROT_KREAD | PROT_KWRITE, PAGE_USAGE_EXECVE) )
|
||||||
return FreeKernelAddress(alloc), false;
|
return FreeKernelAddress(alloc), false;
|
||||||
Memory::Flush();
|
Memory::Flush();
|
||||||
return true;
|
return true;
|
||||||
|
@ -1173,7 +1173,7 @@ static bool sys_execve_alloc(addralloc_t* alloc, size_t size)
|
||||||
|
|
||||||
static void sys_execve_free(addralloc_t* alloc)
|
static void sys_execve_free(addralloc_t* alloc)
|
||||||
{
|
{
|
||||||
Memory::UnmapRange(alloc->from, alloc->size, PAGE_USAGE_EXECUTE);
|
Memory::UnmapRange(alloc->from, alloc->size, PAGE_USAGE_EXECVE);
|
||||||
Memory::Flush();
|
Memory::Flush();
|
||||||
FreeKernelAddress(alloc);
|
FreeKernelAddress(alloc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011-2016, 2021 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011-2016, 2021-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
|
||||||
|
@ -203,6 +203,7 @@ void* syscall_list[SYSCALL_MAX_NUM + 1] =
|
||||||
[SYSCALL_GETDNSCONFIG] = (void*) sys_getdnsconfig,
|
[SYSCALL_GETDNSCONFIG] = (void*) sys_getdnsconfig,
|
||||||
[SYSCALL_SETDNSCONFIG] = (void*) sys_setdnsconfig,
|
[SYSCALL_SETDNSCONFIG] = (void*) sys_setdnsconfig,
|
||||||
[SYSCALL_FUTEX] = (void*) sys_futex,
|
[SYSCALL_FUTEX] = (void*) sys_futex,
|
||||||
|
[SYSCALL_MEMUSAGE] = (void*) sys_memusage,
|
||||||
[SYSCALL_MAX_NUM] = (void*) sys_bad_syscall,
|
[SYSCALL_MAX_NUM] = (void*) sys_bad_syscall,
|
||||||
};
|
};
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2012, 2014, 2015, 2017 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011, 2012, 2014, 2015, 2017, 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
|
||||||
|
@ -220,14 +220,20 @@ void Init(multiboot_info_t* bootinfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Statistics(size_t* amountused, size_t* totalmem)
|
void Statistics(size_t* used, size_t* total, size_t* purposes)
|
||||||
{
|
{
|
||||||
|
ScopedLock lock(&Page::pagelock);
|
||||||
size_t memfree = (Page::stackused - Page::stackreserved) << 12UL;
|
size_t memfree = (Page::stackused - Page::stackreserved) << 12UL;
|
||||||
size_t memused = Page::totalmem - memfree;
|
size_t memused = Page::totalmem - memfree;
|
||||||
if ( amountused )
|
if ( used )
|
||||||
*amountused = memused;
|
*used = memused;
|
||||||
if ( totalmem )
|
if ( total )
|
||||||
*totalmem = Page::totalmem;
|
*total = Page::totalmem;
|
||||||
|
if ( purposes )
|
||||||
|
{
|
||||||
|
for ( size_t i = 0; i < PAGE_USAGE_NUM_KINDS; i++ )
|
||||||
|
purposes[i] = Page::page_usage_counts[i] << 12UL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Memory
|
} // namespace Memory
|
||||||
|
|
|
@ -393,6 +393,7 @@ langinfo/nl_langinfo_l.o \
|
||||||
langinfo/nl_langinfo.o \
|
langinfo/nl_langinfo.o \
|
||||||
locale/localeconv.o \
|
locale/localeconv.o \
|
||||||
locale/setlocale.o \
|
locale/setlocale.o \
|
||||||
|
memusage/memusage.o \
|
||||||
msr/rdmsr.o \
|
msr/rdmsr.o \
|
||||||
msr/wrmsr.o \
|
msr/wrmsr.o \
|
||||||
netdb/endnetent.o \
|
netdb/endnetent.o \
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, 2023 Jonas 'Sortie' Termansen.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* memusage.h
|
||||||
|
* Memory usage statistics.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_MEMUSAGE_H
|
||||||
|
#define _INCLUDE_MEMUSAGE_H
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <sortix/memusage.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int memusage(const size_t*, size_t*, size_t);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, 2023 Jonas 'Sortie' Termansen.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* memsage/memusage.c
|
||||||
|
* Memory usage statistics.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
|
||||||
|
#include <memusage.h>
|
||||||
|
|
||||||
|
DEFN_SYSCALL3(int, sys_memusage, SYSCALL_MEMUSAGE, const size_t*, size_t*,
|
||||||
|
size_t);
|
||||||
|
|
||||||
|
int memusage(const size_t* statistics, size_t* values, size_t length)
|
||||||
|
{
|
||||||
|
return sys_memusage(statistics, values, length);
|
||||||
|
}
|
|
@ -1,6 +1,60 @@
|
||||||
diff -Paur --no-dereference -- xz.upstream/configure xz/configure
|
diff -Paur --no-dereference -- xz.upstream/configure xz/configure
|
||||||
--- xz.upstream/configure
|
--- xz.upstream/configure
|
||||||
+++ xz/configure
|
+++ xz/configure
|
||||||
|
@@ -16829,7 +16829,7 @@
|
||||||
|
done
|
||||||
|
if test -z "$haveit"; then
|
||||||
|
if test -d "$additional_includedir"; then
|
||||||
|
- INCICONV="${INCICONV}${INCICONV:+ }-I$additional_includedir"
|
||||||
|
+ INCICONV="${INCICONV}${INCICONV:+ }"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
@@ -16876,7 +16876,7 @@
|
||||||
|
done
|
||||||
|
if test -z "$haveit"; then
|
||||||
|
if test -d "$additional_libdir"; then
|
||||||
|
- LIBICONV="${LIBICONV}${LIBICONV:+ }-L$additional_libdir"
|
||||||
|
+ LIBICONV="${LIBICONV}${LIBICONV:+ }"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
haveit=
|
||||||
|
@@ -16897,7 +16897,7 @@
|
||||||
|
done
|
||||||
|
if test -z "$haveit"; then
|
||||||
|
if test -d "$additional_libdir"; then
|
||||||
|
- LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$additional_libdir"
|
||||||
|
+ LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
@@ -17772,7 +17772,7 @@
|
||||||
|
done
|
||||||
|
if test -z "$haveit"; then
|
||||||
|
if test -d "$additional_includedir"; then
|
||||||
|
- INCINTL="${INCINTL}${INCINTL:+ }-I$additional_includedir"
|
||||||
|
+ INCINTL="${INCINTL}${INCINTL:+ }"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
@@ -17819,7 +17819,7 @@
|
||||||
|
done
|
||||||
|
if test -z "$haveit"; then
|
||||||
|
if test -d "$additional_libdir"; then
|
||||||
|
- LIBINTL="${LIBINTL}${LIBINTL:+ }-L$additional_libdir"
|
||||||
|
+ LIBINTL="${LIBINTL}${LIBINTL:+ }"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
haveit=
|
||||||
|
@@ -17840,7 +17840,7 @@
|
||||||
|
done
|
||||||
|
if test -z "$haveit"; then
|
||||||
|
if test -d "$additional_libdir"; then
|
||||||
|
- LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-L$additional_libdir"
|
||||||
|
+ LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
@@ -19269,6 +19269,7 @@
|
@@ -19269,6 +19269,7 @@
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__OS2__) \
|
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__OS2__) \
|
||||||
|
@ -19,7 +73,7 @@ diff -Paur --no-dereference -- xz.upstream/src/common/tuklib_physmem.c xz/src/co
|
||||||
+
|
+
|
||||||
+// Sortix
|
+// Sortix
|
||||||
+#elif defined(__sortix__)
|
+#elif defined(__sortix__)
|
||||||
+# include <unistd.h>
|
+# include <memusage.h>
|
||||||
+
|
+
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -29,9 +83,9 @@ diff -Paur --no-dereference -- xz.upstream/src/common/tuklib_physmem.c xz/src/co
|
||||||
if (sysinfo(&si) == 0)
|
if (sysinfo(&si) == 0)
|
||||||
ret = (uint64_t)si.totalram * si.mem_unit;
|
ret = (uint64_t)si.totalram * si.mem_unit;
|
||||||
+#elif defined(__sortix__)
|
+#elif defined(__sortix__)
|
||||||
+ size_t ret_size_t;
|
+ size_t statistic = MEMUSAGE_TOTAL;
|
||||||
+ memstat(NULL, &ret_size_t);
|
+ memusage(&statistic, &statistic, 1);
|
||||||
+ ret = ret_size_t;
|
+ ret = statistic;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -69,6 +69,11 @@ 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 memusage(2)
|
||||||
|
The
|
||||||
|
.Xr memusage 2
|
||||||
|
system call has been added, which provides detailed system memory statistics.
|
||||||
|
This is a minor compatible ABI change.
|
||||||
.Ss Add networking stack
|
.Ss Add networking stack
|
||||||
The network stack has been implemented in the kernel and exposed through
|
The network stack has been implemented in the kernel and exposed through
|
||||||
additions to the system call interface.
|
additions to the system call interface.
|
||||||
|
|
|
@ -1,19 +1,94 @@
|
||||||
.Dd October 6, 2016
|
.Dd March 8, 2023
|
||||||
.Dt MEMSTAT 1
|
.Dt MEMSTAT 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
.Nm memstat
|
.Nm memstat
|
||||||
.Nd print system memory usage information
|
.Nd system memory statistics
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
|
.Op Fl abegkmprt
|
||||||
|
.Op Ar statistic ...
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Nm
|
.Nm
|
||||||
prints the amount of memory in use, the total amount of memory, and the
|
writes the requested system memory
|
||||||
percentage of memory used.
|
.Ar statistics ,
|
||||||
|
or the
|
||||||
|
.Sy total
|
||||||
|
system memory and
|
||||||
|
.Sy used
|
||||||
|
system memory by default.
|
||||||
|
Each statistic is written as a line with three columns aligned with spaces,
|
||||||
|
where the first column is the human readable value, the second column is the
|
||||||
|
name of the statistic, and the third column is how many percent the value is out
|
||||||
|
of total system memory.
|
||||||
|
.Pp
|
||||||
|
The options are as follows:
|
||||||
|
.Bl -tag -width "12345678"
|
||||||
|
.It Fl a
|
||||||
|
Write all statistics.
|
||||||
|
.It Fl b
|
||||||
|
Format values as bytes.
|
||||||
|
.It Fl e
|
||||||
|
Format values as exabytes (1024^6 bytes).
|
||||||
|
.It Fl g
|
||||||
|
Format values as gigabytes (1024^3 bytes).
|
||||||
|
.It Fl k
|
||||||
|
Format values as kilobytes (1024 bytes).
|
||||||
|
.It Fl m
|
||||||
|
Format values as megabytes (1024^2 bytes).
|
||||||
|
.It Fl p
|
||||||
|
Format values as petabytes (1024^5 bytes).
|
||||||
|
.It Fl r
|
||||||
|
Write statistics in the raw machine readable format consisting of the value in
|
||||||
|
the requested unit (bytes by default) with no unit suffix followed by a space
|
||||||
|
and then the statistic name.
|
||||||
|
.It Fl t
|
||||||
|
Format values as terabytes (1024^4 bytes).
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The statistics are as follows:
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width filesystem -compact
|
||||||
|
.It Sy total
|
||||||
|
amount of total memory.
|
||||||
|
.It Sy used
|
||||||
|
amount of memory currently used for any purpose.
|
||||||
|
.It Sy userspace
|
||||||
|
amount of memory purposed for normal user-space pages.
|
||||||
|
.It Sy kernel
|
||||||
|
amount of memory purposed for normal kernel-space pages.
|
||||||
|
.It Sy filesystem
|
||||||
|
amount of memory purposed for kernel filesystem buffers.
|
||||||
|
.It Sy network
|
||||||
|
amount of memory purposed for kernel network buffers.
|
||||||
|
.It Sy paging
|
||||||
|
amount of memory purposed for paging overhead.
|
||||||
|
.It Sy driver
|
||||||
|
amount of memory purposed for kernel driver buffers.
|
||||||
|
.It Sy physical
|
||||||
|
amount of memory purposed for keep track of unused physical memory.
|
||||||
|
.It Sy execve
|
||||||
|
amount of memory purposed for the
|
||||||
|
.Xr execve 2
|
||||||
|
system call.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
.Nm
|
||||||
|
measures an instantaneous consistent snapshot of all the system memory
|
||||||
|
statistics using
|
||||||
|
.Xr memusage 2 .
|
||||||
|
Each page of memory is used for exactly one purpose and the purpose statistics
|
||||||
|
add up to the
|
||||||
|
.Sy used
|
||||||
|
statistic.
|
||||||
.Sh EXIT STATUS
|
.Sh EXIT STATUS
|
||||||
.Nm
|
.Nm
|
||||||
will exit 0 on success and non-zero otherwise.
|
will exit 0 on success and non-zero otherwise.
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr ps 1 ,
|
.Xr ps 1 ,
|
||||||
.Xr pstree 1 ,
|
.Xr pstree 1 ,
|
||||||
.Xr memstat 2
|
.Xr memusage 2
|
||||||
|
.Sh HISTORY
|
||||||
|
.Nm
|
||||||
|
originally appeared in Sortix 0.5.
|
||||||
|
The output was changed to the current table format in Sortix 1.1.
|
||||||
|
|
205
utils/memstat.c
205
utils/memstat.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011, 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
|
||||||
|
@ -14,13 +14,16 @@
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*
|
*
|
||||||
* memstat.c
|
* memstat.c
|
||||||
* Prints system memory usage information.
|
* System memory statistics.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
|
#include <memusage.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#define BYTES 0
|
#define BYTES 0
|
||||||
#define KIBI 1
|
#define KIBI 1
|
||||||
|
@ -30,49 +33,173 @@
|
||||||
#define PEBI 5
|
#define PEBI 5
|
||||||
#define EXBI 6
|
#define EXBI 6
|
||||||
|
|
||||||
void printbytes(unsigned long long bytes)
|
static char* format_bytes_amount(uintmax_t num_bytes, int unit, bool raw)
|
||||||
{
|
{
|
||||||
unsigned unit = BYTES;
|
uintmax_t value = num_bytes;
|
||||||
if ( (bytes >> 10ULL) & 1023ULL ) { unit = KIBI; }
|
uintmax_t value_fraction = 0;
|
||||||
if ( (bytes >> 20ULL) & 1023ULL ) { unit = MEBI; }
|
uintmax_t exponent = 1024;
|
||||||
if ( (bytes >> 30ULL) & 1023ULL ) { unit = GIBI; }
|
char suffixes[] = { 'B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' };
|
||||||
if ( (bytes >> 40ULL) & 1023ULL ) { unit = TEBI; }
|
size_t num_suffixes = sizeof(suffixes) / sizeof(suffixes[0]);
|
||||||
if ( (bytes >> 50ULL) & 1023ULL ) { unit = PEBI; }
|
size_t suffix_index = 0;
|
||||||
if ( (bytes >> 60ULL) & 1023ULL ) { unit = EXBI; }
|
while ( (unit < 0 ? exponent <= value : (int) suffix_index < unit) &&
|
||||||
|
suffix_index + 1 < num_suffixes )
|
||||||
switch ( unit )
|
|
||||||
{
|
{
|
||||||
case EXBI:
|
value_fraction = value % exponent;
|
||||||
printf("%llu ZiB ", (bytes >> 60ULL) & 1023ULL);
|
value /= exponent;
|
||||||
case PEBI:
|
suffix_index++;
|
||||||
printf("%llu PiB ", (bytes >> 50ULL) & 1023ULL);
|
|
||||||
case TEBI:
|
|
||||||
printf("%llu TiB ", (bytes >> 40ULL) & 1023ULL);
|
|
||||||
case GIBI:
|
|
||||||
printf("%llu GiB ", (bytes >> 30ULL) & 1023ULL);
|
|
||||||
case MEBI:
|
|
||||||
printf("%llu MiB ", (bytes >> 20ULL) & 1023ULL);
|
|
||||||
case KIBI:
|
|
||||||
printf("%llu KiB", (bytes >> 10ULL) & 1023ULL);
|
|
||||||
break;
|
|
||||||
case BYTES:
|
|
||||||
printf("%llu B", (bytes >> 0ULL) & 1023ULL);
|
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
struct memusage
|
||||||
{
|
{
|
||||||
size_t memused = 0;
|
size_t counter;
|
||||||
size_t memtotal = 0;
|
const char* name;
|
||||||
if ( memstat(&memused, &memtotal) )
|
};
|
||||||
err(1, "memstat");
|
|
||||||
|
|
||||||
printf("memory usage: ");
|
static const struct memusage memusages[] =
|
||||||
printbytes(memused);
|
{
|
||||||
printf(" used / ");
|
{MEMUSAGE_TOTAL, "total"},
|
||||||
printbytes(memtotal);
|
{MEMUSAGE_USED, "used"},
|
||||||
unsigned percent = ((unsigned long long) memused * 100ULL ) / memtotal;
|
{MEMUSAGE_PURPOSE_USERSPACE, "userspace"},
|
||||||
printf(" total (%u%s)\n", percent, "%");
|
{MEMUSAGE_PURPOSE_KERNEL, "kernel"},
|
||||||
|
{MEMUSAGE_PURPOSE_FILESYSTEM, "filesystem"},
|
||||||
|
{MEMUSAGE_PURPOSE_NETWORK, "network"},
|
||||||
|
{MEMUSAGE_PURPOSE_PAGING, "paging"},
|
||||||
|
{MEMUSAGE_PURPOSE_DRIVER, "driver"},
|
||||||
|
{MEMUSAGE_PURPOSE_PHYSICAL, "physical"},
|
||||||
|
{MEMUSAGE_PURPOSE_EXECVE, "execve"},
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
bool all = false;
|
||||||
|
bool raw = false;
|
||||||
|
int unit = -1;
|
||||||
|
|
||||||
|
int opt;
|
||||||
|
while ( (opt = getopt(argc, argv, "abegkmprt")) != -1 )
|
||||||
|
{
|
||||||
|
switch ( opt )
|
||||||
|
{
|
||||||
|
case 'a': all = true; break;
|
||||||
|
case 'b': unit = BYTES; break;
|
||||||
|
case 'e': unit = EXBI; break;
|
||||||
|
case 'g': unit = GIBI; break;
|
||||||
|
case 'k': unit = KIBI; break;
|
||||||
|
case 'm': unit = MEBI; break;
|
||||||
|
case 'p': unit = PEBI; break;
|
||||||
|
case 'r': raw = true; break;
|
||||||
|
case 't': unit = TEBI; break;
|
||||||
|
default: return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t MAX_COUNTERS = sizeof(memusages) / sizeof(memusages[0]);
|
||||||
|
const struct memusage* usages[MAX_COUNTERS];
|
||||||
|
size_t num_counters;
|
||||||
|
size_t start_counter = 0;
|
||||||
|
|
||||||
|
if ( all )
|
||||||
|
{
|
||||||
|
if ( optind < argc )
|
||||||
|
errx(1, "extra operand: %s", argv[optind]);
|
||||||
|
num_counters = MAX_COUNTERS;
|
||||||
|
for ( size_t i = 0; i < num_counters; i++ )
|
||||||
|
usages[i] = &memusages[i];
|
||||||
|
}
|
||||||
|
else if ( optind < argc )
|
||||||
|
{
|
||||||
|
num_counters = 1;
|
||||||
|
start_counter = 1;
|
||||||
|
usages[0] = &memusages[0];
|
||||||
|
for ( int i = optind; i < argc; i++ )
|
||||||
|
{
|
||||||
|
if ( num_counters == MAX_COUNTERS )
|
||||||
|
errx(1, "too many counters");
|
||||||
|
bool found = false;
|
||||||
|
for ( size_t n = 0; n < MAX_COUNTERS; n++ )
|
||||||
|
{
|
||||||
|
if ( strcmp(argv[i], memusages[n].name) != 0 )
|
||||||
|
continue;
|
||||||
|
usages[num_counters++] = &memusages[n];
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( !found )
|
||||||
|
errx(1, "unknown statistic: %s", argv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
num_counters = 2;
|
||||||
|
usages[0] = &memusages[0];
|
||||||
|
usages[1] = &memusages[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t counts[MAX_COUNTERS];
|
||||||
|
for ( size_t i = 0; i < num_counters; i++ )
|
||||||
|
counts[i] = usages[i]->counter;
|
||||||
|
|
||||||
|
size_t values[MAX_COUNTERS];
|
||||||
|
if ( memusage(counts, values, num_counters) )
|
||||||
|
err(1, "memusage");
|
||||||
|
|
||||||
|
if ( raw && unit == -1 )
|
||||||
|
unit = BYTES;
|
||||||
|
|
||||||
|
size_t total = values[0];
|
||||||
|
|
||||||
|
size_t usage_width = 0;
|
||||||
|
size_t name_width = 0;
|
||||||
|
for ( size_t i = start_counter; i < num_counters; i++ )
|
||||||
|
{
|
||||||
|
size_t count = values[i];
|
||||||
|
const char* name = usages[i]->name;
|
||||||
|
char* usage = format_bytes_amount(count, unit, raw);
|
||||||
|
if ( !usage )
|
||||||
|
err(1, "malloc");
|
||||||
|
size_t usage_len = strlen(usage);
|
||||||
|
if ( usage_width < usage_len )
|
||||||
|
usage_width = usage_len;
|
||||||
|
size_t name_len = strlen(name);
|
||||||
|
if ( name_width < name_len )
|
||||||
|
name_width = name_len;
|
||||||
|
free(usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( size_t i = start_counter; i < num_counters; i++ )
|
||||||
|
{
|
||||||
|
size_t count = values[i];
|
||||||
|
const char* name = usages[i]->name;
|
||||||
|
char* usage = format_bytes_amount(count, unit, raw);
|
||||||
|
if ( !usage )
|
||||||
|
err(1, "malloc");
|
||||||
|
if ( raw )
|
||||||
|
{
|
||||||
|
if ( num_counters - start_counter == 1 )
|
||||||
|
printf("%s\n", usage);
|
||||||
|
else
|
||||||
|
printf("%s %s\n", usage, name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("%*s", (int) usage_width, usage);
|
||||||
|
printf(" %-*s", (int) name_width, name);
|
||||||
|
unsigned percent = ((uintmax_t) count * 100) / total;
|
||||||
|
printf(" %3u%%\n", percent);
|
||||||
|
}
|
||||||
|
free(usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ferror(stdout) || fflush(stdout) == EOF )
|
||||||
|
err(1, "stdout");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue