blob: f48a3c5d3804fe9a26f3d25378287e3da5626919 [file] [log] [blame] [raw]
/*
htop - freebsd/FreeBSDDiskList.c
Copyright 2015-2022 Rivoreo
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
/*{
#include "DiskList.h"
#include <libgeom.h>
typedef struct {
DiskList super;
void *previous_stats;
struct gmesh tree;
} FreeBSDDiskList;
}*/
#include "FreeBSDDiskList.h"
#include "FreeBSDDisk.h"
#include "CRT.h"
#include "XAlloc.h"
#include <sys/resource.h>
#include <sys/devicestat.h>
#include <devstat.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
DiskList *DiskList_new(const Settings *settings) {
int e = geom_stats_open();
if(e && e != EBUSY) CRT_fatalError("geom_stats_open", e);
FreeBSDDiskList *disk_list = xMalloc(sizeof(FreeBSDDiskList));
DiskList_init(&disk_list->super, Class(Disk), settings);
disk_list->previous_stats = geom_stats_snapshot_get();
if(!disk_list->previous_stats) CRT_fatalError("geom_stats_snapshot_get", 0);
e = geom_gettree(&disk_list->tree);
if(e) CRT_fatalError("geom_gettree", e);
return (DiskList *)disk_list;
}
void DiskList_delete(DiskList *super) {
FreeBSDDiskList *this = (FreeBSDDiskList *)super;
geom_stats_snapshot_free(this->previous_stats);
free(this);
}
#define BINTIME_TO_HUNDREDTHSEC(BINTIME) \
((BINTIME)->sec * 100 + (((uint8_t)((BINTIME)->frac>>48) * (uint8_t)100) >> 8))
void DiskList_internalScan(DiskList *super, double unused_interval) {
FreeBSDDiskList *this = (FreeBSDDiskList *)super;
void *stats = geom_stats_snapshot_get();
if(!stats) return;
struct timespec ts, prev_ts;
geom_stats_snapshot_timestamp(stats, &ts);
geom_stats_snapshot_timestamp(this->previous_stats, &prev_ts);
long double interval = (ts.tv_sec - prev_ts.tv_sec) +
(long double)(ts.tv_nsec - prev_ts.tv_nsec) / 1000000000;
struct devstat *devstat;
while((devstat = geom_stats_snapshot_next(stats))) {
struct devstat *prev_devstat = geom_stats_snapshot_next(this->previous_stats);
const struct gident *gid = geom_lookupid(&this->tree, devstat->id);
if(!gid) continue;
if(gid->lg_what != ISPROVIDER) continue;
const struct gprovider *p = gid->lg_ptr;
if(p->lg_geom->lg_rank != 1) continue;
bool is_existing;
Disk *disk = DiskList_getOrCreate(super, p->lg_name, &is_existing, (DiskConstructor)FreeBSDDisk_new);
if(!is_existing) {
//disk->block_size = lg_sectorsize;
disk->block_size = devstat->block_size ? : 512;
disk->creation_time = devstat->creation_time.sec;
if(super->settings->disk_flags & HTOP_DISK_DEVID_FLAG) {
struct gconfig *kvp;
LIST_FOREACH(kvp, &p->lg_config, lg_config) {
if(strcmp(kvp->lg_name, "ident") == 0) {
disk->devid = xStrdup(kvp->lg_val);
break;
}
}
}
DiskList_add(super, disk);
}
#ifdef DSM_TOTAL_DURATION
long double total_duration;
#endif
#ifdef DSM_TOTAL_BUSY_TIME
long double total_busy_time;
#endif
devstat_compute_statistics(devstat, NULL, 0,
DSM_QUEUE_LENGTH, &disk->queue_length,
DSM_TOTAL_TRANSFERS, &disk->operation_count,
DSM_TOTAL_TRANSFERS_READ, &disk->read_operation_count,
DSM_TOTAL_TRANSFERS_WRITE, &disk->write_operation_count,
DSM_TOTAL_BLOCKS_READ, &disk->read_block_count,
DSM_TOTAL_BLOCKS_WRITE, &disk->write_block_count,
#ifdef DSM_TOTAL_DURATION
DSM_TOTAL_DURATION, &total_duration,
#endif
#ifdef DSM_TOTAL_BUSY_TIME
DSM_TOTAL_BUSY_TIME, &total_busy_time,
#endif
DSM_NONE);
#ifdef DSM_TOTAL_DURATION
disk->oper_time = total_duration * 100;
#else
disk->oper_time =
BINTIME_TO_HUNDREDTHSEC(devstat->duration + DEVSTAT_READ) +
BINTIME_TO_HUNDREDTHSEC(devstat->duration + DEVSTAT_WRITE) +
BINTIME_TO_HUNDREDTHSEC(devstat->duration + DEVSTAT_FREE) +
BINTIME_TO_HUNDREDTHSEC(devstat->duration + DEVSTAT_NO_DATA);
#endif
#ifdef DSM_TOTAL_BUSY_TIME
disk->busy_time = total_busy_time * 100;
#else
disk->busy_time = BINTIME_TO_HUNDREDTHSEC(&devstat->busy_time);
#endif
if(prev_devstat) {
long double transfers_per_second;
long double transfers_per_second_read;
long double transfers_per_second_write;
long double blocks_per_seconds_read;
long double blocks_per_seconds_write;
long double busy_pct;
assert(devstat->id == prev_devstat->id);
devstat_compute_statistics(devstat, prev_devstat, interval,
DSM_TRANSFERS_PER_SECOND, &transfers_per_second,
DSM_TRANSFERS_PER_SECOND_READ, &transfers_per_second_read,
DSM_TRANSFERS_PER_SECOND_WRITE, &transfers_per_second_write,
DSM_BLOCKS_PER_SECOND_READ, &blocks_per_seconds_read,
DSM_BLOCKS_PER_SECOND_WRITE, &blocks_per_seconds_write,
DSM_BUSY_PCT, &busy_pct,
DSM_NONE);
disk->operation_rate = transfers_per_second;
disk->read_operation_rate = transfers_per_second_read;
disk->write_operation_rate = transfers_per_second_write;
disk->read_block_rate = blocks_per_seconds_read;
disk->write_block_rate = blocks_per_seconds_write;
disk->percent_busy = busy_pct;
}
disk->updated = true;
}
geom_stats_snapshot_reset(stats);
geom_stats_snapshot_free(this->previous_stats);
this->previous_stats = stats;
}